@open-mercato/core 0.4.2-canary-07dbc98202 → 0.4.2-canary-11e19dfb84
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/dist/generated/entities.ids.generated.js +59 -63
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +0 -2
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/api_docs/frontend/docs/api/page.js +2 -3
- package/dist/modules/api_docs/frontend/docs/api/page.js.map +2 -2
- package/dist/modules/auth/api/admin/nav.js +3 -4
- package/dist/modules/auth/api/admin/nav.js.map +2 -2
- package/dist/modules/auth/api/reset/confirm.js +2 -25
- package/dist/modules/auth/api/reset/confirm.js.map +2 -2
- package/dist/modules/auth/api/reset.js +0 -23
- package/dist/modules/auth/api/reset.js.map +2 -2
- package/dist/modules/auth/api/sidebar/preferences/route.js +9 -14
- package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
- package/dist/modules/auth/commands/users.js +0 -55
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/auth/lib/setup-app.js +0 -1
- package/dist/modules/auth/lib/setup-app.js.map +2 -2
- package/dist/modules/auth/services/authService.js +3 -3
- package/dist/modules/auth/services/authService.js.map +2 -2
- package/dist/modules/configs/cli.js +0 -6
- package/dist/modules/configs/cli.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +0 -31
- package/dist/modules/customers/commands/deals.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +0 -53
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/commands/payments.js +0 -26
- package/dist/modules/sales/commands/payments.js.map +2 -2
- package/dist/modules/staff/commands/leave-requests.js +0 -79
- package/dist/modules/staff/commands/leave-requests.js.map +2 -2
- package/generated/entities.ids.generated.ts +59 -63
- package/generated/entity-fields-registry.ts +0 -2
- package/package.json +2 -2
- package/src/modules/api_docs/frontend/docs/api/page.tsx +2 -3
- package/src/modules/auth/api/admin/nav.ts +6 -10
- package/src/modules/auth/api/reset/confirm.ts +2 -25
- package/src/modules/auth/api/reset.ts +0 -23
- package/src/modules/auth/api/sidebar/preferences/route.ts +12 -21
- package/src/modules/auth/commands/users.ts +0 -68
- package/src/modules/auth/i18n/de.json +1 -29
- package/src/modules/auth/i18n/en.json +1 -29
- package/src/modules/auth/i18n/es.json +1 -29
- package/src/modules/auth/i18n/pl.json +1 -29
- package/src/modules/auth/lib/setup-app.ts +0 -1
- package/src/modules/auth/services/authService.ts +4 -4
- package/src/modules/business_rules/i18n/en.json +1 -3
- package/src/modules/catalog/i18n/en.json +1 -3
- package/src/modules/configs/cli.ts +0 -6
- package/src/modules/customers/commands/deals.ts +0 -39
- package/src/modules/customers/i18n/en.json +1 -5
- package/src/modules/sales/commands/documents.ts +0 -65
- package/src/modules/sales/commands/payments.ts +0 -33
- package/src/modules/sales/i18n/de.json +0 -20
- package/src/modules/sales/i18n/en.json +1 -25
- package/src/modules/sales/i18n/es.json +0 -20
- package/src/modules/sales/i18n/pl.json +0 -20
- package/src/modules/staff/commands/leave-requests.ts +0 -94
- package/src/modules/staff/i18n/de.json +0 -4
- package/src/modules/staff/i18n/en.json +1 -9
- package/src/modules/staff/i18n/es.json +0 -4
- package/src/modules/staff/i18n/pl.json +0 -4
- package/src/modules/workflows/i18n/en.json +1 -3
- package/dist/generated/entities/notification/index.js +0 -57
- package/dist/generated/entities/notification/index.js.map +0 -7
- package/dist/modules/auth/api/profile/route.js +0 -155
- package/dist/modules/auth/api/profile/route.js.map +0 -7
- package/dist/modules/auth/backend/auth/profile/page.js +0 -99
- package/dist/modules/auth/backend/auth/profile/page.js.map +0 -7
- package/dist/modules/auth/backend/auth/profile/page.meta.js +0 -12
- package/dist/modules/auth/backend/auth/profile/page.meta.js.map +0 -7
- package/dist/modules/auth/notifications.js +0 -112
- package/dist/modules/auth/notifications.js.map +0 -7
- package/dist/modules/business_rules/notifications.js +0 -28
- package/dist/modules/business_rules/notifications.js.map +0 -7
- package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js +0 -37
- package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js.map +0 -7
- package/dist/modules/catalog/notifications.js +0 -28
- package/dist/modules/catalog/notifications.js.map +0 -7
- package/dist/modules/catalog/subscribers/low-stock-notification.js +0 -38
- package/dist/modules/catalog/subscribers/low-stock-notification.js.map +0 -7
- package/dist/modules/customers/notifications.js +0 -48
- package/dist/modules/customers/notifications.js.map +0 -7
- package/dist/modules/notifications/acl.js +0 -11
- package/dist/modules/notifications/acl.js.map +0 -7
- package/dist/modules/notifications/api/[id]/action/route.js +0 -74
- package/dist/modules/notifications/api/[id]/action/route.js.map +0 -7
- package/dist/modules/notifications/api/[id]/dismiss/route.js +0 -15
- package/dist/modules/notifications/api/[id]/dismiss/route.js.map +0 -7
- package/dist/modules/notifications/api/[id]/read/route.js +0 -15
- package/dist/modules/notifications/api/[id]/read/route.js.map +0 -7
- package/dist/modules/notifications/api/[id]/restore/route.js +0 -53
- package/dist/modules/notifications/api/[id]/restore/route.js.map +0 -7
- package/dist/modules/notifications/api/batch/route.js +0 -17
- package/dist/modules/notifications/api/batch/route.js.map +0 -7
- package/dist/modules/notifications/api/feature/route.js +0 -17
- package/dist/modules/notifications/api/feature/route.js.map +0 -7
- package/dist/modules/notifications/api/mark-all-read/route.js +0 -35
- package/dist/modules/notifications/api/mark-all-read/route.js.map +0 -7
- package/dist/modules/notifications/api/openapi.js +0 -76
- package/dist/modules/notifications/api/openapi.js.map +0 -7
- package/dist/modules/notifications/api/role/route.js +0 -17
- package/dist/modules/notifications/api/role/route.js.map +0 -7
- package/dist/modules/notifications/api/route.js +0 -85
- package/dist/modules/notifications/api/route.js.map +0 -7
- package/dist/modules/notifications/api/settings/route.js +0 -155
- package/dist/modules/notifications/api/settings/route.js.map +0 -7
- package/dist/modules/notifications/api/unread-count/route.js +0 -38
- package/dist/modules/notifications/api/unread-count/route.js.map +0 -7
- package/dist/modules/notifications/backend/config/notifications/page.js +0 -10
- package/dist/modules/notifications/backend/config/notifications/page.js.map +0 -7
- package/dist/modules/notifications/backend/config/notifications/page.meta.js +0 -24
- package/dist/modules/notifications/backend/config/notifications/page.meta.js.map +0 -7
- package/dist/modules/notifications/cli.js +0 -16
- package/dist/modules/notifications/cli.js.map +0 -7
- package/dist/modules/notifications/data/entities.js +0 -112
- package/dist/modules/notifications/data/entities.js.map +0 -7
- package/dist/modules/notifications/data/validators.js +0 -94
- package/dist/modules/notifications/data/validators.js.map +0 -7
- package/dist/modules/notifications/di.js +0 -13
- package/dist/modules/notifications/di.js.map +0 -7
- package/dist/modules/notifications/emails/NotificationEmail.js +0 -58
- package/dist/modules/notifications/emails/NotificationEmail.js.map +0 -7
- package/dist/modules/notifications/frontend/NotificationInboxPageClient.js +0 -44
- package/dist/modules/notifications/frontend/NotificationInboxPageClient.js.map +0 -7
- package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js +0 -219
- package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js.map +0 -7
- package/dist/modules/notifications/index.js +0 -14
- package/dist/modules/notifications/index.js.map +0 -7
- package/dist/modules/notifications/lib/deliveryConfig.js +0 -105
- package/dist/modules/notifications/lib/deliveryConfig.js.map +0 -7
- package/dist/modules/notifications/lib/events.js +0 -12
- package/dist/modules/notifications/lib/events.js.map +0 -7
- package/dist/modules/notifications/lib/notificationBuilder.js +0 -66
- package/dist/modules/notifications/lib/notificationBuilder.js.map +0 -7
- package/dist/modules/notifications/lib/notificationFactory.js +0 -54
- package/dist/modules/notifications/lib/notificationFactory.js.map +0 -7
- package/dist/modules/notifications/lib/notificationMapper.js +0 -34
- package/dist/modules/notifications/lib/notificationMapper.js.map +0 -7
- package/dist/modules/notifications/lib/notificationRecipients.js +0 -35
- package/dist/modules/notifications/lib/notificationRecipients.js.map +0 -7
- package/dist/modules/notifications/lib/notificationService.js +0 -279
- package/dist/modules/notifications/lib/notificationService.js.map +0 -7
- package/dist/modules/notifications/lib/routeHelpers.js +0 -101
- package/dist/modules/notifications/lib/routeHelpers.js.map +0 -7
- package/dist/modules/notifications/lib/safeHref.js +0 -24
- package/dist/modules/notifications/lib/safeHref.js.map +0 -7
- package/dist/modules/notifications/migrations/Migration20260123000001.js +0 -70
- package/dist/modules/notifications/migrations/Migration20260123000001.js.map +0 -7
- package/dist/modules/notifications/migrations/Migration20260126150000.js +0 -37
- package/dist/modules/notifications/migrations/Migration20260126150000.js.map +0 -7
- package/dist/modules/notifications/subscribers/deliver-notification.js +0 -139
- package/dist/modules/notifications/subscribers/deliver-notification.js.map +0 -7
- package/dist/modules/notifications/workers/create-notification.worker.js +0 -70
- package/dist/modules/notifications/workers/create-notification.worker.js.map +0 -7
- package/dist/modules/sales/notifications.client.js +0 -51
- package/dist/modules/sales/notifications.client.js.map +0 -7
- package/dist/modules/sales/notifications.js +0 -88
- package/dist/modules/sales/notifications.js.map +0 -7
- package/dist/modules/sales/subscribers/quote-expiring-notification.js +0 -38
- package/dist/modules/sales/subscribers/quote-expiring-notification.js.map +0 -7
- package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js +0 -137
- package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js.map +0 -7
- package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js +0 -137
- package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js.map +0 -7
- package/dist/modules/sales/widgets/notifications/index.js +0 -7
- package/dist/modules/sales/widgets/notifications/index.js.map +0 -7
- package/dist/modules/sales/widgets/notifications/useSalesDocumentTotals.js +0 -60
- package/dist/modules/sales/widgets/notifications/useSalesDocumentTotals.js.map +0 -7
- package/dist/modules/staff/notifications.js +0 -75
- package/dist/modules/staff/notifications.js.map +0 -7
- package/dist/modules/workflows/notifications.js +0 -28
- package/dist/modules/workflows/notifications.js.map +0 -7
- package/dist/modules/workflows/subscribers/task-assigned-notification.js +0 -38
- package/dist/modules/workflows/subscribers/task-assigned-notification.js.map +0 -7
- package/generated/entities/notification/index.ts +0 -27
- package/src/modules/auth/api/profile/route.ts +0 -160
- package/src/modules/auth/backend/auth/profile/page.meta.ts +0 -8
- package/src/modules/auth/backend/auth/profile/page.tsx +0 -127
- package/src/modules/auth/notifications.ts +0 -109
- package/src/modules/business_rules/notifications.ts +0 -25
- package/src/modules/business_rules/subscribers/rule-execution-failed-notification.ts +0 -50
- package/src/modules/catalog/notifications.ts +0 -25
- package/src/modules/catalog/subscribers/low-stock-notification.ts +0 -52
- package/src/modules/customers/notifications.ts +0 -44
- package/src/modules/notifications/acl.ts +0 -7
- package/src/modules/notifications/api/[id]/action/route.ts +0 -75
- package/src/modules/notifications/api/[id]/dismiss/route.ts +0 -12
- package/src/modules/notifications/api/[id]/read/route.ts +0 -12
- package/src/modules/notifications/api/[id]/restore/route.ts +0 -53
- package/src/modules/notifications/api/batch/route.ts +0 -14
- package/src/modules/notifications/api/feature/route.ts +0 -14
- package/src/modules/notifications/api/mark-all-read/route.ts +0 -34
- package/src/modules/notifications/api/openapi.ts +0 -76
- package/src/modules/notifications/api/role/route.ts +0 -14
- package/src/modules/notifications/api/route.ts +0 -92
- package/src/modules/notifications/api/settings/route.ts +0 -157
- package/src/modules/notifications/api/unread-count/route.ts +0 -38
- package/src/modules/notifications/backend/config/notifications/page.meta.ts +0 -22
- package/src/modules/notifications/backend/config/notifications/page.tsx +0 -12
- package/src/modules/notifications/cli.ts +0 -18
- package/src/modules/notifications/data/entities.ts +0 -99
- package/src/modules/notifications/data/validators.ts +0 -110
- package/src/modules/notifications/di.ts +0 -11
- package/src/modules/notifications/emails/NotificationEmail.tsx +0 -98
- package/src/modules/notifications/frontend/NotificationInboxPageClient.tsx +0 -42
- package/src/modules/notifications/frontend/NotificationSettingsPageClient.tsx +0 -231
- package/src/modules/notifications/i18n/de.json +0 -50
- package/src/modules/notifications/i18n/en.json +0 -50
- package/src/modules/notifications/i18n/es.json +0 -50
- package/src/modules/notifications/i18n/pl.json +0 -50
- package/src/modules/notifications/index.ts +0 -12
- package/src/modules/notifications/lib/deliveryConfig.ts +0 -145
- package/src/modules/notifications/lib/events.ts +0 -48
- package/src/modules/notifications/lib/notificationBuilder.ts +0 -121
- package/src/modules/notifications/lib/notificationFactory.ts +0 -76
- package/src/modules/notifications/lib/notificationMapper.ts +0 -33
- package/src/modules/notifications/lib/notificationRecipients.ts +0 -83
- package/src/modules/notifications/lib/notificationService.ts +0 -414
- package/src/modules/notifications/lib/routeHelpers.ts +0 -151
- package/src/modules/notifications/lib/safeHref.ts +0 -29
- package/src/modules/notifications/migrations/.snapshot-open-mercato.json +0 -300
- package/src/modules/notifications/migrations/Migration20260123000001.ts +0 -73
- package/src/modules/notifications/migrations/Migration20260126150000.ts +0 -39
- package/src/modules/notifications/subscribers/deliver-notification.ts +0 -175
- package/src/modules/notifications/workers/create-notification.worker.ts +0 -122
- package/src/modules/sales/notifications.client.ts +0 -65
- package/src/modules/sales/notifications.ts +0 -82
- package/src/modules/sales/subscribers/quote-expiring-notification.ts +0 -53
- package/src/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.tsx +0 -156
- package/src/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.tsx +0 -156
- package/src/modules/sales/widgets/notifications/index.ts +0 -2
- package/src/modules/sales/widgets/notifications/useSalesDocumentTotals.ts +0 -81
- package/src/modules/staff/notifications.ts +0 -71
- package/src/modules/workflows/notifications.ts +0 -25
- package/src/modules/workflows/subscribers/task-assigned-notification.ts +0 -53
|
@@ -9,26 +9,6 @@
|
|
|
9
9
|
"title": "Vertriebsmanagement",
|
|
10
10
|
"description": "Angebote, Aufträge, Fulfillment, Rechnungsstellung und Zahlungen verbunden mit dem Produktkatalog."
|
|
11
11
|
},
|
|
12
|
-
"notifications": {
|
|
13
|
-
"order": {
|
|
14
|
-
"created": {
|
|
15
|
-
"title": "Neue Bestellung",
|
|
16
|
-
"body": "Bestellung {orderNumber} wurde erstellt{total}"
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
"quote": {
|
|
20
|
-
"created": {
|
|
21
|
-
"title": "Neues Angebot",
|
|
22
|
-
"body": "Angebot {quoteNumber} wurde erstellt{total}"
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
"renderer": {
|
|
26
|
-
"viewOrder": "Bestellung anzeigen",
|
|
27
|
-
"viewQuote": "Angebot anzeigen",
|
|
28
|
-
"assignedToYou": "Ihnen zugewiesen",
|
|
29
|
-
"pendingReview": "Ausstehende Prüfung"
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
12
|
"quotes": {
|
|
33
13
|
"send": {
|
|
34
14
|
"action": "An Kunden senden",
|
|
@@ -9,26 +9,6 @@
|
|
|
9
9
|
"title": "Sales Management",
|
|
10
10
|
"description": "Quotes, orders, fulfillment, invoicing, and payments connected to the product catalog."
|
|
11
11
|
},
|
|
12
|
-
"notifications": {
|
|
13
|
-
"order": {
|
|
14
|
-
"created": {
|
|
15
|
-
"title": "New Sales Order",
|
|
16
|
-
"body": "Sales order {orderNumber} has been created{total}"
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
"quote": {
|
|
20
|
-
"created": {
|
|
21
|
-
"title": "New Sales Quote",
|
|
22
|
-
"body": "Sales quote {quoteNumber} has been created{total}"
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
"renderer": {
|
|
26
|
-
"viewOrder": "View Order",
|
|
27
|
-
"viewQuote": "View Quote",
|
|
28
|
-
"assignedToYou": "Assigned to you",
|
|
29
|
-
"pendingReview": "Pending review"
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
12
|
"quotes": {
|
|
33
13
|
"send": {
|
|
34
14
|
"action": "Send to customer",
|
|
@@ -1536,9 +1516,5 @@
|
|
|
1536
1516
|
"sales.search.badge.deliveryWindow": "Delivery window",
|
|
1537
1517
|
"sales.search.badge.paymentMethod": "Payment method",
|
|
1538
1518
|
"sales.search.badge.taxRate": "Tax rate",
|
|
1539
|
-
"sales.search.badge.documentTag": "Document tag"
|
|
1540
|
-
"sales.notifications.payment.received.title": "Payment Received",
|
|
1541
|
-
"sales.notifications.payment.received.body": "Payment of {amount} received for order #{orderNumber}",
|
|
1542
|
-
"sales.notifications.quote.expiring.title": "Quote Expiring Soon",
|
|
1543
|
-
"sales.notifications.quote.expiring.body": "Quote #{quoteNumber} expires in {daysUntilExpiry} days ({expiresAt})"
|
|
1519
|
+
"sales.search.badge.documentTag": "Document tag"
|
|
1544
1520
|
}
|
|
@@ -9,26 +9,6 @@
|
|
|
9
9
|
"title": "Gestión de ventas",
|
|
10
10
|
"description": "Cotizaciones, pedidos, cumplimiento, facturación y pagos conectados al catálogo de productos."
|
|
11
11
|
},
|
|
12
|
-
"notifications": {
|
|
13
|
-
"order": {
|
|
14
|
-
"created": {
|
|
15
|
-
"title": "Nuevo pedido de venta",
|
|
16
|
-
"body": "El pedido {orderNumber} ha sido creado{total}"
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
"quote": {
|
|
20
|
-
"created": {
|
|
21
|
-
"title": "Nueva cotización",
|
|
22
|
-
"body": "La cotización {quoteNumber} ha sido creada{total}"
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
"renderer": {
|
|
26
|
-
"viewOrder": "Ver pedido",
|
|
27
|
-
"viewQuote": "Ver cotización",
|
|
28
|
-
"assignedToYou": "Asignado a usted",
|
|
29
|
-
"pendingReview": "Pendiente de revisión"
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
12
|
"quotes": {
|
|
33
13
|
"send": {
|
|
34
14
|
"action": "Enviar al cliente",
|
|
@@ -9,26 +9,6 @@
|
|
|
9
9
|
"title": "Sprzedaż",
|
|
10
10
|
"description": "Oferty, zamówienia, realizacja, fakturowanie i płatności powiązane z katalogiem produktów."
|
|
11
11
|
},
|
|
12
|
-
"notifications": {
|
|
13
|
-
"order": {
|
|
14
|
-
"created": {
|
|
15
|
-
"title": "Nowe zamówienie",
|
|
16
|
-
"body": "Zamówienie {orderNumber} zostało utworzone{total}"
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
"quote": {
|
|
20
|
-
"created": {
|
|
21
|
-
"title": "Nowa oferta",
|
|
22
|
-
"body": "Oferta {quoteNumber} została utworzona{total}"
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
"renderer": {
|
|
26
|
-
"viewOrder": "Zobacz zamówienie",
|
|
27
|
-
"viewQuote": "Zobacz ofertę",
|
|
28
|
-
"assignedToYou": "Przypisane do Ciebie",
|
|
29
|
-
"pendingReview": "Oczekuje na przegląd"
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
12
|
"quotes": {
|
|
33
13
|
"send": {
|
|
34
14
|
"action": "Wyślij do klienta",
|
|
@@ -21,9 +21,6 @@ import {
|
|
|
21
21
|
} from '../data/validators'
|
|
22
22
|
import { ensureOrganizationScope, ensureTenantScope, extractUndoPayload, requireTeamMember } from './shared'
|
|
23
23
|
import { E } from '#generated/entities.ids.generated'
|
|
24
|
-
import { resolveNotificationService } from '../../notifications/lib/notificationService'
|
|
25
|
-
import { buildFeatureNotificationFromType, buildNotificationFromType } from '../../notifications/lib/notificationBuilder'
|
|
26
|
-
import { notificationTypes } from '../notifications'
|
|
27
24
|
|
|
28
25
|
const leaveRequestCrudIndexer: CrudIndexerConfig<StaffLeaveRequest> = {
|
|
29
26
|
entityType: E.staff.staff_leave_request,
|
|
@@ -261,36 +258,6 @@ const createLeaveRequestCommand: CommandHandler<StaffLeaveRequestCreateInput, {
|
|
|
261
258
|
indexer: leaveRequestCrudIndexer,
|
|
262
259
|
})
|
|
263
260
|
|
|
264
|
-
// Create notification for users who can approve/reject leave requests
|
|
265
|
-
try {
|
|
266
|
-
const notificationService = resolveNotificationService(ctx.container)
|
|
267
|
-
const typeDef = notificationTypes.find((type) => type.type === 'staff.leave_request.pending')
|
|
268
|
-
if (typeDef) {
|
|
269
|
-
const memberName = member.displayName || 'Team member'
|
|
270
|
-
const startDateStr = request.startDate.toLocaleDateString()
|
|
271
|
-
const endDateStr = request.endDate.toLocaleDateString()
|
|
272
|
-
|
|
273
|
-
const notificationInput = buildFeatureNotificationFromType(typeDef, {
|
|
274
|
-
requiredFeature: 'staff.leave_requests.manage',
|
|
275
|
-
bodyVariables: {
|
|
276
|
-
memberName,
|
|
277
|
-
startDate: startDateStr,
|
|
278
|
-
endDate: endDateStr,
|
|
279
|
-
},
|
|
280
|
-
sourceEntityType: 'staff:leave_request',
|
|
281
|
-
sourceEntityId: request.id,
|
|
282
|
-
linkHref: `/backend/staff/leave-requests/${request.id}`,
|
|
283
|
-
})
|
|
284
|
-
|
|
285
|
-
await notificationService.createForFeature(notificationInput, {
|
|
286
|
-
tenantId: request.tenantId,
|
|
287
|
-
organizationId: request.organizationId,
|
|
288
|
-
})
|
|
289
|
-
}
|
|
290
|
-
} catch {
|
|
291
|
-
// Notification creation is non-critical, don't fail the command
|
|
292
|
-
}
|
|
293
|
-
|
|
294
261
|
return { requestId: request.id }
|
|
295
262
|
},
|
|
296
263
|
captureAfter: async (_input, result, ctx) => {
|
|
@@ -608,36 +575,6 @@ const acceptLeaveRequestCommand: CommandHandler<StaffLeaveRequestDecisionInput,
|
|
|
608
575
|
ruleIds: createdRuleIds,
|
|
609
576
|
})
|
|
610
577
|
|
|
611
|
-
// Send notification to the requester
|
|
612
|
-
if (request.submittedByUserId) {
|
|
613
|
-
try {
|
|
614
|
-
const notificationService = resolveNotificationService(ctx.container)
|
|
615
|
-
const typeDef = notificationTypes.find((type) => type.type === 'staff.leave_request.approved')
|
|
616
|
-
if (typeDef) {
|
|
617
|
-
const startDateStr = request.startDate.toLocaleDateString()
|
|
618
|
-
const endDateStr = request.endDate.toLocaleDateString()
|
|
619
|
-
|
|
620
|
-
const notificationInput = buildNotificationFromType(typeDef, {
|
|
621
|
-
recipientUserId: request.submittedByUserId,
|
|
622
|
-
bodyVariables: {
|
|
623
|
-
startDate: startDateStr,
|
|
624
|
-
endDate: endDateStr,
|
|
625
|
-
},
|
|
626
|
-
sourceEntityType: 'staff:leave_request',
|
|
627
|
-
sourceEntityId: request.id,
|
|
628
|
-
linkHref: `/backend/staff/leave-requests/${request.id}`,
|
|
629
|
-
})
|
|
630
|
-
|
|
631
|
-
await notificationService.create(notificationInput, {
|
|
632
|
-
tenantId: request.tenantId,
|
|
633
|
-
organizationId: request.organizationId,
|
|
634
|
-
})
|
|
635
|
-
}
|
|
636
|
-
} catch {
|
|
637
|
-
// Notification creation is non-critical, don't fail the command
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
|
|
641
578
|
return { requestId: request.id, ruleIds: createdRuleIds }
|
|
642
579
|
},
|
|
643
580
|
buildLog: async ({ result, ctx, snapshots }) => {
|
|
@@ -759,37 +696,6 @@ const rejectLeaveRequestCommand: CommandHandler<StaffLeaveRequestDecisionInput,
|
|
|
759
696
|
indexer: leaveRequestCrudIndexer,
|
|
760
697
|
})
|
|
761
698
|
|
|
762
|
-
// Send notification to the requester
|
|
763
|
-
if (request.submittedByUserId) {
|
|
764
|
-
try {
|
|
765
|
-
const notificationService = resolveNotificationService(ctx.container)
|
|
766
|
-
const typeDef = notificationTypes.find((type) => type.type === 'staff.leave_request.rejected')
|
|
767
|
-
if (typeDef) {
|
|
768
|
-
const startDateStr = request.startDate.toLocaleDateString()
|
|
769
|
-
const endDateStr = request.endDate.toLocaleDateString()
|
|
770
|
-
|
|
771
|
-
const notificationInput = buildNotificationFromType(typeDef, {
|
|
772
|
-
recipientUserId: request.submittedByUserId,
|
|
773
|
-
bodyVariables: {
|
|
774
|
-
startDate: startDateStr,
|
|
775
|
-
endDate: endDateStr,
|
|
776
|
-
reason: request.decisionComment ?? '',
|
|
777
|
-
},
|
|
778
|
-
sourceEntityType: 'staff:leave_request',
|
|
779
|
-
sourceEntityId: request.id,
|
|
780
|
-
linkHref: `/backend/staff/leave-requests/${request.id}`,
|
|
781
|
-
})
|
|
782
|
-
|
|
783
|
-
await notificationService.create(notificationInput, {
|
|
784
|
-
tenantId: request.tenantId,
|
|
785
|
-
organizationId: request.organizationId,
|
|
786
|
-
})
|
|
787
|
-
}
|
|
788
|
-
} catch {
|
|
789
|
-
// Notification creation is non-critical, don't fail the command
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
|
|
793
699
|
return { requestId: request.id }
|
|
794
700
|
},
|
|
795
701
|
async prepare(rawInput, ctx) {
|
|
@@ -797,10 +797,6 @@
|
|
|
797
797
|
"staff.teams.tabs.details": "Details",
|
|
798
798
|
"staff.teams.tabs.label": "Teamabschnitte",
|
|
799
799
|
"staff.teams.tabs.members": "Teammitglieder",
|
|
800
|
-
"staff.notifications.leaveRequest.pending.title": "Urlaubsantrag ausstehend",
|
|
801
|
-
"staff.notifications.leaveRequest.pending.body": "{memberName} hat Urlaub vom {startDate} bis {endDate} beantragt",
|
|
802
|
-
"staff.notifications.leaveRequest.actions.approve": "Genehmigen",
|
|
803
|
-
"staff.notifications.leaveRequest.actions.reject": "Ablehnen",
|
|
804
800
|
"staff.leaveRequests.page.title": "Urlaubsantr\u00e4ge",
|
|
805
801
|
"staff.leaveRequests.page.description": "Urlaubsantr\u00e4ge des Teams pr\u00fcfen.",
|
|
806
802
|
"staff.leaveRequests.my.title": "Meine Urlaubsantr\u00e4ge",
|
|
@@ -797,10 +797,6 @@
|
|
|
797
797
|
"staff.teams.tabs.details": "Details",
|
|
798
798
|
"staff.teams.tabs.label": "Team sections",
|
|
799
799
|
"staff.teams.tabs.members": "Team members",
|
|
800
|
-
"staff.notifications.leaveRequest.pending.title": "Leave Request Pending",
|
|
801
|
-
"staff.notifications.leaveRequest.pending.body": "{memberName} has requested leave from {startDate} to {endDate}",
|
|
802
|
-
"staff.notifications.leaveRequest.actions.approve": "Approve",
|
|
803
|
-
"staff.notifications.leaveRequest.actions.reject": "Reject",
|
|
804
800
|
"staff.leaveRequests.page.title": "Leave requests",
|
|
805
801
|
"staff.leaveRequests.page.description": "Review leave requests from your team.",
|
|
806
802
|
"staff.leaveRequests.my.title": "My leave requests",
|
|
@@ -878,9 +874,5 @@
|
|
|
878
874
|
"staff.myAvailability.readOnly.body": "Use leave requests to request changes.",
|
|
879
875
|
"staff.teamMembers.self.createTitle": "Create my profile",
|
|
880
876
|
"staff.teamMembers.self.created": "Profile created.",
|
|
881
|
-
"staff.teamMembers.self.exists": "Team member profile already exists."
|
|
882
|
-
"staff.notifications.leaveRequest.approved.title": "Leave Request Approved",
|
|
883
|
-
"staff.notifications.leaveRequest.approved.body": "Your leave request from {startDate} to {endDate} has been approved",
|
|
884
|
-
"staff.notifications.leaveRequest.rejected.title": "Leave Request Rejected",
|
|
885
|
-
"staff.notifications.leaveRequest.rejected.body": "Your leave request from {startDate} to {endDate} has been rejected{reason, select, other { - {reason}}}"
|
|
877
|
+
"staff.teamMembers.self.exists": "Team member profile already exists."
|
|
886
878
|
}
|
|
@@ -797,10 +797,6 @@
|
|
|
797
797
|
"staff.teams.tabs.details": "Detalles",
|
|
798
798
|
"staff.teams.tabs.label": "Secciones del equipo",
|
|
799
799
|
"staff.teams.tabs.members": "Miembros del equipo",
|
|
800
|
-
"staff.notifications.leaveRequest.pending.title": "Solicitud de ausencia pendiente",
|
|
801
|
-
"staff.notifications.leaveRequest.pending.body": "{memberName} ha solicitado ausencia del {startDate} al {endDate}",
|
|
802
|
-
"staff.notifications.leaveRequest.actions.approve": "Aprobar",
|
|
803
|
-
"staff.notifications.leaveRequest.actions.reject": "Rechazar",
|
|
804
800
|
"staff.leaveRequests.page.title": "Solicitudes de ausencia",
|
|
805
801
|
"staff.leaveRequests.page.description": "Revisa las solicitudes de ausencia del equipo.",
|
|
806
802
|
"staff.leaveRequests.my.title": "Mis solicitudes de ausencia",
|
|
@@ -797,10 +797,6 @@
|
|
|
797
797
|
"staff.teams.tabs.details": "Szczeg\u00f3\u0142y",
|
|
798
798
|
"staff.teams.tabs.label": "Sekcje zespo\u0142u",
|
|
799
799
|
"staff.teams.tabs.members": "Cz\u0142onkowie zespo\u0142u",
|
|
800
|
-
"staff.notifications.leaveRequest.pending.title": "Wniosek urlopowy oczekuje",
|
|
801
|
-
"staff.notifications.leaveRequest.pending.body": "{memberName} zło\u017cył wniosek o urlop od {startDate} do {endDate}",
|
|
802
|
-
"staff.notifications.leaveRequest.actions.approve": "Zatwierd\u017a",
|
|
803
|
-
"staff.notifications.leaveRequest.actions.reject": "Odrzu\u0107",
|
|
804
800
|
"staff.leaveRequests.page.title": "Wnioski urlopowe",
|
|
805
801
|
"staff.leaveRequests.page.description": "Przegl\u0105daj wnioski urlopowe zespo\u0142u.",
|
|
806
802
|
"staff.leaveRequests.my.title": "Moje wnioski urlopowe",
|
|
@@ -676,7 +676,5 @@
|
|
|
676
676
|
"success": "Sub-workflow completed successfully",
|
|
677
677
|
"failed": "Sub-workflow failed"
|
|
678
678
|
}
|
|
679
|
-
}
|
|
680
|
-
"workflows.notifications.task.assigned.title": "Task Assigned",
|
|
681
|
-
"workflows.notifications.task.assigned.body": "You have been assigned to task \"{taskName}\" in workflow \"{workflowName}\"{dueDate, select, other { (due: {dueDate})}}"
|
|
679
|
+
}
|
|
682
680
|
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
const id = "id";
|
|
2
|
-
const recipient_user_id = "recipient_user_id";
|
|
3
|
-
const type = "type";
|
|
4
|
-
const title_key = "title_key";
|
|
5
|
-
const body_key = "body_key";
|
|
6
|
-
const title_variables = "title_variables";
|
|
7
|
-
const body_variables = "body_variables";
|
|
8
|
-
const title = "title";
|
|
9
|
-
const body = "body";
|
|
10
|
-
const icon = "icon";
|
|
11
|
-
const severity = "severity";
|
|
12
|
-
const status = "status";
|
|
13
|
-
const action_data = "action_data";
|
|
14
|
-
const action_result = "action_result";
|
|
15
|
-
const action_taken = "action_taken";
|
|
16
|
-
const source_module = "source_module";
|
|
17
|
-
const source_entity_type = "source_entity_type";
|
|
18
|
-
const source_entity_id = "source_entity_id";
|
|
19
|
-
const link_href = "link_href";
|
|
20
|
-
const group_key = "group_key";
|
|
21
|
-
const created_at = "created_at";
|
|
22
|
-
const read_at = "read_at";
|
|
23
|
-
const actioned_at = "actioned_at";
|
|
24
|
-
const dismissed_at = "dismissed_at";
|
|
25
|
-
const expires_at = "expires_at";
|
|
26
|
-
const tenant_id = "tenant_id";
|
|
27
|
-
const organization_id = "organization_id";
|
|
28
|
-
export {
|
|
29
|
-
action_data,
|
|
30
|
-
action_result,
|
|
31
|
-
action_taken,
|
|
32
|
-
actioned_at,
|
|
33
|
-
body,
|
|
34
|
-
body_key,
|
|
35
|
-
body_variables,
|
|
36
|
-
created_at,
|
|
37
|
-
dismissed_at,
|
|
38
|
-
expires_at,
|
|
39
|
-
group_key,
|
|
40
|
-
icon,
|
|
41
|
-
id,
|
|
42
|
-
link_href,
|
|
43
|
-
organization_id,
|
|
44
|
-
read_at,
|
|
45
|
-
recipient_user_id,
|
|
46
|
-
severity,
|
|
47
|
-
source_entity_id,
|
|
48
|
-
source_entity_type,
|
|
49
|
-
source_module,
|
|
50
|
-
status,
|
|
51
|
-
tenant_id,
|
|
52
|
-
title,
|
|
53
|
-
title_key,
|
|
54
|
-
title_variables,
|
|
55
|
-
type
|
|
56
|
-
};
|
|
57
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../generated/entities/notification/index.ts"],
|
|
4
|
-
"sourcesContent": ["export const id = 'id'\nexport const recipient_user_id = 'recipient_user_id'\nexport const type = 'type'\nexport const title_key = 'title_key'\nexport const body_key = 'body_key'\nexport const title_variables = 'title_variables'\nexport const body_variables = 'body_variables'\nexport const title = 'title'\nexport const body = 'body'\nexport const icon = 'icon'\nexport const severity = 'severity'\nexport const status = 'status'\nexport const action_data = 'action_data'\nexport const action_result = 'action_result'\nexport const action_taken = 'action_taken'\nexport const source_module = 'source_module'\nexport const source_entity_type = 'source_entity_type'\nexport const source_entity_id = 'source_entity_id'\nexport const link_href = 'link_href'\nexport const group_key = 'group_key'\nexport const created_at = 'created_at'\nexport const read_at = 'read_at'\nexport const actioned_at = 'actioned_at'\nexport const dismissed_at = 'dismissed_at'\nexport const expires_at = 'expires_at'\nexport const tenant_id = 'tenant_id'\nexport const organization_id = 'organization_id'\n"],
|
|
5
|
-
"mappings": "AAAO,MAAM,KAAK;AACX,MAAM,oBAAoB;AAC1B,MAAM,OAAO;AACb,MAAM,YAAY;AAClB,MAAM,WAAW;AACjB,MAAM,kBAAkB;AACxB,MAAM,iBAAiB;AACvB,MAAM,QAAQ;AACd,MAAM,OAAO;AACb,MAAM,OAAO;AACb,MAAM,WAAW;AACjB,MAAM,SAAS;AACf,MAAM,cAAc;AACpB,MAAM,gBAAgB;AACtB,MAAM,eAAe;AACrB,MAAM,gBAAgB;AACtB,MAAM,qBAAqB;AAC3B,MAAM,mBAAmB;AACzB,MAAM,YAAY;AAClB,MAAM,YAAY;AAClB,MAAM,aAAa;AACnB,MAAM,UAAU;AAChB,MAAM,cAAc;AACpB,MAAM,eAAe;AACrB,MAAM,aAAa;AACnB,MAAM,YAAY;AAClB,MAAM,kBAAkB;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
4
|
-
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
5
|
-
import { signJwt } from "@open-mercato/shared/lib/auth/jwt";
|
|
6
|
-
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
7
|
-
import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
8
|
-
import { User } from "@open-mercato/core/modules/auth/data/entities";
|
|
9
|
-
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
10
|
-
const profileResponseSchema = z.object({
|
|
11
|
-
email: z.string().email()
|
|
12
|
-
});
|
|
13
|
-
const updateSchema = z.object({
|
|
14
|
-
email: z.string().email().optional(),
|
|
15
|
-
password: z.string().min(6).optional()
|
|
16
|
-
}).refine((data) => Boolean(data.email || data.password), {
|
|
17
|
-
message: "Provide an email or password.",
|
|
18
|
-
path: ["email"]
|
|
19
|
-
});
|
|
20
|
-
const profileUpdateResponseSchema = z.object({
|
|
21
|
-
ok: z.literal(true),
|
|
22
|
-
email: z.string().email()
|
|
23
|
-
});
|
|
24
|
-
const metadata = {
|
|
25
|
-
GET: { requireAuth: true },
|
|
26
|
-
PUT: { requireAuth: true }
|
|
27
|
-
};
|
|
28
|
-
function buildCommandContext(container, auth, req) {
|
|
29
|
-
return {
|
|
30
|
-
container,
|
|
31
|
-
auth,
|
|
32
|
-
organizationScope: null,
|
|
33
|
-
selectedOrganizationId: auth.orgId ?? null,
|
|
34
|
-
organizationIds: auth.orgId ? [auth.orgId] : null,
|
|
35
|
-
request: req
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
async function GET(req) {
|
|
39
|
-
const { translate } = await resolveTranslations();
|
|
40
|
-
const auth = await getAuthFromRequest(req);
|
|
41
|
-
if (!auth?.sub) {
|
|
42
|
-
return NextResponse.json({ error: translate("api.errors.unauthorized", "Unauthorized") }, { status: 401 });
|
|
43
|
-
}
|
|
44
|
-
try {
|
|
45
|
-
const container = await createRequestContainer();
|
|
46
|
-
const em = container.resolve("em");
|
|
47
|
-
const user = await findOneWithDecryption(
|
|
48
|
-
em,
|
|
49
|
-
User,
|
|
50
|
-
{ id: auth.sub, deletedAt: null },
|
|
51
|
-
void 0,
|
|
52
|
-
{ tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null }
|
|
53
|
-
);
|
|
54
|
-
if (!user) {
|
|
55
|
-
return NextResponse.json({ error: translate("auth.users.form.errors.notFound", "User not found") }, { status: 404 });
|
|
56
|
-
}
|
|
57
|
-
return NextResponse.json({ email: String(user.email) });
|
|
58
|
-
} catch (err) {
|
|
59
|
-
console.error("auth.profile.load failed", err);
|
|
60
|
-
return NextResponse.json({ error: translate("auth.profile.form.errors.load", "Failed to load profile.") }, { status: 400 });
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
async function PUT(req) {
|
|
64
|
-
const { translate } = await resolveTranslations();
|
|
65
|
-
const auth = await getAuthFromRequest(req);
|
|
66
|
-
if (!auth?.sub) {
|
|
67
|
-
return NextResponse.json({ error: translate("api.errors.unauthorized", "Unauthorized") }, { status: 401 });
|
|
68
|
-
}
|
|
69
|
-
try {
|
|
70
|
-
const body = await req.json().catch(() => ({}));
|
|
71
|
-
const parsed = updateSchema.safeParse(body);
|
|
72
|
-
if (!parsed.success) {
|
|
73
|
-
return NextResponse.json(
|
|
74
|
-
{
|
|
75
|
-
error: translate("auth.profile.form.errors.invalid", "Invalid profile update."),
|
|
76
|
-
issues: parsed.error.issues
|
|
77
|
-
},
|
|
78
|
-
{ status: 400 }
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
const container = await createRequestContainer();
|
|
82
|
-
const commandBus = container.resolve("commandBus");
|
|
83
|
-
const ctx = buildCommandContext(container, auth, req);
|
|
84
|
-
const { result } = await commandBus.execute(
|
|
85
|
-
"auth.users.update",
|
|
86
|
-
{
|
|
87
|
-
input: {
|
|
88
|
-
id: auth.sub,
|
|
89
|
-
email: parsed.data.email,
|
|
90
|
-
password: parsed.data.password
|
|
91
|
-
},
|
|
92
|
-
ctx
|
|
93
|
-
}
|
|
94
|
-
);
|
|
95
|
-
const authService = container.resolve("authService");
|
|
96
|
-
const roles = await authService.getUserRoles(result, result.tenantId ? String(result.tenantId) : null);
|
|
97
|
-
const jwt = signJwt({
|
|
98
|
-
sub: String(result.id),
|
|
99
|
-
tenantId: result.tenantId ? String(result.tenantId) : null,
|
|
100
|
-
orgId: result.organizationId ? String(result.organizationId) : null,
|
|
101
|
-
email: result.email,
|
|
102
|
-
roles
|
|
103
|
-
});
|
|
104
|
-
const res = NextResponse.json({ ok: true, email: String(result.email) });
|
|
105
|
-
res.cookies.set("auth_token", jwt, {
|
|
106
|
-
httpOnly: true,
|
|
107
|
-
path: "/",
|
|
108
|
-
sameSite: "lax",
|
|
109
|
-
secure: process.env.NODE_ENV === "production",
|
|
110
|
-
maxAge: 60 * 60 * 8
|
|
111
|
-
});
|
|
112
|
-
return res;
|
|
113
|
-
} catch (err) {
|
|
114
|
-
if (err instanceof CrudHttpError) {
|
|
115
|
-
return NextResponse.json(err.body, { status: err.status });
|
|
116
|
-
}
|
|
117
|
-
console.error("auth.profile.update failed", err);
|
|
118
|
-
return NextResponse.json({ error: translate("auth.profile.form.errors.save", "Failed to update profile.") }, { status: 400 });
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
const openApi = {
|
|
122
|
-
tag: "Authentication & Accounts",
|
|
123
|
-
summary: "Profile settings",
|
|
124
|
-
methods: {
|
|
125
|
-
GET: {
|
|
126
|
-
summary: "Get current profile",
|
|
127
|
-
description: "Returns the email address for the signed-in user.",
|
|
128
|
-
responses: [
|
|
129
|
-
{ status: 200, description: "Profile payload", schema: profileResponseSchema },
|
|
130
|
-
{ status: 401, description: "Unauthorized", schema: z.object({ error: z.string() }) },
|
|
131
|
-
{ status: 404, description: "User not found", schema: z.object({ error: z.string() }) }
|
|
132
|
-
]
|
|
133
|
-
},
|
|
134
|
-
PUT: {
|
|
135
|
-
summary: "Update current profile",
|
|
136
|
-
description: "Updates the email address or password for the signed-in user.",
|
|
137
|
-
requestBody: {
|
|
138
|
-
contentType: "application/json",
|
|
139
|
-
schema: updateSchema
|
|
140
|
-
},
|
|
141
|
-
responses: [
|
|
142
|
-
{ status: 200, description: "Profile updated", schema: profileUpdateResponseSchema },
|
|
143
|
-
{ status: 400, description: "Invalid payload", schema: z.object({ error: z.string() }) },
|
|
144
|
-
{ status: 401, description: "Unauthorized", schema: z.object({ error: z.string() }) }
|
|
145
|
-
]
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
export {
|
|
150
|
-
GET,
|
|
151
|
-
PUT,
|
|
152
|
-
metadata,
|
|
153
|
-
openApi
|
|
154
|
-
};
|
|
155
|
-
//# sourceMappingURL=route.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../../src/modules/auth/api/profile/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { signJwt } from '@open-mercato/shared/lib/auth/jwt'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { AuthService } from '@open-mercato/core/modules/auth/services/authService'\nimport { User } from '@open-mercato/core/modules/auth/data/entities'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\n\nconst profileResponseSchema = z.object({\n email: z.string().email(),\n})\n\nconst updateSchema = z.object({\n email: z.string().email().optional(),\n password: z.string().min(6).optional(),\n}).refine((data) => Boolean(data.email || data.password), {\n message: 'Provide an email or password.',\n path: ['email'],\n})\n\nconst profileUpdateResponseSchema = z.object({\n ok: z.literal(true),\n email: z.string().email(),\n})\n\nexport const metadata = {\n GET: { requireAuth: true },\n PUT: { requireAuth: true },\n}\n\nfunction buildCommandContext(container: Awaited<ReturnType<typeof createRequestContainer>>, auth: NonNullable<Awaited<ReturnType<typeof getAuthFromRequest>>>, req: Request): CommandRuntimeContext {\n return {\n container,\n auth,\n organizationScope: null,\n selectedOrganizationId: auth.orgId ?? null,\n organizationIds: auth.orgId ? [auth.orgId] : null,\n request: req,\n }\n}\n\nexport async function GET(req: Request) {\n const { translate } = await resolveTranslations()\n const auth = await getAuthFromRequest(req)\n if (!auth?.sub) {\n return NextResponse.json({ error: translate('api.errors.unauthorized', 'Unauthorized') }, { status: 401 })\n }\n try {\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager)\n const user = await findOneWithDecryption(\n em,\n User,\n { id: auth.sub, deletedAt: null },\n undefined,\n { tenantId: auth.tenantId ?? null, organizationId: auth.orgId ?? null },\n )\n if (!user) {\n return NextResponse.json({ error: translate('auth.users.form.errors.notFound', 'User not found') }, { status: 404 })\n }\n return NextResponse.json({ email: String(user.email) })\n } catch (err) {\n console.error('auth.profile.load failed', err)\n return NextResponse.json({ error: translate('auth.profile.form.errors.load', 'Failed to load profile.') }, { status: 400 })\n }\n}\n\nexport async function PUT(req: Request) {\n const { translate } = await resolveTranslations()\n const auth = await getAuthFromRequest(req)\n if (!auth?.sub) {\n return NextResponse.json({ error: translate('api.errors.unauthorized', 'Unauthorized') }, { status: 401 })\n }\n try {\n const body = await req.json().catch(() => ({}))\n const parsed = updateSchema.safeParse(body)\n if (!parsed.success) {\n return NextResponse.json(\n {\n error: translate('auth.profile.form.errors.invalid', 'Invalid profile update.'),\n issues: parsed.error.issues,\n },\n { status: 400 },\n )\n }\n const container = await createRequestContainer()\n const commandBus = (container.resolve('commandBus') as CommandBus)\n const ctx = buildCommandContext(container, auth, req)\n const { result } = await commandBus.execute<{ id: string; email?: string; password?: string }, User>(\n 'auth.users.update',\n {\n input: {\n id: auth.sub,\n email: parsed.data.email,\n password: parsed.data.password,\n },\n ctx,\n },\n )\n const authService = container.resolve('authService') as AuthService\n const roles = await authService.getUserRoles(result, result.tenantId ? String(result.tenantId) : null)\n const jwt = signJwt({\n sub: String(result.id),\n tenantId: result.tenantId ? String(result.tenantId) : null,\n orgId: result.organizationId ? String(result.organizationId) : null,\n email: result.email,\n roles,\n })\n const res = NextResponse.json({ ok: true, email: String(result.email) })\n res.cookies.set('auth_token', jwt, {\n httpOnly: true,\n path: '/',\n sameSite: 'lax',\n secure: process.env.NODE_ENV === 'production',\n maxAge: 60 * 60 * 8,\n })\n return res\n } catch (err) {\n if (err instanceof CrudHttpError) {\n return NextResponse.json(err.body, { status: err.status })\n }\n console.error('auth.profile.update failed', err)\n return NextResponse.json({ error: translate('auth.profile.form.errors.save', 'Failed to update profile.') }, { status: 400 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Authentication & Accounts',\n summary: 'Profile settings',\n methods: {\n GET: {\n summary: 'Get current profile',\n description: 'Returns the email address for the signed-in user.',\n responses: [\n { status: 200, description: 'Profile payload', schema: profileResponseSchema },\n { status: 401, description: 'Unauthorized', schema: z.object({ error: z.string() }) },\n { status: 404, description: 'User not found', schema: z.object({ error: z.string() }) },\n ],\n },\n PUT: {\n summary: 'Update current profile',\n description: 'Updates the email address or password for the signed-in user.',\n requestBody: {\n contentType: 'application/json',\n schema: updateSchema,\n },\n responses: [\n { status: 200, description: 'Profile updated', schema: profileUpdateResponseSchema },\n { status: 400, description: 'Invalid payload', schema: z.object({ error: z.string() }) },\n { status: 401, description: 'Unauthorized', schema: z.object({ error: z.string() }) },\n ],\n },\n },\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx } from "react/jsx-runtime";
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
import { useRouter } from "next/navigation";
|
|
5
|
-
import { Page, PageBody } from "@open-mercato/ui/backend/Page";
|
|
6
|
-
import { CrudForm } from "@open-mercato/ui/backend/CrudForm";
|
|
7
|
-
import { apiCall, readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
|
|
8
|
-
import { createCrudFormError } from "@open-mercato/ui/backend/utils/serverErrors";
|
|
9
|
-
import { flash } from "@open-mercato/ui/backend/FlashMessages";
|
|
10
|
-
import { LoadingMessage, ErrorMessage } from "@open-mercato/ui/backend/detail";
|
|
11
|
-
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
12
|
-
function AuthProfilePage() {
|
|
13
|
-
const t = useT();
|
|
14
|
-
const router = useRouter();
|
|
15
|
-
const [loading, setLoading] = React.useState(true);
|
|
16
|
-
const [error, setError] = React.useState(null);
|
|
17
|
-
const [email, setEmail] = React.useState("");
|
|
18
|
-
const [formKey, setFormKey] = React.useState(0);
|
|
19
|
-
React.useEffect(() => {
|
|
20
|
-
let cancelled = false;
|
|
21
|
-
async function load() {
|
|
22
|
-
setLoading(true);
|
|
23
|
-
setError(null);
|
|
24
|
-
try {
|
|
25
|
-
const { ok, result } = await apiCall("/api/auth/profile");
|
|
26
|
-
if (!ok) throw new Error("load_failed");
|
|
27
|
-
const resolvedEmail = typeof result?.email === "string" ? result.email : "";
|
|
28
|
-
if (!cancelled) setEmail(resolvedEmail);
|
|
29
|
-
} catch (err) {
|
|
30
|
-
console.error("Failed to load auth profile", err);
|
|
31
|
-
if (!cancelled) setError(t("auth.profile.form.errors.load", "Failed to load profile."));
|
|
32
|
-
} finally {
|
|
33
|
-
if (!cancelled) setLoading(false);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
load();
|
|
37
|
-
return () => {
|
|
38
|
-
cancelled = true;
|
|
39
|
-
};
|
|
40
|
-
}, [t]);
|
|
41
|
-
const fields = React.useMemo(() => [
|
|
42
|
-
{ id: "email", label: t("auth.profile.form.email", "Email"), type: "text", required: true },
|
|
43
|
-
{ id: "password", label: t("auth.profile.form.password", "New password"), type: "text" },
|
|
44
|
-
{ id: "confirmPassword", label: t("auth.profile.form.confirmPassword", "Confirm new password"), type: "text" }
|
|
45
|
-
], [t]);
|
|
46
|
-
const handleSubmit = React.useCallback(async (values) => {
|
|
47
|
-
const nextEmail = values.email?.trim() ?? "";
|
|
48
|
-
const password = values.password?.trim() ?? "";
|
|
49
|
-
const confirmPassword = values.confirmPassword?.trim() ?? "";
|
|
50
|
-
if (!nextEmail) {
|
|
51
|
-
const message = t("auth.profile.form.errors.emailRequired", "Email is required.");
|
|
52
|
-
throw createCrudFormError(message, { email: message });
|
|
53
|
-
}
|
|
54
|
-
if (password || confirmPassword) {
|
|
55
|
-
if (password !== confirmPassword) {
|
|
56
|
-
const message = t("auth.profile.form.errors.passwordMismatch", "Passwords do not match.");
|
|
57
|
-
throw createCrudFormError(message, { confirmPassword: message });
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
if (!password && nextEmail === email) {
|
|
61
|
-
throw createCrudFormError(t("auth.profile.form.errors.noChanges", "No changes to save."));
|
|
62
|
-
}
|
|
63
|
-
const payload = { email: nextEmail };
|
|
64
|
-
if (password) payload.password = password;
|
|
65
|
-
const result = await readApiResultOrThrow(
|
|
66
|
-
"/api/auth/profile",
|
|
67
|
-
{
|
|
68
|
-
method: "PUT",
|
|
69
|
-
headers: { "content-type": "application/json" },
|
|
70
|
-
body: JSON.stringify(payload)
|
|
71
|
-
},
|
|
72
|
-
{ errorMessage: t("auth.profile.form.errors.save", "Failed to update profile.") }
|
|
73
|
-
);
|
|
74
|
-
const resolvedEmail = typeof result?.email === "string" ? result.email : nextEmail;
|
|
75
|
-
setEmail(resolvedEmail);
|
|
76
|
-
setFormKey((prev) => prev + 1);
|
|
77
|
-
flash(t("auth.profile.form.success", "Profile updated."), "success");
|
|
78
|
-
router.refresh();
|
|
79
|
-
}, [email, router, t]);
|
|
80
|
-
return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: loading ? /* @__PURE__ */ jsx(LoadingMessage, { label: t("auth.profile.form.loading", "Loading profile...") }) : error ? /* @__PURE__ */ jsx(ErrorMessage, { label: error }) : /* @__PURE__ */ jsx(
|
|
81
|
-
CrudForm,
|
|
82
|
-
{
|
|
83
|
-
title: t("auth.profile.title", "Profile"),
|
|
84
|
-
fields,
|
|
85
|
-
initialValues: {
|
|
86
|
-
email,
|
|
87
|
-
password: "",
|
|
88
|
-
confirmPassword: ""
|
|
89
|
-
},
|
|
90
|
-
submitLabel: t("auth.profile.form.save", "Save changes"),
|
|
91
|
-
onSubmit: handleSubmit
|
|
92
|
-
},
|
|
93
|
-
formKey
|
|
94
|
-
) }) });
|
|
95
|
-
}
|
|
96
|
-
export {
|
|
97
|
-
AuthProfilePage as default
|
|
98
|
-
};
|
|
99
|
-
//# sourceMappingURL=page.js.map
|