Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revamped student issue details styling #107

Merged
merged 5 commits into from
Oct 26, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion front-end/src/App.js
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import "./App.css";
import StudentDashboard from "./layouts/StudentDashboard/StudentDashboard";
import IssueDetails from "./components/student/StudentIssueOverlay/IssueDetails";
import IssueDetails from "./components/student/StudentIssueOverlay/DesktopIssueDetails";
import LoginPage from "./layouts/LoginPage/LoginPage.js";
import AdminDashboard from "./layouts/AdminDashboard/AdminDashboard";

Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
@import url("../../../assets/styles.css");

.student-issue-view {
font-family: var(--primary-font);
color: var(--text);
text-align: left;
}

.student-issue-view>h2 {
margin: 30px 0 20px 30px;
width: 90%;
font-size: 25px;
}

.student-issue-view .issue-content {
display: flex;
}

.student-issue-view .leftside-section {
flex: 4;
}

.student-issue-view .rightside-section {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
margin-top: 30px;
padding-bottom: 5px;
}


.student-issue-view .issue-history-section {
margin: 0 30px;
}

.student-issue-view .issue-history-and-status {
display: flex;
justify-content: space-between;
align-items: center;
}

.student-issue-view .issue-history-and-status>h3 {
font-size: 21px;
margin: 0px;
}

.student-issue-view .issue-status-box {
padding: 10px 13px;
border-radius: 5px;
}

.student-issue-view .history-updates {
height: 300px;
background-color: rgb(245, 248, 250);
border: 1.5px solid rgb(216, 222, 227);
/* box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1); */
overflow-y: scroll;
margin-top: 15px;
border-radius: 2px;
}

.student-issue-view .history-updates>.update {
margin: 20px 20px 25px 20px;
}

.student-issue-view .history-updates>.update>h4 {
margin: 0;
}

.student-issue-view .history-updates>.update>p {
background-color: #fff;
margin-top: 10px;
padding: 15px;
border-radius: 3px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.student-issue-view .add-comment>h3 {
margin: 30px 0 10px 0;
}

.student-issue-view .comment-input {
min-height: 80px;
width: 97%;
resize: vertical;
padding: 10px;
font-family: var(--primary-font);
border-radius: 3px;
border: 1px solid var(--primary);
font-size: 17px;
}

.student-issue-view .comment-input:focus {
outline: 1px solid var(--accent);
}

.student-issue-view .fix-add-button {
position: relative;
width: 100%;
}

.student-issue-view .submit-comment-button {
position: absolute;
bottom: 15px;
right: 30px;
}

.student-issue-view .rightside-section>.departments-tagged {
margin-top: 50px;

}

.student-issue-view .department-pill {
padding: 5px 10px;
border-radius: 15px;
width: fit-content;
font-size: 13px;
background-color: rgba(131, 84, 219, 0.212);
/* border: 1px solid rgba(131, 84, 219, 0.782); */
font-weight: bold;
color: rgb(131, 84, 219);
margin: 10px 0 0 2px;

}

.student-issue-view .attachment-box,
.student-issue-view .department-box {
list-style-type: none;
padding: 0;
}

.issue-buttons,
.student-issue-view .submit-comment-button {
background: var(--primary);
color: var(--background);
padding: 10px 15px;
border: none;
border-radius: 5px;
cursor: pointer;
margin-top: 10px;
font-family: var(--primary-font);

}

.closeButton {
position: absolute;
top: 20px;
right: 20px;
z-index: 10;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
import { useState, useEffect } from 'react';
import axios from 'axios';
import './DesktopIssueDetails.css';

const DesktopIssueDetails = ({ index }) => {
const [issue, setIssue] = useState(null);
const [comment, setComment] = useState('');
const [comments, setComments] = useState([]); // Assuming comments is an array

const handleCommentChange = (event) => {
setComment(event.target.value);
};

const submitComment = async () => {
if (comment.trim()) {
try {
const response = await axios.post('/api/comments', { comment });
console.log('Comment submitted successfully:', response.data);
// You can add more logic here depending on your needs
// For example, clear the comment field or update the UI to show the new comment
setComment('');
// Update the UI to show the new comment
// Assuming response.data contains the new comment object
setComments([...comments, response.data]);
} catch (error) {
console.error('Error submitting comment:', error.response ? error.response.data : error.message);
// Handle the error accordingly
}
} else {
console.error('Comment cannot be empty');
// You might want to show a user-friendly error message here
}
};

// Might change implementation to passing data by props from the previous page
useEffect(() => {
const apiUrl = "https://hasiburratul.github.io/mock-api/MOCK_DATA.json";
fetch(apiUrl)
.then(response => response.json())
.then(data => {
const specificIssue = data[parseInt(index - 1)];
setIssue(specificIssue);
})
.catch(error => {
console.error("Error fetching the issue data: ", error);
});
}, [index]);

const reopenIssue = () => {
setIssue({ ...issue, currentStatus: 'Open' });
};

const acceptResolution = () => {
setIssue({ ...issue, currentStatus: 'Resolved' });
// Since the issue status is already 'Resolved', no need to change it.
};

if (!issue) {
return <p>Loading issue data...</p>;
}

const issueUpdates = [
issue.description,
issue.description,
issue.description,
issue.description
// just replicated issues for styling updates
];

// Converts a department value to its display name
const mapDepartmentToDisplayName = (departmentValue) => {
switch (departmentValue) {
case "IT":
return "IT";
case "Admin":
return "Admin";
case "Library":
return "Library";
case "Facilities":
return "Facilities";
case "Registrar":
return "Registrar";
case "Health":
return "Health Center";
case "Finance":
return "Student Finance";
case "GlobalEd":
return "Global Education";
case "ResEd":
return "Residential Education";
case "CDC":
return "Career Development Center";
default:
return departmentValue;
}
};

const getStatusClass = (status) => {
switch (status) {
case 'Action Required':
return 'status-action-required';
case 'Resolved':
return 'status-closed';
case 'In Progress':
return 'status-in-progress';
case 'Open':
return 'status-open';
default:
return '';
}
};
// hardcoded attachments for testing
issue.attachments = [
"attachment 1",
"attachment 2",
"attachment 3"
];
return (

<div className="student-issue-view">
{/* {renderIssueOverlay()} */}
<h2>{issue.title}</h2>
<div className="issue-content">

<div className='leftside-section'>
<div className="issue-history-section">
<div className='issue-history-and-status'>
<h3>Issue History</h3>
<span className={`issue-status-box ${getStatusClass(issue.currentStatus)}`}>{issue.currentStatus}</span>
</div>

<div className='history-updates'>
{issueUpdates.map((update, index) => (
<div key={index} className="update">
<h4>Update {issueUpdates.length - index}</h4>
<p>{update}</p>
</div>
))}
</div>

<div className="add-comment">
<h3>Add a Comment</h3>
<div className='fix-add-button'>
{/* the above div is just for the purpose of styling */}
{/* it is essential to make sure the button stays fixed in diverse screen sizes */}
<textarea className='comment-input'
value={comment}
onChange={handleCommentChange}
placeholder="Your comment..."
></textarea>
<button className="submit-comment-button" onClick={submitComment}>Add</button>
</div>

</div>
</div>
</div>
<div className='rightside-section'>
{/* Right side goes here */}
<div >
{/* use of the outer div is just for consistent styling regardless of the number of attachments */}
{/* it makes sure that the footer buttons always stay at the bottom */}
<div className="departments-tagged">
<h3>Departments Tagged</h3>
<ul className='department-box'>
{issue.departments.map((dept, index) => <li className='issue-li department-pill' key={index}>{mapDepartmentToDisplayName(dept)}</li>)}
</ul>
</div>
{issue.attachments && issue.attachments.length > 0 && (
<div className="attachments">
<h3>Attachments</h3>
<ul className='attachment-box'>
{issue.attachments.map((attach, index) => <li className='issue-li' key={index}>{attach}</li>)}
</ul>
</div>
)}
</div>
<div className="footer-buttons">
{issue.currentStatus === 'Resolved' && (
<button className="issue-buttons" onClick={reopenIssue}>Reopen Issue</button>
)}
{issue.currentStatus === 'Action Required' && (
<button className="issue-buttons" onClick={acceptResolution}>Accept Resolution</button>
)}
</div>
</div>
</div>

{comments && comments.length > 0 && (
<div className="comments-section">
<h3>Comments</h3>
{comments.map((comment, index) => (
<div key={index} className="comment">
<p>{comment.text /* Assuming comment object has a text property */}</p>
</div>
))}
</div>
)}

</div>
);
};

export default DesktopIssueDetails;
154 changes: 0 additions & 154 deletions front-end/src/components/student/StudentIssueOverlay/IssueDetails.css

This file was deleted.

200 changes: 0 additions & 200 deletions front-end/src/components/student/StudentIssueOverlay/IssueDetails.js

This file was deleted.

24 changes: 17 additions & 7 deletions front-end/src/layouts/StudentDashboard/StudentDashboard.css
Original file line number Diff line number Diff line change
@@ -12,7 +12,8 @@
display: flex;
flex-direction: column;
min-height: 100vh;
transition: filter 0.3s ease; /* Smooth transition for the blur effect */
transition: filter 0.3s ease;
/* Smooth transition for the blur effect */
}

.h2-student-dashboard {
@@ -118,6 +119,7 @@
border-radius: 15px;
font-size: 12px;
background-color: rgba(131, 84, 219, 0.212);
/* border: 1px solid rgba(131, 84, 219, 0.782); */
font-weight: bold;
color: rgb(131, 84, 219);
margin: 2px;
@@ -215,17 +217,25 @@

.issueOverlay {
position: absolute;
right: 12.5%;
top: 6.5%;
width: 75%;
padding: 10px;
/* centering the div */
right: 0;
top: 0;
left: 0;
bottom: 0;
margin: auto;

width: 95%;
height: 87%;
/* padding: 10px; */
background-color: var(--background);
border-radius: 5px;
z-index: 1001;
display: flex;
/* display: flex;
flex-direction: column;
align-items: center;
align-items: center; */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
overflow: hidden;
overflow-y: scroll;
}

.pagination button:hover {
132 changes: 66 additions & 66 deletions front-end/src/layouts/StudentDashboard/StudentDashboard.js
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ import { Link } from "react-router-dom";
import "./StudentDashboard.css";
import StudentNavbar from "../../components/student/StudentNavbar/StudentNavbar";
import StudentViewFilter from "../../components/student/StudentViewFilter/StudentViewFilter";
import DesktopIssueDetails from "../../components/student/StudentIssueOverlay/IssueDetails";
import DesktopIssueDetails from "../../components/student/StudentIssueOverlay/DesktopIssueDetails";

const StudentDashboard = () => {
// State initialization for holding requests and their display variant
@@ -88,26 +88,26 @@ const StudentDashboard = () => {

// Function to close the overlay
const closeIssueOverlay = () => {
setIsIssueOverlayOpen(false);
setIsIssueOverlayOpen(false);
};

// Add event listener to handle clicks outside the overlay
useEffect(() => {
const handleOutsideClick = (e) => {
if (overlayRef.current && !overlayRef.current.contains(e.target)) {
closeIssueOverlay();
}
};

if (isIssueOverlayOpen) {
document.addEventListener('mousedown', handleOutsideClick);
} else {
document.removeEventListener('mousedown', handleOutsideClick);
const handleOutsideClick = (e) => {
if (overlayRef.current && !overlayRef.current.contains(e.target)) {
closeIssueOverlay();
}
};

if (isIssueOverlayOpen) {
document.addEventListener('mousedown', handleOutsideClick);
} else {
document.removeEventListener('mousedown', handleOutsideClick);
}

return () => {
document.removeEventListener('mousedown', handleOutsideClick);
};
return () => {
document.removeEventListener('mousedown', handleOutsideClick);
};
}, [isIssueOverlayOpen]);

const getStatusClass = (status) => {
@@ -175,17 +175,17 @@ const StudentDashboard = () => {
return (
<tr key={index}>
<td className="title-cell" onClick={() => {
setIsIssueOverlayOpen(true);
setRequest(request.index);
}}>
{request.title}
setIsIssueOverlayOpen(true);
setRequest(request.index);
}}>
{request.title}
</td>

<td className="description-cell" onClick={() => {
setIsIssueOverlayOpen(true);
setRequest(request.index);
}}>
{truncatedDescription}
setIsIssueOverlayOpen(true);
setRequest(request.index);
}}>
{truncatedDescription}
</td>

<td className="departments-cell">
@@ -413,54 +413,54 @@ const StudentDashboard = () => {

return (
<>
<div className={`requests ${isIssueOverlayOpen ? 'blur-background' : ''}`}>

<StudentNavbar studentName={studentName} />

<h2 className="h2-student-dashboard">Your Requests</h2>
<div className="actions">
<div className="search-bar">
<input
className="input-student-dashboard"
type="text"
placeholder="Search"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
onKeyDown={handleKeyDown}
/>
<button className="button-student-dashboard" onClick={handleSearch}>Search</button>
<div className={`requests ${isIssueOverlayOpen ? 'blur-background' : ''}`}>

<StudentNavbar studentName={studentName} />

<h2 className="h2-student-dashboard">Your Requests</h2>
<div className="actions">
<div className="search-bar">
<input
className="input-student-dashboard"
type="text"
placeholder="Search"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
onKeyDown={handleKeyDown}
/>
<button className="button-student-dashboard" onClick={handleSearch}>Search</button>
</div>

<StudentViewFilter filterHandler={handleFilterByDepartment} selectedOption={selectedDepartment} options={departmentOptions} />
<StudentViewFilter filterHandler={handleFilterByStatus} selectedOption={selectedStatus} options={statusOptions} />

<div className="create-request-button">
<button className="button-student-dashboard" onClick={handleCreateRequest}>Create Request +</button>
</div>
</div>

<StudentViewFilter filterHandler={handleFilterByDepartment} selectedOption={selectedDepartment} options={departmentOptions} />
<StudentViewFilter filterHandler={handleFilterByStatus} selectedOption={selectedStatus} options={statusOptions} />

<div className="create-request-button">
<button className="button-student-dashboard" onClick={handleCreateRequest}>Create Request +</button>
<div className="table">
<table className="table-student-dashboard">
{renderTableHeader()}
<tbody>{renderRequests()}</tbody>
</table>
</div>
<div className="pagination">
<div className="pagination-box">{renderPagination()}</div>
</div>
<div className="footer-student-dashboard">
<p>New York University Abu Dhabi</p>
</div>
</div>
{/* The Overlay popup is triggered by clicking on the title or description */}
{/* It is only for Desktop view for now */}
{isIssueOverlayOpen && (
<div className="issueOverlay" ref={overlayRef}>
<button className="closeButton issue-buttons" onClick={closeIssueOverlay}>X</button>

<div className="table">
<table className="table-student-dashboard">
{renderTableHeader()}
<tbody>{renderRequests()}</tbody>
</table>
</div>
<div className="pagination">
<div className="pagination-box">{renderPagination()}</div>
</div>
<div className="footer-student-dashboard">
<p>New York University Abu Dhabi</p>
</div>
</div>
{/* The Overlay popup is triggered by clicking on the title or description */}
{/* It is only for Desktop view for now */}
{isIssueOverlayOpen && (
<div className="issueOverlay" ref={overlayRef}>
<button className="closeButton issue-buttons" onClick={closeIssueOverlay}>X</button>

<DesktopIssueDetails index={request} />
</div>
)}
<DesktopIssueDetails index={request} />
</div>
)}
</>
);
};