@pablo2410/shared-ui 0.18.2 → 0.19.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/reporting/ReportingToolbar.tsx","../../src/reporting/index.ts"],"sourcesContent":["/**\n * ReportingToolbar — standard Safety / Environmental / Stop Work incident\n * reporting and Problem / Suggestion feedback for all Oplytics subdomains.\n *\n * Visual model — a single grouped dropdown button in the top-right of the\n * header, so the header doesn't carry two separate buttons for what is, from\n * the user's perspective, one \"get help / raise something\" action:\n * ⚡ User Actions ▾ → Safety Incident | Environmental | Stop Work\n * ── (separator) ──\n * Report Problem | Suggestion\n *\n * Selecting an option opens a self-contained dialog with the right form for\n * that report/feedback type (severity / location / description / immediate\n * action for incidents; subject / description for feedback). On submit the\n * configured `onReportSubmit` / `onFeedbackSubmit` handler is called with\n * the canonical `IncidentReport` / `FeedbackReport` shape.\n *\n * Ported from the Policy Deployment subdomain — the canonical visual\n * reference. Originally two separate dropdown buttons (Report / Feedback);\n * merged into one \"User Actions\" menu to reduce header clutter.\n *\n * Oplytics dark theme: #0A0E1A bg, #8C34E9 accent.\n */\nimport { useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport {\n Button,\n Badge,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Input,\n Label,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogFooter,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"../primitives\";\nimport {\n ShieldAlert,\n Leaf,\n OctagonX,\n Bug,\n Lightbulb,\n ChevronDown,\n Send,\n AlertTriangle,\n UserCog,\n} from \"lucide-react\";\nimport { toast } from \"sonner\";\nimport type {\n ReportCategory,\n FeedbackCategory,\n IncidentReport,\n FeedbackReport,\n ReportingToolbarConfig,\n} from \"./index\";\n\n/* ── Report / feedback option catalogues ── */\n\ninterface ReportOption {\n category: ReportCategory;\n label: string;\n description: string;\n icon: React.ElementType;\n color: string;\n}\n\ninterface FeedbackOption {\n category: FeedbackCategory;\n label: string;\n description: string;\n icon: React.ElementType;\n color: string;\n}\n\nconst ALL_REPORT_OPTIONS: ReportOption[] = [\n {\n category: \"safety\",\n label: \"Safety Incident\",\n description: \"Report a safety hazard, near miss, or injury\",\n icon: ShieldAlert,\n color: \"#EF4444\",\n },\n {\n category: \"environmental\",\n label: \"Environmental\",\n description: \"Report an environmental concern or spill\",\n icon: Leaf,\n color: \"#22C55E\",\n },\n {\n category: \"stop-work\",\n label: \"Stop Work\",\n description: \"Raise a stop work authority — immediate halt\",\n icon: OctagonX,\n color: \"#F59E0B\",\n },\n];\n\nconst ALL_FEEDBACK_OPTIONS: FeedbackOption[] = [\n {\n category: \"problem\",\n label: \"Report Problem\",\n description: \"Something isn't working\",\n icon: Bug,\n color: \"#EF4444\",\n },\n {\n category: \"suggestion\",\n label: \"Suggestion\",\n description: \"Idea for improvement\",\n icon: Lightbulb,\n color: \"#8C34E9\",\n },\n];\n\nconst SEVERITY_OPTIONS: {\n value: NonNullable<IncidentReport[\"severity\"]>;\n label: string;\n color: string;\n}[] = [\n { value: \"critical\", label: \"Critical\", color: \"#EF4444\" },\n { value: \"high\", label: \"High\", color: \"#F59E0B\" },\n { value: \"medium\", label: \"Medium\", color: \"#3b82f6\" },\n { value: \"low\", label: \"Low\", color: \"#22C55E\" },\n];\n\n/* ── Props ── */\n\nexport interface ReportingToolbarProps extends Omit<\n ReportingToolbarConfig,\n \"moduleName\"\n> {\n /** Service/module name (e.g. \"Connect\", \"Policy Deployment\"). Defaults to \"Oplytics\". */\n moduleName?: string;\n /** Optional pre-fill for the report dialog's Location/Area field. */\n defaultLocation?: string;\n /**\n * Compact mode — currently a no-op (the new design always responsive-collapses\n * the labels at small breakpoints). Kept on the prop type so callers that\n * still pass it continue to type-check.\n * @deprecated The toolbar handles responsive collapse on its own.\n */\n compact?: boolean;\n /** CSS class for the container. */\n className?: string;\n}\n\n/* ── Component ── */\n\nexport function ReportingToolbar({\n moduleName = \"Oplytics\",\n showIncidentReporting = true,\n showFeedback = true,\n reportCategories = [\"safety\", \"environmental\", \"stop-work\"],\n feedbackCategories = [\"problem\", \"suggestion\"],\n onReportSubmit,\n onFeedbackSubmit,\n defaultLocation = \"\",\n className,\n}: ReportingToolbarProps) {\n const reportOptions = ALL_REPORT_OPTIONS.filter(opt =>\n reportCategories.includes(opt.category)\n );\n const feedbackOptions = ALL_FEEDBACK_OPTIONS.filter(opt =>\n feedbackCategories.includes(opt.category)\n );\n\n /* ── Report dialog state ── */\n const [reportDialogOpen, setReportDialogOpen] = useState(false);\n const [selectedReportCategory, setSelectedReportCategory] =\n useState<ReportCategory>(\"safety\");\n const [reportSeverity, setReportSeverity] =\n useState<NonNullable<IncidentReport[\"severity\"]>>(\"medium\");\n const [reportLocation, setReportLocation] = useState(defaultLocation);\n const [reportDescription, setReportDescription] = useState(\"\");\n const [reportImmediateAction, setReportImmediateAction] = useState(\"\");\n\n /* ── Feedback dialog state ── */\n const [feedbackDialogOpen, setFeedbackDialogOpen] = useState(false);\n const [selectedFeedbackCategory, setSelectedFeedbackCategory] =\n useState<FeedbackCategory>(\"problem\");\n const [feedbackSubject, setFeedbackSubject] = useState(\"\");\n const [feedbackDescription, setFeedbackDescription] = useState(\"\");\n\n const [submitting, setSubmitting] = useState(false);\n\n const openReportDialog = (category: ReportCategory) => {\n setSelectedReportCategory(category);\n setReportSeverity(category === \"stop-work\" ? \"critical\" : \"medium\");\n setReportLocation(defaultLocation);\n setReportDescription(\"\");\n setReportImmediateAction(\"\");\n setReportDialogOpen(true);\n };\n\n const openFeedbackDialog = (category: FeedbackCategory) => {\n setSelectedFeedbackCategory(category);\n setFeedbackSubject(\"\");\n setFeedbackDescription(\"\");\n setFeedbackDialogOpen(true);\n };\n\n const handleReportSubmit = async () => {\n if (!reportDescription.trim()) {\n toast.error(\"Please provide a description\");\n return;\n }\n setSubmitting(true);\n try {\n const report: IncidentReport = {\n category: selectedReportCategory,\n description: reportDescription,\n location: reportLocation || undefined,\n severity: reportSeverity,\n immediateAction: reportImmediateAction || undefined,\n moduleName,\n timestamp: new Date().toISOString(),\n };\n await onReportSubmit(report);\n toast.success(\"Report submitted successfully\", {\n description:\n selectedReportCategory === \"stop-work\"\n ? \"Stop Work authority raised — management has been notified\"\n : \"Your report has been logged and assigned for review\",\n });\n setReportDialogOpen(false);\n } catch (err) {\n console.error(\"[ReportingToolbar] report submit failed:\", err);\n toast.error(\"Failed to submit report. Please try again.\");\n } finally {\n setSubmitting(false);\n }\n };\n\n const handleFeedbackSubmit = async () => {\n if (!feedbackDescription.trim()) {\n toast.error(\"Please provide a description\");\n return;\n }\n setSubmitting(true);\n try {\n const feedback: FeedbackReport = {\n category: selectedFeedbackCategory,\n subject: feedbackSubject || undefined,\n description: feedbackDescription,\n moduleName,\n timestamp: new Date().toISOString(),\n pageContext:\n typeof window !== \"undefined\" ? window.location.pathname : undefined,\n };\n await onFeedbackSubmit(feedback);\n toast.success(\n selectedFeedbackCategory === \"problem\"\n ? \"Problem reported — Oplytics team will review\"\n : \"Suggestion submitted — thank you for your feedback\"\n );\n setFeedbackDialogOpen(false);\n } catch (err) {\n console.error(\"[ReportingToolbar] feedback submit failed:\", err);\n toast.error(\"Failed to submit feedback. Please try again.\");\n } finally {\n setSubmitting(false);\n }\n };\n\n const reportConfig = ALL_REPORT_OPTIONS.find(\n r => r.category === selectedReportCategory\n );\n\n return (\n <>\n {/* Toolbar button — Report + Feedback merged into one menu */}\n <div className={cn(\"flex items-center gap-2\", className)}>\n {(showIncidentReporting && reportOptions.length > 0) ||\n (showFeedback && feedbackOptions.length > 0) ? (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-9 gap-1.5 text-xs font-medium text-[#8890A0] hover:bg-[#1E2738] hover:text-[#E2E8F0] border border-[#1E2738]\"\n >\n <UserCog className=\"h-3.5 w-3.5\" />\n <span className=\"shell-hidden shell-sm:inline\">\n User Actions\n </span>\n <ChevronDown className=\"h-3 w-3\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-56\">\n {showIncidentReporting && reportOptions.length > 0 && (\n <>\n <DropdownMenuLabel className=\"text-[10px] uppercase tracking-wide text-muted-foreground\">\n Report\n </DropdownMenuLabel>\n {reportOptions.map(opt => (\n <DropdownMenuItem\n key={opt.category}\n onClick={() => openReportDialog(opt.category)}\n className=\"gap-3 py-2.5\"\n >\n <opt.icon\n className=\"h-4 w-4\"\n style={{ color: opt.color }}\n />\n <div>\n <p className=\"text-sm font-medium\">{opt.label}</p>\n <p className=\"text-[10px] text-muted-foreground\">\n {opt.description}\n </p>\n </div>\n </DropdownMenuItem>\n ))}\n </>\n )}\n\n {showIncidentReporting &&\n reportOptions.length > 0 &&\n showFeedback &&\n feedbackOptions.length > 0 && <DropdownMenuSeparator />}\n\n {showFeedback && feedbackOptions.length > 0 && (\n <>\n <DropdownMenuLabel className=\"text-[10px] uppercase tracking-wide text-muted-foreground\">\n Feedback\n </DropdownMenuLabel>\n {feedbackOptions.map(opt => (\n <DropdownMenuItem\n key={opt.category}\n onClick={() => openFeedbackDialog(opt.category)}\n className=\"gap-3 py-2.5\"\n >\n <opt.icon\n className=\"h-4 w-4\"\n style={{ color: opt.color }}\n />\n <div>\n <p className=\"text-sm font-medium\">{opt.label}</p>\n <p className=\"text-[10px] text-muted-foreground\">\n {opt.description}\n </p>\n </div>\n </DropdownMenuItem>\n ))}\n </>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n ) : null}\n </div>\n\n {/* Report Dialog */}\n <Dialog open={reportDialogOpen} onOpenChange={setReportDialogOpen}>\n <DialogContent className=\"sm:max-w-[500px]\">\n <DialogHeader>\n <DialogTitle className=\"flex items-center gap-2\">\n {reportConfig && (\n <reportConfig.icon\n className=\"h-5 w-5\"\n style={{ color: reportConfig.color }}\n />\n )}\n {reportConfig?.label || \"Report\"}\n {selectedReportCategory === \"stop-work\" && (\n <Badge className=\"bg-[#F59E0B] text-white text-[9px] border-0\">\n URGENT\n </Badge>\n )}\n </DialogTitle>\n <DialogDescription>\n {reportConfig?.description}. All reports are logged and tracked.\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-4 py-2\">\n <div className=\"space-y-2\">\n <Label className=\"text-xs font-medium\">Severity</Label>\n <Select\n value={reportSeverity}\n onValueChange={v =>\n setReportSeverity(\n v as NonNullable<IncidentReport[\"severity\"]>\n )\n }\n >\n <SelectTrigger className=\"h-9\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {SEVERITY_OPTIONS.map(s => (\n <SelectItem key={s.value} value={s.value}>\n <div className=\"flex items-center gap-2\">\n <div\n className=\"h-2 w-2 rounded-full\"\n style={{ backgroundColor: s.color }}\n />\n {s.label}\n </div>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"space-y-2\">\n <Label className=\"text-xs font-medium\">Location / Area</Label>\n <Input\n value={reportLocation}\n onChange={e => setReportLocation(e.target.value)}\n placeholder=\"e.g., Production Line 3, Warehouse B\"\n className=\"h-9\"\n />\n </div>\n\n <div className=\"space-y-2\">\n <Label className=\"text-xs font-medium\">Description *</Label>\n <Textarea\n value={reportDescription}\n onChange={e => setReportDescription(e.target.value)}\n placeholder=\"Describe what happened or what you observed...\"\n rows={4}\n />\n </div>\n\n <div className=\"space-y-2\">\n <Label className=\"text-xs font-medium\">\n Immediate Action Taken\n </Label>\n <Textarea\n value={reportImmediateAction}\n onChange={e => setReportImmediateAction(e.target.value)}\n placeholder=\"Describe any immediate action taken to make the area safe...\"\n rows={2}\n />\n </div>\n </div>\n\n <DialogFooter>\n <Button\n variant=\"outline\"\n onClick={() => setReportDialogOpen(false)}\n >\n Cancel\n </Button>\n <Button\n onClick={handleReportSubmit}\n disabled={submitting || !reportDescription.trim()}\n className=\"gap-2\"\n style={{\n backgroundColor: reportConfig?.color,\n color: \"white\",\n }}\n >\n <Send className=\"h-3.5 w-3.5\" />\n {submitting ? \"Submitting...\" : \"Submit Report\"}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n {/* Feedback Dialog */}\n <Dialog open={feedbackDialogOpen} onOpenChange={setFeedbackDialogOpen}>\n <DialogContent className=\"sm:max-w-[500px]\">\n <DialogHeader>\n <DialogTitle className=\"flex items-center gap-2\">\n {selectedFeedbackCategory === \"problem\" ? (\n <Bug className=\"h-5 w-5 text-[#EF4444]\" />\n ) : (\n <Lightbulb className=\"h-5 w-5 text-[#8C34E9]\" />\n )}\n {selectedFeedbackCategory === \"problem\"\n ? \"Report a Problem\"\n : \"Submit a Suggestion\"}\n </DialogTitle>\n <DialogDescription>\n {selectedFeedbackCategory === \"problem\"\n ? \"Help us fix issues — describe what went wrong.\"\n : \"We'd love to hear your ideas for improving Oplytics.\"}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-4 py-2\">\n <div className=\"space-y-2\">\n <Label className=\"text-xs font-medium\">Subject</Label>\n <Input\n value={feedbackSubject}\n onChange={e => setFeedbackSubject(e.target.value)}\n placeholder={\n selectedFeedbackCategory === \"problem\"\n ? \"Brief summary of the issue\"\n : \"Brief summary of your idea\"\n }\n className=\"h-9\"\n />\n </div>\n\n <div className=\"space-y-2\">\n <Label className=\"text-xs font-medium\">Description *</Label>\n <Textarea\n value={feedbackDescription}\n onChange={e => setFeedbackDescription(e.target.value)}\n placeholder={\n selectedFeedbackCategory === \"problem\"\n ? \"What were you trying to do? What happened instead?\"\n : \"Describe your suggestion and how it would help...\"\n }\n rows={5}\n />\n </div>\n\n <div className=\"text-[10px] text-muted-foreground\">\n Module: {moduleName} — Feedback is reviewed by the Oplytics team\n </div>\n </div>\n\n <DialogFooter>\n <Button\n variant=\"outline\"\n onClick={() => setFeedbackDialogOpen(false)}\n >\n Cancel\n </Button>\n <Button\n onClick={handleFeedbackSubmit}\n disabled={submitting || !feedbackDescription.trim()}\n className=\"gap-2\"\n style={{\n backgroundColor:\n selectedFeedbackCategory === \"problem\"\n ? \"#EF4444\"\n : \"#8C34E9\",\n color: \"white\",\n }}\n >\n <Send className=\"h-3.5 w-3.5\" />\n {submitting ? \"Submitting...\" : \"Submit\"}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </>\n );\n}\n","/**\n * @oplytics/shared-ui/reporting\n *\n * Reporting and feedback toolbar types and configuration for all Oplytics subdomains.\n * Provides the standard Safety/Environmental/Stop Work incident reporting buttons\n * and Problem/Suggestion feedback buttons.\n *\n * The actual ReportingToolbar React component depends on shadcn/ui primitives\n * (Dialog, Button, Textarea, Select) which vary across subdomains until\n * consolidation. This module provides the types, configuration, and submission\n * logic that are shared.\n */\n\n// ─── Report Types ────────────────────────────────────────────────────────────\n\nexport type ReportCategory = \"safety\" | \"environmental\" | \"stop-work\";\nexport type FeedbackCategory = \"problem\" | \"suggestion\";\n\nexport interface IncidentReport {\n category: ReportCategory;\n description: string;\n location?: string;\n severity?: \"low\" | \"medium\" | \"high\" | \"critical\";\n /** Optional — what was done at the scene to make the area safe. */\n immediateAction?: string;\n moduleName: string;\n /** ISO timestamp */\n timestamp: string;\n /** User who submitted */\n submittedBy?: string;\n /** Hierarchy context at time of submission */\n hierarchyContext?: {\n enterpriseId?: number;\n businessUnitId?: number;\n siteId?: number;\n areaId?: number;\n assetId?: number;\n };\n}\n\nexport interface FeedbackReport {\n category: FeedbackCategory;\n /** Optional — short summary entered in the dialog before the description. */\n subject?: string;\n description: string;\n moduleName: string;\n /** ISO timestamp */\n timestamp: string;\n /** User who submitted */\n submittedBy?: string;\n /** Page/route where feedback was submitted */\n pageContext?: string;\n}\n\n// ─── Toolbar Configuration ───────────────────────────────────────────────────\n\nexport interface ReportingToolbarConfig {\n /** Service/module name (e.g., \"SQDCP\", \"OEE Manager\") */\n moduleName: string;\n /** Whether to show incident reporting buttons (default: true) */\n showIncidentReporting?: boolean;\n /** Whether to show feedback buttons (default: true) */\n showFeedback?: boolean;\n /** Custom report categories to show (default: all three) */\n reportCategories?: ReportCategory[];\n /** Custom feedback categories to show (default: both) */\n feedbackCategories?: FeedbackCategory[];\n /** Handler called when an incident report is submitted */\n onReportSubmit: (report: IncidentReport) => Promise<void> | void;\n /** Handler called when feedback is submitted */\n onFeedbackSubmit: (feedback: FeedbackReport) => Promise<void> | void;\n}\n\n// ─── Report Button Definitions ───────────────────────────────────────────────\n\nexport interface ReportButtonDef {\n category: ReportCategory;\n label: string;\n iconName: string;\n color: string;\n description: string;\n}\n\nexport interface FeedbackButtonDef {\n category: FeedbackCategory;\n label: string;\n iconName: string;\n color: string;\n description: string;\n}\n\n/** Standard incident report buttons — consistent across all subdomains */\nexport const REPORT_BUTTONS: ReportButtonDef[] = [\n {\n category: \"safety\",\n label: \"Safety\",\n iconName: \"ShieldAlert\",\n color: \"#ef4444\",\n description: \"Report a safety incident, near-miss, or hazard\",\n },\n {\n category: \"environmental\",\n label: \"Environmental\",\n iconName: \"Leaf\",\n color: \"#22c55e\",\n description: \"Report an environmental incident or concern\",\n },\n {\n category: \"stop-work\",\n label: \"Stop Work\",\n iconName: \"OctagonX\",\n color: \"#f59e0b\",\n description: \"Raise a stop work authority — immediate safety concern\",\n },\n];\n\n/** Standard feedback buttons — consistent across all subdomains */\nexport const FEEDBACK_BUTTONS: FeedbackButtonDef[] = [\n {\n category: \"problem\",\n label: \"Problem\",\n iconName: \"AlertTriangle\",\n color: \"#ef4444\",\n description: \"Report a problem with the platform\",\n },\n {\n category: \"suggestion\",\n label: \"Suggestion\",\n iconName: \"Lightbulb\",\n color: \"#8C34E9\",\n description: \"Suggest an improvement or new feature\",\n },\n];\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\n/** Create a default ReportingToolbarConfig with sensible defaults */\nexport function createReportingConfig(\n moduleName: string,\n handlers: {\n onReportSubmit: (report: IncidentReport) => Promise<void> | void;\n onFeedbackSubmit: (feedback: FeedbackReport) => Promise<void> | void;\n }\n): ReportingToolbarConfig {\n return {\n moduleName,\n showIncidentReporting: true,\n showFeedback: true,\n reportCategories: [\"safety\", \"environmental\", \"stop-work\"],\n feedbackCategories: [\"problem\", \"suggestion\"],\n ...handlers,\n };\n}\n\n// ─── ReportingToolbar Component ─────────────────────────────────────────────\n\nexport {\n ReportingToolbar,\n type ReportingToolbarProps,\n} from \"./ReportingToolbar\";\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/reporting/ReportingToolbar.tsx","../../src/reporting/index.ts"],"sourcesContent":["/**\n * ReportingToolbar — the header \"User Actions\" dropdown for all Oplytics\n * subdomains.\n *\n * ⚙ User Actions ▾ → Report (Coming soon while gated)\n * Safety Incident\n * Environmental\n * Stop Work\n * ── (separator) ──\n * Feedback\n * Report a Problem\n * Suggestion\n *\n * Feedback opens a self-contained dialog: pick the service, say whether it's\n * blocking you, a short summary, the detail, and optionally attach a\n * screenshot. On submit `onFeedbackSubmit(feedback: FeedbackReport)` is called\n * — the host POSTs it to Portal's /api/service/feedback.\n *\n * Report (Safety / Environmental / Stop Work) is not wired yet. While\n * `reportsComingSoon` is true (the default) those items are disabled with a\n * \"Coming soon\" badge; a later release adds the per-type forms.\n *\n * Oplytics dark theme: #0A0E1A bg, #8C34E9 accent.\n */\nimport { useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport {\n Button,\n Badge,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Input,\n Label,\n Switch,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogFooter,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"../primitives\";\nimport {\n ShieldAlert,\n Leaf,\n OctagonX,\n Bug,\n Lightbulb,\n ChevronDown,\n Send,\n ImagePlus,\n X,\n UserCog,\n} from \"lucide-react\";\nimport { toast } from \"sonner\";\nimport {\n OPLYTICS_SERVICES,\n isAcceptableScreenshot,\n readFileAsScreenshot,\n type ReportCategory,\n type FeedbackCategory,\n type IncidentReport,\n type FeedbackReport,\n type ReportScreenshot,\n type ReportSubmitter,\n type ReportHierarchyContext,\n type OplyticsService,\n type ReportingToolbarConfig,\n} from \"./index\";\n\n/* ── Option catalogues ── */\n\ninterface ReportOption {\n category: ReportCategory;\n label: string;\n description: string;\n icon: React.ElementType;\n color: string;\n}\n\nconst ALL_REPORT_OPTIONS: ReportOption[] = [\n {\n category: \"safety\",\n label: \"Safety Incident\",\n description: \"Report a safety hazard, near miss, or injury\",\n icon: ShieldAlert,\n color: \"#EF4444\",\n },\n {\n category: \"environmental\",\n label: \"Environmental\",\n description: \"Report an environmental concern or spill\",\n icon: Leaf,\n color: \"#22C55E\",\n },\n {\n category: \"stop-work\",\n label: \"Stop Work\",\n description: \"Raise a stop work authority — immediate halt\",\n icon: OctagonX,\n color: \"#F59E0B\",\n },\n];\n\ninterface FeedbackOption {\n category: FeedbackCategory;\n label: string;\n description: string;\n icon: React.ElementType;\n color: string;\n}\n\nconst ALL_FEEDBACK_OPTIONS: FeedbackOption[] = [\n {\n category: \"problem\",\n label: \"Report a Problem\",\n description: \"Something isn't working\",\n icon: Bug,\n color: \"#EF4444\",\n },\n {\n category: \"suggestion\",\n label: \"Suggestion\",\n description: \"An idea for improvement\",\n icon: Lightbulb,\n color: \"#8C34E9\",\n },\n];\n\n/* ── Props ── */\n\nexport interface ReportingToolbarProps extends Omit<\n ReportingToolbarConfig,\n \"moduleName\"\n> {\n /** Service/module name (e.g. \"Connect\"). Defaults to \"Oplytics\". */\n moduleName?: string;\n /** The current org-hierarchy selection, forwarded on every submission. */\n hierarchyContext?: ReportHierarchyContext;\n /** The authenticated user — openId is authoritative, name/email are hints. */\n currentUser?: ReportSubmitter;\n /** Service list for the feedback picker. Defaults to OPLYTICS_SERVICES. */\n services?: OplyticsService[];\n /** Pre-selected service slug in the feedback picker. */\n defaultServiceSlug?: string;\n /** Show the \"attach screenshot\" control (default: true). */\n enableScreenshot?: boolean;\n /**\n * While true (the DEFAULT), the Report items are disabled with a \"Coming\n * soon\" badge and `onReportSubmit` is never called. A later release wires the\n * per-type forms and passes `false`.\n */\n reportsComingSoon?: boolean;\n /**\n * @deprecated the toolbar handles responsive collapse itself.\n */\n compact?: boolean;\n /** CSS class for the container. */\n className?: string;\n}\n\n/* ── Component ── */\n\nexport function ReportingToolbar({\n moduleName = \"Oplytics\",\n showIncidentReporting = true,\n showFeedback = true,\n reportCategories = [\"safety\", \"environmental\", \"stop-work\"],\n feedbackCategories = [\"problem\", \"suggestion\"],\n onReportSubmit,\n onFeedbackSubmit,\n hierarchyContext,\n currentUser,\n services = OPLYTICS_SERVICES,\n defaultServiceSlug,\n enableScreenshot = true,\n reportsComingSoon = true,\n className,\n}: ReportingToolbarProps) {\n const reportOptions = ALL_REPORT_OPTIONS.filter(opt =>\n reportCategories.includes(opt.category)\n );\n const feedbackOptions = ALL_FEEDBACK_OPTIONS.filter(opt =>\n feedbackCategories.includes(opt.category)\n );\n\n const firstServiceSlug = defaultServiceSlug ?? services[0]?.slug ?? \"portal\";\n\n /* ── Feedback dialog state ── */\n const [feedbackOpen, setFeedbackOpen] = useState(false);\n const [category, setCategory] = useState<FeedbackCategory>(\"problem\");\n const [serviceSlug, setServiceSlug] = useState(firstServiceSlug);\n const [isBlocking, setIsBlocking] = useState(false);\n const [summary, setSummary] = useState(\"\");\n const [details, setDetails] = useState(\"\");\n const [screenshot, setScreenshot] = useState<ReportScreenshot | null>(null);\n const [screenshotName, setScreenshotName] = useState<string | null>(null);\n const [submitting, setSubmitting] = useState(false);\n const fileInputRef = useRef<HTMLInputElement | null>(null);\n\n const openFeedback = (c: FeedbackCategory) => {\n setCategory(c);\n setServiceSlug(firstServiceSlug);\n setIsBlocking(false);\n setSummary(\"\");\n setDetails(\"\");\n setScreenshot(null);\n setScreenshotName(null);\n setFeedbackOpen(true);\n };\n\n const handlePickFile = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = \"\"; // allow re-picking the same file\n if (!file) return;\n const check = isAcceptableScreenshot(file);\n if (!check.ok) {\n toast.error(check.reason);\n return;\n }\n try {\n const shot = await readFileAsScreenshot(file);\n setScreenshot(shot);\n setScreenshotName(file.name);\n } catch (err) {\n console.error(\"[ReportingToolbar] screenshot read failed:\", err);\n toast.error(\"Could not read that image.\");\n }\n };\n\n const submitFeedback = async () => {\n if (!details.trim()) {\n toast.error(\"Please describe the problem or idea.\");\n return;\n }\n setSubmitting(true);\n try {\n const feedback: FeedbackReport = {\n category,\n serviceSlug,\n summary: summary.trim() || undefined,\n details: details.trim(),\n isBlocking,\n moduleName,\n timestamp: new Date().toISOString(),\n pageContext:\n typeof window !== \"undefined\" ? window.location.pathname : undefined,\n submittedBy: currentUser,\n screenshot: screenshot ?? undefined,\n };\n await onFeedbackSubmit(feedback);\n toast.success(\n category === \"problem\"\n ? \"Thanks — we've logged it. You'll get a confirmation email.\"\n : \"Thanks for the suggestion — you'll get a confirmation email.\"\n );\n setFeedbackOpen(false);\n } catch (err) {\n console.error(\"[ReportingToolbar] feedback submit failed:\", err);\n toast.error(\"Couldn't submit that. Please try again.\");\n } finally {\n setSubmitting(false);\n }\n };\n\n const showReportGroup = showIncidentReporting && reportOptions.length > 0;\n const showFeedbackGroup = showFeedback && feedbackOptions.length > 0;\n if (!showReportGroup && !showFeedbackGroup) return null;\n\n // hierarchyContext is forwarded to onReportSubmit once the Report forms are\n // wired; referenced here so the prop isn't flagged unused before then.\n void hierarchyContext;\n\n return (\n <>\n <div className={cn(\"flex items-center gap-2\", className)}>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-9 gap-1.5 text-xs font-medium text-[#8890A0] hover:bg-[#1E2738] hover:text-[#E2E8F0] border border-[#1E2738]\"\n >\n <UserCog className=\"h-3.5 w-3.5\" />\n <span className=\"shell-hidden shell-sm:inline\">User Actions</span>\n <ChevronDown className=\"h-3 w-3\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-60\">\n {showReportGroup && (\n <>\n <DropdownMenuLabel className=\"flex items-center gap-2 text-[10px] uppercase tracking-wide text-muted-foreground\">\n Report\n {reportsComingSoon && (\n <Badge\n variant=\"outline\"\n className=\"border-[#8C34E9]/40 text-[9px] font-normal text-[#C084FC]\"\n >\n Coming soon\n </Badge>\n )}\n </DropdownMenuLabel>\n {reportOptions.map(opt => (\n <DropdownMenuItem\n key={opt.category}\n disabled={reportsComingSoon}\n onClick={() => {\n if (!reportsComingSoon) {\n // Wired in a later release.\n void onReportSubmit;\n }\n }}\n className=\"gap-3 py-2.5\"\n >\n <opt.icon\n className=\"h-4 w-4\"\n style={{ color: opt.color }}\n />\n <div>\n <p className=\"text-sm font-medium\">{opt.label}</p>\n <p className=\"text-[10px] text-muted-foreground\">\n {opt.description}\n </p>\n </div>\n </DropdownMenuItem>\n ))}\n </>\n )}\n\n {showReportGroup && showFeedbackGroup && <DropdownMenuSeparator />}\n\n {showFeedbackGroup && (\n <>\n <DropdownMenuLabel className=\"text-[10px] uppercase tracking-wide text-muted-foreground\">\n Feedback\n </DropdownMenuLabel>\n {feedbackOptions.map(opt => (\n <DropdownMenuItem\n key={opt.category}\n onClick={() => openFeedback(opt.category)}\n className=\"gap-3 py-2.5\"\n >\n <opt.icon\n className=\"h-4 w-4\"\n style={{ color: opt.color }}\n />\n <div>\n <p className=\"text-sm font-medium\">{opt.label}</p>\n <p className=\"text-[10px] text-muted-foreground\">\n {opt.description}\n </p>\n </div>\n </DropdownMenuItem>\n ))}\n </>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n\n {/* Feedback dialog */}\n <Dialog open={feedbackOpen} onOpenChange={setFeedbackOpen}>\n <DialogContent className=\"sm:max-w-[520px]\">\n <DialogHeader>\n <DialogTitle className=\"flex items-center gap-2\">\n {category === \"problem\" ? (\n <Bug className=\"h-5 w-5 text-[#EF4444]\" />\n ) : (\n <Lightbulb className=\"h-5 w-5 text-[#8C34E9]\" />\n )}\n {category === \"problem\"\n ? \"Report a Problem\"\n : \"Share a Suggestion\"}\n </DialogTitle>\n <DialogDescription>\n {category === \"problem\"\n ? \"Tell us what went wrong. We triage within 24 hours.\"\n : \"We review every suggestion and schedule improvements against the roadmap.\"}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-4 py-2\">\n <div className=\"space-y-2\">\n <Label className=\"text-xs font-medium\">Which service?</Label>\n <Select value={serviceSlug} onValueChange={setServiceSlug}>\n <SelectTrigger className=\"h-9\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {services.map(s => (\n <SelectItem key={s.slug} value={s.slug}>\n {s.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {category === \"problem\" && (\n <div className=\"flex items-center justify-between rounded-md border border-[#1E2738] px-3 py-2\">\n <div>\n <p className=\"text-sm font-medium\">Is this blocking you?</p>\n <p className=\"text-[10px] text-muted-foreground\">\n Blocking issues are treated as high priority.\n </p>\n </div>\n <Switch checked={isBlocking} onCheckedChange={setIsBlocking} />\n </div>\n )}\n\n <div className=\"space-y-2\">\n <Label className=\"text-xs font-medium\">Summary</Label>\n <Input\n value={summary}\n onChange={e => setSummary(e.target.value)}\n placeholder={\n category === \"problem\"\n ? \"Brief summary of the issue\"\n : \"Brief summary of your idea\"\n }\n className=\"h-9\"\n />\n </div>\n\n <div className=\"space-y-2\">\n <Label className=\"text-xs font-medium\">Details *</Label>\n <Textarea\n value={details}\n onChange={e => setDetails(e.target.value)}\n placeholder={\n category === \"problem\"\n ? \"What were you trying to do? What happened instead?\"\n : \"Describe your suggestion and how it would help…\"\n }\n rows={5}\n />\n </div>\n\n {enableScreenshot && (\n <div className=\"space-y-2\">\n <Label className=\"text-xs font-medium\">\n Screenshot (optional)\n </Label>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n className=\"hidden\"\n onChange={handlePickFile}\n />\n {screenshot ? (\n <div className=\"flex items-center gap-2 rounded-md border border-[#1E2738] px-3 py-2\">\n <ImagePlus className=\"h-4 w-4 text-[#8C34E9]\" />\n <span className=\"flex-1 truncate text-xs text-[#E2E8F0]\">\n {screenshotName ?? \"screenshot\"}\n </span>\n <button\n type=\"button\"\n onClick={() => {\n setScreenshot(null);\n setScreenshotName(null);\n }}\n className=\"text-muted-foreground hover:text-[#E2E8F0]\"\n aria-label=\"Remove screenshot\"\n >\n <X className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n ) : (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-9 gap-1.5\"\n onClick={() => fileInputRef.current?.click()}\n >\n <ImagePlus className=\"h-3.5 w-3.5\" />\n Attach an image\n </Button>\n )}\n </div>\n )}\n\n <p className=\"text-[10px] text-muted-foreground\">\n {moduleName} · you'll get a confirmation email once this is\n logged.\n </p>\n </div>\n\n <DialogFooter>\n <Button variant=\"outline\" onClick={() => setFeedbackOpen(false)}>\n Cancel\n </Button>\n <Button\n onClick={submitFeedback}\n disabled={submitting || !details.trim()}\n className=\"gap-2\"\n style={{\n backgroundColor: category === \"problem\" ? \"#EF4444\" : \"#8C34E9\",\n color: \"white\",\n }}\n >\n <Send className=\"h-3.5 w-3.5\" />\n {submitting ? \"Submitting…\" : \"Submit\"}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </>\n );\n}\n","/**\n * @oplytics/shared-ui/reporting\n *\n * Reporting and feedback toolbar types + configuration for all Oplytics\n * subdomains — the header \"User Actions\" dropdown (ReportingToolbar).\n *\n * Feedback (Report Problem / Suggestion) is fully wired: the dialog collects a\n * service, an \"is this blocking you?\" signal, a short summary, the detail, and\n * an optional screenshot, then calls `onFeedbackSubmit` with the canonical\n * `FeedbackReport` shape. The host owns the transport (it POSTs to Portal's\n * `/api/service/feedback`).\n *\n * Report (Safety / Environmental / Stop Work) is not wired yet — while\n * `reportsComingSoon` is true (the default), those items render disabled with a\n * \"Coming soon\" badge. A later release adds the per-type forms and flips the\n * default.\n */\n\n// ─── Report types ───────────────────────────────────────────────────────────\n\nexport type ReportCategory = \"safety\" | \"environmental\" | \"stop-work\";\nexport type FeedbackCategory = \"problem\" | \"suggestion\";\n\n/** Where in the org hierarchy the submission was made. */\nexport interface ReportHierarchyContext {\n enterpriseId?: number;\n businessUnitId?: number;\n siteId?: number;\n areaId?: number;\n assetId?: number;\n}\n\n/** The authenticated user, as much as the host can supply. */\nexport interface ReportSubmitter {\n /** JWT `openId` claim — the host must NOT trust name/email over this. */\n openId?: string;\n name?: string;\n email?: string;\n}\n\n/** An attached screenshot: base64 WITHOUT the `data:...;base64,` prefix. */\nexport interface ReportScreenshot {\n dataBase64: string;\n mime: string;\n}\n\nexport interface IncidentReport {\n category: ReportCategory;\n description: string;\n location?: string;\n severity?: \"low\" | \"medium\" | \"high\" | \"critical\";\n /** Optional — what was done at the scene to make the area safe. */\n immediateAction?: string;\n moduleName: string;\n /** ISO timestamp */\n timestamp: string;\n submittedBy?: ReportSubmitter;\n hierarchyContext?: ReportHierarchyContext;\n}\n\nexport interface FeedbackReport {\n category: FeedbackCategory;\n /** Canonical service slug the feedback is about (from the picker). */\n serviceSlug: string;\n /** Optional short one-liner shown above the detail. */\n summary?: string;\n /** Required detail body. */\n details: string;\n /** \"Is this blocking you?\" — drives priority server-side. */\n isBlocking: boolean;\n /** Human-readable originating module (\"OEE Manager\", \"SQDCP\", …). */\n moduleName: string;\n /** ISO timestamp */\n timestamp: string;\n /** Route the submitter was on. */\n pageContext?: string;\n submittedBy?: ReportSubmitter;\n screenshot?: ReportScreenshot;\n}\n\n// ─── Service catalogue ──────────────────────────────────────────────────────\n\nexport interface OplyticsService {\n slug: string;\n label: string;\n}\n\n/**\n * The services a user can attribute feedback to. Kept here so every subdomain's\n * picker shows the same list; a host can narrow or override it via the\n * `services` prop. Slugs match Portal's `platform_feedback.serviceSlug`.\n */\nexport const OPLYTICS_SERVICES: OplyticsService[] = [\n { slug: \"sqdcp\", label: \"SQDCP\" },\n { slug: \"oee-manager\", label: \"OEE Manager\" },\n { slug: \"action-manager\", label: \"Action Manager\" },\n { slug: \"policy-deployment\", label: \"Policy Deployment\" },\n { slug: \"connect\", label: \"Connect\" },\n { slug: \"portal\", label: \"Portal\" },\n];\n\n// ─── Toolbar configuration ──────────────────────────────────────────────────\n\nexport interface ReportingToolbarConfig {\n /** Service/module name (e.g. \"SQDCP\", \"OEE Manager\"). */\n moduleName: string;\n /** Whether to show the Report group at all (default: true). */\n showIncidentReporting?: boolean;\n /** Whether to show the Feedback group at all (default: true). */\n showFeedback?: boolean;\n /** Report categories to show (default: all three). */\n reportCategories?: ReportCategory[];\n /** Feedback categories to show (default: both). */\n feedbackCategories?: FeedbackCategory[];\n /** Called when an incident report is submitted (not wired yet). */\n onReportSubmit: (report: IncidentReport) => Promise<void> | void;\n /** Called when feedback is submitted — the host POSTs it to Portal. */\n onFeedbackSubmit: (feedback: FeedbackReport) => Promise<void> | void;\n}\n\n// ─── Button definitions (kept for backwards compatibility / config helpers) ──\n\nexport interface ReportButtonDef {\n category: ReportCategory;\n label: string;\n iconName: string;\n color: string;\n description: string;\n}\n\nexport interface FeedbackButtonDef {\n category: FeedbackCategory;\n label: string;\n iconName: string;\n color: string;\n description: string;\n}\n\nexport const REPORT_BUTTONS: ReportButtonDef[] = [\n {\n category: \"safety\",\n label: \"Safety\",\n iconName: \"ShieldAlert\",\n color: \"#ef4444\",\n description: \"Report a safety incident, near-miss, or hazard\",\n },\n {\n category: \"environmental\",\n label: \"Environmental\",\n iconName: \"Leaf\",\n color: \"#22c55e\",\n description: \"Report an environmental incident or concern\",\n },\n {\n category: \"stop-work\",\n label: \"Stop Work\",\n iconName: \"OctagonX\",\n color: \"#f59e0b\",\n description: \"Raise a stop work authority — immediate safety concern\",\n },\n];\n\nexport const FEEDBACK_BUTTONS: FeedbackButtonDef[] = [\n {\n category: \"problem\",\n label: \"Problem\",\n iconName: \"AlertTriangle\",\n color: \"#ef4444\",\n description: \"Report a problem with the platform\",\n },\n {\n category: \"suggestion\",\n label: \"Suggestion\",\n iconName: \"Lightbulb\",\n color: \"#8C34E9\",\n description: \"Suggest an improvement or new feature\",\n },\n];\n\n// ─── Helpers ────────────────────────────────────────────────────────────────\n\n/** Create a default ReportingToolbarConfig with sensible defaults. */\nexport function createReportingConfig(\n moduleName: string,\n handlers: {\n onReportSubmit: (report: IncidentReport) => Promise<void> | void;\n onFeedbackSubmit: (feedback: FeedbackReport) => Promise<void> | void;\n }\n): ReportingToolbarConfig {\n return {\n moduleName,\n showIncidentReporting: true,\n showFeedback: true,\n reportCategories: [\"safety\", \"environmental\", \"stop-work\"],\n feedbackCategories: [\"problem\", \"suggestion\"],\n ...handlers,\n };\n}\n\n/**\n * Read a picked File into `{ dataBase64, mime }` (no data: prefix), rejecting\n * non-images and anything over `maxBytes` decoded. Pure-ish (needs FileReader);\n * exported so the size rule can be unit-tested and reused.\n */\nexport const FEEDBACK_SCREENSHOT_MAX_BYTES = 300 * 1024;\n\nexport function isAcceptableScreenshot(\n file: { type: string; size: number },\n maxBytes: number = FEEDBACK_SCREENSHOT_MAX_BYTES\n): { ok: true } | { ok: false; reason: string } {\n if (!file.type.startsWith(\"image/\")) {\n return { ok: false, reason: \"Please choose an image file.\" };\n }\n if (file.size > maxBytes) {\n return {\n ok: false,\n reason: `Image is too large (max ${Math.round(maxBytes / 1024)} KB).`,\n };\n }\n return { ok: true };\n}\n\nexport function readFileAsScreenshot(file: File): Promise<ReportScreenshot> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onerror = () => reject(new Error(\"Could not read the file.\"));\n reader.onload = () => {\n const result = String(reader.result || \"\");\n const comma = result.indexOf(\",\");\n const dataBase64 = comma >= 0 ? result.slice(comma + 1) : result;\n resolve({ dataBase64, mime: file.type || \"image/png\" });\n };\n reader.readAsDataURL(file);\n });\n}\n\n// ─── ReportingToolbar component ─────────────────────────────────────────────\n\nexport {\n ReportingToolbar,\n type ReportingToolbarProps,\n} from \"./ReportingToolbar\";\n"],"mappings":"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","names":[]}
@@ -5,13 +5,13 @@ import {
5
5
  CrossServiceNav,
6
6
  DashboardLayout,
7
7
  HealthFooter
8
- } from "../chunk-TTDKZK6L.js";
8
+ } from "../chunk-NLQ45OYS.js";
9
9
  import "../chunk-4QJMLQSH.js";
10
- import "../chunk-CPRJSW7F.js";
10
+ import "../chunk-VJEXXX2P.js";
11
11
  import "../chunk-DMUQ5WNO.js";
12
12
  import "../chunk-A6UTXAPS.js";
13
13
  import "../chunk-HLMIR5UV.js";
14
- import "../chunk-NXE653CX.js";
14
+ import "../chunk-K6FHU4HN.js";
15
15
  import "../chunk-JT3XLKKD.js";
16
16
  import "../chunk-BKGUIIN2.js";
17
17