ultisuite-client/app/drive/s/[token]/[[...path]]/page.tsx
R3D347HR4Y 6ec95262af Add OnlyOffice integration and update project configurations
- Updated .env.example to include configuration for OnlyOffice Document Server.
- Modified the workspace configuration to remove the drive-suite path.
- Adjusted TypeScript environment imports for consistency.
- Enhanced Next.js configuration to disable canvas in Webpack.
- Updated package.json to include new dependencies for OnlyOffice and PDF.js.
- Added global styles for OnlyOffice theme integration in the CSS.
- Created new layout and page components for the Drive feature, including public sharing and editing functionalities.
- Updated metadata handling across various layouts to reflect the new app structure.
2026-06-07 15:49:21 +02:00

92 lines
3.3 KiB
TypeScript

"use client"
import { useParams } from "next/navigation"
import { useEffect, useState } from "react"
import { Loader2, Lock } from "lucide-react"
import {
PublicShareChrome,
PublicShareViewPanel,
} from "@/components/drive/public-share-view"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { usePublicShare } from "@/lib/api/hooks/use-public-share-queries"
import { folderPathFromPublicSegments } from "@/lib/api/public-share"
export default function PublicSharePage() {
const params = useParams()
const token = String(params.token ?? "")
const pathSegments = params.path as string[] | undefined
const path = folderPathFromPublicSegments(pathSegments)
const [passwordInput, setPasswordInput] = useState("")
const [password, setPassword] = useState<string | undefined>(undefined)
const { data, isLoading, isError, error, refetch, isFetching } = usePublicShare(
token,
path,
password
)
const needsPassword =
isError && error instanceof Error && error.message === "password_required"
useEffect(() => {
if (password && typeof window !== "undefined") {
sessionStorage.setItem(`public-share-pw:${token}`, password)
}
}, [password, token])
const submitPassword = (event: React.FormEvent) => {
event.preventDefault()
const trimmed = passwordInput.trim()
if (!trimmed) return
setPassword(trimmed)
}
return (
<PublicShareChrome>
{isLoading || (isFetching && !data) ? (
<div className="flex min-h-[40vh] items-center justify-center">
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
</div>
) : needsPassword ? (
<div className="mx-auto flex min-h-[40vh] max-w-md flex-col justify-center px-4 py-12">
<div className="rounded-2xl border border-border bg-mail-surface p-6 shadow-sm">
<div className="mb-4 flex items-center gap-2 text-[#3c4043] dark:text-[#e8eaed]">
<Lock className="h-5 w-5" />
<h1 className="text-lg font-medium">Lien protégé par mot de passe</h1>
</div>
<p className="mb-4 text-sm text-muted-foreground">
Saisissez le mot de passe pour accéder à ce partage.
</p>
<form className="flex flex-col gap-3" onSubmit={submitPassword}>
<Input
type="password"
autoComplete="current-password"
placeholder="Mot de passe"
value={passwordInput}
onChange={(e) => setPasswordInput(e.target.value)}
/>
<Button type="submit">Accéder</Button>
</form>
</div>
</div>
) : isError || !data ? (
<div className="mx-auto max-w-lg px-4 py-16 text-center">
<h1 className="text-lg font-medium text-[#3c4043] dark:text-[#e8eaed]">
Partage indisponible
</h1>
<p className="mt-2 text-sm text-muted-foreground">
Ce lien est expiré, révoqué ou incorrect.
</p>
<Button type="button" variant="outline" className="mt-6" onClick={() => void refetch()}>
Réessayer
</Button>
</div>
) : (
<PublicShareViewPanel token={token} path={path} data={data} password={password} />
)}
</PublicShareChrome>
)
}