@local-civics/mgmt-ui 0.1.61 → 0.1.63

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.mjs CHANGED
@@ -1,9 +1,9 @@
1
- import { NotificationsProvider } from '@mantine/notifications';
2
- export { showNotification, updateNotification } from '@mantine/notifications';
3
- import { IconChevronDown, IconClipboardCopy, IconTableExport, IconArrowLeft, IconCategory2, IconPlaylistAdd, IconCheck, IconTrash, IconDownload, IconX, IconCloudUpload, IconInfoCircle, IconColorSwatch, IconSwitchHorizontal, IconLogout, IconHome2, IconGauge, IconAlbum, IconLambda, IconBrandInstagram, IconBrandLinkedin, IconBrandFacebook } from '@tabler/icons';
4
1
  import * as React from 'react';
5
2
  import { useState } from 'react';
6
- import { createStyles, Text, Tabs as Tabs$1, Group, Button, Menu, ActionIcon, Title, Image, Grid, Badge as Badge$1, ScrollArea, UnstyledButton, Avatar, Table as Table$g, Container, Stack as Stack$3, LoadingOverlay, Select, Autocomplete, Drawer, Divider, TextInput, Tooltip, Paper, ThemeIcon, Card, Overlay, createEmotionCache, MantineProvider, Modal, Navbar as Navbar$1, Center, AppShell, Loader } from '@mantine/core';
3
+ import { createStyles, Navbar as Navbar$1, Center, Avatar, Image, Stack as Stack$3, Tooltip, UnstyledButton, Group, Text, Box, Badge as Badge$1, ThemeIcon, Collapse, Burger, Code, ScrollArea, Card, Modal, Loader, SimpleGrid, Tabs as Tabs$1, Button, Menu, ActionIcon, Title, Grid, Table as Table$g, Container, LoadingOverlay, Select, Autocomplete, Drawer, Divider, TextInput, Paper, Overlay, createEmotionCache, MantineProvider, AppShell } from '@mantine/core';
4
+ import { IconSwitchHorizontal, IconLogout, IconHome2, IconGauge, IconCategory2, IconAlbum, IconLambda, IconChevronRight, IconChevronLeft, IconBuilding, IconBatteryEco, IconBooks, IconBackpack, IconChevronDown, IconClipboardCopy, IconTableExport, IconArrowLeft, IconPlaylistAdd, IconCheck, IconTrash, IconDownload, IconX, IconCloudUpload, IconInfoCircle, IconColorSwatch, IconBrandInstagram, IconBrandLinkedin, IconBrandFacebook } from '@tabler/icons';
5
+ import { NotificationsProvider } from '@mantine/notifications';
6
+ export { showNotification, updateNotification } from '@mantine/notifications';
7
7
  import { DataTable } from 'mantine-datatable';
8
8
  import { Dropzone, MIME_TYPES } from '@mantine/dropzone';
9
9
  import { useForm } from '@mantine/form';
@@ -11,7 +11,415 @@ import * as papa from 'papaparse';
11
11
  import { openConfirmModal, ModalsProvider } from '@mantine/modals';
12
12
  import { Chart } from 'react-charts';
13
13
 
14
+ const useStyles$j = createStyles((theme) => ({
15
+ link: {
16
+ width: 50,
17
+ height: 50,
18
+ borderRadius: theme.radius.md,
19
+ display: "flex",
20
+ alignItems: "center",
21
+ justifyContent: "center",
22
+ color: theme.colorScheme === "dark" ? theme.colors.dark[0] : theme.colors.gray[7],
23
+ "&:hover": {
24
+ backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[5] : theme.colors.gray[0]
25
+ }
26
+ },
27
+ active: {
28
+ "&, &:hover": {
29
+ backgroundColor: theme.fn.variant({ variant: "light", color: theme.primaryColor }).background,
30
+ color: theme.fn.variant({ variant: "light", color: theme.primaryColor }).color
31
+ }
32
+ }
33
+ }));
34
+ const data$1 = [
35
+ { icon: IconHome2, label: "Home", href: "/home" },
36
+ { icon: IconGauge, label: "Dashboard", href: "/dashboard" },
37
+ { icon: IconCategory2, label: "Classes", href: "/classes" },
38
+ { icon: IconAlbum, label: "Badges", href: "/badges" },
39
+ { icon: IconLambda, label: "Lessons", href: "/lessons" }
40
+ ];
41
+ const NavbarLink = ({ icon: Icon, label, active, onClick }) => {
42
+ const { classes, cx } = useStyles$j();
43
+ return /* @__PURE__ */ React.createElement(Tooltip, { label, position: "right", transitionDuration: 0 }, /* @__PURE__ */ React.createElement(UnstyledButton, { onClick, className: cx(classes.link, { [classes.active]: active }) }, /* @__PURE__ */ React.createElement(Icon, { stroke: 1.5 })));
44
+ };
45
+ const Navbar = (props) => {
46
+ const links = data$1.map((link) => /* @__PURE__ */ React.createElement(
47
+ NavbarLink,
48
+ {
49
+ key: link.label,
50
+ label: link.label,
51
+ icon: link.icon,
52
+ active: link.label === props.active,
53
+ onClick: () => props.navigate(link.href)
54
+ }
55
+ ));
56
+ return /* @__PURE__ */ React.createElement(Navbar$1, { width: { base: 80 }, p: "md" }, /* @__PURE__ */ React.createElement(Center, null, /* @__PURE__ */ React.createElement(Avatar, { color: "blue", radius: "sm" }, /* @__PURE__ */ React.createElement("div", { style: { width: 15, marginLeft: "auto", marginRight: "auto" } }, /* @__PURE__ */ React.createElement(Image, { fit: "contain", src: "https://cdn.localcivics.io/brand/l.png" })))), /* @__PURE__ */ React.createElement(Navbar$1.Section, { grow: true, mt: 50 }, /* @__PURE__ */ React.createElement(Stack$3, { justify: "center", spacing: 0 }, links)), /* @__PURE__ */ React.createElement(Navbar$1.Section, null, /* @__PURE__ */ React.createElement(Stack$3, { justify: "center", spacing: 0 }, /* @__PURE__ */ React.createElement(
57
+ NavbarLink,
58
+ {
59
+ icon: IconSwitchHorizontal,
60
+ label: "Switch accounts",
61
+ onClick: props.onSwitchAccounts
62
+ }
63
+ ), /* @__PURE__ */ React.createElement(
64
+ NavbarLink,
65
+ {
66
+ icon: IconLogout,
67
+ label: "Logout",
68
+ onClick: props.onLogout
69
+ }
70
+ ))));
71
+ };
72
+
73
+ var __defProp$5 = Object.defineProperty;
74
+ var __getOwnPropSymbols$5 = Object.getOwnPropertySymbols;
75
+ var __hasOwnProp$5 = Object.prototype.hasOwnProperty;
76
+ var __propIsEnum$5 = Object.prototype.propertyIsEnumerable;
77
+ var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
78
+ var __spreadValues$5 = (a, b) => {
79
+ for (var prop in b || (b = {}))
80
+ if (__hasOwnProp$5.call(b, prop))
81
+ __defNormalProp$5(a, prop, b[prop]);
82
+ if (__getOwnPropSymbols$5)
83
+ for (var prop of __getOwnPropSymbols$5(b)) {
84
+ if (__propIsEnum$5.call(b, prop))
85
+ __defNormalProp$5(a, prop, b[prop]);
86
+ }
87
+ return a;
88
+ };
89
+ var __objRest$1 = (source, exclude) => {
90
+ var target = {};
91
+ for (var prop in source)
92
+ if (__hasOwnProp$5.call(source, prop) && exclude.indexOf(prop) < 0)
93
+ target[prop] = source[prop];
94
+ if (source != null && __getOwnPropSymbols$5)
95
+ for (var prop of __getOwnPropSymbols$5(source)) {
96
+ if (exclude.indexOf(prop) < 0 && __propIsEnum$5.call(source, prop))
97
+ target[prop] = source[prop];
98
+ }
99
+ return target;
100
+ };
101
+ const useStyles$i = createStyles((theme) => ({
102
+ user: {
103
+ display: "block",
104
+ width: "100%",
105
+ padding: theme.spacing.md,
106
+ cursor: "default",
107
+ color: theme.colorScheme === "dark" ? theme.colors.dark[0] : theme.black
108
+ }
109
+ }));
110
+ function UserButton(_a) {
111
+ var _b = _a, { image, name, email, icon } = _b, others = __objRest$1(_b, ["image", "name", "email", "icon"]);
112
+ const { classes } = useStyles$i();
113
+ return /* @__PURE__ */ React.createElement(Group, __spreadValues$5({ className: classes.user }, others), /* @__PURE__ */ React.createElement(Avatar, { src: image, radius: "xl" }), /* @__PURE__ */ React.createElement("div", { style: { flex: 1 } }, /* @__PURE__ */ React.createElement(Text, { size: "sm", weight: 500 }, name), /* @__PURE__ */ React.createElement(Text, { color: "dimmed", size: "xs" }, email)));
114
+ }
115
+
116
+ const compact = (num) => {
117
+ return Intl.NumberFormat("en-US", {
118
+ notation: "compact",
119
+ maximumFractionDigits: 1
120
+ }).format(num || 0);
121
+ };
122
+
123
+ const useStyles$h = createStyles((theme, _params, getRef) => {
124
+ const icon = getRef("icon");
125
+ return {
126
+ control: {
127
+ fontWeight: 500,
128
+ width: "100%",
129
+ padding: `${theme.spacing.xs}px ${theme.spacing.md}px`,
130
+ color: theme.colorScheme === "dark" ? theme.colors.dark[0] : theme.black,
131
+ fontSize: theme.fontSizes.sm,
132
+ "&:hover": {
133
+ backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[7] : theme.colors.gray[0],
134
+ color: theme.colorScheme === "dark" ? theme.white : theme.black
135
+ }
136
+ },
137
+ controlButton: {
138
+ cursor: "pointer"
139
+ },
140
+ badge: {
141
+ pointerEvents: "none"
142
+ },
143
+ link: {
144
+ fontWeight: 500,
145
+ display: "block",
146
+ textDecoration: "none",
147
+ padding: `${theme.spacing.xs}px ${theme.spacing.md}px`,
148
+ paddingLeft: 31,
149
+ marginLeft: 30,
150
+ fontSize: theme.fontSizes.sm,
151
+ color: theme.colorScheme === "dark" ? theme.colors.dark[0] : theme.colors.gray[7],
152
+ borderLeft: `1px solid ${theme.colorScheme === "dark" ? theme.colors.dark[4] : theme.colors.gray[3]}`,
153
+ "&:hover": {
154
+ backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[7] : theme.colors.gray[0],
155
+ color: theme.colorScheme === "dark" ? theme.white : theme.black
156
+ }
157
+ },
158
+ linkActive: {
159
+ "&, &:hover": {
160
+ backgroundColor: theme.fn.variant({ variant: "light", color: theme.primaryColor }).background,
161
+ color: theme.fn.variant({ variant: "light", color: theme.primaryColor }).color,
162
+ [`& .${icon}`]: {
163
+ color: theme.fn.variant({ variant: "light", color: theme.primaryColor }).color
164
+ }
165
+ }
166
+ },
167
+ chevron: {
168
+ transition: "transform 200ms ease"
169
+ },
170
+ linkIcon: {
171
+ ref: icon
172
+ }
173
+ };
174
+ });
175
+ function LinksGroup({ icon: Icon, href, label, initiallyOpened, links, active, notifications }) {
176
+ const { classes, theme, cx } = useStyles$h();
177
+ const hasLinks = Array.isArray(links) && links.length > 0;
178
+ const hasActiveLinks = Array.isArray(links) && links.map((l) => !!active && active === `${label}/${l.label}`).reduce((a, b) => a || b, false);
179
+ const [opened, setOpened] = useState(initiallyOpened || hasActiveLinks || false);
180
+ React.useEffect(() => {
181
+ setOpened(hasActiveLinks);
182
+ }, [hasActiveLinks]);
183
+ const ChevronIcon = theme.dir === "ltr" ? IconChevronRight : IconChevronLeft;
184
+ const items = (hasLinks ? links : []).map((link) => {
185
+ return /* @__PURE__ */ React.createElement(
186
+ Box,
187
+ {
188
+ className: cx(classes.link, { [classes.linkActive]: !!active && active === `${label}/${link.label}` }),
189
+ key: link.label
190
+ },
191
+ /* @__PURE__ */ React.createElement(Group, { position: "apart", spacing: 0 }, /* @__PURE__ */ React.createElement(Text, { component: "a", href: link.href }, link.label), !!link.notifications && /* @__PURE__ */ React.createElement(Badge$1, { size: "sm", variant: "filled", className: classes.badge }, compact(link.notifications)))
192
+ );
193
+ });
194
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
195
+ Group,
196
+ {
197
+ className: cx(classes.control, {
198
+ [classes.linkActive]: !!active && !hasLinks && label === active,
199
+ [classes.controlButton]: hasLinks
200
+ }),
201
+ onClick: () => setOpened((o) => !o),
202
+ position: "apart",
203
+ spacing: 0
204
+ },
205
+ /* @__PURE__ */ React.createElement(Box, { sx: { display: "flex", alignItems: "center" } }, /* @__PURE__ */ React.createElement(ThemeIcon, { variant: "light", size: 30 }, /* @__PURE__ */ React.createElement(Icon, { className: classes.linkIcon, size: 18 })), /* @__PURE__ */ React.createElement(Box, { ml: "md" }, /* @__PURE__ */ React.createElement(Text, { component: "a", href }, label))),
206
+ !!notifications && /* @__PURE__ */ React.createElement(Badge$1, { size: "sm", variant: "filled", className: classes.badge }, compact(notifications)),
207
+ hasLinks && /* @__PURE__ */ React.createElement(
208
+ ChevronIcon,
209
+ {
210
+ className: classes.chevron,
211
+ size: 14,
212
+ stroke: 1.5,
213
+ style: {
214
+ transform: opened ? `rotate(${theme.dir === "rtl" ? -90 : 90}deg)` : "none"
215
+ }
216
+ }
217
+ )
218
+ ), hasLinks ? /* @__PURE__ */ React.createElement(Collapse, { in: opened }, items) : null);
219
+ }
220
+
221
+ var __defProp$4 = Object.defineProperty;
222
+ var __defProps$2 = Object.defineProperties;
223
+ var __getOwnPropDescs$2 = Object.getOwnPropertyDescriptors;
224
+ var __getOwnPropSymbols$4 = Object.getOwnPropertySymbols;
225
+ var __hasOwnProp$4 = Object.prototype.hasOwnProperty;
226
+ var __propIsEnum$4 = Object.prototype.propertyIsEnumerable;
227
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
228
+ var __spreadValues$4 = (a, b) => {
229
+ for (var prop in b || (b = {}))
230
+ if (__hasOwnProp$4.call(b, prop))
231
+ __defNormalProp$4(a, prop, b[prop]);
232
+ if (__getOwnPropSymbols$4)
233
+ for (var prop of __getOwnPropSymbols$4(b)) {
234
+ if (__propIsEnum$4.call(b, prop))
235
+ __defNormalProp$4(a, prop, b[prop]);
236
+ }
237
+ return a;
238
+ };
239
+ var __spreadProps$2 = (a, b) => __defProps$2(a, __getOwnPropDescs$2(b));
240
+ const useStyles$g = createStyles((theme, _params, getRef) => {
241
+ const icon = getRef("icon");
242
+ return {
243
+ navbar: {
244
+ backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[6] : theme.white
245
+ },
246
+ navBody: {
247
+ [`@media (max-width: ${theme.breakpoints.sm}px)`]: {
248
+ display: "none"
249
+ }
250
+ },
251
+ burger: {
252
+ [theme.fn.largerThan("sm")]: {
253
+ display: "none"
254
+ }
255
+ },
256
+ header: {
257
+ padding: theme.spacing.md,
258
+ paddingTop: 0,
259
+ marginLeft: -theme.spacing.md,
260
+ marginRight: -theme.spacing.md,
261
+ color: theme.colorScheme === "dark" ? theme.white : theme.black,
262
+ borderBottom: `1px solid ${theme.colorScheme === "dark" ? theme.colors.dark[4] : theme.colors.gray[3]}`
263
+ },
264
+ link: __spreadProps$2(__spreadValues$4({}, theme.fn.focusStyles()), {
265
+ display: "flex",
266
+ alignItems: "center",
267
+ textDecoration: "none",
268
+ fontSize: theme.fontSizes.sm,
269
+ color: theme.colorScheme === "dark" ? theme.colors.dark[1] : theme.colors.gray[7],
270
+ padding: `${theme.spacing.xs}px ${theme.spacing.sm}px`,
271
+ borderRadius: theme.radius.sm,
272
+ fontWeight: 500,
273
+ "&:hover": {
274
+ backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[6] : theme.colors.gray[0],
275
+ color: theme.colorScheme === "dark" ? theme.white : theme.black,
276
+ [`& .${icon}`]: {
277
+ color: theme.colorScheme === "dark" ? theme.white : theme.black
278
+ }
279
+ }
280
+ }),
281
+ linkIcon: {
282
+ ref: icon,
283
+ color: theme.colorScheme === "dark" ? theme.colors.dark[2] : theme.colors.gray[6],
284
+ marginRight: theme.spacing.sm
285
+ },
286
+ links: {
287
+ marginLeft: -theme.spacing.md,
288
+ marginRight: -theme.spacing.md
289
+ },
290
+ user: {
291
+ margin: theme.spacing.md,
292
+ marginLeft: 0,
293
+ marginRight: 0
294
+ },
295
+ linksInner: {
296
+ paddingBottom: theme.spacing.xl
297
+ },
298
+ footer: {
299
+ paddingTop: theme.spacing.md,
300
+ paddingBottom: theme.spacing.md,
301
+ borderTop: `1px solid ${theme.colorScheme === "dark" ? theme.colors.dark[4] : theme.colors.gray[2]}`
302
+ },
303
+ active: {
304
+ "&, &:hover": {
305
+ backgroundColor: theme.fn.variant({ variant: "light", color: theme.primaryColor }).background,
306
+ color: theme.fn.variant({ variant: "light", color: theme.primaryColor }).color
307
+ }
308
+ }
309
+ };
310
+ });
311
+ const data = [
312
+ { label: "Home", icon: IconHome2 },
313
+ { label: "Dashboard", icon: IconGauge },
314
+ { label: "Classes", icon: IconCategory2 },
315
+ { label: "Badges", icon: IconAlbum },
316
+ { label: "Lessons", icon: IconLambda },
317
+ {
318
+ label: "Organization",
319
+ icon: IconBuilding,
320
+ links: [
321
+ { label: "Overview" },
322
+ { label: "People" }
323
+ ]
324
+ }
325
+ ];
326
+ function NestedNavbar(props) {
327
+ const { classes, cx } = useStyles$g();
328
+ const [burgerOpen, setBurgerOpen] = React.useState(false);
329
+ const toggle = () => setBurgerOpen(!burgerOpen);
330
+ const links = data.map((item) => {
331
+ const context = props.links[item.label] || { notifications: 0, href: "" };
332
+ if (context.hidden) {
333
+ return null;
334
+ }
335
+ return /* @__PURE__ */ React.createElement(
336
+ LinksGroup,
337
+ __spreadProps$2(__spreadValues$4(__spreadValues$4({
338
+ key: item.label,
339
+ active: props.active
340
+ }, item), context), {
341
+ links: (item.links || []).map((link) => {
342
+ return __spreadValues$4(__spreadValues$4({}, link), props.links[`${item.label}/${link.label}`] || { notifications: 0, href: "" });
343
+ })
344
+ })
345
+ );
346
+ });
347
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Burger, { opened: burgerOpen, onClick: toggle, className: classes.burger, size: "sm" }), /* @__PURE__ */ React.createElement(Navbar$1, { width: { sm: 300 }, p: "md", className: classes.navbar }, /* @__PURE__ */ React.createElement(Navbar$1.Section, { className: classes.header }, /* @__PURE__ */ React.createElement(Group, { position: "apart" }, /* @__PURE__ */ React.createElement(Center, null, /* @__PURE__ */ React.createElement(Avatar, { color: "blue", radius: "sm" }, /* @__PURE__ */ React.createElement("div", { style: { width: 15, marginLeft: "auto", marginRight: "auto" } }, /* @__PURE__ */ React.createElement(Image, { fit: "contain", src: "https://cdn.localcivics.io/brand/l.png" })))), /* @__PURE__ */ React.createElement(Group, { position: "apart" }, /* @__PURE__ */ React.createElement(Code, { sx: { fontWeight: 700 } }, props.version), /* @__PURE__ */ React.createElement(Burger, { opened: burgerOpen, onClick: toggle, className: classes.burger, size: "sm" })))), /* @__PURE__ */ React.createElement("div", { className: cx({ [classes.navBody]: !burgerOpen }) }, /* @__PURE__ */ React.createElement(
348
+ UserButton,
349
+ {
350
+ className: classes.user,
351
+ image: props.image,
352
+ name: props.name,
353
+ email: props.email
354
+ }
355
+ ), /* @__PURE__ */ React.createElement(Navbar$1.Section, { grow: true, className: classes.links, component: ScrollArea }, /* @__PURE__ */ React.createElement("div", { className: classes.linksInner }, links)), /* @__PURE__ */ React.createElement(Navbar$1.Section, { className: classes.footer }, !!props.onSwitchAccounts && /* @__PURE__ */ React.createElement("a", { href: "#", className: classes.link, onClick: (event) => {
356
+ event.preventDefault();
357
+ props.onSwitchAccounts && props.onSwitchAccounts();
358
+ } }, /* @__PURE__ */ React.createElement(IconSwitchHorizontal, { className: classes.linkIcon, stroke: 1.5 }), /* @__PURE__ */ React.createElement("span", null, "Change account")), /* @__PURE__ */ React.createElement("a", { href: "#", className: classes.link, onClick: (event) => {
359
+ event.preventDefault();
360
+ props.onLogout();
361
+ } }, /* @__PURE__ */ React.createElement(IconLogout, { className: classes.linkIcon, stroke: 1.5 }), /* @__PURE__ */ React.createElement("span", null, "Logout"))))));
362
+ }
363
+
14
364
  const useStyles$f = createStyles((theme) => ({
365
+ title: {
366
+ fontSize: 34,
367
+ fontWeight: 900,
368
+ [theme.fn.smallerThan("sm")]: {
369
+ fontSize: 24
370
+ }
371
+ },
372
+ description: {
373
+ maxWidth: 600,
374
+ margin: "auto",
375
+ "&::after": {
376
+ content: '""',
377
+ display: "block",
378
+ backgroundColor: theme.fn.primaryColor(),
379
+ width: 45,
380
+ height: 2,
381
+ marginTop: theme.spacing.sm,
382
+ marginLeft: "auto",
383
+ marginRight: "auto"
384
+ }
385
+ },
386
+ card: {
387
+ transition: "box-shadow 150ms ease, transform 100ms ease",
388
+ "&:hover": {
389
+ boxShadow: `${theme.shadows.md} !important`,
390
+ transform: "scale(1.05)"
391
+ }
392
+ },
393
+ cardTitle: {
394
+ "&::after": {
395
+ content: '""',
396
+ display: "block",
397
+ backgroundColor: theme.fn.primaryColor(),
398
+ width: 45,
399
+ height: 2,
400
+ marginTop: theme.spacing.sm
401
+ }
402
+ }
403
+ }));
404
+ const SwitchAccount = (props) => {
405
+ const { classes, theme } = useStyles$f();
406
+ const options = props.accounts.map((a) => {
407
+ return /* @__PURE__ */ React.createElement(UnstyledButton, { onClick: () => props.onClick && props.onClick(a.accountId), key: a.accountId, p: theme.spacing.md }, /* @__PURE__ */ React.createElement(Card, { withBorder: true, shadow: "md", radius: "md", className: classes.card, p: "xl" }, a.isAdmin && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(IconBatteryEco, { size: 50, stroke: 2, color: theme.fn.primaryColor() })), a.isGroupAdmin && !a.isAdmin && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(IconBooks, { size: 50, stroke: 2, color: theme.fn.primaryColor() })), !a.isAdmin && !a.isGroupAdmin && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(IconBackpack, { size: 50, stroke: 2, color: theme.fn.primaryColor() })), /* @__PURE__ */ React.createElement(Text, { size: "lg", weight: 500, className: classes.cardTitle, mt: "md" }, a.name), /* @__PURE__ */ React.createElement(Text, { size: "sm", color: "dimmed", mt: "sm" }, a.isAdmin ? "Admin" : a.isGroupAdmin ? "Educator" : "Student")));
408
+ });
409
+ return /* @__PURE__ */ React.createElement(
410
+ Modal,
411
+ {
412
+ centered: true,
413
+ fullScreen: true,
414
+ opened: props.opened,
415
+ onClose: () => props.onClose && props.onClose(),
416
+ size: "sm"
417
+ },
418
+ /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, props.loading && /* @__PURE__ */ React.createElement(Center, { style: { height: 400 } }, /* @__PURE__ */ React.createElement(Loader, null)), !props.loading && /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 600 }, /* @__PURE__ */ React.createElement(SimpleGrid, { cols: 3, spacing: "xl", breakpoints: [{ maxWidth: "md", cols: 1 }] }, options)))
419
+ );
420
+ };
421
+
422
+ const useStyles$e = createStyles((theme) => ({
15
423
  root: {
16
424
  display: "flex",
17
425
  backgroundImage: `linear-gradient(-60deg, ${theme.colors[theme.primaryColor][4]} 0%, ${theme.colors[theme.primaryColor][7]} 100%)`,
@@ -58,7 +466,7 @@ const useStyles$f = createStyles((theme) => ({
58
466
  }
59
467
  }));
60
468
  const StatsGroup = ({ data }) => {
61
- const { classes } = useStyles$f();
469
+ const { classes } = useStyles$e();
62
470
  const stats = data.map((stat) => {
63
471
  const value = (() => {
64
472
  if (stat.unit === "%") {
@@ -77,7 +485,7 @@ const Tabs = (props) => {
77
485
  return /* @__PURE__ */ React.createElement(Tabs$1, { value: props.value, onTabChange: props.onChange }, /* @__PURE__ */ React.createElement(Tabs$1.List, null, tabs));
78
486
  };
79
487
 
80
- const useStyles$e = createStyles((theme) => ({
488
+ const useStyles$d = createStyles((theme) => ({
81
489
  button: {
82
490
  borderTopRightRadius: 0,
83
491
  borderBottomRightRadius: 0,
@@ -92,14 +500,15 @@ const useStyles$e = createStyles((theme) => ({
92
500
  }
93
501
  }));
94
502
  const SplitButton$2 = (props) => {
95
- const { classes, theme } = useStyles$e();
503
+ const { classes, theme } = useStyles$d();
96
504
  const menuIconColor = theme.colors[theme.primaryColor][theme.colorScheme === "dark" ? 5 : 6];
97
505
  return /* @__PURE__ */ React.createElement(Group, { noWrap: true, spacing: 0 }, /* @__PURE__ */ React.createElement(
98
506
  Button,
99
507
  {
508
+ component: "a",
509
+ href: props.href,
100
510
  className: classes.button,
101
- variant: "gradient",
102
- onClick: props.onPreviewClick
511
+ variant: "gradient"
103
512
  },
104
513
  "Preview"
105
514
  ), /* @__PURE__ */ React.createElement(Menu, { transition: "pop", position: "bottom-end" }, /* @__PURE__ */ React.createElement(Menu.Target, null, /* @__PURE__ */ React.createElement(
@@ -128,7 +537,7 @@ const SplitButton$2 = (props) => {
128
537
  ))));
129
538
  };
130
539
 
131
- const useStyles$d = createStyles((theme) => ({
540
+ const useStyles$c = createStyles((theme) => ({
132
541
  wrapper: {
133
542
  display: "flex",
134
543
  alignItems: "center",
@@ -179,7 +588,7 @@ const useStyles$d = createStyles((theme) => ({
179
588
  }
180
589
  }));
181
590
  const PlaceholderBanner = (props) => {
182
- const { classes } = useStyles$d();
591
+ const { classes } = useStyles$c();
183
592
  const title = props.title || "Nothing to display";
184
593
  const description = props.description || "We don't have anything to show you here just yet. Add data, check back later, or adjust your search.";
185
594
  return /* @__PURE__ */ React.createElement("div", { className: classes.wrapper }, /* @__PURE__ */ React.createElement("div", { className: classes.body }, /* @__PURE__ */ React.createElement(Title, { className: classes.title }, props.loading ? "Loading..." : title), /* @__PURE__ */ React.createElement(Text, { size: "sm", color: "dimmed" }, props.loading ? "Hold on, we're loading your data." : description)), /* @__PURE__ */ React.createElement(Image, { src: `https://cdn.localcivics.io/illustrations/${props.icon}.svg`, className: classes.image }));
@@ -189,7 +598,7 @@ function Stack$2(props) {
189
598
  if (props.items.length === 0) {
190
599
  return null;
191
600
  }
192
- const rows = props.items.map((row) => /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Grid.Col, { span: 6 }, /* @__PURE__ */ React.createElement(Title, { color: "dark.4", size: "lg" }, row.lessonName)), /* @__PURE__ */ React.createElement(Grid.Col, { span: 6 }, row.completion >= 1 && /* @__PURE__ */ React.createElement(Badge$1, { variant: "filled" }, "Complete"), row.completion === 0 && !row.isStarted && /* @__PURE__ */ React.createElement(Badge$1, { color: "red", variant: "filled" }, "Not started"), row.completion > 0 && row.completion < 1 && /* @__PURE__ */ React.createElement(Badge$1, { color: "violet", variant: "filled" }, Math.round((row.completion + Number.EPSILON) * 100), "% Complete"))));
601
+ const rows = props.items.map((row) => /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Grid.Col, { span: 6 }, /* @__PURE__ */ React.createElement(Text, { component: "a", href: row.href, color: "dark.4", weight: "bold", size: "md" }, row.lessonName)), /* @__PURE__ */ React.createElement(Grid.Col, { span: 6 }, row.completion >= 1 && /* @__PURE__ */ React.createElement(Badge$1, { variant: "filled" }, "Complete"), row.completion === 0 && !row.isStarted && /* @__PURE__ */ React.createElement(Badge$1, { color: "red", variant: "filled" }, "Not started"), row.completion > 0 && row.completion < 1 && /* @__PURE__ */ React.createElement(Badge$1, { color: "violet", variant: "filled" }, Math.round((row.completion + Number.EPSILON) * 100), "% Complete"))));
193
602
  return /* @__PURE__ */ React.createElement(Grid, { grow: true, gutter: "lg", sx: { padding: 20, minWidth: 700 } }, rows);
194
603
  }
195
604
 
@@ -205,7 +614,7 @@ function Table$f(props) {
205
614
  }
206
615
  );
207
616
  }
208
- return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(
617
+ return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 600 }, /* @__PURE__ */ React.createElement(
209
618
  DataTable,
210
619
  {
211
620
  verticalSpacing: "sm",
@@ -220,7 +629,7 @@ function Table$f(props) {
220
629
  columns: [{
221
630
  accessor: "name",
222
631
  title: "Student Name",
223
- render: (row) => /* @__PURE__ */ React.createElement(UnstyledButton, null, /* @__PURE__ */ React.createElement(Group, { spacing: "sm" }, /* @__PURE__ */ React.createElement(Avatar, { size: 40, src: row.avatar, radius: 40 }), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Text, { size: "sm", weight: 500 }, row.name), /* @__PURE__ */ React.createElement(Text, { size: "xs", color: "dimmed" }, row.email))))
632
+ render: (row) => /* @__PURE__ */ React.createElement(Group, { spacing: "sm" }, /* @__PURE__ */ React.createElement(Avatar, { size: 40, src: row.avatar, radius: 40 }), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Text, { size: "sm", weight: 500 }, row.name), /* @__PURE__ */ React.createElement(Text, { component: "a", size: "xs", color: "dimmed" }, row.email)))
224
633
  }, {
225
634
  accessor: "status",
226
635
  render: (row) => /* @__PURE__ */ React.createElement(React.Fragment, null, !!row.isComplete && /* @__PURE__ */ React.createElement(Badge$1, { variant: "filled" }, "Complete"), !row.isComplete && /* @__PURE__ */ React.createElement(Badge$1, { color: "red", variant: "filled" }, "Incomplete"))
@@ -246,12 +655,12 @@ function Table$e(props) {
246
655
  }
247
656
  const rows = props.items.map((row) => {
248
657
  const percentageCompletion = Math.round((row.percentageCompletion + Number.EPSILON) * 100);
249
- return /* @__PURE__ */ React.createElement("tr", { key: row.lessonName }, /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(UnstyledButton, { onClick: () => props.onClick && props.onClick(row) }, row.lessonName)), /* @__PURE__ */ React.createElement("td", null, percentageCompletion, "%"));
658
+ return /* @__PURE__ */ React.createElement("tr", { key: row.lessonName }, /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(Text, { href: row.href, component: "a" }, row.lessonName)), /* @__PURE__ */ React.createElement("td", null, percentageCompletion, "%"));
250
659
  });
251
- return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Lesson Name"), /* @__PURE__ */ React.createElement("th", null, "Lesson Completion"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
660
+ return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 600 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Lesson Name"), /* @__PURE__ */ React.createElement("th", null, "Lesson Completion"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
252
661
  }
253
662
 
254
- const useStyles$c = createStyles((theme) => ({
663
+ const useStyles$b = createStyles((theme) => ({
255
664
  title: {
256
665
  fontSize: 34,
257
666
  fontWeight: 900,
@@ -264,22 +673,22 @@ const useStyles$c = createStyles((theme) => ({
264
673
  }
265
674
  }));
266
675
  const Badge = (props) => {
267
- const { classes } = useStyles$c();
676
+ const { classes } = useStyles$b();
268
677
  const [tab, setTab] = useState("lessons");
269
678
  const numberOfStudents = props.students.length;
270
679
  const percentageOfBadgesEarned = numberOfStudents > 0 ? props.students.filter((u) => u.isComplete).length / numberOfStudents : 0;
271
- return /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: "md" }, /* @__PURE__ */ React.createElement(Grid, null, /* @__PURE__ */ React.createElement(Grid.Col, { sm: "auto" }, /* @__PURE__ */ React.createElement(
680
+ return /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: "md" }, /* @__PURE__ */ React.createElement(Grid, null, /* @__PURE__ */ React.createElement(Grid.Col, { sm: "auto" }, /* @__PURE__ */ React.createElement(UnstyledButton, { onClick: props.onBackClick }, /* @__PURE__ */ React.createElement(
272
681
  Badge$1,
273
682
  {
274
683
  variant: "filled",
275
- leftSection: /* @__PURE__ */ React.createElement(ActionIcon, { onClick: props.onBackClick, color: "blue", size: "xs", radius: "xl", variant: "filled" }, /* @__PURE__ */ React.createElement(IconArrowLeft, { size: 14 })),
684
+ leftSection: /* @__PURE__ */ React.createElement(ActionIcon, { color: "blue", size: "xs", radius: "xl", variant: "filled" }, /* @__PURE__ */ React.createElement(IconArrowLeft, { size: 14 })),
276
685
  size: "lg"
277
686
  },
278
687
  "Badges"
279
- ), /* @__PURE__ */ React.createElement(Group, null, /* @__PURE__ */ React.createElement(Stack$3, { spacing: 0 }, /* @__PURE__ */ React.createElement(Title, { order: 2, className: classes.title, mt: "md" }, props.displayName || "Badge"), /* @__PURE__ */ React.createElement(Text, { color: "dimmed", className: classes.description, mt: "sm" }, props.description || "No description")), /* @__PURE__ */ React.createElement(Stack$3, { ml: "auto" }, /* @__PURE__ */ React.createElement(
688
+ )), /* @__PURE__ */ React.createElement(Group, null, /* @__PURE__ */ React.createElement(Stack$3, { spacing: 0 }, /* @__PURE__ */ React.createElement(Title, { order: 2, className: classes.title, mt: "md" }, props.displayName || "Badge"), /* @__PURE__ */ React.createElement(Text, { color: "dimmed", className: classes.description, mt: "sm" }, props.description || "No description")), /* @__PURE__ */ React.createElement(Stack$3, { ml: "auto" }, /* @__PURE__ */ React.createElement(
280
689
  SplitButton$2,
281
690
  {
282
- onPreviewClick: props.onPreviewClick,
691
+ href: props.href,
283
692
  onCopyLinkClick: props.onCopyLinkClick,
284
693
  onExportDataClick: props.onExportDataClick
285
694
  }
@@ -318,15 +727,13 @@ const Badge = (props) => {
318
727
  Table$e,
319
728
  {
320
729
  loading: props.loading,
321
- items: props.lessons,
322
- onClick: props.onLessonClick
730
+ items: props.lessons
323
731
  }
324
732
  ), tab === "students" && /* @__PURE__ */ React.createElement(
325
733
  Table$f,
326
734
  {
327
735
  loading: props.loading,
328
- items: props.students,
329
- onClick: props.onUserClick
736
+ items: props.students
330
737
  }
331
738
  )))))));
332
739
  };
@@ -346,6 +753,8 @@ function Table$d(props) {
346
753
  const rows = props.items.map((row) => /* @__PURE__ */ React.createElement("tr", { key: row.badgeId }, /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(
347
754
  UnstyledButton,
348
755
  {
756
+ component: "a",
757
+ href: row.href,
349
758
  sx: (theme) => ({
350
759
  display: "block",
351
760
  width: "100%",
@@ -354,15 +763,14 @@ function Table$d(props) {
354
763
  "&:hover": {
355
764
  backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[8] : theme.colors.gray[1]
356
765
  }
357
- }),
358
- onClick: () => props.onClick && props.onClick(row)
766
+ })
359
767
  },
360
768
  /* @__PURE__ */ React.createElement(Group, null, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Text, { size: "sm", weight: 500 }, row.name), /* @__PURE__ */ React.createElement(Text, { size: "xs", color: "dimmed" }, row.description)))
361
769
  ))));
362
- return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(Table$g, { horizontalSpacing: 0, verticalSpacing: 0, sx: { minWidth: 700 } }, /* @__PURE__ */ React.createElement("tbody", null, rows)));
770
+ return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 600 }, /* @__PURE__ */ React.createElement(Table$g, { horizontalSpacing: 0, verticalSpacing: 0, sx: { minWidth: 700 } }, /* @__PURE__ */ React.createElement("tbody", null, rows)));
363
771
  }
364
772
 
365
- const useStyles$b = createStyles((theme) => ({
773
+ const useStyles$a = createStyles((theme) => ({
366
774
  title: {
367
775
  fontSize: 34,
368
776
  fontWeight: 900,
@@ -375,7 +783,7 @@ const useStyles$b = createStyles((theme) => ({
375
783
  }
376
784
  }));
377
785
  const Badges = (props) => {
378
- const { classes } = useStyles$b();
786
+ const { classes } = useStyles$a();
379
787
  return /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: "md" }, /* @__PURE__ */ React.createElement(Grid, null, /* @__PURE__ */ React.createElement(Grid.Col, { sm: "auto" }, /* @__PURE__ */ React.createElement(Badge$1, { variant: "filled", size: "lg" }, "Badges"), /* @__PURE__ */ React.createElement(Title, { order: 2, className: classes.title, mt: "md" }, "Badges and micro-credentials"), /* @__PURE__ */ React.createElement(Text, { color: "dimmed", className: classes.description, mt: "sm" }, "Project-sized skills acquisition and standards alignment."))), /* @__PURE__ */ React.createElement(
380
788
  Autocomplete,
381
789
  {
@@ -387,8 +795,7 @@ const Badges = (props) => {
387
795
  Table$d,
388
796
  {
389
797
  loading: props.loading,
390
- items: props.badges,
391
- onClick: props.onBadgeClick
798
+ items: props.badges
392
799
  }
393
800
  ))));
394
801
  };
@@ -406,7 +813,7 @@ function Table$c(props) {
406
813
  );
407
814
  }
408
815
  const rows = props.items.map((row) => /* @__PURE__ */ React.createElement("tr", { key: row.studentName }, /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(UnstyledButton, { onClick: () => props.onViewProfile(row) }, row.studentName)), /* @__PURE__ */ React.createElement("td", null, row.className)));
409
- return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Student Name"), /* @__PURE__ */ React.createElement("th", null, "Class Name"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
816
+ return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 600 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Student Name"), /* @__PURE__ */ React.createElement("th", null, "Class Name"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
410
817
  }
411
818
 
412
819
  const units = [
@@ -446,7 +853,7 @@ function Table$b(props) {
446
853
  );
447
854
  }
448
855
  const rows = props.items.map((row) => /* @__PURE__ */ React.createElement("tr", { key: row.studentName + row.lessonName }, /* @__PURE__ */ React.createElement("td", null, row.studentName), /* @__PURE__ */ React.createElement("td", null, row.lessonName), /* @__PURE__ */ React.createElement("td", null, row.reflection), /* @__PURE__ */ React.createElement("td", null, relativeTimeFromDates(new Date(row.updatedAt)))));
449
- return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Student Name"), /* @__PURE__ */ React.createElement("th", null, "Lesson Name"), /* @__PURE__ */ React.createElement("th", null, "Reflection"), /* @__PURE__ */ React.createElement("th", null, "Updated At"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
856
+ return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 600 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Student Name"), /* @__PURE__ */ React.createElement("th", null, "Lesson Name"), /* @__PURE__ */ React.createElement("th", null, "Reflection"), /* @__PURE__ */ React.createElement("th", null, "Updated At"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
450
857
  }
451
858
 
452
859
  function Table$a(props) {
@@ -462,7 +869,7 @@ function Table$a(props) {
462
869
  );
463
870
  }
464
871
  const rows = props.items.map((row) => /* @__PURE__ */ React.createElement("tr", { key: row.studentName }, /* @__PURE__ */ React.createElement("td", null, row.studentName), /* @__PURE__ */ React.createElement("td", null, row.impactStatement)));
465
- return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Student Name"), /* @__PURE__ */ React.createElement("th", null, "Impact Statement"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
872
+ return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 600 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Student Name"), /* @__PURE__ */ React.createElement("th", null, "Impact Statement"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
466
873
  }
467
874
 
468
875
  function Table$9(props) {
@@ -478,7 +885,7 @@ function Table$9(props) {
478
885
  );
479
886
  }
480
887
  const rows = props.items.map((row) => /* @__PURE__ */ React.createElement("tr", { key: row.badgeId }, /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(UnstyledButton, { onClick: () => props.onClick && props.onClick(row) }, row.name)), /* @__PURE__ */ React.createElement("td", null, row.description), /* @__PURE__ */ React.createElement("td", null, Math.round((row.percentageCompletion + Number.EPSILON) * 100), "%")));
481
- return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Badge Name"), /* @__PURE__ */ React.createElement("th", null, "Description"), /* @__PURE__ */ React.createElement("th", null, "Completion"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
888
+ return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 600 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Badge Name"), /* @__PURE__ */ React.createElement("th", null, "Description"), /* @__PURE__ */ React.createElement("th", null, "Completion"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
482
889
  }
483
890
 
484
891
  function Table$8(props) {
@@ -494,7 +901,7 @@ function Table$8(props) {
494
901
  );
495
902
  }
496
903
  const rows = props.items.map((row) => /* @__PURE__ */ React.createElement("tr", { key: row.lessonId }, /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(UnstyledButton, { onClick: () => props.onClick && props.onClick(row) }, row.name)), /* @__PURE__ */ React.createElement("td", null, row.description), /* @__PURE__ */ React.createElement("td", null, Math.round((row.percentageCompletion + Number.EPSILON) * 100), "%")));
497
- return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Lesson Name"), /* @__PURE__ */ React.createElement("th", null, "Description"), /* @__PURE__ */ React.createElement("th", null, "Completion"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
904
+ return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 600 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Lesson Name"), /* @__PURE__ */ React.createElement("th", null, "Description"), /* @__PURE__ */ React.createElement("th", null, "Completion"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
498
905
  }
499
906
 
500
907
  const Dashboard = (props) => {
@@ -583,7 +990,7 @@ const Dashboard = (props) => {
583
990
  )))))));
584
991
  };
585
992
 
586
- const useStyles$a = createStyles((theme) => ({
993
+ const useStyles$9 = createStyles((theme) => ({
587
994
  button: {
588
995
  borderTopRightRadius: 0,
589
996
  borderBottomRightRadius: 0,
@@ -598,7 +1005,7 @@ const useStyles$a = createStyles((theme) => ({
598
1005
  }
599
1006
  }));
600
1007
  const SplitButton$1 = (props) => {
601
- const { classes, theme } = useStyles$a();
1008
+ const { classes, theme } = useStyles$9();
602
1009
  const menuIconColor = theme.colors[theme.primaryColor][theme.colorScheme === "dark" ? 5 : 6];
603
1010
  const hasMenu = !!props.withClassLink;
604
1011
  return /* @__PURE__ */ React.createElement(Group, { noWrap: true, spacing: 0 }, /* @__PURE__ */ React.createElement(
@@ -606,9 +1013,9 @@ const SplitButton$1 = (props) => {
606
1013
  {
607
1014
  className: hasMenu ? classes.button : "",
608
1015
  leftIcon: /* @__PURE__ */ React.createElement(IconPlaylistAdd, { size: 14 }),
609
- onClick: props.onAddStudentsClick
1016
+ onClick: props.onAddMembersClick
610
1017
  },
611
- "Add students"
1018
+ "Add members"
612
1019
  ), hasMenu && /* @__PURE__ */ React.createElement(Menu, { transition: "pop", position: "bottom-end" }, /* @__PURE__ */ React.createElement(Menu.Target, null, /* @__PURE__ */ React.createElement(
613
1020
  ActionIcon,
614
1021
  {
@@ -633,7 +1040,7 @@ function Table$7(props) {
633
1040
  return /* @__PURE__ */ React.createElement(
634
1041
  PlaceholderBanner,
635
1042
  {
636
- title: "No students to display",
1043
+ title: "No members to display",
637
1044
  description: "You have not rostered any students yet.",
638
1045
  loading: props.loading,
639
1046
  icon: "groups"
@@ -648,13 +1055,21 @@ function Table$7(props) {
648
1055
  confirmProps: { color: "red" },
649
1056
  onConfirm: () => props.onDelete && props.onDelete(student)
650
1057
  });
651
- const rows = props.items.map((row) => /* @__PURE__ */ React.createElement("tr", { key: row.email }, /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(UnstyledButton, { onClick: () => props.onViewProfile && props.onViewProfile(row) }, /* @__PURE__ */ React.createElement(Group, { spacing: "sm" }, /* @__PURE__ */ React.createElement(Avatar, { size: 40, src: row.avatar, radius: 40 }), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Text, { size: "sm", weight: 500 }, row.givenName && row.familyName ? `${row.givenName} ${row.familyName}` : row.email), /* @__PURE__ */ React.createElement(Text, { size: "xs", color: "dimmed" }, row.email))))), /* @__PURE__ */ React.createElement("td", null, row.badgesEarned), /* @__PURE__ */ React.createElement("td", null, row.lessonsCompleted), /* @__PURE__ */ React.createElement("td", null, row.hasAccount && /* @__PURE__ */ React.createElement(IconCheck, { color: "green" })), /* @__PURE__ */ React.createElement("td", null, row.lastActivity ? relativeTimeFromDates(row.lastActivity) : ""), /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(Group, { noWrap: true, spacing: 0, position: "right" }, !row.readonly && !!props.onDelete && /* @__PURE__ */ React.createElement(ActionIcon, { color: "red" }, /* @__PURE__ */ React.createElement(IconTrash, { onClick: () => openDeleteModal(row), size: 16, stroke: 1.5 }))))));
652
- return /* @__PURE__ */ React.createElement(ScrollArea, null, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: 20, sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Student Name"), /* @__PURE__ */ React.createElement("th", null, "Badges Earned"), /* @__PURE__ */ React.createElement("th", null, "Lessons Completed"), /* @__PURE__ */ React.createElement("th", null, "Account Created?"), /* @__PURE__ */ React.createElement("th", null, "Last Active"), /* @__PURE__ */ React.createElement("th", null))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
1058
+ const rows = props.items.map((row) => /* @__PURE__ */ React.createElement("tr", { key: row.email }, /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(UnstyledButton, { component: "a", href: row.href }, /* @__PURE__ */ React.createElement(Group, { spacing: "sm" }, /* @__PURE__ */ React.createElement(Avatar, { size: 40, src: row.avatar, radius: 40 }), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Text, { size: "sm", weight: 500 }, row.givenName && row.familyName ? `${row.givenName} ${row.familyName}` : row.email), /* @__PURE__ */ React.createElement(Text, { size: "xs", color: "dimmed" }, row.email))))), /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(Box, { maw: 100 }, /* @__PURE__ */ React.createElement(
1059
+ Select,
1060
+ {
1061
+ size: "sm",
1062
+ value: row.isAdmin ? "admin" : "member",
1063
+ onChange: (value) => props.onRoleChange && props.onRoleChange(row, value),
1064
+ data: [{ value: "member", label: "Member" }, { value: "admin", label: "Admin" }]
1065
+ }
1066
+ ))), /* @__PURE__ */ React.createElement("td", null, row.badgesEarned), /* @__PURE__ */ React.createElement("td", null, row.lessonsCompleted), /* @__PURE__ */ React.createElement("td", null, row.hasAccount && /* @__PURE__ */ React.createElement(IconCheck, { color: "green" })), /* @__PURE__ */ React.createElement("td", null, row.lastActivity ? relativeTimeFromDates(row.lastActivity) : ""), /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(Group, { noWrap: true, spacing: 0, position: "right" }, !row.readonly && !!props.onDelete && /* @__PURE__ */ React.createElement(ActionIcon, { color: "red" }, /* @__PURE__ */ React.createElement(IconTrash, { onClick: () => openDeleteModal(row), size: 16, stroke: 1.5 }))))));
1067
+ return /* @__PURE__ */ React.createElement(ScrollArea, null, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: 20, sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Name"), /* @__PURE__ */ React.createElement("th", null, "Role"), /* @__PURE__ */ React.createElement("th", null, "Badges Earned"), /* @__PURE__ */ React.createElement("th", null, "Lessons Completed"), /* @__PURE__ */ React.createElement("th", null, "Account Created?"), /* @__PURE__ */ React.createElement("th", null, "Last Active"), /* @__PURE__ */ React.createElement("th", null))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
653
1068
  }
654
1069
 
655
1070
  var __defProp$3 = Object.defineProperty;
656
- var __defProps = Object.defineProperties;
657
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
1071
+ var __defProps$1 = Object.defineProperties;
1072
+ var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors;
658
1073
  var __getOwnPropSymbols$3 = Object.getOwnPropertySymbols;
659
1074
  var __hasOwnProp$3 = Object.prototype.hasOwnProperty;
660
1075
  var __propIsEnum$3 = Object.prototype.propertyIsEnumerable;
@@ -670,8 +1085,8 @@ var __spreadValues$3 = (a, b) => {
670
1085
  }
671
1086
  return a;
672
1087
  };
673
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
674
- const useStyles$9 = createStyles((theme) => ({
1088
+ var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b));
1089
+ const useStyles$8 = createStyles((theme) => ({
675
1090
  title: {
676
1091
  fontSize: 34,
677
1092
  fontWeight: 900,
@@ -682,6 +1097,9 @@ const useStyles$9 = createStyles((theme) => ({
682
1097
  description: {
683
1098
  maxWidth: 600
684
1099
  },
1100
+ autocomplete: {
1101
+ maxWidth: 400
1102
+ },
685
1103
  wrapper: {
686
1104
  position: "relative",
687
1105
  marginBottom: 30
@@ -701,11 +1119,11 @@ const useStyles$9 = createStyles((theme) => ({
701
1119
  }
702
1120
  }));
703
1121
  const Class = (props) => {
704
- const { classes } = useStyles$9();
1122
+ const { classes } = useStyles$8();
705
1123
  const form = useForm({
706
1124
  initialValues: {
707
1125
  classId: "",
708
- studentId: "",
1126
+ userId: "",
709
1127
  email: "",
710
1128
  givenName: "",
711
1129
  familyName: "",
@@ -715,10 +1133,12 @@ const Class = (props) => {
715
1133
  lastActivity: null,
716
1134
  hasAccount: false,
717
1135
  lessonsCompleted: 0,
718
- badgesEarned: 0
1136
+ badgesEarned: 0,
1137
+ href: "",
1138
+ isAdmin: false
719
1139
  },
720
1140
  validate: {
721
- email: (value) => /^\S+@\S+$/.test(value) && props.students.filter((u) => u.email === value).length === 0 ? null : "Invalid email"
1141
+ email: (value) => /^\S+@\S+$/.test(value) && props.members.filter((u) => u.email === value).length === 0 ? null : "Invalid email"
722
1142
  }
723
1143
  });
724
1144
  const [opened, setOpened] = useState(false);
@@ -727,15 +1147,15 @@ const Class = (props) => {
727
1147
  {
728
1148
  opened,
729
1149
  onClose: () => setOpened(false),
730
- title: /* @__PURE__ */ React.createElement(Title, { size: "h5" }, "Add students"),
1150
+ title: /* @__PURE__ */ React.createElement(Title, { size: "h5" }, "Add members"),
731
1151
  padding: "xl",
732
1152
  size: "xl"
733
1153
  },
734
- /* @__PURE__ */ React.createElement(Stack$3, { spacing: "md" }, /* @__PURE__ */ React.createElement(DropzoneButton, __spreadProps(__spreadValues$3({}, props), { close: () => setOpened(false) })), /* @__PURE__ */ React.createElement(Divider, { label: "or", labelPosition: "center", my: "md", variant: "dashed" }), /* @__PURE__ */ React.createElement("form", { onSubmit: form.onSubmit(() => {
1154
+ /* @__PURE__ */ React.createElement(Stack$3, { spacing: "md" }, /* @__PURE__ */ React.createElement(DropzoneButton, __spreadProps$1(__spreadValues$3({}, props), { close: () => setOpened(false) })), /* @__PURE__ */ React.createElement(Divider, { label: "or", labelPosition: "center", my: "md", variant: "dashed" }), /* @__PURE__ */ React.createElement("form", { onSubmit: form.onSubmit(() => {
735
1155
  const values = form.values;
736
1156
  form.reset();
737
1157
  setOpened(false);
738
- props.onCreateStudents && props.onCreateStudents([values]);
1158
+ props.onCreateMembers && props.onCreateMembers([values]);
739
1159
  }) }, /* @__PURE__ */ React.createElement(Stack$3, null, /* @__PURE__ */ React.createElement(
740
1160
  TextInput,
741
1161
  __spreadValues$3({
@@ -756,25 +1176,25 @@ const Class = (props) => {
756
1176
  placeholder: "Family name"
757
1177
  }, form.getInputProps("familyName"))
758
1178
  )), /* @__PURE__ */ React.createElement(Button, { type: "submit", fullWidth: true, mt: "md" }, "Submit"))))
759
- ), /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: "md" }, /* @__PURE__ */ React.createElement(Grid, null, /* @__PURE__ */ React.createElement(Grid.Col, { sm: "auto" }, /* @__PURE__ */ React.createElement(
1179
+ ), /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: "md" }, /* @__PURE__ */ React.createElement(Grid, null, /* @__PURE__ */ React.createElement(Grid.Col, { sm: "auto" }, /* @__PURE__ */ React.createElement(UnstyledButton, { onClick: props.onBackClick }, /* @__PURE__ */ React.createElement(
760
1180
  Badge$1,
761
1181
  {
762
1182
  variant: "filled",
763
- leftSection: /* @__PURE__ */ React.createElement(ActionIcon, { onClick: props.onBackClick, color: "blue", size: "xs", radius: "xl", variant: "filled" }, /* @__PURE__ */ React.createElement(IconArrowLeft, { size: 14 })),
1183
+ leftSection: /* @__PURE__ */ React.createElement(ActionIcon, { color: "blue", size: "xs", radius: "xl", variant: "filled" }, /* @__PURE__ */ React.createElement(IconArrowLeft, { size: 14 })),
764
1184
  size: "lg"
765
1185
  },
766
1186
  "Classes"
767
- ), /* @__PURE__ */ React.createElement(Title, { order: 2, className: classes.title, mt: "md" }, props.displayName || "Class"), /* @__PURE__ */ React.createElement(Text, { color: "dimmed", className: classes.description, mt: "sm" }, props.description || "No description")), /* @__PURE__ */ React.createElement(Grid.Col, { sm: "content" }, !props.loading && /* @__PURE__ */ React.createElement(
1187
+ )), /* @__PURE__ */ React.createElement(Title, { order: 2, className: classes.title, mt: "md" }, props.displayName || "Class"), /* @__PURE__ */ React.createElement(Text, { color: "dimmed", className: classes.description, mt: "sm" }, props.description || "No description")), /* @__PURE__ */ React.createElement(Grid.Col, { sm: "content" }, !props.loading && /* @__PURE__ */ React.createElement(
768
1188
  SplitButton$1,
769
1189
  {
770
1190
  withClassLink: props.withClassLink,
771
- onAddStudentsClick: () => setOpened(true),
1191
+ onAddMembersClick: () => setOpened(true),
772
1192
  onCopyClassLinkClick: props.onCopyLinkClick
773
1193
  }
774
1194
  ))), /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React.createElement(LoadingOverlay, { visible: props.loading, overlayBlur: 2 }), /* @__PURE__ */ React.createElement(Stack$3, { spacing: "sm" }, /* @__PURE__ */ React.createElement(StatsGroup, { data: [
775
1195
  {
776
1196
  title: "# OF STUDENTS",
777
- value: props.students.length
1197
+ value: props.members.length
778
1198
  },
779
1199
  {
780
1200
  title: "ACCOUNT CREATION",
@@ -793,14 +1213,14 @@ const Class = (props) => {
793
1213
  Table$7,
794
1214
  {
795
1215
  loading: props.loading,
796
- items: props.students,
797
- onDelete: props.onDeleteStudent,
798
- onViewProfile: (student) => props.onStudentClick(student)
1216
+ items: props.members,
1217
+ onDelete: props.onDeleteMember,
1218
+ onRoleChange: props.onChangeUserRole
799
1219
  }
800
1220
  ))))));
801
1221
  };
802
1222
  const DropzoneButton = (props) => {
803
- const { classes, theme } = useStyles$9();
1223
+ const { classes, theme } = useStyles$8();
804
1224
  const openRef = React.useRef(null);
805
1225
  const [loading, setLoading] = React.useState(false);
806
1226
  const onDrop = React.useCallback((acceptedFiles) => {
@@ -813,8 +1233,8 @@ const DropzoneButton = (props) => {
813
1233
  skipEmptyLines: true,
814
1234
  worker: true,
815
1235
  complete: function(results) {
816
- const data = results.data.filter((v) => /^\S+@\S+$/.test(v.email) && props.students.filter((u) => u.email === v.email).length === 0);
817
- data.length > 0 && props.onCreateStudents && props.onCreateStudents(data);
1236
+ const data = results.data.filter((v) => /^\S+@\S+$/.test(v.email) && props.members.filter((u) => u.email === v.email).length === 0);
1237
+ data.length > 0 && props.onCreateMembers && props.onCreateMembers(data);
818
1238
  setLoading(false);
819
1239
  props.close();
820
1240
  }
@@ -866,8 +1286,8 @@ function Table$6(props) {
866
1286
  confirmProps: { color: "red" },
867
1287
  onConfirm: () => props.onDeleteClass(group)
868
1288
  });
869
- const rows = props.items.map((row) => /* @__PURE__ */ React.createElement("tr", { key: row.classId }, /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(UnstyledButton, { onClick: () => props.onClick(row) }, /* @__PURE__ */ React.createElement(Text, { size: 14 }, row.name))), /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(Text, { size: 14 }, row.description)), /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(Group, { noWrap: true, spacing: 0, position: "right" }, /* @__PURE__ */ React.createElement(ActionIcon, { color: "red" }, /* @__PURE__ */ React.createElement(IconTrash, { onClick: () => openDeleteModal(row), size: 16, stroke: 1.5 }))))));
870
- return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 300 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: 20, sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Class Name"), /* @__PURE__ */ React.createElement("th", null, "Description"), /* @__PURE__ */ React.createElement("th", null))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
1289
+ const rows = props.items.map((row) => /* @__PURE__ */ React.createElement("tr", { key: row.classId }, /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(UnstyledButton, { component: "a", href: row.href }, /* @__PURE__ */ React.createElement(Text, { size: 14 }, row.name))), /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(Text, { size: 14 }, row.description)), /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(Text, { size: 14 }, row.numberOfStudents || 0)), /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(Group, { noWrap: true, spacing: 0, position: "right" }, /* @__PURE__ */ React.createElement(ActionIcon, { color: "red" }, /* @__PURE__ */ React.createElement(IconTrash, { onClick: () => openDeleteModal(row), size: 16, stroke: 1.5 }))))));
1290
+ return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 600 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: 20, sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Class Name"), /* @__PURE__ */ React.createElement("th", null, "Description"), /* @__PURE__ */ React.createElement("th", null, "# of Students"), /* @__PURE__ */ React.createElement("th", null))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
871
1291
  }
872
1292
 
873
1293
  var __defProp$2 = Object.defineProperty;
@@ -886,7 +1306,7 @@ var __spreadValues$2 = (a, b) => {
886
1306
  }
887
1307
  return a;
888
1308
  };
889
- const useStyles$8 = createStyles((theme) => ({
1309
+ const useStyles$7 = createStyles((theme) => ({
890
1310
  title: {
891
1311
  fontSize: 34,
892
1312
  fontWeight: 900,
@@ -899,12 +1319,14 @@ const useStyles$8 = createStyles((theme) => ({
899
1319
  }
900
1320
  }));
901
1321
  const Classes = (props) => {
902
- const { classes } = useStyles$8();
1322
+ const { classes } = useStyles$7();
903
1323
  const form = useForm({
904
1324
  initialValues: {
905
1325
  classId: "",
906
1326
  name: "",
907
- description: ""
1327
+ description: "",
1328
+ href: "",
1329
+ numberOfStudents: 0
908
1330
  },
909
1331
  validate: {
910
1332
  name: (val) => val.length <= 6 ? "Name should include at least 6 characters" : null
@@ -939,7 +1361,7 @@ const Classes = (props) => {
939
1361
  placeholder: "A class for my first period English students"
940
1362
  }, form.getInputProps("description"))
941
1363
  )), /* @__PURE__ */ React.createElement(Button, { type: "submit", fullWidth: true, mt: "md" }, "Submit"))
942
- ), /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: "md" }, /* @__PURE__ */ React.createElement(Grid, null, /* @__PURE__ */ React.createElement(Grid.Col, { sm: "auto" }, /* @__PURE__ */ React.createElement(Badge$1, { variant: "filled", size: "lg" }, "Classes"), /* @__PURE__ */ React.createElement(Title, { order: 2, className: classes.title, mt: "md" }, "Organize students into classes"), /* @__PURE__ */ React.createElement(Text, { color: "dimmed", className: classes.description, mt: "sm" }, "A class can be for a specific period of time, grade, team, or other cohorts.")), /* @__PURE__ */ React.createElement(Grid.Col, { sm: "content" }, !props.loading && /* @__PURE__ */ React.createElement(
1364
+ ), /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: "md" }, /* @__PURE__ */ React.createElement(Grid, null, /* @__PURE__ */ React.createElement(Grid.Col, { sm: "auto" }, /* @__PURE__ */ React.createElement(Badge$1, { variant: "filled", size: "lg" }, "Classes"), /* @__PURE__ */ React.createElement(Title, { order: 2, className: classes.title, mt: "md" }, "Organize people into classes"), /* @__PURE__ */ React.createElement(Text, { color: "dimmed", className: classes.description, mt: "sm" }, "A class can be for a specific period of time, grade, team, or other cohorts.")), /* @__PURE__ */ React.createElement(Grid.Col, { sm: "content" }, !props.loading && /* @__PURE__ */ React.createElement(
943
1365
  Button,
944
1366
  {
945
1367
  onClick: () => setOpened(true),
@@ -952,17 +1374,23 @@ const Classes = (props) => {
952
1374
  value: props.classes.length
953
1375
  }
954
1376
  ] }), /* @__PURE__ */ React.createElement(
1377
+ Autocomplete,
1378
+ {
1379
+ placeholder: "Search for classes",
1380
+ data: props.classes.map((item) => item.name),
1381
+ onChange: props.onAutocompleteChange
1382
+ }
1383
+ ), /* @__PURE__ */ React.createElement(
955
1384
  Table$6,
956
1385
  {
957
1386
  loading: props.loading,
958
1387
  items: props.classes,
959
- onDeleteClass: props.onDeleteClass,
960
- onClick: props.onClassClick
1388
+ onDeleteClass: props.onDeleteClass
961
1389
  }
962
1390
  ))))));
963
1391
  };
964
1392
 
965
- const useStyles$7 = createStyles((theme) => ({
1393
+ const useStyles$6 = createStyles((theme) => ({
966
1394
  title: {
967
1395
  fontSize: 34,
968
1396
  fontWeight: 900,
@@ -976,7 +1404,7 @@ const useStyles$7 = createStyles((theme) => ({
976
1404
  }
977
1405
  }));
978
1406
  const UserInfo = (props) => {
979
- const { classes } = useStyles$7();
1407
+ const { classes } = useStyles$6();
980
1408
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Title, { className: classes.title }, props.name), /* @__PURE__ */ React.createElement(Text, { color: "dimmed", className: classes.description, mt: "xs" }, props.impactStatement));
981
1409
  };
982
1410
 
@@ -992,8 +1420,31 @@ function Table$5(props) {
992
1420
  }
993
1421
  );
994
1422
  }
995
- const rows = props.items.map((row) => /* @__PURE__ */ React.createElement("tr", { key: row.badgeName }, /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(UnstyledButton, { onClick: () => props.onClick(row) }, row.badgeName)), /* @__PURE__ */ React.createElement("td", null, !!row.isComplete && /* @__PURE__ */ React.createElement(Badge$1, { variant: "filled" }, "Complete"), !row.isComplete && /* @__PURE__ */ React.createElement(Badge$1, { color: "red", variant: "filled" }, "Incomplete"))));
996
- return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Badge Name"), /* @__PURE__ */ React.createElement("th", null, "Status"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
1423
+ return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 600 }, /* @__PURE__ */ React.createElement(
1424
+ DataTable,
1425
+ {
1426
+ verticalSpacing: "sm",
1427
+ sx: { minWidth: 700 },
1428
+ withBorder: false,
1429
+ borderRadius: "sm",
1430
+ withColumnBorders: true,
1431
+ striped: true,
1432
+ highlightOnHover: true,
1433
+ records: props.items,
1434
+ idAccessor: "badgeId",
1435
+ columns: [{
1436
+ accessor: "name",
1437
+ title: "Badge Name",
1438
+ render: (row) => /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Text, null, row.badgeName))
1439
+ }, {
1440
+ accessor: "status",
1441
+ render: (row) => /* @__PURE__ */ React.createElement(React.Fragment, null, !!row.isComplete && /* @__PURE__ */ React.createElement(Badge$1, { variant: "filled" }, "Complete"), !row.isComplete && /* @__PURE__ */ React.createElement(Badge$1, { color: "red", variant: "filled" }, "Incomplete"))
1442
+ }],
1443
+ rowExpansion: {
1444
+ content: ({ record }) => /* @__PURE__ */ React.createElement(Stack$2, { items: record.lessons })
1445
+ }
1446
+ }
1447
+ ));
997
1448
  }
998
1449
 
999
1450
  function Table$4(props) {
@@ -1008,8 +1459,8 @@ function Table$4(props) {
1008
1459
  }
1009
1460
  );
1010
1461
  }
1011
- const rows = props.items.map((row) => /* @__PURE__ */ React.createElement("tr", { key: row.questionName }, /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(UnstyledButton, { onClick: () => props.onClick(row) }, row.lessonName)), /* @__PURE__ */ React.createElement("td", null, row.questionName), /* @__PURE__ */ React.createElement("td", null, row.answer.join(","))));
1012
- return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Lesson Name"), /* @__PURE__ */ React.createElement("th", null, "Question"), /* @__PURE__ */ React.createElement("th", null, "Answer"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
1462
+ const rows = props.items.map((row) => /* @__PURE__ */ React.createElement("tr", { key: row.questionName }, /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(Text, { component: "a", href: row.href }, row.lessonName)), /* @__PURE__ */ React.createElement("td", null, row.questionName), /* @__PURE__ */ React.createElement("td", null, row.answer.join(","))));
1463
+ return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 600 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Lesson Name"), /* @__PURE__ */ React.createElement("th", null, "Question"), /* @__PURE__ */ React.createElement("th", null, "Answer"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
1013
1464
  }
1014
1465
 
1015
1466
  function Table$3(props) {
@@ -1024,23 +1475,23 @@ function Table$3(props) {
1024
1475
  }
1025
1476
  );
1026
1477
  }
1027
- const rows = props.items.map((row) => /* @__PURE__ */ React.createElement("tr", { key: row.lessonName }, /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(UnstyledButton, { onClick: () => props.onClick(row) }, row.lessonName)), /* @__PURE__ */ React.createElement("td", null, row.reflection), /* @__PURE__ */ React.createElement("td", null, row.rating.toLocaleString())));
1028
- return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Lesson Name"), /* @__PURE__ */ React.createElement("th", null, "Reflection"), /* @__PURE__ */ React.createElement("th", null, "Rating"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
1478
+ const rows = props.items.map((row) => /* @__PURE__ */ React.createElement("tr", { key: row.lessonName }, /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(Text, { component: "a", href: row.href }, row.lessonName)), /* @__PURE__ */ React.createElement("td", null, row.reflection), /* @__PURE__ */ React.createElement("td", null, row.rating.toLocaleString())));
1479
+ return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 600 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Lesson Name"), /* @__PURE__ */ React.createElement("th", null, "Reflection"), /* @__PURE__ */ React.createElement("th", null, "Rating"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
1029
1480
  }
1030
1481
 
1031
1482
  const Student = (props) => {
1032
1483
  const [tab, setTab] = useState("badges");
1033
1484
  const numberOfBadges = props.badges.length;
1034
1485
  const percentageOfBadgesEarned = numberOfBadges > 0 ? props.badges.filter((b) => b.isComplete).length / numberOfBadges : 0;
1035
- return /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: "md" }, /* @__PURE__ */ React.createElement(Grid, { gutter: "md" }, /* @__PURE__ */ React.createElement(Grid.Col, { sm: "auto" }, /* @__PURE__ */ React.createElement(
1486
+ return /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: "md" }, /* @__PURE__ */ React.createElement(Grid, { gutter: "md" }, /* @__PURE__ */ React.createElement(Grid.Col, { sm: "auto" }, /* @__PURE__ */ React.createElement(UnstyledButton, { onClick: props.onBackClick }, /* @__PURE__ */ React.createElement(
1036
1487
  Badge$1,
1037
1488
  {
1038
1489
  variant: "filled",
1039
- leftSection: /* @__PURE__ */ React.createElement(ActionIcon, { onClick: props.onBackClick, color: "blue", size: "xs", radius: "xl", variant: "filled" }, /* @__PURE__ */ React.createElement(IconArrowLeft, { size: 14 })),
1490
+ leftSection: /* @__PURE__ */ React.createElement(ActionIcon, { color: "blue", size: "xs", radius: "xl", variant: "filled" }, /* @__PURE__ */ React.createElement(IconArrowLeft, { size: 14 })),
1040
1491
  size: "lg"
1041
1492
  },
1042
1493
  "Students"
1043
- ), /* @__PURE__ */ React.createElement(
1494
+ )), /* @__PURE__ */ React.createElement(
1044
1495
  UserInfo,
1045
1496
  {
1046
1497
  variant: "compact",
@@ -1077,27 +1528,24 @@ const Student = (props) => {
1077
1528
  Table$5,
1078
1529
  {
1079
1530
  loading: props.loading,
1080
- items: props.badges,
1081
- onClick: props.onBadgeClick
1531
+ items: props.badges
1082
1532
  }
1083
1533
  ), tab === "answers" && /* @__PURE__ */ React.createElement(
1084
1534
  Table$4,
1085
1535
  {
1086
1536
  loading: props.loading,
1087
- items: props.answers,
1088
- onClick: props.onAnswerClick
1537
+ items: props.answers
1089
1538
  }
1090
1539
  ), tab === "reflections" && /* @__PURE__ */ React.createElement(
1091
1540
  Table$3,
1092
1541
  {
1093
1542
  loading: props.loading,
1094
- items: props.reflections,
1095
- onClick: props.onReflectionClick
1543
+ items: props.reflections
1096
1544
  }
1097
1545
  ))))));
1098
1546
  };
1099
1547
 
1100
- const useStyles$6 = createStyles((theme, props) => {
1548
+ const useStyles$5 = createStyles((theme, props) => {
1101
1549
  const from = props.from || "blue";
1102
1550
  const to = props.to || "green";
1103
1551
  return {
@@ -1125,7 +1573,7 @@ const useStyles$6 = createStyles((theme, props) => {
1125
1573
  };
1126
1574
  });
1127
1575
  function CardGradient(props) {
1128
- const { classes } = useStyles$6(props);
1576
+ const { classes } = useStyles$5(props);
1129
1577
  const from = props.from || "blue";
1130
1578
  const to = props.to || "green";
1131
1579
  const icon = props.icon || /* @__PURE__ */ React.createElement(IconColorSwatch, { size: 28, stroke: 1.5 });
@@ -1169,7 +1617,7 @@ var __objRest = (source, exclude) => {
1169
1617
  }
1170
1618
  return target;
1171
1619
  };
1172
- const useStyles$5 = createStyles((theme) => ({
1620
+ const useStyles$4 = createStyles((theme) => ({
1173
1621
  card: {
1174
1622
  height: 240,
1175
1623
  backgroundSize: "cover",
@@ -1214,7 +1662,7 @@ const TenantBanner = (_a) => {
1214
1662
  "style",
1215
1663
  "className"
1216
1664
  ]);
1217
- const { classes, cx, theme } = useStyles$5();
1665
+ const { classes, cx, theme } = useStyles$4();
1218
1666
  return /* @__PURE__ */ React.createElement(
1219
1667
  Card,
1220
1668
  __spreadValues$1({
@@ -1276,7 +1724,7 @@ const Home = (props) => {
1276
1724
  CardGradient,
1277
1725
  {
1278
1726
  title: "Classes",
1279
- description: "Organize students into classes.",
1727
+ description: "Organize people into classes.",
1280
1728
  onClick: props.onClassesClick
1281
1729
  }
1282
1730
  )), /* @__PURE__ */ React.createElement(Grid.Col, null, /* @__PURE__ */ React.createElement(
@@ -1309,10 +1757,10 @@ function Table$2(props) {
1309
1757
  );
1310
1758
  }
1311
1759
  const rows = props.items.map((row) => /* @__PURE__ */ React.createElement("tr", { key: row.studentName }, /* @__PURE__ */ React.createElement("td", null, row.studentName), /* @__PURE__ */ React.createElement("td", null, row.reflection), /* @__PURE__ */ React.createElement("td", null, row.rating.toLocaleString())));
1312
- return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Student Name"), /* @__PURE__ */ React.createElement("th", null, "Reflection"), /* @__PURE__ */ React.createElement("th", null, "Rating"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
1760
+ return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 600 }, /* @__PURE__ */ React.createElement(Table$g, { verticalSpacing: "sm", sx: { minWidth: 700 }, highlightOnHover: true, striped: true }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("th", null, "Student Name"), /* @__PURE__ */ React.createElement("th", null, "Reflection"), /* @__PURE__ */ React.createElement("th", null, "Rating"))), /* @__PURE__ */ React.createElement("tbody", null, rows)));
1313
1761
  }
1314
1762
 
1315
- const useStyles$4 = createStyles((theme) => ({
1763
+ const useStyles$3 = createStyles((theme) => ({
1316
1764
  button: {
1317
1765
  borderTopRightRadius: 0,
1318
1766
  borderBottomRightRadius: 0,
@@ -1327,14 +1775,15 @@ const useStyles$4 = createStyles((theme) => ({
1327
1775
  }
1328
1776
  }));
1329
1777
  const SplitButton = (props) => {
1330
- const { classes, theme } = useStyles$4();
1778
+ const { classes, theme } = useStyles$3();
1331
1779
  const menuIconColor = theme.colors[theme.primaryColor][theme.colorScheme === "dark" ? 5 : 6];
1332
1780
  return /* @__PURE__ */ React.createElement(Group, { noWrap: true, spacing: 0 }, /* @__PURE__ */ React.createElement(
1333
1781
  Button,
1334
1782
  {
1783
+ component: "a",
1784
+ href: props.href,
1335
1785
  className: classes.button,
1336
- variant: "gradient",
1337
- onClick: props.onPreviewClick
1786
+ variant: "gradient"
1338
1787
  },
1339
1788
  "Preview"
1340
1789
  ), /* @__PURE__ */ React.createElement(Menu, { transition: "pop", position: "bottom-end" }, /* @__PURE__ */ React.createElement(Menu.Target, null, /* @__PURE__ */ React.createElement(
@@ -1368,7 +1817,7 @@ function Stack$1(props) {
1368
1817
  return null;
1369
1818
  }
1370
1819
  const rows = props.items.map((row) => /* @__PURE__ */ React.createElement(Stack$3, { spacing: 0, key: row.questionName }, /* @__PURE__ */ React.createElement(Title, { color: "dark.4", size: "lg" }, row.questionName), /* @__PURE__ */ React.createElement(Text, null, row.answer.join(",") || "No answer.")));
1371
- return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: 24, sx: { padding: 20, minWidth: 700 } }, rows));
1820
+ return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 600 }, /* @__PURE__ */ React.createElement(UnstyledButton, { component: "a", href: props.href }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: 24, sx: { padding: 20, minWidth: 700 } }, rows)));
1372
1821
  }
1373
1822
 
1374
1823
  function Table$1(props) {
@@ -1383,7 +1832,7 @@ function Table$1(props) {
1383
1832
  }
1384
1833
  );
1385
1834
  }
1386
- return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(
1835
+ return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 600 }, /* @__PURE__ */ React.createElement(
1387
1836
  DataTable,
1388
1837
  {
1389
1838
  verticalSpacing: "sm",
@@ -1404,7 +1853,7 @@ function Table$1(props) {
1404
1853
  render: (row) => /* @__PURE__ */ React.createElement(React.Fragment, null, !!row.isComplete && /* @__PURE__ */ React.createElement(Badge$1, { variant: "filled" }, "Complete"), !row.isComplete && !row.isStarted && /* @__PURE__ */ React.createElement(Badge$1, { color: "red", variant: "filled" }, "Not started"), !row.isComplete && !!row.isStarted && /* @__PURE__ */ React.createElement(Badge$1, { color: "violet", variant: "filled" }, "In progress"))
1405
1854
  }],
1406
1855
  rowExpansion: {
1407
- content: ({ record }) => /* @__PURE__ */ React.createElement(Stack$1, { items: record.answers })
1856
+ content: ({ record }) => /* @__PURE__ */ React.createElement(Stack$1, { href: record.href, items: record.answers })
1408
1857
  }
1409
1858
  }
1410
1859
  ));
@@ -1469,7 +1918,7 @@ function Stack(props) {
1469
1918
  }
1470
1919
  ))));
1471
1920
  }
1472
- return /* @__PURE__ */ React.createElement(Card, { key: row.question, withBorder: true, p: "xl", radius: "md" }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: 4 }, /* @__PURE__ */ React.createElement(Title, { size: "lg" }, row.question), /* @__PURE__ */ React.createElement(Text, { size: "sm" }, row.answers.length, " answers"), /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: 4 }, row.answers.map((a) => {
1921
+ return /* @__PURE__ */ React.createElement(Card, { key: row.question, withBorder: true, p: "xl", radius: "md" }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: 4 }, /* @__PURE__ */ React.createElement(Title, { size: "lg" }, row.question), /* @__PURE__ */ React.createElement(Text, { size: "sm" }, row.answers.length, " answers"), /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 600 }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: 4 }, row.answers.map((a) => {
1473
1922
  const answerText = a.join("\n");
1474
1923
  return /* @__PURE__ */ React.createElement(Card, { key: answerText, p: 5, radius: 0, bg: "gray.0" }, /* @__PURE__ */ React.createElement(Text, null, answerText));
1475
1924
  })))));
@@ -1478,7 +1927,7 @@ function Stack(props) {
1478
1927
  }
1479
1928
  const truncateWithEllipses = (text, max) => text.substr(0, max - 1) + (text.length > max ? "&hellip;" : "");
1480
1929
 
1481
- const useStyles$3 = createStyles((theme) => ({
1930
+ const useStyles$2 = createStyles((theme) => ({
1482
1931
  title: {
1483
1932
  fontSize: 34,
1484
1933
  fontWeight: 900,
@@ -1491,22 +1940,22 @@ const useStyles$3 = createStyles((theme) => ({
1491
1940
  }
1492
1941
  }));
1493
1942
  const Lesson = (props) => {
1494
- const { classes } = useStyles$3();
1943
+ const { classes } = useStyles$2();
1495
1944
  const [tab, setTab] = useState("question");
1496
1945
  const numberOfStudents = props.students.length;
1497
1946
  const percentageOfLessonsCompleted = numberOfStudents > 0 ? props.students.filter((u) => u.isComplete).length / numberOfStudents : 0;
1498
- return /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: "md" }, /* @__PURE__ */ React.createElement(Grid, null, /* @__PURE__ */ React.createElement(Grid.Col, { sm: "auto" }, /* @__PURE__ */ React.createElement(
1947
+ return /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: "md" }, /* @__PURE__ */ React.createElement(Grid, null, /* @__PURE__ */ React.createElement(Grid.Col, { sm: "auto" }, /* @__PURE__ */ React.createElement(UnstyledButton, { onClick: props.onBackClick }, /* @__PURE__ */ React.createElement(
1499
1948
  Badge$1,
1500
1949
  {
1501
1950
  variant: "filled",
1502
- leftSection: /* @__PURE__ */ React.createElement(ActionIcon, { onClick: props.onBackClick, color: "blue", size: "xs", radius: "xl", variant: "filled" }, /* @__PURE__ */ React.createElement(IconArrowLeft, { size: 14 })),
1951
+ leftSection: /* @__PURE__ */ React.createElement(ActionIcon, { color: "blue", size: "xs", radius: "xl", variant: "filled" }, /* @__PURE__ */ React.createElement(IconArrowLeft, { size: 14 })),
1503
1952
  size: "lg"
1504
1953
  },
1505
1954
  "Lessons"
1506
- ), /* @__PURE__ */ React.createElement(Group, null, /* @__PURE__ */ React.createElement(Stack$3, { spacing: 0 }, /* @__PURE__ */ React.createElement(Title, { order: 2, className: classes.title, mt: "md" }, props.displayName || "Lesson"), /* @__PURE__ */ React.createElement(Text, { color: "dimmed", className: classes.description, mt: "sm" }, props.description || "No description")), /* @__PURE__ */ React.createElement(Stack$3, { ml: "auto" }, /* @__PURE__ */ React.createElement(
1955
+ )), /* @__PURE__ */ React.createElement(Group, null, /* @__PURE__ */ React.createElement(Stack$3, { spacing: 0 }, /* @__PURE__ */ React.createElement(Title, { order: 2, className: classes.title, mt: "md" }, props.displayName || "Lesson"), /* @__PURE__ */ React.createElement(Text, { color: "dimmed", className: classes.description, mt: "sm" }, props.description || "No description")), /* @__PURE__ */ React.createElement(Stack$3, { ml: "auto" }, /* @__PURE__ */ React.createElement(
1507
1956
  SplitButton,
1508
1957
  {
1509
- onPreviewClick: props.onPreviewClick,
1958
+ href: props.href,
1510
1959
  onCopyLinkClick: props.onCopyLinkClick,
1511
1960
  onExportDataClick: props.onExportDataClick
1512
1961
  }
@@ -1558,8 +2007,7 @@ const Lesson = (props) => {
1558
2007
  Table$1,
1559
2008
  {
1560
2009
  loading: props.loading,
1561
- items: props.students,
1562
- onClick: props.onUserClick
2010
+ items: props.students
1563
2011
  }
1564
2012
  )))))));
1565
2013
  };
@@ -1579,6 +2027,8 @@ function Table(props) {
1579
2027
  const rows = props.items.map((row) => /* @__PURE__ */ React.createElement("tr", { key: row.lessonId }, /* @__PURE__ */ React.createElement("td", null, /* @__PURE__ */ React.createElement(
1580
2028
  UnstyledButton,
1581
2029
  {
2030
+ component: "a",
2031
+ href: row.href,
1582
2032
  sx: (theme) => ({
1583
2033
  display: "block",
1584
2034
  width: "100%",
@@ -1587,15 +2037,14 @@ function Table(props) {
1587
2037
  "&:hover": {
1588
2038
  backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[8] : theme.colors.gray[1]
1589
2039
  }
1590
- }),
1591
- onClick: () => props.onClick && props.onClick(row)
2040
+ })
1592
2041
  },
1593
2042
  /* @__PURE__ */ React.createElement(Group, null, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Text, { size: "sm", weight: 500 }, row.name), /* @__PURE__ */ React.createElement(Text, { size: "xs", color: "dimmed" }, row.description)))
1594
2043
  ))));
1595
- return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(Table$g, { horizontalSpacing: 0, verticalSpacing: 0, sx: { minWidth: 700 } }, /* @__PURE__ */ React.createElement("tbody", null, rows)));
2044
+ return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 600 }, /* @__PURE__ */ React.createElement(Table$g, { horizontalSpacing: 0, verticalSpacing: 0, sx: { minWidth: 700 } }, /* @__PURE__ */ React.createElement("tbody", null, rows)));
1596
2045
  }
1597
2046
 
1598
- const useStyles$2 = createStyles((theme) => ({
2047
+ const useStyles$1 = createStyles((theme) => ({
1599
2048
  title: {
1600
2049
  fontSize: 34,
1601
2050
  fontWeight: 900,
@@ -1608,7 +2057,7 @@ const useStyles$2 = createStyles((theme) => ({
1608
2057
  }
1609
2058
  }));
1610
2059
  const Lessons = (props) => {
1611
- const { classes } = useStyles$2();
2060
+ const { classes } = useStyles$1();
1612
2061
  return /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: "md" }, /* @__PURE__ */ React.createElement(Grid, null, /* @__PURE__ */ React.createElement(Grid.Col, { sm: "auto" }, /* @__PURE__ */ React.createElement(Badge$1, { variant: "filled", size: "lg" }, "Lessons"), /* @__PURE__ */ React.createElement(Title, { order: 2, className: classes.title, mt: "md" }, "Lessons"), /* @__PURE__ */ React.createElement(Text, { color: "dimmed", className: classes.description, mt: "sm" }, "Explore units of instruction and/or see corresponding class progress."))), /* @__PURE__ */ React.createElement(
1613
2062
  Autocomplete,
1614
2063
  {
@@ -1620,8 +2069,7 @@ const Lessons = (props) => {
1620
2069
  Table,
1621
2070
  {
1622
2071
  loading: props.loading,
1623
- items: props.lessons,
1624
- onClick: props.onLessonClick
2072
+ items: props.lessons
1625
2073
  }
1626
2074
  ))));
1627
2075
  };
@@ -1631,10 +2079,23 @@ const mycCache = createEmotionCache({
1631
2079
  prepend: false
1632
2080
  });
1633
2081
  const AdminProvider = (props) => {
1634
- return /* @__PURE__ */ React.createElement(MantineProvider, { withNormalizeCSS: true, withGlobalStyles: true, emotionCache: mycCache, theme: { loader: "bars" } }, /* @__PURE__ */ React.createElement(NotificationsProvider, { limit: props.notificationLimit || 5 }, /* @__PURE__ */ React.createElement(ModalsProvider, null, props.children)));
2082
+ return /* @__PURE__ */ React.createElement(
2083
+ MantineProvider,
2084
+ {
2085
+ theme: {
2086
+ loader: "bars"
2087
+ },
2088
+ withNormalizeCSS: true,
2089
+ withGlobalStyles: true,
2090
+ emotionCache: mycCache
2091
+ },
2092
+ /* @__PURE__ */ React.createElement(NotificationsProvider, { limit: props.notificationLimit || 5 }, /* @__PURE__ */ React.createElement(ModalsProvider, null, props.children))
2093
+ );
1635
2094
  };
1636
2095
 
1637
2096
  var __defProp = Object.defineProperty;
2097
+ var __defProps = Object.defineProperties;
2098
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
1638
2099
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
1639
2100
  var __hasOwnProp = Object.prototype.hasOwnProperty;
1640
2101
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
@@ -1650,101 +2111,12 @@ var __spreadValues = (a, b) => {
1650
2111
  }
1651
2112
  return a;
1652
2113
  };
1653
- const SwitchAccount = (props) => {
1654
- const form = useForm({
1655
- initialValues: {
1656
- active: props.account
1657
- }
1658
- });
1659
- return /* @__PURE__ */ React.createElement(
1660
- Modal,
1661
- {
1662
- centered: true,
1663
- opened: props.opened,
1664
- onClose: () => props.onClose && props.onClose(),
1665
- size: "sm",
1666
- title: /* @__PURE__ */ React.createElement(Title, { size: "h5" }, "Accounts")
1667
- },
1668
- /* @__PURE__ */ React.createElement("form", { onSubmit: form.onSubmit(() => {
1669
- props.onChange && props.onChange(form.values.active);
1670
- }) }, /* @__PURE__ */ React.createElement(
1671
- Select,
1672
- __spreadValues({
1673
- required: true,
1674
- placeholder: "Select an account",
1675
- defaultValue: props.account,
1676
- data: props.accounts.map((a) => {
1677
- return { value: a.accountId, label: a.name };
1678
- })
1679
- }, form.getInputProps("active"))
1680
- ), /* @__PURE__ */ React.createElement(Button, { type: "submit", fullWidth: true, mt: "xl" }, "Switch"))
1681
- );
1682
- };
1683
-
1684
- const useStyles$1 = createStyles((theme) => ({
1685
- link: {
1686
- width: 50,
1687
- height: 50,
1688
- borderRadius: theme.radius.md,
1689
- display: "flex",
1690
- alignItems: "center",
1691
- justifyContent: "center",
1692
- color: theme.colorScheme === "dark" ? theme.colors.dark[0] : theme.colors.gray[7],
1693
- "&:hover": {
1694
- backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[5] : theme.colors.gray[0]
1695
- }
1696
- },
1697
- active: {
1698
- "&, &:hover": {
1699
- backgroundColor: theme.fn.variant({ variant: "light", color: theme.primaryColor }).background,
1700
- color: theme.fn.variant({ variant: "light", color: theme.primaryColor }).color
1701
- }
1702
- }
1703
- }));
1704
- const data = [
1705
- { icon: IconHome2, label: "Home", href: "/home" },
1706
- { icon: IconGauge, label: "Dashboard", href: "/dashboard" },
1707
- { icon: IconCategory2, label: "Classes", href: "/classes" },
1708
- { icon: IconAlbum, label: "Badges", href: "/badges" },
1709
- { icon: IconLambda, label: "Lessons", href: "/lessons" }
1710
- ];
1711
- const NavbarLink = ({ icon: Icon, label, active, onClick }) => {
1712
- const { classes, cx } = useStyles$1();
1713
- return /* @__PURE__ */ React.createElement(Tooltip, { label, position: "right", transitionDuration: 0 }, /* @__PURE__ */ React.createElement(UnstyledButton, { onClick, className: cx(classes.link, { [classes.active]: active }) }, /* @__PURE__ */ React.createElement(Icon, { stroke: 1.5 })));
1714
- };
1715
- const Navbar = (props) => {
1716
- const links = data.map((link) => /* @__PURE__ */ React.createElement(
1717
- NavbarLink,
1718
- {
1719
- key: link.label,
1720
- label: link.label,
1721
- icon: link.icon,
1722
- active: link.label === props.active,
1723
- onClick: () => props.navigate(link.href)
1724
- }
1725
- ));
1726
- return /* @__PURE__ */ React.createElement(Navbar$1, { width: { base: 80 }, p: "md" }, /* @__PURE__ */ React.createElement(Center, null, /* @__PURE__ */ React.createElement(Avatar, { color: "blue", radius: "sm" }, /* @__PURE__ */ React.createElement("div", { style: { width: 15, marginLeft: "auto", marginRight: "auto" } }, /* @__PURE__ */ React.createElement(Image, { fit: "contain", src: "https://cdn.localcivics.io/brand/l.png" })))), /* @__PURE__ */ React.createElement(Navbar$1.Section, { grow: true, mt: 50 }, /* @__PURE__ */ React.createElement(Stack$3, { justify: "center", spacing: 0 }, links)), /* @__PURE__ */ React.createElement(Navbar$1.Section, null, /* @__PURE__ */ React.createElement(Stack$3, { justify: "center", spacing: 0 }, /* @__PURE__ */ React.createElement(
1727
- NavbarLink,
1728
- {
1729
- icon: IconSwitchHorizontal,
1730
- label: "Switch accounts",
1731
- onClick: props.onSwitchAccounts
1732
- }
1733
- ), /* @__PURE__ */ React.createElement(
1734
- NavbarLink,
1735
- {
1736
- icon: IconLogout,
1737
- label: "Logout",
1738
- onClick: props.onLogout
1739
- }
1740
- ))));
1741
- };
1742
-
2114
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
1743
2115
  const useStyles = createStyles((theme) => ({
1744
2116
  footer: {
1745
2117
  paddingTop: theme.spacing.xl * 2,
1746
2118
  paddingBottom: theme.spacing.xl * 2,
1747
- paddingLeft: theme.spacing.xl * 3,
2119
+ paddingLeft: theme.spacing.xl * 13,
1748
2120
  backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[6] : theme.colors.gray[0],
1749
2121
  borderTop: `1px solid ${theme.colorScheme === "dark" ? theme.colors.dark[5] : theme.colors.gray[2]}`
1750
2122
  },
@@ -1824,13 +2196,10 @@ const App = (props) => {
1824
2196
  {
1825
2197
  padding: "xs",
1826
2198
  navbar: /* @__PURE__ */ React.createElement(
1827
- Navbar,
1828
- {
1829
- active: props.navbar.props.active,
1830
- navigate: props.navbar.props.navigate,
1831
- onLogout: props.navbar.props.onLogout,
2199
+ NestedNavbar,
2200
+ __spreadProps(__spreadValues({}, props.navbar.props), {
1832
2201
  onSwitchAccounts: () => account.setChangeModalOpen(true)
1833
- }
2202
+ })
1834
2203
  ),
1835
2204
  footer: /* @__PURE__ */ React.createElement(React.Fragment, null, !account.opened && /* @__PURE__ */ React.createElement("footer", { className: classes.footer }, /* @__PURE__ */ React.createElement(Container, { className: classes.inner }, /* @__PURE__ */ React.createElement("div", { className: classes.logo }, /* @__PURE__ */ React.createElement(Group, { spacing: "xs" }, /* @__PURE__ */ React.createElement("div", { style: { width: 15 } }, /* @__PURE__ */ React.createElement(Image, { fit: "contain", src: "https://cdn.localcivics.io/brand/l.png" })), /* @__PURE__ */ React.createElement(Title, { color: "dimmed", size: "h5" }, "Local Civics")), /* @__PURE__ */ React.createElement(Text, { size: "xs", color: "dimmed", className: classes.description }, "We connect students to powerful civic learning experiences.")), /* @__PURE__ */ React.createElement("div", { className: classes.groups }, /* @__PURE__ */ React.createElement("div", { className: classes.wrapper }, /* @__PURE__ */ React.createElement(
1836
2205
  Text,
@@ -1878,9 +2247,10 @@ const App = (props) => {
1878
2247
  SwitchAccount,
1879
2248
  {
1880
2249
  opened: account.opened,
2250
+ loading: account.loading,
1881
2251
  account: account.account,
1882
2252
  accounts: account.accounts,
1883
- onChange: account.onAccountChange,
2253
+ onClick: account.onAccountChange,
1884
2254
  onClose: () => account.setChangeModalOpen(false)
1885
2255
  }
1886
2256
  )
@@ -1890,6 +2260,7 @@ const useAccount = (account, accounts, onAccountChange) => {
1890
2260
  const accountsKey = JSON.stringify(accounts);
1891
2261
  const [changeModalOpen, setChangeModalOpen] = useState(false);
1892
2262
  const [active, setActive] = useState(account);
2263
+ const [loading, setLoading] = useState(false);
1893
2264
  React.useEffect(() => {
1894
2265
  setActive(account);
1895
2266
  }, [account, accountsKey]);
@@ -1897,14 +2268,18 @@ const useAccount = (account, accounts, onAccountChange) => {
1897
2268
  opened: changeModalOpen,
1898
2269
  account: active,
1899
2270
  accounts,
2271
+ loading,
1900
2272
  setChangeModalOpen,
1901
2273
  onAccountChange: (account2) => {
1902
- setActive(account2);
1903
- setChangeModalOpen(false);
1904
- onAccountChange(account2);
2274
+ setLoading(true);
2275
+ onAccountChange(account2).then(() => {
2276
+ setActive(account2);
2277
+ setLoading(false);
2278
+ setChangeModalOpen(false);
2279
+ });
1905
2280
  }
1906
2281
  };
1907
2282
  };
1908
2283
 
1909
- export { AdminProvider, App, Badge, Badges, Class, Classes, Dashboard, Home, Lesson, Lessons, Navbar, Student, SwitchAccount };
2284
+ export { AdminProvider, App, Badge, Badges, Class, Classes, Dashboard, Home, Lesson, Lessons, Navbar, NestedNavbar, Student, SwitchAccount };
1910
2285
  //# sourceMappingURL=index.mjs.map