import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { CircleX, Copy, Pencil, Save, Building2, UserCircle, Mail, FileText, } from "lucide-react"; import { Form, useDataProvider, useGetIdentity, useGetOne, useNotify, useTranslate, } from "ra-core"; import { useState } from "react"; import { useFormState } from "react-hook-form"; import { useNavigate } from "react-router"; import { RecordField } from "@/components/ds/admin/record-field"; import { TextInput } from "@/components/ds/admin/text-input"; import { Button } from "@/components/ds/ui/button"; import { Card, CardContent } from "@/components/ds/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger, } from "@/components/ds/ui/tabs"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ds/ui/tooltip"; import ImageEditorField from "../misc/ImageEditorField"; import type { CrmDataProvider } from "../providers/types"; import type { SalesFormData } from "../types"; import { TemplatesList } from "../invoices/TemplatesList"; import { isDemoMode } from "@/lib/demo-utils"; import { Alert, AlertDescription } from "@/components/ds/ui/alert"; import { Info, Brain } from "lucide-react"; import { AgentToggle } from "./AgentToggle"; export const SettingsPage = () => { const translate = useTranslate(); return (

{translate("crm.nav.settings")}

{translate("crm.settings.section.profile") || "Profile"} {translate("crm.settings.section.organization") || "Organization"} {translate("resources.invoice_templates.name", { smart_count: 2, }) || "Templates"}
); }; const ProfileSettings = () => { const [isEditMode, setEditMode] = useState(false); const { identity, refetch: refetchIdentity } = useGetIdentity(); const { data, refetch: refetchUser } = useGetOne("sales", { id: identity?.id, }); const notify = useNotify(); const translate = useTranslate(); const dataProvider = useDataProvider(); const { mutate } = useMutation({ mutationKey: ["profile-update"], mutationFn: async (data: SalesFormData) => { if (!identity) throw new Error("Identity not found"); return dataProvider.salesUpdate(identity.id, data); }, onSuccess: () => { refetchIdentity(); refetchUser(); setEditMode(false); notify(translate("crm.settings.notification.profile_updated")); }, onError: () => { notify(translate("crm.settings.notification.error"), { type: "error" }); }, }); if (!identity) return null; return (
mutate(values)} record={data}> {isDemoMode() && ( You are in Demo Mode. Personal settings can be viewed but not all actions (like password changes) are available. )}
mutate(values)} linkPosition="right" />
{!isEditMode && } {isEditMode && }
{import.meta.env.VITE_INBOUND_EMAIL && (

{translate("crm.settings.inbound_email.title")}

{translate("crm.settings.inbound_email.description")}

)}
); }; const OrganizationSettings = () => { const [isEditMode, setEditMode] = useState(false); const notify = useNotify(); const translate = useTranslate(); const dataProvider = useDataProvider(); const queryClient = useQueryClient(); const { data: businessProfile, isLoading, refetch, } = useQuery({ queryKey: ["business_profile"], queryFn: async () => { const { data } = await dataProvider.getOne("business_profile", { id: 1 }); return data; }, }); const { mutate } = useMutation({ mutationFn: async (values: any) => { return dataProvider.update("business_profile", { id: 1, data: values, previousData: businessProfile, }); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["business_profile"] }); refetch(); setEditMode(false); notify( translate("resources.business_profile.notification.updated") || "Organization profile updated", ); }, onError: (error: any) => { notify(error.message || "Error updating organization profile", { type: "error", }); }, }); if (isLoading) return
Loading...
; return (
mutate(values)} record={businessProfile}>
mutate(values)} linkPosition="bottom" />

AI & Automation

{translate("crm.settings.section.email") || "Email Settings"}

{isEditMode && }
); }; // Sub-components const PasswordChangeButton = () => { const translate = useTranslate(); const navigate = useNavigate(); const isDemo = isDemoMode(); return ( {isDemo && (

Password changes are disabled in demo mode

)}
); }; const SaveButton = () => { const translate = useTranslate(); const { isDirty } = useFormState(); return ( ); }; const TextRender = ({ source, label, isEditMode, multiline = false, rows = 1, helperText, type = "text", disabled = false, }: { source: string; label: string; isEditMode: boolean; multiline?: boolean; rows?: number; helperText?: string; type?: "text" | "password"; disabled?: boolean; }) => { if (isEditMode) { return ( ); } return (

{label}

); }; const CopyPaste = ({ value }: { value: string }) => { const [copied, setCopied] = useState(false); const translate = useTranslate(); const handleCopy = () => { setCopied(true); navigator.clipboard.writeText(value); setTimeout(() => setCopied(false), 1500); }; return (

{copied ? "Copied!" : translate("crm.integrations.api_keys.action.copy")}

); }; SettingsPage.path = "/settings";