@burdenoff/microfe-files 2026.624.2 → 2026.625.1

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.
@@ -10,14 +10,15 @@ import { ArrowLeft as p, Loader2 as m, Lock as h } from "lucide-react";
10
10
  import { jsx as g, jsxs as _ } from "react/jsx-runtime";
11
11
  import { useLocation as v, useNavigate as y, useParams as b } from "react-router-dom";
12
12
  import { useI18n as x } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
13
- import { print as S } from "graphql";
13
+ import { GlassCard as S } from "@burdenoff/fe-libs/ui";
14
+ import { print as C } from "graphql";
14
15
  //#region src/files/pages/ShareAccessPage.tsx
15
- function C(e) {
16
+ function w(e) {
16
17
  let t = e || c.apiGatewayUrl;
17
18
  if (!t) throw Error("Files API gateway URL is not configured");
18
19
  return t.includes("/graphql") ? t : s(t, "workspaces");
19
20
  }
20
- async function w(e, t, n) {
21
+ async function T(e, t, n) {
21
22
  let r = await fetch(e, {
22
23
  method: "POST",
23
24
  credentials: "omit",
@@ -30,7 +31,7 @@ async function w(e, t, n) {
30
31
  if (!r.ok || a || !i.data) throw Error(a || "Unable to access shared file");
31
32
  return i.data;
32
33
  }
33
- function T(e) {
34
+ function E(e) {
34
35
  let t = e.name.includes(".") && e.name.split(".").pop() || "";
35
36
  return {
36
37
  id: e.id,
@@ -47,45 +48,46 @@ function T(e) {
47
48
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
48
49
  };
49
50
  }
50
- function E() {
51
- let { t: s } = x(), c = y(), { pathname: E } = v(), { token: D } = b(), O = d(() => {
52
- if (D) return D;
53
- let e = E.match(/\/share\/([^/]+)/);
51
+ function D() {
52
+ let { t: s } = x(), c = y(), { pathname: D } = v(), { token: O } = b(), k = d(() => {
53
+ if (O) return O;
54
+ let e = D.match(/\/share\/([^/]+)/);
54
55
  return e?.[1] ? decodeURIComponent(e[1]) : "";
55
- }, [E, D]), k = e(), { apiGatewayUrl: A } = k, j = d(() => C(A), [A]), [M, N] = f(!1), [P, F] = f(""), [I, L] = f(!1), [R, z] = f(null), [B, V] = f(null), H = l(async (e) => {
56
- if (!O) throw Error("Share token is missing");
57
- N(!0);
56
+ }, [D, O]), A = e(), { apiGatewayUrl: j } = A, M = d(() => w(j), [j]), [N, P] = f(!1), [F, I] = f(""), [L, R] = f(!1), [z, B] = f(null), [V, H] = f(null), U = l(async (e) => {
57
+ if (!k) throw Error("Share token is missing");
58
+ P(!0);
58
59
  try {
59
- let n = (await w(j, S(t), { input: {
60
- token: O,
60
+ let n = (await T(M, C(t), { input: {
61
+ token: k,
61
62
  password: e || void 0
62
63
  } })).accessShare;
63
64
  if (!n?.file || !n.share) throw Error(n?.message || "Shared file is unavailable");
64
- L(!!n.share.requiresPassword), V(T(n.file)), z(null);
65
+ R(!!n.share.requiresPassword), H(E(n.file)), B(null);
65
66
  } finally {
66
- N(!1);
67
+ P(!1);
67
68
  }
68
- }, [j, O]);
69
+ }, [M, k]);
69
70
  return u(() => {
70
- H().catch((e) => {
71
+ U().catch((e) => {
71
72
  let t = e instanceof Error ? e.message : "Unable to access shared file";
72
- z(t), L(t.toLowerCase().includes("password"));
73
+ B(t), R(t.toLowerCase().includes("password"));
73
74
  });
74
- }, [H]), B ? /* @__PURE__ */ g(r, {
75
- file: B,
75
+ }, [U]), V ? /* @__PURE__ */ g(r, {
76
+ file: V,
76
77
  onClose: () => c("/files/browse"),
77
78
  onDownload: async () => {
78
- if (!B) return;
79
- let e = B.downloadUrl || B.url;
80
- e && (i("light"), await a(e), o(k, "files.share.downloaded", {
81
- fileId: B.id,
82
- fileName: B.name
79
+ if (!V) return;
80
+ let e = V.downloadUrl || V.url;
81
+ e && (i("light"), await a(e), o(A, "files.share.downloaded", {
82
+ fileId: V.id,
83
+ fileName: V.name
83
84
  }));
84
85
  }
85
86
  }) : /* @__PURE__ */ g("div", {
86
- className: "flex min-h-[70vh] items-center justify-center px-4 py-10",
87
- children: /* @__PURE__ */ _("div", {
88
- className: "w-full max-w-md rounded-2xl border border-border-default bg-bg-surface p-6 shadow-elevation-2",
87
+ className: "flex min-h-[70vh] items-center justify-center bg-hero-mesh px-4 py-10",
88
+ children: /* @__PURE__ */ _(S, {
89
+ treatment: "glass",
90
+ className: "w-full max-w-md p-6",
89
91
  children: [
90
92
  /* @__PURE__ */ _("button", {
91
93
  type: "button",
@@ -103,53 +105,53 @@ function E() {
103
105
  children: n(s, "files.share.subtitle", "Open a shared file preview using the access token from the share link.")
104
106
  })]
105
107
  }),
106
- M ? /* @__PURE__ */ _("div", {
107
- className: "flex items-center gap-3 rounded-lg border border-border-default bg-bg-sunken px-4 py-3 text-sm text-text-secondary",
108
+ N ? /* @__PURE__ */ _("div", {
109
+ className: "flex items-center gap-3 rounded-lg border border-border-seam bg-bg-sunken px-4 py-3 text-sm text-text-secondary",
108
110
  children: [/* @__PURE__ */ g(m, { className: "size-4 animate-spin text-action-primary-bg" }), n(s, "files.share.verifying", "Verifying share access…")]
109
- }) : I ? /* @__PURE__ */ _("form", {
111
+ }) : L ? /* @__PURE__ */ _("form", {
110
112
  className: "space-y-4",
111
113
  onSubmit: async (e) => {
112
114
  e.preventDefault();
113
115
  try {
114
- await H(P);
116
+ await U(F);
115
117
  } catch (e) {
116
- z(e instanceof Error ? e.message : "Unable to unlock shared file");
118
+ B(e instanceof Error ? e.message : "Unable to unlock shared file");
117
119
  }
118
120
  },
119
121
  children: [
120
122
  /* @__PURE__ */ _("label", {
121
123
  className: "block text-sm font-medium text-text-primary",
122
124
  children: [n(s, "files.share.password.label", "Share password"), /* @__PURE__ */ _("div", {
123
- className: "mt-2 flex items-center gap-2 rounded-lg border border-border-default px-3 py-2",
125
+ className: "mt-2 flex items-center gap-2 rounded-lg border border-border-seam px-3 py-2",
124
126
  children: [/* @__PURE__ */ g(h, { className: "size-4 text-text-tertiary" }), /* @__PURE__ */ g("input", {
125
127
  type: "password",
126
- value: P,
127
- onChange: (e) => F(e.target.value),
128
+ value: F,
129
+ onChange: (e) => I(e.target.value),
128
130
  "aria-label": n(s, "files.share.password.label", "Share password"),
129
131
  className: "w-full bg-transparent text-sm text-text-primary outline-none",
130
132
  placeholder: n(s, "files.share.password.placeholder", "Enter the share password")
131
133
  })]
132
134
  })]
133
135
  }),
134
- R && /* @__PURE__ */ g("div", {
136
+ z && /* @__PURE__ */ g("div", {
135
137
  className: "rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
136
- children: R
138
+ children: z
137
139
  }),
138
140
  /* @__PURE__ */ g("button", {
139
141
  type: "submit",
140
- disabled: !P.trim(),
142
+ disabled: !F.trim(),
141
143
  className: "inline-flex w-full items-center justify-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2.5 text-sm font-medium text-text-inverse transition-colors hover:bg-action-primary-bg-hover disabled:cursor-not-allowed disabled:bg-bg-sunken disabled:text-text-tertiary",
142
144
  children: n(s, "files.share.unlock", "Unlock shared file")
143
145
  })
144
146
  ]
145
147
  }) : /* @__PURE__ */ _("div", {
146
148
  className: "space-y-4",
147
- children: [R && /* @__PURE__ */ g("div", {
149
+ children: [z && /* @__PURE__ */ g("div", {
148
150
  className: "rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
149
- children: R
151
+ children: z
150
152
  }), /* @__PURE__ */ g("button", {
151
153
  type: "button",
152
- onClick: () => H(),
154
+ onClick: () => U(),
153
155
  className: "inline-flex w-full items-center justify-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2.5 text-sm font-medium text-text-inverse transition-colors hover:bg-action-primary-bg-hover",
154
156
  children: n(s, "files.share.retry", "Retry shared file access")
155
157
  })]
@@ -159,6 +161,6 @@ function E() {
159
161
  });
160
162
  }
161
163
  //#endregion
162
- export { E as ShareAccessPage };
164
+ export { D as ShareAccessPage };
163
165
 
164
166
  //# sourceMappingURL=ShareAccessPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ShareAccessPage.js","names":[],"sources":["../../../src/files/pages/ShareAccessPage.tsx"],"sourcesContent":["import {\n type FormEvent,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport { useLocation, useNavigate, useParams } from \"react-router-dom\";\nimport { ArrowLeft, Loader2, Lock } from \"lucide-react\";\nimport { print } from \"graphql\";\nimport { AccessShareDocument } from \"../../generated/wspace-operations\";\nimport type {\n AccessShareMutation,\n AccessShareMutationVariables,\n} from \"../../generated/wspace-operations\";\nimport { buildGraphQLEndpoint, config } from \"../../config\";\nimport { FilePreviewModal } from \"../components/FilePreviewModal\";\nimport type { FileItem } from \"../types\";\nimport { useFilesContext } from \"../providers/FilesProvider\";\nimport { emitFilesEvent } from \"../utils/events\";\nimport { nativeImpact, nativeOpenUrl } from \"../../utils/nativeBridge\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { tWithFallback } from \"../utils/i18n\";\n\ntype GraphQLResponse<TData> = {\n data?: TData;\n errors?: Array<{ message?: string }>;\n};\n\nfunction resolveWorkspaceGraphQLEndpoint(apiGatewayUrl?: string): string {\n const configuredUrl = apiGatewayUrl || config.apiGatewayUrl;\n\n if (!configuredUrl) {\n throw new Error(\"Files API gateway URL is not configured\");\n }\n\n return configuredUrl.includes(\"/graphql\")\n ? configuredUrl\n : buildGraphQLEndpoint(configuredUrl, \"workspaces\");\n}\n\nasync function requestPublicGraphQL<TData, TVariables>(\n endpoint: string,\n query: string,\n variables: TVariables,\n): Promise<TData> {\n const response = await fetch(endpoint, {\n method: \"POST\",\n credentials: \"omit\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ query, variables }),\n });\n\n const payload = (await response.json()) as GraphQLResponse<TData>;\n const errorMessage = payload.errors?.[0]?.message;\n\n if (!response.ok || errorMessage || !payload.data) {\n throw new Error(errorMessage || \"Unable to access shared file\");\n }\n\n return payload.data;\n}\n\nfunction buildSharedFile(payload: {\n id: string;\n name: string;\n workspaceId: string;\n mimeType: string;\n size: string;\n s3Key: string;\n downloadUrl?: string | null;\n}): FileItem {\n const extension = payload.name.includes(\".\")\n ? payload.name.split(\".\").pop() || \"\"\n : \"\";\n\n return {\n id: payload.id,\n name: payload.name,\n workspaceId: payload.workspaceId,\n mimeType: payload.mimeType,\n extension,\n size: Number(payload.size),\n s3Key: payload.s3Key,\n url: payload.downloadUrl ?? \"\",\n downloadUrl: payload.downloadUrl ?? undefined,\n starred: false,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n}\n\nexport function ShareAccessPage() {\n const { t } = useI18n();\n const navigate = useNavigate();\n const { pathname } = useLocation();\n const { token: routeToken } = useParams<{ token: string }>();\n const token = useMemo(() => {\n if (routeToken) {\n return routeToken;\n }\n\n const match = pathname.match(/\\/share\\/([^/]+)/);\n return match?.[1] ? decodeURIComponent(match[1]) : \"\";\n }, [pathname, routeToken]);\n const filesContext = useFilesContext();\n const { apiGatewayUrl } = filesContext;\n const endpoint = useMemo(\n () => resolveWorkspaceGraphQLEndpoint(apiGatewayUrl),\n [apiGatewayUrl],\n );\n const [loading, setLoading] = useState(false);\n const [password, setPassword] = useState(\"\");\n const [requiresPassword, setRequiresPassword] = useState(false);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n const [sharedFile, setSharedFile] = useState<FileItem | null>(null);\n\n const loadShare = useCallback(\n async (sharePassword?: string) => {\n if (!token) {\n throw new Error(\"Share token is missing\");\n }\n\n setLoading(true);\n\n try {\n const data = await requestPublicGraphQL<\n AccessShareMutation,\n AccessShareMutationVariables\n >(endpoint, print(AccessShareDocument), {\n input: {\n token,\n password: sharePassword || undefined,\n },\n });\n\n const payload = data.accessShare;\n if (!payload?.file || !payload.share) {\n throw new Error(payload?.message || \"Shared file is unavailable\");\n }\n\n setRequiresPassword(Boolean(payload.share.requiresPassword));\n setSharedFile(buildSharedFile(payload.file));\n setErrorMessage(null);\n } finally {\n setLoading(false);\n }\n },\n [endpoint, token],\n );\n\n useEffect(() => {\n loadShare().catch((error) => {\n const message =\n error instanceof Error ? error.message : \"Unable to access shared file\";\n setErrorMessage(message);\n setRequiresPassword(message.toLowerCase().includes(\"password\"));\n });\n }, [loadShare]);\n\n const handleDownload = async () => {\n if (!sharedFile) {\n return;\n }\n\n const downloadUrl = sharedFile.downloadUrl || sharedFile.url;\n if (downloadUrl) {\n nativeImpact(\"light\");\n await nativeOpenUrl(downloadUrl);\n emitFilesEvent(filesContext, \"files.share.downloaded\", {\n fileId: sharedFile.id,\n fileName: sharedFile.name,\n });\n }\n };\n\n const handlePasswordSubmit = async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n\n try {\n await loadShare(password);\n } catch (error) {\n setErrorMessage(\n error instanceof Error ? error.message : \"Unable to unlock shared file\",\n );\n }\n };\n\n if (sharedFile) {\n return (\n <FilePreviewModal\n file={sharedFile}\n onClose={() => navigate(\"/files/browse\")}\n onDownload={handleDownload}\n />\n );\n }\n\n return (\n <div className=\"flex min-h-[70vh] items-center justify-center px-4 py-10\">\n <div className=\"w-full max-w-md rounded-2xl border border-border-default bg-bg-surface p-6 shadow-elevation-2\">\n <button\n type=\"button\"\n onClick={() => navigate(\"/files/browse\")}\n className=\"mb-6 inline-flex items-center gap-2 text-sm font-medium text-text-secondary transition-colors hover:text-text-primary\"\n >\n <ArrowLeft className=\"size-4\" />\n {tWithFallback(t, \"files.share.back\", \"Back to files\")}\n </button>\n\n <div className=\"mb-6\">\n <h1 className=\"text-xl font-semibold text-text-primary\">\n {tWithFallback(t, \"files.share.title\", \"Shared file access\")}\n </h1>\n <p className=\"mt-2 text-sm text-text-secondary\">\n {tWithFallback(\n t,\n \"files.share.subtitle\",\n \"Open a shared file preview using the access token from the share link.\",\n )}\n </p>\n </div>\n\n {loading ? (\n <div className=\"flex items-center gap-3 rounded-lg border border-border-default bg-bg-sunken px-4 py-3 text-sm text-text-secondary\">\n <Loader2 className=\"size-4 animate-spin text-action-primary-bg\" />\n {tWithFallback(\n t,\n \"files.share.verifying\",\n \"Verifying share access…\",\n )}\n </div>\n ) : requiresPassword ? (\n <form className=\"space-y-4\" onSubmit={handlePasswordSubmit}>\n <label className=\"block text-sm font-medium text-text-primary\">\n {tWithFallback(t, \"files.share.password.label\", \"Share password\")}\n <div className=\"mt-2 flex items-center gap-2 rounded-lg border border-border-default px-3 py-2\">\n <Lock className=\"size-4 text-text-tertiary\" />\n <input\n type=\"password\"\n value={password}\n onChange={(event) => setPassword(event.target.value)}\n aria-label={tWithFallback(\n t,\n \"files.share.password.label\",\n \"Share password\",\n )}\n className=\"w-full bg-transparent text-sm text-text-primary outline-none\"\n placeholder={tWithFallback(\n t,\n \"files.share.password.placeholder\",\n \"Enter the share password\",\n )}\n />\n </div>\n </label>\n\n {errorMessage && (\n <div className=\"rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {errorMessage}\n </div>\n )}\n\n <button\n type=\"submit\"\n disabled={!password.trim()}\n className=\"inline-flex w-full items-center justify-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2.5 text-sm font-medium text-text-inverse transition-colors hover:bg-action-primary-bg-hover disabled:cursor-not-allowed disabled:bg-bg-sunken disabled:text-text-tertiary\"\n >\n {tWithFallback(t, \"files.share.unlock\", \"Unlock shared file\")}\n </button>\n </form>\n ) : (\n <div className=\"space-y-4\">\n {errorMessage && (\n <div className=\"rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {errorMessage}\n </div>\n )}\n <button\n type=\"button\"\n onClick={() => loadShare()}\n className=\"inline-flex w-full items-center justify-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2.5 text-sm font-medium text-text-inverse transition-colors hover:bg-action-primary-bg-hover\"\n >\n {tWithFallback(\n t,\n \"files.share.retry\",\n \"Retry shared file access\",\n )}\n </button>\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ShareAccessPage.js","names":[],"sources":["../../../src/files/pages/ShareAccessPage.tsx"],"sourcesContent":["import {\n type FormEvent,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport { useLocation, useNavigate, useParams } from \"react-router-dom\";\nimport { ArrowLeft, Loader2, Lock } from \"lucide-react\";\nimport { print } from \"graphql\";\nimport { AccessShareDocument } from \"../../generated/wspace-operations\";\nimport type {\n AccessShareMutation,\n AccessShareMutationVariables,\n} from \"../../generated/wspace-operations\";\nimport { buildGraphQLEndpoint, config } from \"../../config\";\nimport { FilePreviewModal } from \"../components/FilePreviewModal\";\nimport type { FileItem } from \"../types\";\nimport { useFilesContext } from \"../providers/FilesProvider\";\nimport { emitFilesEvent } from \"../utils/events\";\nimport { nativeImpact, nativeOpenUrl } from \"../../utils/nativeBridge\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport { tWithFallback } from \"../utils/i18n\";\n\ntype GraphQLResponse<TData> = {\n data?: TData;\n errors?: Array<{ message?: string }>;\n};\n\nfunction resolveWorkspaceGraphQLEndpoint(apiGatewayUrl?: string): string {\n const configuredUrl = apiGatewayUrl || config.apiGatewayUrl;\n\n if (!configuredUrl) {\n throw new Error(\"Files API gateway URL is not configured\");\n }\n\n return configuredUrl.includes(\"/graphql\")\n ? configuredUrl\n : buildGraphQLEndpoint(configuredUrl, \"workspaces\");\n}\n\nasync function requestPublicGraphQL<TData, TVariables>(\n endpoint: string,\n query: string,\n variables: TVariables,\n): Promise<TData> {\n const response = await fetch(endpoint, {\n method: \"POST\",\n credentials: \"omit\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ query, variables }),\n });\n\n const payload = (await response.json()) as GraphQLResponse<TData>;\n const errorMessage = payload.errors?.[0]?.message;\n\n if (!response.ok || errorMessage || !payload.data) {\n throw new Error(errorMessage || \"Unable to access shared file\");\n }\n\n return payload.data;\n}\n\nfunction buildSharedFile(payload: {\n id: string;\n name: string;\n workspaceId: string;\n mimeType: string;\n size: string;\n s3Key: string;\n downloadUrl?: string | null;\n}): FileItem {\n const extension = payload.name.includes(\".\")\n ? payload.name.split(\".\").pop() || \"\"\n : \"\";\n\n return {\n id: payload.id,\n name: payload.name,\n workspaceId: payload.workspaceId,\n mimeType: payload.mimeType,\n extension,\n size: Number(payload.size),\n s3Key: payload.s3Key,\n url: payload.downloadUrl ?? \"\",\n downloadUrl: payload.downloadUrl ?? undefined,\n starred: false,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n}\n\nexport function ShareAccessPage() {\n const { t } = useI18n();\n const navigate = useNavigate();\n const { pathname } = useLocation();\n const { token: routeToken } = useParams<{ token: string }>();\n const token = useMemo(() => {\n if (routeToken) {\n return routeToken;\n }\n\n const match = pathname.match(/\\/share\\/([^/]+)/);\n return match?.[1] ? decodeURIComponent(match[1]) : \"\";\n }, [pathname, routeToken]);\n const filesContext = useFilesContext();\n const { apiGatewayUrl } = filesContext;\n const endpoint = useMemo(\n () => resolveWorkspaceGraphQLEndpoint(apiGatewayUrl),\n [apiGatewayUrl],\n );\n const [loading, setLoading] = useState(false);\n const [password, setPassword] = useState(\"\");\n const [requiresPassword, setRequiresPassword] = useState(false);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n const [sharedFile, setSharedFile] = useState<FileItem | null>(null);\n\n const loadShare = useCallback(\n async (sharePassword?: string) => {\n if (!token) {\n throw new Error(\"Share token is missing\");\n }\n\n setLoading(true);\n\n try {\n const data = await requestPublicGraphQL<\n AccessShareMutation,\n AccessShareMutationVariables\n >(endpoint, print(AccessShareDocument), {\n input: {\n token,\n password: sharePassword || undefined,\n },\n });\n\n const payload = data.accessShare;\n if (!payload?.file || !payload.share) {\n throw new Error(payload?.message || \"Shared file is unavailable\");\n }\n\n setRequiresPassword(Boolean(payload.share.requiresPassword));\n setSharedFile(buildSharedFile(payload.file));\n setErrorMessage(null);\n } finally {\n setLoading(false);\n }\n },\n [endpoint, token],\n );\n\n useEffect(() => {\n loadShare().catch((error) => {\n const message =\n error instanceof Error ? error.message : \"Unable to access shared file\";\n setErrorMessage(message);\n setRequiresPassword(message.toLowerCase().includes(\"password\"));\n });\n }, [loadShare]);\n\n const handleDownload = async () => {\n if (!sharedFile) {\n return;\n }\n\n const downloadUrl = sharedFile.downloadUrl || sharedFile.url;\n if (downloadUrl) {\n nativeImpact(\"light\");\n await nativeOpenUrl(downloadUrl);\n emitFilesEvent(filesContext, \"files.share.downloaded\", {\n fileId: sharedFile.id,\n fileName: sharedFile.name,\n });\n }\n };\n\n const handlePasswordSubmit = async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n\n try {\n await loadShare(password);\n } catch (error) {\n setErrorMessage(\n error instanceof Error ? error.message : \"Unable to unlock shared file\",\n );\n }\n };\n\n if (sharedFile) {\n return (\n <FilePreviewModal\n file={sharedFile}\n onClose={() => navigate(\"/files/browse\")}\n onDownload={handleDownload}\n />\n );\n }\n\n return (\n <div className=\"flex min-h-[70vh] items-center justify-center bg-hero-mesh px-4 py-10\">\n <GlassCard treatment=\"glass\" className=\"w-full max-w-md p-6\">\n <button\n type=\"button\"\n onClick={() => navigate(\"/files/browse\")}\n className=\"mb-6 inline-flex items-center gap-2 text-sm font-medium text-text-secondary transition-colors hover:text-text-primary\"\n >\n <ArrowLeft className=\"size-4\" />\n {tWithFallback(t, \"files.share.back\", \"Back to files\")}\n </button>\n\n <div className=\"mb-6\">\n <h1 className=\"text-xl font-semibold text-text-primary\">\n {tWithFallback(t, \"files.share.title\", \"Shared file access\")}\n </h1>\n <p className=\"mt-2 text-sm text-text-secondary\">\n {tWithFallback(\n t,\n \"files.share.subtitle\",\n \"Open a shared file preview using the access token from the share link.\",\n )}\n </p>\n </div>\n\n {loading ? (\n <div className=\"flex items-center gap-3 rounded-lg border border-border-seam bg-bg-sunken px-4 py-3 text-sm text-text-secondary\">\n <Loader2 className=\"size-4 animate-spin text-action-primary-bg\" />\n {tWithFallback(\n t,\n \"files.share.verifying\",\n \"Verifying share access…\",\n )}\n </div>\n ) : requiresPassword ? (\n <form className=\"space-y-4\" onSubmit={handlePasswordSubmit}>\n <label className=\"block text-sm font-medium text-text-primary\">\n {tWithFallback(t, \"files.share.password.label\", \"Share password\")}\n <div className=\"mt-2 flex items-center gap-2 rounded-lg border border-border-seam px-3 py-2\">\n <Lock className=\"size-4 text-text-tertiary\" />\n <input\n type=\"password\"\n value={password}\n onChange={(event) => setPassword(event.target.value)}\n aria-label={tWithFallback(\n t,\n \"files.share.password.label\",\n \"Share password\",\n )}\n className=\"w-full bg-transparent text-sm text-text-primary outline-none\"\n placeholder={tWithFallback(\n t,\n \"files.share.password.placeholder\",\n \"Enter the share password\",\n )}\n />\n </div>\n </label>\n\n {errorMessage && (\n <div className=\"rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {errorMessage}\n </div>\n )}\n\n <button\n type=\"submit\"\n disabled={!password.trim()}\n className=\"inline-flex w-full items-center justify-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2.5 text-sm font-medium text-text-inverse transition-colors hover:bg-action-primary-bg-hover disabled:cursor-not-allowed disabled:bg-bg-sunken disabled:text-text-tertiary\"\n >\n {tWithFallback(t, \"files.share.unlock\", \"Unlock shared file\")}\n </button>\n </form>\n ) : (\n <div className=\"space-y-4\">\n {errorMessage && (\n <div className=\"rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {errorMessage}\n </div>\n )}\n <button\n type=\"button\"\n onClick={() => loadShare()}\n className=\"inline-flex w-full items-center justify-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2.5 text-sm font-medium text-text-inverse transition-colors hover:bg-action-primary-bg-hover\"\n >\n {tWithFallback(\n t,\n \"files.share.retry\",\n \"Retry shared file access\",\n )}\n </button>\n </div>\n )}\n </GlassCard>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AA8BA,SAAS,EAAgC,GAAgC;CACvE,IAAM,IAAgB,KAAiB,EAAO;AAE9C,KAAI,CAAC,EACH,OAAU,MAAM,0CAA0C;AAG5D,QAAO,EAAc,SAAS,WAAW,GACrC,IACA,EAAqB,GAAe,aAAa;;AAGvD,eAAe,EACb,GACA,GACA,GACgB;CAChB,IAAM,IAAW,MAAM,MAAM,GAAU;EACrC,QAAQ;EACR,aAAa;EACb,SAAS,EACP,gBAAgB,oBACjB;EACD,MAAM,KAAK,UAAU;GAAE;GAAO;GAAW,CAAC;EAC3C,CAAC,EAEI,IAAW,MAAM,EAAS,MAAM,EAChC,IAAe,EAAQ,SAAS,IAAI;AAE1C,KAAI,CAAC,EAAS,MAAM,KAAgB,CAAC,EAAQ,KAC3C,OAAU,MAAM,KAAgB,+BAA+B;AAGjE,QAAO,EAAQ;;AAGjB,SAAS,EAAgB,GAQZ;CACX,IAAM,IAAY,EAAQ,KAAK,SAAS,IAAI,IACxC,EAAQ,KAAK,MAAM,IAAI,CAAC,KAAK,IAC7B;AAEJ,QAAO;EACL,IAAI,EAAQ;EACZ,MAAM,EAAQ;EACd,aAAa,EAAQ;EACrB,UAAU,EAAQ;EAClB;EACA,MAAM,OAAO,EAAQ,KAAK;EAC1B,OAAO,EAAQ;EACf,KAAK,EAAQ,eAAe;EAC5B,aAAa,EAAQ,eAAe,KAAA;EACpC,SAAS;EACT,4BAAW,IAAI,MAAM,EAAC,aAAa;EACnC,4BAAW,IAAI,MAAM,EAAC,aAAa;EACpC;;AAGH,SAAgB,IAAkB;CAChC,IAAM,EAAE,SAAM,GAAS,EACjB,IAAW,GAAa,EACxB,EAAE,gBAAa,GAAa,EAC5B,EAAE,OAAO,MAAe,GAA8B,EACtD,IAAQ,QAAc;AAC1B,MAAI,EACF,QAAO;EAGT,IAAM,IAAQ,EAAS,MAAM,mBAAmB;AAChD,SAAO,IAAQ,KAAK,mBAAmB,EAAM,GAAG,GAAG;IAClD,CAAC,GAAU,EAAW,CAAC,EACpB,IAAe,GAAiB,EAChC,EAAE,qBAAkB,GACpB,IAAW,QACT,EAAgC,EAAc,EACpD,CAAC,EAAc,CAChB,EACK,CAAC,GAAS,KAAc,EAAS,GAAM,EACvC,CAAC,GAAU,KAAe,EAAS,GAAG,EACtC,CAAC,GAAkB,KAAuB,EAAS,GAAM,EACzD,CAAC,GAAc,KAAmB,EAAwB,KAAK,EAC/D,CAAC,GAAY,KAAiB,EAA0B,KAAK,EAE7D,IAAY,EAChB,OAAO,MAA2B;AAChC,MAAI,CAAC,EACH,OAAU,MAAM,yBAAyB;AAG3C,IAAW,GAAK;AAEhB,MAAI;GAWF,IAAM,KAVO,MAAM,EAGjB,GAAU,EAAM,EAAoB,EAAE,EACtC,OAAO;IACL;IACA,UAAU,KAAiB,KAAA;IAC5B,EACF,CAAC,EAEmB;AACrB,OAAI,CAAC,GAAS,QAAQ,CAAC,EAAQ,MAC7B,OAAU,MAAM,GAAS,WAAW,6BAA6B;AAKnE,GAFA,EAAoB,EAAQ,EAAQ,MAAM,iBAAkB,EAC5D,EAAc,EAAgB,EAAQ,KAAK,CAAC,EAC5C,EAAgB,KAAK;YACb;AACR,KAAW,GAAM;;IAGrB,CAAC,GAAU,EAAM,CAClB;AAiDD,QA/CA,QAAgB;AACd,KAAW,CAAC,OAAO,MAAU;GAC3B,IAAM,IACJ,aAAiB,QAAQ,EAAM,UAAU;AAE3C,GADA,EAAgB,EAAQ,EACxB,EAAoB,EAAQ,aAAa,CAAC,SAAS,WAAW,CAAC;IAC/D;IACD,CAAC,EAAU,CAAC,EA8BX,IAEA,kBAAC,GAAD;EACE,MAAM;EACN,eAAe,EAAS,gBAAgB;EACxC,YAjCiB,YAAY;AACjC,OAAI,CAAC,EACH;GAGF,IAAM,IAAc,EAAW,eAAe,EAAW;AACzD,GAAI,MACF,EAAa,QAAQ,EACrB,MAAM,EAAc,EAAY,EAChC,EAAe,GAAc,0BAA0B;IACrD,QAAQ,EAAW;IACnB,UAAU,EAAW;IACtB,CAAC;;EAsBA,CAAA,GAKJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GAAW,WAAU;GAAQ,WAAU;aAAvC;IACE,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,EAAS,gBAAgB;KACxC,WAAU;eAHZ,CAKE,kBAAC,GAAD,EAAW,WAAU,UAAW,CAAA,EAC/B,EAAc,GAAG,oBAAoB,gBAAgB,CAC/C;;IAET,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAc,GAAG,qBAAqB,qBAAqB;MACzD,CAAA,EACL,kBAAC,KAAD;MAAG,WAAU;gBACV,EACC,GACA,wBACA,yEACD;MACC,CAAA,CACA;;IAEL,IACC,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAS,WAAU,8CAA+C,CAAA,EACjE,EACC,GACA,yBACA,0BACD,CACG;SACJ,IACF,kBAAC,QAAD;KAAM,WAAU;KAAY,UAzDP,OAAO,MAAsC;AACxE,QAAM,gBAAgB;AAEtB,UAAI;AACF,aAAM,EAAU,EAAS;eAClB,GAAO;AACd,SACE,aAAiB,QAAQ,EAAM,UAAU,+BAC1C;;;eAiDG;MACE,kBAAC,SAAD;OAAO,WAAU;iBAAjB,CACG,EAAc,GAAG,8BAA8B,iBAAiB,EACjE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD,EAAM,WAAU,6BAA8B,CAAA,EAC9C,kBAAC,SAAD;SACE,MAAK;SACL,OAAO;SACP,WAAW,MAAU,EAAY,EAAM,OAAO,MAAM;SACpD,cAAY,EACV,GACA,8BACA,iBACD;SACD,WAAU;SACV,aAAa,EACX,GACA,oCACA,2BACD;SACD,CAAA,CACE;UACA;;MAEP,KACC,kBAAC,OAAD;OAAK,WAAU;iBACZ;OACG,CAAA;MAGR,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,CAAC,EAAS,MAAM;OAC1B,WAAU;iBAET,EAAc,GAAG,sBAAsB,qBAAqB;OACtD,CAAA;MACJ;SAEP,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,KACC,kBAAC,OAAD;MAAK,WAAU;gBACZ;MACG,CAAA,EAER,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,GAAW;MAC1B,WAAU;gBAET,EACC,GACA,qBACA,2BACD;MACM,CAAA,CACL;;IAEE;;EACR,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-files",
3
- "version": "2026.624.2",
3
+ "version": "2026.625.1",
4
4
  "description": "Burdenoff Files Microfrontend - Standalone file management module",
5
5
  "type": "module",
6
6
  "imports": {
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "@apollo/client": "^4.0.13",
48
- "@burdenoff/fe-libs": "2026.623.8",
48
+ "@burdenoff/fe-libs": "2026.625.1",
49
49
  "@tanstack/react-query": "^5.90.17",
50
50
  "graphql": "^16.12.0",
51
51
  "lucide-react": "^0.468.0",