@carlonicora/nextjs-jsonapi 4.1.2 → 4.2.1
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/{AssistantMessageInterface-CubxuBIJ.d.ts → AssistantMessageInterface-DHJJO_Z_.d.ts} +1 -1
- package/dist/{AssistantMessageInterface-sHjI2zPN.d.mts → AssistantMessageInterface-S7oyERTT.d.mts} +1 -1
- package/dist/{BlockNoteEditor-VOYKZOP5.mjs → BlockNoteEditor-HXAHDJA7.mjs} +34 -27
- package/dist/BlockNoteEditor-HXAHDJA7.mjs.map +1 -0
- package/dist/{BlockNoteEditor-BENYTTCZ.js → BlockNoteEditor-LLCZDFLZ.js} +50 -43
- package/dist/BlockNoteEditor-LLCZDFLZ.js.map +1 -0
- package/dist/{BlockNoteViewer-USLR4Y7C.js → BlockNoteViewer-77CCTC2U.js} +3 -3
- package/dist/{BlockNoteViewer-USLR4Y7C.js.map → BlockNoteViewer-77CCTC2U.js.map} +1 -1
- package/dist/{BlockNoteViewer-Y2ZM4ESA.mjs → BlockNoteViewer-MDPO6BXN.mjs} +2 -2
- package/dist/{auth.interface-Df4vXbNz.d.mts → auth.interface-CeFCz9NU.d.mts} +1 -1
- package/dist/{auth.interface-BzI4onI_.d.ts → auth.interface-D1R7VVky.d.ts} +1 -1
- package/dist/billing/index.d.mts +40 -6
- package/dist/billing/index.d.ts +40 -6
- package/dist/billing/index.js +806 -774
- package/dist/billing/index.js.map +1 -1
- package/dist/billing/index.mjs +494 -462
- package/dist/billing/index.mjs.map +1 -1
- package/dist/{chunk-6ISF5KNQ.mjs → chunk-2VXDZRYY.mjs} +1103 -816
- package/dist/chunk-2VXDZRYY.mjs.map +1 -0
- package/dist/{chunk-4BZJ4LAB.js → chunk-4ORLPEK7.js} +136 -104
- package/dist/chunk-4ORLPEK7.js.map +1 -0
- package/dist/{chunk-ZZ6E33FO.mjs → chunk-6DRSSW5O.mjs} +36 -4
- package/dist/chunk-6DRSSW5O.mjs.map +1 -0
- package/dist/{chunk-KS6WZP2E.js → chunk-6SMJRAE3.js} +4 -4
- package/dist/{chunk-KS6WZP2E.js.map → chunk-6SMJRAE3.js.map} +1 -1
- package/dist/{chunk-WQ77CUUZ.js → chunk-GPXYQMOZ.js} +7 -7
- package/dist/{chunk-WQ77CUUZ.js.map → chunk-GPXYQMOZ.js.map} +1 -1
- package/dist/{chunk-46S3KPLU.mjs → chunk-ILFFC6BG.mjs} +2 -2
- package/dist/{chunk-HZVVRIJQ.mjs → chunk-IUS2RHCX.mjs} +2 -2
- package/dist/{chunk-F7RNBGHS.js → chunk-KJMMBUOA.js} +3 -3
- package/dist/{chunk-F7RNBGHS.js.map → chunk-KJMMBUOA.js.map} +1 -1
- package/dist/{chunk-ZO3QQ5CQ.mjs → chunk-MQDR6MEE.mjs} +2 -2
- package/dist/{chunk-ORU7KLCY.js → chunk-VDVIUDY5.js} +1445 -1158
- package/dist/chunk-VDVIUDY5.js.map +1 -0
- package/dist/client/index.d.mts +20 -6
- package/dist/client/index.d.ts +20 -6
- package/dist/client/index.js +6 -4
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +5 -3
- package/dist/components/index.d.mts +59 -21
- package/dist/components/index.d.ts +59 -21
- package/dist/components/index.js +4 -4
- package/dist/components/index.mjs +3 -3
- package/dist/{config-CEAq4Ozy.d.mts → config-BP2vyddw.d.mts} +5 -0
- package/dist/{config-DydDHCfb.d.ts → config-BhW2QrRD.d.ts} +5 -0
- package/dist/contexts/index.d.mts +4 -4
- package/dist/contexts/index.d.ts +4 -4
- package/dist/contexts/index.js +4 -4
- package/dist/contexts/index.mjs +3 -3
- package/dist/core/index.d.mts +17 -9
- package/dist/core/index.d.ts +17 -9
- package/dist/core/index.js +4 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +3 -1
- package/dist/features/analytics/index.d.mts +1 -1
- package/dist/features/analytics/index.d.ts +1 -1
- package/dist/features/analytics/index.js +122 -122
- package/dist/features/analytics/index.mjs +4 -4
- package/dist/features/analytics/server.js +4 -4
- package/dist/features/analytics/server.mjs +2 -2
- package/dist/features/help/index.d.mts +1 -1
- package/dist/features/help/index.d.ts +1 -1
- package/dist/features/help/index.js +42 -40
- package/dist/features/help/index.js.map +1 -1
- package/dist/features/help/index.mjs +8 -6
- package/dist/features/help/index.mjs.map +1 -1
- package/dist/features/tokenusage/index.js +125 -125
- package/dist/features/tokenusage/index.mjs +4 -4
- package/dist/index.d.mts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4 -2
- package/dist/{notification.interface-P_pNfzZQ.d.mts → notification.interface-BB6GPpZY.d.mts} +1 -1
- package/dist/{notification.interface-BNCvnVCW.d.ts → notification.interface-CmAGrijJ.d.ts} +1 -1
- package/dist/{s3.service-CbUa6a-8.d.ts → s3.service-C-4YpEMu.d.ts} +7 -3
- package/dist/{s3.service-DAp8FbuG.d.mts → s3.service-dVj-nxMl.d.mts} +7 -3
- package/dist/server/index.d.mts +4 -4
- package/dist/server/index.d.ts +4 -4
- package/dist/server/index.js +3 -3
- package/dist/server/index.mjs +2 -2
- package/dist/{useSocket-BHVIyigI.d.ts → useSocket-B0H9pmmH.d.ts} +1 -1
- package/dist/{useSocket-B9gTbuCj.d.mts → useSocket-B5RQb6v2.d.mts} +1 -1
- package/dist/{user.interface-CrmwJLYW.d.ts → user.interface-C0ZdsBZj.d.ts} +2 -0
- package/dist/{user.interface-CSaGWFbg.d.mts → user.interface-CIWGlbqM.d.mts} +2 -0
- package/package.json +1 -1
- package/src/components/containers/RoundPageContainer.tsx +3 -1
- package/src/components/containers/RoundPageContainerTitle.tsx +5 -2
- package/src/components/editors/BlockNoteEditor.tsx +31 -15
- package/src/components/editors/BlockNoteEditorAiActions.tsx +11 -7
- package/src/components/editors/__tests__/{BlockNoteEditorAiActions.test.ts → BlockNoteEditorAiActions.spec.ts} +10 -3
- package/src/components/errors/ErrorDetails.tsx +5 -2
- package/src/components/forms/CommonAssociationForm.tsx +1 -1
- package/src/components/forms/EntityMultiSelector.tsx +6 -2
- package/src/components/forms/EntitySelector.tsx +4 -1
- package/src/components/forms/FileUploader.tsx +3 -2
- package/src/components/forms/MultiFileUploader.tsx +3 -1
- package/src/components/navigations/Breadcrumb.tsx +3 -2
- package/src/components/navigations/Header.tsx +3 -1
- package/src/components/navigations/MobileNavigationBar.tsx +3 -1
- package/src/components/navigations/__tests__/Header.spec.tsx +2 -2
- package/src/components/tables/__tests__/ContentListTable.spec.tsx +1 -1
- package/src/components/tables/cells/cell.id.tsx +13 -2
- package/src/core/abstracts/AbstractService.ts +3 -3
- package/src/core/abstracts/ClientAbstractService.ts +3 -2
- package/src/features/assistant-action/components/ApprovalActionCard.tsx +74 -5
- package/src/features/assistant-action/components/__tests__/ApprovalActionCard.spec.tsx +81 -0
- package/src/features/assistant-message/components/parts/RelevanceMeter.tsx +4 -1
- package/src/features/assistant-message/components/parts/tabs/UsersTab.tsx +2 -1
- package/src/features/auth/components/buttons/GoogleSignInButton.tsx +4 -1
- package/src/features/auth/components/details/LandingComponent.tsx +1 -1
- package/src/features/auth/components/forms/ForgotPassword.tsx +1 -1
- package/src/features/auth/components/forms/Login.tsx +1 -1
- package/src/features/auth/components/forms/Register.tsx +1 -1
- package/src/features/auth/components/forms/ResetPassword.tsx +2 -2
- package/src/features/auth/components/two-factor/BackupCodesDialog.tsx +1 -1
- package/src/features/auth/components/two-factor/PasskeyButton.tsx +1 -1
- package/src/features/billing/components/cards/BillingUsageSummaryCard.tsx +21 -11
- package/src/features/billing/components/cards/CustomerInfoCard.tsx +16 -13
- package/src/features/billing/components/cards/InvoicesSummaryCard.tsx +33 -21
- package/src/features/billing/components/cards/PaymentMethodSummaryCard.tsx +20 -10
- package/src/features/billing/components/cards/SubscriptionSummaryCard.tsx +35 -22
- package/src/features/billing/components/containers/BillingDashboardContainer.tsx +24 -24
- package/src/features/billing/components/utils/__tests__/billing-formatters.spec.ts +63 -0
- package/src/features/billing/components/utils/currency.ts +67 -10
- package/src/features/billing/components/utils/date.ts +9 -4
- package/src/features/billing/components/utils/format-options.ts +20 -0
- package/src/features/billing/components/utils/index.ts +3 -1
- package/src/features/billing/components/utils/useBillingFormatOptions.ts +11 -0
- package/src/features/billing/components/widgets/BillingAlertBanner.tsx +8 -9
- package/src/features/billing/contexts/PriceContext.tsx +18 -6
- package/src/features/billing/i18n-keys.ts +212 -0
- package/src/features/billing/stripe-customer/components/containers/PaymentMethodsContainer.tsx +8 -8
- package/src/features/billing/stripe-customer/components/details/PaymentMethodCard.tsx +11 -9
- package/src/features/billing/stripe-customer/components/forms/PaymentMethodEditor.tsx +4 -4
- package/src/features/billing/stripe-customer/components/forms/PaymentMethodForm.tsx +9 -7
- package/src/features/billing/stripe-invoice/components/containers/InvoicesContainer.tsx +10 -8
- package/src/features/billing/stripe-invoice/components/details/InvoiceDetails.tsx +34 -29
- package/src/features/billing/stripe-invoice/components/lists/InvoicesList.tsx +12 -9
- package/src/features/billing/stripe-invoice/components/widgets/InvoiceStatusBadge.tsx +9 -6
- package/src/features/billing/stripe-price/components/details/PriceDetails.tsx +4 -3
- package/src/features/billing/stripe-price/components/forms/PriceArchiver.tsx +3 -1
- package/src/features/billing/stripe-price/components/forms/PriceEditor.tsx +3 -1
- package/src/features/billing/stripe-price/hooks/useStripePriceTableStructure.tsx +6 -5
- package/src/features/billing/stripe-promotion-code/components/PromoCodeInput.tsx +12 -7
- package/src/features/billing/stripe-promotion-code/data/stripe-promotion-code.service.ts +3 -1
- package/src/features/billing/stripe-subscription/components/containers/SubscriptionsContainer.tsx +10 -6
- package/src/features/billing/stripe-subscription/components/details/SubscriptionDetails.tsx +44 -29
- package/src/features/billing/stripe-subscription/components/forms/CancelSubscriptionDialog.tsx +14 -11
- package/src/features/billing/stripe-subscription/components/lists/SubscriptionsList.tsx +20 -17
- package/src/features/billing/stripe-subscription/components/widgets/IntervalToggle.tsx +4 -2
- package/src/features/billing/stripe-subscription/components/widgets/PricingCard.tsx +16 -7
- package/src/features/billing/stripe-subscription/components/widgets/ProductPricingList.tsx +3 -1
- package/src/features/billing/stripe-subscription/components/widgets/ProductPricingRow.tsx +3 -1
- package/src/features/billing/stripe-subscription/components/widgets/ProrationPreview.tsx +12 -7
- package/src/features/billing/stripe-subscription/components/widgets/SubscriptionConfirmation.tsx +11 -8
- package/src/features/billing/stripe-subscription/components/widgets/SubscriptionStatusBadge.tsx +13 -10
- package/src/features/billing/stripe-subscription/components/wizards/SubscriptionWizard.tsx +8 -6
- package/src/features/billing/stripe-subscription/components/wizards/WizardProgressIndicator.tsx +7 -4
- package/src/features/billing/stripe-subscription/components/wizards/WizardStepPaymentMethod.tsx +4 -2
- package/src/features/billing/stripe-subscription/components/wizards/WizardStepPlanSelection.tsx +3 -1
- package/src/features/billing/stripe-subscription/components/wizards/WizardStepReview.tsx +37 -28
- package/src/features/billing/stripe-subscription/hooks/useConfirmSubscriptionPayment.ts +9 -7
- package/src/features/billing/stripe-subscription/hooks/useSubscriptionWizard.ts +20 -9
- package/src/features/billing/stripe-usage/components/containers/UsageContainer.tsx +6 -6
- package/src/features/billing/stripe-usage/components/details/UsageSummaryCard.tsx +24 -9
- package/src/features/billing/stripe-usage/components/lists/UsageHistoryTable.tsx +16 -12
- package/src/features/company/components/details/TokenStatusIndicator.tsx +7 -5
- package/src/features/company/components/forms/CompanyEditor.tsx +2 -2
- package/src/features/help/components/HelpArticleBody.tsx +1 -1
- package/src/features/help/components/HelpHeader.tsx +1 -1
- package/src/features/help/components/HelpSideNav.tsx +1 -1
- package/src/features/help/i18n-keys.ts +2 -0
- package/src/features/notification/components/common/NotificationErrorBoundary.tsx +17 -12
- package/src/features/notification/components/containers/NotificationsListContainer.tsx +4 -2
- package/src/features/notification/components/notifications/Notification.tsx +6 -3
- package/src/features/notification/contexts/NotificationContext.tsx +9 -4
- package/src/features/notification/contexts/__tests__/NotificationContext.spec.tsx +13 -0
- package/src/features/notification/hooks/useNotificationTableStructure.tsx +4 -2
- package/src/features/oauth/components/OAuthClientCard.tsx +13 -7
- package/src/features/oauth/components/OAuthClientDetail.tsx +34 -30
- package/src/features/oauth/components/OAuthClientForm.tsx +24 -24
- package/src/features/oauth/components/OAuthClientList.tsx +10 -6
- package/src/features/oauth/components/OAuthClientSecretDisplay.tsx +10 -8
- package/src/features/oauth/components/OAuthRedirectUriInput.tsx +9 -13
- package/src/features/oauth/components/OAuthScopeSelector.tsx +15 -6
- package/src/features/oauth/components/__tests__/OAuthClientForm.spec.tsx +11 -9
- package/src/features/oauth/components/consent/OAuthScopeList.tsx +4 -2
- package/src/features/oauth/hooks/__tests__/useOAuthScopeText.spec.ts +30 -0
- package/src/features/oauth/hooks/index.ts +1 -0
- package/src/features/oauth/hooks/useOAuthClient.ts +11 -5
- package/src/features/oauth/hooks/useOAuthClients.ts +9 -3
- package/src/features/oauth/hooks/useOAuthConsent.ts +11 -5
- package/src/features/oauth/hooks/useOAuthScopeText.ts +33 -0
- package/src/features/rbac/components/RbacByRoleContainer.tsx +7 -6
- package/src/features/rbac/components/RbacContainer.tsx +7 -6
- package/src/features/rbac/contexts/RbacContext.tsx +3 -3
- package/src/features/user/components/containers/UserContainer.tsx +3 -1
- package/src/features/user/data/__tests__/user.spec.ts +66 -0
- package/src/features/user/data/user.interface.ts +2 -0
- package/src/features/user/data/user.service.ts +9 -0
- package/src/features/user/data/user.ts +7 -0
- package/src/features/waitlist/components/forms/WaitlistForm.tsx +1 -1
- package/src/features/waitlist/components/lists/WaitlistList.tsx +1 -1
- package/src/i18n/__tests__/{config.test.ts → config.spec.ts} +21 -1
- package/src/i18n/config.ts +13 -0
- package/src/i18n/index.ts +1 -0
- package/src/shadcnui/custom/multi-select.tsx +47 -14
- package/src/shadcnui/custom/multiple-selector.tsx +14 -2
- package/src/shadcnui/ui/__tests__/{confirm-dialog.test.tsx → confirm-dialog.spec.tsx} +1 -1
- package/src/shadcnui/ui/__tests__/{cursor-controls.test.tsx → cursor-controls.spec.tsx} +1 -1
- package/src/shadcnui/ui/__tests__/{cursor-menu-items.test.tsx → cursor-menu-items.spec.tsx} +1 -1
- package/src/shadcnui/ui/__tests__/{empty-state.test.tsx → empty-state.spec.tsx} +1 -1
- package/src/shadcnui/ui/__tests__/{spinner.test.tsx → spinner.spec.tsx} +1 -1
- package/src/shadcnui/ui/__tests__/use-ui-text.spec.tsx +76 -0
- package/src/shadcnui/ui/breadcrumb.tsx +9 -2
- package/src/shadcnui/ui/carousel.tsx +15 -4
- package/src/shadcnui/ui/dialog.tsx +15 -2
- package/src/shadcnui/ui/sheet.tsx +6 -1
- package/src/shadcnui/ui/sidebar.tsx +33 -7
- package/src/shadcnui/ui/spinner.tsx +6 -1
- package/src/shadcnui/ui/use-ui-text.ts +49 -0
- package/src/utils/__tests__/{date-formatter.test.ts → date-formatter.spec.ts} +24 -1
- package/src/utils/date-formatter.ts +16 -0
- package/src/utils/index.ts +1 -1
- package/dist/BlockNoteEditor-BENYTTCZ.js.map +0 -1
- package/dist/BlockNoteEditor-VOYKZOP5.mjs.map +0 -1
- package/dist/chunk-4BZJ4LAB.js.map +0 -1
- package/dist/chunk-6ISF5KNQ.mjs.map +0 -1
- package/dist/chunk-ORU7KLCY.js.map +0 -1
- package/dist/chunk-ZZ6E33FO.mjs.map +0 -1
- /package/dist/{BlockNoteViewer-Y2ZM4ESA.mjs.map → BlockNoteViewer-MDPO6BXN.mjs.map} +0 -0
- /package/dist/{chunk-46S3KPLU.mjs.map → chunk-ILFFC6BG.mjs.map} +0 -0
- /package/dist/{chunk-HZVVRIJQ.mjs.map → chunk-IUS2RHCX.mjs.map} +0 -0
- /package/dist/{chunk-ZO3QQ5CQ.mjs.map → chunk-MQDR6MEE.mjs.map} +0 -0
- /package/scripts/{check-rtl-classes.test.ts → check-rtl-classes.spec.ts} +0 -0
- /package/src/client/__tests__/{JsonApiClient.test.ts → JsonApiClient.spec.ts} +0 -0
- /package/src/client/__tests__/{request.test.ts → request.spec.ts} +0 -0
- /package/src/client/hooks/__tests__/{useJsonApiGet.test.tsx → useJsonApiGet.spec.tsx} +0 -0
- /package/src/client/hooks/__tests__/{useJsonApiMutation.test.tsx → useJsonApiMutation.spec.tsx} +0 -0
- /package/src/client/hooks/__tests__/{useRehydration.test.ts → useRehydration.spec.ts} +0 -0
- /package/src/components/editors/__tests__/{BlockNoteEditorMentionInlineContent.test.ts → BlockNoteEditorMentionInlineContent.spec.ts} +0 -0
- /package/src/components/forms/__tests__/{CommonEditorDiscardDialog.test.tsx → CommonEditorDiscardDialog.spec.tsx} +0 -0
- /package/src/components/forms/__tests__/{EditorSheet.test.tsx → EditorSheet.spec.tsx} +0 -0
- /package/src/components/forms/__tests__/{FormCheckbox.test.tsx → FormCheckbox.spec.tsx} +0 -0
- /package/src/components/forms/__tests__/{FormDate.test.tsx → FormDate.spec.tsx} +0 -0
- /package/src/components/forms/__tests__/{FormInput.test.tsx → FormInput.spec.tsx} +0 -0
- /package/src/components/forms/__tests__/{FormSelect.test.tsx → FormSelect.spec.tsx} +0 -0
- /package/src/components/forms/__tests__/{useEditorDialog.test.ts → useEditorDialog.spec.ts} +0 -0
- /package/src/components/grids/__tests__/{ContentListGrid.test.tsx → ContentListGrid.spec.tsx} +0 -0
- /package/src/components/tables/__tests__/{ContentListTable.test.tsx → ContentListTable.rendering.spec.tsx} +0 -0
- /package/src/contexts/__tests__/{DirectionContext.test.tsx → DirectionContext.spec.tsx} +0 -0
- /package/src/contexts/__tests__/{SessionContext.test.tsx → SessionContext.spec.tsx} +0 -0
- /package/src/contexts/__tests__/{SocketContext.session.test.tsx → SocketContext.session.spec.tsx} +0 -0
- /package/src/core/abstracts/__tests__/{AbstractService.locale.test.ts → AbstractService.locale.spec.ts} +0 -0
- /package/src/core/endpoint/__tests__/{EndpointCreator.test.ts → EndpointCreator.spec.ts} +0 -0
- /package/src/core/factories/__tests__/{JsonApiDataFactory.test.ts → JsonApiDataFactory.spec.ts} +0 -0
- /package/src/core/factories/__tests__/{RehydrationFactory.test.ts → RehydrationFactory.spec.ts} +0 -0
- /package/src/core/registry/__tests__/{DataClassRegistry.test.ts → DataClassRegistry.spec.ts} +0 -0
- /package/src/core/registry/__tests__/{ModuleRegistrar.test.ts → ModuleRegistrar.spec.ts} +0 -0
- /package/src/core/registry/__tests__/{viewportStore.test.ts → viewportStore.spec.ts} +0 -0
- /package/src/core/utils/__tests__/{translateResponse.test.ts → translateResponse.spec.ts} +0 -0
- /package/src/features/ai-connection/data/__tests__/{ai-connection.test.ts → ai-connection.spec.ts} +0 -0
- /package/src/features/company/data/{company.test.ts → company.spec.ts} +0 -0
- /package/src/features/company/hooks/{useSubscriptionStatus.test.ts → useSubscriptionStatus.spec.ts} +0 -0
- /package/src/hooks/__tests__/{useDataListRetriever.test.ts → useDataListRetriever.spec.ts} +0 -0
- /package/src/hooks/__tests__/{useDebounce.test.ts → useDebounce.spec.ts} +0 -0
- /package/src/hooks/__tests__/{useSocket.render.test.ts → useSocket.render.spec.ts} +0 -0
- /package/src/lib/__tests__/{direction.test.ts → direction.spec.ts} +0 -0
- /package/src/next-config/__tests__/{createNextConfig.test.ts → createNextConfig.spec.ts} +0 -0
- /package/src/server/__tests__/{JsonApiServer.test.ts → JsonApiServer.spec.ts} +0 -0
- /package/src/server/__tests__/{ServerSession.read.test.ts → ServerSession.read.spec.ts} +0 -0
- /package/src/server/__tests__/{cache.test.ts → cache.spec.ts} +0 -0
- /package/src/server/__tests__/{cachedGet.test.ts → cachedGet.spec.ts} +0 -0
- /package/src/server/__tests__/{request.test.ts → request.spec.ts} +0 -0
- /package/src/shadcnui/ui/__tests__/{sidebar.menu-skeleton.test.tsx → sidebar.menu-skeleton.spec.tsx} +0 -0
- /package/src/shadcnui/ui/__tests__/{sidebar.session.test.tsx → sidebar.session.spec.tsx} +0 -0
- /package/src/unified/__tests__/{JsonApiGet.cache.test.ts → JsonApiGet.cache.spec.ts} +0 -0
- /package/src/unified/__tests__/{JsonApiRequest.test.ts → JsonApiRequest.spec.ts} +0 -0
- /package/src/utils/__tests__/{exists.test.ts → exists.spec.ts} +0 -0
- /package/src/utils/__tests__/{italian-validators.test.ts → italian-validators.spec.ts} +0 -0
- /package/src/utils/__tests__/{map-thenable.test.ts → map-thenable.spec.ts} +0 -0
- /package/src/utils/__tests__/{use-mobile.test.tsx → use-mobile.spec.tsx} +0 -0
- /package/src/utils/{cn.test.ts → cn.spec.ts} +0 -0
- /package/src/utils/{isRemoteImageSrc.test.ts → isRemoteImageSrc.spec.ts} +0 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { renderHook } from "@testing-library/react";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { OAUTH_SCOPE_DISPLAY } from "../../interfaces/oauth.interface";
|
|
4
|
+
import { useOAuthScopeText } from "../useOAuthScopeText";
|
|
5
|
+
|
|
6
|
+
// The suite's next-intl mock (vitest.setup.ts) returns the key itself.
|
|
7
|
+
describe("useOAuthScopeText", () => {
|
|
8
|
+
it("reads the built-in scopes from oauth.ui.scopes.<id>.*", () => {
|
|
9
|
+
const { result } = renderHook(() => useOAuthScopeText());
|
|
10
|
+
|
|
11
|
+
expect(result.current("mcp")).toEqual({
|
|
12
|
+
name: "oauth.ui.scopes.mcp.name",
|
|
13
|
+
description: "oauth.ui.scopes.mcp.description",
|
|
14
|
+
});
|
|
15
|
+
expect(result.current(OAUTH_SCOPE_DISPLAY.read)).toEqual({
|
|
16
|
+
name: "oauth.ui.scopes.read.name",
|
|
17
|
+
description: "oauth.ui.scopes.read.description",
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("keeps the text an app-defined scope carries, falling back to its id", () => {
|
|
22
|
+
const { result } = renderHook(() => useOAuthScopeText());
|
|
23
|
+
|
|
24
|
+
expect(result.current({ scope: "photos:read", name: "View Photographs", description: "See photos" })).toEqual({
|
|
25
|
+
name: "View Photographs",
|
|
26
|
+
description: "See photos",
|
|
27
|
+
});
|
|
28
|
+
expect(result.current("photos:write")).toEqual({ name: "photos:write", description: "" });
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import { useTranslations } from "next-intl";
|
|
3
4
|
import { useAtomValue, useSetAtom } from "jotai";
|
|
4
|
-
import { useCallback, useEffect, useState } from "react";
|
|
5
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
5
6
|
import {
|
|
6
7
|
oauthClientByIdAtom,
|
|
7
8
|
removeOAuthClientAtom,
|
|
@@ -49,6 +50,11 @@ export function useOAuthClient(clientId: string): UseOAuthClientReturn {
|
|
|
49
50
|
const updateClientInStore = useSetAtom(updateOAuthClientAtom);
|
|
50
51
|
const removeClientFromStore = useSetAtom(removeOAuthClientAtom);
|
|
51
52
|
const setNewClientSecret = useSetAtom(setNewClientSecretAtom);
|
|
53
|
+
const t = useTranslations();
|
|
54
|
+
// A ref, not a dependency: the translator must not re-create the callbacks below
|
|
55
|
+
// (they drive effects that refetch), it only words the fallback errors.
|
|
56
|
+
const tRef = useRef(t);
|
|
57
|
+
tRef.current = t;
|
|
52
58
|
|
|
53
59
|
// Local state for fetched client (if not in store)
|
|
54
60
|
const [fetchedClient, setFetchedClient] = useState<OAuthClientInterface | null>(null);
|
|
@@ -68,7 +74,7 @@ export function useOAuthClient(clientId: string): UseOAuthClientReturn {
|
|
|
68
74
|
setFetchedClient(fetched);
|
|
69
75
|
} catch (err) {
|
|
70
76
|
console.error("[useOAuthClient] Failed to fetch client:", err);
|
|
71
|
-
setError(err instanceof Error ? err : new Error("
|
|
77
|
+
setError(err instanceof Error ? err : new Error(tRef.current("oauth.ui.errors.fetch_client")));
|
|
72
78
|
} finally {
|
|
73
79
|
setIsLoading(false);
|
|
74
80
|
}
|
|
@@ -94,7 +100,7 @@ export function useOAuthClient(clientId: string): UseOAuthClientReturn {
|
|
|
94
100
|
setFetchedClient(updated);
|
|
95
101
|
} catch (err) {
|
|
96
102
|
console.error("[useOAuthClient] Failed to update client:", err);
|
|
97
|
-
const error = err instanceof Error ? err : new Error("
|
|
103
|
+
const error = err instanceof Error ? err : new Error(tRef.current("oauth.ui.errors.update_client"));
|
|
98
104
|
setError(error);
|
|
99
105
|
throw error;
|
|
100
106
|
} finally {
|
|
@@ -115,7 +121,7 @@ export function useOAuthClient(clientId: string): UseOAuthClientReturn {
|
|
|
115
121
|
removeClientFromStore(clientId);
|
|
116
122
|
} catch (err) {
|
|
117
123
|
console.error("[useOAuthClient] Failed to delete client:", err);
|
|
118
|
-
const error = err instanceof Error ? err : new Error("
|
|
124
|
+
const error = err instanceof Error ? err : new Error(tRef.current("oauth.ui.errors.delete_client"));
|
|
119
125
|
setError(error);
|
|
120
126
|
throw error;
|
|
121
127
|
} finally {
|
|
@@ -141,7 +147,7 @@ export function useOAuthClient(clientId: string): UseOAuthClientReturn {
|
|
|
141
147
|
return result.clientSecret;
|
|
142
148
|
} catch (err) {
|
|
143
149
|
console.error("[useOAuthClient] Failed to regenerate secret:", err);
|
|
144
|
-
const error = err instanceof Error ? err : new Error("
|
|
150
|
+
const error = err instanceof Error ? err : new Error(tRef.current("oauth.ui.errors.regenerate_secret"));
|
|
145
151
|
setError(error);
|
|
146
152
|
throw error;
|
|
147
153
|
} finally {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import { useTranslations } from "next-intl";
|
|
3
4
|
import { useAtom, useSetAtom } from "jotai";
|
|
4
|
-
import { useCallback, useEffect } from "react";
|
|
5
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
5
6
|
import {
|
|
6
7
|
addOAuthClientAtom,
|
|
7
8
|
oauthClientsAtom,
|
|
@@ -48,6 +49,11 @@ export function useOAuthClients(): UseOAuthClientsReturn {
|
|
|
48
49
|
const [error, setError] = useAtom(oauthClientsErrorAtom);
|
|
49
50
|
const addClient = useSetAtom(addOAuthClientAtom);
|
|
50
51
|
const setNewClientSecret = useSetAtom(setNewClientSecretAtom);
|
|
52
|
+
const t = useTranslations();
|
|
53
|
+
// A ref, not a dependency: the translator must not re-create the callbacks below
|
|
54
|
+
// (they drive effects that refetch), it only words the fallback errors.
|
|
55
|
+
const tRef = useRef(t);
|
|
56
|
+
tRef.current = t;
|
|
51
57
|
|
|
52
58
|
const fetchClients = useCallback(async () => {
|
|
53
59
|
setIsLoading(true);
|
|
@@ -58,7 +64,7 @@ export function useOAuthClients(): UseOAuthClientsReturn {
|
|
|
58
64
|
setClients(fetchedClients);
|
|
59
65
|
} catch (err) {
|
|
60
66
|
console.error("[useOAuthClients] Failed to fetch clients:", err);
|
|
61
|
-
setError(err instanceof Error ? err : new Error("
|
|
67
|
+
setError(err instanceof Error ? err : new Error(tRef.current("oauth.ui.errors.fetch_clients")));
|
|
62
68
|
} finally {
|
|
63
69
|
setIsLoading(false);
|
|
64
70
|
}
|
|
@@ -91,7 +97,7 @@ export function useOAuthClients(): UseOAuthClientsReturn {
|
|
|
91
97
|
return result;
|
|
92
98
|
} catch (err) {
|
|
93
99
|
console.error("[useOAuthClients] Failed to create client:", err);
|
|
94
|
-
const error = err instanceof Error ? err : new Error("
|
|
100
|
+
const error = err instanceof Error ? err : new Error(tRef.current("oauth.ui.errors.create_client"));
|
|
95
101
|
setError(error);
|
|
96
102
|
throw error;
|
|
97
103
|
} finally {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { useTranslations } from "next-intl";
|
|
4
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
5
|
import { OAuthConsentInfo, OAuthConsentRequest } from "../interfaces/oauth.interface";
|
|
5
6
|
import { OAuthService } from "../data/oauth.service";
|
|
6
7
|
import { useCurrentUserContextOptional } from "../../user/contexts/CurrentUserContext";
|
|
@@ -60,6 +61,11 @@ export function useOAuthConsent(
|
|
|
60
61
|
const [companyId, setCompanyId] = useState<string | undefined>(undefined);
|
|
61
62
|
const contextCompanyId = useCurrentUserContextOptional()?.company?.id;
|
|
62
63
|
const currentCompanyId = options?.defaultCompanyId ?? contextCompanyId;
|
|
64
|
+
const t = useTranslations();
|
|
65
|
+
// A ref, not a dependency: the translator must not re-create the callbacks below
|
|
66
|
+
// (they drive effects that refetch), it only words the fallback errors.
|
|
67
|
+
const tRef = useRef(t);
|
|
68
|
+
tRef.current = t;
|
|
63
69
|
|
|
64
70
|
// Seed the studio choice once the user's companies arrive: the studio open in
|
|
65
71
|
// the web session when it is in the list, otherwise the first one.
|
|
@@ -78,7 +84,7 @@ export function useOAuthConsent(
|
|
|
78
84
|
// scope is deliberately NOT required: RFC 6749 §3.3 makes it optional
|
|
79
85
|
// and the server defaults to the client's registered scopes.
|
|
80
86
|
if (!params.clientId || !params.redirectUri) {
|
|
81
|
-
setError(new Error("
|
|
87
|
+
setError(new Error(tRef.current("oauth.ui.errors.missing_parameters")));
|
|
82
88
|
setIsLoading(false);
|
|
83
89
|
return;
|
|
84
90
|
}
|
|
@@ -91,7 +97,7 @@ export function useOAuthConsent(
|
|
|
91
97
|
setClientInfo(info);
|
|
92
98
|
} catch (err) {
|
|
93
99
|
console.error("[useOAuthConsent] Failed to fetch authorization info:", err);
|
|
94
|
-
setError(err instanceof Error ? err : new Error("
|
|
100
|
+
setError(err instanceof Error ? err : new Error(tRef.current("oauth.ui.errors.load_authorization")));
|
|
95
101
|
} finally {
|
|
96
102
|
setIsLoading(false);
|
|
97
103
|
}
|
|
@@ -120,7 +126,7 @@ export function useOAuthConsent(
|
|
|
120
126
|
}
|
|
121
127
|
} catch (err) {
|
|
122
128
|
console.error("[useOAuthConsent] Failed to approve authorization:", err);
|
|
123
|
-
setError(err instanceof Error ? err : new Error("
|
|
129
|
+
setError(err instanceof Error ? err : new Error(tRef.current("oauth.ui.errors.approve_authorization")));
|
|
124
130
|
setIsSubmitting(false);
|
|
125
131
|
}
|
|
126
132
|
// Note: Don't set isSubmitting to false on success - we're redirecting
|
|
@@ -139,7 +145,7 @@ export function useOAuthConsent(
|
|
|
139
145
|
}
|
|
140
146
|
} catch (err) {
|
|
141
147
|
console.error("[useOAuthConsent] Failed to deny authorization:", err);
|
|
142
|
-
setError(err instanceof Error ? err : new Error("
|
|
148
|
+
setError(err instanceof Error ? err : new Error(tRef.current("oauth.ui.errors.deny_authorization")));
|
|
143
149
|
setIsSubmitting(false);
|
|
144
150
|
}
|
|
145
151
|
// Note: Don't set isSubmitting to false on success - we're redirecting
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useTranslations } from "next-intl";
|
|
4
|
+
import { useCallback } from "react";
|
|
5
|
+
import { OAUTH_SCOPE_DISPLAY, OAuthScopeInfo } from "../interfaces/oauth.interface";
|
|
6
|
+
|
|
7
|
+
export type OAuthScopeText = { name: string; description: string };
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Returns a function that words a scope in the active language.
|
|
11
|
+
*
|
|
12
|
+
* The scopes defined in `OAUTH_SCOPE_DISPLAY` read their name and description
|
|
13
|
+
* from `oauth.ui.scopes.<id>.*`; the English text in that constant stays as
|
|
14
|
+
* data only. Any other scope (an app's own, or one the server describes) keeps
|
|
15
|
+
* the name and description it carries, falling back to its id.
|
|
16
|
+
*/
|
|
17
|
+
export function useOAuthScopeText(): (scope: string | OAuthScopeInfo) => OAuthScopeText {
|
|
18
|
+
const t = useTranslations();
|
|
19
|
+
return useCallback(
|
|
20
|
+
(scope: string | OAuthScopeInfo): OAuthScopeText => {
|
|
21
|
+
const id = typeof scope === "string" ? scope : scope.scope;
|
|
22
|
+
if (Object.prototype.hasOwnProperty.call(OAUTH_SCOPE_DISPLAY, id)) {
|
|
23
|
+
return {
|
|
24
|
+
name: t(`oauth.ui.scopes.${id}.name`),
|
|
25
|
+
description: t(`oauth.ui.scopes.${id}.description`),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const info = typeof scope === "string" ? undefined : scope;
|
|
29
|
+
return { name: info?.name || id, description: info?.description ?? "" };
|
|
30
|
+
},
|
|
31
|
+
[t],
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -61,11 +61,12 @@ const CellButton = memo(function CellButton({
|
|
|
61
61
|
);
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
64
|
+
/** Message keys for the action column headers. */
|
|
65
|
+
const ACTION_LABEL_KEYS: Record<ActionType, string> = {
|
|
66
|
+
read: "rbac.actions.read",
|
|
67
|
+
create: "rbac.actions.create",
|
|
68
|
+
update: "rbac.actions.update",
|
|
69
|
+
delete: "rbac.actions.delete",
|
|
69
70
|
};
|
|
70
71
|
|
|
71
72
|
export default function RbacByRoleContainer() {
|
|
@@ -192,7 +193,7 @@ export default function RbacByRoleContainer() {
|
|
|
192
193
|
key={action}
|
|
193
194
|
className="min-w-28 px-2 py-2 text-center text-xs font-medium text-muted-foreground"
|
|
194
195
|
>
|
|
195
|
-
{
|
|
196
|
+
{t(ACTION_LABEL_KEYS[action])}
|
|
196
197
|
</th>
|
|
197
198
|
))}
|
|
198
199
|
</tr>
|
|
@@ -81,11 +81,12 @@ const CellButton = memo(function CellButton({
|
|
|
81
81
|
// changed.
|
|
82
82
|
// ---------------------------------------------------------------------------
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
84
|
+
/** Message keys for the action column headers. */
|
|
85
|
+
const ACTION_LABEL_KEYS: Record<ActionType, string> = {
|
|
86
|
+
read: "rbac.actions.read",
|
|
87
|
+
create: "rbac.actions.create",
|
|
88
|
+
update: "rbac.actions.update",
|
|
89
|
+
delete: "rbac.actions.delete",
|
|
89
90
|
};
|
|
90
91
|
|
|
91
92
|
interface ModuleEditorProps {
|
|
@@ -121,7 +122,7 @@ const ModuleEditor = memo(function ModuleEditor({
|
|
|
121
122
|
<th className="w-40 px-4 py-2 text-start text-xs font-medium text-muted-foreground">{t("rbac.role")}</th>
|
|
122
123
|
{ACTION_TYPES.map((action) => (
|
|
123
124
|
<th key={action} className="min-w-28 px-2 py-2 text-center text-xs font-medium text-muted-foreground">
|
|
124
|
-
{
|
|
125
|
+
{t(ACTION_LABEL_KEYS[action])}
|
|
125
126
|
</th>
|
|
126
127
|
))}
|
|
127
128
|
</tr>
|
|
@@ -138,14 +138,14 @@ export const RbacProvider = ({
|
|
|
138
138
|
setSaving(true);
|
|
139
139
|
try {
|
|
140
140
|
await RbacService.saveMatrix({ matrix, roleNames, moduleNames, outputPath });
|
|
141
|
-
showToast(
|
|
141
|
+
showToast(t("rbac.saved_to", { path: outputPath }));
|
|
142
142
|
} catch (err) {
|
|
143
143
|
console.error("Failed to save RBAC matrix:", err);
|
|
144
144
|
showError(err instanceof Error ? err.message : String(err));
|
|
145
145
|
} finally {
|
|
146
146
|
setSaving(false);
|
|
147
147
|
}
|
|
148
|
-
}, [matrix, roleNames, moduleNames, outputPath]);
|
|
148
|
+
}, [matrix, roleNames, moduleNames, outputPath, t]);
|
|
149
149
|
|
|
150
150
|
const breadcrumb = (): BreadcrumbItemData[] => {
|
|
151
151
|
const response: BreadcrumbItemData[] = [];
|
|
@@ -168,7 +168,7 @@ export const RbacProvider = ({
|
|
|
168
168
|
functions.push(
|
|
169
169
|
<Button key="rbacSave" size="sm" onClick={handleSave} disabled={!canSave} className="gap-1">
|
|
170
170
|
{saving ? <Loader2Icon className="h-3.5 w-3.5 animate-spin" /> : <DownloadIcon className="h-3.5 w-3.5" />}
|
|
171
|
-
|
|
171
|
+
{t("rbac.save_to_file")}
|
|
172
172
|
</Button>,
|
|
173
173
|
);
|
|
174
174
|
if (functions.length > 0) response.functions = functions;
|
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
import { RoundPageContainer, Tab } from "@/components";
|
|
4
4
|
import { Modules } from "@/core";
|
|
5
|
+
import { useTranslations } from "next-intl";
|
|
5
6
|
import { useUserContext } from "../../contexts";
|
|
6
7
|
import { UserContent } from "../details";
|
|
7
8
|
|
|
8
9
|
export function UserContainer() {
|
|
10
|
+
const t = useTranslations();
|
|
9
11
|
const { user } = useUserContext();
|
|
10
12
|
if (!user) return null;
|
|
11
13
|
|
|
12
14
|
const tabs: Tab[] = [
|
|
13
15
|
{
|
|
14
|
-
label: "
|
|
16
|
+
label: t("ui.labels.details"),
|
|
15
17
|
content: <UserContent user={user} />,
|
|
16
18
|
},
|
|
17
19
|
];
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { beforeAll, describe, expect, it } from "vitest";
|
|
2
|
+
import { ApiRequestDataTypeInterface } from "../../../../core/interfaces/ApiRequestDataTypeInterface";
|
|
3
|
+
import { ModuleRegistry } from "../../../../core/registry/ModuleRegistry";
|
|
4
|
+
import { User } from "../user";
|
|
5
|
+
|
|
6
|
+
// The model resolves its JSON:API types through the real ModuleRegistry, so every
|
|
7
|
+
// module it names in rehydrate()/createJsonApi() must be registered.
|
|
8
|
+
const modules: Record<string, ApiRequestDataTypeInterface> = {
|
|
9
|
+
User: { name: "users", model: User } as any,
|
|
10
|
+
Role: { name: "roles", model: class {} } as any,
|
|
11
|
+
Company: { name: "companies", model: class {} } as any,
|
|
12
|
+
Module: { name: "modules", model: class {} } as any,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const registerIfAbsent = (key: string, module: ApiRequestDataTypeInterface) => {
|
|
16
|
+
try {
|
|
17
|
+
ModuleRegistry.get(key as any);
|
|
18
|
+
} catch {
|
|
19
|
+
ModuleRegistry.register(key, module);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
beforeAll(() => {
|
|
24
|
+
for (const [key, module] of Object.entries(modules)) registerIfAbsent(key, module);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
function makeHydratedData(attributeOverrides: Record<string, any> = {}) {
|
|
28
|
+
return {
|
|
29
|
+
jsonApi: {
|
|
30
|
+
id: "user-1",
|
|
31
|
+
type: "users",
|
|
32
|
+
attributes: {
|
|
33
|
+
name: "Carlo",
|
|
34
|
+
email: "carlo@example.test",
|
|
35
|
+
...attributeOverrides,
|
|
36
|
+
},
|
|
37
|
+
meta: {},
|
|
38
|
+
relationships: {},
|
|
39
|
+
},
|
|
40
|
+
included: [] as any[],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
describe("User.rehydrate", () => {
|
|
45
|
+
it("exposes the saved language", () => {
|
|
46
|
+
const user = new User().rehydrate(makeHydratedData({ language: "it" }));
|
|
47
|
+
expect(user.language).toBe("it");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("leaves language undefined when the user has not chosen one", () => {
|
|
51
|
+
const user = new User().rehydrate(makeHydratedData());
|
|
52
|
+
expect(user.language).toBeUndefined();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe("User.createJsonApi", () => {
|
|
57
|
+
it("writes language when provided", () => {
|
|
58
|
+
const payload = new User().createJsonApi({ id: "user-1", language: "it" });
|
|
59
|
+
expect(payload.data.attributes.language).toBe("it");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("omits language when undefined", () => {
|
|
63
|
+
const payload = new User().createJsonApi({ id: "user-1", name: "Carlo" });
|
|
64
|
+
expect(payload.data.attributes).not.toHaveProperty("language");
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -17,6 +17,7 @@ export type UserInput = {
|
|
|
17
17
|
avatar?: string;
|
|
18
18
|
phone?: string;
|
|
19
19
|
rate?: number;
|
|
20
|
+
language?: string;
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
export interface UserInterface extends ApiDataInterface {
|
|
@@ -28,6 +29,7 @@ export interface UserInterface extends ApiDataInterface {
|
|
|
28
29
|
get avatarUrl(): string | undefined;
|
|
29
30
|
get phone(): string | undefined;
|
|
30
31
|
get rate(): number | undefined;
|
|
32
|
+
get language(): string | undefined;
|
|
31
33
|
|
|
32
34
|
get isActivated(): boolean;
|
|
33
35
|
get isDeleted(): boolean;
|
|
@@ -243,6 +243,15 @@ export class UserService extends AbstractService {
|
|
|
243
243
|
});
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
+
static async patchLanguage(params: { id: string; language: string }): Promise<UserInterface> {
|
|
247
|
+
return this.callApi({
|
|
248
|
+
type: Modules.User,
|
|
249
|
+
method: HttpMethod.PATCH,
|
|
250
|
+
endpoint: new EndpointCreator({ endpoint: Modules.User, id: params.id, childEndpoint: "language" }).generate(),
|
|
251
|
+
input: params,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
246
255
|
static async patchRate(params: UserInput): Promise<UserInterface> {
|
|
247
256
|
return this.callApi({
|
|
248
257
|
type: Modules.User,
|
|
@@ -14,6 +14,7 @@ export class User extends AbstractApiData implements UserInterface, SearchResult
|
|
|
14
14
|
private _avatarUrl?: string;
|
|
15
15
|
private _phone?: string;
|
|
16
16
|
private _rate?: number;
|
|
17
|
+
private _language?: string;
|
|
17
18
|
|
|
18
19
|
private _isActivated?: boolean;
|
|
19
20
|
private _isDeleted?: boolean;
|
|
@@ -62,6 +63,10 @@ export class User extends AbstractApiData implements UserInterface, SearchResult
|
|
|
62
63
|
return this._rate;
|
|
63
64
|
}
|
|
64
65
|
|
|
66
|
+
get language(): string | undefined {
|
|
67
|
+
return this._language;
|
|
68
|
+
}
|
|
69
|
+
|
|
65
70
|
get relevance(): number | undefined {
|
|
66
71
|
return this._relevance;
|
|
67
72
|
}
|
|
@@ -103,6 +108,7 @@ export class User extends AbstractApiData implements UserInterface, SearchResult
|
|
|
103
108
|
this._bio = data.jsonApi.attributes.bio;
|
|
104
109
|
this._phone = data.jsonApi.attributes.phone;
|
|
105
110
|
this._rate = data.jsonApi.attributes.rate;
|
|
111
|
+
this._language = data.jsonApi.attributes.language;
|
|
106
112
|
|
|
107
113
|
this._avatar = data.jsonApi.attributes.avatar;
|
|
108
114
|
this._avatarUrl = data.jsonApi.attributes.avatarUrl;
|
|
@@ -143,6 +149,7 @@ export class User extends AbstractApiData implements UserInterface, SearchResult
|
|
|
143
149
|
if (data.adminCreated) response.data.attributes.adminCreated = true;
|
|
144
150
|
if (data.avatar !== undefined) response.data.attributes.avatar = data.avatar;
|
|
145
151
|
if (data.rate !== undefined) response.data.attributes.rate = data.rate;
|
|
152
|
+
if (data.language !== undefined) response.data.attributes.language = data.language;
|
|
146
153
|
|
|
147
154
|
if (data.roleIds) {
|
|
148
155
|
response.data.relationships.roles = {
|
|
@@ -115,7 +115,7 @@ export function WaitlistForm({ onSuccess }: WaitlistFormProps) {
|
|
|
115
115
|
setIsSuccess(true);
|
|
116
116
|
onSuccess?.();
|
|
117
117
|
} catch (e) {
|
|
118
|
-
errorToast({ error: e });
|
|
118
|
+
errorToast({ title: t("common.errors.error"), error: e });
|
|
119
119
|
} finally {
|
|
120
120
|
setIsSubmitting(false);
|
|
121
121
|
}
|
|
@@ -38,7 +38,7 @@ export function WaitlistList({ fullWidth }: WaitlistListProps = {}) {
|
|
|
38
38
|
showToast(t("waitlist.admin.invite_sent", { email: entry.email }));
|
|
39
39
|
void data.refresh();
|
|
40
40
|
} catch (error) {
|
|
41
|
-
errorToast({ error });
|
|
41
|
+
errorToast({ title: t("common.errors.error"), error });
|
|
42
42
|
}
|
|
43
43
|
};
|
|
44
44
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { configureI18n, getI18nServerLocale, type I18nConfig } from "../config";
|
|
2
|
+
import { configureI18n, getI18nServerLocale, getI18nSupportedLocales, type I18nConfig } from "../config";
|
|
3
3
|
|
|
4
4
|
function config(getLocale: I18nConfig["getLocale"]): I18nConfig {
|
|
5
5
|
return {
|
|
@@ -25,3 +25,23 @@ describe("getI18nServerLocale", () => {
|
|
|
25
25
|
await expect(getI18nServerLocale()).rejects.toThrow(/configureI18n/);
|
|
26
26
|
});
|
|
27
27
|
});
|
|
28
|
+
|
|
29
|
+
describe("getI18nSupportedLocales", () => {
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
configureI18n(null as unknown as I18nConfig);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('returns ["en"] when i18n is not configured', () => {
|
|
35
|
+
expect(getI18nSupportedLocales()).toEqual(["en"]);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('returns ["en"] when supportedLocales is not set', () => {
|
|
39
|
+
configureI18n(config(async () => "en"));
|
|
40
|
+
expect(getI18nSupportedLocales()).toEqual(["en"]);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("returns the configured supported locales", () => {
|
|
44
|
+
configureI18n({ ...config(async () => "en"), supportedLocales: ["en", "it"] });
|
|
45
|
+
expect(getI18nSupportedLocales()).toEqual(["en", "it"]);
|
|
46
|
+
});
|
|
47
|
+
});
|
package/src/i18n/config.ts
CHANGED
|
@@ -33,6 +33,11 @@ export interface I18nConfig {
|
|
|
33
33
|
* `next/root-params` — a module only allowed inside the app directory.
|
|
34
34
|
*/
|
|
35
35
|
getLocale: GetLocaleFunction;
|
|
36
|
+
/**
|
|
37
|
+
* Locales the app supports. The first entry is the fallback.
|
|
38
|
+
* Defaults to `["en"]` when omitted.
|
|
39
|
+
*/
|
|
40
|
+
supportedLocales?: string[];
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
// Private storage
|
|
@@ -89,3 +94,11 @@ export function useI18nDateFnsLocale(): any {
|
|
|
89
94
|
// Fallback to undefined (Calendar will use default)
|
|
90
95
|
return undefined;
|
|
91
96
|
}
|
|
97
|
+
|
|
98
|
+
/** The app's supported locales. Defaults to `["en"]` when not configured. */
|
|
99
|
+
export function getI18nSupportedLocales(): string[] {
|
|
100
|
+
if (_config?.supportedLocales && _config.supportedLocales.length > 0) {
|
|
101
|
+
return _config.supportedLocales;
|
|
102
|
+
}
|
|
103
|
+
return ["en"];
|
|
104
|
+
}
|