@open-mercato/core 0.10.1-develop.7917.1.c74e12c1d2 → 0.10.1-develop.7921.1.e5774a7073

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.
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { Users, Phone, Check, Mail, Calendar, X, StickyNote } from "lucide-react";
5
5
  import { cn } from "@open-mercato/shared/lib/utils";
@@ -32,6 +32,7 @@ import {
32
32
  LinkedEntitiesField
33
33
  } from "./schedule/index.js";
34
34
  import { PRIORITY_NUMBER, priorityFromNumber } from "../../lib/calendar/editorPayload.js";
35
+ import { selectedEventType, useEventTypeCatalog } from "../calendar/editor/useEventTypeCatalog.js";
35
36
  const TYPE_TABS = [
36
37
  { type: "meeting", icon: Users, labelKey: "customers.schedule.types.meeting", fallback: "Meeting" },
37
38
  { type: "call", icon: Phone, labelKey: "customers.schedule.types.call", fallback: "Call" },
@@ -124,9 +125,37 @@ function ScheduleActivityDialog({
124
125
  defaultCountryIso2
125
126
  }) {
126
127
  const t = useT();
127
- const state = useScheduleFormState({ open, editData: editData ?? null });
128
+ const needsTypeCatalog = Boolean(editData?.interactionType && !TYPE_TABS.some(({ type }) => type === editData.interactionType));
129
+ const catalog = useEventTypeCatalog(open && needsTypeCatalog);
130
+ const definition = needsTypeCatalog ? selectedEventType(catalog.items, editData.interactionType) : null;
131
+ const baseKind = definition?.behavior.baseKind;
132
+ const initialActivityType = baseKind === "event" ? "meeting" : baseKind;
133
+ const resolvedEditData = React.useMemo(
134
+ () => editData && initialActivityType ? { ...editData, interactionType: initialActivityType } : editData,
135
+ [editData, initialActivityType]
136
+ );
137
+ const state = useScheduleFormState({ open, editData: resolvedEditData ?? null });
128
138
  const presentationType = resolveScheduleActivityType(state.activityType);
129
- const visibleFields = FIELD_VISIBILITY[presentationType];
139
+ const [typeChanged, setTypeChanged] = React.useState(false);
140
+ React.useEffect(() => {
141
+ setTypeChanged(false);
142
+ }, [open, editData]);
143
+ const keepsCustomType = needsTypeCatalog && !typeChanged && state.activityType === initialActivityType;
144
+ const catalogPending = needsTypeCatalog && catalog.status !== "ready";
145
+ const visibleFields = React.useMemo(() => {
146
+ const fields = new Set(FIELD_VISIBILITY[presentationType]);
147
+ if (!keepsCustomType || !definition) return fields;
148
+ const configured = definition.behavior.fields;
149
+ if (!configured.endTime) fields.delete("duration");
150
+ if (!configured.allDay) fields.delete("allDay");
151
+ if (!configured.recurrence) fields.delete("recurrence");
152
+ if (configured.location === "none") fields.delete("location");
153
+ if (configured.people === "none") {
154
+ fields.delete("participants");
155
+ fields.delete("guestPermissions");
156
+ }
157
+ return fields;
158
+ }, [presentationType, keepsCustomType, definition]);
130
159
  const { confirm, ConfirmDialogElement } = useConfirmDialog();
131
160
  const isEditing = Boolean(editData?.id);
132
161
  const chrome = TYPE_CHROME[presentationType];
@@ -220,7 +249,7 @@ function ScheduleActivityDialog({
220
249
  const snapshotOpenKeyRef = React.useRef(null);
221
250
  const snapshotSettleCountRef = React.useRef(0);
222
251
  const closeConfirmPendingRef = React.useRef(false);
223
- const openKey = open ? `${editData?.id ?? "new"}` : null;
252
+ const openKey = open ? `${editData?.id ?? "new"}:${initialActivityType ?? ""}` : null;
224
253
  React.useEffect(() => {
225
254
  if (!open) {
226
255
  initialSnapshotRef.current = null;
@@ -330,8 +359,9 @@ function ScheduleActivityDialog({
330
359
  const trimmedCallPhone = callPhoneNumber.trim();
331
360
  const isDateMissing = isDateRequired(presentationType) && !trimmedDate;
332
361
  const isTimeMissing = isTimeRequired(presentationType) && !state.allDay && !trimmedStartTime;
333
- const isSubmitDisabled = state.saving || !state.title.trim() || isDateMissing || isTimeMissing;
362
+ const isSubmitDisabled = catalogPending || state.saving || !state.title.trim() || isDateMissing || isTimeMissing;
334
363
  const handleSave = React.useCallback(async () => {
364
+ if (catalogPending) return;
335
365
  if (!state.title.trim()) return;
336
366
  if (isDateMissing) {
337
367
  flash(t("customers.activities.errors.dateRequired", "Date is required"), "error");
@@ -368,33 +398,35 @@ function ScheduleActivityDialog({
368
398
  if (phoneNumberForPayload) customValues.callPhoneNumber = phoneNumberForPayload;
369
399
  }
370
400
  const payloadEntityId = isSaveEdit && editData?.entityId ? editData.entityId : entityId;
401
+ const hiddenFieldValue = keepsCustomType && isSaveEdit ? void 0 : null;
402
+ const preservesSchedule = keepsCustomType && isSaveEdit && !visibleFields.has("date");
371
403
  const payload = {
372
404
  ...isSaveEdit ? { id: editData.id } : {},
373
405
  entityId: payloadEntityId,
374
406
  dealId,
375
- interactionType: state.activityType,
407
+ interactionType: keepsCustomType ? editData.interactionType : state.activityType,
376
408
  title: state.title.trim(),
377
409
  body: state.description.trim() || null,
378
410
  // The dialog has no status control, so an edit must leave the stored status
379
411
  // (and its `occurredAt`) alone instead of re-opening a completed activity (#6481).
380
412
  ...isSaveEdit ? {} : { status: "planned" },
381
- date: trimmedDate || null,
382
- time: trimmedDate ? timeForPayload || null : null,
413
+ date: preservesSchedule ? void 0 : trimmedDate || null,
414
+ time: preservesSchedule ? void 0 : trimmedDate ? timeForPayload || null : null,
383
415
  phoneNumber: presentationType === "call" ? phoneNumberForPayload : void 0,
384
416
  // Only tasks expose the priority control, so other types leave the column
385
417
  // untouched rather than clearing it on a type switch (#5943).
386
418
  priority: presentationType === "task" ? buildTaskPriorityPayload(taskPriority, seededTaskPriority) : void 0,
387
- scheduledAt,
388
- durationMinutes: visibleFields.has("duration") && !state.allDay ? state.duration : null,
389
- location: visibleFields.has("location") ? state.location.trim() || null : null,
390
- allDay: visibleFields.has("allDay") ? state.allDay : null,
391
- recurrenceRule: visibleFields.has("recurrence") ? recurrenceRule : null,
392
- recurrenceEnd: visibleFields.has("recurrence") && state.recurrenceEndType === "date" && state.recurrenceEndDate ? new Date(state.recurrenceEndDate).toISOString() : null,
393
- participants: visibleFields.has("participants") && state.participants.length > 0 ? state.participants.map((p) => ({ userId: p.userId, name: p.name, email: p.email, status: p.status ?? "pending" })) : null,
394
- guestPermissions: visibleFields.has("participants") && state.participants.length > 0 ? state.guestPermissions : null,
419
+ scheduledAt: preservesSchedule ? void 0 : scheduledAt,
420
+ durationMinutes: visibleFields.has("duration") ? state.allDay ? null : state.duration : hiddenFieldValue,
421
+ location: visibleFields.has("location") ? state.location.trim() || null : hiddenFieldValue,
422
+ allDay: visibleFields.has("allDay") ? state.allDay : hiddenFieldValue,
423
+ recurrenceRule: visibleFields.has("recurrence") ? recurrenceRule : hiddenFieldValue,
424
+ recurrenceEnd: visibleFields.has("recurrence") && state.recurrenceEndType === "date" && state.recurrenceEndDate ? new Date(state.recurrenceEndDate).toISOString() : visibleFields.has("recurrence") ? null : hiddenFieldValue,
425
+ participants: visibleFields.has("participants") ? state.participants.length > 0 ? state.participants.map((p) => ({ userId: p.userId, name: p.name, email: p.email, status: p.status ?? "pending" })) : null : hiddenFieldValue,
426
+ guestPermissions: visibleFields.has("participants") ? state.participants.length > 0 ? state.guestPermissions : null : hiddenFieldValue,
395
427
  linkedEntities: state.linkedEntities.length > 0 ? state.linkedEntities.map((e) => ({ id: e.id, type: e.type, label: e.label })) : null,
396
- reminderMinutes: visibleFields.has("reminder") ? state.reminderMinutes : null,
397
- visibility: visibleFields.has("visibility") ? state.visibility : null,
428
+ reminderMinutes: visibleFields.has("reminder") ? state.reminderMinutes : hiddenFieldValue,
429
+ visibility: visibleFields.has("visibility") ? state.visibility : hiddenFieldValue,
398
430
  ...Object.keys(customValues).length > 0 ? { customValues } : {}
399
431
  };
400
432
  await runGuardedMutation(
@@ -409,7 +441,7 @@ function ScheduleActivityDialog({
409
441
  {
410
442
  operation: isSaveEdit ? "updateActivity" : "createActivity",
411
443
  interactionId: editData?.id ?? null,
412
- interactionType: state.activityType
444
+ interactionType: payload.interactionType
413
445
  }
414
446
  );
415
447
  flash(t("customers.schedule.saved", "Activity scheduled"), "success");
@@ -437,7 +469,7 @@ function ScheduleActivityDialog({
437
469
  } finally {
438
470
  state.setSaving(false);
439
471
  }
440
- }, [callDirection, callOutcome, callPhoneInvalidMessage, callPhoneNumber, isDateMissing, isTimeMissing, presentationType, 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]);
472
+ }, [callDirection, callOutcome, callPhoneInvalidMessage, callPhoneNumber, catalogPending, keepsCustomType, isDateMissing, isTimeMissing, presentationType, 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]);
441
473
  const handleKeyDown = useDialogKeyHandler({ onConfirm: handleSave });
442
474
  return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (o) => {
443
475
  if (!o) void guardedClose();
@@ -464,103 +496,135 @@ function ScheduleActivityDialog({
464
496
  }, className: "flex size-9 shrink-0 items-center justify-center rounded-md border border-border bg-background", "aria-label": t("customers.schedule.cancel", "Cancel"), children: /* @__PURE__ */ jsx(X, { className: "size-4 text-muted-foreground" }) })
465
497
  ] }),
466
498
  /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 bg-background p-6", children: [
467
- state.conflict && /* @__PURE__ */ jsxs(Alert, { status: "warning", className: "rounded-lg", children: [
468
- /* @__PURE__ */ jsx(AlertTitle, { children: t("customers.schedule.conflict.title", "Calendar conflict") }),
469
- /* @__PURE__ */ jsx(AlertDescription, { children: state.conflict })
499
+ catalogPending && /* @__PURE__ */ jsxs(Alert, { status: catalog.status === "error" ? "error" : "information", children: [
500
+ /* @__PURE__ */ jsx(AlertDescription, { children: t(catalog.status === "error" ? "customers.calendar.editor.catalogLoadFailed" : "customers.calendar.editor.catalogLoading") }),
501
+ catalog.status === "error" && /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: catalog.retry, children: t("customers.calendar.errors.retry") })
470
502
  ] }),
471
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-4 gap-2", children: TYPE_TABS.map(({ type, icon: Icon, labelKey, fallback }) => {
472
- const isActive = state.activityType === type;
473
- return /* @__PURE__ */ jsxs(
474
- "button",
475
- {
476
- type: "button",
477
- onClick: () => state.setActivityType(type),
478
- "aria-pressed": isActive,
479
- className: cn(
480
- "flex h-[80px] flex-col items-center justify-center gap-2 rounded-md border text-[14px] font-semibold transition-colors",
481
- isActive ? "border-transparent bg-foreground text-background" : "border-border bg-card text-muted-foreground hover:border-foreground/40 hover:text-foreground"
482
- ),
483
- children: [
484
- /* @__PURE__ */ jsx(Icon, { className: "size-[18px]" }),
485
- t(labelKey, fallback)
486
- ]
487
- },
488
- type
489
- );
490
- }) }),
491
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
492
- /* @__PURE__ */ jsx("label", { className: "text-overline font-semibold text-muted-foreground tracking-wider", children: getFieldLabel(presentationType, "title", t, "customers.schedule.titleLabel", "Title") }),
503
+ !catalogPending && /* @__PURE__ */ jsxs(Fragment, { children: [
504
+ state.conflict && /* @__PURE__ */ jsxs(Alert, { status: "warning", className: "rounded-lg", children: [
505
+ /* @__PURE__ */ jsx(AlertTitle, { children: t("customers.schedule.conflict.title", "Calendar conflict") }),
506
+ /* @__PURE__ */ jsx(AlertDescription, { children: state.conflict })
507
+ ] }),
508
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-4 gap-2", children: TYPE_TABS.map(({ type, icon: Icon, labelKey, fallback }) => {
509
+ const isActive = state.activityType === type;
510
+ return /* @__PURE__ */ jsxs(
511
+ "button",
512
+ {
513
+ type: "button",
514
+ onClick: () => {
515
+ setTypeChanged(true);
516
+ state.setActivityType(type);
517
+ },
518
+ "aria-pressed": isActive,
519
+ className: cn(
520
+ "flex h-[80px] flex-col items-center justify-center gap-2 rounded-md border text-[14px] font-semibold transition-colors",
521
+ isActive ? "border-transparent bg-foreground text-background" : "border-border bg-card text-muted-foreground hover:border-foreground/40 hover:text-foreground"
522
+ ),
523
+ children: [
524
+ /* @__PURE__ */ jsx(Icon, { className: "size-[18px]" }),
525
+ t(labelKey, fallback)
526
+ ]
527
+ },
528
+ type
529
+ );
530
+ }) }),
531
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
532
+ /* @__PURE__ */ jsx("label", { className: "text-overline font-semibold text-muted-foreground tracking-wider", children: getFieldLabel(presentationType, "title", t, "customers.schedule.titleLabel", "Title") }),
533
+ /* @__PURE__ */ jsx(
534
+ "input",
535
+ {
536
+ type: "text",
537
+ value: state.title,
538
+ onChange: (e) => state.setTitle(e.target.value),
539
+ placeholder: presentationType === "email" ? t("customers.schedule.subjectPlaceholder", "Subject...") : t("customers.schedule.titlePlaceholder", "Activity title..."),
540
+ className: "w-full rounded-md border border-border bg-background px-3 py-2.5 text-sm text-foreground outline-none focus:border-foreground",
541
+ autoFocus: true
542
+ }
543
+ )
544
+ ] }),
493
545
  /* @__PURE__ */ jsx(
494
- "input",
546
+ DateTimeFields,
495
547
  {
496
- type: "text",
497
- value: state.title,
498
- onChange: (e) => state.setTitle(e.target.value),
499
- placeholder: presentationType === "email" ? t("customers.schedule.subjectPlaceholder", "Subject...") : t("customers.schedule.titlePlaceholder", "Activity title..."),
500
- className: "w-full rounded-md border border-border bg-background px-3 py-2.5 text-sm text-foreground outline-none focus:border-foreground",
501
- autoFocus: true
548
+ visible: visibleFields,
549
+ activityType: presentationType,
550
+ date: state.date,
551
+ setDate: state.setDate,
552
+ startTime: state.startTime,
553
+ setStartTime: state.setStartTime,
554
+ duration: state.duration,
555
+ setDuration: state.setDuration,
556
+ allDay: state.allDay,
557
+ setAllDay: state.setAllDay,
558
+ recurrenceEnabled: state.recurrenceEnabled,
559
+ setRecurrenceEnabled: state.setRecurrenceEnabled,
560
+ recurrenceDays: state.recurrenceDays,
561
+ toggleRecurrenceDay: state.toggleRecurrenceDay,
562
+ recurrenceEndType: state.recurrenceEndType,
563
+ setRecurrenceEndType: state.setRecurrenceEndType,
564
+ recurrenceCount: state.recurrenceCount,
565
+ setRecurrenceCount: state.setRecurrenceCount,
566
+ recurrenceEndDate: state.recurrenceEndDate,
567
+ setRecurrenceEndDate: state.setRecurrenceEndDate
502
568
  }
503
- )
504
- ] }),
505
- /* @__PURE__ */ jsx(
506
- DateTimeFields,
507
- {
508
- visible: visibleFields,
509
- activityType: presentationType,
510
- date: state.date,
511
- setDate: state.setDate,
512
- startTime: state.startTime,
513
- setStartTime: state.setStartTime,
514
- duration: state.duration,
515
- setDuration: state.setDuration,
516
- allDay: state.allDay,
517
- setAllDay: state.setAllDay,
518
- recurrenceEnabled: state.recurrenceEnabled,
519
- setRecurrenceEnabled: state.setRecurrenceEnabled,
520
- recurrenceDays: state.recurrenceDays,
521
- toggleRecurrenceDay: state.toggleRecurrenceDay,
522
- recurrenceEndType: state.recurrenceEndType,
523
- setRecurrenceEndType: state.setRecurrenceEndType,
524
- recurrenceCount: state.recurrenceCount,
525
- setRecurrenceCount: state.setRecurrenceCount,
526
- recurrenceEndDate: state.recurrenceEndDate,
527
- setRecurrenceEndDate: state.setRecurrenceEndDate
528
- }
529
- ),
530
- presentationType === "call" && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
531
- /* @__PURE__ */ jsxs("div", { children: [
532
- /* @__PURE__ */ jsx("label", { className: "text-overline font-semibold uppercase text-muted-foreground tracking-wider", children: t("customers.schedule.call.directionLabel", "Direction") }),
533
- /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-2", children: CALL_DIRECTIONS.map((opt) => {
534
- const isActive = callDirection === opt.key;
535
- return /* @__PURE__ */ jsxs(
536
- "button",
537
- {
538
- type: "button",
539
- "aria-pressed": isActive,
540
- onClick: () => setCallDirection(opt.key),
541
- className: cn(
542
- "inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-sm font-medium transition-colors",
543
- isActive ? "border-transparent bg-foreground text-background" : "border-border bg-card text-muted-foreground hover:border-foreground/40"
544
- ),
545
- children: [
546
- /* @__PURE__ */ jsx("span", { className: cn("inline-block size-1.5 rounded-full", opt.dot), "aria-hidden": true }),
547
- t(opt.labelKey, opt.labelFallback)
548
- ]
549
- },
550
- opt.key
551
- );
552
- }) })
569
+ ),
570
+ presentationType === "call" && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
571
+ /* @__PURE__ */ jsxs("div", { children: [
572
+ /* @__PURE__ */ jsx("label", { className: "text-overline font-semibold uppercase text-muted-foreground tracking-wider", children: t("customers.schedule.call.directionLabel", "Direction") }),
573
+ /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-2", children: CALL_DIRECTIONS.map((opt) => {
574
+ const isActive = callDirection === opt.key;
575
+ return /* @__PURE__ */ jsxs(
576
+ "button",
577
+ {
578
+ type: "button",
579
+ "aria-pressed": isActive,
580
+ onClick: () => setCallDirection(opt.key),
581
+ className: cn(
582
+ "inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-sm font-medium transition-colors",
583
+ isActive ? "border-transparent bg-foreground text-background" : "border-border bg-card text-muted-foreground hover:border-foreground/40"
584
+ ),
585
+ children: [
586
+ /* @__PURE__ */ jsx("span", { className: cn("inline-block size-1.5 rounded-full", opt.dot), "aria-hidden": true }),
587
+ t(opt.labelKey, opt.labelFallback)
588
+ ]
589
+ },
590
+ opt.key
591
+ );
592
+ }) })
593
+ ] }),
594
+ /* @__PURE__ */ jsxs("div", { children: [
595
+ /* @__PURE__ */ jsx("label", { className: "text-overline font-semibold uppercase text-muted-foreground tracking-wider", children: t("customers.schedule.call.outcomeLabel", "Outcome") }),
596
+ /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-2", children: CALL_OUTCOMES.map((opt) => {
597
+ const isActive = callOutcome === opt.key;
598
+ return /* @__PURE__ */ jsxs(
599
+ "button",
600
+ {
601
+ type: "button",
602
+ "aria-pressed": isActive,
603
+ onClick: () => setCallOutcome(isActive ? null : opt.key),
604
+ className: cn(
605
+ "inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-sm font-medium transition-colors",
606
+ isActive ? "border-transparent bg-foreground text-background" : "border-border bg-card text-muted-foreground hover:border-foreground/40"
607
+ ),
608
+ children: [
609
+ /* @__PURE__ */ jsx("span", { className: cn("inline-block size-1.5 rounded-full", opt.dot), "aria-hidden": true }),
610
+ t(opt.labelKey, opt.labelFallback)
611
+ ]
612
+ },
613
+ opt.key
614
+ );
615
+ }) })
616
+ ] })
553
617
  ] }),
554
- /* @__PURE__ */ jsxs("div", { children: [
555
- /* @__PURE__ */ jsx("label", { className: "text-overline font-semibold uppercase text-muted-foreground tracking-wider", children: t("customers.schedule.call.outcomeLabel", "Outcome") }),
556
- /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-2", children: CALL_OUTCOMES.map((opt) => {
557
- const isActive = callOutcome === opt.key;
618
+ presentationType === "task" && /* @__PURE__ */ jsxs("div", { children: [
619
+ /* @__PURE__ */ jsx("label", { className: "text-overline font-semibold uppercase text-muted-foreground tracking-wider", children: t("customers.schedule.task.priorityLabel", "Priority") }),
620
+ /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-2", children: TASK_PRIORITIES.map((opt) => {
621
+ const isActive = taskPriority === opt.key;
558
622
  return /* @__PURE__ */ jsxs(
559
623
  "button",
560
624
  {
561
625
  type: "button",
562
626
  "aria-pressed": isActive,
563
- onClick: () => setCallOutcome(isActive ? null : opt.key),
627
+ onClick: () => setTaskPriority(opt.key),
564
628
  className: cn(
565
629
  "inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-sm font-medium transition-colors",
566
630
  isActive ? "border-transparent bg-foreground text-background" : "border-border bg-card text-muted-foreground hover:border-foreground/40"
@@ -570,106 +634,83 @@ function ScheduleActivityDialog({
570
634
  t(opt.labelKey, opt.labelFallback)
571
635
  ]
572
636
  },
573
- opt.key
637
+ opt.key ?? "none"
574
638
  );
575
639
  }) })
576
- ] })
577
- ] }),
578
- presentationType === "task" && /* @__PURE__ */ jsxs("div", { children: [
579
- /* @__PURE__ */ jsx("label", { className: "text-overline font-semibold uppercase text-muted-foreground tracking-wider", children: t("customers.schedule.task.priorityLabel", "Priority") }),
580
- /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-2", children: TASK_PRIORITIES.map((opt) => {
581
- const isActive = taskPriority === opt.key;
582
- return /* @__PURE__ */ jsxs(
583
- "button",
640
+ ] }),
641
+ /* @__PURE__ */ jsx(
642
+ ParticipantsField,
643
+ {
644
+ visible: visibleFields,
645
+ activityType: presentationType,
646
+ participants: state.participants,
647
+ setParticipants: state.setParticipants,
648
+ removeParticipant: state.removeParticipant,
649
+ guestPermissions: state.guestPermissions,
650
+ setGuestPermissions: state.setGuestPermissions
651
+ }
652
+ ),
653
+ presentationType === "call" ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
654
+ /* @__PURE__ */ jsx("label", { htmlFor: "schedule-call-phone", className: "text-overline font-semibold uppercase text-muted-foreground tracking-wider", children: t("customers.schedule.call.phoneLabel", "Phone number") }),
655
+ /* @__PURE__ */ jsx(
656
+ PhoneNumberField,
584
657
  {
585
- type: "button",
586
- "aria-pressed": isActive,
587
- onClick: () => setTaskPriority(opt.key),
588
- className: cn(
589
- "inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-sm font-medium transition-colors",
590
- isActive ? "border-transparent bg-foreground text-background" : "border-border bg-card text-muted-foreground hover:border-foreground/40"
591
- ),
592
- children: [
593
- /* @__PURE__ */ jsx("span", { className: cn("inline-block size-1.5 rounded-full", opt.dot), "aria-hidden": true }),
594
- t(opt.labelKey, opt.labelFallback)
595
- ]
596
- },
597
- opt.key ?? "none"
598
- );
599
- }) })
600
- ] }),
601
- /* @__PURE__ */ jsx(
602
- ParticipantsField,
603
- {
604
- visible: visibleFields,
605
- activityType: presentationType,
606
- participants: state.participants,
607
- setParticipants: state.setParticipants,
608
- removeParticipant: state.removeParticipant,
609
- guestPermissions: state.guestPermissions,
610
- setGuestPermissions: state.setGuestPermissions
611
- }
612
- ),
613
- presentationType === "call" ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
614
- /* @__PURE__ */ jsx("label", { htmlFor: "schedule-call-phone", className: "text-overline font-semibold uppercase text-muted-foreground tracking-wider", children: t("customers.schedule.call.phoneLabel", "Phone number") }),
658
+ id: "schedule-call-phone",
659
+ value: callPhoneNumber,
660
+ onValueChange: handleCallPhoneChange,
661
+ placeholder: t("customers.schedule.call.phonePlaceholder", "+1 555 000 0000"),
662
+ externalError: callPhoneError,
663
+ invalidLabel: callPhoneInvalidMessage,
664
+ minDigits: 7,
665
+ defaultCountryIso2
666
+ }
667
+ )
668
+ ] }) : /* @__PURE__ */ jsx(
669
+ LocationField,
670
+ {
671
+ visible: visibleFields,
672
+ activityType: presentationType,
673
+ location: state.location,
674
+ setLocation: state.setLocation
675
+ }
676
+ ),
615
677
  /* @__PURE__ */ jsx(
616
- PhoneNumberField,
678
+ LinkedEntitiesField,
617
679
  {
618
- id: "schedule-call-phone",
619
- value: callPhoneNumber,
620
- onValueChange: handleCallPhoneChange,
621
- placeholder: t("customers.schedule.call.phonePlaceholder", "+1 555 000 0000"),
622
- externalError: callPhoneError,
623
- invalidLabel: callPhoneInvalidMessage,
624
- minDigits: 7,
625
- defaultCountryIso2
680
+ visible: visibleFields,
681
+ activityType: presentationType,
682
+ linkedEntities: state.linkedEntities,
683
+ setLinkedEntities: state.setLinkedEntities
626
684
  }
627
- )
628
- ] }) : /* @__PURE__ */ jsx(
629
- LocationField,
630
- {
631
- visible: visibleFields,
632
- activityType: presentationType,
633
- location: state.location,
634
- setLocation: state.setLocation
635
- }
636
- ),
637
- /* @__PURE__ */ jsx(
638
- LinkedEntitiesField,
639
- {
640
- visible: visibleFields,
641
- activityType: presentationType,
642
- linkedEntities: state.linkedEntities,
643
- setLinkedEntities: state.setLinkedEntities
644
- }
645
- ),
646
- /* @__PURE__ */ jsxs("div", { children: [
647
- /* @__PURE__ */ jsx("label", { className: "text-overline font-semibold uppercase text-muted-foreground tracking-wider", children: getFieldLabel(presentationType, "description", t, "customers.schedule.description", "Description") }),
648
- /* @__PURE__ */ jsx("div", { className: "mt-[8px]", children: /* @__PURE__ */ jsx(
649
- SwitchableMarkdownInput,
685
+ ),
686
+ /* @__PURE__ */ jsxs("div", { children: [
687
+ /* @__PURE__ */ jsx("label", { className: "text-overline font-semibold uppercase text-muted-foreground tracking-wider", children: getFieldLabel(presentationType, "description", t, "customers.schedule.description", "Description") }),
688
+ /* @__PURE__ */ jsx("div", { className: "mt-[8px]", children: /* @__PURE__ */ jsx(
689
+ SwitchableMarkdownInput,
690
+ {
691
+ value: state.description,
692
+ onChange: state.setDescription,
693
+ isMarkdownEnabled: state.markdownEnabled,
694
+ disableMarkdown: presentationType === "email",
695
+ rows: presentationType === "email" ? 8 : void 0,
696
+ textareaClassName: presentationType === "email" ? "w-full resize-y overflow-y-auto rounded-lg border border-muted-foreground/20 bg-background px-3 py-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" : void 0,
697
+ height: 120,
698
+ placeholder: t("customers.schedule.descriptionPlaceholder", "Add details...")
699
+ }
700
+ ) })
701
+ ] }),
702
+ /* @__PURE__ */ jsx(
703
+ FooterFields,
650
704
  {
651
- value: state.description,
652
- onChange: state.setDescription,
653
- isMarkdownEnabled: state.markdownEnabled,
654
- disableMarkdown: presentationType === "email",
655
- rows: presentationType === "email" ? 8 : void 0,
656
- textareaClassName: presentationType === "email" ? "w-full resize-y overflow-y-auto rounded-lg border border-muted-foreground/20 bg-background px-3 py-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" : void 0,
657
- height: 120,
658
- placeholder: t("customers.schedule.descriptionPlaceholder", "Add details...")
705
+ visible: visibleFields,
706
+ activityType: presentationType,
707
+ reminderMinutes: state.reminderMinutes,
708
+ setReminderMinutes: state.setReminderMinutes,
709
+ visibility: state.visibility,
710
+ setVisibility: state.setVisibility
659
711
  }
660
- ) })
661
- ] }),
662
- /* @__PURE__ */ jsx(
663
- FooterFields,
664
- {
665
- visible: visibleFields,
666
- activityType: presentationType,
667
- reminderMinutes: state.reminderMinutes,
668
- setReminderMinutes: state.setReminderMinutes,
669
- visibility: state.visibility,
670
- setVisibility: state.setVisibility
671
- }
672
- )
712
+ )
713
+ ] })
673
714
  ] }) }),
674
715
  /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center justify-end gap-2.5 border-t border-border bg-muted/50 px-6 py-4", children: [
675
716
  /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: () => {