@local-civics/mgmt-ui 0.1.54 → 0.1.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +55 -35
- package/dist/index.js +123 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +152 -48
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { NotificationsProvider } from '@mantine/notifications';
|
|
2
2
|
export { showNotification, updateNotification } from '@mantine/notifications';
|
|
3
|
-
import { IconArrowLeft, IconCategory2, IconCheck, IconTrash,
|
|
3
|
+
import { IconArrowLeft, IconCategory2, IconPlaylistAdd, IconChevronDown, IconClipboardCopy, IconCheck, IconTrash, IconDownload, IconX, IconCloudUpload, IconInfoCircle, IconColorSwatch, IconSwitchHorizontal, IconLogout, IconHome2, IconGauge, IconAlbum, IconLambda, IconBrandInstagram, IconBrandLinkedin, IconBrandFacebook } from '@tabler/icons';
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import { useState } from 'react';
|
|
6
|
-
import { createStyles, Text, Tabs as Tabs$1, Title, Image,
|
|
6
|
+
import { createStyles, Text, Tabs as Tabs$1, Title, Image, Grid, Badge as Badge$1, ScrollArea, UnstyledButton, Group, Avatar, Table as Table$g, Container, Stack as Stack$3, ActionIcon, Button, LoadingOverlay, Select, Autocomplete, Menu, Drawer, Divider, TextInput, Tooltip, Paper, ThemeIcon, Card, Overlay, createEmotionCache, MantineProvider, Modal, Navbar as Navbar$1, Center, AppShell, Loader } from '@mantine/core';
|
|
7
|
+
import { DataTable } from 'mantine-datatable';
|
|
7
8
|
import { Dropzone, MIME_TYPES } from '@mantine/dropzone';
|
|
8
9
|
import { useForm } from '@mantine/form';
|
|
9
10
|
import * as papa from 'papaparse';
|
|
10
11
|
import { openConfirmModal, ModalsProvider } from '@mantine/modals';
|
|
11
12
|
import { Chart } from 'react-charts';
|
|
12
13
|
|
|
13
|
-
const useStyles$
|
|
14
|
+
const useStyles$d = createStyles((theme) => ({
|
|
14
15
|
root: {
|
|
15
16
|
display: "flex",
|
|
16
17
|
backgroundImage: `linear-gradient(-60deg, ${theme.colors[theme.primaryColor][4]} 0%, ${theme.colors[theme.primaryColor][7]} 100%)`,
|
|
@@ -57,7 +58,7 @@ const useStyles$c = createStyles((theme) => ({
|
|
|
57
58
|
}
|
|
58
59
|
}));
|
|
59
60
|
const StatsGroup = ({ data }) => {
|
|
60
|
-
const { classes } = useStyles$
|
|
61
|
+
const { classes } = useStyles$d();
|
|
61
62
|
const stats = data.map((stat) => {
|
|
62
63
|
const value = (() => {
|
|
63
64
|
if (stat.unit === "%") {
|
|
@@ -76,7 +77,7 @@ const Tabs = (props) => {
|
|
|
76
77
|
return /* @__PURE__ */ React.createElement(Tabs$1, { value: props.value, onTabChange: props.onChange }, /* @__PURE__ */ React.createElement(Tabs$1.List, null, tabs));
|
|
77
78
|
};
|
|
78
79
|
|
|
79
|
-
const useStyles$
|
|
80
|
+
const useStyles$c = createStyles((theme) => ({
|
|
80
81
|
wrapper: {
|
|
81
82
|
display: "flex",
|
|
82
83
|
alignItems: "center",
|
|
@@ -127,12 +128,20 @@ const useStyles$b = createStyles((theme) => ({
|
|
|
127
128
|
}
|
|
128
129
|
}));
|
|
129
130
|
const PlaceholderBanner = (props) => {
|
|
130
|
-
const { classes } = useStyles$
|
|
131
|
+
const { classes } = useStyles$c();
|
|
131
132
|
const title = props.title || "Nothing to display";
|
|
132
133
|
const description = props.description || "We don't have anything to show you here just yet. Add data, check back later, or adjust your search.";
|
|
133
134
|
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 }));
|
|
134
135
|
};
|
|
135
136
|
|
|
137
|
+
function Stack$2(props) {
|
|
138
|
+
if (props.items.length === 0) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
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.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"))));
|
|
142
|
+
return /* @__PURE__ */ React.createElement(Grid, { grow: true, gutter: "lg", sx: { padding: 20, minWidth: 700 } }, rows);
|
|
143
|
+
}
|
|
144
|
+
|
|
136
145
|
function Table$f(props) {
|
|
137
146
|
if (props.items.length === 0) {
|
|
138
147
|
return /* @__PURE__ */ React.createElement(
|
|
@@ -145,8 +154,30 @@ function Table$f(props) {
|
|
|
145
154
|
}
|
|
146
155
|
);
|
|
147
156
|
}
|
|
148
|
-
|
|
149
|
-
|
|
157
|
+
return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(
|
|
158
|
+
DataTable,
|
|
159
|
+
{
|
|
160
|
+
verticalSpacing: "sm",
|
|
161
|
+
sx: { minWidth: 700 },
|
|
162
|
+
withBorder: false,
|
|
163
|
+
borderRadius: "sm",
|
|
164
|
+
withColumnBorders: true,
|
|
165
|
+
striped: true,
|
|
166
|
+
highlightOnHover: true,
|
|
167
|
+
records: props.items,
|
|
168
|
+
columns: [{
|
|
169
|
+
accessor: "name",
|
|
170
|
+
title: "Student Name",
|
|
171
|
+
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))))
|
|
172
|
+
}, {
|
|
173
|
+
accessor: "status",
|
|
174
|
+
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"))
|
|
175
|
+
}],
|
|
176
|
+
rowExpansion: {
|
|
177
|
+
content: ({ record }) => /* @__PURE__ */ React.createElement(Stack$2, { items: record.lessons })
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
));
|
|
150
181
|
}
|
|
151
182
|
|
|
152
183
|
function Table$e(props) {
|
|
@@ -168,7 +199,7 @@ function Table$e(props) {
|
|
|
168
199
|
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)));
|
|
169
200
|
}
|
|
170
201
|
|
|
171
|
-
const useStyles$
|
|
202
|
+
const useStyles$b = createStyles((theme) => ({
|
|
172
203
|
title: {
|
|
173
204
|
fontSize: 34,
|
|
174
205
|
fontWeight: 900,
|
|
@@ -181,11 +212,11 @@ const useStyles$a = createStyles((theme) => ({
|
|
|
181
212
|
}
|
|
182
213
|
}));
|
|
183
214
|
const Badge = (props) => {
|
|
184
|
-
const { classes } = useStyles$
|
|
215
|
+
const { classes } = useStyles$b();
|
|
185
216
|
const [tab, setTab] = useState("lessons");
|
|
186
217
|
const numberOfStudents = props.students.length;
|
|
187
218
|
const percentageOfBadgesEarned = numberOfStudents > 0 ? props.students.filter((u) => u.isComplete).length / numberOfStudents : 0;
|
|
188
|
-
return /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$
|
|
219
|
+
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(
|
|
189
220
|
Badge$1,
|
|
190
221
|
{
|
|
191
222
|
variant: "filled",
|
|
@@ -193,14 +224,14 @@ const Badge = (props) => {
|
|
|
193
224
|
size: "lg"
|
|
194
225
|
},
|
|
195
226
|
"Badges"
|
|
196
|
-
), /* @__PURE__ */ React.createElement(Group, null, /* @__PURE__ */ React.createElement(Stack$
|
|
227
|
+
), /* @__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(
|
|
197
228
|
Button,
|
|
198
229
|
{
|
|
199
230
|
variant: "gradient",
|
|
200
231
|
onClick: props.onPreviewClick
|
|
201
232
|
},
|
|
202
233
|
"Preview"
|
|
203
|
-
))))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React.createElement(LoadingOverlay, { visible: props.loading, overlayBlur: 2 }), /* @__PURE__ */ React.createElement(Stack$
|
|
234
|
+
))))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React.createElement(LoadingOverlay, { visible: props.loading, overlayBlur: 2 }), /* @__PURE__ */ React.createElement(Stack$3, null, /* @__PURE__ */ React.createElement(StatsGroup, { data: [
|
|
204
235
|
{
|
|
205
236
|
title: "BADGE COMPLETION",
|
|
206
237
|
value: percentageOfBadgesEarned,
|
|
@@ -221,7 +252,7 @@ const Badge = (props) => {
|
|
|
221
252
|
return { value: g.classId, label: g.name };
|
|
222
253
|
})
|
|
223
254
|
}
|
|
224
|
-
), /* @__PURE__ */ React.createElement(Stack$
|
|
255
|
+
), /* @__PURE__ */ React.createElement(Stack$3, { spacing: 0 }, /* @__PURE__ */ React.createElement(
|
|
225
256
|
Tabs,
|
|
226
257
|
{
|
|
227
258
|
value: tab,
|
|
@@ -279,7 +310,7 @@ function Table$d(props) {
|
|
|
279
310
|
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)));
|
|
280
311
|
}
|
|
281
312
|
|
|
282
|
-
const useStyles$
|
|
313
|
+
const useStyles$a = createStyles((theme) => ({
|
|
283
314
|
title: {
|
|
284
315
|
fontSize: 34,
|
|
285
316
|
fontWeight: 900,
|
|
@@ -292,8 +323,8 @@ const useStyles$9 = createStyles((theme) => ({
|
|
|
292
323
|
}
|
|
293
324
|
}));
|
|
294
325
|
const Badges = (props) => {
|
|
295
|
-
const { classes } = useStyles$
|
|
296
|
-
return /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$
|
|
326
|
+
const { classes } = useStyles$a();
|
|
327
|
+
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(
|
|
297
328
|
Autocomplete,
|
|
298
329
|
{
|
|
299
330
|
placeholder: "Search for a badge that fits your needs",
|
|
@@ -416,7 +447,7 @@ function Table$8(props) {
|
|
|
416
447
|
|
|
417
448
|
const Dashboard = (props) => {
|
|
418
449
|
const [tab, setTab] = useState("students");
|
|
419
|
-
return /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$
|
|
450
|
+
return /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$3, null, /* @__PURE__ */ React.createElement(Stack$3, { spacing: 0 }, /* @__PURE__ */ React.createElement(Title, { size: "h3" }, "Dashboard"), /* @__PURE__ */ React.createElement(Text, { color: "dimmed", size: "sm", mt: "md" }, "Fast-track learning for your students.")), /* @__PURE__ */ React.createElement(Stack$3, null, /* @__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: [
|
|
420
451
|
{
|
|
421
452
|
title: "# OF STUDENTS",
|
|
422
453
|
value: props.students.length
|
|
@@ -451,7 +482,7 @@ const Dashboard = (props) => {
|
|
|
451
482
|
return { value: g.classId, label: g.name };
|
|
452
483
|
})
|
|
453
484
|
}
|
|
454
|
-
), /* @__PURE__ */ React.createElement(Stack$
|
|
485
|
+
), /* @__PURE__ */ React.createElement(Stack$3, { spacing: 0 }, /* @__PURE__ */ React.createElement(
|
|
455
486
|
Tabs,
|
|
456
487
|
{
|
|
457
488
|
value: tab,
|
|
@@ -500,6 +531,50 @@ const Dashboard = (props) => {
|
|
|
500
531
|
)))))));
|
|
501
532
|
};
|
|
502
533
|
|
|
534
|
+
const useStyles$9 = createStyles((theme) => ({
|
|
535
|
+
button: {
|
|
536
|
+
borderTopRightRadius: 0,
|
|
537
|
+
borderBottomRightRadius: 0,
|
|
538
|
+
marginLeft: 0,
|
|
539
|
+
marginRight: 0
|
|
540
|
+
},
|
|
541
|
+
menuControl: {
|
|
542
|
+
borderTopLeftRadius: 0,
|
|
543
|
+
borderBottomLeftRadius: 0,
|
|
544
|
+
border: 0,
|
|
545
|
+
borderLeft: `1px solid ${theme.colorScheme === "dark" ? theme.colors.dark[7] : theme.white}`
|
|
546
|
+
}
|
|
547
|
+
}));
|
|
548
|
+
const SplitButton = (props) => {
|
|
549
|
+
const { classes, theme } = useStyles$9();
|
|
550
|
+
const menuIconColor = theme.colors[theme.primaryColor][theme.colorScheme === "dark" ? 5 : 6];
|
|
551
|
+
return /* @__PURE__ */ React.createElement(Group, { noWrap: true, spacing: 0 }, /* @__PURE__ */ React.createElement(
|
|
552
|
+
Button,
|
|
553
|
+
{
|
|
554
|
+
className: classes.button,
|
|
555
|
+
leftIcon: /* @__PURE__ */ React.createElement(IconPlaylistAdd, { size: 14 }),
|
|
556
|
+
onClick: props.onAddStudentsClick
|
|
557
|
+
},
|
|
558
|
+
"Add students"
|
|
559
|
+
), /* @__PURE__ */ React.createElement(Menu, { transition: "pop", position: "bottom-end" }, /* @__PURE__ */ React.createElement(Menu.Target, null, /* @__PURE__ */ React.createElement(
|
|
560
|
+
ActionIcon,
|
|
561
|
+
{
|
|
562
|
+
variant: "filled",
|
|
563
|
+
color: theme.primaryColor,
|
|
564
|
+
size: 36,
|
|
565
|
+
className: classes.menuControl
|
|
566
|
+
},
|
|
567
|
+
/* @__PURE__ */ React.createElement(IconChevronDown, { size: 16, stroke: 1.5 })
|
|
568
|
+
)), /* @__PURE__ */ React.createElement(Menu.Dropdown, null, /* @__PURE__ */ React.createElement(
|
|
569
|
+
Menu.Item,
|
|
570
|
+
{
|
|
571
|
+
icon: /* @__PURE__ */ React.createElement(IconClipboardCopy, { size: 16, stroke: 1.5, color: menuIconColor }),
|
|
572
|
+
onClick: props.onCopyClassLinkClick
|
|
573
|
+
},
|
|
574
|
+
"Copy class link"
|
|
575
|
+
))));
|
|
576
|
+
};
|
|
577
|
+
|
|
503
578
|
function Table$7(props) {
|
|
504
579
|
if (props.items.length === 0) {
|
|
505
580
|
return /* @__PURE__ */ React.createElement(
|
|
@@ -603,12 +678,12 @@ const Class = (props) => {
|
|
|
603
678
|
padding: "xl",
|
|
604
679
|
size: "xl"
|
|
605
680
|
},
|
|
606
|
-
/* @__PURE__ */ React.createElement(Stack$
|
|
681
|
+
/* @__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(() => {
|
|
607
682
|
const values = form.values;
|
|
608
683
|
form.reset();
|
|
609
684
|
setOpened(false);
|
|
610
685
|
props.onCreateStudents && props.onCreateStudents([values]);
|
|
611
|
-
}) }, /* @__PURE__ */ React.createElement(Stack$
|
|
686
|
+
}) }, /* @__PURE__ */ React.createElement(Stack$3, null, /* @__PURE__ */ React.createElement(
|
|
612
687
|
TextInput,
|
|
613
688
|
__spreadValues$3({
|
|
614
689
|
withAsterisk: true,
|
|
@@ -628,7 +703,7 @@ const Class = (props) => {
|
|
|
628
703
|
placeholder: "Family name"
|
|
629
704
|
}, form.getInputProps("familyName"))
|
|
630
705
|
)), /* @__PURE__ */ React.createElement(Button, { type: "submit", fullWidth: true, mt: "md" }, "Submit"))))
|
|
631
|
-
), /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$
|
|
706
|
+
), /* @__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(
|
|
632
707
|
Badge$1,
|
|
633
708
|
{
|
|
634
709
|
variant: "filled",
|
|
@@ -637,13 +712,12 @@ const Class = (props) => {
|
|
|
637
712
|
},
|
|
638
713
|
"Classes"
|
|
639
714
|
), /* @__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(
|
|
640
|
-
|
|
715
|
+
SplitButton,
|
|
641
716
|
{
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
))), /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React.createElement(LoadingOverlay, { visible: props.loading, overlayBlur: 2 }), /* @__PURE__ */ React.createElement(Stack$1, { spacing: "sm" }, /* @__PURE__ */ React.createElement(StatsGroup, { data: [
|
|
717
|
+
onAddStudentsClick: () => setOpened(true),
|
|
718
|
+
onCopyClassLinkClick: props.onCopyLinkClick
|
|
719
|
+
}
|
|
720
|
+
))), /* @__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: [
|
|
647
721
|
{
|
|
648
722
|
title: "# OF STUDENTS",
|
|
649
723
|
value: props.students.length
|
|
@@ -799,7 +873,7 @@ const Classes = (props) => {
|
|
|
799
873
|
form.reset();
|
|
800
874
|
setOpened(false);
|
|
801
875
|
props.onCreateClass && props.onCreateClass(values);
|
|
802
|
-
}) }, /* @__PURE__ */ React.createElement(Stack$
|
|
876
|
+
}) }, /* @__PURE__ */ React.createElement(Stack$3, null, /* @__PURE__ */ React.createElement(
|
|
803
877
|
TextInput,
|
|
804
878
|
__spreadValues$2({
|
|
805
879
|
withAsterisk: true,
|
|
@@ -813,14 +887,14 @@ const Classes = (props) => {
|
|
|
813
887
|
placeholder: "A class for my first period English students"
|
|
814
888
|
}, form.getInputProps("description"))
|
|
815
889
|
)), /* @__PURE__ */ React.createElement(Button, { type: "submit", fullWidth: true, mt: "md" }, "Submit"))
|
|
816
|
-
), /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$
|
|
890
|
+
), /* @__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(
|
|
817
891
|
Button,
|
|
818
892
|
{
|
|
819
893
|
onClick: () => setOpened(true),
|
|
820
894
|
leftIcon: /* @__PURE__ */ React.createElement(IconPlaylistAdd, { size: 14 })
|
|
821
895
|
},
|
|
822
896
|
"Create class"
|
|
823
|
-
))), /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React.createElement(LoadingOverlay, { visible: props.loading, overlayBlur: 2 }), /* @__PURE__ */ React.createElement(Stack$
|
|
897
|
+
))), /* @__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: [
|
|
824
898
|
{
|
|
825
899
|
title: "# OF CLASSES",
|
|
826
900
|
value: props.classes.length
|
|
@@ -906,7 +980,7 @@ const Student = (props) => {
|
|
|
906
980
|
const [tab, setTab] = useState("badges");
|
|
907
981
|
const numberOfBadges = props.badges.length;
|
|
908
982
|
const percentageOfBadgesEarned = numberOfBadges > 0 ? props.badges.filter((b) => b.isComplete).length / numberOfBadges : 0;
|
|
909
|
-
return /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$
|
|
983
|
+
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(
|
|
910
984
|
Badge$1,
|
|
911
985
|
{
|
|
912
986
|
variant: "filled",
|
|
@@ -921,7 +995,7 @@ const Student = (props) => {
|
|
|
921
995
|
name: props.name,
|
|
922
996
|
impactStatement: props.impactStatement
|
|
923
997
|
}
|
|
924
|
-
))), /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React.createElement(LoadingOverlay, { visible: props.loading, overlayBlur: 2 }), /* @__PURE__ */ React.createElement(Stack$
|
|
998
|
+
))), /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React.createElement(LoadingOverlay, { visible: props.loading, overlayBlur: 2 }), /* @__PURE__ */ React.createElement(Stack$3, { spacing: "lg" }, /* @__PURE__ */ React.createElement(StatsGroup, { data: [
|
|
925
999
|
{
|
|
926
1000
|
title: "PROBLEMS SOLVED",
|
|
927
1001
|
value: props.numberOfProblemsSolved
|
|
@@ -936,7 +1010,7 @@ const Student = (props) => {
|
|
|
936
1010
|
value: percentageOfBadgesEarned,
|
|
937
1011
|
unit: "%"
|
|
938
1012
|
}
|
|
939
|
-
] }), /* @__PURE__ */ React.createElement(Stack$
|
|
1013
|
+
] }), /* @__PURE__ */ React.createElement(Stack$3, { spacing: 0 }, /* @__PURE__ */ React.createElement(
|
|
940
1014
|
Tabs,
|
|
941
1015
|
{
|
|
942
1016
|
value: tab,
|
|
@@ -1121,7 +1195,7 @@ const TenantBanner = (_a) => {
|
|
|
1121
1195
|
};
|
|
1122
1196
|
|
|
1123
1197
|
const Home = (props) => {
|
|
1124
|
-
return /* @__PURE__ */ React.createElement(Container, { size: "lg" }, /* @__PURE__ */ React.createElement(Stack$
|
|
1198
|
+
return /* @__PURE__ */ React.createElement(Container, { size: "lg" }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: "lg" }, /* @__PURE__ */ React.createElement(Grid, { gutter: "md" }, /* @__PURE__ */ React.createElement(Grid.Col, { md: 6 }, /* @__PURE__ */ React.createElement(
|
|
1125
1199
|
UserInfo,
|
|
1126
1200
|
{
|
|
1127
1201
|
variant: "compact",
|
|
@@ -1186,6 +1260,14 @@ function Table$2(props) {
|
|
|
1186
1260
|
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)));
|
|
1187
1261
|
}
|
|
1188
1262
|
|
|
1263
|
+
function Stack$1(props) {
|
|
1264
|
+
if (props.items.length === 0) {
|
|
1265
|
+
return null;
|
|
1266
|
+
}
|
|
1267
|
+
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.")));
|
|
1268
|
+
return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(Stack$3, { spacing: 24, sx: { padding: 20, minWidth: 700 } }, rows));
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1189
1271
|
function Table$1(props) {
|
|
1190
1272
|
if (props.items.length === 0) {
|
|
1191
1273
|
return /* @__PURE__ */ React.createElement(
|
|
@@ -1198,8 +1280,30 @@ function Table$1(props) {
|
|
|
1198
1280
|
}
|
|
1199
1281
|
);
|
|
1200
1282
|
}
|
|
1201
|
-
|
|
1202
|
-
|
|
1283
|
+
return /* @__PURE__ */ React.createElement(ScrollArea.Autosize, { maxHeight: 500 }, /* @__PURE__ */ React.createElement(
|
|
1284
|
+
DataTable,
|
|
1285
|
+
{
|
|
1286
|
+
verticalSpacing: "sm",
|
|
1287
|
+
sx: { minWidth: 700 },
|
|
1288
|
+
withBorder: false,
|
|
1289
|
+
borderRadius: "sm",
|
|
1290
|
+
withColumnBorders: true,
|
|
1291
|
+
striped: true,
|
|
1292
|
+
highlightOnHover: true,
|
|
1293
|
+
records: props.items,
|
|
1294
|
+
columns: [{
|
|
1295
|
+
accessor: "name",
|
|
1296
|
+
title: "Student Name",
|
|
1297
|
+
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))))
|
|
1298
|
+
}, {
|
|
1299
|
+
accessor: "status",
|
|
1300
|
+
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"))
|
|
1301
|
+
}],
|
|
1302
|
+
rowExpansion: {
|
|
1303
|
+
content: ({ record }) => /* @__PURE__ */ React.createElement(Stack$1, { items: record.answers })
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
));
|
|
1203
1307
|
}
|
|
1204
1308
|
|
|
1205
1309
|
function Stack(props) {
|
|
@@ -1242,7 +1346,7 @@ function Stack(props) {
|
|
|
1242
1346
|
labelMap[r] = labelMap[r] ? labelMap[r] + 1 : 1;
|
|
1243
1347
|
}
|
|
1244
1348
|
}));
|
|
1245
|
-
return /* @__PURE__ */ React.createElement(Card, { key: row.question, withBorder: true, p: "xl", radius: "md" }, /* @__PURE__ */ React.createElement(Stack$
|
|
1349
|
+
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("div", { style: { background: "white", height: "300px", width: "100%", position: "relative" } }, /* @__PURE__ */ React.createElement(
|
|
1246
1350
|
Chart,
|
|
1247
1351
|
{
|
|
1248
1352
|
options: {
|
|
@@ -1261,12 +1365,12 @@ function Stack(props) {
|
|
|
1261
1365
|
}
|
|
1262
1366
|
))));
|
|
1263
1367
|
}
|
|
1264
|
-
return /* @__PURE__ */ React.createElement(Card, { key: row.question, withBorder: true, p: "xl", radius: "md" }, /* @__PURE__ */ React.createElement(Stack$
|
|
1368
|
+
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) => {
|
|
1265
1369
|
const answerText = a.join("\n");
|
|
1266
1370
|
return /* @__PURE__ */ React.createElement(Card, { key: answerText, p: 5, radius: 0, bg: "gray.0" }, /* @__PURE__ */ React.createElement(Text, null, answerText));
|
|
1267
1371
|
})))));
|
|
1268
1372
|
});
|
|
1269
|
-
return /* @__PURE__ */ React.createElement(Stack$
|
|
1373
|
+
return /* @__PURE__ */ React.createElement(Stack$3, { py: 4, spacing: 10, sx: { minWidth: 700 } }, rows);
|
|
1270
1374
|
}
|
|
1271
1375
|
const truncateWithEllipses = (text, max) => text.substr(0, max - 1) + (text.length > max ? "…" : "");
|
|
1272
1376
|
|
|
@@ -1287,7 +1391,7 @@ const Lesson = (props) => {
|
|
|
1287
1391
|
const [tab, setTab] = useState("question");
|
|
1288
1392
|
const numberOfStudents = props.students.length;
|
|
1289
1393
|
const percentageOfLessonsCompleted = numberOfStudents > 0 ? props.students.filter((u) => u.isComplete).length / numberOfStudents : 0;
|
|
1290
|
-
return /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$
|
|
1394
|
+
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(
|
|
1291
1395
|
Badge$1,
|
|
1292
1396
|
{
|
|
1293
1397
|
variant: "filled",
|
|
@@ -1295,14 +1399,14 @@ const Lesson = (props) => {
|
|
|
1295
1399
|
size: "lg"
|
|
1296
1400
|
},
|
|
1297
1401
|
"Lessons"
|
|
1298
|
-
), /* @__PURE__ */ React.createElement(Group, null, /* @__PURE__ */ React.createElement(Stack$
|
|
1402
|
+
), /* @__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(
|
|
1299
1403
|
Button,
|
|
1300
1404
|
{
|
|
1301
1405
|
variant: "gradient",
|
|
1302
1406
|
onClick: props.onPreviewClick
|
|
1303
1407
|
},
|
|
1304
1408
|
"Preview"
|
|
1305
|
-
))))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React.createElement(LoadingOverlay, { visible: props.loading, overlayBlur: 2 }), /* @__PURE__ */ React.createElement(Stack$
|
|
1409
|
+
))))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React.createElement(LoadingOverlay, { visible: props.loading, overlayBlur: 2 }), /* @__PURE__ */ React.createElement(Stack$3, null, /* @__PURE__ */ React.createElement(StatsGroup, { data: [
|
|
1306
1410
|
{
|
|
1307
1411
|
title: "LESSON COMPLETION",
|
|
1308
1412
|
value: percentageOfLessonsCompleted,
|
|
@@ -1323,14 +1427,14 @@ const Lesson = (props) => {
|
|
|
1323
1427
|
return { value: g.classId, label: g.name };
|
|
1324
1428
|
})
|
|
1325
1429
|
}
|
|
1326
|
-
), /* @__PURE__ */ React.createElement(Stack$
|
|
1430
|
+
), /* @__PURE__ */ React.createElement(Stack$3, { spacing: 0 }, /* @__PURE__ */ React.createElement(
|
|
1327
1431
|
Tabs,
|
|
1328
1432
|
{
|
|
1329
1433
|
value: tab,
|
|
1330
1434
|
data: [
|
|
1331
1435
|
{ label: "By question", value: "question" },
|
|
1332
|
-
{ label: "By
|
|
1333
|
-
{ label: "By
|
|
1436
|
+
{ label: "By student", value: "students" },
|
|
1437
|
+
{ label: "By reflection", value: "reflections" }
|
|
1334
1438
|
],
|
|
1335
1439
|
onChange: setTab
|
|
1336
1440
|
}
|
|
@@ -1401,7 +1505,7 @@ const useStyles$2 = createStyles((theme) => ({
|
|
|
1401
1505
|
}));
|
|
1402
1506
|
const Lessons = (props) => {
|
|
1403
1507
|
const { classes } = useStyles$2();
|
|
1404
|
-
return /* @__PURE__ */ React.createElement(Container, { size: "lg", py: "xl" }, /* @__PURE__ */ React.createElement(Stack$
|
|
1508
|
+
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(
|
|
1405
1509
|
Autocomplete,
|
|
1406
1510
|
{
|
|
1407
1511
|
placeholder: "Search for a lesson that fits your needs",
|
|
@@ -1515,7 +1619,7 @@ const Navbar = (props) => {
|
|
|
1515
1619
|
onClick: () => props.navigate(link.href)
|
|
1516
1620
|
}
|
|
1517
1621
|
));
|
|
1518
|
-
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$
|
|
1622
|
+
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(
|
|
1519
1623
|
NavbarLink,
|
|
1520
1624
|
{
|
|
1521
1625
|
icon: IconSwitchHorizontal,
|