@open-mercato/core 0.10.1-develop.7763.1.caea616ebf → 0.10.1-develop.7764.1.7505d7340b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/customers/api/companies/route.js +2 -1
  3. package/dist/modules/customers/api/companies/route.js.map +2 -2
  4. package/dist/modules/customers/api/people/route.js +2 -1
  5. package/dist/modules/customers/api/people/route.js.map +2 -2
  6. package/dist/modules/customers/backend/customers/companies/page.js +21 -3
  7. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  8. package/dist/modules/customers/backend/customers/listSorting.js +2 -1
  9. package/dist/modules/customers/backend/customers/listSorting.js.map +2 -2
  10. package/dist/modules/customers/backend/customers/people/page.js +17 -1
  11. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  12. package/dist/modules/customers/lib/createdAtDayFilter.js +64 -0
  13. package/dist/modules/customers/lib/createdAtDayFilter.js.map +7 -0
  14. package/package.json +7 -7
  15. package/src/modules/customers/api/companies/route.ts +2 -1
  16. package/src/modules/customers/api/people/route.ts +2 -1
  17. package/src/modules/customers/backend/customers/companies/page.tsx +26 -3
  18. package/src/modules/customers/backend/customers/listSorting.ts +1 -0
  19. package/src/modules/customers/backend/customers/people/page.tsx +22 -1
  20. package/src/modules/customers/i18n/de.json +2 -0
  21. package/src/modules/customers/i18n/en.json +2 -0
  22. package/src/modules/customers/i18n/es.json +2 -0
  23. package/src/modules/customers/i18n/ko.json +2 -0
  24. package/src/modules/customers/i18n/pl.json +2 -0
  25. package/src/modules/customers/lib/createdAtDayFilter.ts +68 -0
@@ -58,6 +58,8 @@ import {
58
58
  } from '../../../components/detail/assignableStaff'
59
59
  import { CollectionPreviewCell, normalizeCollectionLabels } from '../../../components/list/CollectionPreviewCell'
60
60
  import { appendCustomerListSortParams } from '../listSorting'
61
+ import { expandCreatedAtDayRules } from '../../../lib/createdAtDayFilter'
62
+ import { USER_TIMEZONE } from '../../../lib/localDay'
61
63
 
62
64
  type DictionaryOptionWithTone = AdvancedFilterOption & FilterOption
63
65
 
@@ -119,6 +121,7 @@ type PersonRow = {
119
121
  organizationId?: string | null
120
122
  source?: string | null
121
123
  ownerUserId?: string | null
124
+ createdAt?: string | null
122
125
  } & Record<string, unknown>
123
126
 
124
127
  type PeopleResponse = {
@@ -166,6 +169,7 @@ function mapApiItem(item: Record<string, unknown>): PersonRow | null {
166
169
  const nextInteractionColor = typeof item.next_interaction_color === 'string' ? item.next_interaction_color : null
167
170
  const organizationId = typeof item.organization_id === 'string' ? item.organization_id : null
168
171
  const source = typeof item.source === 'string' ? item.source : null
172
+ const createdAt = typeof item.created_at === 'string' ? item.created_at : null
169
173
  const customFields: Record<string, unknown> = {}
170
174
  for (const [key, value] of Object.entries(item)) {
171
175
  if (key.startsWith('cf_')) {
@@ -196,6 +200,7 @@ function mapApiItem(item: Record<string, unknown>): PersonRow | null {
196
200
  nextInteractionColor,
197
201
  organizationId,
198
202
  source,
203
+ createdAt,
199
204
  ...customFields,
200
205
  }, item)
201
206
  }
@@ -375,7 +380,7 @@ export default function CustomersPeoplePage() {
375
380
  params.set('pageSize', String(pageSize))
376
381
  appendCustomerListSortParams(params, sorting)
377
382
  if (search.trim()) params.set('search', search.trim())
378
- const advancedParams = serializeTree(advancedFilterState)
383
+ const advancedParams = serializeTree(expandCreatedAtDayRules(advancedFilterState, USER_TIMEZONE))
379
384
  for (const [key, val] of Object.entries(advancedParams)) {
380
385
  params.set(key, val)
381
386
  }
@@ -713,6 +718,22 @@ export default function CustomersPeoplePage() {
713
718
  )
714
719
  : <span className="text-muted-foreground text-sm">{t('customers.people.list.noValue')}</span>,
715
720
  },
721
+ {
722
+ accessorKey: 'createdAt',
723
+ header: t('customers.people.list.columns.createdAt', 'Created'),
724
+ meta: {
725
+ columnChooserGroup: t('customers.columnGroups.dates', 'Dates'),
726
+ filterKey: 'created_at',
727
+ filterType: 'date' as const,
728
+ filterGroup: t('customers.columnGroups.activity', 'Activity'),
729
+ filterIconName: 'calendar',
730
+ },
731
+ cell: ({ row }) => (
732
+ <span className="text-sm">
733
+ {formatDate(row.original.createdAt, t('customers.people.list.noValue'))}
734
+ </span>
735
+ ),
736
+ },
716
737
  {
717
738
  accessorKey: 'source',
718
739
  header: t('customers.people.list.columns.source'),
@@ -797,6 +797,7 @@
797
797
  "customers.companies.list.bulkDelete.progressName": "Ausgewählte Unternehmen löschen",
798
798
  "customers.companies.list.bulkDelete.success": "{count} companies deleted",
799
799
  "customers.companies.list.bulkDelete.title": "Delete {count} companies?",
800
+ "customers.companies.list.columns.createdAt": "Erstellt am",
800
801
  "customers.companies.list.columns.email": "E-Mail",
801
802
  "customers.companies.list.columns.lifecycleStage": "Lebenszyklusphase",
802
803
  "customers.companies.list.columns.name": "Name",
@@ -2512,6 +2513,7 @@
2512
2513
  "customers.people.list.bulkDelete.progressName": "Ausgewählte Personen löschen",
2513
2514
  "customers.people.list.bulkDelete.success": "{count} people deleted",
2514
2515
  "customers.people.list.bulkDelete.title": "Delete {count} people?",
2516
+ "customers.people.list.columns.createdAt": "Erstellt am",
2515
2517
  "customers.people.list.columns.email": "E-Mail",
2516
2518
  "customers.people.list.columns.lifecycleStage": "Lebenszyklusphase",
2517
2519
  "customers.people.list.columns.name": "Name",
@@ -797,6 +797,7 @@
797
797
  "customers.companies.list.bulkDelete.progressName": "Delete selected companies",
798
798
  "customers.companies.list.bulkDelete.success": "{count} companies deleted",
799
799
  "customers.companies.list.bulkDelete.title": "Delete {count} companies?",
800
+ "customers.companies.list.columns.createdAt": "Created",
800
801
  "customers.companies.list.columns.email": "Email",
801
802
  "customers.companies.list.columns.lifecycleStage": "Lifecycle stage",
802
803
  "customers.companies.list.columns.name": "Name",
@@ -2512,6 +2513,7 @@
2512
2513
  "customers.people.list.bulkDelete.progressName": "Delete selected people",
2513
2514
  "customers.people.list.bulkDelete.success": "{count} people deleted",
2514
2515
  "customers.people.list.bulkDelete.title": "Delete {count} people?",
2516
+ "customers.people.list.columns.createdAt": "Created",
2515
2517
  "customers.people.list.columns.email": "Email",
2516
2518
  "customers.people.list.columns.lifecycleStage": "Lifecycle stage",
2517
2519
  "customers.people.list.columns.name": "Name",
@@ -797,6 +797,7 @@
797
797
  "customers.companies.list.bulkDelete.progressName": "Eliminar empresas seleccionadas",
798
798
  "customers.companies.list.bulkDelete.success": "{count} companies deleted",
799
799
  "customers.companies.list.bulkDelete.title": "Delete {count} companies?",
800
+ "customers.companies.list.columns.createdAt": "Fecha de creación",
800
801
  "customers.companies.list.columns.email": "Correo electrónico",
801
802
  "customers.companies.list.columns.lifecycleStage": "Etapa del ciclo de vida",
802
803
  "customers.companies.list.columns.name": "Nombre",
@@ -2512,6 +2513,7 @@
2512
2513
  "customers.people.list.bulkDelete.progressName": "Eliminar personas seleccionadas",
2513
2514
  "customers.people.list.bulkDelete.success": "{count} people deleted",
2514
2515
  "customers.people.list.bulkDelete.title": "Delete {count} people?",
2516
+ "customers.people.list.columns.createdAt": "Fecha de creación",
2515
2517
  "customers.people.list.columns.email": "Correo electrónico",
2516
2518
  "customers.people.list.columns.lifecycleStage": "Etapa del ciclo de vida",
2517
2519
  "customers.people.list.columns.name": "Nombre",
@@ -797,6 +797,7 @@
797
797
  "customers.companies.list.bulkDelete.progressName": "선택한 회사 삭제",
798
798
  "customers.companies.list.bulkDelete.success": "회사 {count}개가 삭제되었습니다",
799
799
  "customers.companies.list.bulkDelete.title": "회사 {count}개를 삭제하시겠습니까?",
800
+ "customers.companies.list.columns.createdAt": "생성일",
800
801
  "customers.companies.list.columns.email": "이메일",
801
802
  "customers.companies.list.columns.lifecycleStage": "라이프사이클 단계",
802
803
  "customers.companies.list.columns.name": "이름",
@@ -2512,6 +2513,7 @@
2512
2513
  "customers.people.list.bulkDelete.progressName": "선택한 연락처 삭제",
2513
2514
  "customers.people.list.bulkDelete.success": "{count}명의 연락처가 삭제되었습니다",
2514
2515
  "customers.people.list.bulkDelete.title": "{count}명의 연락처를 삭제하시겠습니까?",
2516
+ "customers.people.list.columns.createdAt": "생성일",
2515
2517
  "customers.people.list.columns.email": "이메일",
2516
2518
  "customers.people.list.columns.lifecycleStage": "라이프사이클 단계",
2517
2519
  "customers.people.list.columns.name": "이름",
@@ -797,6 +797,7 @@
797
797
  "customers.companies.list.bulkDelete.progressName": "Usuń zaznaczone firmy",
798
798
  "customers.companies.list.bulkDelete.success": "Usunięto {count} firm",
799
799
  "customers.companies.list.bulkDelete.title": "Usunąć {count} firm?",
800
+ "customers.companies.list.columns.createdAt": "Data utworzenia",
800
801
  "customers.companies.list.columns.email": "E-mail",
801
802
  "customers.companies.list.columns.lifecycleStage": "Etap cyklu życia",
802
803
  "customers.companies.list.columns.name": "Nazwa",
@@ -2512,6 +2513,7 @@
2512
2513
  "customers.people.list.bulkDelete.progressName": "Usuń zaznaczone osoby",
2513
2514
  "customers.people.list.bulkDelete.success": "Usunięto {count} osób",
2514
2515
  "customers.people.list.bulkDelete.title": "Usunąć {count} osób?",
2516
+ "customers.people.list.columns.createdAt": "Data utworzenia",
2515
2517
  "customers.people.list.columns.email": "E-mail",
2516
2518
  "customers.people.list.columns.lifecycleStage": "Etap cyklu życia",
2517
2519
  "customers.people.list.columns.name": "Nazwa",
@@ -0,0 +1,68 @@
1
+ import { fromZonedTime } from 'date-fns-tz'
2
+ import type { AdvancedFilterTree, FilterGroup, FilterRule } from '@open-mercato/shared/lib/query/advanced-filter-tree'
3
+
4
+ const CREATED_AT_FIELD = 'created_at'
5
+ const DATE_ONLY_PATTERN = /^\d{4}-\d{2}-\d{2}$/
6
+
7
+ function isDateOnly(value: unknown): value is string {
8
+ return typeof value === 'string' && DATE_ONLY_PATTERN.test(value.trim())
9
+ }
10
+
11
+ function startOfDay(value: string, timeZone: string): string {
12
+ return fromZonedTime(`${value.trim()}T00:00:00.000`, timeZone).toISOString()
13
+ }
14
+
15
+ function endOfDay(value: string, timeZone: string): string {
16
+ return fromZonedTime(`${value.trim()}T23:59:59.999`, timeZone).toISOString()
17
+ }
18
+
19
+ function expandRule(rule: FilterRule, timeZone: string): FilterRule {
20
+ if (rule.field !== CREATED_AT_FIELD) return rule
21
+ switch (rule.operator) {
22
+ case 'is':
23
+ case 'equals':
24
+ if (!isDateOnly(rule.value)) return rule
25
+ return { ...rule, operator: 'between', value: [startOfDay(rule.value, timeZone), endOfDay(rule.value, timeZone)] }
26
+ case 'is_after':
27
+ case 'greater_than':
28
+ if (!isDateOnly(rule.value)) return rule
29
+ return { ...rule, operator: 'greater_than', value: endOfDay(rule.value, timeZone) }
30
+ case 'less_or_equal':
31
+ if (!isDateOnly(rule.value)) return rule
32
+ return { ...rule, value: endOfDay(rule.value, timeZone) }
33
+ case 'is_before':
34
+ case 'less_than':
35
+ if (!isDateOnly(rule.value)) return rule
36
+ return { ...rule, operator: 'less_than', value: startOfDay(rule.value, timeZone) }
37
+ case 'greater_or_equal':
38
+ if (!isDateOnly(rule.value)) return rule
39
+ return { ...rule, value: startOfDay(rule.value, timeZone) }
40
+ case 'between': {
41
+ if (!Array.isArray(rule.value) || rule.value.length !== 2) return rule
42
+ const [start, end] = rule.value
43
+ return {
44
+ ...rule,
45
+ value: [
46
+ isDateOnly(start) ? startOfDay(start, timeZone) : start,
47
+ isDateOnly(end) ? endOfDay(end, timeZone) : end,
48
+ ],
49
+ }
50
+ }
51
+ default:
52
+ return rule
53
+ }
54
+ }
55
+
56
+ function expandGroup(group: FilterGroup, timeZone: string): FilterGroup {
57
+ return {
58
+ ...group,
59
+ children: group.children.map((child) =>
60
+ child.type === 'group' ? expandGroup(child, timeZone) : expandRule(child, timeZone),
61
+ ),
62
+ }
63
+ }
64
+
65
+ export function expandCreatedAtDayRules<T extends AdvancedFilterTree | null>(tree: T, timeZone: string): T {
66
+ if (!tree) return tree
67
+ return { ...tree, root: expandGroup(tree.root, timeZone) } as T
68
+ }