@plumile/backoffice-react 0.1.87 → 0.1.90
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/README.md +6 -6
- package/lib/esm/{AcceptInvitationScreen-dnOvRx4Z.js → AcceptInvitationScreen-DLc4aovr.js} +8 -7
- package/lib/esm/AcceptInvitationScreen-DLc4aovr.js.map +1 -0
- package/lib/esm/{AuthPanel-DiHejPoq.js → AuthPanel-BaIRFGbX.js} +2 -2
- package/lib/esm/{AuthPanel-DiHejPoq.js.map → AuthPanel-BaIRFGbX.js.map} +1 -1
- package/lib/esm/{BackofficeAcceptInvitationPage-CGht2ka0.js → BackofficeAcceptInvitationPage-D0dZnrV7.js} +4 -4
- package/lib/esm/{BackofficeAcceptInvitationPage-CGht2ka0.js.map → BackofficeAcceptInvitationPage-D0dZnrV7.js.map} +1 -1
- package/lib/esm/{BackofficeDashboardPage-h1OWb_rV.js → BackofficeDashboardPage-YWvoQODn.js} +33 -33
- package/lib/esm/{BackofficeDashboardPage-h1OWb_rV.js.map → BackofficeDashboardPage-YWvoQODn.js.map} +1 -1
- package/lib/esm/{BackofficeDetailPayload-iVx66o_6.js → BackofficeDetailPayload-P61MDRLE.js} +2 -2
- package/lib/esm/{BackofficeDetailPayload-iVx66o_6.js.map → BackofficeDetailPayload-P61MDRLE.js.map} +1 -1
- package/lib/esm/{BackofficeEntityActionFormDialog-V4QXnvpy.js → BackofficeEntityActionFormDialog-BgRTJ_JS.js} +3 -4
- package/lib/esm/BackofficeEntityActionFormDialog-BgRTJ_JS.js.map +1 -0
- package/lib/esm/BackofficeEntityDetailLayoutPage-DXjRqvcZ.js.map +1 -1
- package/lib/esm/{BackofficeEntityDetailPage-CIyGKwVP.js → BackofficeEntityDetailPage-DPFXbJxC.js} +34 -34
- package/lib/esm/BackofficeEntityDetailPage-DPFXbJxC.js.map +1 -0
- package/lib/esm/{BackofficeEntityListPage-DmZozSNk.js → BackofficeEntityListPage-C8Ucmc_E.js} +3 -4
- package/lib/esm/BackofficeEntityListPage-C8Ucmc_E.js.map +1 -0
- package/lib/esm/{useBackofficeReactTranslation-WfXU8kCf.js → BackofficeErrorBoundary-BwRVSDHU.js} +3 -9
- package/lib/esm/BackofficeErrorBoundary-BwRVSDHU.js.map +1 -0
- package/lib/esm/{BackofficeLayoutPage-DtFDn_nU.js → BackofficeLayoutPage-j3VUX3Tu.js} +35 -35
- package/lib/esm/{BackofficeLayoutPage-DtFDn_nU.js.map → BackofficeLayoutPage-j3VUX3Tu.js.map} +1 -1
- package/lib/esm/{BackofficeLoginPage-BvOPqbKO.js → BackofficeLoginPage-DgdIWTeu.js} +5 -5
- package/lib/esm/{BackofficeLoginPage-BvOPqbKO.js.map → BackofficeLoginPage-DgdIWTeu.js.map} +1 -1
- package/lib/esm/{BackofficePasswordResetCompletePage-ZLhghfhC.js → BackofficePasswordResetCompletePage-CF_0t3Nq.js} +4 -5
- package/lib/esm/BackofficePasswordResetCompletePage-CF_0t3Nq.js.map +1 -0
- package/lib/esm/{BackofficePasswordResetRequestPage-BLNHQD79.js → BackofficePasswordResetRequestPage-BJOrQXcy.js} +4 -4
- package/lib/esm/BackofficePasswordResetRequestPage-BJOrQXcy.js.map +1 -0
- package/lib/esm/BackofficeRightPageLayout-DZQvIHnj.js.map +1 -1
- package/lib/esm/{BackofficeVerifyEmailPage-BSTtLXdx.js → BackofficeVerifyEmailPage-C81LlsNM.js} +4 -5
- package/lib/esm/BackofficeVerifyEmailPage-C81LlsNM.js.map +1 -0
- package/lib/esm/{EntityFilterValue-B5ZGHO_u.js → EntityFilterValue-BWUdPBwp.js} +10 -9
- package/lib/esm/EntityFilterValue-BWUdPBwp.js.map +1 -0
- package/lib/esm/{EntityIdPickerDialog-DbTnDU4v.js → EntityIdPickerDialog-Yhmr-WsV.js} +9 -9
- package/lib/esm/{EntityIdPickerDialog-DbTnDU4v.js.map → EntityIdPickerDialog-Yhmr-WsV.js.map} +1 -1
- package/lib/esm/{LazyBackofficeEntityActionFormDialog-BE3wVfU6.js → LazyBackofficeEntityActionFormDialog-DVPQyWlr.js} +8 -7
- package/lib/esm/{LazyBackofficeEntityActionFormDialog-BE3wVfU6.js.map → LazyBackofficeEntityActionFormDialog-DVPQyWlr.js.map} +1 -1
- package/lib/esm/{PasswordResetCompleteScreen-B0P_tZg2.js → PasswordResetCompleteScreen-Cgg96DPo.js} +6 -5
- package/lib/esm/PasswordResetCompleteScreen-Cgg96DPo.js.map +1 -0
- package/lib/esm/{PasswordResetRequestScreen-p9s0dblR.js → PasswordResetRequestScreen-I1nFvGLd.js} +6 -5
- package/lib/esm/PasswordResetRequestScreen-I1nFvGLd.js.map +1 -0
- package/lib/esm/{VerifyEmailScreen--9lxOGlW.js → VerifyEmailScreen-Br5KyHjg.js} +7 -6
- package/lib/esm/VerifyEmailScreen-Br5KyHjg.js.map +1 -0
- package/lib/esm/backoffice-react.js +830 -1001
- package/lib/esm/backoffice-react.js.map +1 -1
- package/lib/esm/buildBreadcrumbs-CqF9Nh6x.js.map +1 -1
- package/lib/esm/environment-BXoBq_6e.js.map +1 -1
- package/lib/esm/loginPage.css-B7Io_DuU.js +6 -0
- package/lib/esm/loginPage.css-B7Io_DuU.js.map +1 -0
- package/lib/esm/mutationResult-CcQMY13J.js.map +1 -1
- package/lib/esm/pageResolution-hAQA5C6S.js.map +1 -1
- package/lib/esm/sidebarUtils-CuwJ_3mD.js.map +1 -1
- package/lib/esm/{synchronizeAuthStatusQuery-By_lNCnP.js → synchronizeAuthStatusQuery-1juorUEX.js} +47 -46
- package/lib/esm/synchronizeAuthStatusQuery-1juorUEX.js.map +1 -0
- package/lib/esm/{useAuth-OVPPa9bO.js → useAuth-BdSNpGqe.js} +43 -42
- package/lib/esm/useAuth-BdSNpGqe.js.map +1 -0
- package/lib/esm/{useBackofficeAuth-BvEoEqnB.js → useBackofficeAuth-C16Euw2X.js} +3 -3
- package/lib/esm/{useBackofficeAuth-BvEoEqnB.js.map → useBackofficeAuth-C16Euw2X.js.map} +1 -1
- package/lib/esm/{useBackofficeLazyValue-Dnii1_dE.js → useBackofficeLazyValue-Bh_13h8A.js} +2 -2
- package/lib/esm/{useBackofficeLazyValue-Dnii1_dE.js.map → useBackofficeLazyValue-Bh_13h8A.js.map} +1 -1
- package/lib/esm/useBackofficeListUrlState-D4fx5O7u.js.map +1 -1
- package/lib/esm/useBackofficeReactTranslation-Btt58EIo.js +18 -0
- package/lib/esm/useBackofficeReactTranslation-Btt58EIo.js.map +1 -0
- package/lib/types/components/backoffice/scaffolds/BackofficeListFilterContext.d.ts.map +1 -1
- package/lib/types/hooks/useConditionalSubscription.d.ts.map +1 -1
- package/lib/types/i18n/resources.d.ts +211 -409
- package/lib/types/i18n/resources.d.ts.map +1 -1
- package/lib/types/pages/BackofficeEntityDetailPage.d.ts.map +1 -1
- package/lib/types/provider/BackofficeProvider.d.ts.map +1 -1
- package/lib/types/router/createBackofficeRoutes.d.ts.map +1 -1
- package/package.json +14 -12
- package/lib/esm/AcceptInvitationScreen-dnOvRx4Z.js.map +0 -1
- package/lib/esm/BackofficeConfigContext-R0t1owTI.js +0 -12
- package/lib/esm/BackofficeConfigContext-R0t1owTI.js.map +0 -1
- package/lib/esm/BackofficeEntityActionFormDialog-V4QXnvpy.js.map +0 -1
- package/lib/esm/BackofficeEntityDetailPage-CIyGKwVP.js.map +0 -1
- package/lib/esm/BackofficeEntityListPage-DmZozSNk.js.map +0 -1
- package/lib/esm/BackofficePasswordResetCompletePage-ZLhghfhC.js.map +0 -1
- package/lib/esm/BackofficePasswordResetRequestPage-BLNHQD79.js.map +0 -1
- package/lib/esm/BackofficeVerifyEmailPage-BSTtLXdx.js.map +0 -1
- package/lib/esm/EntityFilterValue-B5ZGHO_u.js.map +0 -1
- package/lib/esm/PasswordResetCompleteScreen-B0P_tZg2.js.map +0 -1
- package/lib/esm/PasswordResetRequestScreen-p9s0dblR.js.map +0 -1
- package/lib/esm/VerifyEmailScreen--9lxOGlW.js.map +0 -1
- package/lib/esm/loginPage.css-CBJ1Ozm5.js +0 -12
- package/lib/esm/loginPage.css-CBJ1Ozm5.js.map +0 -1
- package/lib/esm/synchronizeAuthStatusQuery-By_lNCnP.js.map +0 -1
- package/lib/esm/useAuth-OVPPa9bO.js.map +0 -1
- package/lib/esm/useBackofficeReactTranslation-WfXU8kCf.js.map +0 -1
- package/lib/types/i18n/useSharedTranslation.d.ts +0 -3
- package/lib/types/i18n/useSharedTranslation.d.ts.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"BackofficePasswordResetCompletePage-ZLhghfhC.js","names":[],"sources":["../../src/pages/BackofficePasswordResetCompletePage.tsx"],"sourcesContent":["import { useCallback, useContext, type JSX } from 'react';\nimport * as ReactRelay from 'react-relay';\nimport type { MutationParameters } from 'relay-runtime';\nimport { RoutingContext } from '@plumile/router';\n\nimport { PasswordResetCompleteScreen } from '../auth/pages/PasswordResetCompleteScreen.js';\nimport {\n type MutationPayloadBase,\n requireField,\n resolveMutationOutcome,\n} from '../relay/mutationResult.js';\nimport { useSharedTranslation } from '../i18n/useSharedTranslation.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport { useBackofficeAuthPasswordResetCompleteConfig } from '../provider/useBackofficeLazyValue.js';\nimport { getBackofficeLoginPath } from '../router/backofficeAuthPaths.js';\n\nconst { useMutation } = ReactRelay;\n\ntype CompletePasswordResetErrorReason =\n | 'INVALID_TOKEN'\n | 'TOKEN_EXPIRED'\n | 'PASSWORD_POLICY_VIOLATION'\n | 'INTERNAL_ERROR';\n\ntype CompletePasswordResetMutationPayload =\n MutationPayloadBase<CompletePasswordResetErrorReason> & {\n success?: boolean | null;\n };\n\nexport const BackofficePasswordResetCompletePage = (): JSX.Element => {\n const routerContext = useContext(RoutingContext);\n const { basePath } = useBackofficeConfig();\n const auth = useBackofficeAuthPasswordResetCompleteConfig();\n const { t } = useSharedTranslation();\n type CompletePasswordResetMutation = MutationParameters & {\n response: {\n completePasswordReset?: CompletePasswordResetMutationPayload | null;\n };\n variables: { input: { newPassword: string; token: string } };\n };\n const [commitReset] = useMutation<CompletePasswordResetMutation>(\n auth.completePasswordResetMutation,\n );\n\n const handleBackToLogin = useCallback(() => {\n routerContext?.history.push({ pathname: getBackofficeLoginPath(basePath) });\n }, [basePath, routerContext?.history]);\n\n const handleCompleteReset = useCallback(\n async (input: { newPassword: string; token: string }): Promise<boolean> => {\n const invalidMessage = t('auth.passwordResetComplete.errors.invalid');\n const defaultErrorMessage = invalidMessage;\n\n return new Promise((resolve, reject) => {\n commitReset({\n variables: {\n input,\n },\n onCompleted: (response) => {\n const outcome = resolveMutationOutcome(\n response.completePasswordReset ?? null,\n {\n defaultErrorMessage,\n mapReason: (reason) => {\n switch (reason) {\n case 'INVALID_TOKEN':\n return invalidMessage;\n case 'TOKEN_EXPIRED':\n return t('auth.passwordResetComplete.errors.expired');\n case 'PASSWORD_POLICY_VIOLATION':\n return t(\n 'auth.passwordResetComplete.errors.policyViolation',\n );\n case 'INTERNAL_ERROR':\n return invalidMessage;\n default:\n return null;\n }\n },\n },\n );\n if (!outcome.ok) {\n reject(new Error(outcome.message));\n return;\n }\n\n const successResult = requireField(\n outcome.payload.success ?? null,\n defaultErrorMessage,\n );\n if (!successResult.ok) {\n reject(new Error(successResult.message));\n return;\n }\n resolve(successResult.value);\n },\n onError: (mutationError) => {\n let error = new Error(defaultErrorMessage);\n if (mutationError instanceof Error) {\n error = mutationError;\n }\n reject(error);\n },\n });\n });\n },\n [commitReset, t],\n );\n\n return (\n <PasswordResetCompleteScreen\n onBackToLogin={handleBackToLogin}\n onCompletePasswordReset={handleCompleteReset}\n />\n );\n};\n\nexport default BackofficePasswordResetCompletePage;\n"],"mappings":";;;;;;;;;;;AAgBA,IAAM,EAAE,mBAAgB,GAaX,UAAyD;CACpE,IAAM,IAAgB,EAAW,EAAe,EAC1C,EAAE,gBAAa,GAAqB,EACpC,IAAO,GAA8C,EACrD,EAAE,SAAM,GAAsB,EAO9B,CAAC,KAAe,EACpB,EAAK,8BACN;AAmED,QACE,kBAAC,GAAD;EACE,eAnEsB,QAAkB;AAC1C,MAAe,QAAQ,KAAK,EAAE,UAAU,EAAuB,EAAS,EAAE,CAAC;KAC1E,CAAC,GAAU,GAAe,QAAQ,CAAC;EAkElC,yBAhEwB,EAC1B,OAAO,MAAoE;GACzE,IAAM,IAAiB,EAAE,4CAA4C,EAC/D,IAAsB;AAE5B,UAAO,IAAI,SAAS,GAAS,MAAW;AACtC,MAAY;KACV,WAAW,EACT,UACD;KACD,cAAc,MAAa;MACzB,IAAM,IAAU,EACd,EAAS,yBAAyB,MAClC;OACE;OACA,YAAY,MAAW;AACrB,gBAAQ,GAAR;SACE,KAAK,gBACH,QAAO;SACT,KAAK,gBACH,QAAO,EAAE,4CAA4C;SACvD,KAAK,4BACH,QAAO,EACL,oDACD;SACH,KAAK,iBACH,QAAO;SACT,QACE,QAAO;;;OAGd,CACF;AACD,UAAI,CAAC,EAAQ,IAAI;AACf,SAAW,MAAM,EAAQ,QAAQ,CAAC;AAClC;;MAGF,IAAM,IAAgB,EACpB,EAAQ,QAAQ,WAAW,MAC3B,EACD;AACD,UAAI,CAAC,EAAc,IAAI;AACrB,SAAW,MAAM,EAAc,QAAQ,CAAC;AACxC;;AAEF,QAAQ,EAAc,MAAM;;KAE9B,UAAU,MAAkB;MAC1B,IAAI,IAAY,MAAM,EAAoB;AAI1C,MAHI,aAAyB,UAC3B,IAAQ,IAEV,EAAO,EAAM;;KAEhB,CAAC;KACF;KAEJ,CAAC,GAAa,EAAE,CACjB;EAMG,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"BackofficePasswordResetRequestPage-BLNHQD79.js","names":[],"sources":["../../src/pages/BackofficePasswordResetRequestPage.tsx"],"sourcesContent":["import { useCallback, type JSX } from 'react';\nimport * as ReactRelay from 'react-relay';\nimport type { MutationParameters } from 'relay-runtime';\n\nimport { PasswordResetRequestScreen } from '../auth/pages/PasswordResetRequestScreen.js';\nimport {\n type MutationPayloadBase,\n requireField,\n resolveMutationOutcome,\n} from '../relay/mutationResult.js';\nimport { useSharedTranslation } from '../i18n/useSharedTranslation.js';\nimport { useBackofficeAuthPasswordResetRequestConfig } from '../provider/useBackofficeLazyValue.js';\n\nconst { useMutation } = ReactRelay;\n\ntype StartPasswordResetErrorReason =\n | 'INVALID_EMAIL'\n | 'RATE_LIMITED'\n | 'INTERNAL_ERROR';\n\ntype StartPasswordResetMutationPayload =\n MutationPayloadBase<StartPasswordResetErrorReason> & {\n payload?: { success?: boolean | null } | null;\n };\n\nexport const BackofficePasswordResetRequestPage = (): JSX.Element => {\n const auth = useBackofficeAuthPasswordResetRequestConfig();\n const { t } = useSharedTranslation();\n type StartPasswordResetMutation = MutationParameters & {\n response: { startPasswordReset?: StartPasswordResetMutationPayload | null };\n variables: { input: { email: string; locale?: string } };\n };\n const [commitReset] = useMutation<StartPasswordResetMutation>(\n auth.startPasswordResetMutation,\n );\n\n const mapStartResetReason = useCallback(\n (reason: StartPasswordResetErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_EMAIL':\n return t('auth.passwordResetRequest.errors.invalidEmail');\n case 'RATE_LIMITED':\n return t('auth.passwordResetRequest.errors.rateLimited');\n case 'INTERNAL_ERROR':\n return t('auth.passwordResetRequest.errors.startFailed');\n default:\n return null;\n }\n },\n [t],\n );\n\n const handleStartReset = useCallback(\n async (input: { email: string; locale?: string }): Promise<boolean> => {\n const defaultErrorMessage = t(\n 'auth.passwordResetRequest.errors.startFailed',\n );\n\n return new Promise((resolve, reject) => {\n commitReset({\n variables: {\n input,\n },\n onCompleted: (response) => {\n const outcome = resolveMutationOutcome(\n response.startPasswordReset ?? null,\n {\n defaultErrorMessage,\n mapReason: mapStartResetReason,\n },\n );\n if (!outcome.ok) {\n reject(new Error(outcome.message));\n return;\n }\n\n const successResult = requireField(\n outcome.payload.payload?.success ?? null,\n defaultErrorMessage,\n );\n if (!successResult.ok) {\n reject(new Error(successResult.message));\n return;\n }\n resolve(successResult.value);\n },\n onError: (mutationError) => {\n let error = new Error(defaultErrorMessage);\n if (mutationError instanceof Error) {\n error = mutationError;\n }\n reject(error);\n },\n });\n });\n },\n [commitReset, mapStartResetReason, t],\n );\n\n return <PasswordResetRequestScreen onStartPasswordReset={handleStartReset} />;\n};\n\nexport default BackofficePasswordResetRequestPage;\n"],"mappings":";;;;;;;;AAaA,IAAM,EAAE,mBAAgB,GAYX,UAAwD;CACnE,IAAM,IAAO,GAA6C,EACpD,EAAE,SAAM,GAAsB,EAK9B,CAAC,KAAe,EACpB,EAAK,2BACN,EAEK,IAAsB,GACzB,MAAyD;AACxD,UAAQ,GAAR;GACE,KAAK,gBACH,QAAO,EAAE,gDAAgD;GAC3D,KAAK,eACH,QAAO,EAAE,+CAA+C;GAC1D,KAAK,iBACH,QAAO,EAAE,+CAA+C;GAC1D,QACE,QAAO;;IAGb,CAAC,EAAE,CACJ;AAiDD,QAAO,kBAAC,GAAD,EAA4B,sBA/CV,EACvB,OAAO,MAAgE;EACrE,IAAM,IAAsB,EAC1B,+CACD;AAED,SAAO,IAAI,SAAS,GAAS,MAAW;AACtC,KAAY;IACV,WAAW,EACT,UACD;IACD,cAAc,MAAa;KACzB,IAAM,IAAU,EACd,EAAS,sBAAsB,MAC/B;MACE;MACA,WAAW;MACZ,CACF;AACD,SAAI,CAAC,EAAQ,IAAI;AACf,QAAW,MAAM,EAAQ,QAAQ,CAAC;AAClC;;KAGF,IAAM,IAAgB,EACpB,EAAQ,QAAQ,SAAS,WAAW,MACpC,EACD;AACD,SAAI,CAAC,EAAc,IAAI;AACrB,QAAW,MAAM,EAAc,QAAQ,CAAC;AACxC;;AAEF,OAAQ,EAAc,MAAM;;IAE9B,UAAU,MAAkB;KAC1B,IAAI,IAAY,MAAM,EAAoB;AAI1C,KAHI,aAAyB,UAC3B,IAAQ,IAEV,EAAO,EAAM;;IAEhB,CAAC;IACF;IAEJ;EAAC;EAAa;EAAqB;EAAE,CACtC,EAE4E,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"BackofficeVerifyEmailPage-BSTtLXdx.js","names":[],"sources":["../../src/pages/BackofficeVerifyEmailPage.tsx"],"sourcesContent":["import { useCallback, useContext, type JSX } from 'react';\nimport * as ReactRelay from 'react-relay';\nimport type { MutationParameters } from 'relay-runtime';\nimport { RoutingContext } from '@plumile/router';\n\nimport { VerifyEmailScreen } from '../auth/pages/VerifyEmailScreen.js';\nimport {\n type MutationPayloadBase,\n requireField,\n resolveMutationOutcome,\n} from '../relay/mutationResult.js';\nimport { useSharedTranslation } from '../i18n/useSharedTranslation.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport { useBackofficeAuthVerifyEmailConfig } from '../provider/useBackofficeLazyValue.js';\nimport { getBackofficeLoginPath } from '../router/backofficeAuthPaths.js';\n\nconst { useMutation } = ReactRelay;\n\ntype VerifyEmailErrorReason =\n | 'INVALID_TOKEN'\n | 'TOKEN_EXPIRED'\n | 'ALREADY_VERIFIED'\n | 'INTERNAL_ERROR';\n\ntype VerifyEmailMutationPayload =\n MutationPayloadBase<VerifyEmailErrorReason> & {\n success?: boolean | null;\n };\n\nexport const BackofficeVerifyEmailPage = (): JSX.Element => {\n const routerContext = useContext(RoutingContext);\n const { basePath } = useBackofficeConfig();\n const auth = useBackofficeAuthVerifyEmailConfig();\n const { t } = useSharedTranslation();\n type VerifyEmailMutation = MutationParameters & {\n response: { verifyEmail?: VerifyEmailMutationPayload | null };\n variables: { input: { token: string } };\n };\n const [commitVerify] = useMutation<VerifyEmailMutation>(\n auth.verifyEmailMutation,\n );\n\n const handleBackToLogin = useCallback(() => {\n routerContext?.history.push({ pathname: getBackofficeLoginPath(basePath) });\n }, [basePath, routerContext?.history]);\n\n const handleVerifyEmail = useCallback(\n async (input: { token: string }): Promise<boolean> => {\n const invalidMessage = t('auth.verifyEmail.errors.invalid');\n const defaultErrorMessage = invalidMessage;\n\n return new Promise((resolve, reject) => {\n commitVerify({\n variables: {\n input,\n },\n onCompleted: (response) => {\n const outcome = resolveMutationOutcome(\n response.verifyEmail ?? null,\n {\n defaultErrorMessage,\n mapReason: (reason) => {\n switch (reason) {\n case 'INVALID_TOKEN':\n return invalidMessage;\n case 'TOKEN_EXPIRED':\n return t('auth.verifyEmail.errors.expired');\n case 'ALREADY_VERIFIED':\n return t('auth.verifyEmail.errors.alreadyVerified');\n case 'INTERNAL_ERROR':\n return invalidMessage;\n default:\n return null;\n }\n },\n },\n );\n if (!outcome.ok) {\n reject(new Error(outcome.message));\n return;\n }\n\n const successResult = requireField(\n outcome.payload.success ?? null,\n defaultErrorMessage,\n );\n if (!successResult.ok) {\n reject(new Error(successResult.message));\n return;\n }\n resolve(successResult.value);\n },\n onError: (mutationError) => {\n let error = new Error(defaultErrorMessage);\n if (mutationError instanceof Error) {\n error = mutationError;\n }\n reject(error);\n },\n });\n });\n },\n [commitVerify, t],\n );\n\n return (\n <VerifyEmailScreen\n onBackToLogin={handleBackToLogin}\n onVerifyEmail={handleVerifyEmail}\n />\n );\n};\n\nexport default BackofficeVerifyEmailPage;\n"],"mappings":";;;;;;;;;;;AAgBA,IAAM,EAAE,mBAAgB,GAaX,UAA+C;CAC1D,IAAM,IAAgB,EAAW,EAAe,EAC1C,EAAE,gBAAa,GAAqB,EACpC,IAAO,GAAoC,EAC3C,EAAE,SAAM,GAAsB,EAK9B,CAAC,KAAgB,EACrB,EAAK,oBACN;AAiED,QACE,kBAAC,GAAD;EACE,eAjEsB,QAAkB;AAC1C,MAAe,QAAQ,KAAK,EAAE,UAAU,EAAuB,EAAS,EAAE,CAAC;KAC1E,CAAC,GAAU,GAAe,QAAQ,CAAC;EAgElC,eA9DsB,EACxB,OAAO,MAA+C;GACpD,IAAM,IAAiB,EAAE,kCAAkC,EACrD,IAAsB;AAE5B,UAAO,IAAI,SAAS,GAAS,MAAW;AACtC,MAAa;KACX,WAAW,EACT,UACD;KACD,cAAc,MAAa;MACzB,IAAM,IAAU,EACd,EAAS,eAAe,MACxB;OACE;OACA,YAAY,MAAW;AACrB,gBAAQ,GAAR;SACE,KAAK,gBACH,QAAO;SACT,KAAK,gBACH,QAAO,EAAE,kCAAkC;SAC7C,KAAK,mBACH,QAAO,EAAE,0CAA0C;SACrD,KAAK,iBACH,QAAO;SACT,QACE,QAAO;;;OAGd,CACF;AACD,UAAI,CAAC,EAAQ,IAAI;AACf,SAAW,MAAM,EAAQ,QAAQ,CAAC;AAClC;;MAGF,IAAM,IAAgB,EACpB,EAAQ,QAAQ,WAAW,MAC3B,EACD;AACD,UAAI,CAAC,EAAc,IAAI;AACrB,SAAW,MAAM,EAAc,QAAQ,CAAC;AACxC;;AAEF,QAAQ,EAAc,MAAM;;KAE9B,UAAU,MAAkB;MAC1B,IAAI,IAAY,MAAM,EAAoB;AAI1C,MAHI,aAAyB,UAC3B,IAAQ,IAEV,EAAO,EAAM;;KAEhB,CAAC;KACF;KAEJ,CAAC,GAAc,EAAE,CAClB;EAMG,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EntityFilterValue-B5ZGHO_u.js","names":[],"sources":["../../src/components/backoffice/scaffolds/BackofficeListFilterContext.tsx","../../src/components/backoffice/filters/EntityFilterValue.tsx"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useMemo,\n type JSX,\n type ReactNode,\n} from 'react';\n\nimport type {\n BackofficeListState,\n BackofficeResolvedListFacetConfig,\n} from '@plumile/backoffice-core/types.js';\nimport { buildBackofficeListLink } from '@plumile/backoffice-core/state/buildListHref.js';\nimport { setWhereValue } from '@plumile/backoffice-core/filters/where.js';\n\nexport type BackofficeListFilterContextValue = {\n config: BackofficeResolvedListFacetConfig;\n state: BackofficeListState<Record<string, unknown>, string>;\n pushState: (\n next: BackofficeListState<Record<string, unknown>, string>,\n ) => void;\n applyFilter: (\n whereKey: string,\n value: unknown,\n path?: readonly string[],\n ) => void;\n buildFilterLink: (\n whereKey: string,\n value: unknown,\n path?: readonly string[],\n ) => { pathname: string; search: string };\n};\n\nconst BackofficeListFilterContext =\n createContext<BackofficeListFilterContextValue | null>(null);\n\ntype ProviderProps<\n Where extends Record<string, unknown>,\n Sort extends string,\n> = {\n config: BackofficeResolvedListFacetConfig<Where, Sort>;\n state: BackofficeListState<Where, Sort>;\n pushState: (next: BackofficeListState<Where, Sort>) => void;\n children: ReactNode;\n};\n\nexport const BackofficeListFilterProvider = <\n Where extends Record<string, unknown>,\n Sort extends string,\n>(\n props: ProviderProps<Where, Sort>,\n): JSX.Element => {\n const { config, state, pushState, children } = props;\n\n const applyFilter = useCallback(\n (whereKey: string, value: unknown, path?: readonly string[]) => {\n const nextWhere = setWhereValue(\n state.where,\n whereKey as keyof Where,\n value,\n path,\n );\n pushState({ ...state, where: nextWhere });\n },\n [pushState, state],\n );\n\n const buildFilterLink = useCallback(\n (whereKey: string, value: unknown, path?: readonly string[]) => {\n const nextWhere = setWhereValue(\n state.where,\n whereKey as keyof Where,\n value,\n path,\n );\n return buildBackofficeListLink(config, { ...state, where: nextWhere });\n },\n [config, state],\n );\n\n const contextValue = useMemo<BackofficeListFilterContextValue>(() => {\n return {\n config: config as BackofficeResolvedListFacetConfig,\n state: state as unknown as BackofficeListState<\n Record<string, unknown>,\n string\n >,\n pushState: pushState as BackofficeListFilterContextValue['pushState'],\n applyFilter,\n buildFilterLink,\n };\n }, [applyFilter, buildFilterLink, config, pushState, state]);\n\n return (\n <BackofficeListFilterContext.Provider value={contextValue}>\n {children}\n </BackofficeListFilterContext.Provider>\n );\n};\n\nexport const useBackofficeListFilterContext =\n (): BackofficeListFilterContextValue | null => {\n return useContext(BackofficeListFilterContext);\n };\n\nexport default BackofficeListFilterContext;\n","import { Suspense, type JSX } from 'react';\nimport * as ReactRelay from 'react-relay';\nimport type { OperationType } from 'relay-runtime';\n\nimport type { BackofficePickerValueConfig } from '@plumile/backoffice-core/types.js';\n\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\nimport { useBackofficePickerEntityLoader } from '../../../provider/useBackofficeEntityLoader.js';\nimport { BackofficeErrorBoundary } from '../errors/BackofficeErrorBoundary.js';\n\nconst { useLazyLoadQuery } = ReactRelay;\n\ntype EntityFilterValueContentProps<RowRef, RowView> = {\n valueConfig: BackofficePickerValueConfig<RowRef, RowView>;\n id: string;\n children: (label: string | null) => JSX.Element;\n};\n\nconst resolveTitle = (value: unknown): string | null => {\n if (value == null || typeof value !== 'object') {\n return null;\n }\n const { title } = value as { title?: unknown };\n if (typeof title !== 'string') {\n return null;\n }\n const trimmed = title.trim();\n if (trimmed === '') {\n return null;\n }\n return trimmed;\n};\n\nconst EntityFilterValueContent = <RowRef, RowView>({\n valueConfig,\n id,\n children,\n}: EntityFilterValueContentProps<RowRef, RowView>): JSX.Element => {\n const data = useLazyLoadQuery<OperationType>(valueConfig.query, { id });\n const rowRef = valueConfig.resolveRow(data);\n let row: RowView | null = null;\n if (rowRef != null) {\n row = valueConfig.toRow(rowRef);\n }\n const title = resolveTitle(row);\n\n return children(title);\n};\n\nexport type EntityFilterValueTextProps = {\n entityId: string;\n id: string;\n children: (label: string | null) => JSX.Element;\n};\n\nexport const EntityFilterValueText = ({\n entityId,\n id,\n children,\n}: EntityFilterValueTextProps): JSX.Element => {\n const resolvedId = id.trim();\n const pickerEntityState = useBackofficePickerEntityLoader(entityId, {\n enabled: resolvedId !== '',\n });\n let valueConfig: BackofficePickerValueConfig<unknown, unknown> | null = null;\n if (pickerEntityState.status === 'loaded') {\n valueConfig = pickerEntityState.module.config.picker.value ?? null;\n }\n\n const fallback = children(null);\n if (valueConfig == null) {\n return fallback;\n }\n\n return (\n <BackofficeErrorBoundary\n fallback={() => {\n return fallback;\n }}\n >\n <Suspense fallback={fallback}>\n <EntityFilterValueContent valueConfig={valueConfig} id={id}>\n {children}\n </EntityFilterValueContent>\n </Suspense>\n </BackofficeErrorBoundary>\n );\n};\n\nexport type EntityFilterValueProps = {\n entityId: string;\n id: string;\n};\n\nexport const EntityFilterValue = ({\n entityId,\n id,\n}: EntityFilterValueProps): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const resolvedId = id.trim();\n\n return (\n <EntityFilterValueText entityId={entityId} id={id}>\n {(label) => {\n let fallbackLabel = resolvedId;\n if (resolvedId === '') {\n fallbackLabel = t('filters.placeholders.unresolved');\n }\n return <span>{label ?? fallbackLabel}</span>;\n }}\n </EntityFilterValueText>\n );\n};\n\nexport default EntityFilterValue;\n"],"mappings":";;;;;;;;AAkCA,IAAM,IACJ,EAAuD,KAAK,EAYjD,KAIX,MACgB;CAChB,IAAM,EAAE,WAAQ,UAAO,cAAW,gBAAa,GAEzC,IAAc,GACjB,GAAkB,GAAgB,MAA6B;EAC9D,IAAM,IAAY,EAChB,EAAM,OACN,GACA,GACA,EACD;AACD,IAAU;GAAE,GAAG;GAAO,OAAO;GAAW,CAAC;IAE3C,CAAC,GAAW,EAAM,CACnB,EAEK,IAAkB,GACrB,GAAkB,GAAgB,MAA6B;EAC9D,IAAM,IAAY,EAChB,EAAM,OACN,GACA,GACA,EACD;AACD,SAAO,EAAwB,GAAQ;GAAE,GAAG;GAAO,OAAO;GAAW,CAAC;IAExE,CAAC,GAAQ,EAAM,CAChB,EAEK,IAAe,SACZ;EACG;EACD;EAII;EACX;EACA;EACD,GACA;EAAC;EAAa;EAAiB;EAAQ;EAAW;EAAM,CAAC;AAE5D,QACE,kBAAC,EAA4B,UAA7B;EAAsC,OAAO;EAC1C;EACoC,CAAA;GAI9B,UAEF,EAAW,EAA4B,EC7F5C,EAAE,wBAAqB,GAQvB,KAAgB,MAAkC;AACtD,KAAqB,OAAO,KAAU,aAAlC,EACF,QAAO;CAET,IAAM,EAAE,aAAU;AAClB,KAAI,OAAO,KAAU,SACnB,QAAO;CAET,IAAM,IAAU,EAAM,MAAM;AAI5B,QAHI,MAAY,KACP,OAEF;GAGH,KAA6C,EACjD,gBACA,OACA,kBACiE;CACjE,IAAM,IAAO,EAAgC,EAAY,OAAO,EAAE,OAAI,CAAC,EACjE,IAAS,EAAY,WAAW,EAAK,EACvC,IAAsB;AAM1B,QALI,KAAU,SACZ,IAAM,EAAY,MAAM,EAAO,GAI1B,EAFO,EAAa,EAAI,CAET;GASX,KAAyB,EACpC,aACA,OACA,kBAC6C;CAE7C,IAAM,IAAoB,EAAgC,GAAU,EAClE,SAFiB,EAAG,MAAM,KAEF,IACzB,CAAC,EACE,IAAoE;AACxE,CAAI,EAAkB,WAAW,aAC/B,IAAc,EAAkB,OAAO,OAAO,OAAO,SAAS;CAGhE,IAAM,IAAW,EAAS,KAAK;AAK/B,QAJI,KAAe,OACV,IAIP,kBAAC,GAAD;EACE,gBACS;YAGT,kBAAC,GAAD;GAAoB;aAClB,kBAAC,GAAD;IAAuC;IAAiB;IACrD;IACwB,CAAA;GAClB,CAAA;EACa,CAAA;GASjB,KAAqB,EAChC,aACA,YACyC;CACzC,IAAM,EAAE,SAAM,GAA+B,EACvC,IAAa,EAAG,MAAM;AAE5B,QACE,kBAAC,GAAD;EAAiC;EAAc;aAC3C,MAAU;GACV,IAAI,IAAgB;AAIpB,UAHI,MAAe,OACjB,IAAgB,EAAE,kCAAkC,GAE/C,kBAAC,QAAD,EAAA,UAAO,KAAS,GAAqB,CAAA;;EAExB,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PasswordResetCompleteScreen-B0P_tZg2.js","names":[],"sources":["../../src/auth/pages/PasswordResetCompleteScreen.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n useCallback,\n useMemo,\n useState,\n type FormEvent,\n type JSX,\n} from 'react';\nimport { useSharedTranslation } from '../../i18n/useSharedTranslation.js';\n\nimport { AuthLayout, Button, FormError, FormField } from '@plumile/ui';\n\nimport * as styles from '../login/loginPage.css.js';\nimport AuthPanel from '../login/AuthPanel.js';\n\nconst MIN_PASSWORD_LENGTH = 8;\n\ntype Props = {\n onBackToLogin: () => void;\n onCompletePasswordReset: (input: {\n newPassword: string;\n token: string;\n }) => Promise<boolean>;\n token?: string;\n};\n\nexport const PasswordResetCompleteScreen = ({\n onBackToLogin,\n onCompletePasswordReset,\n token,\n}: Props): JSX.Element => {\n const { t } = useSharedTranslation();\n const [password, setPassword] = useState('');\n const [passwordConfirm, setPasswordConfirm] = useState('');\n const [status, setStatus] = useState<'idle' | 'completed'>('idle');\n const [error, setError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const resolvedToken = useMemo(() => {\n if (token != null) {\n return token;\n }\n if (typeof window === 'undefined') {\n return '';\n }\n const params = new URLSearchParams(window.location.search);\n return params.get('token') ?? '';\n }, [token]);\n\n const handleSubmit = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setError(null);\n\n if (resolvedToken === '') {\n setError(t('auth.passwordResetComplete.errors.missingToken'));\n return;\n }\n\n if (password.length < MIN_PASSWORD_LENGTH) {\n setError(\n t('auth.passwordResetComplete.errors.minLength', {\n minLength: MIN_PASSWORD_LENGTH,\n }),\n );\n return;\n }\n\n if (password !== passwordConfirm) {\n setError(t('auth.passwordResetComplete.errors.mismatch'));\n return;\n }\n\n setIsSubmitting(true);\n\n const completePasswordReset = async (): Promise<void> => {\n try {\n const success = await onCompletePasswordReset({\n newPassword: password,\n token: resolvedToken,\n });\n if (success) {\n setStatus('completed');\n } else {\n setError(t('auth.passwordResetComplete.errors.invalid'));\n }\n } catch (mutationError) {\n setError(\n mutationError instanceof Error\n ? mutationError.message\n : t('auth.passwordResetComplete.errors.invalid'),\n );\n } finally {\n setIsSubmitting(false);\n }\n };\n\n completePasswordReset().catch(() => {\n return undefined;\n });\n },\n [onCompletePasswordReset, password, passwordConfirm, resolvedToken, t],\n );\n\n let content: JSX.Element;\n if (status === 'completed') {\n content = (\n <AuthPanel\n title={t('auth.passwordResetComplete.success.title')}\n description={t('auth.passwordResetComplete.success.description')}\n footer={\n <Button\n type=\"button\"\n variant=\"secondary\"\n className={styles.brandGhostButton}\n onClick={onBackToLogin}\n >\n {t('auth.passwordResetComplete.success.action')}\n </Button>\n }\n >\n <p className={styles.helper}>\n {t('auth.passwordResetComplete.success.helper')}\n </p>\n </AuthPanel>\n );\n } else {\n content = (\n <AuthPanel\n title={t('auth.passwordResetComplete.form.title')}\n description={t('auth.passwordResetComplete.form.description')}\n >\n <form className={styles.formSurface} onSubmit={handleSubmit} noValidate>\n {error != null ? <FormError>{error}</FormError> : null}\n <FormField\n label={t('auth.passwordResetComplete.form.passwordLabel')}\n name=\"new-password\"\n type=\"password\"\n value={password}\n onChange={(event) => {\n setPassword(event.target.value);\n setError(null);\n }}\n placeholder={t(\n 'auth.passwordResetComplete.form.passwordPlaceholder',\n )}\n autoComplete=\"new-password\"\n required\n />\n <FormField\n label={t('auth.passwordResetComplete.form.confirmLabel')}\n name=\"confirm-password\"\n type=\"password\"\n value={passwordConfirm}\n onChange={(event) => {\n setPasswordConfirm(event.target.value);\n setError(null);\n }}\n placeholder={t(\n 'auth.passwordResetComplete.form.confirmPlaceholder',\n )}\n autoComplete=\"new-password\"\n required\n />\n <Button type=\"submit\" isLoading={isSubmitting}>\n {t('auth.passwordResetComplete.form.submit')}\n </Button>\n </form>\n </AuthPanel>\n );\n }\n\n return (\n <AuthLayout\n title={t('auth.passwordResetComplete.title')}\n subtitle={t('auth.passwordResetComplete.subtitle')}\n >\n {content}\n </AuthLayout>\n );\n};\n"],"mappings":";;;;;;AAeA,IAAM,IAAsB,GAWf,KAA+B,EAC1C,kBACA,4BACA,eACwB;CACxB,IAAM,EAAE,SAAM,GAAsB,EAC9B,CAAC,GAAU,KAAe,EAAS,GAAG,EACtC,CAAC,GAAiB,KAAsB,EAAS,GAAG,EACpD,CAAC,GAAQ,KAAa,EAA+B,OAAO,EAC5D,CAAC,GAAO,KAAY,EAAwB,KAAK,EACjD,CAAC,GAAc,KAAmB,EAAS,GAAM,EAEjD,IAAgB,QAChB,MAGA,OAAO,SAAW,MACb,KAEM,IAAI,gBAAgB,OAAO,SAAS,OAAO,CAC5C,IAAI,QAAQ,IAAI,KAC7B,CAAC,EAAM,CAAC,EAEL,IAAe,GAClB,MAAsC;AAIrC,MAHA,EAAM,gBAAgB,EACtB,EAAS,KAAK,EAEV,MAAkB,IAAI;AACxB,KAAS,EAAE,iDAAiD,CAAC;AAC7D;;AAGF,MAAI,EAAS,SAAS,GAAqB;AACzC,KACE,EAAE,+CAA+C,EAC/C,WAAW,GACZ,CAAC,CACH;AACD;;AAGF,MAAI,MAAa,GAAiB;AAChC,KAAS,EAAE,6CAA6C,CAAC;AACzD;;AA2BF,EAxBA,EAAgB,GAAK,GAES,YAA2B;AACvD,OAAI;AAKF,IAJgB,MAAM,EAAwB;KAC5C,aAAa;KACb,OAAO;KACR,CAAC,GAEA,EAAU,YAAY,GAEtB,EAAS,EAAE,4CAA4C,CAAC;YAEnD,GAAe;AACtB,MACE,aAAyB,QACrB,EAAc,UACd,EAAE,4CAA4C,CACnD;aACO;AACR,MAAgB,GAAM;;MAIH,CAAC,YAAY,GAElC;IAEJ;EAAC;EAAyB;EAAU;EAAiB;EAAe;EAAE,CACvE,EAEG;AAoEJ,QAnEA,AAsBE,IAtBE,MAAW,cAEX,kBAAC,GAAD;EACE,OAAO,EAAE,2CAA2C;EACpD,aAAa,EAAE,iDAAiD;EAChE,QACE,kBAAC,GAAD;GACE,MAAK;GACL,SAAQ;GACR,WAAW;GACX,SAAS;aAER,EAAE,4CAA4C;GACxC,CAAA;YAGX,kBAAC,KAAD;GAAG,WAAW;aACX,EAAE,4CAA4C;GAC7C,CAAA;EACM,CAAA,GAIZ,kBAAC,GAAD;EACE,OAAO,EAAE,wCAAwC;EACjD,aAAa,EAAE,8CAA8C;YAE7D,kBAAC,QAAD;GAAM,WAAW;GAAoB,UAAU;GAAc,YAAA;aAA7D;IACG,KAAS,OAAwC,OAAjC,kBAAC,GAAD,EAAA,UAAY,GAAkB,CAAA;IAC/C,kBAAC,GAAD;KACE,OAAO,EAAE,gDAAgD;KACzD,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;AAEnB,MADA,EAAY,EAAM,OAAO,MAAM,EAC/B,EAAS,KAAK;;KAEhB,aAAa,EACX,sDACD;KACD,cAAa;KACb,UAAA;KACA,CAAA;IACF,kBAAC,GAAD;KACE,OAAO,EAAE,+CAA+C;KACxD,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;AAEnB,MADA,EAAmB,EAAM,OAAO,MAAM,EACtC,EAAS,KAAK;;KAEhB,aAAa,EACX,qDACD;KACD,cAAa;KACb,UAAA;KACA,CAAA;IACF,kBAAC,GAAD;KAAQ,MAAK;KAAS,WAAW;eAC9B,EAAE,yCAAyC;KACrC,CAAA;IACJ;;EACG,CAAA,EAKd,kBAAC,GAAD;EACE,OAAO,EAAE,mCAAmC;EAC5C,UAAU,EAAE,sCAAsC;YAEjD;EACU,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PasswordResetRequestScreen-p9s0dblR.js","names":[],"sources":["../../src/auth/pages/PasswordResetRequestScreen.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n useCallback,\n useMemo,\n useState,\n type FormEvent,\n type JSX,\n} from 'react';\nimport { useSharedTranslation } from '../../i18n/useSharedTranslation.js';\n\nimport { AuthLayout, Button, FormError, FormField } from '@plumile/ui';\n\nimport * as styles from '../login/loginPage.css.js';\nimport AuthPanel from '../login/AuthPanel.js';\n\ntype Props = {\n onStartPasswordReset: (input: {\n email: string;\n locale?: string;\n }) => Promise<boolean>;\n};\n\nexport const PasswordResetRequestScreen = ({\n onStartPasswordReset,\n}: Props): JSX.Element => {\n const { i18n, t } = useSharedTranslation();\n const [email, setEmail] = useState('');\n const [status, setStatus] = useState<'idle' | 'sent'>('idle');\n const [error, setError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const locale = useMemo(() => {\n const language = i18n.language.trim();\n if (language !== '') {\n return language;\n }\n if (typeof navigator === 'undefined') {\n return undefined;\n }\n return navigator.language;\n }, [i18n.language]);\n\n const handleSubmit = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setError(null);\n\n if (email.trim() === '') {\n setError(t('auth.passwordResetRequest.errors.emailRequired'));\n return;\n }\n\n setIsSubmitting(true);\n onStartPasswordReset({\n email: email.trim(),\n locale,\n })\n .then((success) => {\n if (success) {\n setStatus('sent');\n } else {\n setError(t('auth.passwordResetRequest.errors.startFailed'));\n }\n })\n .catch((mutationError) => {\n setError(\n mutationError instanceof Error\n ? mutationError.message\n : t('auth.passwordResetRequest.errors.startFailed'),\n );\n })\n .finally(() => {\n setIsSubmitting(false);\n });\n },\n [email, locale, onStartPasswordReset, t],\n );\n\n let content: JSX.Element;\n if (status === 'sent') {\n content = (\n <AuthPanel\n title={t('auth.passwordResetRequest.sent.title')}\n description={t('auth.passwordResetRequest.sent.description', { email })}\n footer={\n <Button\n type=\"button\"\n variant=\"secondary\"\n onClick={() => {\n setStatus('idle');\n }}\n >\n {t('auth.passwordResetRequest.sent.action')}\n </Button>\n }\n >\n <p className={styles.helper}>\n {t('auth.passwordResetRequest.sent.helper')}\n </p>\n </AuthPanel>\n );\n } else {\n content = (\n <AuthPanel description={t('auth.passwordResetRequest.form.description')}>\n <form className={styles.formSurface} onSubmit={handleSubmit} noValidate>\n {error != null ? <FormError>{error}</FormError> : null}\n <FormField\n label={t('auth.passwordResetRequest.form.emailLabel')}\n name=\"email\"\n type=\"email\"\n value={email}\n onChange={(event) => {\n setEmail(event.target.value);\n setError(null);\n }}\n placeholder={t('auth.passwordResetRequest.form.emailPlaceholder')}\n autoComplete=\"email\"\n autoFocus\n required\n />\n <Button type=\"submit\" isLoading={isSubmitting}>\n {t('auth.passwordResetRequest.form.submit')}\n </Button>\n </form>\n </AuthPanel>\n );\n }\n\n return (\n <AuthLayout title={t('auth.passwordResetRequest.title')}>\n {content}\n </AuthLayout>\n );\n};\n"],"mappings":";;;;;;AAsBA,IAAa,KAA8B,EACzC,8BACwB;CACxB,IAAM,EAAE,SAAM,SAAM,GAAsB,EACpC,CAAC,GAAO,KAAY,EAAS,GAAG,EAChC,CAAC,GAAQ,KAAa,EAA0B,OAAO,EACvD,CAAC,GAAO,KAAY,EAAwB,KAAK,EACjD,CAAC,GAAc,KAAmB,EAAS,GAAM,EAEjD,IAAS,QAAc;EAC3B,IAAM,IAAW,EAAK,SAAS,MAAM;AACrC,MAAI,MAAa,GACf,QAAO;AAEL,eAAO,YAAc,KAGzB,QAAO,UAAU;IAChB,CAAC,EAAK,SAAS,CAAC,EAEb,IAAe,GAClB,MAAsC;AAIrC,MAHA,EAAM,gBAAgB,EACtB,EAAS,KAAK,EAEV,EAAM,MAAM,KAAK,IAAI;AACvB,KAAS,EAAE,iDAAiD,CAAC;AAC7D;;AAIF,EADA,EAAgB,GAAK,EACrB,EAAqB;GACnB,OAAO,EAAM,MAAM;GACnB;GACD,CAAC,CACC,MAAM,MAAY;AACjB,GAAI,IACF,EAAU,OAAO,GAEjB,EAAS,EAAE,+CAA+C,CAAC;IAE7D,CACD,OAAO,MAAkB;AACxB,KACE,aAAyB,QACrB,EAAc,UACd,EAAE,+CAA+C,CACtD;IACD,CACD,cAAc;AACb,KAAgB,GAAM;IACtB;IAEN;EAAC;EAAO;EAAQ;EAAsB;EAAE,CACzC,EAEG;AAkDJ,QAjDA,AAuBE,IAvBE,MAAW,SAEX,kBAAC,GAAD;EACE,OAAO,EAAE,uCAAuC;EAChD,aAAa,EAAE,8CAA8C,EAAE,UAAO,CAAC;EACvE,QACE,kBAAC,GAAD;GACE,MAAK;GACL,SAAQ;GACR,eAAe;AACb,MAAU,OAAO;;aAGlB,EAAE,wCAAwC;GACpC,CAAA;YAGX,kBAAC,KAAD;GAAG,WAAW;aACX,EAAE,wCAAwC;GACzC,CAAA;EACM,CAAA,GAIZ,kBAAC,GAAD;EAAW,aAAa,EAAE,6CAA6C;YACrE,kBAAC,QAAD;GAAM,WAAW;GAAoB,UAAU;GAAc,YAAA;aAA7D;IACG,KAAS,OAAwC,OAAjC,kBAAC,GAAD,EAAA,UAAY,GAAkB,CAAA;IAC/C,kBAAC,GAAD;KACE,OAAO,EAAE,4CAA4C;KACrD,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;AAEnB,MADA,EAAS,EAAM,OAAO,MAAM,EAC5B,EAAS,KAAK;;KAEhB,aAAa,EAAE,kDAAkD;KACjE,cAAa;KACb,WAAA;KACA,UAAA;KACA,CAAA;IACF,kBAAC,GAAD;KAAQ,MAAK;KAAS,WAAW;eAC9B,EAAE,wCAAwC;KACpC,CAAA;IACJ;;EACG,CAAA,EAKd,kBAAC,GAAD;EAAY,OAAO,EAAE,kCAAkC;YACpD;EACU,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"VerifyEmailScreen--9lxOGlW.js","names":[],"sources":["../../src/auth/pages/VerifyEmailScreen.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport { useEffect, useMemo, useState, type JSX } from 'react';\nimport { useSharedTranslation } from '../../i18n/useSharedTranslation.js';\n\nimport { AuthLayout, Button, FormError } from '@plumile/ui';\n\nimport * as styles from '../login/loginPage.css.js';\n\ntype VerificationState = 'pending' | 'success' | 'error';\n\ntype Props = {\n onBackToLogin: () => void;\n onVerifyEmail: (input: { token: string }) => Promise<boolean>;\n token?: string;\n};\n\nexport const VerifyEmailScreen = ({\n onBackToLogin,\n onVerifyEmail,\n token,\n}: Props): JSX.Element => {\n const { t } = useSharedTranslation();\n const [state, setState] = useState<VerificationState>('pending');\n const [error, setError] = useState<string | null>(null);\n\n const resolvedToken = useMemo(() => {\n if (token != null) {\n return token;\n }\n if (typeof window === 'undefined') {\n return '';\n }\n const params = new URLSearchParams(window.location.search);\n return params.get('token') ?? '';\n }, [token]);\n\n useEffect(() => {\n if (resolvedToken === '') {\n setState('error');\n setError(t('auth.verifyEmail.errors.missingToken'));\n return;\n }\n\n const verifyEmail = async (): Promise<void> => {\n try {\n const success = await onVerifyEmail({ token: resolvedToken });\n if (success) {\n setState('success');\n } else {\n setState('error');\n setError(t('auth.verifyEmail.errors.invalid'));\n }\n } catch (mutationError) {\n setState('error');\n setError(\n mutationError instanceof Error\n ? mutationError.message\n : t('auth.verifyEmail.errors.invalid'),\n );\n }\n };\n\n verifyEmail().catch(() => {\n return undefined;\n });\n }, [onVerifyEmail, resolvedToken, t]);\n\n let content: JSX.Element;\n if (state === 'success') {\n content = (\n <div className={styles.stack}>\n <p className={styles.helper}>{t('auth.verifyEmail.status.success')}</p>\n <Button type=\"button\" variant=\"secondary\" onClick={onBackToLogin}>\n {t('auth.verifyEmail.actions.continue')}\n </Button>\n </div>\n );\n } else if (state === 'error') {\n content = (\n <div className={styles.stack}>\n {error != null ? <FormError>{error}</FormError> : null}\n <Button type=\"button\" variant=\"secondary\" onClick={onBackToLogin}>\n {t('auth.verifyEmail.actions.return')}\n </Button>\n </div>\n );\n } else {\n content = (\n <div className={styles.stack}>\n <p className={styles.helper}>\n {t('auth.verifyEmail.status.verifying')}\n </p>\n <Button type=\"button\" isLoading>\n {t('auth.verifyEmail.status.verifyingButton')}\n </Button>\n </div>\n );\n }\n\n return (\n <AuthLayout\n title={t('auth.verifyEmail.title')}\n subtitle={t('auth.verifyEmail.subtitle')}\n >\n {content}\n </AuthLayout>\n );\n};\n"],"mappings":";;;;;AAgBA,IAAa,KAAqB,EAChC,kBACA,kBACA,eACwB;CACxB,IAAM,EAAE,SAAM,GAAsB,EAC9B,CAAC,GAAO,KAAY,EAA4B,UAAU,EAC1D,CAAC,GAAO,KAAY,EAAwB,KAAK,EAEjD,IAAgB,QAChB,MAGA,OAAO,SAAW,MACb,KAEM,IAAI,gBAAgB,OAAO,SAAS,OAAO,CAC5C,IAAI,QAAQ,IAAI,KAC7B,CAAC,EAAM,CAAC;AAEX,SAAgB;AACd,MAAI,MAAkB,IAAI;AAExB,GADA,EAAS,QAAQ,EACjB,EAAS,EAAE,uCAAuC,CAAC;AACnD;;AAsBF,GAnBoB,YAA2B;AAC7C,OAAI;AAEF,IADgB,MAAM,EAAc,EAAE,OAAO,GAAe,CAAC,GAE3D,EAAS,UAAU,IAEnB,EAAS,QAAQ,EACjB,EAAS,EAAE,kCAAkC,CAAC;YAEzC,GAAe;AAEtB,IADA,EAAS,QAAQ,EACjB,EACE,aAAyB,QACrB,EAAc,UACd,EAAE,kCAAkC,CACzC;;MAIQ,CAAC,YAAY,GAExB;IACD;EAAC;EAAe;EAAe;EAAE,CAAC;CAErC,IAAI;AAgCJ,QA/BA,AAmBE,IAnBE,MAAU,YAEV,kBAAC,OAAD;EAAK,WAAW;YAAhB,CACE,kBAAC,KAAD;GAAG,WAAW;aAAgB,EAAE,kCAAkC;GAAK,CAAA,EACvE,kBAAC,GAAD;GAAQ,MAAK;GAAS,SAAQ;GAAY,SAAS;aAChD,EAAE,oCAAoC;GAChC,CAAA,CACL;MAEC,MAAU,UAEjB,kBAAC,OAAD;EAAK,WAAW;YAAhB,CACG,KAAS,OAAwC,OAAjC,kBAAC,GAAD,EAAA,UAAY,GAAkB,CAAA,EAC/C,kBAAC,GAAD;GAAQ,MAAK;GAAS,SAAQ;GAAY,SAAS;aAChD,EAAE,kCAAkC;GAC9B,CAAA,CACL;MAIN,kBAAC,OAAD;EAAK,WAAW;YAAhB,CACE,kBAAC,KAAD;GAAG,WAAW;aACX,EAAE,oCAAoC;GACrC,CAAA,EACJ,kBAAC,GAAD;GAAQ,MAAK;GAAS,WAAA;aACnB,EAAE,0CAA0C;GACtC,CAAA,CACL;KAKR,kBAAC,GAAD;EACE,OAAO,EAAE,yBAAyB;EAClC,UAAU,EAAE,4BAA4B;YAEvC;EACU,CAAA"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { useTranslation as e } from "react-i18next";
|
|
2
|
-
//#region src/i18n/useSharedTranslation.ts
|
|
3
|
-
function t() {
|
|
4
|
-
return e("shared");
|
|
5
|
-
}
|
|
6
|
-
//#endregion
|
|
7
|
-
//#region src/auth/login/loginPage.css.ts
|
|
8
|
-
var n = "txvbqb9ip txvbqbai7 txvbqbaop", r = "txvbqb9ip txvbqbai7 txvbqbu7g", i = "txvbqbvbd txvbqb8y txvbqbfcp txvbqbf5y", a = "txvbqbcp txvbqb9ip txvbqbajy txvbqbaog txvbqbdpp txvbqbhyg", o = "w8yhmy0 txvbqbvaz txvbqbamp txvbqb78 txvbqb6x txvbqb7k", s = "txvbqbnwy txvbqbok7 txvbqbp7g txvbqblz7 txvbqb767 txvbqb73g txvbqb7d7 txvbqb7ag", c = "txvbqb9ip txvbqbai7 txvbqbaop", l = "txvbqbu7g", u = "txvbqbfcp txvbqb9p txvbqbamy txvbqbvaz txvbqbee7", d = "txvbqbhyp", f = "w8yhmy1 txvbqb107 txvbqb1dg txvbqb1qg txvbqbvaz txvbqbv5t txvbqb78 txvbqb6w txvbqb7k";
|
|
9
|
-
//#endregion
|
|
10
|
-
export { r as a, o as c, n as d, t as f, d as i, s as l, c as n, l as o, f as r, i as s, a as t, u };
|
|
11
|
-
|
|
12
|
-
//# sourceMappingURL=loginPage.css-CBJ1Ozm5.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"loginPage.css-CBJ1Ozm5.js","names":[],"sources":["../../src/i18n/useSharedTranslation.ts","../../src/auth/login/loginPage.css.ts"],"sourcesContent":["import { useTranslation } from 'react-i18next';\n\n/** Returns i18n helpers bound to the shared namespace. */\nexport function useSharedTranslation(): ReturnType<typeof useTranslation> {\n return useTranslation('shared');\n}\n","import { style } from '@vanilla-extract/css';\nimport { sprinkles, vars } from '@plumile/ui';\n\nexport const stack = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n});\n\nexport const formSurface = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n width: 'full',\n});\n\nexport const helper = sprinkles({\n color: 'brandDarkGray',\n fontSize: 'sm',\n margin: 0,\n lineHeight: 1.6,\n});\n\nexport const divider = sprinkles({\n alignItems: 'center',\n color: 'brandDarkGray',\n display: 'flex',\n gap: 2,\n marginTop: 5,\n marginBottom: 3,\n});\n\nexport const dividerLine = sprinkles({\n backgroundColor: 'brandPrimaryRed',\n height: 'px',\n flex: 1,\n borderRadius: 'full',\n opacity: 35,\n});\n\nexport const actionsRow = sprinkles({\n alignItems: 'center',\n display: 'flex',\n flexWrap: 'wrap',\n gap: 3,\n justifyContent: 'space-between',\n marginTop: 3,\n});\n\nexport const inlineLink = style([\n sprinkles({\n color: 'brandPrimaryRed',\n fontWeight: 'semibold',\n transitionProperty: 'colors',\n transitionDuration: 150,\n transitionTimingFunction: 'ease',\n }),\n {\n background: 'transparent',\n borderWidth: 0,\n borderStyle: 'none',\n cursor: 'pointer',\n padding: 0,\n textDecoration: 'none',\n ':hover': {\n color: vars.colors.brandSecondaryOrange,\n textDecoration: 'underline',\n },\n },\n]);\n\nexport const panel = sprinkles({\n borderTopLeftRadius: 'none',\n borderTopRightRadius: 'none',\n borderBottomLeftRadius: '2xl',\n borderBottomRightRadius: '2xl',\n paddingX: 6,\n paddingY: 6,\n});\n\nexport const block = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n});\n\nexport const fullWidth = sprinkles({\n width: 'full',\n});\n\nexport const panelTitle = sprinkles({\n margin: 0,\n fontSize: 'xl',\n fontWeight: 'bold',\n color: 'brandPrimaryRed',\n letterSpacing: 'tight',\n});\n\nexport const footer = sprinkles({\n marginTop: 4,\n});\n\nexport const brandGhostButton = style([\n sprinkles({\n borderColor: 'brandPrimaryRed',\n borderWidth: 'px',\n borderStyle: 'solid',\n color: 'brandPrimaryRed',\n backgroundColor: 'brandLightGray',\n transitionProperty: 'colors',\n transitionDuration: 120,\n transitionTimingFunction: 'ease',\n }),\n {\n selectors: {\n '&:hover:not(:disabled)': {\n backgroundColor: `color-mix(in srgb, ${vars.colors.brandPrimaryRed} 8%, transparent)`,\n color: vars.colors.brandSecondaryOrange,\n borderColor: vars.colors.brandSecondaryOrange,\n },\n },\n },\n]);\n"],"mappings":";;AAGA,SAAgB,IAA0D;AACxE,QAAO,EAAe,SAAS"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"synchronizeAuthStatusQuery-By_lNCnP.js","names":[],"sources":["../../src/auth/login/PasskeyLoginForm.tsx","../../src/auth/login/MethodChooser.tsx","../../src/auth/login/EmailCapturePanel.tsx","../../src/auth/login/OidcButtons.tsx","../../src/auth/login/PasswordLoginPanel.tsx","../../src/auth/login/LoginFlow.tsx","../../src/auth/login/synchronizeAuthStatusQuery.ts"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n useCallback,\n useEffect,\n useState,\n type FormEvent,\n type JSX,\n} from 'react';\nimport { useSharedTranslation } from '../../i18n/useSharedTranslation.js';\n\nimport { Button, FormError, FormField } from '@plumile/ui';\n\nimport type { UseAuthReturn } from '../../hooks/useAuth.js';\n\nimport * as styles from './loginPage.css.js';\n\ntype Props = {\n auth: Pick<\n UseAuthReturn,\n | 'loginWithPasskey'\n | 'isLoading'\n | 'error'\n | 'emailHint'\n | 'nextStep'\n | 'beginAuthentication'\n | 'lockedUntil'\n | 'availableMethods'\n >;\n onSuccess: () => void;\n defaultEmail?: string;\n isAttemptingPasskey?: boolean;\n onShowMethods?: () => void;\n};\n\nexport const PasskeyLoginForm = ({\n auth,\n onSuccess,\n defaultEmail,\n isAttemptingPasskey = false,\n onShowMethods,\n}: Props): JSX.Element => {\n const { t } = useSharedTranslation();\n const [email, setEmail] = useState(auth.emailHint ?? '');\n const [localError, setLocalError] = useState<string | null>(null);\n\n useEffect(() => {\n if (auth.emailHint != null && auth.emailHint !== '') {\n setEmail(auth.emailHint);\n } else if (defaultEmail != null && defaultEmail !== '') {\n setEmail(defaultEmail);\n }\n }, [auth.emailHint, defaultEmail]);\n\n const handleSubmit = useCallback(\n async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setLocalError(null);\n\n if (email.trim() === '') {\n setLocalError(t('auth.passkey.errors.emailRequired'));\n return;\n }\n\n try {\n const result = await auth.beginAuthentication(email.trim());\n if (Array.isArray(result.methods) && result.methods.length === 0) {\n const lockedUntilMessage =\n result.lockedUntil != null\n ? t('auth.passkey.errors.lockedWithTime', {\n time: new Date(result.lockedUntil).toLocaleString(),\n })\n : t('auth.passkey.errors.locked');\n setLocalError(lockedUntilMessage);\n return;\n }\n if (\n Array.isArray(result.methods) &&\n !result.methods.includes('PASSKEY')\n ) {\n setLocalError(t('auth.passkey.errors.notAvailable'));\n return;\n }\n\n const status = await auth.loginWithPasskey({ email: email.trim() });\n if (status === 'success') {\n onSuccess();\n }\n } catch {\n const authMessage = auth.error?.message;\n setLocalError(authMessage ?? t('auth.passkey.errors.failed'));\n }\n },\n [auth, email, onSuccess, t],\n );\n\n const formError = localError ?? auth.error?.message ?? null;\n\n return (\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n <form className={styles.formSurface} onSubmit={handleSubmit} noValidate>\n <div className={styles.stack}>\n <p className={styles.helper}>{t('auth.passkey.helper')}</p>\n {formError != null ? <FormError>{formError}</FormError> : null}\n <FormField\n label={t('auth.passkey.form.emailLabel')}\n name=\"passkey-email\"\n type=\"email\"\n value={email}\n onChange={(event) => {\n setEmail(event.target.value);\n setLocalError(null);\n }}\n placeholder={t('auth.passkey.form.emailPlaceholder')}\n autoComplete=\"email\"\n required\n />\n </div>\n <div className={styles.actionsRow}>\n <Button type=\"submit\" variant=\"primary\" isLoading={auth.isLoading}>\n {isAttemptingPasskey\n ? t('auth.passkey.actions.submitting')\n : t('auth.passkey.actions.submit')}\n </Button>\n {onShowMethods != null ? (\n <button\n type=\"button\"\n className={styles.inlineLink}\n onClick={onShowMethods}\n >\n {t('auth.passkey.actions.showMethods')}\n </button>\n ) : null}\n </div>\n </form>\n );\n};\n","/* eslint-disable no-ternary */\nimport { type JSX } from 'react';\nimport { Trans } from 'react-i18next';\nimport { Button, FormError, cx } from '@plumile/ui';\n\nimport type { AuthMethod } from '../../modules/sharedSchemaTypes.js';\nimport { useSharedTranslation } from '../../i18n/useSharedTranslation.js';\n\nimport * as styles from './loginPage.css.js';\n\ntype Props = {\n email: string;\n methods: readonly AuthMethod[];\n lockedUntil: string | null;\n onSelect: (method: AuthMethod) => void;\n onBack: () => void;\n};\n\nexport const MethodChooser = ({\n email,\n methods,\n lockedUntil,\n onSelect,\n onBack,\n}: Props): JSX.Element => {\n const { t } = useSharedTranslation();\n const isLocked = methods.length === 0;\n const lockedMessage =\n lockedUntil != null\n ? t('auth.methodChooser.lockedWithTime', {\n time: new Date(lockedUntil).toLocaleString(),\n })\n : t('auth.methodChooser.locked');\n\n const methodButtons = methods.map((method) => {\n const label =\n method === 'PASSKEY'\n ? t('auth.methodChooser.methods.passkey')\n : method === 'PASSWORD'\n ? t('auth.methodChooser.methods.password')\n : t('auth.methodChooser.methods.other', {\n method: method.toLowerCase(),\n });\n return (\n <Button\n key={method}\n type=\"button\"\n variant=\"secondary\"\n onClick={() => {\n onSelect(method);\n }}\n className={cx(styles.fullWidth, styles.brandGhostButton)}\n >\n {label}\n </Button>\n );\n });\n\n return (\n <div className={styles.formSurface}>\n <div className={styles.stack}>\n <p className={styles.helper}>\n <Trans\n i18nKey=\"auth.methodChooser.prompt\"\n values={{ email }}\n components={{ strong: <strong /> }}\n />\n </p>\n {isLocked ? <FormError>{lockedMessage}</FormError> : null}\n {!isLocked ? methodButtons : null}\n <Button\n type=\"button\"\n variant=\"text\"\n onClick={onBack}\n className={styles.inlineLink}\n >\n {t('auth.methodChooser.actions.back')}\n </Button>\n </div>\n </div>\n );\n};\n","import { type JSX } from 'react';\nimport { useSharedTranslation } from '../../i18n/useSharedTranslation.js';\n\nimport { Button, FormError, FormField } from '@plumile/ui';\n\nimport { AuthPanel } from './AuthPanel.js';\nimport * as styles from './loginPage.css.js';\n\ntype Props = {\n email: string;\n errorMessage: string | null;\n isLoading: boolean;\n onEmailChange: (value: string) => void;\n onContinue: () => void;\n onForgotPassword: () => void;\n};\n\nexport const EmailCapturePanel = ({\n email,\n errorMessage,\n isLoading,\n onEmailChange,\n onContinue,\n onForgotPassword,\n}: Props): JSX.Element => {\n const { t } = useSharedTranslation();\n return (\n <AuthPanel>\n <div className={styles.formSurface}>\n <p className={styles.helper}>{t('auth.emailCapture.description')}</p>\n {errorMessage != null && <FormError>{errorMessage}</FormError>}\n <FormField\n label={t('auth.emailCapture.emailLabel')}\n name=\"email\"\n type=\"email\"\n value={email}\n onChange={(event) => {\n onEmailChange(event.target.value);\n }}\n placeholder={t('auth.emailCapture.emailPlaceholder')}\n autoComplete=\"email\"\n required\n />\n <div className={styles.actionsRow}>\n <Button\n type=\"button\"\n variant=\"primary\"\n onClick={onContinue}\n isLoading={isLoading}\n >\n {t('auth.emailCapture.continue')}\n </Button>\n <button\n type=\"button\"\n className={styles.inlineLink}\n onClick={onForgotPassword}\n >\n {t('auth.emailCapture.forgotPassword')}\n </button>\n </div>\n </div>\n </AuthPanel>\n );\n};\n","import { type JSX } from 'react';\n\nimport { Button } from '@plumile/ui';\n\nimport type { OidcProviderKind } from '../../modules/sharedSchemaTypes.js';\nimport { useSharedTranslation } from '../../i18n/useSharedTranslation.js';\n\nimport * as styles from './loginPage.css.js';\n\nconst OIDC_START_PATH = '/auth/oidc/start';\n\ntype Props = {\n providers: readonly OidcProviderKind[];\n};\n\nexport const OidcButtons = ({ providers }: Props): JSX.Element | null => {\n const { t } = useSharedTranslation();\n\n if (providers.length === 0) {\n return null;\n }\n\n return (\n <div className={styles.stack}>\n {providers.map((provider) => {\n let label = t('auth.oidc.buttons.generic');\n if (provider === 'GOOGLE') {\n label = t('auth.oidc.buttons.google');\n } else if (provider === 'APPLE') {\n label = t('auth.oidc.buttons.apple');\n }\n const providerName = provider.toLowerCase();\n return (\n <Button\n key={provider}\n type=\"button\"\n variant=\"secondary\"\n className={styles.brandGhostButton}\n onClick={() => {\n window.location.assign(\n `${OIDC_START_PATH}?provider=${providerName}`,\n );\n }}\n >\n {label}\n </Button>\n );\n })}\n </div>\n );\n};\n","import { type JSX } from 'react';\nimport { useSharedTranslation } from '../../i18n/useSharedTranslation.js';\n\nimport { LoginForm, type LoginFormAuthAdapter } from '@plumile/ui';\n\nimport type { OidcProviderKind } from '../../modules/sharedSchemaTypes.js';\n\nimport { AuthPanel } from './AuthPanel.js';\nimport { OidcButtons } from './OidcButtons.js';\nimport * as styles from './loginPage.css.js';\n\ntype Props = {\n auth: LoginFormAuthAdapter;\n defaultEmail: string;\n onForgotPassword: () => void;\n onSuccess: () => void;\n providers: readonly OidcProviderKind[];\n};\n\nexport const PasswordLoginPanel = ({\n auth,\n defaultEmail,\n onForgotPassword,\n onSuccess,\n providers,\n}: Props): JSX.Element => {\n const { t } = useSharedTranslation();\n return (\n <AuthPanel title={t('auth.passwordLogin.title')}>\n <div className={styles.formSurface}>\n <LoginForm\n auth={auth}\n onSuccess={onSuccess}\n defaultEmail={defaultEmail}\n />\n <div className={styles.actionsRow}>\n <button\n type=\"button\"\n className={styles.inlineLink}\n onClick={onForgotPassword}\n >\n {t('auth.passwordLogin.forgotPassword')}\n </button>\n </div>\n <OidcButtons providers={providers} />\n </div>\n </AuthPanel>\n );\n};\n","/* eslint-disable no-ternary */\nimport {\n type JSX,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useSharedTranslation } from '../../i18n/useSharedTranslation.js';\n\nimport { AuthLayout } from '@plumile/ui';\n\nimport type {\n AuthMethod,\n OidcProviderKind,\n} from '../../modules/sharedSchemaTypes.js';\nimport type { UseAuthReturn } from '../../hooks/useAuth.js';\n\nimport { MfaChallengeForm } from './MfaChallengeForm.js';\nimport { PasskeyLoginForm } from './PasskeyLoginForm.js';\nimport { MethodChooser } from './MethodChooser.js';\nimport AuthPanel from './AuthPanel.js';\nimport { EmailCapturePanel } from './EmailCapturePanel.js';\nimport { PasswordLoginPanel } from './PasswordLoginPanel.js';\n\nexport type LoginFlowProps = {\n auth: UseAuthReturn;\n oidcProviders: readonly OidcProviderKind[];\n onLoginSuccess: () => void;\n onForgotPassword: () => void;\n};\n\ntype View = 'email' | 'passkey' | 'methods' | 'password' | 'mfa';\n\nexport const LoginFlow = ({\n auth,\n oidcProviders,\n onLoginSuccess,\n onForgotPassword,\n}: LoginFlowProps): JSX.Element => {\n const { t } = useSharedTranslation();\n const [email, setEmail] = useState('');\n const [methods, setMethods] = useState<readonly AuthMethod[]>([]);\n const [lockedUntil, setLockedUntil] = useState<string | null>(null);\n const [view, setView] = useState<View>('email');\n const [hasTriedPasskey, setHasTriedPasskey] = useState(false);\n const [localError, setLocalError] = useState<string | null>(null);\n const passkeyAttemptActive = useRef(true);\n\n const loginAdapter = useMemo(() => {\n return {\n ...auth,\n beginAuthentication: async (inputEmail: string) => {\n const result = await auth.beginAuthentication(inputEmail);\n setEmail(inputEmail);\n setMethods(result.methods);\n setLockedUntil(result.lockedUntil);\n return result;\n },\n };\n }, [auth]);\n\n const handleLoginSuccess = useCallback(\n ({ force } = { force: false }) => {\n if (!force && auth.nextStep === 'TOTP') {\n return;\n }\n onLoginSuccess();\n },\n [auth.nextStep, onLoginSuccess],\n );\n\n const isMfaStep = auth.nextStep === 'TOTP' || view === 'mfa';\n const title = isMfaStep\n ? t('auth.loginFlow.title.mfa')\n : t('auth.loginFlow.title.default');\n const subtitle = isMfaStep\n ? t('auth.loginFlow.subtitle.mfa')\n : t('auth.loginFlow.subtitle.default');\n\n const startFlowForEmail = useCallback(\n async (inputEmail: string) => {\n setLocalError(null);\n try {\n const trimmed = inputEmail.trim();\n const result = await auth.beginAuthentication(trimmed);\n setEmail(trimmed);\n setMethods(result.methods);\n setLockedUntil(result.lockedUntil);\n const hasPasskey = result.methods.some((method) => {\n return method === 'PASSKEY';\n });\n\n if (hasPasskey) {\n setView('passkey');\n } else if (result.methods.includes('PASSWORD')) {\n setView('password');\n } else {\n setView('methods');\n }\n } catch (beginError) {\n const message =\n beginError instanceof Error\n ? beginError.message\n : t('auth.loginFlow.errors.tryAgain');\n setLocalError(message);\n }\n },\n [auth, t],\n );\n\n useEffect(() => {\n passkeyAttemptActive.current = true;\n const trimmedEmail = email.trim();\n const shouldAttempt =\n view === 'passkey' && !hasTriedPasskey && trimmedEmail !== '';\n\n if (shouldAttempt) {\n setHasTriedPasskey(true);\n const runPasskeyLogin = async () => {\n try {\n const status = await loginAdapter.loginWithPasskey({\n email: trimmedEmail,\n });\n\n if (!passkeyAttemptActive.current) {\n return;\n }\n\n if (status === 'success') {\n handleLoginSuccess();\n return;\n }\n\n if (status === 'mfa-required') {\n setView('mfa');\n return;\n }\n\n setView('methods');\n setLocalError(t('auth.loginFlow.errors.passkeyUnavailable'));\n } catch (passkeyError) {\n if (!passkeyAttemptActive.current) {\n return;\n }\n\n const message =\n passkeyError instanceof Error\n ? passkeyError.message\n : t('auth.loginFlow.errors.passkeyUnavailable');\n setLocalError(message);\n setView('methods');\n }\n };\n runPasskeyLogin().catch(() => {\n // Errors are handled inside runPasskeyLogin; ignore any unexpected rethrow.\n });\n }\n\n return () => {\n passkeyAttemptActive.current = false;\n };\n }, [email, handleLoginSuccess, hasTriedPasskey, loginAdapter, t, view]);\n\n let content: JSX.Element;\n\n if (isMfaStep) {\n content = (\n <AuthPanel>\n <MfaChallengeForm\n auth={auth}\n onSuccess={() => {\n handleLoginSuccess({ force: true });\n }}\n onBack={() => {\n auth.reset();\n setView('email');\n }}\n />\n </AuthPanel>\n );\n } else if (view === 'passkey') {\n content = (\n <AuthPanel\n title={t('auth.loginFlow.passkey.title')}\n description={t('auth.loginFlow.passkey.description', { email })}\n >\n <PasskeyLoginForm\n auth={loginAdapter}\n onSuccess={handleLoginSuccess}\n onShowMethods={() => {\n setView('methods');\n }}\n defaultEmail={email}\n isAttemptingPasskey={auth.isLoading}\n />\n </AuthPanel>\n );\n } else if (view === 'methods') {\n content = (\n <AuthPanel title={t('auth.loginFlow.methods.title')}>\n <MethodChooser\n email={email}\n methods={methods}\n lockedUntil={lockedUntil}\n onSelect={(method) => {\n if (method === 'PASSKEY') {\n setView('passkey');\n return;\n }\n if (method === 'PASSWORD') {\n setView('password');\n }\n }}\n onBack={() => {\n setView('email');\n }}\n />\n </AuthPanel>\n );\n } else if (view === 'password') {\n content = (\n <PasswordLoginPanel\n auth={loginAdapter}\n defaultEmail={email}\n onForgotPassword={onForgotPassword}\n onSuccess={handleLoginSuccess}\n providers={oidcProviders}\n />\n );\n } else {\n // email capture only\n content = (\n <EmailCapturePanel\n email={email}\n errorMessage={localError}\n isLoading={auth.isLoading}\n onEmailChange={(value) => {\n setEmail(value);\n setLocalError(null);\n }}\n onContinue={() => {\n const trimmed = email.trim();\n if (trimmed === '') {\n setLocalError(t('auth.loginFlow.errors.emailRequired'));\n return;\n }\n startFlowForEmail(trimmed).catch(() => {\n // startFlowForEmail handles its own errors.\n });\n }}\n onForgotPassword={onForgotPassword}\n />\n );\n }\n\n return (\n <AuthLayout title={title} subtitle={subtitle}>\n {content}\n </AuthLayout>\n );\n};\n","import RelayRuntime, {\n type GraphQLTaggedNode,\n type IEnvironment,\n type OperationType,\n} from 'relay-runtime';\n\nconst { fetchQuery } = RelayRuntime;\n\ntype AuthStatusQueryResponse = {\n readonly isLoggedIn?: boolean | null;\n};\n\n/**\n * Forces a fresh auth-status read from network to avoid stale cache guards\n * right after login mutations complete.\n */\nexport async function synchronizeAuthStatusQuery<TQuery extends OperationType>(\n environment: IEnvironment,\n query: GraphQLTaggedNode,\n): Promise<boolean> {\n const response = await fetchQuery<TQuery>(\n environment,\n query,\n {},\n { fetchPolicy: 'network-only' },\n ).toPromise();\n\n const isLoggedIn = (response as AuthStatusQueryResponse | null | undefined)\n ?.isLoggedIn;\n return isLoggedIn === true;\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useAuth-OVPPa9bO.js","names":[],"sources":["../../src/auth/login/MfaChallengeForm.tsx","../../src/modules/webauthn.ts","../../src/hooks/useAuth.ts"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n useCallback,\n useEffect,\n useState,\n type FormEvent,\n type JSX,\n} from 'react';\nimport { useSharedTranslation } from '../../i18n/useSharedTranslation.js';\n\nimport { Button, FormError, FormField } from '@plumile/ui';\n\nimport type { TotpCredentials, UseAuthReturn } from '../../hooks/useAuth.js';\n\nimport * as styles from './loginPage.css.js';\n\ntype Props = {\n auth: Pick<\n UseAuthReturn,\n 'completeMfa' | 'isLoading' | 'error' | 'emailHint' | 'reset' | 'clearError'\n >;\n onSuccess: () => void;\n onBack: () => void;\n};\n\nexport const MfaChallengeForm = ({\n auth,\n onSuccess,\n onBack,\n}: Props): JSX.Element => {\n const { t } = useSharedTranslation();\n const [code, setCode] = useState('');\n const [localError, setLocalError] = useState<string | null>(null);\n\n // Clear any stale errors when the MFA form is shown\n useEffect(() => {\n auth.clearError();\n setLocalError(null);\n }, [auth]);\n\n const handleSubmit = useCallback(\n async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setLocalError(null);\n\n const trimmed = code.trim();\n if (trimmed.length < 4) {\n setLocalError(t('auth.mfa.errors.shortCode'));\n return;\n }\n\n try {\n const credentials: TotpCredentials = {\n code: trimmed,\n };\n await auth.completeMfa(credentials);\n onSuccess();\n } catch {\n const authMessage = auth.error?.message;\n setLocalError(authMessage ?? t('auth.mfa.errors.verificationFailed'));\n }\n },\n [auth, code, onSuccess, t],\n );\n\n const helper =\n auth.emailHint != null\n ? t('auth.mfa.helper.withEmail', { email: auth.emailHint })\n : t('auth.mfa.helper.default');\n\n const formError = localError ?? auth.error?.message ?? null;\n\n return (\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n <form className={styles.formSurface} onSubmit={handleSubmit} noValidate>\n <div className={styles.stack}>\n <p className={styles.helper}>{helper}</p>\n {formError != null ? <FormError>{formError}</FormError> : null}\n <FormField\n label={t('auth.mfa.form.label')}\n name=\"code\"\n type=\"text\"\n value={code}\n onChange={(event) => {\n setCode(event.target.value);\n setLocalError(null);\n }}\n placeholder={t('auth.mfa.form.placeholder')}\n autoComplete=\"one-time-code\"\n autoFocus\n required\n />\n </div>\n <div className={styles.actionsRow}>\n <Button\n type=\"button\"\n variant=\"text\"\n size=\"small\"\n className={styles.inlineLink}\n onClick={() => {\n auth.reset();\n onBack();\n }}\n >\n {t('auth.mfa.actions.back')}\n </Button>\n <Button type=\"submit\" size=\"large\" isLoading={auth.isLoading}>\n {t('auth.mfa.actions.submit')}\n </Button>\n </div>\n </form>\n );\n};\n","/**\n * Buffer to base64 url\n */\nexport function bufferToBase64Url(input: ArrayBuffer): string {\n const byteArray = new Uint8Array(input);\n let binary = '';\n for (const byte of byteArray) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary)\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n}\n\n/**\n * Base64 url to buffer\n */\nexport function base64UrlToBuffer(input: string): ArrayBuffer {\n const normalized = input.replace(/-/g, '+').replace(/_/g, '/');\n const remainder = normalized.length % 4;\n let padding = '';\n if (remainder === 2) {\n padding = '==';\n } else if (remainder === 3) {\n padding = '=';\n } else if (remainder === 1) {\n throw new Error('Invalid base64url input length.');\n }\n const padded = `${normalized}${padding}`;\n const binary = atob(padded);\n const output = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) {\n output[i] = binary.charCodeAt(i);\n }\n return output.buffer;\n}\n\nexport type WebAuthnRegistrationErrorKind =\n | 'cancelled'\n | 'credentialInUse'\n | 'notSupported'\n | 'failed';\n\n/**\n * Maps a browser WebAuthn registration error to a stable UI category.\n */\nexport function mapWebAuthnRegistrationError(\n error: unknown,\n): WebAuthnRegistrationErrorKind {\n if (!(error instanceof DOMException)) {\n return 'failed';\n }\n\n switch (error.name) {\n case 'NotAllowedError':\n case 'AbortError':\n return 'cancelled';\n case 'InvalidStateError':\n return 'credentialInUse';\n case 'SecurityError':\n case 'NotSupportedError':\n return 'notSupported';\n default:\n return 'failed';\n }\n}\n\n/**\n * Parse sign count\n */\nexport function parseSignCount(authenticatorData: ArrayBuffer): number {\n if (authenticatorData.byteLength < 37) {\n return 0;\n }\n const view = new DataView(authenticatorData);\n return view.getUint32(33, false);\n}\n","/* eslint-disable no-ternary */\nimport { useCallback, useState } from 'react';\n\nimport {\n type MutationPayloadBase,\n requireField,\n resolveMutationOutcome,\n} from '../relay/mutationResult.js';\nimport { useSharedTranslation } from '../i18n/useSharedTranslation.js';\n\nimport { resetRelayStore } from '../relay/environment.js';\nimport type { PayloadError } from 'relay-runtime';\n\nimport type {\n AuthMethod,\n LoginNextStep,\n MfaLevel,\n} from '../modules/sharedSchemaTypes.js';\nimport {\n base64UrlToBuffer,\n bufferToBase64Url,\n parseSignCount,\n} from '../modules/webauthn.js';\n\nexport type AuthPayload = {\n authMethod: AuthMethod | null | undefined;\n challengeToken: string | null | undefined;\n loggedInUser: { id: string } | null | undefined;\n mfaLevel: MfaLevel | null | undefined;\n nextStep: LoginNextStep | null | undefined;\n};\n\ntype LoginErrorReason =\n | 'INVALID_CREDENTIALS'\n | 'ACCOUNT_LOCKED'\n | 'RATE_LIMITED'\n | 'INTERNAL_ERROR';\n\ntype LogoutErrorReason =\n | 'UNAUTHENTICATED'\n | 'SESSION_NOT_FOUND'\n | 'INTERNAL_ERROR';\n\ntype BeginAuthenticationErrorReason = 'INVALID_EMAIL' | 'INTERNAL_ERROR';\n\ntype BeginPasskeyLoginErrorReason =\n | 'INVALID_EMAIL'\n | 'PASSKEY_NOT_FOUND'\n | 'PASSKEY_NOT_SUPPORTED'\n | 'INTERNAL_ERROR';\n\ntype FinishPasskeyLoginErrorReason =\n | 'INVALID_CHALLENGE_TOKEN'\n | 'CHALLENGE_EXPIRED'\n | 'INVALID_ASSERTION'\n | 'INTERNAL_ERROR';\n\ntype CompleteMfaErrorReason =\n | 'INVALID_CHALLENGE_TOKEN'\n | 'CHALLENGE_EXPIRED'\n | 'INVALID_CODE'\n | 'TOO_MANY_ATTEMPTS'\n | 'INTERNAL_ERROR';\n\ntype AcceptInvitationErrorReason =\n | 'INVALID_TOKEN'\n | 'TOKEN_EXPIRED'\n | 'ALREADY_ACCEPTED'\n | 'PASSWORD_MISMATCH'\n | 'PASSWORD_POLICY_VIOLATION'\n | 'RATE_LIMITED'\n | 'EMAIL_MISMATCH'\n | 'INTERNAL_ERROR';\n\nexport type BeginAuthenticationPayload =\n MutationPayloadBase<BeginAuthenticationErrorReason> & {\n lockedUntil: string | null | undefined;\n methods: readonly {\n method: AuthMethod;\n mfaEnforced?: boolean | null | undefined;\n }[];\n };\n\nexport type BeginPasskeyLoginPayload =\n MutationPayloadBase<BeginPasskeyLoginErrorReason> & {\n allowCredentials: readonly string[];\n challenge: string;\n challengeToken: string;\n rpId: string;\n };\n\ntype LoginMutationPayload = MutationPayloadBase<LoginErrorReason> & {\n payload?: AuthPayload | null | undefined;\n};\n\ntype LogoutPayload = {\n loggedOut?: boolean | null | undefined;\n};\n\ntype LogoutMutationPayload = MutationPayloadBase<LogoutErrorReason> & {\n payload?: LogoutPayload | null | undefined;\n};\n\ntype CompleteMfaMutationPayload =\n MutationPayloadBase<CompleteMfaErrorReason> & {\n payload?: AuthPayload | null | undefined;\n };\n\ntype FinishPasskeyLoginMutationPayload =\n MutationPayloadBase<FinishPasskeyLoginErrorReason> & {\n payload?: AuthPayload | null | undefined;\n };\n\ntype AcceptInvitationMutationPayload =\n MutationPayloadBase<AcceptInvitationErrorReason> & {\n payload?: AuthPayload | null | undefined;\n };\n\nexport type LoginResponse = { login: AuthPayload | LoginMutationPayload };\nexport type LogoutResponse = { logout: LogoutPayload | LogoutMutationPayload };\nexport type CompleteMfaResponse = {\n completeMfa: AuthPayload | CompleteMfaMutationPayload;\n};\nexport type FinishPasskeyLoginResponse = {\n finishPasskeyLogin: AuthPayload | FinishPasskeyLoginMutationPayload;\n};\nexport type AcceptInvitationResponse = {\n acceptInvitation: AuthPayload | AcceptInvitationMutationPayload;\n};\nexport type BeginAuthenticationResponse = {\n beginAuthentication: BeginAuthenticationPayload;\n};\nexport type BeginPasskeyLoginResponse = {\n beginPasskeyLogin: BeginPasskeyLoginPayload;\n};\n\nexport type LoginVariables = {\n input: LoginCredentials;\n};\n\nexport type LogoutVariables = Record<PropertyKey, never>;\n\nexport type CompleteMfaVariables = {\n input: {\n challengeToken: string;\n code: string;\n };\n};\n\nexport type BeginPasskeyLoginVariables = {\n email: string;\n};\n\nexport type FinishPasskeyLoginVariables = {\n input: {\n challenge: string;\n challengeToken: string;\n credentialId: string;\n signCount: number;\n userHandle?: string | null;\n };\n};\n\nexport type AcceptInvitationVariables = {\n input: {\n token: string;\n password: string;\n passwordConfirmation: string;\n };\n};\n\nexport type BeginAuthenticationVariables = {\n email: string;\n};\n\ntype MutationCommitConfig<TVariables, TResponse> = {\n variables: TVariables;\n onCompleted?: (\n response: TResponse,\n errors: readonly PayloadError[] | null,\n ) => void;\n onError?: (error: Error) => void;\n};\n\ntype MutationCommit<TVariables, TResponse> = (\n config: MutationCommitConfig<TVariables, TResponse>,\n) => void;\n\ntype MutationEntry<TVariables, TResponse> = {\n commit: MutationCommit<TVariables, TResponse>;\n isInFlight: boolean;\n};\n\nexport type AuthMutationHooks = {\n login: MutationEntry<LoginVariables, LoginResponse>;\n logout: MutationEntry<LogoutVariables, LogoutResponse>;\n completeMfa: MutationEntry<CompleteMfaVariables, CompleteMfaResponse>;\n beginPasskeyLogin: MutationEntry<\n BeginPasskeyLoginVariables,\n BeginPasskeyLoginResponse\n >;\n finishPasskeyLogin: MutationEntry<\n FinishPasskeyLoginVariables,\n FinishPasskeyLoginResponse\n >;\n acceptInvitation?: MutationEntry<\n AcceptInvitationVariables,\n AcceptInvitationResponse\n >;\n beginAuthentication: MutationEntry<\n BeginAuthenticationVariables,\n BeginAuthenticationResponse\n >;\n};\n\ninterface User {\n id: string;\n}\n\nexport type LoginStatus = 'success' | 'mfa-required' | 'error';\n\nexport interface LoginCredentials {\n email: string;\n password: string;\n}\n\nexport interface TotpCredentials {\n code: string;\n}\n\nexport interface AcceptInvitationCredentials {\n token: string;\n password: string;\n passwordConfirmation: string;\n}\n\nexport interface AuthError {\n message: string;\n code?: string;\n}\n\nexport interface UseAuthReturn {\n authMethod: AuthMethod | null;\n challengeToken: string | null;\n nextStep: LoginNextStep | null;\n mfaLevel: MfaLevel | null;\n emailHint: string | null;\n lockedUntil: string | null;\n availableMethods: AuthMethod[];\n login: (credentials: LoginCredentials) => Promise<LoginStatus>;\n loginWithPasskey: (params: { email: string }) => Promise<LoginStatus>;\n completeMfa: (credentials: TotpCredentials) => Promise<void>;\n acceptInvitation: (\n credentials: AcceptInvitationCredentials,\n ) => Promise<LoginStatus>;\n beginAuthentication: (\n email: string,\n ) => Promise<{ methods: AuthMethod[]; lockedUntil: string | null }>;\n logout: () => Promise<void>;\n reset: () => void;\n clearError: () => void;\n isLoading: boolean;\n error: AuthError | null;\n user: User | null;\n}\n\nconst initialState = {\n authMethod: null as AuthMethod | null,\n challengeToken: null as string | null,\n emailHint: null as string | null,\n mfaLevel: null as MfaLevel | null,\n nextStep: null as LoginNextStep | null,\n};\n\nexport const createUseAuth = (mutations: AuthMutationHooks) => {\n return (): UseAuthReturn => {\n const { t } = useSharedTranslation();\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n const [user, setUser] = useState<User | null>(null);\n const [lockedUntil, setLockedUntil] = useState<string | null>(null);\n const [availableMethods, setAvailableMethods] = useState<AuthMethod[]>([]);\n const [authState, setAuthState] = useState(initialState);\n\n const commitLoginMutation = mutations.login.commit;\n const commitLogoutMutation = mutations.logout.commit;\n const commitCompleteMfaMutation = mutations.completeMfa.commit;\n const commitBeginPasskeyLoginMutation = mutations.beginPasskeyLogin.commit;\n const commitFinishPasskeyLoginMutation =\n mutations.finishPasskeyLogin.commit;\n const commitAcceptInvitationMutation = mutations.acceptInvitation?.commit;\n const commitBeginAuthenticationMutation =\n mutations.beginAuthentication.commit;\n\n const defaultLoginErrorMessage = t('auth.loginFlow.errors.tryAgain');\n const defaultBeginAuthenticationErrorMessage = t(\n 'auth.loginFlow.errors.tryAgain',\n );\n const defaultPasskeyErrorMessage = t('auth.passkey.errors.failed');\n const defaultMfaErrorMessage = t('auth.mfa.errors.verificationFailed');\n const defaultInvitationErrorMessage = t(\n 'auth.acceptInvitation.errors.default',\n );\n const mfaInvalidChallengeMessage = t('auth.mfa.errors.invalidChallenge');\n const passkeyNotAvailableMessage = t('auth.passkey.errors.notAvailable');\n const defaultLogoutErrorMessage = 'Logout failed.';\n\n const reset = useCallback(() => {\n setError(null);\n setUser(null);\n setLockedUntil(null);\n setAvailableMethods([]);\n setAuthState(initialState);\n }, []);\n\n const clearError = useCallback(() => {\n setError(null);\n }, []);\n\n const updateAuthStateFromPayload = useCallback(\n (payload: AuthPayload): LoginStatus => {\n const authMethod = payload.authMethod ?? null;\n const challengeToken = payload.challengeToken ?? null;\n const mfaLevel = payload.mfaLevel ?? null;\n const nextStep = payload.nextStep ?? null;\n\n setAuthState((prev) => {\n return {\n ...prev,\n authMethod,\n challengeToken,\n mfaLevel,\n nextStep,\n };\n });\n\n if (payload.loggedInUser != null && nextStep == null) {\n setUser({\n id: payload.loggedInUser.id,\n });\n return 'success';\n }\n\n if (nextStep === 'TOTP' && challengeToken != null) {\n return 'mfa-required';\n }\n\n return 'error';\n },\n [],\n );\n\n const isMutationPayload = useCallback(\n (value: unknown): value is MutationPayloadBase => {\n return (\n value != null &&\n typeof value === 'object' &&\n ('status' in value || 'result' in value)\n );\n },\n [],\n );\n\n const mapLoginReason = useCallback(\n (reason: LoginErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_CREDENTIALS':\n return t('auth.loginFlow.errors.invalidCredentials');\n case 'ACCOUNT_LOCKED':\n return t('auth.loginFlow.errors.accountLocked');\n case 'RATE_LIMITED':\n return t('auth.loginFlow.errors.rateLimited');\n case 'INTERNAL_ERROR':\n return t('auth.loginFlow.errors.tryAgain');\n default:\n return null;\n }\n },\n [t],\n );\n\n const mapBeginAuthenticationReason = useCallback(\n (reason: BeginAuthenticationErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_EMAIL':\n return t('auth.loginFlow.errors.invalidEmail');\n case 'INTERNAL_ERROR':\n return t('auth.loginFlow.errors.tryAgain');\n default:\n return null;\n }\n },\n [t],\n );\n\n const mapBeginPasskeyLoginReason = useCallback(\n (reason: BeginPasskeyLoginErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_EMAIL':\n return t('auth.passkey.errors.invalidEmail');\n case 'PASSKEY_NOT_FOUND':\n return t('auth.passkey.errors.notFound');\n case 'PASSKEY_NOT_SUPPORTED':\n return t('auth.passkey.errors.notAvailable');\n case 'INTERNAL_ERROR':\n return t('auth.passkey.errors.failed');\n default:\n return null;\n }\n },\n [t],\n );\n\n const mapFinishPasskeyLoginReason = useCallback(\n (reason: FinishPasskeyLoginErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_CHALLENGE_TOKEN':\n return t('auth.passkey.errors.invalidChallenge');\n case 'CHALLENGE_EXPIRED':\n return t('auth.passkey.errors.challengeExpired');\n case 'INVALID_ASSERTION':\n return t('auth.passkey.errors.invalidAssertion');\n case 'INTERNAL_ERROR':\n return t('auth.passkey.errors.failed');\n default:\n return null;\n }\n },\n [t],\n );\n\n const mapCompleteMfaReason = useCallback(\n (reason: CompleteMfaErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_CHALLENGE_TOKEN':\n return t('auth.mfa.errors.invalidChallenge');\n case 'CHALLENGE_EXPIRED':\n return t('auth.mfa.errors.expired');\n case 'INVALID_CODE':\n return t('auth.mfa.errors.invalidCode');\n case 'TOO_MANY_ATTEMPTS':\n return t('auth.mfa.errors.tooManyAttempts');\n case 'INTERNAL_ERROR':\n return t('auth.mfa.errors.verificationFailed');\n default:\n return null;\n }\n },\n [t],\n );\n\n const mapAcceptInvitationReason = useCallback(\n (reason: AcceptInvitationErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_TOKEN':\n return t('auth.acceptInvitation.errors.invalidToken');\n case 'TOKEN_EXPIRED':\n return t('auth.acceptInvitation.errors.expired');\n case 'ALREADY_ACCEPTED':\n return t('auth.acceptInvitation.errors.alreadyAccepted');\n case 'PASSWORD_MISMATCH':\n return t('auth.acceptInvitation.errors.passwordMismatch');\n case 'PASSWORD_POLICY_VIOLATION':\n return t('auth.acceptInvitation.errors.passwordPolicyViolation');\n case 'RATE_LIMITED':\n return t('auth.acceptInvitation.errors.rateLimited');\n case 'EMAIL_MISMATCH':\n return t('auth.acceptInvitation.errors.emailMismatch');\n case 'INTERNAL_ERROR':\n return t('auth.acceptInvitation.errors.default');\n default:\n return null;\n }\n },\n [t],\n );\n\n const beginAuthentication = useCallback(\n async (\n email: string,\n ): Promise<{ methods: AuthMethod[]; lockedUntil: string | null }> => {\n return new Promise((resolve, reject) => {\n commitBeginAuthenticationMutation({\n variables: { email },\n onCompleted: (response) => {\n const rawPayload = response.beginAuthentication;\n let payload = rawPayload;\n\n if (isMutationPayload(rawPayload)) {\n const outcome = resolveMutationOutcome(rawPayload, {\n defaultErrorMessage: defaultBeginAuthenticationErrorMessage,\n mapReason: mapBeginAuthenticationReason,\n });\n if (!outcome.ok) {\n const authError: AuthError = {\n message: outcome.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n payload = outcome.payload;\n }\n\n const methods = payload.methods.map((item) => {\n return item.method;\n });\n const locked = payload.lockedUntil ?? null;\n setAvailableMethods(methods);\n setLockedUntil(locked);\n resolve({ methods, lockedUntil: locked });\n },\n onError: () => {\n const authError: AuthError = {\n message: defaultBeginAuthenticationErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n });\n });\n },\n [\n commitBeginAuthenticationMutation,\n defaultBeginAuthenticationErrorMessage,\n isMutationPayload,\n mapBeginAuthenticationReason,\n ],\n );\n\n const login = useCallback(\n async (credentials: LoginCredentials): Promise<LoginStatus> => {\n setIsLoading(true);\n setError(null);\n setAuthState((prev) => {\n return {\n ...prev,\n emailHint: credentials.email,\n };\n });\n\n return new Promise((resolve, reject) => {\n commitLoginMutation({\n variables: {\n input: credentials,\n },\n onCompleted: (response) => {\n setIsLoading(false);\n const rawPayload = response.login;\n let authPayload: AuthPayload | null = null;\n\n if (isMutationPayload(rawPayload)) {\n const outcome = resolveMutationOutcome(rawPayload, {\n defaultErrorMessage: defaultLoginErrorMessage,\n mapReason: mapLoginReason,\n });\n if (!outcome.ok) {\n const authError: AuthError = {\n message: outcome.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n authPayload = rawPayload.payload ?? null;\n } else {\n authPayload = rawPayload;\n }\n\n if (authPayload == null) {\n const authError: AuthError = {\n message: defaultLoginErrorMessage,\n };\n setError(authError);\n reject(authError);\n return;\n }\n\n const status = updateAuthStateFromPayload(authPayload);\n if (status === 'success' || status === 'mfa-required') {\n resolve(status);\n return;\n }\n\n const authError: AuthError = {\n message: defaultLoginErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n onError: () => {\n setIsLoading(false);\n const authError: AuthError = {\n message: defaultLoginErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n });\n });\n },\n [\n commitLoginMutation,\n defaultLoginErrorMessage,\n isMutationPayload,\n mapLoginReason,\n updateAuthStateFromPayload,\n ],\n );\n\n const completeMfa = useCallback(\n async (credentials: TotpCredentials): Promise<void> => {\n const { challengeToken } = authState;\n if (challengeToken == null) {\n const authError: AuthError = {\n message: mfaInvalidChallengeMessage,\n };\n setError(authError);\n return Promise.reject(authError);\n }\n\n setIsLoading(true);\n setError(null);\n\n return new Promise((resolve, reject) => {\n commitCompleteMfaMutation({\n variables: {\n input: {\n challengeToken,\n code: credentials.code,\n },\n },\n onCompleted: (response) => {\n setIsLoading(false);\n const rawPayload = response.completeMfa;\n let authPayload: AuthPayload | null = null;\n\n if (isMutationPayload(rawPayload)) {\n const outcome = resolveMutationOutcome(rawPayload, {\n defaultErrorMessage: defaultMfaErrorMessage,\n mapReason: mapCompleteMfaReason,\n });\n if (!outcome.ok) {\n const authError: AuthError = {\n message: outcome.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n authPayload = rawPayload.payload ?? null;\n } else {\n authPayload = rawPayload;\n }\n\n if (authPayload == null) {\n const authError: AuthError = {\n message: defaultMfaErrorMessage,\n };\n setError(authError);\n reject(authError);\n return;\n }\n\n const status = updateAuthStateFromPayload(authPayload);\n if (status === 'success') {\n resolve();\n return;\n }\n\n const authError: AuthError = {\n message: defaultMfaErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n onError: () => {\n setIsLoading(false);\n const authError: AuthError = {\n message: defaultMfaErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n });\n });\n },\n [\n authState,\n commitCompleteMfaMutation,\n defaultMfaErrorMessage,\n isMutationPayload,\n mapCompleteMfaReason,\n mfaInvalidChallengeMessage,\n updateAuthStateFromPayload,\n ],\n );\n\n const loginWithPasskey = useCallback(\n async ({ email }: { email: string }): Promise<LoginStatus> => {\n if (typeof window === 'undefined') {\n const authError: AuthError = {\n message: passkeyNotAvailableMessage,\n };\n setError(authError);\n return Promise.reject(authError);\n }\n\n setIsLoading(true);\n setError(null);\n setAuthState((prev) => {\n return {\n ...prev,\n emailHint: email,\n };\n });\n\n return new Promise((resolve, reject) => {\n commitBeginPasskeyLoginMutation({\n variables: {\n email,\n },\n onCompleted: (response) => {\n const rawOptions = response.beginPasskeyLogin;\n let options = rawOptions;\n\n if (isMutationPayload(rawOptions)) {\n const outcome = resolveMutationOutcome(rawOptions, {\n defaultErrorMessage: defaultPasskeyErrorMessage,\n mapReason: mapBeginPasskeyLoginReason,\n });\n if (!outcome.ok) {\n setIsLoading(false);\n const authError: AuthError = {\n message: outcome.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n options = outcome.payload;\n }\n\n const continuePasskeyLogin = async (): Promise<void> => {\n try {\n const assertion = (await navigator.credentials.get({\n publicKey: {\n allowCredentials: options.allowCredentials.map(\n (credentialId) => {\n return {\n id: base64UrlToBuffer(credentialId),\n type: 'public-key' as const,\n };\n },\n ),\n challenge: base64UrlToBuffer(options.challenge),\n rpId: options.rpId,\n userVerification: 'preferred',\n },\n })) as PublicKeyCredential | null;\n\n if (assertion == null) {\n throw new Error(\n 'No credential returned by the authenticator.',\n );\n }\n\n const assertionResponse =\n assertion.response as AuthenticatorAssertionResponse;\n const signCount = parseSignCount(\n assertionResponse.authenticatorData,\n );\n\n commitFinishPasskeyLoginMutation({\n variables: {\n input: {\n challenge: options.challenge,\n challengeToken: options.challengeToken,\n credentialId: assertion.id,\n signCount,\n userHandle:\n assertionResponse.userHandle != null\n ? bufferToBase64Url(assertionResponse.userHandle)\n : null,\n },\n },\n onCompleted: (finishResponse) => {\n setIsLoading(false);\n const rawPayload = finishResponse.finishPasskeyLogin;\n let authPayload: AuthPayload | null = null;\n\n if (isMutationPayload(rawPayload)) {\n const outcome = resolveMutationOutcome(rawPayload, {\n defaultErrorMessage: defaultPasskeyErrorMessage,\n mapReason: mapFinishPasskeyLoginReason,\n });\n if (!outcome.ok) {\n const authError: AuthError = {\n message: outcome.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n authPayload = rawPayload.payload ?? null;\n } else {\n authPayload = rawPayload;\n }\n\n if (authPayload == null) {\n const authError: AuthError = {\n message: defaultPasskeyErrorMessage,\n };\n setError(authError);\n reject(authError);\n return;\n }\n\n const status = updateAuthStateFromPayload(authPayload);\n if (status === 'success') {\n resolve(status);\n return;\n }\n const authError: AuthError = {\n message: defaultPasskeyErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n onError: () => {\n setIsLoading(false);\n const authError: AuthError = {\n message: defaultPasskeyErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n });\n } catch (credentialError) {\n setIsLoading(false);\n const authError: AuthError = {\n message:\n credentialError instanceof Error\n ? credentialError.message\n : 'Passkey login was cancelled.',\n };\n setError(authError);\n reject(authError);\n }\n };\n\n continuePasskeyLogin().catch(() => {\n return undefined;\n });\n },\n onError: () => {\n setIsLoading(false);\n const authError: AuthError = {\n message: defaultPasskeyErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n });\n });\n },\n [\n commitBeginPasskeyLoginMutation,\n commitFinishPasskeyLoginMutation,\n defaultPasskeyErrorMessage,\n isMutationPayload,\n mapBeginPasskeyLoginReason,\n mapFinishPasskeyLoginReason,\n passkeyNotAvailableMessage,\n updateAuthStateFromPayload,\n ],\n );\n\n const acceptInvitation = useCallback(\n async (\n credentials: AcceptInvitationCredentials,\n ): Promise<LoginStatus> => {\n if (commitAcceptInvitationMutation == null) {\n const authError: AuthError = {\n message: 'Invitation acceptance is not available.',\n };\n setError(authError);\n return Promise.reject(authError);\n }\n\n setIsLoading(true);\n setError(null);\n\n return new Promise((resolve, reject) => {\n commitAcceptInvitationMutation({\n variables: {\n input: {\n token: credentials.token,\n password: credentials.password,\n passwordConfirmation: credentials.passwordConfirmation,\n },\n },\n onCompleted: (response) => {\n setIsLoading(false);\n const rawPayload = response.acceptInvitation;\n let authPayload: AuthPayload | null = null;\n\n if (isMutationPayload(rawPayload)) {\n const outcome = resolveMutationOutcome(rawPayload, {\n defaultErrorMessage: defaultInvitationErrorMessage,\n mapReason: mapAcceptInvitationReason,\n });\n if (!outcome.ok) {\n const authError: AuthError = {\n message: outcome.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n authPayload = rawPayload.payload ?? null;\n } else {\n authPayload = rawPayload;\n }\n\n if (authPayload == null) {\n const authError: AuthError = {\n message: defaultInvitationErrorMessage,\n };\n setError(authError);\n reject(authError);\n return;\n }\n\n const status = updateAuthStateFromPayload(authPayload);\n if (status === 'success' || status === 'mfa-required') {\n resolve(status);\n return;\n }\n const authError: AuthError = {\n message: defaultInvitationErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n onError: () => {\n setIsLoading(false);\n const authError: AuthError = {\n message: defaultInvitationErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n });\n });\n },\n [\n commitAcceptInvitationMutation,\n defaultInvitationErrorMessage,\n isMutationPayload,\n mapAcceptInvitationReason,\n updateAuthStateFromPayload,\n ],\n );\n\n const logout = useCallback(async (): Promise<void> => {\n setIsLoading(true);\n\n return new Promise((resolve, reject) => {\n commitLogoutMutation({\n variables: {},\n onCompleted: (response) => {\n setIsLoading(false);\n const rawPayload = response.logout;\n let loggedOutValue: boolean | null = null;\n\n if (isMutationPayload(rawPayload)) {\n const outcome = resolveMutationOutcome(rawPayload, {\n defaultErrorMessage: defaultLogoutErrorMessage,\n });\n if (!outcome.ok) {\n const authError: AuthError = { message: outcome.message };\n setError(authError);\n reject(authError);\n return;\n }\n\n const loggedOutResult = requireField(\n rawPayload.payload?.loggedOut ?? null,\n defaultLogoutErrorMessage,\n );\n if (!loggedOutResult.ok) {\n const authError: AuthError = {\n message: loggedOutResult.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n loggedOutValue = loggedOutResult.value;\n } else {\n const loggedOutResult = requireField(\n rawPayload.loggedOut ?? null,\n defaultLogoutErrorMessage,\n );\n if (!loggedOutResult.ok) {\n const authError: AuthError = {\n message: loggedOutResult.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n loggedOutValue = loggedOutResult.value;\n }\n\n if (!loggedOutValue) {\n const authError: AuthError = {\n message: defaultLogoutErrorMessage,\n };\n setError(authError);\n reject(authError);\n return;\n }\n\n localStorage.removeItem('auth_token');\n localStorage.removeItem('remember_me');\n setUser(null);\n setAuthState(initialState);\n resetRelayStore();\n\n resolve();\n },\n onError: () => {\n setIsLoading(false);\n const authError: AuthError = {\n message: defaultLogoutErrorMessage,\n };\n setError(authError);\n resetRelayStore();\n\n reject(authError);\n },\n });\n });\n }, [commitLogoutMutation, defaultLogoutErrorMessage, isMutationPayload]);\n\n const combinedIsLoading =\n isLoading ||\n mutations.login.isInFlight ||\n mutations.logout.isInFlight ||\n mutations.completeMfa.isInFlight ||\n mutations.beginPasskeyLogin.isInFlight ||\n mutations.finishPasskeyLogin.isInFlight ||\n (mutations.acceptInvitation?.isInFlight ?? false) ||\n mutations.beginAuthentication.isInFlight;\n\n return {\n authMethod: authState.authMethod,\n challengeToken: authState.challengeToken,\n nextStep: authState.nextStep,\n mfaLevel: authState.mfaLevel,\n emailHint: authState.emailHint,\n login,\n loginWithPasskey,\n completeMfa,\n acceptInvitation,\n beginAuthentication,\n logout,\n reset,\n clearError,\n isLoading: combinedIsLoading,\n error,\n user,\n lockedUntil,\n availableMethods,\n };\n };\n};\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useBackofficeReactTranslation-WfXU8kCf.js","names":[],"sources":["../../src/components/backoffice/errors/BackofficeErrorBoundary.tsx","../../src/i18n/useBackofficeReactTranslation.ts"],"sourcesContent":["import { Component, type ReactNode } from 'react';\n\nexport type BackofficeErrorBoundaryProps = {\n children: ReactNode;\n fallback: (args: { error: unknown; reset: () => void }) => ReactNode;\n};\n\ntype State = { error: unknown };\n\nexport class BackofficeErrorBoundary extends Component<\n BackofficeErrorBoundaryProps,\n State\n> {\n public state: State = { error: null };\n\n public static getDerivedStateFromError(error: unknown): State {\n return { error };\n }\n\n public reset = (): void => {\n this.setState({ error: null });\n };\n\n public render(): ReactNode {\n if (this.state.error != null) {\n return this.props.fallback({\n error: this.state.error,\n reset: this.reset,\n });\n }\n return this.props.children;\n }\n}\n\nexport default BackofficeErrorBoundary;\n","import { useTranslation } from 'react-i18next';\n\n/** Returns i18n helpers bound to the backofficeReact namespace. */\nexport function useBackofficeReactTranslation(): ReturnType<\n typeof useTranslation\n> {\n return useTranslation('backofficeReact');\n}\n"],"mappings":";;;AASA,IAAa,IAAb,cAA6C,EAG3C;CACA,QAAsB,EAAE,OAAO,MAAM;CAErC,OAAc,yBAAyB,GAAuB;AAC5D,SAAO,EAAE,UAAO;;CAGlB,cAA2B;AACzB,OAAK,SAAS,EAAE,OAAO,MAAM,CAAC;;CAGhC,SAA2B;AAOzB,SANI,KAAK,MAAM,SAAS,OAMjB,KAAK,MAAM,WALT,KAAK,MAAM,SAAS;GACzB,OAAO,KAAK,MAAM;GAClB,OAAO,KAAK;GACb,CAAC;;;;;ACzBR,SAAgB,IAEd;AACA,QAAO,EAAe,kBAAkB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useSharedTranslation.d.ts","sourceRoot":"","sources":["../../../src/i18n/useSharedTranslation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAG/C,wBAAgB,oBAAoB,IAAI,UAAU,CAAC,OAAO,cAAc,CAAC,CAExE"}
|