Skip to content

Commit bff0868

Browse files
Merge pull request #5 from VikrantParmar/vp-route-guard
Implement user-specific article management functionality
2 parents e68d33d + 68fa364 commit bff0868

17 files changed

+874
-75
lines changed
Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
1-
import PropTypes from 'prop-types';
1+
import PropTypes from "prop-types";
22

33
// third-party
4-
import { motion, useCycle } from 'framer-motion';
4+
import { motion, useCycle } from "framer-motion";
55

6-
export default function AnimateButton({ children, type = 'scale', direction = 'right', offset = 10, scale = { hover: 1.05, tap: 0.954 } }) {
6+
export default function AnimateButton({
7+
children,
8+
type = "scale",
9+
direction = "right",
10+
offset = 10,
11+
scale = { hover: 1.05, tap: 0.954 },
12+
}) {
713
let offset1;
814
let offset2;
915
switch (direction) {
10-
case 'up':
11-
case 'left':
16+
case "up":
17+
case "left":
1218
offset1 = offset;
1319
offset2 = 0;
1420
break;
15-
case 'right':
16-
case 'down':
21+
case "right":
22+
case "down":
1723
default:
1824
offset1 = 0;
1925
offset2 = offset;
@@ -24,44 +30,55 @@ export default function AnimateButton({ children, type = 'scale', direction = 'r
2430
const [y, cycleY] = useCycle(offset1, offset2);
2531

2632
switch (type) {
27-
case 'rotate':
33+
case "rotate":
2834
return (
2935
<motion.div
3036
animate={{ rotate: 360 }}
3137
transition={{
3238
repeat: Infinity,
33-
repeatType: 'loop',
39+
repeatType: "loop",
3440
duration: 2,
35-
repeatDelay: 0
41+
repeatDelay: 0,
3642
}}
3743
>
3844
{children}
3945
</motion.div>
4046
);
41-
case 'slide':
42-
if (direction === 'up' || direction === 'down') {
47+
case "slide":
48+
if (direction === "up" || direction === "down") {
4349
return (
44-
<motion.div animate={{ y: y !== undefined ? y : '' }} onHoverEnd={() => cycleY()} onHoverStart={() => cycleY()}>
50+
<motion.div
51+
animate={{ y: y !== undefined ? y : "" }}
52+
onHoverEnd={() => cycleY()}
53+
onHoverStart={() => cycleY()}
54+
>
4555
{children}
4656
</motion.div>
4757
);
4858
}
4959
return (
50-
<motion.div animate={{ x: x !== undefined ? x : '' }} onHoverEnd={() => cycleX()} onHoverStart={() => cycleX()}>
60+
<motion.div
61+
animate={{ x: x !== undefined ? x : "" }}
62+
onHoverEnd={() => cycleX()}
63+
onHoverStart={() => cycleX()}
64+
>
5165
{children}
5266
</motion.div>
5367
);
5468

55-
case 'scale':
69+
case "scale":
5670
default:
57-
if (typeof scale === 'number') {
71+
if (typeof scale === "number") {
5872
scale = {
5973
hover: scale,
60-
tap: scale
74+
tap: scale,
6175
};
6276
}
6377
return (
64-
<motion.div whileHover={{ scale: scale?.hover }} whileTap={{ scale: scale?.tap }}>
78+
<motion.div
79+
whileHover={{ scale: scale?.hover }}
80+
whileTap={{ scale: scale?.tap }}
81+
>
6582
{children}
6683
</motion.div>
6784
);
@@ -70,8 +87,8 @@ export default function AnimateButton({ children, type = 'scale', direction = 'r
7087

7188
AnimateButton.propTypes = {
7289
children: PropTypes.node,
73-
type: PropTypes.oneOf(['slide', 'scale', 'rotate']),
74-
direction: PropTypes.oneOf(['up', 'down', 'left', 'right']),
90+
type: PropTypes.oneOf(["slide", "scale", "rotate"]),
91+
direction: PropTypes.oneOf(["up", "down", "left", "right"]),
7592
offset: PropTypes.number,
76-
scale: PropTypes.object
93+
scale: PropTypes.object,
7794
};
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import PropTypes from "prop-types";
2+
import { useState } from "react";
3+
import {
4+
Button,
5+
Dialog,
6+
DialogContent,
7+
Stack,
8+
Avatar,
9+
Typography,
10+
} from "@mui/material";
11+
import { DeleteOutlined } from "@mui/icons-material";
12+
import { useSelector, useDispatch } from "react-redux";
13+
import { _loader } from "@/utils/loaderHelper";
14+
import { PopupTransition } from "@/components/@extended/Transitions";
15+
import AnimateButton from "@/components/@extended/AnimateButton";
16+
import { useShowNotification } from "@/hooks/useShowNotification";
17+
import { deleteBlog } from "@/store/blogs/blogSlice";
18+
19+
export default function BlogDeleteAlert({
20+
id,
21+
onClose,
22+
recordData,
23+
open,
24+
onSuccess,
25+
}) {
26+
const { showNotification } = useShowNotification();
27+
const dispatch = useDispatch();
28+
const { isLoadingDelete: isLoading } = useSelector((state) => state.blogs);
29+
const deleteHandler = async () => {
30+
try {
31+
const response = await dispatch(deleteBlog(id)).unwrap();
32+
showNotification(
33+
response?.message || "Blog deleted successfully.",
34+
"success"
35+
);
36+
if (onSuccess) {
37+
onSuccess(response);
38+
}
39+
onClose();
40+
} catch (error) {
41+
showNotification(error?.message || "Blog could not be deleted.", "error");
42+
} finally {
43+
onClose();
44+
}
45+
};
46+
47+
const blogTitle = recordData ? recordData.title : "";
48+
return (
49+
<Dialog
50+
open={open}
51+
onClose={onClose}
52+
keepMounted
53+
TransitionComponent={PopupTransition}
54+
maxWidth="xs"
55+
aria-labelledby="blog-delete-title"
56+
aria-describedby="blog-delete-description"
57+
>
58+
<DialogContent sx={{ mt: 2, my: 1 }}>
59+
<Stack alignItems="center" spacing={3.5}>
60+
<Avatar
61+
sx={{
62+
width: 72,
63+
height: 72,
64+
fontSize: "1.75rem",
65+
bgcolor: (theme) => theme.palette.error.main,
66+
}}
67+
>
68+
<DeleteOutlined />
69+
</Avatar>
70+
<Stack spacing={2}>
71+
<Typography variant="h4" align="center">
72+
Are you sure you want to delete this blog?
73+
</Typography>
74+
<Typography align="center">
75+
<Typography variant="subtitle1" component="span">
76+
&quot; {blogTitle} &quot;{" "}
77+
</Typography>
78+
</Typography>
79+
</Stack>
80+
81+
<Stack
82+
direction="row"
83+
spacing={2}
84+
sx={{
85+
width: 1,
86+
justifyContent: "center",
87+
alignItems: "center",
88+
}}
89+
>
90+
<AnimateButton>
91+
<Button
92+
fullWidth
93+
onClick={onClose}
94+
color="dark"
95+
variant="outlined"
96+
>
97+
Cancel
98+
</Button>
99+
</AnimateButton>
100+
<AnimateButton>
101+
<Button
102+
fullWidth
103+
color="error"
104+
variant="contained"
105+
onClick={deleteHandler}
106+
autoFocus
107+
sx={{ minWidth: "5vw" }}
108+
disabled={isLoading}
109+
>
110+
{_loader({
111+
type: "btn",
112+
isSubmitting: isLoading,
113+
btnTitle: "Delete",
114+
})}
115+
</Button>
116+
</AnimateButton>
117+
</Stack>
118+
</Stack>
119+
</DialogContent>
120+
</Dialog>
121+
);
122+
}
123+
124+
BlogDeleteAlert.propTypes = {
125+
id: PropTypes.number,
126+
recordData: PropTypes.oneOfType([PropTypes.object, PropTypes.oneOf([null])]),
127+
open: PropTypes.bool,
128+
onClose: PropTypes.func,
129+
onSuccess: PropTypes.func,
130+
};

0 commit comments

Comments
 (0)