@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.mjs
CHANGED
|
@@ -578,7 +578,7 @@ const Badge = (props) => {
|
|
|
578
578
|
const [tab, setTab] = useState("lessons");
|
|
579
579
|
const numberOfStudents = props.students.length;
|
|
580
580
|
const numberOfBadges = numberOfStudents > 0 ? props.students.filter((u) => u.isComplete).length : 0;
|
|
581
|
-
return /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-5 px-4 py-8" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-start justify-between gap-4" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-start gap-4" }, /* @__PURE__ */ React.createElement(Emblem, { imageURL: props.imageURL, alt: props.displayName, size: "xl", icon: IconAlbum, accent: "mint" }), /* @__PURE__ */ React.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React.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.createElement(IconArrowLeft, { size: 13, stroke: 2.5 }), "Back"), /* @__PURE__ */ React.createElement("h1", { className: "text-2xl font-extrabold tracking-tight text-dark-blue-400" }, props.displayName || "Badge"), /* @__PURE__ */ React.createElement("p", { className: "max-w-xl text-sm text-slate-500" }, props.description || "No description"))), !props.trial && /* @__PURE__ */ React.createElement(
|
|
581
|
+
return /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-5 px-4 py-8" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-start justify-between gap-4" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-start gap-4" }, /* @__PURE__ */ React.createElement(Emblem, { imageURL: props.imageURL, alt: props.displayName, size: "xl", icon: IconAlbum, accent: "mint" }), /* @__PURE__ */ React.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React.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.createElement(IconArrowLeft, { size: 13, stroke: 2.5 }), "Back"), !!props.pathwayTitle && /* @__PURE__ */ React.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.createElement(IconArrowLeft, { size: 13, stroke: 2.5 }), "Go to Pathway"), /* @__PURE__ */ React.createElement("h1", { className: "text-2xl font-extrabold tracking-tight text-dark-blue-400" }, props.displayName || "Badge"), /* @__PURE__ */ React.createElement("p", { className: "max-w-xl text-sm text-slate-500" }, props.description || "No description"))), !props.trial && /* @__PURE__ */ React.createElement(
|
|
582
582
|
SplitButton$4,
|
|
583
583
|
{
|
|
584
584
|
href: props.href,
|
|
@@ -3070,6 +3070,11 @@ const OTHER_FILTER = "__other__";
|
|
|
3070
3070
|
function Table$1(props) {
|
|
3071
3071
|
const { items: sortedBadges, requestSort, sortConfig } = useSortableData(props.badges);
|
|
3072
3072
|
const [categoryFilter, setCategoryFilter] = React.useState("");
|
|
3073
|
+
React.useEffect(() => {
|
|
3074
|
+
if (props.activeCategoryId !== void 0) {
|
|
3075
|
+
setCategoryFilter(props.activeCategoryId);
|
|
3076
|
+
}
|
|
3077
|
+
}, [props.activeCategoryId]);
|
|
3073
3078
|
if (props.badges.length === 0) {
|
|
3074
3079
|
return /* @__PURE__ */ React.createElement(
|
|
3075
3080
|
PlaceholderBanner,
|
|
@@ -3086,6 +3091,7 @@ function Table$1(props) {
|
|
|
3086
3091
|
var _a;
|
|
3087
3092
|
return !((_a = b.categories) == null ? void 0 : _a.some((id) => groupedIds.has(id)));
|
|
3088
3093
|
});
|
|
3094
|
+
const extraCategory = categoryFilter && categoryFilter !== OTHER_FILTER && !groupedIds.has(categoryFilter) ? { categoryId: categoryFilter, name: props.activeCategoryLabel || categoryFilter } : void 0;
|
|
3089
3095
|
const visibleBadges = !categoryFilter ? sortedBadges : categoryFilter === OTHER_FILTER ? other : sortedBadges.filter((b) => {
|
|
3090
3096
|
var _a;
|
|
3091
3097
|
return (_a = b.categories) == null ? void 0 : _a.includes(categoryFilter);
|
|
@@ -3098,7 +3104,7 @@ function Table$1(props) {
|
|
|
3098
3104
|
active: categoryFilter === category.categoryId,
|
|
3099
3105
|
onClick: () => setCategoryFilter(category.categoryId)
|
|
3100
3106
|
}
|
|
3101
|
-
)), other.length > 0 && /* @__PURE__ */ React.createElement(CategoryPill, { label: "Other", active: categoryFilter === OTHER_FILTER, onClick: () => setCategoryFilter(OTHER_FILTER) })), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex gap-4 px-4" }, /* @__PURE__ */ React.createElement(SortableHeader, { label: "Badge Name", sortKey: "badgeName", sortConfig, onSort: requestSort, className: "flex-1" }), /* @__PURE__ */ React.createElement(SortableHeader, { label: "Point Value", sortKey: "weight", sortConfig, onSort: requestSort, align: "right", className: "w-24 shrink-0" }), /* @__PURE__ */ React.createElement(SortableHeader, { label: "Badge Completion", sortKey: "percentageCompletion", sortConfig, onSort: requestSort, align: "right", className: "w-36 shrink-0" })), visibleBadges.length === 0 && /* @__PURE__ */ React.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.createElement(
|
|
3107
|
+
)), extraCategory && /* @__PURE__ */ React.createElement(CategoryPill, { label: extraCategory.name, active: true, onClick: () => setCategoryFilter(extraCategory.categoryId) }), other.length > 0 && /* @__PURE__ */ React.createElement(CategoryPill, { label: "Other", active: categoryFilter === OTHER_FILTER, onClick: () => setCategoryFilter(OTHER_FILTER) })), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex gap-4 px-4" }, /* @__PURE__ */ React.createElement(SortableHeader, { label: "Badge Name", sortKey: "badgeName", sortConfig, onSort: requestSort, className: "flex-1" }), /* @__PURE__ */ React.createElement(SortableHeader, { label: "Point Value", sortKey: "weight", sortConfig, onSort: requestSort, align: "right", className: "w-24 shrink-0" }), /* @__PURE__ */ React.createElement(SortableHeader, { label: "Badge Completion", sortKey: "percentageCompletion", sortConfig, onSort: requestSort, align: "right", className: "w-36 shrink-0" })), visibleBadges.length === 0 && /* @__PURE__ */ React.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.createElement(
|
|
3102
3108
|
Link,
|
|
3103
3109
|
{
|
|
3104
3110
|
key: row.badgeId,
|
|
@@ -3173,13 +3179,26 @@ function buildCategoryTree(categories) {
|
|
|
3173
3179
|
|
|
3174
3180
|
function CategoriesModal(props) {
|
|
3175
3181
|
const tree = React.useMemo(() => buildCategoryTree(props.categories || []), [props.categories]);
|
|
3176
|
-
return /* @__PURE__ */ React.createElement(Modal, { opened: props.opened, onClose: props.onClose, title: "Category structure", size: "lg", centered: true }, /* @__PURE__ */ React.createElement("div", { className: "flex max-h-[70vh] flex-col gap-2 overflow-y-auto pr-1" }, tree.length === 0 && /* @__PURE__ */ React.createElement("p", { className: "text-sm text-slate-400" }, "No categories to display."), tree.map((node) => /* @__PURE__ */ React.createElement(CategoryNode, { key: node.categoryId, node, criteria: props.criteria, depth: 0 }))));
|
|
3182
|
+
return /* @__PURE__ */ React.createElement(Modal, { opened: props.opened, onClose: props.onClose, title: "Category structure", size: "lg", centered: true }, /* @__PURE__ */ React.createElement("div", { className: "flex max-h-[70vh] flex-col gap-2 overflow-y-auto pr-1" }, tree.length === 0 && /* @__PURE__ */ React.createElement("p", { className: "text-sm text-slate-400" }, "No categories to display."), tree.map((node) => /* @__PURE__ */ React.createElement(CategoryNode, { key: node.categoryId, node, criteria: props.criteria, depth: 0, onCategoryClick: props.onCategoryClick }))));
|
|
3177
3183
|
}
|
|
3178
3184
|
const CategoryNode = (props) => {
|
|
3179
3185
|
var _a;
|
|
3180
3186
|
const hasChildren = props.node.children.length > 0;
|
|
3181
3187
|
const required = props.criteria[props.node.categoryId];
|
|
3182
|
-
|
|
3188
|
+
const clickable = !!props.onCategoryClick;
|
|
3189
|
+
return /* @__PURE__ */ React.createElement(
|
|
3190
|
+
"div",
|
|
3191
|
+
{
|
|
3192
|
+
onClick: clickable ? (e) => {
|
|
3193
|
+
e.stopPropagation();
|
|
3194
|
+
props.onCategoryClick(props.node.categoryId);
|
|
3195
|
+
} : void 0,
|
|
3196
|
+
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" : ""}`
|
|
3197
|
+
},
|
|
3198
|
+
/* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center justify-between gap-2" }, /* @__PURE__ */ React.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.createElement("div", { className: "flex flex-wrap items-center gap-1.5" }, required !== void 0 && /* @__PURE__ */ React.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.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"))),
|
|
3199
|
+
!!((_a = props.node.description) == null ? void 0 : _a.trim()) && /* @__PURE__ */ React.createElement("p", { className: "mt-0.5 text-xs text-slate-500" }, props.node.description),
|
|
3200
|
+
hasChildren && /* @__PURE__ */ React.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.createElement(CategoryNode, { key: child.categoryId, node: child, criteria: props.criteria, depth: props.depth + 1, onCategoryClick: props.onCategoryClick })))
|
|
3201
|
+
);
|
|
3183
3202
|
};
|
|
3184
3203
|
|
|
3185
3204
|
const TABS$1 = [
|
|
@@ -3187,9 +3206,10 @@ const TABS$1 = [
|
|
|
3187
3206
|
{ label: "By student", value: "students" }
|
|
3188
3207
|
];
|
|
3189
3208
|
const Pathway = (props) => {
|
|
3190
|
-
var _a, _b, _c;
|
|
3209
|
+
var _a, _b, _c, _d;
|
|
3191
3210
|
const [tab, setTab] = useState("badges");
|
|
3192
3211
|
const [categoriesOpen, setCategoriesOpen] = useState(false);
|
|
3212
|
+
const [selectedCategoryId, setSelectedCategoryId] = useState(void 0);
|
|
3193
3213
|
const numberOfStudents = props.students.length;
|
|
3194
3214
|
const numberOfBadgesEarned = numberOfStudents > 0 ? props.students.filter((u) => u.isComplete).length : 0;
|
|
3195
3215
|
const criteria = props.criteria || {};
|
|
@@ -3198,7 +3218,8 @@ const Pathway = (props) => {
|
|
|
3198
3218
|
(props.allCategories || []).filter((c) => !c.parentCategoryId).map((c) => c.categoryId)
|
|
3199
3219
|
);
|
|
3200
3220
|
const badgeGroupCategories = criteriaCategories.filter((c) => !rootCategoryIds.has(c.categoryId));
|
|
3201
|
-
|
|
3221
|
+
const selectedCategoryName = selectedCategoryId ? (_a = (props.allCategories || []).find((c) => c.categoryId === selectedCategoryId)) == null ? void 0 : _a.name : void 0;
|
|
3222
|
+
return /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-5 px-4 py-8" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-start justify-between gap-4" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-start gap-4" }, /* @__PURE__ */ React.createElement(Emblem, { imageURL: props.imageURL, alt: props.title, size: "xl", icon: IconRoute, accent: "cyan" }), /* @__PURE__ */ React.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React.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.createElement(IconArrowLeft, { size: 13, stroke: 2.5 }), "Back"), /* @__PURE__ */ React.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.createElement("div", { className: "flex flex-wrap gap-1.5" }, props.displayTags.map((tag) => /* @__PURE__ */ React.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.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.createElement("div", { className: "flex flex-wrap items-center gap-1.5 pt-0.5" }, criteriaCategories.length > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", { className: "text-[10.5px] font-extrabold uppercase tracking-wide text-slate-400" }, "Criteria"), criteriaCategories.map((c) => /* @__PURE__ */ React.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.createElement(
|
|
3202
3223
|
"button",
|
|
3203
3224
|
{
|
|
3204
3225
|
onClick: () => setCategoriesOpen(true),
|
|
@@ -3235,13 +3256,18 @@ const Pathway = (props) => {
|
|
|
3235
3256
|
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"}`
|
|
3236
3257
|
},
|
|
3237
3258
|
t.label
|
|
3238
|
-
))), (!!props.trial || tab === "badges") && /* @__PURE__ */ React.createElement(Table$1, { loading: props.loading, badges: props.badges, categories: badgeGroupCategories }), !props.trial && tab === "students" && /* @__PURE__ */ React.createElement(Table$2, { loading: props.loading, items: props.students, categories: props.categories })), /* @__PURE__ */ React.createElement(
|
|
3259
|
+
))), (!!props.trial || tab === "badges") && /* @__PURE__ */ React.createElement(Table$1, { loading: props.loading, badges: props.badges, categories: badgeGroupCategories, activeCategoryId: selectedCategoryId, activeCategoryLabel: selectedCategoryName }), !props.trial && tab === "students" && /* @__PURE__ */ React.createElement(Table$2, { loading: props.loading, items: props.students, categories: props.categories })), /* @__PURE__ */ React.createElement(
|
|
3239
3260
|
CategoriesModal,
|
|
3240
3261
|
{
|
|
3241
3262
|
opened: categoriesOpen,
|
|
3242
3263
|
onClose: () => setCategoriesOpen(false),
|
|
3243
3264
|
categories: props.allCategories || [],
|
|
3244
|
-
criteria
|
|
3265
|
+
criteria,
|
|
3266
|
+
onCategoryClick: (id) => {
|
|
3267
|
+
setSelectedCategoryId(id);
|
|
3268
|
+
setTab("badges");
|
|
3269
|
+
setCategoriesOpen(false);
|
|
3270
|
+
}
|
|
3245
3271
|
}
|
|
3246
3272
|
));
|
|
3247
3273
|
};
|