@nextlyhq/plugin-form-builder 0.0.2-alpha.4 → 0.0.2-alpha.41

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.
Files changed (38) hide show
  1. package/README.md +4 -5
  2. package/dist/admin/index.d.ts +123 -331
  3. package/dist/admin/index.js +3809 -3419
  4. package/dist/admin/index.js.map +1 -1
  5. package/dist/chunk-WVI7N3QO.js +559 -0
  6. package/dist/chunk-WVI7N3QO.js.map +1 -0
  7. package/dist/index.d.ts +12 -11
  8. package/dist/index.js +555 -661
  9. package/dist/index.js.map +1 -1
  10. package/dist/{index-C0kBvYjm.d.ts → types-r8uBeB0u.d.ts} +126 -125
  11. package/package.json +28 -30
  12. package/dist/CheckboxFieldEditor-K4T6QX52.js +0 -121
  13. package/dist/CheckboxFieldEditor-K4T6QX52.js.map +0 -1
  14. package/dist/DateFieldEditor-JFJFAVOH.js +0 -187
  15. package/dist/DateFieldEditor-JFJFAVOH.js.map +0 -1
  16. package/dist/EmailFieldEditor-MMOXXL7P.js +0 -138
  17. package/dist/EmailFieldEditor-MMOXXL7P.js.map +0 -1
  18. package/dist/NumberFieldEditor-UISAYR6Z.js +0 -175
  19. package/dist/NumberFieldEditor-UISAYR6Z.js.map +0 -1
  20. package/dist/RadioFieldEditor-6UQFH4WT.js +0 -165
  21. package/dist/RadioFieldEditor-6UQFH4WT.js.map +0 -1
  22. package/dist/SelectFieldEditor-PSO4KHV4.js +0 -213
  23. package/dist/SelectFieldEditor-PSO4KHV4.js.map +0 -1
  24. package/dist/TextFieldEditor-5EU64EA5.js +0 -187
  25. package/dist/TextFieldEditor-5EU64EA5.js.map +0 -1
  26. package/dist/TextareaFieldEditor-773G3LNM.js +0 -190
  27. package/dist/TextareaFieldEditor-773G3LNM.js.map +0 -1
  28. package/dist/admin/index.css +0 -934
  29. package/dist/admin/index.css.map +0 -1
  30. package/dist/chunk-ABNZFTQK.js +0 -586
  31. package/dist/chunk-ABNZFTQK.js.map +0 -1
  32. package/dist/chunk-XTCEPJ7B.js +0 -256
  33. package/dist/chunk-XTCEPJ7B.js.map +0 -1
  34. package/dist/components/index.d.ts +0 -3
  35. package/dist/components/index.js +0 -9
  36. package/dist/components/index.js.map +0 -1
  37. package/dist/styles/form-builder.css +0 -1150
  38. package/dist/styles/submissions-filter.css +0 -75
@@ -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 &larr; 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"]}
@@ -1,256 +0,0 @@
1
- // src/admin/fields/OptionsEditor.tsx
2
- import {
3
- DndContext,
4
- closestCenter,
5
- KeyboardSensor,
6
- PointerSensor,
7
- useSensor,
8
- useSensors
9
- } from "@dnd-kit/core";
10
- import {
11
- arrayMove,
12
- SortableContext,
13
- sortableKeyboardCoordinates,
14
- useSortable,
15
- verticalListSortingStrategy
16
- } from "@dnd-kit/sortable";
17
- import { CSS } from "@dnd-kit/utilities";
18
- import { Input } from "@nextlyhq/ui";
19
- import { GripVertical, Plus, Trash2 } from "lucide-react";
20
- import { useCallback } from "react";
21
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
22
- function generateValueFromLabel(label) {
23
- return label.toLowerCase().trim().replace(/\s+/g, "_").replace(/[^a-z0-9_]/g, "");
24
- }
25
- function addIdsToOptions(options) {
26
- return options.map((opt, index) => ({
27
- ...opt,
28
- id: `opt_${index}_${opt.value}`
29
- }));
30
- }
31
- function removeIdsFromOptions(options) {
32
- return options.map(({ label, value }) => ({ label, value }));
33
- }
34
- function SortableOption({
35
- option,
36
- index,
37
- onLabelChange,
38
- onValueChange,
39
- onDelete,
40
- disabled
41
- }) {
42
- const {
43
- attributes,
44
- listeners,
45
- setNodeRef,
46
- transform,
47
- transition,
48
- isDragging
49
- } = useSortable({ id: option.id });
50
- const style = {
51
- transform: CSS.Transform.toString(transform),
52
- transition,
53
- opacity: isDragging ? 0.5 : 1
54
- };
55
- return /* @__PURE__ */ jsxs(
56
- "div",
57
- {
58
- ref: setNodeRef,
59
- style,
60
- className: `options-editor__option ${isDragging ? "options-editor__option--dragging" : ""}`,
61
- children: [
62
- /* @__PURE__ */ jsx(
63
- "button",
64
- {
65
- type: "button",
66
- className: "options-editor__drag-handle",
67
- disabled,
68
- "aria-label": `Drag to reorder option ${index + 1}`,
69
- ...attributes,
70
- ...listeners,
71
- children: /* @__PURE__ */ jsx(GripVertical, { className: "options-editor__drag-icon" })
72
- }
73
- ),
74
- /* @__PURE__ */ jsx("div", { className: "options-editor__input-group", children: /* @__PURE__ */ jsx(
75
- Input,
76
- {
77
- type: "text",
78
- value: option.label,
79
- onChange: (e) => onLabelChange(option.id, e.target.value),
80
- placeholder: "Label",
81
- disabled,
82
- className: "options-editor__input"
83
- }
84
- ) }),
85
- /* @__PURE__ */ jsx("div", { className: "options-editor__input-group", children: /* @__PURE__ */ jsx(
86
- Input,
87
- {
88
- type: "text",
89
- value: option.value,
90
- onChange: (e) => onValueChange(option.id, e.target.value),
91
- placeholder: "value",
92
- disabled,
93
- className: "options-editor__input options-editor__input--mono"
94
- }
95
- ) }),
96
- /* @__PURE__ */ jsx(
97
- "button",
98
- {
99
- type: "button",
100
- className: "options-editor__delete-btn",
101
- onClick: () => onDelete(option.id),
102
- disabled,
103
- "aria-label": `Delete option ${option.label || index + 1}`,
104
- children: /* @__PURE__ */ jsx(Trash2, { className: "options-editor__delete-icon" })
105
- }
106
- )
107
- ]
108
- }
109
- );
110
- }
111
- function OptionsEditor({
112
- options,
113
- onOptionsChange,
114
- disabled = false
115
- }) {
116
- const optionsWithIds = addIdsToOptions(options);
117
- const sensors = useSensors(
118
- useSensor(PointerSensor, {
119
- activationConstraint: {
120
- distance: 8
121
- }
122
- }),
123
- useSensor(KeyboardSensor, {
124
- coordinateGetter: sortableKeyboardCoordinates
125
- })
126
- );
127
- const handleAddOption = useCallback(() => {
128
- const newIndex = options.length + 1;
129
- const newOption = {
130
- label: `Option ${newIndex}`,
131
- value: `option_${newIndex}`
132
- };
133
- onOptionsChange([...options, newOption]);
134
- }, [options, onOptionsChange]);
135
- const handleLabelChange = useCallback(
136
- (id, newLabel) => {
137
- const updatedOptions = optionsWithIds.map((opt) => {
138
- if (opt.id !== id) return opt;
139
- const previousAutoValue = generateValueFromLabel(opt.label);
140
- const shouldAutoGenerate = !opt.value || opt.value === previousAutoValue;
141
- return {
142
- ...opt,
143
- label: newLabel,
144
- value: shouldAutoGenerate ? generateValueFromLabel(newLabel) : opt.value
145
- };
146
- });
147
- onOptionsChange(removeIdsFromOptions(updatedOptions));
148
- },
149
- [optionsWithIds, onOptionsChange]
150
- );
151
- const handleValueChange = useCallback(
152
- (id, newValue) => {
153
- const updatedOptions = optionsWithIds.map(
154
- (opt) => opt.id === id ? { ...opt, value: newValue } : opt
155
- );
156
- onOptionsChange(removeIdsFromOptions(updatedOptions));
157
- },
158
- [optionsWithIds, onOptionsChange]
159
- );
160
- const handleDeleteOption = useCallback(
161
- (id) => {
162
- const updatedOptions = optionsWithIds.filter((opt) => opt.id !== id);
163
- onOptionsChange(removeIdsFromOptions(updatedOptions));
164
- },
165
- [optionsWithIds, onOptionsChange]
166
- );
167
- const handleDragEnd = useCallback(
168
- (event) => {
169
- const { active, over } = event;
170
- if (over && active.id !== over.id) {
171
- const oldIndex = optionsWithIds.findIndex((opt) => opt.id === active.id);
172
- const newIndex = optionsWithIds.findIndex((opt) => opt.id === over.id);
173
- const reorderedOptions = arrayMove(optionsWithIds, oldIndex, newIndex);
174
- onOptionsChange(removeIdsFromOptions(reorderedOptions));
175
- }
176
- },
177
- [optionsWithIds, onOptionsChange]
178
- );
179
- return /* @__PURE__ */ jsxs("div", { className: "options-editor", children: [
180
- /* @__PURE__ */ jsxs("div", { className: "options-editor__header", children: [
181
- /* @__PURE__ */ jsx("label", { className: "options-editor__label", children: "Options" }),
182
- /* @__PURE__ */ jsxs(
183
- "button",
184
- {
185
- type: "button",
186
- className: "options-editor__add-btn",
187
- onClick: handleAddOption,
188
- disabled,
189
- children: [
190
- /* @__PURE__ */ jsx(Plus, { className: "options-editor__add-icon" }),
191
- "Add Option"
192
- ]
193
- }
194
- )
195
- ] }),
196
- options.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
197
- /* @__PURE__ */ jsxs("div", { className: "options-editor__column-headers", children: [
198
- /* @__PURE__ */ jsx("div", { className: "options-editor__column-spacer" }),
199
- /* @__PURE__ */ jsx("div", { className: "options-editor__column-label", children: "Label (displayed)" }),
200
- /* @__PURE__ */ jsx("div", { className: "options-editor__column-label", children: "Value (stored)" }),
201
- /* @__PURE__ */ jsx("div", { className: "options-editor__column-spacer" })
202
- ] }),
203
- /* @__PURE__ */ jsx(
204
- DndContext,
205
- {
206
- sensors,
207
- collisionDetection: closestCenter,
208
- onDragEnd: handleDragEnd,
209
- children: /* @__PURE__ */ jsx(
210
- SortableContext,
211
- {
212
- items: optionsWithIds.map((opt) => opt.id),
213
- strategy: verticalListSortingStrategy,
214
- children: /* @__PURE__ */ jsx("div", { className: "options-editor__list", children: optionsWithIds.map((option, index) => /* @__PURE__ */ jsx(
215
- SortableOption,
216
- {
217
- option,
218
- index,
219
- onLabelChange: handleLabelChange,
220
- onValueChange: handleValueChange,
221
- onDelete: handleDeleteOption,
222
- disabled
223
- },
224
- option.id
225
- )) })
226
- }
227
- )
228
- }
229
- )
230
- ] }) : (
231
- /* Empty State */
232
- /* @__PURE__ */ jsxs("div", { className: "options-editor__empty", children: [
233
- /* @__PURE__ */ jsx("p", { className: "options-editor__empty-text", children: "No options defined" }),
234
- /* @__PURE__ */ jsxs(
235
- "button",
236
- {
237
- type: "button",
238
- className: "options-editor__add-first-btn",
239
- onClick: handleAddOption,
240
- disabled,
241
- children: [
242
- /* @__PURE__ */ jsx(Plus, { className: "options-editor__add-icon" }),
243
- "Add first option"
244
- ]
245
- }
246
- )
247
- ] })
248
- ),
249
- /* @__PURE__ */ jsx("p", { className: "options-editor__hint", children: "Drag options to reorder. Value is auto-generated from label." })
250
- ] });
251
- }
252
-
253
- export {
254
- OptionsEditor
255
- };
256
- //# sourceMappingURL=chunk-XTCEPJ7B.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/admin/fields/OptionsEditor.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * Options Editor Component\n *\n * Shared component for editing options arrays in Select and Radio fields.\n * Features:\n * - Add/edit/remove options\n * - Drag-and-drop reordering with @dnd-kit\n * - Auto-generate value from label\n *\n * @module admin/fields/OptionsEditor\n * @since 0.1.0\n */\n\n\"use client\";\n\nimport {\n DndContext,\n closestCenter,\n KeyboardSensor,\n PointerSensor,\n useSensor,\n useSensors,\n type DragEndEvent,\n} from \"@dnd-kit/core\";\nimport {\n arrayMove,\n SortableContext,\n sortableKeyboardCoordinates,\n useSortable,\n verticalListSortingStrategy,\n} from \"@dnd-kit/sortable\";\nimport { CSS } from \"@dnd-kit/utilities\";\nimport { Input } from \"@nextlyhq/ui\";\nimport { GripVertical, Plus, Trash2 } from \"lucide-react\";\nimport { useCallback } from \"react\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Option interface for Select/Radio fields */\nexport interface FieldOption {\n label: string;\n value: string;\n}\n\n/** Internal option with ID for drag-and-drop */\ninterface OptionWithId extends FieldOption {\n id: string;\n}\n\nexport interface OptionsEditorProps {\n /** Current options array */\n options: FieldOption[];\n /** Callback when options change */\n onOptionsChange: (options: FieldOption[]) => void;\n /** Disable editing */\n disabled?: boolean;\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Generate a value from a label (snake_case format)\n */\nfunction generateValueFromLabel(label: string): string {\n return label\n .toLowerCase()\n .trim()\n .replace(/\\s+/g, \"_\")\n .replace(/[^a-z0-9_]/g, \"\");\n}\n\n/**\n * Add IDs to options for DnD tracking\n */\nfunction addIdsToOptions(options: FieldOption[]): OptionWithId[] {\n return options.map((opt, index) => ({\n ...opt,\n id: `opt_${index}_${opt.value}`,\n }));\n}\n\n/**\n * Remove IDs from options when saving\n */\nfunction removeIdsFromOptions(options: OptionWithId[]): FieldOption[] {\n return options.map(({ label, value }) => ({ label, value }));\n}\n\n// ============================================================================\n// SortableOption Component\n// ============================================================================\n\ninterface SortableOptionProps {\n option: OptionWithId;\n index: number;\n onLabelChange: (id: string, label: string) => void;\n onValueChange: (id: string, value: string) => void;\n onDelete: (id: string) => void;\n disabled?: boolean;\n}\n\nfunction SortableOption({\n option,\n index,\n onLabelChange,\n onValueChange,\n onDelete,\n disabled,\n}: SortableOptionProps) {\n const {\n attributes,\n listeners,\n setNodeRef,\n transform,\n transition,\n isDragging,\n } = useSortable({ id: option.id });\n\n const style = {\n transform: CSS.Transform.toString(transform),\n transition,\n opacity: isDragging ? 0.5 : 1,\n };\n\n return (\n <div\n ref={setNodeRef}\n style={style}\n className={`options-editor__option ${isDragging ? \"options-editor__option--dragging\" : \"\"}`}\n >\n {/* Drag Handle */}\n <button\n type=\"button\"\n className=\"options-editor__drag-handle\"\n disabled={disabled}\n aria-label={`Drag to reorder option ${index + 1}`}\n {...attributes}\n {...listeners}\n >\n <GripVertical className=\"options-editor__drag-icon\" />\n </button>\n\n {/* Label Input */}\n <div className=\"options-editor__input-group\">\n <Input\n type=\"text\"\n value={option.label}\n onChange={e => onLabelChange(option.id, e.target.value)}\n placeholder=\"Label\"\n disabled={disabled}\n className=\"options-editor__input\"\n />\n </div>\n\n {/* Value Input */}\n <div className=\"options-editor__input-group\">\n <Input\n type=\"text\"\n value={option.value}\n onChange={e => onValueChange(option.id, e.target.value)}\n placeholder=\"value\"\n disabled={disabled}\n className=\"options-editor__input options-editor__input--mono\"\n />\n </div>\n\n {/* Delete Button */}\n <button\n type=\"button\"\n className=\"options-editor__delete-btn\"\n onClick={() => onDelete(option.id)}\n disabled={disabled}\n aria-label={`Delete option ${option.label || index + 1}`}\n >\n <Trash2 className=\"options-editor__delete-icon\" />\n </button>\n </div>\n );\n}\n\n// ============================================================================\n// Main Component\n// ============================================================================\n\n/**\n * OptionsEditor - Manage options for Select/Radio fields\n *\n * Provides a list of editable options with:\n * - Drag-and-drop reordering\n * - Add/remove options\n * - Auto-generate value from label\n *\n * @example\n * ```tsx\n * <OptionsEditor\n * options={field.options}\n * onOptionsChange={(options) => onUpdate({ options })}\n * />\n * ```\n */\nexport function OptionsEditor({\n options,\n onOptionsChange,\n disabled = false,\n}: OptionsEditorProps) {\n // Convert options to internal format with IDs for DnD\n const optionsWithIds = addIdsToOptions(options);\n\n // DnD sensors with activation distance to prevent accidental drags\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: {\n distance: 8,\n },\n }),\n useSensor(KeyboardSensor, {\n coordinateGetter: sortableKeyboardCoordinates,\n })\n );\n\n // Add a new option\n const handleAddOption = useCallback(() => {\n const newIndex = options.length + 1;\n const newOption: FieldOption = {\n label: `Option ${newIndex}`,\n value: `option_${newIndex}`,\n };\n onOptionsChange([...options, newOption]);\n }, [options, onOptionsChange]);\n\n // Handle label change with auto-generate value\n const handleLabelChange = useCallback(\n (id: string, newLabel: string) => {\n const updatedOptions = optionsWithIds.map(opt => {\n if (opt.id !== id) return opt;\n\n // Auto-generate value if it matches the old auto-generated value or is empty\n const previousAutoValue = generateValueFromLabel(opt.label);\n const shouldAutoGenerate =\n !opt.value || opt.value === previousAutoValue;\n\n return {\n ...opt,\n label: newLabel,\n value: shouldAutoGenerate\n ? generateValueFromLabel(newLabel)\n : opt.value,\n };\n });\n\n onOptionsChange(removeIdsFromOptions(updatedOptions));\n },\n [optionsWithIds, onOptionsChange]\n );\n\n // Handle value change (manual override)\n const handleValueChange = useCallback(\n (id: string, newValue: string) => {\n const updatedOptions = optionsWithIds.map(opt =>\n opt.id === id ? { ...opt, value: newValue } : opt\n );\n onOptionsChange(removeIdsFromOptions(updatedOptions));\n },\n [optionsWithIds, onOptionsChange]\n );\n\n // Delete an option\n const handleDeleteOption = useCallback(\n (id: string) => {\n const updatedOptions = optionsWithIds.filter(opt => opt.id !== id);\n onOptionsChange(removeIdsFromOptions(updatedOptions));\n },\n [optionsWithIds, onOptionsChange]\n );\n\n // Handle drag end for reordering\n const handleDragEnd = useCallback(\n (event: DragEndEvent) => {\n const { active, over } = event;\n\n if (over && active.id !== over.id) {\n const oldIndex = optionsWithIds.findIndex(opt => opt.id === active.id);\n const newIndex = optionsWithIds.findIndex(opt => opt.id === over.id);\n const reorderedOptions = arrayMove(optionsWithIds, oldIndex, newIndex);\n onOptionsChange(removeIdsFromOptions(reorderedOptions));\n }\n },\n [optionsWithIds, onOptionsChange]\n );\n\n return (\n <div className=\"options-editor\">\n {/* Header */}\n <div className=\"options-editor__header\">\n <label className=\"options-editor__label\">Options</label>\n <button\n type=\"button\"\n className=\"options-editor__add-btn\"\n onClick={handleAddOption}\n disabled={disabled}\n >\n <Plus className=\"options-editor__add-icon\" />\n Add Option\n </button>\n </div>\n\n {/* Options List */}\n {options.length > 0 ? (\n <>\n {/* Column Headers */}\n <div className=\"options-editor__column-headers\">\n <div className=\"options-editor__column-spacer\" />\n <div className=\"options-editor__column-label\">\n Label (displayed)\n </div>\n <div className=\"options-editor__column-label\">Value (stored)</div>\n <div className=\"options-editor__column-spacer\" />\n </div>\n\n {/* Sortable List */}\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n onDragEnd={handleDragEnd}\n >\n <SortableContext\n items={optionsWithIds.map(opt => opt.id)}\n strategy={verticalListSortingStrategy}\n >\n <div className=\"options-editor__list\">\n {optionsWithIds.map((option, index) => (\n <SortableOption\n key={option.id}\n option={option}\n index={index}\n onLabelChange={handleLabelChange}\n onValueChange={handleValueChange}\n onDelete={handleDeleteOption}\n disabled={disabled}\n />\n ))}\n </div>\n </SortableContext>\n </DndContext>\n </>\n ) : (\n /* Empty State */\n <div className=\"options-editor__empty\">\n <p className=\"options-editor__empty-text\">No options defined</p>\n <button\n type=\"button\"\n className=\"options-editor__add-first-btn\"\n onClick={handleAddOption}\n disabled={disabled}\n >\n <Plus className=\"options-editor__add-icon\" />\n Add first option\n </button>\n </div>\n )}\n\n {/* Help Text */}\n <p className=\"options-editor__hint\">\n Drag options to reorder. Value is auto-generated from label.\n </p>\n </div>\n );\n}\n\nexport default OptionsEditor;\n"],"mappings":";AAiBA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,WAAW;AACpB,SAAS,aAAa;AACtB,SAAS,cAAc,MAAM,cAAc;AAC3C,SAAS,mBAAmB;AA+FxB,SAuLI,UAzKA,KAdJ;AA9DJ,SAAS,uBAAuB,OAAuB;AACrD,SAAO,MACJ,YAAY,EACZ,KAAK,EACL,QAAQ,QAAQ,GAAG,EACnB,QAAQ,eAAe,EAAE;AAC9B;AAKA,SAAS,gBAAgB,SAAwC;AAC/D,SAAO,QAAQ,IAAI,CAAC,KAAK,WAAW;AAAA,IAClC,GAAG;AAAA,IACH,IAAI,OAAO,KAAK,IAAI,IAAI,KAAK;AAAA,EAC/B,EAAE;AACJ;AAKA,SAAS,qBAAqB,SAAwC;AACpE,SAAO,QAAQ,IAAI,CAAC,EAAE,OAAO,MAAM,OAAO,EAAE,OAAO,MAAM,EAAE;AAC7D;AAeA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAwB;AACtB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,YAAY,EAAE,IAAI,OAAO,GAAG,CAAC;AAEjC,QAAM,QAAQ;AAAA,IACZ,WAAW,IAAI,UAAU,SAAS,SAAS;AAAA,IAC3C;AAAA,IACA,SAAS,aAAa,MAAM;AAAA,EAC9B;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL;AAAA,MACA,WAAW,0BAA0B,aAAa,qCAAqC,EAAE;AAAA,MAGzF;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAU;AAAA,YACV;AAAA,YACA,cAAY,0BAA0B,QAAQ,CAAC;AAAA,YAC9C,GAAG;AAAA,YACH,GAAG;AAAA,YAEJ,8BAAC,gBAAa,WAAU,6BAA4B;AAAA;AAAA,QACtD;AAAA,QAGA,oBAAC,SAAI,WAAU,+BACb;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,OAAO,OAAO;AAAA,YACd,UAAU,OAAK,cAAc,OAAO,IAAI,EAAE,OAAO,KAAK;AAAA,YACtD,aAAY;AAAA,YACZ;AAAA,YACA,WAAU;AAAA;AAAA,QACZ,GACF;AAAA,QAGA,oBAAC,SAAI,WAAU,+BACb;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,OAAO,OAAO;AAAA,YACd,UAAU,OAAK,cAAc,OAAO,IAAI,EAAE,OAAO,KAAK;AAAA,YACtD,aAAY;AAAA,YACZ;AAAA,YACA,WAAU;AAAA;AAAA,QACZ,GACF;AAAA,QAGA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAU;AAAA,YACV,SAAS,MAAM,SAAS,OAAO,EAAE;AAAA,YACjC;AAAA,YACA,cAAY,iBAAiB,OAAO,SAAS,QAAQ,CAAC;AAAA,YAEtD,8BAAC,UAAO,WAAU,+BAA8B;AAAA;AAAA,QAClD;AAAA;AAAA;AAAA,EACF;AAEJ;AAsBO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,WAAW;AACb,GAAuB;AAErB,QAAM,iBAAiB,gBAAgB,OAAO;AAG9C,QAAM,UAAU;AAAA,IACd,UAAU,eAAe;AAAA,MACvB,sBAAsB;AAAA,QACpB,UAAU;AAAA,MACZ;AAAA,IACF,CAAC;AAAA,IACD,UAAU,gBAAgB;AAAA,MACxB,kBAAkB;AAAA,IACpB,CAAC;AAAA,EACH;AAGA,QAAM,kBAAkB,YAAY,MAAM;AACxC,UAAM,WAAW,QAAQ,SAAS;AAClC,UAAM,YAAyB;AAAA,MAC7B,OAAO,UAAU,QAAQ;AAAA,MACzB,OAAO,UAAU,QAAQ;AAAA,IAC3B;AACA,oBAAgB,CAAC,GAAG,SAAS,SAAS,CAAC;AAAA,EACzC,GAAG,CAAC,SAAS,eAAe,CAAC;AAG7B,QAAM,oBAAoB;AAAA,IACxB,CAAC,IAAY,aAAqB;AAChC,YAAM,iBAAiB,eAAe,IAAI,SAAO;AAC/C,YAAI,IAAI,OAAO,GAAI,QAAO;AAG1B,cAAM,oBAAoB,uBAAuB,IAAI,KAAK;AAC1D,cAAM,qBACJ,CAAC,IAAI,SAAS,IAAI,UAAU;AAE9B,eAAO;AAAA,UACL,GAAG;AAAA,UACH,OAAO;AAAA,UACP,OAAO,qBACH,uBAAuB,QAAQ,IAC/B,IAAI;AAAA,QACV;AAAA,MACF,CAAC;AAED,sBAAgB,qBAAqB,cAAc,CAAC;AAAA,IACtD;AAAA,IACA,CAAC,gBAAgB,eAAe;AAAA,EAClC;AAGA,QAAM,oBAAoB;AAAA,IACxB,CAAC,IAAY,aAAqB;AAChC,YAAM,iBAAiB,eAAe;AAAA,QAAI,SACxC,IAAI,OAAO,KAAK,EAAE,GAAG,KAAK,OAAO,SAAS,IAAI;AAAA,MAChD;AACA,sBAAgB,qBAAqB,cAAc,CAAC;AAAA,IACtD;AAAA,IACA,CAAC,gBAAgB,eAAe;AAAA,EAClC;AAGA,QAAM,qBAAqB;AAAA,IACzB,CAAC,OAAe;AACd,YAAM,iBAAiB,eAAe,OAAO,SAAO,IAAI,OAAO,EAAE;AACjE,sBAAgB,qBAAqB,cAAc,CAAC;AAAA,IACtD;AAAA,IACA,CAAC,gBAAgB,eAAe;AAAA,EAClC;AAGA,QAAM,gBAAgB;AAAA,IACpB,CAAC,UAAwB;AACvB,YAAM,EAAE,QAAQ,KAAK,IAAI;AAEzB,UAAI,QAAQ,OAAO,OAAO,KAAK,IAAI;AACjC,cAAM,WAAW,eAAe,UAAU,SAAO,IAAI,OAAO,OAAO,EAAE;AACrE,cAAM,WAAW,eAAe,UAAU,SAAO,IAAI,OAAO,KAAK,EAAE;AACnE,cAAM,mBAAmB,UAAU,gBAAgB,UAAU,QAAQ;AACrE,wBAAgB,qBAAqB,gBAAgB,CAAC;AAAA,MACxD;AAAA,IACF;AAAA,IACA,CAAC,gBAAgB,eAAe;AAAA,EAClC;AAEA,SACE,qBAAC,SAAI,WAAU,kBAEb;AAAA,yBAAC,SAAI,WAAU,0BACb;AAAA,0BAAC,WAAM,WAAU,yBAAwB,qBAAO;AAAA,MAChD;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAU;AAAA,UACV,SAAS;AAAA,UACT;AAAA,UAEA;AAAA,gCAAC,QAAK,WAAU,4BAA2B;AAAA,YAAE;AAAA;AAAA;AAAA,MAE/C;AAAA,OACF;AAAA,IAGC,QAAQ,SAAS,IAChB,iCAEE;AAAA,2BAAC,SAAI,WAAU,kCACb;AAAA,4BAAC,SAAI,WAAU,iCAAgC;AAAA,QAC/C,oBAAC,SAAI,WAAU,gCAA+B,+BAE9C;AAAA,QACA,oBAAC,SAAI,WAAU,gCAA+B,4BAAc;AAAA,QAC5D,oBAAC,SAAI,WAAU,iCAAgC;AAAA,SACjD;AAAA,MAGA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,oBAAoB;AAAA,UACpB,WAAW;AAAA,UAEX;AAAA,YAAC;AAAA;AAAA,cACC,OAAO,eAAe,IAAI,SAAO,IAAI,EAAE;AAAA,cACvC,UAAU;AAAA,cAEV,8BAAC,SAAI,WAAU,wBACZ,yBAAe,IAAI,CAAC,QAAQ,UAC3B;AAAA,gBAAC;AAAA;AAAA,kBAEC;AAAA,kBACA;AAAA,kBACA,eAAe;AAAA,kBACf,eAAe;AAAA,kBACf,UAAU;AAAA,kBACV;AAAA;AAAA,gBANK,OAAO;AAAA,cAOd,CACD,GACH;AAAA;AAAA,UACF;AAAA;AAAA,MACF;AAAA,OACF;AAAA;AAAA,MAGA,qBAAC,SAAI,WAAU,yBACb;AAAA,4BAAC,OAAE,WAAU,8BAA6B,gCAAkB;AAAA,QAC5D;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAU;AAAA,YACV,SAAS;AAAA,YACT;AAAA,YAEA;AAAA,kCAAC,QAAK,WAAU,4BAA2B;AAAA,cAAE;AAAA;AAAA;AAAA,QAE/C;AAAA,SACF;AAAA;AAAA,IAIF,oBAAC,OAAE,WAAU,wBAAuB,0EAEpC;AAAA,KACF;AAEJ;","names":[]}
@@ -1,3 +0,0 @@
1
- export { J as SubmissionDetail, t as SubmissionDetailProps, K as SubmissionList, u as SubmissionListProps } from '../index-C0kBvYjm.js';
2
- import 'react';
3
- import 'nextly';
@@ -1,9 +0,0 @@
1
- import {
2
- SubmissionDetail,
3
- SubmissionList
4
- } from "../chunk-ABNZFTQK.js";
5
- export {
6
- SubmissionDetail,
7
- SubmissionList
8
- };
9
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}