Skip to content

Commit 8a6a833

Browse files
Update header for NHS.UK frontend v10.0.0
1 parent 91c0094 commit 8a6a833

File tree

20 files changed

+601
-881
lines changed

20 files changed

+601
-881
lines changed
Lines changed: 46 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,33 @@
11
'use client';
2-
import React, { FC, HTMLProps, useContext, useState, useEffect, useMemo, useRef } from 'react';
2+
import React, { HTMLProps, useState, useEffect, useMemo, useRef, Children } from 'react';
33
import classNames from 'classnames';
4-
import NHSLogo, { NHSLogoNavProps } from './components/NHSLogo';
5-
import OrganisationalLogo, { OrganisationalLogoProps } from './components/OrganisationalLogo';
4+
import { Container } from '@components/layout';
5+
import { childIsOfComponentType } from '@util/types/TypeGuards';
66
import HeaderContext, { IHeaderContext } from './HeaderContext';
7+
import Account from './components/Account';
8+
import AccountItem from './components/AccountItem';
79
import Search from './components/Search';
8-
import Nav from './components/Nav';
9-
import NavItem from './components/NavItem';
10-
import NavDropdownMenu from './components/NavDropdownMenu';
11-
import { Container } from '@components/layout';
12-
import Content from './components/Content';
13-
import TransactionalServiceName from './components/TransactionalServiceName';
10+
import Navigation from './components/Navigation';
11+
import NavigationItem from './components/NavigationItem';
12+
import Service from './components/Service';
1413
import { Header } from 'nhsuk-frontend';
1514

16-
const HeaderLogo: FC<OrganisationalLogoProps & NHSLogoNavProps> = (props) => {
17-
const { orgName } = useContext<IHeaderContext>(HeaderContext);
18-
if (orgName) {
19-
return <OrganisationalLogo {...props} />;
20-
}
21-
return <NHSLogo {...props} />;
22-
};
23-
24-
const HeaderContainer: FC<HTMLProps<HTMLDivElement>> = ({ className, ...rest }) => (
25-
<Container className={classNames('nhsuk-header__container', className)} {...rest} />
26-
);
27-
2815
interface HeaderProps extends HTMLProps<HTMLDivElement> {
29-
transactional?: boolean;
30-
orgName?: string;
31-
orgSplit?: string;
32-
orgDescriptor?: string;
33-
serviceName?: string;
34-
white?: boolean;
16+
containerClasses?: string;
17+
organisation?: IHeaderContext['organisation'];
3518
}
3619

37-
const HeaderComponent = ({
38-
className,
39-
children,
40-
transactional,
41-
orgName,
42-
orgSplit,
43-
orgDescriptor,
44-
role = 'banner',
45-
serviceName,
46-
white,
47-
...rest
48-
}: HeaderProps) => {
20+
const HeaderComponent = ({ className, containerClasses, children, ...rest }: HeaderProps) => {
4921
const moduleRef = useRef<HTMLDivElement>(null);
5022

51-
const [hasMenuToggle, setHasMenuToggle] = useState(false);
52-
const [hasSearch, setHasSearch] = useState(false);
53-
const [hasServiceName, setHasServiceName] = useState(false);
23+
const [service, setService] = useState<IHeaderContext['service']>();
24+
const [organisation, setOrganisation] = useState<IHeaderContext['organisation']>();
5425
const [instance, setInstance] = useState<Header>();
55-
const [menuOpen, setMenuOpen] = useState(false);
26+
27+
useEffect(() => {
28+
setOrganisation(rest.organisation);
29+
return () => setOrganisation(undefined);
30+
}, [rest.organisation]);
5631

5732
useEffect(() => {
5833
if (!moduleRef.current || instance) {
@@ -62,79 +37,50 @@ const HeaderComponent = ({
6237
setInstance(new Header(moduleRef.current));
6338
}, [moduleRef, instance]);
6439

65-
const setMenuToggle = (toggle: boolean): void => {
66-
setHasMenuToggle(toggle);
67-
};
68-
69-
const setSearch = (toggle: boolean): void => {
70-
setHasSearch(toggle);
71-
};
72-
73-
const toggleMenu = (): void => {
74-
setMenuOpen(!menuOpen);
75-
};
76-
77-
const setServiceName = (toggle: boolean): void => {
78-
setHasServiceName(toggle);
79-
};
80-
8140
const contextValue: IHeaderContext = useMemo(() => {
8241
return {
83-
orgName,
84-
orgSplit,
85-
orgDescriptor,
86-
serviceName,
87-
hasSearch,
88-
hasMenuToggle,
89-
hasServiceName,
90-
setMenuToggle,
91-
setSearch,
92-
setServiceName,
93-
toggleMenu,
94-
menuOpen,
95-
transactional: transactional ?? false,
42+
service,
43+
organisation,
44+
setService,
45+
setOrganisation,
9646
};
97-
}, [
98-
orgName,
99-
orgSplit,
100-
orgDescriptor,
101-
serviceName,
102-
hasSearch,
103-
hasMenuToggle,
104-
hasServiceName,
105-
setMenuToggle,
106-
setSearch,
107-
setServiceName,
108-
toggleMenu,
109-
menuOpen,
110-
transactional,
111-
]);
47+
}, [service, organisation]);
48+
49+
const items = Children.toArray(children);
50+
51+
const [childService] = items.filter((child) => childIsOfComponentType(child, Service));
52+
const [childSearch] = items.filter((child) => childIsOfComponentType(child, Search));
53+
const [childNavigation] = items.filter((child) => childIsOfComponentType(child, Navigation));
54+
const [childAccount] = items.filter((child) => childIsOfComponentType(child, Account));
11255

11356
return (
11457
<header
11558
className={classNames(
11659
'nhsuk-header',
117-
{ 'nhsuk-header__transactional': transactional },
118-
{ 'nhsuk-header--organisation': orgName },
119-
{ 'nhsuk-header--white': white },
60+
{ 'nhsuk-header--organisation': organisation },
12061
className,
12162
)}
122-
role={role}
63+
data-module="nhsuk-header"
64+
role="banner"
12365
ref={moduleRef}
124-
{...rest}
12566
>
126-
<HeaderContext.Provider value={contextValue}>{children}</HeaderContext.Provider>
67+
<HeaderContext.Provider value={contextValue}>
68+
<Container className={classNames('nhsuk-header__container', containerClasses)}>
69+
{childService}
70+
{childSearch}
71+
{childAccount}
72+
</Container>
73+
{childNavigation}
74+
</HeaderContext.Provider>
12775
</header>
12876
);
12977
};
13078

131-
HeaderComponent.Logo = HeaderLogo;
79+
HeaderComponent.Account = Account;
80+
HeaderComponent.AccountItem = AccountItem;
13281
HeaderComponent.Search = Search;
133-
HeaderComponent.Nav = Nav;
134-
HeaderComponent.NavItem = NavItem;
135-
HeaderComponent.NavDropdownMenu = NavDropdownMenu;
136-
HeaderComponent.Container = HeaderContainer;
137-
HeaderComponent.Content = Content;
138-
HeaderComponent.ServiceName = TransactionalServiceName;
82+
HeaderComponent.Navigation = Navigation;
83+
HeaderComponent.NavigationItem = NavigationItem;
84+
HeaderComponent.Service = Service;
13985

14086
export default HeaderComponent;
Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,28 @@
11
import { createContext } from 'react';
22

33
export interface IHeaderContext {
4-
orgName: string | undefined;
5-
serviceName: string | undefined;
6-
orgSplit: string | undefined;
7-
orgDescriptor: string | undefined;
8-
setSearch: (toggle: boolean) => void;
9-
setMenuToggle: (toggle: boolean) => void;
10-
setServiceName: (toggle: boolean) => void;
11-
toggleMenu: () => void;
12-
hasSearch: boolean;
13-
hasMenuToggle: boolean;
14-
hasServiceName: boolean;
15-
menuOpen: boolean;
16-
transactional: boolean;
4+
logo?: {
5+
href?: string;
6+
src?: string;
7+
};
8+
service?: {
9+
href?: string;
10+
text?: string;
11+
};
12+
organisation?: {
13+
name?: string;
14+
split?: string;
15+
descriptor?: string;
16+
};
17+
setService: (service: IHeaderContext['service']) => void;
18+
setOrganisation: (organisation: IHeaderContext['organisation']) => void;
1719
}
1820

1921
export default createContext<IHeaderContext>({
2022
/* eslint-disable @typescript-eslint/no-empty-function */
21-
orgName: undefined,
22-
serviceName: undefined,
23-
orgSplit: undefined,
24-
orgDescriptor: undefined,
25-
setSearch: () => {},
26-
setMenuToggle: () => {},
27-
setServiceName: () => {},
28-
hasSearch: false,
29-
hasMenuToggle: false,
30-
hasServiceName: false,
31-
toggleMenu: () => {},
32-
menuOpen: false,
33-
transactional: false,
23+
logo: undefined,
24+
service: undefined,
25+
organisation: undefined,
26+
setService: () => {},
27+
setOrganisation: () => {},
3428
});

0 commit comments

Comments
 (0)