@open-mercato/core 0.5.1-develop.2987.9f8c1e0f68 → 0.5.1-develop.3032.01699048cb

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 (143) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/sidebar_variant/index.js +25 -0
  3. package/dist/generated/entities/sidebar_variant/index.js.map +7 -0
  4. package/dist/generated/entities.ids.generated.js +1 -0
  5. package/dist/generated/entities.ids.generated.js.map +2 -2
  6. package/dist/generated/entity-fields-registry.js +13 -0
  7. package/dist/generated/entity-fields-registry.js.map +2 -2
  8. package/dist/helpers/integration/authUi.js +1 -1
  9. package/dist/helpers/integration/authUi.js.map +2 -2
  10. package/dist/modules/audit_logs/services/actionLogService.js +4 -5
  11. package/dist/modules/audit_logs/services/actionLogService.js.map +2 -2
  12. package/dist/modules/auth/api/sidebar/preferences/route.js +224 -35
  13. package/dist/modules/auth/api/sidebar/preferences/route.js.map +3 -3
  14. package/dist/modules/auth/api/sidebar/variants/[id]/route.js +161 -0
  15. package/dist/modules/auth/api/sidebar/variants/[id]/route.js.map +7 -0
  16. package/dist/modules/auth/api/sidebar/variants/route.js +142 -0
  17. package/dist/modules/auth/api/sidebar/variants/route.js.map +7 -0
  18. package/dist/modules/auth/backend/sidebar-customization/page.js +16 -0
  19. package/dist/modules/auth/backend/sidebar-customization/page.js.map +7 -0
  20. package/dist/modules/auth/backend/sidebar-customization/page.meta.js +28 -0
  21. package/dist/modules/auth/backend/sidebar-customization/page.meta.js.map +7 -0
  22. package/dist/modules/auth/data/entities.js +45 -4
  23. package/dist/modules/auth/data/entities.js.map +2 -2
  24. package/dist/modules/auth/data/validators.js +63 -1
  25. package/dist/modules/auth/data/validators.js.map +2 -2
  26. package/dist/modules/auth/migrations/Migration20260427081815.js +15 -0
  27. package/dist/modules/auth/migrations/Migration20260427081815.js.map +7 -0
  28. package/dist/modules/auth/migrations/Migration20260427124900.js +15 -0
  29. package/dist/modules/auth/migrations/Migration20260427124900.js.map +7 -0
  30. package/dist/modules/auth/migrations/Migration20260427143311.js +72 -0
  31. package/dist/modules/auth/migrations/Migration20260427143311.js.map +7 -0
  32. package/dist/modules/auth/services/sidebarPreferencesService.js +176 -16
  33. package/dist/modules/auth/services/sidebarPreferencesService.js.map +2 -2
  34. package/dist/modules/customers/api/companies/[id]/route.js +30 -20
  35. package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
  36. package/dist/modules/customers/api/companies/route.js +12 -7
  37. package/dist/modules/customers/api/companies/route.js.map +2 -2
  38. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +12 -7
  39. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +2 -2
  40. package/dist/modules/customers/api/people/route.js +12 -7
  41. package/dist/modules/customers/api/people/route.js.map +2 -2
  42. package/dist/modules/customers/backend/customers/companies/[id]/page.js +3 -1
  43. package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
  44. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +25 -2
  45. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  46. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +35 -33
  47. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  48. package/dist/modules/customers/components/detail/ActivitiesAddNewMenu.js +56 -0
  49. package/dist/modules/customers/components/detail/ActivitiesAddNewMenu.js.map +7 -0
  50. package/dist/modules/customers/components/detail/ActivitiesCard.js +175 -0
  51. package/dist/modules/customers/components/detail/ActivitiesCard.js.map +7 -0
  52. package/dist/modules/customers/components/detail/ActivitiesDayStrip.js +324 -0
  53. package/dist/modules/customers/components/detail/ActivitiesDayStrip.js.map +7 -0
  54. package/dist/modules/customers/components/detail/ActivitiesSection.js +62 -13
  55. package/dist/modules/customers/components/detail/ActivitiesSection.js.map +2 -2
  56. package/dist/modules/customers/components/detail/ActivityLogTab.js +14 -23
  57. package/dist/modules/customers/components/detail/ActivityLogTab.js.map +2 -2
  58. package/dist/modules/customers/components/detail/ActivityTimeline.js +13 -13
  59. package/dist/modules/customers/components/detail/ActivityTimeline.js.map +2 -2
  60. package/dist/modules/customers/components/detail/ActivityTimelineFilters.js +35 -22
  61. package/dist/modules/customers/components/detail/ActivityTimelineFilters.js.map +2 -2
  62. package/dist/modules/customers/components/detail/AiActionChips.js +15 -22
  63. package/dist/modules/customers/components/detail/AiActionChips.js.map +2 -2
  64. package/dist/modules/customers/components/detail/CompanyPeopleSection.js +3 -2
  65. package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
  66. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +196 -28
  67. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
  68. package/dist/modules/customers/components/detail/schedule/DateTimeFields.js +2 -2
  69. package/dist/modules/customers/components/detail/schedule/DateTimeFields.js.map +2 -2
  70. package/dist/modules/customers/components/detail/schedule/FooterFields.js +14 -2
  71. package/dist/modules/customers/components/detail/schedule/FooterFields.js.map +2 -2
  72. package/dist/modules/customers/components/detail/schedule/LinkedEntitiesField.js +9 -2
  73. package/dist/modules/customers/components/detail/schedule/LinkedEntitiesField.js.map +2 -2
  74. package/dist/modules/customers/components/detail/schedule/ParticipantsField.js +9 -2
  75. package/dist/modules/customers/components/detail/schedule/ParticipantsField.js.map +2 -2
  76. package/dist/modules/customers/components/detail/schedule/fieldConfig.js +25 -4
  77. package/dist/modules/customers/components/detail/schedule/fieldConfig.js.map +2 -2
  78. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +20 -3
  79. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
  80. package/dist/modules/customers/components/formConfig.js +3 -3
  81. package/dist/modules/customers/components/formConfig.js.map +2 -2
  82. package/dist/modules/customers/lib/displayName.js +12 -0
  83. package/dist/modules/customers/lib/displayName.js.map +2 -2
  84. package/dist/modules/entities/cli.js +5 -6
  85. package/dist/modules/entities/cli.js.map +2 -2
  86. package/dist/modules/portal/frontend/[orgSlug]/portal/reset-password/page.js +124 -0
  87. package/dist/modules/portal/frontend/[orgSlug]/portal/reset-password/page.js.map +7 -0
  88. package/dist/modules/portal/frontend/[orgSlug]/portal/reset-password/page.meta.js +11 -0
  89. package/dist/modules/portal/frontend/[orgSlug]/portal/reset-password/page.meta.js.map +7 -0
  90. package/generated/entities/sidebar_variant/index.ts +11 -0
  91. package/generated/entities.ids.generated.ts +1 -0
  92. package/generated/entity-fields-registry.ts +13 -0
  93. package/package.json +6 -6
  94. package/src/helpers/integration/authUi.ts +1 -1
  95. package/src/modules/audit_logs/services/actionLogService.ts +5 -6
  96. package/src/modules/auth/api/sidebar/preferences/route.ts +266 -34
  97. package/src/modules/auth/api/sidebar/variants/[id]/route.ts +183 -0
  98. package/src/modules/auth/api/sidebar/variants/route.ts +157 -0
  99. package/src/modules/auth/backend/sidebar-customization/page.meta.ts +34 -0
  100. package/src/modules/auth/backend/sidebar-customization/page.tsx +17 -0
  101. package/src/modules/auth/data/entities.ts +48 -2
  102. package/src/modules/auth/data/validators.ts +70 -0
  103. package/src/modules/auth/migrations/.snapshot-open-mercato.json +790 -71
  104. package/src/modules/auth/migrations/Migration20260427081815.ts +16 -0
  105. package/src/modules/auth/migrations/Migration20260427124900.ts +19 -0
  106. package/src/modules/auth/migrations/Migration20260427143311.ts +83 -0
  107. package/src/modules/auth/services/sidebarPreferencesService.ts +243 -18
  108. package/src/modules/customers/api/companies/[id]/route.ts +30 -20
  109. package/src/modules/customers/api/companies/route.ts +12 -7
  110. package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +12 -7
  111. package/src/modules/customers/api/people/route.ts +12 -7
  112. package/src/modules/customers/backend/customers/companies/[id]/page.tsx +5 -4
  113. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +28 -5
  114. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +41 -30
  115. package/src/modules/customers/components/detail/ActivitiesAddNewMenu.tsx +67 -0
  116. package/src/modules/customers/components/detail/ActivitiesCard.tsx +231 -0
  117. package/src/modules/customers/components/detail/ActivitiesDayStrip.tsx +390 -0
  118. package/src/modules/customers/components/detail/ActivitiesSection.tsx +91 -40
  119. package/src/modules/customers/components/detail/ActivityLogTab.tsx +25 -23
  120. package/src/modules/customers/components/detail/ActivityTimeline.tsx +15 -19
  121. package/src/modules/customers/components/detail/ActivityTimelineFilters.tsx +36 -29
  122. package/src/modules/customers/components/detail/AiActionChips.tsx +17 -23
  123. package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +3 -2
  124. package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +233 -41
  125. package/src/modules/customers/components/detail/schedule/DateTimeFields.tsx +6 -2
  126. package/src/modules/customers/components/detail/schedule/FooterFields.tsx +22 -2
  127. package/src/modules/customers/components/detail/schedule/LinkedEntitiesField.tsx +10 -2
  128. package/src/modules/customers/components/detail/schedule/ParticipantsField.tsx +10 -2
  129. package/src/modules/customers/components/detail/schedule/fieldConfig.ts +26 -6
  130. package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +32 -3
  131. package/src/modules/customers/components/formConfig.tsx +3 -3
  132. package/src/modules/customers/i18n/de.json +69 -2
  133. package/src/modules/customers/i18n/en.json +69 -2
  134. package/src/modules/customers/i18n/es.json +69 -2
  135. package/src/modules/customers/i18n/pl.json +68 -1
  136. package/src/modules/customers/lib/displayName.ts +21 -0
  137. package/src/modules/entities/cli.ts +5 -6
  138. package/src/modules/portal/frontend/[orgSlug]/portal/reset-password/page.meta.ts +9 -0
  139. package/src/modules/portal/frontend/[orgSlug]/portal/reset-password/page.tsx +168 -0
  140. package/src/modules/portal/i18n/de.json +20 -0
  141. package/src/modules/portal/i18n/en.json +20 -0
  142. package/src/modules/portal/i18n/es.json +20 -0
  143. package/src/modules/portal/i18n/pl.json +20 -0
@@ -4,12 +4,33 @@
4
4
  "audit_logs.resource_kind.customers.comment": "Comentario",
5
5
  "audit_logs.resource_kind.customers.todoLink": "Tarea",
6
6
  "backend.nav.configuration": "Configuración",
7
+ "customers.activities.add.call": "Registrar llamada",
8
+ "customers.activities.add.email": "Redactar correo",
9
+ "customers.activities.add.meeting": "Nueva reunión",
10
+ "customers.activities.add.task": "Nueva tarea",
11
+ "customers.activities.addNew": "Añadir nuevo",
12
+ "customers.activities.calendar.eventPlural": "eventos",
13
+ "customers.activities.calendar.eventSingular": "evento",
14
+ "customers.activities.calendar.eventsSummary": "{count} {countLabel} · {duration}",
15
+ "customers.activities.calendar.hoursMinutesShort": "{hours}h {minutes}m",
16
+ "customers.activities.calendar.hoursShort": "{hours}h",
17
+ "customers.activities.calendar.minutesShort": "{minutes}m",
18
+ "customers.activities.calendar.monthYear": "{month} {year}",
19
+ "customers.activities.calendar.nextMonth": "Próximo mes",
20
+ "customers.activities.calendar.nextWindow": "Días siguientes",
21
+ "customers.activities.calendar.prevMonth": "Mes anterior",
22
+ "customers.activities.calendar.prevWindow": "Días anteriores",
23
+ "customers.activities.calendar.weekend": "Fin de semana",
24
+ "customers.activities.card.empty": "Nada programado para este día.",
25
+ "customers.activities.card.overdue": "{count} vencidas",
26
+ "customers.activities.card.title": "Actividades",
7
27
  "customers.activities.filters.clearAll": "Clear filters",
8
28
  "customers.activities.filters.dateRange": "Date range",
9
29
  "customers.activities.loadFailed": "No se pudieron cargar las actividades.",
10
30
  "customers.activities.loadMore": "Load more",
11
31
  "customers.activities.overdue": "",
12
32
  "customers.activities.seeAll": "",
33
+ "customers.activities.seeMatching": "",
13
34
  "customers.activities.yearSeparator": "",
14
35
  "customers.activityComposer.cancel": "Cancel",
15
36
  "customers.activityComposer.dateLabel": "Date",
@@ -1781,22 +1802,46 @@
1781
1802
  "customers.schedule.addVisibleLinks": "Agregar todos los visibles",
1782
1803
  "customers.schedule.addVisibleParticipants": "Agregar todos los visibles",
1783
1804
  "customers.schedule.allDay": "All day",
1805
+ "customers.schedule.attendees": "Attendees",
1784
1806
  "customers.schedule.body": "Contenido",
1807
+ "customers.schedule.call.direction.inbound": "Entrante",
1808
+ "customers.schedule.call.direction.outbound": "Saliente",
1809
+ "customers.schedule.call.directionLabel": "Dirección",
1810
+ "customers.schedule.call.outcome.badNumber": "Número incorrecto",
1811
+ "customers.schedule.call.outcome.busy": "Ocupado",
1812
+ "customers.schedule.call.outcome.connected": "Conectado",
1813
+ "customers.schedule.call.outcome.noAnswer": "Sin respuesta",
1814
+ "customers.schedule.call.outcome.voicemail": "Buzón de voz",
1815
+ "customers.schedule.call.outcomeLabel": "Resultado",
1816
+ "customers.schedule.call.phoneLabel": "Número de teléfono",
1817
+ "customers.schedule.call.phonePlaceholder": "+1 555 000 0000",
1818
+ "customers.schedule.call.save": "Registrar llamada",
1819
+ "customers.schedule.call.subtitle": "Registra una llamada que acabas de tener o programa una",
1820
+ "customers.schedule.call.title": "Registrar llamada",
1821
+ "customers.schedule.callNotes": "Call notes",
1785
1822
  "customers.schedule.cancel": "Cancel",
1786
1823
  "customers.schedule.conflict.description": "Overlaps with: {{items}}",
1787
1824
  "customers.schedule.conflict.title": "Calendar conflict",
1825
+ "customers.schedule.connections": "Connections",
1826
+ "customers.schedule.contact": "Contact",
1788
1827
  "customers.schedule.context": "On timeline: {{name}}",
1789
1828
  "customers.schedule.date": "Date",
1790
1829
  "customers.schedule.description": "Description",
1791
1830
  "customers.schedule.descriptionPlaceholder": "Add details...",
1831
+ "customers.schedule.details": "Details",
1792
1832
  "customers.schedule.discardConfirm.cancel": "Seguir editando",
1793
1833
  "customers.schedule.discardConfirm.confirm": "Descartar",
1794
1834
  "customers.schedule.discardConfirm.description": "Tienes cambios sin guardar en esta actividad. Guárdalos primero o continúa para descartarlos.",
1795
1835
  "customers.schedule.discardConfirm.title": "¿Descartar cambios sin guardar?",
1796
1836
  "customers.schedule.dueDate": "Fecha límite",
1837
+ "customers.schedule.dueTime": "Due time",
1797
1838
  "customers.schedule.duration": "Duration",
1798
1839
  "customers.schedule.editTitle": "Editar actividad",
1840
+ "customers.schedule.email.save": "Enviar correo",
1841
+ "customers.schedule.email.subtitle": "Redacta y envía un correo con seguimiento",
1842
+ "customers.schedule.email.title": "Redactar correo",
1799
1843
  "customers.schedule.error": "Failed to schedule activity",
1844
+ "customers.schedule.estimate": "Estimate",
1800
1845
  "customers.schedule.guestPerm.invite": "Invite others",
1801
1846
  "customers.schedule.guestPerm.modify": "Modify",
1802
1847
  "customers.schedule.guestPerm.seeList": "See list",
@@ -1808,6 +1853,10 @@
1808
1853
  "customers.schedule.loadMore": "Load more",
1809
1854
  "customers.schedule.location": "Location",
1810
1855
  "customers.schedule.locationPlaceholder": "Add location or meeting link...",
1856
+ "customers.schedule.meeting.save": "Guardar actividad",
1857
+ "customers.schedule.meeting.subtitle": "Bloquea tiempo en el calendario con asistentes",
1858
+ "customers.schedule.meeting.title": "Nueva reunión",
1859
+ "customers.schedule.message": "Message",
1811
1860
  "customers.schedule.noResults": "No results",
1812
1861
  "customers.schedule.participants": "Participants",
1813
1862
  "customers.schedule.recurrence.active": "Repeats",
@@ -1815,10 +1864,15 @@
1815
1864
  "customers.schedule.recurrence.edit": "Editar",
1816
1865
  "customers.schedule.recurrence.ends": "Ends",
1817
1866
  "customers.schedule.recurrence.never": "Never",
1818
- "customers.schedule.recurrence.none": "No repeat",
1867
+ "customers.schedule.recurrence.none": "Does not repeat",
1819
1868
  "customers.schedule.recurrence.onDate": "On date",
1820
1869
  "customers.schedule.recurrence.title": "Recurrence",
1821
1870
  "customers.schedule.reminder": "Reminder",
1871
+ "customers.schedule.reminder.dayBefore": "1 day before",
1872
+ "customers.schedule.reminder.daysBefore": "{days} days before",
1873
+ "customers.schedule.reminder.hourBefore": "1 hour before",
1874
+ "customers.schedule.reminder.hoursBefore": "{hours} hours before",
1875
+ "customers.schedule.reminder.minutesBefore": "{minutes} min before",
1822
1876
  "customers.schedule.reminder.none": "None",
1823
1877
  "customers.schedule.removeLink": "Eliminar enlace",
1824
1878
  "customers.schedule.removeParticipant": "Eliminar participante",
@@ -1834,9 +1888,19 @@
1834
1888
  "customers.schedule.searching": "Searching...",
1835
1889
  "customers.schedule.start": "Start",
1836
1890
  "customers.schedule.subject": "Asunto",
1891
+ "customers.schedule.subjectPlaceholder": "Subject...",
1892
+ "customers.schedule.task.priority.high": "Alta",
1893
+ "customers.schedule.task.priority.low": "Baja",
1894
+ "customers.schedule.task.priority.medium": "Media",
1895
+ "customers.schedule.task.priority.urgent": "Urgente",
1896
+ "customers.schedule.task.priorityLabel": "Prioridad",
1897
+ "customers.schedule.task.save": "Guardar tarea",
1898
+ "customers.schedule.task.subtitle": "Captura algo para hacer seguimiento",
1899
+ "customers.schedule.task.title": "Nueva tarea",
1837
1900
  "customers.schedule.title": "Schedule activity",
1838
1901
  "customers.schedule.titleLabel": "Title",
1839
1902
  "customers.schedule.titlePlaceholder": "Activity title...",
1903
+ "customers.schedule.to": "To",
1840
1904
  "customers.schedule.types.call": "Call",
1841
1905
  "customers.schedule.types.email": "Email",
1842
1906
  "customers.schedule.types.meeting": "Meeting",
@@ -1923,10 +1987,11 @@
1923
1987
  "customers.temperature.warm": "High Interest",
1924
1988
  "customers.timeline.author": "by {{name}}",
1925
1989
  "customers.timeline.date.today": "today",
1990
+ "customers.timeline.date.tomorrow": "tomorrow",
1926
1991
  "customers.timeline.date.yesterday": "yesterday",
1927
1992
  "customers.timeline.edit": "Edit",
1928
1993
  "customers.timeline.empty": "No activities match the current filters.",
1929
- "customers.timeline.filter.all": "All",
1994
+ "customers.timeline.filter.all": "All Activities",
1930
1995
  "customers.timeline.filter.call": "Call",
1931
1996
  "customers.timeline.filter.email": "Email",
1932
1997
  "customers.timeline.filter.from": "From date",
@@ -1934,6 +1999,8 @@
1934
1999
  "customers.timeline.filter.note": "Note",
1935
2000
  "customers.timeline.filter.to": "To date",
1936
2001
  "customers.timeline.history.filtered": "filtered: {{types}} · {{count}} results",
2002
+ "customers.timeline.history.searchAriaLabel": "",
2003
+ "customers.timeline.history.searchPlaceholder": "",
1937
2004
  "customers.timeline.history.seeAll": "See all {{count}} activities",
1938
2005
  "customers.timeline.history.title": "Interaction history with {{name}}",
1939
2006
  "customers.timeline.history.titleGeneric": "Interaction history",
@@ -4,12 +4,33 @@
4
4
  "audit_logs.resource_kind.customers.comment": "Komentarz",
5
5
  "audit_logs.resource_kind.customers.todoLink": "Zadanie",
6
6
  "backend.nav.configuration": "Konfiguracja",
7
+ "customers.activities.add.call": "Zarejestruj rozmowę",
8
+ "customers.activities.add.email": "Napisz e-mail",
9
+ "customers.activities.add.meeting": "Nowe spotkanie",
10
+ "customers.activities.add.task": "Nowe zadanie",
11
+ "customers.activities.addNew": "Dodaj nowe",
12
+ "customers.activities.calendar.eventPlural": "wydarzeń",
13
+ "customers.activities.calendar.eventSingular": "wydarzenie",
14
+ "customers.activities.calendar.eventsSummary": "{count} {countLabel} · {duration}",
15
+ "customers.activities.calendar.hoursMinutesShort": "{hours}h {minutes}m",
16
+ "customers.activities.calendar.hoursShort": "{hours}h",
17
+ "customers.activities.calendar.minutesShort": "{minutes}m",
18
+ "customers.activities.calendar.monthYear": "{month} {year}",
19
+ "customers.activities.calendar.nextMonth": "Następny miesiąc",
20
+ "customers.activities.calendar.nextWindow": "Następne dni",
21
+ "customers.activities.calendar.prevMonth": "Poprzedni miesiąc",
22
+ "customers.activities.calendar.prevWindow": "Poprzednie dni",
23
+ "customers.activities.calendar.weekend": "Weekend",
24
+ "customers.activities.card.empty": "Nic nie zaplanowano na ten dzień.",
25
+ "customers.activities.card.overdue": "{count} zaległych",
26
+ "customers.activities.card.title": "Aktywności",
7
27
  "customers.activities.filters.clearAll": "Clear filters",
8
28
  "customers.activities.filters.dateRange": "Date range",
9
29
  "customers.activities.loadFailed": "Nie udało się załadować aktywności.",
10
30
  "customers.activities.loadMore": "Load more",
11
31
  "customers.activities.overdue": "{count} zaległe",
12
32
  "customers.activities.seeAll": "Zobacz wszystkie {count} aktywności",
33
+ "customers.activities.seeMatching": "Pokazuję {visible} z {total} aktywności",
13
34
  "customers.activities.yearSeparator": "{year}",
14
35
  "customers.activityComposer.cancel": "Anuluj",
15
36
  "customers.activityComposer.dateLabel": "Data",
@@ -1781,22 +1802,46 @@
1781
1802
  "customers.schedule.addVisibleLinks": "Dodaj wszystkie widoczne",
1782
1803
  "customers.schedule.addVisibleParticipants": "Dodaj wszystkich widocznych",
1783
1804
  "customers.schedule.allDay": "Cały dzień",
1805
+ "customers.schedule.attendees": "Uczestnicy",
1784
1806
  "customers.schedule.body": "Treść",
1807
+ "customers.schedule.call.direction.inbound": "Przychodzący",
1808
+ "customers.schedule.call.direction.outbound": "Wychodzący",
1809
+ "customers.schedule.call.directionLabel": "Kierunek",
1810
+ "customers.schedule.call.outcome.badNumber": "Zły numer",
1811
+ "customers.schedule.call.outcome.busy": "Zajęty",
1812
+ "customers.schedule.call.outcome.connected": "Połączono",
1813
+ "customers.schedule.call.outcome.noAnswer": "Brak odpowiedzi",
1814
+ "customers.schedule.call.outcome.voicemail": "Poczta głosowa",
1815
+ "customers.schedule.call.outcomeLabel": "Wynik",
1816
+ "customers.schedule.call.phoneLabel": "Numer telefonu",
1817
+ "customers.schedule.call.phonePlaceholder": "+1 555 000 0000",
1818
+ "customers.schedule.call.save": "Zarejestruj rozmowę",
1819
+ "customers.schedule.call.subtitle": "Zarejestruj odbytą rozmowę lub zaplanuj nową",
1820
+ "customers.schedule.call.title": "Zarejestruj rozmowę",
1821
+ "customers.schedule.callNotes": "Notatki z rozmowy",
1785
1822
  "customers.schedule.cancel": "Anuluj",
1786
1823
  "customers.schedule.conflict.description": "Overlaps with: {{items}}",
1787
1824
  "customers.schedule.conflict.title": "Konflikt w kalendarzu",
1825
+ "customers.schedule.connections": "Powiązania",
1826
+ "customers.schedule.contact": "Kontakt",
1788
1827
  "customers.schedule.context": "Na osi czasu: {{name}}",
1789
1828
  "customers.schedule.date": "Data",
1790
1829
  "customers.schedule.description": "Opis",
1791
1830
  "customers.schedule.descriptionPlaceholder": "Dodaj szczegóły...",
1831
+ "customers.schedule.details": "Szczegóły",
1792
1832
  "customers.schedule.discardConfirm.cancel": "Kontynuuj edycję",
1793
1833
  "customers.schedule.discardConfirm.confirm": "Odrzuć",
1794
1834
  "customers.schedule.discardConfirm.description": "Masz niezapisane zmiany w tej aktywności. Zapisz je lub kontynuuj, aby je odrzucić.",
1795
1835
  "customers.schedule.discardConfirm.title": "Odrzucić niezapisane zmiany?",
1796
1836
  "customers.schedule.dueDate": "Termin",
1837
+ "customers.schedule.dueTime": "Godzina",
1797
1838
  "customers.schedule.duration": "Czas trwania",
1798
1839
  "customers.schedule.editTitle": "Edytuj aktywność",
1840
+ "customers.schedule.email.save": "Wyślij e-mail",
1841
+ "customers.schedule.email.subtitle": "Napisz i wyślij śledzony e-mail",
1842
+ "customers.schedule.email.title": "Napisz e-mail",
1799
1843
  "customers.schedule.error": "Nie udało się zaplanować aktywności",
1844
+ "customers.schedule.estimate": "Szacowany czas",
1800
1845
  "customers.schedule.guestPerm.invite": "Invite others",
1801
1846
  "customers.schedule.guestPerm.modify": "Modify",
1802
1847
  "customers.schedule.guestPerm.seeList": "See list",
@@ -1808,6 +1853,10 @@
1808
1853
  "customers.schedule.loadMore": "Load more",
1809
1854
  "customers.schedule.location": "Lokalizacja",
1810
1855
  "customers.schedule.locationPlaceholder": "Dodaj lokalizację lub link do spotkania...",
1856
+ "customers.schedule.meeting.save": "Zapisz aktywność",
1857
+ "customers.schedule.meeting.subtitle": "Zarezerwuj czas w kalendarzu z uczestnikami",
1858
+ "customers.schedule.meeting.title": "Nowe spotkanie",
1859
+ "customers.schedule.message": "Wiadomość",
1811
1860
  "customers.schedule.noResults": "No results",
1812
1861
  "customers.schedule.participants": "Uczestnicy",
1813
1862
  "customers.schedule.recurrence.active": "Powtarza się",
@@ -1819,6 +1868,11 @@
1819
1868
  "customers.schedule.recurrence.onDate": "Dnia",
1820
1869
  "customers.schedule.recurrence.title": "Powtarzanie",
1821
1870
  "customers.schedule.reminder": "Przypomnienie",
1871
+ "customers.schedule.reminder.dayBefore": "1 dzień przed",
1872
+ "customers.schedule.reminder.daysBefore": "{days} dni przed",
1873
+ "customers.schedule.reminder.hourBefore": "1 godzinę przed",
1874
+ "customers.schedule.reminder.hoursBefore": "{hours} godz. przed",
1875
+ "customers.schedule.reminder.minutesBefore": "{minutes} min przed",
1822
1876
  "customers.schedule.reminder.none": "Brak",
1823
1877
  "customers.schedule.removeLink": "Usuń powiązanie",
1824
1878
  "customers.schedule.removeParticipant": "Usuń uczestnika",
@@ -1834,9 +1888,19 @@
1834
1888
  "customers.schedule.searching": "Searching...",
1835
1889
  "customers.schedule.start": "Start",
1836
1890
  "customers.schedule.subject": "Temat",
1891
+ "customers.schedule.subjectPlaceholder": "Temat...",
1892
+ "customers.schedule.task.priority.high": "Wysoki",
1893
+ "customers.schedule.task.priority.low": "Niski",
1894
+ "customers.schedule.task.priority.medium": "Średni",
1895
+ "customers.schedule.task.priority.urgent": "Pilny",
1896
+ "customers.schedule.task.priorityLabel": "Priorytet",
1897
+ "customers.schedule.task.save": "Zapisz zadanie",
1898
+ "customers.schedule.task.subtitle": "Zapisz coś do późniejszego wykonania",
1899
+ "customers.schedule.task.title": "Nowe zadanie",
1837
1900
  "customers.schedule.title": "Zaplanuj aktywność",
1838
1901
  "customers.schedule.titleLabel": "Tytuł",
1839
1902
  "customers.schedule.titlePlaceholder": "Tytuł aktywności...",
1903
+ "customers.schedule.to": "Do",
1840
1904
  "customers.schedule.types.call": "Połączenie",
1841
1905
  "customers.schedule.types.email": "E-mail",
1842
1906
  "customers.schedule.types.meeting": "Spotkanie",
@@ -1923,10 +1987,11 @@
1923
1987
  "customers.temperature.warm": "High Interest",
1924
1988
  "customers.timeline.author": "by {{name}}",
1925
1989
  "customers.timeline.date.today": "dziś",
1990
+ "customers.timeline.date.tomorrow": "tomorrow",
1926
1991
  "customers.timeline.date.yesterday": "wczoraj",
1927
1992
  "customers.timeline.edit": "Edytuj",
1928
1993
  "customers.timeline.empty": "Brak aktywności pasujących do filtrów.",
1929
- "customers.timeline.filter.all": "Wszystkie",
1994
+ "customers.timeline.filter.all": "Wszystkie aktywności",
1930
1995
  "customers.timeline.filter.call": "Telefon",
1931
1996
  "customers.timeline.filter.email": "E-mail",
1932
1997
  "customers.timeline.filter.from": "Od daty",
@@ -1934,6 +1999,8 @@
1934
1999
  "customers.timeline.filter.note": "Notatka",
1935
2000
  "customers.timeline.filter.to": "Do daty",
1936
2001
  "customers.timeline.history.filtered": "filtered: {{types}} · {{count}} wyników",
2002
+ "customers.timeline.history.searchAriaLabel": "Szukaj w historii interakcji",
2003
+ "customers.timeline.history.searchPlaceholder": "Szukaj...",
1937
2004
  "customers.timeline.history.seeAll": "Zobacz wszystkie {{count}} aktywności",
1938
2005
  "customers.timeline.history.title": "Historia interakcji z {{name}}",
1939
2006
  "customers.timeline.history.titleGeneric": "Historia interakcji",
@@ -1,3 +1,24 @@
1
+ /**
2
+ * Coerce an arbitrary `displayName` payload to a string for safe UI consumption.
3
+ *
4
+ * The encryption pipeline used to coerce numeric-looking string display names
5
+ * back into numbers (issue #1734). The root cause is fixed in
6
+ * `parseDecryptedFieldValue`, but this helper remains as belt-and-suspenders
7
+ * for any persisted data that was already corrupted on read paths that bypass
8
+ * the new heuristic.
9
+ */
10
+ export function coerceDisplayName(value: unknown): string {
11
+ if (typeof value === 'string') return value
12
+ if (value == null) return ''
13
+ return String(value)
14
+ }
15
+
16
+ export function coerceDisplayNameOrNull(value: unknown): string | null {
17
+ if (value == null) return null
18
+ if (typeof value === 'string') return value
19
+ return String(value)
20
+ }
21
+
1
22
  export function deriveDisplayName(
2
23
  firstName: string | null | undefined,
3
24
  lastName: string | null | undefined,
@@ -17,7 +17,10 @@ import {
17
17
  TenantDataEncryptionError,
18
18
  TenantDataEncryptionErrorCode,
19
19
  } from '@open-mercato/shared/lib/encryption/aes'
20
- import { TenantDataEncryptionService } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'
20
+ import {
21
+ TenantDataEncryptionService,
22
+ parseDecryptedFieldValue,
23
+ } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'
21
24
  import { resolveEntityIdFromMetadata } from '@open-mercato/shared/lib/encryption/entityIds'
22
25
  import { Organization } from '../directory/data/entities'
23
26
  import crypto from 'node:crypto'
@@ -563,11 +566,7 @@ const rotateEncryptionKey: ModuleCli = {
563
566
  if (typeof value !== 'string' || !isEncryptedPayload(value)) continue
564
567
  const decrypted = decryptWithOldKey(value, oldDek)
565
568
  if (decrypted === null) continue
566
- try {
567
- payload[rule.field] = JSON.parse(decrypted)
568
- } catch {
569
- payload[rule.field] = decrypted
570
- }
569
+ payload[rule.field] = parseDecryptedFieldValue(decrypted)
571
570
  }
572
571
  }
573
572
  const encrypted = await encryptionService.encryptEntityPayload(
@@ -0,0 +1,9 @@
1
+ import type { PageMetadata } from '@open-mercato/shared/modules/registry'
2
+
3
+ export const metadata: PageMetadata = {
4
+ titleKey: 'portal.nav.resetPassword',
5
+ title: 'Reset Password',
6
+ navHidden: true,
7
+ }
8
+
9
+ export default metadata
@@ -0,0 +1,168 @@
1
+ "use client"
2
+ import { useCallback, useMemo, useState, useEffect } from 'react'
3
+ import { useSearchParams } from 'next/navigation'
4
+ import Link from 'next/link'
5
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
6
+ import { Input } from '@open-mercato/ui/primitives/input'
7
+ import { Label } from '@open-mercato/ui/primitives/label'
8
+ import { Button } from '@open-mercato/ui/primitives/button'
9
+ import { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'
10
+ import { Spinner } from '@open-mercato/ui/primitives/spinner'
11
+ import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
12
+ import { usePortalContext } from '@open-mercato/ui/portal/PortalContext'
13
+ import { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'
14
+ import { PortalInjectionSpots } from '@open-mercato/ui/backend/injection/spotIds'
15
+
16
+ type Props = { params: { orgSlug: string } }
17
+
18
+ export default function PortalResetPasswordPage({ params }: Props) {
19
+ const t = useT()
20
+ const orgSlug = params.orgSlug
21
+ const { tenant } = usePortalContext()
22
+ const searchParams = useSearchParams()
23
+
24
+ const [password, setPassword] = useState('')
25
+ const [confirmPassword, setConfirmPassword] = useState('')
26
+ const [error, setError] = useState<string | null>(null)
27
+ const [success, setSuccess] = useState(false)
28
+ const [submitting, setSubmitting] = useState(false)
29
+ const [token, setToken] = useState<string | null>(null)
30
+
31
+ useEffect(() => {
32
+ const tokenParam = searchParams.get('token')
33
+ if (!tokenParam) {
34
+ setError(t('portal.resetPassword.error.noToken', 'Invalid or missing reset token.'))
35
+ } else {
36
+ setToken(tokenParam)
37
+ }
38
+ }, [searchParams, t])
39
+
40
+ const handleSubmit = useCallback(
41
+ async (event: React.FormEvent) => {
42
+ event.preventDefault()
43
+ setError(null)
44
+
45
+ if (!token) {
46
+ setError(t('portal.resetPassword.error.noToken', 'Invalid or missing reset token.'))
47
+ return
48
+ }
49
+
50
+ if (password !== confirmPassword) {
51
+ setError(t('portal.resetPassword.error.passwordMismatch', 'Passwords do not match.'))
52
+ return
53
+ }
54
+
55
+ if (password.length < 8) {
56
+ setError(t('portal.resetPassword.error.passwordTooShort', 'Password must be at least 8 characters long.'))
57
+ return
58
+ }
59
+
60
+ setSubmitting(true)
61
+ try {
62
+ const result = await apiCall<{ ok: boolean; error?: string }>('/api/customer_accounts/password/reset-confirm', {
63
+ method: 'POST',
64
+ headers: { 'Content-Type': 'application/json' },
65
+ body: JSON.stringify({ token, password }),
66
+ })
67
+
68
+ if (result.ok && result.result?.ok) {
69
+ setSuccess(true)
70
+ return
71
+ }
72
+
73
+ if (result.status === 400) {
74
+ setError(t('portal.resetPassword.error.invalidToken', 'Invalid or expired reset token.'))
75
+ } else {
76
+ setError(result.result?.error || t('portal.resetPassword.error.generic', 'Password reset failed. Please try again.'))
77
+ }
78
+ } catch {
79
+ setError(t('portal.resetPassword.error.generic', 'Password reset failed. Please try again.'))
80
+ } finally {
81
+ setSubmitting(false)
82
+ }
83
+ },
84
+ [token, password, confirmPassword, t],
85
+ )
86
+
87
+ const injectionContext = useMemo(
88
+ () => ({ orgSlug }),
89
+ [orgSlug],
90
+ )
91
+
92
+ if (tenant.loading) {
93
+ return <div className="flex items-center justify-center py-20"><Spinner /></div>
94
+ }
95
+
96
+ if (tenant.error) {
97
+ return (
98
+ <div className="mx-auto w-full max-w-md py-12">
99
+ <Alert variant="destructive">
100
+ <AlertDescription>{t('portal.org.invalid', 'Organization not found.')}</AlertDescription>
101
+ </Alert>
102
+ </div>
103
+ )
104
+ }
105
+
106
+ if (success) {
107
+ return (
108
+ <div className="mx-auto w-full max-w-sm">
109
+ <div className="mb-8 text-center">
110
+ <h1 className="text-2xl font-bold tracking-tight">{t('portal.resetPassword.success.title', 'Password Reset Complete')}</h1>
111
+ <p className="mt-1.5 text-sm text-muted-foreground">{t('portal.resetPassword.success.description', 'Your password has been successfully reset.')}</p>
112
+ </div>
113
+
114
+ <Alert>
115
+ <AlertDescription>{t('portal.resetPassword.success.message', 'You can now sign in with your new password.')}</AlertDescription>
116
+ </Alert>
117
+
118
+ <div className="mt-6 text-center">
119
+ <Link href={`/${orgSlug}/portal/login`} className="font-medium text-foreground underline underline-offset-4 hover:opacity-80">
120
+ {t('portal.resetPassword.success.loginLink', 'Go to Sign In')}
121
+ </Link>
122
+ </div>
123
+ </div>
124
+ )
125
+ }
126
+
127
+ return (
128
+ <div className="mx-auto w-full max-w-sm">
129
+ <div className="mb-8 text-center">
130
+ <h1 className="text-2xl font-bold tracking-tight">{t('portal.resetPassword.title', 'Reset Password')}</h1>
131
+ <p className="mt-1.5 text-sm text-muted-foreground">{t('portal.resetPassword.description', 'Enter your new password below.')}</p>
132
+ </div>
133
+
134
+ <InjectionSpot spotId={PortalInjectionSpots.pageBefore('reset-password')} context={injectionContext} />
135
+
136
+ <form onSubmit={handleSubmit} className="flex flex-col gap-4">
137
+ {error ? (
138
+ <Alert variant="destructive">
139
+ <AlertDescription>{error}</AlertDescription>
140
+ </Alert>
141
+ ) : null}
142
+
143
+ <div className="flex flex-col gap-1.5">
144
+ <Label htmlFor="reset-password" className="text-overline font-semibold uppercase tracking-wider text-muted-foreground/70">{t('portal.resetPassword.password', 'New Password')}</Label>
145
+ <Input id="reset-password" type="password" autoComplete="new-password" required placeholder={t('portal.resetPassword.password.placeholder', '••••••••')} value={password} onChange={(e) => setPassword(e.target.value)} disabled={submitting || !token} className="rounded-lg" />
146
+ </div>
147
+
148
+ <div className="flex flex-col gap-1.5">
149
+ <Label htmlFor="confirm-password" className="text-overline font-semibold uppercase tracking-wider text-muted-foreground/70">{t('portal.resetPassword.confirmPassword', 'Confirm New Password')}</Label>
150
+ <Input id="confirm-password" type="password" autoComplete="new-password" required placeholder={t('portal.resetPassword.confirmPassword.placeholder', '••••••••')} value={confirmPassword} onChange={(e) => setConfirmPassword(e.target.value)} disabled={submitting || !token} className="rounded-lg" />
151
+ </div>
152
+
153
+ <Button type="submit" disabled={submitting || !token} className="mt-1 w-full rounded-lg">
154
+ {submitting ? t('portal.resetPassword.submitting', 'Resetting password...') : t('portal.resetPassword.submit', 'Reset Password')}
155
+ </Button>
156
+
157
+ <p className="text-center text-sm text-muted-foreground">
158
+ {t('portal.resetPassword.backToLogin', 'Remember your password?')}{' '}
159
+ <Link href={`/${orgSlug}/portal/login`} className="font-medium text-foreground underline underline-offset-4 hover:opacity-80">
160
+ {t('portal.resetPassword.loginLink', 'Sign in')}
161
+ </Link>
162
+ </p>
163
+ </form>
164
+
165
+ <InjectionSpot spotId={PortalInjectionSpots.pageAfter('reset-password')} context={injectionContext} />
166
+ </div>
167
+ )
168
+ }
@@ -52,6 +52,7 @@
52
52
  "portal.nav.login": "Anmelden",
53
53
  "portal.nav.logout": "Abmelden",
54
54
  "portal.nav.profile": "Profil",
55
+ "portal.nav.resetPassword": "Passwort zurücksetzen",
55
56
  "portal.nav.signup": "Registrieren",
56
57
  "portal.notifications.badge": "{count} ungelesen",
57
58
  "portal.notifications.daysAgo": "vor {d} Tagen",
@@ -73,6 +74,25 @@
73
74
  "portal.org.noOrganization": "Kein Organisationskontext verfügbar.",
74
75
  "portal.profile.label": "Konto",
75
76
  "portal.profile.title": "Profil",
77
+ "portal.resetPassword.backToLogin": "Erinnern Sie sich an Ihr Passwort?",
78
+ "portal.resetPassword.confirmPassword": "Neues Passwort bestätigen",
79
+ "portal.resetPassword.confirmPassword.placeholder": "••••••••",
80
+ "portal.resetPassword.description": "Geben Sie unten Ihr neues Passwort ein.",
81
+ "portal.resetPassword.error.generic": "Passwort-Zurücksetzung fehlgeschlagen. Bitte versuchen Sie es erneut.",
82
+ "portal.resetPassword.error.invalidToken": "Ungültiges oder abgelaufenes Zurücksetzungs-Token.",
83
+ "portal.resetPassword.error.noToken": "Ungültiges oder fehlendes Zurücksetzungs-Token.",
84
+ "portal.resetPassword.error.passwordMismatch": "Passwörter stimmen nicht überein.",
85
+ "portal.resetPassword.error.passwordTooShort": "Das Passwort muss mindestens 8 Zeichen lang sein.",
86
+ "portal.resetPassword.loginLink": "Anmelden",
87
+ "portal.resetPassword.password": "Neues Passwort",
88
+ "portal.resetPassword.password.placeholder": "••••••••",
89
+ "portal.resetPassword.submit": "Passwort zurücksetzen",
90
+ "portal.resetPassword.submitting": "Passwort wird zurückgesetzt…",
91
+ "portal.resetPassword.success.description": "Ihr Passwort wurde erfolgreich zurückgesetzt.",
92
+ "portal.resetPassword.success.loginLink": "Zur Anmeldung",
93
+ "portal.resetPassword.success.message": "Sie können sich jetzt mit Ihrem neuen Passwort anmelden.",
94
+ "portal.resetPassword.success.title": "Passwort zurückgesetzt",
95
+ "portal.resetPassword.title": "Passwort zurücksetzen",
76
96
  "portal.signup.description": "Registrieren Sie ein neues Kundenkonto.",
77
97
  "portal.signup.displayName": "Anzeigename",
78
98
  "portal.signup.displayName.placeholder": "Ihr Name",
@@ -52,6 +52,7 @@
52
52
  "portal.nav.login": "Log In",
53
53
  "portal.nav.logout": "Log Out",
54
54
  "portal.nav.profile": "Profile",
55
+ "portal.nav.resetPassword": "Reset Password",
55
56
  "portal.nav.signup": "Sign Up",
56
57
  "portal.notifications.badge": "{count} unread",
57
58
  "portal.notifications.daysAgo": "{d}d ago",
@@ -73,6 +74,25 @@
73
74
  "portal.org.noOrganization": "No organization context available.",
74
75
  "portal.profile.label": "Account",
75
76
  "portal.profile.title": "Profile",
77
+ "portal.resetPassword.backToLogin": "Remember your password?",
78
+ "portal.resetPassword.confirmPassword": "Confirm New Password",
79
+ "portal.resetPassword.confirmPassword.placeholder": "••••••••",
80
+ "portal.resetPassword.description": "Enter your new password below.",
81
+ "portal.resetPassword.error.generic": "Password reset failed. Please try again.",
82
+ "portal.resetPassword.error.invalidToken": "Invalid or expired reset token.",
83
+ "portal.resetPassword.error.noToken": "Invalid or missing reset token.",
84
+ "portal.resetPassword.error.passwordMismatch": "Passwords do not match.",
85
+ "portal.resetPassword.error.passwordTooShort": "Password must be at least 8 characters long.",
86
+ "portal.resetPassword.loginLink": "Sign in",
87
+ "portal.resetPassword.password": "New Password",
88
+ "portal.resetPassword.password.placeholder": "••••••••",
89
+ "portal.resetPassword.submit": "Reset Password",
90
+ "portal.resetPassword.submitting": "Resetting password…",
91
+ "portal.resetPassword.success.description": "Your password has been successfully reset.",
92
+ "portal.resetPassword.success.loginLink": "Go to Sign In",
93
+ "portal.resetPassword.success.message": "You can now sign in with your new password.",
94
+ "portal.resetPassword.success.title": "Password Reset Complete",
95
+ "portal.resetPassword.title": "Reset Password",
76
96
  "portal.signup.description": "Register for a new customer account.",
77
97
  "portal.signup.displayName": "Display Name",
78
98
  "portal.signup.displayName.placeholder": "Your name",
@@ -52,6 +52,7 @@
52
52
  "portal.nav.login": "Iniciar sesión",
53
53
  "portal.nav.logout": "Cerrar sesión",
54
54
  "portal.nav.profile": "Perfil",
55
+ "portal.nav.resetPassword": "Restablecer contraseña",
55
56
  "portal.nav.signup": "Registrarse",
56
57
  "portal.notifications.badge": "{count} sin leer",
57
58
  "portal.notifications.daysAgo": "hace {d} días",
@@ -73,6 +74,25 @@
73
74
  "portal.org.noOrganization": "No hay contexto de organización disponible.",
74
75
  "portal.profile.label": "Cuenta",
75
76
  "portal.profile.title": "Perfil",
77
+ "portal.resetPassword.backToLogin": "¿Recuerdas tu contraseña?",
78
+ "portal.resetPassword.confirmPassword": "Confirmar nueva contraseña",
79
+ "portal.resetPassword.confirmPassword.placeholder": "••••••••",
80
+ "portal.resetPassword.description": "Introduce tu nueva contraseña a continuación.",
81
+ "portal.resetPassword.error.generic": "El restablecimiento de la contraseña falló. Inténtalo de nuevo.",
82
+ "portal.resetPassword.error.invalidToken": "Token de restablecimiento no válido o expirado.",
83
+ "portal.resetPassword.error.noToken": "Token de restablecimiento no válido o faltante.",
84
+ "portal.resetPassword.error.passwordMismatch": "Las contraseñas no coinciden.",
85
+ "portal.resetPassword.error.passwordTooShort": "La contraseña debe tener al menos 8 caracteres.",
86
+ "portal.resetPassword.loginLink": "Iniciar sesión",
87
+ "portal.resetPassword.password": "Nueva contraseña",
88
+ "portal.resetPassword.password.placeholder": "••••••••",
89
+ "portal.resetPassword.submit": "Restablecer contraseña",
90
+ "portal.resetPassword.submitting": "Restableciendo contraseña…",
91
+ "portal.resetPassword.success.description": "Tu contraseña se ha restablecido correctamente.",
92
+ "portal.resetPassword.success.loginLink": "Ir a Iniciar sesión",
93
+ "portal.resetPassword.success.message": "Ahora puedes iniciar sesión con tu nueva contraseña.",
94
+ "portal.resetPassword.success.title": "Contraseña restablecida",
95
+ "portal.resetPassword.title": "Restablecer contraseña",
76
96
  "portal.signup.description": "Regístrate para una nueva cuenta de cliente.",
77
97
  "portal.signup.displayName": "Nombre para mostrar",
78
98
  "portal.signup.displayName.placeholder": "Tu nombre",