@open-mercato/core 0.6.6-develop.6515.1.01911d00e2 → 0.6.6-develop.6519.1.bdc91fb755
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/configs/lib/upgrade-actions.js +31 -1
- package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
- package/dist/modules/customers/ai-tools/activities-tasks-pack.js +11 -2
- package/dist/modules/customers/ai-tools/activities-tasks-pack.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/route.js +3 -2
- package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/context.js +4 -2
- package/dist/modules/customers/api/dictionaries/context.js.map +2 -2
- package/dist/modules/customers/api/interactions/conflicts/route.js +2 -1
- package/dist/modules/customers/api/interactions/conflicts/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/counts/route.js +7 -2
- package/dist/modules/customers/api/interactions/counts/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/route.js +3 -2
- package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
- package/dist/modules/customers/cli.js +19 -0
- package/dist/modules/customers/cli.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js +8 -3
- package/dist/modules/customers/commands/interactions.js.map +2 -2
- package/dist/modules/customers/commands/shared.js +2 -1
- package/dist/modules/customers/commands/shared.js.map +2 -2
- package/dist/modules/customers/components/DictionarySettings.js +5 -0
- package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
- package/dist/modules/customers/components/DictionarySortSettings.js +5 -0
- package/dist/modules/customers/components/DictionarySortSettings.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivitiesCard.js +3 -2
- package/dist/modules/customers/components/detail/ActivitiesCard.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivityCard.js +2 -1
- package/dist/modules/customers/components/detail/ActivityCard.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivityTimeline.js +3 -2
- package/dist/modules/customers/components/detail/ActivityTimeline.js.map +2 -2
- package/dist/modules/customers/components/detail/TaskDialog.js +3 -2
- package/dist/modules/customers/components/detail/TaskDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/TaskForm.js +170 -69
- package/dist/modules/customers/components/detail/TaskForm.js.map +2 -2
- package/dist/modules/customers/components/detail/TasksSection.js +27 -4
- package/dist/modules/customers/components/detail/TasksSection.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/usePersonTasks.js.map +2 -2
- package/dist/modules/customers/data/enrichers.js +2 -2
- package/dist/modules/customers/data/enrichers.js.map +2 -2
- package/dist/modules/customers/data/validators.js +6 -2
- package/dist/modules/customers/data/validators.js.map +2 -2
- package/dist/modules/customers/lib/dictionaries.js +2 -1
- package/dist/modules/customers/lib/dictionaries.js.map +2 -2
- package/dist/modules/customers/lib/interactionProjection.js +2 -1
- package/dist/modules/customers/lib/interactionProjection.js.map +2 -2
- package/dist/modules/customers/lib/interactionStatus.js +24 -0
- package/dist/modules/customers/lib/interactionStatus.js.map +7 -0
- package/dist/modules/customers/lib/link-channel-message-handler.js +4 -5
- package/dist/modules/customers/lib/link-channel-message-handler.js.map +2 -2
- package/dist/modules/dictionaries/components/AppearanceSelector.js +7 -3
- package/dist/modules/dictionaries/components/AppearanceSelector.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js +1 -0
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/configs/lib/upgrade-actions.ts +31 -1
- package/src/modules/customers/ai-tools/activities-tasks-pack.ts +12 -3
- package/src/modules/customers/api/companies/[id]/route.ts +3 -2
- package/src/modules/customers/api/dictionaries/context.ts +2 -0
- package/src/modules/customers/api/interactions/conflicts/route.ts +2 -1
- package/src/modules/customers/api/interactions/counts/route.ts +7 -2
- package/src/modules/customers/api/people/[id]/route.ts +3 -2
- package/src/modules/customers/cli.ts +19 -0
- package/src/modules/customers/commands/interactions.ts +8 -3
- package/src/modules/customers/commands/shared.ts +1 -0
- package/src/modules/customers/components/DictionarySettings.tsx +5 -0
- package/src/modules/customers/components/DictionarySortSettings.tsx +5 -0
- package/src/modules/customers/components/detail/ActivitiesCard.tsx +3 -2
- package/src/modules/customers/components/detail/ActivityCard.tsx +2 -1
- package/src/modules/customers/components/detail/ActivityTimeline.tsx +3 -2
- package/src/modules/customers/components/detail/TaskDialog.tsx +4 -1
- package/src/modules/customers/components/detail/TaskForm.tsx +218 -71
- package/src/modules/customers/components/detail/TasksSection.tsx +28 -2
- package/src/modules/customers/components/detail/hooks/usePersonTasks.ts +1 -0
- package/src/modules/customers/data/enrichers.ts +2 -7
- package/src/modules/customers/data/validators.ts +16 -2
- package/src/modules/customers/i18n/de.json +10 -0
- package/src/modules/customers/i18n/en.json +10 -0
- package/src/modules/customers/i18n/es.json +10 -0
- package/src/modules/customers/i18n/pl.json +10 -0
- package/src/modules/customers/lib/dictionaries.ts +1 -0
- package/src/modules/customers/lib/interactionProjection.ts +6 -2
- package/src/modules/customers/lib/interactionStatus.ts +30 -0
- package/src/modules/customers/lib/link-channel-message-handler.ts +4 -5
- package/src/modules/dictionaries/components/AppearanceSelector.tsx +10 -1
- package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +1 -0
|
@@ -836,6 +836,8 @@
|
|
|
836
836
|
"customers.config.dictionaries.sections.dealStatuses.title": "Deal statuses",
|
|
837
837
|
"customers.config.dictionaries.sections.industries.description": "Manage the industries used by companies.",
|
|
838
838
|
"customers.config.dictionaries.sections.industries.title": "Industries",
|
|
839
|
+
"customers.config.dictionaries.sections.interactionStatuses.description": "Manage the statuses available for tasks and logged interactions.",
|
|
840
|
+
"customers.config.dictionaries.sections.interactionStatuses.title": "Interaction statuses",
|
|
839
841
|
"customers.config.dictionaries.sections.jobTitles.description": "Configure job titles with their appearance.",
|
|
840
842
|
"customers.config.dictionaries.sections.jobTitles.title": "Job titles",
|
|
841
843
|
"customers.config.dictionaries.sections.lifecycle.description": "Configure lifecycle stages to track customer progress.",
|
|
@@ -861,6 +863,10 @@
|
|
|
861
863
|
"customers.config.nav.customers": "Customers",
|
|
862
864
|
"customers.config.pipelineStages.deletePipelineDesc": "This pipeline and all its stages will be permanently removed. Deals assigned to it will lose their pipeline assignment.",
|
|
863
865
|
"customers.config.pipelineStages.deleteStageDesc": "This stage will be permanently removed. Deals assigned to it will lose their stage assignment.",
|
|
866
|
+
"customers.config.upgradeActions.interactionStatuses.cta": "Seed interaction statuses",
|
|
867
|
+
"customers.config.upgradeActions.interactionStatuses.loading": "Seeding interaction statuses…",
|
|
868
|
+
"customers.config.upgradeActions.interactionStatuses.message": "Seed the interaction-statuses dictionary so CRM tasks and logged interactions can use the configurable status list.",
|
|
869
|
+
"customers.config.upgradeActions.interactionStatuses.success": "Interaction statuses are ready.",
|
|
864
870
|
"customers.countries.ca": "Canada",
|
|
865
871
|
"customers.countries.de": "Germany",
|
|
866
872
|
"customers.countries.es": "Spain",
|
|
@@ -1609,7 +1615,9 @@
|
|
|
1609
1615
|
"customers.interactions.load.error": "Failed to load interactions.",
|
|
1610
1616
|
"customers.interactions.status.canceled": "Canceled",
|
|
1611
1617
|
"customers.interactions.status.done": "Done",
|
|
1618
|
+
"customers.interactions.status.in_progress": "In progress",
|
|
1612
1619
|
"customers.interactions.status.planned": "Planned",
|
|
1620
|
+
"customers.interactions.status.waiting": "Waiting / blocked",
|
|
1613
1621
|
"customers.interactions.update.error": "Failed to update interaction.",
|
|
1614
1622
|
"customers.interactions.update.success": "Interaction updated.",
|
|
1615
1623
|
"customers.linking.actions.cancel": "Cancel",
|
|
@@ -2126,6 +2134,8 @@
|
|
|
2126
2134
|
"customers.people.detail.tasks.fields.priorityPlaceholder": "0-100",
|
|
2127
2135
|
"customers.people.detail.tasks.fields.scheduledAt": "Scheduled for",
|
|
2128
2136
|
"customers.people.detail.tasks.fields.scheduledAtPlaceholder": "Choose a date and time",
|
|
2137
|
+
"customers.people.detail.tasks.fields.status": "Status",
|
|
2138
|
+
"customers.people.detail.tasks.fields.statusPlaceholder": "Select a status",
|
|
2129
2139
|
"customers.people.detail.tasks.fields.title": "Title",
|
|
2130
2140
|
"customers.people.detail.tasks.fields.titlePlaceholder": "Task title",
|
|
2131
2141
|
"customers.people.detail.tasks.form.customFields": "Task attributes",
|
|
@@ -836,6 +836,8 @@
|
|
|
836
836
|
"customers.config.dictionaries.sections.dealStatuses.title": "Estados de oportunidades",
|
|
837
837
|
"customers.config.dictionaries.sections.industries.description": "Gestiona las industrias utilizadas por las empresas.",
|
|
838
838
|
"customers.config.dictionaries.sections.industries.title": "Industrias",
|
|
839
|
+
"customers.config.dictionaries.sections.interactionStatuses.description": "Manage the statuses available for tasks and logged interactions.",
|
|
840
|
+
"customers.config.dictionaries.sections.interactionStatuses.title": "Interaction statuses",
|
|
839
841
|
"customers.config.dictionaries.sections.jobTitles.description": "Configura los cargos y su apariencia.",
|
|
840
842
|
"customers.config.dictionaries.sections.jobTitles.title": "Cargos",
|
|
841
843
|
"customers.config.dictionaries.sections.lifecycle.description": "Configura las etapas del ciclo de vida para seguir el progreso de los clientes.",
|
|
@@ -861,6 +863,10 @@
|
|
|
861
863
|
"customers.config.nav.customers": "Clientes",
|
|
862
864
|
"customers.config.pipelineStages.deletePipelineDesc": "This pipeline and all its stages will be permanently removed. Deals assigned to it will lose their pipeline assignment.",
|
|
863
865
|
"customers.config.pipelineStages.deleteStageDesc": "This stage will be permanently removed. Deals assigned to it will lose their stage assignment.",
|
|
866
|
+
"customers.config.upgradeActions.interactionStatuses.cta": "Seed interaction statuses",
|
|
867
|
+
"customers.config.upgradeActions.interactionStatuses.loading": "Seeding interaction statuses…",
|
|
868
|
+
"customers.config.upgradeActions.interactionStatuses.message": "Seed the interaction-statuses dictionary so CRM tasks and logged interactions can use the configurable status list.",
|
|
869
|
+
"customers.config.upgradeActions.interactionStatuses.success": "Interaction statuses are ready.",
|
|
864
870
|
"customers.countries.ca": "Canadá",
|
|
865
871
|
"customers.countries.de": "Alemania",
|
|
866
872
|
"customers.countries.es": "España",
|
|
@@ -1609,7 +1615,9 @@
|
|
|
1609
1615
|
"customers.interactions.load.error": "Failed to load interactions.",
|
|
1610
1616
|
"customers.interactions.status.canceled": "Canceled",
|
|
1611
1617
|
"customers.interactions.status.done": "Done",
|
|
1618
|
+
"customers.interactions.status.in_progress": "In progress",
|
|
1612
1619
|
"customers.interactions.status.planned": "Planned",
|
|
1620
|
+
"customers.interactions.status.waiting": "Waiting / blocked",
|
|
1613
1621
|
"customers.interactions.update.error": "Failed to update interaction.",
|
|
1614
1622
|
"customers.interactions.update.success": "Interaction updated.",
|
|
1615
1623
|
"customers.linking.actions.cancel": "Cancelar",
|
|
@@ -2126,6 +2134,8 @@
|
|
|
2126
2134
|
"customers.people.detail.tasks.fields.priorityPlaceholder": "0-100",
|
|
2127
2135
|
"customers.people.detail.tasks.fields.scheduledAt": "Programada para",
|
|
2128
2136
|
"customers.people.detail.tasks.fields.scheduledAtPlaceholder": "Elige una fecha y hora",
|
|
2137
|
+
"customers.people.detail.tasks.fields.status": "Status",
|
|
2138
|
+
"customers.people.detail.tasks.fields.statusPlaceholder": "Selecciona un estado",
|
|
2129
2139
|
"customers.people.detail.tasks.fields.title": "Título",
|
|
2130
2140
|
"customers.people.detail.tasks.fields.titlePlaceholder": "Título de la tarea",
|
|
2131
2141
|
"customers.people.detail.tasks.form.customFields": "Atributos de tarea",
|
|
@@ -836,6 +836,8 @@
|
|
|
836
836
|
"customers.config.dictionaries.sections.dealStatuses.title": "Statusy szans sprzedaży",
|
|
837
837
|
"customers.config.dictionaries.sections.industries.description": "Zarządzaj branżami używanymi przez firmy.",
|
|
838
838
|
"customers.config.dictionaries.sections.industries.title": "Branże",
|
|
839
|
+
"customers.config.dictionaries.sections.interactionStatuses.description": "Manage the statuses available for tasks and logged interactions.",
|
|
840
|
+
"customers.config.dictionaries.sections.interactionStatuses.title": "Interaction statuses",
|
|
839
841
|
"customers.config.dictionaries.sections.jobTitles.description": "Skonfiguruj stanowiska i ich wygląd.",
|
|
840
842
|
"customers.config.dictionaries.sections.jobTitles.title": "Stanowiska",
|
|
841
843
|
"customers.config.dictionaries.sections.lifecycle.description": "Skonfiguruj etapy cyklu życia do śledzenia postępu klientów.",
|
|
@@ -861,6 +863,10 @@
|
|
|
861
863
|
"customers.config.nav.customers": "Klienci",
|
|
862
864
|
"customers.config.pipelineStages.deletePipelineDesc": "This pipeline and all its stages will be permanently removed. Deals assigned to it will lose their pipeline assignment.",
|
|
863
865
|
"customers.config.pipelineStages.deleteStageDesc": "This stage will be permanently removed. Deals assigned to it will lose their stage assignment.",
|
|
866
|
+
"customers.config.upgradeActions.interactionStatuses.cta": "Seed interaction statuses",
|
|
867
|
+
"customers.config.upgradeActions.interactionStatuses.loading": "Seeding interaction statuses…",
|
|
868
|
+
"customers.config.upgradeActions.interactionStatuses.message": "Seed the interaction-statuses dictionary so CRM tasks and logged interactions can use the configurable status list.",
|
|
869
|
+
"customers.config.upgradeActions.interactionStatuses.success": "Interaction statuses are ready.",
|
|
864
870
|
"customers.countries.ca": "Kanada",
|
|
865
871
|
"customers.countries.de": "Niemcy",
|
|
866
872
|
"customers.countries.es": "Hiszpania",
|
|
@@ -1609,7 +1615,9 @@
|
|
|
1609
1615
|
"customers.interactions.load.error": "Failed to load interactions.",
|
|
1610
1616
|
"customers.interactions.status.canceled": "Canceled",
|
|
1611
1617
|
"customers.interactions.status.done": "Done",
|
|
1618
|
+
"customers.interactions.status.in_progress": "In progress",
|
|
1612
1619
|
"customers.interactions.status.planned": "Planned",
|
|
1620
|
+
"customers.interactions.status.waiting": "Waiting / blocked",
|
|
1613
1621
|
"customers.interactions.update.error": "Failed to update interaction.",
|
|
1614
1622
|
"customers.interactions.update.success": "Interaction updated.",
|
|
1615
1623
|
"customers.linking.actions.cancel": "Anuluj",
|
|
@@ -2126,6 +2134,8 @@
|
|
|
2126
2134
|
"customers.people.detail.tasks.fields.priorityPlaceholder": "0-100",
|
|
2127
2135
|
"customers.people.detail.tasks.fields.scheduledAt": "Zaplanowano na",
|
|
2128
2136
|
"customers.people.detail.tasks.fields.scheduledAtPlaceholder": "Wybierz datę i godzinę",
|
|
2137
|
+
"customers.people.detail.tasks.fields.status": "Status",
|
|
2138
|
+
"customers.people.detail.tasks.fields.statusPlaceholder": "Wybierz status",
|
|
2129
2139
|
"customers.people.detail.tasks.fields.title": "Tytuł",
|
|
2130
2140
|
"customers.people.detail.tasks.fields.titlePlaceholder": "Tytuł zadania",
|
|
2131
2141
|
"customers.people.detail.tasks.form.customFields": "Atrybuty zadania",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
2
|
import { sql } from 'kysely'
|
|
3
|
+
import { TERMINAL_INTERACTION_STATUS_LIST } from './interactionStatus'
|
|
3
4
|
|
|
4
5
|
export type NextInteractionProjectionResult = {
|
|
5
6
|
nextInteractionId: string | null
|
|
@@ -9,7 +10,10 @@ export type NextInteractionProjectionResult = {
|
|
|
9
10
|
* Recomputes the next-interaction projection fields on a CustomerEntity.
|
|
10
11
|
*
|
|
11
12
|
* Algorithm:
|
|
12
|
-
* 1. Find all interactions for entityId
|
|
13
|
+
* 1. Find all OPEN interactions for entityId (status NOT IN terminal — see lib/interactionStatus.ts),
|
|
14
|
+
* scheduled_at IS NOT NULL, deleted_at IS NULL. A scheduled task that moves planned -> in_progress
|
|
15
|
+
* stays the next step; this projection only tracks scheduled next-steps, so undated open tasks are
|
|
16
|
+
* deliberately excluded (next_interaction_at must stay a real date for grid sort / search index).
|
|
13
17
|
* 2. Sort by scheduled_at ASC, priority DESC NULLS LAST, created_at ASC, id ASC
|
|
14
18
|
* 3. Take the first row and project its fields onto the CustomerEntity
|
|
15
19
|
* 4. If no candidates, set all projection fields to NULL
|
|
@@ -32,7 +36,7 @@ export async function recomputeNextInteraction(
|
|
|
32
36
|
'appearance_color',
|
|
33
37
|
])
|
|
34
38
|
.where('entity_id', '=', entityId)
|
|
35
|
-
.where('status', '
|
|
39
|
+
.where('status', 'not in', [...TERMINAL_INTERACTION_STATUS_LIST])
|
|
36
40
|
.where('scheduled_at', 'is not', null)
|
|
37
41
|
.where('deleted_at', 'is', null)
|
|
38
42
|
if (organizationId) {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Single source of truth for interaction (CRM task) open/terminal semantics.
|
|
2
|
+
//
|
|
3
|
+
// The editable list of statuses lives in the `interaction-statuses` dictionary and
|
|
4
|
+
// is configurable per tenant. The behaviorally-significant question — does a status
|
|
5
|
+
// mean the task is still open, or is it closed/terminal — stays in code here so every
|
|
6
|
+
// call site agrees. A status not known to code counts as OPEN (non-terminal): it shows
|
|
7
|
+
// in the open-activities badge and is never auto-treated as completed. That is the safe
|
|
8
|
+
// default and matches the deal open-activities enricher's `status NOT IN (terminal)` filter.
|
|
9
|
+
|
|
10
|
+
export const INTERACTION_STATUS_COMPLETED = 'done' as const
|
|
11
|
+
export const INTERACTION_STATUS_CANCELED = 'canceled' as const
|
|
12
|
+
export const INTERACTION_STATUS_PLANNED = 'planned' as const
|
|
13
|
+
|
|
14
|
+
// `completed` is a legacy spelling accepted defensively; `done` is the canonical
|
|
15
|
+
// terminal-success value persisted by the complete action and the email logger.
|
|
16
|
+
export const TERMINAL_INTERACTION_STATUS_LIST: readonly string[] = [
|
|
17
|
+
INTERACTION_STATUS_COMPLETED,
|
|
18
|
+
INTERACTION_STATUS_CANCELED,
|
|
19
|
+
'completed',
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
const TERMINAL_INTERACTION_STATUSES = new Set<string>(TERMINAL_INTERACTION_STATUS_LIST)
|
|
23
|
+
|
|
24
|
+
export function isTerminalInteractionStatus(value: string | null | undefined): boolean {
|
|
25
|
+
return value != null && TERMINAL_INTERACTION_STATUSES.has(value)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function isOpenInteractionStatus(value: string | null | undefined): boolean {
|
|
29
|
+
return !isTerminalInteractionStatus(value)
|
|
30
|
+
}
|
|
@@ -3,6 +3,7 @@ import { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/
|
|
|
3
3
|
import { CustomerEntity, CustomerInteraction } from '../data/entities'
|
|
4
4
|
import { findPeopleByAddresses, normalizeAddresses } from './findPeopleByAddresses'
|
|
5
5
|
import { emitCustomersEvent } from '../events'
|
|
6
|
+
import { INTERACTION_STATUS_COMPLETED } from './interactionStatus'
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Shared implementation for the link-channel-message subscribers.
|
|
@@ -481,11 +482,9 @@ async function persistInteractions(
|
|
|
481
482
|
// scheduled work. Without an explicit status the entity default
|
|
482
483
|
// ('planned') combined with a past `occurredAt` makes the activity
|
|
483
484
|
// timeline render the email as "overdue", which is the wrong UX.
|
|
484
|
-
// The canonical
|
|
485
|
-
// `
|
|
486
|
-
|
|
487
|
-
// defensively but the activity timeline `isOverdue` predicate does NOT.
|
|
488
|
-
status: 'done',
|
|
485
|
+
// The canonical terminal-success value is `INTERACTION_STATUS_COMPLETED`
|
|
486
|
+
// ('done'); see `lib/interactionStatus.ts` for the open/terminal semantics.
|
|
487
|
+
status: INTERACTION_STATUS_COMPLETED,
|
|
489
488
|
externalMessageId: data.linkId,
|
|
490
489
|
visibility: data.visibility,
|
|
491
490
|
channelProviderKey: data.channelProviderKey,
|
|
@@ -31,6 +31,11 @@ type AppearanceSelectorProps = {
|
|
|
31
31
|
iconSuggestions?: IconOption[]
|
|
32
32
|
iconLibrary?: IconOption[]
|
|
33
33
|
className?: string
|
|
34
|
+
/**
|
|
35
|
+
* Title/value shown alongside the icon and color swatch in the preview, so the entry
|
|
36
|
+
* previews the way it renders elsewhere (icon + color + label). Omit to preview appearance only.
|
|
37
|
+
*/
|
|
38
|
+
previewLabel?: string | null
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
const ICON_PICKER_LIMIT = 240
|
|
@@ -45,10 +50,13 @@ export function AppearanceSelector({
|
|
|
45
50
|
iconSuggestions = ICON_SUGGESTIONS,
|
|
46
51
|
iconLibrary,
|
|
47
52
|
className,
|
|
53
|
+
previewLabel,
|
|
48
54
|
}: AppearanceSelectorProps) {
|
|
49
55
|
const normalizedIcon = icon ?? ''
|
|
50
56
|
const normalizedColor = color ?? '#000000'
|
|
51
57
|
const hasAppearance = Boolean(icon) || Boolean(color)
|
|
58
|
+
const trimmedPreviewLabel = typeof previewLabel === 'string' ? previewLabel.trim() : ''
|
|
59
|
+
const hasPreviewContent = hasAppearance || trimmedPreviewLabel.length > 0
|
|
52
60
|
const iconOptions = React.useMemo(() => (iconLibrary && iconLibrary.length ? iconLibrary : ICON_LIBRARY), [iconLibrary])
|
|
53
61
|
const [pickerOpen, setPickerOpen] = React.useState(false)
|
|
54
62
|
const [iconSearch, setIconSearch] = React.useState('')
|
|
@@ -240,10 +248,11 @@ export function AppearanceSelector({
|
|
|
240
248
|
<div>
|
|
241
249
|
<label className="text-sm font-medium">Preview</label>
|
|
242
250
|
<div className="flex items-center gap-3 rounded border border-dashed border-border px-3 py-2">
|
|
243
|
-
{
|
|
251
|
+
{hasPreviewContent ? (
|
|
244
252
|
<>
|
|
245
253
|
{renderDictionaryIcon(icon, 'h-5 w-5')}
|
|
246
254
|
{renderDictionaryColor(color, 'h-4 w-4 rounded-full')}
|
|
255
|
+
{trimmedPreviewLabel ? <span className="text-sm">{trimmedPreviewLabel}</span> : null}
|
|
247
256
|
</>
|
|
248
257
|
) : (
|
|
249
258
|
<span className="text-sm text-muted-foreground">{labels.previewEmptyLabel}</span>
|
|
@@ -471,6 +471,7 @@ export function DictionaryEntriesEditor({ dictionaryId, dictionaryName, readOnly
|
|
|
471
471
|
<AppearanceSelector
|
|
472
472
|
icon={appearance.icon}
|
|
473
473
|
color={appearance.color}
|
|
474
|
+
previewLabel={formState.label.trim() || formState.value.trim()}
|
|
474
475
|
onIconChange={(next) => {
|
|
475
476
|
appearance.setIcon(next)
|
|
476
477
|
setFormState((prev) => ({ ...prev, icon: next }))
|