@open-mercato/core 0.5.1-develop.2996.ce62fd491c → 0.5.1-develop.3036.f02c281f23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/modules/auth/api/sidebar/preferences/route.js +2 -2
- package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
- package/dist/modules/auth/api/sidebar/variants/[id]/route.js +2 -2
- package/dist/modules/auth/api/sidebar/variants/[id]/route.js.map +2 -2
- package/dist/modules/auth/api/sidebar/variants/route.js +1 -1
- package/dist/modules/auth/api/sidebar/variants/route.js.map +2 -2
- package/dist/modules/auth/backend/sidebar-customization/page.meta.js +1 -0
- package/dist/modules/auth/backend/sidebar-customization/page.meta.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/route.js +30 -20
- package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/companies/route.js +12 -7
- package/dist/modules/customers/api/companies/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +12 -7
- package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +2 -2
- package/dist/modules/customers/api/people/route.js +12 -7
- package/dist/modules/customers/api/people/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +21 -0
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +27 -30
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivitiesAddNewMenu.js +56 -0
- package/dist/modules/customers/components/detail/ActivitiesAddNewMenu.js.map +7 -0
- package/dist/modules/customers/components/detail/ActivitiesCard.js +175 -0
- package/dist/modules/customers/components/detail/ActivitiesCard.js.map +7 -0
- package/dist/modules/customers/components/detail/ActivitiesDayStrip.js +324 -0
- package/dist/modules/customers/components/detail/ActivitiesDayStrip.js.map +7 -0
- package/dist/modules/customers/components/detail/ActivitiesSection.js +62 -13
- package/dist/modules/customers/components/detail/ActivitiesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivityLogTab.js +14 -23
- package/dist/modules/customers/components/detail/ActivityLogTab.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivityTimeline.js +13 -13
- package/dist/modules/customers/components/detail/ActivityTimeline.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivityTimelineFilters.js +35 -22
- package/dist/modules/customers/components/detail/ActivityTimelineFilters.js.map +2 -2
- package/dist/modules/customers/components/detail/AiActionChips.js +15 -22
- package/dist/modules/customers/components/detail/AiActionChips.js.map +2 -2
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +196 -28
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/DateTimeFields.js +2 -2
- package/dist/modules/customers/components/detail/schedule/DateTimeFields.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/FooterFields.js +14 -2
- package/dist/modules/customers/components/detail/schedule/FooterFields.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/LinkedEntitiesField.js +9 -2
- package/dist/modules/customers/components/detail/schedule/LinkedEntitiesField.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/ParticipantsField.js +9 -2
- package/dist/modules/customers/components/detail/schedule/ParticipantsField.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/fieldConfig.js +25 -4
- package/dist/modules/customers/components/detail/schedule/fieldConfig.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +20 -3
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
- package/package.json +3 -3
- package/src/modules/auth/api/sidebar/preferences/route.ts +2 -2
- package/src/modules/auth/api/sidebar/variants/[id]/route.ts +2 -2
- package/src/modules/auth/api/sidebar/variants/route.ts +1 -1
- package/src/modules/auth/backend/sidebar-customization/page.meta.ts +1 -8
- package/src/modules/customers/api/companies/[id]/route.ts +30 -20
- package/src/modules/customers/api/companies/route.ts +12 -7
- package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +12 -7
- package/src/modules/customers/api/people/route.ts +12 -7
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +22 -0
- package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +28 -21
- package/src/modules/customers/components/detail/ActivitiesAddNewMenu.tsx +67 -0
- package/src/modules/customers/components/detail/ActivitiesCard.tsx +231 -0
- package/src/modules/customers/components/detail/ActivitiesDayStrip.tsx +390 -0
- package/src/modules/customers/components/detail/ActivitiesSection.tsx +91 -40
- package/src/modules/customers/components/detail/ActivityLogTab.tsx +25 -23
- package/src/modules/customers/components/detail/ActivityTimeline.tsx +15 -19
- package/src/modules/customers/components/detail/ActivityTimelineFilters.tsx +36 -29
- package/src/modules/customers/components/detail/AiActionChips.tsx +17 -23
- package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +233 -41
- package/src/modules/customers/components/detail/schedule/DateTimeFields.tsx +6 -2
- package/src/modules/customers/components/detail/schedule/FooterFields.tsx +22 -2
- package/src/modules/customers/components/detail/schedule/LinkedEntitiesField.tsx +10 -2
- package/src/modules/customers/components/detail/schedule/ParticipantsField.tsx +10 -2
- package/src/modules/customers/components/detail/schedule/fieldConfig.ts +26 -6
- package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +32 -3
- package/src/modules/customers/i18n/de.json +69 -2
- package/src/modules/customers/i18n/en.json +69 -2
- package/src/modules/customers/i18n/es.json +69 -2
- package/src/modules/customers/i18n/pl.json +68 -1
|
@@ -1,40 +1,31 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
4
|
-
import { PlannedActivitiesSection } from "./PlannedActivitiesSection.js";
|
|
3
|
+
import { ActivitiesCard } from "./ActivitiesCard.js";
|
|
5
4
|
import { ActivityHistorySection } from "./ActivityHistorySection.js";
|
|
6
5
|
function ActivityLogTab({
|
|
7
6
|
entityId,
|
|
8
7
|
plannedActivities,
|
|
9
|
-
onActivityCreated,
|
|
10
8
|
onScheduleRequested,
|
|
11
|
-
|
|
9
|
+
onAddActivity,
|
|
12
10
|
onEditActivity,
|
|
13
|
-
onCancelActivity,
|
|
14
|
-
runGuardedMutation,
|
|
15
11
|
refreshKey = 0,
|
|
16
|
-
useCanonicalInteractions = false
|
|
12
|
+
useCanonicalInteractions = false,
|
|
13
|
+
entityCompanyName
|
|
17
14
|
}) {
|
|
15
|
+
const handleAddNew = (kind) => {
|
|
16
|
+
if (onAddActivity) onAddActivity(kind);
|
|
17
|
+
else onScheduleRequested();
|
|
18
|
+
};
|
|
18
19
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
19
20
|
/* @__PURE__ */ jsx(
|
|
20
|
-
|
|
21
|
+
ActivitiesCard,
|
|
21
22
|
{
|
|
22
|
-
entityType: "company",
|
|
23
23
|
entityId,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
),
|
|
30
|
-
/* @__PURE__ */ jsx(
|
|
31
|
-
PlannedActivitiesSection,
|
|
32
|
-
{
|
|
33
|
-
activities: plannedActivities,
|
|
34
|
-
onComplete: onMarkDone,
|
|
35
|
-
onSchedule: onScheduleRequested,
|
|
36
|
-
onEdit: onEditActivity,
|
|
37
|
-
onCancel: onCancelActivity
|
|
24
|
+
plannedActivities,
|
|
25
|
+
refreshKey,
|
|
26
|
+
onAddNew: handleAddNew,
|
|
27
|
+
onEditActivity,
|
|
28
|
+
entityCompanyName
|
|
38
29
|
}
|
|
39
30
|
),
|
|
40
31
|
/* @__PURE__ */ jsx(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/components/detail/ActivityLogTab.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport {
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport { ActivitiesCard } from './ActivitiesCard'\nimport type { ActivityKind } from './ActivitiesAddNewMenu'\nimport { ActivityHistorySection } from './ActivityHistorySection'\nimport type { InteractionSummary } from './types'\n\ntype GuardedMutationRunner = <T,>(\n operation: () => Promise<T>,\n mutationPayload?: Record<string, unknown>,\n) => Promise<T>\n\ntype ActivityLogTabProps = {\n entityId: string\n plannedActivities: InteractionSummary[]\n /** @deprecated No longer used after the ActivitiesCard refactor. Kept optional for callers; remove after one minor cycle. */\n onActivityCreated?: () => void\n onScheduleRequested: () => void\n onAddActivity?: (kind: ActivityKind) => void\n /** @deprecated No longer used after the ActivitiesCard refactor. Kept optional for callers; remove after one minor cycle. */\n onMarkDone?: (id: string) => void\n onEditActivity: (activity: InteractionSummary) => void\n /** @deprecated No longer used after the ActivitiesCard refactor. Kept optional for callers; remove after one minor cycle. */\n onCancelActivity?: (id: string) => void\n /** @deprecated No longer used after the ActivitiesCard refactor. Kept optional for callers; remove after one minor cycle. */\n runGuardedMutation?: GuardedMutationRunner\n refreshKey?: number\n useCanonicalInteractions?: boolean\n /** Optional parent-entity company name; surfaces in planned event subtitles when no deal is set. */\n entityCompanyName?: string | null\n}\n\nexport function ActivityLogTab({\n entityId,\n plannedActivities,\n onScheduleRequested,\n onAddActivity,\n onEditActivity,\n refreshKey = 0,\n useCanonicalInteractions = false,\n entityCompanyName,\n}: ActivityLogTabProps) {\n const handleAddNew = (kind: ActivityKind) => {\n if (onAddActivity) onAddActivity(kind)\n else onScheduleRequested()\n }\n\n return (\n <div className=\"space-y-4\">\n <ActivitiesCard\n entityId={entityId}\n plannedActivities={plannedActivities}\n refreshKey={refreshKey}\n onAddNew={handleAddNew}\n onEditActivity={onEditActivity}\n entityCompanyName={entityCompanyName}\n />\n\n <ActivityHistorySection\n entityId={entityId}\n useCanonicalInteractions={useCanonicalInteractions}\n refreshKey={refreshKey}\n onEditActivity={onEditActivity}\n />\n </div>\n )\n}\n\nexport default ActivityLogTab\n"],
|
|
5
|
+
"mappings": ";AAgDI,SACE,KADF;AA9CJ,SAAS,sBAAsB;AAE/B,SAAS,8BAA8B;AA4BhC,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb,2BAA2B;AAAA,EAC3B;AACF,GAAwB;AACtB,QAAM,eAAe,CAAC,SAAuB;AAC3C,QAAI,cAAe,eAAc,IAAI;AAAA,QAChC,qBAAoB;AAAA,EAC3B;AAEA,SACE,qBAAC,SAAI,WAAU,aACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA,UAAU;AAAA,QACV;AAAA,QACA;AAAA;AAAA,IACF;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;AAEA,IAAO,yBAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -52,30 +52,30 @@ function TimelineEntry({
|
|
|
52
52
|
return /* @__PURE__ */ jsx(
|
|
53
53
|
"div",
|
|
54
54
|
{
|
|
55
|
-
className: `
|
|
55
|
+
className: `py-2.5 ${withBorder ? "border-b border-border/60" : ""} ${onEdit ? "cursor-pointer hover:bg-accent/40 transition-colors" : ""}`,
|
|
56
56
|
onClick: () => onEdit?.(activity),
|
|
57
57
|
role: onEdit ? "button" : void 0,
|
|
58
58
|
tabIndex: onEdit ? 0 : void 0,
|
|
59
59
|
onKeyDown: onEdit ? (e) => {
|
|
60
60
|
if (e.key === "Enter") onEdit(activity);
|
|
61
61
|
} : void 0,
|
|
62
|
-
children: /* @__PURE__ */ jsxs("div", { className: "grid items-start gap-3", style: { gridTemplateColumns: "
|
|
63
|
-
/* @__PURE__ */ jsxs("div", { className: "shrink-0
|
|
64
|
-
/* @__PURE__ */ jsx("span", { className: "block text-
|
|
65
|
-
/* @__PURE__ */ jsx("span", { className: "block text-
|
|
62
|
+
children: /* @__PURE__ */ jsxs("div", { className: "grid items-start gap-3", style: { gridTemplateColumns: "75px 32px 1fr" }, children: [
|
|
63
|
+
/* @__PURE__ */ jsxs("div", { className: "shrink-0", children: [
|
|
64
|
+
/* @__PURE__ */ jsx("span", { className: "block text-[11px] font-semibold leading-tight text-foreground", children: formatRelativeDate(dateStr, t) }),
|
|
65
|
+
/* @__PURE__ */ jsx("span", { className: "block text-[10px] leading-tight text-muted-foreground", children: formatTime(dateStr) })
|
|
66
66
|
] }),
|
|
67
|
-
/* @__PURE__ */ jsx("div", { className: "flex size-
|
|
68
|
-
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
69
|
-
/* @__PURE__ */
|
|
67
|
+
/* @__PURE__ */ jsx("div", { className: "flex size-8 items-center justify-center rounded-md bg-muted shrink-0", children: TypeIcon ? /* @__PURE__ */ jsx(TypeIcon, { className: "size-3.5 text-muted-foreground" }) : null }),
|
|
68
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 space-y-1.5", children: [
|
|
69
|
+
/* @__PURE__ */ jsxs("span", { className: "block text-[12px] font-semibold leading-tight text-foreground", children: [
|
|
70
70
|
title,
|
|
71
71
|
duration
|
|
72
|
-
] })
|
|
73
|
-
activity.body && activity.title && /* @__PURE__ */ jsx("p", { className: "
|
|
74
|
-
activity.authorName && /* @__PURE__ */ jsxs("div", { className: "
|
|
75
|
-
/* @__PURE__ */ jsx(User, { className: "size-
|
|
72
|
+
] }),
|
|
73
|
+
activity.body && activity.title && /* @__PURE__ */ jsx("p", { className: "text-[11px] leading-snug text-muted-foreground", children: activity.body }),
|
|
74
|
+
activity.authorName && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-[10px] text-muted-foreground", children: [
|
|
75
|
+
/* @__PURE__ */ jsx(User, { className: "size-2.5 shrink-0" }),
|
|
76
76
|
/* @__PURE__ */ jsx("span", { children: t("customers.timeline.author", "by {{name}}", { name: activity.authorName }) })
|
|
77
77
|
] }),
|
|
78
|
-
/* @__PURE__ */ jsx(
|
|
78
|
+
/* @__PURE__ */ jsx(AiActionChips, { activityType: activity.interactionType })
|
|
79
79
|
] })
|
|
80
80
|
] })
|
|
81
81
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/components/detail/ActivityTimeline.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\nimport * as React from 'react'\nimport { Phone, Mail, Users, StickyNote, User } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { AiActionChips } from './AiActionChips'\nimport type { InteractionSummary } from './types'\n\nconst TYPE_ICONS: Record<string, React.ComponentType<{ className?: string }>> = {\n call: Phone,\n email: Mail,\n meeting: Users,\n note: StickyNote,\n}\n\ninterface ActivityTimelineProps {\n activities: InteractionSummary[]\n onEdit?: (activity: InteractionSummary) => void\n}\n\nexport function ActivityTimeline({ activities, onEdit }: ActivityTimelineProps) {\n const t = useT()\n\n if (activities.length === 0) {\n return (\n <div className=\"py-6 text-center text-sm text-muted-foreground\">\n {t('customers.timeline.empty', 'No activities match the current filters.')}\n </div>\n )\n }\n\n return (\n <div>\n {activities.map((activity, index) => {\n const dateStr = activity.scheduledAt ?? activity.occurredAt ?? activity.createdAt\n const activityYear = dateStr ? new Date(dateStr).getFullYear() : null\n const prevDateStr = index > 0 ? (activities[index - 1].scheduledAt ?? activities[index - 1].occurredAt ?? activities[index - 1].createdAt) : null\n const prevYear = prevDateStr ? new Date(prevDateStr).getFullYear() : null\n const showYearSeparator = activityYear !== null && prevYear !== null && activityYear !== prevYear\n\n return (\n <React.Fragment key={activity.id}>\n {showYearSeparator && (\n <div className=\"flex items-center gap-3 py-3 px-5\">\n <div className=\"h-px flex-1 bg-border\" />\n <span className=\"text-xs font-semibold text-muted-foreground\">\n {t('customers.activities.yearSeparator', '{year}', { year: activityYear })}\n </span>\n <div className=\"h-px flex-1 bg-border\" />\n </div>\n )}\n <TimelineEntry\n activity={activity}\n t={t}\n withBorder={index < activities.length - 1}\n onEdit={onEdit}\n />\n </React.Fragment>\n )\n })}\n </div>\n )\n}\n\nfunction TimelineEntry({\n activity,\n t,\n withBorder,\n onEdit,\n}: {\n activity: InteractionSummary\n t: TranslateFn\n withBorder: boolean\n onEdit?: (activity: InteractionSummary) => void\n}) {\n const dateStr = activity.scheduledAt ?? activity.occurredAt ?? activity.createdAt\n const TypeIcon = TYPE_ICONS[activity.interactionType]\n const title = activity.title ?? activity.body ?? activity.interactionType\n const duration = activity.duration ? ` (${activity.duration} min)` : ''\n\n return (\n <div\n className={`
|
|
5
|
-
"mappings": ";AAyBM,cAkBQ,YAlBR;AAxBN,YAAY,WAAW;AACvB,SAAS,OAAO,MAAM,OAAO,YAAY,YAAY;AACrD,SAAS,YAAY;AAErB,SAAS,qBAAqB;AAG9B,MAAM,aAA0E;AAAA,EAC9E,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,MAAM;AACR;AAOO,SAAS,iBAAiB,EAAE,YAAY,OAAO,GAA0B;AAC9E,QAAM,IAAI,KAAK;AAEf,MAAI,WAAW,WAAW,GAAG;AAC3B,WACE,oBAAC,SAAI,WAAU,kDACZ,YAAE,4BAA4B,0CAA0C,GAC3E;AAAA,EAEJ;AAEA,SACE,oBAAC,SACE,qBAAW,IAAI,CAAC,UAAU,UAAU;AACnC,UAAM,UAAU,SAAS,eAAe,SAAS,cAAc,SAAS;AACxE,UAAM,eAAe,UAAU,IAAI,KAAK,OAAO,EAAE,YAAY,IAAI;AACjE,UAAM,cAAc,QAAQ,IAAK,WAAW,QAAQ,CAAC,EAAE,eAAe,WAAW,QAAQ,CAAC,EAAE,cAAc,WAAW,QAAQ,CAAC,EAAE,YAAa;AAC7I,UAAM,WAAW,cAAc,IAAI,KAAK,WAAW,EAAE,YAAY,IAAI;AACrE,UAAM,oBAAoB,iBAAiB,QAAQ,aAAa,QAAQ,iBAAiB;AAEzF,WACE,qBAAC,MAAM,UAAN,EACE;AAAA,2BACC,qBAAC,SAAI,WAAU,qCACb;AAAA,4BAAC,SAAI,WAAU,yBAAwB;AAAA,QACvC,oBAAC,UAAK,WAAU,+CACb,YAAE,sCAAsC,UAAU,EAAE,MAAM,aAAa,CAAC,GAC3E;AAAA,QACA,oBAAC,SAAI,WAAU,yBAAwB;AAAA,SACzC;AAAA,MAEF;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA,YAAY,QAAQ,WAAW,SAAS;AAAA,UACxC;AAAA;AAAA,MACF;AAAA,SAfmB,SAAS,EAgB9B;AAAA,EAEJ,CAAC,GACH;AAEJ;AAEA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,UAAU,SAAS,eAAe,SAAS,cAAc,SAAS;AACxE,QAAM,WAAW,WAAW,SAAS,eAAe;AACpD,QAAM,QAAQ,SAAS,SAAS,SAAS,QAAQ,SAAS;AAC1D,QAAM,WAAW,SAAS,WAAW,KAAK,SAAS,QAAQ,UAAU;AAErE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,
|
|
4
|
+
"sourcesContent": ["'use client'\nimport * as React from 'react'\nimport { Phone, Mail, Users, StickyNote, User } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { AiActionChips } from './AiActionChips'\nimport type { InteractionSummary } from './types'\n\nconst TYPE_ICONS: Record<string, React.ComponentType<{ className?: string }>> = {\n call: Phone,\n email: Mail,\n meeting: Users,\n note: StickyNote,\n}\n\ninterface ActivityTimelineProps {\n activities: InteractionSummary[]\n onEdit?: (activity: InteractionSummary) => void\n}\n\nexport function ActivityTimeline({ activities, onEdit }: ActivityTimelineProps) {\n const t = useT()\n\n if (activities.length === 0) {\n return (\n <div className=\"py-6 text-center text-sm text-muted-foreground\">\n {t('customers.timeline.empty', 'No activities match the current filters.')}\n </div>\n )\n }\n\n return (\n <div>\n {activities.map((activity, index) => {\n const dateStr = activity.scheduledAt ?? activity.occurredAt ?? activity.createdAt\n const activityYear = dateStr ? new Date(dateStr).getFullYear() : null\n const prevDateStr = index > 0 ? (activities[index - 1].scheduledAt ?? activities[index - 1].occurredAt ?? activities[index - 1].createdAt) : null\n const prevYear = prevDateStr ? new Date(prevDateStr).getFullYear() : null\n const showYearSeparator = activityYear !== null && prevYear !== null && activityYear !== prevYear\n\n return (\n <React.Fragment key={activity.id}>\n {showYearSeparator && (\n <div className=\"flex items-center gap-3 py-3 px-5\">\n <div className=\"h-px flex-1 bg-border\" />\n <span className=\"text-xs font-semibold text-muted-foreground\">\n {t('customers.activities.yearSeparator', '{year}', { year: activityYear })}\n </span>\n <div className=\"h-px flex-1 bg-border\" />\n </div>\n )}\n <TimelineEntry\n activity={activity}\n t={t}\n withBorder={index < activities.length - 1}\n onEdit={onEdit}\n />\n </React.Fragment>\n )\n })}\n </div>\n )\n}\n\nfunction TimelineEntry({\n activity,\n t,\n withBorder,\n onEdit,\n}: {\n activity: InteractionSummary\n t: TranslateFn\n withBorder: boolean\n onEdit?: (activity: InteractionSummary) => void\n}) {\n const dateStr = activity.scheduledAt ?? activity.occurredAt ?? activity.createdAt\n const TypeIcon = TYPE_ICONS[activity.interactionType]\n const title = activity.title ?? activity.body ?? activity.interactionType\n const duration = activity.duration ? ` (${activity.duration} min)` : ''\n\n return (\n <div\n className={`py-2.5 ${withBorder ? 'border-b border-border/60' : ''} ${onEdit ? 'cursor-pointer hover:bg-accent/40 transition-colors' : ''}`}\n onClick={() => onEdit?.(activity)}\n role={onEdit ? 'button' : undefined}\n tabIndex={onEdit ? 0 : undefined}\n onKeyDown={onEdit ? (e) => { if (e.key === 'Enter') onEdit(activity) } : undefined}\n >\n <div className=\"grid items-start gap-3\" style={{ gridTemplateColumns: '75px 32px 1fr' }}>\n {/* Column 1: Date */}\n <div className=\"shrink-0\">\n <span className=\"block text-[11px] font-semibold leading-tight text-foreground\">\n {formatRelativeDate(dateStr, t)}\n </span>\n <span className=\"block text-[10px] leading-tight text-muted-foreground\">\n {formatTime(dateStr)}\n </span>\n </div>\n\n {/* Column 2: Type icon */}\n <div className=\"flex size-8 items-center justify-center rounded-md bg-muted shrink-0\">\n {TypeIcon ? <TypeIcon className=\"size-3.5 text-muted-foreground\" /> : null}\n </div>\n\n {/* Column 3: Content */}\n <div className=\"min-w-0 space-y-1.5\">\n <span className=\"block text-[12px] font-semibold leading-tight text-foreground\">\n {title}{duration}\n </span>\n\n {activity.body && activity.title && (\n <p className=\"text-[11px] leading-snug text-muted-foreground\">\n {activity.body}\n </p>\n )}\n\n {activity.authorName && (\n <div className=\"flex items-center gap-1 text-[10px] text-muted-foreground\">\n <User className=\"size-2.5 shrink-0\" />\n <span>{t('customers.timeline.author', 'by {{name}}', { name: activity.authorName })}</span>\n </div>\n )}\n\n <AiActionChips activityType={activity.interactionType} />\n </div>\n </div>\n </div>\n )\n}\n\nfunction formatRelativeDate(isoString: string, t: TranslateFn): string {\n try {\n const date = new Date(isoString)\n const now = new Date()\n // Compare calendar dates (not time-based diff) to correctly handle same-day future times\n const dateDay = new Date(date.getFullYear(), date.getMonth(), date.getDate())\n const nowDay = new Date(now.getFullYear(), now.getMonth(), now.getDate())\n const diffDays = Math.round((nowDay.getTime() - dateDay.getTime()) / (1000 * 60 * 60 * 24))\n\n if (diffDays === 0) return t('customers.timeline.date.today', 'today')\n if (diffDays === 1) return t('customers.timeline.date.yesterday', 'yesterday')\n return date.toLocaleDateString(undefined, { day: 'numeric', month: 'short' })\n } catch {\n return ''\n }\n}\n\nfunction formatTime(isoString: string): string {\n try {\n return new Date(isoString).toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' })\n } catch {\n return ''\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -5,14 +5,18 @@ import { Phone, Mail, Users, StickyNote, SlidersHorizontal } from "lucide-react"
|
|
|
5
5
|
import { cn } from "@open-mercato/shared/lib/utils";
|
|
6
6
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
7
7
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
8
|
+
import { IconButton } from "@open-mercato/ui/primitives/icon-button";
|
|
8
9
|
import { Popover, PopoverContent, PopoverTrigger } from "@open-mercato/ui/primitives/popover";
|
|
9
10
|
import { readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
|
|
10
11
|
const FILTER_TYPES = [
|
|
12
|
+
{ type: "note", icon: StickyNote },
|
|
11
13
|
{ type: "call", icon: Phone },
|
|
12
|
-
{ type: "email", icon: Mail },
|
|
13
14
|
{ type: "meeting", icon: Users },
|
|
14
|
-
{ type: "
|
|
15
|
+
{ type: "email", icon: Mail }
|
|
15
16
|
];
|
|
17
|
+
const CHIP_BASE = "inline-flex h-7 items-center gap-1.5 rounded-lg px-2.5 text-sm font-medium transition-colors";
|
|
18
|
+
const CHIP_INACTIVE = "border border-border bg-card text-muted-foreground hover:bg-accent/40";
|
|
19
|
+
const CHIP_ACTIVE = "border border-status-info-border bg-status-info-bg text-status-info-text";
|
|
16
20
|
function ActivityTimelineFilters({
|
|
17
21
|
entityId,
|
|
18
22
|
activeTypes,
|
|
@@ -25,6 +29,7 @@ function ActivityTimelineFilters({
|
|
|
25
29
|
}) {
|
|
26
30
|
const t = useT();
|
|
27
31
|
const hasActiveFilters = activeTypes.length > 0 || dateFrom || dateTo;
|
|
32
|
+
const allActive = activeTypes.length === 0;
|
|
28
33
|
const [counts, setCounts] = React.useState(null);
|
|
29
34
|
React.useEffect(() => {
|
|
30
35
|
if (!entityId) return;
|
|
@@ -49,28 +54,38 @@ function ActivityTimelineFilters({
|
|
|
49
54
|
onTypesChange([...activeTypes, type]);
|
|
50
55
|
}
|
|
51
56
|
}, [activeTypes, onTypesChange]);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
const handleSelectAll = React.useCallback(() => {
|
|
58
|
+
onTypesChange([]);
|
|
59
|
+
}, [onTypesChange]);
|
|
60
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
|
|
61
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2.5", children: [
|
|
62
|
+
/* @__PURE__ */ jsx(
|
|
63
|
+
"button",
|
|
64
|
+
{
|
|
65
|
+
type: "button",
|
|
66
|
+
onClick: handleSelectAll,
|
|
67
|
+
"aria-pressed": allActive,
|
|
68
|
+
className: cn(CHIP_BASE, allActive ? CHIP_ACTIVE : CHIP_INACTIVE),
|
|
69
|
+
children: /* @__PURE__ */ jsx("span", { children: t("customers.timeline.filter.all", "All Activities") })
|
|
70
|
+
}
|
|
71
|
+
),
|
|
55
72
|
FILTER_TYPES.map(({ type, icon: Icon }) => {
|
|
56
73
|
const isActive = activeTypes.includes(type);
|
|
57
74
|
const count = counts?.[type];
|
|
75
|
+
const hasCount = typeof count === "number" && count > 0;
|
|
58
76
|
return /* @__PURE__ */ jsxs(
|
|
59
|
-
|
|
77
|
+
"button",
|
|
60
78
|
{
|
|
61
79
|
type: "button",
|
|
62
|
-
variant: "outline",
|
|
63
|
-
size: "sm",
|
|
64
80
|
onClick: () => handleTypeToggle(type),
|
|
65
|
-
className: cn(
|
|
66
|
-
"h-7 rounded-full px-2.5 text-xs gap-1.5",
|
|
67
|
-
isActive ? "border-foreground bg-background text-foreground" : "border-border bg-background text-muted-foreground"
|
|
68
|
-
),
|
|
69
81
|
"aria-pressed": isActive,
|
|
82
|
+
className: cn(CHIP_BASE, isActive ? CHIP_ACTIVE : CHIP_INACTIVE),
|
|
70
83
|
children: [
|
|
71
|
-
/* @__PURE__ */ jsx(Icon, { className: "size-
|
|
72
|
-
/* @__PURE__ */
|
|
73
|
-
|
|
84
|
+
/* @__PURE__ */ jsx(Icon, { className: "size-[18px] shrink-0" }),
|
|
85
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
86
|
+
t(`customers.timeline.filter.${type}`, type),
|
|
87
|
+
hasCount ? ` ${count}` : ""
|
|
88
|
+
] })
|
|
74
89
|
]
|
|
75
90
|
},
|
|
76
91
|
type
|
|
@@ -78,17 +93,15 @@ function ActivityTimelineFilters({
|
|
|
78
93
|
})
|
|
79
94
|
] }),
|
|
80
95
|
/* @__PURE__ */ jsxs(Popover, { children: [
|
|
81
|
-
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */
|
|
82
|
-
|
|
96
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
97
|
+
IconButton,
|
|
83
98
|
{
|
|
84
99
|
type: "button",
|
|
85
100
|
variant: "outline",
|
|
86
101
|
size: "sm",
|
|
87
|
-
className: "
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
t("customers.people.detail.activities.moreFilters", "More")
|
|
91
|
-
]
|
|
102
|
+
className: "size-7 rounded-md text-muted-foreground",
|
|
103
|
+
"aria-label": t("customers.people.detail.activities.moreFilters", "More filters"),
|
|
104
|
+
children: /* @__PURE__ */ jsx(SlidersHorizontal, { className: "size-3.5" })
|
|
92
105
|
}
|
|
93
106
|
) }),
|
|
94
107
|
/* @__PURE__ */ jsxs(PopoverContent, { align: "end", className: "w-72 space-y-3", children: [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/components/detail/ActivityTimelineFilters.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\nimport * as React from 'react'\nimport { Phone, Mail, Users, StickyNote, SlidersHorizontal } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Popover, PopoverContent, PopoverTrigger } from '@open-mercato/ui/primitives/popover'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\n\nconst FILTER_TYPES = [\n { type: '
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["'use client'\nimport * as React from 'react'\nimport { Phone, Mail, Users, StickyNote, SlidersHorizontal } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Popover, PopoverContent, PopoverTrigger } from '@open-mercato/ui/primitives/popover'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\n\nconst FILTER_TYPES = [\n { type: 'note', icon: StickyNote },\n { type: 'call', icon: Phone },\n { type: 'meeting', icon: Users },\n { type: 'email', icon: Mail },\n] as const\n\ntype InteractionCounts = {\n call: number\n email: number\n meeting: number\n note: number\n total: number\n}\n\ninterface ActivityTimelineFiltersProps {\n entityId: string | null\n activeTypes: string[]\n dateFrom: string\n dateTo: string\n onTypesChange: (types: string[]) => void\n onDateFromChange: (value: string) => void\n onDateToChange: (value: string) => void\n onReset: () => void\n}\n\nconst CHIP_BASE = 'inline-flex h-7 items-center gap-1.5 rounded-lg px-2.5 text-sm font-medium transition-colors'\nconst CHIP_INACTIVE = 'border border-border bg-card text-muted-foreground hover:bg-accent/40'\nconst CHIP_ACTIVE = 'border border-status-info-border bg-status-info-bg text-status-info-text'\n\nexport function ActivityTimelineFilters({\n entityId,\n activeTypes,\n dateFrom,\n dateTo,\n onTypesChange,\n onDateFromChange,\n onDateToChange,\n onReset,\n}: ActivityTimelineFiltersProps) {\n const t = useT()\n const hasActiveFilters = activeTypes.length > 0 || dateFrom || dateTo\n const allActive = activeTypes.length === 0\n const [counts, setCounts] = React.useState<InteractionCounts | null>(null)\n\n React.useEffect(() => {\n if (!entityId) return\n const controller = new AbortController()\n void (async () => {\n try {\n const nextCounts = await readApiResultOrThrow<InteractionCounts>(\n `/api/customers/interactions/counts?entityId=${encodeURIComponent(entityId)}`,\n { signal: controller.signal },\n )\n setCounts(nextCounts)\n } catch {\n setCounts(null)\n }\n })()\n return () => controller.abort()\n }, [entityId])\n\n const handleTypeToggle = React.useCallback((type: string) => {\n if (activeTypes.includes(type)) {\n onTypesChange(activeTypes.filter((filterType) => filterType !== type))\n } else {\n onTypesChange([...activeTypes, type])\n }\n }, [activeTypes, onTypesChange])\n\n const handleSelectAll = React.useCallback(() => {\n onTypesChange([])\n }, [onTypesChange])\n\n return (\n <div className=\"flex flex-col gap-3 md:flex-row md:items-center md:justify-between\">\n <div className=\"flex flex-wrap items-center gap-2.5\">\n <button\n type=\"button\"\n onClick={handleSelectAll}\n aria-pressed={allActive}\n className={cn(CHIP_BASE, allActive ? CHIP_ACTIVE : CHIP_INACTIVE)}\n >\n <span>{t('customers.timeline.filter.all', 'All Activities')}</span>\n </button>\n\n {FILTER_TYPES.map(({ type, icon: Icon }) => {\n const isActive = activeTypes.includes(type)\n const count = counts?.[type as keyof InteractionCounts]\n const hasCount = typeof count === 'number' && count > 0\n return (\n <button\n key={type}\n type=\"button\"\n onClick={() => handleTypeToggle(type)}\n aria-pressed={isActive}\n className={cn(CHIP_BASE, isActive ? CHIP_ACTIVE : CHIP_INACTIVE)}\n >\n <Icon className=\"size-[18px] shrink-0\" />\n <span>\n {t(`customers.timeline.filter.${type}`, type)}\n {hasCount ? ` ${count}` : ''}\n </span>\n </button>\n )\n })}\n </div>\n\n <Popover>\n <PopoverTrigger asChild>\n <IconButton\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"size-7 rounded-md text-muted-foreground\"\n aria-label={t('customers.people.detail.activities.moreFilters', 'More filters')}\n >\n <SlidersHorizontal className=\"size-3.5\" />\n </IconButton>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-72 space-y-3\">\n <div className=\"space-y-1.5\">\n <label className=\"text-xs font-medium\">\n {t('customers.activities.filters.dateRange', 'Date range')}\n </label>\n <div className=\"flex items-center gap-2\">\n <input\n type=\"date\"\n value={dateFrom}\n onChange={(event) => onDateFromChange(event.target.value)}\n className=\"h-8 w-full rounded-md border bg-background px-2 text-xs focus:outline-none focus:ring-1 focus:ring-ring\"\n aria-label={t('customers.timeline.filter.from', 'From date')}\n />\n <span className=\"shrink-0 text-xs text-muted-foreground\">\u2014</span>\n <input\n type=\"date\"\n value={dateTo}\n onChange={(event) => onDateToChange(event.target.value)}\n className=\"h-8 w-full rounded-md border bg-background px-2 text-xs focus:outline-none focus:ring-1 focus:ring-ring\"\n aria-label={t('customers.timeline.filter.to', 'To date')}\n />\n </div>\n </div>\n\n {hasActiveFilters ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={onReset}\n className=\"h-7 w-full text-xs\"\n >\n {t('customers.activities.filters.clearAll', 'Clear filters')}\n </Button>\n ) : null}\n </PopoverContent>\n </Popover>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,34 +1,27 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import * as React from "react";
|
|
4
3
|
import { Sparkles } from "lucide-react";
|
|
5
4
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
6
|
-
import { Button } from "@open-mercato/ui/primitives/button";
|
|
7
5
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@open-mercato/ui/primitives/tooltip";
|
|
8
6
|
import { AI_TIMELINE_ACTIONS_BY_TYPE, resolveAiActions } from "./aiActionCatalog.js";
|
|
9
7
|
function AiActionChips({ activityType }) {
|
|
10
8
|
const t = useT();
|
|
11
9
|
const actions = resolveAiActions(activityType, AI_TIMELINE_ACTIONS_BY_TYPE);
|
|
12
|
-
return /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 300, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-
|
|
13
|
-
/* @__PURE__ */ jsx("span", { className: "
|
|
14
|
-
actions.map((action
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
]
|
|
28
|
-
}
|
|
29
|
-
) }),
|
|
30
|
-
/* @__PURE__ */ jsx(TooltipContent, { side: "bottom", className: "text-xs", children: t("customers.ai.comingSoon", "Coming soon") })
|
|
31
|
-
] })
|
|
10
|
+
return /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 300, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
11
|
+
/* @__PURE__ */ jsx("span", { className: "text-[9px] font-bold text-muted-foreground/70", children: t("customers.ai.prefix", "AI:") }),
|
|
12
|
+
actions.map((action) => /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
13
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
14
|
+
"button",
|
|
15
|
+
{
|
|
16
|
+
type: "button",
|
|
17
|
+
className: "inline-flex items-center gap-1 rounded-[4px] border border-dashed border-border bg-card pl-1.5 pr-[7px] py-[3px] text-[9px] font-medium text-muted-foreground/70 transition-colors hover:border-muted-foreground hover:text-foreground",
|
|
18
|
+
children: [
|
|
19
|
+
/* @__PURE__ */ jsx(Sparkles, { className: "size-2.5 shrink-0" }),
|
|
20
|
+
t(action.i18nKey, action.fallback)
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
) }),
|
|
24
|
+
/* @__PURE__ */ jsx(TooltipContent, { side: "bottom", className: "text-xs", children: t("customers.ai.comingSoon", "Coming soon") })
|
|
32
25
|
] }, action.key))
|
|
33
26
|
] }) });
|
|
34
27
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/components/detail/AiActionChips.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { Sparkles } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { Sparkles } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@open-mercato/ui/primitives/tooltip'\nimport { AI_TIMELINE_ACTIONS_BY_TYPE, resolveAiActions } from './aiActionCatalog'\n\ninterface AiActionChipsProps {\n activityType: string\n}\n\nexport function AiActionChips({ activityType }: AiActionChipsProps) {\n const t = useT()\n const actions = resolveAiActions(activityType, AI_TIMELINE_ACTIONS_BY_TYPE)\n\n return (\n <TooltipProvider delayDuration={300}>\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-[9px] font-bold text-muted-foreground/70\">\n {t('customers.ai.prefix', 'AI:')}\n </span>\n {actions.map((action) => (\n <Tooltip key={action.key}>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n className=\"inline-flex items-center gap-1 rounded-[4px] border border-dashed border-border bg-card pl-1.5 pr-[7px] py-[3px] text-[9px] font-medium text-muted-foreground/70 transition-colors hover:border-muted-foreground hover:text-foreground\"\n >\n <Sparkles className=\"size-2.5 shrink-0\" />\n {t(action.i18nKey, action.fallback)}\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" className=\"text-xs\">\n {t('customers.ai.comingSoon', 'Coming soon')}\n </TooltipContent>\n </Tooltip>\n ))}\n </div>\n </TooltipProvider>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAmBQ,cAMM,YANN;AAhBR,SAAS,gBAAgB;AACzB,SAAS,YAAY;AACrB,SAAS,SAAS,gBAAgB,iBAAiB,sBAAsB;AACzE,SAAS,6BAA6B,wBAAwB;AAMvD,SAAS,cAAc,EAAE,aAAa,GAAuB;AAClE,QAAM,IAAI,KAAK;AACf,QAAM,UAAU,iBAAiB,cAAc,2BAA2B;AAE1E,SACE,oBAAC,mBAAgB,eAAe,KAC9B,+BAAC,SAAI,WAAU,6BACb;AAAA,wBAAC,UAAK,WAAU,iDACb,YAAE,uBAAuB,KAAK,GACjC;AAAA,IACC,QAAQ,IAAI,CAAC,WACZ,qBAAC,WACC;AAAA,0BAAC,kBAAe,SAAO,MACrB;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAU;AAAA,UAEV;AAAA,gCAAC,YAAS,WAAU,qBAAoB;AAAA,YACvC,EAAE,OAAO,SAAS,OAAO,QAAQ;AAAA;AAAA;AAAA,MACpC,GACF;AAAA,MACA,oBAAC,kBAAe,MAAK,UAAS,WAAU,WACrC,YAAE,2BAA2B,aAAa,GAC7C;AAAA,SAZY,OAAO,GAarB,CACD;AAAA,KACH,GACF;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|