@pablo2410/shared-ui 0.23.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/reporting/index.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
+
Alert,
|
|
3
|
+
AlertDescription,
|
|
4
|
+
AlertTitle,
|
|
2
5
|
Badge,
|
|
6
|
+
Checkbox,
|
|
3
7
|
DropdownMenu,
|
|
4
8
|
DropdownMenuContent,
|
|
5
9
|
DropdownMenuItem,
|
|
@@ -41,7 +45,8 @@ import {
|
|
|
41
45
|
Send,
|
|
42
46
|
ImagePlus,
|
|
43
47
|
X,
|
|
44
|
-
UserCog
|
|
48
|
+
UserCog,
|
|
49
|
+
BookMarked
|
|
45
50
|
} from "lucide-react";
|
|
46
51
|
import { toast } from "sonner";
|
|
47
52
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -84,6 +89,12 @@ var ALL_FEEDBACK_OPTIONS = [
|
|
|
84
89
|
color: "#8C34E9"
|
|
85
90
|
}
|
|
86
91
|
];
|
|
92
|
+
var EMPTY_DRAFT = {
|
|
93
|
+
description: "",
|
|
94
|
+
location: "",
|
|
95
|
+
severity: "medium",
|
|
96
|
+
immediateAction: ""
|
|
97
|
+
};
|
|
87
98
|
function ReportingToolbar({
|
|
88
99
|
moduleName = "Oplytics",
|
|
89
100
|
showIncidentReporting = true,
|
|
@@ -97,7 +108,7 @@ function ReportingToolbar({
|
|
|
97
108
|
services = OPLYTICS_SERVICES,
|
|
98
109
|
defaultServiceSlug,
|
|
99
110
|
enableScreenshot = true,
|
|
100
|
-
reportsComingSoon =
|
|
111
|
+
reportsComingSoon = false,
|
|
101
112
|
className
|
|
102
113
|
}) {
|
|
103
114
|
const reportOptions = ALL_REPORT_OPTIONS.filter(
|
|
@@ -127,6 +138,119 @@ function ReportingToolbar({
|
|
|
127
138
|
setScreenshotName(null);
|
|
128
139
|
setFeedbackOpen(true);
|
|
129
140
|
};
|
|
141
|
+
const [reportOpen, setReportOpen] = useState(false);
|
|
142
|
+
const [reportCategory, setReportCategory] = useState("safety");
|
|
143
|
+
const [reportDraft, setReportDraft] = useState(EMPTY_DRAFT);
|
|
144
|
+
const [reportSubmitting, setReportSubmitting] = useState(false);
|
|
145
|
+
const [injuryOccurred, setInjuryOccurred] = useState(false);
|
|
146
|
+
const [injuryClassification, setInjuryClassification] = useState(void 0);
|
|
147
|
+
const [daysAwayFromWork, setDaysAwayFromWork] = useState("");
|
|
148
|
+
const [daysRestrictedOrTransferred, setDaysRestrictedOrTransferred] = useState("");
|
|
149
|
+
const [firstAiderAttended, setFirstAiderAttended] = useState(false);
|
|
150
|
+
const [witnessName, setWitnessName] = useState("");
|
|
151
|
+
const [bodyPart, setBodyPart] = useState("");
|
|
152
|
+
const [treatmentType, setTreatmentType] = useState("");
|
|
153
|
+
const [environmentalAspect, setEnvironmentalAspect] = useState(void 0);
|
|
154
|
+
const [regulatoryReportable, setRegulatoryReportable] = useState(false);
|
|
155
|
+
const [substance, setSubstance] = useState("");
|
|
156
|
+
const [estimatedQuantity, setEstimatedQuantity] = useState("");
|
|
157
|
+
const [contained, setContained] = useState(false);
|
|
158
|
+
const [reachedWatercourse, setReachedWatercourse] = useState(false);
|
|
159
|
+
const [hazardCategory, setHazardCategory] = useState(void 0);
|
|
160
|
+
const [hazardDescription, setHazardDescription] = useState("");
|
|
161
|
+
const [areaMadeSafe, setAreaMadeSafe] = useState(false);
|
|
162
|
+
const [workResumed, setWorkResumed] = useState(false);
|
|
163
|
+
const openReport = (c) => {
|
|
164
|
+
setReportCategory(c);
|
|
165
|
+
setReportDraft({
|
|
166
|
+
...EMPTY_DRAFT,
|
|
167
|
+
severity: c === "stop-work" ? "critical" : "medium"
|
|
168
|
+
});
|
|
169
|
+
setInjuryOccurred(false);
|
|
170
|
+
setInjuryClassification(void 0);
|
|
171
|
+
setDaysAwayFromWork("");
|
|
172
|
+
setDaysRestrictedOrTransferred("");
|
|
173
|
+
setFirstAiderAttended(false);
|
|
174
|
+
setWitnessName("");
|
|
175
|
+
setBodyPart("");
|
|
176
|
+
setTreatmentType("");
|
|
177
|
+
setEnvironmentalAspect(void 0);
|
|
178
|
+
setRegulatoryReportable(false);
|
|
179
|
+
setSubstance("");
|
|
180
|
+
setEstimatedQuantity("");
|
|
181
|
+
setContained(false);
|
|
182
|
+
setReachedWatercourse(false);
|
|
183
|
+
setHazardCategory(void 0);
|
|
184
|
+
setHazardDescription("");
|
|
185
|
+
setAreaMadeSafe(false);
|
|
186
|
+
setWorkResumed(false);
|
|
187
|
+
setReportOpen(true);
|
|
188
|
+
};
|
|
189
|
+
const submitReport = async () => {
|
|
190
|
+
if (!reportDraft.description.trim()) {
|
|
191
|
+
toast.error("Please describe what happened.");
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
setReportSubmitting(true);
|
|
195
|
+
try {
|
|
196
|
+
const base = {
|
|
197
|
+
description: reportDraft.description.trim(),
|
|
198
|
+
location: reportDraft.location.trim() || void 0,
|
|
199
|
+
severity: reportDraft.severity,
|
|
200
|
+
immediateAction: reportDraft.immediateAction.trim() || void 0,
|
|
201
|
+
moduleName,
|
|
202
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
203
|
+
submittedBy: currentUser,
|
|
204
|
+
hierarchyContext
|
|
205
|
+
};
|
|
206
|
+
let report;
|
|
207
|
+
if (reportCategory === "safety") {
|
|
208
|
+
const safety = {
|
|
209
|
+
...base,
|
|
210
|
+
category: "safety",
|
|
211
|
+
injuryOccurred,
|
|
212
|
+
injuryClassification,
|
|
213
|
+
daysAwayFromWork: daysAwayFromWork ? Number(daysAwayFromWork) : void 0,
|
|
214
|
+
daysRestrictedOrTransferred: daysRestrictedOrTransferred ? Number(daysRestrictedOrTransferred) : void 0,
|
|
215
|
+
firstAiderAttended,
|
|
216
|
+
witnessName: witnessName.trim() || void 0,
|
|
217
|
+
bodyPart: bodyPart.trim() || void 0,
|
|
218
|
+
treatmentType: treatmentType.trim() || void 0
|
|
219
|
+
};
|
|
220
|
+
report = safety;
|
|
221
|
+
} else if (reportCategory === "environmental") {
|
|
222
|
+
const environmental = {
|
|
223
|
+
...base,
|
|
224
|
+
category: "environmental",
|
|
225
|
+
environmentalAspect,
|
|
226
|
+
regulatoryReportable,
|
|
227
|
+
substance: substance.trim() || void 0,
|
|
228
|
+
estimatedQuantity: estimatedQuantity.trim() || void 0,
|
|
229
|
+
contained,
|
|
230
|
+
reachedWatercourse
|
|
231
|
+
};
|
|
232
|
+
report = environmental;
|
|
233
|
+
} else {
|
|
234
|
+
const stopWork = {
|
|
235
|
+
...base,
|
|
236
|
+
category: "stop-work",
|
|
237
|
+
hazardCategory,
|
|
238
|
+
hazardDescription: hazardDescription.trim() || void 0,
|
|
239
|
+
areaMadeSafe,
|
|
240
|
+
workResumed
|
|
241
|
+
};
|
|
242
|
+
report = stopWork;
|
|
243
|
+
}
|
|
244
|
+
await onReportSubmit(report);
|
|
245
|
+
toast.success("Report logged. Thanks for raising it.");
|
|
246
|
+
setReportOpen(false);
|
|
247
|
+
} catch (err) {
|
|
248
|
+
console.error("[ReportingToolbar] report submit failed:", err);
|
|
249
|
+
toast.error("Couldn't submit that. Please try again.");
|
|
250
|
+
} finally {
|
|
251
|
+
setReportSubmitting(false);
|
|
252
|
+
}
|
|
253
|
+
};
|
|
130
254
|
const handlePickFile = async (e) => {
|
|
131
255
|
const file = e.target.files?.[0];
|
|
132
256
|
e.target.value = "";
|
|
@@ -179,7 +303,6 @@ function ReportingToolbar({
|
|
|
179
303
|
const showReportGroup = showIncidentReporting && reportOptions.length > 0;
|
|
180
304
|
const showFeedbackGroup = showFeedback && feedbackOptions.length > 0;
|
|
181
305
|
if (!showReportGroup && !showFeedbackGroup) return null;
|
|
182
|
-
void hierarchyContext;
|
|
183
306
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
184
307
|
/* @__PURE__ */ jsx("div", { className: cn("flex items-center gap-2", className), children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
185
308
|
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
@@ -213,9 +336,7 @@ function ReportingToolbar({
|
|
|
213
336
|
{
|
|
214
337
|
disabled: reportsComingSoon,
|
|
215
338
|
onClick: () => {
|
|
216
|
-
if (!reportsComingSoon)
|
|
217
|
-
void onReportSubmit;
|
|
218
|
-
}
|
|
339
|
+
if (!reportsComingSoon) openReport(opt.category);
|
|
219
340
|
},
|
|
220
341
|
className: "gap-3 py-2.5",
|
|
221
342
|
children: [
|
|
@@ -228,7 +349,7 @@ function ReportingToolbar({
|
|
|
228
349
|
),
|
|
229
350
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
230
351
|
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: opt.label }),
|
|
231
|
-
/* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground", children: opt.
|
|
352
|
+
/* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground", children: REPORT_STANDARD_REFERENCES[opt.category].label })
|
|
232
353
|
] })
|
|
233
354
|
]
|
|
234
355
|
},
|
|
@@ -376,6 +497,375 @@ function ReportingToolbar({
|
|
|
376
497
|
}
|
|
377
498
|
)
|
|
378
499
|
] })
|
|
500
|
+
] }) }),
|
|
501
|
+
/* @__PURE__ */ jsx(Dialog, { open: reportOpen, onOpenChange: setReportOpen, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-[560px] max-h-[90vh] overflow-y-auto", children: [
|
|
502
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
503
|
+
/* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-2", children: [
|
|
504
|
+
reportCategory === "safety" && /* @__PURE__ */ jsx(ShieldAlert, { className: "h-5 w-5 text-[#EF4444]" }),
|
|
505
|
+
reportCategory === "environmental" && /* @__PURE__ */ jsx(Leaf, { className: "h-5 w-5 text-[#22C55E]" }),
|
|
506
|
+
reportCategory === "stop-work" && /* @__PURE__ */ jsx(OctagonX, { className: "h-5 w-5 text-[#F59E0B]" }),
|
|
507
|
+
ALL_REPORT_OPTIONS.find((o) => o.category === reportCategory)?.label ?? "Report"
|
|
508
|
+
] }),
|
|
509
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: ALL_REPORT_OPTIONS.find((o) => o.category === reportCategory)?.description })
|
|
510
|
+
] }),
|
|
511
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-4 py-2", children: [
|
|
512
|
+
/* @__PURE__ */ jsxs(Alert, { className: "border-[#8C34E9]/30 bg-[#8C34E9]/5", children: [
|
|
513
|
+
/* @__PURE__ */ jsx(BookMarked, { className: "h-4 w-4 text-[#8C34E9]" }),
|
|
514
|
+
/* @__PURE__ */ jsx(AlertTitle, { className: "text-xs font-semibold text-[#C084FC]", children: REPORT_STANDARD_REFERENCES[reportCategory].label }),
|
|
515
|
+
/* @__PURE__ */ jsx(AlertDescription, { className: "text-[11px]", children: REPORT_STANDARD_REFERENCES[reportCategory].description })
|
|
516
|
+
] }),
|
|
517
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
518
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Severity" }),
|
|
519
|
+
/* @__PURE__ */ jsxs(
|
|
520
|
+
Select,
|
|
521
|
+
{
|
|
522
|
+
value: reportDraft.severity,
|
|
523
|
+
onValueChange: (v) => setReportDraft((d) => ({ ...d, severity: v })),
|
|
524
|
+
children: [
|
|
525
|
+
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-9", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
526
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
527
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "low", children: "Low" }),
|
|
528
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "medium", children: "Medium" }),
|
|
529
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "high", children: "High" }),
|
|
530
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "critical", children: "Critical" })
|
|
531
|
+
] })
|
|
532
|
+
]
|
|
533
|
+
}
|
|
534
|
+
)
|
|
535
|
+
] }),
|
|
536
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
537
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Location (optional)" }),
|
|
538
|
+
/* @__PURE__ */ jsx(
|
|
539
|
+
Input,
|
|
540
|
+
{
|
|
541
|
+
value: reportDraft.location,
|
|
542
|
+
onChange: (e) => setReportDraft((d) => ({ ...d, location: e.target.value })),
|
|
543
|
+
placeholder: "Where did this happen?",
|
|
544
|
+
className: "h-9"
|
|
545
|
+
}
|
|
546
|
+
)
|
|
547
|
+
] }),
|
|
548
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
549
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "What happened? *" }),
|
|
550
|
+
/* @__PURE__ */ jsx(
|
|
551
|
+
Textarea,
|
|
552
|
+
{
|
|
553
|
+
value: reportDraft.description,
|
|
554
|
+
onChange: (e) => setReportDraft((d) => ({
|
|
555
|
+
...d,
|
|
556
|
+
description: e.target.value
|
|
557
|
+
})),
|
|
558
|
+
placeholder: "Describe what happened\u2026",
|
|
559
|
+
rows: 4
|
|
560
|
+
}
|
|
561
|
+
)
|
|
562
|
+
] }),
|
|
563
|
+
reportCategory === "safety" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
564
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between rounded-md border border-[#1E2738] px-3 py-2", children: [
|
|
565
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "Was anyone injured?" }),
|
|
566
|
+
/* @__PURE__ */ jsx(
|
|
567
|
+
Switch,
|
|
568
|
+
{
|
|
569
|
+
checked: injuryOccurred,
|
|
570
|
+
onCheckedChange: setInjuryOccurred
|
|
571
|
+
}
|
|
572
|
+
)
|
|
573
|
+
] }),
|
|
574
|
+
injuryOccurred && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
575
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
576
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Injury classification (OSHA 1904)" }),
|
|
577
|
+
/* @__PURE__ */ jsxs(
|
|
578
|
+
Select,
|
|
579
|
+
{
|
|
580
|
+
value: injuryClassification,
|
|
581
|
+
onValueChange: (v) => setInjuryClassification(v),
|
|
582
|
+
children: [
|
|
583
|
+
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-9", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select a classification" }) }),
|
|
584
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
585
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "first_aid_only", children: "First aid only" }),
|
|
586
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "recordable", children: "Recordable" }),
|
|
587
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "days_away_restricted_transfer", children: "Days away, restricted, or transferred (DART)" }),
|
|
588
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "fatality", children: "Fatality" })
|
|
589
|
+
] })
|
|
590
|
+
]
|
|
591
|
+
}
|
|
592
|
+
)
|
|
593
|
+
] }),
|
|
594
|
+
injuryClassification === "days_away_restricted_transfer" && /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
595
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
596
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Days away from work" }),
|
|
597
|
+
/* @__PURE__ */ jsx(
|
|
598
|
+
Input,
|
|
599
|
+
{
|
|
600
|
+
type: "number",
|
|
601
|
+
min: 0,
|
|
602
|
+
value: daysAwayFromWork,
|
|
603
|
+
onChange: (e) => setDaysAwayFromWork(e.target.value),
|
|
604
|
+
className: "h-9"
|
|
605
|
+
}
|
|
606
|
+
)
|
|
607
|
+
] }),
|
|
608
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
609
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Days restricted/transferred" }),
|
|
610
|
+
/* @__PURE__ */ jsx(
|
|
611
|
+
Input,
|
|
612
|
+
{
|
|
613
|
+
type: "number",
|
|
614
|
+
min: 0,
|
|
615
|
+
value: daysRestrictedOrTransferred,
|
|
616
|
+
onChange: (e) => setDaysRestrictedOrTransferred(e.target.value),
|
|
617
|
+
className: "h-9"
|
|
618
|
+
}
|
|
619
|
+
)
|
|
620
|
+
] })
|
|
621
|
+
] }),
|
|
622
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
623
|
+
/* @__PURE__ */ jsx(
|
|
624
|
+
Checkbox,
|
|
625
|
+
{
|
|
626
|
+
id: "firstAiderAttended",
|
|
627
|
+
checked: firstAiderAttended,
|
|
628
|
+
onCheckedChange: (c) => setFirstAiderAttended(!!c)
|
|
629
|
+
}
|
|
630
|
+
),
|
|
631
|
+
/* @__PURE__ */ jsx(
|
|
632
|
+
Label,
|
|
633
|
+
{
|
|
634
|
+
htmlFor: "firstAiderAttended",
|
|
635
|
+
className: "text-xs font-normal",
|
|
636
|
+
children: "A first aider attended"
|
|
637
|
+
}
|
|
638
|
+
)
|
|
639
|
+
] }),
|
|
640
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
641
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
642
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Body part affected" }),
|
|
643
|
+
/* @__PURE__ */ jsx(
|
|
644
|
+
Input,
|
|
645
|
+
{
|
|
646
|
+
value: bodyPart,
|
|
647
|
+
onChange: (e) => setBodyPart(e.target.value),
|
|
648
|
+
className: "h-9"
|
|
649
|
+
}
|
|
650
|
+
)
|
|
651
|
+
] }),
|
|
652
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
653
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Treatment given" }),
|
|
654
|
+
/* @__PURE__ */ jsx(
|
|
655
|
+
Input,
|
|
656
|
+
{
|
|
657
|
+
value: treatmentType,
|
|
658
|
+
onChange: (e) => setTreatmentType(e.target.value),
|
|
659
|
+
className: "h-9"
|
|
660
|
+
}
|
|
661
|
+
)
|
|
662
|
+
] })
|
|
663
|
+
] }),
|
|
664
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
665
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Witness name (optional)" }),
|
|
666
|
+
/* @__PURE__ */ jsx(
|
|
667
|
+
Input,
|
|
668
|
+
{
|
|
669
|
+
value: witnessName,
|
|
670
|
+
onChange: (e) => setWitnessName(e.target.value),
|
|
671
|
+
className: "h-9"
|
|
672
|
+
}
|
|
673
|
+
)
|
|
674
|
+
] })
|
|
675
|
+
] })
|
|
676
|
+
] }),
|
|
677
|
+
reportCategory === "environmental" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
678
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
679
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Environmental aspect (ISO 14001)" }),
|
|
680
|
+
/* @__PURE__ */ jsxs(
|
|
681
|
+
Select,
|
|
682
|
+
{
|
|
683
|
+
value: environmentalAspect,
|
|
684
|
+
onValueChange: (v) => setEnvironmentalAspect(v),
|
|
685
|
+
children: [
|
|
686
|
+
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-9", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "What element of the environment is affected?" }) }),
|
|
687
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
688
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "air_emission", children: "Air emission" }),
|
|
689
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "water_discharge", children: "Water discharge" }),
|
|
690
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "soil_contamination", children: "Soil contamination" }),
|
|
691
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "waste", children: "Waste" }),
|
|
692
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "spill", children: "Spill" }),
|
|
693
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "noise", children: "Noise" }),
|
|
694
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "other", children: "Other" })
|
|
695
|
+
] })
|
|
696
|
+
]
|
|
697
|
+
}
|
|
698
|
+
)
|
|
699
|
+
] }),
|
|
700
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
701
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
702
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Substance (optional)" }),
|
|
703
|
+
/* @__PURE__ */ jsx(
|
|
704
|
+
Input,
|
|
705
|
+
{
|
|
706
|
+
value: substance,
|
|
707
|
+
onChange: (e) => setSubstance(e.target.value),
|
|
708
|
+
className: "h-9"
|
|
709
|
+
}
|
|
710
|
+
)
|
|
711
|
+
] }),
|
|
712
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
713
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Estimated quantity" }),
|
|
714
|
+
/* @__PURE__ */ jsx(
|
|
715
|
+
Input,
|
|
716
|
+
{
|
|
717
|
+
value: estimatedQuantity,
|
|
718
|
+
onChange: (e) => setEstimatedQuantity(e.target.value),
|
|
719
|
+
className: "h-9"
|
|
720
|
+
}
|
|
721
|
+
)
|
|
722
|
+
] })
|
|
723
|
+
] }),
|
|
724
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
725
|
+
/* @__PURE__ */ jsx(
|
|
726
|
+
Checkbox,
|
|
727
|
+
{
|
|
728
|
+
id: "contained",
|
|
729
|
+
checked: contained,
|
|
730
|
+
onCheckedChange: (c) => setContained(!!c)
|
|
731
|
+
}
|
|
732
|
+
),
|
|
733
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "contained", className: "text-xs font-normal", children: "Contained on site" })
|
|
734
|
+
] }),
|
|
735
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
736
|
+
/* @__PURE__ */ jsx(
|
|
737
|
+
Checkbox,
|
|
738
|
+
{
|
|
739
|
+
id: "reachedWatercourse",
|
|
740
|
+
checked: reachedWatercourse,
|
|
741
|
+
onCheckedChange: (c) => setReachedWatercourse(!!c)
|
|
742
|
+
}
|
|
743
|
+
),
|
|
744
|
+
/* @__PURE__ */ jsx(
|
|
745
|
+
Label,
|
|
746
|
+
{
|
|
747
|
+
htmlFor: "reachedWatercourse",
|
|
748
|
+
className: "text-xs font-normal",
|
|
749
|
+
children: "Reached a watercourse"
|
|
750
|
+
}
|
|
751
|
+
)
|
|
752
|
+
] }),
|
|
753
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
754
|
+
/* @__PURE__ */ jsx(
|
|
755
|
+
Checkbox,
|
|
756
|
+
{
|
|
757
|
+
id: "regulatoryReportable",
|
|
758
|
+
checked: regulatoryReportable,
|
|
759
|
+
onCheckedChange: (c) => setRegulatoryReportable(!!c)
|
|
760
|
+
}
|
|
761
|
+
),
|
|
762
|
+
/* @__PURE__ */ jsx(
|
|
763
|
+
Label,
|
|
764
|
+
{
|
|
765
|
+
htmlFor: "regulatoryReportable",
|
|
766
|
+
className: "text-xs font-normal",
|
|
767
|
+
children: "This may need reporting to a regulator"
|
|
768
|
+
}
|
|
769
|
+
)
|
|
770
|
+
] })
|
|
771
|
+
] }),
|
|
772
|
+
reportCategory === "stop-work" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
773
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
774
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Hazard category (ISO 45001)" }),
|
|
775
|
+
/* @__PURE__ */ jsxs(
|
|
776
|
+
Select,
|
|
777
|
+
{
|
|
778
|
+
value: hazardCategory,
|
|
779
|
+
onValueChange: (v) => setHazardCategory(v),
|
|
780
|
+
children: [
|
|
781
|
+
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-9", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "What kind of hazard?" }) }),
|
|
782
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
783
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "mechanical", children: "Mechanical" }),
|
|
784
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "electrical", children: "Electrical" }),
|
|
785
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "chemical", children: "Chemical" }),
|
|
786
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "working_at_height", children: "Working at height" }),
|
|
787
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "confined_space", children: "Confined space" }),
|
|
788
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "vehicle_traffic", children: "Vehicle / traffic" }),
|
|
789
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "other", children: "Other" })
|
|
790
|
+
] })
|
|
791
|
+
]
|
|
792
|
+
}
|
|
793
|
+
)
|
|
794
|
+
] }),
|
|
795
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
796
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Hazard description" }),
|
|
797
|
+
/* @__PURE__ */ jsx(
|
|
798
|
+
Textarea,
|
|
799
|
+
{
|
|
800
|
+
value: hazardDescription,
|
|
801
|
+
onChange: (e) => setHazardDescription(e.target.value),
|
|
802
|
+
rows: 3
|
|
803
|
+
}
|
|
804
|
+
)
|
|
805
|
+
] }),
|
|
806
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
807
|
+
/* @__PURE__ */ jsx(
|
|
808
|
+
Checkbox,
|
|
809
|
+
{
|
|
810
|
+
id: "areaMadeSafe",
|
|
811
|
+
checked: areaMadeSafe,
|
|
812
|
+
onCheckedChange: (c) => setAreaMadeSafe(!!c)
|
|
813
|
+
}
|
|
814
|
+
),
|
|
815
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "areaMadeSafe", className: "text-xs font-normal", children: "Area has been made safe" })
|
|
816
|
+
] }),
|
|
817
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
818
|
+
/* @__PURE__ */ jsx(
|
|
819
|
+
Checkbox,
|
|
820
|
+
{
|
|
821
|
+
id: "workResumed",
|
|
822
|
+
checked: workResumed,
|
|
823
|
+
onCheckedChange: (c) => setWorkResumed(!!c)
|
|
824
|
+
}
|
|
825
|
+
),
|
|
826
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "workResumed", className: "text-xs font-normal", children: "Work has resumed" })
|
|
827
|
+
] })
|
|
828
|
+
] }),
|
|
829
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
830
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Immediate action taken (optional)" }),
|
|
831
|
+
/* @__PURE__ */ jsx(
|
|
832
|
+
Textarea,
|
|
833
|
+
{
|
|
834
|
+
value: reportDraft.immediateAction,
|
|
835
|
+
onChange: (e) => setReportDraft((d) => ({
|
|
836
|
+
...d,
|
|
837
|
+
immediateAction: e.target.value
|
|
838
|
+
})),
|
|
839
|
+
rows: 2
|
|
840
|
+
}
|
|
841
|
+
)
|
|
842
|
+
] }),
|
|
843
|
+
/* @__PURE__ */ jsxs("p", { className: "text-[10px] text-muted-foreground", children: [
|
|
844
|
+
moduleName,
|
|
845
|
+
" \xB7 this is logged centrally and escalated automatically."
|
|
846
|
+
] })
|
|
847
|
+
] }),
|
|
848
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
849
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => setReportOpen(false), children: "Cancel" }),
|
|
850
|
+
/* @__PURE__ */ jsxs(
|
|
851
|
+
Button,
|
|
852
|
+
{
|
|
853
|
+
onClick: submitReport,
|
|
854
|
+
disabled: reportSubmitting || !reportDraft.description.trim(),
|
|
855
|
+
className: "gap-2",
|
|
856
|
+
style: {
|
|
857
|
+
backgroundColor: ALL_REPORT_OPTIONS.find(
|
|
858
|
+
(o) => o.category === reportCategory
|
|
859
|
+
)?.color,
|
|
860
|
+
color: "white"
|
|
861
|
+
},
|
|
862
|
+
children: [
|
|
863
|
+
/* @__PURE__ */ jsx(Send, { className: "h-3.5 w-3.5" }),
|
|
864
|
+
reportSubmitting ? "Submitting\u2026" : "Submit"
|
|
865
|
+
]
|
|
866
|
+
}
|
|
867
|
+
)
|
|
868
|
+
] })
|
|
379
869
|
] }) })
|
|
380
870
|
] });
|
|
381
871
|
}
|
|
@@ -428,6 +918,23 @@ var FEEDBACK_BUTTONS = [
|
|
|
428
918
|
description: "Suggest an improvement or new feature"
|
|
429
919
|
}
|
|
430
920
|
];
|
|
921
|
+
var REPORT_STANDARD_REFERENCES = {
|
|
922
|
+
safety: {
|
|
923
|
+
category: "safety",
|
|
924
|
+
label: "OSHA 29 CFR 1904 \xB7 ISO 45001",
|
|
925
|
+
description: "Injury classification follows OSHA's recordkeeping taxonomy (first aid only / recordable / days away, restricted, or transferred / fatality), within an ISO 45001 occupational health & safety management system."
|
|
926
|
+
},
|
|
927
|
+
environmental: {
|
|
928
|
+
category: "environmental",
|
|
929
|
+
label: "ISO 14001",
|
|
930
|
+
description: "Environmental aspect and regulatory-reportable classification follow ISO 14001's environmental management system requirements."
|
|
931
|
+
},
|
|
932
|
+
"stop-work": {
|
|
933
|
+
category: "stop-work",
|
|
934
|
+
label: "ISO 45001",
|
|
935
|
+
description: "Stop Work authority is a hazard-control mechanism exercised under an ISO 45001 occupational health & safety management system."
|
|
936
|
+
}
|
|
937
|
+
};
|
|
431
938
|
function createReportingConfig(moduleName, handlers) {
|
|
432
939
|
return {
|
|
433
940
|
moduleName,
|
|
@@ -469,6 +976,7 @@ export {
|
|
|
469
976
|
FEEDBACK_SCREENSHOT_MAX_BYTES,
|
|
470
977
|
OPLYTICS_SERVICES,
|
|
471
978
|
REPORT_BUTTONS,
|
|
979
|
+
REPORT_STANDARD_REFERENCES,
|
|
472
980
|
ReportingToolbar,
|
|
473
981
|
createReportingConfig,
|
|
474
982
|
isAcceptableScreenshot,
|