Skip to content

Commit f424056

Browse files
committed
feat: select all switch
1 parent a1a6c4f commit f424056

3 files changed

Lines changed: 124 additions & 4 deletions

File tree

assets/js/Components/ReviewFilesPage.css

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,41 @@
1313
}
1414
}
1515

16+
.unused-files-list-container {
17+
display: flex;
18+
flex-direction: column;
19+
gap: 0.5rem;
20+
padding: 1rem 1.5rem;
21+
}
22+
23+
.select-all-unused-toggle-row {
24+
display: flex;
25+
flex-direction: row;
26+
gap: 0.5rem;
27+
padding: 0.25rem 0.25rem 0.5rem;
28+
}
29+
30+
.unused-file-list-item {
31+
display: flex;
32+
flex-direction: row;
33+
align-items: center;
34+
gap: 0.75rem;
35+
padding: 0.75rem;
36+
border: 1px solid var(--border-color);
37+
border-radius: var(--element-radius);
38+
background-color: var(--white);
39+
cursor: pointer;
40+
}
41+
42+
.unused-file-list-details {
43+
display: flex;
44+
flex-direction: column;
45+
}
46+
47+
.unused-file-list-title {
48+
font-weight: 500;
49+
}
50+
1651
.udoit-sortable-table {
1752
tr {
1853

assets/js/Components/ReviewFilesPage.js

Lines changed: 85 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, { useState, useEffect } from 'react'
22
import ReviewFilesFilters from './Widgets/ReviewFilesFilters'
3+
import ToggleSwitch from './Widgets/ToggleSwitch'
34
import SortableTable from './Widgets/SortableTable'
45
import FileFixitWidget from './Widgets/FileFixitWidget'
56
import FileReviewPreview from './Widgets/FileReviewPreview'
@@ -106,7 +107,7 @@ export default function ReviewFilesPage({
106107
const [showLearnMore, setShowLearnMore] = useState(false)
107108

108109
const [unusedFiles, setUnusedFiles] = useState([])
109-
const [fileDeleteQueue, setFileDeleteQueue] = useState([])
110+
const [deleteFileQueue, setDeleteFileQueue] = useState([])
110111

111112

112113
const formatFileData = (fileData) => {
@@ -240,12 +241,14 @@ export default function ReviewFilesPage({
240241
for (const [key, value] of Object.entries(tempFiles)) {
241242
let tempFile = formatFileData(value)
242243
tempUnfilteredIssues.push(tempFile)
243-
if(!tempFile?.fileData?.references || tempFile?.fileData?.references?.length == 0){
244+
if((!tempFile?.fileData?.references || tempFile?.fileData?.references?.length === 0)
245+
&& (!tempFile?.fileData?.sectionRefs || tempFile?.fileData?.sectionRefs?.length === 0)) {
244246
tempUnusedFiles.push(tempFile.fileData)
245247
}
246248
}
247249

248-
console.log(tempUnusedFiles)
250+
setUnusedFiles(tempUnusedFiles)
251+
setDeleteFileQueue((oldQueue) => oldQueue.filter((fileId) => tempUnusedFiles.some((file) => file.id === fileId)))
249252

250253
tempUnfilteredIssues.sort((a, b) => {
251254
return (a.formLabel.toLowerCase() < b.formLabel.toLowerCase()) ? -1 : 1
@@ -379,6 +382,28 @@ export default function ReviewFilesPage({
379382
}
380383
}
381384

385+
const toggleDeleteFileQueue = (fileId) => {
386+
if(!fileId) {
387+
return
388+
}
389+
390+
setDeleteFileQueue((oldQueue) => {
391+
if(oldQueue.includes(fileId)) {
392+
return oldQueue.filter((id) => id !== fileId)
393+
}
394+
return [...oldQueue, fileId]
395+
})
396+
}
397+
398+
const updateSelectAllUnusedFilesToggle = (newValue) => {
399+
if(newValue === false) {
400+
setDeleteFileQueue([])
401+
return
402+
}
403+
404+
setDeleteFileQueue(unusedFiles.map((file) => file.id))
405+
}
406+
382407
const getFileTypeDisplay = (fileType) => {
383408
const fileTypeText = t(`label.mime.${fileType}`)
384409

@@ -935,6 +960,8 @@ const getSectionPostOptions = (newFile, sectionReferences) => {
935960
}
936961
}
937962

963+
const allUnusedFilesSelected = unusedFiles.length > 0 && deleteFileQueue.length === unusedFiles.length
964+
938965
return (
939966
<>
940967
{ widgetState === WIDGET_STATE.LOADING ? (
@@ -1079,7 +1106,61 @@ const getSectionPostOptions = (newFile, sectionReferences) => {
10791106
<div className='flex-column h-100'>
10801107
<div className='dialog-header'>
10811108
<h2>{t('files.button.delete_unused_files')}</h2>
1082-
<CloseIcon onClick={() => closeDialog(unusedFileDialogId)} onKeyDown={(e) => e.key == "Enter" ? () => closeDialog(unusedFileDialogId) : ""} className="close-icon icon-lg" tabIndex="0" alt={t('fix.button.close')} title={t('fix.button.close')} />
1109+
<CloseIcon onClick={() => closeDialog(unusedFileDialogId)} onKeyDown={(e) => e.key == "Enter" ? closeDialog(unusedFileDialogId) : ""} className="close-icon icon-lg" tabIndex="0" alt={t('fix.button.close')} title={t('fix.button.close')} />
1110+
</div>
1111+
<div className="dialog-content">
1112+
<div className="unused-files-list-container">
1113+
{unusedFiles.length > 0 && (
1114+
<div className="select-all-unused-toggle-row">
1115+
<ToggleSwitch
1116+
key={allUnusedFilesSelected ? 'select-all-on' : 'select-all-off'}
1117+
labelId="selectAllUnusedFiles"
1118+
initialValue={allUnusedFilesSelected}
1119+
updateToggle={updateSelectAllUnusedFilesToggle}
1120+
small={true}
1121+
/>
1122+
<div id="selectAllUnusedFiles" className="align-self-center subtext">
1123+
{t('files.label.select_all_unused_files')}
1124+
</div>
1125+
</div>
1126+
)}
1127+
{unusedFiles.length === 0 ? (
1128+
<div className="flex-column gap-2 p-3">
1129+
<h3 className="mt-0 mb-0 primary-dark">{t('report.label.no_results')}</h3>
1130+
<div className="subtext">{t('files.msg.no_unused_files')}</div>
1131+
</div>
1132+
) : (
1133+
unusedFiles.map((unusedFile) => {
1134+
const isSelected = deleteFileQueue.includes(unusedFile.id)
1135+
return (
1136+
<label key={unusedFile.id} htmlFor={`unused-file-${unusedFile.id}`} className="unused-file-list-item">
1137+
<input
1138+
id={`unused-file-${unusedFile.id}`}
1139+
type="checkbox"
1140+
checked={isSelected}
1141+
onChange={() => toggleDeleteFileQueue(unusedFile.id)}
1142+
/>
1143+
<div className="unused-file-list-details">
1144+
<div className="unused-file-list-title">{unusedFile.fileName || t('label.unknown')}</div>
1145+
<div className="subtext">{getReadableFileType(unusedFile.fileType)}</div>
1146+
</div>
1147+
</label>
1148+
)
1149+
})
1150+
)}
1151+
</div>
1152+
</div>
1153+
<div className='dialog-footer'>
1154+
<div className="subtext align-self-center">{t('files.label.selected_count', { count: deleteFileQueue.length })}</div>
1155+
<div className="flex-row gap-2">
1156+
<button
1157+
className='btn btn-small btn-icon-left review-files-delete-button'
1158+
tabIndex='0'
1159+
disabled={deleteFileQueue.length === 0}>
1160+
<DeleteIcon className="icon-sm" />
1161+
<div className="flex-column justify-content-center">{t('files.button.delete_selected')}</div>
1162+
</button>
1163+
</div>
10831164
</div>
10841165
</div>
10851166
</dialog>

translations/en.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@
5959
"files.title": "Review Files",
6060
"files.subtitle": "Files cannot be automatically scanned by UDOIT. Review course files for common accessibility issues and update them if necessary.",
6161
"files.button.delete_unused_files": "Delete Unused Files",
62+
"files.button.delete_selected": "Delete Selected",
63+
"files.label.select_all_unused_files": "Select All Unused Files",
64+
"files.label.selected_count": "{count} file(s) selected",
65+
"files.msg.no_unused_files": "No unused files were found.",
6266

6367
"report.title": "Reports",
6468
"report.subtitle": "View and print detailed accessibility reports for your course currently or over time.",

0 commit comments

Comments
 (0)