@local-civics/mgmt-ui 0.1.224 → 0.1.226
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 +3 -0
- package/dist/index.js +34 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +34 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -136,10 +136,13 @@ type BadgeProps = {
|
|
|
136
136
|
href: string;
|
|
137
137
|
trial?: boolean;
|
|
138
138
|
lessonsCompleted?: number;
|
|
139
|
+
pathwayId?: string;
|
|
140
|
+
pathwayTitle?: string;
|
|
139
141
|
onBackClick: () => void;
|
|
140
142
|
onClassChange: (classId: string) => void;
|
|
141
143
|
onCopyLinkClick: () => void;
|
|
142
144
|
onExportDataClick: () => void;
|
|
145
|
+
onPathwayClick?: () => void;
|
|
143
146
|
};
|
|
144
147
|
/**
|
|
145
148
|
* Badge
|
package/dist/index.js
CHANGED
|
@@ -598,7 +598,7 @@ const Badge = (props) => {
|
|
|
598
598
|
const [tab, setTab] = React.useState("lessons");
|
|
599
599
|
const numberOfStudents = props.students.length;
|
|
600
600
|
const numberOfBadges = numberOfStudents > 0 ? props.students.filter((u) => u.isComplete).length : 0;
|
|
601
|
-
return /* @__PURE__ */ React__namespace.createElement("div", { className: "flex flex-col gap-5 px-4 py-8" }, /* @__PURE__ */ React__namespace.createElement("div", { className: "flex flex-wrap items-start justify-between gap-4" }, /* @__PURE__ */ React__namespace.createElement("div", { className: "flex items-start gap-4" }, /* @__PURE__ */ React__namespace.createElement(Emblem, { imageURL: props.imageURL, alt: props.displayName, size: "xl", icon: icons.IconAlbum, accent: "mint" }), /* @__PURE__ */ React__namespace.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React__namespace.createElement("div", { onClick: props.onBackClick, className: "flex w-max cursor-pointer items-center gap-1 text-xs font-bold text-sky-blue-400" }, /* @__PURE__ */ React__namespace.createElement(icons.IconArrowLeft, { size: 13, stroke: 2.5 }), "Back"), /* @__PURE__ */ React__namespace.createElement("h1", { className: "text-2xl font-extrabold tracking-tight text-dark-blue-400" }, props.displayName || "Badge"), /* @__PURE__ */ React__namespace.createElement("p", { className: "max-w-xl text-sm text-slate-500" }, props.description || "No description"))), !props.trial && /* @__PURE__ */ React__namespace.createElement(
|
|
601
|
+
return /* @__PURE__ */ React__namespace.createElement("div", { className: "flex flex-col gap-5 px-4 py-8" }, /* @__PURE__ */ React__namespace.createElement("div", { className: "flex flex-wrap items-start justify-between gap-4" }, /* @__PURE__ */ React__namespace.createElement("div", { className: "flex items-start gap-4" }, /* @__PURE__ */ React__namespace.createElement(Emblem, { imageURL: props.imageURL, alt: props.displayName, size: "xl", icon: icons.IconAlbum, accent: "mint" }), /* @__PURE__ */ React__namespace.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React__namespace.createElement("div", { onClick: props.onBackClick, className: "flex w-max cursor-pointer items-center gap-1 text-xs font-bold text-sky-blue-400" }, /* @__PURE__ */ React__namespace.createElement(icons.IconArrowLeft, { size: 13, stroke: 2.5 }), "Back"), !!props.pathwayTitle && /* @__PURE__ */ React__namespace.createElement("div", { onClick: props.onPathwayClick, className: "flex w-max cursor-pointer items-center gap-1 text-xs font-bold text-sky-blue-400" }, /* @__PURE__ */ React__namespace.createElement(icons.IconArrowLeft, { size: 13, stroke: 2.5 }), "Go to Pathway"), /* @__PURE__ */ React__namespace.createElement("h1", { className: "text-2xl font-extrabold tracking-tight text-dark-blue-400" }, props.displayName || "Badge"), /* @__PURE__ */ React__namespace.createElement("p", { className: "max-w-xl text-sm text-slate-500" }, props.description || "No description"))), !props.trial && /* @__PURE__ */ React__namespace.createElement(
|
|
602
602
|
SplitButton$4,
|
|
603
603
|
{
|
|
604
604
|
href: props.href,
|
|
@@ -3090,6 +3090,11 @@ const OTHER_FILTER = "__other__";
|
|
|
3090
3090
|
function Table$1(props) {
|
|
3091
3091
|
const { items: sortedBadges, requestSort, sortConfig } = useSortableData(props.badges);
|
|
3092
3092
|
const [categoryFilter, setCategoryFilter] = React__namespace.useState("");
|
|
3093
|
+
React__namespace.useEffect(() => {
|
|
3094
|
+
if (props.activeCategoryId !== void 0) {
|
|
3095
|
+
setCategoryFilter(props.activeCategoryId);
|
|
3096
|
+
}
|
|
3097
|
+
}, [props.activeCategoryId]);
|
|
3093
3098
|
if (props.badges.length === 0) {
|
|
3094
3099
|
return /* @__PURE__ */ React__namespace.createElement(
|
|
3095
3100
|
PlaceholderBanner,
|
|
@@ -3106,6 +3111,7 @@ function Table$1(props) {
|
|
|
3106
3111
|
var _a;
|
|
3107
3112
|
return !((_a = b.categories) == null ? void 0 : _a.some((id) => groupedIds.has(id)));
|
|
3108
3113
|
});
|
|
3114
|
+
const extraCategory = categoryFilter && categoryFilter !== OTHER_FILTER && !groupedIds.has(categoryFilter) ? { categoryId: categoryFilter, name: props.activeCategoryLabel || categoryFilter } : void 0;
|
|
3109
3115
|
const visibleBadges = !categoryFilter ? sortedBadges : categoryFilter === OTHER_FILTER ? other : sortedBadges.filter((b) => {
|
|
3110
3116
|
var _a;
|
|
3111
3117
|
return (_a = b.categories) == null ? void 0 : _a.includes(categoryFilter);
|
|
@@ -3118,7 +3124,7 @@ function Table$1(props) {
|
|
|
3118
3124
|
active: categoryFilter === category.categoryId,
|
|
3119
3125
|
onClick: () => setCategoryFilter(category.categoryId)
|
|
3120
3126
|
}
|
|
3121
|
-
)), other.length > 0 && /* @__PURE__ */ React__namespace.createElement(CategoryPill, { label: "Other", active: categoryFilter === OTHER_FILTER, onClick: () => setCategoryFilter(OTHER_FILTER) })), /* @__PURE__ */ React__namespace.createElement("div", { className: "flex flex-col gap-2" }, /* @__PURE__ */ React__namespace.createElement("div", { className: "flex gap-4 px-4" }, /* @__PURE__ */ React__namespace.createElement(SortableHeader, { label: "Badge Name", sortKey: "badgeName", sortConfig, onSort: requestSort, className: "flex-1" }), /* @__PURE__ */ React__namespace.createElement(SortableHeader, { label: "Point Value", sortKey: "weight", sortConfig, onSort: requestSort, align: "right", className: "w-24 shrink-0" }), /* @__PURE__ */ React__namespace.createElement(SortableHeader, { label: "Badge Completion", sortKey: "percentageCompletion", sortConfig, onSort: requestSort, align: "right", className: "w-36 shrink-0" })), visibleBadges.length === 0 && /* @__PURE__ */ React__namespace.createElement("div", { className: "rounded-xl border border-dashed border-slate-200 px-4 py-3 text-xs text-slate-400" }, categoryFilter ? "No badges in this category yet." : "No badges yet."), visibleBadges.map((row) => /* @__PURE__ */ React__namespace.createElement(
|
|
3127
|
+
)), extraCategory && /* @__PURE__ */ React__namespace.createElement(CategoryPill, { label: extraCategory.name, active: true, onClick: () => setCategoryFilter(extraCategory.categoryId) }), other.length > 0 && /* @__PURE__ */ React__namespace.createElement(CategoryPill, { label: "Other", active: categoryFilter === OTHER_FILTER, onClick: () => setCategoryFilter(OTHER_FILTER) })), /* @__PURE__ */ React__namespace.createElement("div", { className: "flex flex-col gap-2" }, /* @__PURE__ */ React__namespace.createElement("div", { className: "flex gap-4 px-4" }, /* @__PURE__ */ React__namespace.createElement(SortableHeader, { label: "Badge Name", sortKey: "badgeName", sortConfig, onSort: requestSort, className: "flex-1" }), /* @__PURE__ */ React__namespace.createElement(SortableHeader, { label: "Point Value", sortKey: "weight", sortConfig, onSort: requestSort, align: "right", className: "w-24 shrink-0" }), /* @__PURE__ */ React__namespace.createElement(SortableHeader, { label: "Badge Completion", sortKey: "percentageCompletion", sortConfig, onSort: requestSort, align: "right", className: "w-36 shrink-0" })), visibleBadges.length === 0 && /* @__PURE__ */ React__namespace.createElement("div", { className: "rounded-xl border border-dashed border-slate-200 px-4 py-3 text-xs text-slate-400" }, categoryFilter ? "No badges in this category yet." : "No badges yet."), visibleBadges.map((row) => /* @__PURE__ */ React__namespace.createElement(
|
|
3122
3128
|
reactRouterDom.Link,
|
|
3123
3129
|
{
|
|
3124
3130
|
key: row.badgeId,
|
|
@@ -3193,13 +3199,26 @@ function buildCategoryTree(categories) {
|
|
|
3193
3199
|
|
|
3194
3200
|
function CategoriesModal(props) {
|
|
3195
3201
|
const tree = React__namespace.useMemo(() => buildCategoryTree(props.categories || []), [props.categories]);
|
|
3196
|
-
return /* @__PURE__ */ React__namespace.createElement(core.Modal, { opened: props.opened, onClose: props.onClose, title: "Category structure", size: "lg", centered: true }, /* @__PURE__ */ React__namespace.createElement("div", { className: "flex max-h-[70vh] flex-col gap-2 overflow-y-auto pr-1" }, tree.length === 0 && /* @__PURE__ */ React__namespace.createElement("p", { className: "text-sm text-slate-400" }, "No categories to display."), tree.map((node) => /* @__PURE__ */ React__namespace.createElement(CategoryNode, { key: node.categoryId, node, criteria: props.criteria, depth: 0 }))));
|
|
3202
|
+
return /* @__PURE__ */ React__namespace.createElement(core.Modal, { opened: props.opened, onClose: props.onClose, title: "Category structure", size: "lg", centered: true }, /* @__PURE__ */ React__namespace.createElement("div", { className: "flex max-h-[70vh] flex-col gap-2 overflow-y-auto pr-1" }, tree.length === 0 && /* @__PURE__ */ React__namespace.createElement("p", { className: "text-sm text-slate-400" }, "No categories to display."), tree.map((node) => /* @__PURE__ */ React__namespace.createElement(CategoryNode, { key: node.categoryId, node, criteria: props.criteria, depth: 0, onCategoryClick: props.onCategoryClick }))));
|
|
3197
3203
|
}
|
|
3198
3204
|
const CategoryNode = (props) => {
|
|
3199
3205
|
var _a;
|
|
3200
3206
|
const hasChildren = props.node.children.length > 0;
|
|
3201
3207
|
const required = props.criteria[props.node.categoryId];
|
|
3202
|
-
|
|
3208
|
+
const clickable = !!props.onCategoryClick;
|
|
3209
|
+
return /* @__PURE__ */ React__namespace.createElement(
|
|
3210
|
+
"div",
|
|
3211
|
+
{
|
|
3212
|
+
onClick: clickable ? (e) => {
|
|
3213
|
+
e.stopPropagation();
|
|
3214
|
+
props.onCategoryClick(props.node.categoryId);
|
|
3215
|
+
} : void 0,
|
|
3216
|
+
className: `${hasChildren ? "rounded-lg border border-slate-100 bg-slate-50/60 p-3" : "rounded-lg px-3 py-2 hover:bg-slate-50"} ${clickable ? "cursor-pointer" : ""}`
|
|
3217
|
+
},
|
|
3218
|
+
/* @__PURE__ */ React__namespace.createElement("div", { className: "flex flex-wrap items-center justify-between gap-2" }, /* @__PURE__ */ React__namespace.createElement("span", { className: props.depth === 0 ? "text-sm font-extrabold text-dark-blue-400" : "text-xs font-bold text-dark-blue-400" }, props.node.name), /* @__PURE__ */ React__namespace.createElement("div", { className: "flex flex-wrap items-center gap-1.5" }, required !== void 0 && /* @__PURE__ */ React__namespace.createElement("span", { className: "rounded-full bg-sky-blue-400/15 px-2 py-0.5 text-[10px] font-bold text-dark-blue-400" }, "min. ", required, " pts"), !!props.node.maxPoints && /* @__PURE__ */ React__namespace.createElement("span", { className: "rounded-full bg-gold-400/15 px-2 py-0.5 text-[10px] font-bold text-dark-blue-400" }, "cap ", props.node.maxPoints, " pts"))),
|
|
3219
|
+
!!((_a = props.node.description) == null ? void 0 : _a.trim()) && /* @__PURE__ */ React__namespace.createElement("p", { className: "mt-0.5 text-xs text-slate-500" }, props.node.description),
|
|
3220
|
+
hasChildren && /* @__PURE__ */ React__namespace.createElement("div", { className: "mt-3 flex flex-col gap-2 border-l-2 border-slate-200 pl-4" }, props.node.children.map((child) => /* @__PURE__ */ React__namespace.createElement(CategoryNode, { key: child.categoryId, node: child, criteria: props.criteria, depth: props.depth + 1, onCategoryClick: props.onCategoryClick })))
|
|
3221
|
+
);
|
|
3203
3222
|
};
|
|
3204
3223
|
|
|
3205
3224
|
const TABS$1 = [
|
|
@@ -3207,9 +3226,10 @@ const TABS$1 = [
|
|
|
3207
3226
|
{ label: "By student", value: "students" }
|
|
3208
3227
|
];
|
|
3209
3228
|
const Pathway = (props) => {
|
|
3210
|
-
var _a, _b, _c;
|
|
3229
|
+
var _a, _b, _c, _d;
|
|
3211
3230
|
const [tab, setTab] = React.useState("badges");
|
|
3212
3231
|
const [categoriesOpen, setCategoriesOpen] = React.useState(false);
|
|
3232
|
+
const [selectedCategoryId, setSelectedCategoryId] = React.useState(void 0);
|
|
3213
3233
|
const numberOfStudents = props.students.length;
|
|
3214
3234
|
const numberOfBadgesEarned = numberOfStudents > 0 ? props.students.filter((u) => u.isComplete).length : 0;
|
|
3215
3235
|
const criteria = props.criteria || {};
|
|
@@ -3218,7 +3238,8 @@ const Pathway = (props) => {
|
|
|
3218
3238
|
(props.allCategories || []).filter((c) => !c.parentCategoryId).map((c) => c.categoryId)
|
|
3219
3239
|
);
|
|
3220
3240
|
const badgeGroupCategories = criteriaCategories.filter((c) => !rootCategoryIds.has(c.categoryId));
|
|
3221
|
-
|
|
3241
|
+
const selectedCategoryName = selectedCategoryId ? (_a = (props.allCategories || []).find((c) => c.categoryId === selectedCategoryId)) == null ? void 0 : _a.name : void 0;
|
|
3242
|
+
return /* @__PURE__ */ React__namespace.createElement("div", { className: "flex flex-col gap-5 px-4 py-8" }, /* @__PURE__ */ React__namespace.createElement("div", { className: "flex flex-wrap items-start justify-between gap-4" }, /* @__PURE__ */ React__namespace.createElement("div", { className: "flex items-start gap-4" }, /* @__PURE__ */ React__namespace.createElement(Emblem, { imageURL: props.imageURL, alt: props.title, size: "xl", icon: icons.IconRoute, accent: "cyan" }), /* @__PURE__ */ React__namespace.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React__namespace.createElement("div", { onClick: props.onBackClick, className: "flex w-max cursor-pointer items-center gap-1 text-xs font-bold text-sky-blue-400" }, /* @__PURE__ */ React__namespace.createElement(icons.IconArrowLeft, { size: 13, stroke: 2.5 }), "Back"), /* @__PURE__ */ React__namespace.createElement("h1", { className: "text-2xl font-extrabold tracking-tight text-dark-blue-400" }, props.title || "Pathway"), !!((_b = props.displayTags) == null ? void 0 : _b.length) && /* @__PURE__ */ React__namespace.createElement("div", { className: "flex flex-wrap gap-1.5" }, props.displayTags.map((tag) => /* @__PURE__ */ React__namespace.createElement("span", { key: tag, className: "rounded-full bg-slate-100 px-2.5 py-1 text-[10px] font-bold text-slate-500" }, tag))), /* @__PURE__ */ React__namespace.createElement("p", { className: "max-w-xl text-sm text-slate-500" }, props.description || "No description"), (criteriaCategories.length > 0 || !!((_c = props.allCategories) == null ? void 0 : _c.length)) && /* @__PURE__ */ React__namespace.createElement("div", { className: "flex flex-wrap items-center gap-1.5 pt-0.5" }, criteriaCategories.length > 0 && /* @__PURE__ */ React__namespace.createElement(React__namespace.Fragment, null, /* @__PURE__ */ React__namespace.createElement("span", { className: "text-[10.5px] font-extrabold uppercase tracking-wide text-slate-400" }, "Criteria"), criteriaCategories.map((c) => /* @__PURE__ */ React__namespace.createElement("span", { key: c.categoryId, className: "rounded-full bg-sky-blue-400/15 px-2.5 py-1 text-[10px] font-bold text-dark-blue-400" }, c.name, ": ", criteria[c.categoryId], "+", c.maxPoints ? ` of ${c.maxPoints}` : "", " pts"))), !!((_d = props.allCategories) == null ? void 0 : _d.length) && /* @__PURE__ */ React__namespace.createElement(
|
|
3222
3243
|
"button",
|
|
3223
3244
|
{
|
|
3224
3245
|
onClick: () => setCategoriesOpen(true),
|
|
@@ -3255,13 +3276,18 @@ const Pathway = (props) => {
|
|
|
3255
3276
|
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"}`
|
|
3256
3277
|
},
|
|
3257
3278
|
t.label
|
|
3258
|
-
))), (!!props.trial || tab === "badges") && /* @__PURE__ */ React__namespace.createElement(Table$1, { loading: props.loading, badges: props.badges, categories: badgeGroupCategories }), !props.trial && tab === "students" && /* @__PURE__ */ React__namespace.createElement(Table$2, { loading: props.loading, items: props.students, categories: props.categories })), /* @__PURE__ */ React__namespace.createElement(
|
|
3279
|
+
))), (!!props.trial || tab === "badges") && /* @__PURE__ */ React__namespace.createElement(Table$1, { loading: props.loading, badges: props.badges, categories: badgeGroupCategories, activeCategoryId: selectedCategoryId, activeCategoryLabel: selectedCategoryName }), !props.trial && tab === "students" && /* @__PURE__ */ React__namespace.createElement(Table$2, { loading: props.loading, items: props.students, categories: props.categories })), /* @__PURE__ */ React__namespace.createElement(
|
|
3259
3280
|
CategoriesModal,
|
|
3260
3281
|
{
|
|
3261
3282
|
opened: categoriesOpen,
|
|
3262
3283
|
onClose: () => setCategoriesOpen(false),
|
|
3263
3284
|
categories: props.allCategories || [],
|
|
3264
|
-
criteria
|
|
3285
|
+
criteria,
|
|
3286
|
+
onCategoryClick: (id) => {
|
|
3287
|
+
setSelectedCategoryId(id);
|
|
3288
|
+
setTab("badges");
|
|
3289
|
+
setCategoriesOpen(false);
|
|
3290
|
+
}
|
|
3265
3291
|
}
|
|
3266
3292
|
));
|
|
3267
3293
|
};
|