first
This commit is contained in:
61
src/components/cards/AuthFooter.js
Normal file
61
src/components/cards/AuthFooter.js
Normal file
@@ -0,0 +1,61 @@
|
||||
// material-ui
|
||||
import { Container, Link, Stack, Typography, useMediaQuery } from '@mui/material';
|
||||
|
||||
// ==============================|| FOOTER - AUTHENTICATION ||============================== //
|
||||
|
||||
const AuthFooter = () => {
|
||||
const matchDownSM = useMediaQuery((theme) => theme.breakpoints.down('sm'));
|
||||
|
||||
return (
|
||||
<Container maxWidth="xl">
|
||||
<Stack
|
||||
direction={matchDownSM ? 'column' : 'row'}
|
||||
justifyContent={matchDownSM ? 'center' : 'space-between'}
|
||||
spacing={2}
|
||||
textAlign={matchDownSM ? 'center' : 'inherit'}
|
||||
>
|
||||
<Typography variant="subtitle2" color="secondary" component="span">
|
||||
This site is protected by{' '}
|
||||
<Typography component={Link} variant="subtitle2" href="#mantis-privacy" target="_blank" underline="hover">
|
||||
Privacy Policy
|
||||
</Typography>
|
||||
</Typography>
|
||||
|
||||
<Stack direction={matchDownSM ? 'column' : 'row'} spacing={matchDownSM ? 1 : 3} textAlign={matchDownSM ? 'center' : 'inherit'}>
|
||||
<Typography
|
||||
variant="subtitle2"
|
||||
color="secondary"
|
||||
component={Link}
|
||||
href="https://codedthemes.com"
|
||||
target="_blank"
|
||||
underline="hover"
|
||||
>
|
||||
Terms and Conditions
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="subtitle2"
|
||||
color="secondary"
|
||||
component={Link}
|
||||
href="https://codedthemes.com"
|
||||
target="_blank"
|
||||
underline="hover"
|
||||
>
|
||||
Privacy Policy
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="subtitle2"
|
||||
color="secondary"
|
||||
component={Link}
|
||||
href="https://codedthemes.com"
|
||||
target="_blank"
|
||||
underline="hover"
|
||||
>
|
||||
CA Privacy Notice
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default AuthFooter;
|
||||
49
src/components/cards/ComponentHeader.js
Normal file
49
src/components/cards/ComponentHeader.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { Box, Grid, Link, Stack, Typography } from '@mui/material';
|
||||
|
||||
// assets
|
||||
import { GlobalOutlined, NodeExpandOutlined } from '@ant-design/icons';
|
||||
|
||||
// ==============================|| COMPONENTS - BREADCRUMBS ||============================== //
|
||||
|
||||
const ComponentHeader = ({ title, caption, directory, link }) => (
|
||||
<Box sx={{ pl: 3 }}>
|
||||
<Stack spacing={1.25}>
|
||||
<Typography variant="h2">{title}</Typography>
|
||||
{caption && (
|
||||
<Typography variant="h6" color="textSecondary">
|
||||
{caption}
|
||||
</Typography>
|
||||
)}
|
||||
</Stack>
|
||||
<Grid container spacing={0.75} sx={{ mt: 1.75 }}>
|
||||
{directory && (
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="caption" color="textSecondary">
|
||||
<NodeExpandOutlined style={{ marginRight: 10 }} />
|
||||
{directory}
|
||||
</Typography>
|
||||
</Grid>
|
||||
)}
|
||||
{link && (
|
||||
<Grid item xs={12}>
|
||||
<Link variant="caption" color="primary" href={link} target="_blank">
|
||||
<GlobalOutlined style={{ marginRight: 10 }} />
|
||||
{link}
|
||||
</Link>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
|
||||
ComponentHeader.propTypes = {
|
||||
title: PropTypes.string,
|
||||
caption: PropTypes.string,
|
||||
directory: PropTypes.string,
|
||||
link: PropTypes.string
|
||||
};
|
||||
|
||||
export default ComponentHeader;
|
||||
55
src/components/cards/e-commerce/FloatingCart.js
Normal file
55
src/components/cards/e-commerce/FloatingCart.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import { sum } from 'lodash';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Fab, Badge } from '@mui/material';
|
||||
|
||||
// project import
|
||||
import { useSelector } from 'store';
|
||||
|
||||
// assets
|
||||
import { ShoppingCartOutlined } from '@ant-design/icons';
|
||||
|
||||
// ==============================|| CART ITEMS - FLOATING BUTTON ||============================== //
|
||||
|
||||
const FloatingCart = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
const cart = useSelector((state) => state.cart);
|
||||
const totalQuantity = sum(cart.checkout.products.map((item) => item.quantity));
|
||||
|
||||
return (
|
||||
<Fab
|
||||
component={Link}
|
||||
to="/apps/e-commerce/checkout"
|
||||
size="large"
|
||||
sx={{
|
||||
top: '75%',
|
||||
position: 'fixed',
|
||||
right: 0,
|
||||
zIndex: theme.zIndex.speedDial,
|
||||
boxShadow: theme.customShadows.primary,
|
||||
bgcolor: 'primary.lighter',
|
||||
color: 'primary.main',
|
||||
borderRadius: '25%',
|
||||
borderTopRightRadius: 0,
|
||||
borderBottomRightRadius: 0,
|
||||
'&:hover': {
|
||||
bgcolor: 'primary.100',
|
||||
boxShadow: theme.customShadows.primary
|
||||
},
|
||||
'&:focus-visible': {
|
||||
outline: `2px solid ${theme.palette.primary.dark}`,
|
||||
outlineOffset: 2
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Badge showZero badgeContent={totalQuantity} color="error">
|
||||
<ShoppingCartOutlined style={{ color: theme.palette.primary.main, fontSize: '1.5rem' }} />
|
||||
</Badge>
|
||||
</Fab>
|
||||
);
|
||||
};
|
||||
|
||||
export default FloatingCart;
|
||||
176
src/components/cards/e-commerce/ProductCard.js
Normal file
176
src/components/cards/e-commerce/ProductCard.js
Normal file
@@ -0,0 +1,176 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { Box, Button, CardContent, CardMedia, Chip, Divider, Grid, Rating, Stack, Typography } from '@mui/material';
|
||||
|
||||
// project import
|
||||
import MainCard from 'components/MainCard';
|
||||
import IconButton from 'components/@extended/IconButton';
|
||||
import SkeletonProductPlaceholder from 'components/cards/skeleton/ProductPlaceholder';
|
||||
import { useDispatch, useSelector } from 'store';
|
||||
import { addProduct } from 'store/reducers/cart';
|
||||
import { openSnackbar } from 'store/reducers/snackbar';
|
||||
|
||||
// assets
|
||||
import { HeartOutlined, HeartFilled } from '@ant-design/icons';
|
||||
|
||||
const prodImage = require.context('assets/images/e-commerce', true);
|
||||
|
||||
// ==============================|| PRODUCT CARD ||============================== //
|
||||
|
||||
const ProductCard = ({ id, color, name, brand, offer, isStock, image, description, offerPrice, salePrice, rating }) => {
|
||||
const theme = useTheme();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const prodProfile = image && prodImage(`./${image}`);
|
||||
const [productRating] = useState(rating);
|
||||
const [wishlisted, setWishlisted] = useState(false);
|
||||
const cart = useSelector((state) => state.cart);
|
||||
|
||||
const addCart = () => {
|
||||
dispatch(addProduct({ id, name, image, salePrice, offerPrice, color, size: 8, quantity: 1, description }, cart.checkout.products));
|
||||
dispatch(
|
||||
openSnackbar({
|
||||
open: true,
|
||||
message: 'Add To Cart Success',
|
||||
variant: 'alert',
|
||||
alert: {
|
||||
color: 'success'
|
||||
},
|
||||
close: false
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const addToFavourite = () => {
|
||||
setWishlisted(!wishlisted);
|
||||
dispatch(
|
||||
openSnackbar({
|
||||
open: true,
|
||||
message: 'Added to favourites',
|
||||
variant: 'alert',
|
||||
alert: {
|
||||
color: 'success'
|
||||
},
|
||||
close: false
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const [isLoading, setLoading] = useState(true);
|
||||
useEffect(() => {
|
||||
setLoading(false);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
{isLoading ? (
|
||||
<SkeletonProductPlaceholder />
|
||||
) : (
|
||||
<MainCard
|
||||
content={false}
|
||||
boxShadow
|
||||
sx={{
|
||||
'&:hover': {
|
||||
transform: 'scale3d(1.02, 1.02, 1)',
|
||||
transition: 'all .4s ease-in-out'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Box sx={{ width: 250, m: 'auto' }}>
|
||||
<CardMedia
|
||||
sx={{ height: 250, textDecoration: 'none', opacity: isStock ? 1 : 0.25 }}
|
||||
image={prodProfile}
|
||||
component={Link}
|
||||
to={`/apps/e-commerce/product-details/${id}`}
|
||||
/>
|
||||
</Box>
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
sx={{ width: '100%', position: 'absolute', top: 0, pt: 1.75, pl: 2, pr: 1 }}
|
||||
>
|
||||
{!isStock && <Chip variant="light" color="error" size="small" label="Sold out" />}
|
||||
{offer && <Chip label={offer} variant="combined" color="success" size="small" />}
|
||||
<IconButton color="secondary" sx={{ ml: 'auto', '&:hover': { background: 'transparent' } }} onClick={addToFavourite}>
|
||||
{wishlisted ? (
|
||||
<HeartFilled style={{ fontSize: '1.15rem', color: theme.palette.error.main }} />
|
||||
) : (
|
||||
<HeartOutlined style={{ fontSize: '1.15rem' }} />
|
||||
)}
|
||||
</IconButton>
|
||||
</Stack>
|
||||
<Divider />
|
||||
<CardContent sx={{ p: 2 }}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Stack>
|
||||
<Typography
|
||||
component={Link}
|
||||
to={`/apps/e-commerce/product-details/${id}`}
|
||||
color="textPrimary"
|
||||
variant="h5"
|
||||
sx={{
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
display: 'block',
|
||||
textDecoration: 'none'
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</Typography>
|
||||
<Typography variant="h6" color="textSecondary">
|
||||
{brand}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Stack direction="row" justifyContent="space-between" alignItems="flex-end" flexWrap="wrap" rowGap={1.75}>
|
||||
<Stack>
|
||||
<Stack direction="row" spacing={1} alignItems="center">
|
||||
<Typography variant="h5">${offerPrice}</Typography>
|
||||
{salePrice && (
|
||||
<Typography variant="h6" color="textSecondary" sx={{ textDecoration: 'line-through' }}>
|
||||
${salePrice}
|
||||
</Typography>
|
||||
)}
|
||||
</Stack>
|
||||
<Stack direction="row" alignItems="flex-start">
|
||||
<Rating precision={0.5} name="size-small" value={productRating} size="small" readOnly />
|
||||
<Typography variant="caption">({productRating?.toFixed(1)})</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<Button variant="contained" onClick={addCart} disabled={!isStock}>
|
||||
{!isStock ? 'Sold Out' : 'Add to Cart'}
|
||||
</Button>
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</MainCard>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
ProductCard.propTypes = {
|
||||
id: PropTypes.number,
|
||||
color: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
brand: PropTypes.string,
|
||||
isStock: PropTypes.bool,
|
||||
image: PropTypes.string,
|
||||
description: PropTypes.string,
|
||||
offerPrice: PropTypes.number,
|
||||
salePrice: PropTypes.number,
|
||||
offer: PropTypes.string,
|
||||
rating: PropTypes.number
|
||||
};
|
||||
|
||||
export default ProductCard;
|
||||
52
src/components/cards/e-commerce/ProductReview.js
Normal file
52
src/components/cards/e-commerce/ProductReview.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { Grid, Rating, Stack, Typography } from '@mui/material';
|
||||
|
||||
// project imports
|
||||
import Avatar from 'components/@extended/Avatar';
|
||||
|
||||
// assets
|
||||
import { StarFilled, StarOutlined } from '@ant-design/icons';
|
||||
|
||||
const avatarImage = require.context('assets/images/users', true);
|
||||
|
||||
// ==============================|| PRODUCT DETAILS - REVIEW ||============================== //
|
||||
|
||||
const ProductReview = ({ avatar, date, name, rating, review }) => (
|
||||
<Grid item xs={12}>
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Avatar alt={name} src={avatar && avatarImage(`./${avatar}`)} />
|
||||
<Stack spacing={2}>
|
||||
<Stack>
|
||||
<Typography variant="subtitle1" sx={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block' }}>
|
||||
{name}
|
||||
</Typography>
|
||||
<Typography variant="caption" color="textSecondary">
|
||||
{date}
|
||||
</Typography>
|
||||
<Rating
|
||||
size="small"
|
||||
name="simple-controlled"
|
||||
value={rating < 4 ? rating + 1 : rating}
|
||||
icon={<StarFilled style={{ fontSize: 'inherit' }} />}
|
||||
emptyIcon={<StarOutlined style={{ fontSize: 'inherit' }} />}
|
||||
precision={0.1}
|
||||
readOnly
|
||||
/>
|
||||
</Stack>
|
||||
<Typography variant="body2">{review}</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Grid>
|
||||
);
|
||||
|
||||
ProductReview.propTypes = {
|
||||
avatar: PropTypes.string,
|
||||
date: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
rating: PropTypes.number,
|
||||
review: PropTypes.string
|
||||
};
|
||||
|
||||
export default ProductReview;
|
||||
44
src/components/cards/skeleton/ProductPlaceholder.js
Normal file
44
src/components/cards/skeleton/ProductPlaceholder.js
Normal file
@@ -0,0 +1,44 @@
|
||||
// material-ui
|
||||
import { CardContent, Grid, Skeleton, Stack } from '@mui/material';
|
||||
|
||||
// project import
|
||||
import MainCard from 'components/MainCard';
|
||||
|
||||
// ===========================|| SKELETON - PRODUCT CARD ||=========================== //
|
||||
|
||||
const ProductPlaceholder = () => (
|
||||
<MainCard content={false} boxShadow>
|
||||
<Skeleton variant="rectangular" height={220} />
|
||||
<CardContent sx={{ p: 2 }}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Skeleton variant="rectangular" height={20} />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Skeleton variant="rectangular" height={45} />
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{ pt: '8px !important' }}>
|
||||
<Stack direction="row" alignItems="center" spacing={1}>
|
||||
<Skeleton variant="rectangular" height={20} width={90} />
|
||||
<Skeleton variant="rectangular" height={20} width={38} />
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Stack direction="row" justifyContent="space-between" alignItems="center">
|
||||
<Grid container spacing={1}>
|
||||
<Grid item>
|
||||
<Skeleton variant="rectangular" height={20} width={40} />
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Skeleton variant="rectangular" height={17} width={20} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Skeleton variant="rectangular" height={32} width={47} />
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</MainCard>
|
||||
);
|
||||
|
||||
export default ProductPlaceholder;
|
||||
66
src/components/cards/statistics/AnalyticEcommerce.js
Normal file
66
src/components/cards/statistics/AnalyticEcommerce.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { Box, Chip, Grid, Stack, Typography } from '@mui/material';
|
||||
|
||||
// project import
|
||||
import MainCard from 'components/MainCard';
|
||||
|
||||
// assets
|
||||
import { FallOutlined, RiseOutlined } from '@ant-design/icons';
|
||||
|
||||
// ==============================|| STATISTICS - ECOMMERCE CARD ||============================== //
|
||||
|
||||
const AnalyticEcommerce = ({ color = 'primary', title, count, percentage, isLoss, extra }) => (
|
||||
<MainCard contentSX={{ p: 2.25 }}>
|
||||
<Stack spacing={0.5}>
|
||||
<Typography variant="h6" color="textSecondary">
|
||||
{title}
|
||||
</Typography>
|
||||
<Grid container alignItems="center">
|
||||
<Grid item>
|
||||
<Typography variant="h4" color="inherit">
|
||||
{count}
|
||||
</Typography>
|
||||
</Grid>
|
||||
{percentage && (
|
||||
<Grid item>
|
||||
<Chip
|
||||
variant="combined"
|
||||
color={color}
|
||||
icon={
|
||||
<>
|
||||
{!isLoss && <RiseOutlined style={{ fontSize: '0.75rem', color: 'inherit' }} />}
|
||||
{isLoss && <FallOutlined style={{ fontSize: '0.75rem', color: 'inherit' }} />}
|
||||
</>
|
||||
}
|
||||
label={`${percentage}%`}
|
||||
sx={{ ml: 1.25, pl: 1 }}
|
||||
size="small"
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</Stack>
|
||||
<Box sx={{ pt: 2.25 }}>
|
||||
<Typography variant="caption" color="textSecondary">
|
||||
You made an extra{' '}
|
||||
<Typography component="span" variant="caption" sx={{ color: `${color || 'primary'}.main` }}>
|
||||
{extra}
|
||||
</Typography>{' '}
|
||||
this year
|
||||
</Typography>
|
||||
</Box>
|
||||
</MainCard>
|
||||
);
|
||||
|
||||
AnalyticEcommerce.propTypes = {
|
||||
title: PropTypes.string,
|
||||
count: PropTypes.string,
|
||||
percentage: PropTypes.number,
|
||||
isLoss: PropTypes.bool,
|
||||
color: PropTypes.string,
|
||||
extra: PropTypes.string
|
||||
};
|
||||
|
||||
export default AnalyticEcommerce;
|
||||
56
src/components/cards/statistics/AnalyticsDataCard.js
Normal file
56
src/components/cards/statistics/AnalyticsDataCard.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// material-ui
|
||||
import { Box, Chip, Stack, Typography } from '@mui/material';
|
||||
|
||||
// project import
|
||||
import MainCard from 'components/MainCard';
|
||||
|
||||
// assets
|
||||
import { RiseOutlined, FallOutlined } from '@ant-design/icons';
|
||||
|
||||
// ==============================|| STATISTICS - ECOMMERCE CARD ||============================== //
|
||||
|
||||
const AnalyticsDataCard = ({ color = 'primary', title, count, percentage, isLoss, children }) => (
|
||||
<MainCard content={false}>
|
||||
<Box sx={{ p: 2.25 }}>
|
||||
<Stack spacing={0.5}>
|
||||
<Typography variant="h6" color="textSecondary">
|
||||
{title}
|
||||
</Typography>
|
||||
<Stack direction="row" alignItems="center">
|
||||
<Typography variant="h4" color="inherit">
|
||||
{count}
|
||||
</Typography>
|
||||
{percentage && (
|
||||
<Chip
|
||||
variant="combined"
|
||||
color={color}
|
||||
icon={
|
||||
<>
|
||||
{!isLoss && <RiseOutlined style={{ fontSize: '0.75rem', color: 'inherit' }} />}
|
||||
{isLoss && <FallOutlined style={{ fontSize: '0.75rem', color: 'inherit' }} />}
|
||||
</>
|
||||
}
|
||||
label={`${percentage}%`}
|
||||
sx={{ ml: 1.25, pl: 1 }}
|
||||
size="small"
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Box>
|
||||
{children}
|
||||
</MainCard>
|
||||
);
|
||||
|
||||
AnalyticsDataCard.propTypes = {
|
||||
title: PropTypes.string,
|
||||
count: PropTypes.string,
|
||||
percentage: PropTypes.number,
|
||||
isLoss: PropTypes.bool,
|
||||
color: PropTypes.string,
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
export default AnalyticsDataCard;
|
||||
Reference in New Issue
Block a user