source: components/ComponentDetailsDialog.tsx@ 107303c

main
Last change on this file since 107303c was 6ce6739, checked in by Mihail <mihail2.naumov@…>, 7 months ago

Added real images for components

  • Property mode set to 100644
File size: 7.9 KB
RevLine 
[a932c9e]1import React, {useEffect, useState} from 'react';
2import {
3 Dialog, DialogTitle, DialogContent, DialogActions, Button,
4 Typography, Box, Grid, Chip, CircularProgress, IconButton,
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)) {
35 if (val.length > 0 && typeof val[0] === 'object') {
36 return val.map((v: any) => v.formFactor || v.socket || JSON.stringify(v)).join(', ');
37 }
38 return val.join(', ');
39 }
40
41 const strVal = String(val);
42 const lowerKey = key.toLowerCase();
43
44 // Dodava merni edinici vo zavisnost koja komponenta e
45 if (lowerKey.includes('capacity') || lowerKey.includes('vram') || lowerKey === 'memory') {
46 return `${strVal} GB`;
47 }
48
49 if (lowerKey.includes('tdp') || lowerKey.includes('wattage')) {
50 return `${strVal} W`;
51 }
52
53 if (lowerKey.includes('length') || lowerKey.includes('height') || lowerKey.includes('width')) {
54 return `${strVal} mm`;
55 }
56
57 if (lowerKey.includes('clock')) {
58 return `${strVal} GHz`;
59 }
60 if (lowerKey.includes('speed')) {
61 return `${strVal} MHz`;
62 }
63
64 return strVal;
65 };
66
67 const formatKey = (key: string) => {
68 return key
69 .replace(/([A-Z])/g, ' $1')
70 .replace(/_/g, ' ')
71 .replace(/\b\w/g, c => c.toUpperCase());
72 };
73
74 return (
75 <Dialog
76 open={open}
77 onClose={onClose}
78 maxWidth="lg"
79 // fullWidth
80 sx={{zIndex: 1400}}
81 >
82 <DialogTitle sx={{
83 display: 'flex',
84 justifyContent: 'space-between',
85 alignItems: 'center',
86 bgcolor: '#333',
87 color: 'white'
88 }}>
89 <Box>
90 <Typography variant="caption" sx={{textTransform: 'uppercase', opacity: 0.7}}>
91 {displayData.brand}
92 </Typography>
93 <Typography variant="h6" fontWeight="bold">
94 {displayData.name}
95 </Typography>
96 </Box>
97 <IconButton onClick={onClose} sx={{color: 'white'}}>
98 <CloseIcon/>
99 </IconButton>
100 </DialogTitle>
101
102 <DialogContent dividers>
103 {loading ? (
104 <Box sx={{display: 'flex', justifyContent: 'center', p: 5}}>
105 <CircularProgress/>
106 </Box>
107 ) : (
108 <Grid container spacing={4}>
109 <Grid item xs={12} md={4} sx={{display: 'flex', flexDirection: 'column', alignItems: 'center'}}>
110 <Box
111 component="img"
[6ce6739]112 // src={`https://placehold.co/400x400?text=${encodeURIComponent(displayData.name)}`}
113 src={displayData.imgUrl}
[a932c9e]114 alt={displayData.name}
115 sx={{
116 width: '100%',
117 maxHeight: 300,
118 objectFit: 'contain',
119 mb: 2,
[6ce6739]120 // border: '1px solid #eee',
121 // borderRadius: 2,
[a932c9e]122 p: 2
123 }}
124 />
125 <Chip
126 label={displayData.type?.toUpperCase()}
127 color="primary"
128 sx={{fontWeight: 'bold'}}
129 />
130 </Grid>
131
132 <Grid item xs={12} md={8}>
133 <Typography variant="subtitle1" fontWeight="bold" gutterBottom
134 sx={{borderBottom: '2px solid #ff8201', display: 'inline-block', mb: 0.5}}>
135 Technical Specifications
136 </Typography>
137
138 <TableContainer component={Paper} variant="outlined">
139 <Table size="small">
140 <TableBody>
141 <TableRow>
142 <TableCell component="th" scope="row"
143 sx={{fontWeight: 'bold', width: '30%', bgcolor: '#1e1e1e'}}>
144 Brand
145 </TableCell>
146 <TableCell>{displayData.brand}</TableCell>
147 </TableRow>
148
149 {Object.entries(specs).map(([key, val]) => {
150 if (key === 'componentId' || key === 'id') return null;
151
152 return (
153 <TableRow key={key}>
154 <TableCell component="th" scope="row" sx={{
155 fontWeight: 'bold',
156 width: '30%',
157 bgcolor: '#1e1e1e'
158 }}>
159 {formatKey(key)}
160 </TableCell>
161 <TableCell>{renderValue(key, val)}</TableCell>
162 </TableRow>
163 );
164 })}
165 </TableBody>
166 </Table>
167 </TableContainer>
168 <Box sx={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', mt: 0.5}}>
169 <Typography variant="h4" color="primary.main" fontWeight="bold">
170 {formatMoney(displayData.price)}
171 </Typography>
172 </Box>
173 </Grid>
174 </Grid>
175 )}
176 </DialogContent>
177
178 <DialogActions sx={{p: 2}}>
179 <Button onClick={onClose} variant="contained"
180 sx={{
181 backgroundColor: '#ff8201',
182 color: 'white',
183 borderColor: '#ff8201',
184 onHover: {backgroundColor: '#ba5d02', borderColor: '#ba5d02'}
185 }}
186 >Close</Button>
187 </DialogActions>
188 </Dialog>
189 );
190}
Note: See TracBrowser for help on using the repository browser.