From cdc0007ea9973834d5660971a79c31a0a9a6af63 Mon Sep 17 00:00:00 2001 From: Huy Nguyen Date: Thu, 25 Jan 2024 18:08:33 +0700 Subject: [PATCH 1/4] feat: add common UI components --- packages/components/README.md | 1 - packages/components/__mocks__/styleMock.js | 1 + packages/components/package.json | 7 +- .../src/components/Footer/Footer.tsx | 29 ++++ .../components/src/components/Footer/index.ts | 1 + .../src/components/Header/Header.tsx | 144 ++++++++++++++++++ .../components/src/components/Header/index.ts | 1 + .../src/components/Layout/Layout.tsx | 25 +++ .../components/src/components/Layout/index.ts | 1 + .../components/ToastMessage/ToastMessage.tsx | 6 + .../src/components/ToastMessage/index.ts | 1 + .../__tests__/Footer/Footer.test.tsx | 15 ++ .../__tests__/Header/Header.test.tsx | 96 ++++++++++++ .../__tests__/Layout/Layout.test.tsx | 13 ++ .../ToastMessage/ToastMessage.test.tsx | 23 +++ packages/components/src/index.ts | 6 + packages/components/src/models/common.ts | 6 + packages/components/src/models/index.ts | 1 + packages/components/src/utils/toastMessage.ts | 16 ++ packages/components/stories/Footer.stories.js | 22 +++ packages/components/stories/Header.stories.js | 31 ++++ packages/components/stories/Layout.stories.js | 25 +++ .../stories/ToastMessage.stories.js | 28 ++++ pnpm-lock.yaml | 45 ++++++ 24 files changed, 541 insertions(+), 3 deletions(-) delete mode 100644 packages/components/README.md create mode 100644 packages/components/__mocks__/styleMock.js create mode 100644 packages/components/src/components/Footer/Footer.tsx create mode 100644 packages/components/src/components/Footer/index.ts create mode 100644 packages/components/src/components/Header/Header.tsx create mode 100644 packages/components/src/components/Header/index.ts create mode 100644 packages/components/src/components/Layout/Layout.tsx create mode 100644 packages/components/src/components/Layout/index.ts create mode 100644 packages/components/src/components/ToastMessage/ToastMessage.tsx create mode 100644 packages/components/src/components/ToastMessage/index.ts create mode 100644 packages/components/src/components/__tests__/Footer/Footer.test.tsx create mode 100644 packages/components/src/components/__tests__/Header/Header.test.tsx create mode 100644 packages/components/src/components/__tests__/Layout/Layout.test.tsx create mode 100644 packages/components/src/components/__tests__/ToastMessage/ToastMessage.test.tsx create mode 100644 packages/components/src/models/common.ts create mode 100644 packages/components/src/models/index.ts create mode 100644 packages/components/src/utils/toastMessage.ts create mode 100644 packages/components/stories/Footer.stories.js create mode 100644 packages/components/stories/Header.stories.js create mode 100644 packages/components/stories/Layout.stories.js create mode 100644 packages/components/stories/ToastMessage.stories.js diff --git a/packages/components/README.md b/packages/components/README.md deleted file mode 100644 index c6257c732..000000000 --- a/packages/components/README.md +++ /dev/null @@ -1 +0,0 @@ -# Mock app components diff --git a/packages/components/__mocks__/styleMock.js b/packages/components/__mocks__/styleMock.js new file mode 100644 index 000000000..f053ebf79 --- /dev/null +++ b/packages/components/__mocks__/styleMock.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/packages/components/package.json b/packages/components/package.json index 923b9f884..ae54b5aca 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -10,7 +10,8 @@ "build:watch": "tsc -b --watch", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build", - "test": "jest --ci --env=jest-environment-jsdom" + "test": "jest --ci --env=jest-environment-jsdom", + "coverage": "jest --coverage" }, "eslintConfig": { "extends": [ @@ -46,7 +47,9 @@ "@mui/x-date-pickers": "^6.19.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-scripts": "5.0.1" + "react-router-dom": "^6.21.3", + "react-scripts": "5.0.1", + "react-toastify": "^10.0.4" }, "devDependencies": { "@babel/preset-react": "^7.7.0", diff --git a/packages/components/src/components/Footer/Footer.tsx b/packages/components/src/components/Footer/Footer.tsx new file mode 100644 index 000000000..3727e5708 --- /dev/null +++ b/packages/components/src/components/Footer/Footer.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Box, Typography } from '@mui/material'; + +interface IProps { + textColor?: string; + backgroundColor?: string; +} + +/** + * Footer component is used to display the footer + */ +export const Footer = ({ textColor = '#000', backgroundColor = '#fff' }: IProps) => { + const currentYear = new Date().getFullYear(); + + return ( + + Copyright © {currentYear} + + ); +}; diff --git a/packages/components/src/components/Footer/index.ts b/packages/components/src/components/Footer/index.ts new file mode 100644 index 000000000..65e2506fa --- /dev/null +++ b/packages/components/src/components/Footer/index.ts @@ -0,0 +1 @@ +export { Footer } from './Footer'; diff --git a/packages/components/src/components/Header/Header.tsx b/packages/components/src/components/Header/Header.tsx new file mode 100644 index 000000000..d878d7bc4 --- /dev/null +++ b/packages/components/src/components/Header/Header.tsx @@ -0,0 +1,144 @@ +import React, { useState, MouseEvent } from 'react'; +import { AppBar, Toolbar, Typography, Container, Stack, Box, IconButton, Menu, MenuItem, Button } from '@mui/material'; +import { Menu as MenuIcon } from '@mui/icons-material'; +import { BrowserRouter, Link } from 'react-router-dom'; + +interface IProps { + logoTitle?: string; + logoTitleColor?: string; + backgroundColor?: string; + routerLinks: { title: string; path: string }[]; +} + +/** + * Header component is used to display the header and navigation to other pages + */ +export const Header = ({ routerLinks, logoTitle = 'Logo', logoTitleColor = '#000', backgroundColor = '#fff' }: IProps) => { + const [anchorElNav, setAnchorElNav] = useState(null); + + /** + * open nav menu on mobile. + */ + const handleOpenNavMenu = (event: MouseEvent) => { + setAnchorElNav(event.currentTarget); + }; + + /** + * close nav menu on mobile. + */ + const handleCloseNavMenu = () => { + setAnchorElNav(null); + }; + + return ( + + + + + {/* Logo on desktop or tablet */} + + + {logoTitle} + + + {/* Menu on mobile */} + + + + + + {routerLinks.map((page) => ( + + + {page.title} + + + ))} + + + {/* Logo on mobile */} + + + {logoTitle} + + + {/* Menu item on desktop or tablet */} + + {routerLinks.map((page) => ( + + ))} + + + + + + ); +}; diff --git a/packages/components/src/components/Header/index.ts b/packages/components/src/components/Header/index.ts new file mode 100644 index 000000000..29429dc97 --- /dev/null +++ b/packages/components/src/components/Header/index.ts @@ -0,0 +1 @@ +export { Header } from './Header'; diff --git a/packages/components/src/components/Layout/Layout.tsx b/packages/components/src/components/Layout/Layout.tsx new file mode 100644 index 000000000..81550f13b --- /dev/null +++ b/packages/components/src/components/Layout/Layout.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { Container } from '@mui/material'; + +interface IProps { + children: React.ReactNode; +} + +/** + * Layout component is used to display the header and navigation to other pages + */ +export const Layout = ({ children }: IProps) => { + return ( + + {children} + + ); +}; diff --git a/packages/components/src/components/Layout/index.ts b/packages/components/src/components/Layout/index.ts new file mode 100644 index 000000000..9fc685e2a --- /dev/null +++ b/packages/components/src/components/Layout/index.ts @@ -0,0 +1 @@ +export { Layout } from './Layout'; diff --git a/packages/components/src/components/ToastMessage/ToastMessage.tsx b/packages/components/src/components/ToastMessage/ToastMessage.tsx new file mode 100644 index 000000000..712c5d183 --- /dev/null +++ b/packages/components/src/components/ToastMessage/ToastMessage.tsx @@ -0,0 +1,6 @@ +import { ToastContainer } from 'react-toastify'; +import 'react-toastify/dist/ReactToastify.css'; + +export const ToastMessage = () => { + return ; +}; diff --git a/packages/components/src/components/ToastMessage/index.ts b/packages/components/src/components/ToastMessage/index.ts new file mode 100644 index 000000000..01b44df3f --- /dev/null +++ b/packages/components/src/components/ToastMessage/index.ts @@ -0,0 +1 @@ +export { ToastMessage } from './ToastMessage'; diff --git a/packages/components/src/components/__tests__/Footer/Footer.test.tsx b/packages/components/src/components/__tests__/Footer/Footer.test.tsx new file mode 100644 index 000000000..d62959aa1 --- /dev/null +++ b/packages/components/src/components/__tests__/Footer/Footer.test.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; + +import { Footer } from '../../..'; + +describe('Footer', () => { + test('should render Footer component', () => { + const currentYear = new Date().getFullYear(); + const footerText = `Copyright © ${currentYear}`; + + render(