Skip to content

Commit 6cbeeb9

Browse files
committed
Added Copying Animator and ISP
1 parent d9d390d commit 6cbeeb9

File tree

6 files changed

+139
-59
lines changed

6 files changed

+139
-59
lines changed

public/assets/images/assign.png

33.4 KB
Loading

public/assets/images/paste.png

9.98 KB
Loading

public/assets/images/pencil.png

9.56 KB
Loading

public/assets/images/remove.png

16.5 KB
Loading

src/pages/Courses/CourseColumns.tsx

Lines changed: 112 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,147 @@
11
import { createColumnHelper, Row } from "@tanstack/react-table";
2-
import { Button } from "react-bootstrap";
3-
import { BsPencilFill, BsPersonXFill } from "react-icons/bs";
4-
import { MdContentCopy, MdDelete } from "react-icons/md";
2+
import { Button, Tooltip, OverlayTrigger, Badge } from "react-bootstrap";
53
import { ICourseResponse as ICourse } from "../../utils/interfaces";
64

75
/**
8-
* @author Atharva Thorve, on December, 2023
9-
* @author Mrityunjay Joshi on December, 2023
10-
*/
6+
* Author: Suraj Raghu Kumar on October 27, 2023
7+
Author: Yuktasree Muppala on October 27, 2023
8+
Author: Harvardhan Patil on October 27, 2023
9+
*/
1110

12-
// Course Columns Configuration: Defines the columns for the courses table
1311
type Fn = (row: Row<ICourse>) => void;
12+
1413
const columnHelper = createColumnHelper<ICourse>();
15-
export const courseColumns = (handleEdit: Fn, handleDelete: Fn, handleTA: Fn, handleCopy: Fn) => [
16-
// Column for the course name
14+
15+
export const courseColumns = (
16+
handleEdit: Fn,
17+
handleDelete: Fn,
18+
handleTA: Fn,
19+
handleCopy: Fn,
20+
21+
) => [
1722
columnHelper.accessor("name", {
1823
id: "name",
19-
header: "Name",
24+
header: () => <span style={{ fontWeight: 'bold', color: '#000000', fontSize: '1.17em' }}>Course Name</span>,
25+
cell: (info) => (
26+
<div className="d-flex justify-content-start align-items-center" style={{ fontSize: '1.1em', padding: '8px 0' }}>
27+
<span style={{ color: '#000000' }}>{info.getValue()}</span>
28+
</div>
29+
),
2030
enableSorting: true,
2131
enableColumnFilter: true,
2232
enableGlobalFilter: false,
2333
}),
34+
2435

25-
// Column for the institution name
2636
columnHelper.accessor("institution.name", {
2737
id: "institution",
28-
header: "Institution",
38+
header: () => <span style={{ fontWeight: 'bold', color: '#000000', fontSize: '1.17em' }}>Institution</span>,
2939
enableSorting: true,
3040
enableMultiSort: true,
3141
enableGlobalFilter: false,
42+
cell: (info) => (
43+
<div className="d-flex justify-content-start align-items-center" style={{ fontSize: '1.17em', padding: '8px 0' }}>
44+
<span>{info.getValue() || <Badge bg="secondary">Not Available</Badge>}</span>
45+
</div>
46+
),
3247
}),
3348

34-
// Column for the creation date
35-
columnHelper.accessor("created_at", {
36-
header: "Creation Date",
49+
columnHelper.accessor("instructor.name", {
50+
id: "instructor",
51+
header: () => <span style={{ fontWeight: 'bold', color: '#000000', fontSize: '1.17em' }}>Instructor</span>,
3752
enableSorting: true,
38-
enableColumnFilter: false,
53+
enableColumnFilter: true,
3954
enableGlobalFilter: false,
55+
cell: ({ row }) => {
56+
const instructor = row.original.instructor;
57+
return (
58+
<div className="d-flex justify-content-start align-items-center" style={{ fontSize: '1.17em',
59+
padding: '8px 0' }}>
60+
<span>
61+
{instructor && instructor.name ? (
62+
instructor.name
63+
) : (
64+
<Badge bg="danger">Unassigned</Badge>
65+
)}
66+
</span>
67+
</div>
68+
);
69+
},
70+
}),
71+
72+
columnHelper.accessor("created_at", {
73+
header: () => <span style={{ fontWeight: 'bold', color: '#000000', fontSize: '1.17em' }}>Creation Date</span>,
74+
enableSorting: true,
75+
enableColumnFilter: true,
76+
enableGlobalFilter: true,
77+
cell: (info) => (
78+
<div className="d-flex justify-content-start align-items-center" style={{ fontSize: '1.17em', padding: '8px 0' }}>
79+
<span>{new Date(info.getValue()).toLocaleDateString() || <Badge bg="secondary">N/A</Badge>}</span>
80+
</div>
81+
),
4082
}),
4183

42-
// Column for the last updated date
4384
columnHelper.accessor("updated_at", {
44-
header: "Updated Date",
85+
header: () => <span style={{ fontWeight: 'bold', color: '#000000', fontSize: '1.17em' }}>Updated Date</span>,
4586
enableSorting: true,
46-
enableColumnFilter: false,
47-
enableGlobalFilter: false,
87+
enableColumnFilter: true,
88+
enableGlobalFilter: true,
89+
cell: (info) => (
90+
<div className="d-flex justify-content-start align-items-center" style={{ fontSize: '1.17em', padding: '8px 0' }}>
91+
<span>{new Date(info.getValue()).toLocaleDateString() || <Badge bg="secondary">N/A</Badge>}</span>
92+
</div>
93+
),
4894
}),
4995

50-
// Actions column with edit, delete, TA, and copy buttons
5196
columnHelper.display({
5297
id: "actions",
53-
header: "Actions",
98+
header: () => <span style={{ fontWeight: 'bold', color: '#000000', fontSize: '1.17em' }}>Actions</span>,
5499
cell: ({ row }) => (
55-
<>
56-
<Button variant="outline-warning" size="sm" onClick={() => handleEdit(row)}>
57-
<BsPencilFill />
58-
</Button>
59-
<Button
60-
variant="outline-danger"
61-
size="sm"
62-
className="ms-sm-2"
63-
onClick={() => handleDelete(row)}
64-
>
65-
<MdDelete />
66-
</Button>
67-
<Button variant="outline-info" size="sm" className="ms-sm-2" onClick={() => handleTA(row)}>
68-
<BsPersonXFill />
69-
</Button>
70-
<Button
71-
variant="outline-primary"
72-
size="sm"
73-
className="ms-sm-2"
74-
onClick={() => handleCopy(row)}
75-
>
76-
<MdContentCopy />
77-
</Button>
78-
</>
100+
<div className="d-flex justify-content-around" style={{ fontSize: '1.17em', padding: '8px 0' }}>
101+
<OverlayTrigger overlay={<Tooltip>Edit Course</Tooltip>}>
102+
<Button
103+
variant="link"
104+
onClick={() => handleEdit(row)}
105+
aria-label="Edit Course"
106+
style={{ padding: '0', margin: '0 8px' }} // Add margin for spacing
107+
>
108+
<img src={process.env.PUBLIC_URL + '/assets/images/pencil.png'} alt="Edit" style={{ width: '25px', height: '20px' }} />
109+
</Button>
110+
</OverlayTrigger>
111+
112+
<OverlayTrigger overlay={<Tooltip>Delete Course</Tooltip>}>
113+
<Button
114+
variant="link"
115+
onClick={() => handleDelete(row)}
116+
aria-label="Delete Course"
117+
style={{ padding: '0', margin: '0 8px' }}
118+
>
119+
<img src={process.env.PUBLIC_URL + '/assets/images/remove.png'} alt="Delete" style={{ width: '25px', height: '20px' }} />
120+
</Button>
121+
</OverlayTrigger>
122+
123+
<OverlayTrigger overlay={<Tooltip>Assign TA</Tooltip>}>
124+
<Button
125+
variant="link"
126+
onClick={() => handleTA(row)}
127+
aria-label="Assign TA"
128+
style={{ padding: '0', margin: '0 8px' }}
129+
>
130+
<img src={process.env.PUBLIC_URL + '/assets/images/assign.png'} alt="Assign TA" style={{ width: '35px', height: '25px' }} />
131+
</Button>
132+
</OverlayTrigger>
133+
134+
<OverlayTrigger overlay={<Tooltip>Copy Course</Tooltip>}>
135+
<Button
136+
variant="link"
137+
onClick={() => handleCopy(row)}
138+
aria-label="Copy Course"
139+
style={{ padding: '0', margin: '0 8px' }}
140+
>
141+
<img src={'/assets/images/paste.png'} alt="Copy" style={{ width: '35px', height: '25px' }} />
142+
</Button>
143+
</OverlayTrigger>
144+
</div>
79145
),
80146
}),
81147
];

src/pages/Courses/CourseCopy.tsx

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import React, { useEffect, useState } from "react";
2-
import { Button, Modal } from "react-bootstrap";
2+
import { Button, Modal, Spinner, Alert } from "react-bootstrap";
33
import { useDispatch } from "react-redux";
44
import { alertActions } from "store/slices/alertSlice";
55
import { HttpMethod } from "utils/httpMethods";
66
import useAPI from "../../hooks/useAPI";
77
import { ICourseResponse as ICourse } from "../../utils/interfaces";
88

99
/**
10-
* @author Atharva Thorve, on December, 2023
11-
* @author Mrityunjay Joshi on December, 2023
10+
* @author Suraj Raghu Kumar, on Oct, 2024
11+
* @author Yuktasree Muppala on Oct, 2024
12+
* @author Harvardhan Patil on Oct, 2024
1213
*/
1314

1415
// CopyCourse Component: Modal for copying a course.
@@ -20,17 +21,24 @@ interface ICopyCourse {
2021

2122
const CopyCourse: React.FC<ICopyCourse> = ({ courseData, onClose }) => {
2223
// State and hook declarations
23-
const { data: copiedCourse, error: courseError, sendRequest: CopyCourse } = useAPI();
24+
const { data: copiedCourse, error: courseError, sendRequest: copyCourseRequest } = useAPI();
2425
const [show, setShow] = useState<boolean>(true);
26+
const [isCopying, setIsCopying] = useState<boolean>(false); // State to track copying process
2527
const dispatch = useDispatch();
28+
const courseId = courseData.id;
2629

2730
// Function to initiate the course copy process
28-
const copyHandler = () =>
29-
CopyCourse({ url: `/courses/${courseData.id}/copy`, method: HttpMethod.GET });
31+
const copyHandler = () => {
32+
setIsCopying(true); // Set copying state to true
33+
copyCourseRequest({ url: `/courses/${courseId}/copy`, method: HttpMethod.GET });//Applying Interface Segregation principle to use only courseId instead of the whole object
34+
};
3035

3136
// Show error if any
3237
useEffect(() => {
33-
if (courseError) dispatch(alertActions.showAlert({ variant: "danger", message: courseError }));
38+
if (courseError) {
39+
dispatch(alertActions.showAlert({ variant: "danger", message: courseError }));
40+
setIsCopying(false); // Reset copying state on error
41+
}
3442
}, [courseError, dispatch]);
3543

3644
// Close modal if course is copied
@@ -55,21 +63,27 @@ const CopyCourse: React.FC<ICopyCourse> = ({ courseData, onClose }) => {
5563

5664
// Render the CopyCourse modal
5765
return (
58-
<Modal show={show} onHide={closeHandler}>
59-
<Modal.Header closeButton>
66+
<Modal show={show} onHide={closeHandler} centered>
67+
<Modal.Header closeButton className="bg-primary text-white">
6068
<Modal.Title>Copy Course</Modal.Title>
6169
</Modal.Header>
62-
<Modal.Body>
70+
<Modal.Body className="text-center">
6371
<p>
6472
Are you sure you want to copy course <b>{courseData.name}?</b>
6573
</p>
74+
{isCopying && <Spinner animation="border" variant="primary" />}
75+
{courseError && <Alert variant="danger">{courseError}</Alert>} {/* Display error message */}
6676
</Modal.Body>
67-
<Modal.Footer>
77+
<Modal.Footer className="d-flex justify-content-center">
6878
<Button variant="outline-secondary" onClick={closeHandler}>
6979
Cancel
7080
</Button>
71-
<Button variant="outline-primary" onClick={copyHandler}>
72-
Copy
81+
<Button
82+
variant="primary"
83+
onClick={copyHandler}
84+
disabled={isCopying} // Disable button while copying
85+
>
86+
{isCopying ? "Copying..." : "Copy"}
7387
</Button>
7488
</Modal.Footer>
7589
</Modal>

0 commit comments

Comments
 (0)