Skip to content

Commit 06c5c43

Browse files
authored
Merge pull request #69 from Coding-Club-IITG/sanjeebani
Sanjeebani
2 parents 728797e + 525cb42 commit 06c5c43

File tree

18 files changed

+622
-91
lines changed

18 files changed

+622
-91
lines changed

CourseHub

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit d7ccac769a7556b0184e77b583f206cdd8805685

client/src/actions/filebrowser_actions.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,8 @@ export const RemoveFileFromFolder = (fileId) => ({
5656
type: "REMOVE_FILE_FROM_FOLDER",
5757
payload: fileId,
5858
});
59+
60+
export const RefreshCurrentFolder = () => ({
61+
type: "REFRESH_CURRENT_FOLDER",
62+
payload: Date.now(),
63+
});

client/src/api/Folder.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import axios from "axios";
2+
import serverRoot from "./server";
3+
4+
// Create axios instance with baseURL and withCredentials
5+
const API = axios.create({
6+
baseURL: `${serverRoot}/api`,
7+
withCredentials: true,
8+
});
9+
10+
// Attach token to every request if available (from localStorage)
11+
API.interceptors.request.use((req) => {
12+
const user = JSON.parse(localStorage.getItem("profile"));
13+
if (user) req.headers.Authorization = `Bearer ${user.token}`;
14+
return req;
15+
});
16+
17+
export const createFolder = async ({ name, course, parentFolder,childType }) => {
18+
const { data } = await API.post("/folder/create", {
19+
name,
20+
course,
21+
parentFolder,
22+
childType
23+
});
24+
return data;
25+
};
26+
27+
export const deleteFolder = async ({ folderId, parentFolderId }) => {
28+
const { data } = await API.delete(`/folder/delete`, {
29+
params: { folderId, parentFolderId },
30+
});
31+
return data;
32+
};
33+

client/src/reducers/filebrowser_reducer.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ const FileBrowserReducer = (
8181
},
8282
};
8383

84+
case "REFRESH_CURRENT_FOLDER":
85+
return {
86+
...state,
87+
refreshKey: action.payload,
88+
};
89+
8490
default:
8591
return state;
8692
}
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import React from "react";
2+
import cross from "./cross.svg";
3+
4+
const styles = {
5+
overlay: {
6+
position: "fixed",
7+
top: 0,
8+
left: 0,
9+
right: 0,
10+
bottom: 0,
11+
backgroundColor: "rgba(0, 0, 0, 0.4)",
12+
display: "flex",
13+
alignItems: "center",
14+
justifyContent: "center",
15+
zIndex: 1000,
16+
},
17+
dialog: {
18+
backgroundColor: "#fff",
19+
padding: "25px 30px",
20+
borderRadius: "8px",
21+
maxWidth: "400px",
22+
width: "90%",
23+
boxShadow: "0 4px 20px rgba(0, 0, 0, 0.2)",
24+
textAlign: "center",
25+
fontFamily: "sans-serif",
26+
},
27+
28+
iconImage: {
29+
width: "80px",
30+
height: "80px",
31+
margin: "1em",
32+
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+
deleteBtn: {
48+
display: "flex",
49+
alignItems: "center",
50+
backgroundColor: "#ef4444",
51+
color: "#fff",
52+
border: "none",
53+
padding: "10px 18px",
54+
borderRadius: "5px",
55+
cursor: "pointer",
56+
fontWeight: "bold",
57+
fontSize: "1em",
58+
},
59+
cancelBtn: {
60+
backgroundColor: "#9ca3af",
61+
color: "#fff",
62+
border: "none",
63+
padding: "10px 18px",
64+
borderRadius: "5px",
65+
cursor: "pointer",
66+
fontWeight: "bold",
67+
fontSize: "1em",
68+
},
69+
};
70+
71+
72+
const ConfirmDialog = ({ isOpen, onConfirm, onCancel }) => {
73+
if (!isOpen) return null;
74+
75+
return (
76+
<div style={styles.overlay}>
77+
<div style={styles.dialog}>
78+
<img src={cross} alt="Delete" style={styles.iconImage} />
79+
<h3 style={styles.heading}>Are you sure?</h3>
80+
<p style={styles.message}>
81+
Do you want to permanently delete this folder? This action cannot be undone.
82+
</p>
83+
<div style={styles.buttonGroup}>
84+
<button style={styles.cancelBtn} onClick={onCancel}>
85+
Cancel
86+
</button>
87+
<button style={styles.deleteBtn} onClick={onConfirm}>
88+
Delete
89+
</button>
90+
</div>
91+
</div>
92+
</div>
93+
);
94+
};
95+
96+
export { ConfirmDialog };
Lines changed: 1 addition & 0 deletions
Loading

client/src/screens/browse/components/browsefolder/index.jsx

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,39 @@
11
import "./styles.scss";
2+
import React, { useState } from "react";
23
import { useDispatch } from "react-redux";
34
import { ChangeFolder } from "../../../../actions/filebrowser_actions";
5+
import { deleteFolder } from "../../../../api/Folder";
6+
import { toast } from "react-toastify";
7+
import { RefreshCurrentFolder } from "../../../../actions/filebrowser_actions";
8+
import { ConfirmDialog } from "./confirmDialog";
49
const BrowseFolder = ({ type = "file", color, path, name, subject, folderData }) => {
510
const dispatch = useDispatch();
11+
const [showConfirm, setShowConfirm] = useState(false);
612
const onClick = (folderData) => {
713
// return;
814
dispatch(ChangeFolder(folderData));
915
};
16+
17+
const handleDelete = async (e) => {
18+
try {
19+
await deleteFolder({ folderId: folderData._id, parentFolderId: folderData.parent });
20+
toast.success("Folder deleted successfully!");
21+
dispatch(RefreshCurrentFolder());
22+
} catch (err) {
23+
console.log(err);
24+
toast.error("Failed to delete folder.");
25+
}
26+
setShowConfirm(false);
27+
};
28+
29+
const cancelDelete = () => {
30+
setShowConfirm(false);
31+
};
32+
1033
return (
11-
<div className="browse-folder" onClick={() => onClick(folderData)}>
12-
{/* {type === "folder" ? (
34+
<>
35+
<div className="browse-folder" onClick={() => onClick(folderData)}>
36+
{/* {type === "folder" ? (
1337
<svg
1438
width="200"
1539
height="175"
@@ -86,16 +110,33 @@ const BrowseFolder = ({ type = "file", color, path, name, subject, folderData })
86110
/>
87111
</svg>
88112
)} */}
89-
<div className="content">
90-
<div className="top">
91-
<p className="path">{""}</p>
92-
<p className="name">{name ? name : "Name"}</p>
93-
</div>
94-
<div className="bottom">
95-
<p className="subject">{subject ? subject.toUpperCase() : "Subject Here"}</p>
113+
<div className="content">
114+
<div className="top">
115+
<p className="path">{""}</p>
116+
<p className="name">{name ? name : "Name"}</p>
117+
<span
118+
className="delete"
119+
onClick={(e) => {
120+
e.stopPropagation();
121+
setShowConfirm(true);
122+
}}
123+
title="Delete folder"
124+
></span>
125+
</div>
126+
<div className="bottom">
127+
<p className="subject">
128+
{subject ? subject.toUpperCase() : "Subject Here"}
129+
</p>
130+
</div>
96131
</div>
97132
</div>
98-
</div>
133+
<ConfirmDialog
134+
isOpen={showConfirm}
135+
type="delete"
136+
onConfirm={handleDelete}
137+
onCancel={cancelDelete}
138+
/>
139+
</>
99140
);
100141
};
101142

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.browse-folder{
1+
.browse-folder {
22
width: 200px;
33
height: 175px;
44
margin: 10px;
@@ -8,45 +8,62 @@
88
background: url(./folder.svg), none;
99
background-position: center;
1010
background-repeat: no-repeat;
11-
&:hover{
11+
&:hover {
1212
transform: translateY(-2px);
1313
}
1414

15-
svg{
15+
svg {
1616
position: absolute;
1717
z-index: -1;
1818
}
19-
.content{
19+
.content {
2020
display: flex;
2121
flex-direction: column;
2222
justify-content: space-between;
2323
height: 100%;
24-
.top{
25-
.path{
24+
.top {
25+
position: relative;
26+
.delete {
27+
background: url(./Delete.svg), none;
28+
position: absolute;
29+
top: 5px;
30+
right: 5px;
31+
width: 20px;
32+
height: 20px;
33+
background-size: contain;
34+
background-repeat: no-repeat;
35+
background-position: center;
36+
cursor: pointer;
37+
opacity: 0;
38+
transition: opacity 0.2s ease-in-out;
39+
z-index: 3;
40+
}
41+
.path {
2642
padding: 30px 50px 0px 15px;
2743
font-size: 0.9rem;
2844
}
29-
.name{
30-
font-family: 'Bold';
45+
.name {
46+
font-family: "Bold";
3147
font-size: 1.2rem;
3248
padding: 0px 50px 0px 15px;
3349
}
34-
3550
}
36-
.bottom{
51+
.top:hover .delete {
52+
opacity: 1;
53+
}
54+
.bottom {
3755
width: 100%;
3856
text-align: right;
3957
display: flex;
4058
justify-content: right;
41-
.subject{
59+
.subject {
4260
width: 85%;
4361
text-align: right;
4462
padding: 0px 15px 20px 0px;
45-
font-family: 'Bold';
63+
font-family: "Bold";
4664
font-size: 1.2rem;
47-
color: rgba(80, 80, 80, 0.5)
65+
color: rgba(80, 80, 80, 0.5);
4866
}
4967
}
5068
}
51-
52-
}
69+
}

0 commit comments

Comments
 (0)