@realtek/core-theme-live 0.0.440 → 0.0.445

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"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 r = e?.validations ?? e?.validation ?? e?.rules ?? [];
5768
- for (let e of r) {
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") return t().subtract(Number(n?.value ?? 18), "year");
5771
- if (n?.type === "noFutureDate" || n?.type === "noPastDate") return t();
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({ field: e, name: t, rows: n }) {
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 Vu({ field: e, rows: t, rowIndex: n }) {
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 Hu(e) {
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 Uu(e) {
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 Wu(e, t) {
5826
- return String(e).replaceAll("${module}", Uu(t)).replaceAll("${moduleName}", Uu(t));
5862
+ function Gu(e, t) {
5863
+ return String(e).replaceAll("${module}", Wu(t)).replaceAll("${moduleName}", Wu(t));
5827
5864
  }
5828
- function Gu(e, t, n) {
5829
- let r = Hu(e);
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() ? Wu(i, t) : n === "edit" ? `${Uu(t)} has Updated successfully` : `${Uu(t)} has added successfully`;
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 Ku(e, t, n, r) {
5835
- let i = Hu(e), a = n === "edit" ? i?.editError : i?.addError;
5836
- return a && String(a).trim() ? Wu(a, t) : r && String(r).trim() ? String(r) : n === "edit" ? `Failed to update ${Uu(t)}` : `Failed to create ${Uu(t)}`;
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 qu({ errorFields: e } = {}, t, { root: n = document } = {}) {
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 Ju(e) {
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 Yu(e, t) {
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 Ju(e.value).includes(String(t ?? ""));
5877
- case "notIn": return !Ju(e.value).includes(String(t ?? ""));
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 Xu(e, t, n = !1) {
5918
+ function Zu(e, t, n = !1) {
5882
5919
  let r = n ? e?.combineLabel ?? e?.label : e?.label, i = e?.labelWhen;
5883
- return Yu(i, t) && i?.label ? i.label : r;
5920
+ return Xu(i, t) && i?.label ? i.label : r;
5884
5921
  }
5885
- function Zu(e) {
5922
+ function Qu(e) {
5886
5923
  return e ? [...e.field ? [e] : [], ...(e.conditions ?? []).filter((e) => e?.field)] : [];
5887
5924
  }
5888
- function Qu(e, t) {
5889
- let n = Zu(e);
5925
+ function $u(e, t) {
5926
+ let n = Qu(e);
5890
5927
  if (!n.length) return !0;
5891
- let r = n.map((e) => Yu(e, t(e.field)));
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 $u(e) {
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 ed(e, t, n) {
5899
- for (let t of $u(e)) if (Yu(t, n(t))) return Number(t.col);
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 td(e, t) {
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 nd(e, t) {
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 rd(e, t, n) {
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 : Qu(r, nd(t, n));
5953
+ return !r || !t || !r.field && !(r.conditions ?? []).some((e) => e?.field) ? !1 : $u(r, rd(t, n));
5917
5954
  }
5918
- function id(e, t, n) {
5955
+ function ad(e, t, n) {
5919
5956
  return { validator: (r, i) => {
5920
- if (!rd(e, t, n) || !(i == null || i === "" || Array.isArray(i) && i.length === 0)) return Promise.resolve();
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 ad({ items: e = [] }) {
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 od = (e) => String(e ?? "").trim().replace(/\s+/g, " ").toLowerCase();
5946
- function sd(e = []) {
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 = od(r);
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 cd(e, t) {
5995
+ function ld(e, t) {
5959
5996
  if (!Array.isArray(e)) {
5960
- let n = cd([e], t);
5997
+ let n = ld([e], t);
5961
5998
  return n.length ? n[0] : e;
5962
5999
  }
5963
- let n = sd(t), r = /* @__PURE__ */ new Set(), i = [];
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(od(e)) ?? e, o = od(a);
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 ld(e, t = []) {
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 ud(e, t = []) {
5983
- return e?.blockWhileResolving ? ld(e.field, t).length > 0 : !1;
6019
+ function dd(e, t = []) {
6020
+ return e?.blockWhileResolving ? ud(e.field, t).length > 0 : !1;
5984
6021
  }
5985
- function dd(e) {
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 fd(e, t = []) {
6026
+ function pd(e, t = []) {
5990
6027
  if (!e?.field) return [];
5991
- let n = new Set(ld(e.field, t));
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 pd(e) {
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 md = f(() => import("./index.js").then((e) => e.n)), hd = f(() => import("./DocumentViewer-DcgKxqov.js").then((e) => e.n));
6006
- function gd(e) {
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 _d({ field: e, recordMeta: t, onLinkedRecordUpdated: n }) {
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 ? gd(_.name) : /* @__PURE__ */ w(de, { className: "v1-file-chip__icon" }),
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(hd, {
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(md, {
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
- _d.propTypes = {
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
- }, _d.defaultProps = {
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, Bu 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, Vu 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, qu as _, en as _i, to as _n, lr as _r, Fc as _t, ud 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, rd as c, sn as ca, yt as ci, go as cn, L as cr, Xc as ct, td 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, Yu as f, lt as fi, uo as fn, dr as fr, Vc as ft, Zu as g, Tt as gi, eo as gn, hr as gr, Uc as gt, ed as h, bt as hi, ao as hn, sr as hr, Wc as ht, dd 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, id as l, ln as li, vo as ln, I as lr, Gc as lt, Qu as m, xt as mi, io as mn, vr as mr, Bc as mt, pd as n, zt as na, jt as ni, Wo as nn, Gr as nr, dl as nt, cd as o, Wt as oa, Ue as oi, Po as on, Rr as or, qc as ot, Xu 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, fd as r, Sn as ra, Gt as ri, Uo as rn, Wr as rr, ol as rt, ad as s, Jt as sa, _t as si, _o as sn, Mr as sr, Jc as st, _d as t, Qt as ta, Ot as ti, ss as tn, Kr as tr, fl as tt, $u as u, wn as ui, Oo as un, or as ur, zc as ut, Ku 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, Gu 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 };
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-DTu-0e5x.js.map
6200
+ //# sourceMappingURL=LinkedRecordFileField-BD3KkJt_.js.map