diff --git a/front/src/App.tsx b/front/src/App.tsx index 79d7ba152..928971a73 100644 --- a/front/src/App.tsx +++ b/front/src/App.tsx @@ -1,56 +1,46 @@ import { Navigate, Route, Routes } from 'react-router-dom'; import { RequireAuth } from './modules/auth/components/RequireAuth'; -import { AppLayout } from './modules/ui/layout/AppLayout'; import { AuthCallback } from './pages/auth/AuthCallback'; import { Login } from './pages/auth/Login'; import { Companies } from './pages/companies/Companies'; import { Opportunities } from './pages/opportunities/Opportunities'; import { People } from './pages/people/People'; +import { SettingsProfile } from './pages/settings/SettingsProfile'; export function App() { return ( - <> - { - + + + + } /> + } /> + } /> + } /> + + + } + /> + - - - - } - /> - - - - } - /> - - - - } - /> - - - - } - /> - } /> - } /> + } /> + } /> - - } - + } + /> + + } /> + + } + /> + ); } diff --git a/front/src/AppNavbar.tsx b/front/src/AppNavbar.tsx new file mode 100644 index 000000000..598147462 --- /dev/null +++ b/front/src/AppNavbar.tsx @@ -0,0 +1,64 @@ +import { + TbBuilding, + TbInbox, + TbSearch, + TbSettings, + TbUser, +} from 'react-icons/tb'; +import { useMatch, useResolvedPath } from 'react-router-dom'; + +import NavItemsContainer from '@/ui/layout/navbar/NavItemsContainer'; + +import NavItem from './modules/ui/layout/navbar/NavItem'; +import NavTitle from './modules/ui/layout/navbar/NavTitle'; +import NavWorkspaceButton from './modules/ui/layout/navbar/NavWorkspaceButton'; + +export function AppNavbar() { + return ( + <> + + + } + soon={true} + /> + } + soon={true} + /> + } + /> + + } + active={ + !!useMatch({ + path: useResolvedPath('/people').pathname, + end: true, + }) + } + /> + } + active={ + !!useMatch({ + path: useResolvedPath('/companies').pathname, + end: true, + }) + } + /> + + + ); +} diff --git a/front/src/AppPage.tsx b/front/src/AppPage.tsx new file mode 100644 index 000000000..f633ca865 --- /dev/null +++ b/front/src/AppPage.tsx @@ -0,0 +1,11 @@ +import { DefaultLayout } from '@/ui/layout/DefaultLayout'; + +import { AppNavbar } from './AppNavbar'; + +type OwnProps = { + children: JSX.Element; +}; + +export function AppPage({ children }: OwnProps) { + return {children}; +} diff --git a/front/src/modules/auth/services/AuthService.ts b/front/src/modules/auth/services/AuthService.ts index f612d90d6..e9a6f644d 100644 --- a/front/src/modules/auth/services/AuthService.ts +++ b/front/src/modules/auth/services/AuthService.ts @@ -50,3 +50,8 @@ export const refreshAccessToken = async () => { localStorage.removeItem('accessToken'); } }; + +export const removeTokens = () => { + localStorage.removeItem('refreshToken'); + localStorage.removeItem('accessToken'); +}; diff --git a/front/src/modules/search/components/CommandMenu.tsx b/front/src/modules/search/components/CommandMenu.tsx index fd266e2f8..4c320e125 100644 --- a/front/src/modules/search/components/CommandMenu.tsx +++ b/front/src/modules/search/components/CommandMenu.tsx @@ -57,6 +57,14 @@ export const CommandMenu = ({ initiallyOpen = false }) => { > Companies + { + setOpen(false); + navigate('/settings/profile'); + }} + > + Settings + diff --git a/front/src/modules/settings/components/SettingsNavbar.tsx b/front/src/modules/settings/components/SettingsNavbar.tsx new file mode 100644 index 000000000..1c95b009b --- /dev/null +++ b/front/src/modules/settings/components/SettingsNavbar.tsx @@ -0,0 +1,62 @@ +import { TbColorSwatch, TbLogout, TbSettings, TbUser } from 'react-icons/tb'; +import { useMatch, useResolvedPath } from 'react-router-dom'; + +import { removeTokens } from '@/auth/services/AuthService'; +import NavBackButton from '@/ui/layout/navbar//NavBackButton'; +import NavItem from '@/ui/layout/navbar/NavItem'; +import NavItemsContainer from '@/ui/layout/navbar/NavItemsContainer'; +import NavTitle from '@/ui/layout/navbar/NavTitle'; + +export function SettingsNavbar() { + return ( + <> + + + + } + active={ + !!useMatch({ + path: useResolvedPath('/people').pathname, + end: true, + }) + } + /> + } + soon={true} + active={ + !!useMatch({ + path: useResolvedPath('/settings/profile/experience').pathname, + end: true, + }) + } + /> + + } + soon={true} + active={ + !!useMatch({ + path: useResolvedPath('/settings/workspace').pathname, + end: true, + }) + } + /> + + } + danger={true} + /> + + + ); +} diff --git a/front/src/modules/settings/components/SettingsPage.tsx b/front/src/modules/settings/components/SettingsPage.tsx new file mode 100644 index 000000000..2a6e6801f --- /dev/null +++ b/front/src/modules/settings/components/SettingsPage.tsx @@ -0,0 +1,11 @@ +import { SecondaryLayout } from '@/ui/layout/SecondaryLayout'; + +import { SettingsNavbar } from './SettingsNavbar'; + +type OwnProps = { + children: JSX.Element; +}; + +export function SettingsPage({ children }: OwnProps) { + return {children}; +} diff --git a/front/src/modules/ui/components/board/BoardColumn.tsx b/front/src/modules/ui/components/board/BoardColumn.tsx index cf7655e3c..4762327cb 100644 --- a/front/src/modules/ui/components/board/BoardColumn.tsx +++ b/front/src/modules/ui/components/board/BoardColumn.tsx @@ -13,7 +13,7 @@ export const StyledColumn = styled.div` export const StyledColumnTitle = styled.h3` font-family: 'Inter'; font-style: normal; - font-weight: ${({ theme }) => theme.fontWeightBold}; + font-weight: ${({ theme }) => theme.fontWeightMedium}; font-size: ${({ theme }) => theme.fontSizeMedium}; line-height: ${({ theme }) => theme.lineHeight}; color: ${({ color }) => color}; diff --git a/front/src/modules/ui/components/table/table-header/DropdownButton.tsx b/front/src/modules/ui/components/table/table-header/DropdownButton.tsx index dbf0ca610..718ff5265 100644 --- a/front/src/modules/ui/components/table/table-header/DropdownButton.tsx +++ b/front/src/modules/ui/components/table/table-header/DropdownButton.tsx @@ -108,7 +108,7 @@ const StyledDropdownTopOption = styled.li` cursor: pointer; user-select: none; color: ${(props) => props.theme.text80}; - font-weight: ${(props) => props.theme.fontWeightBold}; + font-weight: ${(props) => props.theme.fontWeightMedium}; &:hover { background: rgba(0, 0, 0, 0.04); @@ -131,7 +131,7 @@ const StyledSearchField = styled.li` cursor: pointer; user-select: none; color: ${(props) => props.theme.text60}; - font-weight: ${(props) => props.theme.fontWeightBold}; + font-weight: ${(props) => props.theme.fontWeightMedium}; border-bottom: var(--wraper-border) solid ${(props) => props.theme.primaryBorder}; diff --git a/front/src/modules/ui/layout/AppLayout.tsx b/front/src/modules/ui/layout/DefaultLayout.tsx similarity index 84% rename from front/src/modules/ui/layout/AppLayout.tsx rename to front/src/modules/ui/layout/DefaultLayout.tsx index eeffdbe06..769bb8c45 100644 --- a/front/src/modules/ui/layout/AppLayout.tsx +++ b/front/src/modules/ui/layout/DefaultLayout.tsx @@ -4,7 +4,7 @@ import { useRecoilState, useRecoilValue } from 'recoil'; import { currentUserState } from '@/auth/states/currentUserState'; import { CommandMenu } from '@/search/components/CommandMenu'; -import { Navbar } from './navbar/Navbar'; +import { NavbarContainer } from './navbar/NavbarContainer'; import { isNavbarOpenedState } from './states/isNavbarOpenedState'; import { MOBILE_VIEWPORT } from './styles/themes'; @@ -35,9 +35,10 @@ const MainContainer = styled.div` type OwnProps = { children: JSX.Element; + Navbar: () => JSX.Element; }; -export function AppLayout({ children }: OwnProps) { +export function DefaultLayout({ children, Navbar }: OwnProps) { const currentUser = useRecoilState(currentUserState); const userIsAuthenticated = !!currentUser; @@ -46,7 +47,9 @@ export function AppLayout({ children }: OwnProps) { {userIsAuthenticated ? ( <> - + + + {children} ) : ( diff --git a/front/src/modules/ui/layout/SecondaryLayout.tsx b/front/src/modules/ui/layout/SecondaryLayout.tsx new file mode 100644 index 000000000..84933568d --- /dev/null +++ b/front/src/modules/ui/layout/SecondaryLayout.tsx @@ -0,0 +1,69 @@ +import styled from '@emotion/styled'; + +import { NavbarContainer } from './navbar/NavbarContainer'; +import { MOBILE_VIEWPORT } from './styles/themes'; + +type OwnProps = { + children: JSX.Element; + Navbar: () => JSX.Element; +}; + +const StyledLayout = styled.div` + display: flex; + flex-direction: row; + width: 100vw; + height: 100vh; + background: ${(props) => props.theme.noisyBackground}; + position: relative; +`; +const MainContainer = styled.div` + overflow: hidden; + display: flex; + flex-direction: row; + width: 100%; +`; + +const SubContainer = styled.div` + display: flex; + flex-direction: column; + background: ${(props) => props.theme.primaryBackground}; + border-radius: ${(props) => props.theme.spacing(2)}; + border: 1px solid ${(props) => props.theme.primaryBorder}; + padding: ${(props) => props.theme.spacing(2)}; + margin: ${(props) => props.theme.spacing(4)}; + width: 100%; + max-width: calc(100vw - 500px); + padding: 32px; + + @media (max-width: ${MOBILE_VIEWPORT}px) { + width: 100%; + max-width: none; + } +`; + +const SubSubContainer = styled.div` + display: flex; + width: 350px; + flex-direction: column; + gap: 32px; + color: ${(props) => props.theme.text100}; + + @media (max-width: ${MOBILE_VIEWPORT}px) { + width: 100%; + } +`; + +export const SecondaryLayout = ({ children, Navbar }: OwnProps) => { + return ( + + + + + + + {children} + + + + ); +}; diff --git a/front/src/modules/ui/layout/navbar/NavBackButton.tsx b/front/src/modules/ui/layout/navbar/NavBackButton.tsx new file mode 100644 index 000000000..91a32191e --- /dev/null +++ b/front/src/modules/ui/layout/navbar/NavBackButton.tsx @@ -0,0 +1,48 @@ +import { TbChevronLeft } from 'react-icons/tb'; +import { useNavigate } from 'react-router-dom'; +import styled from '@emotion/styled'; + +import NavCollapseButton from './NavCollapseButton'; + +type OwnProps = { + title: string; +}; + +const IconAndButtonContainer = styled.button` + display: flex; + flex-direction: row; + align-items: center; + padding: ${(props) => props.theme.spacing(1)}; + gap: ${(props) => props.theme.spacing(1)}; + font-size: ${(props) => props.theme.fontSizeLarge}; + font-weight: ${(props) => props.theme.fontWeightSemibold}; + color: ${(props) => props.theme.text60}; + border: none; + background: inherit; + cursor: pointer; + width: 100%; +`; + +const StyledContainer = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; +`; + +export default function NavBackButton({ title }: OwnProps) { + const navigate = useNavigate(); + + return ( + <> + + navigate('/', { replace: true })} + > + + {title} + + + + + ); +} diff --git a/front/src/modules/ui/layout/navbar/NavCollapseButton.tsx b/front/src/modules/ui/layout/navbar/NavCollapseButton.tsx new file mode 100644 index 000000000..30a84ead4 --- /dev/null +++ b/front/src/modules/ui/layout/navbar/NavCollapseButton.tsx @@ -0,0 +1,66 @@ +import styled from '@emotion/styled'; +import { useRecoilState } from 'recoil'; + +import { IconSidebarLeftCollapse, IconSidebarRightCollapse } from '@/ui/icons'; + +import { isNavbarOpenedState } from '../states/isNavbarOpenedState'; +import { MOBILE_VIEWPORT } from '../styles/themes'; + +const CollapseButton = styled.button<{ hideOnDesktop: boolean | undefined }>` + display: flex; + align-items: center; + justify-content: center; + + width: 32px; + height: 32px; + + user-select: none; + border: 0; + background: inherit; + + padding: 0; + cursor: pointer; + + color: ${(props) => props.theme.text30}; + + ${(props) => + props.hideOnDesktop && + `@media (min-width: ${MOBILE_VIEWPORT}px) { + display:none; + } + `} +`; + +interface CollapseButtonProps { + hideIfOpen?: boolean; + hideIfClosed?: boolean; + hideOnDesktop?: boolean; +} + +export default function NavCollapseButton({ + hideIfOpen, + hideOnDesktop, +}: CollapseButtonProps) { + const [isNavOpen, setIsNavOpen] = useRecoilState(isNavbarOpenedState); + + return ( + <> + {isNavOpen && !hideIfOpen && ( + setIsNavOpen(!isNavOpen)} + hideOnDesktop={hideOnDesktop} + > + + + )} + {!isNavOpen && ( + setIsNavOpen(!isNavOpen)} + hideOnDesktop={hideOnDesktop} + > + + + )} + + ); +} diff --git a/front/src/modules/ui/layout/navbar/NavItem.tsx b/front/src/modules/ui/layout/navbar/NavItem.tsx index c9d6db51f..f29f97521 100644 --- a/front/src/modules/ui/layout/navbar/NavItem.tsx +++ b/front/src/modules/ui/layout/navbar/NavItem.tsx @@ -6,13 +6,18 @@ import { MOBILE_VIEWPORT } from '../styles/themes'; type OwnProps = { label: string; - to: string; + to?: string; + onClick?: () => void; active?: boolean; icon: ReactNode; + danger?: boolean; + soon?: boolean; }; type StyledItemProps = { active?: boolean; + danger?: boolean; + soon?: boolean; }; const StyledItem = styled.button` @@ -20,19 +25,30 @@ const StyledItem = styled.button` align-items: center; border: none; font-size: ${(props) => props.theme.fontSizeMedium}; - cursor: pointer; + cursor: ${(props) => (props.soon ? 'default' : 'pointer')}; + pointer-events: ${(props) => (props.soon ? 'none' : 'auto')}; user-select: none; background: ${(props) => (props.active ? 'rgba(0, 0, 0, 0.04)' : 'inherit')}; padding-top: ${(props) => props.theme.spacing(1)}; padding-bottom: ${(props) => props.theme.spacing(1)}; padding-left: ${(props) => props.theme.spacing(1)}; font-family: 'Inter'; - color: ${(props) => - props.active ? props.theme.text100 : props.theme.text60}; + color: ${(props) => { + if (props.active) { + return props.theme.text100; + } + if (props.danger) { + return props.theme.red; + } + if (props.soon) { + return props.theme.text20; + } + return props.theme.text60; + }}; border-radius: 4px; :hover { background: rgba(0, 0, 0, 0.04); - color: ${(props) => props.theme.text100}; + color: ${(props) => (props.danger ? props.theme.red : props.theme.text100)}; } margin-bottom: calc(${(props) => props.theme.spacing(1)} / 2); @@ -46,19 +62,44 @@ const StyledItemLabel = styled.div` margin-left: ${(props) => props.theme.spacing(2)}; `; -function NavItem({ label, icon, to, active }: OwnProps) { +const StyledSoonPill = styled.div` + display: flex; + justify-content: center; + align-items: center; + border-radius: 50px; + background-color: rgba(0, 0, 0, 0.04); + font-size: ${(props) => props.theme.fontSizeExtraSmall}; + padding: ${(props) => props.theme.spacing(1)} + ${(props) => props.theme.spacing(2)} ${(props) => props.theme.spacing(1)} + ${(props) => props.theme.spacing(2)}; + margin-left: auto; // this aligns the pill to the right +`; + +function NavItem({ label, icon, to, onClick, active, danger, soon }: OwnProps) { const navigate = useNavigate(); + const onItemClick = () => { + if (onClick) { + onClick(); + return; + } + if (to) { + navigate(to); + return; + } + }; + return ( { - navigate(to); - }} + onClick={onItemClick} active={active} aria-selected={active} + danger={danger} + soon={soon} > {icon} {label} + {soon && Soon} ); } diff --git a/front/src/modules/ui/layout/navbar/NavItemsContainer.tsx b/front/src/modules/ui/layout/navbar/NavItemsContainer.tsx new file mode 100644 index 000000000..452ec3b28 --- /dev/null +++ b/front/src/modules/ui/layout/navbar/NavItemsContainer.tsx @@ -0,0 +1,17 @@ +import styled from '@emotion/styled'; + +type OwnProps = { + children: React.ReactNode; +}; + +const StyledNavItemsContainer = styled.div` + display: flex; + flex-direction: column; + margin-top: 40px; +`; + +function NavItemsContainer({ children }: OwnProps) { + return {children}; +} + +export default NavItemsContainer; diff --git a/front/src/modules/ui/layout/navbar/NavTitle.tsx b/front/src/modules/ui/layout/navbar/NavTitle.tsx index 7c74b2523..761b323f9 100644 --- a/front/src/modules/ui/layout/navbar/NavTitle.tsx +++ b/front/src/modules/ui/layout/navbar/NavTitle.tsx @@ -10,7 +10,7 @@ const StyledTitle = styled.div` color: ${(props) => props.theme.text30}; font-size: ${(props) => props.theme.fontSizeExtraSmall}; font-weight: 600; - padding-top: ${(props) => props.theme.spacing(1)}; + padding-top: ${(props) => props.theme.spacing(8)}; padding-bottom: ${(props) => props.theme.spacing(2)}; padding-left: ${(props) => props.theme.spacing(1)}; `; diff --git a/front/src/modules/ui/layout/navbar/WorkspaceContainer.tsx b/front/src/modules/ui/layout/navbar/NavWorkspaceButton.tsx similarity index 65% rename from front/src/modules/ui/layout/navbar/WorkspaceContainer.tsx rename to front/src/modules/ui/layout/navbar/NavWorkspaceButton.tsx index a663e8d36..0c6c43a32 100644 --- a/front/src/modules/ui/layout/navbar/WorkspaceContainer.tsx +++ b/front/src/modules/ui/layout/navbar/NavWorkspaceButton.tsx @@ -1,10 +1,9 @@ import styled from '@emotion/styled'; -import { useRecoilState, useRecoilValue } from 'recoil'; +import { useRecoilValue } from 'recoil'; import { currentUserState } from '@/auth/states/currentUserState'; -import { IconSidebarLeftCollapse } from '@/ui/icons'; -import { isNavbarOpenedState } from '../states/isNavbarOpenedState'; +import NavCollapseButton from './NavCollapseButton'; const StyledContainer = styled.div` display: flex; @@ -47,27 +46,8 @@ const StyledName = styled.div` color: ${(props) => props.theme.text80}; `; -const CollapseButton = styled.button` - display: flex; - align-items: center; - justify-content: center; - - width: 32px; - height: 32px; - - user-select: none; - border: 0; - background: inherit; - - padding: 0; - cursor: pointer; - - color: ${(props) => props.theme.text30}; -`; - -function WorkspaceContainer() { +function NavWorkspaceButton() { const currentUser = useRecoilValue(currentUserState); - const [isNavOpen, setIsNavOpen] = useRecoilState(isNavbarOpenedState); const currentWorkspace = currentUser?.workspaceMember?.workspace; @@ -81,13 +61,9 @@ function WorkspaceContainer() { {currentWorkspace?.displayName} - {isNavOpen && ( - setIsNavOpen(!isNavOpen)}> - - - )} + ); } -export default WorkspaceContainer; +export default NavWorkspaceButton; diff --git a/front/src/modules/ui/layout/navbar/Navbar.tsx b/front/src/modules/ui/layout/navbar/Navbar.tsx deleted file mode 100644 index 490753f25..000000000 --- a/front/src/modules/ui/layout/navbar/Navbar.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { TbBuilding, TbUser } from 'react-icons/tb'; -import { useMatch, useResolvedPath } from 'react-router-dom'; -import styled from '@emotion/styled'; -import { useRecoilValue } from 'recoil'; - -import { isNavbarOpenedState } from '../states/isNavbarOpenedState'; -import { MOBILE_VIEWPORT } from '../styles/themes'; - -import NavItem from './NavItem'; -import NavTitle from './NavTitle'; -import WorkspaceContainer from './WorkspaceContainer'; - -const NavbarContent = styled.div` - display: ${() => (useRecoilValue(isNavbarOpenedState) ? 'block' : 'none')}; -`; - -const NavbarContainer = styled.div` - flex-direction: column; - width: ${() => (useRecoilValue(isNavbarOpenedState) ? '220px' : '0')}; - padding: ${(props) => props.theme.spacing(2)}; - flex-shrink: 0; - overflow: hidden; - - @media (max-width: ${MOBILE_VIEWPORT}px) { - width: ${(props) => - useRecoilValue(isNavbarOpenedState) - ? `calc(100% - ` + props.theme.spacing(4) + `)` - : '0'}; -`; - -const NavItemsContainer = styled.div` - display: flex; - flex-direction: column; - margin-top: 40px; -`; - -export function Navbar() { - return ( - <> - - - - - - } - active={ - !!useMatch({ - path: useResolvedPath('/people').pathname, - end: true, - }) - } - /> - } - active={ - !!useMatch({ - path: useResolvedPath('/companies').pathname, - end: true, - }) - } - /> - - - - - ); -} diff --git a/front/src/modules/ui/layout/navbar/NavbarContainer.tsx b/front/src/modules/ui/layout/navbar/NavbarContainer.tsx new file mode 100644 index 000000000..c1ca83779 --- /dev/null +++ b/front/src/modules/ui/layout/navbar/NavbarContainer.tsx @@ -0,0 +1,62 @@ +import styled from '@emotion/styled'; +import { useRecoilValue } from 'recoil'; + +import { isNavbarOpenedState } from '../states/isNavbarOpenedState'; +import { MOBILE_VIEWPORT } from '../styles/themes'; + +const StyledNavbarContainer = styled.div<{ width: string }>` + flex-direction: column; + width: ${(props) => + useRecoilValue(isNavbarOpenedState) ? props.width : '0'}; + padding: ${(props) => props.theme.spacing(2)}; + flex-shrink: 0; + overflow: hidden; + + @media (max-width: ${MOBILE_VIEWPORT}px) { + width: ${(props) => + useRecoilValue(isNavbarOpenedState) + ? `calc(100% - ` + props.theme.spacing(4) + `)` + : '0'}; +`; + +const NavbarSubContainer = styled.div` + display: flex; + width: 160px; + flex-direction: column; + margin-top: 41px; + margin-left: auto; + + @media (max-width: ${MOBILE_VIEWPORT}px) { + width: 100%; + } +`; + +const NavbarContent = styled.div` + display: ${() => (useRecoilValue(isNavbarOpenedState) ? 'block' : 'none')}; +`; + +interface NavbarProps { + children: React.ReactNode; + layout?: string; +} + +export const NavbarContainer: React.FC = ({ + children, + layout, +}) => { + if (layout === 'secondary') { + return ( + + + {children} + + + ); + } + + return ( + + {children} + + ); +}; diff --git a/front/src/modules/ui/layout/styles/themes.ts b/front/src/modules/ui/layout/styles/themes.ts index ac2ac99a4..efe6b9bd7 100644 --- a/front/src/modules/ui/layout/styles/themes.ts +++ b/front/src/modules/ui/layout/styles/themes.ts @@ -13,7 +13,9 @@ const commonTheme = { iconSizeMedium: '1.08rem', iconSizeLarge: '1.23rem', - fontWeightBold: 500, + fontWeightMedium: 500, + fontWeightSemibold: 600, + fontWeightBold: 700, fontFamily: 'Inter, sans-serif', lineHeight: '150%', @@ -138,7 +140,7 @@ export const textInputStyle = (props: any) => &::-webkit-input-placeholder { font-family: ${props.theme.fontFamily}; color: ${props.theme.text30}; - font-weight: ${props.theme.fontWeightBold}; + font-weight: ${props.theme.fontWeightMedium}; } `; diff --git a/front/src/modules/ui/layout/top-bar/TopBar.tsx b/front/src/modules/ui/layout/top-bar/TopBar.tsx index abf00301f..fbe781a67 100644 --- a/front/src/modules/ui/layout/top-bar/TopBar.tsx +++ b/front/src/modules/ui/layout/top-bar/TopBar.tsx @@ -1,11 +1,8 @@ import { ReactNode } from 'react'; import { TbPlus } from 'react-icons/tb'; import styled from '@emotion/styled'; -import { useRecoilState } from 'recoil'; -import { IconSidebarRightCollapse } from '@/ui/icons'; - -import { isNavbarOpenedState } from '../states/isNavbarOpenedState'; +import NavCollapseButton from '../navbar/NavCollapseButton'; export const TOP_BAR_MIN_HEIGHT = '40px'; @@ -44,24 +41,6 @@ const AddButtonContainer = styled.div` margin-right: ${(props) => props.theme.spacing(1)}; `; -const CollapseButton = styled.button` - display: flex; - align-items: center; - justify-content: center; - - width: 32px; - height: 32px; - - user-select: none; - border: 0; - background: inherit; - - padding: 0; - cursor: pointer; - - color: ${(props) => props.theme.text30}; -`; - type OwnProps = { title: string; icon: ReactNode; @@ -69,16 +48,10 @@ type OwnProps = { }; export function TopBar({ title, icon, onAddButtonClick }: OwnProps) { - const [isNavOpen, setIsNavOpen] = useRecoilState(isNavbarOpenedState); - return ( <> - {!isNavOpen && ( - setIsNavOpen(!isNavOpen)}> - - - )} + {icon} {title} {onAddButtonClick && ( diff --git a/front/src/modules/ui/layout/top-bar/TopTitle.tsx b/front/src/modules/ui/layout/top-bar/TopTitle.tsx new file mode 100644 index 000000000..c87078bc2 --- /dev/null +++ b/front/src/modules/ui/layout/top-bar/TopTitle.tsx @@ -0,0 +1,29 @@ +import styled from '@emotion/styled'; + +import NavCollapseButton from '../navbar/NavCollapseButton'; + +const TitleAndCollapseContainer = styled.div` + display: flex; + flex-direction: row; + align-items: center; +`; + +const TitleContainer = styled.div` + font-size: ${(props) => props.theme.fontSizeLarge}; + font-weight: ${(props) => props.theme.fontWeightSemibold}; + display: flex; + width: 100%; +`; + +type OwnProps = { + title: string; +}; + +export function TopTitle({ title }: OwnProps) { + return ( + + + {title} + + ); +} diff --git a/front/src/pages/companies/Companies.tsx b/front/src/pages/companies/Companies.tsx index aba7d312a..7cda82393 100644 --- a/front/src/pages/companies/Companies.tsx +++ b/front/src/pages/companies/Companies.tsx @@ -23,6 +23,7 @@ import { EntityTableActionBar } from '@/ui/components/table/action-bar/EntityTab import { EntityTable } from '@/ui/components/table/EntityTable'; import { WithTopBarContainer } from '@/ui/layout/containers/WithTopBarContainer'; import { BoolExpType } from '@/utils/interfaces/generic.interface'; +import { AppPage } from '~/AppPage'; import { CompanyOrderByWithRelationInput as Companies_Order_By } from '~/generated/graphql'; import { TableActionBarButtonCreateCommentThreadCompany } from './table/TableActionBarButtonCreateCommentThreadCompany'; @@ -74,29 +75,31 @@ export function Companies() { const companiesColumns = useCompaniesColumns(); return ( - } - onAddButtonClick={handleAddButtonClick} - > - <> - - } - availableSorts={availableSorts} - availableFilters={availableFilters} - onSortsUpdate={updateSorts} - onFiltersUpdate={updateFilters} - /> - - - - - - - + + } + onAddButtonClick={handleAddButtonClick} + > + <> + + } + availableSorts={availableSorts} + availableFilters={availableFilters} + onSortsUpdate={updateSorts} + onFiltersUpdate={updateFilters} + /> + + + + + + + + ); } diff --git a/front/src/pages/opportunities/Opportunities.tsx b/front/src/pages/opportunities/Opportunities.tsx index 8d6a016b8..6a75c4596 100644 --- a/front/src/pages/opportunities/Opportunities.tsx +++ b/front/src/pages/opportunities/Opportunities.tsx @@ -1,6 +1,7 @@ import { FaBullseye } from 'react-icons/fa'; import { WithTopBarContainer } from '@/ui/layout/containers/WithTopBarContainer'; +import { AppPage } from '~/AppPage'; import { initialBoard, @@ -10,8 +11,10 @@ import { Board } from '../../modules/opportunities/components/Board'; export function Opportunities() { return ( - }> - - + + }> + + + ); } diff --git a/front/src/pages/people/People.tsx b/front/src/pages/people/People.tsx index afb50b86d..c482a49f6 100644 --- a/front/src/pages/people/People.tsx +++ b/front/src/pages/people/People.tsx @@ -20,6 +20,7 @@ import { EntityTableActionBar } from '@/ui/components/table/action-bar/EntityTab import { EntityTable } from '@/ui/components/table/EntityTable'; import { WithTopBarContainer } from '@/ui/layout/containers/WithTopBarContainer'; import { BoolExpType } from '@/utils/interfaces/generic.interface'; +import { AppPage } from '~/AppPage'; import { TableActionBarButtonCreateCommentThreadPeople } from './table/TableActionBarButtonCreateCommentThreadPeople'; import { TableActionBarButtonDeletePeople } from './table/TableActionBarButtonDeletePeople'; @@ -72,29 +73,31 @@ export function People() { const peopleColumns = usePeopleColumns(); return ( - } - onAddButtonClick={handleAddButtonClick} - > - <> - - } - availableSorts={availableSorts} - availableFilters={availableFilters} - onSortsUpdate={updateSorts} - onFiltersUpdate={updateFilters} - /> - - - - - - - + + } + onAddButtonClick={handleAddButtonClick} + > + <> + + } + availableSorts={availableSorts} + availableFilters={availableFilters} + onSortsUpdate={updateSorts} + onFiltersUpdate={updateFilters} + /> + + + + + + + + ); } diff --git a/front/src/pages/settings/SettingsProfile.tsx b/front/src/pages/settings/SettingsProfile.tsx new file mode 100644 index 000000000..790ac1bea --- /dev/null +++ b/front/src/pages/settings/SettingsProfile.tsx @@ -0,0 +1,24 @@ +import { useRecoilValue } from 'recoil'; + +import { currentUserState } from '@/auth/states/currentUserState'; +import { SettingsPage } from '@/settings/components/SettingsPage'; +import { TopTitle } from '@/ui/layout/top-bar/TopTitle'; + +export function SettingsProfile() { + const currentUser = useRecoilValue(currentUserState); + return ( + + <> + +
+
Name
+ {currentUser?.displayName} +
+
+
Email
+ {currentUser?.email} +
+ +
+ ); +} diff --git a/front/src/pages/settings/__stories__/settings.stories.tsx b/front/src/pages/settings/__stories__/settings.stories.tsx new file mode 100644 index 000000000..ee42c5405 --- /dev/null +++ b/front/src/pages/settings/__stories__/settings.stories.tsx @@ -0,0 +1,23 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { graphqlMocks } from '~/testing/graphqlMocks'; + +import { SettingsProfile } from '../SettingsProfile'; + +import { render } from './shared'; + +const meta: Meta = { + title: 'Pages/SettingsProfile', + component: SettingsProfile, +}; + +export default meta; + +export type Story = StoryObj; + +export const Default: Story = { + render, + parameters: { + msw: graphqlMocks, + }, +}; diff --git a/front/src/pages/settings/__stories__/shared.tsx b/front/src/pages/settings/__stories__/shared.tsx new file mode 100644 index 000000000..ca29d169c --- /dev/null +++ b/front/src/pages/settings/__stories__/shared.tsx @@ -0,0 +1,22 @@ +import { MemoryRouter } from 'react-router-dom'; +import { ApolloProvider } from '@apollo/client'; +import { RecoilRoot } from 'recoil'; + +import { FullHeightStorybookLayout } from '~/testing/FullHeightStorybookLayout'; +import { mockedClient } from '~/testing/mockedClient'; + +import { SettingsProfile } from '../SettingsProfile'; + +export function render() { + return ( + + + + + + + + + + ); +}