Source: pages/HomePage.jsx

/** ========= REACT & REACT ROUTER ========= */
import { useEffect, useRef } from 'react';
import { useNavigate } from 'react-router-dom';

/** ========= MUI ========= */
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import CircularProgress from '@mui/material/CircularProgress';
import Divider from '@mui/material/Divider';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import { useTheme } from '@mui/material';

/** ========= ICONS ========= */
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
import DashboardIcon from '@mui/icons-material/Dashboard';
import HandshakeIcon from '@mui/icons-material/Handshake';
import LoginIcon from '@mui/icons-material/Login';
import LogoutIcon from '@mui/icons-material/Logout';
import PostAddIcon from '@mui/icons-material/PostAdd';

/** ========= BACKEND ========= */
import { GoogleAuthProvider, signInWithPopup, signOut } from 'firebase/auth';
import { useAuth } from '../contexts/useAuth';
import { useFeedback } from '../contexts/useFeedback';
import { auth } from '../data/Firebase';
import { createUserIfMissing } from '../data/FirestoreMethods';

/** Only want to define once, we don't need to re-define on re-render */
const provider = new GoogleAuthProvider();

export default function HomePage() {
	const { setFeedback } = useFeedback();
	const { user, loading } = useAuth();
	const navigate = useNavigate();
	const theme = useTheme();
	const canvasRef = useRef(null);
	const isDark = theme.palette.mode === 'dark';

	const handleSignIn = async () => {
		try {
			const result = await signInWithPopup(auth, provider);
			await createUserIfMissing(result.user);
		} catch (e) {
			console.error(e);
			setFeedback('Sign in failed', 'error');
		}
	};
	const handleSignOut = async () => {
		try {
			await signOut(auth);
		} catch (e) {
			console.error(e);
			setFeedback('Sign out failed', 'error');
		}
	};

	useEffect(() => {
		const canvas = canvasRef.current;
		const ctx = canvas.getContext('2d');
		let width = (canvas.width = window.innerWidth);
		let height = (canvas.height = window.innerHeight);
		let animationFrameId;

		const nodes = Array.from({ length: 80 }, () => ({
			x: Math.random() * width,
			y: Math.random() * height,
			vx: (Math.random() - 0.5) * 0.4,
			vy: (Math.random() - 0.5) * 0.4,
		}));

		function draw() {
			ctx.clearRect(0, 0, width, height);

			const bg = isDark
				? ctx.createLinearGradient(0, 0, width, height)
				: ctx.createLinearGradient(0, 0, width, height);
			if (isDark) {
				bg.addColorStop(0, '#0d1117');
				bg.addColorStop(0.5, '#17223b');
				bg.addColorStop(1, '#263859');
			} else {
				bg.addColorStop(0, '#f0f4ff');
				bg.addColorStop(1, '#e8f6ff');
			}
			ctx.fillStyle = bg;
			ctx.fillRect(0, 0, width, height);

			for (let i = 0; i < nodes.length; i++) {
				const n = nodes[i];
				n.x += n.vx;
				n.y += n.vy;
				if (n.x < 0 || n.x > width) n.vx *= -1;
				if (n.y < 0 || n.y > height) n.vy *= -1;

				ctx.beginPath();
				ctx.arc(n.x, n.y, 2, 0, Math.PI * 2);
				ctx.fillStyle = isDark ? 'rgba(0,188,212,0.9)' : 'rgba(70,130,180,0.6)';
				ctx.fill();
			}

			for (let i = 0; i < nodes.length; i++) {
				for (let j = i + 1; j < nodes.length; j++) {
					const dx = nodes[i].x - nodes[j].x;
					const dy = nodes[i].y - nodes[j].y;
					const dist = Math.sqrt(dx * dx + dy * dy);
					if (dist < 120) {
						ctx.beginPath();
						ctx.strokeStyle = isDark
							? `rgba(0,188,212,${1 - dist / 120})`
							: `rgba(70,130,180,${0.6 - dist / 200})`;
						ctx.lineWidth = 0.5;
						ctx.moveTo(nodes[i].x, nodes[i].y);
						ctx.lineTo(nodes[j].x, nodes[j].y);
						ctx.stroke();
					}
				}
			}
			animationFrameId = requestAnimationFrame(draw);
		}
		draw();

		const handleResize = () => {
			width = canvas.width = window.innerWidth;
			height = canvas.height = window.innerHeight;
		};
		window.addEventListener('resize', handleResize);

		return () => {
			window.removeEventListener('resize', handleResize);
			cancelAnimationFrame(animationFrameId);
		};
	}, [isDark]);
	return (
		<Box
			sx={{
				position: 'relative',
				minHeight: '100vh',
				width: '100%',
				display: 'flex',
				flexDirection: 'column',
				alignItems: 'center',
				justifyContent: 'center',
				color: isDark ? 'white' : 'black',
				textAlign: 'center',
				overflow: 'hidden',
			}}
		>
			{/* Fullscreen Canvas */}
			<canvas
				ref={canvasRef}
				style={{
					position: 'fixed',
					top: 0,
					left: 0,
					width: '100vw',
					height: '100vh',
					zIndex: -1,
					pointerEvents: 'none',
				}}
			/>
			{/* Hero and Content */}
			{loading ? (
				<CircularProgress color="inherit" sx={{ zIndex: 1 }} />
			) : (
				<>
					<Stack
						spacing={2}
						alignItems="center"
						textAlign="center"
						mb={6}
						sx={{ position: 'relative', zIndex: 1 }}
					>
						<Typography
							fontWeight={800}
							sx={{
								fontSize: { xs: '2.8rem', sm: '4rem', md: '5rem' },
								letterSpacing: '1px',
								background: isDark
									? 'linear-gradient(90deg, #00bcd4, #26c6da, #80deea)'
									: 'linear-gradient(90deg, #1e88e5, #64b5f6)',
								WebkitBackgroundClip: 'text',
								WebkitTextFillColor: 'transparent',
								textShadow: isDark
									? '0 0 25px rgba(0,188,212,0.3)'
									: '0 0 10px rgba(100,149,237,0.2)',
							}}
						>
							Swapify
						</Typography>
						<Typography
							variant="subtitle1"
							sx={{
								fontSize: '1.1rem',
								color: isDark ? 'rgba(255,255,255,0.85)' : 'rgba(0,0,0,0.7)',
							}}
						>
							Trade skills. Grow together.
						</Typography>
						{!user ? (
							<Button
								onClick={handleSignIn}
								variant="contained"
								startIcon={<LoginIcon />}
								sx={{
									mt: 2,
									px: 3,
									py: 1.2,
									fontSize: '1rem',
									backgroundColor: isDark ? '#00bcd4' : '#1e88e5',
									color: 'white',
									textTransform: 'none',
									borderRadius: '10px',
									boxShadow: isDark
										? '0 0 20px rgba(0,188,212,0.4)'
										: '0 3px 10px rgba(100,149,237,0.3)',
									'&:hover': {
										backgroundColor: isDark ? '#00acc1' : '#1976d2',
										boxShadow: isDark
											? '0 0 30px rgba(0,188,212,0.6)'
											: '0 3px 10px rgba(100,149,237,0.5)',
									},
								}}
							>
								Sign in with Google
							</Button>
						) : (
							<>
								<Typography
									variant="body1"
									sx={{
										color: isDark ? 'rgba(255,255,255,0.8)' : 'rgba(0,0,0,0.7)',
									}}
								>
									Hello, {user.displayName || user.email}
								</Typography>

								<Stack direction="row" spacing={2} justifyContent="center">
									<Button
										onClick={() => navigate('/viewTrades')}
										variant="contained"
										color="success"
										startIcon={<DashboardIcon />}
									>
										Go to Dashboard
									</Button>
									<Button
										onClick={handleSignOut}
										variant="outlined"
										color="inherit"
										startIcon={<LogoutIcon />}
									>
										Sign Out
									</Button>
								</Stack>

								<Button
									variant="contained"
									color="secondary"
									startIcon={<PostAddIcon />}
									onClick={() => navigate('/createTrade')}
									sx={{ mt: 2 }}
								>
									Create a New Trade
								</Button>
							</>
						)}
					</Stack>

					<Divider
						sx={{
							width: '100%',
							maxWidth: '800px',
							borderColor: isDark ? 'rgba(255,255,255,0.2)' : 'rgba(0,0,0,0.1)',
							mb: 4,
							zIndex: 1,
						}}
					/>

					<Typography
						variant="h5"
						fontWeight="bold"
						gutterBottom
						sx={{ zIndex: 1 }}
					>
						How It Works
					</Typography>

					<Stack
						direction={{ xs: 'column', md: 'row' }}
						spacing={3}
						alignItems="center"
						justifyContent="center"
						sx={{
							width: '100%',
							maxWidth: '900px',
							px: 2,
							position: 'relative',
							zIndex: 1,
						}}
					>
						{[
							{
								icon: <PostAddIcon fontSize="large" sx={{ mb: 1 }} />,
								title: 'Post a Skill',
								desc: 'List something you can offer — coding, design, tutoring, anything.',
							},
							{
								icon: <ArrowForwardIcon fontSize="large" sx={{ mb: 1 }} />,
								title: 'Find a Match',
								desc: 'Explore and match with users looking to trade compatible skills.',
							},
							{
								icon: <HandshakeIcon fontSize="large" sx={{ mb: 1 }} />,
								title: 'Make the Trade',
								desc: 'Connect securely and exchange skills with clarity and confidence.',
							},
						].map((card, i) => (
							<Card
								key={i}
								sx={{
									backgroundColor: isDark ? '#1f1f1f' : '#ffffff',
									color: isDark ? 'white' : 'black',
									minWidth: 250,
									boxShadow: isDark
										? '0 0 15px rgba(0,188,212,0.2)'
										: '0 3px 10px rgba(100,149,237,0.2)',
									borderRadius: 3,
									transition: 'transform 0.3s ease, box-shadow 0.3s ease',
									'&:hover': {
										transform: 'translateY(-5px)',
										boxShadow: isDark
											? '0 0 25px rgba(0,188,212,0.4)'
											: '0 5px 20px rgba(100,149,237,0.3)',
									},
								}}
							>
								<CardContent>
									{card.icon}
									<Typography variant="h6" fontWeight="bold">
										{card.title}
									</Typography>
									<Typography
										variant="body2"
										sx={{
											color: isDark
												? 'rgba(255,255,255,0.8)'
												: 'rgba(0,0,0,0.7)',
										}}
									>
										{card.desc}
									</Typography>
								</CardContent>
							</Card>
						))}
					</Stack>

					<Typography
						variant="caption"
						sx={{
							mt: 6,
							opacity: 0.6,
							zIndex: 1,
							color: isDark ? 'rgba(255,255,255,0.6)' : 'rgba(0,0,0,0.5)',
						}}
					>
						Built by students at Wilfrid Laurier University to connect and grow.
					</Typography>
				</>
			)}
		</Box>
	);
}