Skip to content

Commit b208dda

Browse files
authored
Merge pull request #140 from Coding-Club-IITG/ps
Approve/Reject Contributions from profile
2 parents 6dc0e01 + 5536fc1 commit b208dda

19 files changed

Lines changed: 413 additions & 44 deletions

File tree

client/src/api/Contribution.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,8 @@ export const GetMyContributions = async () => {
1111
const resp = await axios.get(`${root}/api/contribution/`);
1212
return resp;
1313
};
14+
15+
export const GetBrContribution = async (courses) => {
16+
const resp = await axios.post(`${root}/api/contribution/br`, { courses });
17+
return resp;
18+
}

client/src/screens/dashboard/components/addcoursemodal/components/wrapper/styles.scss

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
width: 40%;
44
padding: 3rem 4rem;
55
background-color: white;
6-
height: auto;
76
position: absolute;
87

98
z-index: 200;
@@ -16,7 +15,7 @@
1615
}
1716
.add-course-scroll {
1817
overflow: auto;
19-
max-height: 250px;
18+
max-height: 25vh;
2019
}
2120

2221
@media screen and (max-width:1270px) {

client/src/screens/dashboard/components/addcoursemodal/index.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ const AddCourseModal = ({ handleAddCourse }) => {
8080
<form onSubmit={(e) => e.preventDefault()}>
8181
<div className="course" style={{marginTop: "1.5rem"}}>
8282
<label htmlFor="course" className="label_course">
83-
KEYWORD :
83+
KEY :
8484
</label>
8585
<input
8686
placeholder="Course Code"
Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import "./styles.scss";
2+
23
const Button = (props) => {
3-
return <div className="btn">{props.text}</div>;
4+
return (
5+
<div className="btn" onClick={props.onClick}>
6+
{props.text}
7+
</div>
8+
);
49
};
5-
export default Button;
10+
11+
export default Button;

client/src/screens/profile.js/components/Contri_section/ContributionCard/Buttons/styles.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
font-size: 1rem;
77
cursor: pointer;
88
transition: 200ms ease;
9-
9+
1010
&:hover {
1111
transform: scale(1.02);
1212
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import React from "react";
2+
import tick from "./assets/tick.svg";
3+
import cross from "./assets/cross.svg";
4+
5+
const styles = {
6+
overlay: {
7+
position: "fixed",
8+
top: 0,
9+
left: 0,
10+
right: 0,
11+
bottom: 0,
12+
backgroundColor: "rgba(0, 0, 0, 0.4)",
13+
display: "flex",
14+
alignItems: "center",
15+
justifyContent: "center",
16+
zIndex: 1000,
17+
},
18+
dialog: {
19+
backgroundColor: "#fff",
20+
padding: "25px 30px",
21+
borderRadius: "8px",
22+
maxWidth: "400px",
23+
width: "90%",
24+
boxShadow: "0 4px 20px rgba(0, 0, 0, 0.2)",
25+
textAlign: "center",
26+
fontFamily: "sans-serif",
27+
},
28+
29+
iconImage: {
30+
width: "80px",
31+
height: "80px",
32+
margin: "1em",
33+
},
34+
heading: {
35+
fontSize: "2em",
36+
},
37+
message: {
38+
fontSize: "1em",
39+
color: "#374151",
40+
margin: "1em",
41+
},
42+
buttonGroup: {
43+
display: "flex",
44+
justifyContent: "center",
45+
gap: "1em",
46+
},
47+
confirmBtn: {
48+
display: "flex",
49+
alignItems: "center",
50+
backgroundColor: "#22c55e",
51+
color: "#fff",
52+
border: "none",
53+
padding: "10px 18px",
54+
borderRadius: "5px",
55+
cursor: "pointer",
56+
fontWeight: "bold",
57+
fontSize: "1em",
58+
},
59+
deleteBtn: {
60+
display: "flex",
61+
alignItems: "center",
62+
backgroundColor: "#ef4444",
63+
color: "#fff",
64+
border: "none",
65+
padding: "10px 18px",
66+
borderRadius: "5px",
67+
cursor: "pointer",
68+
fontWeight: "bold",
69+
fontSize: "1em",
70+
},
71+
disabledBtn: {
72+
display: "flex",
73+
alignItems: "center",
74+
backgroundColor: "#9ca3af",
75+
color: "#fff",
76+
border: "none",
77+
padding: "10px 18px",
78+
borderRadius: "5px",
79+
cursor: "not-allowed",
80+
fontWeight: "bold",
81+
fontSize: "1em",
82+
opacity: 0.6,
83+
},
84+
cancelBtn: {
85+
backgroundColor: "#9ca3af",
86+
color: "#fff",
87+
border: "none",
88+
padding: "10px 18px",
89+
borderRadius: "5px",
90+
cursor: "pointer",
91+
fontWeight: "bold",
92+
fontSize: "1em",
93+
},
94+
cancelBtnDisabled: {
95+
backgroundColor: "#d1d5db",
96+
color: "#6b7280",
97+
border: "none",
98+
padding: "10px 18px",
99+
borderRadius: "5px",
100+
cursor: "not-allowed",
101+
fontWeight: "bold",
102+
fontSize: "1em",
103+
opacity: 0.6,
104+
},
105+
};
106+
107+
const ConfirmDialog = ({ isOpen, type, onConfirm, onCancel, isLoading = false }) => {
108+
if (!isOpen) return null;
109+
110+
const isDelete = type === "delete";
111+
112+
const message = isDelete
113+
? "Do you want to permanently delete this file? This action cannot be undone."
114+
: "Do you want to verify this file? Once verified, it will be visible to all users.";
115+
116+
const getButtonStyle = () => {
117+
if (isLoading) return styles.disabledBtn;
118+
return isDelete ? styles.deleteBtn : styles.confirmBtn;
119+
};
120+
121+
const getButtonText = () => {
122+
if (isLoading) {
123+
return isDelete ? "Deleting..." : "Verifying...";
124+
}
125+
return isDelete ? "Delete" : "Verify";
126+
};
127+
128+
return (
129+
<div style={styles.overlay}>
130+
<div style={styles.dialog}>
131+
<img
132+
src={isDelete ? cross : tick}
133+
alt={isDelete ? "Delete" : "Verify"}
134+
style={styles.iconImage}
135+
/>
136+
<h3 style={styles.heading}>Are you sure?</h3>
137+
<p style={styles.message}>{message}</p>
138+
<div style={styles.buttonGroup}>
139+
<button style={getButtonStyle()} onClick={onConfirm} disabled={isLoading}>
140+
{getButtonText()}
141+
</button>
142+
<button
143+
style={isLoading ? styles.cancelBtnDisabled : styles.cancelBtn}
144+
onClick={onCancel}
145+
disabled={isLoading}
146+
>
147+
Cancel
148+
</button>
149+
</div>
150+
</div>
151+
</div>
152+
);
153+
};
154+
155+
export default ConfirmDialog;
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,87 @@
11
import "./styles.scss";
22
import Button from "./Buttons";
3+
import { toast } from "react-toastify";
34
import date from "date-and-time";
5+
import { verifyFile, unverifyFile } from "../../../../../api/File";
6+
import { useState } from "react";
7+
import ConfirmDialog from "./ConfirmDialog";
8+
49
export default function ContributionCard(props) {
10+
const [showDialog, setShowDialog] = useState(false);
11+
const [dialogType, setDialogType] = useState("verify");
12+
const [onConfirmAction, setOnConfirmAction] = useState(() => () => {});
13+
const handleVerify = async () => {
14+
setDialogType("verify");
15+
setOnConfirmAction(() => async () => {
16+
try {
17+
//console.log("Verifying file:", props?.file?._id);
18+
await verifyFile(props?.file?._id);
19+
props.verify();
20+
toast.success("File verified!");
21+
} catch (err) {
22+
console.error("Error verifying:", err);
23+
toast.error("Failed to verify file.");
24+
} finally {
25+
setShowDialog(false);
26+
}
27+
});
28+
setShowDialog(true);
29+
};
30+
31+
const handleUnverify = async () => {
32+
setDialogType("delete");
33+
setOnConfirmAction(() => async () => {
34+
try {
35+
await unverifyFile(props?.file?._id, props?.file?.fileId, props.parentFolder);
36+
props.unverify();
37+
toast.success("File deleted!");
38+
} catch (err) {
39+
console.error("Error deleting:", err);
40+
toast.error("Failed to delete file.");
41+
} finally {
42+
setShowDialog(false);
43+
}
44+
});
45+
setShowDialog(true);
46+
};
47+
548
const now = new Date(props.uploadDate);
649
const pattern = date.compile(`DD MMM YYYY hh:mm A`);
750
const finalDate = date.format(now, pattern);
851
return (
952
<div className="main_card">
1053
<div className="path">
1154
<p>{finalDate}</p>
12-
<p>
13-
{props.courseCode}
14-
</p>
55+
<p>{props.courseCode}</p>
1556
</div>
16-
<p className="content">{props.content}</p>
17-
<div className="btn">
18-
<Button text={props.isApproved === true ? "APPROVED" : "PENDING"} />
57+
<p className="content">
58+
<a className="file-link" href={props?.file?.webUrl} target="_blank">
59+
{props?.file?.name}
60+
</a>
61+
</p>
62+
63+
<div>
64+
{props.isBR ? (
65+
<div className="br_btn">
66+
<div className="btn approve">
67+
<Button text="APPROVE" onClick={handleVerify} />
68+
</div>
69+
<div className="btn delete">
70+
<Button text="DELETE" onClick={handleUnverify} />
71+
</div>
72+
</div>
73+
) : (
74+
<div className="btn approve">
75+
<Button text={props?.file?.isVerified === true ? "APPROVED" : "PENDING"} />
76+
</div>
77+
)}
1978
</div>
79+
<ConfirmDialog
80+
isOpen={showDialog}
81+
type={dialogType}
82+
onConfirm={onConfirmAction}
83+
onCancel={() => setShowDialog(false)}
84+
/>
2085
</div>
2186
);
2287
}

client/src/screens/profile.js/components/Contri_section/ContributionCard/styles.scss

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,21 @@
77
align-items: center;
88
margin-bottom: 20px;
99

10+
.br_btn {
11+
display: flex;
12+
flex-direction: row;
13+
gap: 10px;
14+
}
15+
16+
.file-link {
17+
text-decoration: none;
18+
color: black;
19+
}
20+
21+
.file-link:hover {
22+
color: blue;
23+
}
24+
1025
.path {
1126
display: flex;
1227
flex-direction: column;
@@ -28,7 +43,10 @@
2843
.content {
2944
justify-content: start;
3045
align-self: flex-start;
31-
width: 50%;
46+
width: 400px;
47+
white-space: nowrap;
48+
overflow: hidden;
49+
text-overflow: ellipsis;
3250
margin: 0px 8px 0px 8px;
3351
}
3452
}
@@ -130,4 +148,4 @@
130148
font-size: 0.8rem;
131149
}
132150
}
133-
}
151+
}

0 commit comments

Comments
 (0)