init
This commit is contained in:
71
src/components/layout/dashboard-layout/DashboardLayout.tsx
Normal file
71
src/components/layout/dashboard-layout/DashboardLayout.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
'use client';
|
||||
|
||||
import Loader from '@/components/common/Loader';
|
||||
import DashboardHeader from '@/components/layout/dashboard-layout/Header/Header';
|
||||
import Sidebar from '@/components/layout/dashboard-layout/Sidebar';
|
||||
import { useAuthContext } from '@/context/auth-context';
|
||||
import { pageLinks } from '@/helpers/constants';
|
||||
import { useMyNavigation } from '@/hooks/useMyNavigation';
|
||||
import { useMyTranslation } from '@/hooks/useMyTranslation';
|
||||
import { Box, styled } from '@mui/material';
|
||||
import { useLocale } from 'next-intl';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
type Props = {
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
const StyledLayout = styled(Box)`
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
'sidebar header'
|
||||
'sidebar main';
|
||||
grid-template-columns: 250px 1fr;
|
||||
grid-template-rows: 80px calc(100vh - 80px);
|
||||
font-family: 'SF Pro Display', sans-serif;
|
||||
|
||||
.layout-header {
|
||||
grid-area: header;
|
||||
height: 100%;
|
||||
}
|
||||
.layout-sidebar {
|
||||
grid-area: sidebar;
|
||||
}
|
||||
.layout-main {
|
||||
grid-area: main;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: #edf1f7;
|
||||
padding: 40px 40px 20px;
|
||||
}
|
||||
`;
|
||||
|
||||
const DashboardLayout = (props: Props) => {
|
||||
const { isAuth, isLoading } = useAuthContext();
|
||||
const navigation = useMyNavigation();
|
||||
|
||||
useEffect(() => {
|
||||
if (!isAuth && !isLoading) {
|
||||
navigation.push(pageLinks.login);
|
||||
}
|
||||
}, [isAuth, isLoading]);
|
||||
|
||||
if (isLoading) return <Loader p={8} size={96} />;
|
||||
|
||||
if (!isAuth && !isLoading) return null;
|
||||
|
||||
return (
|
||||
<StyledLayout className='dashboard-layout'>
|
||||
<header className='layout-header'>
|
||||
<DashboardHeader />
|
||||
</header>
|
||||
<aside className='layout-sidebar'>
|
||||
<Sidebar />
|
||||
</aside>
|
||||
<main className='layout-main'>{props.children}</main>
|
||||
</StyledLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default DashboardLayout;
|
||||
100
src/components/layout/dashboard-layout/Header/Header.tsx
Normal file
100
src/components/layout/dashboard-layout/Header/Header.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
import { Settings } from '@mui/icons-material';
|
||||
import { Box, Icon, IconButton, Stack, Typography, styled } from '@mui/material';
|
||||
import { useLocale } from 'next-intl';
|
||||
import { usePathname, useRouter } from 'next/navigation';
|
||||
import React from 'react';
|
||||
|
||||
type Props = {};
|
||||
|
||||
const StyledBox = styled(Box)`
|
||||
height: 100%;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
background: #fff;
|
||||
box-shadow: 12px 12px 24px 0px rgba(0, 0, 0, 0.04);
|
||||
padding: 27px 40px;
|
||||
|
||||
.user-name {
|
||||
color: #000;
|
||||
font-size: 24px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 32px;
|
||||
letter-spacing: 1.44px;
|
||||
}
|
||||
|
||||
.lng-img {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
flex-shrink: 0;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.lng-select {
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
color: #07275c;
|
||||
}
|
||||
`;
|
||||
|
||||
const DashboardHeader = (props: Props) => {
|
||||
const language = useLocale();
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
|
||||
const changeLanguage = (lng: string) => {
|
||||
router.push(`/${lng}/${pathname.substring(3)}`, { scroll: false });
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledBox>
|
||||
{/* <Typography className='user-name'>Salom, Qurbonmurod</Typography> */}
|
||||
|
||||
<Stack direction={'row'} spacing={1.5}>
|
||||
<Stack direction={'row'} justifyContent={'center'} alignItems={'center'} spacing={1}>
|
||||
<img className='lng-img' src={getLanguageImage(language)} alt='' />
|
||||
|
||||
<select
|
||||
className='lng-select'
|
||||
value={language}
|
||||
onChange={event => {
|
||||
changeLanguage(event.target.value);
|
||||
}}
|
||||
>
|
||||
<option value='uz'>UZ</option>
|
||||
<option value='ru'>RU</option>
|
||||
<option value='en'>EN</option>
|
||||
<option value='cn'>中國人</option>
|
||||
</select>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</StyledBox>
|
||||
);
|
||||
};
|
||||
|
||||
export default DashboardHeader;
|
||||
|
||||
function getLanguageImage(lang: string) {
|
||||
switch (lang) {
|
||||
case 'uz': {
|
||||
return '/static/icons/uz-flag.png';
|
||||
}
|
||||
case 'en': {
|
||||
return '/static/icons/en-flag.png';
|
||||
}
|
||||
case 'ru': {
|
||||
return '/static/icons/ru-flag.webp';
|
||||
}
|
||||
case 'cn': {
|
||||
return '/static/icons/cn-flag.png';
|
||||
}
|
||||
default: {
|
||||
return '/static/icons/uz-flag.png';
|
||||
}
|
||||
}
|
||||
}
|
||||
1
src/components/layout/dashboard-layout/Header/index.ts
Normal file
1
src/components/layout/dashboard-layout/Header/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './Header';
|
||||
171
src/components/layout/dashboard-layout/Sidebar/Sidebar.tsx
Normal file
171
src/components/layout/dashboard-layout/Sidebar/Sidebar.tsx
Normal file
@@ -0,0 +1,171 @@
|
||||
import LogoSvg from '@/components/common/LogoSvg';
|
||||
import NextLink from '@/components/common/NextLink';
|
||||
import { routes } from '@/components/layout/dashboard-layout/routes';
|
||||
import { useAuthContext } from '@/context/auth-context';
|
||||
import { pageLinks } from '@/helpers/constants';
|
||||
import { useMyTranslation } from '@/hooks/useMyTranslation';
|
||||
import { Box, IconButton, Skeleton, Stack, Tooltip, Typography, styled } from '@mui/material';
|
||||
import React from 'react';
|
||||
|
||||
const StyledBox = styled(Box)`
|
||||
height: 100%;
|
||||
background: #3489e4;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-bottom: 20px;
|
||||
|
||||
.logo {
|
||||
padding: 23px 40px;
|
||||
|
||||
h2 {
|
||||
color: #fff;
|
||||
font-size: 32px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
line-height: 36px;
|
||||
letter-spacing: 1.92px;
|
||||
}
|
||||
}
|
||||
|
||||
.nav {
|
||||
padding: 60px 0 20px;
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
padding: 12px 38px;
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
transition:
|
||||
font-weight 0.3s ease,
|
||||
background-color 0.12s ease,
|
||||
color 0.12s ease;
|
||||
|
||||
&:hover {
|
||||
background-color: #ebf3fc;
|
||||
color: #3489e4;
|
||||
}
|
||||
|
||||
&.active-navlink {
|
||||
background-color: #ebf3fc;
|
||||
color: #3489e4;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-nav {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: auto;
|
||||
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.bottom-nav-img {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.bottom-nav-text {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 20px; /* 111.111% */
|
||||
letter-spacing: 1.44px;
|
||||
}
|
||||
|
||||
.bottom-nav-btn {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
color: #fff;
|
||||
border: 1px solid #fff;
|
||||
}
|
||||
`;
|
||||
|
||||
type Props = {};
|
||||
|
||||
const Sidebar = (props: Props) => {
|
||||
const t = useMyTranslation();
|
||||
const { user, isLoading, logout } = useAuthContext();
|
||||
|
||||
const onLogout = () => {
|
||||
if (window.confirm('Do you really want to log out?')) {
|
||||
logout();
|
||||
}
|
||||
};
|
||||
|
||||
const access_routes = routes.filter(route => {
|
||||
const haveAccess = route.roles.includes(user?.role!);
|
||||
return haveAccess;
|
||||
});
|
||||
|
||||
return (
|
||||
<StyledBox>
|
||||
<Box className='logo'>
|
||||
<Typography component='h2'>
|
||||
<NextLink href={pageLinks.home}>
|
||||
<LogoSvg />
|
||||
</NextLink>
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Stack className='nav' spacing={0} component='ul'>
|
||||
{/* {isLoading
|
||||
? [1, 2, 3].map((_, index) => (
|
||||
<NextLink className='nav-item' href={'#'} key={index}>
|
||||
<Skeleton
|
||||
sx={{
|
||||
backgroundColor: '#fff',
|
||||
width: 'calc(100% + 40px)',
|
||||
height: '50px',
|
||||
marginLeft: '-20px',
|
||||
marginRight: '-20px',
|
||||
}}
|
||||
/>
|
||||
</NextLink>
|
||||
))
|
||||
: []} */}
|
||||
{access_routes.map((route, index) => {
|
||||
return (
|
||||
<NextLink className='nav-item' href={route.path} key={index}>
|
||||
{route.icon}
|
||||
<span>{t(route.title)}</span>
|
||||
</NextLink>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
|
||||
<Stack className='bottom-nav'>
|
||||
<Tooltip title={t('log_out')}>
|
||||
<IconButton className='bottom-nav-btn' onClick={onLogout}>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='22' height='20' viewBox='0 0 22 20' fill='none'>
|
||||
<path
|
||||
d='M10 20C4.47715 20 0 15.5228 0 10C0 4.47715 4.47715 0 10 0C13.2713 0 16.1757 1.57078 18.0002 3.99923L15.2909 3.99931C13.8807 2.75499 12.0285 2 10 2C5.58172 2 2 5.58172 2 10C2 14.4183 5.58172 18 10 18C12.029 18 13.8816 17.2446 15.2919 15.9998H18.0009C16.1765 18.4288 13.2717 20 10 20ZM17 14V11H9V9H17V6L22 10L17 14Z'
|
||||
fill='currentColor'
|
||||
/>
|
||||
</svg>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
</StyledBox>
|
||||
);
|
||||
};
|
||||
|
||||
export default Sidebar;
|
||||
1
src/components/layout/dashboard-layout/Sidebar/index.ts
Normal file
1
src/components/layout/dashboard-layout/Sidebar/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './Sidebar';
|
||||
1
src/components/layout/dashboard-layout/index.ts
Normal file
1
src/components/layout/dashboard-layout/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './DashboardLayout';
|
||||
101
src/components/layout/dashboard-layout/routes.tsx
Normal file
101
src/components/layout/dashboard-layout/routes.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
import { UserRoleEnum } from '@/data/user/user.model';
|
||||
import { pageLinks } from '@/helpers/constants';
|
||||
import { SvgIcon } from '@mui/material';
|
||||
|
||||
export const routes = [
|
||||
{
|
||||
title: 'dashboard',
|
||||
path: pageLinks.dashboard.main.index,
|
||||
icon: (
|
||||
<SvgIcon fontSize='small'>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none'>
|
||||
<path
|
||||
d='M20 20.0001C20 20.5524 19.5523 21.0001 19 21.0001H5C4.44772 21.0001 4 20.5524 4 20.0001V11.0001H1L11.3273 1.61162C11.7087 1.26488 12.2913 1.26488 12.6727 1.61162L23 11.0001H20V20.0001ZM8 15.0001V17.0001H16V15.0001H8Z'
|
||||
fill='currentColor'
|
||||
/>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
),
|
||||
roles: [UserRoleEnum.ADMIN, UserRoleEnum.CHINA_WORKER],
|
||||
},
|
||||
{
|
||||
title: 'parties',
|
||||
path: pageLinks.dashboard.parties.index,
|
||||
icon: (
|
||||
<SvgIcon fontSize='small'>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none'>
|
||||
<path
|
||||
d='M5.75 3C5.57531 3.00009 5.4037 3.04594 5.25223 3.13298C5.10077 3.22002 4.97475 3.34521 4.88672 3.49609L3.13672 6.49609C3.04733 6.64899 3.00015 6.82289 3 7V19C3 20.0931 3.90694 21 5 21H19C20.0931 21 21 20.0931 21 19V7C20.9999 6.82289 20.9527 6.64899 20.8633 6.49609L19.1133 3.49609C19.0252 3.34521 18.8992 3.22002 18.7478 3.13298C18.5963 3.04594 18.4247 3.00009 18.25 3H5.75ZM6.32422 5H17.6758L18.8418 7H5.1582L6.32422 5ZM10 9H14C14.552 9 15 9.448 15 10C15 10.552 14.552 11 14 11H10C9.448 11 9 10.552 9 10C9 9.448 9.448 9 10 9Z'
|
||||
fill='currentColor'
|
||||
/>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
),
|
||||
roles: [UserRoleEnum.ADMIN, UserRoleEnum.CHINA_WORKER],
|
||||
},
|
||||
{
|
||||
title: 'packet',
|
||||
path: pageLinks.dashboard.boxes.index,
|
||||
icon: (
|
||||
<SvgIcon fontSize='small'>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none'>
|
||||
<path
|
||||
d='M17.578 4.432L15.578 3.382C13.822 2.461 12.944 2 12 2C11.056 2 10.178 2.46 8.422 3.382L8.101 3.551L17.024 8.65L21.04 6.64C20.394 5.908 19.352 5.361 17.578 4.43M21.748 7.964L17.75 9.964V13C17.75 13.1989 17.671 13.3897 17.5303 13.5303C17.3897 13.671 17.1989 13.75 17 13.75C16.8011 13.75 16.6103 13.671 16.4697 13.5303C16.329 13.3897 16.25 13.1989 16.25 13V10.714L12.75 12.464V21.904C13.468 21.725 14.285 21.297 15.578 20.618L17.578 19.568C19.729 18.439 20.805 17.875 21.403 16.86C22 15.846 22 14.583 22 12.06V11.943C22 10.05 22 8.866 21.748 7.964ZM11.25 21.904V12.464L2.252 7.964C2 8.866 2 10.05 2 11.941V12.058C2 14.583 2 15.846 2.597 16.86C3.195 17.875 4.271 18.44 6.422 19.569L8.422 20.618C9.715 21.297 10.532 21.725 11.25 21.904ZM2.96 6.641L12 11.161L15.411 9.456L6.525 4.378L6.422 4.432C4.649 5.362 3.606 5.909 2.96 6.642'
|
||||
fill='currentColor'
|
||||
/>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
),
|
||||
roles: [UserRoleEnum.ADMIN, UserRoleEnum.CHINA_WORKER],
|
||||
},
|
||||
{
|
||||
title: 'products',
|
||||
path: pageLinks.dashboard.items.index,
|
||||
icon: (
|
||||
<SvgIcon fontSize='small'>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='18' height='20' viewBox='0 0 18 20' fill='none'>
|
||||
<path
|
||||
d='M16.6667 7.77778H17.7778V20H0V7.77778H1.11111V5.55556C1.11111 2.48889 3.6 5.05038e-06 6.66667 5.05038e-06C7.45555 5.05038e-06 8.21111 0.166672 8.88889 0.466672C9.589 0.157923 10.3459 -0.00103288 11.1111 5.05038e-06C14.1778 5.05038e-06 16.6667 2.48889 16.6667 5.55556V7.77778ZM3.33333 5.55556V7.77778H5.55555V5.55556C5.55555 4.3 5.98889 3.15556 6.68889 2.22223H6.66667C4.83333 2.22223 3.33333 3.72223 3.33333 5.55556ZM14.4444 7.77778V5.55556C14.4444 3.72223 12.9444 2.22223 11.1111 2.22223H11.0889C11.8195 3.18031 12.2174 4.35069 12.2222 5.55556V7.77778H14.4444ZM8.88889 3.08889C8.21111 3.7 7.77778 4.57778 7.77778 5.55556V7.77778H10V5.55556C10 4.57778 9.56666 3.7 8.88889 3.08889Z'
|
||||
fill='currentColor'
|
||||
/>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
),
|
||||
roles: [UserRoleEnum.ADMIN, UserRoleEnum.CHINA_WORKER, UserRoleEnum.UZB_WORKER],
|
||||
},
|
||||
{
|
||||
title: 'clients',
|
||||
path: pageLinks.dashboard.customers.index,
|
||||
icon: (
|
||||
<SvgIcon fontSize='small'>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none'>
|
||||
<path
|
||||
d='M16 17.0001V19.0001H2V17.0001C2 17.0001 2 13.0001 9 13.0001C16 13.0001 16 17.0001 16 17.0001ZM12.5 7.50005C12.5 6.80782 12.2947 6.13113 11.9101 5.55556C11.5256 4.97998 10.9789 4.53138 10.3394 4.26647C9.69985 4.00157 8.99612 3.93226 8.31718 4.0673C7.63825 4.20235 7.01461 4.5357 6.52513 5.02518C6.03564 5.51466 5.7023 6.1383 5.56725 6.81724C5.4322 7.49617 5.50152 8.1999 5.76642 8.83944C6.03133 9.47899 6.47993 10.0256 7.0555 10.4102C7.63108 10.7948 8.30777 11.0001 9 11.0001C9.92826 11.0001 10.8185 10.6313 11.4749 9.97493C12.1313 9.31855 12.5 8.42831 12.5 7.50005ZM15.94 13.0001C16.5547 13.4758 17.0578 14.0805 17.4137 14.7716C17.7696 15.4626 17.9697 16.2233 18 17.0001V19.0001H22V17.0001C22 17.0001 22 13.3701 15.94 13.0001ZM15 4.00005C14.3117 3.99622 13.6385 4.20201 13.07 4.59005C13.6774 5.43879 14.0041 6.45634 14.0041 7.50005C14.0041 8.54377 13.6774 9.56132 13.07 10.4101C13.6385 10.7981 14.3117 11.0039 15 11.0001C15.9283 11.0001 16.8185 10.6313 17.4749 9.97493C18.1313 9.31855 18.5 8.42831 18.5 7.50005C18.5 6.57179 18.1313 5.68156 17.4749 5.02518C16.8185 4.3688 15.9283 4.00005 15 4.00005Z'
|
||||
fill='currentColor'
|
||||
/>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
),
|
||||
roles: [UserRoleEnum.ADMIN, UserRoleEnum.UZB_WORKER],
|
||||
},
|
||||
{
|
||||
title: 'staffs',
|
||||
path: pageLinks.dashboard.staffs.index,
|
||||
icon: (
|
||||
<SvgIcon fontSize='small'>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none'>
|
||||
<path
|
||||
d='M11.24 10.7934C13.6185 10.7934 15.5467 8.86523 15.5467 6.48672C15.5467 4.10821 13.6185 2.18005 11.24 2.18005C8.86151 2.18005 6.93335 4.10821 6.93335 6.48672C6.93335 8.86523 8.86151 10.7934 11.24 10.7934Z'
|
||||
fill='currentColor'
|
||||
/>
|
||||
<path d='M14 18.6666H18.6667V19.6H14V18.6666Z' fill='currentColor' />
|
||||
<path
|
||||
d='M9.99998 20V22C9.99998 22.1768 10.0702 22.3464 10.1952 22.4714C10.3203 22.5965 10.4898 22.6667 10.6666 22.6667H22C22.1768 22.6667 22.3464 22.5965 22.4714 22.4714C22.5964 22.3464 22.6666 22.1768 22.6666 22V15.3334C22.6666 15.1566 22.5964 14.987 22.4714 14.862C22.3464 14.7369 22.1768 14.6667 22 14.6667H17.3333V13.6867C17.3333 13.5099 17.2631 13.3403 17.1381 13.2153C17.013 13.0903 16.8435 13.02 16.6666 13.02C16.4898 13.02 16.3203 13.0903 16.1952 13.2153C16.0702 13.3403 16 13.5099 16 13.6867V14.6667H14.6666V12.28C13.5338 12.095 12.3879 12.0014 11.24 12C8.70851 11.9893 6.20541 12.5331 3.90665 13.5934C3.5283 13.7719 3.20912 14.0552 2.98696 14.4097C2.76481 14.7642 2.64901 15.175 2.65331 15.5934V20H9.99998ZM21.3333 21.3334H11.3333V16H16V16.28C16 16.4568 16.0702 16.6264 16.1952 16.7514C16.3203 16.8765 16.4898 16.9467 16.6666 16.9467C16.8435 16.9467 17.013 16.8765 17.1381 16.7514C17.2631 16.6264 17.3333 16.4568 17.3333 16.28V16H21.3333V21.3334Z'
|
||||
fill='currentColor'
|
||||
/>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
),
|
||||
roles: [UserRoleEnum.ADMIN],
|
||||
},
|
||||
];
|
||||
22
src/components/layout/landing-layout/Layout.tsx
Normal file
22
src/components/layout/landing-layout/Layout.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
'use client';
|
||||
|
||||
import Footer from '@/components/layout/landing-layout/footer';
|
||||
import Header from '@/components/layout/landing-layout/header';
|
||||
import { Box } from '@mui/material';
|
||||
import React from 'react';
|
||||
|
||||
type Props = {
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
const Layout = (props: Props) => {
|
||||
return (
|
||||
<Box sx={{}}>
|
||||
<Header />
|
||||
<main className='main-content'>{props.children}</main>
|
||||
<Footer />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
219
src/components/layout/landing-layout/footer/Footer.tsx
Normal file
219
src/components/layout/landing-layout/footer/Footer.tsx
Normal file
@@ -0,0 +1,219 @@
|
||||
import Container from '@/components/common/Container';
|
||||
import NextLink from '@/components/common/NextLink';
|
||||
import { pageLinks } from '@/helpers/constants';
|
||||
import { useMyTranslation } from '@/hooks/useMyTranslation';
|
||||
import { Grid, Stack, Typography, css, styled } from '@mui/material';
|
||||
import React from 'react';
|
||||
|
||||
const StyledFooter = styled('footer')`
|
||||
padding-top: 90px;
|
||||
padding-bottom: 15px;
|
||||
|
||||
.grid-container {
|
||||
margin-bottom: 100px;
|
||||
}
|
||||
|
||||
.logo-link {
|
||||
color: #0076be;
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
line-height: 24px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.info-text {
|
||||
color: #07275c;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.col-title {
|
||||
color: #07275c;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.col-link {
|
||||
color: #0076be;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
.social-link-wrapper {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
flex-shrink: 0;
|
||||
background-color: #0076be;
|
||||
border-radius: 50%;
|
||||
padding: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
filter: drop-shadow(2px 2px 2px rgba(0, 0, 0, 0.1));
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-text {
|
||||
color: #07275c;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
.join-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
.join-input {
|
||||
border-radius: 23px;
|
||||
background: #dbe8f1;
|
||||
padding: 12px 16px;
|
||||
color: #222;
|
||||
width: 100%;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.join-icon {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
padding: 8px;
|
||||
border-radius: 50%;
|
||||
background-color: #1f6bbd;
|
||||
}
|
||||
|
||||
${({ theme }) => css`
|
||||
${theme.breakpoints.down('md')} {
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
type Props = {};
|
||||
|
||||
const Footer = (props: Props) => {
|
||||
const t = useMyTranslation();
|
||||
|
||||
return (
|
||||
<StyledFooter>
|
||||
<Container>
|
||||
<Grid container className='grid-container' spacing={4}>
|
||||
<Grid item xs={12} md={3}>
|
||||
<NextLink className='logo-link' href={pageLinks.home}>
|
||||
CPost
|
||||
</NextLink>
|
||||
<Typography className='info-text'>{t('footer_site_info_text')}</Typography>
|
||||
<Stack direction={'row'} spacing={1.5}>
|
||||
<NextLink className='social-link-wrapper' href='#'>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14' fill='none'>
|
||||
<path
|
||||
d='M12.9573 3.29936C12.512 3.49635 12.0397 3.62574 11.5562 3.68323C12.0656 3.37827 12.4468 2.89852 12.6288 2.33336C12.1501 2.61777 11.6261 2.81795 11.0797 2.92519C10.6185 2.43312 9.97384 2.15427 9.29939 2.15503C7.95235 2.15503 6.85983 3.24719 6.85983 4.59482C6.85983 4.786 6.88176 4.97141 6.92277 5.1503C4.89444 5.04819 3.09754 4.07753 1.89396 2.60132C1.67726 2.97364 1.56337 3.39685 1.56394 3.82764C1.56394 4.67401 1.99477 5.42106 2.64921 5.85842C2.2618 5.84617 1.88293 5.74154 1.54419 5.55317C1.54382 5.56342 1.54382 5.57367 1.54382 5.58336C1.54382 6.76573 2.38478 7.75203 3.50116 7.97597C3.29164 8.03267 3.07552 8.06132 2.85846 8.06114C2.70082 8.06114 2.54783 8.04662 2.39913 8.01809C2.70977 8.98712 3.61017 9.69261 4.6781 9.71197C3.81391 10.3902 2.74674 10.7582 1.64817 10.7566C1.45374 10.7568 1.25947 10.7453 1.06641 10.7223C2.18169 11.4393 3.47989 11.8198 4.80575 11.8184C9.29344 11.8184 11.7472 8.10104 11.7472 4.87731C11.7472 4.77184 11.7446 4.666 11.7399 4.56165C12.2175 4.21659 12.6298 3.78914 12.9573 3.29936Z'
|
||||
fill='white'
|
||||
/>
|
||||
</svg>
|
||||
</NextLink>
|
||||
<NextLink className='social-link-wrapper' href='#'>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14' fill='none'>
|
||||
<path
|
||||
d='M6.83335 5.08333C5.86653 5.08333 5.08333 5.86681 5.08333 6.83333C5.08333 7.80009 5.86682 8.58333 6.83335 8.58333C7.8001 8.58333 8.58335 7.79986 8.58335 6.83333C8.58335 5.86658 7.79987 5.08333 6.83335 5.08333ZM6.83335 3.91667C8.44358 3.91667 9.75001 5.22164 9.75001 6.83333C9.75001 8.44363 8.44504 9.75 6.83335 9.75C5.22306 9.75 3.91667 8.44503 3.91667 6.83333C3.91667 5.22306 5.22164 3.91667 6.83335 3.91667ZM10.625 3.77034C10.625 4.1729 10.2979 4.49952 9.89584 4.49952C9.49329 4.49952 9.16668 4.1724 9.16668 3.77034C9.16668 3.36828 9.49375 3.04167 9.89584 3.04167C10.2974 3.04116 10.625 3.36828 10.625 3.77034ZM6.83335 2.16667C5.38989 2.16667 5.15462 2.17049 4.48325 2.20038C4.02585 2.22186 3.71924 2.28337 3.43436 2.39397C3.18119 2.49216 2.99856 2.60941 2.80398 2.80399C2.60865 2.99932 2.49162 3.18145 2.39383 3.43473C2.28297 3.72027 2.22147 4.0264 2.20038 4.48317C2.1702 5.1272 2.16667 5.35228 2.16667 6.83333C2.16667 8.27679 2.17049 8.51205 2.20038 9.18335C2.22186 9.64057 2.28346 9.94763 2.39379 10.2318C2.49224 10.4854 2.60972 10.6684 2.80336 10.8621C2.99946 11.0579 3.18214 11.1753 3.43302 11.2722C3.72137 11.3836 4.02779 11.4452 4.48316 11.4663C5.1272 11.4964 5.35228 11.5 6.83335 11.5C8.2768 11.5 8.51206 11.4962 9.18336 11.4663C9.63959 11.4449 9.94689 11.3831 10.2318 11.2729C10.4847 11.1747 10.6683 11.0568 10.8621 10.8633C11.0582 10.6669 11.1754 10.4847 11.2723 10.2332C11.3835 9.94588 11.4452 9.63905 11.4663 9.18353C11.4965 8.53947 11.5 8.31436 11.5 6.83333C11.5 5.38989 11.4962 5.15462 11.4663 4.4833C11.4448 4.02695 11.3831 3.7192 11.2727 3.43436C11.1747 3.18189 11.0571 2.9987 10.8627 2.80399C10.667 2.60834 10.4854 2.49154 10.2319 2.39383C9.9466 2.28307 9.63999 2.22148 9.18348 2.20039C8.53948 2.1702 8.31437 2.16667 6.83335 2.16667ZM6.83335 1C8.41803 1 8.61589 1.00583 9.23814 1.035C9.85886 1.06368 10.2823 1.16188 10.6542 1.30625C11.0387 1.45452 11.3634 1.65479 11.6876 1.97903C12.0114 2.30327 12.2117 2.62896 12.3604 3.0125C12.5043 3.38389 12.6025 3.80778 12.6317 4.42854C12.6594 5.05077 12.6667 5.24861 12.6667 6.83333C12.6667 8.41808 12.6608 8.61588 12.6317 9.23812C12.603 9.85891 12.5043 10.2823 12.3604 10.6542C12.2121 11.0387 12.0114 11.3634 11.6876 11.6877C11.3634 12.0114 11.0372 12.2117 10.6542 12.3604C10.2823 12.5043 9.85886 12.6025 9.23814 12.6317C8.61589 12.6594 8.41803 12.6667 6.83335 12.6667C5.24861 12.6667 5.05076 12.6608 4.42854 12.6317C3.80778 12.603 3.38486 12.5043 3.0125 12.3604C2.62847 12.2121 2.30326 12.0114 1.97903 11.6877C1.65479 11.3634 1.455 11.0372 1.30625 10.6542C1.16188 10.2823 1.06417 9.85891 1.035 9.23812C1.00729 8.61588 1 8.41808 1 6.83333C1 5.24861 1.00583 5.05077 1.035 4.42854C1.06368 3.80729 1.16188 3.38438 1.30625 3.0125C1.45451 2.62847 1.65479 2.30327 1.97903 1.97903C2.30326 1.65479 2.62896 1.455 3.0125 1.30625C3.38438 1.16188 3.80729 1.06417 4.42854 1.035C5.05076 1.00729 5.24861 1 6.83335 1Z'
|
||||
fill='white'
|
||||
/>
|
||||
</svg>
|
||||
</NextLink>
|
||||
<NextLink className='social-link-wrapper' href='#'>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14' fill='none'>
|
||||
<path
|
||||
d='M4.22214 3.11156C4.22194 3.56393 3.94749 3.97101 3.52821 4.14084C3.10893 4.31068 2.62855 4.20935 2.31358 3.88464C1.99861 3.55993 1.91196 3.07668 2.09448 2.66277C2.277 2.24886 2.69225 1.98693 3.14442 2.0005C3.74498 2.01853 4.22241 2.51072 4.22214 3.11156ZM4.25547 5.0448H2.03336V12H4.25547V5.0448ZM7.76642 5.0448H5.55541V12H7.7442V8.35018C7.7442 6.31694 10.3941 6.12806 10.3941 8.35018V12H12.5884V7.59466C12.5884 4.16706 8.66638 4.29484 7.7442 5.97807L7.76642 5.0448Z'
|
||||
fill='white'
|
||||
/>
|
||||
</svg>
|
||||
</NextLink>
|
||||
<NextLink className='social-link-wrapper' href='#'>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14' fill='none'>
|
||||
<path
|
||||
d='M8.16683 7.87508H9.62516L10.2085 5.54175H8.16683V4.37508C8.16683 3.77461 8.16683 3.20841 9.3335 3.20841H10.2085V1.24847C10.0185 1.22324 9.30025 1.16675 8.54185 1.16675C6.9584 1.16675 5.8335 2.13325 5.8335 3.90825V5.54175H4.0835V7.87508H5.8335V12.8334H8.16683V7.87508Z'
|
||||
fill='white'
|
||||
/>
|
||||
</svg>
|
||||
</NextLink>
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={3}>
|
||||
<Typography className='col-title'>{t('pages')}</Typography>
|
||||
|
||||
<Stack spacing={1.5}>
|
||||
<NextLink className='col-link' href={pageLinks.home}>
|
||||
{t('main_page')}
|
||||
</NextLink>
|
||||
<NextLink className='col-link' href={pageLinks.home}>
|
||||
{t('services')}
|
||||
</NextLink>
|
||||
{/* <NextLink className='col-link' href={pageLinks.home}>
|
||||
{t('news')}
|
||||
</NextLink> */}
|
||||
<NextLink className='col-link' href={pageLinks.home}>
|
||||
{t('about_us')}
|
||||
</NextLink>
|
||||
<NextLink className='col-link' href={pageLinks.home}>
|
||||
{t('contacts')}
|
||||
</NextLink>
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={3}>
|
||||
<Typography className='col-title'>{t('info')}</Typography>
|
||||
<Stack spacing={1.5}>
|
||||
<NextLink className='col-link' href={pageLinks.home}>
|
||||
{t('privacy_policy')}
|
||||
</NextLink>
|
||||
<NextLink className='col-link' href={pageLinks.home}>
|
||||
{t('terms_of_use')}
|
||||
</NextLink>
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={3}>
|
||||
<Typography className='col-title'>{t('join_tg')}</Typography>
|
||||
<Typography className='col-link' mb={2.5}>
|
||||
{t('sign_up_to_tg')}
|
||||
</Typography>
|
||||
<div className='join-wrapper'>
|
||||
<input className='join-input' type='text' placeholder={t('your_email')} />
|
||||
<div className='join-icon'>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='21' height='20' viewBox='0 0 21 20' fill='none'>
|
||||
<path
|
||||
d='M1.64978 7.76304C1.20682 7.61789 1.20332 7.3837 1.65889 7.23442L17.8383 1.93269C18.2862 1.78589 18.5432 2.0324 18.4177 2.4643L13.795 18.3695C13.667 18.8099 13.4087 18.8252 13.2194 18.4065L10.1725 11.6669L15.2587 5.00023L8.47707 10.0003L1.64978 7.76304Z'
|
||||
fill='white'
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Typography className='bottom-text'>2024 CPost. {t('all_rights_reserved')}</Typography>
|
||||
</Container>
|
||||
</StyledFooter>
|
||||
);
|
||||
};
|
||||
|
||||
export default Footer;
|
||||
1
src/components/layout/landing-layout/footer/index.ts
Normal file
1
src/components/layout/landing-layout/footer/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './Footer';
|
||||
519
src/components/layout/landing-layout/header/Header.tsx
Normal file
519
src/components/layout/landing-layout/header/Header.tsx
Normal file
@@ -0,0 +1,519 @@
|
||||
import { CalculatorModal } from '@/components/common/Calculator/Calculator';
|
||||
import { CheckOrderModal } from '@/components/common/CheckOrder';
|
||||
import Container from '@/components/common/Container';
|
||||
import NextLink from '@/components/common/NextLink';
|
||||
import { pageLinks } from '@/helpers/constants';
|
||||
import { useMyTranslation } from '@/hooks/useMyTranslation';
|
||||
import { Box, Drawer, IconButton, Stack, Typography, css, styled, Button } from '@mui/material';
|
||||
import { useLocale } from 'next-intl';
|
||||
import { Close, Menu } from '@mui/icons-material';
|
||||
import { usePathname, useRouter } from 'next/navigation';
|
||||
import React, { useState } from 'react';
|
||||
import LogoSvg from '@/components/common/LogoSvg';
|
||||
import { VerifyPhoneModal } from '@/components/common/VerifyPhoneModal';
|
||||
import { IRegisterModal } from '@/components/layout/landing-layout/header/components/IRegisterModal';
|
||||
import ILoginBtn from '@/components/layout/landing-layout/header/components/ILoginBtn';
|
||||
import IDollarYuan from '@/components/layout/landing-layout/header/components/IDollarYuan';
|
||||
|
||||
const StyledHeader = styled('header')`
|
||||
z-index: 999;
|
||||
position: sticky;
|
||||
left: 0;
|
||||
top: -43px;
|
||||
|
||||
.top-header {
|
||||
background-color: #07275c;
|
||||
padding: 8px 0;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.top-header-link {
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 20px; /* 142.857% */
|
||||
letter-spacing: 0.14px;
|
||||
}
|
||||
|
||||
.social-link {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
// ---------------------------------
|
||||
|
||||
.main-header {
|
||||
background: #e5eef6;
|
||||
padding: 16px 0;
|
||||
|
||||
.logo-link {
|
||||
color: #003a77;
|
||||
font-size: 28px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
line-height: 36px; /* 128.571% */
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
color: #07275c;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 20px; /* 125% */
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.lng-img {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
flex-shrink: 0;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.lng-select {
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
color: #07275c;
|
||||
}
|
||||
|
||||
.calc-btn {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
border-radius: 4px;
|
||||
border: 2px solid #0076be;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
&:active {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
.check-btn {
|
||||
display: flex;
|
||||
padding: 13px 12px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
border-radius: 4px;
|
||||
background: #0076be;
|
||||
color: #fff;
|
||||
transition: opacity 0.3s ease;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
&:active {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
${({ theme }) => css`
|
||||
${theme.breakpoints.down('md')} {
|
||||
top: 0;
|
||||
|
||||
.main-header {
|
||||
padding: 10px 0;
|
||||
}
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
const StyledDrawer = styled(Drawer)`
|
||||
.logo-link {
|
||||
color: #003a77;
|
||||
font-size: 28px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
line-height: 36px; /* 128.571% */
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
color: #07275c;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 20px; /* 125% */
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.lng-img {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
flex-shrink: 0;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.lng-select {
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
color: #07275c;
|
||||
}
|
||||
|
||||
.calc-btn {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
border-radius: 4px;
|
||||
border: 2px solid #0076be;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
&:active {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
.check-btn {
|
||||
display: flex;
|
||||
padding: 13px 12px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
border-radius: 4px;
|
||||
background: #0076be;
|
||||
color: #fff;
|
||||
transition: opacity 0.3s ease;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
&:active {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
type Props = {};
|
||||
|
||||
const Header = (props: Props) => {
|
||||
const t = useMyTranslation();
|
||||
const language = useLocale();
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const [isOpenMenu, setIsOpenMenu] = useState(false);
|
||||
const [modal, setModal] = useState<'calculator' | 'check_order' | 'verify_phone' | 'register' | null>(null);
|
||||
const [phoneNumber, setPhoneNumber] = useState('');
|
||||
|
||||
const openCalculatorModal = () => {
|
||||
setModal('calculator');
|
||||
};
|
||||
|
||||
const changePhone = (value: string) => {
|
||||
setPhoneNumber(value);
|
||||
};
|
||||
|
||||
const openCheckOrderModal = () => {
|
||||
setModal('check_order');
|
||||
};
|
||||
|
||||
const openVerifyPhoneModal = () => {
|
||||
setModal('verify_phone');
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
setModal(null);
|
||||
};
|
||||
|
||||
const changeLanguage = (lng: string) => {
|
||||
router.push(`/${lng}/${pathname.substring(3)}`, { scroll: false });
|
||||
};
|
||||
|
||||
const openRegister = () => setModal('register');
|
||||
|
||||
return (
|
||||
<StyledHeader>
|
||||
<Box
|
||||
className='top-header'
|
||||
display={{
|
||||
xs: 'none',
|
||||
md: 'block',
|
||||
}}
|
||||
>
|
||||
<Container>
|
||||
<Stack direction={'row'} justifyContent={'space-between'}>
|
||||
<Stack direction={'row'} spacing={1.5}>
|
||||
<Stack direction={'row'} alignItems={'center'} spacing={1.5}>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20' fill='none'>
|
||||
<path
|
||||
d='M17.5 13.6833V16.6301C17.5 17.0676 17.1617 17.4306 16.7254 17.4614C16.3609 17.4872 16.0636 17.5 15.8333 17.5C8.4695 17.5 2.5 11.5305 2.5 4.16667C2.5 3.93642 2.51288 3.63906 2.53863 3.27458C2.56948 2.83823 2.93245 2.5 3.36988 2.5H6.31675C6.53065 2.5 6.7098 2.66202 6.73127 2.87483C6.75056 3.06589 6.76848 3.21928 6.78506 3.33502C6.95362 4.51227 7.29794 5.6328 7.79058 6.66919C7.86966 6.83554 7.81809 7.03466 7.66821 7.14172L5.86962 8.4265C6.9646 10.9843 9.01575 13.0354 11.5735 14.1304L12.8559 12.3349C12.9643 12.1832 13.1658 12.1311 13.3342 12.211C14.3705 12.7032 15.4909 13.0472 16.668 13.2153C16.783 13.2318 16.9354 13.2496 17.1252 13.2687C17.338 13.2902 17.5 13.4694 17.5 13.6833Z'
|
||||
fill='white'
|
||||
/>
|
||||
</svg>
|
||||
<NextLink className='top-header-link' href='#'>
|
||||
+998 (99) 110 22 22
|
||||
</NextLink>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='2' height='20' viewBox='0 0 2 20' fill='none'>
|
||||
<path d='M1 0L0.999999 20' stroke='white' stroke-width='2' />
|
||||
</svg>
|
||||
<NextLink className='top-header-link' href='#'>
|
||||
+86 (150) 2452 0047
|
||||
</NextLink>
|
||||
</Stack>
|
||||
<Stack direction={'row'} alignItems={'center'} spacing={1.5}>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20' fill='none'>
|
||||
<path
|
||||
d='M2.49984 2.5H17.4998C17.9601 2.5 18.3332 2.8731 18.3332 3.33333V16.6667C18.3332 17.1269 17.9601 17.5 17.4998 17.5H2.49984C2.0396 17.5 1.6665 17.1269 1.6665 16.6667V3.33333C1.6665 2.8731 2.0396 2.5 2.49984 2.5ZM16.6665 6.0316L10.0597 11.9483L3.33317 6.01328V15.8333H16.6665V6.0316ZM3.75939 4.16667L10.0514 9.71833L16.2507 4.16667H3.75939Z'
|
||||
fill='white'
|
||||
/>
|
||||
</svg>
|
||||
<NextLink className='top-header-link' href='#'>
|
||||
info@cpost.uz
|
||||
</NextLink>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<Stack direction={'row'} spacing={2} display={'flex'} alignItems={'center'}>
|
||||
<IDollarYuan />
|
||||
{/*<Typography>1 USD = 7.1 Y</Typography>*/}
|
||||
{/*<NextLink className='social-link'>*/}
|
||||
{/* <svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20' fill='none'>*/}
|
||||
{/* <path*/}
|
||||
{/* d='M6.66536 2C4.0927 2 2 4.09464 2 6.66797V13.3346C2 15.9073 4.09464 18 6.66797 18H13.3346C15.9073 18 18 15.9054 18 13.332V6.66536C18 4.0927 15.9054 2 13.332 2H6.66536ZM14.6667 4.66667C15.0347 4.66667 15.3333 4.96533 15.3333 5.33333C15.3333 5.70133 15.0347 6 14.6667 6C14.2987 6 14 5.70133 14 5.33333C14 4.96533 14.2987 4.66667 14.6667 4.66667ZM10 6C12.206 6 14 7.794 14 10C14 12.206 12.206 14 10 14C7.794 14 6 12.206 6 10C6 7.794 7.794 6 10 6ZM10 7.33333C9.29276 7.33333 8.61448 7.61428 8.11438 8.11438C7.61428 8.61448 7.33333 9.29276 7.33333 10C7.33333 10.7072 7.61428 11.3855 8.11438 11.8856C8.61448 12.3857 9.29276 12.6667 10 12.6667C10.7072 12.6667 11.3855 12.3857 11.8856 11.8856C12.3857 11.3855 12.6667 10.7072 12.6667 10C12.6667 9.29276 12.3857 8.61448 11.8856 8.11438C11.3855 7.61428 10.7072 7.33333 10 7.33333Z'*/}
|
||||
{/* fill='white'*/}
|
||||
{/* />*/}
|
||||
{/* </svg>*/}
|
||||
{/*</NextLink>*/}
|
||||
{/*<NextLink className='social-link'>*/}
|
||||
{/* <svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20' fill='none'>*/}
|
||||
{/* <path*/}
|
||||
{/* d='M6.66536 2C4.0927 2 2 4.09464 2 6.66797V13.3346C2 15.9073 4.09464 18 6.66797 18H13.3346C15.9073 18 18 15.9054 18 13.332V6.66536C18 4.0927 15.9054 2 13.332 2H6.66536ZM14.6667 4.66667C15.0347 4.66667 15.3333 4.96533 15.3333 5.33333C15.3333 5.70133 15.0347 6 14.6667 6C14.2987 6 14 5.70133 14 5.33333C14 4.96533 14.2987 4.66667 14.6667 4.66667ZM10 6C12.206 6 14 7.794 14 10C14 12.206 12.206 14 10 14C7.794 14 6 12.206 6 10C6 7.794 7.794 6 10 6ZM10 7.33333C9.29276 7.33333 8.61448 7.61428 8.11438 8.11438C7.61428 8.61448 7.33333 9.29276 7.33333 10C7.33333 10.7072 7.61428 11.3855 8.11438 11.8856C8.61448 12.3857 9.29276 12.6667 10 12.6667C10.7072 12.6667 11.3855 12.3857 11.8856 11.8856C12.3857 11.3855 12.6667 10.7072 12.6667 10C12.6667 9.29276 12.3857 8.61448 11.8856 8.11438C11.3855 7.61428 10.7072 7.33333 10 7.33333Z'*/}
|
||||
{/* fill='white'*/}
|
||||
{/* />*/}
|
||||
{/* </svg>*/}
|
||||
{/*</NextLink>*/}
|
||||
{/*<NextLink className='social-link'>*/}
|
||||
{/* <svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20' fill='none'>*/}
|
||||
{/* <path*/}
|
||||
{/* d='M2.42918 9.84011C7.66585 7.53636 14.4425 4.72761 15.3779 4.33886C17.8317 3.32136 18.5846 3.51636 18.2092 5.76969C17.9396 7.38928 17.1617 12.7514 16.5417 16.0889C16.1738 18.068 15.3483 18.3026 14.0504 17.4464C13.4263 17.0343 10.2758 14.9509 9.5921 14.4618C8.96793 14.0159 8.1071 13.4797 9.18668 12.4234C9.57085 12.0472 12.0892 9.64261 14.0513 7.77094C14.3083 7.52511 13.9854 7.12136 13.6888 7.31844C11.0442 9.07219 7.37751 11.5064 6.91085 11.8234C6.20585 12.3022 5.52876 12.5218 4.31335 12.1726C3.39501 11.9089 2.49793 11.5943 2.14876 11.4743C0.804182 11.0126 1.12335 10.4147 2.42918 9.84011Z'*/}
|
||||
{/* fill='white'*/}
|
||||
{/* />*/}
|
||||
{/* </svg>*/}
|
||||
{/*</NextLink>*/}
|
||||
<ILoginBtn openVerifyPhoneModal={openVerifyPhoneModal} />
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Container>
|
||||
</Box>
|
||||
<div className='main-header'>
|
||||
<Container>
|
||||
<Stack direction={'row'} justifyContent={'space-between'} alignItems={'center'} spacing={7.5}>
|
||||
<NextLink className='logo-link' href={pageLinks.home}>
|
||||
<LogoSvg />
|
||||
</NextLink>
|
||||
<Stack direction={'row'} alignItems={'center'} spacing={2} display={{ xs: 'none', md: 'flex' }}>
|
||||
<NextLink className='nav-link' href={pageLinks.home}>
|
||||
{t('home')}
|
||||
</NextLink>
|
||||
<NextLink className='nav-link' href={pageLinks.home + '#about'}>
|
||||
{t('about_us')}
|
||||
</NextLink>
|
||||
<NextLink className='nav-link' href={pageLinks.home + '#services'}>
|
||||
{t('services')}
|
||||
</NextLink>
|
||||
{/* <NextLink className='nav-link' href={pageLinks.news}>
|
||||
{t('news')}
|
||||
</NextLink> */}
|
||||
<NextLink className='nav-link' href={pageLinks.home + '#tariffs'}>
|
||||
{t('tariffs')}
|
||||
</NextLink>
|
||||
<NextLink className='nav-link' href={pageLinks.home + '#contacts'}>
|
||||
{t('contacts')}
|
||||
</NextLink>
|
||||
</Stack>
|
||||
<Stack direction={'row'} alignItems={'center'} spacing={2}>
|
||||
<Stack direction={'row'} alignItems={'center'} spacing={2} display={{ xs: 'none', sm: 'flex' }}>
|
||||
<img className='lng-img' src={getLanguageImage(language)} alt='' />
|
||||
|
||||
<select
|
||||
className='lng-select'
|
||||
value={language}
|
||||
onChange={event => {
|
||||
changeLanguage(event.target.value);
|
||||
}}
|
||||
>
|
||||
<option value='uz'>UZ</option>
|
||||
<option value='ru'>RU</option>
|
||||
<option value='en'>EN</option>
|
||||
<option value='cn'>中國人</option>
|
||||
</select>
|
||||
|
||||
<button className='calc-btn' onClick={openCalculatorModal}>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20' fill='none'>
|
||||
<path
|
||||
d='M2 0H18C18.5523 0 19 0.44772 19 1V19C19 19.5523 18.5523 20 18 20H2C1.44772 20 1 19.5523 1 19V1C1 0.44772 1.44772 0 2 0ZM3 2V18H17V2H3ZM5 4H15V8H5V4ZM5 10H7V12H5V10ZM5 14H7V16H5V14ZM9 10H11V12H9V10ZM9 14H11V16H9V14ZM13 10H15V16H13V10Z'
|
||||
fill='#0076BE'
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button className='check-btn' onClick={openCheckOrderModal}>
|
||||
{t('check_order')}
|
||||
</button>
|
||||
</Stack>
|
||||
|
||||
<IconButton
|
||||
sx={{
|
||||
display: { xs: 'flex', md: 'none' },
|
||||
}}
|
||||
onClick={() => setIsOpenMenu(p => !p)}
|
||||
>
|
||||
<Menu />
|
||||
</IconButton>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Container>
|
||||
</div>
|
||||
|
||||
{burgerMenu()}
|
||||
<CalculatorModal onClose={closeModal} open={modal === 'calculator'} />
|
||||
<CheckOrderModal onClose={closeModal} open={modal === 'check_order'} />
|
||||
<VerifyPhoneModal changePhone={changePhone} openRegister={openRegister} onClose={closeModal} phoneNumber={phoneNumber} open={modal === 'verify_phone'} />
|
||||
<IRegisterModal phoneNumber={phoneNumber} onClose={closeModal} open={modal === 'register'} />
|
||||
</StyledHeader>
|
||||
);
|
||||
|
||||
function burgerMenu() {
|
||||
return (
|
||||
<StyledDrawer
|
||||
open={isOpenMenu}
|
||||
onClose={() => setIsOpenMenu(false)}
|
||||
anchor='right'
|
||||
sx={{
|
||||
'.MuiPaper-root': {
|
||||
padding: '10px 12px',
|
||||
width: '100%',
|
||||
maxWidth: '400px',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Stack spacing={2}>
|
||||
<Stack direction={'row'} alignItems={'center'} justifyContent={'space-between'}>
|
||||
<NextLink className='logo-link' href={pageLinks.home}>
|
||||
<LogoSvg />
|
||||
</NextLink>
|
||||
<IconButton onClick={() => setIsOpenMenu(false)}>
|
||||
<Close />
|
||||
</IconButton>
|
||||
</Stack>
|
||||
|
||||
<NextLink className='nav-link' href={pageLinks.home} onClick={() => setIsOpenMenu(false)}>
|
||||
{t('home')}
|
||||
</NextLink>
|
||||
<NextLink className='nav-link' href={pageLinks.home + '#about'} onClick={() => setIsOpenMenu(false)}>
|
||||
{t('about_us')}
|
||||
</NextLink>
|
||||
<NextLink className='nav-link' href={pageLinks.home + '#services'} onClick={() => setIsOpenMenu(false)}>
|
||||
{t('services')}
|
||||
</NextLink>
|
||||
{/* <NextLink className='nav-link' href={pageLinks.news} onClick={() => setIsOpenMenu(false)}>
|
||||
{t('news')}
|
||||
</NextLink> */}
|
||||
<NextLink className='nav-link' href={pageLinks.home + '#tariffs'} onClick={() => setIsOpenMenu(false)}>
|
||||
{t('tariffs')}
|
||||
</NextLink>
|
||||
<NextLink className='nav-link' href={pageLinks.home + '#contacts'} onClick={() => setIsOpenMenu(false)}>
|
||||
{t('contacts')}
|
||||
</NextLink>
|
||||
|
||||
<Stack spacing={2} display={{ xs: 'flex' }}>
|
||||
<Stack spacing={2} display={{ sm: 'none' }}>
|
||||
<button className='calc-btn' onClick={openCalculatorModal}>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20' fill='none'>
|
||||
<path
|
||||
d='M2 0H18C18.5523 0 19 0.44772 19 1V19C19 19.5523 18.5523 20 18 20H2C1.44772 20 1 19.5523 1 19V1C1 0.44772 1.44772 0 2 0ZM3 2V18H17V2H3ZM5 4H15V8H5V4ZM5 10H7V12H5V10ZM5 14H7V16H5V14ZM9 10H11V12H9V10ZM9 14H11V16H9V14ZM13 10H15V16H13V10Z'
|
||||
fill='#0076BE'
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button className='check-btn' onClick={openCheckOrderModal}>
|
||||
{t('check_order')}
|
||||
</button>
|
||||
</Stack>
|
||||
|
||||
<button className='check-btn' onClick={openVerifyPhoneModal}>
|
||||
<svg width='18' height='18' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
d='M8 7C9.65685 7 11 5.65685 11 4C11 2.34315 9.65685 1 8 1C6.34315 1 5 2.34315 5 4C5 5.65685 6.34315 7 8 7Z'
|
||||
fill='#fff'
|
||||
/>
|
||||
<path d='M14 12C14 10.3431 12.6569 9 11 9H5C3.34315 9 2 10.3431 2 12V15H14V12Z' fill='#fff' />
|
||||
</svg>
|
||||
<span>Hisobga Kirish</span>
|
||||
</button>
|
||||
|
||||
<Stack display={{ sm: 'none' }} direction={'row'} justifyContent={'flex-start'} alignItems={'center'}>
|
||||
<img className='lng-img' src={getLanguageImage(language)} alt='' />
|
||||
|
||||
<select
|
||||
className='lng-select'
|
||||
value={language}
|
||||
onChange={event => {
|
||||
changeLanguage(event.target.value);
|
||||
}}
|
||||
>
|
||||
<option value='uz'>UZ</option>
|
||||
<option value='ru'>RU</option>
|
||||
<option value='en'>EN</option>
|
||||
<option value='cn'>中國人</option>
|
||||
</select>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</StyledDrawer>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default Header;
|
||||
|
||||
function getLanguageImage(lang: string) {
|
||||
switch (lang) {
|
||||
case 'uz': {
|
||||
return '/static/icons/uz-flag.png';
|
||||
}
|
||||
case 'en': {
|
||||
return '/static/icons/en-flag.png';
|
||||
}
|
||||
case 'ru': {
|
||||
return '/static/icons/ru-flag.webp';
|
||||
}
|
||||
case 'cn': {
|
||||
return '/static/icons/cn-flag.png';
|
||||
}
|
||||
default: {
|
||||
return '/static/icons/uz-flag.png';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
'use client';
|
||||
|
||||
import { Typography } from '@mui/material';
|
||||
import { useEffect, useState } from 'react';
|
||||
import axios from 'axios';
|
||||
|
||||
export default function IDollarYuan() {
|
||||
const [yuan, setYuan] = useState<string | undefined>('');
|
||||
|
||||
useEffect(() => {
|
||||
axios.get('https://api.exchangerate-api.com/v4/latest/USD').then(res => {
|
||||
setYuan(res.data?.rates?.CNY);
|
||||
});
|
||||
}, []);
|
||||
|
||||
if (!yuan) return null;
|
||||
|
||||
return <Typography>1 USD = {yuan} Y</Typography>;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
'use client';
|
||||
|
||||
import { Button } from '@mui/material';
|
||||
import React from 'react';
|
||||
import { useMyNavigation } from '@/hooks/useMyNavigation';
|
||||
|
||||
interface IProps {
|
||||
openVerifyPhoneModal: () => void;
|
||||
}
|
||||
|
||||
export default function ILoginBtn({ openVerifyPhoneModal }: IProps) {
|
||||
const token = typeof window !== "undefined" ? localStorage.getItem('token') : "";
|
||||
const { replace } = useMyNavigation();
|
||||
|
||||
const handleProfile = () => {
|
||||
if (token) {
|
||||
replace('/profile');
|
||||
} else {
|
||||
openVerifyPhoneModal();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
onClick={handleProfile}
|
||||
sx={{
|
||||
backgroundColor: 'transparent',
|
||||
padding: 0,
|
||||
textTransform: 'capitalize',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 0.5,
|
||||
}}
|
||||
>
|
||||
<svg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
d='M8 7C9.65685 7 11 5.65685 11 4C11 2.34315 9.65685 1 8 1C6.34315 1 5 2.34315 5 4C5 5.65685 6.34315 7 8 7Z'
|
||||
fill='#fff'
|
||||
/>
|
||||
<path d='M14 12C14 10.3431 12.6569 9 11 9H5C3.34315 9 2 10.3431 2 12V15H14V12Z' fill='#fff' />
|
||||
</svg>
|
||||
<span>{token ? 'Profil' : 'Kirish'}</span>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Box, TextField } from '@mui/material';
|
||||
import { IRegisterProps } from '@/components/layout/landing-layout/header/components/IRegisterModal';
|
||||
|
||||
|
||||
export const IRegisterFirstStep = ({ formDataChanging, formData, dataErrors }: IRegisterProps) => {
|
||||
return (
|
||||
<Box display={'flex'} flexDirection={'column'} gap={3}>
|
||||
<TextField
|
||||
error={dataErrors.first_name}
|
||||
label='Ism'
|
||||
variant='outlined'
|
||||
fullWidth
|
||||
value={formData.first_name}
|
||||
onChange={e => formDataChanging({ key: 'first_name', value: e.target.value })}
|
||||
/>
|
||||
<TextField
|
||||
error={dataErrors.last_name}
|
||||
label='Familiya'
|
||||
variant='outlined'
|
||||
fullWidth
|
||||
value={formData.last_name}
|
||||
onChange={e => formDataChanging({ key: 'last_name', value: e.target.value })}
|
||||
/>
|
||||
<TextField
|
||||
error={dataErrors.birth_date}
|
||||
label="Tug'ilgan sana"
|
||||
type='date'
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
value={formData.birth_date}
|
||||
onChange={e => formDataChanging({ key: 'birth_date', value: e.target.value })}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Box, Button, TextField, Typography } from '@mui/material';
|
||||
import { IRegisterProps } from '@/components/layout/landing-layout/header/components/IRegisterModal';
|
||||
import MCodeInput from '@/components/common/MComponents/MCodeInput';
|
||||
import React from 'react';
|
||||
|
||||
export function IRegisterFourthStep({ formDataChanging, formData, dataErrors }: IRegisterProps) {
|
||||
return (
|
||||
<Box display={'flex'} flexDirection={'column'} gap={3}>
|
||||
{/*<Typography variant='body1' mb={2}>*/}
|
||||
{/* Iltimos, SMS orqali yuborilgan 4 xonali kodni kiriting:*/}
|
||||
{/*</Typography>*/}
|
||||
|
||||
{/*<MCodeInput clearError={clearCodesError} isError={inputErrors.code} onCodeChange={setVerificationCode} />*/}
|
||||
|
||||
{/*<Box sx={{ mt: 3 }} display='flex' justifyContent={'end'} gap={2}>*/}
|
||||
{/* <Button variant='outlined' onClick={handleBack}>*/}
|
||||
{/* Orqaga*/}
|
||||
{/* </Button>*/}
|
||||
|
||||
{/* <Button variant='contained' color='primary' onClick={handleVerifyCode}>*/}
|
||||
{/* Tasdiqlash*/}
|
||||
{/* </Button>*/}
|
||||
{/*</Box>*/}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
'use client';
|
||||
|
||||
import { Box, Button, Modal, Typography } from '@mui/material';
|
||||
import React, { useState } from 'react';
|
||||
import { IRegisterFirstStep } from '@/components/layout/landing-layout/header/components/IRegisterFirstStep';
|
||||
import { IRegisterSecondStep } from '@/components/layout/landing-layout/header/components/IRegisterSecondStep';
|
||||
import { IRegisterThirdStep } from '@/components/layout/landing-layout/header/components/IRegisterThirdStep';
|
||||
import { usePathname, useRouter } from 'next/navigation';
|
||||
import toast from 'react-hot-toast';
|
||||
import axios from 'axios';
|
||||
import { BASE_URL } from '@/helpers/constants';
|
||||
import { toBase64 } from '@/helpers/toBase64';
|
||||
import MCodeInput from '@/components/common/MComponents/MCodeInput';
|
||||
import myAxios from '@/helpers/myAxios';
|
||||
import authRequest from '@/helpers/authRequest';
|
||||
|
||||
// import { IRegisterFourthStep } from '@/components/layout/landing-layout/header/components/IRegisterFourthStep';
|
||||
|
||||
interface IProps {
|
||||
onClose: () => void;
|
||||
open: boolean;
|
||||
phoneNumber: string;
|
||||
}
|
||||
|
||||
export interface IRegisterData {
|
||||
passport_serie: string;
|
||||
passport_pnfl: string;
|
||||
passport_front: File | null;
|
||||
passport_back: File | null;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
birth_date: string;
|
||||
address: string;
|
||||
filial: string;
|
||||
password: string;
|
||||
password_confirmation: string;
|
||||
}
|
||||
|
||||
export interface IErrorsData {
|
||||
passport_serie: boolean;
|
||||
passport_pnfl: boolean;
|
||||
passport_front: boolean;
|
||||
passport_back: boolean;
|
||||
first_name: boolean;
|
||||
last_name: boolean;
|
||||
birth_date: boolean;
|
||||
address: boolean;
|
||||
filial: boolean;
|
||||
password: boolean;
|
||||
password_confirmation: boolean;
|
||||
}
|
||||
|
||||
export interface IRegisterProps {
|
||||
formData: IRegisterData;
|
||||
formDataChanging: ({ key, value }: { key: string; value: string | number | File | null }) => void;
|
||||
dataErrors: IErrorsData;
|
||||
}
|
||||
|
||||
const style = {
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
width: { xs: '90%', sm: 400 },
|
||||
bgcolor: 'background.paper',
|
||||
borderRadius: 2,
|
||||
boxShadow: 24,
|
||||
p: 4,
|
||||
};
|
||||
|
||||
const initialValues: IRegisterData = {
|
||||
first_name: '',
|
||||
last_name: '',
|
||||
birth_date: '',
|
||||
passport_pnfl: '',
|
||||
passport_serie: '',
|
||||
passport_back: null,
|
||||
passport_front: null,
|
||||
address: '',
|
||||
filial: '',
|
||||
password: '',
|
||||
password_confirmation: '',
|
||||
};
|
||||
|
||||
const initialErrorValues: IErrorsData = {
|
||||
first_name: false,
|
||||
last_name: false,
|
||||
birth_date: false,
|
||||
passport_pnfl: false,
|
||||
passport_serie: false,
|
||||
passport_back: false,
|
||||
passport_front: false,
|
||||
address: false,
|
||||
filial: false,
|
||||
password: false,
|
||||
password_confirmation: false,
|
||||
};
|
||||
|
||||
export function IRegisterModal({ open, onClose, phoneNumber }: IProps) {
|
||||
const pathname = usePathname();
|
||||
const locale = pathname.split('/')[1] || 'uz';
|
||||
const router = useRouter();
|
||||
const [step, setStep] = useState<number>(1);
|
||||
const [formData, setFormData] = useState<IRegisterData>(initialValues);
|
||||
const [dataErrors, setDataErrors] = useState<IErrorsData>(initialErrorValues);
|
||||
const [verifyCode, setVerifyCode] = useState('');
|
||||
|
||||
const formDataChanging = ({ key, value }: { key: string; value: string | number | File | null }): void => {
|
||||
setDataErrors(prev => ({ ...prev, [key]: false }));
|
||||
setFormData({ ...formData, [key]: value });
|
||||
};
|
||||
|
||||
const nextStepHandler = async () => {
|
||||
if (step === 1) {
|
||||
if (!formData.first_name) setDataErrors(prev => ({ ...prev, first_name: true }));
|
||||
if (!formData.last_name) setDataErrors(prev => ({ ...prev, last_name: true }));
|
||||
if (!formData.birth_date) setDataErrors(prev => ({ ...prev, birth_date: true }));
|
||||
|
||||
if (!formData.first_name || !formData.last_name || !formData.birth_date) return;
|
||||
} else if (step === 2) {
|
||||
if (!formData.passport_pnfl) setDataErrors(prev => ({ ...prev, passport_pnfl: true }));
|
||||
if (!formData.passport_serie) setDataErrors(prev => ({ ...prev, passport_serie: true }));
|
||||
if (!formData.passport_front) setDataErrors(prev => ({ ...prev, passport_front: true }));
|
||||
if (!formData.passport_back) setDataErrors(prev => ({ ...prev, passport_back: true }));
|
||||
|
||||
if (!formData.passport_pnfl || !formData.passport_serie || !formData.passport_front || !formData.passport_back) return;
|
||||
} else if (step === 3) {
|
||||
if (!formData.address) setDataErrors(prev => ({ ...prev, address: true }));
|
||||
if (!formData.filial) setDataErrors(prev => ({ ...prev, filial: true }));
|
||||
|
||||
if (!formData.address || !formData.filial) return;
|
||||
|
||||
try {
|
||||
await authRequest.post('/profile/send-otp', { phone: phoneNumber });
|
||||
toast.success("Tasdiqlash ko'di yuborildi");
|
||||
} catch (error: any) {
|
||||
toast.error(error?.message || "Tasdiqlash ko'di yuborilmadi");
|
||||
return;
|
||||
}
|
||||
} else if (step === 4) {
|
||||
if (verifyCode.length !== 4) return;
|
||||
}
|
||||
|
||||
if (step !== 4) return setStep(prev => prev + 1);
|
||||
|
||||
const fData = {
|
||||
name: formData.first_name + ' ' + formData.last_name,
|
||||
phone: phoneNumber,
|
||||
passportSeries: formData.passport_serie,
|
||||
pinfl: formData.passport_pnfl,
|
||||
dateOfBirth: formData.birth_date,
|
||||
address: formData.address,
|
||||
region: formData.filial,
|
||||
passportFront: formData.passport_front ? await toBase64(formData.passport_front) : '',
|
||||
passportBack: formData.passport_back ? await toBase64(formData.passport_back) : '',
|
||||
code: verifyCode,
|
||||
};
|
||||
|
||||
toast
|
||||
.promise(axios.post(BASE_URL + '/api/v1/profile/sign-up', fData), {
|
||||
loading: 'Loading...',
|
||||
success: 'Ma’lumotlaringiz ko‘rib chiqilmoqda. Iltimos, kuting.',
|
||||
error: 'Hatolik yuz berdi',
|
||||
})
|
||||
.then(() => {
|
||||
axios
|
||||
.post(BASE_URL + '/api/v1/profile/sign-in', {
|
||||
phone: phoneNumber,
|
||||
code: '1234',
|
||||
})
|
||||
.then(response => {
|
||||
// router.push(`/${locale}/profile`);
|
||||
setStep(1);
|
||||
setFormData(initialValues);
|
||||
onClose();
|
||||
|
||||
// const data = response.data?.data;
|
||||
// localStorage.setItem('token', data?.accessToken);
|
||||
// localStorage.setItem('username', data?.username);
|
||||
// localStorage.setItem('roles', data?.role?.[0]);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
if(axios.isAxiosError(error) && error.response?.status === 413) {
|
||||
toast.error('Katta hajmdagi fayl yubordingiz. Iltimos, kichikroq hajmli fayl tanlang.');
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
const decStepHandler = () => {
|
||||
if (step === 1) {
|
||||
onClose();
|
||||
} else {
|
||||
setStep(prev => {
|
||||
if (prev > 1) return prev - 1;
|
||||
return prev;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleVerifyCode = () => {};
|
||||
|
||||
return (
|
||||
<Modal open={open} onClose={onClose}>
|
||||
<Box sx={style}>
|
||||
<Typography variant='h6' align={'center'} fontSize={'1.5rem'} fontWeight={'bolder'} component='h2' mb={2}>
|
||||
{`Ro'yxatdan o'tish`}
|
||||
</Typography>
|
||||
|
||||
{step === 1 && <IRegisterFirstStep formDataChanging={formDataChanging} formData={formData} dataErrors={dataErrors} />}
|
||||
{step === 2 && <IRegisterSecondStep formDataChanging={formDataChanging} formData={formData} dataErrors={dataErrors} />}
|
||||
{step === 3 && <IRegisterThirdStep formDataChanging={formDataChanging} formData={formData} dataErrors={dataErrors} />}
|
||||
|
||||
{/*{step === 4 && <IRegisterFourthStep formDataChanging={formDataChanging} formData={formData} dataErrors={dataErrors} />}*/}
|
||||
|
||||
{step === 4 && (
|
||||
<Box display={'flex'} flexDirection={'column'} gap={3}>
|
||||
<Typography variant='body1' mb={2}>
|
||||
Iltimos, SMS orqali yuborilgan 4 xonali kodni kiriting:
|
||||
</Typography>
|
||||
|
||||
{/*<MCodeInput clearError={clearCodesError} isError={inputErrors.code} onCodeChange={value => setVerifyCode(value)} />*/}
|
||||
<MCodeInput isError={false} onCodeChange={value => setVerifyCode(value)} />
|
||||
|
||||
{/*<Box sx={{ mt: 3 }} display='flex' justifyContent={'end'} gap={2}>*/}
|
||||
{/* <Button variant='outlined' onClick={() => setStep(3)}>*/}
|
||||
{/* Orqaga*/}
|
||||
{/* </Button>*/}
|
||||
|
||||
{/* <Button variant='contained' color='primary' onClick={handleVerifyCode}>*/}
|
||||
{/* Tasdiqlash*/}
|
||||
{/* </Button>*/}
|
||||
{/*</Box>*/}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Box sx={{ marginTop: 2, display: 'flex', justifyContent: 'end', gap: 2 }}>
|
||||
<Button variant='outlined' onClick={decStepHandler}>
|
||||
{step === 1 ? 'Bekor qilish' : 'Qaytish'}
|
||||
</Button>
|
||||
<Button variant='contained' onClick={nextStepHandler}>
|
||||
{step === 4 ? 'Yuborish' : 'Keyingi'}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
'use client';
|
||||
|
||||
import { IRegisterProps } from '@/components/layout/landing-layout/header/components/IRegisterModal';
|
||||
import { Box, Card, TextField } from '@mui/material';
|
||||
|
||||
export function IRegisterSecondStep({ formData, formDataChanging, dataErrors }: IRegisterProps) {
|
||||
const handleFrontChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (!e.target.files?.[0]) return;
|
||||
formDataChanging({
|
||||
key: 'passport_front',
|
||||
value: e.target.files[0],
|
||||
});
|
||||
};
|
||||
const handleBackChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (!e.target.files?.[0]) return;
|
||||
formDataChanging({
|
||||
key: 'passport_back',
|
||||
value: e.target.files[0],
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Box display='flex' flexDirection='column' gap={2}>
|
||||
<TextField
|
||||
label='Passport Seriya/Raqami'
|
||||
variant='outlined'
|
||||
error={dataErrors.passport_serie}
|
||||
fullWidth
|
||||
value={formData.passport_serie}
|
||||
onChange={e => formDataChanging({ key: 'passport_serie', value: e.target.value })}
|
||||
/>
|
||||
<TextField
|
||||
label='PINFL'
|
||||
variant='outlined'
|
||||
error={dataErrors.passport_pnfl}
|
||||
fullWidth
|
||||
value={formData.passport_pnfl}
|
||||
onChange={e => formDataChanging({ key: 'passport_pnfl', value: e.target.value })}
|
||||
/>
|
||||
<Box>
|
||||
<Box sx={{ marginBottom: 1, fontWeight: 500 }}>Passport rasmi</Box>
|
||||
<Box display='flex' justifyContent='center' gap={3}>
|
||||
<Box>
|
||||
<Card
|
||||
component='label'
|
||||
sx={{
|
||||
width: 100,
|
||||
height: 100,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
bgcolor: '#f0f0f0',
|
||||
cursor: 'pointer',
|
||||
border: `1px solid ${dataErrors.passport_front ? "red" : "transparent"}`,
|
||||
transition: 'all 0.6 ease-out'
|
||||
}}
|
||||
>
|
||||
{formData.passport_front ? (
|
||||
<Box
|
||||
component='img'
|
||||
src={URL.createObjectURL(formData.passport_front)}
|
||||
sx={{ maxWidth: '100%', maxHeight: '100%' }}
|
||||
/>
|
||||
) : (
|
||||
<Box fontSize={14} color={'#444'}>
|
||||
Oldi rasmi
|
||||
</Box>
|
||||
)}
|
||||
<input type='file' hidden accept='image/*' onChange={handleFrontChange} />
|
||||
</Card>
|
||||
</Box>
|
||||
<Box>
|
||||
<Card
|
||||
component='label'
|
||||
sx={{
|
||||
width: 100,
|
||||
height: 100,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
bgcolor: '#f0f0f0',
|
||||
cursor: 'pointer',
|
||||
border: `1px solid ${dataErrors.passport_back ? "red" : "transparent"}`,
|
||||
transition: 'all 0.6 ease-out'
|
||||
}}
|
||||
>
|
||||
{formData.passport_back ? (
|
||||
<Box
|
||||
component='img'
|
||||
src={URL.createObjectURL(formData.passport_back)}
|
||||
sx={{ maxWidth: '100%', maxHeight: '100%' }}
|
||||
/>
|
||||
) : (
|
||||
<Box fontSize={14} color={'#444'}>
|
||||
Orqa rasmi
|
||||
</Box>
|
||||
)}
|
||||
<input type='file' hidden accept='image/*' onChange={handleBackChange} />
|
||||
</Card>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { Box, TextField, MenuItem } from '@mui/material';
|
||||
import { IRegisterProps } from '@/components/layout/landing-layout/header/components/IRegisterModal';
|
||||
import useMainFetch from '@/hooks/useMainFetch';
|
||||
|
||||
export function IRegisterThirdStep({ formData, formDataChanging, dataErrors }: IRegisterProps) {
|
||||
const { data } = useMainFetch({
|
||||
key: 'branches',
|
||||
endpoint: '/branches',
|
||||
});
|
||||
|
||||
const branchOptions = data?.data?.data?.map((item: { option: string; nameUz: string; nameRu: string; nameEn: string }) => {
|
||||
|
||||
|
||||
return {
|
||||
value: item.option,
|
||||
label: item.nameUz,
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<Box component='form' display='flex' flexDirection='column' gap={2}>
|
||||
<TextField
|
||||
label='Manzil'
|
||||
variant='outlined'
|
||||
fullWidth
|
||||
value={formData.address}
|
||||
error={dataErrors.address}
|
||||
onChange={e => formDataChanging({ key: 'address', value: e.target.value })}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
label='Qulay filial tanlash'
|
||||
variant='outlined'
|
||||
fullWidth
|
||||
select
|
||||
value={formData.filial}
|
||||
error={dataErrors.filial}
|
||||
onChange={e => formDataChanging({ key: 'filial', value: e.target.value })}
|
||||
>
|
||||
{branchOptions?.map((option: {value: string; label: string}) => (
|
||||
<MenuItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
1
src/components/layout/landing-layout/header/index.ts
Normal file
1
src/components/layout/landing-layout/header/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './Header';
|
||||
1
src/components/layout/landing-layout/index.ts
Normal file
1
src/components/layout/landing-layout/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './Layout';
|
||||
Reference in New Issue
Block a user