ultisuite-client/components/drive/drive-name-dialog.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

128 lines
3.2 KiB
TypeScript

"use client"
import { useEffect, useRef, useState } from "react"
import { Button } from "@/components/ui/button"
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog"
import { Input } from "@/components/ui/input"
import {
DRIVE_BTN_GHOST,
DRIVE_BTN_PRIMARY,
DRIVE_DIALOG_BODY,
DRIVE_DIALOG_CONTENT,
DRIVE_DIALOG_FOOTER,
DRIVE_DIALOG_HEADER,
DRIVE_DIALOG_OVERLAY,
DRIVE_FIELD_CLASS,
DRIVE_TEXT_SECONDARY,
DRIVE_TEXT_TITLE,
} from "@/lib/drive/drive-dialog-styles"
import { cn } from "@/lib/utils"
export function DriveNameDialog({
open,
onOpenChange,
title,
description,
defaultValue,
confirmLabel = "Créer",
onConfirm,
}: {
open: boolean
onOpenChange: (open: boolean) => void
title: string
description?: string
defaultValue: string
confirmLabel?: string
onConfirm: (name: string) => void | Promise<void>
}) {
const [value, setValue] = useState(defaultValue)
const [busy, setBusy] = useState(false)
const inputRef = useRef<HTMLInputElement>(null)
useEffect(() => {
if (!open) return
setValue(defaultValue)
const t = setTimeout(() => {
const el = inputRef.current
if (!el) return
el.focus()
el.select()
}, 0)
return () => clearTimeout(t)
}, [open, defaultValue])
const submit = async () => {
const trimmed = value.trim()
if (!trimmed || busy) return
setBusy(true)
try {
await onConfirm(trimmed)
onOpenChange(false)
} finally {
setBusy(false)
}
}
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent
showCloseButton={!busy}
overlayClassName={DRIVE_DIALOG_OVERLAY}
className={cn(DRIVE_DIALOG_CONTENT, "sm:max-w-[420px]")}
onOpenAutoFocus={(e) => e.preventDefault()}
{...(description ? {} : { "aria-describedby": undefined })}
>
<DialogHeader className={DRIVE_DIALOG_HEADER}>
<DialogTitle className={cn("text-base font-medium", DRIVE_TEXT_TITLE)}>
{title}
</DialogTitle>
{description ? (
<DialogDescription className={cn("text-sm", DRIVE_TEXT_SECONDARY)}>
{description}
</DialogDescription>
) : null}
</DialogHeader>
<div className={DRIVE_DIALOG_BODY}>
<Input
ref={inputRef}
value={value}
onChange={(e) => setValue(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter") void submit()
}}
disabled={busy}
autoComplete="off"
className={DRIVE_FIELD_CLASS}
/>
</div>
<DialogFooter className={DRIVE_DIALOG_FOOTER}>
<Button
type="button"
variant="ghost"
className={DRIVE_BTN_GHOST}
onClick={() => onOpenChange(false)}
disabled={busy}
>
Annuler
</Button>
<Button
type="button"
className={DRIVE_BTN_PRIMARY}
onClick={() => void submit()}
disabled={busy || !value.trim()}
>
{confirmLabel}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}