Skip to content
Draft
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
61 changes: 47 additions & 14 deletions laprogram/app/admin/components/ReportTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,25 @@ function CopyButton({ text, disabled }: { text: string; disabled?: boolean }) {
);
}

function downloadExcel(
course: string,
type FeedbackType = "mid_quarter" | "end_of_quarter";

/** Adds a UID sheet — plus, for mid-quarter, a course-change sheet — to `wb`. */
function appendSheets(
wb: XLSX.WorkBook,
uids: UidInformation[],
type: "mid_quarter" | "end_of_quarter",
type: FeedbackType,
prefix = "",
) {
const wb = XLSX.utils.book_new();
const uidRows = uids.map((u) => ({
uid: u.uid,
name: u.name,
email: u.email,
}));
XLSX.utils.book_append_sheet(wb, XLSX.utils.json_to_sheet(uidRows), "UIDs");
XLSX.utils.book_append_sheet(
wb,
XLSX.utils.json_to_sheet(uidRows),
`${prefix}UIDs`,
);

if (type === "mid_quarter") {
const feedbackRows = uids
Expand All @@ -66,13 +73,31 @@ function downloadExcel(
XLSX.utils.book_append_sheet(
wb,
XLSX.utils.json_to_sheet(feedbackRows),
"Course Change",
`${prefix}Course Change`,
);
}
}

function downloadExcel(
course: string,
uids: UidInformation[],
type: FeedbackType,
) {
const wb = XLSX.utils.book_new();
appendSheets(wb, uids, type);
XLSX.writeFile(wb, `${course} UIDs - ${type}.xlsx`);
}

function downloadCombinedExcel(
course: string,
entry: Record<FeedbackType, UidInformation[]>,
) {
const wb = XLSX.utils.book_new();
appendSheets(wb, entry.mid_quarter, "mid_quarter", "Mid-Quarter ");
appendSheets(wb, entry.end_of_quarter, "end_of_quarter", "End-of-Quarter ");
XLSX.writeFile(wb, `${course} UIDs.xlsx`);
}

function UidLists() {
const { data: rows } = useSWR<FeedbackUidRow[]>(
"/api/admin/audit/feedback-uids",
Expand All @@ -84,13 +109,7 @@ function UidLists() {
return <p className="text-sm text-muted-foreground">Loading…</p>;
}

const byCourse = new Map<
string,
{
mid_quarter: UidInformation[];
end_of_quarter: UidInformation[];
}
>();
const byCourse = new Map<string, Record<FeedbackType, UidInformation[]>>();
for (const row of rows) {
const course = row.course ?? "(no course)";
let entry = byCourse.get(course);
Expand Down Expand Up @@ -137,6 +156,19 @@ function UidLists() {
end
</span>
</button>
<button
type="button"
disabled={
entry.mid_quarter.length === 0 &&
entry.end_of_quarter.length === 0
}
onClick={() => downloadCombinedExcel(course, entry)}
className="inline-flex items-center gap-1 rounded-sm px-1.5 py-0.5 text-xs text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-40 disabled:hover:bg-transparent"
title="Download both mid- and end-of-quarter sheets in one Excel file"
>
<Download className="size-3" />
Download Both
</button>
</div>
{isExpanded && (
<div className="grid grid-cols-2 gap-4 pl-5">
Expand Down Expand Up @@ -197,7 +229,8 @@ export function ReportTab() {
<p className="text-xs text-muted-foreground">
Mid-quarter Excel exports include a second sheet with each
student&apos;s &ldquo;What would you change about this course?&rdquo;
response.
response. &ldquo;Download Both&rdquo; puts the mid- and
end-of-quarter sheets in a single file.
</p>
<UidLists />
</div>
Expand Down