## Summary - Closes [#103](#103). - Adds public SPA route `/account-deletion/` (no auth) with Hesychia / `ai.hesychia.chat` branding, in-app deletion steps, soft-delete data retention copy, and a contact path (30-day SLA) for users who cannot sign in. - Documents Play Console **Account deletion URL** in `ANDROID.md` and `android/README.md` (`https://hesychia.ai/account-deletion/`, legacy host, HashRouter form). ## Notes - Retention copy matches backend soft-delete (v1): no claim of full erasure / hard purge yet. - Play Console field still needs to be set out-of-band after deploy. ## Test plan - [ ] Open `/account-deletion/` signed out — page loads (no redirect to sign-in) - [ ] Confirm steps match Account → Delete my account + email confirm - [ ] Confirm retention sections are accurate vs soft-delete - [ ] `npm run test:ci -- --testPathPattern=AccountDeletionPage` - [ ] After beta deploy, set Play Console Account deletion URL to the public HTTPS URLReviewed-on: #110
105 lines
4.4 KiB
TypeScript
105 lines
4.4 KiB
TypeScript
import React, { Component, useContext } from 'react';
|
|
import './App.css';
|
|
import { Routes, Route, Outlet, Navigate } from 'react-router-dom';
|
|
import SignIn from './llm-fe/pages/SignIn/SignIn';
|
|
import SignUp from './llm-fe/pages/SignUp/SignUp';
|
|
import AuthCallback from './llm-fe/pages/AuthCallback/AuthCallback';
|
|
import BillingSuccess from './llm-fe/pages/BillingSuccess/BillingSuccess';
|
|
import BillingCancel from './llm-fe/pages/BillingCancel/BillingCancel';
|
|
import PasswordReset from './llm-fe/pages/PasswordReset/PasswordReset';
|
|
import NotFound from './llm-fe/pages/NotFound/NotFound';
|
|
import { AuthContext } from './llm-fe/contexts/AuthContext';
|
|
import TermsOfService from './llm-fe/pages/TermsOfService/TermsOfService';
|
|
import PublicTermsOfServicePage from './llm-fe/pages/TermsOfService/PublicTermsOfServicePage';
|
|
import AccountDeletionPage from './llm-fe/pages/AccountDeletion/AccountDeletionPage';
|
|
import SetPassword from './llm-fe/components/SetPassword/SetPassword';
|
|
import AsyncDashboard2 from './llm-fe/pages/AsyncDashboard2/AsyncDashboard2';
|
|
import FeedbackPage2 from './llm-fe/pages/FeedbackPage2/FeedbackPage2';
|
|
import DocumentStoragePage from './llm-fe/pages/DocumentStoragePage/DocumentStoragePage';
|
|
import Account2 from './llm-fe/pages/Account2/Account2';
|
|
import AnalyticsPage from './llm-fe/pages/Analytics/Analytics';
|
|
import PasswordResetConfirmation from './llm-fe/pages/PasswordResetConfirmation/PasswordReset';
|
|
import GlobalThemeWrapper from './llm-fe/components/GlobalThemeWrapper/GlobalThemeWrapper';
|
|
import Tracker from './llm-fe/components/Tracker/Tracker';
|
|
import { AnalyticsConsentProvider } from './llm-fe/contexts/AnalyticsConsentContext';
|
|
import AnalyticsConsentBanner from './llm-fe/components/AnalyticsConsentBanner/AnalyticsConsentBanner';
|
|
import AnalyticsSession from './llm-fe/components/AnalyticsSession/AnalyticsSession';
|
|
import AppErrorBoundary from './llm-fe/components/AppErrorBoundary/AppErrorBoundary';
|
|
import ToastHost from './llm-fe/components/ToastHost/ToastHost';
|
|
|
|
const ProtectedRoutes = () => {
|
|
const { authenticated, loading } = useContext(AuthContext);
|
|
if (loading) {
|
|
return (
|
|
<div>Loading</div>
|
|
)
|
|
}
|
|
if (!authenticated) return <Navigate to='/signin/' replace />
|
|
//if(!needsNewPassword) return <Navigate to='/password_reset/' replace/>
|
|
|
|
return <Outlet />
|
|
}
|
|
|
|
|
|
|
|
class App extends Component {
|
|
|
|
render() {
|
|
return (
|
|
<GlobalThemeWrapper>
|
|
<AnalyticsConsentProvider>
|
|
<Tracker />
|
|
<AnalyticsSession />
|
|
<ToastHost />
|
|
<AnalyticsConsentBanner />
|
|
<div className='site'>
|
|
<main>
|
|
<div className="main-container">
|
|
|
|
|
|
<AppErrorBoundary>
|
|
<Routes>
|
|
<Route path='*' element={<NotFound />} />
|
|
|
|
<Route path={"/signin/"} Component={SignIn} />
|
|
<Route path={"/signup/"} Component={SignUp} />
|
|
<Route path={"/auth/callback/"} Component={AuthCallback} />
|
|
<Route path={"/billing/success"} Component={BillingSuccess} />
|
|
<Route path={"/billing/cancel"} Component={BillingCancel} />
|
|
<Route path={"/password_reset/"} Component={PasswordReset} />
|
|
<Route path={"/password_reset_confirmation/"} Component={PasswordResetConfirmation} />
|
|
<Route path={'/set_password/'} Component={SetPassword} />
|
|
{/* Public legal pages (also used for post-login ToS acknowledge) */}
|
|
<Route path={"/terms_of_service/"} Component={TermsOfService} />
|
|
<Route path={"/legal/terms-of-service"} Component={PublicTermsOfServicePage} />
|
|
{/* Play Console account-deletion URL (#103) — must stay public */}
|
|
<Route path={"/account-deletion/"} Component={AccountDeletionPage} />
|
|
|
|
<Route element={<ProtectedRoutes />}>
|
|
<Route path={"/"} index={true} Component={AsyncDashboard2} />
|
|
<Route path={"/account/"} Component={Account2} />
|
|
<Route path={"/document_storage"} Component={DocumentStoragePage} />
|
|
<Route path={"/feedback/"} Component={FeedbackPage2} />
|
|
<Route path={"/analytics/"} Component={AnalyticsPage} />
|
|
|
|
</Route>
|
|
|
|
</Routes>
|
|
</AppErrorBoundary>
|
|
|
|
</div>
|
|
|
|
</main>
|
|
</div>
|
|
</AnalyticsConsentProvider>
|
|
</GlobalThemeWrapper>
|
|
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
export default App;
|