@open-mercato/core 0.8.1-develop.7454.1.010095490f → 0.8.1-develop.7455.1.8f7e53badb

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.
Files changed (155) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/generated/entities/customer_dictionary_entry/index.js +2 -0
  3. package/dist/generated/entities/customer_dictionary_entry/index.js.map +2 -2
  4. package/dist/generated/entities/customer_interaction/index.js +2 -0
  5. package/dist/generated/entities/customer_interaction/index.js.map +2 -2
  6. package/dist/generated/entity-fields-registry.js +2 -0
  7. package/dist/generated/entity-fields-registry.js.map +2 -2
  8. package/dist/modules/customers/api/activity-types/route.js +151 -0
  9. package/dist/modules/customers/api/activity-types/route.js.map +7 -0
  10. package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js +13 -5
  11. package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js.map +2 -2
  12. package/dist/modules/customers/api/dictionaries/[kind]/route.js +20 -5
  13. package/dist/modules/customers/api/dictionaries/[kind]/route.js.map +2 -2
  14. package/dist/modules/customers/api/interactions/route.js +3 -0
  15. package/dist/modules/customers/api/interactions/route.js.map +2 -2
  16. package/dist/modules/customers/api/interactions/tasks/route.js +1 -0
  17. package/dist/modules/customers/api/interactions/tasks/route.js.map +2 -2
  18. package/dist/modules/customers/backend/config/customers/pipeline-stages/page.meta.js +18 -0
  19. package/dist/modules/customers/backend/config/customers/pipeline-stages/page.meta.js.map +2 -2
  20. package/dist/modules/customers/calendar-event-types.js +548 -0
  21. package/dist/modules/customers/calendar-event-types.js.map +7 -0
  22. package/dist/modules/customers/commands/dictionaries.js +70 -10
  23. package/dist/modules/customers/commands/dictionaries.js.map +2 -2
  24. package/dist/modules/customers/commands/interactions.js +187 -22
  25. package/dist/modules/customers/commands/interactions.js.map +3 -3
  26. package/dist/modules/customers/components/ActivityTypeEditor.js +288 -0
  27. package/dist/modules/customers/components/ActivityTypeEditor.js.map +7 -0
  28. package/dist/modules/customers/components/DictionarySettings.js +3 -1
  29. package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
  30. package/dist/modules/customers/components/calendar/CalendarEventEditor.js +391 -297
  31. package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +3 -3
  32. package/dist/modules/customers/components/calendar/CalendarSettingsModal.js +9 -74
  33. package/dist/modules/customers/components/calendar/CalendarSettingsModal.js.map +2 -2
  34. package/dist/modules/customers/components/calendar/TimeGrid.js +20 -16
  35. package/dist/modules/customers/components/calendar/TimeGrid.js.map +2 -2
  36. package/dist/modules/customers/components/calendar/editor/EventTypePanel.js +218 -0
  37. package/dist/modules/customers/components/calendar/editor/EventTypePanel.js.map +7 -0
  38. package/dist/modules/customers/components/calendar/editor/LocationField.js +7 -3
  39. package/dist/modules/customers/components/calendar/editor/LocationField.js.map +2 -2
  40. package/dist/modules/customers/components/calendar/editor/PeopleField.js +5 -2
  41. package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +2 -2
  42. package/dist/modules/customers/components/calendar/editor/PriorityField.js +3 -1
  43. package/dist/modules/customers/components/calendar/editor/PriorityField.js.map +2 -2
  44. package/dist/modules/customers/components/calendar/editor/RepeatField.js +9 -1
  45. package/dist/modules/customers/components/calendar/editor/RepeatField.js.map +2 -2
  46. package/dist/modules/customers/components/calendar/editor/ResourcesField.js +4 -1
  47. package/dist/modules/customers/components/calendar/editor/ResourcesField.js.map +2 -2
  48. package/dist/modules/customers/components/calendar/editor/ScheduleSection.js +15 -7
  49. package/dist/modules/customers/components/calendar/editor/ScheduleSection.js.map +2 -2
  50. package/dist/modules/customers/components/calendar/editor/SegmentGroup.js +3 -1
  51. package/dist/modules/customers/components/calendar/editor/SegmentGroup.js.map +2 -2
  52. package/dist/modules/customers/components/calendar/editor/hooks.js +28 -13
  53. package/dist/modules/customers/components/calendar/editor/hooks.js.map +3 -3
  54. package/dist/modules/customers/components/calendar/editor/inputs.js +14 -6
  55. package/dist/modules/customers/components/calendar/editor/inputs.js.map +2 -2
  56. package/dist/modules/customers/components/calendar/editor/useCalendarCustomFields.js +54 -0
  57. package/dist/modules/customers/components/calendar/editor/useCalendarCustomFields.js.map +7 -0
  58. package/dist/modules/customers/components/calendar/editor/useEventTypeCatalog.js +82 -0
  59. package/dist/modules/customers/components/calendar/editor/useEventTypeCatalog.js.map +7 -0
  60. package/dist/modules/customers/components/calendar/types.js +1 -0
  61. package/dist/modules/customers/components/calendar/types.js.map +2 -2
  62. package/dist/modules/customers/data/entities.js +6 -0
  63. package/dist/modules/customers/data/entities.js.map +2 -2
  64. package/dist/modules/customers/data/validators.js +39 -10
  65. package/dist/modules/customers/data/validators.js.map +2 -2
  66. package/dist/modules/customers/di.js +20 -1
  67. package/dist/modules/customers/di.js.map +2 -2
  68. package/dist/modules/customers/extension-points.js +13 -0
  69. package/dist/modules/customers/extension-points.js.map +2 -2
  70. package/dist/modules/customers/lib/calendar/conflicts.js +59 -16
  71. package/dist/modules/customers/lib/calendar/conflicts.js.map +2 -2
  72. package/dist/modules/customers/lib/calendar/editorPayload.js +34 -16
  73. package/dist/modules/customers/lib/calendar/editorPayload.js.map +2 -2
  74. package/dist/modules/customers/lib/calendar/eventTypeResolver.js +197 -0
  75. package/dist/modules/customers/lib/calendar/eventTypeResolver.js.map +7 -0
  76. package/dist/modules/customers/lib/calendar/interactionApplicability.js +67 -0
  77. package/dist/modules/customers/lib/calendar/interactionApplicability.js.map +7 -0
  78. package/dist/modules/customers/lib/calendar/mapItem.js +5 -2
  79. package/dist/modules/customers/lib/calendar/mapItem.js.map +2 -2
  80. package/dist/modules/customers/lib/calendar/recurrence.js +62 -1
  81. package/dist/modules/customers/lib/calendar/recurrence.js.map +2 -2
  82. package/dist/modules/customers/lib/calendar/timezone.js +111 -0
  83. package/dist/modules/customers/lib/calendar/timezone.js.map +7 -0
  84. package/dist/modules/customers/lib/interactionReadModel.js +1 -0
  85. package/dist/modules/customers/lib/interactionReadModel.js.map +2 -2
  86. package/dist/modules/customers/lib/todoCompatibility.js +1 -0
  87. package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
  88. package/dist/modules/customers/migrations/Migration20260928175058_customers.js +17 -0
  89. package/dist/modules/customers/migrations/Migration20260928175058_customers.js.map +7 -0
  90. package/dist/modules/customers/migrations/Migration20260930110235_customers.js +17 -0
  91. package/dist/modules/customers/migrations/Migration20260930110235_customers.js.map +7 -0
  92. package/dist/modules/dictionaries/components/DictionaryTable.js +60 -51
  93. package/dist/modules/dictionaries/components/DictionaryTable.js.map +2 -2
  94. package/dist/modules/planner/lib/availabilityMerge.js +101 -38
  95. package/dist/modules/planner/lib/availabilityMerge.js.map +3 -3
  96. package/dist/modules/planner/services/plannerAvailabilityService.js.map +2 -2
  97. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js +12 -7
  98. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js.map +2 -2
  99. package/generated/entities/customer_dictionary_entry/index.ts +1 -0
  100. package/generated/entities/customer_interaction/index.ts +1 -0
  101. package/generated/entity-fields-registry.ts +2 -0
  102. package/package.json +7 -7
  103. package/src/modules/customers/api/activity-types/route.ts +154 -0
  104. package/src/modules/customers/api/dictionaries/[kind]/[id]/route.ts +9 -1
  105. package/src/modules/customers/api/dictionaries/[kind]/route.ts +18 -2
  106. package/src/modules/customers/api/interactions/route.ts +4 -0
  107. package/src/modules/customers/api/interactions/tasks/route.ts +1 -0
  108. package/src/modules/customers/backend/config/customers/pipeline-stages/page.meta.ts +20 -0
  109. package/src/modules/customers/calendar-event-types.ts +674 -0
  110. package/src/modules/customers/commands/dictionaries.ts +84 -8
  111. package/src/modules/customers/commands/interactions.ts +244 -21
  112. package/src/modules/customers/components/ActivityTypeEditor.tsx +239 -0
  113. package/src/modules/customers/components/DictionarySettings.tsx +5 -3
  114. package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +347 -218
  115. package/src/modules/customers/components/calendar/CalendarSettingsModal.tsx +18 -96
  116. package/src/modules/customers/components/calendar/TimeGrid.tsx +20 -18
  117. package/src/modules/customers/components/calendar/editor/EventTypePanel.tsx +230 -0
  118. package/src/modules/customers/components/calendar/editor/LocationField.tsx +7 -1
  119. package/src/modules/customers/components/calendar/editor/PeopleField.tsx +4 -0
  120. package/src/modules/customers/components/calendar/editor/PriorityField.tsx +3 -0
  121. package/src/modules/customers/components/calendar/editor/RepeatField.tsx +10 -0
  122. package/src/modules/customers/components/calendar/editor/ResourcesField.tsx +4 -0
  123. package/src/modules/customers/components/calendar/editor/ScheduleSection.tsx +16 -4
  124. package/src/modules/customers/components/calendar/editor/SegmentGroup.tsx +3 -0
  125. package/src/modules/customers/components/calendar/editor/hooks.ts +29 -13
  126. package/src/modules/customers/components/calendar/editor/inputs.tsx +17 -5
  127. package/src/modules/customers/components/calendar/editor/useCalendarCustomFields.ts +49 -0
  128. package/src/modules/customers/components/calendar/editor/useEventTypeCatalog.ts +100 -0
  129. package/src/modules/customers/components/calendar/types.ts +1 -0
  130. package/src/modules/customers/components/detail/types.ts +1 -0
  131. package/src/modules/customers/data/entities.ts +8 -1
  132. package/src/modules/customers/data/validators.ts +42 -7
  133. package/src/modules/customers/di.ts +21 -0
  134. package/src/modules/customers/extension-points.ts +13 -0
  135. package/src/modules/customers/i18n/de.json +83 -0
  136. package/src/modules/customers/i18n/en.json +83 -0
  137. package/src/modules/customers/i18n/es.json +83 -0
  138. package/src/modules/customers/i18n/ko.json +83 -0
  139. package/src/modules/customers/i18n/pl.json +83 -0
  140. package/src/modules/customers/lib/calendar/conflicts.ts +106 -27
  141. package/src/modules/customers/lib/calendar/editorPayload.ts +39 -19
  142. package/src/modules/customers/lib/calendar/eventTypeResolver.ts +258 -0
  143. package/src/modules/customers/lib/calendar/interactionApplicability.ts +99 -0
  144. package/src/modules/customers/lib/calendar/mapItem.ts +6 -2
  145. package/src/modules/customers/lib/calendar/recurrence.ts +65 -1
  146. package/src/modules/customers/lib/calendar/timezone.ts +117 -0
  147. package/src/modules/customers/lib/interactionReadModel.ts +1 -0
  148. package/src/modules/customers/lib/todoCompatibility.ts +2 -0
  149. package/src/modules/customers/migrations/.snapshot-open-mercato.json +34 -0
  150. package/src/modules/customers/migrations/Migration20260928175058_customers.ts +15 -0
  151. package/src/modules/customers/migrations/Migration20260930110235_customers.ts +15 -0
  152. package/src/modules/dictionaries/components/DictionaryTable.tsx +63 -56
  153. package/src/modules/planner/lib/availabilityMerge.ts +106 -41
  154. package/src/modules/planner/services/plannerAvailabilityService.ts +4 -0
  155. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.tsx +25 -13
@@ -0,0 +1,288 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { E } from "../../../generated/entities.ids.generated.js";
5
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
6
+ import { useOrganizationScopeVersion } from "@open-mercato/shared/lib/frontend/useOrganizationScope";
7
+ import { createLogger } from "@open-mercato/shared/lib/logger";
8
+ import { getTelemetryRuntime } from "@open-mercato/shared/lib/telemetry/runtime";
9
+ import { DataTable } from "@open-mercato/ui/backend/DataTable";
10
+ import { RowActions } from "@open-mercato/ui/backend/RowActions";
11
+ import { CrudForm } from "@open-mercato/ui/backend/CrudForm";
12
+ import { ErrorMessage, LoadingMessage } from "@open-mercato/ui/backend/detail";
13
+ import { flash } from "@open-mercato/ui/backend/FlashMessages";
14
+ import { useConfirmDialog } from "@open-mercato/ui/backend/confirm-dialog";
15
+ import { surfaceRecordConflict } from "@open-mercato/ui/backend/conflicts";
16
+ import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
17
+ import { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
18
+ import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
19
+ import { createCrudFormError } from "@open-mercato/ui/backend/utils/serverErrors";
20
+ import { Button } from "@open-mercato/ui/primitives/button";
21
+ import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@open-mercato/ui/primitives/dialog";
22
+ import { calendarEventTypeBehaviorSchema, calendarEventTypeKeySchema, calendarEventTypes } from "../calendar-event-types.js";
23
+ import { getCustomerDictionarySettingsSectionId } from "../lib/dictionaries.js";
24
+ import { renderDictionaryColor, renderDictionaryIcon } from "@open-mercato/core/modules/dictionaries/components/dictionaryAppearance";
25
+ const logger = createLogger("customers");
26
+ const ENTITY_ID = E.customers.customer_interaction;
27
+ const API = "/api/customers/dictionaries/activity-types";
28
+ const defaults = calendarEventTypes[0].behavior;
29
+ function initialValues(item) {
30
+ const behavior = item?.behavior ?? defaults;
31
+ return {
32
+ value: item?.key ?? "",
33
+ label: item?.label ?? "",
34
+ icon: item?.icon ?? "",
35
+ color: item?.color ?? "",
36
+ order: behavior.order,
37
+ baseKind: behavior.baseKind,
38
+ selectable: behavior.selectable,
39
+ ...behavior.fields,
40
+ customFieldsetIds: [...behavior.customFieldsetIds],
41
+ updatedAt: item?.updatedAt ?? void 0
42
+ };
43
+ }
44
+ function ActivityTypeEditor({ title, description }) {
45
+ const t = useT();
46
+ const scopeVersion = useOrganizationScopeVersion();
47
+ const { confirm, ConfirmDialogElement } = useConfirmDialog();
48
+ const [items, setItems] = React.useState([]);
49
+ const [rows, setRows] = React.useState([]);
50
+ const [selected, setSelected] = React.useState(void 0);
51
+ const [fieldsets, setFieldsets] = React.useState([]);
52
+ const [fieldsetsStatus, setFieldsetsStatus] = React.useState("loading");
53
+ const [fieldsetAttempt, setFieldsetAttempt] = React.useState(0);
54
+ const [status, setStatus] = React.useState("loading");
55
+ const { runMutation, retryLastMutation } = useGuardedMutation({
56
+ contextId: "customers-activity-types",
57
+ blockedMessage: t("ui.forms.flash.saveBlocked", "Save blocked by validation")
58
+ });
59
+ const load = React.useCallback(async () => {
60
+ setStatus("loading");
61
+ try {
62
+ const [catalog, dictionary] = await Promise.all([
63
+ readApiResultOrThrow("/api/customers/activity-types"),
64
+ readApiResultOrThrow(API)
65
+ ]);
66
+ if (!Array.isArray(catalog.items) || !Array.isArray(dictionary.items)) throw new Error("[internal] Invalid activity type response");
67
+ setItems(catalog.items);
68
+ setRows(dictionary.items);
69
+ setStatus("ready");
70
+ } catch (err) {
71
+ logger.error("customers.activity_types.settings.load failed", { err });
72
+ getTelemetryRuntime()?.reportError(err, {
73
+ module: "customers",
74
+ code: "customers.activity_type_settings_load_failed"
75
+ });
76
+ setStatus("error");
77
+ }
78
+ }, []);
79
+ React.useEffect(() => {
80
+ void load();
81
+ }, [load, scopeVersion]);
82
+ React.useEffect(() => {
83
+ if (selected === void 0) return;
84
+ let active = true;
85
+ setFieldsetsStatus("loading");
86
+ void readApiResultOrThrow(
87
+ `/api/entities/definitions?entityId=${encodeURIComponent(ENTITY_ID)}`
88
+ ).then((result) => {
89
+ if (!active) return;
90
+ setFieldsets(result.fieldsetsByEntity?.[ENTITY_ID] ?? []);
91
+ setFieldsetsStatus("ready");
92
+ }).catch((err) => {
93
+ logger.error("customers.activity_types.fieldsets.load failed", { err });
94
+ getTelemetryRuntime()?.reportError(err, {
95
+ module: "customers",
96
+ code: "customers.activity_type_fieldsets_load_failed"
97
+ });
98
+ if (active) setFieldsetsStatus("error");
99
+ });
100
+ return () => {
101
+ active = false;
102
+ };
103
+ }, [selected, fieldsetAttempt]);
104
+ const localRow = (key) => rows.find((row) => row.value.toLowerCase() === key && !row.isInherited);
105
+ const remove = async (item) => {
106
+ const row = localRow(item.key);
107
+ if (!row) return;
108
+ const approved = await confirm({
109
+ title: t("customers.config.activityTypes.resetConfirm", "Remove the local activity type configuration?"),
110
+ variant: "destructive"
111
+ });
112
+ if (!approved) return;
113
+ try {
114
+ await runMutation({
115
+ operation: () => withScopedApiRequestHeaders(buildOptimisticLockHeader(row.updatedAt), () => apiCallOrThrow(`${API}/${encodeURIComponent(row.id)}`, { method: "DELETE" })),
116
+ context: { formId: "customers-activity-types", resourceKind: "customers.dictionary", retryLastMutation },
117
+ mutationPayload: { action: "delete", id: row.id, kind: "activity-types" }
118
+ });
119
+ flash(t("customers.config.activityTypes.removed", "Activity type configuration removed."), "success");
120
+ await load();
121
+ } catch (err) {
122
+ logger.error("customers.activity_types.settings.remove failed", { err });
123
+ getTelemetryRuntime()?.reportError(err, {
124
+ module: "customers",
125
+ code: "customers.activity_type_settings_remove_failed"
126
+ });
127
+ if (!surfaceRecordConflict(err, t, { onRefresh: () => {
128
+ void load();
129
+ } })) {
130
+ flash(t("customers.config.activityTypes.saveFailed", "Failed to save activity type."), "error");
131
+ }
132
+ }
133
+ };
134
+ const fields = React.useMemo(() => {
135
+ const label = (key, fallback) => t(`customers.config.activityTypes.fields.${key}`, fallback);
136
+ const options = (values) => values.map((value) => ({ value, label: t(`customers.config.activityTypes.options.${value}`, value) }));
137
+ const knownFieldsets = fieldsets.map(({ code, label: fieldsetLabel }) => ({ value: code, label: fieldsetLabel }));
138
+ const missing = selected?.behavior.customFieldsetIds.filter((code) => !fieldsets.some((fieldset) => fieldset.code === code)) ?? [];
139
+ return [
140
+ { id: "value", type: "text", label: label("value", "Stable key"), required: true, readOnly: !!selected },
141
+ { id: "label", type: "text", label: label("label", "Label"), required: true },
142
+ { id: "icon", type: "text", label: label("icon", "Icon") },
143
+ { id: "color", type: "text", label: label("color", "Color (#RRGGBB)") },
144
+ { id: "order", type: "number", label: label("order", "Display order"), required: true },
145
+ { id: "baseKind", type: "select", label: label("baseKind", "Base behavior"), options: options(["meeting", "call", "email", "note", "event", "task"]) },
146
+ { id: "selectable", type: "checkbox", label: label("selectable", "Available for new events") },
147
+ ...["endTime", "allDay", "recurrence", "priority", "resources"].map((id) => ({ id, type: "checkbox", label: label(id, id) })),
148
+ { id: "location", type: "select", label: label("location", "Location field"), options: options(["none", "location", "phoneLink"]) },
149
+ { id: "people", type: "select", label: label("people", "People field"), options: options(["none", "attendees", "participants", "recipients", "assignee"]) },
150
+ {
151
+ id: "customFieldsetIds",
152
+ type: "select",
153
+ multiple: true,
154
+ label: label("customFieldsetIds", "Custom-field fieldsets"),
155
+ options: [...knownFieldsets, ...missing.map((code) => ({ value: code, label: `${code} (${t("customers.config.activityTypes.missing", "missing")})` }))]
156
+ }
157
+ ];
158
+ }, [fieldsets, selected, t]);
159
+ const groups = [
160
+ { id: "appearance", title: t("customers.config.activityTypes.appearance", "Appearance"), fields: ["value", "label", "icon", "color", "order"] },
161
+ { id: "behavior", title: t("customers.config.activityTypes.behavior", "Form behavior"), fields: ["baseKind", "selectable", "endTime", "allDay", "recurrence", "location", "people", "priority", "resources"] },
162
+ ...fieldsets.length || selected?.behavior.customFieldsetIds.length ? [{ id: "fieldsets", fields: ["customFieldsetIds"] }] : []
163
+ ];
164
+ const save = async (values) => {
165
+ const key = String(values.value ?? "").trim();
166
+ if (!calendarEventTypeKeySchema.safeParse(key).success) throw createCrudFormError(t("customers.config.activityTypes.invalidKey", "Use a lowercase key with letters, numbers, hyphens, or underscores."), { value: t("customers.config.activityTypes.invalidKey", "Use a lowercase key with letters, numbers, hyphens, or underscores.") });
167
+ if (fieldsetsStatus !== "ready") throw createCrudFormError(t("customers.config.activityTypes.fieldsetsUnavailable", "Fieldsets are unavailable. Retry loading before saving."));
168
+ const behavior = calendarEventTypeBehaviorSchema.safeParse({
169
+ schemaVersion: 1,
170
+ baseKind: values.baseKind,
171
+ selectable: values.selectable === true,
172
+ order: Number(values.order),
173
+ customFieldsetIds: values.customFieldsetIds ?? [],
174
+ fields: {
175
+ endTime: values.endTime === true,
176
+ allDay: values.allDay === true,
177
+ recurrence: values.recurrence === true,
178
+ location: values.location,
179
+ people: values.people,
180
+ priority: values.priority === true,
181
+ resources: values.resources === true
182
+ }
183
+ });
184
+ if (!behavior.success) throw createCrudFormError(t("customers.config.activityTypes.invalidBehavior", "Check the form behavior values."));
185
+ const payload = {
186
+ value: key,
187
+ label: String(values.label ?? "").trim(),
188
+ icon: String(values.icon ?? "").trim() || null,
189
+ color: String(values.color ?? "").trim() || null,
190
+ behavior: behavior.data
191
+ };
192
+ const row = selected ? localRow(selected.key) : void 0;
193
+ await apiCallOrThrow(row ? `${API}/${encodeURIComponent(row.id)}` : API, {
194
+ method: row ? "PATCH" : "POST",
195
+ headers: { "content-type": "application/json" },
196
+ body: JSON.stringify(row ? { label: payload.label, icon: payload.icon, color: payload.color, behavior: payload.behavior } : payload)
197
+ });
198
+ setSelected(void 0);
199
+ flash(t("customers.config.activityTypes.saved", "Activity type saved."), "success");
200
+ await load();
201
+ };
202
+ const columns = React.useMemo(() => [
203
+ { accessorKey: "label", header: t("customers.config.activityTypes.columns.type", "Activity type"), cell: ({ row }) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
204
+ row.original.color ? renderDictionaryColor(row.original.color, "size-4 rounded-full border border-border") : null,
205
+ row.original.icon ? renderDictionaryIcon(row.original.icon, "size-4") : null,
206
+ /* @__PURE__ */ jsx("span", { children: row.original.labelKey ? t(row.original.labelKey, row.original.label) : row.original.label })
207
+ ] }) },
208
+ { accessorKey: "key", header: t("customers.config.activityTypes.columns.key", "Stable key") },
209
+ { id: "source", header: t("customers.config.activityTypes.columns.source", "Source"), cell: ({ row }) => row.original.isLocalOverride ? t("customers.config.activityTypes.local", "Local override") : row.original.isInherited ? t("customers.config.activityTypes.inherited", "Inherited") : row.original.source },
210
+ { id: "behavior", header: t("customers.config.activityTypes.columns.behavior", "Behavior"), cell: ({ row }) => t(`customers.config.activityTypes.options.${row.original.behavior.baseKind}`, row.original.behavior.baseKind) },
211
+ { id: "active", header: t("customers.config.activityTypes.columns.active", "Selectable"), cell: ({ row }) => row.original.selectable ? t("customers.config.activityTypes.yes", "Yes") : t("customers.config.activityTypes.no", "No") },
212
+ { id: "fields", header: t("customers.config.activityTypes.columns.fields", "Fields"), cell: ({ row }) => Object.values(row.original.behavior.fields).filter((value) => value !== false && value !== "none").length },
213
+ { id: "fieldsets", header: t("customers.config.activityTypes.columns.fieldsets", "Fieldsets"), cell: ({ row }) => row.original.behavior.customFieldsetIds.length },
214
+ { id: "order", header: t("customers.config.activityTypes.columns.order", "Order"), cell: ({ row }) => row.original.behavior.order }
215
+ ], [t]);
216
+ return /* @__PURE__ */ jsxs("section", { id: getCustomerDictionarySettingsSectionId("activity-types"), className: "scroll-mt-24 rounded border bg-card text-card-foreground shadow-sm", children: [
217
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1 border-b px-6 py-4", children: [
218
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-medium", children: title }),
219
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: description })
220
+ ] }),
221
+ /* @__PURE__ */ jsx("div", { className: "px-2 py-4 sm:px-4", children: status === "error" ? /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
222
+ /* @__PURE__ */ jsx(ErrorMessage, { label: t("customers.config.activityTypes.loadFailed", "Failed to load activity types.") }),
223
+ /* @__PURE__ */ jsx(Button, { type: "button", onClick: () => {
224
+ void load();
225
+ }, children: t("customers.config.activityTypes.retry", "Retry") })
226
+ ] }) : /* @__PURE__ */ jsx(
227
+ DataTable,
228
+ {
229
+ embedded: true,
230
+ columns,
231
+ data: items,
232
+ isLoading: status === "loading",
233
+ title,
234
+ titleHeadingLevel: 2,
235
+ emptyState: t("customers.config.activityTypes.empty", "No activity types available."),
236
+ actions: /* @__PURE__ */ jsx(Button, { type: "button", size: "sm", onClick: () => setSelected(null), children: t("customers.config.activityTypes.new", "New activity type") }),
237
+ refreshButton: { label: t("customers.config.activityTypes.refresh", "Refresh"), onRefresh: load, isRefreshing: status === "loading" },
238
+ rowActions: (item) => {
239
+ const actions = [{ id: "edit", label: item.adminConfigurable ? t("customers.config.activityTypes.configure", "Configure") : t("customers.config.activityTypes.view", "View"), onSelect: () => setSelected(item) }];
240
+ if (localRow(item.key)) actions.push({
241
+ id: "delete",
242
+ label: item.source === "dictionary" ? t("customers.config.activityTypes.delete", "Delete") : t("customers.config.activityTypes.reset", "Reset override"),
243
+ destructive: true,
244
+ onSelect: () => {
245
+ void remove(item);
246
+ }
247
+ });
248
+ return /* @__PURE__ */ jsx(RowActions, { items: actions });
249
+ }
250
+ }
251
+ ) }),
252
+ /* @__PURE__ */ jsx(Dialog, { open: selected !== void 0, onOpenChange: (open) => {
253
+ if (!open) setSelected(void 0);
254
+ }, children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-h-screen overflow-y-auto sm:max-w-2xl", children: [
255
+ /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: selected ? t("customers.config.activityTypes.configure", "Configure") : t("customers.config.activityTypes.new", "New activity type") }) }),
256
+ selected?.isInherited ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("customers.config.activityTypes.inheritedHint", "Saving creates a local override for this organization.") }) : null,
257
+ selected?.inactiveDictionaryOverride ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("customers.config.activityTypes.inactiveHint", "A module currently prevents this override from taking effect.") }) : null,
258
+ selected?.missingCustomFieldsetIds.length ? /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
259
+ t("customers.config.activityTypes.missingHint", "Some configured fieldsets no longer exist."),
260
+ ": ",
261
+ selected.missingCustomFieldsetIds.join(", ")
262
+ ] }) : null,
263
+ fieldsetsStatus === "loading" ? /* @__PURE__ */ jsx(LoadingMessage, { label: t("customers.config.activityTypes.loadingFieldsets", "Loading fieldsets\u2026") }) : null,
264
+ fieldsetsStatus === "error" ? /* @__PURE__ */ jsx(ErrorMessage, { label: t("customers.config.activityTypes.fieldsetsUnavailable", "Fieldsets are unavailable. Retry loading before saving.") }) : null,
265
+ fieldsetsStatus === "error" ? /* @__PURE__ */ jsx(Button, { type: "button", onClick: () => setFieldsetAttempt((attempt) => attempt + 1), children: t("customers.config.activityTypes.retry", "Retry") }) : null,
266
+ fieldsetsStatus === "ready" && fieldsets.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("customers.config.activityTypes.noFieldsets", "No custom-field fieldsets are defined yet.") }) : null,
267
+ selected !== void 0 && fieldsetsStatus === "ready" ? /* @__PURE__ */ jsx(
268
+ CrudForm,
269
+ {
270
+ embedded: true,
271
+ readOnly: selected?.adminConfigurable === false,
272
+ fields,
273
+ groups,
274
+ initialValues: initialValues(selected),
275
+ onSubmit: save,
276
+ submitLabel: t("customers.config.activityTypes.save", "Save"),
277
+ extraActions: /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: () => setSelected(void 0), children: t("customers.config.dictionaries.dialog.cancel", "Cancel") })
278
+ },
279
+ selected?.key ?? "new"
280
+ ) : null
281
+ ] }) }),
282
+ ConfirmDialogElement
283
+ ] });
284
+ }
285
+ export {
286
+ ActivityTypeEditor
287
+ };
288
+ //# sourceMappingURL=ActivityTypeEditor.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/customers/components/ActivityTypeEditor.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { E } from '#generated/entities.ids.generated'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { getTelemetryRuntime } from '@open-mercato/shared/lib/telemetry/runtime'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions, type RowActionItem } from '@open-mercato/ui/backend/RowActions'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { ErrorMessage, LoadingMessage } from '@open-mercato/ui/backend/detail'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { calendarEventTypeBehaviorSchema, calendarEventTypeKeySchema, calendarEventTypes } from '../calendar-event-types'\nimport type { ScopedCalendarEventType } from '../lib/calendar/eventTypeResolver'\nimport { getCustomerDictionarySettingsSectionId } from '../lib/dictionaries'\nimport { renderDictionaryColor, renderDictionaryIcon } from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\n\nconst logger = createLogger('customers')\nconst ENTITY_ID = E.customers.customer_interaction\nconst API = '/api/customers/dictionaries/activity-types'\n\ntype DictionaryRow = { id: string; value: string; updatedAt: string | null; isInherited: boolean }\ntype Fieldset = { code: string; label: string }\ntype FormValues = Record<string, unknown>\n\nconst defaults = calendarEventTypes[0]!.behavior\n\nfunction initialValues(item: ScopedCalendarEventType | null): FormValues {\n const behavior = item?.behavior ?? defaults\n return {\n value: item?.key ?? '', label: item?.label ?? '', icon: item?.icon ?? '', color: item?.color ?? '',\n order: behavior.order, baseKind: behavior.baseKind, selectable: behavior.selectable,\n ...behavior.fields, customFieldsetIds: [...behavior.customFieldsetIds], updatedAt: item?.updatedAt ?? undefined,\n }\n}\n\nexport function ActivityTypeEditor({ title, description }: { title: string; description: string }) {\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const [items, setItems] = React.useState<ScopedCalendarEventType[]>([])\n const [rows, setRows] = React.useState<DictionaryRow[]>([])\n const [selected, setSelected] = React.useState<ScopedCalendarEventType | null | undefined>(undefined)\n const [fieldsets, setFieldsets] = React.useState<Fieldset[]>([])\n const [fieldsetsStatus, setFieldsetsStatus] = React.useState<'loading' | 'ready' | 'error'>('loading')\n const [fieldsetAttempt, setFieldsetAttempt] = React.useState(0)\n const [status, setStatus] = React.useState<'loading' | 'ready' | 'error'>('loading')\n const { runMutation, retryLastMutation } = useGuardedMutation({\n contextId: 'customers-activity-types',\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const load = React.useCallback(async () => {\n setStatus('loading')\n try {\n const [catalog, dictionary] = await Promise.all([\n readApiResultOrThrow<{ items: ScopedCalendarEventType[] }>('/api/customers/activity-types'),\n readApiResultOrThrow<{ items: DictionaryRow[] }>(API),\n ])\n if (!Array.isArray(catalog.items) || !Array.isArray(dictionary.items)) throw new Error('[internal] Invalid activity type response')\n setItems(catalog.items)\n setRows(dictionary.items)\n setStatus('ready')\n } catch (err) {\n logger.error('customers.activity_types.settings.load failed', { err })\n getTelemetryRuntime()?.reportError(err, {\n module: 'customers',\n code: 'customers.activity_type_settings_load_failed',\n })\n setStatus('error')\n }\n }, [])\n React.useEffect(() => { void load() }, [load, scopeVersion])\n\n React.useEffect(() => {\n if (selected === undefined) return\n let active = true\n setFieldsetsStatus('loading')\n void readApiResultOrThrow<{ fieldsetsByEntity?: Record<string, Fieldset[]> }>(\n `/api/entities/definitions?entityId=${encodeURIComponent(ENTITY_ID)}`,\n ).then((result) => {\n if (!active) return\n setFieldsets(result.fieldsetsByEntity?.[ENTITY_ID] ?? [])\n setFieldsetsStatus('ready')\n }).catch((err) => {\n logger.error('customers.activity_types.fieldsets.load failed', { err })\n getTelemetryRuntime()?.reportError(err, {\n module: 'customers',\n code: 'customers.activity_type_fieldsets_load_failed',\n })\n if (active) setFieldsetsStatus('error')\n })\n return () => { active = false }\n }, [selected, fieldsetAttempt])\n\n const localRow = (key: string) => rows.find((row) => row.value.toLowerCase() === key && !row.isInherited)\n const remove = async (item: ScopedCalendarEventType) => {\n const row = localRow(item.key)\n if (!row) return\n const approved = await confirm({\n title: t('customers.config.activityTypes.resetConfirm', 'Remove the local activity type configuration?'),\n variant: 'destructive',\n })\n if (!approved) return\n try {\n await runMutation({\n operation: () => withScopedApiRequestHeaders(buildOptimisticLockHeader(row.updatedAt), () =>\n apiCallOrThrow(`${API}/${encodeURIComponent(row.id)}`, { method: 'DELETE' })),\n context: { formId: 'customers-activity-types', resourceKind: 'customers.dictionary', retryLastMutation },\n mutationPayload: { action: 'delete', id: row.id, kind: 'activity-types' },\n })\n flash(t('customers.config.activityTypes.removed', 'Activity type configuration removed.'), 'success')\n await load()\n } catch (err) {\n logger.error('customers.activity_types.settings.remove failed', { err })\n getTelemetryRuntime()?.reportError(err, {\n module: 'customers',\n code: 'customers.activity_type_settings_remove_failed',\n })\n if (!surfaceRecordConflict(err, t, { onRefresh: () => { void load() } })) {\n flash(t('customers.config.activityTypes.saveFailed', 'Failed to save activity type.'), 'error')\n }\n }\n }\n\n const fields = React.useMemo<CrudField[]>(() => {\n const label = (key: string, fallback: string) => t(`customers.config.activityTypes.fields.${key}`, fallback)\n const options = (values: readonly string[]) => values.map((value) => ({ value, label: t(`customers.config.activityTypes.options.${value}`, value) }))\n const knownFieldsets = fieldsets.map(({ code, label: fieldsetLabel }) => ({ value: code, label: fieldsetLabel }))\n const missing = selected?.behavior.customFieldsetIds.filter((code) => !fieldsets.some((fieldset) => fieldset.code === code)) ?? []\n return [\n { id: 'value', type: 'text', label: label('value', 'Stable key'), required: true, readOnly: !!selected },\n { id: 'label', type: 'text', label: label('label', 'Label'), required: true },\n { id: 'icon', type: 'text', label: label('icon', 'Icon') },\n { id: 'color', type: 'text', label: label('color', 'Color (#RRGGBB)') },\n { id: 'order', type: 'number', label: label('order', 'Display order'), required: true },\n { id: 'baseKind', type: 'select', label: label('baseKind', 'Base behavior'), options: options(['meeting', 'call', 'email', 'note', 'event', 'task']) },\n { id: 'selectable', type: 'checkbox', label: label('selectable', 'Available for new events') },\n ...(['endTime', 'allDay', 'recurrence', 'priority', 'resources'] as const).map((id): CrudField => ({ id, type: 'checkbox', label: label(id, id) })),\n { id: 'location', type: 'select', label: label('location', 'Location field'), options: options(['none', 'location', 'phoneLink']) },\n { id: 'people', type: 'select', label: label('people', 'People field'), options: options(['none', 'attendees', 'participants', 'recipients', 'assignee']) },\n { id: 'customFieldsetIds', type: 'select', multiple: true, label: label('customFieldsetIds', 'Custom-field fieldsets'),\n options: [...knownFieldsets, ...missing.map((code) => ({ value: code, label: `${code} (${t('customers.config.activityTypes.missing', 'missing')})` }))] },\n ]\n }, [fieldsets, selected, t])\n const groups: CrudFormGroup[] = [\n { id: 'appearance', title: t('customers.config.activityTypes.appearance', 'Appearance'), fields: ['value', 'label', 'icon', 'color', 'order'] },\n { id: 'behavior', title: t('customers.config.activityTypes.behavior', 'Form behavior'), fields: ['baseKind', 'selectable', 'endTime', 'allDay', 'recurrence', 'location', 'people', 'priority', 'resources'] },\n ...(fieldsets.length || selected?.behavior.customFieldsetIds.length ? [{ id: 'fieldsets', fields: ['customFieldsetIds'] }] : []),\n ]\n const save = async (values: FormValues) => {\n const key = String(values.value ?? '').trim()\n if (!calendarEventTypeKeySchema.safeParse(key).success) throw createCrudFormError(t('customers.config.activityTypes.invalidKey', 'Use a lowercase key with letters, numbers, hyphens, or underscores.'), { value: t('customers.config.activityTypes.invalidKey', 'Use a lowercase key with letters, numbers, hyphens, or underscores.') })\n if (fieldsetsStatus !== 'ready') throw createCrudFormError(t('customers.config.activityTypes.fieldsetsUnavailable', 'Fieldsets are unavailable. Retry loading before saving.'))\n const behavior = calendarEventTypeBehaviorSchema.safeParse({\n schemaVersion: 1, baseKind: values.baseKind, selectable: values.selectable === true,\n order: Number(values.order), customFieldsetIds: values.customFieldsetIds ?? [],\n fields: { endTime: values.endTime === true, allDay: values.allDay === true, recurrence: values.recurrence === true,\n location: values.location, people: values.people, priority: values.priority === true, resources: values.resources === true },\n })\n if (!behavior.success) throw createCrudFormError(t('customers.config.activityTypes.invalidBehavior', 'Check the form behavior values.'))\n const payload = { value: key, label: String(values.label ?? '').trim(), icon: String(values.icon ?? '').trim() || null,\n color: String(values.color ?? '').trim() || null, behavior: behavior.data }\n const row = selected ? localRow(selected.key) : undefined\n await apiCallOrThrow(row ? `${API}/${encodeURIComponent(row.id)}` : API, {\n method: row ? 'PATCH' : 'POST', headers: { 'content-type': 'application/json' },\n body: JSON.stringify(row ? { label: payload.label, icon: payload.icon, color: payload.color, behavior: payload.behavior } : payload),\n })\n setSelected(undefined)\n flash(t('customers.config.activityTypes.saved', 'Activity type saved.'), 'success')\n await load()\n }\n\n const columns = React.useMemo<ColumnDef<ScopedCalendarEventType>[]>(() => [\n { accessorKey: 'label', header: t('customers.config.activityTypes.columns.type', 'Activity type'), cell: ({ row }) => (\n <div className=\"flex items-center gap-2\">{row.original.color ? renderDictionaryColor(row.original.color, 'size-4 rounded-full border border-border') : null}\n {row.original.icon ? renderDictionaryIcon(row.original.icon, 'size-4') : null}<span>{row.original.labelKey\n ? t(row.original.labelKey, row.original.label)\n : row.original.label}</span></div>) },\n { accessorKey: 'key', header: t('customers.config.activityTypes.columns.key', 'Stable key') },\n { id: 'source', header: t('customers.config.activityTypes.columns.source', 'Source'), cell: ({ row }) => row.original.isLocalOverride\n ? t('customers.config.activityTypes.local', 'Local override') : row.original.isInherited\n ? t('customers.config.activityTypes.inherited', 'Inherited') : row.original.source },\n { id: 'behavior', header: t('customers.config.activityTypes.columns.behavior', 'Behavior'), cell: ({ row }) =>\n t(`customers.config.activityTypes.options.${row.original.behavior.baseKind}`, row.original.behavior.baseKind) },\n { id: 'active', header: t('customers.config.activityTypes.columns.active', 'Selectable'), cell: ({ row }) => row.original.selectable\n ? t('customers.config.activityTypes.yes', 'Yes') : t('customers.config.activityTypes.no', 'No') },\n { id: 'fields', header: t('customers.config.activityTypes.columns.fields', 'Fields'), cell: ({ row }) =>\n Object.values(row.original.behavior.fields).filter((value) => value !== false && value !== 'none').length },\n { id: 'fieldsets', header: t('customers.config.activityTypes.columns.fieldsets', 'Fieldsets'), cell: ({ row }) => row.original.behavior.customFieldsetIds.length },\n { id: 'order', header: t('customers.config.activityTypes.columns.order', 'Order'), cell: ({ row }) => row.original.behavior.order },\n ], [t])\n\n return <section id={getCustomerDictionarySettingsSectionId('activity-types')} className=\"scroll-mt-24 rounded border bg-card text-card-foreground shadow-sm\">\n <div className=\"space-y-1 border-b px-6 py-4\"><h2 className=\"text-lg font-medium\">{title}</h2><p className=\"text-sm text-muted-foreground\">{description}</p></div>\n <div className=\"px-2 py-4 sm:px-4\">\n {status === 'error' ? <div className=\"space-y-3\"><ErrorMessage label={t('customers.config.activityTypes.loadFailed', 'Failed to load activity types.')} /><Button type=\"button\" onClick={() => { void load() }}>{t('customers.config.activityTypes.retry', 'Retry')}</Button></div> :\n <DataTable<ScopedCalendarEventType> embedded columns={columns} data={items} isLoading={status === 'loading'}\n title={title} titleHeadingLevel={2} emptyState={t('customers.config.activityTypes.empty', 'No activity types available.')}\n actions={<Button type=\"button\" size=\"sm\" onClick={() => setSelected(null)}>{t('customers.config.activityTypes.new', 'New activity type')}</Button>}\n refreshButton={{ label: t('customers.config.activityTypes.refresh', 'Refresh'), onRefresh: load, isRefreshing: status === 'loading' }}\n rowActions={(item) => {\n const actions: RowActionItem[] = [{ id: 'edit', label: item.adminConfigurable\n ? t('customers.config.activityTypes.configure', 'Configure') : t('customers.config.activityTypes.view', 'View'), onSelect: () => setSelected(item) }]\n if (localRow(item.key)) actions.push({ id: 'delete', label: item.source === 'dictionary'\n ? t('customers.config.activityTypes.delete', 'Delete') : t('customers.config.activityTypes.reset', 'Reset override'),\n destructive: true, onSelect: () => { void remove(item) } })\n return <RowActions items={actions} />\n }} />}\n </div>\n <Dialog open={selected !== undefined} onOpenChange={(open) => { if (!open) setSelected(undefined) }}>\n <DialogContent className=\"max-h-screen overflow-y-auto sm:max-w-2xl\">\n <DialogHeader><DialogTitle>{selected\n ? t('customers.config.activityTypes.configure', 'Configure') : t('customers.config.activityTypes.new', 'New activity type')}</DialogTitle></DialogHeader>\n {selected?.isInherited ? <p className=\"text-sm text-muted-foreground\">{t('customers.config.activityTypes.inheritedHint', 'Saving creates a local override for this organization.')}</p> : null}\n {selected?.inactiveDictionaryOverride ? <p className=\"text-sm text-muted-foreground\">{t('customers.config.activityTypes.inactiveHint', 'A module currently prevents this override from taking effect.')}</p> : null}\n {selected?.missingCustomFieldsetIds.length ? <p className=\"text-sm text-muted-foreground\">{t('customers.config.activityTypes.missingHint', 'Some configured fieldsets no longer exist.')}: {selected.missingCustomFieldsetIds.join(', ')}</p> : null}\n {fieldsetsStatus === 'loading' ? <LoadingMessage label={t('customers.config.activityTypes.loadingFieldsets', 'Loading fieldsets\u2026')} /> : null}\n {fieldsetsStatus === 'error' ? <ErrorMessage label={t('customers.config.activityTypes.fieldsetsUnavailable', 'Fieldsets are unavailable. Retry loading before saving.')} /> : null}\n {fieldsetsStatus === 'error' ? <Button type=\"button\" onClick={() => setFieldsetAttempt((attempt) => attempt + 1)}>{t('customers.config.activityTypes.retry', 'Retry')}</Button> : null}\n {fieldsetsStatus === 'ready' && fieldsets.length === 0 ? <p className=\"text-sm text-muted-foreground\">{t('customers.config.activityTypes.noFieldsets', 'No custom-field fieldsets are defined yet.')}</p> : null}\n {selected !== undefined && fieldsetsStatus === 'ready' ? <CrudForm<FormValues> key={selected?.key ?? 'new'} embedded\n readOnly={selected?.adminConfigurable === false} fields={fields} groups={groups}\n initialValues={initialValues(selected)} onSubmit={save} submitLabel={t('customers.config.activityTypes.save', 'Save')}\n extraActions={<Button type=\"button\" variant=\"outline\" onClick={() => setSelected(undefined)}>{t('customers.config.dictionaries.dialog.cancel', 'Cancel')}</Button>} /> : null}\n </DialogContent>\n </Dialog>\n {ConfirmDialogElement}\n </section>\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
+ import dynamic from "next/dynamic";
4
5
  import {
5
6
  Dialog,
6
7
  DialogContent,
@@ -26,6 +27,7 @@ import {
26
27
  } from "@open-mercato/core/modules/dictionaries/components/DictionaryTable";
27
28
  import { createLogger } from "@open-mercato/shared/lib/logger";
28
29
  const logger = createLogger("customers");
30
+ const ActivityTypeEditor = dynamic(() => import("./ActivityTypeEditor.js").then((module) => module.ActivityTypeEditor), { ssr: false });
29
31
  const DEFAULT_FORM_VALUES = {
30
32
  value: "",
31
33
  label: "",
@@ -136,7 +138,7 @@ function DictionarySettings() {
136
138
  /* @__PURE__ */ jsx("h1", { className: "text-2xl font-semibold", children: t("customers.config.dictionaries.title", "Customers dictionaries") }),
137
139
  /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("customers.config.dictionaries.description", "Manage the dictionaries used by the customers module.") })
138
140
  ] }),
139
- /* @__PURE__ */ jsx("div", { className: "space-y-6", children: sections.map((section) => /* @__PURE__ */ jsx(CustomerDictionarySection, { ...section }, section.kind)) })
141
+ /* @__PURE__ */ jsx("div", { className: "space-y-6", children: sections.map((section) => section.kind === "activity-types" ? /* @__PURE__ */ jsx(ActivityTypeEditor, { title: section.title, description: section.description }, section.kind) : /* @__PURE__ */ jsx(CustomerDictionarySection, { ...section }, section.kind)) })
140
142
  ] });
141
143
  }
142
144
  function CustomerDictionarySection({ kind, title, description }) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/customers/components/DictionarySettings.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport {\n getCustomerDictionarySettingsSectionId,\n type CustomerDictionaryKind,\n} from '../lib/dictionaries'\nimport { ICON_SUGGESTIONS } from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport {\n DictionaryForm,\n type DictionaryFormValues,\n} from '@open-mercato/core/modules/dictionaries/components/DictionaryForm'\nimport {\n DictionaryTable,\n type DictionaryTableEntry,\n} from '@open-mercato/core/modules/dictionaries/components/DictionaryTable'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\ntype SectionDefinition = {\n kind: CustomerDictionaryKind\n title: string\n description: string\n}\n\ntype DictionaryDeleteError = Error & {\n code?: string\n usageCount?: number\n}\n\ntype DialogState =\n | { mode: 'create' }\n | { mode: 'edit'; entry: DictionaryTableEntry }\n\nconst DEFAULT_FORM_VALUES: DictionaryFormValues = {\n value: '',\n label: '',\n color: null,\n icon: null,\n}\n\nconst DICTIONARY_HASH_SCROLL_RETRY_DELAYS_MS = [100, 350, 1000] as const\n\nfunction getCurrentDictionaryHashTarget(): HTMLElement | null {\n if (typeof window === 'undefined') return null\n const hash = window.location.hash\n if (!hash.startsWith('#customer-dictionary-')) return null\n try {\n return document.getElementById(decodeURIComponent(hash.slice(1)))\n } catch {\n return document.getElementById(hash.slice(1))\n }\n}\n\nexport default function DictionarySettings() {\n const t = useT()\n\n const sections = React.useMemo<SectionDefinition[]>(() => [\n {\n kind: 'person-company-roles',\n title: t('customers.config.dictionaries.sections.personCompanyRoles.title', 'Role types'),\n description: t('customers.config.dictionaries.sections.personCompanyRoles.description', 'Manage the ownership roles available in People tab assignments.'),\n },\n {\n kind: 'statuses',\n title: t('customers.config.dictionaries.sections.statuses.title', 'Statuses'),\n description: t('customers.config.dictionaries.sections.statuses.description', 'Define the statuses available for customer records.'),\n },\n {\n kind: 'deal-statuses',\n title: t('customers.config.dictionaries.sections.dealStatuses.title', 'Deal statuses'),\n description: t('customers.config.dictionaries.sections.dealStatuses.description', 'Manage the statuses available for deals.'),\n },\n {\n kind: 'job-titles',\n title: t('customers.config.dictionaries.sections.jobTitles.title', 'Job titles'),\n description: t('customers.config.dictionaries.sections.jobTitles.description', 'Configure job titles with their appearance.'),\n },\n {\n kind: 'sources',\n title: t('customers.config.dictionaries.sections.sources.title', 'Sources'),\n description: t('customers.config.dictionaries.sections.sources.description', 'Capture how customers were acquired.'),\n },\n {\n kind: 'industries',\n title: t('customers.config.dictionaries.sections.industries.title', 'Industries'),\n description: t('customers.config.dictionaries.sections.industries.description', 'Manage the industries used by companies.'),\n },\n {\n kind: 'lifecycle-stages',\n title: t('customers.config.dictionaries.sections.lifecycle.title', 'Lifecycle stages'),\n description: t('customers.config.dictionaries.sections.lifecycle.description', 'Configure lifecycle stages to track customer progress.'),\n },\n {\n kind: 'activity-types',\n title: t('customers.config.dictionaries.sections.activityTypes.title', 'Activity types'),\n description: t('customers.config.dictionaries.sections.activityTypes.description', 'Define the activity types used for customer interactions.'),\n },\n {\n kind: 'interaction-statuses',\n title: t('customers.config.dictionaries.sections.interactionStatuses.title', 'Interaction statuses'),\n description: t('customers.config.dictionaries.sections.interactionStatuses.description', 'Manage the statuses available for tasks and logged interactions.'),\n },\n {\n kind: 'address-types',\n title: t('customers.config.dictionaries.sections.addressTypes.title', 'Address types'),\n description: t('customers.config.dictionaries.sections.addressTypes.description', 'Define the available address types.'),\n },\n ], [t])\n\n React.useEffect(() => {\n const timeoutIds: number[] = []\n let frameId: number | null = null\n\n const clearScheduledScrolls = () => {\n if (frameId !== null) {\n window.cancelAnimationFrame(frameId)\n frameId = null\n }\n while (timeoutIds.length > 0) {\n const timeoutId = timeoutIds.pop()\n if (timeoutId !== undefined) window.clearTimeout(timeoutId)\n }\n }\n\n const scrollToHashTarget = () => {\n getCurrentDictionaryHashTarget()?.scrollIntoView({ block: 'start' })\n }\n\n const scheduleHashScroll = () => {\n clearScheduledScrolls()\n if (!window.location.hash.startsWith('#customer-dictionary-')) return\n scrollToHashTarget()\n if (typeof window.requestAnimationFrame === 'function') {\n frameId = window.requestAnimationFrame(scrollToHashTarget)\n }\n DICTIONARY_HASH_SCROLL_RETRY_DELAYS_MS.forEach((delay) => {\n timeoutIds.push(window.setTimeout(scrollToHashTarget, delay))\n })\n }\n\n scheduleHashScroll()\n window.addEventListener('hashchange', scheduleHashScroll)\n return () => {\n window.removeEventListener('hashchange', scheduleHashScroll)\n clearScheduledScrolls()\n }\n }, [])\n\n return (\n <div className=\"space-y-8\">\n <header className=\"space-y-2\">\n <h1 className=\"text-2xl font-semibold\">\n {t('customers.config.dictionaries.title', 'Customers dictionaries')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.config.dictionaries.description', 'Manage the dictionaries used by the customers module.')}\n </p>\n </header>\n\n <div className=\"space-y-6\">\n {sections.map((section) => (\n <CustomerDictionarySection key={section.kind} {...section} />\n ))}\n </div>\n </div>\n )\n}\n\ntype CustomerDictionarySectionProps = SectionDefinition\n\nfunction CustomerDictionarySection({ kind, title, description }: CustomerDictionarySectionProps) {\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const scopeVersion = useOrganizationScopeVersion()\n const [entries, setEntries] = React.useState<DictionaryTableEntry[]>([])\n const [loading, setLoading] = React.useState<boolean>(true)\n const [dialog, setDialog] = React.useState<DialogState | null>(null)\n const [submitting, setSubmitting] = React.useState(false)\n\n const saveContextId = `customers-dictionary-${kind}`\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: saveContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const mutationContext = React.useMemo(\n () => ({\n formId: saveContextId,\n resourceKind: 'customers.dictionary',\n retryLastMutation,\n }),\n [retryLastMutation, saveContextId],\n )\n\n const inheritedActionBlocked = t('customers.config.dictionaries.inherited.blocked', 'Inherited entries can only be edited from the parent organization.')\n const inheritedTooltip = t('customers.config.dictionaries.inherited.tooltip', 'Managed in parent organization')\n const inheritedLabel = t('customers.config.dictionaries.inherited.label', 'Inherited')\n const errorLoad = t('customers.config.dictionaries.error.load', 'Failed to load dictionary entries.')\n const errorSave = t('customers.config.dictionaries.error.save', 'Failed to save dictionary entry.')\n const errorDelete = t('customers.config.dictionaries.error.delete', 'Failed to delete dictionary entry.')\n const successSave = t('customers.config.dictionaries.success.save', 'Dictionary entry saved.')\n const successDelete = t('customers.config.dictionaries.success.delete', 'Dictionary entry deleted.')\n const deleteConfirmTemplate = t('customers.config.dictionaries.deleteConfirm', 'Delete \"{{value}}\"?')\n const roleTypeDeleteBlockedTitle = t('customers.config.dictionaries.roleTypes.deleteBlocked.title', 'Role type is in use')\n const roleTypeDeleteBlockedText = t(\n 'customers.config.dictionaries.roleTypes.deleteBlocked.text',\n 'This role type is assigned to {{count}} records. Remove or replace those assignments before deleting it.',\n )\n const usageCountLabel = t('customers.config.dictionaries.roleTypes.usageCount', 'In use on {{count}} records')\n const searchPlaceholder = t('customers.config.dictionaries.searchPlaceholder', 'Search entries\u2026')\n\n const formatCountMessage = React.useCallback((template: string, count: number) => {\n return template.replace('{{count}}', String(count))\n }, [])\n\n const loadEntries = React.useCallback(async () => {\n setLoading(true)\n try {\n const data = await readApiResultOrThrow<{ items?: unknown[] }>(\n `/api/customers/dictionaries/${kind}`,\n undefined,\n { errorMessage: errorLoad },\n )\n if (!Array.isArray(data?.items)) throw new Error(errorLoad)\n const mapped: DictionaryTableEntry[] = data.items.map((item: any) => ({\n id: String(item.id),\n value: String(item.value ?? ''),\n label: typeof item.label === 'string' ? item.label : '',\n color: typeof item.color === 'string' ? item.color : null,\n icon: typeof item.icon === 'string' ? item.icon : null,\n usageCount: typeof item.usageCount === 'number' ? item.usageCount : undefined,\n organizationId: typeof item.organizationId === 'string' ? item.organizationId : null,\n tenantId: typeof item.tenantId === 'string' ? item.tenantId : null,\n isInherited: item.isInherited === true,\n createdAt: typeof item.createdAt === 'string' ? item.createdAt : null,\n updatedAt: typeof item.updatedAt === 'string' ? item.updatedAt : null,\n }))\n setEntries(mapped)\n } catch (err) {\n logger.error('customers.dictionaries.list failed', { err })\n flash(errorLoad, 'error')\n } finally {\n setLoading(false)\n }\n }, [errorLoad, kind, scopeVersion])\n\n React.useEffect(() => {\n loadEntries().catch(() => {})\n }, [loadEntries])\n\n const closeDialog = React.useCallback(() => {\n setDialog(null)\n }, [])\n\n const handleCreate = React.useCallback(() => {\n setDialog({ mode: 'create' })\n }, [])\n\n const handleEdit = React.useCallback((entry: DictionaryTableEntry) => {\n if (entry.isInherited) {\n flash(inheritedActionBlocked, 'info')\n return\n }\n setDialog({ mode: 'edit', entry })\n }, [inheritedActionBlocked])\n\n const handleDelete = React.useCallback(async (entry: DictionaryTableEntry) => {\n if (entry.isInherited) {\n flash(inheritedActionBlocked, 'info')\n return\n }\n if (kind === 'person-company-roles' && (entry.usageCount ?? 0) > 0) {\n await confirm({\n title: roleTypeDeleteBlockedTitle,\n description: formatCountMessage(roleTypeDeleteBlockedText, entry.usageCount ?? 0),\n confirmText: false,\n cancelText: t('customers.config.dictionaries.dialog.cancel', 'Cancel'),\n })\n return\n }\n const message = deleteConfirmTemplate.replace('{{value}}', entry.label || entry.value)\n const confirmed = await confirm({\n title: message,\n variant: 'destructive',\n })\n if (!confirmed) return\n try {\n await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(buildOptimisticLockHeader(entry.updatedAt), () =>\n apiCallOrThrow(\n `/api/customers/dictionaries/${kind}/${encodeURIComponent(entry.id)}`,\n { method: 'DELETE' },\n { errorMessage: errorDelete },\n ),\n ),\n context: mutationContext,\n mutationPayload: { action: 'delete', id: entry.id, kind },\n })\n flash(successDelete, 'success')\n await loadEntries()\n } catch (err) {\n logger.error('customers.dictionaries.delete failed', { err })\n if (kind === 'person-company-roles' && (err as DictionaryDeleteError)?.code === 'role_type_in_use') {\n const usageCount = Number((err as DictionaryDeleteError).usageCount ?? 0)\n await confirm({\n title: roleTypeDeleteBlockedTitle,\n description: formatCountMessage(roleTypeDeleteBlockedText, usageCount),\n confirmText: false,\n cancelText: t('customers.config.dictionaries.dialog.cancel', 'Cancel'),\n })\n return\n }\n const messageValue = err instanceof Error ? err.message : errorDelete\n flash(messageValue, 'error')\n }\n }, [confirm, deleteConfirmTemplate, errorDelete, formatCountMessage, inheritedActionBlocked, kind, loadEntries, mutationContext, roleTypeDeleteBlockedText, roleTypeDeleteBlockedTitle, runMutation, successDelete, t])\n\n const submitForm = React.useCallback(async (values: DictionaryFormValues) => {\n const payload = {\n value: values.value,\n label: values.label,\n color: values.color,\n icon: values.icon,\n }\n setSubmitting(true)\n try {\n if (!dialog || dialog.mode === 'create') {\n await runMutation({\n operation: () =>\n apiCallOrThrow(\n `/api/customers/dictionaries/${kind}`,\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n { errorMessage: errorSave },\n ),\n context: mutationContext,\n mutationPayload: { action: 'create', kind, ...payload },\n })\n flash(successSave, 'success')\n } else if (dialog.mode === 'edit') {\n const target = dialog.entry\n if (target.isInherited) {\n flash(inheritedActionBlocked, 'info')\n return\n }\n const body: Record<string, unknown> = {}\n if (values.value !== target.value) body.value = values.value\n if (values.label !== target.label) body.label = values.label\n const nextColor = values.color ?? null\n if (nextColor !== (target.color ?? null)) body.color = nextColor\n const nextIcon = values.icon ?? null\n if (nextIcon !== (target.icon ?? null)) body.icon = nextIcon\n if (Object.keys(body).length === 0) {\n closeDialog()\n return\n }\n await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(buildOptimisticLockHeader(target.updatedAt), () =>\n apiCallOrThrow(\n `/api/customers/dictionaries/${kind}/${encodeURIComponent(target.id)}`,\n {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n },\n { errorMessage: errorSave },\n ),\n ),\n context: mutationContext,\n mutationPayload: { action: 'update', id: target.id, kind, ...body },\n })\n flash(successSave, 'success')\n }\n closeDialog()\n await loadEntries()\n } catch (err) {\n logger.error('customers.dictionaries.submit failed', { err })\n throw err instanceof Error ? err : new Error(errorSave)\n } finally {\n setSubmitting(false)\n }\n }, [closeDialog, dialog, errorSave, inheritedActionBlocked, kind, loadEntries, mutationContext, runMutation, successSave])\n\n const currentValues = React.useMemo<DictionaryFormValues>(() => {\n if (dialog && dialog.mode === 'edit') {\n return {\n value: dialog.entry.value,\n label: dialog.entry.label,\n color: dialog.entry.color,\n icon: dialog.entry.icon,\n }\n }\n return DEFAULT_FORM_VALUES\n }, [dialog])\n\n const tableTranslations = React.useMemo(() => ({\n title,\n valueColumn: t('customers.config.dictionaries.columns.value', 'Value'),\n labelColumn: t('customers.config.dictionaries.columns.label', 'Label'),\n appearanceColumn: t('customers.config.dictionaries.columns.appearance', 'Appearance'),\n addLabel: t('customers.config.dictionaries.actions.add', 'Add entry'),\n editLabel: t('customers.config.dictionaries.actions.edit', 'Edit'),\n deleteLabel: t('customers.config.dictionaries.actions.delete', 'Delete'),\n refreshLabel: t('customers.config.dictionaries.actions.refresh', 'Refresh'),\n inheritedLabel,\n inheritedTooltip,\n emptyLabel: t('customers.config.dictionaries.empty', 'No entries yet.'),\n usageCountLabel: kind === 'person-company-roles' ? usageCountLabel : undefined,\n searchPlaceholder,\n }), [inheritedLabel, inheritedTooltip, kind, searchPlaceholder, t, title, usageCountLabel])\n\n const formTranslations = React.useMemo(() => ({\n title: dialog?.mode === 'edit'\n ? t('customers.config.dictionaries.dialog.editTitle', 'Edit entry')\n : t('customers.config.dictionaries.dialog.addTitle', 'Add entry'),\n valueLabel: t('customers.config.dictionaries.dialog.valueLabel', 'Value'),\n labelLabel: t('customers.config.dictionaries.dialog.labelLabel', 'Label'),\n saveLabel: t('customers.config.dictionaries.dialog.save', 'Save'),\n cancelLabel: t('customers.config.dictionaries.dialog.cancel', 'Cancel'),\n appearance: {\n colorLabel: t('customers.config.dictionaries.dialog.colorLabel', 'Color'),\n colorHelp: t('customers.config.dictionaries.dialog.colorHelp', 'Pick a highlight color for this entry.'),\n colorClearLabel: t('customers.config.dictionaries.dialog.colorClear', 'Remove color'),\n iconLabel: t('customers.config.dictionaries.dialog.iconLabel', 'Icon'),\n iconPlaceholder: t('customers.config.dictionaries.dialog.iconPlaceholder', 'Type an emoji or pick one of the suggestions.'),\n iconPickerTriggerLabel: t('customers.config.dictionaries.dialog.iconBrowse', 'Browse icons and emojis'),\n iconSearchPlaceholder: t('customers.config.dictionaries.dialog.iconSearchPlaceholder', 'Search icons or emojis\u2026'),\n iconSearchEmptyLabel: t('customers.config.dictionaries.dialog.iconSearchEmpty', 'No icons match your search.'),\n iconSuggestionsLabel: t('customers.config.dictionaries.dialog.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('customers.config.dictionaries.dialog.iconClear', 'Remove icon'),\n previewEmptyLabel: t('customers.config.dictionaries.appearance.empty', 'None'),\n },\n }), [dialog, t])\n\n return (\n <section\n id={getCustomerDictionarySettingsSectionId(kind)}\n className=\"scroll-mt-24 rounded border bg-card text-card-foreground shadow-sm\"\n >\n <div className=\"border-b px-6 py-4 space-y-1\">\n <h2 className=\"text-lg font-medium\">{title}</h2>\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n </div>\n <div className=\"px-2 py-4 sm:px-4\">\n <DictionaryTable\n entries={entries}\n loading={loading}\n canManage\n onCreate={handleCreate}\n onEdit={handleEdit}\n onDelete={handleDelete}\n onRefresh={loadEntries}\n translations={tableTranslations}\n />\n </div>\n <Dialog open={dialog !== null} onOpenChange={(open) => { if (!open) closeDialog() }}>\n <DialogContent className=\"max-w-lg\">\n <DialogHeader>\n <DialogTitle>{formTranslations.title}</DialogTitle>\n </DialogHeader>\n <DictionaryForm\n mode={dialog?.mode === 'edit' ? 'edit' : 'create'}\n initialValues={currentValues}\n onSubmit={submitForm}\n onCancel={closeDialog}\n submitting={submitting}\n translations={formTranslations}\n iconSuggestions={ICON_SUGGESTIONS}\n />\n </DialogContent>\n </Dialog>\n {ConfirmDialogElement}\n </section>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport dynamic from 'next/dynamic'\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport {\n getCustomerDictionarySettingsSectionId,\n type CustomerDictionaryKind,\n} from '../lib/dictionaries'\nimport { ICON_SUGGESTIONS } from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport {\n DictionaryForm,\n type DictionaryFormValues,\n} from '@open-mercato/core/modules/dictionaries/components/DictionaryForm'\nimport {\n DictionaryTable,\n type DictionaryTableEntry,\n} from '@open-mercato/core/modules/dictionaries/components/DictionaryTable'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\nconst ActivityTypeEditor = dynamic(() => import('./ActivityTypeEditor').then((module) => module.ActivityTypeEditor), { ssr: false })\n\ntype SectionDefinition = {\n kind: CustomerDictionaryKind\n title: string\n description: string\n}\n\ntype DictionaryDeleteError = Error & {\n code?: string\n usageCount?: number\n}\n\ntype DialogState =\n | { mode: 'create' }\n | { mode: 'edit'; entry: DictionaryTableEntry }\n\nconst DEFAULT_FORM_VALUES: DictionaryFormValues = {\n value: '',\n label: '',\n color: null,\n icon: null,\n}\n\nconst DICTIONARY_HASH_SCROLL_RETRY_DELAYS_MS = [100, 350, 1000] as const\n\nfunction getCurrentDictionaryHashTarget(): HTMLElement | null {\n if (typeof window === 'undefined') return null\n const hash = window.location.hash\n if (!hash.startsWith('#customer-dictionary-')) return null\n try {\n return document.getElementById(decodeURIComponent(hash.slice(1)))\n } catch {\n return document.getElementById(hash.slice(1))\n }\n}\n\nexport default function DictionarySettings() {\n const t = useT()\n\n const sections = React.useMemo<SectionDefinition[]>(() => [\n {\n kind: 'person-company-roles',\n title: t('customers.config.dictionaries.sections.personCompanyRoles.title', 'Role types'),\n description: t('customers.config.dictionaries.sections.personCompanyRoles.description', 'Manage the ownership roles available in People tab assignments.'),\n },\n {\n kind: 'statuses',\n title: t('customers.config.dictionaries.sections.statuses.title', 'Statuses'),\n description: t('customers.config.dictionaries.sections.statuses.description', 'Define the statuses available for customer records.'),\n },\n {\n kind: 'deal-statuses',\n title: t('customers.config.dictionaries.sections.dealStatuses.title', 'Deal statuses'),\n description: t('customers.config.dictionaries.sections.dealStatuses.description', 'Manage the statuses available for deals.'),\n },\n {\n kind: 'job-titles',\n title: t('customers.config.dictionaries.sections.jobTitles.title', 'Job titles'),\n description: t('customers.config.dictionaries.sections.jobTitles.description', 'Configure job titles with their appearance.'),\n },\n {\n kind: 'sources',\n title: t('customers.config.dictionaries.sections.sources.title', 'Sources'),\n description: t('customers.config.dictionaries.sections.sources.description', 'Capture how customers were acquired.'),\n },\n {\n kind: 'industries',\n title: t('customers.config.dictionaries.sections.industries.title', 'Industries'),\n description: t('customers.config.dictionaries.sections.industries.description', 'Manage the industries used by companies.'),\n },\n {\n kind: 'lifecycle-stages',\n title: t('customers.config.dictionaries.sections.lifecycle.title', 'Lifecycle stages'),\n description: t('customers.config.dictionaries.sections.lifecycle.description', 'Configure lifecycle stages to track customer progress.'),\n },\n {\n kind: 'activity-types',\n title: t('customers.config.dictionaries.sections.activityTypes.title', 'Activity types'),\n description: t('customers.config.dictionaries.sections.activityTypes.description', 'Define the activity types used for customer interactions.'),\n },\n {\n kind: 'interaction-statuses',\n title: t('customers.config.dictionaries.sections.interactionStatuses.title', 'Interaction statuses'),\n description: t('customers.config.dictionaries.sections.interactionStatuses.description', 'Manage the statuses available for tasks and logged interactions.'),\n },\n {\n kind: 'address-types',\n title: t('customers.config.dictionaries.sections.addressTypes.title', 'Address types'),\n description: t('customers.config.dictionaries.sections.addressTypes.description', 'Define the available address types.'),\n },\n ], [t])\n\n React.useEffect(() => {\n const timeoutIds: number[] = []\n let frameId: number | null = null\n\n const clearScheduledScrolls = () => {\n if (frameId !== null) {\n window.cancelAnimationFrame(frameId)\n frameId = null\n }\n while (timeoutIds.length > 0) {\n const timeoutId = timeoutIds.pop()\n if (timeoutId !== undefined) window.clearTimeout(timeoutId)\n }\n }\n\n const scrollToHashTarget = () => {\n getCurrentDictionaryHashTarget()?.scrollIntoView({ block: 'start' })\n }\n\n const scheduleHashScroll = () => {\n clearScheduledScrolls()\n if (!window.location.hash.startsWith('#customer-dictionary-')) return\n scrollToHashTarget()\n if (typeof window.requestAnimationFrame === 'function') {\n frameId = window.requestAnimationFrame(scrollToHashTarget)\n }\n DICTIONARY_HASH_SCROLL_RETRY_DELAYS_MS.forEach((delay) => {\n timeoutIds.push(window.setTimeout(scrollToHashTarget, delay))\n })\n }\n\n scheduleHashScroll()\n window.addEventListener('hashchange', scheduleHashScroll)\n return () => {\n window.removeEventListener('hashchange', scheduleHashScroll)\n clearScheduledScrolls()\n }\n }, [])\n\n return (\n <div className=\"space-y-8\">\n <header className=\"space-y-2\">\n <h1 className=\"text-2xl font-semibold\">\n {t('customers.config.dictionaries.title', 'Customers dictionaries')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n {t('customers.config.dictionaries.description', 'Manage the dictionaries used by the customers module.')}\n </p>\n </header>\n\n <div className=\"space-y-6\">\n {sections.map((section) => section.kind === 'activity-types'\n ? <ActivityTypeEditor key={section.kind} title={section.title} description={section.description} />\n : <CustomerDictionarySection key={section.kind} {...section} />)}\n </div>\n </div>\n )\n}\n\ntype CustomerDictionarySectionProps = SectionDefinition\n\nfunction CustomerDictionarySection({ kind, title, description }: CustomerDictionarySectionProps) {\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const scopeVersion = useOrganizationScopeVersion()\n const [entries, setEntries] = React.useState<DictionaryTableEntry[]>([])\n const [loading, setLoading] = React.useState<boolean>(true)\n const [dialog, setDialog] = React.useState<DialogState | null>(null)\n const [submitting, setSubmitting] = React.useState(false)\n\n const saveContextId = `customers-dictionary-${kind}`\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: saveContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const mutationContext = React.useMemo(\n () => ({\n formId: saveContextId,\n resourceKind: 'customers.dictionary',\n retryLastMutation,\n }),\n [retryLastMutation, saveContextId],\n )\n\n const inheritedActionBlocked = t('customers.config.dictionaries.inherited.blocked', 'Inherited entries can only be edited from the parent organization.')\n const inheritedTooltip = t('customers.config.dictionaries.inherited.tooltip', 'Managed in parent organization')\n const inheritedLabel = t('customers.config.dictionaries.inherited.label', 'Inherited')\n const errorLoad = t('customers.config.dictionaries.error.load', 'Failed to load dictionary entries.')\n const errorSave = t('customers.config.dictionaries.error.save', 'Failed to save dictionary entry.')\n const errorDelete = t('customers.config.dictionaries.error.delete', 'Failed to delete dictionary entry.')\n const successSave = t('customers.config.dictionaries.success.save', 'Dictionary entry saved.')\n const successDelete = t('customers.config.dictionaries.success.delete', 'Dictionary entry deleted.')\n const deleteConfirmTemplate = t('customers.config.dictionaries.deleteConfirm', 'Delete \"{{value}}\"?')\n const roleTypeDeleteBlockedTitle = t('customers.config.dictionaries.roleTypes.deleteBlocked.title', 'Role type is in use')\n const roleTypeDeleteBlockedText = t(\n 'customers.config.dictionaries.roleTypes.deleteBlocked.text',\n 'This role type is assigned to {{count}} records. Remove or replace those assignments before deleting it.',\n )\n const usageCountLabel = t('customers.config.dictionaries.roleTypes.usageCount', 'In use on {{count}} records')\n const searchPlaceholder = t('customers.config.dictionaries.searchPlaceholder', 'Search entries\u2026')\n\n const formatCountMessage = React.useCallback((template: string, count: number) => {\n return template.replace('{{count}}', String(count))\n }, [])\n\n const loadEntries = React.useCallback(async () => {\n setLoading(true)\n try {\n const data = await readApiResultOrThrow<{ items?: unknown[] }>(\n `/api/customers/dictionaries/${kind}`,\n undefined,\n { errorMessage: errorLoad },\n )\n if (!Array.isArray(data?.items)) throw new Error(errorLoad)\n const mapped: DictionaryTableEntry[] = data.items.map((item: any) => ({\n id: String(item.id),\n value: String(item.value ?? ''),\n label: typeof item.label === 'string' ? item.label : '',\n color: typeof item.color === 'string' ? item.color : null,\n icon: typeof item.icon === 'string' ? item.icon : null,\n usageCount: typeof item.usageCount === 'number' ? item.usageCount : undefined,\n organizationId: typeof item.organizationId === 'string' ? item.organizationId : null,\n tenantId: typeof item.tenantId === 'string' ? item.tenantId : null,\n isInherited: item.isInherited === true,\n createdAt: typeof item.createdAt === 'string' ? item.createdAt : null,\n updatedAt: typeof item.updatedAt === 'string' ? item.updatedAt : null,\n }))\n setEntries(mapped)\n } catch (err) {\n logger.error('customers.dictionaries.list failed', { err })\n flash(errorLoad, 'error')\n } finally {\n setLoading(false)\n }\n }, [errorLoad, kind, scopeVersion])\n\n React.useEffect(() => {\n loadEntries().catch(() => {})\n }, [loadEntries])\n\n const closeDialog = React.useCallback(() => {\n setDialog(null)\n }, [])\n\n const handleCreate = React.useCallback(() => {\n setDialog({ mode: 'create' })\n }, [])\n\n const handleEdit = React.useCallback((entry: DictionaryTableEntry) => {\n if (entry.isInherited) {\n flash(inheritedActionBlocked, 'info')\n return\n }\n setDialog({ mode: 'edit', entry })\n }, [inheritedActionBlocked])\n\n const handleDelete = React.useCallback(async (entry: DictionaryTableEntry) => {\n if (entry.isInherited) {\n flash(inheritedActionBlocked, 'info')\n return\n }\n if (kind === 'person-company-roles' && (entry.usageCount ?? 0) > 0) {\n await confirm({\n title: roleTypeDeleteBlockedTitle,\n description: formatCountMessage(roleTypeDeleteBlockedText, entry.usageCount ?? 0),\n confirmText: false,\n cancelText: t('customers.config.dictionaries.dialog.cancel', 'Cancel'),\n })\n return\n }\n const message = deleteConfirmTemplate.replace('{{value}}', entry.label || entry.value)\n const confirmed = await confirm({\n title: message,\n variant: 'destructive',\n })\n if (!confirmed) return\n try {\n await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(buildOptimisticLockHeader(entry.updatedAt), () =>\n apiCallOrThrow(\n `/api/customers/dictionaries/${kind}/${encodeURIComponent(entry.id)}`,\n { method: 'DELETE' },\n { errorMessage: errorDelete },\n ),\n ),\n context: mutationContext,\n mutationPayload: { action: 'delete', id: entry.id, kind },\n })\n flash(successDelete, 'success')\n await loadEntries()\n } catch (err) {\n logger.error('customers.dictionaries.delete failed', { err })\n if (kind === 'person-company-roles' && (err as DictionaryDeleteError)?.code === 'role_type_in_use') {\n const usageCount = Number((err as DictionaryDeleteError).usageCount ?? 0)\n await confirm({\n title: roleTypeDeleteBlockedTitle,\n description: formatCountMessage(roleTypeDeleteBlockedText, usageCount),\n confirmText: false,\n cancelText: t('customers.config.dictionaries.dialog.cancel', 'Cancel'),\n })\n return\n }\n const messageValue = err instanceof Error ? err.message : errorDelete\n flash(messageValue, 'error')\n }\n }, [confirm, deleteConfirmTemplate, errorDelete, formatCountMessage, inheritedActionBlocked, kind, loadEntries, mutationContext, roleTypeDeleteBlockedText, roleTypeDeleteBlockedTitle, runMutation, successDelete, t])\n\n const submitForm = React.useCallback(async (values: DictionaryFormValues) => {\n const payload = {\n value: values.value,\n label: values.label,\n color: values.color,\n icon: values.icon,\n }\n setSubmitting(true)\n try {\n if (!dialog || dialog.mode === 'create') {\n await runMutation({\n operation: () =>\n apiCallOrThrow(\n `/api/customers/dictionaries/${kind}`,\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n { errorMessage: errorSave },\n ),\n context: mutationContext,\n mutationPayload: { action: 'create', kind, ...payload },\n })\n flash(successSave, 'success')\n } else if (dialog.mode === 'edit') {\n const target = dialog.entry\n if (target.isInherited) {\n flash(inheritedActionBlocked, 'info')\n return\n }\n const body: Record<string, unknown> = {}\n if (values.value !== target.value) body.value = values.value\n if (values.label !== target.label) body.label = values.label\n const nextColor = values.color ?? null\n if (nextColor !== (target.color ?? null)) body.color = nextColor\n const nextIcon = values.icon ?? null\n if (nextIcon !== (target.icon ?? null)) body.icon = nextIcon\n if (Object.keys(body).length === 0) {\n closeDialog()\n return\n }\n await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(buildOptimisticLockHeader(target.updatedAt), () =>\n apiCallOrThrow(\n `/api/customers/dictionaries/${kind}/${encodeURIComponent(target.id)}`,\n {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n },\n { errorMessage: errorSave },\n ),\n ),\n context: mutationContext,\n mutationPayload: { action: 'update', id: target.id, kind, ...body },\n })\n flash(successSave, 'success')\n }\n closeDialog()\n await loadEntries()\n } catch (err) {\n logger.error('customers.dictionaries.submit failed', { err })\n throw err instanceof Error ? err : new Error(errorSave)\n } finally {\n setSubmitting(false)\n }\n }, [closeDialog, dialog, errorSave, inheritedActionBlocked, kind, loadEntries, mutationContext, runMutation, successSave])\n\n const currentValues = React.useMemo<DictionaryFormValues>(() => {\n if (dialog && dialog.mode === 'edit') {\n return {\n value: dialog.entry.value,\n label: dialog.entry.label,\n color: dialog.entry.color,\n icon: dialog.entry.icon,\n }\n }\n return DEFAULT_FORM_VALUES\n }, [dialog])\n\n const tableTranslations = React.useMemo(() => ({\n title,\n valueColumn: t('customers.config.dictionaries.columns.value', 'Value'),\n labelColumn: t('customers.config.dictionaries.columns.label', 'Label'),\n appearanceColumn: t('customers.config.dictionaries.columns.appearance', 'Appearance'),\n addLabel: t('customers.config.dictionaries.actions.add', 'Add entry'),\n editLabel: t('customers.config.dictionaries.actions.edit', 'Edit'),\n deleteLabel: t('customers.config.dictionaries.actions.delete', 'Delete'),\n refreshLabel: t('customers.config.dictionaries.actions.refresh', 'Refresh'),\n inheritedLabel,\n inheritedTooltip,\n emptyLabel: t('customers.config.dictionaries.empty', 'No entries yet.'),\n usageCountLabel: kind === 'person-company-roles' ? usageCountLabel : undefined,\n searchPlaceholder,\n }), [inheritedLabel, inheritedTooltip, kind, searchPlaceholder, t, title, usageCountLabel])\n\n const formTranslations = React.useMemo(() => ({\n title: dialog?.mode === 'edit'\n ? t('customers.config.dictionaries.dialog.editTitle', 'Edit entry')\n : t('customers.config.dictionaries.dialog.addTitle', 'Add entry'),\n valueLabel: t('customers.config.dictionaries.dialog.valueLabel', 'Value'),\n labelLabel: t('customers.config.dictionaries.dialog.labelLabel', 'Label'),\n saveLabel: t('customers.config.dictionaries.dialog.save', 'Save'),\n cancelLabel: t('customers.config.dictionaries.dialog.cancel', 'Cancel'),\n appearance: {\n colorLabel: t('customers.config.dictionaries.dialog.colorLabel', 'Color'),\n colorHelp: t('customers.config.dictionaries.dialog.colorHelp', 'Pick a highlight color for this entry.'),\n colorClearLabel: t('customers.config.dictionaries.dialog.colorClear', 'Remove color'),\n iconLabel: t('customers.config.dictionaries.dialog.iconLabel', 'Icon'),\n iconPlaceholder: t('customers.config.dictionaries.dialog.iconPlaceholder', 'Type an emoji or pick one of the suggestions.'),\n iconPickerTriggerLabel: t('customers.config.dictionaries.dialog.iconBrowse', 'Browse icons and emojis'),\n iconSearchPlaceholder: t('customers.config.dictionaries.dialog.iconSearchPlaceholder', 'Search icons or emojis\u2026'),\n iconSearchEmptyLabel: t('customers.config.dictionaries.dialog.iconSearchEmpty', 'No icons match your search.'),\n iconSuggestionsLabel: t('customers.config.dictionaries.dialog.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('customers.config.dictionaries.dialog.iconClear', 'Remove icon'),\n previewEmptyLabel: t('customers.config.dictionaries.appearance.empty', 'None'),\n },\n }), [dialog, t])\n\n return (\n <section\n id={getCustomerDictionarySettingsSectionId(kind)}\n className=\"scroll-mt-24 rounded border bg-card text-card-foreground shadow-sm\"\n >\n <div className=\"border-b px-6 py-4 space-y-1\">\n <h2 className=\"text-lg font-medium\">{title}</h2>\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n </div>\n <div className=\"px-2 py-4 sm:px-4\">\n <DictionaryTable\n entries={entries}\n loading={loading}\n canManage\n onCreate={handleCreate}\n onEdit={handleEdit}\n onDelete={handleDelete}\n onRefresh={loadEntries}\n translations={tableTranslations}\n />\n </div>\n <Dialog open={dialog !== null} onOpenChange={(open) => { if (!open) closeDialog() }}>\n <DialogContent className=\"max-w-lg\">\n <DialogHeader>\n <DialogTitle>{formTranslations.title}</DialogTitle>\n </DialogHeader>\n <DictionaryForm\n mode={dialog?.mode === 'edit' ? 'edit' : 'create'}\n initialValues={currentValues}\n onSubmit={submitForm}\n onCancel={closeDialog}\n submitting={submitting}\n translations={formTranslations}\n iconSuggestions={ICON_SUGGESTIONS}\n />\n </DialogContent>\n </Dialog>\n {ConfirmDialogElement}\n </section>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }