Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cfc57e2bdc | |||
| 35bf3268c7 |
149
src/app/page.tsx
149
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" },
|
||||||
];
|
];
|
||||||
@@ -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