"use client" import { create } from "zustand" import type { OrgSettingsMeta } from "@/lib/admin-settings/map-api-org-settings" import type { Administrator, AuthentikSettings, FilePolicySettings, IntegrationEntry, MailingSettings, NextcloudSettings, OnlyOfficeSettings, RichTextSettings, OrgLLMSettings, OrgSearchSettings, OrgStorageQuotas, PluginEntry, TwoFactorPolicy, UsageQuotaDefaults, IdentityProvidersPolicy, } from "@/lib/admin-settings/org-settings-types" const DEFAULT_AUTHENTIK: AuthentikSettings = { enabled: true, api_url: "", slug: "ulti-suite", client_id: "", enforce_sso: true, allow_password_fallback: false, default_groups: "ulti-users", } const DEFAULT_IDENTITY_PROVIDERS: IdentityProvidersPolicy = { allow_self_enrollment: true, default_login_source: "", providers: [], } const DEFAULT_TWO_FACTOR: TwoFactorPolicy = { required_for_all: false, required_for_admins: true, allowed_methods: ["totp", "webauthn"], grace_period_days: 7, remember_device_days: 30, } const DEFAULT_STORAGE_QUOTAS: OrgStorageQuotas = { default_mail_gib: 5, default_drive_gib: 5, default_photos_gib: 5, warn_threshold_pct: 90, } const DEFAULT_USAGE_QUOTAS: UsageQuotaDefaults = { llm_requests_per_day: 100, llm_tokens_per_month: 500_000, search_requests_per_day: 50, max_api_tokens_per_user: 10, max_webhooks_per_user: 20, } const DEFAULT_FILE_POLICIES: FilePolicySettings = { max_upload_mib: 512, allowed_extensions: "", block_executable: true, external_sharing: "authenticated", default_link_expiry_days: 30, virus_scan_enabled: false, virustotal_api_key: "", retention_trash_days: 30, } const DEFAULT_LLM: OrgLLMSettings = { default_provider_id: "", providers: [], enforce_org_providers: false, allow_user_override: true, } const DEFAULT_SEARCH: OrgSearchSettings = { suite_engine: "postgres", meilisearch_url: "", meilisearch_api_key: "", typesense_url: "", typesense_api_key: "", web_search: { default_provider_id: "brave-default", providers: [] }, enforce_org_search: false, } const DEFAULT_NEXTCLOUD: NextcloudSettings = { enabled: false, base_url: "", admin_user: "", admin_password: "", drive_enabled: true, calendar_enabled: true, contacts_enabled: true, talk_enabled: false, } const DEFAULT_MAILING: MailingSettings = { enabled: false, smtp_host: "", smtp_port: 587, smtp_user: "", smtp_password: "", from_email: "noreply@example.com", from_name: "Ulti Suite", tls_mode: "starttls", } const DEFAULT_ONLYOFFICE: OnlyOfficeSettings = { enabled: false, document_server_url: "", jwt_secret: "", jwt_header: "Authorization", } const DEFAULT_RICHTEXT: RichTextSettings = { enabled: true, storage_mode: "sidecar", export_mirror_format: "", hocuspocus_url: "", } const DEFAULT_PLUGINS: PluginEntry[] = [ { id: "mail-automation", name: "Automatisations mail", description: "Règles, webhooks et tri IA sur la réception.", enabled: true, version: "1.0.0", }, { id: "contact-discovery", name: "Découverte contacts", description: "Enrichissement IA et signatures détectées.", enabled: true, version: "1.0.0", }, { id: "public-share", name: "Partage public Drive", description: "Liens publics et partages externes.", enabled: true, version: "1.0.0", }, { id: "office-editor", name: "Édition OnlyOffice", description: "Édition collaborative de documents.", enabled: false, version: "1.0.0", }, { id: "richtext-editor", name: "Édition rich text TipTap", description: "Éditeur texte collaboratif pour documents Word.", enabled: true, version: "1.0.0", }, ] const DEFAULT_INTEGRATIONS: IntegrationEntry[] = [ { id: "authentik", name: "Authentik", description: "SSO, groupes et provisionnement des comptes.", enabled: true, configured: false, href: "/admin/settings/authentication", }, { id: "nextcloud", name: "Nextcloud", description: "Drive, agenda, contacts et Talk.", enabled: false, configured: false, href: "/admin/settings/nextcloud", }, { id: "onlyoffice", name: "OnlyOffice", description: "Édition de documents dans le navigateur.", enabled: false, configured: false, href: "/admin/settings/onlyoffice", }, { id: "smtp", name: "Mailing unifié", description: "SMTP pour notifications suite (partages, mentions).", enabled: false, configured: false, href: "/admin/settings/mailing", }, ] type OrgSettingsActions = { setAuthentik: (patch: Partial) => void setIdentityProviders: (patch: Partial) => void setTwoFactor: (patch: Partial) => void setStorageQuotas: (patch: Partial) => void setUsageQuotas: (patch: Partial) => void setFilePolicies: (patch: Partial) => void setLlm: (patch: Partial) => void setSearch: (patch: Partial) => void setNextcloud: (patch: Partial) => void setMailing: (patch: Partial) => void setOnlyoffice: (patch: Partial) => void setRichtext: (patch: Partial) => void setAdministrators: (admins: Administrator[]) => void addAdministrator: (admin: Administrator) => void removeAdministrator: (id: string) => void updateAdministrator: (id: string, patch: Partial) => void setPlugins: (plugins: PluginEntry[]) => void togglePlugin: (id: string, enabled: boolean) => void setIntegrations: (integrations: IntegrationEntry[]) => void toggleIntegration: (id: string, enabled: boolean) => void hydrateFromApi: (patch: Partial<{ authentik: AuthentikSettings identityProviders: IdentityProvidersPolicy twoFactor: TwoFactorPolicy storageQuotas: OrgStorageQuotas usageQuotas: UsageQuotaDefaults filePolicies: FilePolicySettings llm: OrgLLMSettings search: OrgSearchSettings administrators: Administrator[] nextcloud: NextcloudSettings mailing: MailingSettings onlyoffice: OnlyOfficeSettings richtext: RichTextSettings plugins: PluginEntry[] integrations: IntegrationEntry[] }>, meta?: OrgSettingsMeta) => void } export const useOrgSettingsStore = create< { authentik: AuthentikSettings identityProviders: IdentityProvidersPolicy twoFactor: TwoFactorPolicy storageQuotas: OrgStorageQuotas usageQuotas: UsageQuotaDefaults filePolicies: FilePolicySettings llm: OrgLLMSettings search: OrgSearchSettings administrators: Administrator[] nextcloud: NextcloudSettings mailing: MailingSettings onlyoffice: OnlyOfficeSettings richtext: RichTextSettings plugins: PluginEntry[] integrations: IntegrationEntry[] meta: OrgSettingsMeta | null apiSynced: boolean } & OrgSettingsActions >()((set) => ({ authentik: DEFAULT_AUTHENTIK, identityProviders: DEFAULT_IDENTITY_PROVIDERS, twoFactor: DEFAULT_TWO_FACTOR, storageQuotas: DEFAULT_STORAGE_QUOTAS, usageQuotas: DEFAULT_USAGE_QUOTAS, filePolicies: DEFAULT_FILE_POLICIES, llm: DEFAULT_LLM, search: DEFAULT_SEARCH, administrators: [], nextcloud: DEFAULT_NEXTCLOUD, mailing: DEFAULT_MAILING, onlyoffice: DEFAULT_ONLYOFFICE, richtext: DEFAULT_RICHTEXT, plugins: DEFAULT_PLUGINS, integrations: DEFAULT_INTEGRATIONS, meta: null, apiSynced: false, setAuthentik: (patch) => set((s) => ({ authentik: { ...s.authentik, ...patch } })), setIdentityProviders: (patch) => set((s) => ({ identityProviders: { ...s.identityProviders, ...patch }, })), setTwoFactor: (patch) => set((s) => ({ twoFactor: { ...s.twoFactor, ...patch } })), setStorageQuotas: (patch) => set((s) => ({ storageQuotas: { ...s.storageQuotas, ...patch } })), setUsageQuotas: (patch) => set((s) => ({ usageQuotas: { ...s.usageQuotas, ...patch } })), setFilePolicies: (patch) => set((s) => ({ filePolicies: { ...s.filePolicies, ...patch } })), setLlm: (patch) => set((s) => ({ llm: { ...s.llm, ...patch } })), setSearch: (patch) => set((s) => ({ search: { ...s.search, ...patch } })), setNextcloud: (patch) => set((s) => ({ nextcloud: { ...s.nextcloud, ...patch } })), setMailing: (patch) => set((s) => ({ mailing: { ...s.mailing, ...patch } })), setOnlyoffice: (patch) => set((s) => ({ onlyoffice: { ...s.onlyoffice, ...patch } })), setRichtext: (patch) => set((s) => ({ richtext: { ...s.richtext, ...patch } })), setAdministrators: (administrators) => set({ administrators }), addAdministrator: (admin) => set((s) => ({ administrators: [...s.administrators, admin] })), removeAdministrator: (id) => set((s) => ({ administrators: s.administrators.filter((a) => a.id !== id), })), updateAdministrator: (id, patch) => set((s) => ({ administrators: s.administrators.map((a) => a.id === id ? { ...a, ...patch } : a ), })), setPlugins: (plugins) => set({ plugins }), togglePlugin: (id, enabled) => set((s) => ({ plugins: s.plugins.map((p) => (p.id === id ? { ...p, enabled } : p)), })), setIntegrations: (integrations) => set({ integrations }), toggleIntegration: (id, enabled) => set((s) => ({ integrations: s.integrations.map((i) => i.id === id ? { ...i, enabled } : i ), })), hydrateFromApi: (patch, meta) => set((s) => ({ ...s, ...patch, meta: meta ?? s.meta, apiSynced: true, })), }))