@nextlyhq/plugin-form-builder 0.0.2-alpha.33 → 0.0.2-alpha.34
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/admin/index.css +28 -871
- package/dist/admin/index.css.map +1 -1
- package/dist/admin/index.js +226 -245
- package/dist/admin/index.js.map +1 -1
- package/dist/{chunk-ABNZFTQK.js → chunk-2LLUO3TV.js} +100 -139
- package/dist/chunk-2LLUO3TV.js.map +1 -0
- package/dist/components/index.js +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/styles/form-builder.css +40 -1062
- package/dist/styles/submissions-filter.css +19 -20
- package/package.json +16 -13
- package/dist/chunk-ABNZFTQK.js.map +0 -1
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Submissions Filter Styles
|
|
3
3
|
*
|
|
4
|
-
* Styles for the SubmissionsFilter component
|
|
5
|
-
*
|
|
4
|
+
* Styles for the SubmissionsFilter component shown above the
|
|
5
|
+
* form-submissions list table. Colors/borders/radius use the admin tokens.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
.submissions-filter {
|
|
9
9
|
margin-bottom: 1rem;
|
|
10
10
|
padding: 1rem;
|
|
11
|
-
background: var(--
|
|
12
|
-
border: 1px solid var(--
|
|
13
|
-
border-radius:
|
|
11
|
+
background: var(--muted);
|
|
12
|
+
border: 1px solid var(--border);
|
|
13
|
+
border-radius: var(--radius);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
.submissions-filter-container {
|
|
@@ -23,33 +23,32 @@
|
|
|
23
23
|
.submissions-filter-label {
|
|
24
24
|
font-size: 0.875rem;
|
|
25
25
|
font-weight: 500;
|
|
26
|
-
color: var(--
|
|
26
|
+
color: var(--muted-foreground);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
.submissions-filter-select {
|
|
30
30
|
padding: 0.5rem 2rem 0.5rem 0.75rem;
|
|
31
31
|
font-size: 0.875rem;
|
|
32
|
-
border: 1px solid var(--
|
|
33
|
-
border-radius:
|
|
34
|
-
background-color: var(--
|
|
35
|
-
color: var(--
|
|
32
|
+
border: 1px solid var(--input);
|
|
33
|
+
border-radius: var(--radius);
|
|
34
|
+
background-color: var(--background);
|
|
35
|
+
color: var(--foreground);
|
|
36
36
|
min-width: 200px;
|
|
37
37
|
cursor: pointer;
|
|
38
38
|
appearance: none;
|
|
39
|
-
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='
|
|
39
|
+
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
|
|
40
40
|
background-position: right 0.5rem center;
|
|
41
41
|
background-repeat: no-repeat;
|
|
42
42
|
background-size: 1.5em 1.5em;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
.submissions-filter-select:hover {
|
|
46
|
-
border-color: var(--
|
|
46
|
+
border-color: var(--border-strong);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
.submissions-filter-select:focus {
|
|
50
50
|
outline: none;
|
|
51
|
-
border-color: var(--
|
|
52
|
-
/* box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); */
|
|
51
|
+
border-color: var(--ring);
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
.submissions-filter-select:disabled {
|
|
@@ -61,15 +60,15 @@
|
|
|
61
60
|
padding: 0.5rem 0.75rem;
|
|
62
61
|
font-size: 0.75rem;
|
|
63
62
|
font-weight: 500;
|
|
64
|
-
color: var(--
|
|
65
|
-
background: var(--
|
|
66
|
-
border: 1px solid var(--
|
|
67
|
-
border-radius:
|
|
63
|
+
color: var(--muted-foreground);
|
|
64
|
+
background: var(--background);
|
|
65
|
+
border: 1px solid var(--input);
|
|
66
|
+
border-radius: var(--radius);
|
|
68
67
|
cursor: pointer;
|
|
69
68
|
transition: all 0.15s ease;
|
|
70
69
|
}
|
|
71
70
|
|
|
72
71
|
.submissions-filter-clear:hover {
|
|
73
|
-
background: var(--
|
|
74
|
-
color: var(--
|
|
72
|
+
background: var(--muted);
|
|
73
|
+
color: var(--foreground);
|
|
75
74
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextlyhq/plugin-form-builder",
|
|
3
|
-
"version": "0.0.2-alpha.
|
|
3
|
+
"version": "0.0.2-alpha.34",
|
|
4
4
|
"description": "Visual form builder plugin for Nextly with Code-First and Schema Builder support",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -10,15 +10,18 @@
|
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
12
12
|
"types": "./dist/index.d.ts",
|
|
13
|
-
"import": "./dist/index.js"
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"default": "./dist/index.js"
|
|
14
15
|
},
|
|
15
16
|
"./admin": {
|
|
16
17
|
"types": "./dist/admin/index.d.ts",
|
|
17
|
-
"import": "./dist/admin/index.js"
|
|
18
|
+
"import": "./dist/admin/index.js",
|
|
19
|
+
"default": "./dist/admin/index.js"
|
|
18
20
|
},
|
|
19
21
|
"./components": {
|
|
20
22
|
"types": "./dist/components/index.d.ts",
|
|
21
|
-
"import": "./dist/components/index.js"
|
|
23
|
+
"import": "./dist/components/index.js",
|
|
24
|
+
"default": "./dist/components/index.js"
|
|
22
25
|
},
|
|
23
26
|
"./styles/builder.css": "./dist/styles/form-builder.css",
|
|
24
27
|
"./styles/submissions-filter.css": "./dist/styles/submissions-filter.css"
|
|
@@ -36,14 +39,14 @@
|
|
|
36
39
|
"@hookform/resolvers": "^3.3.4"
|
|
37
40
|
},
|
|
38
41
|
"peerDependencies": {
|
|
39
|
-
"@nextlyhq/admin": "0.0.2-alpha.
|
|
40
|
-
"nextly": "0.0.2-alpha.
|
|
41
|
-
"@nextlyhq/ui": "0.0.2-alpha.
|
|
42
|
+
"@nextlyhq/admin": "0.0.2-alpha.34",
|
|
43
|
+
"nextly": "0.0.2-alpha.34",
|
|
44
|
+
"@nextlyhq/ui": "0.0.2-alpha.34",
|
|
42
45
|
"@tanstack/react-query": ">=5.0.0",
|
|
43
46
|
"lucide-react": ">=0.400.0",
|
|
44
47
|
"react": "^18.0.0 || ^19.0.0",
|
|
45
48
|
"next": "^14.0.0 || ^15.0.0 || ^16.0.0",
|
|
46
|
-
"@nextlyhq/plugin-sdk": "0.0.2-alpha.
|
|
49
|
+
"@nextlyhq/plugin-sdk": "0.0.2-alpha.34"
|
|
47
50
|
},
|
|
48
51
|
"devDependencies": {
|
|
49
52
|
"@tanstack/react-query": "^5.0.0",
|
|
@@ -53,11 +56,11 @@
|
|
|
53
56
|
"tsup": "^8.0.0",
|
|
54
57
|
"typescript": "^5.3.0",
|
|
55
58
|
"vitest": "^4.0.8",
|
|
56
|
-
"@nextlyhq/tsconfig": "0.0.2-alpha.
|
|
57
|
-
"@nextlyhq/admin": "0.0.2-alpha.
|
|
58
|
-
"nextly": "0.0.2-alpha.
|
|
59
|
-
"@nextlyhq/plugin-sdk": "0.0.2-alpha.
|
|
60
|
-
"@nextlyhq/ui": "0.0.2-alpha.
|
|
59
|
+
"@nextlyhq/tsconfig": "0.0.2-alpha.26",
|
|
60
|
+
"@nextlyhq/admin": "0.0.2-alpha.34",
|
|
61
|
+
"nextly": "0.0.2-alpha.34",
|
|
62
|
+
"@nextlyhq/plugin-sdk": "0.0.2-alpha.34",
|
|
63
|
+
"@nextlyhq/ui": "0.0.2-alpha.34"
|
|
61
64
|
},
|
|
62
65
|
"engines": {
|
|
63
66
|
"node": ">=20.0.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/submissions/SubmissionList.tsx","../src/components/submissions/SubmissionDetail.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * Submission List Component\n *\n * Admin view for listing and managing form submissions.\n * Displays submissions in a filterable table with bulk actions.\n *\n * @module components/submissions/SubmissionList\n * @since 0.1.0\n */\n\n\"use client\";\n\nimport type React from \"react\";\nimport { useState, useCallback, useMemo } from \"react\";\n\nimport type { SubmissionDocument, FormDocument, FormField } from \"../../types\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Props for the SubmissionList component.\n */\nexport interface SubmissionListProps {\n /** Form document containing field definitions */\n form: FormDocument;\n\n /** Array of submission documents to display */\n submissions: SubmissionDocument[];\n\n /** Whether data is currently loading */\n isLoading?: boolean;\n\n /** Callback when submission status is changed */\n onStatusChange?: (\n id: string,\n status: \"new\" | \"read\" | \"archived\"\n ) => Promise<void>;\n\n /** Callback when submission is deleted */\n onDelete?: (id: string) => Promise<void>;\n\n /** Callback when bulk delete is triggered */\n onBulkDelete?: (ids: string[]) => Promise<void>;\n\n /** Callback when bulk status change is triggered */\n onBulkStatusChange?: (\n ids: string[],\n status: \"new\" | \"read\" | \"archived\"\n ) => Promise<void>;\n\n /** Callback when export is triggered */\n onExport?: (format: \"csv\" | \"json\") => void;\n\n /** Callback when a submission is clicked for detail view */\n onViewDetail?: (submission: SubmissionDocument) => void;\n}\n\n/**\n * Status filter options.\n */\ntype StatusFilter = \"all\" | \"new\" | \"read\" | \"archived\";\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Format a value for display in the table.\n */\nfunction formatValue(value: unknown): string {\n if (value === null || value === undefined) return \"-\";\n if (Array.isArray(value)) return value.join(\", \");\n if (typeof value === \"boolean\") return value ? \"Yes\" : \"No\";\n if (value instanceof Date) return value.toLocaleDateString();\n let str: string;\n if (typeof value === \"object\") {\n str = JSON.stringify(value);\n } else {\n // eslint-disable-next-line @typescript-eslint/no-base-to-string -- value narrowed to primitive above; rule doesn't follow control flow on unknown\n str = String(value);\n }\n return str.length > 50 ? str.slice(0, 50) + \"...\" : str;\n}\n\n/**\n * Format a date for display.\n */\nfunction formatDate(date: Date | string): string {\n const d = typeof date === \"string\" ? new Date(date) : date;\n return d.toLocaleString();\n}\n\n/**\n * Get status badge class name.\n */\nfunction getStatusBadgeClass(status: string): string {\n switch (status) {\n case \"new\":\n return \"submission-status-badge submission-status-badge--new\";\n case \"read\":\n return \"submission-status-badge submission-status-badge--read\";\n case \"archived\":\n return \"submission-status-badge submission-status-badge--archived\";\n default:\n return \"submission-status-badge\";\n }\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\n/**\n * Submission List Component\n *\n * Displays form submissions in a table with filtering, selection, and actions.\n *\n * @example\n * ```tsx\n * <SubmissionList\n * form={form}\n * submissions={submissions}\n * onStatusChange={handleStatusChange}\n * onDelete={handleDelete}\n * onExport={handleExport}\n * onViewDetail={handleViewDetail}\n * />\n * ```\n */\nexport function SubmissionList({\n form,\n submissions,\n isLoading = false,\n onStatusChange,\n onDelete,\n onBulkDelete,\n onBulkStatusChange,\n onExport,\n onViewDetail,\n}: SubmissionListProps): React.ReactElement {\n // -------------------------------------------------------------------------\n // State\n // -------------------------------------------------------------------------\n\n const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());\n const [filter, setFilter] = useState<StatusFilter>(\"all\");\n const [processingIds, setProcessingIds] = useState<Set<string>>(new Set());\n\n // -------------------------------------------------------------------------\n // Computed Values\n // -------------------------------------------------------------------------\n\n /** Get display columns from form fields (first 3 fields) */\n const displayFields = useMemo((): FormField[] => {\n return form.fields.filter(f => f.type !== \"hidden\").slice(0, 3);\n }, [form.fields]);\n\n /** Filter submissions by status */\n const filteredSubmissions = useMemo((): SubmissionDocument[] => {\n if (filter === \"all\") return submissions;\n return submissions.filter(sub => sub.status === filter);\n }, [submissions, filter]);\n\n /** Check if all visible submissions are selected */\n const allSelected =\n filteredSubmissions.length > 0 &&\n selectedIds.size === filteredSubmissions.length &&\n filteredSubmissions.every(s => selectedIds.has(s.id));\n\n /** Check if some submissions are selected */\n const someSelected = selectedIds.size > 0;\n\n // -------------------------------------------------------------------------\n // Handlers\n // -------------------------------------------------------------------------\n\n /** Toggle selection for a single submission */\n const toggleSelect = useCallback((id: string) => {\n setSelectedIds(prev => {\n const next = new Set(prev);\n if (next.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n return next;\n });\n }, []);\n\n /** Toggle selection for all visible submissions */\n const toggleSelectAll = useCallback(() => {\n if (allSelected) {\n setSelectedIds(new Set());\n } else {\n setSelectedIds(new Set(filteredSubmissions.map(s => s.id)));\n }\n }, [allSelected, filteredSubmissions]);\n\n /** Handle status change for a single submission */\n const handleStatusChange = useCallback(\n async (id: string, status: \"new\" | \"read\" | \"archived\") => {\n if (!onStatusChange) return;\n\n setProcessingIds(prev => new Set(prev).add(id));\n try {\n await onStatusChange(id, status);\n } finally {\n setProcessingIds(prev => {\n const next = new Set(prev);\n next.delete(id);\n return next;\n });\n }\n },\n [onStatusChange]\n );\n\n /** Handle delete for a single submission */\n const handleDelete = useCallback(\n async (id: string) => {\n if (!onDelete) return;\n if (!window.confirm(\"Are you sure you want to delete this submission?\")) {\n return;\n }\n\n setProcessingIds(prev => new Set(prev).add(id));\n try {\n await onDelete(id);\n setSelectedIds(prev => {\n const next = new Set(prev);\n next.delete(id);\n return next;\n });\n } finally {\n setProcessingIds(prev => {\n const next = new Set(prev);\n next.delete(id);\n return next;\n });\n }\n },\n [onDelete]\n );\n\n /** Handle bulk delete */\n const handleBulkDelete = useCallback(async () => {\n if (!onBulkDelete || selectedIds.size === 0) return;\n if (\n !window.confirm(\n `Are you sure you want to delete ${selectedIds.size} submission(s)?`\n )\n ) {\n return;\n }\n\n const ids = Array.from(selectedIds);\n ids.forEach(id => setProcessingIds(prev => new Set(prev).add(id)));\n\n try {\n await onBulkDelete(ids);\n setSelectedIds(new Set());\n } finally {\n setProcessingIds(new Set());\n }\n }, [onBulkDelete, selectedIds]);\n\n /** Handle bulk status change */\n const handleBulkStatusChange = useCallback(\n async (status: \"new\" | \"read\" | \"archived\") => {\n if (!onBulkStatusChange || selectedIds.size === 0) return;\n\n const ids = Array.from(selectedIds);\n ids.forEach(id => setProcessingIds(prev => new Set(prev).add(id)));\n\n try {\n await onBulkStatusChange(ids, status);\n setSelectedIds(new Set());\n } finally {\n setProcessingIds(new Set());\n }\n },\n [onBulkStatusChange, selectedIds]\n );\n\n /** Handle row click */\n const handleRowClick = useCallback(\n (submission: SubmissionDocument) => {\n onViewDetail?.(submission);\n },\n [onViewDetail]\n );\n\n // -------------------------------------------------------------------------\n // Render\n // -------------------------------------------------------------------------\n\n return (\n <div className=\"submission-list\">\n {/* Toolbar */}\n <div className=\"submission-list__toolbar\">\n <div className=\"submission-list__filters\">\n <select\n value={filter}\n onChange={e => setFilter(e.target.value as StatusFilter)}\n className=\"submission-list__filter-select\"\n aria-label=\"Filter by status\"\n >\n <option value=\"all\">All Submissions ({submissions.length})</option>\n <option value=\"new\">\n New ({submissions.filter(s => s.status === \"new\").length})\n </option>\n <option value=\"read\">\n Read ({submissions.filter(s => s.status === \"read\").length})\n </option>\n <option value=\"archived\">\n Archived (\n {submissions.filter(s => s.status === \"archived\").length})\n </option>\n </select>\n </div>\n\n <div className=\"submission-list__actions\">\n {/* Bulk Actions */}\n {someSelected && (\n <div className=\"submission-list__bulk-actions\">\n <span className=\"submission-list__selected-count\">\n {selectedIds.size} selected\n </span>\n {onBulkStatusChange && (\n <>\n <button\n type=\"button\"\n onClick={() => void handleBulkStatusChange(\"read\")}\n className=\"submission-list__action-btn\"\n >\n Mark Read\n </button>\n <button\n type=\"button\"\n onClick={() => void handleBulkStatusChange(\"archived\")}\n className=\"submission-list__action-btn\"\n >\n Archive\n </button>\n </>\n )}\n {onBulkDelete && (\n <button\n type=\"button\"\n onClick={() => void handleBulkDelete()}\n className=\"submission-list__action-btn submission-list__action-btn--danger\"\n >\n Delete\n </button>\n )}\n </div>\n )}\n\n {/* Export Actions */}\n {onExport && (\n <div className=\"submission-list__export-actions\">\n <button\n type=\"button\"\n onClick={() => onExport(\"csv\")}\n className=\"submission-list__export-btn\"\n >\n Export CSV\n </button>\n <button\n type=\"button\"\n onClick={() => onExport(\"json\")}\n className=\"submission-list__export-btn\"\n >\n Export JSON\n </button>\n </div>\n )}\n </div>\n </div>\n\n {/* Table */}\n <div className=\"submission-list__table-container\">\n <table className=\"submission-list__table\">\n <thead>\n <tr>\n <th className=\"submission-list__th submission-list__th--checkbox\">\n <input\n type=\"checkbox\"\n checked={allSelected}\n onChange={toggleSelectAll}\n aria-label=\"Select all submissions\"\n />\n </th>\n <th className=\"submission-list__th\">ID</th>\n <th className=\"submission-list__th\">Status</th>\n <th className=\"submission-list__th\">Submitted</th>\n {displayFields.map(field => (\n <th key={field.name} className=\"submission-list__th\">\n {field.label}\n </th>\n ))}\n <th className=\"submission-list__th submission-list__th--actions\">\n Actions\n </th>\n </tr>\n </thead>\n <tbody>\n {isLoading ? (\n <tr>\n <td\n colSpan={5 + displayFields.length}\n className=\"submission-list__loading\"\n >\n Loading submissions...\n </td>\n </tr>\n ) : filteredSubmissions.length === 0 ? (\n <tr>\n <td\n colSpan={5 + displayFields.length}\n className=\"submission-list__empty\"\n >\n No submissions found\n </td>\n </tr>\n ) : (\n filteredSubmissions.map(submission => {\n const isSelected = selectedIds.has(submission.id);\n const isProcessing = processingIds.has(submission.id);\n\n return (\n <tr\n key={submission.id}\n className={`submission-list__row ${\n isSelected ? \"submission-list__row--selected\" : \"\"\n } ${isProcessing ? \"submission-list__row--processing\" : \"\"}`}\n onClick={() => handleRowClick(submission)}\n style={{ cursor: onViewDetail ? \"pointer\" : \"default\" }}\n >\n <td\n className=\"submission-list__td submission-list__td--checkbox\"\n onClick={e => e.stopPropagation()}\n >\n <input\n type=\"checkbox\"\n checked={isSelected}\n onChange={() => toggleSelect(submission.id)}\n disabled={isProcessing}\n aria-label={`Select submission ${submission.id}`}\n />\n </td>\n <td className=\"submission-list__td submission-list__td--id\">\n <code>{submission.id.slice(0, 8)}...</code>\n </td>\n <td className=\"submission-list__td\">\n <span className={getStatusBadgeClass(submission.status)}>\n {submission.status}\n </span>\n </td>\n <td className=\"submission-list__td\">\n {formatDate(submission.submittedAt)}\n </td>\n {displayFields.map(field => (\n <td key={field.name} className=\"submission-list__td\">\n {formatValue(submission.data[field.name])}\n </td>\n ))}\n <td\n className=\"submission-list__td submission-list__td--actions\"\n onClick={e => e.stopPropagation()}\n >\n {onStatusChange && submission.status !== \"read\" && (\n <button\n type=\"button\"\n onClick={() =>\n void handleStatusChange(submission.id, \"read\")\n }\n disabled={isProcessing}\n className=\"submission-list__row-action\"\n title=\"Mark as read\"\n >\n Mark Read\n </button>\n )}\n {onStatusChange && submission.status !== \"archived\" && (\n <button\n type=\"button\"\n onClick={() =>\n void handleStatusChange(submission.id, \"archived\")\n }\n disabled={isProcessing}\n className=\"submission-list__row-action\"\n title=\"Archive\"\n >\n Archive\n </button>\n )}\n {onDelete && (\n <button\n type=\"button\"\n onClick={() => void handleDelete(submission.id)}\n disabled={isProcessing}\n className=\"submission-list__row-action submission-list__row-action--danger\"\n title=\"Delete\"\n >\n Delete\n </button>\n )}\n </td>\n </tr>\n );\n })\n )}\n </tbody>\n </table>\n </div>\n\n {/* Summary */}\n <div className=\"submission-list__summary\">\n Showing {filteredSubmissions.length} of {submissions.length} submissions\n </div>\n </div>\n );\n}\n","\"use client\";\n\n/**\n * Submission Detail Component\n *\n * Admin view for viewing and managing a single form submission.\n * Displays all submission data, metadata, and provides status management.\n *\n * @module components/submissions/SubmissionDetail\n * @since 0.1.0\n */\n\n\"use client\";\n\nimport type React from \"react\";\nimport { useState, useCallback } from \"react\";\n\nimport type { SubmissionDocument, FormDocument, FormField } from \"../../types\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Props for the SubmissionDetail component.\n */\nexport interface SubmissionDetailProps {\n /** Form document containing field definitions */\n form: FormDocument;\n\n /** Submission document to display */\n submission: SubmissionDocument;\n\n /** Callback when status is changed */\n onStatusChange?: (status: \"new\" | \"read\" | \"archived\") => Promise<void>;\n\n /** Callback when notes are updated */\n onNotesUpdate?: (notes: string) => Promise<void>;\n\n /** Callback when back button is clicked */\n onBack?: () => void;\n\n /** Callback when delete is triggered */\n onDelete?: () => Promise<void>;\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Stringify a value safely, falling back to JSON for plain objects so we\n * never render the default `[object Object]` representation.\n */\nfunction safeString(value: unknown): string {\n if (typeof value === \"object\" && value !== null) {\n return JSON.stringify(value);\n }\n return String(value);\n}\n\n/**\n * Format a value for display based on field type.\n */\nfunction formatFieldValue(value: unknown, field: FormField): string {\n if (value === null || value === undefined) return \"-\";\n\n switch (field.type) {\n case \"checkbox\":\n return value ? \"Yes\" : \"No\";\n\n case \"select\":\n if (Array.isArray(value)) {\n return value.join(\", \");\n }\n return safeString(value);\n\n case \"file\":\n if (Array.isArray(value)) {\n return value.map(v => safeString(v)).join(\", \");\n }\n return safeString(value);\n\n case \"date\":\n if (value instanceof Date) {\n return value.toLocaleDateString();\n }\n if (typeof value === \"string\") {\n return new Date(value).toLocaleDateString();\n }\n return safeString(value);\n\n case \"time\":\n return safeString(value);\n\n default:\n return safeString(value);\n }\n}\n\n/**\n * Format a date for display.\n */\nfunction formatDate(date: Date | string): string {\n const d = typeof date === \"string\" ? new Date(date) : date;\n return d.toLocaleString();\n}\n\n/**\n * Get status options.\n */\nconst STATUS_OPTIONS: Array<{\n value: \"new\" | \"read\" | \"archived\";\n label: string;\n}> = [\n { value: \"new\", label: \"New\" },\n { value: \"read\", label: \"Read\" },\n { value: \"archived\", label: \"Archived\" },\n];\n\n// ============================================================================\n// Component\n// ============================================================================\n\n/**\n * Submission Detail Component\n *\n * Displays full submission data with status management and notes.\n *\n * @example\n * ```tsx\n * <SubmissionDetail\n * form={form}\n * submission={submission}\n * onStatusChange={handleStatusChange}\n * onNotesUpdate={handleNotesUpdate}\n * onBack={handleBack}\n * />\n * ```\n */\nexport function SubmissionDetail({\n form,\n submission,\n onStatusChange,\n onNotesUpdate,\n onBack,\n onDelete,\n}: SubmissionDetailProps): React.ReactElement {\n // -------------------------------------------------------------------------\n // State\n // -------------------------------------------------------------------------\n\n const [isProcessing, setIsProcessing] = useState(false);\n const [notes, setNotes] = useState(\n (submission as unknown as { notes?: string }).notes || \"\"\n );\n const [notesModified, setNotesModified] = useState(false);\n\n // -------------------------------------------------------------------------\n // Handlers\n // -------------------------------------------------------------------------\n\n /** Handle status change */\n const handleStatusChange = useCallback(\n async (event: React.ChangeEvent<HTMLSelectElement>) => {\n if (!onStatusChange) return;\n\n const newStatus = event.target.value as \"new\" | \"read\" | \"archived\";\n setIsProcessing(true);\n\n try {\n await onStatusChange(newStatus);\n } finally {\n setIsProcessing(false);\n }\n },\n [onStatusChange]\n );\n\n /** Handle notes change */\n const handleNotesChange = useCallback(\n (event: React.ChangeEvent<HTMLTextAreaElement>) => {\n setNotes(event.target.value);\n setNotesModified(true);\n },\n []\n );\n\n /** Handle notes save */\n const handleNotesSave = useCallback(async () => {\n if (!onNotesUpdate || !notesModified) return;\n\n setIsProcessing(true);\n try {\n await onNotesUpdate(notes);\n setNotesModified(false);\n } finally {\n setIsProcessing(false);\n }\n }, [onNotesUpdate, notes, notesModified]);\n\n /** Handle delete */\n const handleDelete = useCallback(async () => {\n if (!onDelete) return;\n if (!window.confirm(\"Are you sure you want to delete this submission?\")) {\n return;\n }\n\n setIsProcessing(true);\n try {\n await onDelete();\n } finally {\n setIsProcessing(false);\n }\n }, [onDelete]);\n\n // -------------------------------------------------------------------------\n // Computed Values\n // -------------------------------------------------------------------------\n\n /** Get displayable fields */\n const displayFields = form.fields;\n\n /** Get submission data */\n const data = submission.data;\n\n // -------------------------------------------------------------------------\n // Render\n // -------------------------------------------------------------------------\n\n return (\n <div className=\"submission-detail\">\n {/* Header */}\n <div className=\"submission-detail__header\">\n <div className=\"submission-detail__header-left\">\n {onBack && (\n <button\n type=\"button\"\n onClick={onBack}\n className=\"submission-detail__back-btn\"\n disabled={isProcessing}\n >\n ← Back to List\n </button>\n )}\n <h2 className=\"submission-detail__title\">Submission Details</h2>\n </div>\n\n <div className=\"submission-detail__header-right\">\n {onStatusChange && (\n <div className=\"submission-detail__status-control\">\n <label htmlFor=\"submission-status\">Status:</label>\n <select\n id=\"submission-status\"\n value={submission.status}\n onChange={e => void handleStatusChange(e)}\n disabled={isProcessing}\n className=\"submission-detail__status-select\"\n >\n {STATUS_OPTIONS.map(option => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </div>\n )}\n\n {onDelete && (\n <button\n type=\"button\"\n onClick={() => void handleDelete()}\n disabled={isProcessing}\n className=\"submission-detail__delete-btn\"\n >\n Delete\n </button>\n )}\n </div>\n </div>\n\n {/* Submission ID */}\n <div className=\"submission-detail__id\">\n <span className=\"submission-detail__id-label\">Submission ID:</span>\n <code className=\"submission-detail__id-value\">{submission.id}</code>\n </div>\n\n {/* Form Fields Data */}\n <div className=\"submission-detail__section\">\n <h3 className=\"submission-detail__section-title\">Submitted Data</h3>\n <div className=\"submission-detail__fields\">\n {displayFields.map(field => (\n <div key={field.name} className=\"submission-detail__field\">\n <div className=\"submission-detail__field-label\">\n {field.label}\n </div>\n <div className=\"submission-detail__field-value\">\n {formatFieldValue(data[field.name], field)}\n </div>\n </div>\n ))}\n\n {displayFields.length === 0 && (\n <div className=\"submission-detail__empty\">No fields to display</div>\n )}\n </div>\n </div>\n\n {/* Notes Section */}\n {onNotesUpdate && (\n <div className=\"submission-detail__section\">\n <h3 className=\"submission-detail__section-title\">Internal Notes</h3>\n <div className=\"submission-detail__notes\">\n <textarea\n value={notes}\n onChange={handleNotesChange}\n placeholder=\"Add internal notes about this submission...\"\n disabled={isProcessing}\n className=\"submission-detail__notes-textarea\"\n rows={4}\n />\n {notesModified && (\n <button\n type=\"button\"\n onClick={() => void handleNotesSave()}\n disabled={isProcessing}\n className=\"submission-detail__notes-save-btn\"\n >\n Save Notes\n </button>\n )}\n </div>\n </div>\n )}\n\n {/* Metadata Section */}\n <div className=\"submission-detail__section\">\n <h3 className=\"submission-detail__section-title\">Metadata</h3>\n <div className=\"submission-detail__metadata\">\n <div className=\"submission-detail__metadata-item\">\n <span className=\"submission-detail__metadata-label\">\n Submitted At:\n </span>\n <span className=\"submission-detail__metadata-value\">\n {formatDate(submission.submittedAt)}\n </span>\n </div>\n\n {submission.ipAddress && (\n <div className=\"submission-detail__metadata-item\">\n <span className=\"submission-detail__metadata-label\">\n IP Address:\n </span>\n <span className=\"submission-detail__metadata-value\">\n <code>{submission.ipAddress}</code>\n </span>\n </div>\n )}\n\n {submission.userAgent && (\n <div className=\"submission-detail__metadata-item\">\n <span className=\"submission-detail__metadata-label\">\n User Agent:\n </span>\n <span className=\"submission-detail__metadata-value submission-detail__metadata-value--truncate\">\n {submission.userAgent}\n </span>\n </div>\n )}\n\n <div className=\"submission-detail__metadata-item\">\n <span className=\"submission-detail__metadata-label\">\n Created At:\n </span>\n <span className=\"submission-detail__metadata-value\">\n {formatDate(submission.createdAt)}\n </span>\n </div>\n\n <div className=\"submission-detail__metadata-item\">\n <span className=\"submission-detail__metadata-label\">\n Updated At:\n </span>\n <span className=\"submission-detail__metadata-value\">\n {formatDate(submission.updatedAt)}\n </span>\n </div>\n </div>\n </div>\n\n {/* Raw Data Section (Expandable) */}\n <details className=\"submission-detail__raw-data\">\n <summary className=\"submission-detail__raw-data-summary\">\n View Raw JSON Data\n </summary>\n <pre className=\"submission-detail__raw-data-content\">\n {JSON.stringify(submission.data, null, 2)}\n </pre>\n </details>\n </div>\n );\n}\n"],"mappings":"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","names":["useState","useCallback","jsx","jsxs","formatDate"]}
|