diff --git a/front/package.json b/front/package.json
index 5a42d8e3b..0c1663c75 100644
--- a/front/package.json
+++ b/front/package.json
@@ -19,6 +19,7 @@
"@types/node": "^16.18.4",
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.9",
+ "@types/react-helmet-async": "^1.0.3",
"@types/react-modal": "^3.16.0",
"afterframe": "^1.0.2",
"apollo-link-rest": "^0.9.0",
@@ -41,6 +42,7 @@
"react-datepicker": "^4.11.0",
"react-dom": "^18.2.0",
"react-dropzone": "^14.2.3",
+ "react-helmet-async": "^1.3.0",
"react-hook-form": "^7.45.1",
"react-hotkeys-hook": "^4.4.0",
"react-loading-skeleton": "^3.3.1",
diff --git a/front/src/App.tsx b/front/src/App.tsx
index fbf9030b7..7a0c8bccf 100644
--- a/front/src/App.tsx
+++ b/front/src/App.tsx
@@ -1,8 +1,9 @@
-import { Navigate, Route, Routes } from 'react-router-dom';
+import { Navigate, Route, Routes, useLocation } from 'react-router-dom';
import { AppPath } from '@/types/AppPath';
import { SettingsPath } from '@/types/SettingsPath';
import { DefaultLayout } from '@/ui/layout/components/DefaultLayout';
+import { PageTitle } from '@/ui/utilities/page-title/PageTitle';
import { CreateProfile } from '~/pages/auth/CreateProfile';
import { CreateWorkspace } from '~/pages/auth/CreateWorkspace';
import { SignInUp } from '~/pages/auth/SignInUp';
@@ -21,13 +22,18 @@ import { Tasks } from '~/pages/tasks/Tasks';
import { AppInternalHooks } from '~/sync-hooks/AppInternalHooks';
import { NotFound } from './pages/not-found/NotFound';
+import { getPageTitleFromPath } from './utils/title-utils';
// TEMP FEATURE FLAG FOR VIEW FIELDS
export const ACTIVATE_VIEW_FIELDS = true;
export function App() {
+ const { pathname } = useLocation();
+ const pageTitle = getPageTitleFromPath(pathname);
+
return (
<>
+
diff --git a/front/src/__stories__/App.stories.tsx b/front/src/__stories__/App.stories.tsx
index 51488fe0c..75624836a 100644
--- a/front/src/__stories__/App.stories.tsx
+++ b/front/src/__stories__/App.stories.tsx
@@ -1,3 +1,4 @@
+import { HelmetProvider } from 'react-helmet-async';
import { MemoryRouter } from 'react-router-dom';
import type { Meta, StoryObj } from '@storybook/react';
import { useRecoilState } from 'recoil';
@@ -24,7 +25,9 @@ const meta: Meta = {
-
+
+
+
diff --git a/front/src/index.tsx b/front/src/index.tsx
index 72884e847..d8d247c5c 100644
--- a/front/src/index.tsx
+++ b/front/src/index.tsx
@@ -1,5 +1,6 @@
import { StrictMode } from 'react';
import ReactDOM from 'react-dom/client';
+import { HelmetProvider } from 'react-helmet-async';
import { BrowserRouter } from 'react-router-dom';
import { RecoilRoot } from 'recoil';
@@ -27,20 +28,22 @@ root.render(
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
,
diff --git a/front/src/modules/ui/utilities/page-title/PageTitle.tsx b/front/src/modules/ui/utilities/page-title/PageTitle.tsx
new file mode 100644
index 000000000..63680379d
--- /dev/null
+++ b/front/src/modules/ui/utilities/page-title/PageTitle.tsx
@@ -0,0 +1,13 @@
+import { Helmet } from 'react-helmet-async';
+
+type OwnProps = {
+ title: string;
+};
+
+export function PageTitle({ title }: OwnProps) {
+ return (
+
+ {title}
+
+ );
+}
diff --git a/front/src/pages/companies/CompanyShow.tsx b/front/src/pages/companies/CompanyShow.tsx
index f6f096d8e..e0049f769 100644
--- a/front/src/pages/companies/CompanyShow.tsx
+++ b/front/src/pages/companies/CompanyShow.tsx
@@ -17,6 +17,7 @@ import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPage
import { ShowPageRightContainer } from '@/ui/layout/show-page/components/ShowPageRightContainer';
import { ShowPageSummaryCard } from '@/ui/layout/show-page/components/ShowPageSummaryCard';
import { ShowPageRecoilScopeContext } from '@/ui/layout/states/ShowPageRecoilScopeContext';
+import { PageTitle } from '@/ui/utilities/page-title/PageTitle';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
import { useUpdateOneCompanyMutation } from '~/generated/graphql';
import { getLogoUrlFromDomainName } from '~/utils';
@@ -45,66 +46,71 @@ export function CompanyShow() {
}
return (
- }
- onFavoriteButtonClick={handleFavoriteButtonClick}
- extraButtons={[
- ,
- ]}
- >
-
-
-
- (
-
- )}
- />
-
-
-
- {companyShowFieldDefinition.map((fieldDefinition) => {
- return (
-
-
-
- );
- })}
-
-
-
-
-
-
+
+ }
+ onFavoriteButtonClick={handleFavoriteButtonClick}
+ extraButtons={[
+
-
-
-
+ />,
+ ]}
+ >
+
+
+
+ (
+
+ )}
+ />
+
+
+
+ {companyShowFieldDefinition.map((fieldDefinition) => {
+ return (
+
+
+
+ );
+ })}
+
+
+
+
+
+
+
+
+
+ >
);
}
diff --git a/front/src/pages/people/PersonShow.tsx b/front/src/pages/people/PersonShow.tsx
index c1bb0e687..c5d1fd4e9 100644
--- a/front/src/pages/people/PersonShow.tsx
+++ b/front/src/pages/people/PersonShow.tsx
@@ -18,6 +18,7 @@ import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPage
import { ShowPageRightContainer } from '@/ui/layout/show-page/components/ShowPageRightContainer';
import { ShowPageSummaryCard } from '@/ui/layout/show-page/components/ShowPageSummaryCard';
import { ShowPageRecoilScopeContext } from '@/ui/layout/states/ShowPageRecoilScopeContext';
+import { PageTitle } from '@/ui/utilities/page-title/PageTitle';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
import {
useUpdateOnePersonMutation,
@@ -63,66 +64,73 @@ export function PersonShow() {
}
return (
- }
- hasBackButton
- isFavorite={isFavorite}
- onFavoriteButtonClick={handleFavoriteButtonClick}
- extraButtons={[
- ,
- ]}
- >
-
-
-
-
- person ? : <>>
- }
- onUploadPicture={onUploadPicture}
- />
-
-
-
- {personShowFieldDefinition.map((fieldDefinition) => {
- return (
-
-
-
- );
- })}
-
-
-
-
-
+
+ }
+ hasBackButton
+ isFavorite={isFavorite}
+ onFavoriteButtonClick={handleFavoriteButtonClick}
+ extraButtons={[
+
-
-
-
+ />,
+ ]}
+ >
+
+
+
+
+ person ? (
+
+ ) : (
+ <>>
+ )
+ }
+ onUploadPicture={onUploadPicture}
+ />
+
+
+
+ {personShowFieldDefinition.map((fieldDefinition) => {
+ return (
+
+
+
+ );
+ })}
+
+
+
+
+
+
+
+
+ >
);
}
diff --git a/front/src/testing/decorators/PageDecorator.tsx b/front/src/testing/decorators/PageDecorator.tsx
index f055baa2e..faada17af 100644
--- a/front/src/testing/decorators/PageDecorator.tsx
+++ b/front/src/testing/decorators/PageDecorator.tsx
@@ -1,3 +1,4 @@
+import { HelmetProvider } from 'react-helmet-async';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import { Decorator } from '@storybook/react';
@@ -29,11 +30,13 @@ export const PageDecorator: Decorator<{
initialEntries={[computeLocation(args.routePath, args.routeParams)]}
>
-
-
- } />
-
-
+
+
+
+ } />
+
+
+
diff --git a/front/src/utils/title-utils.ts b/front/src/utils/title-utils.ts
new file mode 100644
index 000000000..1889a2623
--- /dev/null
+++ b/front/src/utils/title-utils.ts
@@ -0,0 +1,38 @@
+import { AppBasePath } from '@/types/AppBasePath';
+import { AppPath } from '@/types/AppPath';
+import { SettingsPath } from '@/types/SettingsPath';
+
+export function getPageTitleFromPath(pathname: string): string {
+ switch (pathname) {
+ case AppPath.Verify:
+ return 'Verify';
+ case AppPath.SignIn:
+ return 'Sign In';
+ case AppPath.SignUp:
+ return 'Sign Up';
+ case AppPath.Invite:
+ return 'Invite';
+ case AppPath.CreateWorkspace:
+ return 'Create Workspace';
+ case AppPath.CreateProfile:
+ return 'Create Profile';
+ case AppPath.PeoplePage:
+ return 'People';
+ case AppPath.CompaniesPage:
+ return 'Companies';
+ case AppPath.TasksPage:
+ return 'Tasks';
+ case AppPath.OpportunitiesPage:
+ return 'Opportunities';
+ case `${AppBasePath.Settings}/${SettingsPath.ProfilePage}`:
+ return 'Profile';
+ case `${AppBasePath.Settings}/${SettingsPath.Experience}`:
+ return 'Experience';
+ case `${AppBasePath.Settings}/${SettingsPath.WorkspaceMembersPage}`:
+ return 'Workspace Members';
+ case `${AppBasePath.Settings}/${SettingsPath.Workspace}`:
+ return 'Workspace';
+ default:
+ return 'Twenty';
+ }
+}
diff --git a/front/yarn.lock b/front/yarn.lock
index 40ce0cf94..cdc60bb8c 100644
--- a/front/yarn.lock
+++ b/front/yarn.lock
@@ -5603,6 +5603,13 @@
dependencies:
"@types/react" "*"
+"@types/react-helmet-async@^1.0.3":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@types/react-helmet-async/-/react-helmet-async-1.0.3.tgz#89d581d6cb129e5357d39d7d1b41313b20523989"
+ integrity sha512-DqbSuZPSHiH1l3XI/y8LbhrAGNh+Bpc9QY4MsYRM1yD4+qhax8bN4DInUMpv/tNyIdjsa+1V8XXmbRx8W5dB0w==
+ dependencies:
+ react-helmet-async "*"
+
"@types/react-modal@^3.16.0":
version "3.16.0"
resolved "https://registry.yarnpkg.com/@types/react-modal/-/react-modal-3.16.0.tgz#b8d6be10de894139a2ea9f4a2505b1b5d02023df"
@@ -16074,11 +16081,22 @@ react-fast-compare@3.2.1:
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.1.tgz#53933d9e14f364281d6cba24bfed7a4afb808b5f"
integrity sha512-xTYf9zFim2pEif/Fw16dBiXpe0hoy5PxcD8+OwBnTtNLfIm3g6WxhKNurY+6OmdH1u6Ta/W/Vl6vjbYP1MFnDg==
-react-fast-compare@^3.0.1:
+react-fast-compare@^3.0.1, react-fast-compare@^3.2.0:
version "3.2.2"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49"
integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==
+react-helmet-async@*, react-helmet-async@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/react-helmet-async/-/react-helmet-async-1.3.0.tgz#7bd5bf8c5c69ea9f02f6083f14ce33ef545c222e"
+ integrity sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+ invariant "^2.2.4"
+ prop-types "^15.7.2"
+ react-fast-compare "^3.2.0"
+ shallowequal "^1.1.0"
+
react-hook-form@^7.45.1:
version "7.45.4"
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.45.4.tgz#73d228b704026ae95d7e5f7b207a681b173ec62a"
@@ -17160,6 +17178,11 @@ shallow-equal@^1.2.1:
resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.2.1.tgz#4c16abfa56043aa20d050324efa68940b0da79da"
integrity sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==
+shallowequal@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
+ integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
+
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"