Conversation
feat: Add Member Progress Filtering, CSV Export, and fix Review Mode Bug
feat: Past-deadline solution uploads and CSV export fixes
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR expands admin/chief tooling around member management and question set editing, adding solved-count filters/sorting and CSV export, introducing progress filtering/export for clan set analytics, and tightening editability rules in review/deadline-restricted modes.
Changes:
- Added min/max solved filtering, solved sorting, and CSV export to both Chief Members and Admin Members directories.
- Added member-progress filtering and CSV export to the Chief dashboard’s question-set analytics view.
- Prevented draft localStorage persistence during review mode and enforced deadline-based disabling of question set edit controls.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| server/src/features/clans/clan.controller.js | Includes name when populating clan members for various clan mutations. |
| client/src/pages/chief/ChiefMembersTab.jsx | Adds solved filters/sort and CSV export for chief member management. |
| client/src/pages/chief/ChiefDashboardTab.jsx | Adds progress-status filtering and CSV export for per-set member progress. |
| client/src/pages/ChallengeDetails.jsx | Skips localStorage draft load/save while in review mode. |
| admin-client/src/pages/admin/QuestionSetsTab.jsx | Disables set/question edits past deadline; adds disabled support for hints/test cases. |
| admin-client/src/pages/admin/MembersTab.jsx | Adds solved filters/sort and CSV export to the admin member directory. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const filteredMembers = members.filter(member => { | ||
| const matchesSearch = (member.username || '').toLowerCase().includes(searchTerm.toLowerCase()) || | ||
| (member.regNo && member.regNo.toLowerCase().includes(searchTerm.toLowerCase())) || | ||
| (member.email && member.email.toLowerCase().includes(searchTerm.toLowerCase())); |
| const solved = member.solvedProblems || 0; | ||
| const matchesMin = minSolved === '' || solved >= parseInt(minSolved); | ||
| const matchesMax = maxSolved === '' || solved <= parseInt(maxSolved); | ||
|
|
| const handleDownloadCSV = () => { | ||
| const headers = ['Name', 'Username', 'Email', 'Reg No', 'Level', 'Solved', 'XP', 'Streak', 'Status']; | ||
| const rows = sortedMembers.map(user => { | ||
| const isWarned = user.status === 'Warned'; | ||
| const isInactive = user.status === 'Inactive'; | ||
| const status = isWarned ? 'Warned' : isInactive ? 'Inactive' : 'Active'; | ||
|
|
||
| return [ | ||
| `"${user.name || user.username || ''}"`, | ||
| `"${user.username || ''}"`, | ||
| `"${user.email || ''}"`, | ||
| `"${user.regNo || 'N/A'}"`, | ||
| `"${user.codingLevel || 'Beginner'}"`, | ||
| user.solvedProblems || 0, | ||
| user.points || 0, | ||
| user.streak || 0, | ||
| `"${status}"` | ||
| ].join(','); | ||
| }); |
| const url = URL.createObjectURL(blob); | ||
| const link = document.createElement('a'); | ||
| link.setAttribute('href', url); | ||
| link.setAttribute('download', `Member_Management_${clan.name?.replace(/\s+/g, '_') || 'Clan'}.csv`); | ||
| document.body.appendChild(link); | ||
| link.click(); | ||
| document.body.removeChild(link); | ||
| }; |
| <select | ||
| value={filterType} | ||
| onChange={(e) => setFilterType(e.target.value)} | ||
| className="bg-black/20 border border-white/10 text-primary text-xs rounded-lg px-3 py-1.5 focus:outline-none focus:border-accent" | ||
| > |
| const solved = u.solvedProblems || 0; | ||
| const matchesMin = minSolved === '' || solved >= parseInt(minSolved); | ||
| const matchesMax = maxSolved === '' || solved <= parseInt(maxSolved); | ||
|
|
| let status = 'Not Started'; | ||
| if ((u.solvedProblems || 0) > 0) status = 'In Progress'; // Can't easily determine 'Completed all' globally without total question count | ||
|
|
| const handleDownloadCSV = () => { | ||
| const headers = ['Name', 'Username', 'Email', 'Reg No', 'Clan', 'Level', 'Solved', 'XP', 'Streak', 'Status']; | ||
| const rows = sortedUsers.map(u => { | ||
| const activeClan = u.clan ? (clansQuery.data || []).find(c => c._id === u.clan || c._id === u.clan?._id) : null; | ||
| const clanName = activeClan ? activeClan.name : 'Unassigned'; | ||
| let status = 'Not Started'; | ||
| if ((u.solvedProblems || 0) > 0) status = 'In Progress'; // Can't easily determine 'Completed all' globally without total question count | ||
|
|
||
| return [ | ||
| `"${u.name || ''}"`, | ||
| `"${u.username || ''}"`, | ||
| `"${u.email || ''}"`, | ||
| `"${u.regNo || 'N/A'}"`, | ||
| `"${clanName}"`, | ||
| `"${u.codingLevel || 'Beginner'}"`, | ||
| u.solvedProblems || 0, | ||
| u.points || 0, | ||
| u.streak || 0, | ||
| `"${u.status || 'Active'}"` | ||
| ].join(','); | ||
| }); |
| const url = URL.createObjectURL(blob); | ||
| const link = document.createElement('a'); | ||
| link.setAttribute('href', url); | ||
| link.setAttribute('download', `Admin_Directory_${new Date().toISOString().split('T')[0]}.csv`); | ||
| document.body.appendChild(link); | ||
| link.click(); | ||
| document.body.removeChild(link); | ||
| }; |
| const todayStr = new Date().toISOString().split('T')[0]; | ||
| const isPastDeadline = editingSetId && form.deadline && form.deadline < todayStr; |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 994de1e640
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const [previewQuestion, setPreviewQuestion] = useState(null); | ||
|
|
||
| const todayStr = new Date().toISOString().split('T')[0]; | ||
| const isPastDeadline = editingSetId && form.deadline && form.deadline < todayStr; |
There was a problem hiding this comment.
Enforce deadline restrictions on the update API
When a set is past its deadline, this flag only disables form controls in the browser; the submit still sends a full questions payload and the server PUT /api/sets/:id handler still copies title, weekNumber, deadline, targetLevel, questions, and status from any request body. In the past-deadline scenario, an admin with stale state/devtools or a direct API call can still move, remove, or retitle questions and invalidate existing submissions despite the UI warning, so the deadline rule needs to be enforced in updateQuestionSet as well.
Useful? React with 👍 / 👎.
| `"${u.username || ''}"`, | ||
| `"${u.email || ''}"`, | ||
| `"${u.regNo || 'N/A'}"`, | ||
| `"${clanName}"`, |
There was a problem hiding this comment.
Escape clan names in the CSV export
When an admin-created clan name contains a double quote, this manual quoting produces malformed CSV because embedded quotes are not doubled before joining the row; the clan model only trims/limits the name, so values like Alpha "A" can be saved and will shift/corrupt columns when the exported file is opened. Please use a CSV cell escaper for this and the other string fields in the new exporters.
Useful? React with 👍 / 👎.
This pull request introduces several improvements to the admin interface for managing members and question sets. The most significant updates include enhanced filtering, sorting, and export options for the members table, and improved handling of question set editing after deadlines. Additionally, form controls for editing questions and test cases are now correctly disabled when editing is restricted.
Members management enhancements:
Question set editing restrictions:
Form control improvements:
HintsEditorandTestCaseEditorcomponents now support adisabledprop, disabling inputs and action buttons when editing is not allowed (e.g., past deadline).These changes improve the admin experience by making member management more powerful and ensuring question set editing rules are enforced.
This pull request introduces several enhancements to the admin interface, focusing on improved filtering, sorting, and exporting capabilities for the Members tab, as well as stricter controls for editing question sets after their deadlines. Additionally, it improves the user experience by disabling editing functionality for hints and test cases when appropriate.
Admin Members Tab Improvements:
Admin Question Sets Tab Enhancements:
disabledstate, preventing edits when the deadline has passed.These changes streamline admin workflows and provide better control over user and question set management.