@open-mercato/core 0.6.1-develop.3256.1.fe3dec2464 → 0.6.1-develop.3276.1.1fcd145078
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/helpers/integration/authFixtures.js.map +1 -1
- package/dist/helpers/integration/authUi.js +10 -2
- package/dist/helpers/integration/authUi.js.map +2 -2
- package/dist/helpers/integration/salesUi.js +3 -1
- package/dist/helpers/integration/salesUi.js.map +2 -2
- package/dist/modules/api_docs/frontend/docs/api/Explorer.js +10 -1
- package/dist/modules/api_docs/frontend/docs/api/Explorer.js.map +2 -2
- package/dist/modules/audit_logs/lib/display-helpers.js +28 -27
- package/dist/modules/audit_logs/lib/display-helpers.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +21 -3
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/backend/users/[id]/edit/page.js +6 -1
- package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/users/create/page.js +4 -1
- package/dist/modules/auth/backend/users/create/page.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js +56 -2
- package/dist/modules/auth/backend/users/page.js.map +3 -3
- package/dist/modules/auth/commands/users.js +14 -0
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/auth/data/validators.js +8 -0
- package/dist/modules/auth/data/validators.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +1 -1
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +15 -9
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js +26 -3
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +1 -1
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/components/PipelineSettings.js +108 -99
- package/dist/modules/customers/components/PipelineSettings.js.map +2 -2
- package/dist/modules/customers/components/detail/AssignRoleDialog.js +13 -5
- package/dist/modules/customers/components/detail/AssignRoleDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/EntityTagsDialog.js +10 -2
- package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js +15 -8
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/RolesSection.js +35 -22
- package/dist/modules/customers/components/detail/RolesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/TasksSection.js +2 -2
- package/dist/modules/customers/components/detail/TasksSection.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/DateTimeFields.js +73 -64
- package/dist/modules/customers/components/detail/schedule/DateTimeFields.js.map +2 -2
- package/dist/modules/customers/components/linking/LinkEntityDialog.js +11 -2
- package/dist/modules/customers/components/linking/LinkEntityDialog.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +2 -9
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +14 -29
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionariesManager.js +10 -2
- package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/[id]/page.js +79 -95
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js +49 -70
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
- package/dist/modules/planner/components/AvailabilityRuleSetForm.js +1 -1
- package/dist/modules/planner/components/AvailabilityRuleSetForm.js.map +1 -1
- package/dist/modules/planner/components/AvailabilityRulesEditor.js +19 -19
- package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
- package/dist/modules/resources/components/ResourceCrudForm.js +1 -1
- package/dist/modules/resources/components/ResourceCrudForm.js.map +1 -1
- package/dist/modules/resources/components/ResourceTypeCrudForm.js +1 -1
- package/dist/modules/resources/components/ResourceTypeCrudForm.js.map +2 -2
- package/dist/modules/sales/components/documents/ReturnDialog.js +11 -8
- package/dist/modules/sales/components/documents/ReturnDialog.js.map +2 -2
- package/dist/modules/staff/backend/staff/profile/create/page.js +1 -1
- package/dist/modules/staff/backend/staff/profile/create/page.js.map +2 -2
- package/dist/modules/staff/components/TeamForm.js +1 -1
- package/dist/modules/staff/components/TeamForm.js.map +2 -2
- package/dist/modules/staff/components/TeamMemberForm.js +1 -1
- package/dist/modules/staff/components/TeamMemberForm.js.map +1 -1
- package/dist/modules/staff/components/TeamRoleForm.js +1 -1
- package/dist/modules/staff/components/TeamRoleForm.js.map +2 -2
- package/package.json +5 -5
- package/src/helpers/integration/authFixtures.ts +1 -1
- package/src/helpers/integration/authUi.ts +11 -2
- package/src/helpers/integration/salesUi.ts +10 -1
- package/src/modules/api_docs/frontend/docs/api/Explorer.tsx +7 -3
- package/src/modules/audit_logs/lib/display-helpers.tsx +22 -14
- package/src/modules/auth/api/users/route.ts +22 -3
- package/src/modules/auth/backend/users/[id]/edit/page.tsx +9 -1
- package/src/modules/auth/backend/users/create/page.tsx +6 -2
- package/src/modules/auth/backend/users/page.tsx +60 -3
- package/src/modules/auth/commands/users.ts +15 -0
- package/src/modules/auth/data/validators.ts +8 -0
- package/src/modules/auth/i18n/de.json +4 -0
- package/src/modules/auth/i18n/en.json +4 -0
- package/src/modules/auth/i18n/es.json +4 -0
- package/src/modules/auth/i18n/pl.json +4 -0
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +1 -1
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +12 -13
- package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +17 -13
- package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +1 -1
- package/src/modules/customers/components/PipelineSettings.tsx +95 -95
- package/src/modules/customers/components/detail/AssignRoleDialog.tsx +7 -4
- package/src/modules/customers/components/detail/EntityTagsDialog.tsx +13 -8
- package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +16 -12
- package/src/modules/customers/components/detail/RolesSection.tsx +34 -31
- package/src/modules/customers/components/detail/TasksSection.tsx +16 -8
- package/src/modules/customers/components/detail/schedule/DateTimeFields.tsx +77 -51
- package/src/modules/customers/components/linking/LinkEntityDialog.tsx +7 -3
- package/src/modules/data_sync/backend/data-sync/page.tsx +4 -7
- package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +19 -54
- package/src/modules/dictionaries/components/DictionariesManager.tsx +7 -4
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +101 -146
- package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +60 -103
- package/src/modules/planner/components/AvailabilityRuleSetForm.tsx +1 -1
- package/src/modules/planner/components/AvailabilityRulesEditor.tsx +17 -17
- package/src/modules/resources/components/ResourceCrudForm.tsx +1 -1
- package/src/modules/resources/components/ResourceTypeCrudForm.tsx +1 -1
- package/src/modules/sales/components/documents/ReturnDialog.tsx +10 -7
- package/src/modules/sales/i18n/de.json +2 -0
- package/src/modules/sales/i18n/en.json +2 -0
- package/src/modules/sales/i18n/es.json +2 -0
- package/src/modules/sales/i18n/pl.json +2 -0
- package/src/modules/staff/backend/staff/profile/create/page.tsx +1 -1
- package/src/modules/staff/components/TeamForm.tsx +1 -1
- package/src/modules/staff/components/TeamMemberForm.tsx +1 -1
- package/src/modules/staff/components/TeamRoleForm.tsx +1 -1
|
@@ -172,6 +172,7 @@
|
|
|
172
172
|
"auth.users.form.errors.notFound": "User not found",
|
|
173
173
|
"auth.users.form.errors.widgetsAssign": "Failed to assign dashboard widgets to the new user",
|
|
174
174
|
"auth.users.form.field.email": "Email",
|
|
175
|
+
"auth.users.form.field.name": "Display name",
|
|
175
176
|
"auth.users.form.field.newPassword": "New Password",
|
|
176
177
|
"auth.users.form.field.organization": "Organization",
|
|
177
178
|
"auth.users.form.field.password": "Password",
|
|
@@ -190,8 +191,11 @@
|
|
|
190
191
|
"auth.users.form.loading": "Loading user data...",
|
|
191
192
|
"auth.users.form.title.create": "Create User",
|
|
192
193
|
"auth.users.form.title.edit": "Edit User",
|
|
194
|
+
"auth.users.list.columns.name": "Display name",
|
|
193
195
|
"auth.users.list.error.delete": "Failed to delete user",
|
|
194
196
|
"auth.users.list.error.load": "Failed to load users",
|
|
197
|
+
"auth.users.list.filters.name": "Display name",
|
|
198
|
+
"auth.users.list.filters.namePlaceholder": "Filter by display name",
|
|
195
199
|
"auth.users.widgets.errors.load": "Unable to load dashboard widgets. You can configure them later from the user page.",
|
|
196
200
|
"auth.users.widgets.loading": "Loading widgets…",
|
|
197
201
|
"auth.users.widgets.mode.hint": "New users inherit widgets from their assigned roles. Override to pick a custom set.",
|
|
@@ -172,6 +172,7 @@
|
|
|
172
172
|
"auth.users.form.errors.notFound": "Usuario no encontrado",
|
|
173
173
|
"auth.users.form.errors.widgetsAssign": "No se pudieron asignar los widgets del panel al nuevo usuario",
|
|
174
174
|
"auth.users.form.field.email": "Correo electrónico",
|
|
175
|
+
"auth.users.form.field.name": "Nombre visible",
|
|
175
176
|
"auth.users.form.field.newPassword": "Nueva contraseña",
|
|
176
177
|
"auth.users.form.field.organization": "Organización",
|
|
177
178
|
"auth.users.form.field.password": "Contraseña",
|
|
@@ -190,8 +191,11 @@
|
|
|
190
191
|
"auth.users.form.loading": "Cargando datos del usuario...",
|
|
191
192
|
"auth.users.form.title.create": "Crear usuario",
|
|
192
193
|
"auth.users.form.title.edit": "Editar usuario",
|
|
194
|
+
"auth.users.list.columns.name": "Nombre visible",
|
|
193
195
|
"auth.users.list.error.delete": "No se pudo eliminar el usuario",
|
|
194
196
|
"auth.users.list.error.load": "No se pudieron cargar los usuarios",
|
|
197
|
+
"auth.users.list.filters.name": "Nombre visible",
|
|
198
|
+
"auth.users.list.filters.namePlaceholder": "Filtrar por nombre visible",
|
|
195
199
|
"auth.users.widgets.errors.load": "No se pudieron cargar los widgets del panel. Puedes configurarlos más tarde desde la página del usuario.",
|
|
196
200
|
"auth.users.widgets.loading": "Cargando widgets…",
|
|
197
201
|
"auth.users.widgets.mode.hint": "Los nuevos usuarios heredan los widgets de las funciones asignadas. Sobrescribe para elegir un conjunto personalizado.",
|
|
@@ -172,6 +172,7 @@
|
|
|
172
172
|
"auth.users.form.errors.notFound": "Nie znaleziono użytkownika",
|
|
173
173
|
"auth.users.form.errors.widgetsAssign": "Nie udało się przypisać widżetów pulpitu do nowego użytkownika",
|
|
174
174
|
"auth.users.form.field.email": "Email",
|
|
175
|
+
"auth.users.form.field.name": "Nazwa wyświetlana",
|
|
175
176
|
"auth.users.form.field.newPassword": "Nowe hasło",
|
|
176
177
|
"auth.users.form.field.organization": "Organizacja",
|
|
177
178
|
"auth.users.form.field.password": "Hasło",
|
|
@@ -190,8 +191,11 @@
|
|
|
190
191
|
"auth.users.form.loading": "Ładowanie danych użytkownika...",
|
|
191
192
|
"auth.users.form.title.create": "Utwórz użytkownika",
|
|
192
193
|
"auth.users.form.title.edit": "Edytuj użytkownika",
|
|
194
|
+
"auth.users.list.columns.name": "Nazwa wyświetlana",
|
|
193
195
|
"auth.users.list.error.delete": "Nie udało się usunąć użytkownika",
|
|
194
196
|
"auth.users.list.error.load": "Nie udało się wczytać użytkowników",
|
|
197
|
+
"auth.users.list.filters.name": "Nazwa wyświetlana",
|
|
198
|
+
"auth.users.list.filters.namePlaceholder": "Filtruj po nazwie wyświetlanej",
|
|
195
199
|
"auth.users.widgets.errors.load": "Nie udało się załadować widżetów pulpitu. Możesz skonfigurować je później na stronie użytkownika.",
|
|
196
200
|
"auth.users.widgets.loading": "Ładowanie widżetów…",
|
|
197
201
|
"auth.users.widgets.mode.hint": "Nowi użytkownicy dziedziczą widżety z przypisanych ról. Zastąp wybór, aby wskazać własny zestaw.",
|
|
@@ -438,7 +438,7 @@ export default function CompanyDetailV2Page({ params }: { params?: { id?: string
|
|
|
438
438
|
onSubmit={handleFormSubmit}
|
|
439
439
|
onDelete={handleDelete}
|
|
440
440
|
hideFooterActions
|
|
441
|
-
collapsibleGroups={{ pageType: 'company-v2', chevronPosition: '
|
|
441
|
+
collapsibleGroups={{ pageType: 'company-v2', chevronPosition: 'right' }}
|
|
442
442
|
sortableGroups={{ pageType: 'company-v2' }}
|
|
443
443
|
onDirtyChange={setIsDirty}
|
|
444
444
|
/>
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
4
|
import Link from 'next/link'
|
|
5
|
-
import { Building2, Users } from 'lucide-react'
|
|
5
|
+
import { Building2, UserSearch, Users } from 'lucide-react'
|
|
6
|
+
import { EmptyState } from '@open-mercato/ui/primitives/empty-state'
|
|
6
7
|
import { useRouter, useSearchParams } from 'next/navigation'
|
|
7
8
|
import { Page, PageBody } from '@open-mercato/ui/backend/Page'
|
|
8
9
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
@@ -337,7 +338,7 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
|
|
|
337
338
|
showVersionHistory={false}
|
|
338
339
|
showCancelAction={false}
|
|
339
340
|
onDirtyChange={setIsDirty}
|
|
340
|
-
collapsibleGroups={{ pageType: 'deal-detail-v3', chevronPosition: '
|
|
341
|
+
collapsibleGroups={{ pageType: 'deal-detail-v3', chevronPosition: 'right' }}
|
|
341
342
|
sortableGroups={{ pageType: 'deal-detail-v3' }}
|
|
342
343
|
initialValues={{
|
|
343
344
|
...data.deal,
|
|
@@ -424,17 +425,15 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
|
|
|
424
425
|
onScheduleRequested={openSchedule}
|
|
425
426
|
/>
|
|
426
427
|
) : (
|
|
427
|
-
<
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
</div>
|
|
437
|
-
</div>
|
|
428
|
+
<EmptyState
|
|
429
|
+
size="sm"
|
|
430
|
+
icon={<UserSearch className="h-8 w-8" aria-hidden="true" />}
|
|
431
|
+
title={t('customers.deals.detail.activities.selectEntityRequiredTitle', 'Choose a person or company to continue')}
|
|
432
|
+
description={t(
|
|
433
|
+
'customers.deals.detail.activities.selectEntityRequiredDescription',
|
|
434
|
+
'Select the customer record that should receive new deal activities before logging or scheduling anything.',
|
|
435
|
+
)}
|
|
436
|
+
/>
|
|
438
437
|
)}
|
|
439
438
|
<PlannedActivitiesSection
|
|
440
439
|
activities={plannedActivities}
|
|
@@ -11,8 +11,10 @@ import {
|
|
|
11
11
|
SelectTrigger,
|
|
12
12
|
SelectValue,
|
|
13
13
|
} from '@open-mercato/ui/primitives/select'
|
|
14
|
+
import { Layers, MoveRight, Workflow } from 'lucide-react'
|
|
14
15
|
import { Spinner } from '@open-mercato/ui/primitives/spinner'
|
|
15
16
|
import { ErrorNotice } from '@open-mercato/ui/primitives/ErrorNotice'
|
|
17
|
+
import { EmptyState } from '@open-mercato/ui/primitives/empty-state'
|
|
16
18
|
import { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
17
19
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
18
20
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
@@ -528,11 +530,11 @@ export default function SalesPipelinePage(): React.ReactElement {
|
|
|
528
530
|
</div>
|
|
529
531
|
|
|
530
532
|
{!selectedPipelineId ? (
|
|
531
|
-
<
|
|
532
|
-
<
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
533
|
+
<EmptyState
|
|
534
|
+
icon={<Workflow className="h-8 w-8" aria-hidden="true" />}
|
|
535
|
+
title={translate('customers.deals.pipeline.noPipeline', 'No pipeline selected. Create a pipeline in settings.')}
|
|
536
|
+
className="h-[50vh] w-full"
|
|
537
|
+
/>
|
|
536
538
|
) : dealsQuery.isLoading ? (
|
|
537
539
|
<div className="flex h-[50vh] items-center justify-center">
|
|
538
540
|
<Spinner />
|
|
@@ -561,11 +563,11 @@ export default function SalesPipelinePage(): React.ReactElement {
|
|
|
561
563
|
|
|
562
564
|
<div className="flex flex-col gap-4 pb-6 md:flex-row md:overflow-x-auto">
|
|
563
565
|
{stages.length === 0 ? (
|
|
564
|
-
<
|
|
565
|
-
<
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
566
|
+
<EmptyState
|
|
567
|
+
icon={<Layers className="h-8 w-8" aria-hidden="true" />}
|
|
568
|
+
title={translate('customers.deals.pipeline.noStages', 'Define pipeline stages to start tracking deals.')}
|
|
569
|
+
className="h-[50vh] w-full"
|
|
570
|
+
/>
|
|
569
571
|
) : (
|
|
570
572
|
stages.map((stage) => {
|
|
571
573
|
const stageKey = stage.value ?? null
|
|
@@ -584,9 +586,11 @@ export default function SalesPipelinePage(): React.ReactElement {
|
|
|
584
586
|
{renderLaneHeader(stage, laneDeals.length)}
|
|
585
587
|
<div className="flex flex-1 flex-col gap-3 overflow-y-auto px-4 py-3">
|
|
586
588
|
{sortedLaneDeals.length === 0 ? (
|
|
587
|
-
<
|
|
588
|
-
|
|
589
|
-
|
|
589
|
+
<EmptyState
|
|
590
|
+
size="sm"
|
|
591
|
+
icon={<MoveRight className="h-6 w-6" aria-hidden="true" />}
|
|
592
|
+
title={translate('customers.deals.pipeline.emptyLane', 'No deals in this stage yet.')}
|
|
593
|
+
/>
|
|
590
594
|
) : (
|
|
591
595
|
sortedLaneDeals.map((deal) => {
|
|
592
596
|
const isDragging = draggingId === deal.id
|
|
@@ -446,7 +446,7 @@ export default function PersonDetailV2Page({ params }: { params?: { id?: string
|
|
|
446
446
|
onSubmit={handleFormSubmit}
|
|
447
447
|
onDelete={handleFormDelete}
|
|
448
448
|
hideFooterActions
|
|
449
|
-
collapsibleGroups={{ pageType: 'person-v2', chevronPosition: '
|
|
449
|
+
collapsibleGroups={{ pageType: 'person-v2', chevronPosition: 'right' }}
|
|
450
450
|
sortableGroups={{ pageType: 'person-v2' }}
|
|
451
451
|
onDirtyChange={setIsDirty}
|
|
452
452
|
/>
|
|
@@ -19,6 +19,12 @@ import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/u
|
|
|
19
19
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
20
20
|
import { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'
|
|
21
21
|
import { Spinner } from '@open-mercato/ui/primitives/spinner'
|
|
22
|
+
import {
|
|
23
|
+
Accordion,
|
|
24
|
+
AccordionContent,
|
|
25
|
+
AccordionItem,
|
|
26
|
+
AccordionTrigger,
|
|
27
|
+
} from '@open-mercato/ui/primitives/accordion'
|
|
22
28
|
import {
|
|
23
29
|
AppearanceSelector,
|
|
24
30
|
type AppearanceSelectorLabels,
|
|
@@ -207,10 +213,6 @@ export default function PipelineSettings(): React.ReactElement {
|
|
|
207
213
|
await loadPipelines()
|
|
208
214
|
}, [confirm, expandedPipelineId, loadPipelines, t])
|
|
209
215
|
|
|
210
|
-
const toggleExpand = React.useCallback((pipelineId: string) => {
|
|
211
|
-
setExpandedPipelineId((prev) => (prev === pipelineId ? null : pipelineId))
|
|
212
|
-
}, [])
|
|
213
|
-
|
|
214
216
|
const openCreateStage = React.useCallback((pipelineId: string) => {
|
|
215
217
|
setStageForm({ label: '', color: null, icon: null })
|
|
216
218
|
setStageDialog({ mode: 'create', pipelineId })
|
|
@@ -359,35 +361,107 @@ export default function PipelineSettings(): React.ReactElement {
|
|
|
359
361
|
{t('customers.pipelines.empty', 'No pipelines yet. Create one to get started.')}
|
|
360
362
|
</p>
|
|
361
363
|
) : (
|
|
362
|
-
<
|
|
364
|
+
<Accordion
|
|
365
|
+
type="single"
|
|
366
|
+
collapsible
|
|
367
|
+
value={expandedPipelineId ?? ''}
|
|
368
|
+
onValueChange={(next) => setExpandedPipelineId(next || null)}
|
|
369
|
+
className="space-y-2"
|
|
370
|
+
>
|
|
363
371
|
{pipelines.map((pipeline) => {
|
|
364
|
-
const isExpanded = expandedPipelineId === pipeline.id
|
|
365
372
|
const pipelineStages = stages[pipeline.id] ?? []
|
|
366
373
|
const isLoadingStages = loadingStages[pipeline.id] ?? false
|
|
367
374
|
|
|
368
375
|
return (
|
|
369
|
-
<
|
|
370
|
-
<
|
|
371
|
-
<
|
|
376
|
+
<AccordionItem key={pipeline.id} value={pipeline.id}>
|
|
377
|
+
<AccordionTrigger triggerIcon="chevron">
|
|
378
|
+
<span className="flex items-center gap-2">
|
|
372
379
|
<span className="text-sm font-medium">{pipeline.name}</span>
|
|
373
380
|
{pipeline.isDefault ? (
|
|
374
381
|
<span className="rounded-full bg-primary/10 px-2 py-0.5 text-xs text-primary">
|
|
375
382
|
{t('customers.pipelines.defaultBadge', 'Default')}
|
|
376
383
|
</span>
|
|
377
384
|
) : null}
|
|
385
|
+
</span>
|
|
386
|
+
</AccordionTrigger>
|
|
387
|
+
<AccordionContent>
|
|
388
|
+
<div className="mb-3 flex items-center justify-between">
|
|
389
|
+
<span className="text-xs font-medium text-muted-foreground uppercase tracking-wide">
|
|
390
|
+
{t('customers.pipelines.stages.title', 'Stages')}
|
|
391
|
+
</span>
|
|
392
|
+
<Button size="sm" variant="outline" onClick={() => openCreateStage(pipeline.id)}>
|
|
393
|
+
{t('customers.pipelines.stages.add', 'Add stage')}
|
|
394
|
+
</Button>
|
|
378
395
|
</div>
|
|
379
|
-
|
|
396
|
+
|
|
397
|
+
{isLoadingStages ? (
|
|
398
|
+
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
399
|
+
<Spinner className="h-3 w-3" />
|
|
400
|
+
{t('customers.pipelines.stages.loading', 'Loading…')}
|
|
401
|
+
</div>
|
|
402
|
+
) : pipelineStages.length === 0 ? (
|
|
403
|
+
<p className="text-sm text-muted-foreground">
|
|
404
|
+
{t('customers.pipelines.stages.empty', 'No stages yet.')}
|
|
405
|
+
</p>
|
|
406
|
+
) : (
|
|
407
|
+
<div className="divide-y divide-border rounded-md border bg-background">
|
|
408
|
+
{pipelineStages.map((stage, idx) => (
|
|
409
|
+
<div key={stage.id} className="flex items-center justify-between gap-3 px-3 py-2">
|
|
410
|
+
<div className="flex items-center gap-2">
|
|
411
|
+
<span className="w-5 text-center text-xs text-muted-foreground">{idx + 1}</span>
|
|
412
|
+
{stage.color ? renderDictionaryColor(stage.color, 'h-3 w-3 rounded-full') : null}
|
|
413
|
+
{stage.icon ? renderDictionaryIcon(stage.icon, 'h-4 w-4') : null}
|
|
414
|
+
<span className="text-sm">{stage.label}</span>
|
|
415
|
+
</div>
|
|
416
|
+
<div className="flex items-center gap-1">
|
|
417
|
+
<Button
|
|
418
|
+
variant="ghost"
|
|
419
|
+
size="icon"
|
|
420
|
+
className="h-7 w-7"
|
|
421
|
+
disabled={idx === 0}
|
|
422
|
+
onClick={() => void handleMoveStage(stage, 'up')}
|
|
423
|
+
title={t('customers.pipelines.stages.moveUp', 'Move up')}
|
|
424
|
+
>
|
|
425
|
+
↑
|
|
426
|
+
</Button>
|
|
427
|
+
<Button
|
|
428
|
+
variant="ghost"
|
|
429
|
+
size="icon"
|
|
430
|
+
className="h-7 w-7"
|
|
431
|
+
disabled={idx === pipelineStages.length - 1}
|
|
432
|
+
onClick={() => void handleMoveStage(stage, 'down')}
|
|
433
|
+
title={t('customers.pipelines.stages.moveDown', 'Move down')}
|
|
434
|
+
>
|
|
435
|
+
↓
|
|
436
|
+
</Button>
|
|
437
|
+
<Button
|
|
438
|
+
variant="ghost"
|
|
439
|
+
size="sm"
|
|
440
|
+
onClick={() => openEditStage(stage)}
|
|
441
|
+
>
|
|
442
|
+
{t('customers.pipelines.stages.edit', 'Edit')}
|
|
443
|
+
</Button>
|
|
444
|
+
<Button
|
|
445
|
+
variant="ghost"
|
|
446
|
+
size="sm"
|
|
447
|
+
className="text-destructive hover:text-destructive"
|
|
448
|
+
onClick={() => void handleDeleteStage(stage)}
|
|
449
|
+
>
|
|
450
|
+
{t('customers.pipelines.stages.delete', 'Delete')}
|
|
451
|
+
</Button>
|
|
452
|
+
</div>
|
|
453
|
+
</div>
|
|
454
|
+
))}
|
|
455
|
+
</div>
|
|
456
|
+
)}
|
|
457
|
+
|
|
458
|
+
<div className="mt-4 flex items-center justify-end gap-2 border-t pt-3">
|
|
380
459
|
<Button
|
|
381
460
|
variant="ghost"
|
|
382
461
|
size="sm"
|
|
383
|
-
onClick={() =>
|
|
462
|
+
onClick={() => openEditPipeline(pipeline)}
|
|
384
463
|
>
|
|
385
|
-
{
|
|
386
|
-
? t('customers.pipelines.actions.hideStages', 'Hide stages')
|
|
387
|
-
: t('customers.pipelines.actions.manageStages', 'Manage stages')}
|
|
388
|
-
</Button>
|
|
389
|
-
<Button variant="ghost" size="sm" onClick={() => openEditPipeline(pipeline)}>
|
|
390
|
-
{t('customers.pipelines.actions.edit', 'Edit')}
|
|
464
|
+
{t('customers.pipelines.actions.edit', 'Edit pipeline')}
|
|
391
465
|
</Button>
|
|
392
466
|
<Button
|
|
393
467
|
variant="ghost"
|
|
@@ -395,88 +469,14 @@ export default function PipelineSettings(): React.ReactElement {
|
|
|
395
469
|
className="text-destructive hover:text-destructive"
|
|
396
470
|
onClick={() => void handleDeletePipeline(pipeline)}
|
|
397
471
|
>
|
|
398
|
-
{t('customers.pipelines.actions.delete', 'Delete')}
|
|
472
|
+
{t('customers.pipelines.actions.delete', 'Delete pipeline')}
|
|
399
473
|
</Button>
|
|
400
474
|
</div>
|
|
401
|
-
</
|
|
402
|
-
|
|
403
|
-
{isExpanded ? (
|
|
404
|
-
<div className="border-t border-border bg-muted/30 px-4 py-3">
|
|
405
|
-
<div className="mb-3 flex items-center justify-between">
|
|
406
|
-
<span className="text-xs font-medium text-muted-foreground uppercase tracking-wide">
|
|
407
|
-
{t('customers.pipelines.stages.title', 'Stages')}
|
|
408
|
-
</span>
|
|
409
|
-
<Button size="sm" variant="outline" onClick={() => openCreateStage(pipeline.id)}>
|
|
410
|
-
{t('customers.pipelines.stages.add', 'Add stage')}
|
|
411
|
-
</Button>
|
|
412
|
-
</div>
|
|
413
|
-
|
|
414
|
-
{isLoadingStages ? (
|
|
415
|
-
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
416
|
-
<Spinner className="h-3 w-3" />
|
|
417
|
-
{t('customers.pipelines.stages.loading', 'Loading…')}
|
|
418
|
-
</div>
|
|
419
|
-
) : pipelineStages.length === 0 ? (
|
|
420
|
-
<p className="text-sm text-muted-foreground">
|
|
421
|
-
{t('customers.pipelines.stages.empty', 'No stages yet.')}
|
|
422
|
-
</p>
|
|
423
|
-
) : (
|
|
424
|
-
<div className="divide-y divide-border rounded-md border bg-background">
|
|
425
|
-
{pipelineStages.map((stage, idx) => (
|
|
426
|
-
<div key={stage.id} className="flex items-center justify-between gap-3 px-3 py-2">
|
|
427
|
-
<div className="flex items-center gap-2">
|
|
428
|
-
<span className="w-5 text-center text-xs text-muted-foreground">{idx + 1}</span>
|
|
429
|
-
{stage.color ? renderDictionaryColor(stage.color, 'h-3 w-3 rounded-full') : null}
|
|
430
|
-
{stage.icon ? renderDictionaryIcon(stage.icon, 'h-4 w-4') : null}
|
|
431
|
-
<span className="text-sm">{stage.label}</span>
|
|
432
|
-
</div>
|
|
433
|
-
<div className="flex items-center gap-1">
|
|
434
|
-
<Button
|
|
435
|
-
variant="ghost"
|
|
436
|
-
size="icon"
|
|
437
|
-
className="h-7 w-7"
|
|
438
|
-
disabled={idx === 0}
|
|
439
|
-
onClick={() => void handleMoveStage(stage, 'up')}
|
|
440
|
-
title={t('customers.pipelines.stages.moveUp', 'Move up')}
|
|
441
|
-
>
|
|
442
|
-
↑
|
|
443
|
-
</Button>
|
|
444
|
-
<Button
|
|
445
|
-
variant="ghost"
|
|
446
|
-
size="icon"
|
|
447
|
-
className="h-7 w-7"
|
|
448
|
-
disabled={idx === pipelineStages.length - 1}
|
|
449
|
-
onClick={() => void handleMoveStage(stage, 'down')}
|
|
450
|
-
title={t('customers.pipelines.stages.moveDown', 'Move down')}
|
|
451
|
-
>
|
|
452
|
-
↓
|
|
453
|
-
</Button>
|
|
454
|
-
<Button
|
|
455
|
-
variant="ghost"
|
|
456
|
-
size="sm"
|
|
457
|
-
onClick={() => openEditStage(stage)}
|
|
458
|
-
>
|
|
459
|
-
{t('customers.pipelines.stages.edit', 'Edit')}
|
|
460
|
-
</Button>
|
|
461
|
-
<Button
|
|
462
|
-
variant="ghost"
|
|
463
|
-
size="sm"
|
|
464
|
-
className="text-destructive hover:text-destructive"
|
|
465
|
-
onClick={() => void handleDeleteStage(stage)}
|
|
466
|
-
>
|
|
467
|
-
{t('customers.pipelines.stages.delete', 'Delete')}
|
|
468
|
-
</Button>
|
|
469
|
-
</div>
|
|
470
|
-
</div>
|
|
471
|
-
))}
|
|
472
|
-
</div>
|
|
473
|
-
)}
|
|
474
|
-
</div>
|
|
475
|
-
) : null}
|
|
476
|
-
</div>
|
|
475
|
+
</AccordionContent>
|
|
476
|
+
</AccordionItem>
|
|
477
477
|
)
|
|
478
478
|
})}
|
|
479
|
-
</
|
|
479
|
+
</Accordion>
|
|
480
480
|
)}
|
|
481
481
|
|
|
482
482
|
{/* Pipeline Dialog */}
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
4
|
import Link from 'next/link'
|
|
5
|
-
import { Search, Check, Settings2 } from 'lucide-react'
|
|
5
|
+
import { Search, Check, CheckCheck, Settings2 } from 'lucide-react'
|
|
6
|
+
import { EmptyState } from '@open-mercato/ui/primitives/empty-state'
|
|
6
7
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
7
8
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
8
9
|
import { Badge } from '@open-mercato/ui/primitives/badge'
|
|
@@ -419,12 +420,14 @@ export function AssignRoleDialog({
|
|
|
419
420
|
</div>
|
|
420
421
|
|
|
421
422
|
{!availableRoleTypes.length ? (
|
|
422
|
-
<
|
|
423
|
-
|
|
423
|
+
<EmptyState
|
|
424
|
+
size="sm"
|
|
425
|
+
icon={<CheckCheck className="h-8 w-8" aria-hidden="true" />}
|
|
426
|
+
title={t(
|
|
424
427
|
'customers.roles.dialog.noAvailableRoles',
|
|
425
428
|
'All available role types are already assigned.',
|
|
426
429
|
)}
|
|
427
|
-
|
|
430
|
+
/>
|
|
428
431
|
) : null}
|
|
429
432
|
</div>
|
|
430
433
|
) : null}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
|
-
import { Check, Plus, Search, SlidersHorizontal, Tag, X } from 'lucide-react'
|
|
4
|
+
import { Check, Plus, Search, SearchX, SlidersHorizontal, Tag, X } from 'lucide-react'
|
|
5
|
+
import { EmptyState } from '@open-mercato/ui/primitives/empty-state'
|
|
5
6
|
import { VisuallyHidden } from '@radix-ui/react-visually-hidden'
|
|
6
7
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
7
8
|
import { cn, slugifyTagLabel } from '@open-mercato/shared/lib/utils'
|
|
@@ -1238,13 +1239,17 @@ export function EntityTagsDialog({
|
|
|
1238
1239
|
{t('customers.personTags.loading', 'Loading...')}
|
|
1239
1240
|
</div>
|
|
1240
1241
|
) : (
|
|
1241
|
-
<
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1242
|
+
<EmptyState
|
|
1243
|
+
size="sm"
|
|
1244
|
+
icon={<SearchX className="h-8 w-8" aria-hidden="true" />}
|
|
1245
|
+
title={
|
|
1246
|
+
searchValue.trim().length > 0
|
|
1247
|
+
? t('customers.personTags.emptySearchResults', 'No options match the current search.')
|
|
1248
|
+
: activeCategory.source === 'dictionary'
|
|
1249
|
+
? t('customers.personTags.emptyDictionaryCategory', 'No options are configured for this category yet.')
|
|
1250
|
+
: t('customers.personTags.emptyCategory', 'No items have been added for this category yet.')
|
|
1251
|
+
}
|
|
1252
|
+
/>
|
|
1248
1253
|
)}
|
|
1249
1254
|
|
|
1250
1255
|
{activeCategory.supportsCreate ? (
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
|
-
import { ArrowLeft, ArrowRight, Link2 } from 'lucide-react'
|
|
4
|
+
import { ArrowLeft, ArrowRight, Building2, Link2 } from 'lucide-react'
|
|
5
|
+
import { EmptyState } from '@open-mercato/ui/primitives/empty-state'
|
|
5
6
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
6
7
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
7
8
|
import { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
@@ -437,17 +438,20 @@ export function PersonCompaniesSection({
|
|
|
437
438
|
))}
|
|
438
439
|
</div>
|
|
439
440
|
) : items.length === 0 ? (
|
|
440
|
-
<
|
|
441
|
-
{
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
441
|
+
<EmptyState
|
|
442
|
+
icon={<Building2 className="h-8 w-8" aria-hidden="true" />}
|
|
443
|
+
title={
|
|
444
|
+
search.trim().length
|
|
445
|
+
? t(
|
|
446
|
+
'customers.people.detail.companies.noSearchResults',
|
|
447
|
+
'No linked companies match your search.',
|
|
448
|
+
)
|
|
449
|
+
: t(
|
|
450
|
+
'customers.people.detail.empty.companies',
|
|
451
|
+
'No company linked to this person.',
|
|
452
|
+
)
|
|
453
|
+
}
|
|
454
|
+
/>
|
|
451
455
|
) : (
|
|
452
456
|
<>
|
|
453
457
|
<div className="space-y-4">
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
4
|
import Link from 'next/link'
|
|
5
|
-
import { Plus } from 'lucide-react'
|
|
5
|
+
import { Plus, Settings, UserCheck } from 'lucide-react'
|
|
6
|
+
import { EmptyState } from '@open-mercato/ui/primitives/empty-state'
|
|
6
7
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
7
8
|
import { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
8
9
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
@@ -254,37 +255,39 @@ export function RolesSection({ entityType, entityId, entityName }: RolesSectionP
|
|
|
254
255
|
)}
|
|
255
256
|
</div>
|
|
256
257
|
) : hasConfiguredRoleTypes ? (
|
|
257
|
-
<
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
258
|
+
<EmptyState
|
|
259
|
+
size="sm"
|
|
260
|
+
icon={<UserCheck className="h-8 w-8" aria-hidden="true" />}
|
|
261
|
+
title={t('customers.roles.emptyState', 'No roles assigned yet. Click below to assign a person.')}
|
|
262
|
+
actions={
|
|
263
|
+
<Button
|
|
264
|
+
type="button"
|
|
265
|
+
variant="outline"
|
|
266
|
+
size="sm"
|
|
267
|
+
onClick={() => openDialog(null)}
|
|
268
|
+
>
|
|
269
|
+
<Plus className="h-4 w-4" aria-hidden="true" />
|
|
270
|
+
{t('customers.roles.choosePerson', 'Choose person')}
|
|
271
|
+
</Button>
|
|
272
|
+
}
|
|
273
|
+
/>
|
|
271
274
|
) : (
|
|
272
|
-
<
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
</
|
|
286
|
-
|
|
287
|
-
|
|
275
|
+
<EmptyState
|
|
276
|
+
size="sm"
|
|
277
|
+
icon={<Settings className="h-8 w-8" aria-hidden="true" />}
|
|
278
|
+
title={t('customers.roles.noRoleTypesTitle', 'No role types configured')}
|
|
279
|
+
description={t(
|
|
280
|
+
'customers.roles.noRoleTypesDescription',
|
|
281
|
+
'Create role types in Customers config before assigning owners here.',
|
|
282
|
+
)}
|
|
283
|
+
actions={
|
|
284
|
+
<Button asChild type="button" variant="outline" size="sm">
|
|
285
|
+
<Link href="/backend/config/customers">
|
|
286
|
+
{t('customers.roles.configureRoleTypes', 'Configure role types')}
|
|
287
|
+
</Link>
|
|
288
|
+
</Button>
|
|
289
|
+
}
|
|
290
|
+
/>
|
|
288
291
|
)}
|
|
289
292
|
|
|
290
293
|
{hasConfiguredRoleTypes ? (
|