@local-civics/mgmt-ui 0.1.229 → 0.1.231
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +5 -0
- package/dist/index.js +222 -32
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +223 -33
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -872,9 +872,11 @@ interface SubmissionItem {
|
|
|
872
872
|
badgeName: string;
|
|
873
873
|
badgeId: string;
|
|
874
874
|
lessonName: string;
|
|
875
|
+
lessonId?: string;
|
|
875
876
|
question: string;
|
|
876
877
|
updatedAt?: string;
|
|
877
878
|
pathwayName?: string;
|
|
879
|
+
pathwayId?: string;
|
|
878
880
|
}
|
|
879
881
|
|
|
880
882
|
/**
|
|
@@ -921,6 +923,9 @@ type FileLockerProps = {
|
|
|
921
923
|
onClassChange: (classId: string) => void;
|
|
922
924
|
onCopyLinkClick: () => void;
|
|
923
925
|
onExportDataClick: () => void;
|
|
926
|
+
onBadgeClick?: (badgeId: string) => void;
|
|
927
|
+
onLessonClick?: (lessonId: string) => void;
|
|
928
|
+
onPathwayClick?: (pathwayId: string) => void;
|
|
924
929
|
};
|
|
925
930
|
/**
|
|
926
931
|
* FileLocker
|
package/dist/index.js
CHANGED
|
@@ -3355,31 +3355,21 @@ const SplitButton = (props) => {
|
|
|
3355
3355
|
};
|
|
3356
3356
|
|
|
3357
3357
|
function Stack(props) {
|
|
3358
|
-
const { items, hideBadge, hideLesson, hidePathway } = props;
|
|
3358
|
+
const { items, hideBadge, hideLesson, hidePathway, onBadgeClick, onLessonClick, onPathwayClick } = props;
|
|
3359
3359
|
if (!items.length)
|
|
3360
3360
|
return null;
|
|
3361
3361
|
const columns = [
|
|
3362
|
-
"minmax(0,2fr)",
|
|
3363
3362
|
!hidePathway && "minmax(0,1.3fr)",
|
|
3364
|
-
!hideLesson && "minmax(0,1.3fr)",
|
|
3365
3363
|
!hideBadge && "minmax(0,1.3fr)",
|
|
3364
|
+
!hideLesson && "minmax(0,1.3fr)",
|
|
3365
|
+
"minmax(0,2fr)",
|
|
3366
3366
|
"auto"
|
|
3367
3367
|
].filter(Boolean).join(" ");
|
|
3368
3368
|
const headerCell = "border-b border-slate-100 pb-2 text-[10.5px] font-extrabold uppercase tracking-wide text-slate-400";
|
|
3369
3369
|
const dataCell = "py-3";
|
|
3370
|
-
return /* @__PURE__ */ React__namespace.createElement("div", { className: "grid items-center gap-x-3", style: { gridTemplateColumns: columns } }, /* @__PURE__ */ React__namespace.createElement("div", { className: headerCell }, "
|
|
3370
|
+
return /* @__PURE__ */ React__namespace.createElement("div", { className: "grid items-center gap-x-3", style: { gridTemplateColumns: columns } }, !hidePathway && /* @__PURE__ */ React__namespace.createElement("div", { className: headerCell }, "Pathway"), !hideBadge && /* @__PURE__ */ React__namespace.createElement("div", { className: headerCell }, "Badge"), !hideLesson && /* @__PURE__ */ React__namespace.createElement("div", { className: headerCell }, "Lesson"), /* @__PURE__ */ React__namespace.createElement("div", { className: headerCell }, "Question"), /* @__PURE__ */ React__namespace.createElement("div", { className: headerCell }), items.map((row, i) => {
|
|
3371
3371
|
const rowBorder = i > 0 ? "border-t border-slate-100" : "";
|
|
3372
|
-
return /* @__PURE__ */ React__namespace.createElement(React__namespace.Fragment, { key: i }, /* @__PURE__ */ React__namespace.createElement("
|
|
3373
|
-
"a",
|
|
3374
|
-
{
|
|
3375
|
-
href: row.link,
|
|
3376
|
-
target: "_blank",
|
|
3377
|
-
rel: "noopener noreferrer",
|
|
3378
|
-
className: "flex items-center gap-1 rounded-md border border-slate-200 px-2.5 py-1.5 text-[11px] font-bold text-slate-600 no-underline hover:bg-slate-50"
|
|
3379
|
-
},
|
|
3380
|
-
/* @__PURE__ */ React__namespace.createElement(icons.IconExternalLink, { size: 12, stroke: 2 }),
|
|
3381
|
-
"Preview"
|
|
3382
|
-
), /* @__PURE__ */ React__namespace.createElement(
|
|
3372
|
+
return /* @__PURE__ */ React__namespace.createElement(React__namespace.Fragment, { key: i }, !hidePathway && (row.pathwayId && onPathwayClick ? /* @__PURE__ */ React__namespace.createElement("button", { type: "button", onClick: () => onPathwayClick(row.pathwayId), className: `${dataCell} ${rowBorder} truncate text-left text-[11px] font-semibold text-sky-blue-400 hover:underline` }, row.pathwayName || "\u2014") : /* @__PURE__ */ React__namespace.createElement("div", { className: `${dataCell} ${rowBorder} truncate text-[11px] text-slate-500` }, row.pathwayName || "\u2014")), !hideBadge && (row.badgeId && onBadgeClick ? /* @__PURE__ */ React__namespace.createElement("button", { type: "button", onClick: () => onBadgeClick(row.badgeId), className: `${dataCell} ${rowBorder} truncate text-left text-[11px] font-semibold text-sky-blue-400 hover:underline` }, row.badgeName) : /* @__PURE__ */ React__namespace.createElement("div", { className: `${dataCell} ${rowBorder} truncate text-[11px] text-slate-500` }, row.badgeName)), !hideLesson && (row.lessonId && onLessonClick ? /* @__PURE__ */ React__namespace.createElement("button", { type: "button", onClick: () => onLessonClick(row.lessonId), className: `${dataCell} ${rowBorder} truncate text-left text-[11px] font-semibold text-sky-blue-400 hover:underline` }, row.lessonName) : /* @__PURE__ */ React__namespace.createElement("div", { className: `${dataCell} ${rowBorder} truncate text-[11px] text-slate-500` }, row.lessonName)), /* @__PURE__ */ React__namespace.createElement("div", { className: `${dataCell} ${rowBorder} text-xs font-semibold text-dark-blue-400` }, row.question), /* @__PURE__ */ React__namespace.createElement("div", { className: `${dataCell} ${rowBorder} flex shrink-0 gap-2` }, /* @__PURE__ */ React__namespace.createElement(
|
|
3383
3373
|
"a",
|
|
3384
3374
|
{
|
|
3385
3375
|
href: row.link,
|
|
@@ -3458,14 +3448,33 @@ function Table(props) {
|
|
|
3458
3448
|
"Review Submission"
|
|
3459
3449
|
)),
|
|
3460
3450
|
/* @__PURE__ */ React__namespace.createElement(icons.IconChevronRight, { size: 16, stroke: 2, className: `w-4 shrink-0 text-slate-300 transition-transform ${isOpen ? "rotate-90" : ""}` })
|
|
3461
|
-
), isOpen && /* @__PURE__ */ React__namespace.createElement("div", { className: "border-t border-slate-100 px-4 py-3" }, /* @__PURE__ */ React__namespace.createElement(
|
|
3451
|
+
), isOpen && /* @__PURE__ */ React__namespace.createElement("div", { className: "border-t border-slate-100 px-4 py-3" }, /* @__PURE__ */ React__namespace.createElement(
|
|
3452
|
+
Stack,
|
|
3453
|
+
{
|
|
3454
|
+
items: row.submissions,
|
|
3455
|
+
hideBadge: props.hideBadge,
|
|
3456
|
+
hideLesson: props.hideLesson,
|
|
3457
|
+
hidePathway: props.hidePathway,
|
|
3458
|
+
onBadgeClick: props.onBadgeClick,
|
|
3459
|
+
onLessonClick: props.onLessonClick,
|
|
3460
|
+
onPathwayClick: props.onPathwayClick
|
|
3461
|
+
}
|
|
3462
|
+
)));
|
|
3462
3463
|
}));
|
|
3463
3464
|
}
|
|
3464
3465
|
|
|
3465
3466
|
const initials = (name) => name.split(" ").map((w) => w[0]).filter(Boolean).slice(0, 2).join("").toUpperCase();
|
|
3466
3467
|
function SubmissionDetail(props) {
|
|
3467
3468
|
const { student } = props;
|
|
3468
|
-
return /* @__PURE__ */ React__namespace.createElement("div", { className: "flex w-full flex-col gap-4 px-4 py-8" }, /* @__PURE__ */ React__namespace.createElement("div", { className: "flex items-center gap-2 text-xs text-slate-400" }, /* @__PURE__ */ React__namespace.createElement("button", { onClick: props.onBack, className: "font-bold text-sky-blue-400 hover:underline" }, "File Locker"), /* @__PURE__ */ React__namespace.createElement("span", null, "/"), /* @__PURE__ */ React__namespace.createElement("span", { className: "font-bold text-dark-blue-400" }, student.name)), /* @__PURE__ */ React__namespace.createElement("div", { className: "flex items-center gap-4 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm" }, student.avatar ? /* @__PURE__ */ React__namespace.createElement("img", { src: student.avatar, className: "h-12 w-12 shrink-0 rounded-full object-cover", alt: "" }) : /* @__PURE__ */ React__namespace.createElement("div", { className: "flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-gradient-to-br from-mint-400 to-dark-blue-400 text-sm font-bold text-white" }, initials(student.name)), /* @__PURE__ */ React__namespace.createElement("div", { className: "min-w-0 flex-1" }, /* @__PURE__ */ React__namespace.createElement("div", { className: "text-lg font-extrabold text-dark-blue-400" }, student.name), /* @__PURE__ */ React__namespace.createElement("div", { className: "mt-0.5 text-xs text-slate-400" }, student.email, props.context ? ` \xB7 ${props.context}` : "")), /* @__PURE__ */ React__namespace.createElement("div", { className: "shrink-0 rounded-full bg-slate-100 px-3 py-1 text-xs font-bold text-slate-500" }, student.submissions.length, " file", student.submissions.length === 1 ? "" : "s")), /* @__PURE__ */ React__namespace.createElement("div", { className: "rounded-2xl border border-slate-200 bg-white p-5 shadow-sm" }, /* @__PURE__ */ React__namespace.createElement("div", { className: "text-sm font-extrabold text-dark-blue-400" }, "Files"), /* @__PURE__ */ React__namespace.createElement("div", { className: "mt-2" }, /* @__PURE__ */ React__namespace.createElement(
|
|
3469
|
+
return /* @__PURE__ */ React__namespace.createElement("div", { className: "flex w-full flex-col gap-4 px-4 py-8" }, /* @__PURE__ */ React__namespace.createElement("div", { className: "flex items-center gap-2 text-xs text-slate-400" }, /* @__PURE__ */ React__namespace.createElement("button", { onClick: props.onBack, className: "font-bold text-sky-blue-400 hover:underline" }, "File Locker"), /* @__PURE__ */ React__namespace.createElement("span", null, "/"), /* @__PURE__ */ React__namespace.createElement("span", { className: "font-bold text-dark-blue-400" }, student.name)), /* @__PURE__ */ React__namespace.createElement("div", { className: "flex items-center gap-4 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm" }, student.avatar ? /* @__PURE__ */ React__namespace.createElement("img", { src: student.avatar, className: "h-12 w-12 shrink-0 rounded-full object-cover", alt: "" }) : /* @__PURE__ */ React__namespace.createElement("div", { className: "flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-gradient-to-br from-mint-400 to-dark-blue-400 text-sm font-bold text-white" }, initials(student.name)), /* @__PURE__ */ React__namespace.createElement("div", { className: "min-w-0 flex-1" }, /* @__PURE__ */ React__namespace.createElement("div", { className: "text-lg font-extrabold text-dark-blue-400" }, student.name), /* @__PURE__ */ React__namespace.createElement("div", { className: "mt-0.5 text-xs text-slate-400" }, student.email, props.context ? ` \xB7 ${props.context}` : "")), /* @__PURE__ */ React__namespace.createElement("div", { className: "shrink-0 rounded-full bg-slate-100 px-3 py-1 text-xs font-bold text-slate-500" }, student.submissions.length, " file", student.submissions.length === 1 ? "" : "s")), /* @__PURE__ */ React__namespace.createElement("div", { className: "rounded-2xl border border-slate-200 bg-white p-5 shadow-sm" }, /* @__PURE__ */ React__namespace.createElement("div", { className: "text-sm font-extrabold text-dark-blue-400" }, "Files"), /* @__PURE__ */ React__namespace.createElement("div", { className: "mt-2" }, /* @__PURE__ */ React__namespace.createElement(
|
|
3470
|
+
Stack,
|
|
3471
|
+
{
|
|
3472
|
+
items: student.submissions,
|
|
3473
|
+
onBadgeClick: props.onBadgeClick,
|
|
3474
|
+
onLessonClick: props.onLessonClick,
|
|
3475
|
+
onPathwayClick: props.onPathwayClick
|
|
3476
|
+
}
|
|
3477
|
+
))), /* @__PURE__ */ React__namespace.createElement("div", { className: "flex gap-3" }, /* @__PURE__ */ React__namespace.createElement(
|
|
3469
3478
|
"button",
|
|
3470
3479
|
{
|
|
3471
3480
|
onClick: () => props.onNav(-1),
|
|
@@ -3556,42 +3565,143 @@ const TABS = [
|
|
|
3556
3565
|
{ value: "badges", label: "By badge" },
|
|
3557
3566
|
{ value: "lessons", label: "By lesson" }
|
|
3558
3567
|
];
|
|
3568
|
+
const SEARCH_PLACEHOLDER = "Search by student, pathway, badge, or lesson";
|
|
3559
3569
|
const countFiles = (students) => students.reduce((acc, s) => {
|
|
3560
3570
|
var _a;
|
|
3561
3571
|
return acc + (((_a = s.submissions) == null ? void 0 : _a.length) || 0);
|
|
3562
3572
|
}, 0);
|
|
3573
|
+
const matchesSearch = (student, term) => {
|
|
3574
|
+
if (!term)
|
|
3575
|
+
return true;
|
|
3576
|
+
if (student.name.toLowerCase().includes(term))
|
|
3577
|
+
return true;
|
|
3578
|
+
return (student.submissions || []).some(
|
|
3579
|
+
(sub) => {
|
|
3580
|
+
var _a, _b, _c;
|
|
3581
|
+
return ((_a = sub.badgeName) == null ? void 0 : _a.toLowerCase().includes(term)) || ((_b = sub.lessonName) == null ? void 0 : _b.toLowerCase().includes(term)) || ((_c = sub.pathwayName) == null ? void 0 : _c.toLowerCase().includes(term));
|
|
3582
|
+
}
|
|
3583
|
+
);
|
|
3584
|
+
};
|
|
3563
3585
|
const GroupCard = (props) => {
|
|
3564
3586
|
const [open, setOpen] = React__namespace.useState(false);
|
|
3565
|
-
return /* @__PURE__ */ React__namespace.createElement("div", { className: "overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm" }, /* @__PURE__ */ React__namespace.createElement("div", { onClick: () => setOpen(!open), className: "flex cursor-pointer items-center gap-3.5 p-4" }, /* @__PURE__ */ React__namespace.createElement("div", { className: "min-w-0 flex-1" },
|
|
3587
|
+
return /* @__PURE__ */ React__namespace.createElement("div", { className: "overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm" }, /* @__PURE__ */ React__namespace.createElement("div", { onClick: () => setOpen(!open), className: "flex cursor-pointer items-center gap-3.5 p-4" }, /* @__PURE__ */ React__namespace.createElement("div", { className: "min-w-0 flex-1" }, props.onTitleClick ? /* @__PURE__ */ React__namespace.createElement(
|
|
3588
|
+
"button",
|
|
3589
|
+
{
|
|
3590
|
+
type: "button",
|
|
3591
|
+
onClick: (e) => {
|
|
3592
|
+
e.stopPropagation();
|
|
3593
|
+
props.onTitleClick();
|
|
3594
|
+
},
|
|
3595
|
+
className: "text-left text-sm font-extrabold text-sky-blue-400 hover:underline"
|
|
3596
|
+
},
|
|
3597
|
+
props.title
|
|
3598
|
+
) : /* @__PURE__ */ React__namespace.createElement("div", { className: "text-sm font-extrabold text-dark-blue-400" }, props.title), props.description && /* @__PURE__ */ React__namespace.createElement("div", { className: "mt-1 text-xs leading-relaxed text-slate-500" }, props.description)), /* @__PURE__ */ React__namespace.createElement("div", { className: "shrink-0 rounded-full bg-mint-100 px-2.5 py-1 text-xs font-bold text-dark-blue-400" }, props.count), /* @__PURE__ */ React__namespace.createElement(icons.IconChevronDown, { size: 15, stroke: 2.3, className: `shrink-0 text-slate-400 transition-transform ${open ? "rotate-180" : ""}` })), open && /* @__PURE__ */ React__namespace.createElement("div", { className: "border-t border-slate-100 p-4" }, props.children));
|
|
3566
3599
|
};
|
|
3567
3600
|
const PathwayGroups = (props) => {
|
|
3568
3601
|
const { byPathway } = useFilteredStudents(props.students);
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3602
|
+
const term = props.search.trim().toLowerCase();
|
|
3603
|
+
const groups = props.pathways.map((p) => {
|
|
3604
|
+
const base = byPathway(p.pathwayId, props.badges);
|
|
3605
|
+
const ownNameMatches = !term || p.title.toLowerCase().includes(term);
|
|
3606
|
+
const filtered = ownNameMatches ? base : base.filter((s) => matchesSearch(s, term));
|
|
3607
|
+
return { pathway: p, filtered };
|
|
3608
|
+
}).filter((g) => !term || g.filtered.length > 0);
|
|
3609
|
+
if (term && groups.length === 0) {
|
|
3610
|
+
return /* @__PURE__ */ React__namespace.createElement("p", { className: "text-sm text-slate-400" }, "No matching entries.");
|
|
3611
|
+
}
|
|
3612
|
+
return /* @__PURE__ */ React__namespace.createElement("div", { className: "flex flex-col gap-3" }, groups.map(({ pathway: p, filtered }) => /* @__PURE__ */ React__namespace.createElement(
|
|
3613
|
+
GroupCard,
|
|
3614
|
+
{
|
|
3615
|
+
key: p.pathwayId,
|
|
3616
|
+
title: p.title,
|
|
3617
|
+
description: p.description,
|
|
3618
|
+
count: countFiles(filtered),
|
|
3619
|
+
onTitleClick: props.onPathwayClick ? () => props.onPathwayClick(p.pathwayId) : void 0
|
|
3620
|
+
},
|
|
3621
|
+
/* @__PURE__ */ React__namespace.createElement(
|
|
3622
|
+
Table,
|
|
3623
|
+
{
|
|
3624
|
+
loading: props.loading,
|
|
3625
|
+
items: filtered,
|
|
3626
|
+
hidePathway: true,
|
|
3627
|
+
onReview: (item) => props.onReview(item, filtered, p.title),
|
|
3628
|
+
onBadgeClick: props.onBadgeClick,
|
|
3629
|
+
onLessonClick: props.onLessonClick
|
|
3630
|
+
}
|
|
3631
|
+
)
|
|
3632
|
+
)));
|
|
3573
3633
|
};
|
|
3574
3634
|
const BadgeGroups = (props) => {
|
|
3575
3635
|
const { byBadge } = useFilteredStudents(props.students);
|
|
3576
|
-
|
|
3577
|
-
|
|
3636
|
+
const term = props.search.trim().toLowerCase();
|
|
3637
|
+
const groups = props.badges.map((b) => {
|
|
3638
|
+
const base = byBadge(b.badgeId);
|
|
3639
|
+
const ownNameMatches = !term || b.displayName.toLowerCase().includes(term);
|
|
3640
|
+
const filtered = ownNameMatches ? base : base.filter((s) => matchesSearch(s, term));
|
|
3641
|
+
return { badge: b, filtered };
|
|
3642
|
+
}).filter((g) => !term || g.filtered.length > 0);
|
|
3643
|
+
if (term && groups.length === 0) {
|
|
3644
|
+
return /* @__PURE__ */ React__namespace.createElement("p", { className: "text-sm text-slate-400" }, "No matching entries.");
|
|
3645
|
+
}
|
|
3646
|
+
return /* @__PURE__ */ React__namespace.createElement("div", { className: "flex flex-col gap-3" }, groups.map(({ badge: b, filtered }) => {
|
|
3578
3647
|
const pathwayTitle = props.pathwayNameForBadge[b.badgeId];
|
|
3579
|
-
return /* @__PURE__ */ React__namespace.createElement(
|
|
3648
|
+
return /* @__PURE__ */ React__namespace.createElement(
|
|
3649
|
+
GroupCard,
|
|
3650
|
+
{
|
|
3651
|
+
key: b.badgeId,
|
|
3652
|
+
title: b.displayName,
|
|
3653
|
+
description: pathwayTitle ? `${pathwayTitle} pathway` : void 0,
|
|
3654
|
+
count: countFiles(filtered),
|
|
3655
|
+
onTitleClick: props.onBadgeClick ? () => props.onBadgeClick(b.badgeId) : void 0
|
|
3656
|
+
},
|
|
3657
|
+
/* @__PURE__ */ React__namespace.createElement(
|
|
3658
|
+
Table,
|
|
3659
|
+
{
|
|
3660
|
+
loading: props.loading,
|
|
3661
|
+
items: filtered,
|
|
3662
|
+
hideBadge: true,
|
|
3663
|
+
hidePathway: true,
|
|
3664
|
+
onReview: (item) => props.onReview(item, filtered, b.displayName),
|
|
3665
|
+
onLessonClick: props.onLessonClick
|
|
3666
|
+
}
|
|
3667
|
+
)
|
|
3668
|
+
);
|
|
3580
3669
|
}));
|
|
3581
3670
|
};
|
|
3582
3671
|
const LessonGroups = (props) => {
|
|
3583
3672
|
const { byLesson } = useFilteredStudents(props.students);
|
|
3584
|
-
|
|
3585
|
-
|
|
3673
|
+
const term = props.search.trim().toLowerCase();
|
|
3674
|
+
const groups = props.lessons.map((l) => {
|
|
3675
|
+
const base = byLesson(l.lessonName);
|
|
3676
|
+
const ownNameMatches = !term || l.lessonName.toLowerCase().includes(term);
|
|
3677
|
+
const filtered = ownNameMatches ? base : base.filter((s) => matchesSearch(s, term));
|
|
3678
|
+
return { lesson: l, filtered };
|
|
3679
|
+
}).filter((g) => !term || g.filtered.length > 0);
|
|
3680
|
+
if (term && groups.length === 0) {
|
|
3681
|
+
return /* @__PURE__ */ React__namespace.createElement("p", { className: "text-sm text-slate-400" }, "No matching entries.");
|
|
3682
|
+
}
|
|
3683
|
+
return /* @__PURE__ */ React__namespace.createElement("div", { className: "flex flex-col gap-3" }, groups.map(({ lesson: l, filtered }) => {
|
|
3586
3684
|
const badge = props.badgeForLesson[l.lessonId];
|
|
3587
3685
|
const pathwayTitle = badge ? props.pathwayNameForBadge[badge.badgeId] : void 0;
|
|
3588
3686
|
const description = badge ? pathwayTitle ? `${badge.displayName} \xB7 ${pathwayTitle} pathway` : badge.displayName : void 0;
|
|
3589
|
-
return /* @__PURE__ */ React__namespace.createElement(
|
|
3687
|
+
return /* @__PURE__ */ React__namespace.createElement(
|
|
3688
|
+
GroupCard,
|
|
3689
|
+
{
|
|
3690
|
+
key: l.lessonId,
|
|
3691
|
+
title: l.lessonName,
|
|
3692
|
+
description,
|
|
3693
|
+
count: countFiles(filtered),
|
|
3694
|
+
onTitleClick: props.onLessonClick ? () => props.onLessonClick(l.lessonId) : void 0
|
|
3695
|
+
},
|
|
3696
|
+
/* @__PURE__ */ React__namespace.createElement(Table, { loading: props.loading, items: filtered, hideBadge: true, hideLesson: true, hidePathway: true, onReview: (item) => props.onReview(item, filtered, l.lessonName) })
|
|
3697
|
+
);
|
|
3590
3698
|
}));
|
|
3591
3699
|
};
|
|
3592
3700
|
const FileLocker = (props) => {
|
|
3593
3701
|
const [tab, setTab] = React__namespace.useState("students");
|
|
3594
3702
|
const [reviewing, setReviewing] = React__namespace.useState(null);
|
|
3703
|
+
const [search, setSearch] = React__namespace.useState("");
|
|
3704
|
+
const searchLower = search.trim().toLowerCase();
|
|
3595
3705
|
const numberOfFiles = countFiles(props.students);
|
|
3596
3706
|
const { thisWeek, thisMonth } = React__namespace.useMemo(() => {
|
|
3597
3707
|
const now = new Date();
|
|
@@ -3622,6 +3732,17 @@ const FileLocker = (props) => {
|
|
|
3622
3732
|
});
|
|
3623
3733
|
return map;
|
|
3624
3734
|
}, [props.badges, props.pathways]);
|
|
3735
|
+
const pathwayIdForBadge = React__namespace.useMemo(() => {
|
|
3736
|
+
const map = {};
|
|
3737
|
+
(props.badges || []).forEach((b) => {
|
|
3738
|
+
if (!Array.isArray(b.categories))
|
|
3739
|
+
return;
|
|
3740
|
+
const pathway = (props.pathways || []).find((p) => b.categories.some((c) => c.startsWith(p.pathwayId)));
|
|
3741
|
+
if (pathway)
|
|
3742
|
+
map[b.badgeId] = pathway.pathwayId;
|
|
3743
|
+
});
|
|
3744
|
+
return map;
|
|
3745
|
+
}, [props.badges, props.pathways]);
|
|
3625
3746
|
const badgeForLesson = React__namespace.useMemo(() => {
|
|
3626
3747
|
const map = {};
|
|
3627
3748
|
(props.badges || []).forEach((b) => {
|
|
@@ -3636,9 +3757,12 @@ const FileLocker = (props) => {
|
|
|
3636
3757
|
}, [props.badges]);
|
|
3637
3758
|
const enrichedStudents = React__namespace.useMemo(() => {
|
|
3638
3759
|
return props.students.map((s) => __spreadProps(__spreadValues({}, s), {
|
|
3639
|
-
submissions: (s.submissions || []).map((sub) => __spreadProps(__spreadValues({}, sub), {
|
|
3760
|
+
submissions: (s.submissions || []).map((sub) => __spreadProps(__spreadValues({}, sub), {
|
|
3761
|
+
pathwayName: pathwayNameForBadge[sub.badgeId] || "",
|
|
3762
|
+
pathwayId: pathwayIdForBadge[sub.badgeId]
|
|
3763
|
+
}))
|
|
3640
3764
|
}));
|
|
3641
|
-
}, [props.students, pathwayNameForBadge]);
|
|
3765
|
+
}, [props.students, pathwayNameForBadge, pathwayIdForBadge]);
|
|
3642
3766
|
const { byPathway } = useFilteredStudents(enrichedStudents);
|
|
3643
3767
|
const mostActivePathway = React__namespace.useMemo(() => {
|
|
3644
3768
|
return (props.pathways || []).reduce((best, p) => {
|
|
@@ -3646,6 +3770,10 @@ const FileLocker = (props) => {
|
|
|
3646
3770
|
return count > 0 && (!best || count > best.count) ? { title: p.title, count } : best;
|
|
3647
3771
|
}, null);
|
|
3648
3772
|
}, [props.pathways, props.badges, byPathway]);
|
|
3773
|
+
const searchedStudents = React__namespace.useMemo(
|
|
3774
|
+
() => searchLower ? enrichedStudents.filter((s) => matchesSearch(s, searchLower)) : enrichedStudents,
|
|
3775
|
+
[enrichedStudents, searchLower]
|
|
3776
|
+
);
|
|
3649
3777
|
const onReview = (item, list, context) => setReviewing({ student: item, list, context });
|
|
3650
3778
|
const onNav = (dir) => {
|
|
3651
3779
|
if (!reviewing)
|
|
@@ -3663,7 +3791,10 @@ const FileLocker = (props) => {
|
|
|
3663
3791
|
student: reviewing.student,
|
|
3664
3792
|
context: reviewing.context,
|
|
3665
3793
|
onBack: () => setReviewing(null),
|
|
3666
|
-
onNav
|
|
3794
|
+
onNav,
|
|
3795
|
+
onBadgeClick: props.onBadgeClick,
|
|
3796
|
+
onLessonClick: props.onLessonClick,
|
|
3797
|
+
onPathwayClick: props.onPathwayClick
|
|
3667
3798
|
}
|
|
3668
3799
|
);
|
|
3669
3800
|
}
|
|
@@ -3690,7 +3821,66 @@ const FileLocker = (props) => {
|
|
|
3690
3821
|
className: `rounded-lg px-4 py-2 text-xs font-bold ${tab === t.value ? "bg-sky-blue-400/20 text-dark-blue-400" : "text-slate-400 hover:text-slate-600"}`
|
|
3691
3822
|
},
|
|
3692
3823
|
t.label
|
|
3693
|
-
))), !props.trial &&
|
|
3824
|
+
))), !props.trial && /* @__PURE__ */ React__namespace.createElement("div", { className: "flex items-center gap-2.5 rounded-xl border border-slate-200 bg-white px-4 py-3 shadow-sm" }, /* @__PURE__ */ React__namespace.createElement(icons.IconSearch, { size: 15, stroke: 1.75, className: "text-slate-400" }), /* @__PURE__ */ React__namespace.createElement(
|
|
3825
|
+
"input",
|
|
3826
|
+
{
|
|
3827
|
+
type: "text",
|
|
3828
|
+
value: search,
|
|
3829
|
+
onChange: (e) => setSearch(e.target.value),
|
|
3830
|
+
placeholder: SEARCH_PLACEHOLDER,
|
|
3831
|
+
className: "flex-1 border-none bg-transparent text-sm text-dark-blue-400 outline-none placeholder:text-slate-400"
|
|
3832
|
+
}
|
|
3833
|
+
)), !props.trial && tab === "students" && /* @__PURE__ */ React__namespace.createElement(
|
|
3834
|
+
Table,
|
|
3835
|
+
{
|
|
3836
|
+
loading: props.loading,
|
|
3837
|
+
items: searchedStudents,
|
|
3838
|
+
onReview: (item) => onReview(item, searchedStudents),
|
|
3839
|
+
onBadgeClick: props.onBadgeClick,
|
|
3840
|
+
onLessonClick: props.onLessonClick,
|
|
3841
|
+
onPathwayClick: props.onPathwayClick
|
|
3842
|
+
}
|
|
3843
|
+
), !props.trial && tab === "pathways" && /* @__PURE__ */ React__namespace.createElement(
|
|
3844
|
+
PathwayGroups,
|
|
3845
|
+
{
|
|
3846
|
+
students: enrichedStudents,
|
|
3847
|
+
loading: props.loading,
|
|
3848
|
+
search,
|
|
3849
|
+
pathways: props.pathways || [],
|
|
3850
|
+
badges: props.badges || [],
|
|
3851
|
+
onReview,
|
|
3852
|
+
onBadgeClick: props.onBadgeClick,
|
|
3853
|
+
onLessonClick: props.onLessonClick,
|
|
3854
|
+
onPathwayClick: props.onPathwayClick
|
|
3855
|
+
}
|
|
3856
|
+
), !props.trial && tab === "badges" && /* @__PURE__ */ React__namespace.createElement(
|
|
3857
|
+
BadgeGroups,
|
|
3858
|
+
{
|
|
3859
|
+
students: enrichedStudents,
|
|
3860
|
+
loading: props.loading,
|
|
3861
|
+
search,
|
|
3862
|
+
badges: props.badges || [],
|
|
3863
|
+
pathwayNameForBadge,
|
|
3864
|
+
onReview,
|
|
3865
|
+
onBadgeClick: props.onBadgeClick,
|
|
3866
|
+
onLessonClick: props.onLessonClick,
|
|
3867
|
+
onPathwayClick: props.onPathwayClick
|
|
3868
|
+
}
|
|
3869
|
+
), !props.trial && tab === "lessons" && /* @__PURE__ */ React__namespace.createElement(
|
|
3870
|
+
LessonGroups,
|
|
3871
|
+
{
|
|
3872
|
+
students: enrichedStudents,
|
|
3873
|
+
loading: props.loading,
|
|
3874
|
+
search,
|
|
3875
|
+
lessons: props.lessons,
|
|
3876
|
+
badgeForLesson,
|
|
3877
|
+
pathwayNameForBadge,
|
|
3878
|
+
onReview,
|
|
3879
|
+
onBadgeClick: props.onBadgeClick,
|
|
3880
|
+
onLessonClick: props.onLessonClick,
|
|
3881
|
+
onPathwayClick: props.onPathwayClick
|
|
3882
|
+
}
|
|
3883
|
+
));
|
|
3694
3884
|
};
|
|
3695
3885
|
|
|
3696
3886
|
Object.defineProperty(exports, 'hideNotification', {
|