diff --git a/packages/app-builder/src/routes/_auth+/_layout.tsx b/packages/app-builder/src/routes/_auth+/_layout.tsx
new file mode 100644
index 000000000..a21dd0cbe
--- /dev/null
+++ b/packages/app-builder/src/routes/_auth+/_layout.tsx
@@ -0,0 +1,58 @@
+import { authI18n } from '@app-builder/components/Auth/auth-i18n';
+import { Player } from '@lottiefiles/react-lottie-player';
+import { Outlet } from '@remix-run/react';
+import { Trans, useTranslation } from 'react-i18next';
+import { Logo } from 'ui-icons';
+
+export const handle = {
+ i18n: authI18n,
+};
+
+export default function AuthLayout() {
+ const { t } = useTranslation(handle.i18n);
+
+ return (
+
+
+
+
+
+ ,
+ }}
+ />
+
+
+ {t('auth:marble_description')}
+
+
+
+
+
+
+
+ );
+}
diff --git a/packages/app-builder/src/routes/_auth+/email-verification.tsx b/packages/app-builder/src/routes/_auth+/email-verification.tsx
new file mode 100644
index 000000000..53f3eaea1
--- /dev/null
+++ b/packages/app-builder/src/routes/_auth+/email-verification.tsx
@@ -0,0 +1,49 @@
+import { authI18n } from '@app-builder/components/Auth/auth-i18n';
+import { SendEmailVerification } from '@app-builder/components/Auth/SendEmailVerification';
+import { serverServices } from '@app-builder/services/init.server';
+import { getRoute } from '@app-builder/utils/routes';
+import { type LoaderFunctionArgs } from '@remix-run/node';
+import { Link } from '@remix-run/react';
+import { Trans, useTranslation } from 'react-i18next';
+
+export const handle = {
+ i18n: authI18n,
+};
+
+export async function loader({ request }: LoaderFunctionArgs) {
+ const { authService } = serverServices;
+ await authService.isAuthenticated(request, {
+ successRedirect: getRoute('/scenarios/'),
+ });
+ return null;
+}
+
+export default function SignUp() {
+ const { t } = useTranslation(handle.i18n);
+
+ return (
+
+
+
+
+
+
+
+ ),
+ }}
+ values={{
+ signIn: t('auth:sign_in'),
+ }}
+ />
+
+
+ );
+}
diff --git a/packages/app-builder/src/routes/_auth+/forgot-password.tsx b/packages/app-builder/src/routes/_auth+/forgot-password.tsx
new file mode 100644
index 000000000..92c2aba2c
--- /dev/null
+++ b/packages/app-builder/src/routes/_auth+/forgot-password.tsx
@@ -0,0 +1,36 @@
+import { authI18n } from '@app-builder/components/Auth/auth-i18n';
+import { ResetPassword } from '@app-builder/components/Auth/ResetPassword';
+import { getRoute } from '@app-builder/utils/routes';
+import { Link } from '@remix-run/react';
+import { Trans, useTranslation } from 'react-i18next';
+
+export const handle = {
+ i18n: authI18n,
+};
+
+export default function ForgotPassword() {
+ const { t } = useTranslation(handle.i18n);
+
+ return (
+
+
+
+
+ ),
+ }}
+ values={{
+ signIn: t('auth:sign_in'),
+ }}
+ />
+
+
+ );
+}
diff --git a/packages/app-builder/src/routes/_auth+/sign-in.tsx b/packages/app-builder/src/routes/_auth+/sign-in.tsx
new file mode 100644
index 000000000..659552cf5
--- /dev/null
+++ b/packages/app-builder/src/routes/_auth+/sign-in.tsx
@@ -0,0 +1,99 @@
+import { authI18n } from '@app-builder/components/Auth/auth-i18n';
+import { AuthError } from '@app-builder/components/Auth/AuthError';
+import { SignInWithEmailAndPassword } from '@app-builder/components/Auth/SignInWithEmailAndPassword';
+import { SignInWithGoogle } from '@app-builder/components/Auth/SignInWithGoogle';
+import { type AuthPayload } from '@app-builder/services/auth/auth.server';
+import { serverServices } from '@app-builder/services/init.server';
+import { getRoute } from '@app-builder/utils/routes';
+import {
+ type ActionFunctionArgs,
+ json,
+ type LoaderFunctionArgs,
+} from '@remix-run/node';
+import { Link, useFetcher, useLoaderData } from '@remix-run/react';
+import { Trans, useTranslation } from 'react-i18next';
+
+export const handle = {
+ i18n: authI18n,
+};
+
+export async function loader({ request }: LoaderFunctionArgs) {
+ const {
+ authService,
+ authSessionService: { getSession },
+ } = serverServices;
+ await authService.isAuthenticated(request, {
+ successRedirect: getRoute('/scenarios/'),
+ });
+ const session = await getSession(request);
+ const error = session.get('authError');
+
+ return json({
+ authError: error?.message,
+ });
+}
+
+export async function action({ request }: ActionFunctionArgs) {
+ const { authService } = serverServices;
+ return await authService.authenticate(request, {
+ successRedirect: getRoute('/scenarios/'),
+ failureRedirect: getRoute('/sign-in'),
+ });
+}
+
+export default function Login() {
+ const { t } = useTranslation(handle.i18n);
+ const { authError } = useLoaderData
();
+
+ const fetcher = useFetcher();
+ const signIn = (authPayload: AuthPayload) =>
+ fetcher.submit(authPayload, {
+ method: 'POST',
+ action: getRoute('/sign-in'),
+ });
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ ),
+ }}
+ values={{
+ signUp: t('auth:sign_up'),
+ }}
+ />
+
+
+ {t('auth:sign_in.forgot_password')}
+
+
+ {authError ?
: null}
+
+ );
+}
diff --git a/packages/app-builder/src/routes/_auth+/sign-up.tsx b/packages/app-builder/src/routes/_auth+/sign-up.tsx
new file mode 100644
index 000000000..945a8bd9f
--- /dev/null
+++ b/packages/app-builder/src/routes/_auth+/sign-up.tsx
@@ -0,0 +1,64 @@
+import { Callout } from '@app-builder/components';
+import { authI18n } from '@app-builder/components/Auth/auth-i18n';
+import { AuthError } from '@app-builder/components/Auth/AuthError';
+import { SignUpWithEmailAndPassword } from '@app-builder/components/Auth/SignUpWithEmailAndPassword';
+import { serverServices } from '@app-builder/services/init.server';
+import { getRoute } from '@app-builder/utils/routes';
+import { json, type LoaderFunctionArgs } from '@remix-run/node';
+import { Link, useLoaderData, useNavigate } from '@remix-run/react';
+import { Trans, useTranslation } from 'react-i18next';
+
+export const handle = {
+ i18n: authI18n,
+};
+
+export async function loader({ request }: LoaderFunctionArgs) {
+ const {
+ authService,
+ authSessionService: { getSession },
+ } = serverServices;
+ await authService.isAuthenticated(request, {
+ successRedirect: getRoute('/scenarios/'),
+ });
+ const session = await getSession(request);
+ const error = session.get('authError');
+
+ return json({
+ authError: error?.message,
+ });
+}
+
+export default function SignUp() {
+ const { t } = useTranslation(handle.i18n);
+ const { authError } = useLoaderData();
+
+ const navigate = useNavigate();
+ const signUp = () => navigate(getRoute('/email-verification'));
+
+ return (
+
+
+ {t('auth:sign_up.description')}
+
+
+
+
+ ),
+ }}
+ values={{
+ signIn: t('auth:sign_in'),
+ }}
+ />
+
+ {authError ?
: null}
+
+ );
+}
diff --git a/packages/app-builder/src/routes/_builder+/$.tsx b/packages/app-builder/src/routes/_builder+/$.tsx
index 68f0674c2..a53c181ba 100644
--- a/packages/app-builder/src/routes/_builder+/$.tsx
+++ b/packages/app-builder/src/routes/_builder+/$.tsx
@@ -1,10 +1,11 @@
import { serverServices } from '@app-builder/services/init.server';
+import { getRoute } from '@app-builder/utils/routes';
import { type LoaderFunctionArgs } from '@remix-run/node';
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
return authService.isAuthenticated(request, {
- successRedirect: '/scenarios',
- failureRedirect: '/login',
+ successRedirect: getRoute('/scenarios/'),
+ failureRedirect: getRoute('/sign-in'),
});
}
diff --git a/packages/app-builder/src/routes/_builder+/_layout.tsx b/packages/app-builder/src/routes/_builder+/_layout.tsx
index 4358ac7f3..9f096223a 100644
--- a/packages/app-builder/src/routes/_builder+/_layout.tsx
+++ b/packages/app-builder/src/routes/_builder+/_layout.tsx
@@ -31,7 +31,7 @@ import { Icon, Logo } from 'ui-icons';
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { user, organization } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const [organizationDetail, orgUsers, orgTags] = await Promise.all([
@@ -54,8 +54,8 @@ export default function Builder() {
useLoaderData();
useSegmentIdentification(user);
- // Refresh is done in the client because it needs to be done in the browser
- // This is only added here to prevent "auto login" on /login pages... (/logout do not trigger logout from Firebase)
+ // Refresh is done in the JSX because it needs to be done in the browser
+ // This is only added here to prevent "auto sign-in" on /sign-in pages... (/logout do not trigger logout from Firebase)
useRefreshToken();
const [expanded, setExpanded] = useState(true);
diff --git a/packages/app-builder/src/routes/_builder+/api.tsx b/packages/app-builder/src/routes/_builder+/api.tsx
index a8fd0592b..37bf8b4ea 100644
--- a/packages/app-builder/src/routes/_builder+/api.tsx
+++ b/packages/app-builder/src/routes/_builder+/api.tsx
@@ -1,6 +1,7 @@
import { Page } from '@app-builder/components';
import { serverServices } from '@app-builder/services/init.server';
import { downloadBlob } from '@app-builder/utils/download-blob';
+import { getRoute } from '@app-builder/utils/routes';
import {
json,
type LinksFunction,
@@ -24,7 +25,7 @@ export const links: LinksFunction = () =>
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { dataModelRepository } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const openapi = await dataModelRepository.getOpenApiSpec();
diff --git a/packages/app-builder/src/routes/_builder+/cases+/$caseId.tsx b/packages/app-builder/src/routes/_builder+/cases+/$caseId.tsx
index 55198d3e8..b2010b03f 100644
--- a/packages/app-builder/src/routes/_builder+/cases+/$caseId.tsx
+++ b/packages/app-builder/src/routes/_builder+/cases+/$caseId.tsx
@@ -39,7 +39,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
const { user, cases, apiClient } = await authService.isAuthenticated(
request,
{
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
},
);
diff --git a/packages/app-builder/src/routes/_builder+/cases+/_index.tsx b/packages/app-builder/src/routes/_builder+/cases+/_index.tsx
index 96b7fdd9f..f8af66024 100644
--- a/packages/app-builder/src/routes/_builder+/cases+/_index.tsx
+++ b/packages/app-builder/src/routes/_builder+/cases+/_index.tsx
@@ -10,7 +10,7 @@ import { Icon } from 'ui-icons';
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const { inboxes } = await apiClient.listInboxes({ withCaseCount: false });
diff --git a/packages/app-builder/src/routes/_builder+/cases+/inboxes.$inboxId.tsx b/packages/app-builder/src/routes/_builder+/cases+/inboxes.$inboxId.tsx
index 61da6578c..a78f950cd 100644
--- a/packages/app-builder/src/routes/_builder+/cases+/inboxes.$inboxId.tsx
+++ b/packages/app-builder/src/routes/_builder+/cases+/inboxes.$inboxId.tsx
@@ -37,7 +37,7 @@ export const handle = {
export async function loader({ request, params }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { cases } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const inboxId = fromParams(params, 'inboxId');
diff --git a/packages/app-builder/src/routes/_builder+/cases+/inboxes._layout.tsx b/packages/app-builder/src/routes/_builder+/cases+/inboxes._layout.tsx
index 9e2358ced..dd1748351 100644
--- a/packages/app-builder/src/routes/_builder+/cases+/inboxes._layout.tsx
+++ b/packages/app-builder/src/routes/_builder+/cases+/inboxes._layout.tsx
@@ -18,7 +18,7 @@ export const handle = {
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const { inboxes } = await apiClient.listInboxes({ withCaseCount: false });
diff --git a/packages/app-builder/src/routes/_builder+/data.tsx b/packages/app-builder/src/routes/_builder+/data.tsx
index d887238a5..f8a87b3cb 100644
--- a/packages/app-builder/src/routes/_builder+/data.tsx
+++ b/packages/app-builder/src/routes/_builder+/data.tsx
@@ -37,7 +37,7 @@ export const handle = {
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { dataModelRepository } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const dataModel = await dataModelRepository.getDataModel();
diff --git a/packages/app-builder/src/routes/_builder+/decisions+/$decisionId.tsx b/packages/app-builder/src/routes/_builder+/decisions+/$decisionId.tsx
index 32783616f..85c407e3a 100644
--- a/packages/app-builder/src/routes/_builder+/decisions+/$decisionId.tsx
+++ b/packages/app-builder/src/routes/_builder+/decisions+/$decisionId.tsx
@@ -13,6 +13,7 @@ import { ScorePanel } from '@app-builder/components/Decisions/Score';
import { TriggerObjectDetail } from '@app-builder/components/Decisions/TriggerObjectDetail';
import { isNotFoundHttpError } from '@app-builder/models';
import { serverServices } from '@app-builder/services/init.server';
+import { getRoute } from '@app-builder/utils/routes';
import { fromParams } from '@app-builder/utils/short-uuid';
import { json, type LoaderFunctionArgs } from '@remix-run/node';
import {
@@ -35,7 +36,7 @@ export const handle = {
export async function loader({ request, params }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const decisionId = fromParams(params, 'decisionId');
diff --git a/packages/app-builder/src/routes/_builder+/decisions+/_index.tsx b/packages/app-builder/src/routes/_builder+/decisions+/_index.tsx
index 79e3a254e..47e49abd4 100644
--- a/packages/app-builder/src/routes/_builder+/decisions+/_index.tsx
+++ b/packages/app-builder/src/routes/_builder+/decisions+/_index.tsx
@@ -45,7 +45,7 @@ export const handle = {
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { decision, scenario } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const parsedFilterQuery = await parseQuerySafe(
diff --git a/packages/app-builder/src/routes/_builder+/lists+/$listId.tsx b/packages/app-builder/src/routes/_builder+/lists+/$listId.tsx
index 5992538b6..2a4c70004 100644
--- a/packages/app-builder/src/routes/_builder+/lists+/$listId.tsx
+++ b/packages/app-builder/src/routes/_builder+/lists+/$listId.tsx
@@ -9,6 +9,7 @@ import { EditList } from '@app-builder/routes/ressources+/lists+/edit';
import { NewListValue } from '@app-builder/routes/ressources+/lists+/value_create';
import { DeleteListValue } from '@app-builder/routes/ressources+/lists+/value_delete';
import { serverServices } from '@app-builder/services/init.server';
+import { getRoute } from '@app-builder/utils/routes';
import { fromParams } from '@app-builder/utils/short-uuid';
import { json, type LoaderFunctionArgs } from '@remix-run/node';
import { Link, useLoaderData, useRouteError } from '@remix-run/react';
@@ -28,7 +29,7 @@ import { Icon } from 'ui-icons';
export async function loader({ request, params }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const listId = fromParams(params, 'listId');
diff --git a/packages/app-builder/src/routes/_builder+/lists+/_index.tsx b/packages/app-builder/src/routes/_builder+/lists+/_index.tsx
index 95a1695e4..804c86ccf 100644
--- a/packages/app-builder/src/routes/_builder+/lists+/_index.tsx
+++ b/packages/app-builder/src/routes/_builder+/lists+/_index.tsx
@@ -22,7 +22,7 @@ import { Icon } from 'ui-icons';
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const { custom_lists } = await apiClient.listCustomLists();
diff --git a/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/_index.tsx b/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/_index.tsx
index d22612fd5..19796f79f 100644
--- a/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/_index.tsx
+++ b/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/_index.tsx
@@ -16,7 +16,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
toastSessionService: { getSession, commitSession },
} = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const scenarioId = fromParams(params, 'scenarioId');
diff --git a/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/_layout.tsx b/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/_layout.tsx
index 88617d3ac..e99f91255 100644
--- a/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/_layout.tsx
+++ b/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/_layout.tsx
@@ -1,6 +1,6 @@
import { ErrorComponent } from '@app-builder/components';
import { serverServices } from '@app-builder/services/init.server';
-import { type RouteID } from '@app-builder/utils/routes';
+import { getRoute, type RouteID } from '@app-builder/utils/routes';
import { fromParams } from '@app-builder/utils/short-uuid';
import {
json,
@@ -18,7 +18,7 @@ export const handle = {
export async function loader({ request, params }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const scenarioId = fromParams(params, 'scenarioId');
diff --git a/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/_index.tsx b/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/_index.tsx
index 996adcc10..f7af7f1b8 100644
--- a/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/_index.tsx
+++ b/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/_index.tsx
@@ -1,10 +1,21 @@
import { serverServices } from '@app-builder/services/init.server';
+import { getRoute } from '@app-builder/utils/routes';
import { type LoaderFunctionArgs } from '@remix-run/node';
-export async function loader({ request }: LoaderFunctionArgs) {
+export async function loader({ request, params }: LoaderFunctionArgs) {
const { authService } = serverServices;
+ const { scenarioId, iterationId } = params;
+ if (!scenarioId || !iterationId) {
+ return {
+ redirect: getRoute('/scenarios/'),
+ };
+ }
+
return authService.isAuthenticated(request, {
- successRedirect: './trigger',
- failureRedirect: '/login',
+ successRedirect: getRoute('/scenarios/:scenarioId/i/:iterationId/trigger', {
+ scenarioId,
+ iterationId,
+ }),
+ failureRedirect: getRoute('/sign-in'),
});
}
diff --git a/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/_layout.tsx b/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/_layout.tsx
index e9281c5ca..d967cc49a 100644
--- a/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/_layout.tsx
+++ b/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/_layout.tsx
@@ -35,7 +35,7 @@ export const handle = {
export async function loader({ request, params }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { scenario } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const scenarioId = fromParams(params, 'scenarioId');
diff --git a/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/decision.tsx b/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/decision.tsx
index c27eb85ab..020882db4 100644
--- a/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/decision.tsx
+++ b/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/decision.tsx
@@ -24,6 +24,7 @@ import {
useGetScenarioErrorMessage,
} from '@app-builder/services/validation';
import { parseFormSafe } from '@app-builder/utils/input-validation';
+import { getRoute } from '@app-builder/utils/routes';
import { fromParams } from '@app-builder/utils/short-uuid';
import { zodResolver } from '@hookform/resolvers/zod';
import { type ActionFunctionArgs, json } from '@remix-run/node';
@@ -85,7 +86,7 @@ function getFormSchema(t: TFunction) {
export async function action({ request, params }: ActionFunctionArgs) {
const { authService, i18nextService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const t = await i18nextService.getFixedT(request, 'scenarios');
const parsedForm = await parseFormSafe(request, getFormSchema(t));
diff --git a/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/rules.tsx b/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/rules.tsx
index ec4a17636..1a70c364f 100644
--- a/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/rules.tsx
+++ b/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/rules.tsx
@@ -10,6 +10,7 @@ import {
useGetScenarioErrorMessage,
} from '@app-builder/services/validation';
import { formatNumber } from '@app-builder/utils/format';
+import { getRoute } from '@app-builder/utils/routes';
import { fromParams, fromUUID, useParam } from '@app-builder/utils/short-uuid';
import { json, type LoaderFunctionArgs } from '@remix-run/node';
import { useLoaderData, useNavigate } from '@remix-run/react';
@@ -31,7 +32,7 @@ export const handle = {
export async function loader({ request, params }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const scenarioIterationId = fromParams(params, 'iterationId');
diff --git a/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/trigger.tsx b/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/trigger.tsx
index aa92ab4df..72cb937a5 100644
--- a/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/trigger.tsx
+++ b/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/trigger.tsx
@@ -53,7 +53,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
const { apiClient, editor, organization } = await authService.isAuthenticated(
request,
{
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
},
);
@@ -98,7 +98,7 @@ export async function action({ request, params }: ActionFunctionArgs) {
} = serverServices;
const session = await getSession(request);
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
try {
diff --git a/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_layout.tsx b/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_layout.tsx
index cde989992..b86d6745c 100644
--- a/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_layout.tsx
+++ b/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_layout.tsx
@@ -3,6 +3,7 @@ import { EditorModeContextProvider } from '@app-builder/services/editor';
import { CurrentScenarioIterationContextProvider } from '@app-builder/services/editor/current-scenario-iteration';
import { serverServices } from '@app-builder/services/init.server';
import { CurrentScenarioValidationContextProvider } from '@app-builder/services/validation/current-scenario-validation';
+import { getRoute } from '@app-builder/utils/routes';
import { fromParams } from '@app-builder/utils/short-uuid';
import { json, type LoaderFunctionArgs } from '@remix-run/node';
import { Outlet, useLoaderData } from '@remix-run/react';
@@ -16,7 +17,7 @@ export const handle = {
export async function loader({ request, params }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { scenario } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const iterationId = fromParams(params, 'iterationId');
diff --git a/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/rules.$ruleId.tsx b/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/rules.$ruleId.tsx
index 3f377efc4..81a2d0180 100644
--- a/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/rules.$ruleId.tsx
+++ b/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/rules.$ruleId.tsx
@@ -39,6 +39,7 @@ import {
useGetScenarioErrorMessage,
} from '@app-builder/services/validation';
import { formatNumber } from '@app-builder/utils/format';
+import { getRoute } from '@app-builder/utils/routes';
import { fromParams, fromUUID, useParam } from '@app-builder/utils/short-uuid';
import {
type ActionFunctionArgs,
@@ -61,7 +62,7 @@ export const handle = {
export async function loader({ request, params }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { apiClient, editor } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const scenarioId = fromParams(params, 'scenarioId');
@@ -104,7 +105,7 @@ export async function action({ request, params }: ActionFunctionArgs) {
const session = await getSession(request);
const { editor } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const parsedForm = editRuleFormSchema.safeParse(formValuesRaw);
diff --git a/packages/app-builder/src/routes/_builder+/scenarios+/_index.tsx b/packages/app-builder/src/routes/_builder+/scenarios+/_index.tsx
index 938b644ff..a6e43bdd1 100644
--- a/packages/app-builder/src/routes/_builder+/scenarios+/_index.tsx
+++ b/packages/app-builder/src/routes/_builder+/scenarios+/_index.tsx
@@ -17,7 +17,7 @@ export const handle = {
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { scenario } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const scenarios = await scenario.listScenarios();
diff --git a/packages/app-builder/src/routes/_builder+/scheduled-executions.tsx b/packages/app-builder/src/routes/_builder+/scheduled-executions.tsx
index 29d90f35d..f80625798 100644
--- a/packages/app-builder/src/routes/_builder+/scheduled-executions.tsx
+++ b/packages/app-builder/src/routes/_builder+/scheduled-executions.tsx
@@ -5,6 +5,7 @@ import {
ScheduledExecutionsList,
} from '@app-builder/components';
import { serverServices } from '@app-builder/services/init.server';
+import { getRoute } from '@app-builder/utils/routes';
import { json, type LoaderFunctionArgs } from '@remix-run/node';
import { useLoaderData, useRouteError } from '@remix-run/react';
import { captureRemixErrorBoundaryError } from '@sentry/remix';
@@ -19,7 +20,7 @@ export const handle = {
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const { scheduled_executions } = await apiClient.listScheduledExecutions({});
diff --git a/packages/app-builder/src/routes/_builder+/settings+/_index.tsx b/packages/app-builder/src/routes/_builder+/settings+/_index.tsx
index e79ad0152..24fb94941 100644
--- a/packages/app-builder/src/routes/_builder+/settings+/_index.tsx
+++ b/packages/app-builder/src/routes/_builder+/settings+/_index.tsx
@@ -11,7 +11,7 @@ export const handle = {
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { user } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
if (!isAdmin(user)) {
return redirect(getRoute('/'));
diff --git a/packages/app-builder/src/routes/_builder+/settings+/_layout.tsx b/packages/app-builder/src/routes/_builder+/settings+/_layout.tsx
index 0dee7a499..c701c3628 100644
--- a/packages/app-builder/src/routes/_builder+/settings+/_layout.tsx
+++ b/packages/app-builder/src/routes/_builder+/settings+/_layout.tsx
@@ -15,7 +15,7 @@ export const handle = {
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
return null;
}
diff --git a/packages/app-builder/src/routes/_builder+/settings+/inboxes.$inboxId.tsx b/packages/app-builder/src/routes/_builder+/settings+/inboxes.$inboxId.tsx
index 99265425e..076e34a17 100644
--- a/packages/app-builder/src/routes/_builder+/settings+/inboxes.$inboxId.tsx
+++ b/packages/app-builder/src/routes/_builder+/settings+/inboxes.$inboxId.tsx
@@ -6,6 +6,7 @@ import { UpdateInboxUser } from '@app-builder/routes/ressources+/settings+/inbox
import { UpdateInbox } from '@app-builder/routes/ressources+/settings+/inboxes+/update';
import { serverServices } from '@app-builder/services/init.server';
import { useOrganizationUsers } from '@app-builder/services/organization/organization-users';
+import { getRoute } from '@app-builder/utils/routes';
import { fromParams } from '@app-builder/utils/short-uuid';
import { json, type LoaderFunctionArgs } from '@remix-run/node';
import { useLoaderData } from '@remix-run/react';
@@ -26,7 +27,7 @@ export const handle = {
export async function loader({ request, params }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { apiClient, cases } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const inboxId = fromParams(params, 'inboxId');
diff --git a/packages/app-builder/src/routes/_builder+/settings+/inboxes._index.tsx b/packages/app-builder/src/routes/_builder+/settings+/inboxes._index.tsx
index e9da2ea6e..3e89f5fcf 100644
--- a/packages/app-builder/src/routes/_builder+/settings+/inboxes._index.tsx
+++ b/packages/app-builder/src/routes/_builder+/settings+/inboxes._index.tsx
@@ -17,7 +17,7 @@ import { Table, useTable } from 'ui-design-system';
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { apiClient, user } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
if (!isAdmin(user)) {
return redirect(getRoute('/'));
diff --git a/packages/app-builder/src/routes/_builder+/settings+/tags.tsx b/packages/app-builder/src/routes/_builder+/settings+/tags.tsx
index 7073dbc3e..868357c41 100644
--- a/packages/app-builder/src/routes/_builder+/settings+/tags.tsx
+++ b/packages/app-builder/src/routes/_builder+/settings+/tags.tsx
@@ -17,7 +17,7 @@ import { Table, useTable } from 'ui-design-system';
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { organization, user } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
if (!isAdmin(user)) {
return redirect(getRoute('/'));
diff --git a/packages/app-builder/src/routes/_builder+/settings+/users.tsx b/packages/app-builder/src/routes/_builder+/settings+/users.tsx
index 2978f7231..fab8b20de 100644
--- a/packages/app-builder/src/routes/_builder+/settings+/users.tsx
+++ b/packages/app-builder/src/routes/_builder+/settings+/users.tsx
@@ -10,7 +10,6 @@ import { json, type LoaderFunctionArgs, redirect } from '@remix-run/node';
import { useLoaderData } from '@remix-run/react';
import { createColumnHelper, getCoreRowModel } from '@tanstack/react-table';
import clsx from 'clsx';
-import { type InboxUserDto } from 'marble-api';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import * as R from 'remeda';
@@ -18,46 +17,40 @@ import { Table, useTable } from 'ui-design-system';
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
- const { apiClient, organization, user } = await authService.isAuthenticated(
- request,
- {
- failureRedirect: '/login',
- },
- );
+ const { user, inbox } = await authService.isAuthenticated(request, {
+ failureRedirect: getRoute('/sign-in'),
+ });
if (!isAdmin(user)) {
return redirect(getRoute('/'));
}
- const { inbox_users } = await apiClient.listAllInboxUsers();
- const org = await organization.getCurrentOrganization();
+ const inboxUsers = await inbox.listAllInboxUsers();
+
+ const inboxUsersByUserId = R.pipe(
+ inboxUsers,
+ R.groupBy(({ userId }) => userId),
+ R.mapValues((value) =>
+ R.pipe(
+ value,
+ R.groupBy((v) => v.role),
+ R.mapValues((v) => v.length),
+ R.toPairs,
+ ),
+ ),
+ );
- return json({ inboxUsers: inbox_users, org, user });
+ return json({ inboxUsersByUserId, user });
}
const columnHelper = createColumnHelper();
export default function Users() {
const { t } = useTranslation(['settings', 'cases']);
- const { inboxUsers, org, user } = useLoaderData();
+ const { inboxUsersByUserId, user } = useLoaderData();
const { orgUsers } = useOrganizationUsers();
- const inboxUsersByUserId = useMemo(
- () =>
- R.pipe(
- inboxUsers as InboxUserDto[],
- R.groupBy((user) => user.user_id),
- R.mapValues((value) =>
- R.pipe(
- value,
- R.groupBy((v) => v.role),
- ),
- ),
- ),
- [inboxUsers],
- );
-
- const columns = useMemo(() => {
- const columns = [
+ const columns = useMemo(
+ () => [
columnHelper.accessor((row) => `${row.firstName} ${row.lastName}`, {
id: 'name',
header: t('settings:users.name'),
@@ -75,21 +68,25 @@ export default function Users() {
id: 'role',
header: t('settings:users.role'),
size: 100,
- cell: ({ getValue }) => t(tKeyForUserRole(getValue())),
+ cell: ({ getValue }) => t(tKeyForUserRole(getValue())),
}),
columnHelper.accessor((row) => row.userId, {
id: 'inbox_user_role',
header: t('settings:users.inbox_user_role'),
size: 200,
cell: ({ getValue }) => {
- const inboxUsers = inboxUsersByUserId[getValue()];
+ const inboxUsers = inboxUsersByUserId[getValue()];
if (!inboxUsers) return null;
- return Object.keys(inboxUsers)
- .map((role) => {
- const count = inboxUsers[role].length;
- return t(tKeyForInboxUserRole(role), { count });
- })
- .join(', ');
+
+ return (
+
+ {inboxUsers.map(([role, count]) => {
+ return (
+ - {t(tKeyForInboxUserRole(role), { count })}
+ );
+ })}
+
+ );
},
}),
columnHelper.display({
@@ -107,9 +104,9 @@ export default function Users() {
);
},
}),
- ];
- return columns;
- }, [inboxUsersByUserId, t, user.actorIdentity.userId]);
+ ],
+ [inboxUsersByUserId, t, user.actorIdentity.userId],
+ );
const { table, getBodyProps, rows, getContainerProps } = useTable({
data: orgUsers,
@@ -125,7 +122,7 @@ export default function Users() {
{t('settings:users')}
-
+
diff --git a/packages/app-builder/src/routes/_builder+/upload+/$objectType.tsx b/packages/app-builder/src/routes/_builder+/upload+/$objectType.tsx
index 04f34828c..49cd62f4b 100644
--- a/packages/app-builder/src/routes/_builder+/upload+/$objectType.tsx
+++ b/packages/app-builder/src/routes/_builder+/upload+/$objectType.tsx
@@ -27,7 +27,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { apiClient, user, dataModelRepository } =
await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
if (!user.permissions.canIngestData) {
diff --git a/packages/app-builder/src/routes/_index.tsx b/packages/app-builder/src/routes/_index.tsx
index 4adceec62..4c6b757f8 100644
--- a/packages/app-builder/src/routes/_index.tsx
+++ b/packages/app-builder/src/routes/_index.tsx
@@ -1,5 +1,5 @@
import { redirect } from '@remix-run/node';
export function loader() {
- return redirect('/login');
+ return redirect('/sign-in');
}
diff --git a/packages/app-builder/src/routes/healthcheck.ts b/packages/app-builder/src/routes/healthcheck.ts
index 785e3bf07..18a3d036e 100644
--- a/packages/app-builder/src/routes/healthcheck.ts
+++ b/packages/app-builder/src/routes/healthcheck.ts
@@ -7,7 +7,7 @@ async function isServerLive(request: LoaderFunctionArgs['request']) {
'NO_HOST';
const url = new URL('/', `http://${host}`);
- return fetch(url.toString(), { method: 'HEAD' }).then((r) => {
+ return fetch(url.href, { method: 'HEAD' }).then((r) => {
if (!r.ok) return Promise.reject(r);
});
}
diff --git a/packages/app-builder/src/routes/login-with-email.tsx b/packages/app-builder/src/routes/login-with-email.tsx
deleted file mode 100644
index b0885d8cd..000000000
--- a/packages/app-builder/src/routes/login-with-email.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import { type AuthErrors } from '@app-builder/models';
-import { serverServices } from '@app-builder/services/init.server';
-import { json, type LoaderFunctionArgs } from '@remix-run/node';
-import { useLoaderData } from '@remix-run/react';
-import { type Namespace, type ParseKeys } from 'i18next';
-import { useTranslation } from 'react-i18next';
-import { Logo } from 'ui-icons';
-
-import { SignInWithEmail } from './ressources+/auth+/login-with-email';
-import { LanguagePicker } from './ressources+/user+/language';
-
-export async function loader({ request }: LoaderFunctionArgs) {
- const {
- authService,
- authSessionService: { getSession },
- } = serverServices;
- await authService.isAuthenticated(request, {
- successRedirect: '/home',
- });
- const session = await getSession(request);
- const error = session.get('authError');
-
- return json({
- authError: error?.message,
- });
-}
-
-export const handle = {
- i18n: ['login', 'common'] satisfies Namespace,
-};
-
-const errorLabels: Record> = {
- NoAccount: 'login:errors.no_account',
- Unknown: 'common:errors.unknown',
-};
-
-export default function LoginWithEmail() {
- const { t } = useTranslation(handle.i18n);
- const { authError } = useLoaderData();
-
- return (
-
-
-
-
-
-
-
{t('login:title')}
-
-
-
-
-
- {authError ? (
-
- {t(errorLabels[authError])}
-
- ) : null}
-
-
- {t('login:help.no_account')} {t('login:help.contact_us')}
-
-
-
-
-
- );
-}
diff --git a/packages/app-builder/src/routes/login.tsx b/packages/app-builder/src/routes/login.tsx
deleted file mode 100644
index f0493eecc..000000000
--- a/packages/app-builder/src/routes/login.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import { type AuthErrors } from '@app-builder/models';
-import { serverServices } from '@app-builder/services/init.server';
-import { json, type LoaderFunctionArgs } from '@remix-run/node';
-import { useLoaderData } from '@remix-run/react';
-import { type Namespace, type ParseKeys } from 'i18next';
-import { useTranslation } from 'react-i18next';
-import { Logo } from 'ui-icons';
-
-import { SignInWithGoogle } from './ressources+/auth+/login';
-import { LanguagePicker } from './ressources+/user+/language';
-
-export async function loader({ request }: LoaderFunctionArgs) {
- const {
- authService,
- authSessionService: { getSession },
- } = serverServices;
- await authService.isAuthenticated(request, {
- successRedirect: '/home',
- });
- const session = await getSession(request);
- const error = session.get('authError');
-
- return json({
- authError: error?.message,
- });
-}
-
-export const handle = {
- i18n: ['login', 'common'] satisfies Namespace,
-};
-
-const errorLabels: Record> = {
- NoAccount: 'login:errors.no_account',
- Unknown: 'common:errors.unknown',
-};
-
-export default function Login() {
- const { t } = useTranslation(handle.i18n);
- const { authError } = useLoaderData();
-
- return (
-
-
-
-
-
-
-
{t('login:title')}
-
-
-
-
-
- {authError ? (
-
- {t(errorLabels[authError])}
-
- ) : null}
-
-
- {t('login:help.no_account')} {t('login:help.contact_us')}
-
-
-
-
-
- );
-}
diff --git a/packages/app-builder/src/routes/ressources+/auth+/logout.tsx b/packages/app-builder/src/routes/ressources+/auth+/logout.tsx
index bd10e3425..d066d59ce 100644
--- a/packages/app-builder/src/routes/ressources+/auth+/logout.tsx
+++ b/packages/app-builder/src/routes/ressources+/auth+/logout.tsx
@@ -5,9 +5,9 @@ import {
} from '@remix-run/node';
export async function loader({ request }: LoaderFunctionArgs) {
- await serverServices.authService.logout(request, { redirectTo: '/login' });
+ await serverServices.authService.logout(request, { redirectTo: '/sign-in' });
}
export async function action({ request }: ActionFunctionArgs) {
- await serverServices.authService.logout(request, { redirectTo: '/login' });
+ await serverServices.authService.logout(request, { redirectTo: '/sign-in' });
}
diff --git a/packages/app-builder/src/routes/ressources+/auth+/refresh.tsx b/packages/app-builder/src/routes/ressources+/auth+/refresh.tsx
index 90dc3ca47..1c3a1366e 100644
--- a/packages/app-builder/src/routes/ressources+/auth+/refresh.tsx
+++ b/packages/app-builder/src/routes/ressources+/auth+/refresh.tsx
@@ -7,7 +7,7 @@ import { useFetcher, useNavigate } from '@remix-run/react';
import { useAuthenticityToken } from 'remix-utils/csrf/react';
export function loader() {
- return redirect(getRoute('/login'));
+ return redirect(getRoute('/sign-in'));
}
export async function action({ request }: ActionFunctionArgs) {
diff --git a/packages/app-builder/src/routes/ressources+/cases+/add-comment.tsx b/packages/app-builder/src/routes/ressources+/cases+/add-comment.tsx
index 68630da19..d51059777 100644
--- a/packages/app-builder/src/routes/ressources+/cases+/add-comment.tsx
+++ b/packages/app-builder/src/routes/ressources+/cases+/add-comment.tsx
@@ -27,7 +27,7 @@ export async function action({ request }: ActionFunctionArgs) {
const session = await getSession(request);
const { cases } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const formData = await request.formData();
diff --git a/packages/app-builder/src/routes/ressources+/cases+/add-to-case.tsx b/packages/app-builder/src/routes/ressources+/cases+/add-to-case.tsx
index 73de5911b..b35f45bf8 100644
--- a/packages/app-builder/src/routes/ressources+/cases+/add-to-case.tsx
+++ b/packages/app-builder/src/routes/ressources+/cases+/add-to-case.tsx
@@ -54,7 +54,7 @@ const addToCaseFormSchema = z.discriminatedUnion('newCase', [
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const inboxes = await apiClient.listInboxes({ withCaseCount: false });
@@ -69,7 +69,7 @@ export async function action({ request }: ActionFunctionArgs) {
toastSessionService: { getSession, commitSession },
} = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const parsedForm = addToCaseFormSchema.safeParse(await request.json());
diff --git a/packages/app-builder/src/routes/ressources+/cases+/create-case.tsx b/packages/app-builder/src/routes/ressources+/cases+/create-case.tsx
index bbf22e47e..9aef3961f 100644
--- a/packages/app-builder/src/routes/ressources+/cases+/create-case.tsx
+++ b/packages/app-builder/src/routes/ressources+/cases+/create-case.tsx
@@ -32,7 +32,7 @@ const createCaseFormSchema = z.object({
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const inboxes = await apiClient.listInboxes({ withCaseCount: false });
@@ -47,7 +47,7 @@ export async function action({ request }: ActionFunctionArgs) {
toastSessionService: { getSession, commitSession },
} = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const parsedForm = createCaseFormSchema.safeParse(await request.json());
diff --git a/packages/app-builder/src/routes/ressources+/cases+/edit-inbox.tsx b/packages/app-builder/src/routes/ressources+/cases+/edit-inbox.tsx
index f638e99c1..9114568fc 100644
--- a/packages/app-builder/src/routes/ressources+/cases+/edit-inbox.tsx
+++ b/packages/app-builder/src/routes/ressources+/cases+/edit-inbox.tsx
@@ -22,7 +22,7 @@ const schema = z.object({
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const inboxes = await apiClient.listInboxes({ withCaseCount: false });
@@ -32,7 +32,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { cases } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const formData = await request.formData();
diff --git a/packages/app-builder/src/routes/ressources+/cases+/edit-name.tsx b/packages/app-builder/src/routes/ressources+/cases+/edit-name.tsx
index c8ad1ea60..006394b3d 100644
--- a/packages/app-builder/src/routes/ressources+/cases+/edit-name.tsx
+++ b/packages/app-builder/src/routes/ressources+/cases+/edit-name.tsx
@@ -16,7 +16,7 @@ const schema = z.object({
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { cases } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const formData = await request.formData();
diff --git a/packages/app-builder/src/routes/ressources+/cases+/edit-status.tsx b/packages/app-builder/src/routes/ressources+/cases+/edit-status.tsx
index 6572788f6..a1add94e9 100644
--- a/packages/app-builder/src/routes/ressources+/cases+/edit-status.tsx
+++ b/packages/app-builder/src/routes/ressources+/cases+/edit-status.tsx
@@ -34,7 +34,7 @@ type Schema = z.infer;
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { cases } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const formData = await request.formData();
diff --git a/packages/app-builder/src/routes/ressources+/cases+/edit-tags.tsx b/packages/app-builder/src/routes/ressources+/cases+/edit-tags.tsx
index 9715b8a4b..4d35860b5 100644
--- a/packages/app-builder/src/routes/ressources+/cases+/edit-tags.tsx
+++ b/packages/app-builder/src/routes/ressources+/cases+/edit-tags.tsx
@@ -26,7 +26,7 @@ const schema = z.object({
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { cases } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const formData = await request.formData();
diff --git a/packages/app-builder/src/routes/ressources+/data+/createField.tsx b/packages/app-builder/src/routes/ressources+/data+/createField.tsx
index 89a268dbe..b2e85830e 100644
--- a/packages/app-builder/src/routes/ressources+/data+/createField.tsx
+++ b/packages/app-builder/src/routes/ressources+/data+/createField.tsx
@@ -58,7 +58,7 @@ const REQUIRED_OPTIONS = [
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const parsedData = createFieldFormSchema.safeParse(await request.json());
diff --git a/packages/app-builder/src/routes/ressources+/data+/createLink.tsx b/packages/app-builder/src/routes/ressources+/data+/createLink.tsx
index 65f5dda80..1928fa2ef 100644
--- a/packages/app-builder/src/routes/ressources+/data+/createLink.tsx
+++ b/packages/app-builder/src/routes/ressources+/data+/createLink.tsx
@@ -42,7 +42,7 @@ const createLinkFormSchema = z.object({
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const parsedForm = await parseFormSafe(request, createLinkFormSchema);
diff --git a/packages/app-builder/src/routes/ressources+/data+/createTable.tsx b/packages/app-builder/src/routes/ressources+/data+/createTable.tsx
index 383364ebb..ad78e24b5 100644
--- a/packages/app-builder/src/routes/ressources+/data+/createTable.tsx
+++ b/packages/app-builder/src/routes/ressources+/data+/createTable.tsx
@@ -36,7 +36,7 @@ const createTableFormSchema = z.object({
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const parsedForm = await parseFormSafe(request, createTableFormSchema);
diff --git a/packages/app-builder/src/routes/ressources+/data+/editField.tsx b/packages/app-builder/src/routes/ressources+/data+/editField.tsx
index 9766253cf..317c49ea2 100644
--- a/packages/app-builder/src/routes/ressources+/data+/editField.tsx
+++ b/packages/app-builder/src/routes/ressources+/data+/editField.tsx
@@ -33,7 +33,7 @@ const editFieldFormSchema = z.object({
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const parsedData = editFieldFormSchema.safeParse(await request.json());
diff --git a/packages/app-builder/src/routes/ressources+/data+/editTable.tsx b/packages/app-builder/src/routes/ressources+/data+/editTable.tsx
index c52f5b784..7beb1811a 100644
--- a/packages/app-builder/src/routes/ressources+/data+/editTable.tsx
+++ b/packages/app-builder/src/routes/ressources+/data+/editTable.tsx
@@ -31,7 +31,7 @@ const editTableFormSchema = z.object({
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const parsedForm = await parseFormSafe(request, editTableFormSchema);
diff --git a/packages/app-builder/src/routes/ressources+/lists+/create.tsx b/packages/app-builder/src/routes/ressources+/lists+/create.tsx
index 3f726c5e0..1e38be3bd 100644
--- a/packages/app-builder/src/routes/ressources+/lists+/create.tsx
+++ b/packages/app-builder/src/routes/ressources+/lists+/create.tsx
@@ -33,7 +33,7 @@ const createListFormSchema = z.object({
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const parsedForm = await parseFormSafe(request, createListFormSchema);
diff --git a/packages/app-builder/src/routes/ressources+/lists+/delete.tsx b/packages/app-builder/src/routes/ressources+/lists+/delete.tsx
index b73a71721..a9b563023 100644
--- a/packages/app-builder/src/routes/ressources+/lists+/delete.tsx
+++ b/packages/app-builder/src/routes/ressources+/lists+/delete.tsx
@@ -20,7 +20,7 @@ const deleteListFormSchema = z.object({
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const parsedForm = await parseFormSafe(request, deleteListFormSchema);
diff --git a/packages/app-builder/src/routes/ressources+/lists+/edit.tsx b/packages/app-builder/src/routes/ressources+/lists+/edit.tsx
index a99bbeac2..c14cb5317 100644
--- a/packages/app-builder/src/routes/ressources+/lists+/edit.tsx
+++ b/packages/app-builder/src/routes/ressources+/lists+/edit.tsx
@@ -32,7 +32,7 @@ const editListFormSchema = z.object({
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const parsedForm = await parseFormSafe(request, editListFormSchema);
diff --git a/packages/app-builder/src/routes/ressources+/lists+/value_create.tsx b/packages/app-builder/src/routes/ressources+/lists+/value_create.tsx
index a9c92dee3..e0a6cbd5b 100644
--- a/packages/app-builder/src/routes/ressources+/lists+/value_create.tsx
+++ b/packages/app-builder/src/routes/ressources+/lists+/value_create.tsx
@@ -31,7 +31,7 @@ const addValueFormSchema = z.object({
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const parsedForm = await parseFormSafe(request, addValueFormSchema);
if (!parsedForm.success) {
diff --git a/packages/app-builder/src/routes/ressources+/lists+/value_delete.tsx b/packages/app-builder/src/routes/ressources+/lists+/value_delete.tsx
index ce29c6a38..ebf408155 100644
--- a/packages/app-builder/src/routes/ressources+/lists+/value_delete.tsx
+++ b/packages/app-builder/src/routes/ressources+/lists+/value_delete.tsx
@@ -22,7 +22,7 @@ const deleteValueFormSchema = z.object({
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const parsedForm = await parseFormSafe(request, deleteValueFormSchema);
if (!parsedForm.success) {
diff --git a/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/create_draft.tsx b/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/create_draft.tsx
index dd10c0676..8cc56dbdb 100644
--- a/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/create_draft.tsx
+++ b/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/create_draft.tsx
@@ -21,7 +21,7 @@ const createDraftIterationFormSchema = z.object({
export async function action({ request, params }: ActionFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const parsedForm = await parseFormSafe(
diff --git a/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/rules+/create.tsx b/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/rules+/create.tsx
index b29852d21..3e20f226f 100644
--- a/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/rules+/create.tsx
+++ b/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/rules+/create.tsx
@@ -15,7 +15,7 @@ export const handle = {
export async function action({ request, params }: ActionFunctionArgs) {
const { authService, i18nextService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const t = await i18nextService.getFixedT(request, 'scenarios');
const scenarioId = fromParams(params, 'scenarioId');
diff --git a/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/rules+/delete.tsx b/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/rules+/delete.tsx
index c4200e650..7c9c15603 100644
--- a/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/rules+/delete.tsx
+++ b/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/rules+/delete.tsx
@@ -23,7 +23,7 @@ const deleteRuleFormSchema = z.object({
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const parsedForm = await parseFormSafe(request, deleteRuleFormSchema);
diff --git a/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/rules+/duplicate.tsx b/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/rules+/duplicate.tsx
index 15ddb213c..dca49cc3b 100644
--- a/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/rules+/duplicate.tsx
+++ b/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/rules+/duplicate.tsx
@@ -24,7 +24,7 @@ export async function action({ request }: ActionFunctionArgs) {
const { authService, i18nextService } = serverServices;
const t = await i18nextService.getFixedT(request, 'scenarios');
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const parsedForm = await parseFormSafe(request, duplicateRuleFormSchema);
diff --git a/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/validate-with-given-trigger-or-rule.tsx b/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/validate-with-given-trigger-or-rule.tsx
index 7b5f52738..224ff51fe 100644
--- a/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/validate-with-given-trigger-or-rule.tsx
+++ b/packages/app-builder/src/routes/ressources+/scenarios+/$scenarioId+/$iterationId+/validate-with-given-trigger-or-rule.tsx
@@ -15,7 +15,7 @@ import { useCallback } from 'react';
export async function action({ request, params }: ActionFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const body = (await request.json()) as {
diff --git a/packages/app-builder/src/routes/ressources+/scenarios+/create.tsx b/packages/app-builder/src/routes/ressources+/scenarios+/create.tsx
index bf951a3e5..0d73979f5 100644
--- a/packages/app-builder/src/routes/ressources+/scenarios+/create.tsx
+++ b/packages/app-builder/src/routes/ressources+/scenarios+/create.tsx
@@ -23,7 +23,7 @@ export const handle = {
export async function loader({ request }: LoaderFunctionArgs) {
const { authService } = serverServices;
const { dataModelRepository } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const dataModel = await dataModelRepository.getDataModel();
@@ -41,7 +41,7 @@ const createScenarioFormSchema = z.object({
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const parsedForm = await parseFormSafe(request, createScenarioFormSchema);
if (!parsedForm.success) {
diff --git a/packages/app-builder/src/routes/ressources+/scenarios+/deployment.tsx b/packages/app-builder/src/routes/ressources+/scenarios+/deployment.tsx
index da25482ff..b3f60a2bc 100644
--- a/packages/app-builder/src/routes/ressources+/scenarios+/deployment.tsx
+++ b/packages/app-builder/src/routes/ressources+/scenarios+/deployment.tsx
@@ -49,7 +49,7 @@ const formSchema = z.object({
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
type Errors = Record<
diff --git a/packages/app-builder/src/routes/ressources+/settings+/inboxes+/create.tsx b/packages/app-builder/src/routes/ressources+/settings+/inboxes+/create.tsx
index 668bd6cb8..e07171716 100644
--- a/packages/app-builder/src/routes/ressources+/settings+/inboxes+/create.tsx
+++ b/packages/app-builder/src/routes/ressources+/settings+/inboxes+/create.tsx
@@ -36,7 +36,7 @@ export async function action({ request }: ActionFunctionArgs) {
toastSessionService: { getSession, commitSession },
} = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const formData = await request.formData();
diff --git a/packages/app-builder/src/routes/ressources+/settings+/inboxes+/delete.tsx b/packages/app-builder/src/routes/ressources+/settings+/inboxes+/delete.tsx
index 594f7c118..019a8e76c 100644
--- a/packages/app-builder/src/routes/ressources+/settings+/inboxes+/delete.tsx
+++ b/packages/app-builder/src/routes/ressources+/settings+/inboxes+/delete.tsx
@@ -22,7 +22,7 @@ const deleteInboxFormSchema = z.object({
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const formData = await parseForm(request, deleteInboxFormSchema);
diff --git a/packages/app-builder/src/routes/ressources+/settings+/inboxes+/inbox-users.create.tsx b/packages/app-builder/src/routes/ressources+/settings+/inboxes+/inbox-users.create.tsx
index b6175dcd7..cf88a6eef 100644
--- a/packages/app-builder/src/routes/ressources+/settings+/inboxes+/inbox-users.create.tsx
+++ b/packages/app-builder/src/routes/ressources+/settings+/inboxes+/inbox-users.create.tsx
@@ -37,7 +37,7 @@ export async function action({ request }: ActionFunctionArgs) {
toastSessionService: { getSession, commitSession },
} = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const formData = await request.formData();
diff --git a/packages/app-builder/src/routes/ressources+/settings+/inboxes+/inbox-users.delete.tsx b/packages/app-builder/src/routes/ressources+/settings+/inboxes+/inbox-users.delete.tsx
index 1319c7fcb..51fec0471 100644
--- a/packages/app-builder/src/routes/ressources+/settings+/inboxes+/inbox-users.delete.tsx
+++ b/packages/app-builder/src/routes/ressources+/settings+/inboxes+/inbox-users.delete.tsx
@@ -24,7 +24,7 @@ const deleteInboxUserFormSchema = z.object({
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const formData = await parseForm(request, deleteInboxUserFormSchema);
diff --git a/packages/app-builder/src/routes/ressources+/settings+/inboxes+/inbox-users.update.tsx b/packages/app-builder/src/routes/ressources+/settings+/inboxes+/inbox-users.update.tsx
index 8760f84bb..27f45a76f 100644
--- a/packages/app-builder/src/routes/ressources+/settings+/inboxes+/inbox-users.update.tsx
+++ b/packages/app-builder/src/routes/ressources+/settings+/inboxes+/inbox-users.update.tsx
@@ -37,7 +37,7 @@ export async function action({ request }: ActionFunctionArgs) {
toastSessionService: { getSession, commitSession },
} = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const formData = await request.formData();
diff --git a/packages/app-builder/src/routes/ressources+/settings+/inboxes+/update.tsx b/packages/app-builder/src/routes/ressources+/settings+/inboxes+/update.tsx
index 486732900..be75ef086 100644
--- a/packages/app-builder/src/routes/ressources+/settings+/inboxes+/update.tsx
+++ b/packages/app-builder/src/routes/ressources+/settings+/inboxes+/update.tsx
@@ -37,7 +37,7 @@ export async function action({ request }: ActionFunctionArgs) {
toastSessionService: { getSession, commitSession },
} = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const formData = await request.formData();
diff --git a/packages/app-builder/src/routes/ressources+/settings+/tags+/create.tsx b/packages/app-builder/src/routes/ressources+/settings+/tags+/create.tsx
index dfb303588..fba54de9e 100644
--- a/packages/app-builder/src/routes/ressources+/settings+/tags+/create.tsx
+++ b/packages/app-builder/src/routes/ressources+/settings+/tags+/create.tsx
@@ -40,7 +40,7 @@ export async function action({ request }: ActionFunctionArgs) {
toastSessionService: { getSession, commitSession },
} = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const formData = await request.formData();
const submission = parse(formData, { schema: createTagFormSchema });
diff --git a/packages/app-builder/src/routes/ressources+/settings+/tags+/delete.tsx b/packages/app-builder/src/routes/ressources+/settings+/tags+/delete.tsx
index 74000870c..bbb8193d2 100644
--- a/packages/app-builder/src/routes/ressources+/settings+/tags+/delete.tsx
+++ b/packages/app-builder/src/routes/ressources+/settings+/tags+/delete.tsx
@@ -22,7 +22,7 @@ const deleteTagFormSchema = z.object({
export async function action({ request }: ActionFunctionArgs) {
const { authService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const formData = await parseForm(request, deleteTagFormSchema);
diff --git a/packages/app-builder/src/routes/ressources+/settings+/tags+/update.tsx b/packages/app-builder/src/routes/ressources+/settings+/tags+/update.tsx
index 3c0598f76..07ca7de85 100644
--- a/packages/app-builder/src/routes/ressources+/settings+/tags+/update.tsx
+++ b/packages/app-builder/src/routes/ressources+/settings+/tags+/update.tsx
@@ -36,7 +36,7 @@ export async function action({ request }: ActionFunctionArgs) {
toastSessionService: { getSession, commitSession },
} = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
const formData = await request.formData();
const submission = parse(formData, { schema: updateTagFormSchema });
diff --git a/packages/app-builder/src/routes/ressources+/settings+/users+/create.tsx b/packages/app-builder/src/routes/ressources+/settings+/users+/create.tsx
index 021a6bc2b..3b84e58b9 100644
--- a/packages/app-builder/src/routes/ressources+/settings+/users+/create.tsx
+++ b/packages/app-builder/src/routes/ressources+/settings+/users+/create.tsx
@@ -3,6 +3,8 @@ import { FormField } from '@app-builder/components/Form/FormField';
import { FormInput } from '@app-builder/components/Form/FormInput';
import { FormLabel } from '@app-builder/components/Form/FormLabel';
import { FormSelect } from '@app-builder/components/Form/FormSelect';
+import { setToastMessage } from '@app-builder/components/MarbleToaster';
+import { isStatusConflictHttpError } from '@app-builder/models';
import { serverServices } from '@app-builder/services/init.server';
import { getRoute } from '@app-builder/utils/routes';
import { conform, useForm } from '@conform-to/react';
@@ -12,6 +14,7 @@ import { useFetcher, useNavigation } from '@remix-run/react';
import { type Namespace, type ParseKeys } from 'i18next';
import { useEffect, useId, useState } from 'react';
import { useTranslation } from 'react-i18next';
+import { AuthenticityTokenInput } from 'remix-utils/csrf/react';
import { Button, Modal, Select } from 'ui-design-system';
import { Icon } from 'ui-icons';
import { z } from 'zod';
@@ -29,10 +32,12 @@ const createUserFormSchema = z.object({
});
export async function action({ request }: ActionFunctionArgs) {
- const { authService } = serverServices;
+ const { authService, csrfService } = serverServices;
const { apiClient } = await authService.isAuthenticated(request, {
- failureRedirect: '/login',
+ failureRedirect: getRoute('/sign-in'),
});
+ await csrfService.validate(request);
+
const formData = await request.formData();
const submission = parse(formData, { schema: createUserFormSchema });
@@ -48,9 +53,25 @@ export async function action({ request }: ActionFunctionArgs) {
role: submission.value.role,
organization_id: submission.value.organizationId,
});
+
return redirect(getRoute('/settings/users'));
} catch (error) {
- return json(submission);
+ const { getSession, commitSession } = serverServices.toastSessionService;
+ const session = await getSession(request);
+ if (isStatusConflictHttpError(error)) {
+ setToastMessage(session, {
+ type: 'error',
+ messageKey: 'common:errors.list.duplicate_email',
+ });
+ } else {
+ setToastMessage(session, {
+ type: 'error',
+ messageKey: 'common:errors.unknown',
+ });
+ }
+ return json(submission, {
+ headers: { 'Set-Cookie': await commitSession(session) },
+ });
}
}
@@ -115,6 +136,7 @@ const CreateUserContent = ({ orgId }: { orgId: string }) => {
{t('settings:users.new_user')}
+
{
try {
- const idToken =
+ const result =
await authenticationClientRepository.emailAndPasswordSignIn(
language,
email,
password,
);
- return { idToken, csrf };
+ if (!result.emailVerified) {
+ throw new EmailUnverified();
+ }
+ return { idToken: result.idToken, csrf };
} catch (error) {
if (error instanceof FirebaseError) {
switch (error.code) {
- case 'auth/user-not-found':
+ case AuthErrorCodes.USER_DELETED:
throw new UserNotFoundError();
- case 'auth/wrong-password':
+ case AuthErrorCodes.INVALID_PASSWORD:
throw new WrongPasswordError();
- case 'auth/invalid-login-credentials':
+ case AuthErrorCodes.INVALID_LOGIN_CREDENTIALS:
throw new InvalidLoginCredentials();
}
}
@@ -70,10 +74,75 @@ export function useEmailAndPasswordSignIn({
};
}
+export class EmailUnverified extends Error {}
export class UserNotFoundError extends Error {}
export class WrongPasswordError extends Error {}
export class InvalidLoginCredentials extends Error {}
+export function useEmailAndPasswordSignUp({
+ authenticationClientRepository,
+}: AuthenticationClientService) {
+ const {
+ i18n: { language },
+ } = useTranslation();
+ const csrf = useAuthenticityToken();
+
+ return async (email: string, password: string) => {
+ try {
+ const idToken =
+ await authenticationClientRepository.emailAndPassswordSignUp(
+ language,
+ email,
+ password,
+ );
+ return { idToken, csrf };
+ } catch (error) {
+ if (error instanceof FirebaseError) {
+ switch (error.code) {
+ case AuthErrorCodes.EMAIL_EXISTS:
+ throw new EmailExistsError();
+ case AuthErrorCodes.WEAK_PASSWORD:
+ throw new WeakPasswordError();
+ }
+ }
+ throw error;
+ }
+ };
+}
+
+export class EmailExistsError extends Error {}
+export class WeakPasswordError extends Error {}
+
+export function useResendEmailVerification({
+ authenticationClientRepository,
+}: AuthenticationClientService) {
+ const {
+ i18n: { language },
+ } = useTranslation();
+
+ return async (logout: () => void) => {
+ await authenticationClientRepository.resendEmailVerification(
+ language,
+ logout,
+ );
+ };
+}
+
+export function useSendPasswordResetEmail({
+ authenticationClientRepository,
+}: AuthenticationClientService) {
+ const {
+ i18n: { language },
+ } = useTranslation();
+
+ return async (email: string) => {
+ await authenticationClientRepository.sendPasswordResetEmail(
+ language,
+ email,
+ );
+ };
+}
+
export function useBackendInfo({
authenticationClientRepository,
}: AuthenticationClientService) {
diff --git a/packages/app-builder/src/services/auth/auth.server.ts b/packages/app-builder/src/services/auth/auth.server.ts
index dfdba7e1c..6293c2502 100644
--- a/packages/app-builder/src/services/auth/auth.server.ts
+++ b/packages/app-builder/src/services/auth/auth.server.ts
@@ -9,6 +9,7 @@ import { type CaseRepository } from '@app-builder/repositories/CaseRepository';
import { type DataModelRepository } from '@app-builder/repositories/DataModelRepository';
import { type DecisionRepository } from '@app-builder/repositories/DecisionRepository';
import { type EditorRepository } from '@app-builder/repositories/EditorRepository';
+import { type InboxRepository } from '@app-builder/repositories/InboxRepository';
import { type MarbleAPIRepository } from '@app-builder/repositories/MarbleAPIRepository';
import { type OrganizationRepository } from '@app-builder/repositories/OrganizationRepository';
import { type ScenarioRepository } from '@app-builder/repositories/ScenarioRepository';
@@ -33,6 +34,7 @@ interface AuthenticatedInfo {
organization: OrganizationRepository;
scenario: ScenarioRepository;
user: CurrentUser;
+ inbox: InboxRepository;
}
export interface AuthenticationServerService {
@@ -70,9 +72,16 @@ export interface AuthenticationServerService {
): Promise;
}
+const schema = z.object({
+ idToken: z.string(),
+ csrf: z.string(),
+});
+export type AuthPayload = z.infer;
+
export function makeAuthenticationServerService(
marbleAPIClient: MarbleAPIRepository,
userRepository: (marbleApiClient: MarbleApi) => UserRepository,
+ inboxRepository: (marbleApiClient: MarbleApi) => InboxRepository,
editorRepository: (marbleApiClient: MarbleApi) => EditorRepository,
decisionRepository: (marbleApiClient: MarbleApi) => DecisionRepository,
caseRepository: (marbleApiClient: MarbleApi) => CaseRepository,
@@ -108,12 +117,7 @@ export function makeAuthenticationServerService(
let redirectUrl = options.failureRedirect;
try {
- const { idToken } = await parseForm(
- request,
- z.object({
- idToken: z.string(),
- }),
- );
+ const { idToken } = await parseForm(request, schema);
await csrfService.validate(request);
const marbleToken = await marbleApi.postToken(
@@ -243,6 +247,7 @@ export function makeAuthenticationServerService(
organization: organizationRepository(apiClient, user.organizationId),
dataModelRepository: dataModelRepository(apiClient),
user,
+ inbox: inboxRepository(apiClient),
};
}
diff --git a/packages/app-builder/src/services/i18n/i18next.d.ts b/packages/app-builder/src/services/i18n/i18next.d.ts
index 22de6ad1e..8a523b569 100644
--- a/packages/app-builder/src/services/i18n/i18next.d.ts
+++ b/packages/app-builder/src/services/i18n/i18next.d.ts
@@ -1,11 +1,11 @@
import type api from '../../../public/locales/en/api.json';
+import type auth from '../../../public/locales/en/auth.json';
import type cases from '../../../public/locales/en/cases.json';
import type common from '../../../public/locales/en/common.json';
import type data from '../../../public/locales/en/data.json';
import type decisions from '../../../public/locales/en/decisions.json';
import type filters from '../../../public/locales/en/filters.json';
import type lists from '../../../public/locales/en/lists.json';
-import type login from '../../../public/locales/en/login.json';
import type navigation from '../../../public/locales/en/navigation.json';
import type scenarios from '../../../public/locales/en/scenarios.json';
import type scheduledExecution from '../../../public/locales/en/scheduledExecution.json';
@@ -25,7 +25,7 @@ declare module 'i18next' {
filters: typeof filters;
navigation: typeof navigation;
lists: typeof lists;
- login: typeof login;
+ auth: typeof auth;
scenarios: typeof scenarios;
scheduledExecution: typeof scheduledExecution;
settings: typeof settings;
diff --git a/packages/app-builder/src/services/init.server.ts b/packages/app-builder/src/services/init.server.ts
index b6151c2a9..ed4f69468 100644
--- a/packages/app-builder/src/services/init.server.ts
+++ b/packages/app-builder/src/services/init.server.ts
@@ -29,6 +29,7 @@ function makeServerServices(repositories: ServerRepositories) {
authService: makeAuthenticationServerService(
repositories.marbleAPIClient,
repositories.userRepository,
+ repositories.inboxRepository,
repositories.editorRepository,
repositories.decisionRepository,
repositories.caseRepository,
diff --git a/packages/app-builder/src/utils/routes/routes.ts b/packages/app-builder/src/utils/routes/routes.ts
index 0f0c097f2..904ea9982 100644
--- a/packages/app-builder/src/utils/routes/routes.ts
+++ b/packages/app-builder/src/utils/routes/routes.ts
@@ -4,6 +4,32 @@ export const routes = [
"path": "",
"file": "root.tsx",
"children": [
+ {
+ "id": "routes/_auth+/_layout",
+ "file": "routes/_auth+/_layout.tsx",
+ "children": [
+ {
+ "id": "routes/_auth+/email-verification",
+ "path": "email-verification",
+ "file": "routes/_auth+/email-verification.tsx"
+ },
+ {
+ "id": "routes/_auth+/forgot-password",
+ "path": "forgot-password",
+ "file": "routes/_auth+/forgot-password.tsx"
+ },
+ {
+ "id": "routes/_auth+/sign-in",
+ "path": "sign-in",
+ "file": "routes/_auth+/sign-in.tsx"
+ },
+ {
+ "id": "routes/_auth+/sign-up",
+ "path": "sign-up",
+ "file": "routes/_auth+/sign-up.tsx"
+ }
+ ]
+ },
{
"id": "routes/_builder+/_layout",
"file": "routes/_builder+/_layout.tsx",
@@ -184,26 +210,6 @@ export const routes = [
"path": "healthcheck",
"file": "routes/healthcheck.ts"
},
- {
- "id": "routes/login-with-email",
- "path": "login-with-email",
- "file": "routes/login-with-email.tsx"
- },
- {
- "id": "routes/login",
- "path": "login",
- "file": "routes/login.tsx"
- },
- {
- "id": "routes/ressources+/auth+/login-with-email",
- "path": "ressources/auth/login-with-email",
- "file": "routes/ressources+/auth+/login-with-email.tsx"
- },
- {
- "id": "routes/ressources+/auth+/login",
- "path": "ressources/auth/login",
- "file": "routes/ressources+/auth+/login.tsx"
- },
{
"id": "routes/ressources+/auth+/logout",
"path": "ressources/auth/logout",
diff --git a/packages/app-builder/src/utils/routes/types.ts b/packages/app-builder/src/utils/routes/types.ts
index 58b80d6b5..78212eb57 100644
--- a/packages/app-builder/src/utils/routes/types.ts
+++ b/packages/app-builder/src/utils/routes/types.ts
@@ -1,5 +1,9 @@
export type RoutePath =
| '/'
+ | '/email-verification'
+ | '/forgot-password'
+ | '/sign-in'
+ | '/sign-up'
| '/*'
| '/api'
| '/cases/:caseId'
@@ -27,10 +31,6 @@ export type RoutePath =
| '/settings/users'
| '/upload/:objectType'
| '/healthcheck'
- | '/login-with-email'
- | '/login'
- | '/ressources/auth/login-with-email'
- | '/ressources/auth/login'
| '/ressources/auth/logout'
| '/ressources/auth/refresh'
| '/ressources/cases/add-comment'
@@ -74,6 +74,11 @@ export type RoutePath =
export type RouteID =
| 'root'
+ | 'routes/_auth+/_layout'
+ | 'routes/_auth+/email-verification'
+ | 'routes/_auth+/forgot-password'
+ | 'routes/_auth+/sign-in'
+ | 'routes/_auth+/sign-up'
| 'routes/_builder+/_layout'
| 'routes/_builder+/$'
| 'routes/_builder+/api'
@@ -107,10 +112,6 @@ export type RouteID =
| 'routes/_builder+/upload+/$objectType'
| 'routes/_index'
| 'routes/healthcheck'
- | 'routes/login-with-email'
- | 'routes/login'
- | 'routes/ressources+/auth+/login-with-email'
- | 'routes/ressources+/auth+/login'
| 'routes/ressources+/auth+/logout'
| 'routes/ressources+/auth+/refresh'
| 'routes/ressources+/cases+/add-comment'
diff --git a/packages/ui-design-system/src/Collapsible/Collapsible.tsx b/packages/ui-design-system/src/Collapsible/Collapsible.tsx
index a04eca9dc..a3aa7e7a1 100644
--- a/packages/ui-design-system/src/Collapsible/Collapsible.tsx
+++ b/packages/ui-design-system/src/Collapsible/Collapsible.tsx
@@ -35,14 +35,17 @@ const CollapsibleTitle = forwardRef(
'group flex cursor-pointer items-center justify-between gap-4 p-4 font-semibold lg:p-6',
className,
)}
+ asChild
{...props}
>
- {children}
-
+
+ {children}
+
+
);
},
diff --git a/packages/ui-icons/src/generated/logos-svg-sprite.svg b/packages/ui-icons/src/generated/logos-svg-sprite.svg
index 05ac0a771..9ee467016 100644
--- a/packages/ui-icons/src/generated/logos-svg-sprite.svg
+++ b/packages/ui-icons/src/generated/logos-svg-sprite.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/packages/ui-icons/svgs/logos/logo-standard.svg b/packages/ui-icons/svgs/logos/logo-standard.svg
index 8245f6792..4e19990a9 100644
--- a/packages/ui-icons/svgs/logos/logo-standard.svg
+++ b/packages/ui-icons/svgs/logos/logo-standard.svg
@@ -1,5 +1,5 @@
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c6cfb4a6a..2326ea04a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -53,6 +53,9 @@ importers:
'@hookform/resolvers':
specifier: ^3.3.4
version: 3.3.4(react-hook-form@7.49.2)
+ '@lottiefiles/react-lottie-player':
+ specifier: ^3.5.3
+ version: 3.5.3(react@18.2.0)
'@radix-ui/react-accordion':
specifier: ^1.1.2
version: 1.1.2(@types/react-dom@18.2.18)(@types/react@18.2.47)(react-dom@18.2.0)(react@18.2.0)
@@ -97,13 +100,13 @@ importers:
version: 1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.47)(react-dom@18.2.0)(react@18.2.0)
'@remix-run/node':
specifier: ^2.4.1
- version: 2.4.1
+ version: 2.4.1(typescript@5.3.3)
'@remix-run/react':
specifier: ^2.4.1
- version: 2.4.1(react-dom@18.2.0)(react@18.2.0)
+ version: 2.4.1(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)
'@remix-run/serve':
specifier: ^2.4.1
- version: 2.4.1
+ version: 2.4.1(typescript@5.3.3)
'@segment/snippet':
specifier: ^5.2.0
version: 5.2.0
@@ -239,7 +242,7 @@ importers:
version: link:../eslint-config
'@remix-run/dev':
specifier: ^2.4.1
- version: 2.4.1(@remix-run/serve@2.4.1)
+ version: 2.4.1(@remix-run/serve@2.4.1)(typescript@5.3.3)(vite@5.0.11)
'@segment/analytics-next':
specifier: ^1.62.0
version: 1.62.0
@@ -475,7 +478,7 @@ importers:
version: 9.3.3
'@testing-library/jest-dom':
specifier: ^6.2.0
- version: 6.2.0
+ version: 6.2.0(vitest@1.1.3)
'@testing-library/react':
specifier: 14.1.2
version: 14.1.2(react-dom@18.2.0)(react@18.2.0)
@@ -2411,7 +2414,6 @@ packages:
cpu: [ppc64]
os: [aix]
requiresBuild: true
- dev: true
optional: true
/@esbuild/android-arm64@0.17.6:
@@ -2436,7 +2438,6 @@ packages:
cpu: [arm64]
os: [android]
requiresBuild: true
- dev: true
optional: true
/@esbuild/android-arm@0.17.6:
@@ -2461,7 +2462,6 @@ packages:
cpu: [arm]
os: [android]
requiresBuild: true
- dev: true
optional: true
/@esbuild/android-x64@0.17.6:
@@ -2486,7 +2486,6 @@ packages:
cpu: [x64]
os: [android]
requiresBuild: true
- dev: true
optional: true
/@esbuild/darwin-arm64@0.17.6:
@@ -2511,7 +2510,6 @@ packages:
cpu: [arm64]
os: [darwin]
requiresBuild: true
- dev: true
optional: true
/@esbuild/darwin-x64@0.17.6:
@@ -2536,7 +2534,6 @@ packages:
cpu: [x64]
os: [darwin]
requiresBuild: true
- dev: true
optional: true
/@esbuild/freebsd-arm64@0.17.6:
@@ -2561,7 +2558,6 @@ packages:
cpu: [arm64]
os: [freebsd]
requiresBuild: true
- dev: true
optional: true
/@esbuild/freebsd-x64@0.17.6:
@@ -2586,7 +2582,6 @@ packages:
cpu: [x64]
os: [freebsd]
requiresBuild: true
- dev: true
optional: true
/@esbuild/linux-arm64@0.17.6:
@@ -2611,7 +2606,6 @@ packages:
cpu: [arm64]
os: [linux]
requiresBuild: true
- dev: true
optional: true
/@esbuild/linux-arm@0.17.6:
@@ -2636,7 +2630,6 @@ packages:
cpu: [arm]
os: [linux]
requiresBuild: true
- dev: true
optional: true
/@esbuild/linux-ia32@0.17.6:
@@ -2661,7 +2654,6 @@ packages:
cpu: [ia32]
os: [linux]
requiresBuild: true
- dev: true
optional: true
/@esbuild/linux-loong64@0.17.6:
@@ -2686,7 +2678,6 @@ packages:
cpu: [loong64]
os: [linux]
requiresBuild: true
- dev: true
optional: true
/@esbuild/linux-mips64el@0.17.6:
@@ -2711,7 +2702,6 @@ packages:
cpu: [mips64el]
os: [linux]
requiresBuild: true
- dev: true
optional: true
/@esbuild/linux-ppc64@0.17.6:
@@ -2736,7 +2726,6 @@ packages:
cpu: [ppc64]
os: [linux]
requiresBuild: true
- dev: true
optional: true
/@esbuild/linux-riscv64@0.17.6:
@@ -2761,7 +2750,6 @@ packages:
cpu: [riscv64]
os: [linux]
requiresBuild: true
- dev: true
optional: true
/@esbuild/linux-s390x@0.17.6:
@@ -2786,7 +2774,6 @@ packages:
cpu: [s390x]
os: [linux]
requiresBuild: true
- dev: true
optional: true
/@esbuild/linux-x64@0.17.6:
@@ -2811,7 +2798,6 @@ packages:
cpu: [x64]
os: [linux]
requiresBuild: true
- dev: true
optional: true
/@esbuild/netbsd-x64@0.17.6:
@@ -2836,7 +2822,6 @@ packages:
cpu: [x64]
os: [netbsd]
requiresBuild: true
- dev: true
optional: true
/@esbuild/openbsd-x64@0.17.6:
@@ -2861,7 +2846,6 @@ packages:
cpu: [x64]
os: [openbsd]
requiresBuild: true
- dev: true
optional: true
/@esbuild/sunos-x64@0.17.6:
@@ -2886,7 +2870,6 @@ packages:
cpu: [x64]
os: [sunos]
requiresBuild: true
- dev: true
optional: true
/@esbuild/win32-arm64@0.17.6:
@@ -2911,7 +2894,6 @@ packages:
cpu: [arm64]
os: [win32]
requiresBuild: true
- dev: true
optional: true
/@esbuild/win32-ia32@0.17.6:
@@ -2936,7 +2918,6 @@ packages:
cpu: [ia32]
os: [win32]
requiresBuild: true
- dev: true
optional: true
/@esbuild/win32-x64@0.17.6:
@@ -2961,7 +2942,6 @@ packages:
cpu: [x64]
os: [win32]
requiresBuild: true
- dev: true
optional: true
/@eslint-community/eslint-utils@4.4.0(eslint@8.56.0):
@@ -3702,6 +3682,15 @@ packages:
resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==}
dev: true
+ /@lottiefiles/react-lottie-player@3.5.3(react@18.2.0):
+ resolution: {integrity: sha512-6pGbiTMjGnPddR1ur8M/TIDCiogZMc1aKIUbMEKXKAuNeYwZ2hvqwBJ+w5KRm88ccdcU88C2cGyLVsboFlSdVQ==}
+ peerDependencies:
+ react: 16 - 18
+ dependencies:
+ lottie-web: 5.12.2
+ react: 18.2.0
+ dev: false
+
/@lukeed/csprng@1.1.0:
resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==}
engines: {node: '>=8'}
@@ -4938,7 +4927,7 @@ packages:
dependencies:
'@babel/runtime': 7.23.5
- /@remix-run/dev@2.4.1(@remix-run/serve@2.4.1):
+ /@remix-run/dev@2.4.1(@remix-run/serve@2.4.1)(typescript@5.3.3)(vite@5.0.11):
resolution: {integrity: sha512-T8GLCKpZ8AX/NCJ+vyMmcTq328xo9stvDSXG2hSJx7njz4Q9sC25miQLXPRb3Lx/Sdf4YlJhWQpR6uq5pnXCZg==}
engines: {node: '>=18.0.0'}
hasBin: true
@@ -4964,10 +4953,10 @@ packages:
'@babel/types': 7.23.6
'@mdx-js/mdx': 2.3.0
'@npmcli/package-json': 4.0.1
- '@remix-run/node': 2.4.1
+ '@remix-run/node': 2.4.1(typescript@5.3.3)
'@remix-run/router': 1.14.1
- '@remix-run/serve': 2.4.1
- '@remix-run/server-runtime': 2.4.1
+ '@remix-run/serve': 2.4.1(typescript@5.3.3)
+ '@remix-run/server-runtime': 2.4.1(typescript@5.3.3)
'@types/mdx': 2.0.10
'@vanilla-extract/integration': 6.2.4
arg: 5.0.2
@@ -5007,6 +4996,8 @@ packages:
set-cookie-parser: 2.6.0
tar-fs: 2.1.1
tsconfig-paths: 4.2.0
+ typescript: 5.3.3
+ vite: 5.0.11
ws: 7.5.9
transitivePeerDependencies:
- '@types/node'
@@ -5022,7 +5013,7 @@ packages:
- ts-node
- utf-8-validate
- /@remix-run/express@2.4.1(express@4.18.2):
+ /@remix-run/express@2.4.1(express@4.18.2)(typescript@5.3.3):
resolution: {integrity: sha512-BTFfKrETeU3zn18YvaWs78i+vyvckG/BeR/A7hSYyJTaRfpw9r5OWq/wGM6jaObG7u4ut64lcY9adhvyV7BBeQ==}
engines: {node: '>=18.0.0'}
peerDependencies:
@@ -5032,10 +5023,11 @@ packages:
typescript:
optional: true
dependencies:
- '@remix-run/node': 2.4.1
+ '@remix-run/node': 2.4.1(typescript@5.3.3)
express: 4.18.2
+ typescript: 5.3.3
- /@remix-run/node@2.4.1:
+ /@remix-run/node@2.4.1(typescript@5.3.3):
resolution: {integrity: sha512-TENt5OiTnjZmoayqpEiU0207JIFF7TbagQ4UT0dFI9oKQrNQJvkDd2JQBEldd8TLDuSYxU8iu7+CXZ/kl3O35w==}
engines: {node: '>=18.0.0'}
peerDependencies:
@@ -5044,7 +5036,7 @@ packages:
typescript:
optional: true
dependencies:
- '@remix-run/server-runtime': 2.4.1
+ '@remix-run/server-runtime': 2.4.1(typescript@5.3.3)
'@remix-run/web-fetch': 4.4.2
'@remix-run/web-file': 3.1.0
'@remix-run/web-stream': 1.1.0
@@ -5052,8 +5044,9 @@ packages:
cookie-signature: 1.2.1
source-map-support: 0.5.21
stream-slice: 0.1.2
+ typescript: 5.3.3
- /@remix-run/react@2.4.1(react-dom@18.2.0)(react@18.2.0):
+ /@remix-run/react@2.4.1(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3):
resolution: {integrity: sha512-6qfLpijD96fKd276/MOtarf/SkFmWDKXTXzpMQzYTiRXofUDezRGG3VqbkopD1O+jl4BjTuKQvI+7YfLcfGx8w==}
engines: {node: '>=18.0.0'}
peerDependencies:
@@ -5065,24 +5058,25 @@ packages:
optional: true
dependencies:
'@remix-run/router': 1.14.1
- '@remix-run/server-runtime': 2.4.1
+ '@remix-run/server-runtime': 2.4.1(typescript@5.3.3)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
react-router: 6.21.1(react@18.2.0)
react-router-dom: 6.21.1(react-dom@18.2.0)(react@18.2.0)
+ typescript: 5.3.3
dev: false
/@remix-run/router@1.14.1:
resolution: {integrity: sha512-Qg4DMQsfPNAs88rb2xkdk03N3bjK4jgX5fR24eHCTR9q6PrhZQZ4UJBPzCHJkIpTRN1UKxx2DzjZmnC+7Lj0Ow==}
engines: {node: '>=14.0.0'}
- /@remix-run/serve@2.4.1:
+ /@remix-run/serve@2.4.1(typescript@5.3.3):
resolution: {integrity: sha512-GvIDkPjbMv6U8KJKyxhnTiwZpGXoO/IwJ9tN+b9RwTufMPL9Vi19p/uxptdeHDtCDXb4CRz+Id0izZD/CUrV2A==}
engines: {node: '>=18.0.0'}
hasBin: true
dependencies:
- '@remix-run/express': 2.4.1(express@4.18.2)
- '@remix-run/node': 2.4.1
+ '@remix-run/express': 2.4.1(express@4.18.2)(typescript@5.3.3)
+ '@remix-run/node': 2.4.1(typescript@5.3.3)
chokidar: 3.5.3
compression: 1.7.4
express: 4.18.2
@@ -5093,7 +5087,7 @@ packages:
- supports-color
- typescript
- /@remix-run/server-runtime@2.4.1:
+ /@remix-run/server-runtime@2.4.1(typescript@5.3.3):
resolution: {integrity: sha512-aQyBa0U8Db4E9sv2sruMfPDBYB4jlqvZ43YvkaZ1BGjUzi84ssfmaHdWgX/QveB6hi61RABTi6v8DV548kmRQg==}
engines: {node: '>=18.0.0'}
peerDependencies:
@@ -5108,13 +5102,14 @@ packages:
cookie: 0.5.0
set-cookie-parser: 2.6.0
source-map: 0.7.4
+ typescript: 5.3.3
/@remix-run/v1-route-convention@0.1.4(@remix-run/dev@2.4.1):
resolution: {integrity: sha512-fVTr9YlNLWfaiM/6Y56sOtcY8x1bBJQHY0sDWO5+Z/vjJ2Ni7fe2fwrzs1jUFciMPXqBQdFGePnkuiYLz3cuUA==}
peerDependencies:
'@remix-run/dev': ^1.15.0 || ^2.0.0
dependencies:
- '@remix-run/dev': 2.4.1(@remix-run/serve@2.4.1)
+ '@remix-run/dev': 2.4.1(@remix-run/serve@2.4.1)(typescript@5.3.3)(vite@5.0.11)
minimatch: 7.4.6
dev: false
@@ -5297,7 +5292,6 @@ packages:
cpu: [arm]
os: [android]
requiresBuild: true
- dev: true
optional: true
/@rollup/rollup-android-arm64@4.9.4:
@@ -5305,7 +5299,6 @@ packages:
cpu: [arm64]
os: [android]
requiresBuild: true
- dev: true
optional: true
/@rollup/rollup-darwin-arm64@4.9.4:
@@ -5313,7 +5306,6 @@ packages:
cpu: [arm64]
os: [darwin]
requiresBuild: true
- dev: true
optional: true
/@rollup/rollup-darwin-x64@4.9.4:
@@ -5321,7 +5313,6 @@ packages:
cpu: [x64]
os: [darwin]
requiresBuild: true
- dev: true
optional: true
/@rollup/rollup-linux-arm-gnueabihf@4.9.4:
@@ -5329,7 +5320,6 @@ packages:
cpu: [arm]
os: [linux]
requiresBuild: true
- dev: true
optional: true
/@rollup/rollup-linux-arm64-gnu@4.9.4:
@@ -5337,7 +5327,6 @@ packages:
cpu: [arm64]
os: [linux]
requiresBuild: true
- dev: true
optional: true
/@rollup/rollup-linux-arm64-musl@4.9.4:
@@ -5345,7 +5334,6 @@ packages:
cpu: [arm64]
os: [linux]
requiresBuild: true
- dev: true
optional: true
/@rollup/rollup-linux-riscv64-gnu@4.9.4:
@@ -5353,7 +5341,6 @@ packages:
cpu: [riscv64]
os: [linux]
requiresBuild: true
- dev: true
optional: true
/@rollup/rollup-linux-x64-gnu@4.9.4:
@@ -5361,7 +5348,6 @@ packages:
cpu: [x64]
os: [linux]
requiresBuild: true
- dev: true
optional: true
/@rollup/rollup-linux-x64-musl@4.9.4:
@@ -5369,7 +5355,6 @@ packages:
cpu: [x64]
os: [linux]
requiresBuild: true
- dev: true
optional: true
/@rollup/rollup-win32-arm64-msvc@4.9.4:
@@ -5377,7 +5362,6 @@ packages:
cpu: [arm64]
os: [win32]
requiresBuild: true
- dev: true
optional: true
/@rollup/rollup-win32-ia32-msvc@4.9.4:
@@ -5385,7 +5369,6 @@ packages:
cpu: [ia32]
os: [win32]
requiresBuild: true
- dev: true
optional: true
/@rollup/rollup-win32-x64-msvc@4.9.4:
@@ -5393,7 +5376,6 @@ packages:
cpu: [x64]
os: [win32]
requiresBuild: true
- dev: true
optional: true
/@segment/analytics-core@1.4.0:
@@ -5623,8 +5605,8 @@ packages:
'@remix-run/react': 1.x || 2.x
react: 16.x || 17.x || 18.x
dependencies:
- '@remix-run/node': 2.4.1
- '@remix-run/react': 2.4.1(react-dom@18.2.0)(react@18.2.0)
+ '@remix-run/node': 2.4.1(typescript@5.3.3)
+ '@remix-run/react': 2.4.1(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)
'@sentry/cli': 2.24.1
'@sentry/core': 7.92.0
'@sentry/node': 7.92.0
@@ -7474,6 +7456,7 @@ packages:
/@swagger-api/apidom-ns-json-schema-draft-4@0.91.0:
resolution: {integrity: sha512-oVxUVucnPSjcmUaYkTHAaqCGLbkgFEDWePGs+sqJj7WxhfJxLS+A8oFkvtXfTmfBel2ESQ7AFlReb/zhCpUfOg==}
+ requiresBuild: true
dependencies:
'@babel/runtime-corejs3': 7.23.7
'@swagger-api/apidom-ast': 0.91.0
@@ -7885,7 +7868,7 @@ packages:
pretty-format: 27.5.1
dev: true
- /@testing-library/jest-dom@6.2.0:
+ /@testing-library/jest-dom@6.2.0(vitest@1.1.3):
resolution: {integrity: sha512-+BVQlJ9cmEn5RDMUS8c2+TU6giLvzaHZ8sU/x0Jj7fk+6/46wPdwlgOPcpxS17CjcanBi/3VmGMqVr2rmbUmNw==}
engines: {node: '>=14', npm: '>=6', yarn: '>=1'}
peerDependencies:
@@ -7911,6 +7894,7 @@ packages:
dom-accessibility-api: 0.6.3
lodash: 4.17.21
redent: 3.0.0
+ vitest: 1.1.3(@vitest/ui@1.1.3)
dev: true
/@testing-library/react@14.1.2(react-dom@18.2.0)(react@18.2.0):
@@ -10489,7 +10473,6 @@ packages:
'@esbuild/win32-arm64': 0.19.11
'@esbuild/win32-ia32': 0.19.11
'@esbuild/win32-x64': 0.19.11
- dev: true
/escalade@3.1.1:
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
@@ -12767,6 +12750,10 @@ packages:
dependencies:
js-tokens: 4.0.0
+ /lottie-web@5.12.2:
+ resolution: {integrity: sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==}
+ dev: false
+
/loupe@2.3.7:
resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==}
dependencies:
@@ -15270,7 +15257,7 @@ packages:
peerDependencies:
'@remix-run/dev': ^1.15.0 || ^2
dependencies:
- '@remix-run/dev': 2.4.1(@remix-run/serve@2.4.1)
+ '@remix-run/dev': 2.4.1(@remix-run/serve@2.4.1)(typescript@5.3.3)(vite@5.0.11)
'@remix-run/v1-route-convention': 0.1.4(@remix-run/dev@2.4.1)
fs-extra: 11.2.0
minimatch: 5.1.6
@@ -15285,8 +15272,8 @@ packages:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-i18next: ^13.0.0 || ^14.0.0
dependencies:
- '@remix-run/react': 2.4.1(react-dom@18.2.0)(react@18.2.0)
- '@remix-run/server-runtime': 2.4.1
+ '@remix-run/react': 2.4.1(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)
+ '@remix-run/server-runtime': 2.4.1(typescript@5.3.3)
accept-language-parser: 1.5.0
i18next: 23.7.16
intl-parse-accept-language: 1.0.0
@@ -15332,8 +15319,8 @@ packages:
zod:
optional: true
dependencies:
- '@remix-run/node': 2.4.1
- '@remix-run/react': 2.4.1(react-dom@18.2.0)(react@18.2.0)
+ '@remix-run/node': 2.4.1(typescript@5.3.3)
+ '@remix-run/react': 2.4.1(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)
crypto-js: 4.2.0
react: 18.2.0
type-fest: 4.9.0
@@ -15500,7 +15487,6 @@ packages:
'@rollup/rollup-win32-ia32-msvc': 4.9.4
'@rollup/rollup-win32-x64-msvc': 4.9.4
fsevents: 2.3.3
- dev: true
/rrweb-cssom@0.6.0:
resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
@@ -17239,7 +17225,6 @@ packages:
rollup: 4.9.4
optionalDependencies:
fsevents: 2.3.3
- dev: true
/vitest@1.1.3(@vitest/ui@1.1.3):
resolution: {integrity: sha512-2l8om1NOkiA90/Y207PsEvJLYygddsOyr81wLQ20Ra8IlLKbyQncWsGZjnbkyG2KwwuTXLQjEPOJuxGMG8qJBQ==}