@open-mercato/core 0.6.4-develop.4339.1.fad812f76f → 0.6.4-develop.4358.1.233d5675c7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js +15 -10
- package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +2 -6
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentDialog.js +10 -12
- package/dist/modules/sales/components/documents/AdjustmentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +10 -10
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentDialog.js +8 -15
- package/dist/modules/sales/components/documents/PaymentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +10 -14
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/workflows/components/EdgeEditDialog.js +3 -9
- package/dist/modules/workflows/components/EdgeEditDialog.js.map +2 -2
- package/dist/modules/workflows/components/NodeEditDialog.js +3 -9
- package/dist/modules/workflows/components/NodeEditDialog.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/customers/components/detail/ConfirmDealLostDialog.tsx +15 -10
- package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +2 -6
- package/src/modules/sales/components/documents/AdjustmentDialog.tsx +11 -12
- package/src/modules/sales/components/documents/LineItemDialog.tsx +11 -10
- package/src/modules/sales/components/documents/PaymentDialog.tsx +9 -16
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +10 -14
- package/src/modules/workflows/components/EdgeEditDialog.tsx +3 -9
- package/src/modules/workflows/components/NodeEditDialog.tsx +3 -9
|
@@ -8,6 +8,7 @@ import { Alert, AlertDescription, AlertTitle } from "@open-mercato/ui/primitives
|
|
|
8
8
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
9
9
|
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@open-mercato/ui/primitives/dialog";
|
|
10
10
|
import { Textarea } from "@open-mercato/ui/primitives/textarea";
|
|
11
|
+
import { useDialogKeyHandler } from "@open-mercato/ui/hooks/useDialogKeyHandler";
|
|
11
12
|
function ConfirmDealLostDialog({
|
|
12
13
|
open,
|
|
13
14
|
dealTitle,
|
|
@@ -22,6 +23,7 @@ function ConfirmDealLostDialog({
|
|
|
22
23
|
const [lossReasons, setLossReasons] = React.useState([]);
|
|
23
24
|
const [reasonListOpen, setReasonListOpen] = React.useState(false);
|
|
24
25
|
const [error, setError] = React.useState("");
|
|
26
|
+
const [isConfirming, setIsConfirming] = React.useState(false);
|
|
25
27
|
React.useEffect(() => {
|
|
26
28
|
if (!open) return;
|
|
27
29
|
let cancelled = false;
|
|
@@ -51,17 +53,20 @@ function ConfirmDealLostDialog({
|
|
|
51
53
|
setError(t("customers.deals.detail.lost.reasonRequired", "Please select a loss reason"));
|
|
52
54
|
return;
|
|
53
55
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
void handleConfirm();
|
|
56
|
+
setIsConfirming(true);
|
|
57
|
+
try {
|
|
58
|
+
await onConfirm({
|
|
59
|
+
lossReasonId,
|
|
60
|
+
lossNotes: lossNotes.trim() || void 0
|
|
61
|
+
});
|
|
62
|
+
} finally {
|
|
63
|
+
setIsConfirming(false);
|
|
63
64
|
}
|
|
64
|
-
}, [
|
|
65
|
+
}, [lossNotes, lossReasonId, onConfirm, t]);
|
|
66
|
+
const handleKeyDown = useDialogKeyHandler({
|
|
67
|
+
onConfirm: () => void handleConfirm(),
|
|
68
|
+
disabled: isConfirming
|
|
69
|
+
});
|
|
65
70
|
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (nextOpen) => {
|
|
66
71
|
if (!nextOpen) onClose();
|
|
67
72
|
}, children: /* @__PURE__ */ jsx(DialogContent, { className: "overflow-hidden p-0 sm:max-w-[560px]", onKeyDown: handleKeyDown, children: /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-lg bg-card", children: [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/components/detail/ConfirmDealLostDialog.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { AlertTriangle, Check, ChevronDown } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { loadDictionaryEntriesByKey } from '@open-mercato/core/modules/dictionaries/lib/clientEntries'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\n\ntype LossReasonOption = {\n id: string\n value: string\n label: string\n description?: string | null\n}\n\ntype ConfirmDealLostDialogProps = {\n open: boolean\n dealTitle: string\n dealValue?: string | null\n companyName?: string | null\n onClose: () => void\n onConfirm: (input: { lossReasonId: string; lossNotes?: string }) => void | Promise<void>\n}\n\nexport function ConfirmDealLostDialog({\n open,\n dealTitle,\n dealValue,\n companyName,\n onClose,\n onConfirm,\n}: ConfirmDealLostDialogProps) {\n const t = useT()\n const [lossReasonId, setLossReasonId] = React.useState('')\n const [lossNotes, setLossNotes] = React.useState('')\n const [lossReasons, setLossReasons] = React.useState<LossReasonOption[]>([])\n const [reasonListOpen, setReasonListOpen] = React.useState(false)\n const [error, setError] = React.useState('')\n\n React.useEffect(() => {\n if (!open) return\n let cancelled = false\n loadDictionaryEntriesByKey('sales.deal_loss_reason')\n .then((items) => {\n if (!cancelled) setLossReasons(items)\n })\n .catch((loadError) => {\n console.error('customers.deals.detail.lossReasons failed', loadError)\n if (!cancelled) setLossReasons([])\n })\n return () => {\n cancelled = true\n }\n }, [open])\n\n React.useEffect(() => {\n if (!open) return\n setLossReasonId('')\n setLossNotes('')\n setReasonListOpen(false)\n setError('')\n }, [open])\n\n const selectedLossReason = React.useMemo(\n () => lossReasons.find((reason) => reason.id === lossReasonId) ?? null,\n [lossReasonId, lossReasons],\n )\n\n const handleConfirm = React.useCallback(async () => {\n if (!lossReasonId) {\n setError(t('customers.deals.detail.lost.reasonRequired', 'Please select a loss reason'))\n return\n }\n await onConfirm({\n
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { AlertTriangle, Check, ChevronDown } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { loadDictionaryEntriesByKey } from '@open-mercato/core/modules/dictionaries/lib/clientEntries'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { useDialogKeyHandler } from '@open-mercato/ui/hooks/useDialogKeyHandler'\n\ntype LossReasonOption = {\n id: string\n value: string\n label: string\n description?: string | null\n}\n\ntype ConfirmDealLostDialogProps = {\n open: boolean\n dealTitle: string\n dealValue?: string | null\n companyName?: string | null\n onClose: () => void\n onConfirm: (input: { lossReasonId: string; lossNotes?: string }) => void | Promise<void>\n}\n\nexport function ConfirmDealLostDialog({\n open,\n dealTitle,\n dealValue,\n companyName,\n onClose,\n onConfirm,\n}: ConfirmDealLostDialogProps) {\n const t = useT()\n const [lossReasonId, setLossReasonId] = React.useState('')\n const [lossNotes, setLossNotes] = React.useState('')\n const [lossReasons, setLossReasons] = React.useState<LossReasonOption[]>([])\n const [reasonListOpen, setReasonListOpen] = React.useState(false)\n const [error, setError] = React.useState('')\n const [isConfirming, setIsConfirming] = React.useState(false)\n\n React.useEffect(() => {\n if (!open) return\n let cancelled = false\n loadDictionaryEntriesByKey('sales.deal_loss_reason')\n .then((items) => {\n if (!cancelled) setLossReasons(items)\n })\n .catch((loadError) => {\n console.error('customers.deals.detail.lossReasons failed', loadError)\n if (!cancelled) setLossReasons([])\n })\n return () => {\n cancelled = true\n }\n }, [open])\n\n React.useEffect(() => {\n if (!open) return\n setLossReasonId('')\n setLossNotes('')\n setReasonListOpen(false)\n setError('')\n }, [open])\n\n const selectedLossReason = React.useMemo(\n () => lossReasons.find((reason) => reason.id === lossReasonId) ?? null,\n [lossReasonId, lossReasons],\n )\n\n const handleConfirm = React.useCallback(async () => {\n if (!lossReasonId) {\n setError(t('customers.deals.detail.lost.reasonRequired', 'Please select a loss reason'))\n return\n }\n setIsConfirming(true)\n try {\n await onConfirm({\n lossReasonId,\n lossNotes: lossNotes.trim() || undefined,\n })\n } finally {\n setIsConfirming(false)\n }\n }, [lossNotes, lossReasonId, onConfirm, t])\n\n const handleKeyDown = useDialogKeyHandler({\n onConfirm: () => void handleConfirm(),\n disabled: isConfirming,\n })\n\n return (\n <Dialog open={open} onOpenChange={(nextOpen) => { if (!nextOpen) onClose() }}>\n <DialogContent className=\"overflow-hidden p-0 sm:max-w-[560px]\" onKeyDown={handleKeyDown}>\n <div className=\"overflow-hidden rounded-lg bg-card\">\n <DialogHeader className=\"border-b border-border/70 px-7 py-5\">\n <div className=\"flex items-start gap-4\">\n <div className=\"flex size-10 shrink-0 items-center justify-center rounded-md bg-destructive/10 text-destructive\">\n <AlertTriangle className=\"size-5\" />\n </div>\n <div className=\"min-w-0\">\n <DialogTitle className=\"text-lg font-bold leading-none tracking-tight text-foreground\">\n {t('customers.deals.detail.lost.title', 'Mark deal as Lost?')}\n </DialogTitle>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {dealTitle}\n {dealValue ? ` \u00B7 ${dealValue}` : ''}\n {companyName ? ` \u00B7 ${companyName}` : ''}\n </p>\n </div>\n </div>\n </DialogHeader>\n\n <div className=\"space-y-6 px-7 py-6\">\n <Alert variant=\"warning\" className=\"rounded-md\">\n <AlertTriangle className=\"size-4\" />\n <AlertTitle>\n {t('customers.deals.detail.lost.warningTitle', 'This action closes the deal')}\n </AlertTitle>\n <AlertDescription>\n {t('customers.deals.detail.lost.warning', \"This action sets the stage to 'Lost' and cannot be undone without 'sales.reopen' permission\")}\n </AlertDescription>\n </Alert>\n\n <div className=\"space-y-2\">\n <label className=\"text-sm font-semibold text-foreground\">\n {t('customers.deals.detail.lost.reasonLabel', 'Loss reason')}\n <span className=\"ml-1 text-destructive\">*</span>\n </label>\n <div className=\"space-y-3\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setReasonListOpen((current) => !current)}\n className=\"h-auto flex w-full items-center justify-between rounded-md border-2 border-foreground bg-background px-4 py-3 text-left\"\n >\n <div className=\"min-w-0\">\n <div className=\"truncate text-base font-semibold text-foreground\">\n {selectedLossReason?.label ?? t('customers.deals.detail.lost.reasonPlaceholder', 'Select loss reason')}\n </div>\n <div className=\"truncate text-sm text-muted-foreground\">\n {selectedLossReason?.description ?? t('customers.deals.detail.lost.reasonHelp', 'Choose the closest reason from the dictionary.')}\n </div>\n </div>\n <ChevronDown className=\"ml-3 size-4 shrink-0 text-muted-foreground\" />\n </Button>\n\n {reasonListOpen ? (\n <div className=\"overflow-hidden rounded-md border border-border/80 bg-background\">\n {lossReasons.map((reason, index) => {\n const isSelected = reason.id === lossReasonId\n return (\n <Button\n key={reason.id}\n type=\"button\"\n variant=\"ghost\"\n onClick={() => {\n setLossReasonId(reason.id)\n setReasonListOpen(false)\n setError('')\n }}\n className={`h-auto flex w-full items-center justify-between rounded-none px-4 py-3 text-left ${\n index < lossReasons.length - 1 ? 'border-b border-border/60' : ''\n } ${isSelected ? 'bg-muted/60' : 'hover:bg-accent/50'}`}\n >\n <div className=\"min-w-0\">\n <div className=\"text-base font-semibold text-foreground\">{reason.label}</div>\n <div className=\"text-sm text-muted-foreground\">\n {reason.description ?? t('customers.deals.detail.lost.reasonFallbackDescription', 'No description available.')}\n </div>\n </div>\n {isSelected ? (\n <span className=\"ml-3 flex size-6 shrink-0 items-center justify-center rounded-full bg-foreground text-background\">\n <Check className=\"size-3.5\" />\n </span>\n ) : null}\n </Button>\n )\n })}\n </div>\n ) : null}\n </div>\n {error ? <p className=\"text-xs text-destructive\">{error}</p> : null}\n </div>\n\n <div className=\"space-y-2\">\n <label className=\"text-sm font-semibold text-foreground\">\n {t('customers.deals.detail.lost.notesLabel', 'Loss notes (optional)')}\n </label>\n <Textarea\n value={lossNotes}\n onChange={(event) => setLossNotes(event.target.value)}\n placeholder={t('customers.deals.detail.lost.notesPlaceholder', 'Additional context about the loss...')}\n rows={4}\n className=\"min-h-[88px] rounded-md border-border/80 px-4 py-3 shadow-none\"\n />\n </div>\n </div>\n\n <DialogFooter className=\"border-t border-border/70 px-7 py-4 sm:justify-end\">\n <Button type=\"button\" variant=\"outline\" onClick={onClose}>\n {t('customers.deals.detail.lost.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" variant=\"destructive\" onClick={() => { void handleConfirm() }}>\n {t('customers.deals.detail.lost.confirm', 'Mark as Lost')}\n </Button>\n </DialogFooter>\n </div>\n </DialogContent>\n </Dialog>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -13,6 +13,7 @@ import { Alert, AlertDescription, AlertTitle } from "@open-mercato/ui/primitives
|
|
|
13
13
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
14
14
|
import { IconButton } from "@open-mercato/ui/primitives/icon-button";
|
|
15
15
|
import { Dialog, DialogContent, DialogTitle } from "@open-mercato/ui/primitives/dialog";
|
|
16
|
+
import { useDialogKeyHandler } from "@open-mercato/ui/hooks/useDialogKeyHandler";
|
|
16
17
|
import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
|
|
17
18
|
import { PhoneNumberField, SwitchableMarkdownInput } from "@open-mercato/ui/backend/inputs";
|
|
18
19
|
import { useConfirmDialog } from "@open-mercato/ui/backend/confirm-dialog";
|
|
@@ -400,12 +401,7 @@ function ScheduleActivityDialog({
|
|
|
400
401
|
state.setSaving(false);
|
|
401
402
|
}
|
|
402
403
|
}, [callDirection, callOutcome, callPhoneInvalidMessage, callPhoneNumber, isDateMissing, isTimeMissing, state.activityType, state.allDay, state.date, state.description, dealId, state.duration, editData, entityId, state.guestPermissions, state.linkedEntities, state.location, onActivityCreated, onClose, state.participants, state.recurrenceCount, state.recurrenceDays, state.recurrenceEnabled, state.recurrenceEndDate, state.recurrenceEndType, state.reminderMinutes, runGuardedMutation, state.startTime, t, taskPriority, state.title, translateErrorMessage, trimmedCallPhone, trimmedDate, trimmedStartTime, state.visibility, visibleFields]);
|
|
403
|
-
const handleKeyDown =
|
|
404
|
-
if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
|
|
405
|
-
e.preventDefault();
|
|
406
|
-
handleSave();
|
|
407
|
-
}
|
|
408
|
-
}, [handleSave]);
|
|
404
|
+
const handleKeyDown = useDialogKeyHandler({ onConfirm: handleSave });
|
|
409
405
|
return /* @__PURE__ */ jsxs(Dialog, { open, onOpenChange: (o) => {
|
|
410
406
|
if (!o) void guardedClose();
|
|
411
407
|
}, children: [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/components/detail/ScheduleActivityDialog.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { Users, Phone, Check, Mail, Calendar, AlertTriangle, X, StickyNote } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { validatePhoneNumber } from '@open-mercato/shared/lib/phone'\nimport { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { mapCrudServerErrorToFormErrors } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Dialog, DialogContent, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { VisuallyHidden } from '@radix-ui/react-visually-hidden'\nimport { PhoneNumberField, SwitchableMarkdownInput } from '@open-mercato/ui/backend/inputs'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport {\n useScheduleFormState,\n FIELD_VISIBILITY,\n getFieldLabel,\n DateTimeFields,\n ParticipantsField,\n LocationField,\n FooterFields,\n LinkedEntitiesField,\n} from './schedule'\nimport type { ActivityType, ScheduleActivityEditData } from './schedule'\n\nconst TYPE_TABS: Array<{ type: ActivityType; icon: React.ComponentType<{ className?: string }>; labelKey: string; fallback: string }> = [\n { type: 'meeting', icon: Users, labelKey: 'customers.schedule.types.meeting', fallback: 'Meeting' },\n { type: 'call', icon: Phone, labelKey: 'customers.schedule.types.call', fallback: 'Call' },\n { type: 'task', icon: Check, labelKey: 'customers.schedule.types.task', fallback: 'Task' },\n { type: 'email', icon: Mail, labelKey: 'customers.schedule.types.email', fallback: 'Email' },\n { type: 'note', icon: StickyNote, labelKey: 'customers.schedule.types.note', fallback: 'Note' },\n]\n\ntype DialogChrome = { titleKey: string; titleFallback: string; subtitleKey: string; subtitleFallback: string; saveKey: string; saveFallback: string; saveIcon: React.ComponentType<{ className?: string }> }\n\nconst TYPE_CHROME: Record<ActivityType, DialogChrome> = {\n meeting: {\n titleKey: 'customers.schedule.meeting.title', titleFallback: 'New meeting',\n subtitleKey: 'customers.schedule.meeting.subtitle', subtitleFallback: 'Block time on the calendar with attendees',\n saveKey: 'customers.schedule.meeting.save', saveFallback: 'Save activity', saveIcon: Calendar,\n },\n call: {\n titleKey: 'customers.schedule.call.title', titleFallback: 'Log call',\n subtitleKey: 'customers.schedule.call.subtitle', subtitleFallback: 'Log a call you just had or schedule one',\n saveKey: 'customers.schedule.call.save', saveFallback: 'Log call', saveIcon: Phone,\n },\n task: {\n titleKey: 'customers.schedule.task.title', titleFallback: 'New task',\n subtitleKey: 'customers.schedule.task.subtitle', subtitleFallback: 'Capture something to follow up on',\n saveKey: 'customers.schedule.task.save', saveFallback: 'Save task', saveIcon: Check,\n },\n email: {\n titleKey: 'customers.schedule.email.title', titleFallback: 'Compose email',\n subtitleKey: 'customers.schedule.email.subtitle', subtitleFallback: 'Compose and send a tracked email',\n saveKey: 'customers.schedule.email.save', saveFallback: 'Send email', saveIcon: Mail,\n },\n note: {\n titleKey: 'customers.schedule.note.title', titleFallback: 'Add note',\n subtitleKey: 'customers.schedule.note.subtitle', subtitleFallback: 'Write down a note about this interaction',\n saveKey: 'customers.schedule.note.save', saveFallback: 'Save note', saveIcon: StickyNote,\n },\n}\n\nconst CALL_DIRECTIONS: Array<{ key: 'outbound' | 'inbound'; labelKey: string; labelFallback: string; dot: string }> = [\n { key: 'outbound', labelKey: 'customers.schedule.call.direction.outbound', labelFallback: 'Outbound', dot: 'bg-status-info-icon' },\n { key: 'inbound', labelKey: 'customers.schedule.call.direction.inbound', labelFallback: 'Inbound', dot: 'bg-status-success-icon' },\n]\n\nconst CALL_OUTCOMES: Array<{ key: string; labelKey: string; labelFallback: string; dot: string }> = [\n { key: 'connected', labelKey: 'customers.schedule.call.outcome.connected', labelFallback: 'Connected', dot: 'bg-status-success-icon' },\n { key: 'voicemail', labelKey: 'customers.schedule.call.outcome.voicemail', labelFallback: 'Voicemail', dot: 'bg-status-warning-icon' },\n { key: 'noanswer', labelKey: 'customers.schedule.call.outcome.noAnswer', labelFallback: 'No answer', dot: 'bg-muted-foreground' },\n { key: 'busy', labelKey: 'customers.schedule.call.outcome.busy', labelFallback: 'Busy', dot: 'bg-status-warning-icon' },\n { key: 'badnumber', labelKey: 'customers.schedule.call.outcome.badNumber', labelFallback: 'Bad number', dot: 'bg-status-error-icon' },\n]\n\nconst TASK_PRIORITIES: Array<{ key: string; labelKey: string; labelFallback: string; dot: string }> = [\n { key: 'low', labelKey: 'customers.schedule.task.priority.low', labelFallback: 'Low', dot: 'bg-muted-foreground' },\n { key: 'medium', labelKey: 'customers.schedule.task.priority.medium', labelFallback: 'Medium', dot: 'bg-status-info-icon' },\n { key: 'high', labelKey: 'customers.schedule.task.priority.high', labelFallback: 'High', dot: 'bg-status-warning-icon' },\n { key: 'urgent', labelKey: 'customers.schedule.task.priority.urgent', labelFallback: 'Urgent', dot: 'bg-status-error-icon' },\n]\n\ninterface ScheduleActivityDialogProps {\n open: boolean\n onClose: () => void\n entityId: string\n dealId?: string | null\n entityName?: string\n companyName?: string | null\n entityType: 'company' | 'person' | 'deal'\n onActivityCreated?: () => void\n /** When provided, dialog opens in edit mode with pre-filled data */\n editData?: ScheduleActivityEditData | null\n}\n\nexport function ScheduleActivityDialog({\n open,\n onClose,\n entityId,\n dealId = null,\n entityName,\n companyName,\n entityType,\n onActivityCreated,\n editData,\n}: ScheduleActivityDialogProps) {\n const t = useT()\n const state = useScheduleFormState({ open, editData: editData ?? null })\n const visibleFields = FIELD_VISIBILITY[state.activityType]\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const isEditing = Boolean(editData?.id)\n const chrome = TYPE_CHROME[state.activityType]\n const SaveIcon = chrome.saveIcon\n const [callDirection, setCallDirection] = React.useState<'outbound' | 'inbound'>('outbound')\n const [callOutcome, setCallOutcome] = React.useState<string | null>(null)\n const [callPhoneNumber, setCallPhoneNumber] = React.useState('')\n const [callPhoneError, setCallPhoneError] = React.useState<string | null>(null)\n const [taskPriority, setTaskPriority] = React.useState<string>('medium')\n const callPhoneInvalidMessage = React.useMemo(\n () =>\n t(\n 'customers.activities.errors.phoneInvalid',\n 'Enter a valid phone number with country code (e.g. +1 212 555 1234)',\n ),\n [t],\n )\n const translateErrorMessage = React.useCallback(\n (message: string | undefined, fallback: string) => {\n const key = typeof message === 'string' ? message.trim() : ''\n return key ? t(key, key) : fallback\n },\n [t],\n )\n\n React.useEffect(() => {\n if (!open) return\n const raw = editData as (Record<string, unknown> & { customValues?: unknown; phoneNumber?: unknown }) | null | undefined\n const cv = (raw?.customValues && typeof raw.customValues === 'object' ? raw.customValues : null) as Record<string, unknown> | null\n setCallDirection(typeof cv?.callDirection === 'string' && cv.callDirection === 'inbound' ? 'inbound' : 'outbound')\n setCallOutcome(typeof cv?.callOutcome === 'string' ? cv.callOutcome : null)\n // Seed phone number from either top-level `phoneNumber` (newer write path)\n // or legacy `customValues.callPhoneNumber` so previously-saved calls still\n // round-trip on edit (#1808).\n const seededPhone =\n typeof raw?.phoneNumber === 'string' && raw.phoneNumber.trim().length > 0\n ? raw.phoneNumber\n : typeof cv?.callPhoneNumber === 'string'\n ? cv.callPhoneNumber\n : ''\n setCallPhoneNumber(seededPhone)\n setCallPhoneError(null)\n setTaskPriority(typeof cv?.taskPriority === 'string' ? cv.taskPriority : 'medium')\n }, [open, editData])\n\n // Reset per-type chip state when the user switches activity type in create mode.\n // In edit mode, the persisted customValues should win, so we skip the reset.\n React.useEffect(() => {\n if (!open || isEditing) return\n setCallDirection('outbound')\n setCallOutcome(null)\n setCallPhoneNumber('')\n setCallPhoneError(null)\n setTaskPriority('medium')\n }, [state.activityType, open, isEditing])\n\n const handleCallPhoneChange = React.useCallback((next: string | undefined) => {\n setCallPhoneNumber(next ?? '')\n setCallPhoneError(null)\n }, [])\n\n const formSnapshot = React.useMemo(() => JSON.stringify({\n activityType: state.activityType,\n title: state.title,\n date: state.date,\n startTime: state.startTime,\n duration: state.duration,\n allDay: state.allDay,\n description: state.description,\n location: state.location,\n reminderMinutes: state.reminderMinutes,\n visibility: state.visibility,\n participants: state.participants,\n linkedEntities: state.linkedEntities,\n recurrenceEnabled: state.recurrenceEnabled,\n recurrenceDays: state.recurrenceDays,\n recurrenceEndType: state.recurrenceEndType,\n recurrenceCount: state.recurrenceCount,\n recurrenceEndDate: state.recurrenceEndDate,\n guestPermissions: state.guestPermissions,\n }), [\n state.activityType, state.title, state.date, state.startTime, state.duration, state.allDay,\n state.description, state.location, state.reminderMinutes, state.visibility, state.participants,\n state.linkedEntities, state.recurrenceEnabled, state.recurrenceDays, state.recurrenceEndType,\n state.recurrenceCount, state.recurrenceEndDate, state.guestPermissions,\n ])\n const initialSnapshotRef = React.useRef<string | null>(null)\n const snapshotOpenKeyRef = React.useRef<string | null>(null)\n const snapshotSettleCountRef = React.useRef(0)\n const openKey = open ? `${editData?.id ?? 'new'}` : null\n React.useEffect(() => {\n if (!open) {\n initialSnapshotRef.current = null\n snapshotOpenKeyRef.current = null\n snapshotSettleCountRef.current = 0\n return\n }\n if (snapshotOpenKeyRef.current !== openKey) {\n snapshotOpenKeyRef.current = openKey\n snapshotSettleCountRef.current = 0\n initialSnapshotRef.current = null\n }\n if (snapshotSettleCountRef.current < 2) {\n initialSnapshotRef.current = formSnapshot\n snapshotSettleCountRef.current += 1\n }\n }, [open, openKey, formSnapshot])\n\n const isDirty = React.useCallback(() => {\n if (initialSnapshotRef.current == null) return false\n return initialSnapshotRef.current !== formSnapshot\n }, [formSnapshot])\n\n const guardedClose = React.useCallback(async () => {\n if (!isDirty()) {\n onClose()\n return\n }\n const ok = await confirm({\n title: t('customers.schedule.discardConfirm.title', 'Discard unsaved changes?'),\n description: t(\n 'customers.schedule.discardConfirm.description',\n 'You have unsaved edits in this activity. Save them first or continue to discard them.',\n ),\n confirmText: t('customers.schedule.discardConfirm.confirm', 'Discard'),\n cancelText: t('customers.schedule.discardConfirm.cancel', 'Keep editing'),\n variant: 'destructive',\n })\n if (ok) onClose()\n }, [confirm, isDirty, onClose, t])\n\n const mutationContextId = React.useMemo(\n () => `customer-activity:${entityType}:${entityId}`,\n [entityId, entityType],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId: string\n entityType: 'company' | 'person' | 'deal'\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: mutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const mutationContext = React.useMemo(\n () => ({\n formId: mutationContextId,\n resourceKind:\n entityType === 'company'\n ? 'customers.company'\n : entityType === 'person'\n ? 'customers.person'\n : 'customers.deal',\n resourceId: entityId,\n entityType,\n retryLastMutation,\n }),\n [entityId, entityType, mutationContextId, retryLastMutation],\n )\n const runGuardedMutation = React.useCallback(\n async <T,>(operation: () => Promise<T>, mutationPayload: Record<string, unknown>) =>\n runMutation({\n operation,\n mutationPayload,\n context: mutationContext,\n }),\n [mutationContext, runMutation],\n )\n\n // Conflict detection -- debounced check when date/time/duration changes\n React.useEffect(() => {\n if (!open || state.allDay || !state.date || !state.startTime) {\n state.setConflict(null)\n return\n }\n const timer = setTimeout(async () => {\n try {\n const localStart = new Date(`${state.date}T${state.startTime}:00`)\n const params = new URLSearchParams({\n date: state.date,\n startTime: state.startTime,\n duration: String(state.duration),\n })\n if (editData?.id) {\n params.set('excludeId', editData.id)\n }\n if (!Number.isNaN(localStart.getTime())) {\n params.set('timezoneOffsetMinutes', String(-localStart.getTimezoneOffset()))\n }\n const data = await readApiResultOrThrow<{\n hasConflicts: boolean\n conflicts: Array<{ id: string; title: string | null; startTime: string; endTime: string; type: string }>\n }>(`/api/customers/interactions/conflicts?${params.toString()}`)\n if (data?.hasConflicts && Array.isArray(data.conflicts) && data.conflicts.length > 0) {\n const descriptions = data.conflicts\n .map((c) => `${c.startTime}\u2013${c.endTime}: ${c.title ?? c.type}`)\n .join(', ')\n state.setConflict(\n t('customers.schedule.conflict.description', 'Overlaps with: {{items}}', { items: descriptions }),\n )\n } else {\n state.setConflict(null)\n }\n } catch {\n state.setConflict(null)\n }\n }, 500)\n return () => clearTimeout(timer)\n }, [editData?.id, open, state.date, state.startTime, state.duration, state.allDay, t]) // eslint-disable-line react-hooks/exhaustive-deps\n\n const trimmedDate = state.date.trim()\n const trimmedStartTime = state.startTime.trim()\n const trimmedCallPhone = callPhoneNumber.trim()\n const isDateMissing = !trimmedDate\n const isTimeMissing = !state.allDay && !trimmedStartTime\n const isSubmitDisabled =\n state.saving ||\n !state.title.trim() ||\n isDateMissing ||\n isTimeMissing\n\n const handleSave = React.useCallback(async () => {\n if (!state.title.trim()) return\n if (isDateMissing) {\n flash(t('customers.activities.errors.dateRequired', 'Date is required'), 'error')\n return\n }\n if (isTimeMissing) {\n flash(t('customers.activities.errors.timeRequired', 'Time is required'), 'error')\n return\n }\n let phoneNumberForPayload: string | undefined\n if (state.activityType === 'call' && trimmedCallPhone) {\n const phoneValidation = validatePhoneNumber(trimmedCallPhone)\n if (!phoneValidation.valid) {\n setCallPhoneError(callPhoneInvalidMessage)\n flash(callPhoneInvalidMessage, 'error')\n return\n }\n phoneNumberForPayload = phoneValidation.normalized ?? trimmedCallPhone\n setCallPhoneError(null)\n if (phoneNumberForPayload !== callPhoneNumber) {\n setCallPhoneNumber(phoneNumberForPayload)\n }\n }\n state.setSaving(true)\n try {\n const scheduledAt = state.allDay\n ? new Date(`${state.date}T00:00:00`).toISOString()\n : new Date(`${state.date}T${state.startTime}:00`).toISOString()\n\n const recurrenceRule = state.recurrenceEnabled\n ? buildRecurrenceRule(state.recurrenceDays, state.recurrenceEndType, state.recurrenceCount, state.recurrenceEndDate)\n : null\n\n const isSaveEdit = Boolean(editData?.id)\n const customValues: Record<string, unknown> = {}\n if (state.activityType === 'call') {\n customValues.callDirection = callDirection\n if (callOutcome) customValues.callOutcome = callOutcome\n if (phoneNumberForPayload) customValues.callPhoneNumber = phoneNumberForPayload\n }\n if (state.activityType === 'task') {\n customValues.taskPriority = taskPriority\n }\n const payload = {\n ...(isSaveEdit ? { id: editData!.id } : {}),\n entityId,\n dealId,\n interactionType: state.activityType,\n title: state.title.trim(),\n body: state.description.trim() || null,\n status: 'planned',\n date: trimmedDate,\n time: state.allDay ? '00:00' : trimmedStartTime,\n phoneNumber: state.activityType === 'call' ? phoneNumberForPayload : undefined,\n scheduledAt,\n durationMinutes: visibleFields.has('duration') && !state.allDay ? state.duration : null,\n location: visibleFields.has('location') ? (state.location.trim() || null) : null,\n allDay: visibleFields.has('allDay') ? state.allDay : null,\n recurrenceRule: visibleFields.has('recurrence') ? recurrenceRule : null,\n recurrenceEnd: visibleFields.has('recurrence') && state.recurrenceEndType === 'date' && state.recurrenceEndDate\n ? new Date(state.recurrenceEndDate).toISOString()\n : null,\n participants: visibleFields.has('participants') && state.participants.length > 0\n ? state.participants.map((p) => ({ userId: p.userId, name: p.name, email: p.email, status: p.status ?? 'pending' }))\n : null,\n guestPermissions: visibleFields.has('participants') && state.participants.length > 0 ? state.guestPermissions : null,\n linkedEntities: state.linkedEntities.length > 0\n ? state.linkedEntities.map((e) => ({ id: e.id, type: e.type, label: e.label }))\n : null,\n reminderMinutes: visibleFields.has('reminder') ? state.reminderMinutes : null,\n visibility: visibleFields.has('visibility') ? state.visibility : null,\n ...(Object.keys(customValues).length > 0 ? { customValues } : {}),\n }\n await runGuardedMutation(\n () =>\n apiCallOrThrow('/api/customers/interactions', {\n method: isSaveEdit ? 'PUT' : 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n }),\n {\n operation: isSaveEdit ? 'updateActivity' : 'createActivity',\n interactionId: editData?.id ?? null,\n interactionType: state.activityType,\n },\n )\n flash(t('customers.schedule.saved', 'Activity scheduled'), 'success')\n onClose()\n // Delay data reload so the dialog can unmount cleanly and Radix restores body scroll\n requestAnimationFrame(() => { onActivityCreated?.() })\n } catch (err) {\n const { message, fieldErrors } = mapCrudServerErrorToFormErrors(err)\n const phoneFieldError = fieldErrors?.phoneNumber\n if (state.activityType === 'call' && phoneFieldError) {\n const translatedPhoneError = translateErrorMessage(phoneFieldError, callPhoneInvalidMessage)\n setCallPhoneError(translatedPhoneError)\n flash(translatedPhoneError, 'error')\n return\n }\n flash(\n translateErrorMessage(message, t('customers.schedule.error', 'Failed to schedule activity')),\n 'error',\n )\n } finally {\n state.setSaving(false)\n }\n }, [callDirection, callOutcome, callPhoneInvalidMessage, callPhoneNumber, isDateMissing, isTimeMissing, state.activityType, state.allDay, state.date, state.description, dealId, state.duration, editData, entityId, state.guestPermissions, state.linkedEntities, state.location, onActivityCreated, onClose, state.participants, state.recurrenceCount, state.recurrenceDays, state.recurrenceEnabled, state.recurrenceEndDate, state.recurrenceEndType, state.reminderMinutes, runGuardedMutation, state.startTime, t, taskPriority, state.title, translateErrorMessage, trimmedCallPhone, trimmedDate, trimmedStartTime, state.visibility, visibleFields]) // eslint-disable-line react-hooks/exhaustive-deps\n\n const handleKeyDown = React.useCallback((e: React.KeyboardEvent) => {\n if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {\n e.preventDefault()\n handleSave()\n }\n }, [handleSave])\n\n return (\n <Dialog open={open} onOpenChange={(o) => { if (!o) void guardedClose() }}>\n {ConfirmDialogElement}\n <DialogContent className=\"flex max-h-[90vh] flex-col overflow-hidden border-border p-0 shadow-xl sm:max-w-[760px] sm:rounded-xl [&>[data-dialog-close]]:hidden\" onKeyDown={handleKeyDown} aria-describedby={undefined}>\n <VisuallyHidden>\n <DialogTitle>{isEditing ? t('customers.schedule.editTitle', 'Edit activity') : t(chrome.titleKey, chrome.titleFallback)}</DialogTitle>\n </VisuallyHidden>\n\n {/* Header */}\n <div className=\"flex shrink-0 items-start justify-between gap-3 border-b border-border bg-background px-6 py-5\">\n <div className=\"flex flex-col gap-1\">\n <h2 className=\"text-lg font-semibold leading-tight tracking-tight text-foreground\">\n {isEditing ? t('customers.schedule.editTitle', 'Edit activity') : t(chrome.titleKey, chrome.titleFallback)}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t(chrome.subtitleKey, chrome.subtitleFallback)}\n </p>\n {entityName ? (\n <p className=\"mt-0.5 text-xs text-muted-foreground/80\">\n {t('customers.schedule.context', 'On timeline: {{name}}', { name: entityName })}\n {companyName ? ` \u00B7 ${companyName}` : ''}\n </p>\n ) : null}\n </div>\n <IconButton type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => { void guardedClose() }} className=\"flex size-9 shrink-0 items-center justify-center rounded-md border border-border bg-background\" aria-label={t('customers.schedule.cancel', 'Cancel')}>\n <X className=\"size-4 text-muted-foreground\" />\n </IconButton>\n </div>\n\n <div className=\"flex-1 overflow-y-auto\">\n <div className=\"flex flex-col gap-4 bg-background p-6\">\n\n {/* Conflict warning */}\n {state.conflict && (\n <Alert variant=\"warning\" className=\"rounded-lg\">\n <AlertTriangle className=\"size-5\" />\n <AlertTitle>\n {t('customers.schedule.conflict.title', 'Calendar conflict')}\n </AlertTitle>\n <AlertDescription>{state.conflict}</AlertDescription>\n </Alert>\n )}\n\n {/* Type tabs \u2014 large rectangular tiles per Figma */}\n <div className=\"grid grid-cols-4 gap-2\">\n {TYPE_TABS.map(({ type, icon: Icon, labelKey, fallback }) => {\n const isActive = state.activityType === type\n return (\n <button\n key={type}\n type=\"button\"\n onClick={() => state.setActivityType(type)}\n aria-pressed={isActive}\n className={cn(\n 'flex h-[80px] flex-col items-center justify-center gap-2 rounded-md border text-[14px] font-semibold transition-colors',\n isActive\n ? 'border-transparent bg-foreground text-background'\n : 'border-border bg-card text-muted-foreground hover:border-foreground/40 hover:text-foreground',\n )}\n >\n <Icon className=\"size-[18px]\" />\n {t(labelKey, fallback)}\n </button>\n )\n })}\n </div>\n\n {/* Title */}\n <div className=\"flex flex-col gap-1.5\">\n <label className=\"text-overline font-semibold text-muted-foreground tracking-wider\">\n {getFieldLabel(state.activityType, 'title', t, 'customers.schedule.titleLabel', 'Title')}\n </label>\n <input\n type=\"text\"\n value={state.title}\n onChange={(e) => state.setTitle(e.target.value)}\n placeholder={\n state.activityType === 'email'\n ? t('customers.schedule.subjectPlaceholder', 'Subject...')\n : t('customers.schedule.titlePlaceholder', 'Activity title...')\n }\n className=\"w-full rounded-md border border-border bg-background px-3 py-2.5 text-sm text-foreground outline-none focus:border-foreground\"\n autoFocus\n />\n </div>\n\n {/* Date/Time/Duration \u2014 placed before per-type chip rows so the call/task\n workflows match Figma 829:50 / 790:280 (date row first, then status chips). */}\n <DateTimeFields\n visible={visibleFields}\n activityType={state.activityType}\n date={state.date}\n setDate={state.setDate}\n startTime={state.startTime}\n setStartTime={state.setStartTime}\n duration={state.duration}\n setDuration={state.setDuration}\n allDay={state.allDay}\n setAllDay={state.setAllDay}\n recurrenceEnabled={state.recurrenceEnabled}\n setRecurrenceEnabled={state.setRecurrenceEnabled}\n recurrenceDays={state.recurrenceDays}\n toggleRecurrenceDay={state.toggleRecurrenceDay}\n recurrenceEndType={state.recurrenceEndType}\n setRecurrenceEndType={state.setRecurrenceEndType}\n recurrenceCount={state.recurrenceCount}\n setRecurrenceCount={state.setRecurrenceCount}\n recurrenceEndDate={state.recurrenceEndDate}\n setRecurrenceEndDate={state.setRecurrenceEndDate}\n />\n\n {/* Call: Direction + Outcome chips */}\n {state.activityType === 'call' && (\n <div className=\"flex flex-col gap-3\">\n <div>\n <label className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {t('customers.schedule.call.directionLabel', 'Direction')}\n </label>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {CALL_DIRECTIONS.map((opt) => {\n const isActive = callDirection === opt.key\n return (\n <button\n key={opt.key}\n type=\"button\"\n aria-pressed={isActive}\n onClick={() => setCallDirection(opt.key)}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-sm font-medium transition-colors',\n isActive\n ? 'border-transparent bg-foreground text-background'\n : 'border-border bg-card text-muted-foreground hover:border-foreground/40',\n )}\n >\n <span className={cn('inline-block size-1.5 rounded-full', opt.dot)} aria-hidden />\n {t(opt.labelKey, opt.labelFallback)}\n </button>\n )\n })}\n </div>\n </div>\n <div>\n <label className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {t('customers.schedule.call.outcomeLabel', 'Outcome')}\n </label>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {CALL_OUTCOMES.map((opt) => {\n const isActive = callOutcome === opt.key\n return (\n <button\n key={opt.key}\n type=\"button\"\n aria-pressed={isActive}\n onClick={() => setCallOutcome(isActive ? null : opt.key)}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-sm font-medium transition-colors',\n isActive\n ? 'border-transparent bg-foreground text-background'\n : 'border-border bg-card text-muted-foreground hover:border-foreground/40',\n )}\n >\n <span className={cn('inline-block size-1.5 rounded-full', opt.dot)} aria-hidden />\n {t(opt.labelKey, opt.labelFallback)}\n </button>\n )\n })}\n </div>\n </div>\n </div>\n )}\n\n {/* Task: Priority chips */}\n {state.activityType === 'task' && (\n <div>\n <label className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {t('customers.schedule.task.priorityLabel', 'Priority')}\n </label>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {TASK_PRIORITIES.map((opt) => {\n const isActive = taskPriority === opt.key\n return (\n <button\n key={opt.key}\n type=\"button\"\n aria-pressed={isActive}\n onClick={() => setTaskPriority(opt.key)}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-sm font-medium transition-colors',\n isActive\n ? 'border-transparent bg-foreground text-background'\n : 'border-border bg-card text-muted-foreground hover:border-foreground/40',\n )}\n >\n <span className={cn('inline-block size-1.5 rounded-full', opt.dot)} aria-hidden />\n {t(opt.labelKey, opt.labelFallback)}\n </button>\n )\n })}\n </div>\n </div>\n )}\n\n {/* Participants */}\n <ParticipantsField\n visible={visibleFields}\n activityType={state.activityType}\n participants={state.participants}\n setParticipants={state.setParticipants}\n removeParticipant={state.removeParticipant}\n guestPermissions={state.guestPermissions}\n setGuestPermissions={state.setGuestPermissions}\n />\n\n {/* Location (or phone number for calls) */}\n {state.activityType === 'call' ? (\n <div className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"schedule-call-phone\" className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {t('customers.schedule.call.phoneLabel', 'Phone number')}\n </label>\n <PhoneNumberField\n id=\"schedule-call-phone\"\n value={callPhoneNumber}\n onValueChange={handleCallPhoneChange}\n placeholder={t('customers.schedule.call.phonePlaceholder', '+1 555 000 0000')}\n externalError={callPhoneError}\n invalidLabel={callPhoneInvalidMessage}\n minDigits={7}\n />\n </div>\n ) : (\n <LocationField\n visible={visibleFields}\n activityType={state.activityType}\n location={state.location}\n setLocation={state.setLocation}\n />\n )}\n\n {/* Linked Entities */}\n <LinkedEntitiesField\n visible={visibleFields}\n activityType={state.activityType}\n linkedEntities={state.linkedEntities}\n setLinkedEntities={state.setLinkedEntities}\n />\n\n {/* Description */}\n <div>\n <label className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {getFieldLabel(state.activityType, 'description', t, 'customers.schedule.description', 'Description')}\n </label>\n <div className=\"mt-[8px]\">\n <SwitchableMarkdownInput\n value={state.description}\n onChange={state.setDescription}\n isMarkdownEnabled={state.markdownEnabled}\n height={120}\n placeholder={t('customers.schedule.descriptionPlaceholder', 'Add details...')}\n />\n </div>\n </div>\n\n {/* Reminder + Visibility */}\n <FooterFields\n visible={visibleFields}\n activityType={state.activityType}\n reminderMinutes={state.reminderMinutes}\n setReminderMinutes={state.setReminderMinutes}\n visibility={state.visibility}\n setVisibility={state.setVisibility}\n />\n\n </div>\n </div>\n\n {/* Footer */}\n <div className=\"flex shrink-0 items-center justify-end gap-2.5 border-t border-border bg-muted/50 px-6 py-4\">\n <Button type=\"button\" variant=\"outline\" onClick={() => { void guardedClose() }} className=\"rounded-md border border-input bg-background px-5 py-3 text-sm font-semibold text-foreground\">\n {t('customers.schedule.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" onClick={handleSave} disabled={isSubmitDisabled} className=\"flex items-center gap-2 rounded-md bg-foreground px-5 py-3 text-sm font-semibold text-background hover:bg-foreground/90 disabled:opacity-50\">\n <SaveIcon className=\"size-3.5\" />\n {state.saving\n ? t('customers.schedule.saving', 'Saving...')\n : isEditing\n ? t('customers.schedule.update', 'Update activity')\n : t(chrome.saveKey, chrome.saveFallback)}\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n )\n}\n\nexport type { ScheduleActivityEditData }\n\nfunction buildRecurrenceRule(\n days: boolean[],\n endType: 'never' | 'count' | 'date',\n count: number,\n endDate: string,\n): string {\n const dayNames = ['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU']\n const selectedDays = days.map((active, i) => (active ? dayNames[i] : null)).filter(Boolean)\n let rule = `FREQ=WEEKLY;BYDAY=${selectedDays.join(',')}`\n if (endType === 'count') rule += `;COUNT=${count}`\n if (endType === 'date' && endDate) rule += `;UNTIL=${endDate.replace(/-/g, '')}T235959Z`\n return rule\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { Users, Phone, Check, Mail, Calendar, AlertTriangle, X, StickyNote } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { validatePhoneNumber } from '@open-mercato/shared/lib/phone'\nimport { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { mapCrudServerErrorToFormErrors } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Dialog, DialogContent, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { useDialogKeyHandler } from '@open-mercato/ui/hooks/useDialogKeyHandler'\nimport { VisuallyHidden } from '@radix-ui/react-visually-hidden'\nimport { PhoneNumberField, SwitchableMarkdownInput } from '@open-mercato/ui/backend/inputs'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport {\n useScheduleFormState,\n FIELD_VISIBILITY,\n getFieldLabel,\n DateTimeFields,\n ParticipantsField,\n LocationField,\n FooterFields,\n LinkedEntitiesField,\n} from './schedule'\nimport type { ActivityType, ScheduleActivityEditData } from './schedule'\n\nconst TYPE_TABS: Array<{ type: ActivityType; icon: React.ComponentType<{ className?: string }>; labelKey: string; fallback: string }> = [\n { type: 'meeting', icon: Users, labelKey: 'customers.schedule.types.meeting', fallback: 'Meeting' },\n { type: 'call', icon: Phone, labelKey: 'customers.schedule.types.call', fallback: 'Call' },\n { type: 'task', icon: Check, labelKey: 'customers.schedule.types.task', fallback: 'Task' },\n { type: 'email', icon: Mail, labelKey: 'customers.schedule.types.email', fallback: 'Email' },\n { type: 'note', icon: StickyNote, labelKey: 'customers.schedule.types.note', fallback: 'Note' },\n]\n\ntype DialogChrome = { titleKey: string; titleFallback: string; subtitleKey: string; subtitleFallback: string; saveKey: string; saveFallback: string; saveIcon: React.ComponentType<{ className?: string }> }\n\nconst TYPE_CHROME: Record<ActivityType, DialogChrome> = {\n meeting: {\n titleKey: 'customers.schedule.meeting.title', titleFallback: 'New meeting',\n subtitleKey: 'customers.schedule.meeting.subtitle', subtitleFallback: 'Block time on the calendar with attendees',\n saveKey: 'customers.schedule.meeting.save', saveFallback: 'Save activity', saveIcon: Calendar,\n },\n call: {\n titleKey: 'customers.schedule.call.title', titleFallback: 'Log call',\n subtitleKey: 'customers.schedule.call.subtitle', subtitleFallback: 'Log a call you just had or schedule one',\n saveKey: 'customers.schedule.call.save', saveFallback: 'Log call', saveIcon: Phone,\n },\n task: {\n titleKey: 'customers.schedule.task.title', titleFallback: 'New task',\n subtitleKey: 'customers.schedule.task.subtitle', subtitleFallback: 'Capture something to follow up on',\n saveKey: 'customers.schedule.task.save', saveFallback: 'Save task', saveIcon: Check,\n },\n email: {\n titleKey: 'customers.schedule.email.title', titleFallback: 'Compose email',\n subtitleKey: 'customers.schedule.email.subtitle', subtitleFallback: 'Compose and send a tracked email',\n saveKey: 'customers.schedule.email.save', saveFallback: 'Send email', saveIcon: Mail,\n },\n note: {\n titleKey: 'customers.schedule.note.title', titleFallback: 'Add note',\n subtitleKey: 'customers.schedule.note.subtitle', subtitleFallback: 'Write down a note about this interaction',\n saveKey: 'customers.schedule.note.save', saveFallback: 'Save note', saveIcon: StickyNote,\n },\n}\n\nconst CALL_DIRECTIONS: Array<{ key: 'outbound' | 'inbound'; labelKey: string; labelFallback: string; dot: string }> = [\n { key: 'outbound', labelKey: 'customers.schedule.call.direction.outbound', labelFallback: 'Outbound', dot: 'bg-status-info-icon' },\n { key: 'inbound', labelKey: 'customers.schedule.call.direction.inbound', labelFallback: 'Inbound', dot: 'bg-status-success-icon' },\n]\n\nconst CALL_OUTCOMES: Array<{ key: string; labelKey: string; labelFallback: string; dot: string }> = [\n { key: 'connected', labelKey: 'customers.schedule.call.outcome.connected', labelFallback: 'Connected', dot: 'bg-status-success-icon' },\n { key: 'voicemail', labelKey: 'customers.schedule.call.outcome.voicemail', labelFallback: 'Voicemail', dot: 'bg-status-warning-icon' },\n { key: 'noanswer', labelKey: 'customers.schedule.call.outcome.noAnswer', labelFallback: 'No answer', dot: 'bg-muted-foreground' },\n { key: 'busy', labelKey: 'customers.schedule.call.outcome.busy', labelFallback: 'Busy', dot: 'bg-status-warning-icon' },\n { key: 'badnumber', labelKey: 'customers.schedule.call.outcome.badNumber', labelFallback: 'Bad number', dot: 'bg-status-error-icon' },\n]\n\nconst TASK_PRIORITIES: Array<{ key: string; labelKey: string; labelFallback: string; dot: string }> = [\n { key: 'low', labelKey: 'customers.schedule.task.priority.low', labelFallback: 'Low', dot: 'bg-muted-foreground' },\n { key: 'medium', labelKey: 'customers.schedule.task.priority.medium', labelFallback: 'Medium', dot: 'bg-status-info-icon' },\n { key: 'high', labelKey: 'customers.schedule.task.priority.high', labelFallback: 'High', dot: 'bg-status-warning-icon' },\n { key: 'urgent', labelKey: 'customers.schedule.task.priority.urgent', labelFallback: 'Urgent', dot: 'bg-status-error-icon' },\n]\n\ninterface ScheduleActivityDialogProps {\n open: boolean\n onClose: () => void\n entityId: string\n dealId?: string | null\n entityName?: string\n companyName?: string | null\n entityType: 'company' | 'person' | 'deal'\n onActivityCreated?: () => void\n /** When provided, dialog opens in edit mode with pre-filled data */\n editData?: ScheduleActivityEditData | null\n}\n\nexport function ScheduleActivityDialog({\n open,\n onClose,\n entityId,\n dealId = null,\n entityName,\n companyName,\n entityType,\n onActivityCreated,\n editData,\n}: ScheduleActivityDialogProps) {\n const t = useT()\n const state = useScheduleFormState({ open, editData: editData ?? null })\n const visibleFields = FIELD_VISIBILITY[state.activityType]\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const isEditing = Boolean(editData?.id)\n const chrome = TYPE_CHROME[state.activityType]\n const SaveIcon = chrome.saveIcon\n const [callDirection, setCallDirection] = React.useState<'outbound' | 'inbound'>('outbound')\n const [callOutcome, setCallOutcome] = React.useState<string | null>(null)\n const [callPhoneNumber, setCallPhoneNumber] = React.useState('')\n const [callPhoneError, setCallPhoneError] = React.useState<string | null>(null)\n const [taskPriority, setTaskPriority] = React.useState<string>('medium')\n const callPhoneInvalidMessage = React.useMemo(\n () =>\n t(\n 'customers.activities.errors.phoneInvalid',\n 'Enter a valid phone number with country code (e.g. +1 212 555 1234)',\n ),\n [t],\n )\n const translateErrorMessage = React.useCallback(\n (message: string | undefined, fallback: string) => {\n const key = typeof message === 'string' ? message.trim() : ''\n return key ? t(key, key) : fallback\n },\n [t],\n )\n\n React.useEffect(() => {\n if (!open) return\n const raw = editData as (Record<string, unknown> & { customValues?: unknown; phoneNumber?: unknown }) | null | undefined\n const cv = (raw?.customValues && typeof raw.customValues === 'object' ? raw.customValues : null) as Record<string, unknown> | null\n setCallDirection(typeof cv?.callDirection === 'string' && cv.callDirection === 'inbound' ? 'inbound' : 'outbound')\n setCallOutcome(typeof cv?.callOutcome === 'string' ? cv.callOutcome : null)\n // Seed phone number from either top-level `phoneNumber` (newer write path)\n // or legacy `customValues.callPhoneNumber` so previously-saved calls still\n // round-trip on edit (#1808).\n const seededPhone =\n typeof raw?.phoneNumber === 'string' && raw.phoneNumber.trim().length > 0\n ? raw.phoneNumber\n : typeof cv?.callPhoneNumber === 'string'\n ? cv.callPhoneNumber\n : ''\n setCallPhoneNumber(seededPhone)\n setCallPhoneError(null)\n setTaskPriority(typeof cv?.taskPriority === 'string' ? cv.taskPriority : 'medium')\n }, [open, editData])\n\n // Reset per-type chip state when the user switches activity type in create mode.\n // In edit mode, the persisted customValues should win, so we skip the reset.\n React.useEffect(() => {\n if (!open || isEditing) return\n setCallDirection('outbound')\n setCallOutcome(null)\n setCallPhoneNumber('')\n setCallPhoneError(null)\n setTaskPriority('medium')\n }, [state.activityType, open, isEditing])\n\n const handleCallPhoneChange = React.useCallback((next: string | undefined) => {\n setCallPhoneNumber(next ?? '')\n setCallPhoneError(null)\n }, [])\n\n const formSnapshot = React.useMemo(() => JSON.stringify({\n activityType: state.activityType,\n title: state.title,\n date: state.date,\n startTime: state.startTime,\n duration: state.duration,\n allDay: state.allDay,\n description: state.description,\n location: state.location,\n reminderMinutes: state.reminderMinutes,\n visibility: state.visibility,\n participants: state.participants,\n linkedEntities: state.linkedEntities,\n recurrenceEnabled: state.recurrenceEnabled,\n recurrenceDays: state.recurrenceDays,\n recurrenceEndType: state.recurrenceEndType,\n recurrenceCount: state.recurrenceCount,\n recurrenceEndDate: state.recurrenceEndDate,\n guestPermissions: state.guestPermissions,\n }), [\n state.activityType, state.title, state.date, state.startTime, state.duration, state.allDay,\n state.description, state.location, state.reminderMinutes, state.visibility, state.participants,\n state.linkedEntities, state.recurrenceEnabled, state.recurrenceDays, state.recurrenceEndType,\n state.recurrenceCount, state.recurrenceEndDate, state.guestPermissions,\n ])\n const initialSnapshotRef = React.useRef<string | null>(null)\n const snapshotOpenKeyRef = React.useRef<string | null>(null)\n const snapshotSettleCountRef = React.useRef(0)\n const openKey = open ? `${editData?.id ?? 'new'}` : null\n React.useEffect(() => {\n if (!open) {\n initialSnapshotRef.current = null\n snapshotOpenKeyRef.current = null\n snapshotSettleCountRef.current = 0\n return\n }\n if (snapshotOpenKeyRef.current !== openKey) {\n snapshotOpenKeyRef.current = openKey\n snapshotSettleCountRef.current = 0\n initialSnapshotRef.current = null\n }\n if (snapshotSettleCountRef.current < 2) {\n initialSnapshotRef.current = formSnapshot\n snapshotSettleCountRef.current += 1\n }\n }, [open, openKey, formSnapshot])\n\n const isDirty = React.useCallback(() => {\n if (initialSnapshotRef.current == null) return false\n return initialSnapshotRef.current !== formSnapshot\n }, [formSnapshot])\n\n const guardedClose = React.useCallback(async () => {\n if (!isDirty()) {\n onClose()\n return\n }\n const ok = await confirm({\n title: t('customers.schedule.discardConfirm.title', 'Discard unsaved changes?'),\n description: t(\n 'customers.schedule.discardConfirm.description',\n 'You have unsaved edits in this activity. Save them first or continue to discard them.',\n ),\n confirmText: t('customers.schedule.discardConfirm.confirm', 'Discard'),\n cancelText: t('customers.schedule.discardConfirm.cancel', 'Keep editing'),\n variant: 'destructive',\n })\n if (ok) onClose()\n }, [confirm, isDirty, onClose, t])\n\n const mutationContextId = React.useMemo(\n () => `customer-activity:${entityType}:${entityId}`,\n [entityId, entityType],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId: string\n entityType: 'company' | 'person' | 'deal'\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: mutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const mutationContext = React.useMemo(\n () => ({\n formId: mutationContextId,\n resourceKind:\n entityType === 'company'\n ? 'customers.company'\n : entityType === 'person'\n ? 'customers.person'\n : 'customers.deal',\n resourceId: entityId,\n entityType,\n retryLastMutation,\n }),\n [entityId, entityType, mutationContextId, retryLastMutation],\n )\n const runGuardedMutation = React.useCallback(\n async <T,>(operation: () => Promise<T>, mutationPayload: Record<string, unknown>) =>\n runMutation({\n operation,\n mutationPayload,\n context: mutationContext,\n }),\n [mutationContext, runMutation],\n )\n\n // Conflict detection -- debounced check when date/time/duration changes\n React.useEffect(() => {\n if (!open || state.allDay || !state.date || !state.startTime) {\n state.setConflict(null)\n return\n }\n const timer = setTimeout(async () => {\n try {\n const localStart = new Date(`${state.date}T${state.startTime}:00`)\n const params = new URLSearchParams({\n date: state.date,\n startTime: state.startTime,\n duration: String(state.duration),\n })\n if (editData?.id) {\n params.set('excludeId', editData.id)\n }\n if (!Number.isNaN(localStart.getTime())) {\n params.set('timezoneOffsetMinutes', String(-localStart.getTimezoneOffset()))\n }\n const data = await readApiResultOrThrow<{\n hasConflicts: boolean\n conflicts: Array<{ id: string; title: string | null; startTime: string; endTime: string; type: string }>\n }>(`/api/customers/interactions/conflicts?${params.toString()}`)\n if (data?.hasConflicts && Array.isArray(data.conflicts) && data.conflicts.length > 0) {\n const descriptions = data.conflicts\n .map((c) => `${c.startTime}\u2013${c.endTime}: ${c.title ?? c.type}`)\n .join(', ')\n state.setConflict(\n t('customers.schedule.conflict.description', 'Overlaps with: {{items}}', { items: descriptions }),\n )\n } else {\n state.setConflict(null)\n }\n } catch {\n state.setConflict(null)\n }\n }, 500)\n return () => clearTimeout(timer)\n }, [editData?.id, open, state.date, state.startTime, state.duration, state.allDay, t]) // eslint-disable-line react-hooks/exhaustive-deps\n\n const trimmedDate = state.date.trim()\n const trimmedStartTime = state.startTime.trim()\n const trimmedCallPhone = callPhoneNumber.trim()\n const isDateMissing = !trimmedDate\n const isTimeMissing = !state.allDay && !trimmedStartTime\n const isSubmitDisabled =\n state.saving ||\n !state.title.trim() ||\n isDateMissing ||\n isTimeMissing\n\n const handleSave = React.useCallback(async () => {\n if (!state.title.trim()) return\n if (isDateMissing) {\n flash(t('customers.activities.errors.dateRequired', 'Date is required'), 'error')\n return\n }\n if (isTimeMissing) {\n flash(t('customers.activities.errors.timeRequired', 'Time is required'), 'error')\n return\n }\n let phoneNumberForPayload: string | undefined\n if (state.activityType === 'call' && trimmedCallPhone) {\n const phoneValidation = validatePhoneNumber(trimmedCallPhone)\n if (!phoneValidation.valid) {\n setCallPhoneError(callPhoneInvalidMessage)\n flash(callPhoneInvalidMessage, 'error')\n return\n }\n phoneNumberForPayload = phoneValidation.normalized ?? trimmedCallPhone\n setCallPhoneError(null)\n if (phoneNumberForPayload !== callPhoneNumber) {\n setCallPhoneNumber(phoneNumberForPayload)\n }\n }\n state.setSaving(true)\n try {\n const scheduledAt = state.allDay\n ? new Date(`${state.date}T00:00:00`).toISOString()\n : new Date(`${state.date}T${state.startTime}:00`).toISOString()\n\n const recurrenceRule = state.recurrenceEnabled\n ? buildRecurrenceRule(state.recurrenceDays, state.recurrenceEndType, state.recurrenceCount, state.recurrenceEndDate)\n : null\n\n const isSaveEdit = Boolean(editData?.id)\n const customValues: Record<string, unknown> = {}\n if (state.activityType === 'call') {\n customValues.callDirection = callDirection\n if (callOutcome) customValues.callOutcome = callOutcome\n if (phoneNumberForPayload) customValues.callPhoneNumber = phoneNumberForPayload\n }\n if (state.activityType === 'task') {\n customValues.taskPriority = taskPriority\n }\n const payload = {\n ...(isSaveEdit ? { id: editData!.id } : {}),\n entityId,\n dealId,\n interactionType: state.activityType,\n title: state.title.trim(),\n body: state.description.trim() || null,\n status: 'planned',\n date: trimmedDate,\n time: state.allDay ? '00:00' : trimmedStartTime,\n phoneNumber: state.activityType === 'call' ? phoneNumberForPayload : undefined,\n scheduledAt,\n durationMinutes: visibleFields.has('duration') && !state.allDay ? state.duration : null,\n location: visibleFields.has('location') ? (state.location.trim() || null) : null,\n allDay: visibleFields.has('allDay') ? state.allDay : null,\n recurrenceRule: visibleFields.has('recurrence') ? recurrenceRule : null,\n recurrenceEnd: visibleFields.has('recurrence') && state.recurrenceEndType === 'date' && state.recurrenceEndDate\n ? new Date(state.recurrenceEndDate).toISOString()\n : null,\n participants: visibleFields.has('participants') && state.participants.length > 0\n ? state.participants.map((p) => ({ userId: p.userId, name: p.name, email: p.email, status: p.status ?? 'pending' }))\n : null,\n guestPermissions: visibleFields.has('participants') && state.participants.length > 0 ? state.guestPermissions : null,\n linkedEntities: state.linkedEntities.length > 0\n ? state.linkedEntities.map((e) => ({ id: e.id, type: e.type, label: e.label }))\n : null,\n reminderMinutes: visibleFields.has('reminder') ? state.reminderMinutes : null,\n visibility: visibleFields.has('visibility') ? state.visibility : null,\n ...(Object.keys(customValues).length > 0 ? { customValues } : {}),\n }\n await runGuardedMutation(\n () =>\n apiCallOrThrow('/api/customers/interactions', {\n method: isSaveEdit ? 'PUT' : 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n }),\n {\n operation: isSaveEdit ? 'updateActivity' : 'createActivity',\n interactionId: editData?.id ?? null,\n interactionType: state.activityType,\n },\n )\n flash(t('customers.schedule.saved', 'Activity scheduled'), 'success')\n onClose()\n // Delay data reload so the dialog can unmount cleanly and Radix restores body scroll\n requestAnimationFrame(() => { onActivityCreated?.() })\n } catch (err) {\n const { message, fieldErrors } = mapCrudServerErrorToFormErrors(err)\n const phoneFieldError = fieldErrors?.phoneNumber\n if (state.activityType === 'call' && phoneFieldError) {\n const translatedPhoneError = translateErrorMessage(phoneFieldError, callPhoneInvalidMessage)\n setCallPhoneError(translatedPhoneError)\n flash(translatedPhoneError, 'error')\n return\n }\n flash(\n translateErrorMessage(message, t('customers.schedule.error', 'Failed to schedule activity')),\n 'error',\n )\n } finally {\n state.setSaving(false)\n }\n }, [callDirection, callOutcome, callPhoneInvalidMessage, callPhoneNumber, isDateMissing, isTimeMissing, state.activityType, state.allDay, state.date, state.description, dealId, state.duration, editData, entityId, state.guestPermissions, state.linkedEntities, state.location, onActivityCreated, onClose, state.participants, state.recurrenceCount, state.recurrenceDays, state.recurrenceEnabled, state.recurrenceEndDate, state.recurrenceEndType, state.reminderMinutes, runGuardedMutation, state.startTime, t, taskPriority, state.title, translateErrorMessage, trimmedCallPhone, trimmedDate, trimmedStartTime, state.visibility, visibleFields]) // eslint-disable-line react-hooks/exhaustive-deps\n\n const handleKeyDown = useDialogKeyHandler({ onConfirm: handleSave })\n\n return (\n <Dialog open={open} onOpenChange={(o) => { if (!o) void guardedClose() }}>\n {ConfirmDialogElement}\n <DialogContent className=\"flex max-h-[90vh] flex-col overflow-hidden border-border p-0 shadow-xl sm:max-w-[760px] sm:rounded-xl [&>[data-dialog-close]]:hidden\" onKeyDown={handleKeyDown} aria-describedby={undefined}>\n <VisuallyHidden>\n <DialogTitle>{isEditing ? t('customers.schedule.editTitle', 'Edit activity') : t(chrome.titleKey, chrome.titleFallback)}</DialogTitle>\n </VisuallyHidden>\n\n {/* Header */}\n <div className=\"flex shrink-0 items-start justify-between gap-3 border-b border-border bg-background px-6 py-5\">\n <div className=\"flex flex-col gap-1\">\n <h2 className=\"text-lg font-semibold leading-tight tracking-tight text-foreground\">\n {isEditing ? t('customers.schedule.editTitle', 'Edit activity') : t(chrome.titleKey, chrome.titleFallback)}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t(chrome.subtitleKey, chrome.subtitleFallback)}\n </p>\n {entityName ? (\n <p className=\"mt-0.5 text-xs text-muted-foreground/80\">\n {t('customers.schedule.context', 'On timeline: {{name}}', { name: entityName })}\n {companyName ? ` \u00B7 ${companyName}` : ''}\n </p>\n ) : null}\n </div>\n <IconButton type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => { void guardedClose() }} className=\"flex size-9 shrink-0 items-center justify-center rounded-md border border-border bg-background\" aria-label={t('customers.schedule.cancel', 'Cancel')}>\n <X className=\"size-4 text-muted-foreground\" />\n </IconButton>\n </div>\n\n <div className=\"flex-1 overflow-y-auto\">\n <div className=\"flex flex-col gap-4 bg-background p-6\">\n\n {/* Conflict warning */}\n {state.conflict && (\n <Alert variant=\"warning\" className=\"rounded-lg\">\n <AlertTriangle className=\"size-5\" />\n <AlertTitle>\n {t('customers.schedule.conflict.title', 'Calendar conflict')}\n </AlertTitle>\n <AlertDescription>{state.conflict}</AlertDescription>\n </Alert>\n )}\n\n {/* Type tabs \u2014 large rectangular tiles per Figma */}\n <div className=\"grid grid-cols-4 gap-2\">\n {TYPE_TABS.map(({ type, icon: Icon, labelKey, fallback }) => {\n const isActive = state.activityType === type\n return (\n <button\n key={type}\n type=\"button\"\n onClick={() => state.setActivityType(type)}\n aria-pressed={isActive}\n className={cn(\n 'flex h-[80px] flex-col items-center justify-center gap-2 rounded-md border text-[14px] font-semibold transition-colors',\n isActive\n ? 'border-transparent bg-foreground text-background'\n : 'border-border bg-card text-muted-foreground hover:border-foreground/40 hover:text-foreground',\n )}\n >\n <Icon className=\"size-[18px]\" />\n {t(labelKey, fallback)}\n </button>\n )\n })}\n </div>\n\n {/* Title */}\n <div className=\"flex flex-col gap-1.5\">\n <label className=\"text-overline font-semibold text-muted-foreground tracking-wider\">\n {getFieldLabel(state.activityType, 'title', t, 'customers.schedule.titleLabel', 'Title')}\n </label>\n <input\n type=\"text\"\n value={state.title}\n onChange={(e) => state.setTitle(e.target.value)}\n placeholder={\n state.activityType === 'email'\n ? t('customers.schedule.subjectPlaceholder', 'Subject...')\n : t('customers.schedule.titlePlaceholder', 'Activity title...')\n }\n className=\"w-full rounded-md border border-border bg-background px-3 py-2.5 text-sm text-foreground outline-none focus:border-foreground\"\n autoFocus\n />\n </div>\n\n {/* Date/Time/Duration \u2014 placed before per-type chip rows so the call/task\n workflows match Figma 829:50 / 790:280 (date row first, then status chips). */}\n <DateTimeFields\n visible={visibleFields}\n activityType={state.activityType}\n date={state.date}\n setDate={state.setDate}\n startTime={state.startTime}\n setStartTime={state.setStartTime}\n duration={state.duration}\n setDuration={state.setDuration}\n allDay={state.allDay}\n setAllDay={state.setAllDay}\n recurrenceEnabled={state.recurrenceEnabled}\n setRecurrenceEnabled={state.setRecurrenceEnabled}\n recurrenceDays={state.recurrenceDays}\n toggleRecurrenceDay={state.toggleRecurrenceDay}\n recurrenceEndType={state.recurrenceEndType}\n setRecurrenceEndType={state.setRecurrenceEndType}\n recurrenceCount={state.recurrenceCount}\n setRecurrenceCount={state.setRecurrenceCount}\n recurrenceEndDate={state.recurrenceEndDate}\n setRecurrenceEndDate={state.setRecurrenceEndDate}\n />\n\n {/* Call: Direction + Outcome chips */}\n {state.activityType === 'call' && (\n <div className=\"flex flex-col gap-3\">\n <div>\n <label className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {t('customers.schedule.call.directionLabel', 'Direction')}\n </label>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {CALL_DIRECTIONS.map((opt) => {\n const isActive = callDirection === opt.key\n return (\n <button\n key={opt.key}\n type=\"button\"\n aria-pressed={isActive}\n onClick={() => setCallDirection(opt.key)}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-sm font-medium transition-colors',\n isActive\n ? 'border-transparent bg-foreground text-background'\n : 'border-border bg-card text-muted-foreground hover:border-foreground/40',\n )}\n >\n <span className={cn('inline-block size-1.5 rounded-full', opt.dot)} aria-hidden />\n {t(opt.labelKey, opt.labelFallback)}\n </button>\n )\n })}\n </div>\n </div>\n <div>\n <label className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {t('customers.schedule.call.outcomeLabel', 'Outcome')}\n </label>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {CALL_OUTCOMES.map((opt) => {\n const isActive = callOutcome === opt.key\n return (\n <button\n key={opt.key}\n type=\"button\"\n aria-pressed={isActive}\n onClick={() => setCallOutcome(isActive ? null : opt.key)}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-sm font-medium transition-colors',\n isActive\n ? 'border-transparent bg-foreground text-background'\n : 'border-border bg-card text-muted-foreground hover:border-foreground/40',\n )}\n >\n <span className={cn('inline-block size-1.5 rounded-full', opt.dot)} aria-hidden />\n {t(opt.labelKey, opt.labelFallback)}\n </button>\n )\n })}\n </div>\n </div>\n </div>\n )}\n\n {/* Task: Priority chips */}\n {state.activityType === 'task' && (\n <div>\n <label className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {t('customers.schedule.task.priorityLabel', 'Priority')}\n </label>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {TASK_PRIORITIES.map((opt) => {\n const isActive = taskPriority === opt.key\n return (\n <button\n key={opt.key}\n type=\"button\"\n aria-pressed={isActive}\n onClick={() => setTaskPriority(opt.key)}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-sm font-medium transition-colors',\n isActive\n ? 'border-transparent bg-foreground text-background'\n : 'border-border bg-card text-muted-foreground hover:border-foreground/40',\n )}\n >\n <span className={cn('inline-block size-1.5 rounded-full', opt.dot)} aria-hidden />\n {t(opt.labelKey, opt.labelFallback)}\n </button>\n )\n })}\n </div>\n </div>\n )}\n\n {/* Participants */}\n <ParticipantsField\n visible={visibleFields}\n activityType={state.activityType}\n participants={state.participants}\n setParticipants={state.setParticipants}\n removeParticipant={state.removeParticipant}\n guestPermissions={state.guestPermissions}\n setGuestPermissions={state.setGuestPermissions}\n />\n\n {/* Location (or phone number for calls) */}\n {state.activityType === 'call' ? (\n <div className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"schedule-call-phone\" className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {t('customers.schedule.call.phoneLabel', 'Phone number')}\n </label>\n <PhoneNumberField\n id=\"schedule-call-phone\"\n value={callPhoneNumber}\n onValueChange={handleCallPhoneChange}\n placeholder={t('customers.schedule.call.phonePlaceholder', '+1 555 000 0000')}\n externalError={callPhoneError}\n invalidLabel={callPhoneInvalidMessage}\n minDigits={7}\n />\n </div>\n ) : (\n <LocationField\n visible={visibleFields}\n activityType={state.activityType}\n location={state.location}\n setLocation={state.setLocation}\n />\n )}\n\n {/* Linked Entities */}\n <LinkedEntitiesField\n visible={visibleFields}\n activityType={state.activityType}\n linkedEntities={state.linkedEntities}\n setLinkedEntities={state.setLinkedEntities}\n />\n\n {/* Description */}\n <div>\n <label className=\"text-overline font-semibold uppercase text-muted-foreground tracking-wider\">\n {getFieldLabel(state.activityType, 'description', t, 'customers.schedule.description', 'Description')}\n </label>\n <div className=\"mt-[8px]\">\n <SwitchableMarkdownInput\n value={state.description}\n onChange={state.setDescription}\n isMarkdownEnabled={state.markdownEnabled}\n height={120}\n placeholder={t('customers.schedule.descriptionPlaceholder', 'Add details...')}\n />\n </div>\n </div>\n\n {/* Reminder + Visibility */}\n <FooterFields\n visible={visibleFields}\n activityType={state.activityType}\n reminderMinutes={state.reminderMinutes}\n setReminderMinutes={state.setReminderMinutes}\n visibility={state.visibility}\n setVisibility={state.setVisibility}\n />\n\n </div>\n </div>\n\n {/* Footer */}\n <div className=\"flex shrink-0 items-center justify-end gap-2.5 border-t border-border bg-muted/50 px-6 py-4\">\n <Button type=\"button\" variant=\"outline\" onClick={() => { void guardedClose() }} className=\"rounded-md border border-input bg-background px-5 py-3 text-sm font-semibold text-foreground\">\n {t('customers.schedule.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" onClick={handleSave} disabled={isSubmitDisabled} className=\"flex items-center gap-2 rounded-md bg-foreground px-5 py-3 text-sm font-semibold text-background hover:bg-foreground/90 disabled:opacity-50\">\n <SaveIcon className=\"size-3.5\" />\n {state.saving\n ? t('customers.schedule.saving', 'Saving...')\n : isEditing\n ? t('customers.schedule.update', 'Update activity')\n : t(chrome.saveKey, chrome.saveFallback)}\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n )\n}\n\nexport type { ScheduleActivityEditData }\n\nfunction buildRecurrenceRule(\n days: boolean[],\n endType: 'never' | 'count' | 'date',\n count: number,\n endDate: string,\n): string {\n const dayNames = ['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU']\n const selectedDays = days.map((active, i) => (active ? dayNames[i] : null)).filter(Boolean)\n let rule = `FREQ=WEEKLY;BYDAY=${selectedDays.join(',')}`\n if (endType === 'count') rule += `;COUNT=${count}`\n if (endType === 'date' && endDate) rule += `;UNTIL=${endDate.replace(/-/g, '')}T235959Z`\n return rule\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@open-mercato/ui/primitives/dialog";
|
|
5
|
+
import { useDialogKeyHandler } from "@open-mercato/ui/hooks/useDialogKeyHandler";
|
|
5
6
|
import { Badge } from "@open-mercato/ui/primitives/badge";
|
|
6
7
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
7
8
|
import { Input } from "@open-mercato/ui/primitives/input";
|
|
@@ -555,22 +556,19 @@ function AdjustmentDialog({
|
|
|
555
556
|
t
|
|
556
557
|
]
|
|
557
558
|
);
|
|
559
|
+
const handleSubmitForm = React.useCallback(
|
|
560
|
+
() => dialogContentRef.current?.querySelector("form")?.requestSubmit(),
|
|
561
|
+
[]
|
|
562
|
+
);
|
|
563
|
+
const handleKeyDown = useDialogKeyHandler({
|
|
564
|
+
onConfirm: handleSubmitForm,
|
|
565
|
+
onCancel: () => onOpenChange(false)
|
|
566
|
+
});
|
|
558
567
|
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
|
|
559
568
|
DialogContent,
|
|
560
569
|
{
|
|
561
570
|
className: "sm:max-w-5xl",
|
|
562
|
-
onKeyDown:
|
|
563
|
-
if (event.key === "Escape") {
|
|
564
|
-
event.preventDefault();
|
|
565
|
-
onOpenChange(false);
|
|
566
|
-
return;
|
|
567
|
-
}
|
|
568
|
-
if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
|
|
569
|
-
event.preventDefault();
|
|
570
|
-
const form = dialogContentRef.current?.querySelector("form");
|
|
571
|
-
form?.requestSubmit();
|
|
572
|
-
}
|
|
573
|
-
},
|
|
571
|
+
onKeyDown: handleKeyDown,
|
|
574
572
|
ref: dialogContentRef,
|
|
575
573
|
children: [
|
|
576
574
|
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: initialAdjustment ? labels.editTitle : labels.addTitle }) }),
|