diff --git a/src/frontend/apps/impress/src/features/auth/__tests__/UserReconciliation.test.tsx b/src/frontend/apps/impress/src/features/auth/__tests__/UserReconciliation.test.tsx
new file mode 100644
index 00000000..4f2d3959
--- /dev/null
+++ b/src/frontend/apps/impress/src/features/auth/__tests__/UserReconciliation.test.tsx
@@ -0,0 +1,62 @@
+import { render, screen, waitFor } from '@testing-library/react';
+import fetchMock from 'fetch-mock';
+import React from 'react';
+import { describe, expect, test } from 'vitest';
+
+import { AppWrapper } from '@/tests/utils';
+
+import { UserReconciliation } from '../components/UserReconciliation';
+
+describe('UserReconciliation', () => {
+ beforeEach(() => {
+ fetchMock.reset();
+ });
+
+ ['active', 'inactive'].forEach((type) => {
+ test(`renders when reconciliation is a ${type} success`, async () => {
+ fetchMock.get(
+ `http://test.jest/api/v1.0/user_reconciliations/${type}/123456/`,
+ { details: 'Success' },
+ );
+
+ render(
+ ,
+ {
+ wrapper: AppWrapper,
+ },
+ );
+
+ await waitFor(() => {
+ expect(fetchMock.calls().length).toBe(1);
+ });
+
+ expect(
+ await screen.findByText(/Email validated successfully !/i),
+ ).toBeInTheDocument();
+ });
+ });
+
+ test('renders when reconciliation fails', async () => {
+ fetchMock.get(
+ `http://test.jest/api/v1.0/user_reconciliations/active/invalid-id/`,
+ {
+ throws: new Error('invalid id'),
+ },
+ );
+
+ render(, {
+ wrapper: AppWrapper,
+ });
+
+ await waitFor(() => {
+ expect(fetchMock.calls().length).toBe(1);
+ });
+
+ expect(
+ await screen.findByText(/An error occurred during email validation./i),
+ ).toBeInTheDocument();
+ });
+});
diff --git a/src/frontend/apps/impress/src/features/auth/api/index.ts b/src/frontend/apps/impress/src/features/auth/api/index.ts
index ce8db5d4..a07760a0 100644
--- a/src/frontend/apps/impress/src/features/auth/api/index.ts
+++ b/src/frontend/apps/impress/src/features/auth/api/index.ts
@@ -1,2 +1,3 @@
export * from './useAuthQuery';
+export * from './useUserReconciliations';
export * from './types';
diff --git a/src/frontend/apps/impress/src/features/auth/api/useUserReconciliations.tsx b/src/frontend/apps/impress/src/features/auth/api/useUserReconciliations.tsx
new file mode 100644
index 00000000..9185563d
--- /dev/null
+++ b/src/frontend/apps/impress/src/features/auth/api/useUserReconciliations.tsx
@@ -0,0 +1,51 @@
+import { UseQueryOptions, useQuery } from '@tanstack/react-query';
+
+import { APIError, errorCauses, fetchAPI } from '@/api';
+
+type UserReconciliationResponse = {
+ details: string;
+};
+
+interface UserReconciliationProps {
+ type: 'active' | 'inactive';
+ reconciliationId?: string;
+}
+
+export const userReconciliations = async ({
+ type,
+ reconciliationId,
+}: UserReconciliationProps): Promise => {
+ const response = await fetchAPI(
+ `user_reconciliations/${type}/${reconciliationId}/`,
+ );
+
+ if (!response.ok) {
+ throw new APIError(
+ 'Failed to do the user reconciliation',
+ await errorCauses(response),
+ );
+ }
+
+ return response.json() as Promise;
+};
+
+export const KEY_USER_RECONCILIATIONS = 'user_reconciliations';
+
+export function useUserReconciliationsQuery(
+ param: UserReconciliationProps,
+ queryConfig?: UseQueryOptions<
+ UserReconciliationResponse,
+ APIError,
+ UserReconciliationResponse
+ >,
+) {
+ return useQuery<
+ UserReconciliationResponse,
+ APIError,
+ UserReconciliationResponse
+ >({
+ queryKey: [KEY_USER_RECONCILIATIONS, param],
+ queryFn: () => userReconciliations(param),
+ ...queryConfig,
+ });
+}
diff --git a/src/frontend/apps/impress/src/features/auth/assets/rocket.gif b/src/frontend/apps/impress/src/features/auth/assets/rocket.gif
new file mode 100644
index 00000000..d0f18326
Binary files /dev/null and b/src/frontend/apps/impress/src/features/auth/assets/rocket.gif differ
diff --git a/src/frontend/apps/impress/src/features/auth/components/UserReconciliation.tsx b/src/frontend/apps/impress/src/features/auth/components/UserReconciliation.tsx
new file mode 100644
index 00000000..40a1e5e1
--- /dev/null
+++ b/src/frontend/apps/impress/src/features/auth/components/UserReconciliation.tsx
@@ -0,0 +1,104 @@
+import { Button } from '@gouvfr-lasuite/cunningham-react';
+import Image from 'next/image';
+import { useTranslation } from 'react-i18next';
+import styled from 'styled-components';
+
+import error_img from '@/assets/icons/error-planetes.png';
+import { Box, Icon, Loading, StyledLink, Text } from '@/components';
+
+import { useUserReconciliationsQuery } from '../api';
+import success_gif from '../assets/rocket.gif';
+
+const StyledButton = styled(Button)`
+ width: fit-content;
+`;
+
+interface UserReconciliationProps {
+ type: 'active' | 'inactive';
+ reconciliationId: string;
+}
+
+export const UserReconciliation = ({
+ type,
+ reconciliationId,
+}: UserReconciliationProps) => {
+ const { t } = useTranslation();
+ const { data: userReconciliations, isError } = useUserReconciliationsQuery({
+ type,
+ reconciliationId,
+ });
+
+ if (!userReconciliations && !isError) {
+ return (
+
+ );
+ }
+
+ let render = (
+ <>
+
+
+ {t('Email validated successfully !')}
+
+ >
+ );
+
+ if (isError) {
+ render = (
+ <>
+
+
+ {t('An error occurred during email validation.')}
+
+ >
+ );
+ }
+
+ return (
+
+ {render}
+
+
+
+
+ }
+ >
+ {t('Home')}
+
+
+
+
+ );
+};
diff --git a/src/frontend/apps/impress/src/features/auth/components/index.ts b/src/frontend/apps/impress/src/features/auth/components/index.ts
index 26ebaf2e..0a91bf37 100644
--- a/src/frontend/apps/impress/src/features/auth/components/index.ts
+++ b/src/frontend/apps/impress/src/features/auth/components/index.ts
@@ -1,3 +1,4 @@
export * from './Auth';
export * from './ButtonLogin';
export * from './UserAvatar';
+export * from './UserReconciliation';
diff --git a/src/frontend/apps/impress/src/pages/user_reconciliations/active/[id]/index.tsx b/src/frontend/apps/impress/src/pages/user_reconciliations/active/[id]/index.tsx
new file mode 100644
index 00000000..7fa8c27a
--- /dev/null
+++ b/src/frontend/apps/impress/src/pages/user_reconciliations/active/[id]/index.tsx
@@ -0,0 +1,40 @@
+import Head from 'next/head';
+import { useRouter } from 'next/router';
+import { ReactElement } from 'react';
+import { useTranslation } from 'react-i18next';
+
+import { UserReconciliation } from '@/features/auth/components/UserReconciliation';
+import { PageLayout } from '@/layouts';
+import { NextPageWithLayout } from '@/types/next';
+
+const Page: NextPageWithLayout = () => {
+ const { t } = useTranslation();
+ const {
+ query: { id },
+ } = useRouter();
+
+ if (typeof id !== 'string') {
+ return null;
+ }
+
+ return (
+ <>
+
+
+ {`${t('User reconciliation')} - ${t('Docs')}`}
+
+
+
+ >
+ );
+};
+
+Page.getLayout = function getLayout(page: ReactElement) {
+ return {page};
+};
+
+export default Page;
diff --git a/src/frontend/apps/impress/src/pages/user_reconciliations/inactive/[id]/index.tsx b/src/frontend/apps/impress/src/pages/user_reconciliations/inactive/[id]/index.tsx
new file mode 100644
index 00000000..c10cbb38
--- /dev/null
+++ b/src/frontend/apps/impress/src/pages/user_reconciliations/inactive/[id]/index.tsx
@@ -0,0 +1,40 @@
+import Head from 'next/head';
+import { useRouter } from 'next/router';
+import { ReactElement } from 'react';
+import { useTranslation } from 'react-i18next';
+
+import { UserReconciliation } from '@/features/auth/components/UserReconciliation';
+import { PageLayout } from '@/layouts';
+import { NextPageWithLayout } from '@/types/next';
+
+const Page: NextPageWithLayout = () => {
+ const { t } = useTranslation();
+ const {
+ query: { id },
+ } = useRouter();
+
+ if (typeof id !== 'string') {
+ return null;
+ }
+
+ return (
+ <>
+
+
+ {`${t('User reconciliation')} - ${t('Docs')}`}
+
+
+
+ >
+ );
+};
+
+Page.getLayout = function getLayout(page: ReactElement) {
+ return {page};
+};
+
+export default Page;
diff --git a/src/frontend/apps/impress/vitest.setup.ts b/src/frontend/apps/impress/vitest.setup.ts
index de0945cf..6e449e8b 100644
--- a/src/frontend/apps/impress/vitest.setup.ts
+++ b/src/frontend/apps/impress/vitest.setup.ts
@@ -1,4 +1,23 @@
import '@testing-library/jest-dom/vitest';
import * as dotenv from 'dotenv';
+import React from 'react';
+import { vi } from 'vitest';
dotenv.config({ path: './.env.test', quiet: true });
+
+vi.mock('next/image', () => ({
+ __esModule: true,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ default: (props: any) => {
+ const {
+ src,
+ alt = '',
+ unoptimized: _unoptimized,
+ priority: _priority,
+ ...rest
+ } = props;
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
+ const resolved = typeof src === 'string' ? src : src?.src;
+ return React.createElement('img', { src: resolved, alt, ...rest });
+ },
+}));