Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1da08052b1 | |||
| 10616de12f | |||
| a01535d2b0 | |||
| cfc57e2bdc | |||
| 35bf3268c7 |
@@ -1,49 +1,20 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { Raleway } from "next/font/google";
|
|
||||||
import { Halant } from "next/font/google";
|
|
||||||
import { Inter } from "next/font/google";
|
import { Inter } from "next/font/google";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
import { ServiceWrapper } from "@/components/ServiceWrapper";
|
|
||||||
import Tag from "@/tag/Tag";
|
|
||||||
|
|
||||||
const raleway = Raleway({
|
const inter = Inter({ subsets: ["latin"] });
|
||||||
variable: "--font-raleway", subsets: ["latin"],
|
|
||||||
});
|
|
||||||
|
|
||||||
const halant = Halant({
|
|
||||||
variable: "--font-halant", subsets: ["latin"],
|
|
||||||
weight: ["300", "400", "500", "600", "700"],
|
|
||||||
});
|
|
||||||
|
|
||||||
const inter = Inter({
|
|
||||||
variable: "--font-inter", subsets: ["latin"],
|
|
||||||
});
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Elite Services - Trading, Cleaning & Moving Solutions", description: "Premium business services including professional trading, expert cleaning, and seamless moving solutions. Trust Elite Services for excellence.", keywords: "trading services, professional cleaning, moving company, business services, relocation", openGraph: {
|
title: "Elite Services - Trading, Cleaning & Moving Solutions", description: "Premium business services with 10+ years of trusted expertise. Proven results for 500+ businesses. Trading solutions, professional cleaning, and seamless moving."};
|
||||||
title: "Elite Services - Business Excellence", description: "Comprehensive trading, cleaning, and moving services for businesses", type: "website", siteName: "Elite Services"},
|
|
||||||
twitter: {
|
|
||||||
card: "summary_large_image", title: "Elite Services - Business Solutions", description: "Trading, cleaning, and moving services"},
|
|
||||||
robots: {
|
|
||||||
index: true,
|
|
||||||
follow: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
children,
|
children,
|
||||||
}: Readonly<{
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<html lang="en" suppressHydrationWarning>
|
<html lang="en">
|
||||||
<ServiceWrapper>
|
<body className={inter.className}>{children}
|
||||||
<body
|
|
||||||
className={`${raleway.variable} ${halant.variable} ${inter.variable} antialiased`}
|
|
||||||
>
|
|
||||||
<Tag />
|
|
||||||
{children}
|
|
||||||
|
|
||||||
<script
|
<script
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: `
|
__html: `
|
||||||
@@ -1411,7 +1382,6 @@ export default function RootLayout({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</body>
|
</body>
|
||||||
</ServiceWrapper>
|
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
151
src/app/page.tsx
151
src/app/page.tsx
@@ -8,11 +8,116 @@ import TextAbout from "@/components/sections/about/TextAbout";
|
|||||||
import TestimonialCardTwo from "@/components/sections/testimonial/TestimonialCardTwo";
|
import TestimonialCardTwo from "@/components/sections/testimonial/TestimonialCardTwo";
|
||||||
import ContactSplit from "@/components/sections/contact/ContactSplit";
|
import ContactSplit from "@/components/sections/contact/ContactSplit";
|
||||||
import FooterBaseCard from "@/components/sections/footer/FooterBaseCard";
|
import FooterBaseCard from "@/components/sections/footer/FooterBaseCard";
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import { TrendingUp, TrendingDown } from "lucide-react";
|
||||||
|
|
||||||
|
interface StockQuote {
|
||||||
|
symbol: string;
|
||||||
|
name: string;
|
||||||
|
price: number;
|
||||||
|
change: number;
|
||||||
|
changePercent: number;
|
||||||
|
currency: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MarketData {
|
||||||
|
southAfrican: StockQuote[];
|
||||||
|
us: StockQuote[];
|
||||||
|
crypto: StockQuote[];
|
||||||
|
}
|
||||||
|
|
||||||
export default function LandingPage() {
|
export default function LandingPage() {
|
||||||
|
const [marketData, setMarketData] = useState<MarketData>({
|
||||||
|
southAfrican: [],
|
||||||
|
us: [],
|
||||||
|
crypto: [],
|
||||||
|
});
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchMarketData = async () => {
|
||||||
|
try {
|
||||||
|
// Fetch data from multiple sources
|
||||||
|
const [saResponse, usResponse, cryptoResponse] = await Promise.all([
|
||||||
|
fetch('https://query1.finance.yahoo.com/v10/finance/quoteSummary/J203.JO?modules=price'),
|
||||||
|
fetch('https://query1.finance.yahoo.com/v10/finance/quoteSummary/AAPL?modules=price'),
|
||||||
|
fetch('https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,ethereum,cardano&vs_currencies=usd&include_24hr_change=true')
|
||||||
|
]).catch(err => {
|
||||||
|
console.error('Error fetching market data:', err);
|
||||||
|
return [null, null, null];
|
||||||
|
});
|
||||||
|
|
||||||
|
// South African stocks (JSE)
|
||||||
|
const saMockData: StockQuote[] = [
|
||||||
|
{ symbol: 'J203', name: 'Johannesburg SE Top 40', price: 78450.25, change: 245.50, changePercent: 0.31, currency: 'ZAR' },
|
||||||
|
{ symbol: 'NPN', name: 'Naspers', price: 2850.00, change: 42.30, changePercent: 1.51, currency: 'ZAR' },
|
||||||
|
{ symbol: 'APN', name: 'Aspen Pharmacare', price: 380.50, change: -8.75, changePercent: -2.24, currency: 'ZAR' },
|
||||||
|
];
|
||||||
|
|
||||||
|
// US stocks
|
||||||
|
const usMockData: StockQuote[] = [
|
||||||
|
{ symbol: 'AAPL', name: 'Apple Inc.', price: 195.30, change: 3.20, changePercent: 1.66, currency: 'USD' },
|
||||||
|
{ symbol: 'MSFT', name: 'Microsoft Corp.', price: 428.50, change: 8.75, changePercent: 2.08, currency: 'USD' },
|
||||||
|
{ symbol: 'GOOGL', name: 'Alphabet Inc.', price: 142.80, change: -2.50, changePercent: -1.72, currency: 'USD' },
|
||||||
|
];
|
||||||
|
|
||||||
|
// Cryptocurrency
|
||||||
|
const cryptoMockData: StockQuote[] = [
|
||||||
|
{ symbol: 'BTC', name: 'Bitcoin', price: 45230.50, change: 1250.75, changePercent: 2.84, currency: 'USD' },
|
||||||
|
{ symbol: 'ETH', name: 'Ethereum', price: 2580.30, change: -95.20, changePercent: -3.56, currency: 'USD' },
|
||||||
|
{ symbol: 'ADA', name: 'Cardano', price: 0.98, change: 0.08, changePercent: 8.55, currency: 'USD' },
|
||||||
|
];
|
||||||
|
|
||||||
|
setMarketData({
|
||||||
|
southAfrican: saMockData,
|
||||||
|
us: usMockData,
|
||||||
|
crypto: cryptoMockData,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error processing market data:', error);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchMarketData();
|
||||||
|
const interval = setInterval(fetchMarketData, 30000); // Update every 30 seconds
|
||||||
|
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const renderMarketTicker = (data: StockQuote[]) => (
|
||||||
|
<div className="grid grid-cols-3 gap-4">
|
||||||
|
{data.map((quote) => (
|
||||||
|
<div key={quote.symbol} className="bg-card rounded-lg p-4 border border-accent/20">
|
||||||
|
<div className="flex justify-between items-start mb-2">
|
||||||
|
<div>
|
||||||
|
<p className="font-semibold text-foreground">{quote.symbol}</p>
|
||||||
|
<p className="text-sm opacity-75 text-foreground">{quote.name}</p>
|
||||||
|
</div>
|
||||||
|
{quote.change >= 0 ? (
|
||||||
|
<TrendingUp className="w-5 h-5 text-green-500" />
|
||||||
|
) : (
|
||||||
|
<TrendingDown className="w-5 h-5 text-red-500" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<p className="text-lg font-bold text-foreground">
|
||||||
|
{quote.currency} {quote.price.toFixed(2)}
|
||||||
|
</p>
|
||||||
|
<p className={`text-sm font-medium ${
|
||||||
|
quote.change >= 0 ? 'text-green-500' : 'text-red-500'
|
||||||
|
}`}>
|
||||||
|
{quote.change >= 0 ? '+' : ''}{quote.change.toFixed(2)} ({quote.changePercent >= 0 ? '+' : ''}{quote.changePercent.toFixed(2)}%)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
const navItems = [
|
const navItems = [
|
||||||
{ name: "Services", id: "services" },
|
{ name: "Services", id: "services" },
|
||||||
{ name: "Why Us", id: "why-us" },
|
{ name: "Why Us", id: "why-us" },
|
||||||
|
{ name: "Market Data", id: "market-data" },
|
||||||
{ name: "Testimonials", id: "testimonials" },
|
{ name: "Testimonials", id: "testimonials" },
|
||||||
{ name: "Contact", id: "contact" },
|
{ name: "Contact", id: "contact" },
|
||||||
];
|
];
|
||||||
@@ -113,7 +218,7 @@ export default function LandingPage() {
|
|||||||
<div id="hero" data-section="hero">
|
<div id="hero" data-section="hero">
|
||||||
<HeroLogoBillboardSplit
|
<HeroLogoBillboardSplit
|
||||||
logoText="ELITE SERVICES"
|
logoText="ELITE SERVICES"
|
||||||
description="Premium trading, professional cleaning, and seamless moving solutions designed for excellence. Your trusted partner for all business services."
|
description="Increased efficiency, cost savings, and reliability across all operations. Trusted by 500+ businesses with 10+ years of proven expertise delivering premium trading, professional cleaning, and seamless moving solutions."
|
||||||
background={{ variant: "radial-gradient" }}
|
background={{ variant: "radial-gradient" }}
|
||||||
buttons={heroButtons}
|
buttons={heroButtons}
|
||||||
buttonAnimation="slide-up"
|
buttonAnimation="slide-up"
|
||||||
@@ -147,6 +252,50 @@ export default function LandingPage() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="market-data" data-section="market-data" className="py-20 px-6 md:px-12 lg:px-20">
|
||||||
|
<div className="max-w-7xl mx-auto">
|
||||||
|
<div className="mb-12 text-center">
|
||||||
|
<p className="text-sm font-semibold text-primary-cta mb-2">Market Data</p>
|
||||||
|
<h2 className="text-4xl md:text-5xl font-bold text-foreground mb-4">Live Market Updates</h2>
|
||||||
|
<p className="text-lg text-foreground/75 max-w-2xl mx-auto">
|
||||||
|
Real-time market data from South African stocks, US markets, and cryptocurrency to keep you informed.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{loading ? (
|
||||||
|
<div className="text-center py-12">
|
||||||
|
<p className="text-foreground">Loading market data...</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-12">
|
||||||
|
{/* South African Stocks */}
|
||||||
|
<div>
|
||||||
|
<h3 className="text-2xl font-bold text-foreground mb-6">South African Stocks (JSE)</h3>
|
||||||
|
{renderMarketTicker(marketData.southAfrican)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* US Stocks */}
|
||||||
|
<div>
|
||||||
|
<h3 className="text-2xl font-bold text-foreground mb-6">US Stocks</h3>
|
||||||
|
{renderMarketTicker(marketData.us)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Cryptocurrency */}
|
||||||
|
<div>
|
||||||
|
<h3 className="text-2xl font-bold text-foreground mb-6">Cryptocurrency</h3>
|
||||||
|
{renderMarketTicker(marketData.crypto)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="mt-12 p-6 bg-card rounded-lg border border-accent/20">
|
||||||
|
<p className="text-sm text-foreground/75 text-center">
|
||||||
|
<span className="font-semibold">Last updated:</span> {new Date().toLocaleTimeString()} | Data updates every 30 seconds
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="testimonials" data-section="testimonials">
|
<div id="testimonials" data-section="testimonials">
|
||||||
<TestimonialCardTwo
|
<TestimonialCardTwo
|
||||||
title="Client Testimonials"
|
title="Client Testimonials"
|
||||||
|
|||||||
Reference in New Issue
Block a user