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