Skip to content

Commit 32e7606

Browse files
authored
Merge pull request #702 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents 046c4d5 + e4048ba commit 32e7606

File tree

2 files changed

+321
-54
lines changed

2 files changed

+321
-54
lines changed

src/components/CippComponents/CippAddTestReportDrawer.jsx

Lines changed: 251 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
11
import React, { useState, useEffect } from "react";
2-
import { Button } from "@mui/material";
2+
import {
3+
Button,
4+
Card,
5+
CardContent,
6+
TextField,
7+
Typography,
8+
Box,
9+
Chip,
10+
Tab,
11+
Tabs,
12+
Paper,
13+
Stack,
14+
} from "@mui/material";
315
import { Grid } from "@mui/system";
4-
import { useForm, useFormState } from "react-hook-form";
16+
import { useForm, useFormState, useWatch } from "react-hook-form";
517
import { Add } from "@mui/icons-material";
618
import { CippOffCanvas } from "./CippOffCanvas";
719
import CippFormComponent from "./CippFormComponent";
@@ -10,6 +22,8 @@ import { ApiPostCall, ApiGetCall } from "../../api/ApiCall";
1022

1123
export const CippAddTestReportDrawer = ({ buttonText = "Create custom report" }) => {
1224
const [drawerVisible, setDrawerVisible] = useState(false);
25+
const [activeTab, setActiveTab] = useState(0);
26+
const [searchTerm, setSearchTerm] = useState("");
1327

1428
const formControl = useForm({
1529
mode: "onChange",
@@ -22,6 +36,10 @@ export const CippAddTestReportDrawer = ({ buttonText = "Create custom report" })
2236
});
2337

2438
const { isValid } = useFormState({ control: formControl.control });
39+
const selectedIdentityTests =
40+
useWatch({ control: formControl.control, name: "IdentityTests" }) || [];
41+
const selectedDeviceTests =
42+
useWatch({ control: formControl.control, name: "DevicesTests" }) || [];
2543

2644
const createReport = ApiPostCall({
2745
urlFromData: true,
@@ -69,6 +87,8 @@ export const CippAddTestReportDrawer = ({ buttonText = "Create custom report" })
6987

7088
const handleCloseDrawer = () => {
7189
setDrawerVisible(false);
90+
setSearchTerm("");
91+
setActiveTab(0);
7292
formControl.reset({
7393
name: "",
7494
description: "",
@@ -77,6 +97,43 @@ export const CippAddTestReportDrawer = ({ buttonText = "Create custom report" })
7797
});
7898
};
7999

100+
const toggleTest = (testId, testType) => {
101+
const fieldName = testType === "Identity" ? "IdentityTests" : "DevicesTests";
102+
const currentTests = formControl.getValues(fieldName) || [];
103+
104+
if (currentTests.includes(testId)) {
105+
formControl.setValue(
106+
fieldName,
107+
currentTests.filter((id) => id !== testId),
108+
{ shouldValidate: true }
109+
);
110+
} else {
111+
formControl.setValue(fieldName, [...currentTests, testId], { shouldValidate: true });
112+
}
113+
};
114+
115+
const isTestSelected = (testId, testType) => {
116+
return testType === "Identity"
117+
? selectedIdentityTests.includes(testId)
118+
: selectedDeviceTests.includes(testId);
119+
};
120+
121+
const filterTests = (tests) => {
122+
if (!searchTerm) return tests;
123+
return tests.filter(
124+
(test) =>
125+
test.id.toLowerCase().includes(searchTerm.toLowerCase()) ||
126+
test.name.toLowerCase().includes(searchTerm.toLowerCase())
127+
);
128+
};
129+
130+
const currentTests =
131+
activeTab === 0
132+
? filterTests(availableTests.IdentityTests || [])
133+
: filterTests(availableTests.DevicesTests || []);
134+
135+
const currentTestType = activeTab === 0 ? "Identity" : "Devices";
136+
80137
return (
81138
<>
82139
<Button
@@ -116,53 +173,203 @@ export const CippAddTestReportDrawer = ({ buttonText = "Create custom report" })
116173
</div>
117174
}
118175
>
119-
<Grid container spacing={2}>
120-
<Grid size={12}>
121-
<CippFormComponent
122-
type="textField"
123-
label="Report Name"
124-
name="name"
125-
formControl={formControl}
126-
validators={{ required: "Report Name is required" }}
127-
/>
128-
</Grid>
176+
<Grid container spacing={3}>
177+
{/* Report Details Section */}
129178
<Grid size={12}>
130-
<CippFormComponent
131-
type="textField"
132-
label="Description"
133-
name="description"
134-
formControl={formControl}
135-
multiline
136-
rows={3}
137-
/>
179+
<Paper sx={{ p: 3, backgroundColor: "background.default" }}>
180+
<Typography variant="h6" gutterBottom>
181+
Report Details
182+
</Typography>
183+
<Grid container spacing={2}>
184+
<Grid size={12}>
185+
<CippFormComponent
186+
type="textField"
187+
label="Report Name"
188+
name="name"
189+
formControl={formControl}
190+
validators={{ required: "Report Name is required" }}
191+
/>
192+
</Grid>
193+
<Grid size={12}>
194+
<CippFormComponent
195+
type="textField"
196+
label="Description"
197+
name="description"
198+
formControl={formControl}
199+
multiline
200+
rows={3}
201+
/>
202+
</Grid>
203+
</Grid>
204+
</Paper>
138205
</Grid>
206+
207+
{/* Selection Summary */}
139208
<Grid size={12}>
140-
<CippFormComponent
141-
type="autoComplete"
142-
label="Identity Tests"
143-
name="IdentityTests"
144-
formControl={formControl}
145-
multiple
146-
options={availableTests.IdentityTests?.map((test) => ({
147-
value: test.id,
148-
label: `${test.id} - ${test.name}`,
149-
}))}
150-
isFetching={availableTestsApi.isFetching}
151-
/>
209+
<Paper sx={{ p: 2, backgroundColor: "primary.50" }}>
210+
<Stack direction="row" spacing={2} alignItems="center">
211+
<Typography variant="subtitle2" color="primary">
212+
Selected Tests:
213+
</Typography>
214+
<Chip
215+
label={`${selectedIdentityTests.length} Identity`}
216+
color="primary"
217+
size="small"
218+
variant="outlined"
219+
/>
220+
<Chip
221+
label={`${selectedDeviceTests.length} Device`}
222+
color="secondary"
223+
size="small"
224+
variant="outlined"
225+
/>
226+
<Box sx={{ flex: 1 }} />
227+
<Typography variant="caption" color="text.secondary">
228+
Total: {selectedIdentityTests.length + selectedDeviceTests.length} tests
229+
</Typography>
230+
</Stack>
231+
</Paper>
152232
</Grid>
233+
234+
{/* Test Selection Section */}
153235
<Grid size={12}>
154-
<CippFormComponent
155-
type="autoComplete"
156-
label="Device Tests"
157-
name="DevicesTests"
158-
formControl={formControl}
159-
multiple
160-
options={availableTests.DevicesTests?.map((test) => ({
161-
value: test.id,
162-
label: `${test.id} - ${test.name}`,
163-
}))}
164-
isFetching={availableTestsApi.isFetching}
165-
/>
236+
<Paper sx={{ p: 0 }}>
237+
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
238+
<Tabs
239+
value={activeTab}
240+
onChange={(e, newValue) => {
241+
setActiveTab(newValue);
242+
setSearchTerm("");
243+
}}
244+
variant="fullWidth"
245+
>
246+
<Tab
247+
label={
248+
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
249+
<span>Identity Tests</span>
250+
{selectedIdentityTests.length > 0 && (
251+
<Chip size="small" label={selectedIdentityTests.length} color="primary" />
252+
)}
253+
</Box>
254+
}
255+
/>
256+
<Tab
257+
label={
258+
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
259+
<span>Device Tests</span>
260+
{selectedDeviceTests.length > 0 && (
261+
<Chip size="small" label={selectedDeviceTests.length} color="secondary" />
262+
)}
263+
</Box>
264+
}
265+
/>
266+
</Tabs>
267+
</Box>
268+
269+
{/* Search Bar */}
270+
<Box sx={{ p: 2, borderBottom: 1, borderColor: "divider" }}>
271+
<TextField
272+
fullWidth
273+
size="small"
274+
placeholder={`Search ${currentTestType} tests...`}
275+
value={searchTerm}
276+
onChange={(e) => setSearchTerm(e.target.value)}
277+
/>
278+
</Box>
279+
280+
{/* Test List */}
281+
<Box
282+
sx={{
283+
maxHeight: "400px",
284+
overflowY: "auto",
285+
p: 2,
286+
}}
287+
>
288+
{availableTestsApi.isFetching ? (
289+
<Box sx={{ textAlign: "center", py: 4 }}>
290+
<Typography color="text.secondary">Loading tests...</Typography>
291+
</Box>
292+
) : currentTests.length === 0 ? (
293+
<Box sx={{ textAlign: "center", py: 4 }}>
294+
<Typography color="text.secondary">
295+
{searchTerm ? "No tests found matching your search" : "No tests available"}
296+
</Typography>
297+
</Box>
298+
) : (
299+
<Grid container spacing={1}>
300+
{currentTests.map((test) => {
301+
const isSelected = isTestSelected(test.id, currentTestType);
302+
return (
303+
<Grid size={12} key={test.id}>
304+
<Card
305+
sx={{
306+
cursor: "pointer",
307+
transition: "all 0.2s",
308+
border: 1,
309+
borderColor: isSelected ? "primary.main" : "divider",
310+
backgroundColor: isSelected ? "primary.50" : "background.paper",
311+
"&:hover": {
312+
borderColor: "primary.main",
313+
boxShadow: 2,
314+
},
315+
}}
316+
onClick={() => toggleTest(test.id, currentTestType)}
317+
>
318+
<CardContent sx={{ p: 2, "&:last-child": { pb: 2 } }}>
319+
<Box sx={{ display: "flex", alignItems: "center", gap: 1.5 }}>
320+
<Box sx={{ flex: 1, minWidth: 0 }}>
321+
<Box
322+
sx={{
323+
display: "flex",
324+
alignItems: "center",
325+
gap: 1,
326+
mb: 0.5,
327+
}}
328+
>
329+
<Chip
330+
label={test.id}
331+
size="small"
332+
color={isSelected ? "primary" : "default"}
333+
sx={{ fontFamily: "monospace", fontSize: "0.75rem" }}
334+
/>
335+
<Typography
336+
variant="body2"
337+
sx={{
338+
fontWeight: isSelected ? 600 : 400,
339+
color: isSelected ? "primary.main" : "text.primary",
340+
overflow: "hidden",
341+
textOverflow: "ellipsis",
342+
whiteSpace: "nowrap",
343+
}}
344+
>
345+
{test.name}
346+
</Typography>
347+
</Box>
348+
{test.description && (
349+
<Typography
350+
variant="caption"
351+
color="text.secondary"
352+
sx={{
353+
display: "-webkit-box",
354+
WebkitLineClamp: 2,
355+
WebkitBoxOrient: "vertical",
356+
overflow: "hidden",
357+
}}
358+
>
359+
{test.description}
360+
</Typography>
361+
)}
362+
</Box>
363+
</Box>
364+
</CardContent>
365+
</Card>
366+
</Grid>
367+
);
368+
})}
369+
</Grid>
370+
)}
371+
</Box>
372+
</Paper>
166373
</Grid>
167374
</Grid>
168375
</CippOffCanvas>

0 commit comments

Comments
 (0)