@open-mercato/core 0.6.4-develop.4199.1.86677441c2 → 0.6.4-develop.4217.1.c9aa050183
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/api_docs/frontend/docs/api/Explorer.js +14 -14
- package/dist/modules/api_docs/frontend/docs/api/Explorer.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentContentPreview.js +2 -2
- package/dist/modules/attachments/components/AttachmentContentPreview.js.map +2 -2
- package/dist/modules/audit_logs/backend/audit-logs/page.js +3 -3
- package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +3 -7
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivityCard.js +2 -2
- package/dist/modules/customers/components/detail/ActivityCard.js.map +2 -2
- package/dist/modules/customers/components/detail/AssignRoleDialog.js +34 -49
- package/dist/modules/customers/components/detail/AssignRoleDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/ChangelogEntryRow.js +2 -2
- package/dist/modules/customers/components/detail/ChangelogEntryRow.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyDetailHeader.js +10 -1
- package/dist/modules/customers/components/detail/CompanyDetailHeader.js.map +2 -2
- package/dist/modules/customers/components/detail/DealLinkedEntitiesTab.js +7 -51
- package/dist/modules/customers/components/detail/DealLinkedEntitiesTab.js.map +2 -2
- package/dist/modules/customers/components/detail/DetailTabsLayout.js +1 -1
- package/dist/modules/customers/components/detail/DetailTabsLayout.js.map +2 -2
- package/dist/modules/customers/components/detail/ManageTagsDialog.js +25 -33
- package/dist/modules/customers/components/detail/ManageTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonCard.js +3 -2
- package/dist/modules/customers/components/detail/PersonCard.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonDetailHeader.js +3 -2
- package/dist/modules/customers/components/detail/PersonDetailHeader.js.map +2 -2
- package/dist/modules/customers/components/detail/RoleAssignmentRow.js +4 -5
- package/dist/modules/customers/components/detail/RoleAssignmentRow.js.map +2 -2
- package/dist/modules/customers/components/detail/utils.js +0 -7
- package/dist/modules/customers/components/detail/utils.js.map +2 -2
- package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js +3 -8
- package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js.map +2 -2
- package/dist/modules/dictionaries/components/AppearanceSelector.js +3 -4
- package/dist/modules/dictionaries/components/AppearanceSelector.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/[id]/page.js +17 -17
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js +1 -1
- package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js.map +2 -2
- package/dist/modules/planner/components/AvailabilityRulesEditor.js +65 -1
- package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
- package/dist/modules/planner/lib/deleteAvailabilityRuleSet.js +20 -0
- package/dist/modules/planner/lib/deleteAvailabilityRuleSet.js.map +7 -0
- package/dist/modules/resources/backend/resources/resources/[id]/page.js +2 -2
- package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
- package/dist/modules/sales/api/quotes/accept/route.js +14 -37
- package/dist/modules/sales/api/quotes/accept/route.js.map +3 -3
- package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +1 -1
- package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +1 -1
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +6 -2
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js +3 -2
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +1 -1
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/translations/components/TranslationDrawerAction.js +27 -65
- package/dist/modules/translations/components/TranslationDrawerAction.js.map +2 -2
- package/dist/modules/translations/components/TranslationManager.js +2 -2
- package/dist/modules/translations/components/TranslationManager.js.map +2 -2
- package/dist/modules/translations/widgets/injection/translation-manager/widget.client.js +54 -92
- package/dist/modules/translations/widgets/injection/translation-manager/widget.client.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/api_docs/frontend/docs/api/Explorer.tsx +14 -14
- package/src/modules/attachments/components/AttachmentContentPreview.tsx +2 -2
- package/src/modules/audit_logs/backend/audit-logs/page.tsx +3 -3
- package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +4 -8
- package/src/modules/customers/components/detail/ActivityCard.tsx +2 -4
- package/src/modules/customers/components/detail/AssignRoleDialog.tsx +28 -55
- package/src/modules/customers/components/detail/ChangelogEntryRow.tsx +6 -4
- package/src/modules/customers/components/detail/CompanyDetailHeader.tsx +7 -3
- package/src/modules/customers/components/detail/DealLinkedEntitiesTab.tsx +11 -49
- package/src/modules/customers/components/detail/DetailTabsLayout.tsx +1 -1
- package/src/modules/customers/components/detail/ManageTagsDialog.tsx +27 -36
- package/src/modules/customers/components/detail/PersonCard.tsx +3 -4
- package/src/modules/customers/components/detail/PersonDetailHeader.tsx +3 -4
- package/src/modules/customers/components/detail/RoleAssignmentRow.tsx +4 -7
- package/src/modules/customers/components/detail/utils.ts +0 -7
- package/src/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.tsx +4 -9
- package/src/modules/dictionaries/components/AppearanceSelector.tsx +3 -4
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +21 -21
- package/src/modules/planner/backend/planner/availability-rulesets/[id]/page.tsx +1 -1
- package/src/modules/planner/components/AvailabilityRulesEditor.tsx +62 -0
- package/src/modules/planner/lib/deleteAvailabilityRuleSet.ts +35 -0
- package/src/modules/resources/backend/resources/resources/[id]/page.tsx +2 -2
- package/src/modules/sales/api/quotes/accept/route.ts +22 -38
- package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +1 -1
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +1 -1
- package/src/modules/sales/commands/documents.ts +16 -2
- package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +3 -2
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +1 -1
- package/src/modules/staff/i18n/de.json +5 -0
- package/src/modules/staff/i18n/en.json +5 -0
- package/src/modules/staff/i18n/es.json +5 -0
- package/src/modules/staff/i18n/pl.json +5 -0
- package/src/modules/translations/components/TranslationDrawerAction.tsx +31 -66
- package/src/modules/translations/components/TranslationManager.tsx +2 -2
- package/src/modules/translations/widgets/injection/translation-manager/widget.client.tsx +53 -84
|
@@ -45,6 +45,7 @@ import { ChatPaneTabs } from '@open-mercato/ui/ai/ChatPaneTabs'
|
|
|
45
45
|
import '../../../components/CatalogStatsCard'
|
|
46
46
|
import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
|
|
47
47
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
48
|
+
import { ButtonGroup } from '@open-mercato/ui/primitives/button-group'
|
|
48
49
|
import { IconButton } from '@open-mercato/ui/primitives/icon-button'
|
|
49
50
|
import {
|
|
50
51
|
Dialog,
|
|
@@ -387,7 +388,7 @@ export function MerchandisingAssistantSheet({
|
|
|
387
388
|
|
|
388
389
|
return (
|
|
389
390
|
<>
|
|
390
|
-
<
|
|
391
|
+
<ButtonGroup className={className}>
|
|
391
392
|
<Button
|
|
392
393
|
type="button"
|
|
393
394
|
variant="outline"
|
|
@@ -395,10 +396,7 @@ export function MerchandisingAssistantSheet({
|
|
|
395
396
|
data-ai-merchandising-trigger=""
|
|
396
397
|
aria-label={triggerLabel}
|
|
397
398
|
title={triggerLabel}
|
|
398
|
-
className=
|
|
399
|
-
'relative',
|
|
400
|
-
agents.length > 1 && 'rounded-r-none border-r-0',
|
|
401
|
-
)}
|
|
399
|
+
className="relative"
|
|
402
400
|
>
|
|
403
401
|
<AiIcon className="size-4" />
|
|
404
402
|
<span>{labelText}</span>
|
|
@@ -417,10 +415,8 @@ export function MerchandisingAssistantSheet({
|
|
|
417
415
|
<IconButton
|
|
418
416
|
type="button"
|
|
419
417
|
variant="outline"
|
|
420
|
-
size="lg"
|
|
421
418
|
aria-label={moreAgentsLabel}
|
|
422
419
|
title={moreAgentsLabel}
|
|
423
|
-
className="rounded-l-none"
|
|
424
420
|
data-ai-merchandising-picker=""
|
|
425
421
|
>
|
|
426
422
|
<ChevronDown className="size-4" aria-hidden />
|
|
@@ -454,7 +450,7 @@ export function MerchandisingAssistantSheet({
|
|
|
454
450
|
</PopoverContent>
|
|
455
451
|
</Popover>
|
|
456
452
|
) : null}
|
|
457
|
-
</
|
|
453
|
+
</ButtonGroup>
|
|
458
454
|
<Dialog open={open} onOpenChange={setOpen}>
|
|
459
455
|
<DialogContent
|
|
460
456
|
className={cn(
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
4
|
import { Calendar, Check, ExternalLink, ListTodo, Mail, MoreHorizontal, Phone, StickyNote, Users } from 'lucide-react'
|
|
5
|
+
import { Avatar } from '@open-mercato/ui/primitives/avatar'
|
|
5
6
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
6
7
|
import { IconButton } from '@open-mercato/ui/primitives/icon-button'
|
|
7
8
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
@@ -10,7 +11,6 @@ import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
|
10
11
|
import { cn } from '@open-mercato/shared/lib/utils'
|
|
11
12
|
import type { InteractionSummary } from './types'
|
|
12
13
|
import { ActivityAiActions } from './ActivityAiActions'
|
|
13
|
-
import { getInitials } from './utils'
|
|
14
14
|
|
|
15
15
|
type GuardedMutationRunner = <T,>(
|
|
16
16
|
operation: () => Promise<T>,
|
|
@@ -199,9 +199,7 @@ export function ActivityCard({ activity, onOpen, onChanged, runMutation }: Activ
|
|
|
199
199
|
) : null}
|
|
200
200
|
|
|
201
201
|
<div className="mt-3 flex flex-wrap items-center gap-1.5 text-xs text-muted-foreground">
|
|
202
|
-
<
|
|
203
|
-
{getInitials(actorLabel)}
|
|
204
|
-
</span>
|
|
202
|
+
<Avatar label={actorLabel} size="xs" variant="monochrome" />
|
|
205
203
|
<span className="font-medium text-foreground">{actorLabel}</span>
|
|
206
204
|
{target && direction ? (
|
|
207
205
|
<>
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
import * as React from 'react'
|
|
4
4
|
import Link from 'next/link'
|
|
5
5
|
import { Search, Check, CheckCheck, Settings2 } from 'lucide-react'
|
|
6
|
+
import { Avatar } from '@open-mercato/ui/primitives/avatar'
|
|
6
7
|
import { EmptyState } from '@open-mercato/ui/primitives/empty-state'
|
|
8
|
+
import { StepIndicator, type StepIndicatorStep } from '@open-mercato/ui/primitives/step-indicator'
|
|
7
9
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
8
10
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
9
11
|
import { Badge } from '@open-mercato/ui/primitives/badge'
|
|
@@ -18,7 +20,6 @@ import {
|
|
|
18
20
|
import type { DictionaryEntryOption } from '@open-mercato/core/modules/dictionaries/lib/clientEntries'
|
|
19
21
|
import type { RoleAssignment } from './RoleAssignmentRow'
|
|
20
22
|
import { fetchAssignableStaffMembersPage } from './assignableStaff'
|
|
21
|
-
import { getInitials } from './utils'
|
|
22
23
|
|
|
23
24
|
const MANAGE_ROLE_TYPES_HREF = '/backend/config/customers'
|
|
24
25
|
|
|
@@ -297,9 +298,11 @@ export function AssignRoleDialog({
|
|
|
297
298
|
{t('customers.roles.dialog.preview', 'Assignment preview')}
|
|
298
299
|
</p>
|
|
299
300
|
<div className="mt-3 flex items-center gap-3">
|
|
300
|
-
<
|
|
301
|
-
{
|
|
302
|
-
|
|
301
|
+
<Avatar
|
|
302
|
+
label={selectedUser.displayName}
|
|
303
|
+
size="lg"
|
|
304
|
+
className="bg-background text-foreground"
|
|
305
|
+
/>
|
|
303
306
|
<div className="min-w-0">
|
|
304
307
|
<div className="flex flex-wrap items-center gap-2 text-sm font-semibold text-foreground">
|
|
305
308
|
<span>{selectedUser.displayName}</span>
|
|
@@ -350,25 +353,26 @@ export function AssignRoleDialog({
|
|
|
350
353
|
</DialogHeader>
|
|
351
354
|
|
|
352
355
|
<div className="border-b border-border/70 px-6 py-4">
|
|
353
|
-
<
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
356
|
+
<StepIndicator
|
|
357
|
+
className="justify-center"
|
|
358
|
+
steps={[
|
|
359
|
+
{
|
|
360
|
+
id: '1',
|
|
361
|
+
label: t('customers.roles.dialog.step1', 'Role type'),
|
|
362
|
+
status: step > 1 ? 'complete' : step === 1 ? 'current' : 'pending',
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
id: '2',
|
|
366
|
+
label: t('customers.roles.dialog.step2', 'Select person'),
|
|
367
|
+
status: step > 2 ? 'complete' : step === 2 ? 'current' : 'pending',
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
id: '3',
|
|
371
|
+
label: t('customers.roles.dialog.step3', 'Confirm'),
|
|
372
|
+
status: step === 3 ? 'current' : 'pending',
|
|
373
|
+
},
|
|
374
|
+
] satisfies StepIndicatorStep[]}
|
|
375
|
+
/>
|
|
372
376
|
</div>
|
|
373
377
|
|
|
374
378
|
<div className="min-h-0 flex-1 overflow-y-auto">
|
|
@@ -550,9 +554,7 @@ export function AssignRoleDialog({
|
|
|
550
554
|
: 'border-border/70 bg-background hover:bg-accent/40'
|
|
551
555
|
}`}
|
|
552
556
|
>
|
|
553
|
-
<
|
|
554
|
-
{getInitials(user.displayName)}
|
|
555
|
-
</div>
|
|
557
|
+
<Avatar label={user.displayName} size="lg" variant="monochrome" />
|
|
556
558
|
<div className="min-w-0 flex-1">
|
|
557
559
|
<div className="flex flex-wrap items-center gap-2">
|
|
558
560
|
<span className="text-sm font-semibold text-foreground">
|
|
@@ -672,32 +674,3 @@ export function AssignRoleDialog({
|
|
|
672
674
|
)
|
|
673
675
|
}
|
|
674
676
|
|
|
675
|
-
function StepBadge({
|
|
676
|
-
step,
|
|
677
|
-
currentStep,
|
|
678
|
-
label,
|
|
679
|
-
}: {
|
|
680
|
-
step: StepId
|
|
681
|
-
currentStep: StepId
|
|
682
|
-
label: string
|
|
683
|
-
}) {
|
|
684
|
-
const isComplete = currentStep > step
|
|
685
|
-
const isCurrent = currentStep === step
|
|
686
|
-
|
|
687
|
-
return (
|
|
688
|
-
<div className="flex items-center gap-2">
|
|
689
|
-
<span
|
|
690
|
-
className={`flex size-5 items-center justify-center rounded-full border text-xs font-semibold ${
|
|
691
|
-
isComplete || isCurrent
|
|
692
|
-
? 'border-foreground bg-foreground text-background'
|
|
693
|
-
: 'border-border bg-background text-muted-foreground'
|
|
694
|
-
}`}
|
|
695
|
-
>
|
|
696
|
-
{isComplete ? <Check className="size-3" /> : step}
|
|
697
|
-
</span>
|
|
698
|
-
<span className={isCurrent ? 'font-semibold text-foreground' : 'text-muted-foreground'}>
|
|
699
|
-
{label}
|
|
700
|
-
</span>
|
|
701
|
-
</div>
|
|
702
|
-
)
|
|
703
|
-
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
|
+
import { Avatar } from '@open-mercato/ui/primitives/avatar'
|
|
4
5
|
import { Badge } from '@open-mercato/ui/primitives/badge'
|
|
5
6
|
import { Settings2, SquarePen, Plus, Trash2, UserRoundPlus, ArrowRight } from 'lucide-react'
|
|
6
7
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
7
|
-
import { getInitials } from './utils'
|
|
8
8
|
|
|
9
9
|
type ChangelogActionType = 'create' | 'edit' | 'delete' | 'assign' | 'system'
|
|
10
10
|
type ChangelogSource = 'ui' | 'api' | 'system'
|
|
@@ -84,9 +84,11 @@ export function ChangelogEntryRow({ entry }: ChangelogEntryRowProps) {
|
|
|
84
84
|
</div>
|
|
85
85
|
|
|
86
86
|
<div className="flex items-start gap-2">
|
|
87
|
-
|
|
88
|
-
{
|
|
89
|
-
|
|
87
|
+
{entry.actorUserId ? (
|
|
88
|
+
<Avatar label={actorLabel} size="sm" variant="monochrome" />
|
|
89
|
+
) : (
|
|
90
|
+
<Avatar label="" icon={<Settings2 />} size="sm" variant="monochrome" />
|
|
91
|
+
)}
|
|
90
92
|
<span className="truncate pt-1 text-sm text-foreground">{actorLabel}</span>
|
|
91
93
|
</div>
|
|
92
94
|
|
|
@@ -4,6 +4,7 @@ import * as React from 'react'
|
|
|
4
4
|
import { Phone, Mail, Trash2, Building2, Globe, Pencil, MapPin } from 'lucide-react'
|
|
5
5
|
import { useQueryClient } from '@tanstack/react-query'
|
|
6
6
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
7
|
+
import { Avatar } from '@open-mercato/ui/primitives/avatar'
|
|
7
8
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
8
9
|
import { IconButton } from '@open-mercato/ui/primitives/icon-button'
|
|
9
10
|
import { Badge } from '@open-mercato/ui/primitives/badge'
|
|
@@ -103,9 +104,12 @@ export function CompanyDetailHeader({
|
|
|
103
104
|
{/* Top row: avatar + company info + account manager + actions */}
|
|
104
105
|
<div className="flex flex-col gap-4 px-6 pt-6 pb-3 sm:flex-row sm:items-start sm:gap-5">
|
|
105
106
|
{/* Avatar */}
|
|
106
|
-
<
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
<Avatar
|
|
108
|
+
label=""
|
|
109
|
+
icon={<Building2 />}
|
|
110
|
+
size="xl"
|
|
111
|
+
variant="monochrome"
|
|
112
|
+
/>
|
|
109
113
|
|
|
110
114
|
{/* Company info */}
|
|
111
115
|
<div className="min-w-0 flex-1">
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
4
|
import Link from 'next/link'
|
|
5
|
-
import {
|
|
5
|
+
import { Link2 } from 'lucide-react'
|
|
6
6
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
7
7
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
8
8
|
import { Input } from '@open-mercato/ui/primitives/input'
|
|
9
|
+
import { Pagination } from '@open-mercato/ui/primitives/pagination'
|
|
9
10
|
import { LinkEntityDialog, type LinkEntityAdapter, type LinkEntityOption } from '../linking/LinkEntityDialog'
|
|
10
11
|
|
|
11
12
|
type LinkedEntityOption = {
|
|
@@ -54,49 +55,6 @@ function applyFilter(items: LinkedEntityOption[], query: string): LinkedEntityOp
|
|
|
54
55
|
})
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
function Pagination({
|
|
58
|
-
page,
|
|
59
|
-
totalPages,
|
|
60
|
-
onPageChange,
|
|
61
|
-
}: {
|
|
62
|
-
page: number
|
|
63
|
-
totalPages: number
|
|
64
|
-
onPageChange: (page: number) => void
|
|
65
|
-
}) {
|
|
66
|
-
if (totalPages <= 1) return null
|
|
67
|
-
return (
|
|
68
|
-
<div className="flex items-center justify-between border-t border-border/70 pt-3 text-sm text-muted-foreground">
|
|
69
|
-
<span>
|
|
70
|
-
Page {page} of {totalPages}
|
|
71
|
-
</span>
|
|
72
|
-
<div className="flex items-center gap-2">
|
|
73
|
-
<Button
|
|
74
|
-
type="button"
|
|
75
|
-
variant="outline"
|
|
76
|
-
size="sm"
|
|
77
|
-
className="h-8 rounded-lg px-3 text-xs"
|
|
78
|
-
onClick={() => onPageChange(Math.max(1, page - 1))}
|
|
79
|
-
disabled={page <= 1}
|
|
80
|
-
>
|
|
81
|
-
<ArrowLeft className="mr-1.5 size-3.5" />
|
|
82
|
-
Previous
|
|
83
|
-
</Button>
|
|
84
|
-
<Button
|
|
85
|
-
type="button"
|
|
86
|
-
variant="outline"
|
|
87
|
-
size="sm"
|
|
88
|
-
className="h-8 rounded-lg px-3 text-xs"
|
|
89
|
-
onClick={() => onPageChange(Math.min(totalPages, page + 1))}
|
|
90
|
-
disabled={page >= totalPages}
|
|
91
|
-
>
|
|
92
|
-
Next
|
|
93
|
-
<ArrowRight className="ml-1.5 size-3.5" />
|
|
94
|
-
</Button>
|
|
95
|
-
</div>
|
|
96
|
-
</div>
|
|
97
|
-
)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
58
|
export function DealLinkedEntitiesTab({
|
|
101
59
|
entityLabel,
|
|
102
60
|
entityLabelPlural,
|
|
@@ -313,11 +271,15 @@ export function DealLinkedEntitiesTab({
|
|
|
313
271
|
</div>
|
|
314
272
|
</Link>
|
|
315
273
|
))}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
274
|
+
{visibleTotalPages > 1 ? (
|
|
275
|
+
<Pagination
|
|
276
|
+
className="border-t border-border/70 pt-3"
|
|
277
|
+
page={visiblePage}
|
|
278
|
+
pageSize={PAGE_SIZE}
|
|
279
|
+
total={visibleTotalPages * PAGE_SIZE}
|
|
280
|
+
onPageChange={setPage}
|
|
281
|
+
/>
|
|
282
|
+
) : null}
|
|
321
283
|
</div>
|
|
322
284
|
) : remoteLinkedLoading ? (
|
|
323
285
|
<div className="rounded-lg border border-border bg-muted/20 px-5 py-5 text-sm text-muted-foreground">
|
|
@@ -63,7 +63,7 @@ export function DetailTabsLayout<TId extends string = string>({
|
|
|
63
63
|
className={cn(
|
|
64
64
|
'h-auto rounded-none border-b-2 px-0 py-1',
|
|
65
65
|
activeTab === tab.id
|
|
66
|
-
? 'border-
|
|
66
|
+
? 'border-accent-indigo text-foreground hover:bg-transparent'
|
|
67
67
|
: 'border-transparent text-muted-foreground hover:text-foreground hover:bg-transparent'
|
|
68
68
|
)}
|
|
69
69
|
>
|
|
@@ -42,8 +42,11 @@ import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
|
42
42
|
import { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
43
43
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
44
44
|
import { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'
|
|
45
|
+
import { Badge } from '@open-mercato/ui/primitives/badge'
|
|
45
46
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
47
|
+
import { ColorPicker } from '@open-mercato/ui/primitives/color-picker'
|
|
46
48
|
import { IconButton } from '@open-mercato/ui/primitives/icon-button'
|
|
49
|
+
import { ScrollArea } from '@open-mercato/ui/primitives/scroll-area'
|
|
47
50
|
import {
|
|
48
51
|
Dialog,
|
|
49
52
|
DialogContent,
|
|
@@ -421,23 +424,12 @@ function SortableEntryRow({
|
|
|
421
424
|
</div>
|
|
422
425
|
|
|
423
426
|
{/* Color picker */}
|
|
424
|
-
<
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
<input
|
|
431
|
-
type="color"
|
|
432
|
-
value={normalizeColor(entry.color)}
|
|
433
|
-
onChange={(e) => onColorChange(normalizeColor(e.target.value))}
|
|
434
|
-
className="absolute inset-0 size-full cursor-pointer opacity-0"
|
|
435
|
-
/>
|
|
436
|
-
</label>
|
|
437
|
-
<span className="text-xs font-medium text-muted-foreground">
|
|
438
|
-
{normalizeColor(entry.color)}
|
|
439
|
-
</span>
|
|
440
|
-
</div>
|
|
427
|
+
<ColorPicker
|
|
428
|
+
value={normalizeColor(entry.color)}
|
|
429
|
+
onChange={(next) => onColorChange(normalizeColor(next))}
|
|
430
|
+
size="sm"
|
|
431
|
+
className="shrink-0"
|
|
432
|
+
/>
|
|
441
433
|
|
|
442
434
|
{/* Delete */}
|
|
443
435
|
<IconButton
|
|
@@ -1065,12 +1057,12 @@ export function ManageTagsDialog({ open, onClose }: ManageTagsDialogProps) {
|
|
|
1065
1057
|
) : null}
|
|
1066
1058
|
|
|
1067
1059
|
{/* Tab bar */}
|
|
1068
|
-
<div className="flex shrink-0 items-
|
|
1060
|
+
<div className="flex shrink-0 items-end gap-2 border-b border-input px-4 pt-1.5">
|
|
1069
1061
|
<IconButton
|
|
1070
1062
|
type="button"
|
|
1071
1063
|
variant="ghost"
|
|
1072
1064
|
size="sm"
|
|
1073
|
-
className="size-8 shrink-0 rounded-full"
|
|
1065
|
+
className="size-8 shrink-0 self-center rounded-full"
|
|
1074
1066
|
onClick={() => scrollCategoryRail('left')}
|
|
1075
1067
|
disabled={!canScrollLeft}
|
|
1076
1068
|
aria-label={t('customers.tags.manage.scrollLeft', 'Scroll categories left')}
|
|
@@ -1079,7 +1071,7 @@ export function ManageTagsDialog({ open, onClose }: ManageTagsDialogProps) {
|
|
|
1079
1071
|
</IconButton>
|
|
1080
1072
|
<div
|
|
1081
1073
|
ref={categoryRailRef}
|
|
1082
|
-
className="min-w-0 flex-1 overflow-x-auto
|
|
1074
|
+
className="scrollbar-hide min-w-0 flex-1 overflow-x-auto"
|
|
1083
1075
|
>
|
|
1084
1076
|
<div className="flex items-end gap-0.5">
|
|
1085
1077
|
{translatedCategories.map((category) => {
|
|
@@ -1096,10 +1088,10 @@ export function ManageTagsDialog({ open, onClose }: ManageTagsDialogProps) {
|
|
|
1096
1088
|
setActiveTab(category.kind)
|
|
1097
1089
|
setSearchValue('')
|
|
1098
1090
|
}}
|
|
1099
|
-
className={`flex h-auto shrink-0 items-center gap-1.5 rounded-none border-b-2 px-2.5 py-2 hover:bg-transparent ${
|
|
1091
|
+
className={`flex h-auto shrink-0 items-center gap-1.5 rounded-none border-b-2 px-2.5 py-2 hover:bg-transparent -mb-px ${
|
|
1100
1092
|
isActive
|
|
1101
|
-
? '-
|
|
1102
|
-
: '
|
|
1093
|
+
? 'border-accent-indigo text-foreground'
|
|
1094
|
+
: 'border-transparent text-muted-foreground'
|
|
1103
1095
|
}`}
|
|
1104
1096
|
>
|
|
1105
1097
|
<Icon className="size-3.5" />
|
|
@@ -1120,7 +1112,7 @@ export function ManageTagsDialog({ open, onClose }: ManageTagsDialogProps) {
|
|
|
1120
1112
|
type="button"
|
|
1121
1113
|
variant="ghost"
|
|
1122
1114
|
size="sm"
|
|
1123
|
-
className="size-8 shrink-0 rounded-full"
|
|
1115
|
+
className="size-8 shrink-0 self-center rounded-full"
|
|
1124
1116
|
onClick={() => scrollCategoryRail('right')}
|
|
1125
1117
|
disabled={!canScrollRight}
|
|
1126
1118
|
aria-label={t('customers.tags.manage.scrollRight', 'Scroll categories right')}
|
|
@@ -1130,7 +1122,8 @@ export function ManageTagsDialog({ open, onClose }: ManageTagsDialogProps) {
|
|
|
1130
1122
|
</div>
|
|
1131
1123
|
|
|
1132
1124
|
{/* Content */}
|
|
1133
|
-
<
|
|
1125
|
+
<ScrollArea className="min-h-0 flex-1" viewportClassName="px-6 py-3.5">
|
|
1126
|
+
<div className="flex flex-col gap-3">
|
|
1134
1127
|
{activeMeta ? (
|
|
1135
1128
|
<>
|
|
1136
1129
|
{/* Category header + search */}
|
|
@@ -1141,18 +1134,15 @@ export function ManageTagsDialog({ open, onClose }: ManageTagsDialogProps) {
|
|
|
1141
1134
|
{activeMeta.shortLabel}
|
|
1142
1135
|
</span>
|
|
1143
1136
|
{(activeMeta.badges ?? []).map((badge) => (
|
|
1144
|
-
<
|
|
1137
|
+
<Badge
|
|
1145
1138
|
key={badge}
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
? 'bg-status-warning-bg text-status-warning-text'
|
|
1149
|
-
: 'bg-muted text-muted-foreground'
|
|
1150
|
-
}`}
|
|
1139
|
+
variant={badge === 'required' ? 'warning' : 'muted'}
|
|
1140
|
+
size="sm"
|
|
1151
1141
|
>
|
|
1152
1142
|
{badge === 'required'
|
|
1153
1143
|
? t('customers.tags.manage.badge.required', 'REQUIRED')
|
|
1154
1144
|
: t('customers.tags.manage.badge.system', 'SYSTEM')}
|
|
1155
|
-
</
|
|
1145
|
+
</Badge>
|
|
1156
1146
|
))}
|
|
1157
1147
|
</div>
|
|
1158
1148
|
<div className="flex items-center gap-1.5">
|
|
@@ -1178,17 +1168,17 @@ export function ManageTagsDialog({ open, onClose }: ManageTagsDialogProps) {
|
|
|
1178
1168
|
<div className="flex items-center gap-3 px-3 py-1.5">
|
|
1179
1169
|
<div className="w-[18px] shrink-0" />
|
|
1180
1170
|
<div className="min-w-0 flex-1">
|
|
1181
|
-
<span className="text-overline font-
|
|
1171
|
+
<span className="text-overline font-medium uppercase tracking-wider text-muted-foreground">
|
|
1182
1172
|
{t('customers.tags.manage.columns.label', 'LABEL')}
|
|
1183
1173
|
</span>
|
|
1184
1174
|
</div>
|
|
1185
1175
|
<div className="w-[140px] shrink-0">
|
|
1186
|
-
<span className="text-overline font-
|
|
1176
|
+
<span className="text-overline font-medium uppercase tracking-wider text-muted-foreground">
|
|
1187
1177
|
{t('customers.tags.manage.columns.slug', 'SLUG')}
|
|
1188
1178
|
</span>
|
|
1189
1179
|
</div>
|
|
1190
1180
|
<div className="w-[80px] shrink-0">
|
|
1191
|
-
<span className="text-overline font-
|
|
1181
|
+
<span className="text-overline font-medium uppercase tracking-wider text-muted-foreground">
|
|
1192
1182
|
{t('customers.tags.manage.columns.color', 'COLOR')}
|
|
1193
1183
|
</span>
|
|
1194
1184
|
</div>
|
|
@@ -1283,7 +1273,8 @@ export function ManageTagsDialog({ open, onClose }: ManageTagsDialogProps) {
|
|
|
1283
1273
|
{t('customers.tags.manage.noDictionaries', 'No tag categories found.')}
|
|
1284
1274
|
</div>
|
|
1285
1275
|
)}
|
|
1286
|
-
|
|
1276
|
+
</div>
|
|
1277
|
+
</ScrollArea>
|
|
1287
1278
|
|
|
1288
1279
|
{/* Separator */}
|
|
1289
1280
|
<div className="h-px shrink-0 bg-border" />
|
|
@@ -7,10 +7,11 @@ import { cn } from '@open-mercato/shared/lib/utils'
|
|
|
7
7
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
8
8
|
import { Badge } from '@open-mercato/ui/primitives/badge'
|
|
9
9
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
10
|
+
import { Avatar } from '@open-mercato/ui/primitives/avatar'
|
|
10
11
|
import { IconButton } from '@open-mercato/ui/primitives/icon-button'
|
|
11
12
|
import { Popover, PopoverContent, PopoverTrigger } from '@open-mercato/ui/primitives/popover'
|
|
12
13
|
import type { CompanyPersonSummary } from './CompanyPeopleSection'
|
|
13
|
-
import { formatDate, formatFallbackLabel
|
|
14
|
+
import { formatDate, formatFallbackLabel } from './utils'
|
|
14
15
|
|
|
15
16
|
const sourceColorMap: Record<string, string> = {
|
|
16
17
|
linkedin: 'border-status-info-icon text-status-info-icon',
|
|
@@ -70,9 +71,7 @@ export function PersonCard({ person, isStarred, onToggleStar, onUnlink }: Person
|
|
|
70
71
|
<div className="min-w-0 overflow-hidden rounded-lg border bg-card p-4">
|
|
71
72
|
<div className="flex items-start justify-between gap-3">
|
|
72
73
|
<div className="flex min-w-0 flex-1 items-start gap-3">
|
|
73
|
-
<
|
|
74
|
-
{getInitials(person.displayName)}
|
|
75
|
-
</div>
|
|
74
|
+
<Avatar label={person.displayName} size="lg" variant="monochrome" />
|
|
76
75
|
<div className="min-w-0 flex-1 space-y-1">
|
|
77
76
|
<div className="flex min-w-0 flex-wrap items-center gap-1.5">
|
|
78
77
|
<span className="min-w-0 break-words text-sm font-bold leading-5 text-foreground">{person.displayName}</span>
|
|
@@ -5,6 +5,7 @@ import Link from 'next/link'
|
|
|
5
5
|
import { Phone, Mail, Building2, Trash2, Pencil } from 'lucide-react'
|
|
6
6
|
import { cn } from '@open-mercato/shared/lib/utils'
|
|
7
7
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
8
|
+
import { Avatar } from '@open-mercato/ui/primitives/avatar'
|
|
8
9
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
9
10
|
import { IconButton } from '@open-mercato/ui/primitives/icon-button'
|
|
10
11
|
import { Badge } from '@open-mercato/ui/primitives/badge'
|
|
@@ -18,7 +19,7 @@ import type { TagSummary } from './types'
|
|
|
18
19
|
import type { TagsSectionController } from '@open-mercato/ui/backend/detail'
|
|
19
20
|
import type { PersonOverview } from '../formConfig'
|
|
20
21
|
import type { CustomerDictionaryMap } from '@open-mercato/core/modules/customers/lib/dictionaries'
|
|
21
|
-
import {
|
|
22
|
+
import { formatFallbackLabel } from './utils'
|
|
22
23
|
|
|
23
24
|
const HEADER_ICON_BUTTON_CLASS = 'size-8 rounded-md'
|
|
24
25
|
|
|
@@ -125,9 +126,7 @@ export function PersonDetailHeader({
|
|
|
125
126
|
<div className="rounded-lg border bg-card px-6 py-5">
|
|
126
127
|
<div className="flex flex-col gap-4 sm:flex-row sm:items-start sm:gap-5">
|
|
127
128
|
{/* Avatar */}
|
|
128
|
-
<
|
|
129
|
-
{getInitials(displayName)}
|
|
130
|
-
</div>
|
|
129
|
+
<Avatar label={displayName} size="xl" variant="monochrome" />
|
|
131
130
|
|
|
132
131
|
{/* Person info */}
|
|
133
132
|
<div className="min-w-0 flex-1">
|
|
@@ -7,11 +7,11 @@ import { apiCallOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
|
7
7
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
8
8
|
import { LookupSelect, type LookupSelectItem } from '@open-mercato/ui/backend/inputs/LookupSelect'
|
|
9
9
|
import { IconButton } from '@open-mercato/ui/primitives/icon-button'
|
|
10
|
+
import { Avatar } from '@open-mercato/ui/primitives/avatar'
|
|
10
11
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
11
12
|
import { Badge } from '@open-mercato/ui/primitives/badge'
|
|
12
13
|
import { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'
|
|
13
14
|
import { fetchAssignableStaffMembers } from './assignableStaff'
|
|
14
|
-
import { getInitials } from './utils'
|
|
15
15
|
|
|
16
16
|
export interface RoleAssignment {
|
|
17
17
|
id: string
|
|
@@ -136,9 +136,8 @@ export function RoleAssignmentRow({
|
|
|
136
136
|
[role.userEmail, role.userId, role.userName],
|
|
137
137
|
)
|
|
138
138
|
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
return getInitials(name || '?')
|
|
139
|
+
const userLabel = React.useMemo(() => {
|
|
140
|
+
return role.userName ?? role.userEmail ?? '?'
|
|
142
141
|
}, [role.userEmail, role.userName])
|
|
143
142
|
|
|
144
143
|
const displayName = role.userName ?? role.userEmail ?? role.userId
|
|
@@ -165,9 +164,7 @@ export function RoleAssignmentRow({
|
|
|
165
164
|
</div>
|
|
166
165
|
|
|
167
166
|
<div className="mt-4 flex min-w-0 flex-col gap-3 sm:flex-row sm:items-start">
|
|
168
|
-
<
|
|
169
|
-
{initials}
|
|
170
|
-
</div>
|
|
167
|
+
<Avatar label={userLabel} size="lg" variant="monochrome" />
|
|
171
168
|
<div className="min-w-0 flex-1">
|
|
172
169
|
<div className="break-all text-sm font-semibold leading-5 text-foreground">{displayName}</div>
|
|
173
170
|
{role.userEmail ? (
|
|
@@ -148,13 +148,6 @@ export function createDictionarySelectLabels(
|
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
export function getInitials(name: string): string {
|
|
152
|
-
const words = name.trim().split(/\s+/)
|
|
153
|
-
if (words.length === 0 || !words[0]) return '?'
|
|
154
|
-
if (words.length === 1) return words[0].charAt(0).toUpperCase()
|
|
155
|
-
return (words[0].charAt(0) + words[words.length - 1].charAt(0)).toUpperCase()
|
|
156
|
-
}
|
|
157
|
-
|
|
158
151
|
export function formatCurrency(amount: number, currency?: string | null): string {
|
|
159
152
|
try {
|
|
160
153
|
return new Intl.NumberFormat(undefined, {
|
|
@@ -24,6 +24,7 @@ import { useAiDock } from '@open-mercato/ui/ai/AiDock'
|
|
|
24
24
|
import { useAiChatSessions } from '@open-mercato/ui/ai/AiChatSessions'
|
|
25
25
|
import { ChatPaneTabs } from '@open-mercato/ui/ai/ChatPaneTabs'
|
|
26
26
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
27
|
+
import { ButtonGroup } from '@open-mercato/ui/primitives/button-group'
|
|
27
28
|
import { IconButton } from '@open-mercato/ui/primitives/icon-button'
|
|
28
29
|
import {
|
|
29
30
|
Dialog,
|
|
@@ -525,7 +526,7 @@ export default function AiAssistantTriggerWidget({ context }: AiAssistantTrigger
|
|
|
525
526
|
|
|
526
527
|
return (
|
|
527
528
|
<>
|
|
528
|
-
<
|
|
529
|
+
<ButtonGroup>
|
|
529
530
|
<Button
|
|
530
531
|
type="button"
|
|
531
532
|
variant="outline"
|
|
@@ -533,11 +534,7 @@ export default function AiAssistantTriggerWidget({ context }: AiAssistantTrigger
|
|
|
533
534
|
data-ai-customers-inject-trigger=""
|
|
534
535
|
aria-label={triggerLabel}
|
|
535
536
|
title={triggerLabel}
|
|
536
|
-
className={cn(
|
|
537
|
-
'relative',
|
|
538
|
-
'hover:bg-brand-violet/10',
|
|
539
|
-
agents.length > 1 && 'rounded-r-none border-r-0',
|
|
540
|
-
)}
|
|
537
|
+
className={cn('relative', 'hover:bg-brand-violet/10')}
|
|
541
538
|
>
|
|
542
539
|
<AiIcon className="size-4" />
|
|
543
540
|
<span>{labelText}</span>
|
|
@@ -556,10 +553,8 @@ export default function AiAssistantTriggerWidget({ context }: AiAssistantTrigger
|
|
|
556
553
|
<IconButton
|
|
557
554
|
type="button"
|
|
558
555
|
variant="outline"
|
|
559
|
-
size="lg"
|
|
560
556
|
aria-label={moreAgentsLabel}
|
|
561
557
|
title={moreAgentsLabel}
|
|
562
|
-
className="rounded-l-none"
|
|
563
558
|
data-ai-customers-inject-picker=""
|
|
564
559
|
>
|
|
565
560
|
<ChevronDown className="size-4" aria-hidden />
|
|
@@ -593,7 +588,7 @@ export default function AiAssistantTriggerWidget({ context }: AiAssistantTrigger
|
|
|
593
588
|
</PopoverContent>
|
|
594
589
|
</Popover>
|
|
595
590
|
) : null}
|
|
596
|
-
</
|
|
591
|
+
</ButtonGroup>
|
|
597
592
|
<Dialog open={open} onOpenChange={setOpen}>
|
|
598
593
|
<DialogContent
|
|
599
594
|
className={cn(
|