From 772426fc72c5f110021646872a1d48f5f5113aec Mon Sep 17 00:00:00 2001 From: Andriamanampisoa Date: Wed, 15 Jul 2026 19:21:56 +0200 Subject: [PATCH 1/2] feat: add privacy page --- .../organisms/landing-footer/index.spec.tsx | 6 + .../organisms/landing-footer/index.tsx | 2 +- web/src/config/routes.config.ts | 1 + web/src/routeTree.gen.ts | 21 +++ web/src/routes/__root.tsx | 1 + web/src/routes/privacy.tsx | 174 ++++++++++++++++++ 6 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 web/src/routes/privacy.tsx diff --git a/web/src/components/organisms/landing-footer/index.spec.tsx b/web/src/components/organisms/landing-footer/index.spec.tsx index f119e43a..c43eeef2 100644 --- a/web/src/components/organisms/landing-footer/index.spec.tsx +++ b/web/src/components/organisms/landing-footer/index.spec.tsx @@ -27,6 +27,12 @@ describe('LandingFooter', () => { expect(screen.getByText('Legal')).toBeInTheDocument(); }); + it('renders internal /privacy link via router Link', () => { + render(); + const privacy = screen.getByRole('link', { name: 'Privacy' }); + expect(privacy).toHaveAttribute('href', '/privacy'); + }); + it('renders internal /about link via router Link', () => { render(); const about = screen.getByRole('link', { name: 'About' }); diff --git a/web/src/components/organisms/landing-footer/index.tsx b/web/src/components/organisms/landing-footer/index.tsx index 5eca0c18..8dcf1dc4 100644 --- a/web/src/components/organisms/landing-footer/index.tsx +++ b/web/src/components/organisms/landing-footer/index.tsx @@ -27,7 +27,7 @@ const COLUMNS: { title: 'Legal', items: [ { label: 'Terms', href: '#' }, - { label: 'Privacy', href: '#' }, + { label: 'Privacy', href: '/privacy' }, { label: 'Cookies', href: '#' }, ], }, diff --git a/web/src/config/routes.config.ts b/web/src/config/routes.config.ts index cb08f990..e5533cb8 100644 --- a/web/src/config/routes.config.ts +++ b/web/src/config/routes.config.ts @@ -13,6 +13,7 @@ export const routeConfigs: RouteConfig[] = [ { path: '/forgot-password', requiresAuth: false }, { path: '/reset-password', requiresAuth: false }, { path: '/about', requiresAuth: false }, + { path: '/privacy', requiresAuth: false }, { path: '/register-organization', requiresAuth: false }, // Protected routes - Main pages diff --git a/web/src/routeTree.gen.ts b/web/src/routeTree.gen.ts index 4e64df85..17197751 100644 --- a/web/src/routeTree.gen.ts +++ b/web/src/routeTree.gen.ts @@ -16,6 +16,7 @@ import { Route as RegisterOrganizationRouteImport } from './routes/register-orga import { Route as RegisterRouteImport } from './routes/register' import { Route as ProgressionRouteImport } from './routes/progression' import { Route as ProfileRouteImport } from './routes/profile' +import { Route as PrivacyRouteImport } from './routes/privacy' import { Route as LoginRouteImport } from './routes/login' import { Route as ForgotPasswordRouteImport } from './routes/forgot-password' import { Route as DiaryRouteImport } from './routes/diary' @@ -76,6 +77,11 @@ const ProfileRoute = ProfileRouteImport.update({ path: '/profile', getParentRoute: () => rootRouteImport, } as any) +const PrivacyRoute = PrivacyRouteImport.update({ + id: '/privacy', + path: '/privacy', + getParentRoute: () => rootRouteImport, +} as any) const LoginRoute = LoginRouteImport.update({ id: '/login', path: '/login', @@ -210,6 +216,7 @@ export interface FileRoutesByFullPath { '/diary': typeof DiaryRoute '/forgot-password': typeof ForgotPasswordRoute '/login': typeof LoginRoute + '/privacy': typeof PrivacyRoute '/profile': typeof ProfileRoute '/progression': typeof ProgressionRoute '/register': typeof RegisterRoute @@ -243,6 +250,7 @@ export interface FileRoutesByTo { '/diary': typeof DiaryRoute '/forgot-password': typeof ForgotPasswordRoute '/login': typeof LoginRoute + '/privacy': typeof PrivacyRoute '/profile': typeof ProfileRoute '/progression': typeof ProgressionRoute '/register': typeof RegisterRoute @@ -277,6 +285,7 @@ export interface FileRoutesById { '/diary': typeof DiaryRoute '/forgot-password': typeof ForgotPasswordRoute '/login': typeof LoginRoute + '/privacy': typeof PrivacyRoute '/profile': typeof ProfileRoute '/progression': typeof ProgressionRoute '/register': typeof RegisterRoute @@ -312,6 +321,7 @@ export interface FileRouteTypes { | '/diary' | '/forgot-password' | '/login' + | '/privacy' | '/profile' | '/progression' | '/register' @@ -345,6 +355,7 @@ export interface FileRouteTypes { | '/diary' | '/forgot-password' | '/login' + | '/privacy' | '/profile' | '/progression' | '/register' @@ -378,6 +389,7 @@ export interface FileRouteTypes { | '/diary' | '/forgot-password' | '/login' + | '/privacy' | '/profile' | '/progression' | '/register' @@ -412,6 +424,7 @@ export interface RootRouteChildren { DiaryRoute: typeof DiaryRoute ForgotPasswordRoute: typeof ForgotPasswordRoute LoginRoute: typeof LoginRoute + PrivacyRoute: typeof PrivacyRoute ProfileRoute: typeof ProfileRoute ProgressionRoute: typeof ProgressionRoute RegisterRoute: typeof RegisterRoute @@ -488,6 +501,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof ProfileRouteImport parentRoute: typeof rootRouteImport } + '/privacy': { + id: '/privacy' + path: '/privacy' + fullPath: '/privacy' + preLoaderRoute: typeof PrivacyRouteImport + parentRoute: typeof rootRouteImport + } '/login': { id: '/login' path: '/login' @@ -668,6 +688,7 @@ const rootRouteChildren: RootRouteChildren = { DiaryRoute: DiaryRoute, ForgotPasswordRoute: ForgotPasswordRoute, LoginRoute: LoginRoute, + PrivacyRoute: PrivacyRoute, ProfileRoute: ProfileRoute, ProgressionRoute: ProgressionRoute, RegisterRoute: RegisterRoute, diff --git a/web/src/routes/__root.tsx b/web/src/routes/__root.tsx index 3399e736..1fb388b1 100644 --- a/web/src/routes/__root.tsx +++ b/web/src/routes/__root.tsx @@ -12,6 +12,7 @@ import { useState } from 'react'; const PUBLIC_SHELL_PATHS = new Set([ '/', + '/privacy', '/login', '/register', '/register-organization', diff --git a/web/src/routes/privacy.tsx b/web/src/routes/privacy.tsx new file mode 100644 index 00000000..9c07b7c6 --- /dev/null +++ b/web/src/routes/privacy.tsx @@ -0,0 +1,174 @@ +import LandingFooter from '@/components/organisms/landing-footer'; +import LandingNav from '@/components/organisms/landing-nav'; +import { createFileRoute } from '@tanstack/react-router'; + +export const Route = createFileRoute('/privacy')({ + component: PrivacyPage, +}); + +const LAST_UPDATED = 'July 15, 2026'; + +interface LegalSection { + title: string; + paragraphs: string[]; + list?: string[]; +} + +const SECTIONS: LegalSection[] = [ + { + title: '1. Introduction', + paragraphs: [ + 'TalkUp.AI ("TalkUp", "we", "us") helps candidates prepare for interviews through AI-powered simulations, CV analysis, coaching tools, and related career features.', + 'This Privacy Policy explains what personal data we collect, why we use it, how long we keep it, and what rights you have. By creating an account or using TalkUp, you acknowledge that you have read this policy.', + ], + }, + { + title: '2. Data controller', + paragraphs: [ + 'TalkUp.AI is the data controller for the personal data processed through our platform.', + 'For privacy-related requests, contact us at contact@talkup.ai. We are based in Paris, France.', + ], + }, + { + title: '3. Personal data we collect', + paragraphs: ['Depending on how you use TalkUp, we may process the following categories of data:'], + list: [ + 'Account information: name, email address, password hash, and profile details you choose to provide.', + 'Career data: CV or résumé files, parsed CV content, job applications, target roles, notes, and interview preparation history.', + 'Simulation data: audio, video, transcripts, and behavioral feedback generated during mock interviews.', + 'Usage data: pages visited, features used, device and browser information, and approximate log timestamps.', + 'Communication data: messages you send to our support team or through in-app coaching features.', + ], + }, + { + title: '4. How we use your data', + paragraphs: ['We use personal data to:'], + list: [ + 'Create and manage your account.', + 'Analyze your CV against job offers and generate compatibility insights.', + 'Run interview simulations and provide personalized feedback.', + 'Save your notes, applications, agenda items, and progression over time.', + 'Improve product reliability, security, and user experience.', + 'Respond to support requests and send essential service communications.', + 'Comply with legal obligations and enforce our terms.', + ], + }, + { + title: '5. Legal basis for processing', + paragraphs: [ + 'Where applicable under the GDPR, we rely on one or more of the following legal bases:', + ], + list: [ + 'Performance of a contract — to provide the TalkUp services you sign up for.', + 'Consent — for example, when you upload a CV for analysis or enable optional features.', + 'Legitimate interests — to secure our platform, prevent abuse, and improve our product, balanced against your rights.', + 'Legal obligation — when we must retain or disclose data to comply with applicable law.', + ], + }, + { + title: '6. AI processing', + paragraphs: [ + 'TalkUp uses artificial intelligence to parse CVs, extract job-offer details, generate interview questions, analyze responses, and produce coaching feedback.', + 'Your content may be processed by automated systems to deliver these features. We do not use your personal data to train public third-party models unless we explicitly tell you otherwise and obtain your consent where required.', + ], + }, + { + title: '7. Sharing and subprocessors', + paragraphs: [ + 'We do not sell your personal data. We may share data with trusted service providers that help us host the platform, send emails, process AI workloads, or provide analytics — only under contracts that require appropriate safeguards.', + 'We may also disclose data if required by law, to protect the rights and safety of TalkUp and its users, or in connection with a merger, acquisition, or asset sale subject to continued protection of your information.', + ], + }, + { + title: '8. Data retention', + paragraphs: [ + 'We keep personal data only for as long as necessary to provide the service, meet legal requirements, or resolve disputes.', + 'You may delete your account at any time. When you do, we delete or anonymize your personal data within a reasonable period, except where retention is required by law or for legitimate backup and security purposes.', + ], + }, + { + title: '9. Your rights', + paragraphs: [ + 'Depending on your location, you may have the right to access, rectify, erase, restrict, or object to certain processing of your personal data, as well as the right to data portability.', + 'You can update much of your information directly in your account settings. To exercise other rights, email contact@talkup.ai. You may also lodge a complaint with your local supervisory authority.', + ], + }, + { + title: '10. Security', + paragraphs: [ + 'We implement technical and organizational measures designed to protect personal data against unauthorized access, loss, or misuse. No online service can guarantee absolute security, but we work continuously to reduce risk.', + ], + }, + { + title: '11. Cookies and similar technologies', + paragraphs: [ + 'TalkUp uses cookies and similar technologies to keep you signed in, remember preferences, and understand how the product is used.', + 'For more detail on the cookies we use and how to manage them, see our Cookies policy (coming soon).', + ], + }, + { + title: '12. International transfers', + paragraphs: [ + 'Your data may be processed in the European Economic Area and, where necessary, in other countries with appropriate safeguards such as standard contractual clauses or equivalent mechanisms.', + ], + }, + { + title: '13. Changes to this policy', + paragraphs: [ + 'We may update this Privacy Policy from time to time. When we make material changes, we will post the updated version on this page and adjust the "Last updated" date. Continued use of TalkUp after an update means you accept the revised policy.', + ], + }, + { + title: '14. Contact', + paragraphs: [ + 'Questions about this Privacy Policy or your personal data? Email us at contact@talkup.ai.', + ], + }, +]; + +function PrivacyPage() { + return ( +
+ +
+
+
+

+ Legal +

+

Privacy Policy

+

+ Last updated: {LAST_UPDATED} +

+
+ +
+ {SECTIONS.map((section) => ( +
+

{section.title}

+
+ {section.paragraphs.map((paragraph) => ( +

+ {paragraph} +

+ ))} + {section.list && ( +
    + {section.list.map((item) => ( +
  • {item}
  • + ))} +
+ )} +
+
+ ))} +
+
+
+ +
+ ); +} From 3e38fcd10ec8c0bfd310701bc2e320649660ace4 Mon Sep 17 00:00:00 2001 From: Andriamanampisoa Date: Wed, 15 Jul 2026 19:42:02 +0200 Subject: [PATCH 2/2] refactor: code quality --- web/src/routes/privacy.tsx | 350 +++++++++++++++++++------------------ 1 file changed, 176 insertions(+), 174 deletions(-) diff --git a/web/src/routes/privacy.tsx b/web/src/routes/privacy.tsx index 9c07b7c6..b3d235cf 100644 --- a/web/src/routes/privacy.tsx +++ b/web/src/routes/privacy.tsx @@ -1,174 +1,176 @@ -import LandingFooter from '@/components/organisms/landing-footer'; -import LandingNav from '@/components/organisms/landing-nav'; -import { createFileRoute } from '@tanstack/react-router'; - -export const Route = createFileRoute('/privacy')({ - component: PrivacyPage, -}); - -const LAST_UPDATED = 'July 15, 2026'; - -interface LegalSection { - title: string; - paragraphs: string[]; - list?: string[]; -} - -const SECTIONS: LegalSection[] = [ - { - title: '1. Introduction', - paragraphs: [ - 'TalkUp.AI ("TalkUp", "we", "us") helps candidates prepare for interviews through AI-powered simulations, CV analysis, coaching tools, and related career features.', - 'This Privacy Policy explains what personal data we collect, why we use it, how long we keep it, and what rights you have. By creating an account or using TalkUp, you acknowledge that you have read this policy.', - ], - }, - { - title: '2. Data controller', - paragraphs: [ - 'TalkUp.AI is the data controller for the personal data processed through our platform.', - 'For privacy-related requests, contact us at contact@talkup.ai. We are based in Paris, France.', - ], - }, - { - title: '3. Personal data we collect', - paragraphs: ['Depending on how you use TalkUp, we may process the following categories of data:'], - list: [ - 'Account information: name, email address, password hash, and profile details you choose to provide.', - 'Career data: CV or résumé files, parsed CV content, job applications, target roles, notes, and interview preparation history.', - 'Simulation data: audio, video, transcripts, and behavioral feedback generated during mock interviews.', - 'Usage data: pages visited, features used, device and browser information, and approximate log timestamps.', - 'Communication data: messages you send to our support team or through in-app coaching features.', - ], - }, - { - title: '4. How we use your data', - paragraphs: ['We use personal data to:'], - list: [ - 'Create and manage your account.', - 'Analyze your CV against job offers and generate compatibility insights.', - 'Run interview simulations and provide personalized feedback.', - 'Save your notes, applications, agenda items, and progression over time.', - 'Improve product reliability, security, and user experience.', - 'Respond to support requests and send essential service communications.', - 'Comply with legal obligations and enforce our terms.', - ], - }, - { - title: '5. Legal basis for processing', - paragraphs: [ - 'Where applicable under the GDPR, we rely on one or more of the following legal bases:', - ], - list: [ - 'Performance of a contract — to provide the TalkUp services you sign up for.', - 'Consent — for example, when you upload a CV for analysis or enable optional features.', - 'Legitimate interests — to secure our platform, prevent abuse, and improve our product, balanced against your rights.', - 'Legal obligation — when we must retain or disclose data to comply with applicable law.', - ], - }, - { - title: '6. AI processing', - paragraphs: [ - 'TalkUp uses artificial intelligence to parse CVs, extract job-offer details, generate interview questions, analyze responses, and produce coaching feedback.', - 'Your content may be processed by automated systems to deliver these features. We do not use your personal data to train public third-party models unless we explicitly tell you otherwise and obtain your consent where required.', - ], - }, - { - title: '7. Sharing and subprocessors', - paragraphs: [ - 'We do not sell your personal data. We may share data with trusted service providers that help us host the platform, send emails, process AI workloads, or provide analytics — only under contracts that require appropriate safeguards.', - 'We may also disclose data if required by law, to protect the rights and safety of TalkUp and its users, or in connection with a merger, acquisition, or asset sale subject to continued protection of your information.', - ], - }, - { - title: '8. Data retention', - paragraphs: [ - 'We keep personal data only for as long as necessary to provide the service, meet legal requirements, or resolve disputes.', - 'You may delete your account at any time. When you do, we delete or anonymize your personal data within a reasonable period, except where retention is required by law or for legitimate backup and security purposes.', - ], - }, - { - title: '9. Your rights', - paragraphs: [ - 'Depending on your location, you may have the right to access, rectify, erase, restrict, or object to certain processing of your personal data, as well as the right to data portability.', - 'You can update much of your information directly in your account settings. To exercise other rights, email contact@talkup.ai. You may also lodge a complaint with your local supervisory authority.', - ], - }, - { - title: '10. Security', - paragraphs: [ - 'We implement technical and organizational measures designed to protect personal data against unauthorized access, loss, or misuse. No online service can guarantee absolute security, but we work continuously to reduce risk.', - ], - }, - { - title: '11. Cookies and similar technologies', - paragraphs: [ - 'TalkUp uses cookies and similar technologies to keep you signed in, remember preferences, and understand how the product is used.', - 'For more detail on the cookies we use and how to manage them, see our Cookies policy (coming soon).', - ], - }, - { - title: '12. International transfers', - paragraphs: [ - 'Your data may be processed in the European Economic Area and, where necessary, in other countries with appropriate safeguards such as standard contractual clauses or equivalent mechanisms.', - ], - }, - { - title: '13. Changes to this policy', - paragraphs: [ - 'We may update this Privacy Policy from time to time. When we make material changes, we will post the updated version on this page and adjust the "Last updated" date. Continued use of TalkUp after an update means you accept the revised policy.', - ], - }, - { - title: '14. Contact', - paragraphs: [ - 'Questions about this Privacy Policy or your personal data? Email us at contact@talkup.ai.', - ], - }, -]; - -function PrivacyPage() { - return ( -
- -
-
-
-

- Legal -

-

Privacy Policy

-

- Last updated: {LAST_UPDATED} -

-
- -
- {SECTIONS.map((section) => ( -
-

{section.title}

-
- {section.paragraphs.map((paragraph) => ( -

- {paragraph} -

- ))} - {section.list && ( -
    - {section.list.map((item) => ( -
  • {item}
  • - ))} -
- )} -
-
- ))} -
-
-
- -
- ); -} +import LandingFooter from '@/components/organisms/landing-footer'; +import LandingNav from '@/components/organisms/landing-nav'; +import { createFileRoute } from '@tanstack/react-router'; + +export const Route = createFileRoute('/privacy')({ + component: PrivacyPage, +}); + +const LAST_UPDATED = 'July 15, 2026'; + +interface LegalSection { + title: string; + paragraphs: string[]; + list?: string[]; +} + +const SECTIONS: LegalSection[] = [ + { + title: '1. Introduction', + paragraphs: [ + 'TalkUp.AI ("TalkUp", "we", "us") helps candidates prepare for interviews through AI-powered simulations, CV analysis, coaching tools, and related career features.', + 'This Privacy Policy explains what personal data we collect, why we use it, how long we keep it, and what rights you have. By creating an account or using TalkUp, you acknowledge that you have read this policy.', + ], + }, + { + title: '2. Data controller', + paragraphs: [ + 'TalkUp.AI is the data controller for the personal data processed through our platform.', + 'For privacy-related requests, contact us at contact@talkup.ai. We are based in Paris, France.', + ], + }, + { + title: '3. Personal data we collect', + paragraphs: [ + 'Depending on how you use TalkUp, we may process the following categories of data:', + ], + list: [ + 'Account information: name, email address, password hash, and profile details you choose to provide.', + 'Career data: CV or résumé files, parsed CV content, job applications, target roles, notes, and interview preparation history.', + 'Simulation data: audio, video, transcripts, and behavioral feedback generated during mock interviews.', + 'Usage data: pages visited, features used, device and browser information, and approximate log timestamps.', + 'Communication data: messages you send to our support team or through in-app coaching features.', + ], + }, + { + title: '4. How we use your data', + paragraphs: ['We use personal data to:'], + list: [ + 'Create and manage your account.', + 'Analyze your CV against job offers and generate compatibility insights.', + 'Run interview simulations and provide personalized feedback.', + 'Save your notes, applications, agenda items, and progression over time.', + 'Improve product reliability, security, and user experience.', + 'Respond to support requests and send essential service communications.', + 'Comply with legal obligations and enforce our terms.', + ], + }, + { + title: '5. Legal basis for processing', + paragraphs: [ + 'Where applicable under the GDPR, we rely on one or more of the following legal bases:', + ], + list: [ + 'Performance of a contract — to provide the TalkUp services you sign up for.', + 'Consent — for example, when you upload a CV for analysis or enable optional features.', + 'Legitimate interests — to secure our platform, prevent abuse, and improve our product, balanced against your rights.', + 'Legal obligation — when we must retain or disclose data to comply with applicable law.', + ], + }, + { + title: '6. AI processing', + paragraphs: [ + 'TalkUp uses artificial intelligence to parse CVs, extract job-offer details, generate interview questions, analyze responses, and produce coaching feedback.', + 'Your content may be processed by automated systems to deliver these features. We do not use your personal data to train public third-party models unless we explicitly tell you otherwise and obtain your consent where required.', + ], + }, + { + title: '7. Sharing and subprocessors', + paragraphs: [ + 'We do not sell your personal data. We may share data with trusted service providers that help us host the platform, send emails, process AI workloads, or provide analytics — only under contracts that require appropriate safeguards.', + 'We may also disclose data if required by law, to protect the rights and safety of TalkUp and its users, or in connection with a merger, acquisition, or asset sale subject to continued protection of your information.', + ], + }, + { + title: '8. Data retention', + paragraphs: [ + 'We keep personal data only for as long as necessary to provide the service, meet legal requirements, or resolve disputes.', + 'You may delete your account at any time. When you do, we delete or anonymize your personal data within a reasonable period, except where retention is required by law or for legitimate backup and security purposes.', + ], + }, + { + title: '9. Your rights', + paragraphs: [ + 'Depending on your location, you may have the right to access, rectify, erase, restrict, or object to certain processing of your personal data, as well as the right to data portability.', + 'You can update much of your information directly in your account settings. To exercise other rights, email contact@talkup.ai. You may also lodge a complaint with your local supervisory authority.', + ], + }, + { + title: '10. Security', + paragraphs: [ + 'We implement technical and organizational measures designed to protect personal data against unauthorized access, loss, or misuse. No online service can guarantee absolute security, but we work continuously to reduce risk.', + ], + }, + { + title: '11. Cookies and similar technologies', + paragraphs: [ + 'TalkUp uses cookies and similar technologies to keep you signed in, remember preferences, and understand how the product is used.', + 'For more detail on the cookies we use and how to manage them, see our Cookies policy (coming soon).', + ], + }, + { + title: '12. International transfers', + paragraphs: [ + 'Your data may be processed in the European Economic Area and, where necessary, in other countries with appropriate safeguards such as standard contractual clauses or equivalent mechanisms.', + ], + }, + { + title: '13. Changes to this policy', + paragraphs: [ + 'We may update this Privacy Policy from time to time. When we make material changes, we will post the updated version on this page and adjust the "Last updated" date. Continued use of TalkUp after an update means you accept the revised policy.', + ], + }, + { + title: '14. Contact', + paragraphs: [ + 'Questions about this Privacy Policy or your personal data? Email us at contact@talkup.ai.', + ], + }, +]; + +function PrivacyPage() { + return ( +
+ +
+
+
+

+ Legal +

+

Privacy Policy

+

+ Last updated: {LAST_UPDATED} +

+
+ +
+ {SECTIONS.map((section) => ( +
+

{section.title}

+
+ {section.paragraphs.map((paragraph) => ( +

+ {paragraph} +

+ ))} + {section.list && ( +
    + {section.list.map((item) => ( +
  • {item}
  • + ))} +
+ )} +
+
+ ))} +
+
+
+ +
+ ); +}