initial commit

This commit is contained in:
2026-05-13 17:48:36 +05:30
commit 5a80256856
305 changed files with 80994 additions and 0 deletions

View File

@@ -0,0 +1,275 @@
import PropTypes from 'prop-types';
import { useState } from 'react';
import { Link } from 'react-router-dom';
// material-ui
import { useTheme } from '@mui/material/styles';
import {
Box,
Chip,
Drawer,
Grid,
InputAdornment,
List,
ListItemButton,
ListItemIcon,
ListItemText,
Menu,
MenuItem,
OutlinedInput,
Stack,
Typography,
useMediaQuery
} from '@mui/material';
// project imports
import UserAvatar from './UserAvatar';
// import UserList from './UserList';
import MainCard from 'components/MainCard';
import IconButton from 'components/@extended/IconButton';
import SimpleBar from 'components/third-party/SimpleBar';
import { ThemeMode } from 'config';
import useAuth from 'hooks/useAuth';
// assets
import {
CheckCircleFilled,
ClockCircleFilled,
LogoutOutlined,
MinusCircleFilled,
RightOutlined,
SearchOutlined,
SettingOutlined
} from '@ant-design/icons';
// ==============================|| CHAT DRAWER ||============================== //
function ChatDrawer({ handleDrawerOpen, openChatDrawer, setUser }) {
const theme = useTheme();
const { user } = useAuth();
const matchDownLG = useMediaQuery(theme.breakpoints.down('lg'));
const drawerBG = theme.palette.mode === ThemeMode.DARK ? 'dark.main' : 'white';
// show menu to set current user status
const [anchorEl, setAnchorEl] = useState();
const handleClickRightMenu = (event) => {
setAnchorEl(event?.currentTarget);
};
const handleCloseRightMenu = () => {
setAnchorEl(null);
};
// set user status on status menu click
const [status, setStatus] = useState('available');
const handleRightMenuItemClick = (userStatus) => () => {
setStatus(userStatus);
handleCloseRightMenu();
};
const [search, setSearch] = useState('');
const handleSearch = async (event) => {
const newString = event?.target.value;
setSearch(newString);
};
return (
<Drawer
sx={{
width: 320,
flexShrink: 0,
zIndex: { xs: 1100, lg: 0 },
'& .MuiDrawer-paper': {
height: matchDownLG ? '100%' : 'auto',
width: 320,
boxSizing: 'border-box',
position: 'relative',
border: 'none'
}
}}
variant={matchDownLG ? 'temporary' : 'persistent'}
anchor="left"
open={openChatDrawer}
ModalProps={{ keepMounted: true }}
onClose={handleDrawerOpen}
>
<MainCard
sx={{
bgcolor: matchDownLG ? 'transparent' : drawerBG,
borderRadius: '4px 0 0 4px',
borderRight: 'none'
}}
border={!matchDownLG}
content={false}
>
<Box sx={{ p: 3, pb: 1 }}>
<Stack spacing={2}>
<Stack direction="row" spacing={0.5} alignItems="center">
<Typography variant="h5" color="inherit">
Messages
</Typography>
<Chip
label="9"
component="span"
color="secondary"
sx={{
width: 20,
height: 20,
borderRadius: '50%',
'& .MuiChip-label': {
px: 0.5
}
}}
/>
</Stack>
<OutlinedInput
fullWidth
id="input-search-header"
placeholder="Search"
value={search}
onChange={handleSearch}
sx={{
'& .MuiOutlinedInput-input': {
p: '10.5px 0px 12px'
}
}}
startAdornment={
<InputAdornment position="start">
<SearchOutlined style={{ fontSize: 'small' }} />
</InputAdornment>
}
/>
</Stack>
</Box>
<SimpleBar
sx={{
overflowX: 'hidden',
height: matchDownLG ? 'calc(100vh - 120px)' : 'calc(100vh - 428px)',
minHeight: matchDownLG ? 0 : 420
}}
>
<Box sx={{ p: 3, pt: 0 }}>
{/* <UserList setUser={setUser} search={search} /> */}
</Box>
</SimpleBar>
<Box sx={{ p: 3, pb: 0 }}>
<List component="nav">
<ListItemButton divider>
<ListItemIcon>
<LogoutOutlined />
</ListItemIcon>
<ListItemText primary="LogOut" />
</ListItemButton>
<ListItemButton divider>
<ListItemIcon>
<SettingOutlined />
</ListItemIcon>
<ListItemText primary="Settings" />
</ListItemButton>
</List>
</Box>
<Box sx={{ p: 3, pt: 1, pl: 5 }}>
<Grid container>
<Grid item xs={12}>
<Grid container spacing={1} alignItems="center" sx={{ flexWrap: 'nowrap' }}>
<Grid item>
<UserAvatar user={{ online_status: status, avatar: 'avatar-1.png', name: 'User 1' }} />
</Grid>
<Grid item xs zeroMinWidth>
<Stack sx={{ cursor: 'pointer', textDecoration: 'none' }} component={Link} to="/apps/profiles/user/personal">
<Typography align="left" variant="h5" color="textPrimary">
{user?.name}
</Typography>
<Typography align="left" variant="caption" color="textSecondary">
{user?.role}
</Typography>
</Stack>
</Grid>
<Grid item>
<IconButton onClick={handleClickRightMenu} size="small" color="secondary">
<RightOutlined />
</IconButton>
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleCloseRightMenu}
anchorOrigin={{
vertical: 'top',
horizontal: 'right'
}}
transformOrigin={{
vertical: 'bottom',
horizontal: 'right'
}}
sx={{
'& .MuiMenu-list': {
p: 0
},
'& .MuiMenuItem-root': {
pl: '6px',
py: '3px'
}
}}
>
<MenuItem onClick={handleRightMenuItemClick('available')}>
<IconButton
size="small"
sx={{
color: theme.palette.success.main,
'&:hover': { color: theme.palette.success.main, bgcolor: 'transparent', transition: 'none', padding: 0 }
}}
>
<CheckCircleFilled />
</IconButton>
<Typography>Active</Typography>
</MenuItem>
<MenuItem onClick={handleRightMenuItemClick('offline')}>
<IconButton
size="small"
sx={{
color: theme.palette.warning.main,
'&:hover': { color: theme.palette.warning.main, bgcolor: 'transparent', transition: 'none', padding: 0 }
}}
>
<ClockCircleFilled />
</IconButton>
<Typography>Away</Typography>
</MenuItem>
<MenuItem onClick={handleRightMenuItemClick('do_not_disturb')}>
<IconButton
size="small"
sx={{
color: theme.palette.grey[400],
'&:hover': { color: theme.palette.grey[400], bgcolor: 'transparent', transition: 'none', padding: 0 }
}}
>
<MinusCircleFilled />
</IconButton>
<Typography>Do not disturb</Typography>
</MenuItem>
</Menu>
</Grid>
</Grid>
</Grid>
</Grid>
</Box>
</MainCard>
</Drawer>
);
}
ChatDrawer.propTypes = {
handleDrawerOpen: PropTypes.func,
openChatDrawer: PropTypes.bool,
setUser: PropTypes.func
};
export default ChatDrawer;

View File

@@ -0,0 +1,119 @@
import PropTypes from 'prop-types';
import { useCallback, useEffect, useRef } from 'react';
// material-ui
import { Card, CardContent, Grid, Stack, Typography } from '@mui/material';
// project imports
import UserAvatar from './UserAvatar';
// import ChatMessageAction from './ChatMessageAction';
import IconButton from 'components/@extended/IconButton';
import { ThemeMode } from 'config';
// assets
import { EditOutlined } from '@ant-design/icons';
// ==============================|| CHAT MESSAGE HISTORY ||============================== //
const ChatHistory = ({ data, theme, user }) => {
// scroll to bottom when new message is sent or received
const wrapper = useRef(document.createElement('div'));
const el = wrapper.current;
const scrollToBottom = useCallback(() => {
el.scrollIntoView(false);
}, [el]);
useEffect(() => {
scrollToBottom();
}, [data.length, scrollToBottom]);
return (
<Grid container spacing={2.5} ref={wrapper}>
{data.map((history, index) => (
<Grid item xs={12} key={index}>
{history.from !== user.name ? (
<Stack spacing={1.25} direction="row">
<Grid container spacing={1} justifyContent="flex-end">
<Grid item xs={2} md={3} xl={4} />
<Grid item xs={10} md={9} xl={8}>
<Stack direction="row" justifyContent="flex-end" alignItems="flex-start">
{/* <ChatMessageAction index={index} /> */}
<IconButton size="small" color="secondary">
<EditOutlined />
</IconButton>
<Card
sx={{
display: 'inline-block',
float: 'right',
bgcolor: theme.palette.primary.main,
boxShadow: 'none',
ml: 1
}}
>
<CardContent sx={{ p: 1, pb: '8px !important', width: 'fit-content', ml: 'auto' }}>
<Grid container spacing={1}>
<Grid item xs={12}>
<Typography variant="h6" color={theme.palette.grey[0]} sx={{ overflowWrap: 'anywhere' }}>
{history.text}
</Typography>
</Grid>
</Grid>
</CardContent>
</Card>
</Stack>
</Grid>
<Grid item xs={12}>
<Typography align="right" variant="subtitle2" color="textSecondary">
{history.time}
</Typography>
</Grid>
</Grid>
<UserAvatar user={{ online_status: 'available', avatar: 'avatar-1.png', name: 'User 1' }} />
</Stack>
) : (
<Stack direction="row" spacing={1.25} alignItems="flext-start">
<UserAvatar user={{ online_status: user.online_status, avatar: user.avatar, name: user.name }} />
<Grid container>
<Grid item xs={12} sm={7}>
<Card
sx={{
display: 'inline-block',
float: 'left',
bgcolor: theme.palette.mode === ThemeMode.DARK ? 'background.background' : 'grey.0',
boxShadow: 'none'
}}
>
<CardContent sx={{ p: 1, pb: '8px !important' }}>
<Grid container spacing={1}>
<Grid item xs={12}>
<Typography variant="h6" color="textPrimary" sx={{ overflowWrap: 'anywhere' }}>
{history.text}
</Typography>
</Grid>
</Grid>
</CardContent>
</Card>
</Grid>
<Grid item xs={12} sx={{ mt: 1 }}>
<Typography align="left" variant="subtitle2" color="textSecondary">
{history.time}
</Typography>
</Grid>
</Grid>
</Stack>
)}
</Grid>
))}
</Grid>
);
};
ChatHistory.propTypes = {
data: PropTypes.array,
theme: PropTypes.object,
user: PropTypes.object
};
export default ChatHistory;

View File

@@ -0,0 +1,33 @@
import PropTypes from 'prop-types';
// material-ui
import { Badge } from '@mui/material';
// project imports
// import AvatarStatus from './AvatarStatus';
import Avatar from 'components/@extended/Avatar';
// assets
const avatarImage = require.context('assets/images/users', true);
// ==============================|| CHAT USER AVATAR WITH STATUS ICON ||============================== //
const UserAvatar = ({ user }) => (
<Badge
overlap="circular"
// badgeContent={<AvatarStatus status={user.online_status} />}
anchorOrigin={{
vertical: 'top',
horizontal: 'right'
}}
sx={{ '& .MuiBox-root': { width: 6, height: 6 }, padding: 0, minWidth: 12, '& svg': { background: '#fff', borderRadius: '50%' } }}
>
<Avatar alt={user.name} src={user.avatar && avatarImage(`./${user.avatar}`)} />
</Badge>
);
UserAvatar.propTypes = {
user: PropTypes.object
};
export default UserAvatar;

View File

@@ -0,0 +1,303 @@
import PropTypes from 'prop-types';
import { useState } from 'react';
// material-ui
import { useTheme } from '@mui/material/styles';
import { useMediaQuery, Box, Chip, Collapse, Divider, Grid, Stack, Switch, Typography } from '@mui/material';
// project imports
// import AvatarStatus from './AvatarStatus';
import MainCard from 'components/MainCard';
import Avatar from 'components/@extended/Avatar';
import IconButton from 'components/@extended/IconButton';
import SimpleBar from 'components/third-party/SimpleBar';
import { ThemeMode } from 'config';
// assets
import {
CloseOutlined,
DownOutlined,
FileDoneOutlined,
FileSyncOutlined,
FolderOpenOutlined,
LinkOutlined,
MessageOutlined,
MoreOutlined,
PhoneOutlined,
PictureOutlined,
RightOutlined,
VideoCameraOutlined
} from '@ant-design/icons';
const avatarImage = require.context('assets/images/users', true);
// ==============================|| USER PROFILE / DETAILS ||============================== //
const UserDetails = ({ user, onClose }) => {
const theme = useTheme();
const matchDownLG = useMediaQuery(theme.breakpoints.down('md'));
const [checked, setChecked] = useState(true);
if (Object.keys(user).length === 0) return <Typography>...Loading</Typography>;
let statusBGColor;
let statusColor;
if (user.online_status === 'available') {
statusBGColor = theme.palette.success.lighter;
statusColor = theme.palette.success.main;
} else if (user.online_status === 'do_not_disturb') {
statusBGColor = theme.palette.grey.A100;
statusColor = theme.palette.grey.A200;
} else {
statusBGColor = theme.palette.warning.lighter;
statusColor = theme.palette.warning.main;
}
return (
<MainCard
sx={{
bgcolor: theme.palette.mode === ThemeMode.DARK ? 'dark.main' : 'grey.0',
borderRadius: '0 4px 4px 0',
borderLeft: 'none'
}}
content={false}
>
<Box sx={{ p: 3 }}>
{onClose && (
<IconButton size="small" sx={{ position: 'absolute', right: 8, top: 8 }} onClick={onClose} color="error">
<CloseOutlined />
</IconButton>
)}
<Grid container spacing={1} justifyContent="center">
<Grid item xs={12}>
<Stack>
<Avatar
alt={user.name}
src={user.avatar && avatarImage(`./${user.avatar}`)}
size="xl"
sx={{
m: '8px auto',
width: 88,
height: 88,
border: '1px solid',
borderColor: theme.palette.primary.main,
p: 1,
bgcolor: 'transparent',
'& .MuiAvatar-img ': {
height: '88px',
width: '88px',
borderRadius: '50%'
}
}}
/>
<Typography variant="h5" align="center" component="div">
{user.name}
</Typography>
<Typography variant="body2" align="center" color="textSecondary">
{user.role}
</Typography>
</Stack>
</Grid>
<Grid item xs={12}>
<Stack
direction="row"
alignItems="center"
spacing={1}
justifyContent="center"
sx={{ mt: 0.75, '& .MuiChip-root': { height: '24px' } }}
>
{/* <AvatarStatus status={user?.online_status} /> */}
<Chip
label={user?.online_status.replaceAll('_', ' ')}
sx={{
bgcolor: statusBGColor,
textTransform: 'capitalize',
color: statusColor,
'& .MuiChip-label': { px: 1 }
}}
/>
</Stack>
</Grid>
</Grid>
<Stack direction="row" spacing={2} justifyContent="center" sx={{ mt: 3 }}>
<IconButton size="medium" color="secondary" sx={{ boxShadow: '0px 8px 25px rgba(0, 0, 0, 0.05)' }}>
<PhoneOutlined />
</IconButton>
<IconButton size="medium" color="secondary" sx={{ boxShadow: '0px 8px 25px rgba(0, 0, 0, 0.05)' }}>
<MessageOutlined />
</IconButton>
<IconButton size="medium" color="secondary" sx={{ boxShadow: '0px 8px 25px rgba(0, 0, 0, 0.05)' }}>
<VideoCameraOutlined />
</IconButton>
</Stack>
</Box>
<Box>
<SimpleBar
sx={{
overflowX: 'hidden',
height: matchDownLG ? 'auto' : 'calc(100vh - 397px)',
minHeight: matchDownLG ? 0 : 420
}}
>
<Stack spacing={3}>
<Stack direction="row" spacing={1.5} justifyContent="center" sx={{ px: 3 }}>
<Box sx={{ bgcolor: 'primary.lighter', p: 2, width: '50%', borderRadius: 2 }}>
<Typography color="primary">All File</Typography>
<Stack direction="row" alignItems="center" spacing={1} sx={{ mt: 0.5 }}>
<FolderOpenOutlined style={{ color: theme.palette.primary.main, fontSize: '1.15em' }} />
<Typography variant="h4">231</Typography>
</Stack>
</Box>
<Box sx={{ bgcolor: 'secondary.lighter', p: 2, width: '50%', borderRadius: 2 }}>
<Typography>All Link</Typography>
<Stack direction="row" alignItems="center" spacing={1} sx={{ mt: 0.5 }}>
<LinkOutlined style={{ fontSize: '1.15em' }} />
<Typography variant="h4">231</Typography>
</Stack>
</Box>
</Stack>
<Box sx={{ px: 3, pb: 3 }}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Stack
direction="row"
alignItems="center"
justifyContent="space-between"
sx={{ cursor: 'pointer' }}
onClick={() => setChecked(!checked)}
>
<Typography variant="h5" component="div">
Information
</Typography>
<IconButton size="small" color="secondary">
<DownOutlined />
</IconButton>
</Stack>
</Grid>
<Grid item xs={12} sx={{ mt: -1 }}>
<Divider />
</Grid>
<Grid item xs={12}>
<Collapse in={checked}>
<Stack direction="row" justifyContent="space-between" sx={{ mt: 1, mb: 2 }}>
<Typography>Address</Typography>
<Typography color="textSecondary">{user.location}</Typography>
</Stack>
<Stack direction="row" justifyContent="space-between" sx={{ mt: 2 }}>
<Typography>Email</Typography>
<Typography color="textSecondary">{user.personal_email}</Typography>
</Stack>
<Stack direction="row" justifyContent="space-between" sx={{ mt: 2 }}>
<Typography>Phone</Typography>
<Typography color="textSecondary">{user.personal_phone}</Typography>
</Stack>
<Stack direction="row" justifyContent="space-between" sx={{ mt: 2, mb: 2 }}>
<Typography>Last visited</Typography>
<Typography color="textSecondary">{user.lastMessage}</Typography>
</Stack>
</Collapse>
</Grid>
<Grid item xs={12}>
<Stack direction="row" alignItems="center" justifyContent="space-between">
<Typography variant="h5">Notification</Typography>
<Switch defaultChecked />
</Stack>
</Grid>
<Grid item xs={12} sx={{ mt: -1 }}>
<Divider />
</Grid>
<Grid item xs={12} sx={{ mt: -1 }}>
<Stack direction="row" alignItems="center" justifyContent="space-between">
<Typography variant="h5">File type</Typography>
<IconButton size="medium" color="secondary">
<MoreOutlined />
</IconButton>
</Stack>
</Grid>
<Grid item xs={12} sx={{ mt: -1 }}>
<Divider />
</Grid>
<Grid item xs={12}>
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Stack direction="row" alignItems="center" spacing={1.5}>
<Avatar
sx={{
color: theme.palette.success.dark,
bgcolor: theme.palette.success.light,
borderRadius: 1
}}
>
<FileDoneOutlined />
</Avatar>
<Stack>
<Typography>Document</Typography>
<Typography color="textSecondary">123 files, 193MB</Typography>
</Stack>
</Stack>
<IconButton size="small" color="secondary">
<RightOutlined />
</IconButton>
</Stack>
</Grid>
<Grid item xs={12}>
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Stack direction="row" alignItems="center" spacing={1.5}>
<Avatar
sx={{
color: theme.palette.warning.main,
bgcolor: theme.palette.warning.lighter,
borderRadius: 1
}}
>
<PictureOutlined />
</Avatar>
<Stack>
<Typography>Photos</Typography>
<Typography color="textSecondary">53 files, 321MB</Typography>
</Stack>
</Stack>
<IconButton size="small" color="secondary">
<RightOutlined />
</IconButton>
</Stack>
</Grid>
<Grid item xs={12}>
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Stack direction="row" alignItems="center" spacing={1.5}>
<Avatar
sx={{
color: theme.palette.primary.main,
bgcolor: theme.palette.primary.lighter,
borderRadius: 1
}}
>
<FileSyncOutlined />
</Avatar>
<Stack>
<Typography>Other</Typography>
<Typography color="textSecondary">49 files, 193MB</Typography>
</Stack>
</Stack>
<IconButton size="small" color="secondary">
<RightOutlined />
</IconButton>
</Stack>
</Grid>
</Grid>
</Box>
</Stack>
</SimpleBar>
</Box>
</MainCard>
);
};
UserDetails.propTypes = {
user: PropTypes.object,
onClose: PropTypes.func
};
export default UserDetails;

View File

@@ -0,0 +1,39 @@
import PropTypes from 'prop-types';
// material-ui
import { useTheme } from '@mui/material/styles';
import { Box } from '@mui/material';
// project import
import MainCard from 'components/MainCard';
// ==============================|| AUTHENTICATION - CARD WRAPPER ||============================== //
const AuthCard = ({ children, ...other }) => {
const theme = useTheme();
return (
<MainCard
sx={{
maxWidth: { xs: 400, lg: 475 },
margin: { xs: 2.5, md: 3 },
'& > *': {
flexGrow: 1,
flexBasis: '50%'
}
}}
content={false}
{...other}
border={false}
boxShadow
shadow={theme.customShadows.z1}
>
<Box sx={{ p: { xs: 2, sm: 3, md: 4, xl: 5 } }}>{children}</Box>
</MainCard>
);
};
AuthCard.propTypes = {
children: PropTypes.node
};
export default AuthCard;

View File

@@ -0,0 +1,55 @@
import PropTypes from 'prop-types';
// material-ui
import { Box, Grid } from '@mui/material';
// project import
import AuthFooter from 'components/cards/AuthFooter';
import Logo from 'components/logo';
import AuthCard from './AuthCard';
// assets
import AuthBackground from 'assets/images/auth/AuthBackground';
// ==============================|| AUTHENTICATION - WRAPPER ||============================== //
const AuthWrapper = ({ children }) => (
<Box sx={{ minHeight: '100vh' }}>
<AuthBackground />
<Grid
container
direction="column"
justifyContent="flex-end"
sx={{
minHeight: '100vh'
}}
>
<Grid item xs={12} sx={{ ml: 3, mt: 3 }}>
<Logo />
</Grid>
<Grid item xs={12}>
<Grid
item
xs={12}
container
justifyContent="center"
alignItems="center"
sx={{ minHeight: { xs: 'calc(100vh - 210px)', sm: 'calc(100vh - 134px)', md: 'calc(100vh - 112px)' } }}
>
<Grid item>
<AuthCard>{children}</AuthCard>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} sx={{ m: 3, mt: 1 }}>
<AuthFooter />
</Grid>
</Grid>
</Box>
);
AuthWrapper.propTypes = {
children: PropTypes.node
};
export default AuthWrapper;

View File

@@ -0,0 +1,66 @@
import { useState } from 'react';
// material-ui
import { useTheme } from '@mui/material/styles';
import { Button, Grid, Stack, Typography } from '@mui/material';
// third-party
import OtpInput from 'react18-input-otp';
// project import
import AnimateButton from 'components/@extended/AnimateButton';
import { ThemeMode } from 'config';
// ============================|| STATIC - CODE VERIFICATION ||============================ //
const AuthCodeVerification = () => {
const theme = useTheme();
const [otp, setOtp] = useState();
const borderColor = theme.palette.mode === ThemeMode.DARK ? theme.palette.grey[200] : theme.palette.grey[300];
return (
<Grid container spacing={3}>
<Grid item xs={12}>
<OtpInput
value={otp}
onChange={(otp) => setOtp(otp)}
numInputs={4}
containerStyle={{ justifyContent: 'space-between' }}
inputStyle={{
width: '100%',
margin: '8px',
padding: '10px',
border: `1px solid ${borderColor}`,
borderRadius: 4,
':hover': {
borderColor: theme.palette.primary.main
}
}}
focusStyle={{
outline: 'none',
boxShadow: theme.customShadows.primary,
border: `1px solid ${theme.palette.primary.main}`
}}
/>
</Grid>
<Grid item xs={12}>
<AnimateButton>
<Button disableElevation fullWidth size="large" type="submit" variant="contained">
Continue
</Button>
</AnimateButton>
</Grid>
<Grid item xs={12}>
<Stack direction="row" justifyContent="space-between" alignItems="baseline">
<Typography>Did not receive the email? Check your spam filter, or</Typography>
<Typography variant="body1" sx={{ minWidth: 85, ml: 2, textDecoration: 'none', cursor: 'pointer' }} color="primary">
Resend code
</Typography>
</Stack>
</Grid>
</Grid>
);
};
export default AuthCodeVerification;

View File

@@ -0,0 +1,126 @@
import { useNavigate } from 'react-router-dom';
// material-ui
import { Button, FormHelperText, Grid, InputLabel, OutlinedInput, Stack, Typography } from '@mui/material';
// third party
import * as Yup from 'yup';
import { Formik } from 'formik';
// project import
import AnimateButton from 'components/@extended/AnimateButton';
import useAuth from 'hooks/useAuth';
import useScriptRef from 'hooks/useScriptRef';
import { dispatch } from 'store';
import { openSnackbar } from 'store/reducers/snackbar';
// ============================|| FIREBASE - FORGOT PASSWORD ||============================ //
const AuthForgotPassword = () => {
const scriptedRef = useScriptRef();
const navigate = useNavigate();
const { isLoggedIn, resetPassword } = useAuth();
return (
<>
<Formik
initialValues={{
email: '',
submit: null
}}
validationSchema={Yup.object().shape({
email: Yup.string().email('Must be a valid email').max(255).required('Email is required')
})}
onSubmit={async (values, { setErrors, setStatus, setSubmitting }) => {
try {
await resetPassword(values.email).then(
() => {
setStatus({ success: true });
setSubmitting(false);
dispatch(
openSnackbar({
open: true,
message: 'Check mail for reset password link',
variant: 'alert',
alert: {
color: 'success'
},
close: false
})
);
setTimeout(() => {
navigate(isLoggedIn ? '/auth/check-mail' : '/check-mail', { replace: true });
}, 1500);
// WARNING: do not set any formik state here as formik might be already destroyed here. You may get following error by doing so.
// Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application.
// To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
// github issue: https://github.com/formium/formik/issues/2430
},
(err) => {
setStatus({ success: false });
setErrors({ submit: err.message });
setSubmitting(false);
}
);
} catch (err) {
console.error(err);
if (scriptedRef.current) {
setStatus({ success: false });
setErrors({ submit: err.message });
setSubmitting(false);
}
}
}}
>
{({ errors, handleBlur, handleChange, handleSubmit, isSubmitting, touched, values }) => (
<form noValidate onSubmit={handleSubmit}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Stack spacing={1}>
<InputLabel htmlFor="email-forgot">Email Address</InputLabel>
<OutlinedInput
fullWidth
error={Boolean(touched.email && errors.email)}
id="email-forgot"
type="email"
value={values.email}
name="email"
onBlur={handleBlur}
onChange={handleChange}
placeholder="Enter email address"
inputProps={{}}
/>
{touched.email && errors.email && (
<FormHelperText error id="helper-text-email-forgot">
{errors.email}
</FormHelperText>
)}
</Stack>
</Grid>
{errors.submit && (
<Grid item xs={12}>
<FormHelperText error>{errors.submit}</FormHelperText>
</Grid>
)}
<Grid item xs={12} sx={{ mb: -2 }}>
<Typography variant="caption">Do not forgot to check SPAM box.</Typography>
</Grid>
<Grid item xs={12}>
<AnimateButton>
<Button disableElevation disabled={isSubmitting} fullWidth size="large" type="submit" variant="contained" color="primary">
Send Password Reset Email
</Button>
</AnimateButton>
</Grid>
</Grid>
</form>
)}
</Formik>
</>
);
};
export default AuthForgotPassword;

View File

@@ -0,0 +1,176 @@
import React from 'react';
import { Link as RouterLink } from 'react-router-dom';
// material-ui
import {
Button,
Checkbox,
FormControlLabel,
FormHelperText,
Grid,
Link,
InputAdornment,
InputLabel,
OutlinedInput,
Stack,
Typography
} from '@mui/material';
// third party
import * as Yup from 'yup';
import { Formik } from 'formik';
// project import
import useAuth from 'hooks/useAuth';
import useScriptRef from 'hooks/useScriptRef';
import IconButton from 'components/@extended/IconButton';
import AnimateButton from 'components/@extended/AnimateButton';
// assets
import { EyeOutlined, EyeInvisibleOutlined } from '@ant-design/icons';
// ============================|| JWT - LOGIN ||============================ //
const AuthLogin = () => {
const [checked, setChecked] = React.useState(false);
const { login } = useAuth();
const scriptedRef = useScriptRef();
const [showPassword, setShowPassword] = React.useState(false);
const handleClickShowPassword = () => {
setShowPassword(!showPassword);
};
const handleMouseDownPassword = (event) => {
event.preventDefault();
};
return (
<>
<Formik
initialValues={{
email: 'info@codedthemes.com',
password: '123456',
submit: null
}}
validationSchema={Yup.object().shape({
email: Yup.string().email('Must be a valid email').max(255).required('Email is required'),
password: Yup.string().max(255).required('Password is required')
})}
onSubmit={async (values, { setErrors, setStatus, setSubmitting }) => {
try {
await login(values.email, values.password);
if (scriptedRef.current) {
setStatus({ success: true });
setSubmitting(false);
}
} catch (err) {
console.error(err);
if (scriptedRef.current) {
setStatus({ success: false });
setErrors({ submit: err.message });
setSubmitting(false);
}
}
}}
>
{({ errors, handleBlur, handleChange, handleSubmit, isSubmitting, touched, values }) => (
<form noValidate onSubmit={handleSubmit}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Stack spacing={1}>
<InputLabel htmlFor="email-login">Email Address</InputLabel>
<OutlinedInput
id="email-login"
type="email"
value={values.email}
name="email"
onBlur={handleBlur}
onChange={handleChange}
placeholder="Enter email address"
fullWidth
error={Boolean(touched.email && errors.email)}
/>
{touched.email && errors.email && (
<FormHelperText error id="standard-weight-helper-text-email-login">
{errors.email}
</FormHelperText>
)}
</Stack>
</Grid>
<Grid item xs={12}>
<Stack spacing={1}>
<InputLabel htmlFor="password-login">Password</InputLabel>
<OutlinedInput
fullWidth
error={Boolean(touched.password && errors.password)}
id="-password-login"
type={showPassword ? 'text' : 'password'}
value={values.password}
name="password"
onBlur={handleBlur}
onChange={handleChange}
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
edge="end"
color="secondary"
>
{showPassword ? <EyeOutlined /> : <EyeInvisibleOutlined />}
</IconButton>
</InputAdornment>
}
placeholder="Enter password"
/>
{touched.password && errors.password && (
<FormHelperText error id="standard-weight-helper-text-password-login">
{errors.password}
</FormHelperText>
)}
</Stack>
</Grid>
<Grid item xs={12} sx={{ mt: -1 }}>
<Stack direction="row" justifyContent="space-between" alignItems="center" spacing={2}>
<FormControlLabel
control={
<Checkbox
checked={checked}
onChange={(event) => setChecked(event.target.checked)}
name="checked"
color="primary"
size="small"
/>
}
label={<Typography variant="h6">Keep me sign in</Typography>}
/>
<Link variant="h6" component={RouterLink} to="/forgot-password" color="text.primary">
Forgot Password?
</Link>
</Stack>
</Grid>
{errors.submit && (
<Grid item xs={12}>
<FormHelperText error>{errors.submit}</FormHelperText>
</Grid>
)}
<Grid item xs={12}>
<AnimateButton>
<Button disableElevation disabled={isSubmitting} fullWidth size="large" type="submit" variant="contained" color="primary">
Login
</Button>
</AnimateButton>
</Grid>
</Grid>
</form>
)}
</Formik>
</>
);
};
export default AuthLogin;

View File

@@ -0,0 +1,282 @@
import { useEffect, useState } from 'react';
import { Link as RouterLink, useNavigate } from 'react-router-dom';
// material-ui
import {
Box,
Button,
FormControl,
FormHelperText,
Grid,
Link,
InputAdornment,
InputLabel,
OutlinedInput,
Stack,
Typography
} from '@mui/material';
// third party
import * as Yup from 'yup';
import { Formik } from 'formik';
// project import
import IconButton from 'components/@extended/IconButton';
import AnimateButton from 'components/@extended/AnimateButton';
import useAuth from 'hooks/useAuth';
import useScriptRef from 'hooks/useScriptRef';
import { dispatch } from 'store';
import { openSnackbar } from 'store/reducers/snackbar';
import { strengthColor, strengthIndicator } from 'utils/password-strength';
// assets
import { EyeOutlined, EyeInvisibleOutlined } from '@ant-design/icons';
// ============================|| JWT - REGISTER ||============================ //
const AuthRegister = () => {
const { register } = useAuth();
const scriptedRef = useScriptRef();
const navigate = useNavigate();
const [level, setLevel] = useState();
const [showPassword, setShowPassword] = useState(false);
const handleClickShowPassword = () => {
setShowPassword(!showPassword);
};
const handleMouseDownPassword = (event) => {
event.preventDefault();
};
const changePassword = (value) => {
const temp = strengthIndicator(value);
setLevel(strengthColor(temp));
};
useEffect(() => {
changePassword('');
}, []);
return (
<>
<Formik
initialValues={{
firstname: '',
lastname: '',
email: '',
company: '',
password: '',
submit: null
}}
validationSchema={Yup.object().shape({
firstname: Yup.string().max(255).required('First Name is required'),
lastname: Yup.string().max(255).required('Last Name is required'),
email: Yup.string().email('Must be a valid email').max(255).required('Email is required'),
password: Yup.string().max(255).required('Password is required')
})}
onSubmit={async (values, { setErrors, setStatus, setSubmitting }) => {
try {
await register(values.email, values.password, values.firstname, values.lastname);
if (scriptedRef.current) {
setStatus({ success: true });
setSubmitting(false);
dispatch(
openSnackbar({
open: true,
message: 'Your registration has been successfully completed.',
variant: 'alert',
alert: {
color: 'success'
},
close: false
})
);
setTimeout(() => {
navigate('/login', { replace: true });
}, 1500);
}
} catch (err) {
console.error(err);
if (scriptedRef.current) {
setStatus({ success: false });
setErrors({ submit: err.message });
setSubmitting(false);
}
}
}}
>
{({ errors, handleBlur, handleChange, handleSubmit, isSubmitting, touched, values }) => (
<form noValidate onSubmit={handleSubmit}>
<Grid container spacing={3}>
<Grid item xs={12} md={6}>
<Stack spacing={1}>
<InputLabel htmlFor="firstname-signup">First Name*</InputLabel>
<OutlinedInput
id="firstname-login"
type="firstname"
value={values.firstname}
name="firstname"
onBlur={handleBlur}
onChange={handleChange}
placeholder="John"
fullWidth
error={Boolean(touched.firstname && errors.firstname)}
/>
{touched.firstname && errors.firstname && (
<FormHelperText error id="helper-text-firstname-signup">
{errors.firstname}
</FormHelperText>
)}
</Stack>
</Grid>
<Grid item xs={12} md={6}>
<Stack spacing={1}>
<InputLabel htmlFor="lastname-signup">Last Name*</InputLabel>
<OutlinedInput
fullWidth
error={Boolean(touched.lastname && errors.lastname)}
id="lastname-signup"
type="lastname"
value={values.lastname}
name="lastname"
onBlur={handleBlur}
onChange={handleChange}
placeholder="Doe"
inputProps={{}}
/>
{touched.lastname && errors.lastname && (
<FormHelperText error id="helper-text-lastname-signup">
{errors.lastname}
</FormHelperText>
)}
</Stack>
</Grid>
<Grid item xs={12}>
<Stack spacing={1}>
<InputLabel htmlFor="company-signup">Company</InputLabel>
<OutlinedInput
fullWidth
error={Boolean(touched.company && errors.company)}
id="company-signup"
value={values.company}
name="company"
onBlur={handleBlur}
onChange={handleChange}
placeholder="Demo Inc."
inputProps={{}}
/>
{touched.company && errors.company && (
<FormHelperText error id="helper-text-company-signup">
{errors.company}
</FormHelperText>
)}
</Stack>
</Grid>
<Grid item xs={12}>
<Stack spacing={1}>
<InputLabel htmlFor="email-signup">Email Address*</InputLabel>
<OutlinedInput
fullWidth
error={Boolean(touched.email && errors.email)}
id="email-login"
type="email"
value={values.email}
name="email"
onBlur={handleBlur}
onChange={handleChange}
placeholder="demo@company.com"
inputProps={{}}
/>
{touched.email && errors.email && (
<FormHelperText error id="helper-text-email-signup">
{errors.email}
</FormHelperText>
)}
</Stack>
</Grid>
<Grid item xs={12}>
<Stack spacing={1}>
<InputLabel htmlFor="password-signup">Password</InputLabel>
<OutlinedInput
fullWidth
error={Boolean(touched.password && errors.password)}
id="password-signup"
type={showPassword ? 'text' : 'password'}
value={values.password}
name="password"
onBlur={handleBlur}
onChange={(e) => {
handleChange(e);
changePassword(e.target.value);
}}
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
edge="end"
color="secondary"
>
{showPassword ? <EyeOutlined /> : <EyeInvisibleOutlined />}
</IconButton>
</InputAdornment>
}
placeholder="******"
inputProps={{}}
/>
{touched.password && errors.password && (
<FormHelperText error id="helper-text-password-signup">
{errors.password}
</FormHelperText>
)}
</Stack>
<FormControl fullWidth sx={{ mt: 2 }}>
<Grid container spacing={2} alignItems="center">
<Grid item>
<Box sx={{ bgcolor: level?.color, width: 85, height: 8, borderRadius: '7px' }} />
</Grid>
<Grid item>
<Typography variant="subtitle1" fontSize="0.75rem">
{level?.label}
</Typography>
</Grid>
</Grid>
</FormControl>
</Grid>
<Grid item xs={12}>
<Typography variant="body2">
By Signing up, you agree to our &nbsp;
<Link variant="subtitle2" component={RouterLink} to="#">
Terms of Service
</Link>
&nbsp; and &nbsp;
<Link variant="subtitle2" component={RouterLink} to="#">
Privacy Policy
</Link>
</Typography>
</Grid>
{errors.submit && (
<Grid item xs={12}>
<FormHelperText error>{errors.submit}</FormHelperText>
</Grid>
)}
<Grid item xs={12}>
<AnimateButton>
<Button disableElevation disabled={isSubmitting} fullWidth size="large" type="submit" variant="contained" color="primary">
Create Account
</Button>
</AnimateButton>
</Grid>
</Grid>
</form>
)}
</Formik>
</>
);
};
export default AuthRegister;

View File

@@ -0,0 +1,201 @@
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
// material-ui
import {
Box,
Button,
FormControl,
FormHelperText,
Grid,
InputAdornment,
InputLabel,
OutlinedInput,
Stack,
Typography
} from '@mui/material';
// third party
import * as Yup from 'yup';
import { Formik } from 'formik';
// project import
import IconButton from 'components/@extended/IconButton';
import AnimateButton from 'components/@extended/AnimateButton';
import useAuth from 'hooks/useAuth';
import useScriptRef from 'hooks/useScriptRef';
import { dispatch } from 'store';
import { openSnackbar } from 'store/reducers/snackbar';
import { strengthColor, strengthIndicator } from 'utils/password-strength';
// assets
import { EyeOutlined, EyeInvisibleOutlined } from '@ant-design/icons';
// ============================|| STATIC - RESET PASSWORD ||============================ //
const AuthResetPassword = () => {
const scriptedRef = useScriptRef();
const navigate = useNavigate();
const { isLoggedIn } = useAuth();
const [level, setLevel] = useState();
const [showPassword, setShowPassword] = useState(false);
const handleClickShowPassword = () => {
setShowPassword(!showPassword);
};
const handleMouseDownPassword = (event) => {
event.preventDefault();
};
const changePassword = (value) => {
const temp = strengthIndicator(value);
setLevel(strengthColor(temp));
};
useEffect(() => {
changePassword('');
}, []);
return (
<Formik
initialValues={{
password: '',
confirmPassword: '',
submit: null
}}
validationSchema={Yup.object().shape({
password: Yup.string().max(255).required('Password is required'),
confirmPassword: Yup.string()
.required('Confirm Password is required')
.test('confirmPassword', 'Both Password must be match!', (confirmPassword, yup) => yup.parent.password === confirmPassword)
})}
onSubmit={async (values, { setErrors, setStatus, setSubmitting }) => {
try {
// password reset
if (scriptedRef.current) {
setStatus({ success: true });
setSubmitting(false);
dispatch(
openSnackbar({
open: true,
message: 'Successfuly reset password.',
variant: 'alert',
alert: {
color: 'success'
},
close: false
})
);
setTimeout(() => {
navigate(isLoggedIn ? '/auth/login' : '/login', { replace: true });
}, 1500);
}
} catch (err) {
console.error(err);
if (scriptedRef.current) {
setStatus({ success: false });
setErrors({ submit: err.message });
setSubmitting(false);
}
}
}}
>
{({ errors, handleBlur, handleChange, handleSubmit, isSubmitting, touched, values }) => (
<form noValidate onSubmit={handleSubmit}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Stack spacing={1}>
<InputLabel htmlFor="password-reset">Password</InputLabel>
<OutlinedInput
fullWidth
error={Boolean(touched.password && errors.password)}
id="password-reset"
type={showPassword ? 'text' : 'password'}
value={values.password}
name="password"
onBlur={handleBlur}
onChange={(e) => {
handleChange(e);
changePassword(e.target.value);
}}
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
edge="end"
color="secondary"
>
{showPassword ? <EyeOutlined /> : <EyeInvisibleOutlined />}
</IconButton>
</InputAdornment>
}
placeholder="Enter password"
/>
{touched.password && errors.password && (
<FormHelperText error id="helper-text-password-reset">
{errors.password}
</FormHelperText>
)}
</Stack>
<FormControl fullWidth sx={{ mt: 2 }}>
<Grid container spacing={2} alignItems="center">
<Grid item>
<Box sx={{ bgcolor: level?.color, width: 85, height: 8, borderRadius: '7px' }} />
</Grid>
<Grid item>
<Typography variant="subtitle1" fontSize="0.75rem">
{level?.label}
</Typography>
</Grid>
</Grid>
</FormControl>
</Grid>
<Grid item xs={12}>
<Stack spacing={1}>
<InputLabel htmlFor="confirm-password-reset">Confirm Password</InputLabel>
<OutlinedInput
fullWidth
error={Boolean(touched.confirmPassword && errors.confirmPassword)}
id="confirm-password-reset"
type="password"
value={values.confirmPassword}
name="confirmPassword"
onBlur={handleBlur}
onChange={handleChange}
placeholder="Enter confirm password"
/>
{touched.confirmPassword && errors.confirmPassword && (
<FormHelperText error id="helper-text-confirm-password-reset">
{errors.confirmPassword}
</FormHelperText>
)}
</Stack>
</Grid>
{errors.submit && (
<Grid item xs={12}>
<FormHelperText error>{errors.submit}</FormHelperText>
</Grid>
)}
<Grid item xs={12}>
<AnimateButton>
<Button disableElevation disabled={isSubmitting} fullWidth size="large" type="submit" variant="contained" color="primary">
Reset Password
</Button>
</AnimateButton>
</Grid>
</Grid>
</form>
)}
</Formik>
);
};
export default AuthResetPassword;

View File

@@ -0,0 +1,82 @@
// material-ui
import { useTheme } from '@mui/material/styles';
import { useMediaQuery, Button, Stack } from '@mui/material';
// project import
import useAuth from 'hooks/useAuth';
// assets
import Google from 'assets/images/icons/google.svg';
import Twitter from 'assets/images/icons/twitter.svg';
import Facebook from 'assets/images/icons/facebook.svg';
// ==============================|| FIREBASE - SOCIAL BUTTON ||============================== //
const FirebaseSocial = () => {
const theme = useTheme();
const matchDownSM = useMediaQuery(theme.breakpoints.down('sm'));
const { firebaseFacebookSignIn, firebaseGoogleSignIn, firebaseTwitterSignIn } = useAuth();
const googleHandler = async () => {
try {
await firebaseGoogleSignIn();
} catch (err) {
console.error(err);
}
};
const twitterHandler = async () => {
try {
await firebaseTwitterSignIn();
} catch (err) {
console.error(err);
}
};
const facebookHandler = async () => {
try {
await firebaseFacebookSignIn();
} catch (err) {
console.error(err);
}
};
return (
<Stack
direction="row"
spacing={matchDownSM ? 1 : 2}
justifyContent={matchDownSM ? 'space-around' : 'space-between'}
sx={{ '& .MuiButton-startIcon': { mr: matchDownSM ? 0 : 1, ml: matchDownSM ? 0 : -0.5 } }}
>
<Button
variant="outlined"
color="secondary"
fullWidth={!matchDownSM}
startIcon={<img src={Google} alt="Google" />}
onClick={googleHandler}
>
{!matchDownSM && 'Google'}
</Button>
<Button
variant="outlined"
color="secondary"
fullWidth={!matchDownSM}
startIcon={<img src={Twitter} alt="Twitter" />}
onClick={twitterHandler}
>
{!matchDownSM && 'Twitter'}
</Button>
<Button
variant="outlined"
color="secondary"
fullWidth={!matchDownSM}
startIcon={<img src={Facebook} alt="Facebook" />}
onClick={facebookHandler}
>
{!matchDownSM && 'Facebook'}
</Button>
</Stack>
);
};
export default FirebaseSocial;

View File

@@ -0,0 +1,68 @@
import { Link as RouterLink } from 'react-router-dom';
// material-ui
import { Link, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography } from '@mui/material';
// project imports
import MainCard from 'components/MainCard';
// table data
function createData(name, designation, product, date, badgeText, badgeType) {
return { name, designation, product, date, badgeText, badgeType };
}
const rows = [
createData('Materially', 'Powerful Admin Theme', '16,300', '$53', '$15,652'),
createData('Photoshop', 'Design Software', '26,421', '$35', '$8,785'),
createData('Guruable', 'Best Admin Template', '8,265', '$98', '$9,652'),
createData('Flatable', 'Admin App', '10,652', '$20', '$7,856')
];
// =========================|| DATA WIDGET - APPLICATION SALES ||========================= //
const ApplicationSales = () => (
<MainCard
title="Application Sales"
content={false}
secondary={
<Link component={RouterLink} to="#" color="primary">
View all
</Link>
}
>
<TableContainer>
<Table>
<TableHead>
<TableRow>
<TableCell sx={{ pl: 3 }}>Application</TableCell>
<TableCell align="right">Sales</TableCell>
<TableCell align="right">Avg. Price</TableCell>
<TableCell align="right" sx={{ pr: 3 }}>
Total
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows.map((row, index) => (
<TableRow hover key={index}>
{/* <TableCell sx={{ pl: 3 }}>
<Typography align="left" variant="subtitle1">
{row.name}
</Typography>
<Typography align="left" variant="caption" color="secondary">
{row.designation}
</Typography>
</TableCell>
<TableCell align="right">{row.product}</TableCell>
<TableCell align="right">{row.date}</TableCell>
<TableCell align="right" sx={{ pr: 3 }}>
<span>{row.badgeText}</span>
</TableCell> */}
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</MainCard>
);
export default ApplicationSales;

View File

@@ -0,0 +1,175 @@
import { Link as RouterLink } from 'react-router-dom';
// material-ui
import { CardContent, Grid, Link, Typography } from '@mui/material';
// project imports
import MainCard from 'components/MainCard';
import Avatar from 'components/@extended/Avatar';
// assets
import { TwitterCircleFilled, ClockCircleFilled, BugFilled, MobileFilled, WarningFilled } from '@ant-design/icons';
// ==============================|| DATA WIDGET - TASKS CARD ||============================== //
const TasksCard = () => (
<MainCard
title="Tasks"
content={false}
secondary={
<Link component={RouterLink} to="#" color="primary">
View all
</Link>
}
>
<CardContent>
<Grid
container
spacing={2.75}
alignItems="center"
sx={{
position: 'relative',
'&>*': {
position: 'relative',
zIndex: '5'
},
'&:after': {
content: '""',
position: 'absolute',
top: 10,
left: 38,
width: 2,
height: '100%',
background: '#ebebeb',
zIndex: '1'
}
}}
>
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item>
<Avatar type="filled" color="success" size="sm" sx={{ top: 10 }}>
<TwitterCircleFilled />
</Avatar>
</Grid>
<Grid item xs zeroMinWidth>
<Grid container spacing={0}>
<Grid item xs={12}>
<Typography align="left" variant="caption" color="secondary">
8:50
</Typography>
</Grid>
<Grid item xs={12}>
<Typography align="left" variant="body2">
Youre getting more and more followers, keep it up!
</Typography>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item>
<Avatar type="filled" color="primary" size="sm" sx={{ top: 10 }}>
<ClockCircleFilled />
</Avatar>
</Grid>
<Grid item xs zeroMinWidth>
<Grid container spacing={0}>
<Grid item xs={12}>
<Typography align="left" variant="caption" color="secondary">
Sat, 5 Mar
</Typography>
</Grid>
<Grid item xs={12}>
<Typography align="left" variant="body2">
Design mobile Application
</Typography>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item>
<Avatar type="filled" color="error" size="sm" sx={{ top: 10 }}>
<BugFilled />
</Avatar>
</Grid>
<Grid item xs zeroMinWidth>
<Grid container spacing={0}>
<Grid item xs={12}>
<Typography align="left" variant="caption" color="secondary">
Sun, 17 Feb
</Typography>
</Grid>
<Grid item xs={12}>
<Typography align="left" variant="body2">
<Link component={RouterLink} to="#" underline="hover">
Jenny
</Link>{' '}
assign you a task{' '}
<Link component={RouterLink} to="#" underline="hover">
Mockup Design
</Link>
.
</Typography>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item>
<Avatar type="filled" color="warning" size="sm" sx={{ top: 10 }}>
<WarningFilled />
</Avatar>
</Grid>
<Grid item xs zeroMinWidth>
<Grid container spacing={0}>
<Grid item xs={12}>
<Typography align="left" variant="caption" color="secondary">
Sat, 18 Mar
</Typography>
</Grid>
<Grid item xs={12}>
<Typography align="left" variant="body2">
Design logo
</Typography>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item>
<Avatar type="filled" color="success" size="sm" sx={{ top: 10 }}>
<MobileFilled />
</Avatar>
</Grid>
<Grid item xs zeroMinWidth>
<Grid container spacing={0}>
<Grid item xs={12}>
<Typography align="left" variant="caption" color="secondary">
Sat, 22 Mar
</Typography>
</Grid>
<Grid item xs={12}>
<Typography align="left" variant="body2">
Design mobile Application
</Typography>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
</CardContent>
</MainCard>
);
export default TasksCard;