Skip to content

Feature/task 255: Capstone Project Management (Admin) #259

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

Merged
merged 123 commits into from
Jul 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
123 commits
Select commit Hold shift + click to select a range
3918840
feat: add Capstone Project Management page with metadata
yuhtnguyen Jul 18, 2025
f44f669
feat: initialize Capstone Project Management component
yuhtnguyen Jul 18, 2025
68c8e2d
feat: implement Capstone Project Management page with thesis data table
yuhtnguyen Jul 18, 2025
5fa439c
feat: integrate TablePagination component into ThesisTable for improv…
yuhtnguyen Jul 18, 2025
0855a35
feat: enhance ThesisTable with combined data from groups and theses, …
yuhtnguyen Jul 19, 2025
4bea550
feat: enhance Supervisor column rendering in ThesisTable for better d…
yuhtnguyen Jul 19, 2025
94aa72b
feat: refactor HomePage layout to use Space component
yuhtnguyen Jul 19, 2025
789c352
feat: update description in Capstone Project Management header for cl…
yuhtnguyen Jul 19, 2025
96daaa1
feat: remove badgeText from Header in Capstone Project Management for…
yuhtnguyen Jul 19, 2025
0fb02e9
feat: improve ThesisTable layout by adjusting search and filter compo…
yuhtnguyen Jul 19, 2025
351f338
feat: update ThesisTable export button text for clarity and adjust co…
yuhtnguyen Jul 19, 2025
56abd1a
feat: enhance ThesisTable data handling and improve rendering for bet…
yuhtnguyen Jul 19, 2025
e1492bf
feat: refactor ThesisTable data structure to improve rowSpan handling…
yuhtnguyen Jul 19, 2025
ed510c4
feat: enhance ThesisTable with group row styling for improved visual …
yuhtnguyen Jul 19, 2025
7498cf7
feat: remove redundant major from ThesisTable data for clarity
yuhtnguyen Jul 19, 2025
d10d39d
feat: remove mock review groups for 'Review 3' to streamline data str…
yuhtnguyen Jul 19, 2025
3e73dc7
Merge branch 'dev' into feature/task-255_thuy
yuhtnguyen Jul 19, 2025
2e83b18
feat: enhance ThesisTable to calculate rowSpan for major and improve …
yuhtnguyen Jul 19, 2025
c0ba57d
fix: improve supervisor rendering logic in ThesisTable for better key…
yuhtnguyen Jul 19, 2025
1a76465
refactor: clean up comments in ThesisTableData type for clarity
yuhtnguyen Jul 19, 2025
d7df288
refactor: remove unnecessary comments for rowSpan initialization in T…
yuhtnguyen Jul 19, 2025
ef1ca67
fix: remove unnecessary comment in major assignment for clarity in Th…
yuhtnguyen Jul 19, 2025
96ef773
refactor: clean up comments in FullMockGroup type for clarity
yuhtnguyen Jul 19, 2025
19e24ef
fix: update import path for ThesisTable in HomePage component
yuhtnguyen Jul 19, 2025
7824590
refactor: update ThesisTable to use structured StudentMember data typ…
yuhtnguyen Jul 19, 2025
e3c22f4
fix: update supervisors
yuhtnguyen Jul 19, 2025
7bc7962
refactor: specify ColumnsType for columns in ThesisTable
yuhtnguyen Jul 19, 2025
db2e2cf
refactor: align columns in ThesisTable and improve Student ID rendering
yuhtnguyen Jul 19, 2025
0515860
refactor: enhance rendering of Full Name and Supervisor columns for b…
yuhtnguyen Jul 19, 2025
393404e
refactor: add student and thesis count display to ThesisTable
yuhtnguyen Jul 19, 2025
95ac733
refactor: update text for student and thesis count display in ThesisT…
yuhtnguyen Jul 19, 2025
ecdd4b8
refactor: add footer text for semester information in ThesisTable
yuhtnguyen Jul 19, 2025
abe59df
refactor: update footer text for semester information in ThesisTable
yuhtnguyen Jul 19, 2025
016c8e3
refactor: replace footer div with Row and Col components for better l…
yuhtnguyen Jul 19, 2025
1461251
refactor: adjust margin for better spacing in ThesisTable and add sem…
yuhtnguyen Jul 19, 2025
3ec37a6
refactor: move semester information footer
yuhtnguyen Jul 19, 2025
aa0461e
refactor: remove unused imports and footer text from HomePage
yuhtnguyen Jul 19, 2025
21e29dc
refactor: add badgeText to Header component in HomePage
yuhtnguyen Jul 19, 2025
bde3439
refactor: remove semester information footer from ThesisTable
yuhtnguyen Jul 19, 2025
e085fd9
refactor: remove major filter functionality and unused imports in The…
yuhtnguyen Jul 19, 2025
274bfc2
refactor: enhance search functionality in ThesisTable with highlight …
yuhtnguyen Jul 19, 2025
dcdf00c
refactor: optimize filtering and rowSpan calculation in ThesisTable
yuhtnguyen Jul 19, 2025
cbfa910
refactor: remove comment from highlightText function
yuhtnguyen Jul 19, 2025
6853c3f
refactor: update column definition in ThesisTable to include custom r…
yuhtnguyen Jul 19, 2025
bab71bf
fix: issue sonar
yuhtnguyen Jul 19, 2025
54a1a66
Merge pull request #256 from 5-logic/feature/task-255_thuy
yuhtnguyen Jul 19, 2025
47ad825
fix: correct key and display name for group members in GroupInformati…
yuhtnguyen Jul 19, 2025
0d0f624
fix: replace DownloadOutlined icon with ExportOutlined in ThesisTable
yuhtnguyen Jul 19, 2025
78d174f
refactor: extract rowSpan calculation logic into a separate helper fu…
yuhtnguyen Jul 19, 2025
c40739a
feat: add MyThesisSection component for lecturer dashboard
yuhtnguyen Jul 19, 2025
ad12627
feat: add CapstoneProjectManagementPage for admin dashboard
yuhtnguyen Jul 20, 2025
944b83a
feat: add CapstoneDefenseResults component for admin dashboard
yuhtnguyen Jul 20, 2025
9d584a9
feat: implement CapstoneDefenseResults page with thesis table and imp…
yuhtnguyen Jul 20, 2025
a0e365e
feat: refactor Capstone Project Management to use GroupTable componen…
yuhtnguyen Jul 20, 2025
0da53e7
feat: update HomePage header to reflect Capstone Defense Results with…
yuhtnguyen Jul 20, 2025
f406048
feat: update CapstoneDefenseResults and CapstoneProjectManagement
yuhtnguyen Jul 20, 2025
03eac21
feat: update ThesisTable to use defenseStatus from member data and si…
yuhtnguyen Jul 20, 2025
d566791
feat: update ThesisTable to include status in search functionality an…
yuhtnguyen Jul 20, 2025
f92c546
fix: update import path for GroupTable in CapstoneDefenseResults comp…
yuhtnguyen Jul 20, 2025
603439f
feat: enhance ThesisTable to show import prompt and conditional rende…
yuhtnguyen Jul 20, 2025
a99ee5d
feat: refactor import section in ThesisTable for improved visibility …
yuhtnguyen Jul 20, 2025
1209be0
fix: correct title and description in CapstoneDefenseResults metadata
yuhtnguyen Jul 21, 2025
e074786
fix: remove unused group metadata entries for clarity and maintenance
yuhtnguyen Jul 21, 2025
6624ac7
Merge branch 'dev' into feature/task-255
yuhtnguyen Jul 21, 2025
c6cb62e
fix: update FullMockGroup structure to use string arrays for members …
yuhtnguyen Jul 21, 2025
317d684
Revert "feat: refactor import section in ThesisTable for improved vis…
yuhtnguyen Jul 21, 2025
6cad924
Revert "fix: correct title and description in CapstoneDefenseResults …
yuhtnguyen Jul 21, 2025
e71d0b8
Revert "fix: update FullMockGroup structure to use string arrays for …
yuhtnguyen Jul 21, 2025
b600d9f
fix: update title and description in CapstoneDefenseResults metadata
yuhtnguyen Jul 21, 2025
5864696
refactor: remove import functionality and simplify search interface i…
yuhtnguyen Jul 21, 2025
e337c5c
fix: remove badgeText from Header in HomePage component
yuhtnguyen Jul 21, 2025
11b04e9
fix: update button label from "Export PDF" to "Export Excel" in Thesi…
yuhtnguyen Jul 21, 2025
2507994
fix: remove badgeText from Header in CapstoneDefenseResults component
yuhtnguyen Jul 21, 2025
46d72f1
fix: add semester field and row span calculation in ThesisTable compo…
yuhtnguyen Jul 21, 2025
5555891
fix: swap 'Thesis Title' and 'Semester' columns in ThesisTable component
yuhtnguyen Jul 21, 2025
4956aa9
fix: add semester field and row span calculation in ThesisTable compo…
yuhtnguyen Jul 21, 2025
66ca114
fix: restore 'Semester' column in ThesisTable component with row span…
yuhtnguyen Jul 21, 2025
d42f0c7
fix: add semester filter to ThesisTable component for improved data v…
yuhtnguyen Jul 21, 2025
b65fe0d
fix: implement row selection and bulk status update functionality in …
yuhtnguyen Jul 21, 2025
cc3e181
fix: remove unused imports in GroupTable component
yuhtnguyen Jul 21, 2025
11c1fce
update: page for admin (done)
yuhtnguyen Jul 21, 2025
e919862
fix: rename ThesisTable to GroupManagement for consistency in compone…
yuhtnguyen Jul 21, 2025
2e5338e
fix: rename ThesisTable to GroupResults for consistency in component …
yuhtnguyen Jul 21, 2025
6070997
feat: refactor GroupManagement component and add FilterBar for improved
yuhtnguyen Jul 21, 2025
e262102
feat: implement ExtendedFilterBar component for enhanced filtering op…
yuhtnguyen Jul 21, 2025
96b18f2
fix: remove outdated comment from calculateRowSpans function
yuhtnguyen Jul 21, 2025
4de4de3
fix: remove outdated file path comment from ExtendedFilterBar component
yuhtnguyen Jul 21, 2025
d208c22
fix: remove outdated file path comment from FilterBar component
yuhtnguyen Jul 21, 2025
80b0f10
fix: remove outdated file path comment from RowSpanCell component
yuhtnguyen Jul 21, 2025
5750185
feat: add calculateRowSpans function for dynamic row span calculations
yuhtnguyen Jul 21, 2025
e9c0c70
refactor: remove FilterBar component as part of code cleanup
yuhtnguyen Jul 21, 2025
d7b5188
feat: replace ExtendedFilterBar with FilterBar component for improved…
yuhtnguyen Jul 21, 2025
9dfe0a7
fix: update import path for calculateRowSpans function in GroupManage…
yuhtnguyen Jul 21, 2025
fb228ec
fix: update import paths for FilterBar and highlightText in GroupMana…
yuhtnguyen Jul 21, 2025
c3af90d
fix: update import path for RowSpanCell in GroupManagement component
yuhtnguyen Jul 21, 2025
9588ad3
feat: implement useThesisTableData
yuhtnguyen Jul 21, 2025
fa71274
feat: add custom row selection highlighting for GroupResults table
yuhtnguyen Jul 21, 2025
e6f7691
fix: update import paths for FilterBar and useThesisTableData in Grou…
yuhtnguyen Jul 21, 2025
4522fca
refactor: remove unused GroupResultsFilterBar component
yuhtnguyen Jul 21, 2025
a4caeb4
refactor: consolidate column
yuhtnguyen Jul 21, 2025
d0acbaf
fix: update import paths for components in Columns.tsx
yuhtnguyen Jul 21, 2025
e88499b
refactor: replace useThesisTableData with useGroupTableData and updat…
yuhtnguyen Jul 21, 2025
f6a1ca5
refactor: replace useThesisTableData with useGroupTableData and updat…
yuhtnguyen Jul 21, 2025
0f0abeb
refactor: implement useDebouncedSearch hook and update related compon…
yuhtnguyen Jul 21, 2025
55d4171
fix: update import path for getColumns in GroupResults.tsx
yuhtnguyen Jul 21, 2025
10094a4
refactor: remove unnecessary comments in GroupResults.tsx
yuhtnguyen Jul 21, 2025
d73bd5f
refactor: remove unnecessary comment in FilterBar.tsx
yuhtnguyen Jul 21, 2025
ff42ac8
refactor: reorder imports in GroupManagement.tsx for better organization
yuhtnguyen Jul 21, 2025
d90be7f
fix: update showAbbreviationSupervisor
yuhtnguyen Jul 21, 2025
2b8c4f5
fix: adjust margin styles in bulk status update confirmation
yuhtnguyen Jul 21, 2025
4bc8d4c
fix: customize button styles for bulk status update confirmation
yuhtnguyen Jul 21, 2025
c5e9300
fix: initialize baseDataState and update it with new status values on…
yuhtnguyen Jul 21, 2025
65875af
fix: correct highlightText usage for abbreviation rendering in getCol…
yuhtnguyen Jul 21, 2025
aac515b
fix: correct getDisplayStatus argument usage in status column rendering
yuhtnguyen Jul 21, 2025
736302d
refactor: improve base data generation and memoization logic in useGr…
yuhtnguyen Jul 21, 2025
550059d
refactor: remove unnecessary comments in useGroupTableData
yuhtnguyen Jul 21, 2025
b111fa5
refactor: update import statement and enhance layout in GroupResults …
yuhtnguyen Jul 21, 2025
64d9564
refactor: remove CapstoneDefenseResults component and its associated …
yuhtnguyen Jul 21, 2025
c424aab
refactor: consolidate CapstoneDefenseResults component and remove Gro…
yuhtnguyen Jul 21, 2025
df7b903
refactor: enhance layout and styling in CapstoneDefenseResults component
yuhtnguyen Jul 21, 2025
b8c96e4
refactor: update export functionality to handle Excel instead of PDF
yuhtnguyen Jul 21, 2025
61ee587
refactor: update type definitions in AssignedGroupsTable and group data
yuhtnguyen Jul 21, 2025
55f4db8
refactor: remove unused toLowerCase method from StudentMember type
yuhtnguyen Jul 21, 2025
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
12 changes: 12 additions & 0 deletions src/app/(dashboard)/admin/capstone-defense-results/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createMetadata } from '@/app/metadata';
import CapstoneDefenseResults from '@/components/features/admin/CapstoneDefenseResults';

export const metadata = createMetadata({
title: 'Admin Capstone Defense Results',
description:
'Admin Capstone Defense Results for TheSync - Group Formation and Capstone Thesis Development',
});

export default function CapstoneDefenseResultsPage() {
return <CapstoneDefenseResults />;
}
12 changes: 12 additions & 0 deletions src/app/(dashboard)/admin/capstone-project-management/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createMetadata } from '@/app/metadata';
import CapstoneProjectManagement from '@/components/features/admin/CapstoneProjectManagement';

export const metadata = createMetadata({
title: 'Admin Capstone Project Management',
description:
'Admin Capstone Project Management for TheSync - Group Formation and Capstone Thesis Development',
});

export default function CapstoneProjectManagementPage() {
return <CapstoneProjectManagement />;
}
273 changes: 273 additions & 0 deletions src/components/features/admin/CapstoneDefenseResults/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
'use client';

import { Button, Col, Modal, Row, Space, Table, Typography } from 'antd';
import type {} from 'antd/es/table';
import { TableRowSelection } from 'antd/es/table/interface';
import React, { useCallback, useMemo, useState } from 'react';

import { Header } from '@/components/common/Header';
import { TablePagination } from '@/components/common/TablePagination';
import { getColumns } from '@/components/features/admin/CapstoneProjectManagement/Columns';
import { FilterBar } from '@/components/features/admin/CapstoneProjectManagement/FilterBar';
import { calculateRowSpans } from '@/components/features/admin/CapstoneProjectManagement/calculateRowSpan';
import {
GroupTableData,
useGroupTableData,
} from '@/components/features/admin/CapstoneProjectManagement/useGroupTableData';
import { useDebouncedSearch } from '@/hooks/ui/useDebounce';
import '@/styles/components.css';

const { Text } = Typography;

const CapstoneDefenseResults = () => {
const { searchValue, debouncedSearchValue, setSearchValue } =
useDebouncedSearch('', 300);
const [selectedSemester, setSelectedSemester] = useState<string>('all');
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [statusUpdates, setStatusUpdates] = useState<Record<string, string>>(
{},
);
const [baseDataState, setBaseDataState] = useState<GroupTableData[]>([]);
const { baseData, availableSemesters } = useGroupTableData();

// Initialize baseDataState when baseData changes
React.useEffect(() => {
setBaseDataState(baseData);
}, [baseData]);

const dataToUse = baseDataState;

const handleSearch = (value: string) => {
setSearchValue(value);
};

const handleExportExcel = () => {
console.log('Exporting to Excel...');
};

const handleRowSelectionChange = (newSelectedKeys: React.Key[]) => {
setSelectedRowKeys(newSelectedKeys);
};

const handleStatusChange = (studentId: string, newStatus: string) => {
setStatusUpdates((prev) => ({
...prev,
[studentId]: newStatus,
}));
};

const handleSaveChanges = () => {
console.log('Status updates to save:', statusUpdates);

// Update the baseDataState with new status values
setBaseDataState((prevData) =>
prevData.map((student) => {
if (statusUpdates[student.studentId]) {
return {
...student,
status: statusUpdates[student.studentId],
};
}
return student;
}),
);

// Clear the temporary updates and selection
setStatusUpdates({});
setSelectedRowKeys([]);
};

const handleBulkStatusUpdate = () => {
if (selectedRowKeys.length === 0) return;

const selectedStudents = filteredData.filter(
(student: { studentId: unknown; groupId: unknown }) =>
selectedRowKeys.includes(`${student.studentId}-${student.groupId}`),
);

Modal.confirm({
title: 'Update Defense Results',
width: 500,
content: (
<div>
<p>
<strong>{selectedRowKeys.length}</strong> student(s) will be
updated:
</p>
<div
style={{
maxHeight: 200,
overflowY: 'auto',
marginBottom: 5,
marginTop: 16,
}}
>
{selectedStudents.map((student: GroupTableData) => (
<div key={String(student.studentId)}>
<b>{student.studentId}</b> - {student.name}
<br />
<small>
Current:{' '}
{getDisplayStatus(
student.status ?? '',
String(student.studentId),
)}
</small>
</div>
))}
</div>
<p>Choose status to apply:</p>
</div>
),
okText: 'PASS',
cancelText: 'FAILED',
okType: 'primary',
okButtonProps: {
style: {
backgroundColor: 'transparent',
borderColor: '#52c41a',
color: 'green',
},
},
cancelButtonProps: {
style: {
borderColor: '#ff4d4f',
color: 'red',
},
},
onOk: () => {
selectedRowKeys.forEach((key) => {
const studentId = String(key).split('-')[0];
handleStatusChange(studentId, 'Pass');
});
setSelectedRowKeys([]);
},
onCancel: () => {
selectedRowKeys.forEach((key) => {
const studentId = String(key).split('-')[0];
handleStatusChange(studentId, 'Failed');
});
setSelectedRowKeys([]);
},
});
};

const hasUnsavedChanges = Object.keys(statusUpdates).length > 0;

const getDisplayStatus = useCallback(
(originalStatus: string, studentId: string) => {
return statusUpdates[studentId] || originalStatus;
},
[statusUpdates],
);

const filteredData = useMemo(() => {
const filtered = dataToUse.filter((item: GroupTableData) => {
const matchesSearch =
!debouncedSearchValue.trim() ||
[
item.name,
item.studentId,
item.thesisName,
item.major,
item.status,
item.semester,
].some((field) =>
String(field ?? '')
.toLowerCase()
.includes(debouncedSearchValue.toLowerCase().trim()),
);
const matchesSemester =
selectedSemester === 'all' || item.semester === selectedSemester;
return matchesSearch && matchesSemester;
});

return calculateRowSpans(filtered);
}, [dataToUse, debouncedSearchValue, selectedSemester]);

const columns = useMemo(
() =>
getColumns(debouncedSearchValue, {
showAbbreviationSupervisor: false,
showStatus: true,
getDisplayStatus,
statusUpdates,
handleStatusChange,
}),
[getDisplayStatus, debouncedSearchValue, statusUpdates],
);

const rowSelection: TableRowSelection<GroupTableData> = {
selectedRowKeys,
onChange: handleRowSelectionChange,
};

return (
<Space direction="vertical" size="small" style={{ width: '100%' }}>
<div>
<Header title="Capstone Defense Results" />
<Row gutter={[16, 16]} align="middle" style={{ marginTop: -4 }}>
<Col flex="auto">
<Typography.Text type="secondary">
View, import, and assess capstone defense results with detailed
student info and final evaluation status.
</Typography.Text>
</Col>
<Col>
<Button
onClick={handleBulkStatusUpdate}
disabled={selectedRowKeys.length === 0}
>
Update Defense Results
</Button>
</Col>
<Col>
<Button
type="primary"
onClick={handleSaveChanges}
disabled={!hasUnsavedChanges}
>
Save Changes{' '}
{hasUnsavedChanges && `(${Object.keys(statusUpdates).length})`}
</Button>
</Col>
</Row>
</div>

<div style={{ marginTop: 24 }}>
<FilterBar
searchText={searchValue}
onSearchChange={handleSearch}
selectedSemester={selectedSemester}
onSemesterChange={setSelectedSemester}
availableSemesters={availableSemesters}
onExportExcel={handleExportExcel}
searchPlaceholder="Search..."
showExportExcel={true}
/>
</div>

<Table
className="group-results-table"
columns={columns}
dataSource={filteredData}
rowKey={(record) => `${record.studentId}-${record.groupId}`}
rowSelection={rowSelection}
pagination={TablePagination}
bordered
/>

<Text type="secondary" style={{ marginTop: 16, display: 'block' }}>
List includes {filteredData.length} students and{' '}
{
new Set(
filteredData.map((item: { groupId: unknown }) => item.groupId),
).size
}{' '}
thesis projects
</Text>
</Space>
);
};

export default CapstoneDefenseResults;
Loading