ultisuite-client/components/admin/settings/sections/agenda-section.tsx
R3D347HR4Y ad1370ea7e
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
feat: enhance configuration and add new demo layouts
- Introduced turbopack alias for canvas in next.config.mjs.
- Updated package.json scripts for development and branding tasks.
- Added new dependencies for Tiptap extensions.
- Implemented new demo layouts for agenda, contacts, drive, and mail applications.
- Enhanced globals.css for improved theming and splash screen animations.
- Added OAuth callback handling for drive mounts.
- Updated layout components to integrate new demo shells and improve structure.
2026-06-12 19:10:24 +02:00

159 lines
5.5 KiB
TypeScript

"use client"
import { useEffect, useState } from "react"
import { OrgSettingsSection } from "@/components/admin/settings/org-settings-form"
import { AgendaVideoProviderSelectLabel } from "@/components/agenda/agenda-video-provider-select-label"
import { useOrgSettingsStore } from "@/lib/admin-settings/org-settings-store"
import {
AGENDA_VIDEO_PROVIDER_LABELS,
AGENDA_VIDEO_PROVIDERS,
type AgendaVideoProvider,
} from "@/lib/agenda/agenda-settings-types"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Switch } from "@/components/ui/switch"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import type { MailThemeMode } from "@/lib/mail-settings/types"
const THEME_OPTIONS: { id: MailThemeMode; label: string }[] = [
{ id: "light", label: "Clair" },
{ id: "dark", label: "Sombre" },
{ id: "system", label: "Système" },
]
export function AgendaSection() {
const agenda = useOrgSettingsStore((s) => s.agenda)
const setAgenda = useOrgSettingsStore((s) => s.setAgenda)
const [draft, setDraft] = useState(agenda)
useEffect(() => {
setDraft(agenda)
}, [agenda])
const updateApiKey = (provider: AgendaVideoProvider, value: string) => {
setDraft((prev) => ({
...prev,
video_provider_api_keys: {
...prev.video_provider_api_keys,
[provider]: value,
},
}))
}
return (
<OrgSettingsSection
title="Agenda"
description="Thème et visioconférence par défaut pour toute l'organisation."
policySection="agenda"
beforeSave={() => setAgenda(draft)}
>
<div className="space-y-6 rounded-lg border p-4">
<div className="space-y-3">
<label className="flex items-center justify-between gap-4">
<div>
<p className="text-sm font-medium">Imposer le thème organisationnel</p>
<p className="text-xs text-muted-foreground">
Les utilisateurs ne peuvent plus changer le mode clair/sombre.
</p>
</div>
<Switch
checked={draft.enforce_org_theme}
onCheckedChange={(v) => setDraft((p) => ({ ...p, enforce_org_theme: v }))}
/>
</label>
<div>
<Label>Thème par défaut</Label>
<Select
value={draft.default_theme_mode}
onValueChange={(v) =>
setDraft((p) => ({ ...p, default_theme_mode: v as MailThemeMode }))
}
>
<SelectTrigger className="mt-1 h-9 w-full max-w-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
{THEME_OPTIONS.map((opt) => (
<SelectItem key={opt.id} value={opt.id}>
{opt.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
<div className="space-y-3 border-t pt-4">
<label className="flex items-center justify-between gap-4">
<div>
<p className="text-sm font-medium">Imposer le fournisseur visio</p>
<p className="text-xs text-muted-foreground">
Les utilisateurs ne peuvent plus choisir Zoom, Meet, etc.
</p>
</div>
<Switch
checked={draft.enforce_org_video_provider}
onCheckedChange={(v) =>
setDraft((p) => ({ ...p, enforce_org_video_provider: v }))
}
/>
</label>
<div>
<Label>Fournisseur visio par défaut</Label>
<Select
value={draft.default_video_provider}
onValueChange={(v) =>
setDraft((p) => ({
...p,
default_video_provider: v as AgendaVideoProvider,
}))
}
>
<SelectTrigger className="mt-1 h-9 w-full max-w-xs">
<SelectValue>
<AgendaVideoProviderSelectLabel provider={draft.default_video_provider} />
</SelectValue>
</SelectTrigger>
<SelectContent>
{AGENDA_VIDEO_PROVIDERS.map((provider) => (
<SelectItem key={provider} value={provider}>
<AgendaVideoProviderSelectLabel provider={provider} />
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
<div className="space-y-3 border-t pt-4">
<p className="text-sm font-medium">Clés API visioconférence (organisation)</p>
<p className="text-xs text-muted-foreground">
Stockées côté serveur. UltiMeet n&apos;exige pas de clé API.
</p>
{(["zoom", "google_meet", "teams", "jitsi"] as AgendaVideoProvider[]).map(
(provider) => (
<div key={provider}>
<Label>{AGENDA_VIDEO_PROVIDER_LABELS[provider]}</Label>
<Input
type="password"
autoComplete="off"
className="mt-1 h-9"
placeholder="Clé API (laisser vide pour conserver l'existante)"
value={draft.video_provider_api_keys[provider] ?? ""}
onChange={(e) => updateApiKey(provider, e.target.value)}
/>
</div>
),
)}
</div>
</div>
</OrgSettingsSection>
)
}