initial commit
This commit is contained in:
275
src/sections/apps/chat/ChatDrawer.js
Normal file
275
src/sections/apps/chat/ChatDrawer.js
Normal 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;
|
||||
119
src/sections/apps/chat/ChatHistory.js
Normal file
119
src/sections/apps/chat/ChatHistory.js
Normal 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;
|
||||
33
src/sections/apps/chat/UserAvatar.js
Normal file
33
src/sections/apps/chat/UserAvatar.js
Normal 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;
|
||||
303
src/sections/apps/chat/UserDetails.js
Normal file
303
src/sections/apps/chat/UserDetails.js
Normal 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;
|
||||
39
src/sections/auth/AuthCard.js
Normal file
39
src/sections/auth/AuthCard.js
Normal 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;
|
||||
55
src/sections/auth/AuthWrapper.js
Normal file
55
src/sections/auth/AuthWrapper.js
Normal 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;
|
||||
66
src/sections/auth/auth-forms/AuthCodeVerification.js
Normal file
66
src/sections/auth/auth-forms/AuthCodeVerification.js
Normal 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;
|
||||
126
src/sections/auth/auth-forms/AuthForgotPassword.js
Normal file
126
src/sections/auth/auth-forms/AuthForgotPassword.js
Normal 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;
|
||||
176
src/sections/auth/auth-forms/AuthLogin.js
Normal file
176
src/sections/auth/auth-forms/AuthLogin.js
Normal 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;
|
||||
282
src/sections/auth/auth-forms/AuthRegister.js
Normal file
282
src/sections/auth/auth-forms/AuthRegister.js
Normal 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
|
||||
<Link variant="subtitle2" component={RouterLink} to="#">
|
||||
Terms of Service
|
||||
</Link>
|
||||
and
|
||||
<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;
|
||||
201
src/sections/auth/auth-forms/AuthResetPassword.js
Normal file
201
src/sections/auth/auth-forms/AuthResetPassword.js
Normal 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;
|
||||
82
src/sections/auth/auth-forms/FirebaseSocial.js
Normal file
82
src/sections/auth/auth-forms/FirebaseSocial.js
Normal 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;
|
||||
68
src/sections/widget/data/ApplicationSales.js
Normal file
68
src/sections/widget/data/ApplicationSales.js
Normal 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;
|
||||
175
src/sections/widget/data/TasksCard.js
Normal file
175
src/sections/widget/data/TasksCard.js
Normal 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">
|
||||
You’re 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;
|
||||
Reference in New Issue
Block a user