source: components/ComponentDetailsDialog.tsx@ 4f2900a

main
Last change on this file since 4f2900a was f727252, checked in by Mihail <mihail2.naumov@…>, 5 months ago

Optimizations & Layout/Text changes

  • Property mode set to 100644
File size: 11.0 KB
RevLine 
[a932c9e]1import React, {useEffect, useState} from 'react';
2import {
3 Dialog, DialogTitle, DialogContent, DialogActions, Button,
[f727252]4 Typography, Box, Chip, CircularProgress, IconButton,
[a932c9e]5 Table, TableBody, TableCell, TableContainer, TableRow, Paper
6} from '@mui/material';
7import CloseIcon from '@mui/icons-material/Close';
8import {onGetComponentDetails} from '../pages/+Layout.telefunc';
9
10export default function ComponentDetailsDialog({open, component, onClose}: any) {
11 const [fullData, setFullData] = useState<any>(null);
12 const [loading, setLoading] = useState(false);
13
14 useEffect(() => {
15 if (open && component) {
16 setLoading(true);
17 onGetComponentDetails({componentId: component.id})
18 .then(data => setFullData(data))
19 .catch(console.error)
20 .finally(() => setLoading(false));
21 } else {
22 setFullData(null);
23 }
24 }, [open, component]);
25
26 if (!open || !component) return null;
27
28 const displayData = fullData || component;
29 const specs = fullData?.details || {};
30
31 const formatMoney = (amount: number) => `$${Number(amount).toFixed(2)}`;
32
33 const renderValue = (key: string, val: any) => {
34 if (Array.isArray(val)) {
[8a7f936]35 if (val.length === 0) return 'None';
36
37 if (typeof val[0] === 'string') {
38 return val.join(', ');
39 }
40
41 if (typeof val[0] === 'object') {
42 const parts = val
43 .map((v: any) =>
44 v.socket ||
45 v.formFactor ||
46 v.name ||
47 v.type ||
48 Object.values(v)[0]
49 )
50 .filter(Boolean);
51 return parts.length > 0 ? parts.join(', ') : 'None';
[a932c9e]52 }
[8a7f936]53
[a932c9e]54 return val.join(', ');
55 }
56
57 const strVal = String(val);
58 const lowerKey = key.toLowerCase();
59
60 if (lowerKey.includes('capacity') || lowerKey.includes('vram') || lowerKey === 'memory') {
61 return `${strVal} GB`;
62 }
63
64 if (lowerKey.includes('tdp') || lowerKey.includes('wattage')) {
65 return `${strVal} W`;
66 }
67
68 if (lowerKey.includes('length') || lowerKey.includes('height') || lowerKey.includes('width')) {
69 return `${strVal} mm`;
70 }
71
72 if (lowerKey.includes('clock')) {
73 return `${strVal} GHz`;
74 }
[8a7f936]75
[a932c9e]76 if (lowerKey.includes('speed')) {
77 return `${strVal} MHz`;
78 }
79
80 return strVal;
81 };
82
83 const formatKey = (key: string) => {
84 return key
85 .replace(/([A-Z])/g, ' $1')
86 .replace(/_/g, ' ')
87 .replace(/\b\w/g, c => c.toUpperCase());
88 };
89
90 return (
91 <Dialog
92 open={open}
93 onClose={onClose}
[f727252]94 maxWidth="md"
95 fullWidth
96 scroll="body"
[a932c9e]97 sx={{zIndex: 1400}}
98 >
99 <DialogTitle sx={{
100 display: 'flex',
101 justifyContent: 'space-between',
102 alignItems: 'center',
103 bgcolor: '#333',
104 color: 'white'
105 }}>
106 <Box>
107 <Typography variant="caption" sx={{textTransform: 'uppercase', opacity: 0.7}}>
108 {displayData.brand}
109 </Typography>
110 <Typography variant="h6" fontWeight="bold">
111 {displayData.name}
112 </Typography>
113 </Box>
114 <IconButton onClick={onClose} sx={{color: 'white'}}>
115 <CloseIcon/>
116 </IconButton>
117 </DialogTitle>
118
[f727252]119 <DialogContent
120 sx={{
121 p: 1,
122 overflow: 'visible'
123 }}
124 >
[a932c9e]125 {loading ? (
126 <Box sx={{display: 'flex', justifyContent: 'center', p: 5}}>
127 <CircularProgress/>
128 </Box>
129 ) : (
[f727252]130 <Box
131 sx={{
132 display: 'grid',
133 gridTemplateColumns: {
134 xs: '1fr',
135 md: '1fr 1fr'
136 },
137 gap: 4,
138 width: '100%'
139 }}
140 >
141 <Box sx={{display: 'flex', flexDirection: 'column', alignItems: 'center'}}>
[a932c9e]142 <Box
143 component="img"
[6ce6739]144 src={displayData.imgUrl}
[a932c9e]145 alt={displayData.name}
146 sx={{
147 width: '100%',
148 maxHeight: 300,
149 objectFit: 'contain',
[f727252]150 mb: 1,
151 mt: 7,
152 p: 1
[a932c9e]153 }}
154 />
155 <Chip
156 label={displayData.type?.toUpperCase()}
157 color="primary"
158 sx={{fontWeight: 'bold'}}
159 />
[f727252]160 </Box>
[a932c9e]161
[f727252]162 <Box sx={{
163 display: 'flex',
164 flexDirection: 'column',
165 alignItems: 'center',
166 width: '70%'
167 }}>
168 <Typography
169 variant="subtitle1"
170 fontWeight="bold"
171 gutterBottom
172 sx={{
173 borderBottom: '2px solid #ff8201',
174 mb: 1,
175 mt: 1,
176 textAlign: 'center',
177 width: '100%'
178 }}
179 >
[a932c9e]180 Technical Specifications
181 </Typography>
182
[f727252]183 <TableContainer
184 component={Paper}
185 variant="outlined"
186 sx={{
187 maxWidth: '100%',
188 width: '100%'
189 }}
190 >
191 <Table size="medium">
[a932c9e]192 <TableBody>
193 <TableRow>
[f727252]194 <TableCell
195 component="th"
196 scope="row"
197 sx={{
198 fontWeight: 'bold',
199 width: '50%',
200 bgcolor: '#1e1e1e',
201 textAlign: 'center',
202 px: 2
203 }}
204 >
[a932c9e]205 Brand
206 </TableCell>
[f727252]207 <TableCell sx={{
208 textAlign: 'center',
209 px: 2,
210 width: '50%'
211 }}>
212 {displayData.brand}
213 </TableCell>
[a932c9e]214 </TableRow>
215
216 {Object.entries(specs).map(([key, val]) => {
217 if (key === 'componentId' || key === 'id') return null;
218
219 return (
220 <TableRow key={key}>
[f727252]221 <TableCell
222 component="th"
223 scope="row"
224 sx={{
225 fontWeight: 'bold',
226 width: '50%',
227 bgcolor: '#1e1e1e',
228 textAlign: 'center',
229 px: 2
230 }}
231 >
[a932c9e]232 {formatKey(key)}
233 </TableCell>
[f727252]234 <TableCell sx={{
235 textAlign: 'center',
236 px: 2,
237 width: '50%'
238 }}>
239 {renderValue(key, val)}
240 </TableCell>
[a932c9e]241 </TableRow>
242 );
243 })}
244 </TableBody>
245 </Table>
246 </TableContainer>
[f727252]247
248 <Box sx={{
249 display: 'flex',
250 justifyContent: 'center',
251 alignItems: 'center',
252 mt: 1,
253 width: '100%'
254 }}>
[a932c9e]255 <Typography variant="h4" color="primary.main" fontWeight="bold">
256 {formatMoney(displayData.price)}
257 </Typography>
258 </Box>
[f727252]259 </Box>
260 </Box>
[a932c9e]261 )}
262 </DialogContent>
263
264 <DialogActions sx={{p: 2}}>
265 <Button onClick={onClose} variant="contained"
266 sx={{
267 backgroundColor: '#ff8201',
268 color: 'white',
269 borderColor: '#ff8201',
[f727252]270 '&:hover': {backgroundColor: '#ba5d02', borderColor: '#ba5d02'}
[a932c9e]271 }}
272 >Close</Button>
273 </DialogActions>
274 </Dialog>
275 );
276}
Note: See TracBrowser for help on using the repository browser.