diff --git a/apps/app/src/app/login/page.tsx b/apps/app/src/app/login/page.tsx
index 975af2f8a..2149dee5b 100644
--- a/apps/app/src/app/login/page.tsx
+++ b/apps/app/src/app/login/page.tsx
@@ -2,32 +2,42 @@
import { isSafeRedirectPath } from '@op/common/client';
import { useAuthUser } from '@op/hooks';
-import { redirect, useSearchParams } from 'next/navigation';
+import { useRouter, useSearchParams } from 'next/navigation';
+import { useEffect } from 'react';
import { LoginPanel } from '@/components/LoginPanel';
-const LoginPageWithLayout = () => {
- return ;
-};
-
const LoginPage = () => {
const user = useAuthUser();
+ const router = useRouter();
const searchParams = useSearchParams();
const redirectParam = searchParams.get('redirect');
+ useEffect(() => {
+ if (!user || user.isFetching || user.isPending) {
+ return;
+ }
+
+ if (user.isFetchedAfterMount && !user.data?.user) {
+ return;
+ }
+
+ if (isSafeRedirectPath(redirectParam)) {
+ router.replace(redirectParam);
+ } else {
+ router.replace('/');
+ }
+ }, [user, redirectParam, router]);
+
if (!user || user.isFetching || user.isPending) {
return null;
}
if (user.isFetchedAfterMount && !user.isFetching && !user.data?.user) {
- return ;
- }
-
- if (isSafeRedirectPath(redirectParam)) {
- redirect(redirectParam);
+ return ;
}
- redirect('/');
+ return null;
};
export default LoginPage;
diff --git a/services/api/src/routers/decision/instances/getCategories.test.ts b/services/api/src/routers/decision/instances/getCategories.test.ts
index 0de1c8c35..ea50a2fdb 100644
--- a/services/api/src/routers/decision/instances/getCategories.test.ts
+++ b/services/api/src/routers/decision/instances/getCategories.test.ts
@@ -6,7 +6,7 @@ import {
taxonomyTerms,
} from '@op/db/schema';
import { randomUUID } from 'node:crypto';
-import { describe, expect, it } from 'vitest';
+import { afterAll, describe, expect, it } from 'vitest';
import { appRouter } from '../..';
import { TestDecisionsDataManager } from '../../../test/helpers/TestDecisionsDataManager';
@@ -42,11 +42,9 @@ async function seedProposalTaxonomy(
.returning({ id: taxonomies.id });
let resolvedTaxonomyId: string;
- let ownsTheTaxonomy = false;
if (inserted) {
resolvedTaxonomyId = inserted.id;
- ownsTheTaxonomy = true;
} else {
// Another test created it — look up the existing one
const [existing] = await db
@@ -82,10 +80,6 @@ async function seedProposalTaxonomy(
),
);
}
- // Only delete taxonomy if this test created it
- if (ownsTheTaxonomy) {
- await db.delete(taxonomies).where(eq(taxonomies.id, resolvedTaxonomyId));
- }
});
return { taxonomyId: resolvedTaxonomyId, termRecords };
@@ -278,6 +272,10 @@ describe.concurrent('getCategories permissions', () => {
});
describe.concurrent('getCategories category matching', () => {
+ afterAll(async () => {
+ await db.delete(taxonomies).where(eq(taxonomies.name, 'proposal'));
+ });
+
it('should return matched categories when config.categories and taxonomy terms exist', async ({
task,
onTestFinished,