Some checks are pending
E2E / Playwright e2e (push) Waiting to run
- 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.
159 lines
5.5 KiB
TypeScript
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'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>
|
|
)
|
|
}
|