@burdenoff/microfe-files 2026.624.3 → 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.
- package/dist/files/components/FileBrowser.js +2 -2
- package/dist/files/components/FileBrowser.js.map +1 -1
- package/dist/files/components/FileCard.js +112 -110
- package/dist/files/components/FileCard.js.map +1 -1
- package/dist/files/components/FileInfoPanel.js +89 -84
- package/dist/files/components/FileInfoPanel.js.map +1 -1
- package/dist/files/components/FileListItem.js +1 -1
- package/dist/files/components/FileListItem.js.map +1 -1
- package/dist/files/components/FileVersionPanel.js +3 -3
- package/dist/files/components/FileVersionPanel.js.map +1 -1
- package/dist/files/components/FolderCard.js +128 -126
- package/dist/files/components/FolderCard.js.map +1 -1
- package/dist/files/pages/BrowserPage.js +390 -405
- package/dist/files/pages/BrowserPage.js.map +1 -1
- package/dist/files/pages/ShareAccessPage.js +45 -43
- package/dist/files/pages/ShareAccessPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -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 {
|
|
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
|
|
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
|
|
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
|
|
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
|
|
51
|
-
let { t: s } = x(), c = y(), { pathname:
|
|
52
|
-
if (
|
|
53
|
-
let e =
|
|
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
|
-
}, [
|
|
56
|
-
if (!
|
|
57
|
-
|
|
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
|
|
60
|
-
token:
|
|
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
|
-
|
|
65
|
+
R(!!n.share.requiresPassword), H(E(n.file)), B(null);
|
|
65
66
|
} finally {
|
|
66
|
-
|
|
67
|
+
P(!1);
|
|
67
68
|
}
|
|
68
|
-
}, [
|
|
69
|
+
}, [M, k]);
|
|
69
70
|
return u(() => {
|
|
70
|
-
|
|
71
|
+
U().catch((e) => {
|
|
71
72
|
let t = e instanceof Error ? e.message : "Unable to access shared file";
|
|
72
|
-
|
|
73
|
+
B(t), R(t.toLowerCase().includes("password"));
|
|
73
74
|
});
|
|
74
|
-
}, [
|
|
75
|
-
file:
|
|
75
|
+
}, [U]), V ? /* @__PURE__ */ g(r, {
|
|
76
|
+
file: V,
|
|
76
77
|
onClose: () => c("/files/browse"),
|
|
77
78
|
onDownload: async () => {
|
|
78
|
-
if (!
|
|
79
|
-
let e =
|
|
80
|
-
e && (i("light"), await a(e), o(
|
|
81
|
-
fileId:
|
|
82
|
-
fileName:
|
|
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__ */ _(
|
|
88
|
-
|
|
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
|
-
|
|
107
|
-
className: "flex items-center gap-3 rounded-lg border border-border-
|
|
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
|
-
}) :
|
|
111
|
+
}) : L ? /* @__PURE__ */ _("form", {
|
|
110
112
|
className: "space-y-4",
|
|
111
113
|
onSubmit: async (e) => {
|
|
112
114
|
e.preventDefault();
|
|
113
115
|
try {
|
|
114
|
-
await
|
|
116
|
+
await U(F);
|
|
115
117
|
} catch (e) {
|
|
116
|
-
|
|
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-
|
|
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:
|
|
127
|
-
onChange: (e) =>
|
|
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
|
-
|
|
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:
|
|
138
|
+
children: z
|
|
137
139
|
}),
|
|
138
140
|
/* @__PURE__ */ g("button", {
|
|
139
141
|
type: "submit",
|
|
140
|
-
disabled: !
|
|
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: [
|
|
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:
|
|
151
|
+
children: z
|
|
150
152
|
}), /* @__PURE__ */ g("button", {
|
|
151
153
|
type: "button",
|
|
152
|
-
onClick: () =>
|
|
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 {
|
|
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":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@burdenoff/microfe-files",
|
|
3
|
-
"version": "2026.
|
|
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.
|
|
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",
|