feat: menu
This commit is contained in:
37
NOTE.md
37
NOTE.md
@ -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
|
|
14
src/App.tsx
14
src/App.tsx
@ -1,21 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Routes, Route } from "react-router-dom";
|
import { AppRoutes } from './routes/AppRoutes'
|
||||||
import { BreakpointProvider } from './components/Breakpoint'
|
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() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<BreakpointProvider>
|
<BreakpointProvider>
|
||||||
<Routes>
|
<AppRoutes />
|
||||||
<Route path="/" element={<Layout />}>
|
|
||||||
<Route index element={<Home />} />
|
|
||||||
<Route path="/login" element={<Login />} />
|
|
||||||
<Route path="/activate" element={<Activate />} />
|
|
||||||
</Route>
|
|
||||||
</Routes>
|
|
||||||
</BreakpointProvider>
|
</BreakpointProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,24 +2,25 @@ import React, { FC, PropsWithChildren } from 'react'
|
|||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { Breakpoint } from '../Breakpoint'
|
import { Breakpoint } from '../Breakpoint'
|
||||||
import { ButtonText } from '../Typography'
|
import { ButtonText } from '../Typography'
|
||||||
|
import { ExternalPaths } from 'routes/Paths'
|
||||||
|
|
||||||
const CompanyLink = {
|
const CompanyLink = {
|
||||||
title: 'iHealth Labs Inc',
|
title: 'iHealth Labs Inc',
|
||||||
href: 'https://ihealthlabs.com/'
|
href: ExternalPaths.CompanyLink
|
||||||
}
|
}
|
||||||
|
|
||||||
const FooterLinks = [{
|
const FooterLinks = [{
|
||||||
title: 'FAQs',
|
title: 'FAQs',
|
||||||
href: 'https://ihealthlabs.com/products/checkmesafe-home-collection-kit-C2-detail',
|
href: ExternalPaths.Faqs,
|
||||||
}, {
|
}, {
|
||||||
title: 'Contact Us',
|
title: 'Contact Us',
|
||||||
href: 'mailto:support@ihealthlabs.com'
|
href: ExternalPaths.ContactUs
|
||||||
}, {
|
}, {
|
||||||
title: 'Terms of Use',
|
title: 'Terms of Use',
|
||||||
href: 'https://www.iHealthCheckMeSafe.com/TermsOfUse'
|
href: ExternalPaths.TermsOfUse
|
||||||
}, {
|
}, {
|
||||||
title: 'Privacy Policy',
|
title: 'Privacy Policy',
|
||||||
href: 'https://www.iHealthCheckMSafe.com/PrivacyPolicy'
|
href: ExternalPaths.PrivacyPolicy
|
||||||
}]
|
}]
|
||||||
|
|
||||||
const Links = styled.div`
|
const Links = styled.div`
|
||||||
|
@ -3,9 +3,10 @@ import styled from 'styled-components'
|
|||||||
import Icon from '@ant-design/icons'
|
import Icon from '@ant-design/icons'
|
||||||
import { Button } from '../Button'
|
import { Button } from '../Button'
|
||||||
import { Breakpoint } from '../Breakpoint'
|
import { Breakpoint } from '../Breakpoint'
|
||||||
import { ReactComponent as Cart } from '../../icons/cart.svg'
|
import { ReactComponent as Cart } from 'icons/cart.svg'
|
||||||
import { ReactComponent as Menu } from '../../icons/menu.svg'
|
import { ReactComponent as Menu } from 'icons/menu.svg'
|
||||||
import { ReactComponent as Logo } from '../../branding/logo.svg'
|
import { ReactComponent as Logo } from 'branding/logo.svg'
|
||||||
|
import { ExternalPaths } from 'routes/Paths'
|
||||||
|
|
||||||
const StyledHeader = styled.header`
|
const StyledHeader = styled.header`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -74,10 +75,11 @@ const StyledButton = styled(Button)`
|
|||||||
right: 156px;
|
right: 156px;
|
||||||
top: 45px;
|
top: 45px;
|
||||||
width: 216px;
|
width: 216px;
|
||||||
|
line-height: 58px;
|
||||||
height: 58px;
|
height: 58px;
|
||||||
|
|
||||||
${props => props.theme.breakpoints.down(600)} {
|
${props => props.theme.breakpoints.down(600)} {
|
||||||
width: 130px;
|
width: 130px;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
@ -117,7 +119,7 @@ export const Header: FC<HeaderProps> = ({
|
|||||||
<StyledButton href={activeKitHref}>Activate Kit</StyledButton>
|
<StyledButton href={activeKitHref}>Activate Kit</StyledButton>
|
||||||
</Breakpoint>}
|
</Breakpoint>}
|
||||||
<StyledCartWrapper target="_blank" rel="noopener noreferrer"
|
<StyledCartWrapper target="_blank" rel="noopener noreferrer"
|
||||||
href="https://ihealthlabs.com/products/checkmesafe-home-collection-kit-C2">
|
href={ExternalPaths.Shop}>
|
||||||
<Icon component={Cart} />
|
<Icon component={Cart} />
|
||||||
<StyledText>SHOP</StyledText>
|
<StyledText>SHOP</StyledText>
|
||||||
</StyledCartWrapper>
|
</StyledCartWrapper>
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import React, { FC, PropsWithChildren } from 'react'
|
import React, { FC, PropsWithChildren, useState } from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { Header, HeaderProps } from './Header'
|
import { Header, HeaderProps } from './Header'
|
||||||
import { Footer } from './Footer'
|
import { Footer } from './Footer'
|
||||||
import { Outlet } from 'react-router-dom'
|
import { Menu } from '../Menu'
|
||||||
|
import { Breakpoint, useBreakpoint } from '../Breakpoint'
|
||||||
|
|
||||||
const StyledSection = styled.section`
|
const StyledSection = styled.section`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -21,16 +22,64 @@ const StyledFooter = styled(Footer)`
|
|||||||
const StyledMain = styled.main`
|
const StyledMain = styled.main`
|
||||||
flex: auto;
|
flex: auto;
|
||||||
`
|
`
|
||||||
|
const StyledMainSection = styled.section`
|
||||||
|
flex: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
`
|
||||||
|
|
||||||
export const Layout: FC<PropsWithChildren<Omit<HeaderProps, 'className'>>> = ({ children, ...headerProps }) => {
|
const StyledMainWrapper = styled.section<{ $column?: boolean }>`
|
||||||
|
flex: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: ${({ $column }) => $column ? 'column' : 'row'};
|
||||||
|
`
|
||||||
|
|
||||||
|
export const Main: FC<PropsWithChildren<{ column?: boolean }>> = ({ children, column }) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Breakpoint s down>
|
||||||
|
{children}
|
||||||
|
</Breakpoint>
|
||||||
|
<Breakpoint s up>
|
||||||
|
<StyledMainWrapper $column={column}>
|
||||||
|
{children}
|
||||||
|
</StyledMainWrapper>
|
||||||
|
</Breakpoint>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Layout: FC<PropsWithChildren<Omit<HeaderProps, 'className' | 'onClickMenu'>>> = ({
|
||||||
|
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 (
|
return (
|
||||||
<StyledSection>
|
<StyledSection>
|
||||||
<StyledHeader {...headerProps} />
|
<StyledHeader {...headerProps} onClickMenu={handleClickMenu} />
|
||||||
<StyledMain>
|
<Main>
|
||||||
<Outlet />
|
{headerProps.showMenu && (!isSmallScreen || displayMenu) ?
|
||||||
{children}
|
<Menu onClose={handleCloseMenu} onLogout={handleLogout} /> : null}
|
||||||
</StyledMain>
|
<StyledMainSection>
|
||||||
<StyledFooter />
|
<StyledMain>
|
||||||
|
{children}
|
||||||
|
</StyledMain>
|
||||||
|
<StyledFooter />
|
||||||
|
</StyledMainSection>
|
||||||
|
</Main>
|
||||||
</StyledSection>
|
</StyledSection>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
58
src/components/Menu/Menu.tsx
Normal file
58
src/components/Menu/Menu.tsx
Normal file
@ -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<MenuProps> = ({ onLogout, onClose }) => {
|
||||||
|
const [copyright] = useState(`Copyright iHealth ${new Date().getFullYear()}. All Rights Rerved.`)
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Breakpoint s down>
|
||||||
|
<StyledBackground>
|
||||||
|
<StyledMenuContainer>
|
||||||
|
<StyledCloseIcon component={CloseSvg} onClick={onClose} />
|
||||||
|
<StyledActivateButton block href={Paths.Activate}>Activate Kit</StyledActivateButton>
|
||||||
|
{menuConfig.map((item) => (
|
||||||
|
<StyledMenuItem key={item.title}>
|
||||||
|
<StyledIcon component={item.icon} />
|
||||||
|
{item.title}
|
||||||
|
</StyledMenuItem>
|
||||||
|
))}
|
||||||
|
<StyledExtraContent>
|
||||||
|
<StyledCopyright>{copyright}</StyledCopyright>
|
||||||
|
<Text primary style={{ lineHeight: 1 }} onClick={onLogout}>Log out</Text>
|
||||||
|
</StyledExtraContent>
|
||||||
|
</StyledMenuContainer>
|
||||||
|
</StyledBackground>
|
||||||
|
</Breakpoint>
|
||||||
|
<Breakpoint s up>
|
||||||
|
<StyledPlainMenuContainer>
|
||||||
|
{menuConfig.map((item) => (
|
||||||
|
<StyledPlainMenuItem key={item.title}>
|
||||||
|
<StyledIcon component={item.icon} />
|
||||||
|
{item.title}
|
||||||
|
</StyledPlainMenuItem>
|
||||||
|
))}
|
||||||
|
<StyledExtraContent>
|
||||||
|
<StyledCopyright>{copyright}</StyledCopyright>
|
||||||
|
<Text primary style={{ lineHeight: 1 }} onClick={onLogout}>Log out</Text>
|
||||||
|
</StyledExtraContent>
|
||||||
|
</StyledPlainMenuContainer>
|
||||||
|
</Breakpoint>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
1
src/components/Menu/index.ts
Normal file
1
src/components/Menu/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './Menu'
|
98
src/components/Menu/styled.ts
Normal file
98
src/components/Menu/styled.ts
Normal file
@ -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;
|
||||||
|
`
|
3
src/icons/home.svg
Normal file
3
src/icons/home.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.15717 0.420883C7.38748 0.210599 7.6881 0.0939941 8 0.0939941C8.3119 0.0939941 8.61252 0.210599 8.84283 0.420883C8.84314 0.421162 8.84344 0.421442 8.84375 0.421722L15.0922 6.1L15.101 6.10816C15.2245 6.22481 15.3234 6.36499 15.392 6.52045C15.4605 6.67591 15.4972 6.84351 15.4999 7.01337L15.5 7.02348V14.25C15.5 14.5816 15.3683 14.8995 15.1339 15.1339C14.8995 15.3684 14.5815 15.5 14.25 15.5H10.5C10.1685 15.5 9.85054 15.3684 9.61612 15.1339C9.38169 14.8995 9.25 14.5816 9.25 14.25V10.5H6.75V14.25C6.75 14.5816 6.6183 14.8995 6.38388 15.1339C6.14946 15.3684 5.83152 15.5 5.5 15.5H1.75C1.41848 15.5 1.10054 15.3684 0.866117 15.1339C0.631696 14.8995 0.5 14.5816 0.5 14.25V7.02348L0.500082 7.01337C0.50283 6.84351 0.539539 6.67591 0.608047 6.52045C0.676556 6.36499 0.775478 6.22481 0.89899 6.10816L0.907791 6.1L7.15625 0.421722C7.15656 0.421442 7.15686 0.421162 7.15717 0.420883ZM1.75592 7.01831L7.99846 1.3454L8 1.34399L8.00154 1.3454L14.2441 7.0183C14.2457 7.02015 14.2471 7.02225 14.2481 7.02452C14.2491 7.02689 14.2498 7.02941 14.25 7.03198V14.25H10.5V10.5C10.5 10.1685 10.3683 9.85058 10.1339 9.61616C9.89946 9.38174 9.58152 9.25005 9.25 9.25005H6.75C6.41848 9.25005 6.10054 9.38174 5.86612 9.61616C5.6317 9.85058 5.5 10.1685 5.5 10.5V14.25H1.75V7.03198C1.75022 7.02941 1.75086 7.02689 1.75191 7.02452C1.75291 7.02225 1.75427 7.02015 1.75592 7.01831Z" fill="#000022"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
@ -15,6 +15,7 @@ import { ActivateGuide } from './ActivateGuide'
|
|||||||
import { observer } from 'mobx-react-lite'
|
import { observer } from 'mobx-react-lite'
|
||||||
import { AuthStore } from 'stores/AuthStore'
|
import { AuthStore } from 'stores/AuthStore'
|
||||||
import { ActivationStore } from 'stores/ActivationStore'
|
import { ActivationStore } from 'stores/ActivationStore'
|
||||||
|
import { Paths } from 'routes/Paths'
|
||||||
|
|
||||||
export const ActivateStarter: FC = observer(() => {
|
export const ActivateStarter: FC = observer(() => {
|
||||||
const { logined } = AuthStore.instance()
|
const { logined } = AuthStore.instance()
|
||||||
@ -79,7 +80,7 @@ export const ActivateStarter: FC = observer(() => {
|
|||||||
{!logined ?
|
{!logined ?
|
||||||
<>
|
<>
|
||||||
Already have an account?
|
Already have an account?
|
||||||
<Link href="/login">Log in</Link>
|
<Link href={Paths.Login}>Log in</Link>
|
||||||
<br />
|
<br />
|
||||||
</> : null}
|
</> : null}
|
||||||
<Link onClick={handleShowModal}>Can’t find your activation code?</Link>
|
<Link onClick={handleShowModal}>Can’t find your activation code?</Link>
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import React, { FC, useState } from 'react'
|
import React, { FC, useState } from 'react'
|
||||||
import { Form, Col, Row, Divider } from 'antd'
|
import { Form, Col, Row, Divider } from 'antd'
|
||||||
import { observer } from 'mobx-react-lite'
|
import { observer } from 'mobx-react-lite'
|
||||||
import { Button } from 'components/Button'
|
|
||||||
import { Link, Paragraph, Title } from 'components/Typography'
|
import { Link, Paragraph, Title } from 'components/Typography'
|
||||||
import { ErrorMessage, Input, LabelWithTooltip, Password } from 'components/FormControl'
|
import { ErrorMessage, Input, LabelWithTooltip, Password } from 'components/FormControl'
|
||||||
import { StyledAccountForm, StyledAccountWrap, StyledHelp, StyledSubmitButton } from './styled'
|
import { StyledAccountForm, StyledAccountWrap, StyledHelp, StyledSubmitButton } from './styled'
|
||||||
import { ActivationStore } from 'stores/ActivationStore'
|
import { ActivationStore } from 'stores/ActivationStore'
|
||||||
import { VerifyModal } from './VerifyModal'
|
import { VerifyModal } from './VerifyModal'
|
||||||
import styled from 'styled-components'
|
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)`
|
const StyledTitle = styled(Title)`
|
||||||
${props => props.theme.breakpoints.up('s')} {
|
${props => props.theme.breakpoints.up('s')} {
|
||||||
@ -33,7 +33,7 @@ export const Account: FC = observer(() => {
|
|||||||
return (
|
return (
|
||||||
<StyledAccountWrap>
|
<StyledAccountWrap>
|
||||||
<StyledTitle level={2}>Create an account to activate your kit</StyledTitle>
|
<StyledTitle level={2}>Create an account to activate your kit</StyledTitle>
|
||||||
<Paragraph style={{ marginBottom: 0 }}>If you already have an account, <Link inherit href="/login">log
|
<Paragraph style={{ marginBottom: 0 }}>If you already have an account, <Link inherit href={Paths.Login}>log
|
||||||
in</Link> to continue.</Paragraph>
|
in</Link> to continue.</Paragraph>
|
||||||
<StyledAccountForm layout="vertical" onFinish={handleFinish}>
|
<StyledAccountForm layout="vertical" onFinish={handleFinish}>
|
||||||
<Row gutter={12}>
|
<Row gutter={12}>
|
||||||
@ -125,8 +125,8 @@ export const Account: FC = observer(() => {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
]}
|
]}
|
||||||
extra={<StyledHelp>By clicking "Next" you acknowledge the <Link inherit>Privacy Policy</Link> and agree to
|
extra={<StyledHelp>By clicking "Next" you acknowledge the <Link inherit href={ExternalPaths.PrivacyPolicy} target="_blank" rel="noopener noreferrer">Privacy Policy</Link> and agree to
|
||||||
our <Link inherit>Terms of Use</Link>.</StyledHelp>}
|
our <Link inherit href={ExternalPaths.TermsOfUse} target="_blank" rel="noopener noreferrer">Terms of Use</Link>.</StyledHelp>}
|
||||||
>
|
>
|
||||||
<Password placeholder="********" />
|
<Password placeholder="********" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
@ -136,9 +136,9 @@ export const Account: FC = observer(() => {
|
|||||||
</StyledAccountForm>
|
</StyledAccountForm>
|
||||||
<Breakpoint s up>
|
<Breakpoint s up>
|
||||||
<div style={{ textAlign: "center", marginTop: 30 }}>
|
<div style={{ textAlign: "center", marginTop: 30 }}>
|
||||||
<Link style={{ padding: '0 17px' }}>Disclaimer</Link>
|
<Link style={{ padding: '0 17px' }} href={ExternalPaths.Disclaimer} target="_blank" rel="noopener noreferrer">Disclaimer</Link>
|
||||||
<Divider type="vertical" />
|
<Divider type="vertical" />
|
||||||
<Link style={{ padding: '0 17px' }}>Privacy</Link>
|
<Link style={{ padding: '0 17px' }} href={ExternalPaths.PrivacyPolicy} target="_blank" rel="noopener noreferrer">Privacy</Link>
|
||||||
</div>
|
</div>
|
||||||
</Breakpoint>
|
</Breakpoint>
|
||||||
<VerifyModal open={showModal} onClose={handleClose} />
|
<VerifyModal open={showModal} onClose={handleClose} />
|
||||||
|
@ -4,6 +4,7 @@ import { Link, Text, Title } from 'components/Typography'
|
|||||||
import { ActivationStore } from 'stores/ActivationStore'
|
import { ActivationStore } from 'stores/ActivationStore'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { ReactComponent as SuccessSvg } from './images/success.svg'
|
import { ReactComponent as SuccessSvg } from './images/success.svg'
|
||||||
|
import { Paths, ExternalPaths } from '../../../../../routes/Paths'
|
||||||
|
|
||||||
const StyledLinkItem = styled.div`
|
const StyledLinkItem = styled.div`
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
@ -19,21 +20,21 @@ const StyledImageWrapper = styled.div`
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
${props => props.theme.breakpoints.up('s')} {
|
${props => props.theme.breakpoints.up('s')} {
|
||||||
height: 316px;
|
height: 316px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding-left: 103px;
|
padding-left: 103px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> svg {
|
> svg {
|
||||||
width: 223px;
|
width: 223px;
|
||||||
height: 231px;
|
height: 231px;
|
||||||
|
|
||||||
${props => props.theme.breakpoints.up('s')} {
|
${props => props.theme.breakpoints.up('s')} {
|
||||||
width: 301px;
|
width: 301px;
|
||||||
height: 385px;
|
height: 385px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -15px;
|
top: -15px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
const StyledTitle = styled(Title)`
|
const StyledTitle = styled(Title)`
|
||||||
@ -58,13 +59,14 @@ export const Done: FC = observer(() => {
|
|||||||
<Title level={2}>What’s Next?</Title>
|
<Title level={2}>What’s Next?</Title>
|
||||||
<div>
|
<div>
|
||||||
<StyledLinkItem>
|
<StyledLinkItem>
|
||||||
<Link>Watch a video on how to collect your sample</Link>
|
<Link href={ExternalPaths.GuideVideo} target="_blank" rel="noopener noreferrer">Watch a video on how to
|
||||||
|
collect your sample</Link>
|
||||||
</StyledLinkItem>
|
</StyledLinkItem>
|
||||||
<StyledLinkItem>
|
<StyledLinkItem>
|
||||||
<Link href="/dashboard">Go to my dashboard</Link>
|
<Link href={Paths.Dashboard}>Go to my dashboard</Link>
|
||||||
</StyledLinkItem>
|
</StyledLinkItem>
|
||||||
<StyledLinkItem>
|
<StyledLinkItem>
|
||||||
<Link>View FAQs</Link>
|
<Link href={ExternalPaths.Faqs} target="_blank" rel="noopener noreferrer">View FAQs</Link>
|
||||||
</StyledLinkItem>
|
</StyledLinkItem>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
@ -10,6 +10,7 @@ import { Button } from 'components/Button'
|
|||||||
import { Breakpoint } from 'components/Breakpoint'
|
import { Breakpoint } from 'components/Breakpoint'
|
||||||
import { observer } from 'mobx-react-lite'
|
import { observer } from 'mobx-react-lite'
|
||||||
import { AuthStore } from 'stores/AuthStore'
|
import { AuthStore } from 'stores/AuthStore'
|
||||||
|
import { Paths } from 'routes/Paths'
|
||||||
|
|
||||||
type Props = Pick<ModalProps, 'open'> & {
|
type Props = Pick<ModalProps, 'open'> & {
|
||||||
onClose?: (success: boolean) => void
|
onClose?: (success: boolean) => void
|
||||||
@ -107,7 +108,7 @@ export const VerifyModal: FC<Props> = observer(({ onClose, ...props }) => {
|
|||||||
</Breakpoint>
|
</Breakpoint>
|
||||||
<StyledRegisterTitle level={2}>Email address is already registered</StyledRegisterTitle>
|
<StyledRegisterTitle level={2}>Email address is already registered</StyledRegisterTitle>
|
||||||
<StyledParagraph>Please login to your existing account.</StyledParagraph>
|
<StyledParagraph>Please login to your existing account.</StyledParagraph>
|
||||||
<Button htmlType="submit" block href="/login">Log in</Button>
|
<Button htmlType="submit" block href={Paths.Login}>Log in</Button>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
@ -2,6 +2,7 @@ import React, { FC } from 'react'
|
|||||||
import { StyledContainer, StyledImageWrapper, StyledMainContent, StyledTitle, StyledContent } from './styled'
|
import { StyledContainer, StyledImageWrapper, StyledMainContent, StyledTitle, StyledContent } from './styled'
|
||||||
import { Divider } from 'antd'
|
import { Divider } from 'antd'
|
||||||
import { Button } from 'components/Button'
|
import { Button } from 'components/Button'
|
||||||
|
import { Paths } from 'routes/Paths'
|
||||||
|
|
||||||
export const Home: FC = () => {
|
export const Home: FC = () => {
|
||||||
return (
|
return (
|
||||||
@ -10,9 +11,9 @@ export const Home: FC = () => {
|
|||||||
<StyledMainContent>
|
<StyledMainContent>
|
||||||
<StyledTitle level={3}>Welcome to iHealth CheckMeSafe!</StyledTitle>
|
<StyledTitle level={3}>Welcome to iHealth CheckMeSafe!</StyledTitle>
|
||||||
<StyledContent>
|
<StyledContent>
|
||||||
<Button block href="/activate">Activate Kit</Button>
|
<Button block href={Paths.Activate}>Activate Kit</Button>
|
||||||
<Divider plain>Or</Divider>
|
<Divider plain>Or</Divider>
|
||||||
<Button block type="default" href="/login">Log in</Button>
|
<Button block type="default" href={Paths.Login}>Log in</Button>
|
||||||
</StyledContent>
|
</StyledContent>
|
||||||
</StyledMainContent>
|
</StyledMainContent>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
|
@ -12,6 +12,7 @@ import { Form } from 'antd'
|
|||||||
import { Paragraph, Link } from 'components/Typography'
|
import { Paragraph, Link } from 'components/Typography'
|
||||||
import { Input, Password, ErrorMessage } from 'components/FormControl'
|
import { Input, Password, ErrorMessage } from 'components/FormControl'
|
||||||
import { ForgetPasswordModal } from './ForgetPasswordModal'
|
import { ForgetPasswordModal } from './ForgetPasswordModal'
|
||||||
|
import { Paths } from 'routes/Paths'
|
||||||
|
|
||||||
export const Login: FC = () => {
|
export const Login: FC = () => {
|
||||||
const [showModal, setModal] = useState(false)
|
const [showModal, setModal] = useState(false)
|
||||||
@ -64,7 +65,7 @@ export const Login: FC = () => {
|
|||||||
<StyledHint>
|
<StyledHint>
|
||||||
<Paragraph>
|
<Paragraph>
|
||||||
Don’t have an account?
|
Don’t have an account?
|
||||||
<Link href="/activate">Activate your kit</Link>
|
<Link href={Paths.Activate}>Activate your kit</Link>
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
</StyledHint>
|
</StyledHint>
|
||||||
</StyledContent>
|
</StyledContent>
|
||||||
|
9
src/pages/customerPortal/dashboard/Dashboard.tsx
Normal file
9
src/pages/customerPortal/dashboard/Dashboard.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
export const Dashboard = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
Hello World
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
1
src/pages/customerPortal/dashboard/index.ts
Normal file
1
src/pages/customerPortal/dashboard/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './Dashboard'
|
24
src/routes/AppRoutes.tsx
Normal file
24
src/routes/AppRoutes.tsx
Normal file
@ -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 (
|
||||||
|
<Routes>
|
||||||
|
<Route path="/" element={<HomeLayout />}>
|
||||||
|
<Route index element={<Home />} />
|
||||||
|
<Route path={Paths.Login} element={<Login />} />
|
||||||
|
<Route path={Paths.Activate} element={<Activate />} />
|
||||||
|
</Route>
|
||||||
|
<Route path={Paths.Account} element={<HomeLayout alwaysShowIcon />}>
|
||||||
|
<Route index element={<Navigate replace to={Paths.Dashboard} />} />
|
||||||
|
<Route path={Paths.Dashboard} element={<Dashboard />} />
|
||||||
|
</Route>
|
||||||
|
</Routes>
|
||||||
|
)
|
||||||
|
}
|
22
src/routes/HomeLayout.tsx
Normal file
22
src/routes/HomeLayout.tsx
Normal file
@ -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 (
|
||||||
|
<Layout showMenu={alwaysShowIcon || showMenu} showActiveKit={alwaysShowIcon} activeKitHref={Paths.Activate}>
|
||||||
|
<Outlet />
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
})
|
19
src/routes/Paths.ts
Normal file
19
src/routes/Paths.ts
Normal file
@ -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: '#'
|
||||||
|
}
|
38
src/routes/menuConfig.ts
Normal file
38
src/routes/menuConfig.ts
Normal file
@ -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<any>
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}]
|
Reference in New Issue
Block a user