mirror of
				https://github.com/lingble/twenty.git
				synced 2025-10-31 04:37:56 +00:00 
			
		
		
		
	Implement new UI
This commit is contained in:
		| @@ -52,6 +52,10 @@ Once this is completed you should have: | |||||||
| - server available on: http://localhost:3000/health | - server available on: http://localhost:3000/health | ||||||
| - postgres: available on http://localhost:5432 that should contain `twenty` database | - postgres: available on http://localhost:5432 that should contain `twenty` database | ||||||
|  |  | ||||||
|  | ### Step 3: IDE setup | ||||||
|  |  | ||||||
|  | If you are using VSCode, please use the `Dev Containers` extension to open the project in a container. This will allow you to run Visual Studio on top of the docker container. This will allow you to run the project without having to install node on your machine.  | ||||||
|  |  | ||||||
| ### Note | ### Note | ||||||
|  |  | ||||||
| If you are using Docker install, make sure to ssh in the docker container during development to execute commands. You can also use `Makefile` to help you | If you are using Docker install, make sure to ssh in the docker container during development to execute commands. You can also use `Makefile` to help you | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro"> | <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter"> | ||||||
| <style type="text/css"> | <style type="text/css"> | ||||||
| body { | body { | ||||||
|   margin: 0; |   margin: 0; | ||||||
|   font-family: 'Source Sans Pro', sans-serif; |   font-family: 'Inter', sans-serif; | ||||||
|   -webkit-font-smoothing: antialiased; |   -webkit-font-smoothing: antialiased; | ||||||
|   -moz-osx-font-smoothing: grayscale; |   -moz-osx-font-smoothing: grayscale; | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								front/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								front/package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -9,7 +9,7 @@ | |||||||
|       "version": "0.1.0", |       "version": "0.1.0", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@apollo/client": "^3.7.5", |         "@apollo/client": "^3.7.5", | ||||||
|         "@emotion/react": "^11.10.5", |         "@emotion/react": "^11.10.6", | ||||||
|         "@emotion/styled": "^11.10.5", |         "@emotion/styled": "^11.10.5", | ||||||
|         "@fortawesome/fontawesome-svg-core": "^6.2.1", |         "@fortawesome/fontawesome-svg-core": "^6.2.1", | ||||||
|         "@fortawesome/free-regular-svg-icons": "^6.2.1", |         "@fortawesome/free-regular-svg-icons": "^6.2.1", | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ | |||||||
|   "private": true, |   "private": true, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@apollo/client": "^3.7.5", |     "@apollo/client": "^3.7.5", | ||||||
|     "@emotion/react": "^11.10.5", |     "@emotion/react": "^11.10.6", | ||||||
|     "@emotion/styled": "^11.10.5", |     "@emotion/styled": "^11.10.5", | ||||||
|     "@fortawesome/fontawesome-svg-core": "^6.2.1", |     "@fortawesome/fontawesome-svg-core": "^6.2.1", | ||||||
|     "@fortawesome/free-regular-svg-icons": "^6.2.1", |     "@fortawesome/free-regular-svg-icons": "^6.2.1", | ||||||
| @@ -49,7 +49,11 @@ | |||||||
|   "overrides": { |   "overrides": { | ||||||
|     "react-refresh": "0.14.0" |     "react-refresh": "0.14.0" | ||||||
|   }, |   }, | ||||||
|   "jest": {}, |   "jest": { | ||||||
|  |     "coveragePathIgnorePatterns" : [ | ||||||
|  |       ".stories.tsx$" | ||||||
|  |     ] | ||||||
|  |   }, | ||||||
|   "browserslist": { |   "browserslist": { | ||||||
|     "production": [ |     "production": [ | ||||||
|       ">0.2%", |       ">0.2%", | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ | |||||||
|     <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> |     <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> | ||||||
|  |  | ||||||
|     <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> |     <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> | ||||||
|     <link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro' rel='stylesheet' type='text/css'> |     <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet"> | ||||||
|  |  | ||||||
|     <title>Twenty</title> |     <title>Twenty</title> | ||||||
|   </head> |   </head> | ||||||
|   | |||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| body { | body { | ||||||
|   margin: 0; |   margin: 0; | ||||||
|   font-family: 'Source Sans Pro', sans-serif; |   font-family: 'Inter'; | ||||||
|   -webkit-font-smoothing: antialiased; |   -webkit-font-smoothing: antialiased; | ||||||
|   -moz-osx-font-smoothing: grayscale; |   -moz-osx-font-smoothing: grayscale; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -10,6 +10,8 @@ import { | |||||||
|   createHttpLink, |   createHttpLink, | ||||||
| } from '@apollo/client'; | } from '@apollo/client'; | ||||||
| import { setContext } from '@apollo/client/link/context'; | import { setContext } from '@apollo/client/link/context'; | ||||||
|  | import '@emotion/react'; | ||||||
|  | import { ThemeType } from './layout/styles/themes'; | ||||||
|  |  | ||||||
| const httpLink = createHttpLink({ uri: process.env.REACT_APP_API_URL }); | const httpLink = createHttpLink({ uri: process.env.REACT_APP_API_URL }); | ||||||
|  |  | ||||||
| @@ -34,3 +36,8 @@ root.render( | |||||||
|     </BrowserRouter> |     </BrowserRouter> | ||||||
|   </ApolloProvider>, |   </ApolloProvider>, | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | declare module '@emotion/react' { | ||||||
|  |   // eslint-disable-next-line @typescript-eslint/no-empty-interface | ||||||
|  |   export interface Theme extends ThemeType {} | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								front/src/interfaces/workspace.interface.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								front/src/interfaces/workspace.interface.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | export interface Workspace { | ||||||
|  |   id: number; | ||||||
|  |   name: string; | ||||||
|  |   logo: string; | ||||||
|  | } | ||||||
| @@ -1,24 +1,37 @@ | |||||||
| import Navbar from './navbar/Navbar'; | import Navbar from './navbar/Navbar'; | ||||||
| import styled from '@emotion/styled'; | import styled from '@emotion/styled'; | ||||||
|  | import { ThemeProvider } from '@emotion/react'; | ||||||
| import { User } from '../interfaces/user.interface'; | import { User } from '../interfaces/user.interface'; | ||||||
|  | import { Workspace } from '../interfaces/workspace.interface'; | ||||||
|  | import { lightTheme } from './styles/themes'; | ||||||
|  |  | ||||||
| const StyledLayout = styled.div` | const StyledLayout = styled.div` | ||||||
|   display: flex; |   display: flex; | ||||||
|   flex-direction: column; |   flex-direction: row; | ||||||
|  |   width: 100vw; | ||||||
|   height: 100vh; |   height: 100vh; | ||||||
| `; | `; | ||||||
|  |  | ||||||
|  | const StyledRightContainer = styled.div` | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: row; | ||||||
|  |   flex: 1; | ||||||
|  | `; | ||||||
|  |  | ||||||
| type OwnProps = { | type OwnProps = { | ||||||
|   children: JSX.Element; |   children: JSX.Element; | ||||||
|   user?: User; |   user?: User; | ||||||
|  |   workspace?: Workspace; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| function AppLayout({ children, user }: OwnProps) { | function AppLayout({ children, user, workspace }: OwnProps) { | ||||||
|   return ( |   return ( | ||||||
|     <StyledLayout> |     <ThemeProvider theme={lightTheme}> | ||||||
|       <Navbar user={user} /> |       <StyledLayout> | ||||||
|       <div>{children}</div> |         <Navbar user={user} workspace={workspace} /> | ||||||
|     </StyledLayout> |         <StyledRightContainer>{children}</StyledRightContainer> | ||||||
|  |       </StyledLayout> | ||||||
|  |     </ThemeProvider> | ||||||
|   ); |   ); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								front/src/layout/__stories__/AppLayout.stories.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								front/src/layout/__stories__/AppLayout.stories.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | import { MemoryRouter } from 'react-router-dom'; | ||||||
|  | import AppLayout from '../AppLayout'; | ||||||
|  | import { ThemeProvider } from '@emotion/react'; | ||||||
|  | import { lightTheme } from '../styles/themes'; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   title: 'AppLayout', | ||||||
|  |   component: AppLayout, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const AppLayoutDefault = () => ( | ||||||
|  |   <ThemeProvider theme={lightTheme}> | ||||||
|  |     <MemoryRouter> | ||||||
|  |       <AppLayout> | ||||||
|  |         <div data-testid="content">Test</div> | ||||||
|  |       </AppLayout> | ||||||
|  |     </MemoryRouter> | ||||||
|  |   </ThemeProvider> | ||||||
|  | ); | ||||||
							
								
								
									
										10
									
								
								front/src/layout/__tests__/AppLayout.test.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								front/src/layout/__tests__/AppLayout.test.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | import { render } from '@testing-library/react'; | ||||||
|  |  | ||||||
|  | import { AppLayoutDefault } from '../__stories__/AppLayout.stories'; | ||||||
|  |  | ||||||
|  | it('Checks the AppLayout render', () => { | ||||||
|  |   const { getByTestId } = render(<AppLayoutDefault />); | ||||||
|  |  | ||||||
|  |   const title = getByTestId('content'); | ||||||
|  |   expect(title).toHaveTextContent('Test'); | ||||||
|  | }); | ||||||
| @@ -1,16 +0,0 @@ | |||||||
| import styled from '@emotion/styled'; |  | ||||||
|  |  | ||||||
| type OwnProps = { |  | ||||||
|   children: JSX.Element; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const StyledContainer = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   height: calc(100vh - 60px); |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| function FullWidthContainer({ children }: OwnProps) { |  | ||||||
|   return <StyledContainer>{children}</StyledContainer>; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default FullWidthContainer; |  | ||||||
							
								
								
									
										45
									
								
								front/src/layout/containers/WithTopBarContainer.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								front/src/layout/containers/WithTopBarContainer.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | import styled from '@emotion/styled'; | ||||||
|  | import TopBar from '../top-bar/TopBar'; | ||||||
|  | import { IconProp } from '@fortawesome/fontawesome-svg-core'; | ||||||
|  |  | ||||||
|  | type OwnProps = { | ||||||
|  |   children: JSX.Element; | ||||||
|  |   title: string; | ||||||
|  |   icon: IconProp; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const StyledContainer = styled.div` | ||||||
|  |   display: flex; | ||||||
|  |   flex: 1; | ||||||
|  |   flex-direction: column; | ||||||
|  | `; | ||||||
|  |  | ||||||
|  | const ContentContainer = styled.div` | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   background: ${(props) => props.theme.noisyBackground}; | ||||||
|  |   flex: 1; | ||||||
|  |   padding-right: 12px; | ||||||
|  |   padding-bottom: 12px; | ||||||
|  | `; | ||||||
|  |  | ||||||
|  | const ContentSubContainer = styled.div` | ||||||
|  |   display: flex; | ||||||
|  |   background: ${(props) => props.theme.primaryBackground}; | ||||||
|  |   border-radius: 8px; | ||||||
|  |   border: 1px solid ${(props) => props.theme.primaryBorder}; | ||||||
|  |   flex: 1; | ||||||
|  | `; | ||||||
|  |  | ||||||
|  | function FullWidthContainer({ children, title, icon }: OwnProps) { | ||||||
|  |   return ( | ||||||
|  |     <StyledContainer> | ||||||
|  |       <TopBar title={title} icon={icon} /> | ||||||
|  |       <ContentContainer> | ||||||
|  |         <ContentSubContainer>{children}</ContentSubContainer> | ||||||
|  |       </ContentContainer> | ||||||
|  |     </StyledContainer> | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default FullWidthContainer; | ||||||
| @@ -1,40 +1,44 @@ | |||||||
| import styled from '@emotion/styled'; | import styled from '@emotion/styled'; | ||||||
| import { useNavigate } from 'react-router-dom'; | import { useNavigate } from 'react-router-dom'; | ||||||
|  | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; | ||||||
|  | import { IconProp } from '@fortawesome/fontawesome-svg-core'; | ||||||
|  |  | ||||||
| type OwnProps = { | type OwnProps = { | ||||||
|   label: string; |   label: string; | ||||||
|   to: string; |   to: string; | ||||||
|   active?: boolean; |   active?: boolean; | ||||||
|  |   icon: IconProp; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| type StyledItemProps = { | type StyledItemProps = { | ||||||
|   active?: boolean; |   active?: boolean; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| const StyledItem = styled.button` | const StyledItem = styled.button<StyledItemProps>` | ||||||
|   display: flex; |   display: flex; | ||||||
|   height: 60px; |   border: none; | ||||||
|   background: inherit; |   font-size: 12px; | ||||||
|   align-items: center; |  | ||||||
|   padding-left: 10px; |  | ||||||
|   padding-right: 10px; |  | ||||||
|   margin-left: 10px; |  | ||||||
|   margin-right: 10px; |  | ||||||
|   font-size: 16px; |  | ||||||
|   margin-bottom: -2px; |  | ||||||
|   cursor: pointer; |   cursor: pointer; | ||||||
|   color: ${(props: StyledItemProps) => (props.active ? 'black' : '#2e3138')}; |   background: ${(props) => (props.active ? 'rgba(0, 0, 0, 0.04)' : 'inherit')}; | ||||||
|   font-weight: ${(props: StyledItemProps) => |   padding-top: 4px; | ||||||
|     props.active ? 'bold' : 'inherit'}; |   padding-bottom: 4px; | ||||||
|   border: 0; |   padding-left: 4px; | ||||||
|   border-bottom: ${(props: StyledItemProps) => |   font-family: 'Inter'; | ||||||
|     props.active ? '2px solid black' : '2px solid #eaecee'}; |   color: ${(props) => | ||||||
|   &:hover { |     props.active ? props.theme.text100 : props.theme.text60}; | ||||||
|     border-bottom: 2px solid #2e3138; |   border-radius: 4px; | ||||||
|  |   :hover { | ||||||
|  |     background: rgba(0, 0, 0, 0.04); | ||||||
|  |     color: ${(props) => props.theme.text100}; | ||||||
|   } |   } | ||||||
| `; | `; | ||||||
|  |  | ||||||
| function NavItem({ label, to, active }: OwnProps) { | const StyledItemLabel = styled.div` | ||||||
|  |   display: flex; | ||||||
|  |   margin-left: 8px; | ||||||
|  | `; | ||||||
|  |  | ||||||
|  | function NavItem({ label, icon, to, active }: OwnProps) { | ||||||
|   const navigate = useNavigate(); |   const navigate = useNavigate(); | ||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
| @@ -45,7 +49,8 @@ function NavItem({ label, to, active }: OwnProps) { | |||||||
|       active={active} |       active={active} | ||||||
|       aria-selected={active} |       aria-selected={active} | ||||||
|     > |     > | ||||||
|       {label} |       <FontAwesomeIcon icon={icon} /> | ||||||
|  |       <StyledItemLabel>{label}</StyledItemLabel> | ||||||
|     </StyledItem> |     </StyledItem> | ||||||
|   ); |   ); | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										22
									
								
								front/src/layout/navbar/NavTitle.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								front/src/layout/navbar/NavTitle.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | import styled from '@emotion/styled'; | ||||||
|  |  | ||||||
|  | type OwnProps = { | ||||||
|  |   label: string; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const StyledTitle = styled.div` | ||||||
|  |   display: flex; | ||||||
|  |   text-transform: uppercase; | ||||||
|  |   color: ${(props) => props.theme.text30}; | ||||||
|  |   font-size: 12px; | ||||||
|  |   font-weight: 600; | ||||||
|  |   padding-top: 4px; | ||||||
|  |   padding-bottom: 4px; | ||||||
|  |   padding-left: 4px; | ||||||
|  | `; | ||||||
|  |  | ||||||
|  | function NavTitle({ label }: OwnProps) { | ||||||
|  |   return <StyledTitle>{label}</StyledTitle>; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default NavTitle; | ||||||
| @@ -1,64 +1,62 @@ | |||||||
| import styled from '@emotion/styled'; | import styled from '@emotion/styled'; | ||||||
| import { useMatch, useResolvedPath } from 'react-router-dom'; | import { useMatch, useResolvedPath } from 'react-router-dom'; | ||||||
| import { User } from '../../interfaces/user.interface'; | import { User } from '../../interfaces/user.interface'; | ||||||
|  | import { Workspace } from '../../interfaces/workspace.interface'; | ||||||
| import NavItem from './NavItem'; | import NavItem from './NavItem'; | ||||||
| import ProfileContainer from './ProfileContainer'; | import NavTitle from './NavTitle'; | ||||||
|  | import WorkspaceContainer from './WorkspaceContainer'; | ||||||
|  | import { faUser } from '@fortawesome/free-regular-svg-icons'; | ||||||
|  | import { faBuilding } from '@fortawesome/free-regular-svg-icons'; | ||||||
|  |  | ||||||
| const NavbarContainer = styled.div` | const NavbarContainer = styled.div` | ||||||
|   display: flex; |   display: flex; | ||||||
|   flex-direction: row; |   flex-direction: column; | ||||||
|   justify-content: space-between; |   background: ${(props) => props.theme.noisyBackground}; | ||||||
|   padding-left: 12px; |   min-width: 220px; | ||||||
|   height: 58px; |   padding: 8px; | ||||||
|   border-bottom: 2px solid #eaecee; |  | ||||||
| `; | `; | ||||||
|  |  | ||||||
| const NavItemsContainer = styled.div` | const NavItemsContainer = styled.div` | ||||||
|   display: flex; |   display: flex; | ||||||
|   flex-direction: row; |   flex-direction: column; | ||||||
|  |   margin-top: 40px; | ||||||
| `; | `; | ||||||
|  |  | ||||||
| type OwnProps = { | type OwnProps = { | ||||||
|   user?: User; |   user?: User; | ||||||
|  |   workspace?: Workspace; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| function Navbar({ user }: OwnProps) { | function Navbar({ workspace }: OwnProps) { | ||||||
|   return ( |   return ( | ||||||
|     <> |     <> | ||||||
|       <NavbarContainer> |       <NavbarContainer> | ||||||
|  |         {workspace && <WorkspaceContainer workspace={workspace} />} | ||||||
|         <NavItemsContainer> |         <NavItemsContainer> | ||||||
|  |           <NavTitle label="Workspace" /> | ||||||
|           <NavItem |           <NavItem | ||||||
|             label="Inbox" |             label="People" | ||||||
|             to="/" |             to="/people" | ||||||
|  |             icon={faUser} | ||||||
|             active={ |             active={ | ||||||
|               !!useMatch({ |               !!useMatch({ | ||||||
|                 path: useResolvedPath('/').pathname, |                 path: useResolvedPath('/people').pathname, | ||||||
|                 end: true, |                 end: true, | ||||||
|               }) |               }) | ||||||
|             } |             } | ||||||
|           /> |           /> | ||||||
|           <NavItem |           <NavItem | ||||||
|             label="Contacts" |             label="Companies" | ||||||
|             to="/contacts" |             to="/companies" | ||||||
|  |             icon={faBuilding} | ||||||
|             active={ |             active={ | ||||||
|               !!useMatch({ |               !!useMatch({ | ||||||
|                 path: useResolvedPath('/contacts').pathname, |                 path: useResolvedPath('/companies').pathname, | ||||||
|                 end: true, |  | ||||||
|               }) |  | ||||||
|             } |  | ||||||
|           /> |  | ||||||
|           <NavItem |  | ||||||
|             label="Insights" |  | ||||||
|             to="/insights" |  | ||||||
|             active={ |  | ||||||
|               !!useMatch({ |  | ||||||
|                 path: useResolvedPath('/insights').pathname, |  | ||||||
|                 end: true, |                 end: true, | ||||||
|               }) |               }) | ||||||
|             } |             } | ||||||
|           /> |           /> | ||||||
|         </NavItemsContainer> |         </NavItemsContainer> | ||||||
|         <ProfileContainer user={user} /> |  | ||||||
|       </NavbarContainer> |       </NavbarContainer> | ||||||
|     </> |     </> | ||||||
|   ); |   ); | ||||||
|   | |||||||
| @@ -1,63 +0,0 @@ | |||||||
| import styled from '@emotion/styled'; |  | ||||||
| import { User } from '../../interfaces/user.interface'; |  | ||||||
|  |  | ||||||
| type OwnProps = { |  | ||||||
|   user?: User; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const StyledContainer = styled.button` |  | ||||||
|   display: flex; |  | ||||||
|   height: 60px; |  | ||||||
|   background: inherit; |  | ||||||
|   align-items: center; |  | ||||||
|   padding-left: 10px; |  | ||||||
|   padding-right: 10px; |  | ||||||
|   margin-left: 10px; |  | ||||||
|   margin-right: 10px; |  | ||||||
|   font-size: 14px; |  | ||||||
|   margin-bottom: -2px; |  | ||||||
|   cursor: pointer; |  | ||||||
|   border: 0; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledInfoContainer = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   flex-direction: column; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledEmail = styled.div` |  | ||||||
|   display: flex; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledAvatar = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   width: 40px; |  | ||||||
|   height: 40px; |  | ||||||
|   border-radius: 40px; |  | ||||||
|   background: black; |  | ||||||
|   font-size: 20px; |  | ||||||
|   color: white; |  | ||||||
|   align-items: center; |  | ||||||
|   justify-content: center; |  | ||||||
|   font-weight: bold; |  | ||||||
|   margin-right: 16px; |  | ||||||
|   flex-shrink: 0; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| function ProfileContainer({ user }: OwnProps) { |  | ||||||
|   return ( |  | ||||||
|     <StyledContainer> |  | ||||||
|       <StyledAvatar> |  | ||||||
|         {user?.first_name |  | ||||||
|           .split(' ') |  | ||||||
|           .map((n) => n[0]) |  | ||||||
|           .join('')} |  | ||||||
|       </StyledAvatar> |  | ||||||
|       <StyledInfoContainer> |  | ||||||
|         <StyledEmail>{user?.email}</StyledEmail> |  | ||||||
|       </StyledInfoContainer> |  | ||||||
|     </StyledContainer> |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default ProfileContainer; |  | ||||||
							
								
								
									
										51
									
								
								front/src/layout/navbar/WorkspaceContainer.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								front/src/layout/navbar/WorkspaceContainer.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | |||||||
|  | import styled from '@emotion/styled'; | ||||||
|  | import { Workspace } from '../../interfaces/workspace.interface'; | ||||||
|  |  | ||||||
|  | type OwnProps = { | ||||||
|  |   workspace: Workspace; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const StyledContainer = styled.button` | ||||||
|  |   display: inline-flex; | ||||||
|  |   width: min-content; | ||||||
|  |   height: 34px; | ||||||
|  |   align-items: center; | ||||||
|  |   cursor: pointer; | ||||||
|  |   border: 0; | ||||||
|  |   background: inherit; | ||||||
|  |   border: 1px solid ${(props) => props.theme.primaryBorder}; | ||||||
|  |   border-radius: 4px; | ||||||
|  |   padding: 8px; | ||||||
|  |   margin-left: 4px; | ||||||
|  | `; | ||||||
|  |  | ||||||
|  | type StyledLogoProps = { | ||||||
|  |   logo: string; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const StyledLogo = styled.div<StyledLogoProps>` | ||||||
|  |   background: url(${(props) => props.logo}); | ||||||
|  |   background-size: cover; | ||||||
|  |   width: 16px; | ||||||
|  |   height: 16px; | ||||||
|  |   border-radius: 2px; | ||||||
|  | `; | ||||||
|  |  | ||||||
|  | const StyledName = styled.div` | ||||||
|  |   margin-left: 4px; | ||||||
|  |   font-family: 'Inter'; | ||||||
|  |   font-weight: 500; | ||||||
|  |   font-size: 14px; | ||||||
|  |   font-color: ${(props) => props.theme.text0}; | ||||||
|  | `; | ||||||
|  |  | ||||||
|  | function ProfileContainer({ workspace }: OwnProps) { | ||||||
|  |   return ( | ||||||
|  |     <StyledContainer> | ||||||
|  |       <StyledLogo logo={workspace.logo}></StyledLogo> | ||||||
|  |       <StyledName>{workspace?.name}</StyledName> | ||||||
|  |     </StyledContainer> | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default ProfileContainer; | ||||||
| @@ -1,6 +1,9 @@ | |||||||
| import { MemoryRouter } from 'react-router-dom'; | import { MemoryRouter } from 'react-router-dom'; | ||||||
|  | import { faUser } from '@fortawesome/free-regular-svg-icons'; | ||||||
|  | import { ThemeProvider } from '@emotion/react'; | ||||||
|  |  | ||||||
| import NavItem from '../../../layout/navbar/NavItem'; | import NavItem from '../../../layout/navbar/NavItem'; | ||||||
|  | import { lightTheme } from '../../styles/themes'; | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|   title: 'NavItem', |   title: 'NavItem', | ||||||
| @@ -8,13 +11,17 @@ export default { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| export const NavItemDefault = () => ( | export const NavItemDefault = () => ( | ||||||
|   <MemoryRouter> |   <ThemeProvider theme={lightTheme}> | ||||||
|     <NavItem label="Test" to="/test" /> |     <MemoryRouter> | ||||||
|   </MemoryRouter> |       <NavItem label="Test" to="/test" icon={faUser} /> | ||||||
|  |     </MemoryRouter> | ||||||
|  |   </ThemeProvider> | ||||||
| ); | ); | ||||||
|  |  | ||||||
| export const NavItemActive = () => ( | export const NavItemActive = () => ( | ||||||
|   <MemoryRouter initialEntries={['/test']}> |   <ThemeProvider theme={lightTheme}> | ||||||
|     <NavItem label="Test" to="/test" active={true} /> |     <MemoryRouter initialEntries={['/test']}> | ||||||
|   </MemoryRouter> |       <NavItem label="Test" to="/test" active={true} icon={faUser} /> | ||||||
|  |     </MemoryRouter> | ||||||
|  |   </ThemeProvider> | ||||||
| ); | ); | ||||||
|   | |||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -1,16 +1,16 @@ | |||||||
| import { render } from '@testing-library/react'; | import { render } from '@testing-library/react'; | ||||||
|  |  | ||||||
| import { NavbarOnInsights } from '../__stories__/Navbar.stories'; | import { NavbarOnCompanies } from '../__stories__/Navbar.stories'; | ||||||
|  |  | ||||||
| it('Checks the NavItem renders', () => { | it('Checks the NavItem renders', () => { | ||||||
|   const { getByRole } = render(<NavbarOnInsights />); |   const { getByRole } = render(<NavbarOnCompanies />); | ||||||
|  |  | ||||||
|   expect(getByRole('button', { name: 'Insights' })).toHaveAttribute( |   expect(getByRole('button', { name: 'Companies' })).toHaveAttribute( | ||||||
|     'aria-selected', |     'aria-selected', | ||||||
|     'true', |     'true', | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
|   expect(getByRole('button', { name: 'Inbox' })).toHaveAttribute( |   expect(getByRole('button', { name: 'People' })).toHaveAttribute( | ||||||
|     'aria-selected', |     'aria-selected', | ||||||
|     'false', |     'false', | ||||||
|   ); |   ); | ||||||
|   | |||||||
							
								
								
									
										55
									
								
								front/src/layout/styles/themes.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								front/src/layout/styles/themes.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | |||||||
|  | export const lightTheme = { | ||||||
|  |   noisyBackground: | ||||||
|  |     '#fcfcfc url(data:image/png;base64,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);', | ||||||
|  |   primaryBackground: '#fff', | ||||||
|  |   secondaryBackground: '#fcfcfc', | ||||||
|  |   tertiaryBackground: '#f5f5f5', | ||||||
|  |   pinkBackground: '#ffe5f4', | ||||||
|  |   greenBackground: '#e6fff2', | ||||||
|  |   purpleBackground: '#e0e0ff', | ||||||
|  |   yellowBackground: '#fff2e7', | ||||||
|  |  | ||||||
|  |   primaryBorder: 'rgba(0, 0, 0, 0.08)', | ||||||
|  |  | ||||||
|  |   text100: '#000', | ||||||
|  |   text80: '#333', | ||||||
|  |   text60: '#666', | ||||||
|  |   text40: '#999', | ||||||
|  |   text30: '#b3b3b3', | ||||||
|  |   text20: '#ccc', | ||||||
|  |   text0: '#fff', | ||||||
|  |  | ||||||
|  |   blue: '#1961ed', | ||||||
|  |   pink: '#cc0078', | ||||||
|  |   green: '#1e7e50', | ||||||
|  |   purple: '#1111b7', | ||||||
|  |   yellow: '#cc660a', | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const darkTheme = { | ||||||
|  |   noisyBackground: | ||||||
|  |     '#191919 url(data:image/png;base64,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);', | ||||||
|  |   primaryBackground: '#141414', | ||||||
|  |   secondaryBackground: '#171717', | ||||||
|  |   tertiaryBackground: '#333333', | ||||||
|  |   pinkBackground: '#cc0078', | ||||||
|  |   greenBackground: '#1e7e50', | ||||||
|  |   purpleBackground: '#1111b7', | ||||||
|  |   yellowBackground: '#cc660a', | ||||||
|  |  | ||||||
|  |   text100: '#ffffff', | ||||||
|  |   text80: '#ccc', | ||||||
|  |   text60: '#999', | ||||||
|  |   text40: '#666', | ||||||
|  |   text30: '#4c4c4c', | ||||||
|  |   text20: '#333', | ||||||
|  |   text0: '#000', | ||||||
|  |  | ||||||
|  |   blue: '#6895ec', | ||||||
|  |   pink: '#ffe5f4', | ||||||
|  |   green: '#e6fff2', | ||||||
|  |   purple: '#e0e0ff', | ||||||
|  |   yellow: '#fff2e7', | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export type ThemeType = typeof lightTheme; | ||||||
							
								
								
									
										38
									
								
								front/src/layout/top-bar/TopBar.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								front/src/layout/top-bar/TopBar.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | |||||||
|  | import styled from '@emotion/styled'; | ||||||
|  | import { IconProp } from '@fortawesome/fontawesome-svg-core'; | ||||||
|  | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; | ||||||
|  |  | ||||||
|  | const TopBarContainer = styled.div` | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: row; | ||||||
|  |   height: 40px; | ||||||
|  |   align-items: center; | ||||||
|  |   background: ${(props) => props.theme.noisyBackground}; | ||||||
|  |   padding: 8px; | ||||||
|  |   font-size: 14px; | ||||||
|  |   color: ${(props) => props.theme.text80}; | ||||||
|  | `; | ||||||
|  |  | ||||||
|  | const TitleContainer = styled.div` | ||||||
|  |   font-family: 'Inter'; | ||||||
|  |   margin-left: 4px; | ||||||
|  |   font-size: 14px; | ||||||
|  | `; | ||||||
|  |  | ||||||
|  | type OwnProps = { | ||||||
|  |   title: string; | ||||||
|  |   icon: IconProp; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | function TopBar({ title, icon }: OwnProps) { | ||||||
|  |   return ( | ||||||
|  |     <> | ||||||
|  |       <TopBarContainer> | ||||||
|  |         <FontAwesomeIcon icon={icon} /> | ||||||
|  |         <TitleContainer data-testid="top-bar-title">{title}</TitleContainer> | ||||||
|  |       </TopBarContainer> | ||||||
|  |     </> | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default TopBar; | ||||||
| @@ -1,9 +0,0 @@ | |||||||
| function Contacts() { |  | ||||||
|   return ( |  | ||||||
|     <div> |  | ||||||
|       <h1>This is the history page</h1> |  | ||||||
|     </div> |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default Contacts; |  | ||||||
| @@ -1,9 +0,0 @@ | |||||||
| function Insights() { |  | ||||||
|   return ( |  | ||||||
|     <div> |  | ||||||
|       <h1>This is the insights page</h1> |  | ||||||
|     </div> |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default Insights; |  | ||||||
							
								
								
									
										12
									
								
								front/src/pages/companies/Companies.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								front/src/pages/companies/Companies.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | import { faBuilding } from '@fortawesome/free-regular-svg-icons'; | ||||||
|  | import WithTopBarContainer from '../../layout/containers/WithTopBarContainer'; | ||||||
|  |  | ||||||
|  | function Companies() { | ||||||
|  |   return ( | ||||||
|  |     <WithTopBarContainer title="Companies" icon={faBuilding}> | ||||||
|  |       <></> | ||||||
|  |     </WithTopBarContainer> | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default Companies; | ||||||
							
								
								
									
										18
									
								
								front/src/pages/companies/__stories__/Companies.stories.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								front/src/pages/companies/__stories__/Companies.stories.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | import { MemoryRouter } from 'react-router-dom'; | ||||||
|  | import Companies from '../Companies'; | ||||||
|  | import { ThemeProvider } from '@emotion/react'; | ||||||
|  | import { lightTheme } from '../../../layout/styles/themes'; | ||||||
|  | import AppLayout from '../../../layout/AppLayout'; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   title: 'Companies', | ||||||
|  |   component: Companies, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const CompaniesDefault = () => ( | ||||||
|  |   <ThemeProvider theme={lightTheme}> | ||||||
|  |     <MemoryRouter> | ||||||
|  |       <Companies /> | ||||||
|  |     </MemoryRouter> | ||||||
|  |   </ThemeProvider> | ||||||
|  | ); | ||||||
							
								
								
									
										10
									
								
								front/src/pages/companies/__tests__/Companies.test.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								front/src/pages/companies/__tests__/Companies.test.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | import { render } from '@testing-library/react'; | ||||||
|  |  | ||||||
|  | import { CompaniesDefault } from '../__stories__/Companies.stories'; | ||||||
|  |  | ||||||
|  | it('Checks the Companies page render', () => { | ||||||
|  |   const { getByTestId } = render(<CompaniesDefault />); | ||||||
|  |  | ||||||
|  |   const title = getByTestId('top-bar-title'); | ||||||
|  |   expect(title).toHaveTextContent('Companies'); | ||||||
|  | }); | ||||||
| @@ -1,18 +0,0 @@ | |||||||
| import FullWidthContainer from '../../layout/containers/FullWidthContainer'; |  | ||||||
| import DiscussionPanel from './discussion-panel/DiscussionPanel'; |  | ||||||
| import ListPanel from './list-panel/ListPanel'; |  | ||||||
| import PluginPanel from './plugin-panel/PluginPanel'; |  | ||||||
|  |  | ||||||
| function Inbox() { |  | ||||||
|   return ( |  | ||||||
|     <FullWidthContainer> |  | ||||||
|       <> |  | ||||||
|         <ListPanel /> |  | ||||||
|         <DiscussionPanel /> |  | ||||||
|         <PluginPanel /> |  | ||||||
|       </> |  | ||||||
|     </FullWidthContainer> |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default Inbox; |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| import { MemoryRouter } from 'react-router-dom'; |  | ||||||
| import Inbox from '../Inbox'; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   title: 'Inbox', |  | ||||||
|   component: Inbox, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export const InboxDefault = () => ( |  | ||||||
|   <MemoryRouter> |  | ||||||
|     <Inbox /> |  | ||||||
|   </MemoryRouter> |  | ||||||
| ); |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| import { render } from '@testing-library/react'; |  | ||||||
|  |  | ||||||
| import { InboxDefault } from '../__stories__/Inbox.stories'; |  | ||||||
|  |  | ||||||
| it('Checks the Inbox page render', () => { |  | ||||||
|   const { getAllByRole } = render(<InboxDefault />); |  | ||||||
|  |  | ||||||
|   const button = getAllByRole('button'); |  | ||||||
|   expect(button[0]).toHaveTextContent('Sylvie Vartan'); |  | ||||||
| }); |  | ||||||
| @@ -1,100 +0,0 @@ | |||||||
| import styled from '@emotion/styled'; |  | ||||||
| import Composer from './composer/Composer'; |  | ||||||
| import Booking, { BookingEvent } from './events/Booking'; |  | ||||||
| import Message, { MessageEvent } from './events/Message'; |  | ||||||
| import Note, { NoteEvent } from './events/Note'; |  | ||||||
|  |  | ||||||
| export type Event = BookingEvent | MessageEvent | NoteEvent; |  | ||||||
|  |  | ||||||
| const StyledPanel = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   flex-grow: 1; |  | ||||||
|   flex-direction: column; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const EventsContainer = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   flex-grow: 1; |  | ||||||
|   flex-direction: column; |  | ||||||
|   padding: 32px; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledToday = styled.div` |  | ||||||
|   font-size: 12px; |  | ||||||
|   color: #2e3138; |  | ||||||
|   border-bottom: 1px solid #eaecee; |  | ||||||
|   margin-top: 32px; |  | ||||||
|   padding-bottom: 8px; |  | ||||||
|   margin-bottom: 8px; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const ComposerContainer = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   padding: 32px; |  | ||||||
|   flex-direction: column; |  | ||||||
|   flex-grow: 1; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| function DiscussionPanel() { |  | ||||||
|   return ( |  | ||||||
|     <StyledPanel> |  | ||||||
|       <EventsContainer> |  | ||||||
|         <Booking |  | ||||||
|           booking={{ |  | ||||||
|             id: 1, |  | ||||||
|             time: 'Wed, Sep 10, 2022', |  | ||||||
|             user: 'Georges', |  | ||||||
|             nights: 4, |  | ||||||
|             guests: 5, |  | ||||||
|             price: '756.90$', |  | ||||||
|             listing: 'Rochefort Montagne', |  | ||||||
|             dateRange: 'Mon, Sep 30 - Fri, Oct 2', |  | ||||||
|           }} |  | ||||||
|         /> |  | ||||||
|         <StyledToday>Today</StyledToday> |  | ||||||
|         <Message |  | ||||||
|           message={{ |  | ||||||
|             id: 1, |  | ||||||
|             time: '2 hours ago', |  | ||||||
|             user: 'Georges Alain', |  | ||||||
|             channel: 'sms', |  | ||||||
|             message: |  | ||||||
|               'I’m looking for my order but couldn’t find it. Could you help me find it. I don’t know where to look for.', |  | ||||||
|           }} |  | ||||||
|         /> |  | ||||||
|         <Message |  | ||||||
|           message={{ |  | ||||||
|             id: 2, |  | ||||||
|             time: 'just now', |  | ||||||
|             user: 'Support', |  | ||||||
|             channel: 'sms', |  | ||||||
|             message: 'Hello I’m here bla bla bla', |  | ||||||
|             agent: 'Leslie A', |  | ||||||
|           }} |  | ||||||
|         /> |  | ||||||
|         <Note |  | ||||||
|           note={{ |  | ||||||
|             id: 1, |  | ||||||
|             time: 'just now', |  | ||||||
|             agent: 'LeslieA', |  | ||||||
|             message: 'Hello I’m here bla bla bla', |  | ||||||
|           }} |  | ||||||
|         /> |  | ||||||
|         <Message |  | ||||||
|           message={{ |  | ||||||
|             id: 3, |  | ||||||
|             time: 'just now', |  | ||||||
|             user: 'Georges Alain', |  | ||||||
|             channel: 'sms', |  | ||||||
|             message: 'Thank you !', |  | ||||||
|           }} |  | ||||||
|         /> |  | ||||||
|       </EventsContainer> |  | ||||||
|       <ComposerContainer> |  | ||||||
|         <Composer /> |  | ||||||
|       </ComposerContainer> |  | ||||||
|     </StyledPanel> |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default DiscussionPanel; |  | ||||||
| @@ -1,8 +0,0 @@ | |||||||
| import DiscussionPanel from '../DiscussionPanel'; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   title: 'DiscussionPanel', |  | ||||||
|   component: DiscussionPanel, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export const DiscussionPanelDefault = () => <DiscussionPanel />; |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| import { render } from '@testing-library/react'; |  | ||||||
|  |  | ||||||
| import { DiscussionPanelDefault } from '../__stories__/DiscussionPanel.stories'; |  | ||||||
|  |  | ||||||
| it('Checks the discussion panel render', () => { |  | ||||||
|   const { getAllByText } = render(<DiscussionPanelDefault />); |  | ||||||
|  |  | ||||||
|   const text = getAllByText('Rochefort Montagne'); |  | ||||||
|   expect(text).toBeDefined(); |  | ||||||
| }); |  | ||||||
| @@ -1,57 +0,0 @@ | |||||||
| import styled from '@emotion/styled'; |  | ||||||
| import ComposerSwitch from './ComposerSwitch'; |  | ||||||
|  |  | ||||||
| const StyledContainer = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   flex-direction: column; |  | ||||||
|   border: 2px solid #000000; |  | ||||||
|   border-radius: 12px; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledInputContainer = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   padding: 8px; |  | ||||||
|   justify-content: center; |  | ||||||
|   & > textarea { |  | ||||||
|     width: 95%; |  | ||||||
|     border: none; |  | ||||||
|     outline: none; |  | ||||||
|     font-family: 'Source Sans Pro'; |  | ||||||
|  |  | ||||||
|     &::placeholder { |  | ||||||
|       font-family: 'Source Sans Pro'; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const ActionContainer = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   padding: 16px; |  | ||||||
|   justify-content: flex-end; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const PrimaryButton = styled.button` |  | ||||||
|   background: black; |  | ||||||
|   font-weight: bold; |  | ||||||
|   color: white; |  | ||||||
|   padding: 16px 24px; |  | ||||||
|   border: 0; |  | ||||||
|   border-radius: 12px; |  | ||||||
|   cursor: pointer; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| function Composer() { |  | ||||||
|   return ( |  | ||||||
|     <StyledContainer> |  | ||||||
|       <ComposerSwitch /> |  | ||||||
|       <StyledInputContainer> |  | ||||||
|         <textarea rows={5} placeholder="Type to chat..."></textarea> |  | ||||||
|       </StyledInputContainer> |  | ||||||
|       <ActionContainer> |  | ||||||
|         <PrimaryButton>Reply by SMS</PrimaryButton> |  | ||||||
|       </ActionContainer> |  | ||||||
|     </StyledContainer> |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default Composer; |  | ||||||
| @@ -1,49 +0,0 @@ | |||||||
| import styled from '@emotion/styled'; |  | ||||||
|  |  | ||||||
| const StyledContainer = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   flex-direction: row; |  | ||||||
|   border-bottom: 2px solid #eaecee; |  | ||||||
|   padding: 0px 12px; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const SwitchTab = styled.button` |  | ||||||
|   display: flex; |  | ||||||
|   border-bottom: 2px solid #eaecee; |  | ||||||
|   margin-bottom: -2px; |  | ||||||
|   padding: 12px; |  | ||||||
|   cursor: pointer; |  | ||||||
|   color: #2e3138; |  | ||||||
|   background: inherit; |  | ||||||
|   border: 0; |  | ||||||
|  |  | ||||||
|   &:hover { |  | ||||||
|     border-bottom: 2px solid #2e3138; |  | ||||||
|   } |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const SwitchTabActive = styled.button` |  | ||||||
|   display: flex; |  | ||||||
|   border: 0; |  | ||||||
|   border-bottom: 2px solid black; |  | ||||||
|   margin-bottom: -2px; |  | ||||||
|   padding: 12px; |  | ||||||
|   cursor: pointer; |  | ||||||
|   color: black; |  | ||||||
|   font-weight: bold; |  | ||||||
|   background: inherit; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| function ComposerSwitch() { |  | ||||||
|   return ( |  | ||||||
|     <StyledContainer> |  | ||||||
|       <SwitchTabActive>Reply</SwitchTabActive> |  | ||||||
|       <SwitchTab>Call</SwitchTab> |  | ||||||
|       <SwitchTab>Note</SwitchTab> |  | ||||||
|       <SwitchTab>Transfer</SwitchTab> |  | ||||||
|       <SwitchTab>Help</SwitchTab> |  | ||||||
|     </StyledContainer> |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default ComposerSwitch; |  | ||||||
| @@ -1,8 +0,0 @@ | |||||||
| import Composer from '../Composer'; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   title: 'Composer', |  | ||||||
|   component: Composer, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export const ComposerDefault = () => <Composer />; |  | ||||||
| @@ -1,8 +0,0 @@ | |||||||
| import ComposerSwitch from '../ComposerSwitch'; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   title: 'Composer', |  | ||||||
|   component: ComposerSwitch, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export const ComposerSwithDefault = () => <ComposerSwitch />; |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| import { render } from '@testing-library/react'; |  | ||||||
|  |  | ||||||
| import { ComposerDefault } from '../__stories__/Composer.stories'; |  | ||||||
|  |  | ||||||
| it('Checks the composer render', () => { |  | ||||||
|   const { getAllByRole } = render(<ComposerDefault />); |  | ||||||
|  |  | ||||||
|   const button = getAllByRole('button'); |  | ||||||
|   expect(button[0]).toHaveTextContent('Reply'); |  | ||||||
| }); |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| import { render } from '@testing-library/react'; |  | ||||||
|  |  | ||||||
| import { ComposerSwithDefault } from '../__stories__/ComposerSwitch.stories'; |  | ||||||
|  |  | ||||||
| it('Checks the composer switch render', () => { |  | ||||||
|   const { getAllByRole } = render(<ComposerSwithDefault />); |  | ||||||
|  |  | ||||||
|   const button = getAllByRole('button'); |  | ||||||
|   expect(button[0]).toHaveTextContent('Reply'); |  | ||||||
| }); |  | ||||||
| @@ -1,80 +0,0 @@ | |||||||
| import styled from '@emotion/styled'; |  | ||||||
|  |  | ||||||
| export type BookingEvent = { |  | ||||||
|   id: number; |  | ||||||
|   user: string; |  | ||||||
|   time: string; |  | ||||||
|   listing: string; |  | ||||||
|   nights: number; |  | ||||||
|   guests: number; |  | ||||||
|   price: string; |  | ||||||
|   dateRange: string; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| type OwnProps = { |  | ||||||
|   booking: BookingEvent; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const StyledBooking = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   flex-direction: column; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledLabel = styled.div` |  | ||||||
|   font-size: 12px; |  | ||||||
|   color: #2e3138; |  | ||||||
|   margin-bottom: 8px; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledContainer = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   padding: 16px; |  | ||||||
|   flex-direction: row; |  | ||||||
|   border: 1px solid #000000; |  | ||||||
|   border-radius: 12px; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledPicture = styled.div` |  | ||||||
|   background: #2e3138; |  | ||||||
|   width: 50px; |  | ||||||
|   height: 42px; |  | ||||||
|   margin-right: 16px; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledContent = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   flex-direction: column; |  | ||||||
|   justify-content: center; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledListing = styled.div` |  | ||||||
|   font-size: 16px; |  | ||||||
|   font-weight: bold; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledDetails = styled.div` |  | ||||||
|   font-size: 12px; |  | ||||||
|   color: #2e3138; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| function Booking({ booking }: OwnProps) { |  | ||||||
|   return ( |  | ||||||
|     <StyledBooking> |  | ||||||
|       <StyledLabel> |  | ||||||
|         {booking.time} · {booking.user} booked a trip |  | ||||||
|       </StyledLabel> |  | ||||||
|       <StyledContainer> |  | ||||||
|         <StyledPicture /> |  | ||||||
|         <StyledContent> |  | ||||||
|           <StyledListing>{booking.listing}</StyledListing> |  | ||||||
|           <StyledDetails> |  | ||||||
|             {booking.dateRange} · {booking.nights} nights · {booking.guests}{' '} |  | ||||||
|             guests · {booking.price} |  | ||||||
|           </StyledDetails> |  | ||||||
|         </StyledContent> |  | ||||||
|       </StyledContainer> |  | ||||||
|     </StyledBooking> |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default Booking; |  | ||||||
| @@ -1,90 +0,0 @@ | |||||||
| import styled from '@emotion/styled'; |  | ||||||
|  |  | ||||||
| export type MessageEvent = { |  | ||||||
|   id: number; |  | ||||||
|   user: string; |  | ||||||
|   time: string; |  | ||||||
|   channel: string; |  | ||||||
|   message: string; |  | ||||||
|   agent?: string; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| type OwnProps = { |  | ||||||
|   message: MessageEvent; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const StyledMessage = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   margin-top: 12px; |  | ||||||
|   margin-bottom: 20px; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledAvatar = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   width: 40px; |  | ||||||
|   height: 40px; |  | ||||||
|   border-radius: 40px; |  | ||||||
|   background: black; |  | ||||||
|   font-size: 20px; |  | ||||||
|   color: white; |  | ||||||
|   align-items: center; |  | ||||||
|   justify-content: center; |  | ||||||
|   font-weight: bold; |  | ||||||
|   margin-right: 16px; |  | ||||||
|   flex-shrink: 0; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledContent = styled.div``; |  | ||||||
|  |  | ||||||
| const StyledTitle = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   align-items: center; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledUser = styled.div` |  | ||||||
|   font-size: 16px; |  | ||||||
|   color: black; |  | ||||||
|   font-weight: bold; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledTime = styled.div` |  | ||||||
|   margin-left: 8px; |  | ||||||
|   font-size: 12px; |  | ||||||
|   color: #2e3138; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledAgent = styled.div` |  | ||||||
|   text-decoration: underline; |  | ||||||
|   margin-left: 4px; |  | ||||||
|   font-size: 12px; |  | ||||||
|   color: #2e3138; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledDetails = styled.div` |  | ||||||
|   margin-top: 8px; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| function Message({ message }: OwnProps) { |  | ||||||
|   return ( |  | ||||||
|     <StyledMessage> |  | ||||||
|       <StyledAvatar> |  | ||||||
|         {message.user |  | ||||||
|           .split(' ') |  | ||||||
|           .map((n) => n[0]) |  | ||||||
|           .join('')} |  | ||||||
|       </StyledAvatar> |  | ||||||
|       <StyledContent> |  | ||||||
|         <StyledTitle> |  | ||||||
|           <StyledUser>{message.user}</StyledUser> |  | ||||||
|           <StyledTime> |  | ||||||
|             {message.time} ({message.channel}) |  | ||||||
|           </StyledTime> |  | ||||||
|           {message.agent && <StyledAgent>by {message.agent}</StyledAgent>} |  | ||||||
|         </StyledTitle> |  | ||||||
|         <StyledDetails>{message.message}</StyledDetails> |  | ||||||
|       </StyledContent> |  | ||||||
|     </StyledMessage> |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default Message; |  | ||||||
| @@ -1,52 +0,0 @@ | |||||||
| import styled from '@emotion/styled'; |  | ||||||
|  |  | ||||||
| export type NoteEvent = { |  | ||||||
|   id: number; |  | ||||||
|   time: string; |  | ||||||
|   message: string; |  | ||||||
|   agent: string; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| type OwnProps = { |  | ||||||
|   note: NoteEvent; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const StyledNote = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   background: #f8f9fa; |  | ||||||
|   border-left: 4px solid black; |  | ||||||
|   padding: 8px 20px; |  | ||||||
|   flex-direction: column; |  | ||||||
|   margin-top: 12px; |  | ||||||
|   margin-bottom: 20px; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledLabel = styled.div` |  | ||||||
|   font-size: 12px; |  | ||||||
|   color: #2e3138; |  | ||||||
|   margin-bottom: 8px; |  | ||||||
|   display: flex; |  | ||||||
|   flex-direction: row; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledAgent = styled.div` |  | ||||||
|   text-decoration: underline; |  | ||||||
|   margin-left: 4px; |  | ||||||
|   font-size: 12px; |  | ||||||
|   color: #2e3138; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledMessage = styled.div``; |  | ||||||
|  |  | ||||||
| function Note({ note }: OwnProps) { |  | ||||||
|   return ( |  | ||||||
|     <StyledNote> |  | ||||||
|       <StyledLabel> |  | ||||||
|         Internal Note {note.time} <StyledAgent>by {note.agent}</StyledAgent> |  | ||||||
|       </StyledLabel> |  | ||||||
|       <StyledMessage>{note.message}</StyledMessage> |  | ||||||
|     </StyledNote> |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default Note; |  | ||||||
| @@ -1,21 +0,0 @@ | |||||||
| import Booking from '../Booking'; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   title: 'DiscussionPanel', |  | ||||||
|   component: Booking, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export const BookingDefault = () => ( |  | ||||||
|   <Booking |  | ||||||
|     booking={{ |  | ||||||
|       id: 1, |  | ||||||
|       time: 'Wed, Sep 10, 2022', |  | ||||||
|       user: 'Georges', |  | ||||||
|       nights: 4, |  | ||||||
|       guests: 5, |  | ||||||
|       price: '756.90$', |  | ||||||
|       listing: 'Rochefort Montagne', |  | ||||||
|       dateRange: 'Mon, Sep 30 - Fri, Oct 2', |  | ||||||
|     }} |  | ||||||
|   /> |  | ||||||
| ); |  | ||||||
| @@ -1,19 +0,0 @@ | |||||||
| import Message from '../Message'; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   title: 'DiscussionPanel', |  | ||||||
|   component: Message, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export const MessageDefault = () => ( |  | ||||||
|   <Message |  | ||||||
|     message={{ |  | ||||||
|       id: 1, |  | ||||||
|       time: '2 hours ago', |  | ||||||
|       user: 'Georges Alain', |  | ||||||
|       channel: 'sms', |  | ||||||
|       message: |  | ||||||
|         'I’m looking for my order but couldn’t find it. Could you help me find it. I don’t know where to look for.', |  | ||||||
|     }} |  | ||||||
|   /> |  | ||||||
| ); |  | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| import Note from '../Note'; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   title: 'DiscussionPanel', |  | ||||||
|   component: Note, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export const NoteDefault = () => ( |  | ||||||
|   <Note |  | ||||||
|     note={{ |  | ||||||
|       id: 1, |  | ||||||
|       time: 'just now', |  | ||||||
|       agent: 'LeslieA', |  | ||||||
|       message: 'Hello I’m here bla bla bla', |  | ||||||
|     }} |  | ||||||
|   /> |  | ||||||
| ); |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| import { render } from '@testing-library/react'; |  | ||||||
|  |  | ||||||
| import { BookingDefault } from '../__stories__/Booking.stories'; |  | ||||||
|  |  | ||||||
| it('Checks the booking event render', () => { |  | ||||||
|   const { getAllByText } = render(<BookingDefault />); |  | ||||||
|  |  | ||||||
|   const text = getAllByText('Rochefort Montagne'); |  | ||||||
|   expect(text).toBeDefined(); |  | ||||||
| }); |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| import { render } from '@testing-library/react'; |  | ||||||
|  |  | ||||||
| import { MessageDefault } from '../__stories__/Message.stories'; |  | ||||||
|  |  | ||||||
| it('Checks the booking event render', () => { |  | ||||||
|   const { getAllByText } = render(<MessageDefault />); |  | ||||||
|  |  | ||||||
|   const text = getAllByText('Georges Alain'); |  | ||||||
|   expect(text).toBeDefined(); |  | ||||||
| }); |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| import { render } from '@testing-library/react'; |  | ||||||
|  |  | ||||||
| import { NoteDefault } from '../__stories__/Note.stories'; |  | ||||||
|  |  | ||||||
| it('Checks the booking event render', () => { |  | ||||||
|   const { getAllByText } = render(<NoteDefault />); |  | ||||||
|  |  | ||||||
|   const text = getAllByText('Hello I’m here bla bla bla'); |  | ||||||
|   expect(text).toBeDefined(); |  | ||||||
| }); |  | ||||||
| @@ -1,50 +0,0 @@ | |||||||
| import styled from '@emotion/styled'; |  | ||||||
| import ListPanelHeader from './ListPanelHeader'; |  | ||||||
| import ListPanelItem from './ListPanelItem'; |  | ||||||
|  |  | ||||||
| const StyledList = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   width: 325px; |  | ||||||
|   flex-direction: column; |  | ||||||
|   border-right: 2px solid #eaecee; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| export type Task = { |  | ||||||
|   id: number; |  | ||||||
|   targetUser: string; |  | ||||||
|   label: string; |  | ||||||
|   time: string; |  | ||||||
|   lastMessage: string; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| function ListPanel() { |  | ||||||
|   const tasks: Task[] = [ |  | ||||||
|     { |  | ||||||
|       id: 1, |  | ||||||
|       targetUser: 'Sylvie Vartan', |  | ||||||
|       label: 'Guest at #xxx property', |  | ||||||
|       time: '3h', |  | ||||||
|       lastMessage: |  | ||||||
|         'I’m looking for my order but couldn’t find it. Could you help me find it. I don’t know where ...', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 2, |  | ||||||
|       targetUser: 'Johnny Halliday', |  | ||||||
|       label: 'Guest at #xxx property', |  | ||||||
|       time: '4h', |  | ||||||
|       lastMessage: 'Hello, this is Johnny', |  | ||||||
|     }, |  | ||||||
|   ]; |  | ||||||
|   return ( |  | ||||||
|     <StyledList> |  | ||||||
|       <> |  | ||||||
|         <ListPanelHeader /> |  | ||||||
|         {tasks.map((item) => ( |  | ||||||
|           <ListPanelItem key={item.id} task={item} /> |  | ||||||
|         ))} |  | ||||||
|       </> |  | ||||||
|     </StyledList> |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default ListPanel; |  | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| import styled from '@emotion/styled'; |  | ||||||
|  |  | ||||||
| const StyledHeader = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   font-weight: bold; |  | ||||||
|   align-items: center; |  | ||||||
|   padding: 16px 24px; |  | ||||||
|   font-size: 18px; |  | ||||||
|   letter-spacing: 1px; |  | ||||||
|   border-bottom: 1px solid #eaecee; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| function ListPanelHeader() { |  | ||||||
|   return <StyledHeader>6 tasks waiting</StyledHeader>; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default ListPanelHeader; |  | ||||||
| @@ -1,98 +0,0 @@ | |||||||
| import styled from '@emotion/styled'; |  | ||||||
| import { Task } from './ListPanel'; |  | ||||||
|  |  | ||||||
| type OwnProps = { |  | ||||||
|   task: Task; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const StyledListItem = styled.button` |  | ||||||
|   display: flex; |  | ||||||
|   padding: 16px 24px; |  | ||||||
|   flex-direction: column; |  | ||||||
|   color: #2e3138; |  | ||||||
|   border: 0; |  | ||||||
|   border-bottom: 1px solid #eaecee; |  | ||||||
|   cursor: pointer; |  | ||||||
|   font-family: inherit; |  | ||||||
|   text-align: inherit; |  | ||||||
|   align-items: inherit; |  | ||||||
|   background: #f1f3f5; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledHeader = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   justify-content: space-between; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledAvatarAndTitle = styled.div` |  | ||||||
|   display: flex; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledAvatar = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   width: 40px; |  | ||||||
|   height: 40px; |  | ||||||
|   border-radius: 40px; |  | ||||||
|   background: #52555b; |  | ||||||
|   font-size: 20px; |  | ||||||
|   color: white; |  | ||||||
|   align-items: center; |  | ||||||
|   justify-content: center; |  | ||||||
|   font-weight: bold; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledTitle = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   flex-direction: column; |  | ||||||
|   margin-left: 8px; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledName = styled.div` |  | ||||||
|   font-weight: bold; |  | ||||||
|   font-size: 18px; |  | ||||||
|   color: black; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledLabel = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   font-size: 14px; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledTime = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   justify-self: flex-end; |  | ||||||
|   color: #7d8187; |  | ||||||
|   font-size: 14px; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledContent = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   color: #52555b; |  | ||||||
|   font-size: 14px; |  | ||||||
|   margin-top: 8px; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| function ListPanelItem({ task }: OwnProps) { |  | ||||||
|   return ( |  | ||||||
|     <StyledListItem> |  | ||||||
|       <StyledHeader> |  | ||||||
|         <StyledAvatarAndTitle> |  | ||||||
|           <StyledAvatar> |  | ||||||
|             {task.targetUser |  | ||||||
|               .split(' ') |  | ||||||
|               .map((n) => n[0]) |  | ||||||
|               .join('')} |  | ||||||
|           </StyledAvatar> |  | ||||||
|           <StyledTitle> |  | ||||||
|             <StyledName>{task.targetUser}</StyledName> |  | ||||||
|             <StyledLabel>{task.label}</StyledLabel> |  | ||||||
|           </StyledTitle> |  | ||||||
|         </StyledAvatarAndTitle> |  | ||||||
|         <StyledTime>{task.time}</StyledTime> |  | ||||||
|       </StyledHeader> |  | ||||||
|       <StyledContent>{task.lastMessage} </StyledContent> |  | ||||||
|     </StyledListItem> |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default ListPanelItem; |  | ||||||
| @@ -1,8 +0,0 @@ | |||||||
| import ListPanel from '../ListPanel'; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   title: 'ListPanel', |  | ||||||
|   component: ListPanel, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export const ListPanelDefault = () => <ListPanel />; |  | ||||||
| @@ -1,9 +0,0 @@ | |||||||
| import { MemoryRouter } from 'react-router-dom'; |  | ||||||
| import ListPanelHeader from '../ListPanelHeader'; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   title: 'ListPanel', |  | ||||||
|   component: ListPanelHeader, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export const ListPanelHeaderDefault = () => <ListPanelHeader />; |  | ||||||
| @@ -1,19 +0,0 @@ | |||||||
| import ListPanelItem from '../ListPanelItem'; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   title: 'ListPanel', |  | ||||||
|   component: ListPanelItem, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export const ListPanelItemDefault = () => ( |  | ||||||
|   <ListPanelItem |  | ||||||
|     task={{ |  | ||||||
|       id: 1, |  | ||||||
|       targetUser: 'Sylvie Vartan', |  | ||||||
|       label: 'Guest at #xxx property', |  | ||||||
|       time: '3h', |  | ||||||
|       lastMessage: |  | ||||||
|         'I’m looking for my order but couldn’t find it. Could you help me find it. I don’t know where ...', |  | ||||||
|     }} |  | ||||||
|   /> |  | ||||||
| ); |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| import { render } from '@testing-library/react'; |  | ||||||
|  |  | ||||||
| import { ListPanelDefault } from '../__stories__/ListPanel.stories'; |  | ||||||
|  |  | ||||||
| it('Checks the task list render', () => { |  | ||||||
|   const { getAllByRole } = render(<ListPanelDefault />); |  | ||||||
|  |  | ||||||
|   const button = getAllByRole('button'); |  | ||||||
|   expect(button[0]).toHaveTextContent('Sylvie Vartan'); |  | ||||||
| }); |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| import { render } from '@testing-library/react'; |  | ||||||
|  |  | ||||||
| import { ListPanelHeaderDefault } from '../__stories__/ListPanelHeader.stories'; |  | ||||||
|  |  | ||||||
| it('Checks the ListPanelHeader render', () => { |  | ||||||
|   const { getAllByText } = render(<ListPanelHeaderDefault />); |  | ||||||
|  |  | ||||||
|   const text = getAllByText('6 tasks waiting'); |  | ||||||
|   expect(text).toBeDefined(); |  | ||||||
| }); |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| import { render } from '@testing-library/react'; |  | ||||||
|  |  | ||||||
| import { ListPanelItemDefault } from '../__stories__/ListPanelItem.stories'; |  | ||||||
|  |  | ||||||
| it('Checks the ListPanelItem render', () => { |  | ||||||
|   const { getAllByText } = render(<ListPanelItemDefault />); |  | ||||||
|  |  | ||||||
|   const text = getAllByText('Sylvie Vartan'); |  | ||||||
|   expect(text).toBeDefined(); |  | ||||||
| }); |  | ||||||
| @@ -1,27 +0,0 @@ | |||||||
| import styled from '@emotion/styled'; |  | ||||||
| import PluginPanelNav from './PluginPanelNav'; |  | ||||||
| import PluginHistory from './plugin-history/PanelHistory'; |  | ||||||
|  |  | ||||||
| const StyledPanel = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   width: 350px; |  | ||||||
|   border-left: 1px solid #eaecee; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledContainer = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   flex-grow: 1; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| function PluginPanel() { |  | ||||||
|   return ( |  | ||||||
|     <StyledPanel> |  | ||||||
|       <StyledContainer> |  | ||||||
|         <PluginHistory /> |  | ||||||
|       </StyledContainer> |  | ||||||
|       <PluginPanelNav /> |  | ||||||
|     </StyledPanel> |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default PluginPanel; |  | ||||||
| @@ -1,46 +0,0 @@ | |||||||
| import styled from '@emotion/styled'; |  | ||||||
| import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; |  | ||||||
| import { faClone } from '@fortawesome/free-regular-svg-icons'; |  | ||||||
|  |  | ||||||
| const StyledNav = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   flex-direction: column; |  | ||||||
|   width: 60px; |  | ||||||
|   border-left: 1px solid #eaecee; |  | ||||||
|   background: #f1f3f5; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| const StyledNavItem = styled.div` |  | ||||||
|   display: flex; |  | ||||||
|   width: 60px; |  | ||||||
|   border-bottom: 1px solid #eaecee; |  | ||||||
|   padding: 22px; |  | ||||||
|   cursor: pointer; |  | ||||||
| `; |  | ||||||
|  |  | ||||||
| function PluginPanelNav() { |  | ||||||
|   return ( |  | ||||||
|     <StyledNav> |  | ||||||
|       <StyledNavItem> |  | ||||||
|         <FontAwesomeIcon icon={faClone} size="lg" /> |  | ||||||
|       </StyledNavItem> |  | ||||||
|       <StyledNavItem> |  | ||||||
|         <FontAwesomeIcon icon={faClone} size="lg" /> |  | ||||||
|       </StyledNavItem> |  | ||||||
|       <StyledNavItem> |  | ||||||
|         <FontAwesomeIcon icon={faClone} size="lg" /> |  | ||||||
|       </StyledNavItem> |  | ||||||
|       <StyledNavItem> |  | ||||||
|         <FontAwesomeIcon icon={faClone} size="lg" /> |  | ||||||
|       </StyledNavItem> |  | ||||||
|       <StyledNavItem> |  | ||||||
|         <FontAwesomeIcon icon={faClone} size="lg" /> |  | ||||||
|       </StyledNavItem> |  | ||||||
|       <StyledNavItem> |  | ||||||
|         <FontAwesomeIcon icon={faClone} size="lg" /> |  | ||||||
|       </StyledNavItem> |  | ||||||
|     </StyledNav> |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default PluginPanelNav; |  | ||||||
| @@ -1,5 +0,0 @@ | |||||||
| function PluginHistory() { |  | ||||||
|   return <div></div>; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default PluginHistory; |  | ||||||
| @@ -1,7 +0,0 @@ | |||||||
| import styled from '@emotion/styled'; |  | ||||||
|  |  | ||||||
| function UserActivity() { |  | ||||||
|   return; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default UserActivity; |  | ||||||
| @@ -1,7 +0,0 @@ | |||||||
| import styled from '@emotion/styled'; |  | ||||||
|  |  | ||||||
| function UserInformation() { |  | ||||||
|   return; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default UserInformation; |  | ||||||
							
								
								
									
										12
									
								
								front/src/pages/people/People.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								front/src/pages/people/People.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | import { faUser } from '@fortawesome/free-regular-svg-icons'; | ||||||
|  | import WithTopBarContainer from '../../layout/containers/WithTopBarContainer'; | ||||||
|  |  | ||||||
|  | function People() { | ||||||
|  |   return ( | ||||||
|  |     <WithTopBarContainer title="People" icon={faUser}> | ||||||
|  |       <></> | ||||||
|  |     </WithTopBarContainer> | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default People; | ||||||
							
								
								
									
										17
									
								
								front/src/pages/people/__stories__/People.stories.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								front/src/pages/people/__stories__/People.stories.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | import { MemoryRouter } from 'react-router-dom'; | ||||||
|  | import People from '../People'; | ||||||
|  | import { ThemeProvider } from '@emotion/react'; | ||||||
|  | import { lightTheme } from '../../../layout/styles/themes'; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   title: 'People', | ||||||
|  |   component: People, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const PeopleDefault = () => ( | ||||||
|  |   <ThemeProvider theme={lightTheme}> | ||||||
|  |     <MemoryRouter> | ||||||
|  |       <People /> | ||||||
|  |     </MemoryRouter> | ||||||
|  |   </ThemeProvider> | ||||||
|  | ); | ||||||
							
								
								
									
										10
									
								
								front/src/pages/people/__tests__/People.test.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								front/src/pages/people/__tests__/People.test.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | import { render } from '@testing-library/react'; | ||||||
|  |  | ||||||
|  | import { PeopleDefault } from '../__stories__/People.stories'; | ||||||
|  |  | ||||||
|  | it('Checks the People page render', () => { | ||||||
|  |   const { getByTestId } = render(<PeopleDefault />); | ||||||
|  |  | ||||||
|  |   const title = getByTestId('top-bar-title'); | ||||||
|  |   expect(title).toHaveTextContent('People'); | ||||||
|  | }); | ||||||
| @@ -8,10 +8,10 @@ sh: ## | |||||||
| 	@docker-compose exec twenty sh | 	@docker-compose exec twenty sh | ||||||
|  |  | ||||||
| front-test: ##  | front-test: ##  | ||||||
| 	@docker-compose exec twenty sh -c "npm run test" | 	@docker-compose exec twenty sh -c "cd front && npm run test" | ||||||
|  |  | ||||||
| front-coverage: ##  | front-coverage: ##  | ||||||
| 	@docker-compose exec twenty sh -c "npm run coverage" | 	@docker-compose exec twenty sh -c "cd front && npm run coverage" | ||||||
|  |  | ||||||
| front-storybook: ##  | front-storybook: ##  | ||||||
| 	@docker-compose exec twenty sh -c "npm run storybook" | 	@docker-compose exec twenty sh -c "cd front && npm run storybook" | ||||||
|   | |||||||
| @@ -1,5 +1,9 @@ | |||||||
| FROM node:18-alpine as app | FROM node:18-alpine as app | ||||||
|  |  | ||||||
|  | RUN apk update && apk upgrade && \ | ||||||
|  |     apk add --no-cache bash git openssh && \ | ||||||
|  |     apk add libc6-compat | ||||||
|  |  | ||||||
| WORKDIR /app | WORKDIR /app | ||||||
| COPY ../.. . | COPY ../.. . | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Charles Bochet
					Charles Bochet