@open-mercato/core 0.7.1-develop.7136.1.0f76137a1d → 0.7.1-develop.7137.1.26575786c0
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/backend/customers/companies-v2/[id]/page.js +1 -0
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +1 -0
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +1 -0
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +25 -12
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +1 -0
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +1 -0
- package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +1 -0
- package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +40 -14
- package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +2 -0
- package/src/modules/customers/i18n/de.json +1 -1
- package/src/modules/customers/i18n/en.json +1 -1
- package/src/modules/customers/i18n/es.json +1 -1
- package/src/modules/customers/i18n/ko.json +1 -1
- package/src/modules/customers/i18n/pl.json +1 -1
|
@@ -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, 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, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader, extractOptimisticLockConflict } from '@open-mercato/ui/backend/utils/optimisticLock'\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 /** Default country ISO2 code for phone number input when value is empty/unparsed */\n defaultCountryIso2?: string\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 defaultCountryIso2,\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 closeConfirmPendingRef = React.useRef(false)\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 (closeConfirmPendingRef.current) return\n if (!isDirty()) {\n onClose()\n return\n }\n closeConfirmPendingRef.current = true\n try {\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 } finally {\n closeConfirmPendingRef.current = false\n }\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 const call = () =>\n apiCallOrThrow('/api/customers/interactions', {\n method: isSaveEdit ? 'PUT' : 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n // Optimistic lock only applies to edits \u2014 a stale modal save against a\n // concurrently changed/deleted activity surfaces the conflict bar (#2055).\n return isSaveEdit\n ? withScopedApiRequestHeaders(buildOptimisticLockHeader(editData?.updatedAt), call)\n : call()\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 // An optimistic-lock 409 was already surfaced as the persistent conflict\n // bar by `runGuardedMutation` (useGuardedMutation \u2192 surfaceRecordConflict).\n // Do NOT additionally flash the raw `record_modified` code here \u2014 that\n // showed an untranslated toast on top of the localized bar (#2055 QA).\n if (extractOptimisticLockConflict(err)) {\n onClose()\n return\n }\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 <DialogContent\n 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\"\n onKeyDown={handleKeyDown}\n aria-describedby={undefined}\n >\n {ConfirmDialogElement}\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 status=\"warning\" className=\"rounded-lg\">\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 defaultCountryIso2={defaultCountryIso2}\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, 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, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader, extractOptimisticLockConflict } from '@open-mercato/ui/backend/utils/optimisticLock'\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'\nimport { PRIORITY_NUMBER, priorityFromNumber, type EditorPriority } from '../../lib/calendar/editorPayload'\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\n// Task priority is the interaction's own nullable `priority` column (0-100), not a\n// custom field \u2014 the same scale `CalendarEventEditor` writes through\n// `PRIORITY_NUMBER` / `priorityFromNumber`. `null` means \"no priority set\", which the\n// column allows (#5943). Dot colours mirror the calendar editor's `PRIORITY_META` so\n// both controls render the same value identically.\ntype TaskPriorityValue = EditorPriority | null\n\nconst TASK_PRIORITIES: Array<{ key: TaskPriorityValue; labelKey: string; labelFallback: string; dot: string }> = [\n { key: null, labelKey: 'customers.schedule.task.priority.none', labelFallback: 'None', dot: 'bg-muted' },\n { key: 'low', labelKey: 'customers.schedule.task.priority.low', labelFallback: 'Low', dot: 'bg-status-info-icon' },\n { key: 'medium', labelKey: 'customers.schedule.task.priority.medium', labelFallback: 'Medium', dot: 'bg-muted-foreground' },\n { key: 'high', labelKey: 'customers.schedule.task.priority.high', labelFallback: 'High', dot: 'bg-status-error-icon' },\n]\n\nfunction readTaskPriorityNumber(raw: { priority?: unknown } | null | undefined): number | null {\n return typeof raw?.priority === 'number' && !Number.isNaN(raw.priority) ? raw.priority : null\n}\n\n// `TaskForm` writes any 0-100 value while these chips only offer three buckets, so a\n// save that did not touch the control must keep the stored number rather than snap it\n// to the bucket midpoint \u2014 `priority` is a sortable column, so rewriting 100 as 90\n// would silently reorder tasks the user never edited.\nfunction buildTaskPriorityPayload(level: TaskPriorityValue, seeded: number | null): number | null {\n if (!level) return null\n if (seeded !== null && priorityFromNumber(seeded) === level) return seeded\n return PRIORITY_NUMBER[level]\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 /** Default country ISO2 code for phone number input when value is empty/unparsed */\n defaultCountryIso2?: string\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 defaultCountryIso2,\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<TaskPriorityValue>(null)\n const [seededTaskPriority, setSeededTaskPriority] = React.useState<number | null>(null)\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; priority?: 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 const seededPriority = readTaskPriorityNumber(raw)\n setSeededTaskPriority(seededPriority)\n setTaskPriority(seededPriority === null ? null : priorityFromNumber(seededPriority))\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(null)\n setSeededTaskPriority(null)\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 closeConfirmPendingRef = React.useRef(false)\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 (closeConfirmPendingRef.current) return\n if (!isDirty()) {\n onClose()\n return\n }\n closeConfirmPendingRef.current = true\n try {\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 } finally {\n closeConfirmPendingRef.current = false\n }\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 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 // Only tasks expose the priority control, so other types leave the column\n // untouched rather than clearing it on a type switch (#5943).\n priority: state.activityType === 'task' ? buildTaskPriorityPayload(taskPriority, seededTaskPriority) : 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 const call = () =>\n apiCallOrThrow('/api/customers/interactions', {\n method: isSaveEdit ? 'PUT' : 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n // Optimistic lock only applies to edits \u2014 a stale modal save against a\n // concurrently changed/deleted activity surfaces the conflict bar (#2055).\n return isSaveEdit\n ? withScopedApiRequestHeaders(buildOptimisticLockHeader(editData?.updatedAt), call)\n : call()\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 // An optimistic-lock 409 was already surfaced as the persistent conflict\n // bar by `runGuardedMutation` (useGuardedMutation \u2192 surfaceRecordConflict).\n // Do NOT additionally flash the raw `record_modified` code here \u2014 that\n // showed an untranslated toast on top of the localized bar (#2055 QA).\n if (extractOptimisticLockConflict(err)) {\n onClose()\n return\n }\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, seededTaskPriority, 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 <DialogContent\n 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\"\n onKeyDown={handleKeyDown}\n aria-describedby={undefined}\n >\n {ConfirmDialogElement}\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 status=\"warning\" className=\"rounded-lg\">\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 ?? 'none'}\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 defaultCountryIso2={defaultCountryIso2}\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
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/customers/components/detail/schedule/useScheduleFormState.ts"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react'\nimport type { ActivityType } from './fieldConfig'\n\nexport type RsvpStatus = 'pending' | 'accepted' | 'declined' | 'tentative'\n\nexport type Participant = {\n userId?: string\n name: string\n email?: string\n color?: string\n status?: RsvpStatus\n}\n\nexport type LinkedEntity = {\n id: string\n type: 'company' | 'deal' | 'offer'\n label: string\n}\n\nexport type ScheduleActivityEditData = {\n id: string\n /** Record version for the OSS optimistic-lock header on edit (#2055). */\n updatedAt?: string | null\n interactionType?: string\n title?: string | null\n body?: string | null\n scheduledAt?: string | null\n /**\n * Historical timestamp for completed activities (status `done`). Required for\n * the edit prefill to restore the original date/time instead of falling back\n * to \"today\" (#1807).\n */\n occurredAt?: string | null\n durationMinutes?: number | null\n location?: string | null\n allDay?: boolean | null\n recurrenceRule?: string | null\n recurrenceEnd?: string | null\n participants?: Array<{ userId?: string; name?: string; email?: string; status?: string }> | null\n reminderMinutes?: number | null\n visibility?: string | null\n linkedEntities?: Array<{ id: string; type: string; label: string }> | null\n guestPermissions?: { canInviteOthers?: boolean; canModify?: boolean; canSeeList?: boolean } | null\n}\n\nexport const PARTICIPANT_COLORS = [\n 'bg-chart-emerald',\n 'bg-chart-blue',\n 'bg-chart-orange',\n 'bg-chart-violet',\n 'bg-chart-pink',\n 'bg-chart-teal',\n]\n\n// Per-Figma defaults for the Reminder dropdown when the user picks an activity\n// type. Meeting/email keep the standard 15 min; tasks default to 1 day (1440 min)\n// because they're plan-ahead artefacts; calls default to 5 min as a stand-in for\n// the Figma \"After call ends\" treatment (which would need a non-numeric sentinel\n// in the API contract \u2014 tracked as a follow-up).\nconst DEFAULT_REMINDER_MINUTES: Record<ActivityType, number> = {\n meeting: 15,\n call: 5,\n task: 1440,\n email: 15,\n note: 15,\n}\n\nfunction padDatePart(value: number): string {\n return String(value).padStart(2, '0')\n}\n\nfunction formatLocalDateInput(date: Date): string {\n return `${date.getFullYear()}-${padDatePart(date.getMonth() + 1)}-${padDatePart(date.getDate())}`\n}\n\nfunction formatLocalTimeInput(date: Date): string {\n return `${padDatePart(date.getHours())}:${padDatePart(date.getMinutes())}`\n}\n\ninterface UseScheduleFormStateParams {\n open: boolean\n editData: ScheduleActivityEditData | null | undefined\n}\n\nexport function useScheduleFormState({ open, editData }: UseScheduleFormStateParams) {\n const [activityType, setActivityType] = React.useState<ActivityType>('meeting')\n const [title, setTitle] = React.useState('')\n const [date, setDate] = React.useState(() => formatLocalDateInput(new Date()))\n const [startTime, setStartTime] = React.useState('10:00')\n const [duration, setDuration] = React.useState(30)\n const [allDay, setAllDay] = React.useState(false)\n const [description, setDescription] = React.useState('')\n const [markdownEnabled, setMarkdownEnabled] = React.useState(true)\n const [location, setLocation] = React.useState('')\n const [reminderMinutes, setReminderMinutes] = React.useState(15)\n const [visibility, setVisibility] = React.useState('team')\n const [participants, setParticipants] = React.useState<Participant[]>([])\n const [linkedEntities, setLinkedEntities] = React.useState<LinkedEntity[]>([])\n const [recurrenceEnabled, setRecurrenceEnabled] = React.useState(false)\n const [recurrenceDays, setRecurrenceDays] = React.useState<boolean[]>([true, false, true, false, false, false, false])\n const [recurrenceEndType, setRecurrenceEndType] = React.useState<'never' | 'count' | 'date'>('never')\n const [recurrenceCount, setRecurrenceCount] = React.useState(8)\n const [recurrenceEndDate, setRecurrenceEndDate] = React.useState('')\n const [conflict, setConflict] = React.useState<string | null>(null)\n const [saving, setSaving] = React.useState(false)\n const [guestPermissions, setGuestPermissions] = React.useState({ canInviteOthers: true, canModify: false, canSeeList: true })\n\n React.useEffect(() => {\n if (open) {\n if (editData) {\n // Edit mode: populate from existing interaction\n const resolvedType = (editData.interactionType as ActivityType) ?? 'meeting'\n setActivityType(resolvedType)\n setTitle(editData.title ?? '')\n // For historical activities the canonical timestamp is `occurredAt`; for\n // planned/future ones it's `scheduledAt`. Without this fallback editing a\n // past activity prefilled to \"today\" instead of its actual moment (#1807).\n // Keep seed values in the user's local timezone, matching the cluster-E\n // local-day convention.\n const sourceTimestamp = editData.occurredAt ?? editData.scheduledAt ?? null\n const seedDate = sourceTimestamp ? new Date(sourceTimestamp) : new Date()\n const seedDateValid = !Number.isNaN(seedDate.getTime())\n const fallbackNow = new Date()\n const dateForForm = seedDateValid ? seedDate : fallbackNow\n setDate(formatLocalDateInput(dateForForm))\n setStartTime(formatLocalTimeInput(dateForForm))\n setDuration(editData.durationMinutes ?? 30)\n setAllDay(editData.allDay ?? false)\n setDescription(editData.body ?? '')\n setLocation(editData.location ?? '')\n // Use per-type default when the editData omits an explicit reminder\n // (the menu-driven \"New X\" flow opens the dialog with `reminderMinutes: null`).\n setReminderMinutes(editData.reminderMinutes ?? DEFAULT_REMINDER_MINUTES[resolvedType])\n setVisibility(editData.visibility ?? 'team')\n setParticipants(\n Array.isArray(editData.participants)\n ? editData.participants.map((p, i) => ({\n userId: p.userId,\n name: p.name ?? p.email ?? p.userId ?? '',\n email: p.email,\n color: PARTICIPANT_COLORS[i % PARTICIPANT_COLORS.length],\n status: (p.status ?? 'pending') as RsvpStatus,\n }))\n : [],\n )\n setLinkedEntities(\n Array.isArray(editData.linkedEntities)\n ? editData.linkedEntities.map((e) => ({ id: e.id, type: e.type as LinkedEntity['type'], label: e.label }))\n : [],\n )\n if (editData.recurrenceRule) {\n setRecurrenceEnabled(true)\n // Parse RRULE to set days and end type\n const rule = editData.recurrenceRule\n const byDayMatch = rule.match(/BYDAY=([A-Z,]+)/)\n if (byDayMatch) {\n const dayNames = ['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU']\n const activeDays = byDayMatch[1].split(',')\n setRecurrenceDays(dayNames.map((d) => activeDays.includes(d)))\n }\n const countMatch = rule.match(/COUNT=(\\d+)/)\n const untilMatch = rule.match(/UNTIL=(\\d{8})/)\n if (countMatch) {\n setRecurrenceEndType('count')\n setRecurrenceCount(Number(countMatch[1]))\n } else if (untilMatch) {\n setRecurrenceEndType('date')\n const raw = untilMatch[1]\n setRecurrenceEndDate(`${raw.slice(0, 4)}-${raw.slice(4, 6)}-${raw.slice(6, 8)}`)\n } else {\n setRecurrenceEndType('never')\n }\n } else {\n setRecurrenceEnabled(false)\n }\n if (editData.guestPermissions) {\n setGuestPermissions({\n canInviteOthers: editData.guestPermissions.canInviteOthers ?? true,\n canModify: editData.guestPermissions.canModify ?? false,\n canSeeList: editData.guestPermissions.canSeeList ?? true,\n })\n }\n } else {\n // Create mode: reset all fields\n setActivityType('meeting')\n setTitle('')\n setDate(formatLocalDateInput(new Date()))\n setStartTime('10:00')\n setDuration(30)\n setAllDay(false)\n setDescription('')\n setLocation('')\n setReminderMinutes(DEFAULT_REMINDER_MINUTES.meeting)\n setVisibility('team')\n setParticipants([])\n setLinkedEntities([])\n setRecurrenceEnabled(false)\n }\n setConflict(null)\n }\n return () => {\n // Safety net: restore body scroll if Radix Dialog fails to clean up\n document.body.style.removeProperty('overflow')\n document.body.style.removeProperty('pointer-events')\n }\n }, [open, editData])\n\n // Update the Reminder default when the activity type changes in create mode.\n // Skipped in edit mode (the persisted value wins), and gated by `open` to\n // avoid flipping the default in a closed-but-mounted dialog.\n const lastReminderTypeRef = React.useRef<ActivityType>('meeting')\n React.useEffect(() => {\n if (!open || editData) {\n lastReminderTypeRef.current = activityType\n return\n }\n if (lastReminderTypeRef.current === activityType) return\n lastReminderTypeRef.current = activityType\n setReminderMinutes(DEFAULT_REMINDER_MINUTES[activityType])\n }, [activityType, editData, open])\n\n const removeParticipant = React.useCallback((index: number) => {\n setParticipants((prev) => prev.filter((_, i) => i !== index))\n }, [])\n\n const toggleRecurrenceDay = React.useCallback((index: number) => {\n setRecurrenceDays((prev) => {\n const next = [...prev]\n next[index] = !next[index]\n return next\n })\n }, [])\n\n return {\n activityType,\n setActivityType,\n title,\n setTitle,\n date,\n setDate,\n startTime,\n setStartTime,\n duration,\n setDuration,\n allDay,\n setAllDay,\n description,\n setDescription,\n markdownEnabled,\n setMarkdownEnabled,\n location,\n setLocation,\n reminderMinutes,\n setReminderMinutes,\n visibility,\n setVisibility,\n participants,\n setParticipants,\n linkedEntities,\n setLinkedEntities,\n recurrenceEnabled,\n setRecurrenceEnabled,\n recurrenceDays,\n setRecurrenceDays,\n recurrenceEndType,\n setRecurrenceEndType,\n recurrenceCount,\n setRecurrenceCount,\n recurrenceEndDate,\n setRecurrenceEndDate,\n conflict,\n setConflict,\n saving,\n setSaving,\n guestPermissions,\n setGuestPermissions,\n removeParticipant,\n toggleRecurrenceDay,\n }\n}\n"],
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;
|
|
4
|
+
"sourcesContent": ["import * as React from 'react'\nimport type { ActivityType } from './fieldConfig'\n\nexport type RsvpStatus = 'pending' | 'accepted' | 'declined' | 'tentative'\n\nexport type Participant = {\n userId?: string\n name: string\n email?: string\n color?: string\n status?: RsvpStatus\n}\n\nexport type LinkedEntity = {\n id: string\n type: 'company' | 'deal' | 'offer'\n label: string\n}\n\nexport type ScheduleActivityEditData = {\n id: string\n /** Record version for the OSS optimistic-lock header on edit (#2055). */\n updatedAt?: string | null\n interactionType?: string\n title?: string | null\n body?: string | null\n scheduledAt?: string | null\n /**\n * Historical timestamp for completed activities (status `done`). Required for\n * the edit prefill to restore the original date/time instead of falling back\n * to \"today\" (#1807).\n */\n occurredAt?: string | null\n durationMinutes?: number | null\n /** Interaction priority column (0-100, nullable) backing the task priority control (#5943). */\n priority?: number | null\n location?: string | null\n allDay?: boolean | null\n recurrenceRule?: string | null\n recurrenceEnd?: string | null\n participants?: Array<{ userId?: string; name?: string; email?: string; status?: string }> | null\n reminderMinutes?: number | null\n visibility?: string | null\n linkedEntities?: Array<{ id: string; type: string; label: string }> | null\n guestPermissions?: { canInviteOthers?: boolean; canModify?: boolean; canSeeList?: boolean } | null\n}\n\nexport const PARTICIPANT_COLORS = [\n 'bg-chart-emerald',\n 'bg-chart-blue',\n 'bg-chart-orange',\n 'bg-chart-violet',\n 'bg-chart-pink',\n 'bg-chart-teal',\n]\n\n// Per-Figma defaults for the Reminder dropdown when the user picks an activity\n// type. Meeting/email keep the standard 15 min; tasks default to 1 day (1440 min)\n// because they're plan-ahead artefacts; calls default to 5 min as a stand-in for\n// the Figma \"After call ends\" treatment (which would need a non-numeric sentinel\n// in the API contract \u2014 tracked as a follow-up).\nconst DEFAULT_REMINDER_MINUTES: Record<ActivityType, number> = {\n meeting: 15,\n call: 5,\n task: 1440,\n email: 15,\n note: 15,\n}\n\nfunction padDatePart(value: number): string {\n return String(value).padStart(2, '0')\n}\n\nfunction formatLocalDateInput(date: Date): string {\n return `${date.getFullYear()}-${padDatePart(date.getMonth() + 1)}-${padDatePart(date.getDate())}`\n}\n\nfunction formatLocalTimeInput(date: Date): string {\n return `${padDatePart(date.getHours())}:${padDatePart(date.getMinutes())}`\n}\n\ninterface UseScheduleFormStateParams {\n open: boolean\n editData: ScheduleActivityEditData | null | undefined\n}\n\nexport function useScheduleFormState({ open, editData }: UseScheduleFormStateParams) {\n const [activityType, setActivityType] = React.useState<ActivityType>('meeting')\n const [title, setTitle] = React.useState('')\n const [date, setDate] = React.useState(() => formatLocalDateInput(new Date()))\n const [startTime, setStartTime] = React.useState('10:00')\n const [duration, setDuration] = React.useState(30)\n const [allDay, setAllDay] = React.useState(false)\n const [description, setDescription] = React.useState('')\n const [markdownEnabled, setMarkdownEnabled] = React.useState(true)\n const [location, setLocation] = React.useState('')\n const [reminderMinutes, setReminderMinutes] = React.useState(15)\n const [visibility, setVisibility] = React.useState('team')\n const [participants, setParticipants] = React.useState<Participant[]>([])\n const [linkedEntities, setLinkedEntities] = React.useState<LinkedEntity[]>([])\n const [recurrenceEnabled, setRecurrenceEnabled] = React.useState(false)\n const [recurrenceDays, setRecurrenceDays] = React.useState<boolean[]>([true, false, true, false, false, false, false])\n const [recurrenceEndType, setRecurrenceEndType] = React.useState<'never' | 'count' | 'date'>('never')\n const [recurrenceCount, setRecurrenceCount] = React.useState(8)\n const [recurrenceEndDate, setRecurrenceEndDate] = React.useState('')\n const [conflict, setConflict] = React.useState<string | null>(null)\n const [saving, setSaving] = React.useState(false)\n const [guestPermissions, setGuestPermissions] = React.useState({ canInviteOthers: true, canModify: false, canSeeList: true })\n\n React.useEffect(() => {\n if (open) {\n if (editData) {\n // Edit mode: populate from existing interaction\n const resolvedType = (editData.interactionType as ActivityType) ?? 'meeting'\n setActivityType(resolvedType)\n setTitle(editData.title ?? '')\n // For historical activities the canonical timestamp is `occurredAt`; for\n // planned/future ones it's `scheduledAt`. Without this fallback editing a\n // past activity prefilled to \"today\" instead of its actual moment (#1807).\n // Keep seed values in the user's local timezone, matching the cluster-E\n // local-day convention.\n const sourceTimestamp = editData.occurredAt ?? editData.scheduledAt ?? null\n const seedDate = sourceTimestamp ? new Date(sourceTimestamp) : new Date()\n const seedDateValid = !Number.isNaN(seedDate.getTime())\n const fallbackNow = new Date()\n const dateForForm = seedDateValid ? seedDate : fallbackNow\n setDate(formatLocalDateInput(dateForForm))\n setStartTime(formatLocalTimeInput(dateForForm))\n setDuration(editData.durationMinutes ?? 30)\n setAllDay(editData.allDay ?? false)\n setDescription(editData.body ?? '')\n setLocation(editData.location ?? '')\n // Use per-type default when the editData omits an explicit reminder\n // (the menu-driven \"New X\" flow opens the dialog with `reminderMinutes: null`).\n setReminderMinutes(editData.reminderMinutes ?? DEFAULT_REMINDER_MINUTES[resolvedType])\n setVisibility(editData.visibility ?? 'team')\n setParticipants(\n Array.isArray(editData.participants)\n ? editData.participants.map((p, i) => ({\n userId: p.userId,\n name: p.name ?? p.email ?? p.userId ?? '',\n email: p.email,\n color: PARTICIPANT_COLORS[i % PARTICIPANT_COLORS.length],\n status: (p.status ?? 'pending') as RsvpStatus,\n }))\n : [],\n )\n setLinkedEntities(\n Array.isArray(editData.linkedEntities)\n ? editData.linkedEntities.map((e) => ({ id: e.id, type: e.type as LinkedEntity['type'], label: e.label }))\n : [],\n )\n if (editData.recurrenceRule) {\n setRecurrenceEnabled(true)\n // Parse RRULE to set days and end type\n const rule = editData.recurrenceRule\n const byDayMatch = rule.match(/BYDAY=([A-Z,]+)/)\n if (byDayMatch) {\n const dayNames = ['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU']\n const activeDays = byDayMatch[1].split(',')\n setRecurrenceDays(dayNames.map((d) => activeDays.includes(d)))\n }\n const countMatch = rule.match(/COUNT=(\\d+)/)\n const untilMatch = rule.match(/UNTIL=(\\d{8})/)\n if (countMatch) {\n setRecurrenceEndType('count')\n setRecurrenceCount(Number(countMatch[1]))\n } else if (untilMatch) {\n setRecurrenceEndType('date')\n const raw = untilMatch[1]\n setRecurrenceEndDate(`${raw.slice(0, 4)}-${raw.slice(4, 6)}-${raw.slice(6, 8)}`)\n } else {\n setRecurrenceEndType('never')\n }\n } else {\n setRecurrenceEnabled(false)\n }\n if (editData.guestPermissions) {\n setGuestPermissions({\n canInviteOthers: editData.guestPermissions.canInviteOthers ?? true,\n canModify: editData.guestPermissions.canModify ?? false,\n canSeeList: editData.guestPermissions.canSeeList ?? true,\n })\n }\n } else {\n // Create mode: reset all fields\n setActivityType('meeting')\n setTitle('')\n setDate(formatLocalDateInput(new Date()))\n setStartTime('10:00')\n setDuration(30)\n setAllDay(false)\n setDescription('')\n setLocation('')\n setReminderMinutes(DEFAULT_REMINDER_MINUTES.meeting)\n setVisibility('team')\n setParticipants([])\n setLinkedEntities([])\n setRecurrenceEnabled(false)\n }\n setConflict(null)\n }\n return () => {\n // Safety net: restore body scroll if Radix Dialog fails to clean up\n document.body.style.removeProperty('overflow')\n document.body.style.removeProperty('pointer-events')\n }\n }, [open, editData])\n\n // Update the Reminder default when the activity type changes in create mode.\n // Skipped in edit mode (the persisted value wins), and gated by `open` to\n // avoid flipping the default in a closed-but-mounted dialog.\n const lastReminderTypeRef = React.useRef<ActivityType>('meeting')\n React.useEffect(() => {\n if (!open || editData) {\n lastReminderTypeRef.current = activityType\n return\n }\n if (lastReminderTypeRef.current === activityType) return\n lastReminderTypeRef.current = activityType\n setReminderMinutes(DEFAULT_REMINDER_MINUTES[activityType])\n }, [activityType, editData, open])\n\n const removeParticipant = React.useCallback((index: number) => {\n setParticipants((prev) => prev.filter((_, i) => i !== index))\n }, [])\n\n const toggleRecurrenceDay = React.useCallback((index: number) => {\n setRecurrenceDays((prev) => {\n const next = [...prev]\n next[index] = !next[index]\n return next\n })\n }, [])\n\n return {\n activityType,\n setActivityType,\n title,\n setTitle,\n date,\n setDate,\n startTime,\n setStartTime,\n duration,\n setDuration,\n allDay,\n setAllDay,\n description,\n setDescription,\n markdownEnabled,\n setMarkdownEnabled,\n location,\n setLocation,\n reminderMinutes,\n setReminderMinutes,\n visibility,\n setVisibility,\n participants,\n setParticipants,\n linkedEntities,\n setLinkedEntities,\n recurrenceEnabled,\n setRecurrenceEnabled,\n recurrenceDays,\n setRecurrenceDays,\n recurrenceEndType,\n setRecurrenceEndType,\n recurrenceCount,\n setRecurrenceCount,\n recurrenceEndDate,\n setRecurrenceEndDate,\n conflict,\n setConflict,\n saving,\n setSaving,\n guestPermissions,\n setGuestPermissions,\n removeParticipant,\n toggleRecurrenceDay,\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.7.1-develop.
|
|
3
|
+
"version": "0.7.1-develop.7137.1.26575786c0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -252,16 +252,16 @@
|
|
|
252
252
|
"zod": "^4.4.3"
|
|
253
253
|
},
|
|
254
254
|
"peerDependencies": {
|
|
255
|
-
"@open-mercato/ai-assistant": "0.7.1-develop.
|
|
256
|
-
"@open-mercato/shared": "0.7.1-develop.
|
|
257
|
-
"@open-mercato/ui": "0.7.1-develop.
|
|
255
|
+
"@open-mercato/ai-assistant": "0.7.1-develop.7137.1.26575786c0",
|
|
256
|
+
"@open-mercato/shared": "0.7.1-develop.7137.1.26575786c0",
|
|
257
|
+
"@open-mercato/ui": "0.7.1-develop.7137.1.26575786c0",
|
|
258
258
|
"react": "^19.0.0",
|
|
259
259
|
"react-dom": "^19.0.0"
|
|
260
260
|
},
|
|
261
261
|
"devDependencies": {
|
|
262
|
-
"@open-mercato/ai-assistant": "0.7.1-develop.
|
|
263
|
-
"@open-mercato/shared": "0.7.1-develop.
|
|
264
|
-
"@open-mercato/ui": "0.7.1-develop.
|
|
262
|
+
"@open-mercato/ai-assistant": "0.7.1-develop.7137.1.26575786c0",
|
|
263
|
+
"@open-mercato/shared": "0.7.1-develop.7137.1.26575786c0",
|
|
264
|
+
"@open-mercato/ui": "0.7.1-develop.7137.1.26575786c0",
|
|
265
265
|
"@testing-library/dom": "^10.4.1",
|
|
266
266
|
"@testing-library/jest-dom": "^7.0.0",
|
|
267
267
|
"@testing-library/react": "^16.3.1",
|
|
@@ -247,6 +247,7 @@ export default function CompanyDetailV2Page({ params }: { params?: { id?: string
|
|
|
247
247
|
scheduledAt: typeof activity.scheduledAt === 'string' ? activity.scheduledAt : null,
|
|
248
248
|
occurredAt: typeof activity.occurredAt === 'string' ? activity.occurredAt : null,
|
|
249
249
|
durationMinutes: durationValue,
|
|
250
|
+
priority: typeof raw.priority === 'number' ? raw.priority as number : null,
|
|
250
251
|
location: typeof raw.location === 'string' ? raw.location as string : null,
|
|
251
252
|
allDay: typeof raw.allDay === 'boolean' ? raw.allDay as boolean : null,
|
|
252
253
|
recurrenceRule: typeof raw.recurrenceRule === 'string' ? raw.recurrenceRule as string : null,
|
|
@@ -264,6 +264,7 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
|
|
|
264
264
|
scheduledAt: activity.scheduledAt ?? null,
|
|
265
265
|
occurredAt: activity.occurredAt ?? null,
|
|
266
266
|
durationMinutes: activity.duration ?? null,
|
|
267
|
+
priority: activity.priority ?? null,
|
|
267
268
|
location: activity.location ?? null,
|
|
268
269
|
allDay: activity.allDay ?? null,
|
|
269
270
|
recurrenceRule: activity.recurrenceRule ?? null,
|
|
@@ -276,6 +276,7 @@ export default function PersonDetailV2Page({ params }: { params?: { id?: string
|
|
|
276
276
|
scheduledAt: typeof activity.scheduledAt === 'string' ? activity.scheduledAt : null,
|
|
277
277
|
occurredAt: typeof activity.occurredAt === 'string' ? activity.occurredAt : null,
|
|
278
278
|
durationMinutes: durationValue,
|
|
279
|
+
priority: typeof raw.priority === 'number' ? raw.priority as number : null,
|
|
279
280
|
location: typeof raw.location === 'string' ? raw.location as string : null,
|
|
280
281
|
allDay: typeof raw.allDay === 'boolean' ? raw.allDay as boolean : null,
|
|
281
282
|
recurrenceRule: typeof raw.recurrenceRule === 'string' ? raw.recurrenceRule as string : null,
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
LinkedEntitiesField,
|
|
30
30
|
} from './schedule'
|
|
31
31
|
import type { ActivityType, ScheduleActivityEditData } from './schedule'
|
|
32
|
+
import { PRIORITY_NUMBER, priorityFromNumber, type EditorPriority } from '../../lib/calendar/editorPayload'
|
|
32
33
|
|
|
33
34
|
const TYPE_TABS: Array<{ type: ActivityType; icon: React.ComponentType<{ className?: string }>; labelKey: string; fallback: string }> = [
|
|
34
35
|
{ type: 'meeting', icon: Users, labelKey: 'customers.schedule.types.meeting', fallback: 'Meeting' },
|
|
@@ -81,13 +82,34 @@ const CALL_OUTCOMES: Array<{ key: string; labelKey: string; labelFallback: strin
|
|
|
81
82
|
{ key: 'badnumber', labelKey: 'customers.schedule.call.outcome.badNumber', labelFallback: 'Bad number', dot: 'bg-status-error-icon' },
|
|
82
83
|
]
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
// Task priority is the interaction's own nullable `priority` column (0-100), not a
|
|
86
|
+
// custom field — the same scale `CalendarEventEditor` writes through
|
|
87
|
+
// `PRIORITY_NUMBER` / `priorityFromNumber`. `null` means "no priority set", which the
|
|
88
|
+
// column allows (#5943). Dot colours mirror the calendar editor's `PRIORITY_META` so
|
|
89
|
+
// both controls render the same value identically.
|
|
90
|
+
type TaskPriorityValue = EditorPriority | null
|
|
91
|
+
|
|
92
|
+
const TASK_PRIORITIES: Array<{ key: TaskPriorityValue; labelKey: string; labelFallback: string; dot: string }> = [
|
|
93
|
+
{ key: null, labelKey: 'customers.schedule.task.priority.none', labelFallback: 'None', dot: 'bg-muted' },
|
|
94
|
+
{ key: 'low', labelKey: 'customers.schedule.task.priority.low', labelFallback: 'Low', dot: 'bg-status-info-icon' },
|
|
95
|
+
{ key: 'medium', labelKey: 'customers.schedule.task.priority.medium', labelFallback: 'Medium', dot: 'bg-muted-foreground' },
|
|
96
|
+
{ key: 'high', labelKey: 'customers.schedule.task.priority.high', labelFallback: 'High', dot: 'bg-status-error-icon' },
|
|
89
97
|
]
|
|
90
98
|
|
|
99
|
+
function readTaskPriorityNumber(raw: { priority?: unknown } | null | undefined): number | null {
|
|
100
|
+
return typeof raw?.priority === 'number' && !Number.isNaN(raw.priority) ? raw.priority : null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// `TaskForm` writes any 0-100 value while these chips only offer three buckets, so a
|
|
104
|
+
// save that did not touch the control must keep the stored number rather than snap it
|
|
105
|
+
// to the bucket midpoint — `priority` is a sortable column, so rewriting 100 as 90
|
|
106
|
+
// would silently reorder tasks the user never edited.
|
|
107
|
+
function buildTaskPriorityPayload(level: TaskPriorityValue, seeded: number | null): number | null {
|
|
108
|
+
if (!level) return null
|
|
109
|
+
if (seeded !== null && priorityFromNumber(seeded) === level) return seeded
|
|
110
|
+
return PRIORITY_NUMBER[level]
|
|
111
|
+
}
|
|
112
|
+
|
|
91
113
|
interface ScheduleActivityDialogProps {
|
|
92
114
|
open: boolean
|
|
93
115
|
onClose: () => void
|
|
@@ -126,7 +148,8 @@ export function ScheduleActivityDialog({
|
|
|
126
148
|
const [callOutcome, setCallOutcome] = React.useState<string | null>(null)
|
|
127
149
|
const [callPhoneNumber, setCallPhoneNumber] = React.useState('')
|
|
128
150
|
const [callPhoneError, setCallPhoneError] = React.useState<string | null>(null)
|
|
129
|
-
const [taskPriority, setTaskPriority] = React.useState<
|
|
151
|
+
const [taskPriority, setTaskPriority] = React.useState<TaskPriorityValue>(null)
|
|
152
|
+
const [seededTaskPriority, setSeededTaskPriority] = React.useState<number | null>(null)
|
|
130
153
|
const callPhoneInvalidMessage = React.useMemo(
|
|
131
154
|
() =>
|
|
132
155
|
t(
|
|
@@ -145,7 +168,7 @@ export function ScheduleActivityDialog({
|
|
|
145
168
|
|
|
146
169
|
React.useEffect(() => {
|
|
147
170
|
if (!open) return
|
|
148
|
-
const raw = editData as (Record<string, unknown> & { customValues?: unknown; phoneNumber?: unknown }) | null | undefined
|
|
171
|
+
const raw = editData as (Record<string, unknown> & { customValues?: unknown; phoneNumber?: unknown; priority?: unknown }) | null | undefined
|
|
149
172
|
const cv = (raw?.customValues && typeof raw.customValues === 'object' ? raw.customValues : null) as Record<string, unknown> | null
|
|
150
173
|
setCallDirection(typeof cv?.callDirection === 'string' && cv.callDirection === 'inbound' ? 'inbound' : 'outbound')
|
|
151
174
|
setCallOutcome(typeof cv?.callOutcome === 'string' ? cv.callOutcome : null)
|
|
@@ -160,7 +183,9 @@ export function ScheduleActivityDialog({
|
|
|
160
183
|
: ''
|
|
161
184
|
setCallPhoneNumber(seededPhone)
|
|
162
185
|
setCallPhoneError(null)
|
|
163
|
-
|
|
186
|
+
const seededPriority = readTaskPriorityNumber(raw)
|
|
187
|
+
setSeededTaskPriority(seededPriority)
|
|
188
|
+
setTaskPriority(seededPriority === null ? null : priorityFromNumber(seededPriority))
|
|
164
189
|
}, [open, editData])
|
|
165
190
|
|
|
166
191
|
// Reset per-type chip state when the user switches activity type in create mode.
|
|
@@ -171,7 +196,8 @@ export function ScheduleActivityDialog({
|
|
|
171
196
|
setCallOutcome(null)
|
|
172
197
|
setCallPhoneNumber('')
|
|
173
198
|
setCallPhoneError(null)
|
|
174
|
-
setTaskPriority(
|
|
199
|
+
setTaskPriority(null)
|
|
200
|
+
setSeededTaskPriority(null)
|
|
175
201
|
}, [state.activityType, open, isEditing])
|
|
176
202
|
|
|
177
203
|
const handleCallPhoneChange = React.useCallback((next: string | undefined) => {
|
|
@@ -388,9 +414,6 @@ export function ScheduleActivityDialog({
|
|
|
388
414
|
if (callOutcome) customValues.callOutcome = callOutcome
|
|
389
415
|
if (phoneNumberForPayload) customValues.callPhoneNumber = phoneNumberForPayload
|
|
390
416
|
}
|
|
391
|
-
if (state.activityType === 'task') {
|
|
392
|
-
customValues.taskPriority = taskPriority
|
|
393
|
-
}
|
|
394
417
|
const payload = {
|
|
395
418
|
...(isSaveEdit ? { id: editData!.id } : {}),
|
|
396
419
|
entityId,
|
|
@@ -402,6 +425,9 @@ export function ScheduleActivityDialog({
|
|
|
402
425
|
date: trimmedDate,
|
|
403
426
|
time: state.allDay ? '00:00' : trimmedStartTime,
|
|
404
427
|
phoneNumber: state.activityType === 'call' ? phoneNumberForPayload : undefined,
|
|
428
|
+
// Only tasks expose the priority control, so other types leave the column
|
|
429
|
+
// untouched rather than clearing it on a type switch (#5943).
|
|
430
|
+
priority: state.activityType === 'task' ? buildTaskPriorityPayload(taskPriority, seededTaskPriority) : undefined,
|
|
405
431
|
scheduledAt,
|
|
406
432
|
durationMinutes: visibleFields.has('duration') && !state.allDay ? state.duration : null,
|
|
407
433
|
location: visibleFields.has('location') ? (state.location.trim() || null) : null,
|
|
@@ -469,7 +495,7 @@ export function ScheduleActivityDialog({
|
|
|
469
495
|
} finally {
|
|
470
496
|
state.setSaving(false)
|
|
471
497
|
}
|
|
472
|
-
}, [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
|
|
498
|
+
}, [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, seededTaskPriority, state.startTime, t, taskPriority, state.title, translateErrorMessage, trimmedCallPhone, trimmedDate, trimmedStartTime, state.visibility, visibleFields]) // eslint-disable-line react-hooks/exhaustive-deps
|
|
473
499
|
|
|
474
500
|
const handleKeyDown = useDialogKeyHandler({ onConfirm: handleSave })
|
|
475
501
|
|
|
@@ -658,7 +684,7 @@ export function ScheduleActivityDialog({
|
|
|
658
684
|
const isActive = taskPriority === opt.key
|
|
659
685
|
return (
|
|
660
686
|
<button
|
|
661
|
-
key={opt.key}
|
|
687
|
+
key={opt.key ?? 'none'}
|
|
662
688
|
type="button"
|
|
663
689
|
aria-pressed={isActive}
|
|
664
690
|
onClick={() => setTaskPriority(opt.key)}
|
|
@@ -32,6 +32,8 @@ export type ScheduleActivityEditData = {
|
|
|
32
32
|
*/
|
|
33
33
|
occurredAt?: string | null
|
|
34
34
|
durationMinutes?: number | null
|
|
35
|
+
/** Interaction priority column (0-100, nullable) backing the task priority control (#5943). */
|
|
36
|
+
priority?: number | null
|
|
35
37
|
location?: string | null
|
|
36
38
|
allDay?: boolean | null
|
|
37
39
|
recurrenceRule?: string | null
|
|
@@ -2658,7 +2658,7 @@
|
|
|
2658
2658
|
"customers.schedule.task.priority.high": "Hoch",
|
|
2659
2659
|
"customers.schedule.task.priority.low": "Niedrig",
|
|
2660
2660
|
"customers.schedule.task.priority.medium": "Mittel",
|
|
2661
|
-
"customers.schedule.task.priority.
|
|
2661
|
+
"customers.schedule.task.priority.none": "Keine",
|
|
2662
2662
|
"customers.schedule.task.priorityLabel": "Priorität",
|
|
2663
2663
|
"customers.schedule.task.save": "Aufgabe speichern",
|
|
2664
2664
|
"customers.schedule.task.subtitle": "Erfassen Sie etwas zum Nachverfolgen",
|
|
@@ -2658,7 +2658,7 @@
|
|
|
2658
2658
|
"customers.schedule.task.priority.high": "High",
|
|
2659
2659
|
"customers.schedule.task.priority.low": "Low",
|
|
2660
2660
|
"customers.schedule.task.priority.medium": "Medium",
|
|
2661
|
-
"customers.schedule.task.priority.
|
|
2661
|
+
"customers.schedule.task.priority.none": "None",
|
|
2662
2662
|
"customers.schedule.task.priorityLabel": "Priority",
|
|
2663
2663
|
"customers.schedule.task.save": "Save task",
|
|
2664
2664
|
"customers.schedule.task.subtitle": "Capture something to follow up on",
|
|
@@ -2658,7 +2658,7 @@
|
|
|
2658
2658
|
"customers.schedule.task.priority.high": "Alta",
|
|
2659
2659
|
"customers.schedule.task.priority.low": "Baja",
|
|
2660
2660
|
"customers.schedule.task.priority.medium": "Media",
|
|
2661
|
-
"customers.schedule.task.priority.
|
|
2661
|
+
"customers.schedule.task.priority.none": "Ninguna",
|
|
2662
2662
|
"customers.schedule.task.priorityLabel": "Prioridad",
|
|
2663
2663
|
"customers.schedule.task.save": "Guardar tarea",
|
|
2664
2664
|
"customers.schedule.task.subtitle": "Captura algo para hacer seguimiento",
|
|
@@ -2658,7 +2658,7 @@
|
|
|
2658
2658
|
"customers.schedule.task.priority.high": "높음",
|
|
2659
2659
|
"customers.schedule.task.priority.low": "낮음",
|
|
2660
2660
|
"customers.schedule.task.priority.medium": "보통",
|
|
2661
|
-
"customers.schedule.task.priority.
|
|
2661
|
+
"customers.schedule.task.priority.none": "없음",
|
|
2662
2662
|
"customers.schedule.task.priorityLabel": "우선순위",
|
|
2663
2663
|
"customers.schedule.task.save": "작업 저장",
|
|
2664
2664
|
"customers.schedule.task.subtitle": "후속 조치가 필요한 사항을 기록하세요",
|