@realtek/core-theme-live 0.0.440 → 0.0.444
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/README.md +82 -82
- package/dist-lib/DocumentViewer-DE0kSU2d.cjs.map +1 -1
- package/dist-lib/DocumentViewer-DcgKxqov.js.map +1 -1
- package/dist-lib/{LinkedRecordFileField-DTu-0e5x.js → LinkedRecordFileField-BD3KkJt_.js} +99 -62
- package/dist-lib/LinkedRecordFileField-BD3KkJt_.js.map +1 -0
- package/dist-lib/LinkedRecordFileField-Bl-KLNrJ.cjs +5 -0
- package/dist-lib/LinkedRecordFileField-Bl-KLNrJ.cjs.map +1 -0
- package/dist-lib/addFormApi-DBeQrNX1.js.map +1 -1
- package/dist-lib/addFormApi-DLfsOijp.cjs.map +1 -1
- package/dist-lib/authApi-DiRtkJl2.cjs.map +1 -1
- package/dist-lib/authApi-Dsc4NnFr.js.map +1 -1
- package/dist-lib/diceCandidateMapper-BjMhHno3.cjs.map +1 -1
- package/dist-lib/diceCandidateMapper-DqBO4EhL.js.map +1 -1
- package/dist-lib/formGroupsCache-Bbz-28ws.cjs.map +1 -1
- package/dist-lib/formGroupsCache-JeC59oNe.js.map +1 -1
- package/dist-lib/index.cjs +7 -7
- package/dist-lib/index.cjs.map +1 -1
- package/dist-lib/index.js +4083 -3989
- package/dist-lib/index.js.map +1 -1
- package/package.json +124 -124
- package/dist-lib/LinkedRecordFileField-DGakZSbb.cjs +0 -5
- package/dist-lib/LinkedRecordFileField-DGakZSbb.cjs.map +0 -1
- package/dist-lib/LinkedRecordFileField-DTu-0e5x.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocumentViewer-DcgKxqov.js","names":[],"sources":["../src/services/documentContentApi.js","../src/components/DocumentViewer.jsx"],"sourcesContent":["import { ensureToken } from './authApi';\r\nimport { AUTH_URL } from './apiConfig';\r\n\r\n// ── Authenticated document content ──────────────────────────────────────────\r\n//\r\n// WHY THIS EXISTS\r\n//\r\n// Documents live in a PRIVATE S3 bucket. The app was building a raw URL from\r\n// the stored object key:\r\n//\r\n// s3BaseUrl + \"candidate/resume/resume_<id>_<ts>.pdf\"\r\n//\r\n// That URL carries no signature, so S3 correctly answers 403 and no resume\r\n// could be opened. Making the bucket public is not an option.\r\n//\r\n// A presigned URL is necessary but NOT sufficient: react-pdf and docx-preview\r\n// fetch the bytes themselves, and the bucket's CORS policy does not allowlist\r\n// our origins, so the fetch is blocked even with a valid signature. The\r\n// backend therefore streams the bytes through our own origin, and we turn them\r\n// into a blob: URL the viewer can render.\r\n//\r\n// THE AUTHORIZATION RULE: this module never sends an S3 key. It names a RECORD\r\n// and lets the server resolve the key. Sending a key would let any user read\r\n// any object in the bucket.\r\n\r\n/** Error carrying the HTTP status, so callers can distinguish 403 from 404. */\r\nexport class DocumentAccessError extends Error {\r\n constructor(message, status) {\r\n super(message);\r\n this.name = 'DocumentAccessError';\r\n this.status = status;\r\n }\r\n}\r\n\r\nfunction messageForStatus(status, serverMessage) {\r\n // Distinct messages per status. \"Could not load document\" for all four sends\r\n // a user to the wrong remedy: a permissions problem and a deleted file need\r\n // completely different actions.\r\n switch (status) {\r\n case 400: return serverMessage || 'This document request was not valid.';\r\n case 401: return 'Your session has expired. Please sign in again.';\r\n case 403: return 'You do not have permission to view this document.';\r\n case 404: return serverMessage || 'This document is no longer available.';\r\n case 502:\r\n case 503: return 'Document storage is temporarily unavailable. Please try again.';\r\n case 504: return 'The document took too long to load. Please try again.';\r\n default: return serverMessage || 'This document could not be loaded.';\r\n }\r\n}\r\n\r\n/**\r\n * fetchDocumentBlob — retrieves a document's bytes through the authenticated\r\n * backend and returns a Blob.\r\n *\r\n * Identify the document by EITHER:\r\n * { documentId }\r\n * { module, refId, fieldName }\r\n *\r\n * @returns {Promise<{ blob: Blob, contentType: string, fileName: string }>}\r\n * @throws {DocumentAccessError}\r\n */\r\nexport async function fetchDocumentBlob({ documentId, module, refId, fieldName, index } = {}) {\r\n const params = new URLSearchParams();\r\n if (documentId) {\r\n params.set('documentId', String(documentId));\r\n } else if (module && refId && fieldName) {\r\n params.set('module', String(module));\r\n params.set('refId', String(refId));\r\n params.set('fieldName', String(fieldName));\r\n // One row of an array of documents stored on the record (REQ-20260911-01 R4).\r\n if (Number.isInteger(index) && index >= 0) params.set('index', String(index));\r\n } else {\r\n throw new DocumentAccessError(\r\n 'A documentId, or module + refId + fieldName, is required to load a document.',\r\n 400,\r\n );\r\n }\r\n\r\n const token = await ensureToken();\r\n const res = await fetch(`${AUTH_URL}/documents/content?${params.toString()}`, {\r\n headers: { Authorization: `Bearer ${token}` },\r\n });\r\n\r\n if (!res.ok) {\r\n // The error body is JSON even though a success is binary.\r\n let serverMessage = '';\r\n try {\r\n const body = await res.json();\r\n serverMessage = body?.error || body?.message || '';\r\n } catch {\r\n // A non-JSON error body is not worth surfacing raw.\r\n }\r\n throw new DocumentAccessError(messageForStatus(res.status, serverMessage), res.status);\r\n }\r\n\r\n const blob = await res.blob();\r\n return {\r\n blob,\r\n contentType: res.headers.get('content-type') || blob.type || '',\r\n fileName: fileNameFromContentDisposition(res.headers.get('content-disposition')),\r\n };\r\n}\r\n\r\n/**\r\n * createDocumentObjectUrl — fetches a document and wraps it in a blob: URL.\r\n *\r\n * THE CALLER MUST REVOKE the returned url (URL.revokeObjectURL) when the\r\n * viewer closes, the source changes, or the component unmounts. A blob URL\r\n * pins its bytes in memory for the lifetime of the document, so an unrevoked\r\n * multi-megabyte resume is a real leak — and a list view that resolved one per\r\n * row would exhaust memory. Resolve lazily, on open, never on render.\r\n *\r\n * @returns {Promise<{ url: string, revoke: () => void, contentType: string, fileName: string }>}\r\n */\r\nexport async function createDocumentObjectUrl(source) {\r\n const { blob, contentType, fileName } = await fetchDocumentBlob(source);\r\n const url = URL.createObjectURL(blob);\r\n let revoked = false;\r\n return {\r\n url,\r\n contentType,\r\n fileName,\r\n // Idempotent: revoking twice is harmless, but a guard makes double-revoke\r\n // in a StrictMode double-invoked effect provably safe.\r\n revoke: () => {\r\n if (revoked) return;\r\n revoked = true;\r\n URL.revokeObjectURL(url);\r\n },\r\n };\r\n}\r\n\r\nfunction fileNameFromContentDisposition(header) {\r\n if (!header) return '';\r\n const match = /filename\\*?=(?:UTF-8'')?\"?([^\";]+)\"?/i.exec(header);\r\n if (!match) return '';\r\n try {\r\n return decodeURIComponent(match[1]);\r\n } catch {\r\n return match[1];\r\n }\r\n}\r\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\r\nimport { createDocumentObjectUrl } from '../services/documentContentApi';\r\nimport PropTypes from 'prop-types';\r\nimport { Modal, Spin, Tooltip, message } from 'antd';\r\nimport {\r\n CloseOutlined,\r\n DownloadOutlined,\r\n FileUnknownOutlined,\r\n LeftOutlined,\r\n RightOutlined,\r\n ZoomInOutlined,\r\n ZoomOutOutlined,\r\n} from '@ant-design/icons';\r\nimport { Document, Page, pdfjs } from 'react-pdf';\r\nimport { renderAsync } from 'docx-preview';\r\nimport DOMPurify from 'dompurify';\r\nimport 'react-pdf/dist/Page/AnnotationLayer.css';\r\nimport 'react-pdf/dist/Page/TextLayer.css';\r\nimport '../styles/DocumentViewer.css';\r\n\r\n// pdf.js needs a web worker; Vite resolves this URL at build time so it works\r\n// in dev and production without copying files into /public.\r\npdfjs.GlobalWorkerOptions.workerSrc = new URL(\r\n 'pdfjs-dist/build/pdf.worker.min.mjs',\r\n import.meta.url,\r\n).toString();\r\n\r\nconst IMAGE_EXT = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp', 'svg', 'avif', 'ico'];\r\nconst TEXT_EXT = ['txt', 'csv', 'log', 'json', 'md', 'xml'];\r\nconst VIDEO_EXT = ['mp4', 'webm', 'ogg', 'ogv', 'mov', 'm4v'];\r\nconst ZOOM_STEP = 0.2;\r\nconst ZOOM_MIN = 0.4;\r\nconst ZOOM_MAX = 3;\r\n\r\n\r\n// Chrome's built-in PDF viewer opens a page-thumbnail strip on the LEFT of any\r\n// PDF shown in an <iframe> - a second, miniature preview inside our preview.\r\n// `toolbar=0` removes its toolbar AND that sidebar; `navpanes=0` asks for no\r\n// navigation pane (honoured by Chrome/Edge/Acrobat). Other browsers ignore the\r\n// fragment. Our own toolbar supplies download. A url that already carries a\r\n// fragment is left alone. REQ-20260923-10.\r\nfunction withEmbeddedPdfParams(url) {\r\n const text = String(url ?? '');\r\n if (!text || text.includes('#')) return text;\r\n return `${text}#toolbar=0&navpanes=0`;\r\n}\r\n\r\nfunction fileNameFromUrl(url) {\r\n if (!url) return 'Document';\r\n const clean = String(url).split('?')[0].split('#')[0];\r\n return decodeURIComponent(clean.split('/').pop() || clean) || 'Document';\r\n}\r\n\r\nfunction extOf(nameOrUrl) {\r\n const clean = String(nameOrUrl || '').split('?')[0].split('#')[0];\r\n const dot = clean.lastIndexOf('.');\r\n return dot === -1 ? '' : clean.slice(dot + 1).toLowerCase();\r\n}\r\n\r\nconst KNOWN_BUCKETS = ['pdf', 'docx', 'image', 'text', 'video', 'html'];\r\n\r\n// bucketFromExt maps a bare extension (no dot) to a renderer bucket, or null.\r\nfunction bucketFromExt(ext) {\r\n if (!ext) return null;\r\n if (ext === 'pdf') return 'pdf';\r\n if (ext === 'doc' || ext === 'docx') return 'docx';\r\n if (IMAGE_EXT.includes(ext)) return 'image';\r\n if (TEXT_EXT.includes(ext)) return 'text';\r\n if (VIDEO_EXT.includes(ext)) return 'video';\r\n return null;\r\n}\r\n\r\n// kindOf maps a document to a renderer bucket: pdf | docx | image | text |\r\n// video | html | unknown.\r\n//\r\n// `doc.type` is normalized rather than trusted verbatim, because it arrives\r\n// in different shapes depending on the caller: an already-correct bucket\r\n// name (\"image\", inline html), a bare file extension as the backend upload\r\n// handler stores it (\"jpg\", \"png\", \"pdf\" — see timesheetController.go's\r\n// `ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(...), \".\"))`), or a\r\n// MIME type (\"image/jpeg\"). Returning a bare extension straight through only\r\n// happened to work for \"pdf\"/\"docx\" because those extensions equal their own\r\n// bucket name — every image extension (\"jpg\", \"png\", …) doesn't equal\r\n// \"image\", so it silently fell through to the \"no preview available\"\r\n// fallback. This maps all three shapes through the same extension table.\r\nfunction kindOf(doc) {\r\n const rawType = String(doc.type || '').toLowerCase().trim();\r\n if (KNOWN_BUCKETS.includes(rawType)) return rawType;\r\n\r\n const mimeExt = rawType.includes('/') ? rawType.split('/').pop() : rawType;\r\n const fromType = bucketFromExt(mimeExt);\r\n if (fromType) return fromType;\r\n\r\n const fromName = bucketFromExt(extOf(doc.name || doc.url));\r\n if (fromName) return fromName;\r\n\r\n return 'unknown';\r\n}\r\n\r\n// normalizeDocs accepts either bare URL strings, file objects, or inline\r\n// document objects ({ name, type: 'text'|'html', content }).\r\nfunction normalizeDocs(documents) {\r\n return (documents || [])\r\n .map((d, i) => {\r\n if (typeof d === 'string') {\r\n return { url: d, name: fileNameFromUrl(d), key: String(i) };\r\n }\r\n // `d.location` is deliberately NOT a url fallback any more. It holds a\r\n // PRIVATE S3 object key, and treating it as a url produced an unsigned\r\n // request that the bucket answered with 403 — the whole reason resumes\r\n // would not open. A doc with only a key must carry `authSource` so the\r\n // bytes are fetched through the authenticated backend instead.\r\n const url = d.url || d.path || '';\r\n return {\r\n url,\r\n name: d.name || fileNameFromUrl(url || d.location || ''),\r\n type: d.type,\r\n content: typeof d.content === 'string' ? d.content : '',\r\n authSource: d.authSource || null,\r\n key: String(d.id ?? d._id ?? i),\r\n };\r\n })\r\n .filter((d) => d.url || d.content || d.authSource);\r\n}\r\n\r\n/* ------------------------------- renderers ------------------------------- */\r\n\r\nfunction PdfRenderer({ url, scale, onNativeFallback }) {\r\n const wrapRef = useRef(null);\r\n const [numPages, setNumPages] = useState(0);\r\n const [width, setWidth] = useState(0);\r\n const [error, setError] = useState(false);\r\n\r\n useEffect(() => {\r\n const el = wrapRef.current;\r\n if (!el) return undefined;\r\n const update = () => setWidth(el.clientWidth);\r\n update();\r\n const ro = new ResizeObserver(update);\r\n ro.observe(el);\r\n return () => ro.disconnect();\r\n }, []);\r\n\r\n // pdf.js streams the file via its own fetch, which fails cross-origin on\r\n // storage URLs the bucket's CORS policy doesn't allowlist this origin for\r\n // (common — see the S3 bucket's CORS config, not something fixable here) —\r\n // distinct from a plain navigation (an <iframe> load), which is NOT subject\r\n // to CORS at all and works regardless. Fall back to that rather than\r\n // dead-ending the preview; the native viewer brings its own zoom/controls,\r\n // so the toolbar hides its (now inert) zoom buttons via onNativeFallback.\r\n //\r\n // This intentionally points the iframe at the raw presigned `url`, not a\r\n // fetched blob — fetching it would hit the same CORS wall react-pdf just\r\n // did. Whether this renders inline vs. downloads depends entirely on the\r\n // `Content-Disposition` the presigned URL responds with; that's set\r\n // server-side (GetPresignedURLInline in Be_Auth_DevOps) rather than worked\r\n // around here, so every consumer of the URL — this iframe, a plain link,\r\n // anything — gets the same correct inline behavior.\r\n if (error) {\r\n return <iframe title=\"PDF preview\" src={withEmbeddedPdfParams(url)} className=\"dv-pdf-native\" />;\r\n }\r\n\r\n return (\r\n <div ref={wrapRef} className=\"dv-pdf-wrap\">\r\n <Document\r\n file={url}\r\n loading={<Spin />}\r\n error={<FallbackStage label=\"This PDF could not be displayed.\" />}\r\n onLoadSuccess={({ numPages: n }) => setNumPages(n)}\r\n onLoadError={() => {\r\n setError(true);\r\n onNativeFallback?.();\r\n }}\r\n >\r\n {Array.from({ length: numPages }, (_, i) => (\r\n <Page\r\n key={`page-${i + 1}`}\r\n pageNumber={i + 1}\r\n width={width ? width * scale : undefined}\r\n className=\"dv-pdf-page\"\r\n renderTextLayer\r\n renderAnnotationLayer\r\n />\r\n ))}\r\n </Document>\r\n </div>\r\n );\r\n}\r\n\r\nPdfRenderer.propTypes = {\r\n url: PropTypes.string.isRequired,\r\n scale: PropTypes.number.isRequired,\r\n onNativeFallback: PropTypes.func,\r\n};\r\n\r\nfunction DocxRenderer({ url }) {\r\n const ref = useRef(null);\r\n const [status, setStatus] = useState('loading'); // loading | ready | error\r\n\r\n useEffect(() => {\r\n let cancelled = false;\r\n\r\n fetch(url)\r\n .then((r) => {\r\n if (!r.ok) throw new Error(`HTTP ${r.status}`);\r\n return r.blob();\r\n })\r\n .then((blob) => {\r\n if (cancelled || !ref.current) return undefined;\r\n ref.current.innerHTML = '';\r\n return renderAsync(blob, ref.current, undefined, {\r\n className: 'dv-docx',\r\n inWrapper: true,\r\n ignoreWidth: false,\r\n ignoreHeight: false,\r\n });\r\n })\r\n .then(() => {\r\n if (!cancelled) setStatus('ready');\r\n })\r\n .catch(() => {\r\n if (!cancelled) setStatus('error');\r\n });\r\n\r\n return () => {\r\n cancelled = true;\r\n };\r\n }, [url]);\r\n\r\n if (status === 'error') {\r\n return <FallbackStage label=\"This document could not be displayed.\" />;\r\n }\r\n\r\n return (\r\n <div className=\"dv-docx-scroll\">\r\n {status === 'loading' && <div className=\"dv-center\"><Spin /></div>}\r\n <div ref={ref} style={{ visibility: status === 'ready' ? 'visible' : 'hidden' }} />\r\n </div>\r\n );\r\n}\r\n\r\nDocxRenderer.propTypes = { url: PropTypes.string.isRequired };\r\n\r\nfunction TextRenderer({ url, content = '' }) {\r\n const [text, setText] = useState(null);\r\n const [status, setStatus] = useState('loading');\r\n\r\n useEffect(() => {\r\n if (content) return undefined;\r\n\r\n let cancelled = false;\r\n fetch(url)\r\n .then((r) => {\r\n if (!r.ok) throw new Error(`HTTP ${r.status}`);\r\n return r.text();\r\n })\r\n .then((t) => {\r\n if (!cancelled) {\r\n setText(t);\r\n setStatus('ready');\r\n }\r\n })\r\n .catch(() => !cancelled && setStatus('error'));\r\n return () => {\r\n cancelled = true;\r\n };\r\n }, [content, url]);\r\n\r\n if (content) return <pre className=\"dv-text\">{content}</pre>;\r\n if (status === 'loading') return <div className=\"dv-center\"><Spin /></div>;\r\n if (status === 'error') return <FallbackStage label=\"This file could not be displayed.\" />;\r\n return <pre className=\"dv-text\">{text}</pre>;\r\n}\r\n\r\nTextRenderer.propTypes = {\r\n url: PropTypes.string,\r\n content: PropTypes.string,\r\n};\r\n\r\nfunction HtmlRenderer({ content }) {\r\n const safeHtml = useMemo(() => DOMPurify.sanitize(content), [content]);\r\n return <div className=\"dv-html\" dangerouslySetInnerHTML={{ __html: safeHtml }} />;\r\n}\r\n\r\nHtmlRenderer.propTypes = { content: PropTypes.string.isRequired };\r\n\r\nfunction ImageRenderer({ url, name, scale }) {\r\n const [error, setError] = useState(false);\r\n if (error) return <FallbackStage label=\"This image could not be displayed.\" />;\r\n return (\r\n <div className=\"dv-image-wrap\">\r\n <img\r\n className=\"dv-image\"\r\n src={url}\r\n alt={name}\r\n style={{ transform: `scale(${scale})` }}\r\n onError={() => setError(true)}\r\n />\r\n </div>\r\n );\r\n}\r\n\r\nImageRenderer.propTypes = {\r\n url: PropTypes.string.isRequired,\r\n name: PropTypes.string.isRequired,\r\n scale: PropTypes.number.isRequired,\r\n};\r\n\r\nfunction VideoRenderer({ url, name }) {\r\n const [error, setError] = useState(false);\r\n if (error) return <FallbackStage label=\"This video could not be played.\" />;\r\n return (\r\n <div className=\"dv-video-wrap\">\r\n <video\r\n className=\"dv-video\"\r\n src={url}\r\n title={name}\r\n controls\r\n preload=\"metadata\"\r\n controlsList=\"nodownload\"\r\n onError={() => setError(true)}\r\n />\r\n </div>\r\n );\r\n}\r\n\r\nVideoRenderer.propTypes = {\r\n url: PropTypes.string.isRequired,\r\n name: PropTypes.string.isRequired,\r\n};\r\n\r\nfunction FallbackStage({ label }) {\r\n return (\r\n <div className=\"dv-center dv-fallback\">\r\n <FileUnknownOutlined className=\"dv-fallback-icon\" />\r\n <p>{label}</p>\r\n <span className=\"dv-fallback-hint\">Use the download button to open it.</span>\r\n </div>\r\n );\r\n}\r\n\r\nFallbackStage.propTypes = { label: PropTypes.string.isRequired };\r\n\r\n/* ----------------------------- main component ---------------------------- */\r\n\r\n/**\r\n * useAuthenticatedDocument — turns a doc carrying `authSource` into one\r\n * carrying a usable blob: `url`.\r\n *\r\n * Returns { doc, loading, error }. A doc that already has a url passes through\r\n * untouched, so this costs nothing for inline content and public links.\r\n *\r\n * REVOCATION is the point of the cleanup function: a blob URL keeps its bytes\r\n * alive until revoked, so a multi-megabyte resume leaks for the lifetime of\r\n * the page if this is skipped. The effect revokes on document change, on\r\n * viewer close (ViewerBody unmounts — the Modal uses destroyOnHidden), and on\r\n * a superseded in-flight fetch.\r\n */\r\nfunction useAuthenticatedDocument(doc) {\r\n // State carries the key it belongs to, so a stale result is detectable\r\n // during render. That removes the need to reset via setState inside the\r\n // effect body, which causes a cascading render (and is a lint error).\r\n const [state, setState] = useState({ key: '', url: '', error: '' });\r\n\r\n const source = doc?.authSource;\r\n // Stringified so the effect compares by VALUE. An object identity dependency\r\n // would refetch on every parent render and leak one blob per render.\r\n const sourceKey = source ? JSON.stringify(source) : '';\r\n const alreadyUsable = Boolean(doc?.url || doc?.content);\r\n const needsFetch = Boolean(sourceKey) && !alreadyUsable;\r\n\r\n useEffect(() => {\r\n if (!needsFetch) return undefined;\r\n\r\n let cancelled = false;\r\n let revokeFn = null;\r\n\r\n createDocumentObjectUrl(JSON.parse(sourceKey))\r\n .then(({ url, revoke }) => {\r\n revokeFn = revoke;\r\n // Losing the race means the user already moved on: revoke immediately\r\n // rather than handing back a URL nothing will ever revoke.\r\n if (cancelled) {\r\n revoke();\r\n return;\r\n }\r\n setState({ key: sourceKey, url, error: '' });\r\n })\r\n .catch((error) => {\r\n if (cancelled) return;\r\n setState({\r\n key: sourceKey,\r\n url: '',\r\n error: error?.message || 'This document could not be loaded.',\r\n });\r\n });\r\n\r\n return () => {\r\n cancelled = true;\r\n if (revokeFn) revokeFn();\r\n };\r\n }, [needsFetch, sourceKey]);\r\n\r\n if (!doc) return { doc: null, loading: false, error: '' };\r\n if (!needsFetch) return { doc, loading: false, error: '' };\r\n\r\n // A result from a PREVIOUS document must never be shown against this one.\r\n const settled = state.key === sourceKey;\r\n if (!settled) return { doc, loading: true, error: '' };\r\n if (state.error) return { doc, loading: false, error: state.error };\r\n return { doc: state.url ? { ...doc, url: state.url } : doc, loading: false, error: '' };\r\n}\r\n\r\n// ViewerBody holds the per-session state (active index + zoom). It lives inside\r\n// the Modal body, which is destroyed on close (destroyOnHidden), so it remounts\r\n// fresh on every open — no manual \"reset on open\" effects required.\r\nfunction ViewerBody({ docs, initialIndex, onClose }) {\r\n const total = docs.length;\r\n const safeInitial = Math.min(Math.max(initialIndex, 0), Math.max(0, total - 1));\r\n const [index, setIndex] = useState(safeInitial);\r\n const [scale, setScale] = useState(1);\r\n // Set when a PDF falls back to the browser's native viewer (see\r\n // PdfRenderer) — that viewer has its own zoom UI, so ours would sit there\r\n // doing nothing if left visible.\r\n const [pdfNativeFallback, setPdfNativeFallback] = useState(false);\r\n\r\n // Resolve the ACTIVE document's bytes through the authenticated backend when\r\n // all we hold is a private-bucket object key.\r\n //\r\n // Lazy by design — only the document actually being viewed is fetched. A\r\n // blob: URL pins its bytes in memory until revoked, so resolving every\r\n // document in the list up front would hold a whole attachment set resident\r\n // for as long as the viewer is open.\r\n const resolved = useAuthenticatedDocument(docs[index]);\r\n const current = resolved.doc;\r\n const kind = current ? kindOf(current) : 'unknown';\r\n const zoomable = (kind === 'pdf' && !pdfNativeFallback) || kind === 'image';\r\n\r\n // setActive changes the document and resets zoom/fallback in one event\r\n // handler, so we never have to reset them from an effect.\r\n const setActive = useCallback((next) => {\r\n setIndex(next);\r\n setScale(1);\r\n setPdfNativeFallback(false);\r\n }, []);\r\n\r\n const goPrev = useCallback(() => setActive(Math.max(0, index - 1)), [index, setActive]);\r\n const goNext = useCallback(\r\n () => setActive(Math.min(total - 1, index + 1)),\r\n [index, total, setActive],\r\n );\r\n\r\n // Keyboard navigation.\r\n useEffect(() => {\r\n const onKey = (e) => {\r\n // A focused <video> uses arrow keys to seek — don't switch documents.\r\n if (e.target?.tagName === 'VIDEO') return;\r\n if (e.key === 'ArrowLeft') goPrev();\r\n else if (e.key === 'ArrowRight') goNext();\r\n };\r\n window.addEventListener('keydown', onKey);\r\n return () => window.removeEventListener('keydown', onKey);\r\n }, [goPrev, goNext]);\r\n\r\n const download = useCallback(async (doc) => {\r\n if (!doc) return;\r\n try {\r\n let blob;\r\n if (doc.content) {\r\n const mimeType = doc.type === 'html' ? 'text/html;charset=utf-8' : 'text/plain;charset=utf-8';\r\n blob = new Blob([doc.content], { type: mimeType });\r\n } else {\r\n const res = await fetch(doc.url);\r\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\r\n blob = await res.blob();\r\n }\r\n const objUrl = URL.createObjectURL(blob);\r\n const a = document.createElement('a');\r\n a.href = objUrl;\r\n a.download = doc.name || 'document';\r\n document.body.appendChild(a);\r\n a.click();\r\n a.remove();\r\n URL.revokeObjectURL(objUrl);\r\n } catch {\r\n // Cross-origin without CORS: fall back to opening in a new tab.\r\n message.info('Opening file in a new tab…');\r\n if (doc.url) window.open(doc.url, '_blank', 'noopener,noreferrer');\r\n }\r\n }, []);\r\n\r\n function renderStage() {\r\n if (!current) {\r\n return <FallbackStage label=\"No document to preview.\" />;\r\n }\r\n // States are distinct on purpose. One generic \"could not load\" message\r\n // sends the user to the wrong remedy — \"you lack permission\", \"the file is\r\n // gone\" and \"storage is briefly down\" need three different actions, and\r\n // the backend already classifies them (403 / 404 / 502).\r\n if (resolved.error) {\r\n return <FallbackStage label={resolved.error} />;\r\n }\r\n if (resolved.loading) {\r\n return <FallbackStage label=\"Loading document…\" />;\r\n }\r\n switch (kind) {\r\n case 'pdf':\r\n return (\r\n <PdfRenderer\r\n key={current.key}\r\n url={current.url}\r\n scale={scale}\r\n onNativeFallback={() => setPdfNativeFallback(true)}\r\n />\r\n );\r\n case 'docx':\r\n return <DocxRenderer key={current.key} url={current.url} />;\r\n case 'image':\r\n return (\r\n <ImageRenderer key={current.key} url={current.url} name={current.name} scale={scale} />\r\n );\r\n case 'text':\r\n return <TextRenderer key={current.key} url={current.url} content={current.content} />;\r\n case 'html':\r\n return <HtmlRenderer key={current.key} content={current.content} />;\r\n case 'video':\r\n return <VideoRenderer key={current.key} url={current.url} name={current.name} />;\r\n default:\r\n return <FallbackStage label=\"Preview is not available for this file type.\" />;\r\n }\r\n }\r\n\r\n return (\r\n <div className=\"dv-root\">\r\n {/* toolbar */}\r\n <div className=\"dv-toolbar\">\r\n <div className=\"dv-title\" title={current?.name}>\r\n <span className=\"dv-title-text\">{current?.name || 'Document'}</span>\r\n {total > 1 && <span className=\"dv-counter\">{index + 1} / {total}</span>}\r\n </div>\r\n <div className=\"dv-actions\">\r\n {zoomable && (\r\n <>\r\n <Tooltip title=\"Zoom out\">\r\n <button\r\n type=\"button\"\r\n className=\"dv-icon-btn\"\r\n onClick={() => setScale((s) => Math.max(ZOOM_MIN, +(s - ZOOM_STEP).toFixed(2)))}\r\n disabled={scale <= ZOOM_MIN}\r\n >\r\n <ZoomOutOutlined />\r\n </button>\r\n </Tooltip>\r\n <span className=\"dv-zoom-label\">{Math.round(scale * 100)}%</span>\r\n <Tooltip title=\"Zoom in\">\r\n <button\r\n type=\"button\"\r\n className=\"dv-icon-btn\"\r\n onClick={() => setScale((s) => Math.min(ZOOM_MAX, +(s + ZOOM_STEP).toFixed(2)))}\r\n disabled={scale >= ZOOM_MAX}\r\n >\r\n <ZoomInOutlined />\r\n </button>\r\n </Tooltip>\r\n <span className=\"dv-divider\" />\r\n </>\r\n )}\r\n <Tooltip title=\"Download\">\r\n <button type=\"button\" className=\"dv-icon-btn dv-download\" onClick={() => download(current)}>\r\n <DownloadOutlined />\r\n </button>\r\n </Tooltip>\r\n <Tooltip title=\"Close\">\r\n <button type=\"button\" className=\"dv-icon-btn\" onClick={onClose}>\r\n <CloseOutlined />\r\n </button>\r\n </Tooltip>\r\n </div>\r\n </div>\r\n\r\n {/* stage + slider arrows */}\r\n <div className=\"dv-stage\">\r\n {total > 1 && (\r\n <button\r\n type=\"button\"\r\n className=\"dv-nav dv-nav--prev\"\r\n onClick={goPrev}\r\n disabled={index === 0}\r\n aria-label=\"Previous document\"\r\n >\r\n <LeftOutlined />\r\n </button>\r\n )}\r\n\r\n <div className=\"dv-canvas\">{renderStage()}</div>\r\n\r\n {total > 1 && (\r\n <button\r\n type=\"button\"\r\n className=\"dv-nav dv-nav--next\"\r\n onClick={goNext}\r\n disabled={index === total - 1}\r\n aria-label=\"Next document\"\r\n >\r\n <RightOutlined />\r\n </button>\r\n )}\r\n </div>\r\n\r\n {/* dots */}\r\n {total > 1 && (\r\n <div className=\"dv-dots\">\r\n {docs.map((d, i) => (\r\n <button\r\n key={d.key}\r\n type=\"button\"\r\n className={`dv-dot${i === index ? ' dv-dot--active' : ''}`}\r\n onClick={() => setActive(i)}\r\n aria-label={`Go to document ${i + 1}`}\r\n />\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\nViewerBody.propTypes = {\r\n docs: PropTypes.arrayOf(PropTypes.object).isRequired,\r\n initialIndex: PropTypes.number.isRequired,\r\n onClose: PropTypes.func.isRequired,\r\n};\r\n\r\n// DocumentViewer is the public component: a Modal shell that mounts ViewerBody\r\n// only while open. `documents` may be URL strings or document objects.\r\n//\r\n// Pass `inline` to render ViewerBody directly with no Modal — used by the timesheet\r\n// manager review, which shows the uploaded screenshot side-by-side with the calendar\r\n// rather than in a popup. Everything ViewerBody already does (pdf/image/docx render,\r\n// zoom, download, multi-document navigation) comes along for free.\r\nexport default function DocumentViewer({ documents, open, onClose, initialIndex = 0, inline = false }) {\r\n const docs = useMemo(() => normalizeDocs(documents), [documents]);\r\n\r\n if (inline) {\r\n return (\r\n <div className=\"dv-root--inline\">\r\n <ViewerBody docs={docs} initialIndex={initialIndex} onClose={onClose ?? (() => {})} />\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <Modal\r\n open={open}\r\n onCancel={onClose}\r\n footer={null}\r\n title={null}\r\n closable={false}\r\n centered\r\n width=\"min(1100px, 94vw)\"\r\n className=\"dv-modal\"\r\n styles={{ content: { padding: 0, overflow: 'hidden', borderRadius: 14 }, body: { padding: 0 } }}\r\n destroyOnHidden\r\n >\r\n <ViewerBody docs={docs} initialIndex={initialIndex} onClose={onClose} />\r\n </Modal>\r\n );\r\n}\r\n\r\nDocumentViewer.propTypes = {\r\n // URL strings, file objects, or inline objects ({ content, type: 'text'|'html' }).\r\n documents: PropTypes.arrayOf(\r\n PropTypes.oneOfType([PropTypes.string, PropTypes.object]),\r\n ).isRequired,\r\n // Required for the Modal shell; unused (and optional) when `inline` is set.\r\n open: PropTypes.bool,\r\n onClose: PropTypes.func,\r\n initialIndex: PropTypes.number,\r\n // Render the viewer body directly, with no Modal wrapper.\r\n inline: PropTypes.bool,\r\n};\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DocumentViewer-DcgKxqov.js","names":[],"sources":["../src/services/documentContentApi.js","../src/components/DocumentViewer.jsx"],"sourcesContent":["import { ensureToken } from './authApi';\nimport { AUTH_URL } from './apiConfig';\n\n// ── Authenticated document content ──────────────────────────────────────────\n//\n// WHY THIS EXISTS\n//\n// Documents live in a PRIVATE S3 bucket. The app was building a raw URL from\n// the stored object key:\n//\n// s3BaseUrl + \"candidate/resume/resume_<id>_<ts>.pdf\"\n//\n// That URL carries no signature, so S3 correctly answers 403 and no resume\n// could be opened. Making the bucket public is not an option.\n//\n// A presigned URL is necessary but NOT sufficient: react-pdf and docx-preview\n// fetch the bytes themselves, and the bucket's CORS policy does not allowlist\n// our origins, so the fetch is blocked even with a valid signature. The\n// backend therefore streams the bytes through our own origin, and we turn them\n// into a blob: URL the viewer can render.\n//\n// THE AUTHORIZATION RULE: this module never sends an S3 key. It names a RECORD\n// and lets the server resolve the key. Sending a key would let any user read\n// any object in the bucket.\n\n/** Error carrying the HTTP status, so callers can distinguish 403 from 404. */\nexport class DocumentAccessError extends Error {\n constructor(message, status) {\n super(message);\n this.name = 'DocumentAccessError';\n this.status = status;\n }\n}\n\nfunction messageForStatus(status, serverMessage) {\n // Distinct messages per status. \"Could not load document\" for all four sends\n // a user to the wrong remedy: a permissions problem and a deleted file need\n // completely different actions.\n switch (status) {\n case 400: return serverMessage || 'This document request was not valid.';\n case 401: return 'Your session has expired. Please sign in again.';\n case 403: return 'You do not have permission to view this document.';\n case 404: return serverMessage || 'This document is no longer available.';\n case 502:\n case 503: return 'Document storage is temporarily unavailable. Please try again.';\n case 504: return 'The document took too long to load. Please try again.';\n default: return serverMessage || 'This document could not be loaded.';\n }\n}\n\n/**\n * fetchDocumentBlob — retrieves a document's bytes through the authenticated\n * backend and returns a Blob.\n *\n * Identify the document by EITHER:\n * { documentId }\n * { module, refId, fieldName }\n *\n * @returns {Promise<{ blob: Blob, contentType: string, fileName: string }>}\n * @throws {DocumentAccessError}\n */\nexport async function fetchDocumentBlob({ documentId, module, refId, fieldName, index } = {}) {\n const params = new URLSearchParams();\n if (documentId) {\n params.set('documentId', String(documentId));\n } else if (module && refId && fieldName) {\n params.set('module', String(module));\n params.set('refId', String(refId));\n params.set('fieldName', String(fieldName));\n // One row of an array of documents stored on the record (REQ-20260911-01 R4).\n if (Number.isInteger(index) && index >= 0) params.set('index', String(index));\n } else {\n throw new DocumentAccessError(\n 'A documentId, or module + refId + fieldName, is required to load a document.',\n 400,\n );\n }\n\n const token = await ensureToken();\n const res = await fetch(`${AUTH_URL}/documents/content?${params.toString()}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!res.ok) {\n // The error body is JSON even though a success is binary.\n let serverMessage = '';\n try {\n const body = await res.json();\n serverMessage = body?.error || body?.message || '';\n } catch {\n // A non-JSON error body is not worth surfacing raw.\n }\n throw new DocumentAccessError(messageForStatus(res.status, serverMessage), res.status);\n }\n\n const blob = await res.blob();\n return {\n blob,\n contentType: res.headers.get('content-type') || blob.type || '',\n fileName: fileNameFromContentDisposition(res.headers.get('content-disposition')),\n };\n}\n\n/**\n * createDocumentObjectUrl — fetches a document and wraps it in a blob: URL.\n *\n * THE CALLER MUST REVOKE the returned url (URL.revokeObjectURL) when the\n * viewer closes, the source changes, or the component unmounts. A blob URL\n * pins its bytes in memory for the lifetime of the document, so an unrevoked\n * multi-megabyte resume is a real leak — and a list view that resolved one per\n * row would exhaust memory. Resolve lazily, on open, never on render.\n *\n * @returns {Promise<{ url: string, revoke: () => void, contentType: string, fileName: string }>}\n */\nexport async function createDocumentObjectUrl(source) {\n const { blob, contentType, fileName } = await fetchDocumentBlob(source);\n const url = URL.createObjectURL(blob);\n let revoked = false;\n return {\n url,\n contentType,\n fileName,\n // Idempotent: revoking twice is harmless, but a guard makes double-revoke\n // in a StrictMode double-invoked effect provably safe.\n revoke: () => {\n if (revoked) return;\n revoked = true;\n URL.revokeObjectURL(url);\n },\n };\n}\n\nfunction fileNameFromContentDisposition(header) {\n if (!header) return '';\n const match = /filename\\*?=(?:UTF-8'')?\"?([^\";]+)\"?/i.exec(header);\n if (!match) return '';\n try {\n return decodeURIComponent(match[1]);\n } catch {\n return match[1];\n }\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { createDocumentObjectUrl } from '../services/documentContentApi';\nimport PropTypes from 'prop-types';\nimport { Modal, Spin, Tooltip, message } from 'antd';\nimport {\n CloseOutlined,\n DownloadOutlined,\n FileUnknownOutlined,\n LeftOutlined,\n RightOutlined,\n ZoomInOutlined,\n ZoomOutOutlined,\n} from '@ant-design/icons';\nimport { Document, Page, pdfjs } from 'react-pdf';\nimport { renderAsync } from 'docx-preview';\nimport DOMPurify from 'dompurify';\nimport 'react-pdf/dist/Page/AnnotationLayer.css';\nimport 'react-pdf/dist/Page/TextLayer.css';\nimport '../styles/DocumentViewer.css';\n\n// pdf.js needs a web worker; Vite resolves this URL at build time so it works\n// in dev and production without copying files into /public.\npdfjs.GlobalWorkerOptions.workerSrc = new URL(\n 'pdfjs-dist/build/pdf.worker.min.mjs',\n import.meta.url,\n).toString();\n\nconst IMAGE_EXT = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp', 'svg', 'avif', 'ico'];\nconst TEXT_EXT = ['txt', 'csv', 'log', 'json', 'md', 'xml'];\nconst VIDEO_EXT = ['mp4', 'webm', 'ogg', 'ogv', 'mov', 'm4v'];\nconst ZOOM_STEP = 0.2;\nconst ZOOM_MIN = 0.4;\nconst ZOOM_MAX = 3;\n\n\n// Chrome's built-in PDF viewer opens a page-thumbnail strip on the LEFT of any\n// PDF shown in an <iframe> - a second, miniature preview inside our preview.\n// `toolbar=0` removes its toolbar AND that sidebar; `navpanes=0` asks for no\n// navigation pane (honoured by Chrome/Edge/Acrobat). Other browsers ignore the\n// fragment. Our own toolbar supplies download. A url that already carries a\n// fragment is left alone. REQ-20260923-10.\nfunction withEmbeddedPdfParams(url) {\n const text = String(url ?? '');\n if (!text || text.includes('#')) return text;\n return `${text}#toolbar=0&navpanes=0`;\n}\n\nfunction fileNameFromUrl(url) {\n if (!url) return 'Document';\n const clean = String(url).split('?')[0].split('#')[0];\n return decodeURIComponent(clean.split('/').pop() || clean) || 'Document';\n}\n\nfunction extOf(nameOrUrl) {\n const clean = String(nameOrUrl || '').split('?')[0].split('#')[0];\n const dot = clean.lastIndexOf('.');\n return dot === -1 ? '' : clean.slice(dot + 1).toLowerCase();\n}\n\nconst KNOWN_BUCKETS = ['pdf', 'docx', 'image', 'text', 'video', 'html'];\n\n// bucketFromExt maps a bare extension (no dot) to a renderer bucket, or null.\nfunction bucketFromExt(ext) {\n if (!ext) return null;\n if (ext === 'pdf') return 'pdf';\n if (ext === 'doc' || ext === 'docx') return 'docx';\n if (IMAGE_EXT.includes(ext)) return 'image';\n if (TEXT_EXT.includes(ext)) return 'text';\n if (VIDEO_EXT.includes(ext)) return 'video';\n return null;\n}\n\n// kindOf maps a document to a renderer bucket: pdf | docx | image | text |\n// video | html | unknown.\n//\n// `doc.type` is normalized rather than trusted verbatim, because it arrives\n// in different shapes depending on the caller: an already-correct bucket\n// name (\"image\", inline html), a bare file extension as the backend upload\n// handler stores it (\"jpg\", \"png\", \"pdf\" — see timesheetController.go's\n// `ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(...), \".\"))`), or a\n// MIME type (\"image/jpeg\"). Returning a bare extension straight through only\n// happened to work for \"pdf\"/\"docx\" because those extensions equal their own\n// bucket name — every image extension (\"jpg\", \"png\", …) doesn't equal\n// \"image\", so it silently fell through to the \"no preview available\"\n// fallback. This maps all three shapes through the same extension table.\nfunction kindOf(doc) {\n const rawType = String(doc.type || '').toLowerCase().trim();\n if (KNOWN_BUCKETS.includes(rawType)) return rawType;\n\n const mimeExt = rawType.includes('/') ? rawType.split('/').pop() : rawType;\n const fromType = bucketFromExt(mimeExt);\n if (fromType) return fromType;\n\n const fromName = bucketFromExt(extOf(doc.name || doc.url));\n if (fromName) return fromName;\n\n return 'unknown';\n}\n\n// normalizeDocs accepts either bare URL strings, file objects, or inline\n// document objects ({ name, type: 'text'|'html', content }).\nfunction normalizeDocs(documents) {\n return (documents || [])\n .map((d, i) => {\n if (typeof d === 'string') {\n return { url: d, name: fileNameFromUrl(d), key: String(i) };\n }\n // `d.location` is deliberately NOT a url fallback any more. It holds a\n // PRIVATE S3 object key, and treating it as a url produced an unsigned\n // request that the bucket answered with 403 — the whole reason resumes\n // would not open. A doc with only a key must carry `authSource` so the\n // bytes are fetched through the authenticated backend instead.\n const url = d.url || d.path || '';\n return {\n url,\n name: d.name || fileNameFromUrl(url || d.location || ''),\n type: d.type,\n content: typeof d.content === 'string' ? d.content : '',\n authSource: d.authSource || null,\n key: String(d.id ?? d._id ?? i),\n };\n })\n .filter((d) => d.url || d.content || d.authSource);\n}\n\n/* ------------------------------- renderers ------------------------------- */\n\nfunction PdfRenderer({ url, scale, onNativeFallback }) {\n const wrapRef = useRef(null);\n const [numPages, setNumPages] = useState(0);\n const [width, setWidth] = useState(0);\n const [error, setError] = useState(false);\n\n useEffect(() => {\n const el = wrapRef.current;\n if (!el) return undefined;\n const update = () => setWidth(el.clientWidth);\n update();\n const ro = new ResizeObserver(update);\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n // pdf.js streams the file via its own fetch, which fails cross-origin on\n // storage URLs the bucket's CORS policy doesn't allowlist this origin for\n // (common — see the S3 bucket's CORS config, not something fixable here) —\n // distinct from a plain navigation (an <iframe> load), which is NOT subject\n // to CORS at all and works regardless. Fall back to that rather than\n // dead-ending the preview; the native viewer brings its own zoom/controls,\n // so the toolbar hides its (now inert) zoom buttons via onNativeFallback.\n //\n // This intentionally points the iframe at the raw presigned `url`, not a\n // fetched blob — fetching it would hit the same CORS wall react-pdf just\n // did. Whether this renders inline vs. downloads depends entirely on the\n // `Content-Disposition` the presigned URL responds with; that's set\n // server-side (GetPresignedURLInline in Be_Auth_DevOps) rather than worked\n // around here, so every consumer of the URL — this iframe, a plain link,\n // anything — gets the same correct inline behavior.\n if (error) {\n return <iframe title=\"PDF preview\" src={withEmbeddedPdfParams(url)} className=\"dv-pdf-native\" />;\n }\n\n return (\n <div ref={wrapRef} className=\"dv-pdf-wrap\">\n <Document\n file={url}\n loading={<Spin />}\n error={<FallbackStage label=\"This PDF could not be displayed.\" />}\n onLoadSuccess={({ numPages: n }) => setNumPages(n)}\n onLoadError={() => {\n setError(true);\n onNativeFallback?.();\n }}\n >\n {Array.from({ length: numPages }, (_, i) => (\n <Page\n key={`page-${i + 1}`}\n pageNumber={i + 1}\n width={width ? width * scale : undefined}\n className=\"dv-pdf-page\"\n renderTextLayer\n renderAnnotationLayer\n />\n ))}\n </Document>\n </div>\n );\n}\n\nPdfRenderer.propTypes = {\n url: PropTypes.string.isRequired,\n scale: PropTypes.number.isRequired,\n onNativeFallback: PropTypes.func,\n};\n\nfunction DocxRenderer({ url }) {\n const ref = useRef(null);\n const [status, setStatus] = useState('loading'); // loading | ready | error\n\n useEffect(() => {\n let cancelled = false;\n\n fetch(url)\n .then((r) => {\n if (!r.ok) throw new Error(`HTTP ${r.status}`);\n return r.blob();\n })\n .then((blob) => {\n if (cancelled || !ref.current) return undefined;\n ref.current.innerHTML = '';\n return renderAsync(blob, ref.current, undefined, {\n className: 'dv-docx',\n inWrapper: true,\n ignoreWidth: false,\n ignoreHeight: false,\n });\n })\n .then(() => {\n if (!cancelled) setStatus('ready');\n })\n .catch(() => {\n if (!cancelled) setStatus('error');\n });\n\n return () => {\n cancelled = true;\n };\n }, [url]);\n\n if (status === 'error') {\n return <FallbackStage label=\"This document could not be displayed.\" />;\n }\n\n return (\n <div className=\"dv-docx-scroll\">\n {status === 'loading' && <div className=\"dv-center\"><Spin /></div>}\n <div ref={ref} style={{ visibility: status === 'ready' ? 'visible' : 'hidden' }} />\n </div>\n );\n}\n\nDocxRenderer.propTypes = { url: PropTypes.string.isRequired };\n\nfunction TextRenderer({ url, content = '' }) {\n const [text, setText] = useState(null);\n const [status, setStatus] = useState('loading');\n\n useEffect(() => {\n if (content) return undefined;\n\n let cancelled = false;\n fetch(url)\n .then((r) => {\n if (!r.ok) throw new Error(`HTTP ${r.status}`);\n return r.text();\n })\n .then((t) => {\n if (!cancelled) {\n setText(t);\n setStatus('ready');\n }\n })\n .catch(() => !cancelled && setStatus('error'));\n return () => {\n cancelled = true;\n };\n }, [content, url]);\n\n if (content) return <pre className=\"dv-text\">{content}</pre>;\n if (status === 'loading') return <div className=\"dv-center\"><Spin /></div>;\n if (status === 'error') return <FallbackStage label=\"This file could not be displayed.\" />;\n return <pre className=\"dv-text\">{text}</pre>;\n}\n\nTextRenderer.propTypes = {\n url: PropTypes.string,\n content: PropTypes.string,\n};\n\nfunction HtmlRenderer({ content }) {\n const safeHtml = useMemo(() => DOMPurify.sanitize(content), [content]);\n return <div className=\"dv-html\" dangerouslySetInnerHTML={{ __html: safeHtml }} />;\n}\n\nHtmlRenderer.propTypes = { content: PropTypes.string.isRequired };\n\nfunction ImageRenderer({ url, name, scale }) {\n const [error, setError] = useState(false);\n if (error) return <FallbackStage label=\"This image could not be displayed.\" />;\n return (\n <div className=\"dv-image-wrap\">\n <img\n className=\"dv-image\"\n src={url}\n alt={name}\n style={{ transform: `scale(${scale})` }}\n onError={() => setError(true)}\n />\n </div>\n );\n}\n\nImageRenderer.propTypes = {\n url: PropTypes.string.isRequired,\n name: PropTypes.string.isRequired,\n scale: PropTypes.number.isRequired,\n};\n\nfunction VideoRenderer({ url, name }) {\n const [error, setError] = useState(false);\n if (error) return <FallbackStage label=\"This video could not be played.\" />;\n return (\n <div className=\"dv-video-wrap\">\n <video\n className=\"dv-video\"\n src={url}\n title={name}\n controls\n preload=\"metadata\"\n controlsList=\"nodownload\"\n onError={() => setError(true)}\n />\n </div>\n );\n}\n\nVideoRenderer.propTypes = {\n url: PropTypes.string.isRequired,\n name: PropTypes.string.isRequired,\n};\n\nfunction FallbackStage({ label }) {\n return (\n <div className=\"dv-center dv-fallback\">\n <FileUnknownOutlined className=\"dv-fallback-icon\" />\n <p>{label}</p>\n <span className=\"dv-fallback-hint\">Use the download button to open it.</span>\n </div>\n );\n}\n\nFallbackStage.propTypes = { label: PropTypes.string.isRequired };\n\n/* ----------------------------- main component ---------------------------- */\n\n/**\n * useAuthenticatedDocument — turns a doc carrying `authSource` into one\n * carrying a usable blob: `url`.\n *\n * Returns { doc, loading, error }. A doc that already has a url passes through\n * untouched, so this costs nothing for inline content and public links.\n *\n * REVOCATION is the point of the cleanup function: a blob URL keeps its bytes\n * alive until revoked, so a multi-megabyte resume leaks for the lifetime of\n * the page if this is skipped. The effect revokes on document change, on\n * viewer close (ViewerBody unmounts — the Modal uses destroyOnHidden), and on\n * a superseded in-flight fetch.\n */\nfunction useAuthenticatedDocument(doc) {\n // State carries the key it belongs to, so a stale result is detectable\n // during render. That removes the need to reset via setState inside the\n // effect body, which causes a cascading render (and is a lint error).\n const [state, setState] = useState({ key: '', url: '', error: '' });\n\n const source = doc?.authSource;\n // Stringified so the effect compares by VALUE. An object identity dependency\n // would refetch on every parent render and leak one blob per render.\n const sourceKey = source ? JSON.stringify(source) : '';\n const alreadyUsable = Boolean(doc?.url || doc?.content);\n const needsFetch = Boolean(sourceKey) && !alreadyUsable;\n\n useEffect(() => {\n if (!needsFetch) return undefined;\n\n let cancelled = false;\n let revokeFn = null;\n\n createDocumentObjectUrl(JSON.parse(sourceKey))\n .then(({ url, revoke }) => {\n revokeFn = revoke;\n // Losing the race means the user already moved on: revoke immediately\n // rather than handing back a URL nothing will ever revoke.\n if (cancelled) {\n revoke();\n return;\n }\n setState({ key: sourceKey, url, error: '' });\n })\n .catch((error) => {\n if (cancelled) return;\n setState({\n key: sourceKey,\n url: '',\n error: error?.message || 'This document could not be loaded.',\n });\n });\n\n return () => {\n cancelled = true;\n if (revokeFn) revokeFn();\n };\n }, [needsFetch, sourceKey]);\n\n if (!doc) return { doc: null, loading: false, error: '' };\n if (!needsFetch) return { doc, loading: false, error: '' };\n\n // A result from a PREVIOUS document must never be shown against this one.\n const settled = state.key === sourceKey;\n if (!settled) return { doc, loading: true, error: '' };\n if (state.error) return { doc, loading: false, error: state.error };\n return { doc: state.url ? { ...doc, url: state.url } : doc, loading: false, error: '' };\n}\n\n// ViewerBody holds the per-session state (active index + zoom). It lives inside\n// the Modal body, which is destroyed on close (destroyOnHidden), so it remounts\n// fresh on every open — no manual \"reset on open\" effects required.\nfunction ViewerBody({ docs, initialIndex, onClose }) {\n const total = docs.length;\n const safeInitial = Math.min(Math.max(initialIndex, 0), Math.max(0, total - 1));\n const [index, setIndex] = useState(safeInitial);\n const [scale, setScale] = useState(1);\n // Set when a PDF falls back to the browser's native viewer (see\n // PdfRenderer) — that viewer has its own zoom UI, so ours would sit there\n // doing nothing if left visible.\n const [pdfNativeFallback, setPdfNativeFallback] = useState(false);\n\n // Resolve the ACTIVE document's bytes through the authenticated backend when\n // all we hold is a private-bucket object key.\n //\n // Lazy by design — only the document actually being viewed is fetched. A\n // blob: URL pins its bytes in memory until revoked, so resolving every\n // document in the list up front would hold a whole attachment set resident\n // for as long as the viewer is open.\n const resolved = useAuthenticatedDocument(docs[index]);\n const current = resolved.doc;\n const kind = current ? kindOf(current) : 'unknown';\n const zoomable = (kind === 'pdf' && !pdfNativeFallback) || kind === 'image';\n\n // setActive changes the document and resets zoom/fallback in one event\n // handler, so we never have to reset them from an effect.\n const setActive = useCallback((next) => {\n setIndex(next);\n setScale(1);\n setPdfNativeFallback(false);\n }, []);\n\n const goPrev = useCallback(() => setActive(Math.max(0, index - 1)), [index, setActive]);\n const goNext = useCallback(\n () => setActive(Math.min(total - 1, index + 1)),\n [index, total, setActive],\n );\n\n // Keyboard navigation.\n useEffect(() => {\n const onKey = (e) => {\n // A focused <video> uses arrow keys to seek — don't switch documents.\n if (e.target?.tagName === 'VIDEO') return;\n if (e.key === 'ArrowLeft') goPrev();\n else if (e.key === 'ArrowRight') goNext();\n };\n window.addEventListener('keydown', onKey);\n return () => window.removeEventListener('keydown', onKey);\n }, [goPrev, goNext]);\n\n const download = useCallback(async (doc) => {\n if (!doc) return;\n try {\n let blob;\n if (doc.content) {\n const mimeType = doc.type === 'html' ? 'text/html;charset=utf-8' : 'text/plain;charset=utf-8';\n blob = new Blob([doc.content], { type: mimeType });\n } else {\n const res = await fetch(doc.url);\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n blob = await res.blob();\n }\n const objUrl = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = objUrl;\n a.download = doc.name || 'document';\n document.body.appendChild(a);\n a.click();\n a.remove();\n URL.revokeObjectURL(objUrl);\n } catch {\n // Cross-origin without CORS: fall back to opening in a new tab.\n message.info('Opening file in a new tab…');\n if (doc.url) window.open(doc.url, '_blank', 'noopener,noreferrer');\n }\n }, []);\n\n function renderStage() {\n if (!current) {\n return <FallbackStage label=\"No document to preview.\" />;\n }\n // States are distinct on purpose. One generic \"could not load\" message\n // sends the user to the wrong remedy — \"you lack permission\", \"the file is\n // gone\" and \"storage is briefly down\" need three different actions, and\n // the backend already classifies them (403 / 404 / 502).\n if (resolved.error) {\n return <FallbackStage label={resolved.error} />;\n }\n if (resolved.loading) {\n return <FallbackStage label=\"Loading document…\" />;\n }\n switch (kind) {\n case 'pdf':\n return (\n <PdfRenderer\n key={current.key}\n url={current.url}\n scale={scale}\n onNativeFallback={() => setPdfNativeFallback(true)}\n />\n );\n case 'docx':\n return <DocxRenderer key={current.key} url={current.url} />;\n case 'image':\n return (\n <ImageRenderer key={current.key} url={current.url} name={current.name} scale={scale} />\n );\n case 'text':\n return <TextRenderer key={current.key} url={current.url} content={current.content} />;\n case 'html':\n return <HtmlRenderer key={current.key} content={current.content} />;\n case 'video':\n return <VideoRenderer key={current.key} url={current.url} name={current.name} />;\n default:\n return <FallbackStage label=\"Preview is not available for this file type.\" />;\n }\n }\n\n return (\n <div className=\"dv-root\">\n {/* toolbar */}\n <div className=\"dv-toolbar\">\n <div className=\"dv-title\" title={current?.name}>\n <span className=\"dv-title-text\">{current?.name || 'Document'}</span>\n {total > 1 && <span className=\"dv-counter\">{index + 1} / {total}</span>}\n </div>\n <div className=\"dv-actions\">\n {zoomable && (\n <>\n <Tooltip title=\"Zoom out\">\n <button\n type=\"button\"\n className=\"dv-icon-btn\"\n onClick={() => setScale((s) => Math.max(ZOOM_MIN, +(s - ZOOM_STEP).toFixed(2)))}\n disabled={scale <= ZOOM_MIN}\n >\n <ZoomOutOutlined />\n </button>\n </Tooltip>\n <span className=\"dv-zoom-label\">{Math.round(scale * 100)}%</span>\n <Tooltip title=\"Zoom in\">\n <button\n type=\"button\"\n className=\"dv-icon-btn\"\n onClick={() => setScale((s) => Math.min(ZOOM_MAX, +(s + ZOOM_STEP).toFixed(2)))}\n disabled={scale >= ZOOM_MAX}\n >\n <ZoomInOutlined />\n </button>\n </Tooltip>\n <span className=\"dv-divider\" />\n </>\n )}\n <Tooltip title=\"Download\">\n <button type=\"button\" className=\"dv-icon-btn dv-download\" onClick={() => download(current)}>\n <DownloadOutlined />\n </button>\n </Tooltip>\n <Tooltip title=\"Close\">\n <button type=\"button\" className=\"dv-icon-btn\" onClick={onClose}>\n <CloseOutlined />\n </button>\n </Tooltip>\n </div>\n </div>\n\n {/* stage + slider arrows */}\n <div className=\"dv-stage\">\n {total > 1 && (\n <button\n type=\"button\"\n className=\"dv-nav dv-nav--prev\"\n onClick={goPrev}\n disabled={index === 0}\n aria-label=\"Previous document\"\n >\n <LeftOutlined />\n </button>\n )}\n\n <div className=\"dv-canvas\">{renderStage()}</div>\n\n {total > 1 && (\n <button\n type=\"button\"\n className=\"dv-nav dv-nav--next\"\n onClick={goNext}\n disabled={index === total - 1}\n aria-label=\"Next document\"\n >\n <RightOutlined />\n </button>\n )}\n </div>\n\n {/* dots */}\n {total > 1 && (\n <div className=\"dv-dots\">\n {docs.map((d, i) => (\n <button\n key={d.key}\n type=\"button\"\n className={`dv-dot${i === index ? ' dv-dot--active' : ''}`}\n onClick={() => setActive(i)}\n aria-label={`Go to document ${i + 1}`}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\nViewerBody.propTypes = {\n docs: PropTypes.arrayOf(PropTypes.object).isRequired,\n initialIndex: PropTypes.number.isRequired,\n onClose: PropTypes.func.isRequired,\n};\n\n// DocumentViewer is the public component: a Modal shell that mounts ViewerBody\n// only while open. `documents` may be URL strings or document objects.\n//\n// Pass `inline` to render ViewerBody directly with no Modal — used by the timesheet\n// manager review, which shows the uploaded screenshot side-by-side with the calendar\n// rather than in a popup. Everything ViewerBody already does (pdf/image/docx render,\n// zoom, download, multi-document navigation) comes along for free.\nexport default function DocumentViewer({ documents, open, onClose, initialIndex = 0, inline = false }) {\n const docs = useMemo(() => normalizeDocs(documents), [documents]);\n\n if (inline) {\n return (\n <div className=\"dv-root--inline\">\n <ViewerBody docs={docs} initialIndex={initialIndex} onClose={onClose ?? (() => {})} />\n </div>\n );\n }\n\n return (\n <Modal\n open={open}\n onCancel={onClose}\n footer={null}\n title={null}\n closable={false}\n centered\n width=\"min(1100px, 94vw)\"\n className=\"dv-modal\"\n styles={{ content: { padding: 0, overflow: 'hidden', borderRadius: 14 }, body: { padding: 0 } }}\n destroyOnHidden\n >\n <ViewerBody docs={docs} initialIndex={initialIndex} onClose={onClose} />\n </Modal>\n );\n}\n\nDocumentViewer.propTypes = {\n // URL strings, file objects, or inline objects ({ content, type: 'text'|'html' }).\n documents: PropTypes.arrayOf(\n PropTypes.oneOfType([PropTypes.string, PropTypes.object]),\n ).isRequired,\n // Required for the Modal shell; unused (and optional) when `inline` is set.\n open: PropTypes.bool,\n onClose: PropTypes.func,\n initialIndex: PropTypes.number,\n // Render the viewer body directly, with no Modal wrapper.\n inline: PropTypes.bool,\n};\n"],"mappings":"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"}
|
|
@@ -5762,16 +5762,53 @@ function Ru({ field: e, readSibling: t, rows: n, rowIndex: r, now: i = or }) {
|
|
|
5762
5762
|
rowIndex: r
|
|
5763
5763
|
}) : !1), o.length ? (e) => o.some((t) => t(e)) : void 0;
|
|
5764
5764
|
}
|
|
5765
|
-
function zu(e, t = or, n = void 0) {
|
|
5765
|
+
function zu(e, t = or, n = void 0, r = void 0) {
|
|
5766
5766
|
if (!Eu(n) && $(n) !== null) return;
|
|
5767
|
-
let
|
|
5768
|
-
for (let e of
|
|
5767
|
+
let i, a = e?.validations ?? e?.validation ?? e?.rules ?? [];
|
|
5768
|
+
for (let e of a) {
|
|
5769
5769
|
let n = typeof e == "string" ? { type: e } : e;
|
|
5770
|
-
if (n?.type === "minAge")
|
|
5771
|
-
|
|
5770
|
+
if (n?.type === "minAge") {
|
|
5771
|
+
i = t().subtract(Number(n?.value ?? 18), "year");
|
|
5772
|
+
break;
|
|
5773
|
+
}
|
|
5774
|
+
if (n?.type === "noFutureDate" || n?.type === "noPastDate") {
|
|
5775
|
+
i = t();
|
|
5776
|
+
break;
|
|
5777
|
+
}
|
|
5772
5778
|
}
|
|
5779
|
+
if (typeof r != "function") return i;
|
|
5780
|
+
let o = E(i ?? t()), s = Bu(o, r);
|
|
5781
|
+
return !s || s.isSame(o, "month") ? i : s;
|
|
5773
5782
|
}
|
|
5774
|
-
function Bu(
|
|
5783
|
+
function Bu(e, t, n = 240) {
|
|
5784
|
+
let r = E(e).startOf("day");
|
|
5785
|
+
if (!r.isValid() || typeof t != "function") return null;
|
|
5786
|
+
let i = (e) => {
|
|
5787
|
+
try {
|
|
5788
|
+
return !t(e);
|
|
5789
|
+
} catch {
|
|
5790
|
+
return !1;
|
|
5791
|
+
}
|
|
5792
|
+
}, a = (e) => {
|
|
5793
|
+
let t = null, n = Infinity, a = e.startOf("month"), o = a.daysInMonth();
|
|
5794
|
+
for (let e = 0; e < o; e += 1) {
|
|
5795
|
+
let o = a.add(e, "day");
|
|
5796
|
+
if (!i(o)) continue;
|
|
5797
|
+
let s = Math.abs(o.diff(r, "day"));
|
|
5798
|
+
s < n && (t = o, n = s);
|
|
5799
|
+
}
|
|
5800
|
+
return t ? {
|
|
5801
|
+
day: t,
|
|
5802
|
+
gap: n
|
|
5803
|
+
} : null;
|
|
5804
|
+
};
|
|
5805
|
+
for (let e = 0; e <= n; e += 1) {
|
|
5806
|
+
let t = (e === 0 ? [a(r)] : [a(r.subtract(e, "month")), a(r.add(e, "month"))]).filter(Boolean);
|
|
5807
|
+
if (t.length) return t.reduce((e, t) => t.gap < e.gap ? t : e).day;
|
|
5808
|
+
}
|
|
5809
|
+
return null;
|
|
5810
|
+
}
|
|
5811
|
+
function Vu({ field: e, name: t, rows: n }) {
|
|
5775
5812
|
if (!Array.isArray(t) || t.length === 0) return [];
|
|
5776
5813
|
let r = t[t.length - 1], i = t.length >= 3 && typeof t[1] == "number", a = /* @__PURE__ */ new Set(), o = e?.validations ?? e?.validation ?? e?.rules ?? [];
|
|
5777
5814
|
for (let e of o) {
|
|
@@ -5800,7 +5837,7 @@ function Bu({ field: e, name: t, rows: n }) {
|
|
|
5800
5837
|
]));
|
|
5801
5838
|
return u;
|
|
5802
5839
|
}
|
|
5803
|
-
function
|
|
5840
|
+
function Hu({ field: e, rows: t, rowIndex: n }) {
|
|
5804
5841
|
let r = e?.rowHierarchy;
|
|
5805
5842
|
return { validator: async (i, a) => {
|
|
5806
5843
|
if (!r || Eu(a) || !Array.isArray(t) || n == null) return Promise.resolve();
|
|
@@ -5815,29 +5852,29 @@ function Vu({ field: e, rows: t, rowIndex: n }) {
|
|
|
5815
5852
|
}
|
|
5816
5853
|
//#endregion
|
|
5817
5854
|
//#region src/utils/submitMessages.js
|
|
5818
|
-
function
|
|
5855
|
+
function Uu(e) {
|
|
5819
5856
|
return (e ?? []).filter((e) => e?.submitMessages && typeof e.submitMessages == "object").sort((e, t) => (e.order ?? 0) - (t.order ?? 0))[0]?.submitMessages ?? null;
|
|
5820
5857
|
}
|
|
5821
|
-
function
|
|
5858
|
+
function Wu(e) {
|
|
5822
5859
|
let t = String(e ?? "").trim();
|
|
5823
5860
|
return t ? t.charAt(0).toUpperCase() + t.slice(1) : "Record";
|
|
5824
5861
|
}
|
|
5825
|
-
function
|
|
5826
|
-
return String(e).replaceAll("${module}",
|
|
5862
|
+
function Gu(e, t) {
|
|
5863
|
+
return String(e).replaceAll("${module}", Wu(t)).replaceAll("${moduleName}", Wu(t));
|
|
5827
5864
|
}
|
|
5828
|
-
function
|
|
5829
|
-
let r =
|
|
5865
|
+
function Ku(e, t, n) {
|
|
5866
|
+
let r = Uu(e);
|
|
5830
5867
|
if (r?.suppress) return null;
|
|
5831
5868
|
let i = n === "edit" ? r?.editSuccess : r?.addSuccess;
|
|
5832
|
-
return i && String(i).trim() ?
|
|
5869
|
+
return i && String(i).trim() ? Gu(i, t) : n === "edit" ? `${Wu(t)} has Updated successfully` : `${Wu(t)} has added successfully`;
|
|
5833
5870
|
}
|
|
5834
|
-
function
|
|
5835
|
-
let i =
|
|
5836
|
-
return a && String(a).trim() ?
|
|
5871
|
+
function qu(e, t, n, r) {
|
|
5872
|
+
let i = Uu(e), a = n === "edit" ? i?.editError : i?.addError;
|
|
5873
|
+
return a && String(a).trim() ? Gu(a, t) : r && String(r).trim() ? String(r) : n === "edit" ? `Failed to update ${Wu(t)}` : `Failed to create ${Wu(t)}`;
|
|
5837
5874
|
}
|
|
5838
5875
|
//#endregion
|
|
5839
5876
|
//#region src/utils/scrollToFirstFormError.js
|
|
5840
|
-
function
|
|
5877
|
+
function Ju({ errorFields: e } = {}, t, { root: n = document } = {}) {
|
|
5841
5878
|
if (!e?.length) return;
|
|
5842
5879
|
let r = e[0]?.name;
|
|
5843
5880
|
setTimeout(() => {
|
|
@@ -5862,10 +5899,10 @@ function qu({ errorFields: e } = {}, t, { root: n = document } = {}) {
|
|
|
5862
5899
|
}
|
|
5863
5900
|
//#endregion
|
|
5864
5901
|
//#region src/components/form/conditionalFieldLabel.js
|
|
5865
|
-
function
|
|
5902
|
+
function Yu(e) {
|
|
5866
5903
|
return Array.isArray(e) ? e.map((e) => String(e ?? "").trim()) : String(e ?? "").split(",").map((e) => e.trim());
|
|
5867
5904
|
}
|
|
5868
|
-
function
|
|
5905
|
+
function Xu(e, t) {
|
|
5869
5906
|
if (!e?.field) return !1;
|
|
5870
5907
|
switch (e.operator ?? "eq") {
|
|
5871
5908
|
case "eq": return String(t ?? "") === String(e.value ?? "");
|
|
@@ -5873,58 +5910,58 @@ function Yu(e, t) {
|
|
|
5873
5910
|
case "truthy": return t != null && t !== "" && t !== !1;
|
|
5874
5911
|
case "falsy": return t == null || t === "" || t === !1;
|
|
5875
5912
|
case "notEmpty": return Array.isArray(t) ? t.length > 0 : !!t;
|
|
5876
|
-
case "in": return
|
|
5877
|
-
case "notIn": return !
|
|
5913
|
+
case "in": return Yu(e.value).includes(String(t ?? ""));
|
|
5914
|
+
case "notIn": return !Yu(e.value).includes(String(t ?? ""));
|
|
5878
5915
|
default: return !1;
|
|
5879
5916
|
}
|
|
5880
5917
|
}
|
|
5881
|
-
function
|
|
5918
|
+
function Zu(e, t, n = !1) {
|
|
5882
5919
|
let r = n ? e?.combineLabel ?? e?.label : e?.label, i = e?.labelWhen;
|
|
5883
|
-
return
|
|
5920
|
+
return Xu(i, t) && i?.label ? i.label : r;
|
|
5884
5921
|
}
|
|
5885
|
-
function
|
|
5922
|
+
function Qu(e) {
|
|
5886
5923
|
return e ? [...e.field ? [e] : [], ...(e.conditions ?? []).filter((e) => e?.field)] : [];
|
|
5887
5924
|
}
|
|
5888
|
-
function
|
|
5889
|
-
let n =
|
|
5925
|
+
function $u(e, t) {
|
|
5926
|
+
let n = Qu(e);
|
|
5890
5927
|
if (!n.length) return !0;
|
|
5891
|
-
let r = n.map((e) =>
|
|
5928
|
+
let r = n.map((e) => Xu(e, t(e.field)));
|
|
5892
5929
|
return e.logic === "or" ? r.some(Boolean) : r.every(Boolean);
|
|
5893
5930
|
}
|
|
5894
|
-
function
|
|
5931
|
+
function ed(e) {
|
|
5895
5932
|
let t = e?.colWhen;
|
|
5896
5933
|
return t ? (Array.isArray(t) ? t : [t]).filter((e) => e?.field && Number(e?.col) > 0) : [];
|
|
5897
5934
|
}
|
|
5898
|
-
function
|
|
5899
|
-
for (let t of
|
|
5935
|
+
function td(e, t, n) {
|
|
5936
|
+
for (let t of ed(e)) if (Xu(t, n(t))) return Number(t.col);
|
|
5900
5937
|
return t;
|
|
5901
5938
|
}
|
|
5902
|
-
function
|
|
5939
|
+
function nd(e, t) {
|
|
5903
5940
|
return e?.field ? t == null ? [e.field] : [...Array.isArray(t) ? t : [t], e.field] : ["__noop_conditional_label__"];
|
|
5904
5941
|
}
|
|
5905
5942
|
//#endregion
|
|
5906
5943
|
//#region src/components/form/conditionalRequired.js
|
|
5907
|
-
function
|
|
5944
|
+
function rd(e, t) {
|
|
5908
5945
|
return (n) => {
|
|
5909
5946
|
if (!e || !n) return;
|
|
5910
5947
|
let r = Array.isArray(t) && t.length > 1 ? [...t.slice(0, -1), n] : [n], i = e.getFieldValue(r);
|
|
5911
5948
|
return i === void 0 ? e.getFieldValue([n]) : i;
|
|
5912
5949
|
};
|
|
5913
5950
|
}
|
|
5914
|
-
function
|
|
5951
|
+
function id(e, t, n) {
|
|
5915
5952
|
let r = e?.requiredWhen;
|
|
5916
|
-
return !r || !t || !r.field && !(r.conditions ?? []).some((e) => e?.field) ? !1 :
|
|
5953
|
+
return !r || !t || !r.field && !(r.conditions ?? []).some((e) => e?.field) ? !1 : $u(r, rd(t, n));
|
|
5917
5954
|
}
|
|
5918
|
-
function
|
|
5955
|
+
function ad(e, t, n) {
|
|
5919
5956
|
return { validator: (r, i) => {
|
|
5920
|
-
if (!
|
|
5957
|
+
if (!id(e, t, n) || !(i == null || i === "" || Array.isArray(i) && i.length === 0)) return Promise.resolve();
|
|
5921
5958
|
let a = e?.label ?? e?.field ?? "This field";
|
|
5922
5959
|
return Promise.reject(Error(e?.requiredWhen?.message ?? `${a} is required`));
|
|
5923
5960
|
} };
|
|
5924
5961
|
}
|
|
5925
5962
|
//#endregion
|
|
5926
5963
|
//#region src/components/Breadcrumb.jsx
|
|
5927
|
-
function
|
|
5964
|
+
function od({ items: e = [] }) {
|
|
5928
5965
|
let t = e.map((t, n) => ({ title: n === e.length - 1 ? /* @__PURE__ */ w(Mr, {
|
|
5929
5966
|
variant: "body",
|
|
5930
5967
|
weight: "medium",
|
|
@@ -5942,34 +5979,34 @@ function ad({ items: e = [] }) {
|
|
|
5942
5979
|
}
|
|
5943
5980
|
//#endregion
|
|
5944
5981
|
//#region src/components/form/canonicalOption.js
|
|
5945
|
-
var
|
|
5946
|
-
function
|
|
5982
|
+
var sd = (e) => String(e ?? "").trim().replace(/\s+/g, " ").toLowerCase();
|
|
5983
|
+
function cd(e = []) {
|
|
5947
5984
|
let t = /* @__PURE__ */ new Map();
|
|
5948
5985
|
for (let n of e) {
|
|
5949
5986
|
if (n == null) continue;
|
|
5950
5987
|
let e = typeof n == "object" ? n.value : n;
|
|
5951
5988
|
if (e != null && e !== "") for (let r of [n?.label, e]) {
|
|
5952
|
-
let n =
|
|
5989
|
+
let n = sd(r);
|
|
5953
5990
|
n && !t.has(n) && t.set(n, e);
|
|
5954
5991
|
}
|
|
5955
5992
|
}
|
|
5956
5993
|
return t;
|
|
5957
5994
|
}
|
|
5958
|
-
function
|
|
5995
|
+
function ld(e, t) {
|
|
5959
5996
|
if (!Array.isArray(e)) {
|
|
5960
|
-
let n =
|
|
5997
|
+
let n = ld([e], t);
|
|
5961
5998
|
return n.length ? n[0] : e;
|
|
5962
5999
|
}
|
|
5963
|
-
let n =
|
|
6000
|
+
let n = cd(t), r = /* @__PURE__ */ new Set(), i = [];
|
|
5964
6001
|
for (let t of e) {
|
|
5965
|
-
let e = typeof t == "object" && t ? t.value : t, a = n.get(
|
|
6002
|
+
let e = typeof t == "object" && t ? t.value : t, a = n.get(sd(e)) ?? e, o = sd(a);
|
|
5966
6003
|
o && r.has(o) || (o && r.add(o), i.push(a));
|
|
5967
6004
|
}
|
|
5968
6005
|
return i;
|
|
5969
6006
|
}
|
|
5970
6007
|
//#endregion
|
|
5971
6008
|
//#region src/components/form/dependencyBusy.js
|
|
5972
|
-
function
|
|
6009
|
+
function ud(e, t = []) {
|
|
5973
6010
|
if (!e) return [];
|
|
5974
6011
|
let n = /* @__PURE__ */ new Set();
|
|
5975
6012
|
for (let r of t) for (let t of r?.fields ?? []) if (t?.field) {
|
|
@@ -5979,16 +6016,16 @@ function ld(e, t = []) {
|
|
|
5979
6016
|
}
|
|
5980
6017
|
return n.delete(e), [...n];
|
|
5981
6018
|
}
|
|
5982
|
-
function
|
|
5983
|
-
return e?.blockWhileResolving ?
|
|
6019
|
+
function dd(e, t = []) {
|
|
6020
|
+
return e?.blockWhileResolving ? ud(e.field, t).length > 0 : !1;
|
|
5984
6021
|
}
|
|
5985
|
-
function
|
|
6022
|
+
function fd(e) {
|
|
5986
6023
|
let t = String(e?.label ?? "").trim();
|
|
5987
6024
|
return t ? `Applying ${t}…` : "Applying your selection…";
|
|
5988
6025
|
}
|
|
5989
|
-
function
|
|
6026
|
+
function pd(e, t = []) {
|
|
5990
6027
|
if (!e?.field) return [];
|
|
5991
|
-
let n = new Set(
|
|
6028
|
+
let n = new Set(ud(e.field, t));
|
|
5992
6029
|
if (n.size === 0) return [];
|
|
5993
6030
|
let r = [];
|
|
5994
6031
|
for (let e of t) {
|
|
@@ -5997,17 +6034,17 @@ function fd(e, t = []) {
|
|
|
5997
6034
|
}
|
|
5998
6035
|
return r;
|
|
5999
6036
|
}
|
|
6000
|
-
function
|
|
6037
|
+
function md(e) {
|
|
6001
6038
|
return String(e?.blockScope ?? "").toLowerCase() === "group";
|
|
6002
6039
|
}
|
|
6003
6040
|
//#endregion
|
|
6004
6041
|
//#region src/components/form/LinkedRecordFileField.jsx
|
|
6005
|
-
var
|
|
6006
|
-
function
|
|
6042
|
+
var hd = f(() => import("./index.js").then((e) => e.n)), gd = f(() => import("./DocumentViewer-DcgKxqov.js").then((e) => e.n));
|
|
6043
|
+
function _d(e) {
|
|
6007
6044
|
let t = String(e ?? "").split(".").pop()?.toLowerCase();
|
|
6008
6045
|
return w(t === "pdf" ? fe : t === "doc" || t === "docx" ? me : de, { className: "v1-file-chip__icon" });
|
|
6009
6046
|
}
|
|
6010
|
-
function
|
|
6047
|
+
function vd({ field: e, recordMeta: t, onLinkedRecordUpdated: n }) {
|
|
6011
6048
|
let r = e?.linkedModule, i = e?.linkedFileField, a = g(() => {
|
|
6012
6049
|
let n = Rc(r, t);
|
|
6013
6050
|
if (n) return n;
|
|
@@ -6071,7 +6108,7 @@ function _d({ field: e, recordMeta: t, onLinkedRecordUpdated: n }) {
|
|
|
6071
6108
|
onClick: () => y && l(!0),
|
|
6072
6109
|
title: y ? `Preview or download ${_.name}` : ae,
|
|
6073
6110
|
children: [
|
|
6074
|
-
y ?
|
|
6111
|
+
y ? _d(_.name) : /* @__PURE__ */ w(de, { className: "v1-file-chip__icon" }),
|
|
6075
6112
|
/* @__PURE__ */ w("span", {
|
|
6076
6113
|
className: "v1-file-chip__name",
|
|
6077
6114
|
children: y ? _.name : ae
|
|
@@ -6095,7 +6132,7 @@ function _d({ field: e, recordMeta: t, onLinkedRecordUpdated: n }) {
|
|
|
6095
6132
|
}),
|
|
6096
6133
|
c && te && /* @__PURE__ */ w(u, {
|
|
6097
6134
|
fallback: null,
|
|
6098
|
-
children: /* @__PURE__ */ w(
|
|
6135
|
+
children: /* @__PURE__ */ w(gd, {
|
|
6099
6136
|
open: c,
|
|
6100
6137
|
onClose: () => l(!1),
|
|
6101
6138
|
documents: [te]
|
|
@@ -6126,7 +6163,7 @@ function _d({ field: e, recordMeta: t, onLinkedRecordUpdated: n }) {
|
|
|
6126
6163
|
},
|
|
6127
6164
|
children: /* @__PURE__ */ w(ie, {})
|
|
6128
6165
|
}),
|
|
6129
|
-
children: /* @__PURE__ */ w(
|
|
6166
|
+
children: /* @__PURE__ */ w(hd, {
|
|
6130
6167
|
moduleName: r,
|
|
6131
6168
|
recordId: a,
|
|
6132
6169
|
embedded: !0,
|
|
@@ -6140,7 +6177,7 @@ function _d({ field: e, recordMeta: t, onLinkedRecordUpdated: n }) {
|
|
|
6140
6177
|
})
|
|
6141
6178
|
] });
|
|
6142
6179
|
}
|
|
6143
|
-
|
|
6180
|
+
vd.propTypes = {
|
|
6144
6181
|
field: D.shape({
|
|
6145
6182
|
label: D.string,
|
|
6146
6183
|
linkedModule: D.string,
|
|
@@ -6153,11 +6190,11 @@ _d.propTypes = {
|
|
|
6153
6190
|
}).isRequired,
|
|
6154
6191
|
recordMeta: D.object,
|
|
6155
6192
|
onLinkedRecordUpdated: D.func
|
|
6156
|
-
},
|
|
6193
|
+
}, vd.defaultProps = {
|
|
6157
6194
|
recordMeta: void 0,
|
|
6158
6195
|
onLinkedRecordUpdated: void 0
|
|
6159
6196
|
};
|
|
6160
6197
|
//#endregion
|
|
6161
|
-
export { Sl as $, pn as $i, ei as $n, Xe as $r, cs as $t, yu as A, xn as Ai, aa as An, Un as Ar, ic as At, fu as B, ot as Bi, xi as Bn, tt as Br, Rs as Bt, zu as C, We as Ci, Sa as Cn, nr as Cr, Oc as Ct,
|
|
6198
|
+
export { Sl as $, pn as $i, ei as $n, Xe as $r, cs as $t, yu as A, xn as Ai, aa as An, Un as Ar, ic as At, fu as B, ot as Bi, xi as Bn, tt as Br, Rs as Bt, zu as C, We as Ci, Sa as Cn, nr as Cr, Oc as Ct, Vu as D, M as Di, Za as Dn, Bn as Dr, gc as Dt, Eu as E, Ht as Ei, za as En, zn as Er, yc as Et, cu as F, nn as Fi, Hi as Fn, gn as Fr, Ks as Ft, Rl as G, Be as Gi, di as Gn, mn as Gr, ys as Gt, Ul as H, St as Hi, bi as Hn, Dn as Hr, Bs as Ht, Wl as I, rn as Ii, Vi as In, fn as Ir, Ys as It, kl as J, ht as Ji, mi as Jn, Ve as Jr, ds as Jt, Nl as K, Ut as Ki, yi as Kn, Rn as Kr, Ts as Kt, ql as L, nt as Li, Ti as Ln, In as Lr, Hs as Lt, vu as M, It as Mi, Xi as Mn, Et as Mr, X as Mt, gu as N, Xt as Ni, Qi as Nn, $e as Nr, $s as Nt, Tu as O, Pt as Oi, Na as On, Hn as Or, _c as Ot, Yl as P, ze as Pi, Li as Pn, Tn as Pr, ec as Pt, Cl as Q, _n as Qi, $r as Qn, Ze as Qr, ls as Qt, Gl as R, pt as Ri, Ei as Rn, Zt as Rr, Vs as Rt, Hu as S, Re as Si, Ga as Sn, P as Sr, kc as St, Ou as T, Qe as Ti, K as Tn, Xn as Tr, bc as Tt, Vl as U, He as Ui, vi as Un, Ct as Ur, ks as Ut, su as V, ut as Vi, Ci as Vn, mt as Vr, zs as Vt, Ll as W, on as Wi, fi as Wn, vn as Wr, Os as Wt, Ol as X, et as Xi, ci as Xn, st as Xr, ps as Xt, Ml as Y, wt as Yi, li as Yn, Nn as Yr, ms as Yt, El as Z, En as Zi, si as Zn, Yt as Zr, us as Zt, Ju as _, en as _i, to as _n, lr as _r, Fc as _t, dd as a, Mt as aa, cn as ai, J as an, Hr as ar, el as at, Ru as b, dn as bi, Ka as bn, Zn as br, jc as bt, id as c, sn as ca, yt as ci, go as cn, L as cr, Xc as ct, nd as d, at as di, Mo as dn, cr as dr, Rc as dt, Ln as ea, ft as ei, os as en, ni as er, cl as et, Xu as f, lt as fi, uo as fn, dr as fr, Vc as ft, Qu as g, Tt as gi, eo as gn, hr as gr, Uc as gt, td as h, bt as hi, ao as hn, sr as hr, Wc as ht, fd as i, Mn as ia, un as ii, Lo as in, Ur as ir, il as it, bu as j, An as ji, Ki as jn, rt as jr, nc as jt, wu as k, Ft as ki, Ma as kn, Vn as kr, oc as kt, ad as l, ln as li, vo as ln, I as lr, Gc as lt, $u as m, xt as mi, io as mn, vr as mr, Bc as mt, md as n, zt as na, jt as ni, Wo as nn, Gr as nr, dl as nt, ld as o, Wt as oa, Ue as oi, Po as on, Rr as or, qc as ot, Zu as p, qt as pi, ho as pn, F as pr, Hc as pt, Il as q, Kt as qi, pi as qn, $t as qr, Ps as qt, pd as r, Sn as ra, Gt as ri, Uo as rn, Wr as rr, ol as rt, od as s, Jt as sa, _t as si, _o as sn, Mr as sr, Jc as st, vd as t, Qt as ta, Ot as ti, ss as tn, Kr as tr, fl as tt, ed as u, wn as ui, Oo as un, or as ur, zc as ut, qu as v, tn as vi, no as vn, Wn as vr, Nc as vt, Du as w, an as wi, V as wn, qn as wr, Ec as wt, Fu as x, Fn as xi, Qa as xn, er as xr, Ac as xt, Ku as y, hn as yi, q as yn, Qn as yr, Mc as yt, lu as z, vt as zi, wi as zn, jn as zr, Ls as zt };
|
|
6162
6199
|
|
|
6163
|
-
//# sourceMappingURL=LinkedRecordFileField-
|
|
6200
|
+
//# sourceMappingURL=LinkedRecordFileField-BD3KkJt_.js.map
|