diff --git a/.changeset/happy-beans-fry.md b/.changeset/happy-beans-fry.md
new file mode 100644
index 000000000..b4e3a1605
--- /dev/null
+++ b/.changeset/happy-beans-fry.md
@@ -0,0 +1,5 @@
+---
+"nextjs-website": minor
+---
+
+Migrate Header component from EC to B2BP
diff --git a/apps/nextjs-website/react-components/components/Header/Header.helpers.tsx b/apps/nextjs-website/react-components/components/Header/Header.helpers.tsx
new file mode 100644
index 000000000..ebe35f94e
--- /dev/null
+++ b/apps/nextjs-website/react-components/components/Header/Header.helpers.tsx
@@ -0,0 +1,33 @@
+import { Stack, useTheme, type Theme } from '@mui/material';
+import { DialogBubbleProps } from '../../types/Header/Header.types';
+
+const useStyles = (muiTheme: Theme) => ({
+ bubbleContainer: {
+ transform: 'rotate(180deg)',
+ position: 'absolute',
+ marginTop: '42px',
+ padding: muiTheme.spacing(2),
+ direction: 'rtl',
+ textAlign: 'left',
+ borderRadius: '4px',
+ },
+ bubble: { transform: 'rotate(180deg)' },
+});
+
+export const DialogBubble = ({
+ children,
+ ...stackProps
+}: DialogBubbleProps) => {
+ const muiTheme = useTheme();
+ const styles = useStyles(muiTheme);
+ return (
+
+
+ {children}
+
+
+ );
+};
diff --git a/apps/nextjs-website/react-components/components/Header/Header.tsx b/apps/nextjs-website/react-components/components/Header/Header.tsx
new file mode 100644
index 000000000..d28b07bc9
--- /dev/null
+++ b/apps/nextjs-website/react-components/components/Header/Header.tsx
@@ -0,0 +1,120 @@
+import Box from '@mui/material/Box';
+import Stack from '@mui/material/Stack';
+import { useEffect, useState } from 'react';
+import { HamburgerMenu } from './components/HamburgerMenu';
+import { Navigation } from './components/Navigation';
+import { HeaderTitle } from './components/Title';
+import { HeaderProps } from '@react-components/types/Header/Header.types';
+import { CtaButtons } from '../common/Common';
+import { BackgroundColor } from '../common/Common.helpers';
+
+const Header = ({
+ product,
+ theme,
+ menu,
+ ctaButtons,
+ avatar,
+ beta,
+ logo,
+}: HeaderProps) => {
+ const backgroundColor = BackgroundColor(theme);
+
+ const [menuOpen, setMenuOpen] = useState(false);
+
+ const openHeader = () => {
+ setMenuOpen(true);
+ };
+
+ const closeHeader = () => {
+ setMenuOpen(false);
+ };
+
+ useEffect(() => {
+ window.addEventListener('resize', closeHeader);
+
+ return () => {
+ window.removeEventListener('resize', closeHeader);
+ };
+ }, []);
+
+ const HeaderCtas = () => {
+ return ctaButtons && ctaButtons.length > 0 ? (
+
+ {CtaButtons({
+ ctaButtons: ctaButtons.map((CtaButton) => ({
+ ...CtaButton,
+ sx: { width: { md: 'auto', xs: '100%' } },
+ })),
+ theme,
+ })}
+
+ ) : null;
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Header;
diff --git a/apps/nextjs-website/react-components/components/Header/components/HamburgerMenu.tsx b/apps/nextjs-website/react-components/components/Header/components/HamburgerMenu.tsx
new file mode 100644
index 000000000..531ac078e
--- /dev/null
+++ b/apps/nextjs-website/react-components/components/Header/components/HamburgerMenu.tsx
@@ -0,0 +1,29 @@
+import CloseIcon from '@mui/icons-material/Close';
+import MenuIcon from '@mui/icons-material/Menu';
+
+interface HamburgerMenuProps {
+ open: boolean;
+ onOpen: () => void;
+ onClose: () => void;
+}
+
+export const HamburgerMenu = ({ open, onOpen, onClose }: HamburgerMenuProps) =>
+ open ? (
+
+ ) : (
+
+ );
diff --git a/apps/nextjs-website/react-components/components/Header/components/MenuDropdown.tsx b/apps/nextjs-website/react-components/components/Header/components/MenuDropdown.tsx
new file mode 100644
index 000000000..fa8d25d8b
--- /dev/null
+++ b/apps/nextjs-website/react-components/components/Header/components/MenuDropdown.tsx
@@ -0,0 +1,153 @@
+import {
+ Stack,
+ type StackProps,
+ Typography,
+ useTheme,
+ useMediaQuery,
+ Link,
+ type Theme,
+} from '@mui/material';
+import { useState } from 'react';
+import { ArrowDropDown } from '@mui/icons-material';
+import { DialogBubble } from '../Header.helpers';
+import { isJSX } from '../../../types/common/Common.types';
+import { DropdownItem, MenuDropdownProp } from '../../../types/Header/Header.types';
+import { TextAlternativeColor } from '@react-components/components/common/Common.helpers';
+
+const TIMEOUT_LENGTH = 100;
+
+const useStyles = ({ theme, active, items }: MenuDropdownProp, { palette, spacing }: Theme) => {
+ const textColor = TextAlternativeColor(theme);
+
+ return {
+ menu: {
+ paddingY: { md: 2 },
+ borderColor: textColor,
+ borderBottomStyle: 'solid',
+ borderBottomWidth: { md: active ? 3 : 0, xs: 0 },
+ },
+ item: {
+ cursor: {
+ md: items?.length ? 'default' : 'pointer',
+ xs: 'pointer',
+ },
+ flexDirection: 'row',
+ color: textColor,
+ textDecoration: 'none',
+ },
+ link: {
+ color: { xs: textColor, md: palette.primary.contrastText },
+ textIndent: { xs: spacing(2), md: 0 },
+ },
+ arrowAnimate: {
+ transition: 'transform 0.2s',
+ transform: { xs: 'rotate(-180deg)', md: '' },
+ },
+ };
+};
+
+export const MenuDropdown = (props: MenuDropdownProp) => {
+ // props
+ const { label, active, theme, items, ...button } = props;
+
+ // state
+ const [menuHover, setMenuHover] = useState(false);
+ const [dropdownHover, setDropdownHover] = useState(false);
+
+ const hoverOnMenu = () => {
+ setMenuHover(true);
+ };
+
+ const leavesMenu = () => {
+ setTimeout(() => {
+ setMenuHover(false);
+ }, TIMEOUT_LENGTH);
+ };
+
+ const hoverOnDropdown = () => {
+ setDropdownHover(true);
+ };
+
+ const leavesDropdown = () => {
+ setTimeout(() => {
+ setDropdownHover(false);
+ }, TIMEOUT_LENGTH);
+ };
+
+ const toggleMenu = () => {
+ setMenuHover((status) => !status);
+ };
+
+ // style
+ const hasLinks = items?.length;
+ const muiTheme = useTheme();
+ const md = useMediaQuery(muiTheme.breakpoints.up('md'));
+ const styles = useStyles(props, muiTheme);
+
+ const dropdownVisible = menuHover || dropdownHover;
+
+ const menuEventsHandlers = md
+ ? {
+ onMouseEnter: hoverOnMenu,
+ onMouseLeave: leavesMenu,
+ }
+ : {
+ onClick: toggleMenu,
+ };
+
+ const Dropdown = ({
+ children,
+ ...stackProps
+ }: { children: JSX.Element[] } & StackProps) =>
+ md ? (
+
+ {children}
+
+ ) : (
+
+ {children}
+
+ );
+
+ return (
+
+
+
+ {label}
+
+ {hasLinks && (
+
+ )}
+
+ {hasLinks && dropdownVisible && (
+
+ {items?.map((item: DropdownItem, index) =>
+ isJSX(item) ? (
+ item
+ ) : (
+
+ {item.label}
+
+ )
+ )}
+
+ )}
+
+ );
+};
diff --git a/apps/nextjs-website/react-components/components/Header/components/Navigation.tsx b/apps/nextjs-website/react-components/components/Header/components/Navigation.tsx
new file mode 100644
index 000000000..9d8617693
--- /dev/null
+++ b/apps/nextjs-website/react-components/components/Header/components/Navigation.tsx
@@ -0,0 +1,16 @@
+import { Stack } from '@mui/material';
+import { MenuDropdown } from './MenuDropdown';
+import { NavigationProps } from '../../../types/Header/Header.types';
+
+export const Navigation = ({ menu, theme }: NavigationProps) => (
+
+ {menu.map((menu, index) => (
+
+ ))}
+
+);
diff --git a/apps/nextjs-website/react-components/components/Header/components/Title.tsx b/apps/nextjs-website/react-components/components/Header/components/Title.tsx
new file mode 100644
index 000000000..36e998470
--- /dev/null
+++ b/apps/nextjs-website/react-components/components/Header/components/Title.tsx
@@ -0,0 +1,59 @@
+import {
+ Stack,
+ Avatar,
+ Typography,
+ Chip,
+ useTheme,
+ Link,
+} from '@mui/material';
+import { HeaderTitleProps } from '../../../types/Header/Header.types';
+
+export const HeaderTitle = ({
+ avatar,
+ beta,
+ product: { name: productName, href: productHref },
+ theme,
+ logo,
+}: HeaderTitleProps) => {
+ const { palette, spacing } = useTheme();
+ const textColor =
+ theme === 'dark' ? palette.primary.contrastText : palette.text.primary;
+ const label = 'beta';
+
+ return (
+
+ {logo && (
+
+
+
+ )}
+ {!logo && (
+ <>
+ {avatar && }
+
+ {productHref ? (
+
+ {productName}
+
+ ) : (
+ {productName}
+ )}
+
+ >
+ )}
+ {beta && (
+
+ )}
+
+ );
+};
diff --git a/apps/nextjs-website/react-components/components/index.ts b/apps/nextjs-website/react-components/components/index.ts
index 280057e62..f2e57983f 100644
--- a/apps/nextjs-website/react-components/components/index.ts
+++ b/apps/nextjs-website/react-components/components/index.ts
@@ -8,6 +8,7 @@ import Footer from './Footer/Footer';
import EditorialSwitch from './Editorial-Switch/Editorial-Switch';
import PreHeader from './PreHeader/PreHeader';
import StripeLink from './StripeLink/StripeLink';
+import Header from './Header/Header';
export {
Hero,
@@ -20,4 +21,5 @@ export {
EditorialSwitch,
PreHeader,
StripeLink,
+ Header,
};
\ No newline at end of file
diff --git a/apps/nextjs-website/react-components/types/Header/Header.types.ts b/apps/nextjs-website/react-components/types/Header/Header.types.ts
new file mode 100644
index 000000000..5f1685d77
--- /dev/null
+++ b/apps/nextjs-website/react-components/types/Header/Header.types.ts
@@ -0,0 +1,43 @@
+import { ReactNode } from "react";
+import { AvatarProps, LinkProps, StackProps } from "@mui/material";
+import { CommonProps, CtaButtonProps, Generic } from "../common/Common.types";
+
+export interface HeaderProps extends HeaderTitleProps, NavigationProps {
+ ctaButtons?: CtaButtonProps[];
+}
+
+interface DropdownLink extends LinkProps {
+ label: string;
+}
+
+export type DropdownItem = Generic | DropdownLink;
+
+export interface MenuDropdownProp
+ extends Partial>,
+ CommonProps {
+ label: string;
+ active?: boolean;
+ items?: DropdownItem[];
+}
+
+export interface NavigationProps extends CommonProps {
+ menu: MenuDropdownProp[];
+}
+
+export interface HeaderTitleProps extends CommonProps {
+ product: {
+ name: string;
+ href?: string;
+ };
+ avatar?: AvatarProps;
+ beta?: boolean;
+ logo?: {
+ src: string;
+ alt: string;
+ href: string;
+ };
+}
+
+export interface DialogBubbleProps extends StackProps {
+ children: ReactNode;
+}
\ No newline at end of file
diff --git a/apps/nextjs-website/react-components/types/index.ts b/apps/nextjs-website/react-components/types/index.ts
index 549231b1e..1fe10f9c1 100644
--- a/apps/nextjs-website/react-components/types/index.ts
+++ b/apps/nextjs-website/react-components/types/index.ts
@@ -8,6 +8,7 @@ import { FooterProps } from './Footer/Footer.types';
import { EditorialSwitchProps } from './Editorial-Switch/Editorial-Switch.types';
import { PreHeaderProps } from './PreHeader/PreHeader.types';
import { StripeLinkProps } from './StripeLink/StripeLink.types';
+import { HeaderProps } from './Header/Header.types';
export type {
HeroProps,
@@ -19,5 +20,6 @@ export type {
FooterProps,
EditorialSwitchProps,
PreHeaderProps,
- StripeLinkProps
+ StripeLinkProps,
+ HeaderProps,
};
\ No newline at end of file
diff --git a/apps/nextjs-website/src/components/Header.tsx b/apps/nextjs-website/src/components/Header.tsx
index 06e264006..df817f329 100644
--- a/apps/nextjs-website/src/components/Header.tsx
+++ b/apps/nextjs-website/src/components/Header.tsx
@@ -1,9 +1,8 @@
'use client';
-import { Header as HeaderEC } from '@pagopa/pagopa-editorial-components/dist/components/Header';
-import { HeaderProps } from '@pagopa/pagopa-editorial-components/dist/components/Header/Header';
-import { Stack } from '@mui/material';
import { usePathname } from 'next/navigation';
import Icon from './Icon';
+import { Header as HeaderRC } from '@react-components/components';
+import { HeaderProps } from '@react-components/types';
import { HeaderWithNavigation } from '@/lib/header';
const makeHeaderProps = (
@@ -42,44 +41,7 @@ const makeHeaderProps = (
const Header = (props: HeaderWithNavigation) => {
const pathname = usePathname();
- return (
-
-
-
- );
+ return ;
};
export default Header;