| [40ac7a9] | 1 | import React, { useEffect, useState } from 'react';
|
|---|
| 2 | import {
|
|---|
| [1bf6e1f] | 3 | Container, Box, Typography, Button, Grid, IconButton, Dialog, DialogTitle, DialogContent
|
|---|
| [40ac7a9] | 4 | } from '@mui/material';
|
|---|
| 5 | import CloseIcon from '@mui/icons-material/Close';
|
|---|
| 6 | import AutoFixHighIcon from '@mui/icons-material/AutoFixHigh';
|
|---|
| [1bf6e1f] | 7 | import ListIcon from '@mui/icons-material/List';
|
|---|
| [40ac7a9] | 8 |
|
|---|
| [1bf6e1f] | 9 | import BuildDetailsDialog from '../../components/BuildDetailsDialog';
|
|---|
| 10 | import BuildCard from '../../components/BuildCard';
|
|---|
| [40ac7a9] | 11 |
|
|---|
| [1bf6e1f] | 12 | import { onGetApprovedBuilds, onGetAuthState, onCloneBuild } from '../+Layout.telefunc';
|
|---|
| [40ac7a9] | 13 |
|
|---|
| 14 | export default function HomePage() {
|
|---|
| 15 | const [data, setData] = useState<any>(null);
|
|---|
| 16 |
|
|---|
| [1bf6e1f] | 17 | const [selectedBuildId, setSelectedBuildId] = useState<number | null>(null);
|
|---|
| 18 |
|
|---|
| [40ac7a9] | 19 | const [openRankedPopup, setOpenRankedPopup] = useState(false);
|
|---|
| 20 |
|
|---|
| 21 | useEffect(() => {
|
|---|
| [1bf6e1f] | 22 | async function loadSite() {
|
|---|
| 23 | try {
|
|---|
| [40ac7a9] | 24 | const [
|
|---|
| [1bf6e1f] | 25 | authData, highestRankedBuilds, communityBuilds
|
|---|
| [40ac7a9] | 26 | ] = await Promise.all([
|
|---|
| [67dfe57] | 27 | onGetAuthState(),
|
|---|
| [1bf6e1f] | 28 | onGetApprovedBuilds({ limit: 3 , sort: 'rating_desc' }),
|
|---|
| [40ac7a9] | 29 | onGetApprovedBuilds({ limit: 12 })
|
|---|
| 30 | ]);
|
|---|
| 31 |
|
|---|
| 32 | setData({
|
|---|
| 33 | isLoggedIn: authData.isLoggedIn,
|
|---|
| 34 | userId: authData.userId,
|
|---|
| 35 | prebuilts: highestRankedBuilds,
|
|---|
| [1bf6e1f] | 36 | communityBuilds: communityBuilds
|
|---|
| [40ac7a9] | 37 | });
|
|---|
| 38 | } catch (error) {
|
|---|
| 39 | console.error("Error loading homepage data:", error);
|
|---|
| 40 | }
|
|---|
| [1bf6e1f] | 41 | }
|
|---|
| 42 | loadSite();
|
|---|
| 43 | }, []);
|
|---|
| [40ac7a9] | 44 |
|
|---|
| [1bf6e1f] | 45 | const handleCloneWrapper = async (buildId: number) => {
|
|---|
| [40ac7a9] | 46 | if (!data?.isLoggedIn) return alert("Please login to clone builds!");
|
|---|
| [1bf6e1f] | 47 | if (confirm(`Clone this build to your dashboard?`)) {
|
|---|
| 48 | await onCloneBuild({ buildId });
|
|---|
| [40ac7a9] | 49 | alert("Build cloned! Check your dashboard.");
|
|---|
| [1bf6e1f] | 50 | setSelectedBuildId(null);
|
|---|
| [40ac7a9] | 51 | }
|
|---|
| 52 | };
|
|---|
| 53 |
|
|---|
| 54 | if (!data) return <Box sx={{ p: 10, textAlign: 'center' }}>Loading Forge...</Box>;
|
|---|
| 55 |
|
|---|
| 56 | return (
|
|---|
| 57 | <Box>
|
|---|
| 58 | <Box sx={{
|
|---|
| 59 | position: 'relative', height: '500px',
|
|---|
| 60 | display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'white',
|
|---|
| [1bf6e1f] | 61 | '&::before': {
|
|---|
| 62 | content: '""', position: 'absolute', top: 0, left: 0, width: '100%', height: '100%',
|
|---|
| 63 | backgroundColor: 'rgba(0,0,0,0.6)'
|
|---|
| 64 | }
|
|---|
| [40ac7a9] | 65 | }}>
|
|---|
| 66 | <Box sx={{ position: 'relative', textAlign: 'center', zIndex: 1, p: 2 }}>
|
|---|
| 67 | <Typography variant="h2" fontWeight="bold" gutterBottom>Forge Your Ultimate Machine</Typography>
|
|---|
| [1bf6e1f] | 68 | <Typography variant="h5" sx={{ maxWidth: '800px', mx: 'auto', mb: 1 }}>
|
|---|
| [40ac7a9] | 69 | Build, share, discuss, and discover custom PC configurations.
|
|---|
| 70 | </Typography>
|
|---|
| [1bf6e1f] | 71 | <Button variant="contained" size="large" href="/forger" startIcon={<AutoFixHighIcon />}
|
|---|
| 72 | sx={{ fontSize: '1.2rem', px: 4, py: 1.5, mt: 2 }}>
|
|---|
| [40ac7a9] | 73 | Start Forging
|
|---|
| 74 | </Button>
|
|---|
| 75 | </Box>
|
|---|
| 76 | </Box>
|
|---|
| 77 |
|
|---|
| 78 | <Container maxWidth="xl" sx={{ mt: 6, mb: 10 }}>
|
|---|
| [1bf6e1f] | 79 | <Box sx={{
|
|---|
| 80 | mb: 4, borderLeft: '5px solid #ff8201', pl: 2,
|
|---|
| 81 | display: 'flex', justifyContent: 'space-between', alignItems: 'end'
|
|---|
| 82 | }}>
|
|---|
| [40ac7a9] | 83 | <Box>
|
|---|
| 84 | <Typography variant="h4" fontWeight="bold">Hall of Fame</Typography>
|
|---|
| [1bf6e1f] | 85 | <Typography variant="subtitle1" color="text.secondary">
|
|---|
| 86 | The highest rated configurations from across the community.
|
|---|
| 87 | </Typography>
|
|---|
| [40ac7a9] | 88 | </Box>
|
|---|
| [1bf6e1f] | 89 | <Button variant="outlined" startIcon={<ListIcon />} onClick={() => setOpenRankedPopup(true)}>
|
|---|
| [40ac7a9] | 90 | Show All Top Ranked
|
|---|
| 91 | </Button>
|
|---|
| 92 | </Box>
|
|---|
| 93 |
|
|---|
| [1bf6e1f] | 94 | <Grid container spacing={2} sx={{ mb: 8, alignItems: 'stretch' }}>
|
|---|
| 95 | {/*<Grid item xs={12} md={3} sx={{ display: 'flex' }}>*/}
|
|---|
| 96 | {/* <Box sx={{*/}
|
|---|
| 97 | {/* width: '100%', p: 3, bgcolor: '#ff8201', color: 'black', borderRadius: 2,*/}
|
|---|
| 98 | {/* display: 'flex', flexDirection: 'column', justifyContent: 'center'*/}
|
|---|
| 99 | {/* }}>*/}
|
|---|
| 100 | {/* <Typography color={'black'} variant="h5" fontWeight="bold" gutterBottom>The Elite</Typography>*/}
|
|---|
| 101 | {/* <Typography variant="body1" fontWeight="bold">The top 3 community-voted builds.</Typography>*/}
|
|---|
| 102 | {/* </Box>*/}
|
|---|
| 103 | {/*</Grid>*/}
|
|---|
| 104 |
|
|---|
| 105 | {data.prebuilts.slice(0, 3).map((build: any) => (
|
|---|
| 106 | <Grid item xs={12} sm={6} md={3} key={build.id} sx={{ display: 'flex' }}>
|
|---|
| 107 | <Box sx={{ width: '100%' }}>
|
|---|
| 108 | <BuildCard
|
|---|
| 109 | build={build}
|
|---|
| 110 | onClick={() => setSelectedBuildId(build.id)}
|
|---|
| 111 | />
|
|---|
| 112 | </Box>
|
|---|
| [40ac7a9] | 113 | </Grid>
|
|---|
| 114 | ))}
|
|---|
| 115 | </Grid>
|
|---|
| 116 |
|
|---|
| [1bf6e1f] | 117 |
|
|---|
| [40ac7a9] | 118 | <SectionHeader title="Community Forge" subtitle="Fresh builds from users around the world."/>
|
|---|
| 119 | <Grid container spacing={3}>
|
|---|
| 120 | {data.communityBuilds.map((build: any) => (
|
|---|
| 121 | <Grid item xs={12} sm={6} md={3} key={build.id}>
|
|---|
| [1bf6e1f] | 122 | <BuildCard
|
|---|
| 123 | build={build}
|
|---|
| 124 | onClick={() => setSelectedBuildId(build.id)}
|
|---|
| 125 | />
|
|---|
| [40ac7a9] | 126 | </Grid>
|
|---|
| 127 | ))}
|
|---|
| 128 | </Grid>
|
|---|
| 129 |
|
|---|
| 130 | <Box sx={{ display: 'flex', justifyContent: 'center', mt: 6 }}>
|
|---|
| 131 | <Button variant="outlined" size="large" href="/completed-builds">View All Community Builds</Button>
|
|---|
| 132 | </Box>
|
|---|
| 133 | </Container>
|
|---|
| 134 |
|
|---|
| [1bf6e1f] | 135 |
|
|---|
| 136 | <BuildDetailsDialog
|
|---|
| 137 | open={!!selectedBuildId}
|
|---|
| 138 | buildId={selectedBuildId}
|
|---|
| 139 | currentUser={data.userId}
|
|---|
| 140 | onClose={() => setSelectedBuildId(null)}
|
|---|
| 141 | onClone={handleCloneWrapper}
|
|---|
| 142 | />
|
|---|
| [40ac7a9] | 143 |
|
|---|
| 144 |
|
|---|
| 145 | <Dialog open={openRankedPopup} onClose={() => setOpenRankedPopup(false)} maxWidth="lg" fullWidth>
|
|---|
| 146 | <DialogTitle sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|---|
| 147 | Hall of Fame (All Top Ranked)
|
|---|
| 148 | <IconButton onClick={() => setOpenRankedPopup(false)}><CloseIcon /></IconButton>
|
|---|
| 149 | </DialogTitle>
|
|---|
| 150 | <DialogContent dividers>
|
|---|
| 151 | <Grid container spacing={3}>
|
|---|
| 152 | {data.prebuilts.concat(data.communityBuilds).map((build: any) => (
|
|---|
| 153 | <Grid item xs={12} sm={6} md={3} key={`popup-${build.id}`}>
|
|---|
| [1bf6e1f] | 154 | <BuildCard
|
|---|
| 155 | build={build}
|
|---|
| 156 | onClick={() => {
|
|---|
| 157 | setOpenRankedPopup(false);
|
|---|
| 158 | setSelectedBuildId(build.id); // Open details from popup
|
|---|
| 159 | }}
|
|---|
| 160 | />
|
|---|
| [40ac7a9] | 161 | </Grid>
|
|---|
| 162 | ))}
|
|---|
| 163 | </Grid>
|
|---|
| 164 | </DialogContent>
|
|---|
| 165 | </Dialog>
|
|---|
| 166 |
|
|---|
| 167 | </Box>
|
|---|
| 168 | );
|
|---|
| 169 | }
|
|---|
| 170 |
|
|---|
| 171 | function SectionHeader({ title, subtitle }: { title: string, subtitle: string }) {
|
|---|
| 172 | return (
|
|---|
| 173 | <Box sx={{ mb: 4, borderLeft: '5px solid #1976d2', pl: 2 }}>
|
|---|
| 174 | <Typography variant="h4" fontWeight="bold" color="text.primary">{title}</Typography>
|
|---|
| 175 | <Typography variant="subtitle1" color="text.secondary">{subtitle}</Typography>
|
|---|
| 176 | </Box>
|
|---|
| 177 | );
|
|---|
| 178 | }
|
|---|