diff --git a/NOTE.md b/NOTE.md deleted file mode 100644 index 72ebf6d..0000000 --- a/NOTE.md +++ /dev/null @@ -1,37 +0,0 @@ -# Responsive - -# Basic Components - -* [x] Typography - * [x] Link -* [x] Button - * [x] IconButton - * [x] TextButton -* [x] Modal -* [x] Step -* [x] Tooltip -* [x] Tag - -# HandWrite Component - -* Hamburger Menu - 需要手写! -* Captcha Input - 需要找别的组件! - -# Form Components - -* [x] Input - * [x] Password Input with Eye Icon -* [x] Radio - 大屏上黑色主题 -* [x] Radio Group -* [x] Checkbox -* [x] Textarea -* [x] Select -* [x] Form -* [x] FormItem - * [x] FormItem with Error Message - -# Layout Components - -* Layout - * [x] Header - * [x] Footer diff --git a/src/App.tsx b/src/App.tsx index 052f0ec..f9a4302 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,21 +1,11 @@ import React from 'react'; -import { Routes, Route } from "react-router-dom"; +import { AppRoutes } from './routes/AppRoutes' import { BreakpointProvider } from './components/Breakpoint' -import { Layout } from './components/Layout' -import { Home } from './pages/activation/home' -import { Login } from './pages/activation/login' -import { Activate } from './pages/activation/activate' function App() { return ( - - }> - } /> - } /> - } /> - - + ); } diff --git a/src/components/Layout/Footer.tsx b/src/components/Layout/Footer.tsx index a92039a..effa58a 100644 --- a/src/components/Layout/Footer.tsx +++ b/src/components/Layout/Footer.tsx @@ -2,24 +2,25 @@ import React, { FC, PropsWithChildren } from 'react' import styled from 'styled-components' import { Breakpoint } from '../Breakpoint' import { ButtonText } from '../Typography' +import { ExternalPaths } from 'routes/Paths' const CompanyLink = { title: 'iHealth Labs Inc', - href: 'https://ihealthlabs.com/' + href: ExternalPaths.CompanyLink } const FooterLinks = [{ title: 'FAQs', - href: 'https://ihealthlabs.com/products/checkmesafe-home-collection-kit-C2-detail', + href: ExternalPaths.Faqs, }, { title: 'Contact Us', - href: 'mailto:support@ihealthlabs.com' + href: ExternalPaths.ContactUs }, { title: 'Terms of Use', - href: 'https://www.iHealthCheckMeSafe.com/TermsOfUse' + href: ExternalPaths.TermsOfUse }, { title: 'Privacy Policy', - href: 'https://www.iHealthCheckMSafe.com/PrivacyPolicy' + href: ExternalPaths.PrivacyPolicy }] const Links = styled.div` diff --git a/src/components/Layout/Header.tsx b/src/components/Layout/Header.tsx index 22d3e6a..76c14ff 100644 --- a/src/components/Layout/Header.tsx +++ b/src/components/Layout/Header.tsx @@ -3,9 +3,10 @@ import styled from 'styled-components' import Icon from '@ant-design/icons' import { Button } from '../Button' import { Breakpoint } from '../Breakpoint' -import { ReactComponent as Cart } from '../../icons/cart.svg' -import { ReactComponent as Menu } from '../../icons/menu.svg' -import { ReactComponent as Logo } from '../../branding/logo.svg' +import { ReactComponent as Cart } from 'icons/cart.svg' +import { ReactComponent as Menu } from 'icons/menu.svg' +import { ReactComponent as Logo } from 'branding/logo.svg' +import { ExternalPaths } from 'routes/Paths' const StyledHeader = styled.header` display: flex; @@ -74,10 +75,11 @@ const StyledButton = styled(Button)` right: 156px; top: 45px; width: 216px; + line-height: 58px; height: 58px; ${props => props.theme.breakpoints.down(600)} { - width: 130px; + width: 130px; } ` @@ -117,7 +119,7 @@ export const Header: FC = ({ Activate Kit } + href={ExternalPaths.Shop}> SHOP diff --git a/src/components/Layout/Layout.tsx b/src/components/Layout/Layout.tsx index 0db6454..f7256da 100644 --- a/src/components/Layout/Layout.tsx +++ b/src/components/Layout/Layout.tsx @@ -1,8 +1,9 @@ -import React, { FC, PropsWithChildren } from 'react' +import React, { FC, PropsWithChildren, useState } from 'react' import styled from 'styled-components' import { Header, HeaderProps } from './Header' import { Footer } from './Footer' -import { Outlet } from 'react-router-dom' +import { Menu } from '../Menu' +import { Breakpoint, useBreakpoint } from '../Breakpoint' const StyledSection = styled.section` display: flex; @@ -21,16 +22,64 @@ const StyledFooter = styled(Footer)` const StyledMain = styled.main` flex: auto; ` +const StyledMainSection = styled.section` + flex: auto; + display: flex; + flex-direction: column; +` -export const Layout: FC>> = ({ children, ...headerProps }) => { +const StyledMainWrapper = styled.section<{ $column?: boolean }>` + flex: auto; + display: flex; + flex-direction: ${({ $column }) => $column ? 'column' : 'row'}; +` + +export const Main: FC> = ({ children, column }) => { + return ( + <> + + {children} + + + + {children} + + + + ) +} + +export const Layout: FC>> = ({ + children, + ...headerProps + }) => { + const isSmallScreen = useBreakpoint({ s: true, down: true }) + const [displayMenu, setDisplayMenu] = useState(false) + + const handleClickMenu = () => { + if (!isSmallScreen) return + setDisplayMenu(s => !s) + } + + const handleCloseMenu = () => { + if (!isSmallScreen) return + setDisplayMenu(false) + } + + const handleLogout = () => {} return ( - - - - {children} - - + +
+ {headerProps.showMenu && (!isSmallScreen || displayMenu) ? + : null} + + + {children} + + + +
) } diff --git a/src/components/Menu/Menu.tsx b/src/components/Menu/Menu.tsx new file mode 100644 index 0000000..0bffcd5 --- /dev/null +++ b/src/components/Menu/Menu.tsx @@ -0,0 +1,58 @@ +import React, { FC, useState } from 'react' +import { Breakpoint } from '../Breakpoint' +import { + StyledActivateButton, StyledBackground, StyledCloseIcon, StyledCopyright, StyledExtraContent, + StyledIcon, + StyledMenuContainer, + StyledMenuItem, + StyledPlainMenuContainer, StyledPlainMenuItem +} from './styled' +import { Paths } from 'routes/Paths' +import { menuConfig } from 'routes/menuConfig' +import { Text } from '../Typography' +import { ReactComponent as CloseSvg } from 'icons/close.svg' + +export interface MenuProps { + onClose: () => void + onLogout: () => void +} + +export const Menu: FC = ({ onLogout, onClose }) => { + const [copyright] = useState(`Copyright iHealth ${new Date().getFullYear()}. All Rights Rerved.`) + return ( + <> + + + + + Activate Kit + {menuConfig.map((item) => ( + + + {item.title} + + ))} + + {copyright} + Log out + + + + + + + {menuConfig.map((item) => ( + + + {item.title} + + ))} + + {copyright} + Log out + + + + + ) +} diff --git a/src/components/Menu/index.ts b/src/components/Menu/index.ts new file mode 100644 index 0000000..67984a1 --- /dev/null +++ b/src/components/Menu/index.ts @@ -0,0 +1 @@ +export * from './Menu' diff --git a/src/components/Menu/styled.ts b/src/components/Menu/styled.ts new file mode 100644 index 0000000..30afec7 --- /dev/null +++ b/src/components/Menu/styled.ts @@ -0,0 +1,98 @@ +import styled from 'styled-components' +import { Button } from '../Button' +import Icon from '@ant-design/icons' + +export const StyledExtraContent = styled.div` + text-align: center; + +` +export const StyledBackground = styled.div` + background: rgba(0, 0, 34, 0.5); + position: fixed; + top: 66px; + left: 0; + right: 0; + bottom: 0; + z-index: 9999; + pointer-events: none; +` +export const StyledMenuContainer = styled.aside` + background: #FDFDFD; + border: 2px solid #000022; + box-shadow: 3px 6px 1px #000022; + padding: 60px 20px 20px; + width: 316px; + box-sizing: border-box; + position: absolute; + pointer-events: auto; + top: 0; + left: 0; + bottom: 0; + + ${StyledExtraContent} { + position: absolute; + padding: 20px; + left: 0; + bottom: 0; + right: 0; + } +` + + +export const StyledActivateButton = styled(Button)` + border-radius: 8px; + margin-bottom: 11px; +` +export const StyledMenuItem = styled.div` + height: 64px; + line-height: 64px; + text-align: center; + border-bottom: 1px solid #000022; + font-weight: 500; + font-size: 16px; + letter-spacing: 0.02em; + color: #000022; +` +export const StyledIcon = styled(Icon)` + margin-right: 6px; +` + +export const StyledCloseIcon = styled(Icon)` + position: absolute; + top: 23px; + right: 23px; +` +export const StyledCopyright = styled.div` + color: #1E1D1F; + font-weight: 400; + line-height: 14px; + font-size: 12px; + margin-bottom: 15px; +` +export const StyledPlainMenuContainer = styled.aside` + width: 268px; + box-sizing: border-box; + background: #F3F3F3; + padding-top: 5px; + flex: 0 0 auto; + + ${StyledExtraContent} { + padding: 37px 7px; + + ${StyledCopyright} { + margin-bottom: 19px; + } + } +` + +export const StyledPlainMenuItem = styled.div` + height: 64px; + line-height: 64px; + padding: 0 20px; + color: #000022; + font-weight: 500; + font-size: 16px; + letter-spacing: 0.02em; + position: relative; + border-bottom: 2px solid #FDFDFD; +` diff --git a/src/icons/home.svg b/src/icons/home.svg new file mode 100644 index 0000000..052894d --- /dev/null +++ b/src/icons/home.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/pages/activation/activate/pages/activate/ActivateStarter.tsx b/src/pages/activation/activate/pages/activate/ActivateStarter.tsx index 147e4b3..97cb021 100644 --- a/src/pages/activation/activate/pages/activate/ActivateStarter.tsx +++ b/src/pages/activation/activate/pages/activate/ActivateStarter.tsx @@ -15,6 +15,7 @@ import { ActivateGuide } from './ActivateGuide' import { observer } from 'mobx-react-lite' import { AuthStore } from 'stores/AuthStore' import { ActivationStore } from 'stores/ActivationStore' +import { Paths } from 'routes/Paths' export const ActivateStarter: FC = observer(() => { const { logined } = AuthStore.instance() @@ -79,7 +80,7 @@ export const ActivateStarter: FC = observer(() => { {!logined ? <> Already have an account?  - Log in + Log in
: null} Can’t find your activation code? diff --git a/src/pages/activation/activate/pages/creation/Account.tsx b/src/pages/activation/activate/pages/creation/Account.tsx index 87296ec..7a65ae9 100644 --- a/src/pages/activation/activate/pages/creation/Account.tsx +++ b/src/pages/activation/activate/pages/creation/Account.tsx @@ -1,14 +1,14 @@ import React, { FC, useState } from 'react' import { Form, Col, Row, Divider } from 'antd' import { observer } from 'mobx-react-lite' -import { Button } from 'components/Button' import { Link, Paragraph, Title } from 'components/Typography' import { ErrorMessage, Input, LabelWithTooltip, Password } from 'components/FormControl' import { StyledAccountForm, StyledAccountWrap, StyledHelp, StyledSubmitButton } from './styled' import { ActivationStore } from 'stores/ActivationStore' import { VerifyModal } from './VerifyModal' import styled from 'styled-components' -import { Breakpoint } from '../../../../../components/Breakpoint' +import { Breakpoint } from 'components/Breakpoint' +import { ExternalPaths, Paths } from 'routes/Paths' const StyledTitle = styled(Title)` ${props => props.theme.breakpoints.up('s')} { @@ -33,7 +33,7 @@ export const Account: FC = observer(() => { return ( Create an account to activate your kit - If you already have an account, log + If you already have an account, log in to continue. @@ -125,8 +125,8 @@ export const Account: FC = observer(() => { }, }), ]} - extra={By clicking "Next" you acknowledge the Privacy Policy and agree to - our Terms of Use.} + extra={By clicking "Next" you acknowledge the Privacy Policy and agree to + our Terms of Use.} > @@ -136,9 +136,9 @@ export const Account: FC = observer(() => {
- Disclaimer + Disclaimer - Privacy + Privacy
diff --git a/src/pages/activation/activate/pages/creation/Done.tsx b/src/pages/activation/activate/pages/creation/Done.tsx index d9c3a60..df80403 100644 --- a/src/pages/activation/activate/pages/creation/Done.tsx +++ b/src/pages/activation/activate/pages/creation/Done.tsx @@ -4,6 +4,7 @@ import { Link, Text, Title } from 'components/Typography' import { ActivationStore } from 'stores/ActivationStore' import styled from 'styled-components' import { ReactComponent as SuccessSvg } from './images/success.svg' +import { Paths, ExternalPaths } from '../../../../../routes/Paths' const StyledLinkItem = styled.div` margin-bottom: 6px; @@ -19,21 +20,21 @@ const StyledImageWrapper = styled.div` text-align: center; ${props => props.theme.breakpoints.up('s')} { - height: 316px; - text-align: left; - padding-left: 103px; + height: 316px; + text-align: left; + padding-left: 103px; } > svg { - width: 223px; - height: 231px; + width: 223px; + height: 231px; - ${props => props.theme.breakpoints.up('s')} { - width: 301px; - height: 385px; - position: absolute; - top: -15px; - } + ${props => props.theme.breakpoints.up('s')} { + width: 301px; + height: 385px; + position: absolute; + top: -15px; + } } ` const StyledTitle = styled(Title)` @@ -58,13 +59,14 @@ export const Done: FC = observer(() => { What’s Next?
- Watch a video on how to collect your sample + Watch a video on how to + collect your sample - Go to my dashboard + Go to my dashboard - View FAQs + View FAQs
diff --git a/src/pages/activation/activate/pages/creation/VerifyModal.tsx b/src/pages/activation/activate/pages/creation/VerifyModal.tsx index 870f7aa..220d51e 100644 --- a/src/pages/activation/activate/pages/creation/VerifyModal.tsx +++ b/src/pages/activation/activate/pages/creation/VerifyModal.tsx @@ -10,6 +10,7 @@ import { Button } from 'components/Button' import { Breakpoint } from 'components/Breakpoint' import { observer } from 'mobx-react-lite' import { AuthStore } from 'stores/AuthStore' +import { Paths } from 'routes/Paths' type Props = Pick & { onClose?: (success: boolean) => void @@ -107,7 +108,7 @@ export const VerifyModal: FC = observer(({ onClose, ...props }) => { Email address is already registered Please login to your existing account. - + ) : ( <> diff --git a/src/pages/activation/home/Home.tsx b/src/pages/activation/home/Home.tsx index 0cba438..b1bd6c1 100644 --- a/src/pages/activation/home/Home.tsx +++ b/src/pages/activation/home/Home.tsx @@ -2,6 +2,7 @@ import React, { FC } from 'react' import { StyledContainer, StyledImageWrapper, StyledMainContent, StyledTitle, StyledContent } from './styled' import { Divider } from 'antd' import { Button } from 'components/Button' +import { Paths } from 'routes/Paths' export const Home: FC = () => { return ( @@ -10,9 +11,9 @@ export const Home: FC = () => { Welcome to iHealth CheckMeSafe! - + Or - + diff --git a/src/pages/activation/login/Login.tsx b/src/pages/activation/login/Login.tsx index d58a7b1..87ecb23 100644 --- a/src/pages/activation/login/Login.tsx +++ b/src/pages/activation/login/Login.tsx @@ -12,6 +12,7 @@ import { Form } from 'antd' import { Paragraph, Link } from 'components/Typography' import { Input, Password, ErrorMessage } from 'components/FormControl' import { ForgetPasswordModal } from './ForgetPasswordModal' +import { Paths } from 'routes/Paths' export const Login: FC = () => { const [showModal, setModal] = useState(false) @@ -64,7 +65,7 @@ export const Login: FC = () => { Don’t have an account?  - Activate your kit + Activate your kit diff --git a/src/pages/customerPortal/dashboard/Dashboard.tsx b/src/pages/customerPortal/dashboard/Dashboard.tsx new file mode 100644 index 0000000..8398a03 --- /dev/null +++ b/src/pages/customerPortal/dashboard/Dashboard.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +export const Dashboard = () => { + return ( +
+ Hello World +
+ ) +} diff --git a/src/pages/customerPortal/dashboard/index.ts b/src/pages/customerPortal/dashboard/index.ts new file mode 100644 index 0000000..f359847 --- /dev/null +++ b/src/pages/customerPortal/dashboard/index.ts @@ -0,0 +1 @@ +export * from './Dashboard' diff --git a/src/routes/AppRoutes.tsx b/src/routes/AppRoutes.tsx new file mode 100644 index 0000000..002b34a --- /dev/null +++ b/src/routes/AppRoutes.tsx @@ -0,0 +1,24 @@ +import React, { FC } from 'react' +import { Route, Routes, Navigate } from 'react-router-dom' +import { Paths } from './Paths' +import { HomeLayout } from './HomeLayout' +import { Home } from 'pages/activation/home' +import { Login } from 'pages/activation/login' +import { Activate } from 'pages/activation/activate' +import { Dashboard } from 'pages/customerPortal/dashboard' + +export const AppRoutes: FC = () => { + return ( + + }> + } /> + } /> + } /> + + }> + } /> + } /> + + + ) +} diff --git a/src/routes/HomeLayout.tsx b/src/routes/HomeLayout.tsx new file mode 100644 index 0000000..a095494 --- /dev/null +++ b/src/routes/HomeLayout.tsx @@ -0,0 +1,22 @@ +import React, { FC, useState } from 'react' +import { observer } from 'mobx-react-lite' +import { Layout } from 'components/Layout' +import { ActivationStore } from 'stores/ActivationStore' +import { Outlet, useMatch } from 'react-router-dom' +import { Paths } from './Paths' +import { useBreakpoint } from '../components/Breakpoint' + +export const HomeLayout: FC<{ alwaysShowIcon?: boolean }> = observer(({ alwaysShowIcon }) => { + const [store] = useState(ActivationStore.instance()) + const isActive = useMatch(Paths.Activate) + const isSmallScreen = useBreakpoint({ + s: true, + down: true + }) + const showMenu = !!isActive && isSmallScreen && store.step === store.stepItems.length - 1 + return ( + + + + ) +}) diff --git a/src/routes/Paths.ts b/src/routes/Paths.ts new file mode 100644 index 0000000..c41cd3e --- /dev/null +++ b/src/routes/Paths.ts @@ -0,0 +1,19 @@ +export const Paths = { + Login: '/login', + Activate: '/activate', + Account: '/account', + Dashboard: '/account/dashboard', + History: '/account/history', + Settings: '/account/settings', +} + +export const ExternalPaths = { + CompanyLink: 'https://ihealthlabs.com/', + Faqs: 'https://ihealthlabs.com/products/checkmesafe-home-collection-kit-C2-detail', + ContactUs: 'mailto:support@ihealthlabs.com', + TermsOfUse: 'https://www.iHealthCheckMeSafe.com/TermsOfUse', + PrivacyPolicy: 'https://www.iHealthCheckMSafe.com/PrivacyPolicy', + Shop: 'https://ihealthlabs.com/products/checkmesafe-home-collection-kit-C2', + GuideVideo: '#', + Disclaimer: '#' +} diff --git a/src/routes/menuConfig.ts b/src/routes/menuConfig.ts new file mode 100644 index 0000000..019760e --- /dev/null +++ b/src/routes/menuConfig.ts @@ -0,0 +1,38 @@ +import { ExternalPaths, Paths } from './Paths' +import { ComponentType } from 'react' +import { ReactComponent as HistorySvg } from 'icons/history.svg' +import { ReactComponent as QuestionSvg } from 'icons/question.svg' +import { ReactComponent as BellSvg } from 'icons/bell.svg' +import { ReactComponent as GearSvg } from 'icons/gear.svg' +import { ReactComponent as HomeSvg } from 'icons/home.svg' + +export interface MenuItem { + title: string + href: string + target?: string + icon: ComponentType +} + +export const menuConfig: MenuItem[] = [{ + title: 'Dashboard', + href: Paths.Dashboard, + icon: HomeSvg +}, { + title: 'Test History', + href: Paths.History, + icon: HistorySvg +}, { + title: 'FAQs', + href: ExternalPaths.Faqs, + target: '_blank', + icon: QuestionSvg +}, { + title: 'Settings', + href: Paths.Settings, + icon: GearSvg +}, { + title: 'Contact Us', + href: ExternalPaths.ContactUs, + target: '_blank', + icon: BellSvg +}]