@olinfo/quizms-firebase 4.1.2 → 5.0.0

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.
Files changed (64) hide show
  1. package/dist/cli.js +14 -14
  2. package/dist/cli.js.map +1 -1
  3. package/dist/package.json.js +1 -1
  4. package/dist/src/cli/definalize.js +17 -17
  5. package/dist/src/cli/definalize.js.map +1 -1
  6. package/dist/src/cli/export.js +42 -34
  7. package/dist/src/cli/export.js.map +1 -1
  8. package/dist/src/cli/files/firestore-indexes.json.js +1 -1
  9. package/dist/src/cli/files/firestore.rules.js +27 -27
  10. package/dist/src/cli/files/firestore.rules.js.map +1 -1
  11. package/dist/src/cli/files/functions-index.js +3 -3
  12. package/dist/src/cli/files/functions-index.js.map +1 -1
  13. package/dist/src/cli/files/storage.rules.js +3 -3
  14. package/dist/src/cli/files/storage.rules.js.map +1 -1
  15. package/dist/src/cli/import.js +65 -71
  16. package/dist/src/cli/import.js.map +1 -1
  17. package/dist/src/cli/update-scores.js +7 -7
  18. package/dist/src/cli/update-scores.js.map +1 -1
  19. package/dist/src/cli/utils/converters-admin.js +23 -22
  20. package/dist/src/cli/utils/converters-admin.js.map +1 -1
  21. package/dist/src/functions/api/index.js +18 -18
  22. package/dist/src/functions/api/index.js.map +1 -1
  23. package/dist/src/functions/api/queries.js +21 -21
  24. package/dist/src/functions/api/queries.js.map +1 -1
  25. package/dist/src/functions/api/student.js +46 -47
  26. package/dist/src/functions/api/student.js.map +1 -1
  27. package/dist/src/functions/api/teacher.js +92 -95
  28. package/dist/src/functions/api/teacher.js.map +1 -1
  29. package/dist/src/functions/submissions.js +11 -7
  30. package/dist/src/functions/submissions.js.map +1 -1
  31. package/dist/src/functions/update-scores.js +14 -14
  32. package/dist/src/functions/update-scores.js.map +1 -1
  33. package/dist/src/models/submission.js +13 -0
  34. package/dist/src/models/submission.js.map +1 -0
  35. package/dist/src/web/admin/announcements.js +45 -42
  36. package/dist/src/web/admin/announcements.js.map +1 -1
  37. package/dist/src/web/admin/contest-settings.js +19 -11
  38. package/dist/src/web/admin/contest-settings.js.map +1 -1
  39. package/dist/src/web/admin/context.js.map +1 -1
  40. package/dist/src/web/admin/dashboard.js +56 -35
  41. package/dist/src/web/admin/dashboard.js.map +1 -1
  42. package/dist/src/web/admin/export.js +100 -43
  43. package/dist/src/web/admin/export.js.map +1 -1
  44. package/dist/src/web/admin/layout.js +25 -21
  45. package/dist/src/web/admin/layout.js.map +1 -1
  46. package/dist/src/web/admin/provider.js +41 -21
  47. package/dist/src/web/admin/provider.js.map +1 -1
  48. package/dist/src/web/admin/school-table.js +20 -24
  49. package/dist/src/web/admin/school-table.js.map +1 -1
  50. package/dist/src/web/common/api.js +24 -20
  51. package/dist/src/web/common/api.js.map +1 -1
  52. package/dist/src/web/common/converters.js +38 -39
  53. package/dist/src/web/common/converters.js.map +1 -1
  54. package/dist/src/web/common/token-login.js +18 -18
  55. package/dist/src/web/common/token-login.js.map +1 -1
  56. package/dist/src/web/entry/admin.js +22 -13
  57. package/dist/src/web/entry/admin.js.map +1 -1
  58. package/dist/src/web/entry/student-statement.js +1 -1
  59. package/dist/src/web/entry/student-statement.js.map +1 -1
  60. package/dist/src/web/entry/student.js +80 -75
  61. package/dist/src/web/entry/student.js.map +1 -1
  62. package/dist/src/web/entry/teacher.js +63 -62
  63. package/dist/src/web/entry/teacher.js.map +1 -1
  64. package/package.json +13 -13
@@ -1,34 +1,38 @@
1
- import { jsxs as o, Fragment as s, jsx as r } from "react/jsx-runtime";
2
- import { Suspense as u } from "react";
3
- import { Title as p, ErrorBoundary as h, Loading as f } from "@olinfo/quizms/components";
4
- import { Navbar as b, NavbarBrand as x, NavbarMenu as N, NavbarSubmenu as v, NavbarMenuItem as w, NavbarContent as g, Dropdown as D, DropdownButton as B, DropdownMenu as I, DropdownItem as L, Button as j } from "@olinfo/react-components";
1
+ import { jsxs as i, Fragment as u, jsx as e } from "react/jsx-runtime";
2
+ import { Suspense as p } from "react";
3
+ import { Title as f, ErrorBoundary as b, Loading as x } from "@olinfo/quizms/components";
4
+ import { Navbar as N, NavbarBrand as v, NavbarMenu as w, NavbarSubmenu as g, NavbarMenuItem as d, NavbarContent as D, Dropdown as $, DropdownButton as B, DropdownMenu as I, DropdownItem as L, Button as j } from "@olinfo/react-components";
5
5
  import k from "clsx";
6
6
  import { LogOut as y } from "lucide-react";
7
- import { useRoute as M, Link as $ } from "wouter";
8
- function T({ name: t, contests: n, logout: l, children: c }) {
9
- const [, a] = M("/:contestId/*?"), i = n.find((e) => e.id === a?.contestId);
10
- return /* @__PURE__ */ o(s, { children: [
11
- /* @__PURE__ */ o(b, { color: "bg-error text-error-content", children: [
12
- /* @__PURE__ */ r(x, { children: /* @__PURE__ */ r("div", { className: "flex items-center h-full font-bold", children: /* @__PURE__ */ r(p, {}) }) }),
13
- i && n.length >= 2 && /* @__PURE__ */ r(N, { children: /* @__PURE__ */ r(v, { title: i.name, children: n.map((e) => {
14
- const d = a?.["*"], m = d ? `/${e.id}/${d}` : `/${e.id}`;
15
- return /* @__PURE__ */ r(w, { children: /* @__PURE__ */ r($, { className: k(i.id === e.id && "active"), href: m, children: e.name }) }, e.id);
16
- }) }) }),
17
- /* @__PURE__ */ r(g, { children: /* @__PURE__ */ r(C, { name: t, logout: l }) })
7
+ import { useRoute as M, Link as l } from "wouter";
8
+ function R({ name: t, contests: n, logout: s, children: m }) {
9
+ const [, a] = M("/:contestId/*?"), o = n.find((r) => r.id === a?.contestId);
10
+ return /* @__PURE__ */ i(u, { children: [
11
+ /* @__PURE__ */ i(N, { color: "bg-error text-error-content", children: [
12
+ /* @__PURE__ */ e(v, { children: /* @__PURE__ */ e("div", { className: "flex items-center h-full font-bold", children: /* @__PURE__ */ e(f, {}) }) }),
13
+ o && n.length >= 2 && /* @__PURE__ */ i(w, { children: [
14
+ /* @__PURE__ */ e(g, { title: o.name, children: n.map((r) => {
15
+ const c = a?.["*"], h = c ? `/${r.id}/${c}` : `/${r.id}`;
16
+ return /* @__PURE__ */ e(d, { children: /* @__PURE__ */ e(l, { className: k(o.id === r.id && "active"), href: h, children: r.name }) }, r.id);
17
+ }) }),
18
+ /* @__PURE__ */ e(d, { children: /* @__PURE__ */ e(l, { href: `/${o.id}`, children: "Gestione gara" }) }),
19
+ /* @__PURE__ */ e(d, { children: /* @__PURE__ */ e(l, { href: `/${o.id}/schools`, children: "Gestione scuole" }) })
20
+ ] }),
21
+ /* @__PURE__ */ e(D, { children: /* @__PURE__ */ e(C, { name: t, logout: s }) })
18
22
  ] }),
19
- /* @__PURE__ */ r("div", { className: "mx-auto flex w-full max-w-screen-xl grow flex-col p-4 pb-8", children: /* @__PURE__ */ r(h, { children: /* @__PURE__ */ r(u, { fallback: /* @__PURE__ */ r(f, {}), children: c }) }) })
23
+ /* @__PURE__ */ e("div", { className: "mx-auto flex w-full max-w-screen-xl grow flex-col p-4 pb-8", children: /* @__PURE__ */ e(b, { children: /* @__PURE__ */ e(p, { fallback: /* @__PURE__ */ e(x, {}), children: m }) }) })
20
24
  ] });
21
25
  }
22
26
  function C({ name: t, logout: n }) {
23
- return /* @__PURE__ */ o(D, { className: "dropdown-end", children: [
24
- /* @__PURE__ */ r(B, { children: /* @__PURE__ */ r("div", { className: "truncate uppercase", children: t }) }),
25
- /* @__PURE__ */ r(I, { children: /* @__PURE__ */ r(L, { children: /* @__PURE__ */ o(j, { className: "flex justify-between gap-4", onClick: n, children: [
27
+ return /* @__PURE__ */ i($, { className: "dropdown-end", children: [
28
+ /* @__PURE__ */ e(B, { children: /* @__PURE__ */ e("div", { className: "truncate uppercase", children: t }) }),
29
+ /* @__PURE__ */ e(I, { children: /* @__PURE__ */ e(L, { children: /* @__PURE__ */ i(j, { className: "flex justify-between gap-4", onClick: n, children: [
26
30
  "Esci ",
27
- /* @__PURE__ */ r(y, { size: 20 })
31
+ /* @__PURE__ */ e(y, { size: 20 })
28
32
  ] }) }) })
29
33
  ] });
30
34
  }
31
35
  export {
32
- T as AdminLayout
36
+ R as AdminLayout
33
37
  };
34
38
  //# sourceMappingURL=layout.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"layout.js","sources":["../../../../src/web/admin/layout.tsx"],"sourcesContent":["import { type ReactNode, Suspense } from \"react\";\n\nimport { ErrorBoundary, Loading, Title } from \"@olinfo/quizms/components\";\nimport type { Contest } from \"@olinfo/quizms/models\";\nimport {\n Button,\n Dropdown,\n DropdownButton,\n DropdownItem,\n DropdownMenu,\n Navbar,\n NavbarBrand,\n NavbarContent,\n NavbarMenu,\n NavbarMenuItem,\n NavbarSubmenu,\n} from \"@olinfo/react-components\";\nimport clsx from \"clsx\";\nimport { LogOut } from \"lucide-react\";\nimport { Link, useRoute } from \"wouter\";\n\ntype Props = {\n name: string;\n contests: Contest[];\n logout: () => Promise<void>;\n children: ReactNode;\n};\n\nexport function AdminLayout({ name, contests, logout, children }: Props) {\n const [, params] = useRoute(\"/:contestId/*?\");\n const contest = contests.find((c) => c.id === params?.contestId);\n\n return (\n <>\n <Navbar color=\"bg-error text-error-content\">\n <NavbarBrand>\n <div className=\"flex items-center h-full font-bold\">\n <Title />\n </div>\n </NavbarBrand>\n {contest && contests.length >= 2 && (\n <NavbarMenu>\n <NavbarSubmenu title={contest.name}>\n {contests.map((c) => {\n const path = params?.[\"*\"];\n const href = path ? `/${c.id}/${path}` : `/${c.id}`;\n return (\n <NavbarMenuItem key={c.id}>\n <Link className={clsx(contest.id === c.id && \"active\")} href={href}>\n {c.name}\n </Link>\n </NavbarMenuItem>\n );\n })}\n </NavbarSubmenu>\n </NavbarMenu>\n )}\n <NavbarContent>\n <UserDropdown name={name} logout={logout} />\n </NavbarContent>\n </Navbar>\n <div className=\"mx-auto flex w-full max-w-screen-xl grow flex-col p-4 pb-8\">\n <ErrorBoundary>\n <Suspense fallback={<Loading />}>{children}</Suspense>\n </ErrorBoundary>\n </div>\n </>\n );\n}\n\nfunction UserDropdown({ name, logout }: { name: string; logout: () => Promise<void> }) {\n return (\n <Dropdown className=\"dropdown-end\">\n <DropdownButton>\n <div className=\"truncate uppercase\">{name}</div>\n </DropdownButton>\n <DropdownMenu>\n <DropdownItem>\n <Button className=\"flex justify-between gap-4\" onClick={logout}>\n Esci <LogOut size={20} />\n </Button>\n </DropdownItem>\n </DropdownMenu>\n </Dropdown>\n );\n}\n"],"names":["AdminLayout","name","contests","logout","children","params","useRoute","contest","c","jsxs","Fragment","Navbar","jsx","NavbarBrand","Title","NavbarMenu","NavbarSubmenu","path","href","NavbarMenuItem","Link","clsx","NavbarContent","UserDropdown","ErrorBoundary","Suspense","Loading","Dropdown","DropdownButton","DropdownMenu","DropdownItem","Button","LogOut"],"mappings":";;;;;;;AA4BO,SAASA,EAAY,EAAE,MAAAC,GAAM,UAAAC,GAAU,QAAAC,GAAQ,UAAAC,KAAmB;AACvE,QAAM,GAAGC,CAAM,IAAIC,EAAS,gBAAgB,GACtCC,IAAUL,EAAS,KAAK,CAACM,MAAMA,EAAE,OAAOH,GAAQ,SAAS;AAE/D,SACE,gBAAAI,EAAAC,GAAA,EACE,UAAA;AAAA,IAAA,gBAAAD,EAACE,GAAA,EAAO,OAAM,+BACZ,UAAA;AAAA,MAAA,gBAAAC,EAACC,GAAA,EACC,4BAAC,OAAA,EAAI,WAAU,sCACb,UAAA,gBAAAD,EAACE,GAAA,CAAA,CAAM,GACT,EAAA,CACF;AAAA,MACCP,KAAWL,EAAS,UAAU,uBAC5Ba,GAAA,EACC,UAAA,gBAAAH,EAACI,GAAA,EAAc,OAAOT,EAAQ,MAC3B,UAAAL,EAAS,IAAI,CAACM,MAAM;AACnB,cAAMS,IAAOZ,IAAS,GAAG,GACnBa,IAAOD,IAAO,IAAIT,EAAE,EAAE,IAAIS,CAAI,KAAK,IAAIT,EAAE,EAAE;AACjD,iCACGW,GAAA,EACC,UAAA,gBAAAP,EAACQ,GAAA,EAAK,WAAWC,EAAKd,EAAQ,OAAOC,EAAE,MAAM,QAAQ,GAAG,MAAAU,GACrD,YAAE,MACL,EAAA,GAHmBV,EAAE,EAIvB;AAAA,MAEJ,CAAC,GACH,GACF;AAAA,wBAEDc,GAAA,EACC,UAAA,gBAAAV,EAACW,GAAA,EAAa,MAAAtB,GAAY,QAAAE,GAAgB,EAAA,CAC5C;AAAA,IAAA,GACF;AAAA,IACA,gBAAAS,EAAC,OAAA,EAAI,WAAU,8DACb,4BAACY,GAAA,EACC,UAAA,gBAAAZ,EAACa,GAAA,EAAS,UAAU,gBAAAb,EAACc,GAAA,CAAA,CAAQ,GAAK,UAAAtB,GAAS,GAC7C,EAAA,CACF;AAAA,EAAA,GACF;AAEJ;AAEA,SAASmB,EAAa,EAAE,MAAAtB,GAAM,QAAAE,KAAyD;AACrF,SACE,gBAAAM,EAACkB,GAAA,EAAS,WAAU,gBAClB,UAAA;AAAA,IAAA,gBAAAf,EAACgB,KACC,UAAA,gBAAAhB,EAAC,OAAA,EAAI,WAAU,sBAAsB,aAAK,EAAA,CAC5C;AAAA,IACA,gBAAAA,EAACiB,KACC,UAAA,gBAAAjB,EAACkB,GAAA,EACC,4BAACC,GAAA,EAAO,WAAU,8BAA6B,SAAS5B,GAAQ,UAAA;AAAA,MAAA;AAAA,MACzD,gBAAAS,EAACoB,GAAA,EAAO,MAAM,GAAA,CAAI;AAAA,IAAA,EAAA,CACzB,GACF,EAAA,CACF;AAAA,EAAA,GACF;AAEJ;"}
1
+ {"version":3,"file":"layout.js","sources":["../../../../src/web/admin/layout.tsx"],"sourcesContent":["import { type ReactNode, Suspense } from \"react\";\n\nimport { ErrorBoundary, Loading, Title } from \"@olinfo/quizms/components\";\nimport type { Contest } from \"@olinfo/quizms/models\";\nimport {\n Button,\n Dropdown,\n DropdownButton,\n DropdownItem,\n DropdownMenu,\n Navbar,\n NavbarBrand,\n NavbarContent,\n NavbarMenu,\n NavbarMenuItem,\n NavbarSubmenu,\n} from \"@olinfo/react-components\";\nimport clsx from \"clsx\";\nimport { LogOut } from \"lucide-react\";\nimport { Link, useRoute } from \"wouter\";\n\ntype Props = {\n name: string;\n contests: Contest[];\n logout: () => Promise<void>;\n children: ReactNode;\n};\n\nexport function AdminLayout({ name, contests, logout, children }: Props) {\n const [, params] = useRoute(\"/:contestId/*?\");\n const contest = contests.find((c) => c.id === params?.contestId);\n\n return (\n <>\n <Navbar color=\"bg-error text-error-content\">\n <NavbarBrand>\n <div className=\"flex items-center h-full font-bold\">\n <Title />\n </div>\n </NavbarBrand>\n {contest && contests.length >= 2 && (\n <NavbarMenu>\n <NavbarSubmenu title={contest.name}>\n {contests.map((c) => {\n const path = params?.[\"*\"];\n const href = path ? `/${c.id}/${path}` : `/${c.id}`;\n return (\n <NavbarMenuItem key={c.id}>\n <Link className={clsx(contest.id === c.id && \"active\")} href={href}>\n {c.name}\n </Link>\n </NavbarMenuItem>\n );\n })}\n </NavbarSubmenu>\n <NavbarMenuItem>\n <Link href={`/${contest.id}`}>Gestione gara</Link>\n </NavbarMenuItem>\n <NavbarMenuItem>\n <Link href={`/${contest.id}/schools`}>Gestione scuole</Link>\n </NavbarMenuItem>\n </NavbarMenu>\n )}\n <NavbarContent>\n <UserDropdown name={name} logout={logout} />\n </NavbarContent>\n </Navbar>\n <div className=\"mx-auto flex w-full max-w-screen-xl grow flex-col p-4 pb-8\">\n <ErrorBoundary>\n <Suspense fallback={<Loading />}>{children}</Suspense>\n </ErrorBoundary>\n </div>\n </>\n );\n}\n\nfunction UserDropdown({ name, logout }: { name: string; logout: () => Promise<void> }) {\n return (\n <Dropdown className=\"dropdown-end\">\n <DropdownButton>\n <div className=\"truncate uppercase\">{name}</div>\n </DropdownButton>\n <DropdownMenu>\n <DropdownItem>\n <Button className=\"flex justify-between gap-4\" onClick={logout}>\n Esci <LogOut size={20} />\n </Button>\n </DropdownItem>\n </DropdownMenu>\n </Dropdown>\n );\n}\n"],"names":["AdminLayout","name","contests","logout","children","params","useRoute","contest","c","jsxs","Fragment","Navbar","jsx","NavbarBrand","Title","NavbarMenu","NavbarSubmenu","path","href","NavbarMenuItem","Link","clsx","NavbarContent","UserDropdown","ErrorBoundary","Suspense","Loading","Dropdown","DropdownButton","DropdownMenu","DropdownItem","Button","LogOut"],"mappings":";;;;;;;AA4BO,SAASA,EAAY,EAAE,MAAAC,GAAM,UAAAC,GAAU,QAAAC,GAAQ,UAAAC,KAAmB;AACvE,QAAM,GAAGC,CAAM,IAAIC,EAAS,gBAAgB,GACtCC,IAAUL,EAAS,KAAK,CAACM,MAAMA,EAAE,OAAOH,GAAQ,SAAS;AAE/D,SACE,gBAAAI,EAAAC,GAAA,EACE,UAAA;AAAA,IAAA,gBAAAD,EAACE,GAAA,EAAO,OAAM,+BACZ,UAAA;AAAA,MAAA,gBAAAC,EAACC,GAAA,EACC,4BAAC,OAAA,EAAI,WAAU,sCACb,UAAA,gBAAAD,EAACE,GAAA,CAAA,CAAM,GACT,EAAA,CACF;AAAA,MACCP,KAAWL,EAAS,UAAU,uBAC5Ba,GAAA,EACC,UAAA;AAAA,QAAA,gBAAAH,EAACI,KAAc,OAAOT,EAAQ,MAC3B,UAAAL,EAAS,IAAI,CAACM,MAAM;AACnB,gBAAMS,IAAOZ,IAAS,GAAG,GACnBa,IAAOD,IAAO,IAAIT,EAAE,EAAE,IAAIS,CAAI,KAAK,IAAIT,EAAE,EAAE;AACjD,mCACGW,GAAA,EACC,UAAA,gBAAAP,EAACQ,GAAA,EAAK,WAAWC,EAAKd,EAAQ,OAAOC,EAAE,MAAM,QAAQ,GAAG,MAAAU,GACrD,YAAE,MACL,EAAA,GAHmBV,EAAE,EAIvB;AAAA,QAEJ,CAAC,EAAA,CACH;AAAA,QACA,gBAAAI,EAACO,GAAA,EACC,UAAA,gBAAAP,EAACQ,GAAA,EAAK,MAAM,IAAIb,EAAQ,EAAE,IAAI,UAAA,gBAAA,CAAa,GAC7C;AAAA,QACA,gBAAAK,EAACO,GAAA,EACC,UAAA,gBAAAP,EAACQ,GAAA,EAAK,MAAM,IAAIb,EAAQ,EAAE,YAAY,UAAA,kBAAA,CAAe,EAAA,CACvD;AAAA,MAAA,GACF;AAAA,wBAEDe,GAAA,EACC,UAAA,gBAAAV,EAACW,GAAA,EAAa,MAAAtB,GAAY,QAAAE,GAAgB,EAAA,CAC5C;AAAA,IAAA,GACF;AAAA,IACA,gBAAAS,EAAC,OAAA,EAAI,WAAU,8DACb,4BAACY,GAAA,EACC,UAAA,gBAAAZ,EAACa,GAAA,EAAS,UAAU,gBAAAb,EAACc,GAAA,CAAA,CAAQ,GAAK,UAAAtB,GAAS,GAC7C,EAAA,CACF;AAAA,EAAA,GACF;AAEJ;AAEA,SAASmB,EAAa,EAAE,MAAAtB,GAAM,QAAAE,KAAyD;AACrF,SACE,gBAAAM,EAACkB,GAAA,EAAS,WAAU,gBAClB,UAAA;AAAA,IAAA,gBAAAf,EAACgB,KACC,UAAA,gBAAAhB,EAAC,OAAA,EAAI,WAAU,sBAAsB,aAAK,EAAA,CAC5C;AAAA,IACA,gBAAAA,EAACiB,KACC,UAAA,gBAAAjB,EAACkB,GAAA,EACC,4BAACC,GAAA,EAAO,WAAU,8BAA6B,SAAS5B,GAAQ,UAAA;AAAA,MAAA;AAAA,MACzD,gBAAAS,EAACoB,GAAA,EAAO,MAAM,GAAA,CAAI;AAAA,IAAA,EAAA,CACzB,GACF,EAAA,CACF;AAAA,EAAA,GACF;AAEJ;"}
@@ -1,30 +1,50 @@
1
- import { jsxs as o, jsx as r } from "react/jsx-runtime";
2
- import { lazy as c } from "react";
3
- import { Route as a, Redirect as d, Link as m, useParams as h, Switch as f } from "wouter";
4
- import { AdminContext as p } from "./context.js";
5
- import { AdminLayout as s } from "./layout.js";
6
- import { SchoolTable as u } from "./school-table.js";
7
- function P({ name: i, contests: e, setContest: l, logout: n }) {
8
- return /* @__PURE__ */ o(s, { name: i, contests: e, logout: n, children: [
9
- /* @__PURE__ */ o(a, { path: "/", children: [
10
- e.length === 1 && /* @__PURE__ */ r(d, { to: `/${e[0].id}` }),
11
- /* @__PURE__ */ o("div", { className: "flex w-full grow flex-col items-center justify-center gap-4", children: [
12
- /* @__PURE__ */ r("p", { className: "text-2xl", children: "Seleziona una gara" }),
13
- /* @__PURE__ */ r("div", { className: "flex flex-wrap justify-center gap-2", children: e.map((t) => /* @__PURE__ */ r(m, { className: "btn btn-primary", href: `/${t.id}`, children: t.name }, t.id)) })
1
+ import { jsxs as o, jsx as e } from "react/jsx-runtime";
2
+ import { lazy as s } from "react";
3
+ import { Route as c, Redirect as m, Link as f, useParams as h, Switch as p } from "wouter";
4
+ import { AdminContext as u } from "./context.js";
5
+ import { AdminLayout as x } from "./layout.js";
6
+ import { SchoolTable as g } from "./school-table.js";
7
+ function A({
8
+ name: i,
9
+ contests: r,
10
+ setContest: d,
11
+ logout: l,
12
+ ...n
13
+ }) {
14
+ return /* @__PURE__ */ o(x, { name: i, contests: r, logout: l, children: [
15
+ /* @__PURE__ */ o(c, { path: "/", children: [
16
+ r.length === 1 && /* @__PURE__ */ e(m, { to: `/${r[0].id}` }),
17
+ r.length === 0 ? /* @__PURE__ */ e("div", { className: "flex w-full grow flex-col items-center justify-center gap-4", children: /* @__PURE__ */ e("p", { className: "text-2xl", children: "Non sono state trovate gare" }) }) : /* @__PURE__ */ o("div", { className: "flex w-full grow flex-col items-center justify-center gap-4", children: [
18
+ /* @__PURE__ */ e("p", { className: "text-2xl", children: "Seleziona una gara" }),
19
+ /* @__PURE__ */ e("div", { className: "flex flex-wrap justify-center gap-2", children: r.map((a) => /* @__PURE__ */ e(f, { className: "btn btn-primary", href: `/${a.id}`, children: a.name }, a.id)) })
14
20
  ] })
15
21
  ] }),
16
- /* @__PURE__ */ r(a, { path: "/:contestId", nest: !0, children: /* @__PURE__ */ r(v, { name: i, contests: e, setContest: l, logout: n }) })
22
+ /* @__PURE__ */ e(c, { path: "/:contestId", nest: !0, children: /* @__PURE__ */ e(
23
+ N,
24
+ {
25
+ name: i,
26
+ contests: r,
27
+ setContest: d,
28
+ logout: l,
29
+ ...n
30
+ }
31
+ ) })
17
32
  ] });
18
33
  }
19
- const x = c(() => import("./dashboard.js"));
20
- function v({ contests: i, ...e }) {
34
+ const v = s(() => import("./dashboard.js"));
35
+ function N({ contests: i, variants: r, ...d }) {
21
36
  const { contestId: l } = h(), n = i.find((t) => t.id === l);
22
- return n ? /* @__PURE__ */ r(p.Provider, { value: { ...e, contest: n, contests: i }, children: /* @__PURE__ */ o(f, { children: [
23
- /* @__PURE__ */ r(a, { path: "/", children: /* @__PURE__ */ r(x, {}) }),
24
- /* @__PURE__ */ r(a, { path: "/schools", children: /* @__PURE__ */ r(u, {}) })
25
- ] }) }) : /* @__PURE__ */ r(d, { to: "/" });
37
+ if (!n)
38
+ return /* @__PURE__ */ e(m, { to: "/" });
39
+ const a = Object.fromEntries(
40
+ r.filter((t) => t.contestId === n?.id).map((t) => [t.id, t])
41
+ );
42
+ return /* @__PURE__ */ e(u.Provider, { value: { ...d, variants: a, contest: n, contests: i }, children: /* @__PURE__ */ o(p, { children: [
43
+ /* @__PURE__ */ e(c, { path: "/", children: /* @__PURE__ */ e(v, {}) }),
44
+ /* @__PURE__ */ e(c, { path: "/schools", children: /* @__PURE__ */ e(g, {}) })
45
+ ] }) });
26
46
  }
27
47
  export {
28
- P as AdminProvider
48
+ A as AdminProvider
29
49
  };
30
50
  //# sourceMappingURL=provider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"provider.js","sources":["../../../../src/web/admin/provider.tsx"],"sourcesContent":["import { lazy } from \"react\";\n\nimport type { Contest } from \"@olinfo/quizms/models\";\nimport { Link, Redirect, Route, Switch, useParams } from \"wouter\";\n\nimport { AdminContext } from \"./context\";\nimport { AdminLayout } from \"./layout\";\nimport { SchoolTable } from \"./school-table\";\n\ntype AdminProviderProps = {\n name: string;\n contests: Contest[];\n setContest: (contest: Contest) => Promise<void>;\n logout: () => Promise<void>;\n};\n\nexport function AdminProvider({ name, contests, setContest, logout }: AdminProviderProps) {\n return (\n <AdminLayout name={name} contests={contests} logout={logout}>\n <Route path=\"/\">\n {contests.length === 1 && <Redirect to={`/${contests[0].id}`} />}\n <div className=\"flex w-full grow flex-col items-center justify-center gap-4\">\n <p className=\"text-2xl\">Seleziona una gara</p>\n <div className=\"flex flex-wrap justify-center gap-2\">\n {contests.map((c) => (\n <Link key={c.id} className=\"btn btn-primary\" href={`/${c.id}`}>\n {c.name}\n </Link>\n ))}\n </div>\n </div>\n </Route>\n <Route path=\"/:contestId\" nest>\n <ProviderInner name={name} contests={contests} setContest={setContest} logout={logout} />\n </Route>\n </AdminLayout>\n );\n}\n\nconst Dashboard = lazy(() => import(\"./dashboard\"));\n\nfunction ProviderInner({ contests, ...props }: AdminProviderProps) {\n const { contestId } = useParams();\n\n const contest = contests.find((c) => c.id === contestId);\n if (!contest) {\n return <Redirect to=\"/\" />;\n }\n\n return (\n <AdminContext.Provider value={{ ...props, contest, contests }}>\n <Switch>\n <Route path=\"/\">\n <Dashboard />\n </Route>\n <Route path=\"/schools\">\n <SchoolTable />\n </Route>\n </Switch>\n </AdminContext.Provider>\n );\n}\n"],"names":["AdminProvider","name","contests","setContest","logout","jsxs","AdminLayout","Route","jsx","Redirect","c","Link","ProviderInner","Dashboard","lazy","props","contestId","useParams","contest","AdminContext","Switch","SchoolTable"],"mappings":";;;;;;AAgBO,SAASA,EAAc,EAAE,MAAAC,GAAM,UAAAC,GAAU,YAAAC,GAAY,QAAAC,KAA8B;AACxF,SACE,gBAAAC,EAACC,GAAA,EAAY,MAAAL,GAAY,UAAAC,GAAoB,QAAAE,GAC3C,UAAA;AAAA,IAAA,gBAAAC,EAACE,GAAA,EAAM,MAAK,KACT,UAAA;AAAA,MAAAL,EAAS,WAAW,KAAK,gBAAAM,EAACC,GAAA,EAAS,IAAI,IAAIP,EAAS,CAAC,EAAE,EAAE,GAAA,CAAI;AAAA,MAC9D,gBAAAG,EAAC,OAAA,EAAI,WAAU,+DACb,UAAA;AAAA,QAAA,gBAAAG,EAAC,KAAA,EAAE,WAAU,YAAW,UAAA,sBAAkB;AAAA,QAC1C,gBAAAA,EAAC,SAAI,WAAU,uCACZ,YAAS,IAAI,CAACE,MACb,gBAAAF,EAACG,GAAA,EAAgB,WAAU,mBAAkB,MAAM,IAAID,EAAE,EAAE,IACxD,YAAE,KAAA,GADMA,EAAE,EAEb,CACD,EAAA,CACH;AAAA,MAAA,EAAA,CACF;AAAA,IAAA,GACF;AAAA,IACA,gBAAAF,EAACD,GAAA,EAAM,MAAK,eAAc,MAAI,IAC5B,UAAA,gBAAAC,EAACI,GAAA,EAAc,MAAAX,GAAY,UAAAC,GAAoB,YAAAC,GAAwB,QAAAC,EAAA,CAAgB,EAAA,CACzF;AAAA,EAAA,GACF;AAEJ;AAEA,MAAMS,IAAYC,EAAK,MAAM,OAAO,gBAAa,CAAC;AAElD,SAASF,EAAc,EAAE,UAAAV,GAAU,GAAGa,KAA6B;AACjE,QAAM,EAAE,WAAAC,EAAA,IAAcC,EAAA,GAEhBC,IAAUhB,EAAS,KAAK,CAACQ,MAAMA,EAAE,OAAOM,CAAS;AACvD,SAAKE,IAKH,gBAAAV,EAACW,EAAa,UAAb,EAAsB,OAAO,EAAE,GAAGJ,GAAO,SAAAG,GAAS,UAAAhB,EAAA,GACjD,UAAA,gBAAAG,EAACe,GAAA,EACC,UAAA;AAAA,IAAA,gBAAAZ,EAACD,GAAA,EAAM,MAAK,KACV,UAAA,gBAAAC,EAACK,KAAU,GACb;AAAA,sBACCN,GAAA,EAAM,MAAK,YACV,UAAA,gBAAAC,EAACa,KAAY,EAAA,CACf;AAAA,EAAA,EAAA,CACF,EAAA,CACF,IAbO,gBAAAb,EAACC,GAAA,EAAS,IAAG,IAAA,CAAI;AAe5B;"}
1
+ {"version":3,"file":"provider.js","sources":["../../../../src/web/admin/provider.tsx"],"sourcesContent":["import { lazy } from \"react\";\n\nimport type { Contest, Variant } from \"@olinfo/quizms/models\";\nimport { Link, Redirect, Route, Switch, useParams } from \"wouter\";\n\nimport { AdminContext } from \"./context\";\nimport { AdminLayout } from \"./layout\";\nimport { SchoolTable } from \"./school-table\";\n\ntype AdminProviderProps = {\n name: string;\n contests: Contest[];\n variants: Variant[];\n setContest: (contest: Contest) => Promise<void>;\n logout: () => Promise<void>;\n};\n\nexport function AdminProvider({\n name,\n contests,\n setContest,\n logout,\n ...props\n}: AdminProviderProps) {\n return (\n <AdminLayout name={name} contests={contests} logout={logout}>\n <Route path=\"/\">\n {contests.length === 1 && <Redirect to={`/${contests[0].id}`} />}\n {contests.length === 0 ? (\n <div className=\"flex w-full grow flex-col items-center justify-center gap-4\">\n <p className=\"text-2xl\">Non sono state trovate gare</p>\n </div>\n ) : (\n <div className=\"flex w-full grow flex-col items-center justify-center gap-4\">\n <p className=\"text-2xl\">Seleziona una gara</p>\n <div className=\"flex flex-wrap justify-center gap-2\">\n {contests.map((c) => (\n <Link key={c.id} className=\"btn btn-primary\" href={`/${c.id}`}>\n {c.name}\n </Link>\n ))}\n </div>\n </div>\n )}\n </Route>\n <Route path=\"/:contestId\" nest>\n <ProviderInner\n name={name}\n contests={contests}\n setContest={setContest}\n logout={logout}\n {...props}\n />\n </Route>\n </AdminLayout>\n );\n}\n\nconst Dashboard = lazy(() => import(\"./dashboard\"));\n\nfunction ProviderInner({ contests, variants, ...props }: AdminProviderProps) {\n const { contestId } = useParams();\n\n const contest = contests.find((c) => c.id === contestId);\n if (!contest) {\n return <Redirect to=\"/\" />;\n }\n\n const contestVariants = Object.fromEntries(\n variants.filter((v) => v.contestId === contest?.id).map((v) => [v.id, v]),\n );\n\n return (\n <AdminContext.Provider value={{ ...props, variants: contestVariants, contest, contests }}>\n <Switch>\n <Route path=\"/\">\n <Dashboard />\n </Route>\n <Route path=\"/schools\">\n <SchoolTable />\n </Route>\n </Switch>\n </AdminContext.Provider>\n );\n}\n"],"names":["AdminProvider","name","contests","setContest","logout","props","jsxs","AdminLayout","Route","jsx","Redirect","c","Link","ProviderInner","Dashboard","lazy","variants","contestId","useParams","contest","contestVariants","v","AdminContext","Switch","SchoolTable"],"mappings":";;;;;;AAiBO,SAASA,EAAc;AAAA,EAC5B,MAAAC;AAAA,EACA,UAAAC;AAAA,EACA,YAAAC;AAAA,EACA,QAAAC;AAAA,EACA,GAAGC;AACL,GAAuB;AACrB,SACE,gBAAAC,EAACC,GAAA,EAAY,MAAAN,GAAY,UAAAC,GAAoB,QAAAE,GAC3C,UAAA;AAAA,IAAA,gBAAAE,EAACE,GAAA,EAAM,MAAK,KACT,UAAA;AAAA,MAAAN,EAAS,WAAW,KAAK,gBAAAO,EAACC,GAAA,EAAS,IAAI,IAAIR,EAAS,CAAC,EAAE,EAAE,GAAA,CAAI;AAAA,MAC7DA,EAAS,WAAW,IACnB,gBAAAO,EAAC,OAAA,EAAI,WAAU,+DACb,UAAA,gBAAAA,EAAC,KAAA,EAAE,WAAU,YAAW,UAAA,8BAAA,CAA2B,GACrD,IAEA,gBAAAH,EAAC,OAAA,EAAI,WAAU,+DACb,UAAA;AAAA,QAAA,gBAAAG,EAAC,KAAA,EAAE,WAAU,YAAW,UAAA,sBAAkB;AAAA,QAC1C,gBAAAA,EAAC,SAAI,WAAU,uCACZ,YAAS,IAAI,CAACE,MACb,gBAAAF,EAACG,GAAA,EAAgB,WAAU,mBAAkB,MAAM,IAAID,EAAE,EAAE,IACxD,YAAE,KAAA,GADMA,EAAE,EAEb,CACD,EAAA,CACH;AAAA,MAAA,EAAA,CACF;AAAA,IAAA,GAEJ;AAAA,IACA,gBAAAF,EAACD,GAAA,EAAM,MAAK,eAAc,MAAI,IAC5B,UAAA,gBAAAC;AAAA,MAACI;AAAA,MAAA;AAAA,QACC,MAAAZ;AAAA,QACA,UAAAC;AAAA,QACA,YAAAC;AAAA,QACA,QAAAC;AAAA,QACC,GAAGC;AAAA,MAAA;AAAA,IAAA,EACN,CACF;AAAA,EAAA,GACF;AAEJ;AAEA,MAAMS,IAAYC,EAAK,MAAM,OAAO,gBAAa,CAAC;AAElD,SAASF,EAAc,EAAE,UAAAX,GAAU,UAAAc,GAAU,GAAGX,KAA6B;AAC3E,QAAM,EAAE,WAAAY,EAAA,IAAcC,EAAA,GAEhBC,IAAUjB,EAAS,KAAK,CAACS,MAAMA,EAAE,OAAOM,CAAS;AACvD,MAAI,CAACE;AACH,WAAO,gBAAAV,EAACC,GAAA,EAAS,IAAG,IAAA,CAAI;AAG1B,QAAMU,IAAkB,OAAO;AAAA,IAC7BJ,EAAS,OAAO,CAACK,MAAMA,EAAE,cAAcF,GAAS,EAAE,EAAE,IAAI,CAACE,MAAM,CAACA,EAAE,IAAIA,CAAC,CAAC;AAAA,EAAA;AAG1E,SACE,gBAAAZ,EAACa,EAAa,UAAb,EAAsB,OAAO,EAAE,GAAGjB,GAAO,UAAUe,GAAiB,SAAAD,GAAS,UAAAjB,KAC5E,4BAACqB,GAAA,EACC,UAAA;AAAA,IAAA,gBAAAd,EAACD,GAAA,EAAM,MAAK,KACV,UAAA,gBAAAC,EAACK,KAAU,GACb;AAAA,sBACCN,GAAA,EAAM,MAAK,YACV,UAAA,gBAAAC,EAACe,KAAY,EAAA,CACf;AAAA,EAAA,EAAA,CACF,EAAA,CACF;AAEJ;"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as e } from "react/jsx-runtime";
2
2
  import { useMemo as s, Suspense as o } from "react";
3
- import { AgGrid as d, Loading as c } from "@olinfo/quizms/components";
4
- import { participationConverter as f } from "../common/converters.js";
3
+ import { AgGrid as d, Loading as u } from "@olinfo/quizms/components";
4
+ import { venueConverter as f } from "../common/converters.js";
5
5
  import "firebase/auth";
6
6
  import "lodash-es";
7
7
  import "react-error-boundary";
@@ -9,25 +9,21 @@ import "swr";
9
9
  import "../common/base-login.js";
10
10
  import { useCollection as m } from "../hooks/collection.js";
11
11
  import "firebase/firestore";
12
- import { useCount as p } from "../hooks/count.js";
13
- import { useAdmin as u } from "./context.js";
14
- function T() {
15
- const { contest: i } = u(), [r, n] = m(
16
- "participations",
17
- f,
18
- {
19
- constraints: { contestId: i.id }
20
- }
21
- ), a = s(() => h(), []);
22
- return /* @__PURE__ */ e(o, { fallback: /* @__PURE__ */ e(c, {}), children: /* @__PURE__ */ e("div", { className: "relative grow p-2", children: /* @__PURE__ */ e("div", { className: "absolute inset-0", children: /* @__PURE__ */ e(
12
+ import { useCount as c } from "../hooks/count.js";
13
+ import { useAdmin as p } from "./context.js";
14
+ function E() {
15
+ const { contest: t } = p(), [r, n] = m("venues", f, {
16
+ constraints: { contestId: t.id }
17
+ }), l = s(() => h(), []);
18
+ return /* @__PURE__ */ e(o, { fallback: /* @__PURE__ */ e(u, {}), children: /* @__PURE__ */ e("div", { className: "relative grow p-2", children: /* @__PURE__ */ e("div", { className: "absolute inset-0", children: /* @__PURE__ */ e(
23
19
  d,
24
20
  {
25
21
  rowData: r,
26
- getRowId: (t) => t.data.id,
27
- columnDefs: a,
28
- onCellEditRequest: async (t) => {
29
- const l = t.data;
30
- t.colDef.field === "finalized" && await n({ ...l, finalized: t.newValue }), t.api.refreshCells({ force: !0 });
22
+ getRowId: (i) => i.data.id,
23
+ columnDefs: l,
24
+ onCellEditRequest: async (i) => {
25
+ const a = i.data;
26
+ i.colDef.field === "finalized" && await n({ ...a, finalized: i.newValue }), i.api.refreshCells({ force: !0 });
31
27
  }
32
28
  }
33
29
  ) }) }) });
@@ -52,9 +48,9 @@ function h() {
52
48
  headerName: "Studenti",
53
49
  width: 100,
54
50
  sortable: !1,
55
- cellRenderer: ({ data: i }) => {
56
- if (i)
57
- return /* @__PURE__ */ e(o, { children: /* @__PURE__ */ e(w, { participationId: i.id }) });
51
+ cellRenderer: ({ data: t }) => {
52
+ if (t)
53
+ return /* @__PURE__ */ e(o, { children: /* @__PURE__ */ e(w, { venueId: t.id }) });
58
54
  }
59
55
  },
60
56
  {
@@ -67,12 +63,12 @@ function h() {
67
63
  }
68
64
  ];
69
65
  }
70
- function w({ participationId: i }) {
71
- return p(`participations/${i}/students`, {
66
+ function w({ venueId: t }) {
67
+ return c(`venues/${t}/students`, {
72
68
  constraints: { disabled: !1 }
73
69
  });
74
70
  }
75
71
  export {
76
- T as SchoolTable
72
+ E as SchoolTable
77
73
  };
78
74
  //# sourceMappingURL=school-table.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"school-table.js","sources":["../../../../src/web/admin/school-table.tsx"],"sourcesContent":["import { Suspense, useMemo } from \"react\";\n\nimport { AgGrid, Loading } from \"@olinfo/quizms/components\";\nimport type { Participation, Student } from \"@olinfo/quizms/models\";\nimport type { CellEditRequestEvent, ColDef, ICellRendererParams } from \"ag-grid-community\";\n\nimport { participationConverter } from \"~/web/common/converters\";\nimport { useCollection } from \"~/web/hooks\";\nimport { useCount } from \"~/web/hooks/count\";\n\nimport { useAdmin } from \"./context\";\n\nexport function SchoolTable() {\n const { contest } = useAdmin();\n\n const [participations, setParticipation] = useCollection(\n \"participations\",\n participationConverter,\n {\n constraints: { contestId: contest.id },\n },\n );\n\n const colDefs = useMemo(() => columnDefinition(), []);\n\n const onCellEditRequest = async (ev: CellEditRequestEvent) => {\n const participation = ev.data as Participation;\n if (ev.colDef.field === \"finalized\") {\n await setParticipation({ ...participation, finalized: ev.newValue });\n }\n ev.api.refreshCells({ force: true });\n };\n\n return (\n <Suspense fallback={<Loading />}>\n <div className=\"relative grow p-2\">\n <div className=\"absolute inset-0\">\n <AgGrid\n rowData={participations}\n getRowId={(row) => (row.data as Participation).id}\n columnDefs={colDefs}\n onCellEditRequest={onCellEditRequest}\n />\n </div>\n </div>\n </Suspense>\n );\n}\n\nfunction columnDefinition(): ColDef[] {\n return [\n {\n field: \"schoolId\",\n headerName: \"ID\",\n width: 150,\n filter: true,\n },\n {\n field: \"name\",\n headerName: \"Nome\",\n minWidth: 200,\n flex: 1,\n filter: true,\n },\n {\n field: \"count\",\n headerName: \"Studenti\",\n width: 100,\n sortable: false,\n cellRenderer: ({ data }: ICellRendererParams<Participation>) => {\n if (!data) return;\n return (\n <Suspense>\n <Count participationId={data.id} />\n </Suspense>\n );\n },\n },\n {\n field: \"finalized\",\n headerName: \"Finalizzato\",\n width: 100,\n filter: true,\n cellDataType: \"boolean\",\n editable: true,\n },\n ];\n}\n\nfunction Count({ participationId }: { participationId: string }) {\n return useCount<Student>(`participations/${participationId}/students`, {\n constraints: { disabled: false },\n });\n}\n"],"names":["SchoolTable","contest","useAdmin","participations","setParticipation","useCollection","participationConverter","colDefs","useMemo","columnDefinition","jsx","Suspense","Loading","AgGrid","row","ev","participation","data","Count","participationId","useCount"],"mappings":";;;;;;;;;;;;;AAYO,SAASA,IAAc;AAC5B,QAAM,EAAE,SAAAC,EAAA,IAAYC,EAAA,GAEd,CAACC,GAAgBC,CAAgB,IAAIC;AAAA,IACzC;AAAA,IACAC;AAAA,IACA;AAAA,MACE,aAAa,EAAE,WAAWL,EAAQ,GAAA;AAAA,IAAG;AAAA,EACvC,GAGIM,IAAUC,EAAQ,MAAMC,EAAA,GAAoB,CAAA,CAAE;AAUpD,SACE,gBAAAC,EAACC,GAAA,EAAS,UAAU,gBAAAD,EAACE,GAAA,CAAA,CAAQ,GAC3B,UAAA,gBAAAF,EAAC,OAAA,EAAI,WAAU,qBACb,UAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,oBACb,UAAA,gBAAAA;AAAA,IAACG;AAAA,IAAA;AAAA,MACC,SAASV;AAAA,MACT,UAAU,CAACW,MAASA,EAAI,KAAuB;AAAA,MAC/C,YAAYP;AAAA,MACZ,mBAhBgB,OAAOQ,MAA6B;AAC5D,cAAMC,IAAgBD,EAAG;AACzB,QAAIA,EAAG,OAAO,UAAU,eACtB,MAAMX,EAAiB,EAAE,GAAGY,GAAe,WAAWD,EAAG,UAAU,GAErEA,EAAG,IAAI,aAAa,EAAE,OAAO,IAAM;AAAA,MACrC;AAAA,IAUU;AAAA,EAAA,EACF,CACF,GACF,GACF;AAEJ;AAEA,SAASN,IAA6B;AACpC,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,QAAQ;AAAA,IAAA;AAAA,IAEV;AAAA,MACE,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,MAAM;AAAA,MACN,QAAQ;AAAA,IAAA;AAAA,IAEV;AAAA,MACE,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc,CAAC,EAAE,MAAAQ,QAA+C;AAC9D,YAAKA;AACL,mCACGN,GAAA,EACC,UAAA,gBAAAD,EAACQ,KAAM,iBAAiBD,EAAK,IAAI,EAAA,CACnC;AAAA,MAEJ;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,UAAU;AAAA,IAAA;AAAA,EACZ;AAEJ;AAEA,SAASC,EAAM,EAAE,iBAAAC,KAAgD;AAC/D,SAAOC,EAAkB,kBAAkBD,CAAe,aAAa;AAAA,IACrE,aAAa,EAAE,UAAU,GAAA;AAAA,EAAM,CAChC;AACH;"}
1
+ {"version":3,"file":"school-table.js","sources":["../../../../src/web/admin/school-table.tsx"],"sourcesContent":["import { Suspense, useMemo } from \"react\";\n\nimport { AgGrid, Loading } from \"@olinfo/quizms/components\";\nimport type { Student, Venue } from \"@olinfo/quizms/models\";\nimport type { CellEditRequestEvent, ColDef, ICellRendererParams } from \"ag-grid-community\";\n\nimport { venueConverter } from \"~/web/common/converters\";\nimport { useCollection } from \"~/web/hooks\";\nimport { useCount } from \"~/web/hooks/count\";\n\nimport { useAdmin } from \"./context\";\n\nexport function SchoolTable() {\n const { contest } = useAdmin();\n\n const [venues, setVenue] = useCollection(\"venues\", venueConverter, {\n constraints: { contestId: contest.id },\n });\n\n const colDefs = useMemo(() => columnDefinition(), []);\n\n const onCellEditRequest = async (ev: CellEditRequestEvent) => {\n const venue = ev.data as Venue;\n if (ev.colDef.field === \"finalized\") {\n await setVenue({ ...venue, finalized: ev.newValue });\n }\n ev.api.refreshCells({ force: true });\n };\n\n return (\n <Suspense fallback={<Loading />}>\n <div className=\"relative grow p-2\">\n <div className=\"absolute inset-0\">\n <AgGrid\n rowData={venues}\n getRowId={(row) => (row.data as Venue).id}\n columnDefs={colDefs}\n onCellEditRequest={onCellEditRequest}\n />\n </div>\n </div>\n </Suspense>\n );\n}\n\nfunction columnDefinition(): ColDef[] {\n return [\n {\n field: \"schoolId\",\n headerName: \"ID\",\n width: 150,\n filter: true,\n },\n {\n field: \"name\",\n headerName: \"Nome\",\n minWidth: 200,\n flex: 1,\n filter: true,\n },\n {\n field: \"count\",\n headerName: \"Studenti\",\n width: 100,\n sortable: false,\n cellRenderer: ({ data }: ICellRendererParams<Venue>) => {\n if (!data) return;\n return (\n <Suspense>\n <Count venueId={data.id} />\n </Suspense>\n );\n },\n },\n {\n field: \"finalized\",\n headerName: \"Finalizzato\",\n width: 100,\n filter: true,\n cellDataType: \"boolean\",\n editable: true,\n },\n ];\n}\n\nfunction Count({ venueId }: { venueId: string }) {\n return useCount<Student>(`venues/${venueId}/students`, {\n constraints: { disabled: false },\n });\n}\n"],"names":["SchoolTable","contest","useAdmin","venues","setVenue","useCollection","venueConverter","colDefs","useMemo","columnDefinition","jsx","Suspense","Loading","AgGrid","row","ev","venue","data","Count","venueId","useCount"],"mappings":";;;;;;;;;;;;;AAYO,SAASA,IAAc;AAC5B,QAAM,EAAE,SAAAC,EAAA,IAAYC,EAAA,GAEd,CAACC,GAAQC,CAAQ,IAAIC,EAAc,UAAUC,GAAgB;AAAA,IACjE,aAAa,EAAE,WAAWL,EAAQ,GAAA;AAAA,EAAG,CACtC,GAEKM,IAAUC,EAAQ,MAAMC,EAAA,GAAoB,CAAA,CAAE;AAUpD,SACE,gBAAAC,EAACC,GAAA,EAAS,UAAU,gBAAAD,EAACE,GAAA,CAAA,CAAQ,GAC3B,UAAA,gBAAAF,EAAC,OAAA,EAAI,WAAU,qBACb,UAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,oBACb,UAAA,gBAAAA;AAAA,IAACG;AAAA,IAAA;AAAA,MACC,SAASV;AAAA,MACT,UAAU,CAACW,MAASA,EAAI,KAAe;AAAA,MACvC,YAAYP;AAAA,MACZ,mBAhBgB,OAAOQ,MAA6B;AAC5D,cAAMC,IAAQD,EAAG;AACjB,QAAIA,EAAG,OAAO,UAAU,eACtB,MAAMX,EAAS,EAAE,GAAGY,GAAO,WAAWD,EAAG,UAAU,GAErDA,EAAG,IAAI,aAAa,EAAE,OAAO,IAAM;AAAA,MACrC;AAAA,IAUU;AAAA,EAAA,EACF,CACF,GACF,GACF;AAEJ;AAEA,SAASN,IAA6B;AACpC,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,QAAQ;AAAA,IAAA;AAAA,IAEV;AAAA,MACE,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,MAAM;AAAA,MACN,QAAQ;AAAA,IAAA;AAAA,IAEV;AAAA,MACE,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc,CAAC,EAAE,MAAAQ,QAAuC;AACtD,YAAKA;AACL,mCACGN,GAAA,EACC,UAAA,gBAAAD,EAACQ,KAAM,SAASD,EAAK,IAAI,EAAA,CAC3B;AAAA,MAEJ;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,UAAU;AAAA,IAAA;AAAA,EACZ;AAEJ;AAEA,SAASC,EAAM,EAAE,SAAAC,KAAgC;AAC/C,SAAOC,EAAkB,UAAUD,CAAO,aAAa;AAAA,IACrD,aAAa,EAAE,UAAU,GAAA;AAAA,EAAM,CAChC;AACH;"}
@@ -1,40 +1,44 @@
1
- import { createTRPCClient as a, httpLink as e } from "@trpc/client";
2
- import { getIdToken as r } from "firebase/auth";
3
- import o from "superjson";
4
- const i = a({
1
+ import { createTRPCClient as o, httpLink as r } from "@trpc/client";
2
+ import { getIdToken as i } from "firebase/auth";
3
+ import a from "superjson";
4
+ const e = o({
5
5
  links: [
6
- e({
6
+ r({
7
7
  url: "/api",
8
- transformer: o,
8
+ transformer: a,
9
9
  async headers({ op: t }) {
10
10
  const n = t.context?.user;
11
11
  return n ? {
12
- Authorization: `Bearer ${await r(n)}`
12
+ Authorization: `Bearer ${await i(n)}`
13
13
  } : {};
14
14
  }
15
15
  })
16
16
  ]
17
17
  });
18
- function m(t) {
19
- return i.teacherLogin.mutate(t);
20
- }
21
18
  function f(t) {
22
- return i.studentLogin.mutate(t);
19
+ return e.teacherLogin.mutate(t);
20
+ }
21
+ function d(t) {
22
+ return e.adminLogin.mutate(t);
23
+ }
24
+ function p(t) {
25
+ return e.studentLogin.mutate(t);
23
26
  }
24
27
  async function h(t, n) {
25
- await i.teacherStartParticipation.mutate({ participationId: n }, { context: { user: t } });
28
+ await e.teacherStartContestWindow.mutate({ venueId: n }, { context: { user: t } });
26
29
  }
27
- async function P(t, n) {
28
- await i.teacherStopParticipation.mutate({ participationId: n }, { context: { user: t } });
30
+ async function w(t, n) {
31
+ await e.teacherStopContestWindow.mutate({ venueId: n }, { context: { user: t } });
29
32
  }
30
33
  async function g(t, n) {
31
- await i.teacherFinalizeParticipation.mutate({ participationId: n }, { context: { user: t } });
34
+ await e.teacherFinalizeVenue.mutate({ venueId: n }, { context: { user: t } });
32
35
  }
33
36
  export {
34
- g as finalizeParticipation,
35
- h as startParticipation,
36
- P as stopParticipation,
37
- f as studentLogin,
38
- m as teacherLogin
37
+ d as adminLogin,
38
+ g as finalizeVenue,
39
+ h as startContestWindow,
40
+ w as stopContestWindow,
41
+ p as studentLogin,
42
+ f as teacherLogin
39
43
  };
40
44
  //# sourceMappingURL=api.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sources":["../../../../src/web/common/api.ts"],"sourcesContent":["import type { Student } from \"@olinfo/quizms/models\";\nimport { createTRPCClient, httpLink } from \"@trpc/client\";\nimport { getIdToken, type User } from \"firebase/auth\";\nimport superjson from \"superjson\";\n\nimport type { AppRouter } from \"~/functions/api\";\n\nconst trpc = createTRPCClient<AppRouter>({\n links: [\n httpLink({\n url: \"/api\",\n transformer: superjson,\n async headers({ op }) {\n const user = op.context?.user as User | undefined;\n if (user) {\n const token = await getIdToken(user);\n return {\n Authorization: `Bearer ${token}`,\n };\n }\n return {};\n },\n }),\n ],\n});\n\nexport function teacherLogin(body: { username: string; password: string }) {\n return trpc.teacherLogin.mutate(body);\n}\n\nexport function studentLogin(body: {\n contestId: string;\n token: string;\n userData: Required<NonNullable<Student[\"userData\"]>>;\n extraData: Record<string, any>;\n}) {\n return trpc.studentLogin.mutate(body);\n}\n\nexport async function startParticipation(user: User, participationId: string) {\n await trpc.teacherStartParticipation.mutate({ participationId }, { context: { user } });\n}\n\nexport async function stopParticipation(user: User, participationId: string) {\n await trpc.teacherStopParticipation.mutate({ participationId }, { context: { user } });\n}\n\nexport async function finalizeParticipation(user: User, participationId: string) {\n await trpc.teacherFinalizeParticipation.mutate({ participationId }, { context: { user } });\n}\n"],"names":["trpc","createTRPCClient","httpLink","superjson","op","user","getIdToken","teacherLogin","body","studentLogin","startParticipation","participationId","stopParticipation","finalizeParticipation"],"mappings":";;;AAOA,MAAMA,IAAOC,EAA4B;AAAA,EACvC,OAAO;AAAA,IACLC,EAAS;AAAA,MACP,KAAK;AAAA,MACL,aAAaC;AAAA,MACb,MAAM,QAAQ,EAAE,IAAAC,KAAM;AACpB,cAAMC,IAAOD,EAAG,SAAS;AACzB,eAAIC,IAEK;AAAA,UACL,eAAe,UAFH,MAAMC,EAAWD,CAAI,CAEH;AAAA,QAAA,IAG3B,CAAA;AAAA,MACT;AAAA,IAAA,CACD;AAAA,EAAA;AAEL,CAAC;AAEM,SAASE,EAAaC,GAA8C;AACzE,SAAOR,EAAK,aAAa,OAAOQ,CAAI;AACtC;AAEO,SAASC,EAAaD,GAK1B;AACD,SAAOR,EAAK,aAAa,OAAOQ,CAAI;AACtC;AAEA,eAAsBE,EAAmBL,GAAYM,GAAyB;AAC5E,QAAMX,EAAK,0BAA0B,OAAO,EAAE,iBAAAW,EAAA,GAAmB,EAAE,SAAS,EAAE,MAAAN,EAAA,GAAQ;AACxF;AAEA,eAAsBO,EAAkBP,GAAYM,GAAyB;AAC3E,QAAMX,EAAK,yBAAyB,OAAO,EAAE,iBAAAW,EAAA,GAAmB,EAAE,SAAS,EAAE,MAAAN,EAAA,GAAQ;AACvF;AAEA,eAAsBQ,EAAsBR,GAAYM,GAAyB;AAC/E,QAAMX,EAAK,6BAA6B,OAAO,EAAE,iBAAAW,EAAA,GAAmB,EAAE,SAAS,EAAE,MAAAN,EAAA,GAAQ;AAC3F;"}
1
+ {"version":3,"file":"api.js","sources":["../../../../src/web/common/api.ts"],"sourcesContent":["import type { Student } from \"@olinfo/quizms/models\";\nimport { createTRPCClient, httpLink } from \"@trpc/client\";\nimport { getIdToken, type User } from \"firebase/auth\";\nimport superjson from \"superjson\";\n\nimport type { AppRouter } from \"~/functions/api\";\n\nconst trpc = createTRPCClient<AppRouter>({\n links: [\n httpLink({\n url: \"/api\",\n transformer: superjson,\n async headers({ op }) {\n const user = op.context?.user as User | undefined;\n if (user) {\n const token = await getIdToken(user);\n return {\n Authorization: `Bearer ${token}`,\n };\n }\n return {};\n },\n }),\n ],\n});\n\nexport function teacherLogin(body: { username: string; password: string }) {\n return trpc.teacherLogin.mutate(body);\n}\n\nexport function adminLogin(body: { username: string; password: string }) {\n return trpc.adminLogin.mutate(body);\n}\n\nexport function studentLogin(body: {\n contestId: string;\n token: string;\n userData: Required<NonNullable<Student[\"userData\"]>>;\n extraData: Record<string, any>;\n}) {\n return trpc.studentLogin.mutate(body);\n}\n\nexport async function startContestWindow(user: User, venueId: string) {\n await trpc.teacherStartContestWindow.mutate({ venueId }, { context: { user } });\n}\n\nexport async function stopContestWindow(user: User, venueId: string) {\n await trpc.teacherStopContestWindow.mutate({ venueId }, { context: { user } });\n}\n\nexport async function finalizeVenue(user: User, venueId: string) {\n await trpc.teacherFinalizeVenue.mutate({ venueId }, { context: { user } });\n}\n"],"names":["trpc","createTRPCClient","httpLink","superjson","op","user","getIdToken","teacherLogin","body","adminLogin","studentLogin","startContestWindow","venueId","stopContestWindow","finalizeVenue"],"mappings":";;;AAOA,MAAMA,IAAOC,EAA4B;AAAA,EACvC,OAAO;AAAA,IACLC,EAAS;AAAA,MACP,KAAK;AAAA,MACL,aAAaC;AAAA,MACb,MAAM,QAAQ,EAAE,IAAAC,KAAM;AACpB,cAAMC,IAAOD,EAAG,SAAS;AACzB,eAAIC,IAEK;AAAA,UACL,eAAe,UAFH,MAAMC,EAAWD,CAAI,CAEH;AAAA,QAAA,IAG3B,CAAA;AAAA,MACT;AAAA,IAAA,CACD;AAAA,EAAA;AAEL,CAAC;AAEM,SAASE,EAAaC,GAA8C;AACzE,SAAOR,EAAK,aAAa,OAAOQ,CAAI;AACtC;AAEO,SAASC,EAAWD,GAA8C;AACvE,SAAOR,EAAK,WAAW,OAAOQ,CAAI;AACpC;AAEO,SAASE,EAAaF,GAK1B;AACD,SAAOR,EAAK,aAAa,OAAOQ,CAAI;AACtC;AAEA,eAAsBG,EAAmBN,GAAYO,GAAiB;AACpE,QAAMZ,EAAK,0BAA0B,OAAO,EAAE,SAAAY,EAAA,GAAW,EAAE,SAAS,EAAE,MAAAP,EAAA,GAAQ;AAChF;AAEA,eAAsBQ,EAAkBR,GAAYO,GAAiB;AACnE,QAAMZ,EAAK,yBAAyB,OAAO,EAAE,SAAAY,EAAA,GAAW,EAAE,SAAS,EAAE,MAAAP,EAAA,GAAQ;AAC/E;AAEA,eAAsBS,EAAcT,GAAYO,GAAiB;AAC/D,QAAMZ,EAAK,qBAAqB,OAAO,EAAE,SAAAY,EAAA,GAAW,EAAE,SAAS,EAAE,MAAAP,EAAA,GAAQ;AAC3E;"}
@@ -1,57 +1,56 @@
1
- import { contestSchema as f, participationSchema as d, studentRestoreSchema as p, variantSchema as u, announcementSchema as F, studentSchema as S } from "@olinfo/quizms/models";
2
- import { validate as h } from "@olinfo/quizms/utils";
3
- import { serverTimestamp as c, Timestamp as m } from "firebase/firestore";
4
- import { cloneDeepWith as v, omit as C, isDate as D, isString as b, transform as T, isObject as w } from "lodash-es";
5
- import { websiteSchema as A } from "../../models/website.js";
6
- function i(r) {
7
- return v(C(r, "id"), (t) => {
8
- if (D(t))
9
- return m.fromDate(t);
10
- if (b(t))
11
- return t.trim();
12
- if (t === void 0)
13
- return null;
1
+ import { contestSchema as a, venueSchema as u, studentRestoreSchema as f, variantSchema as d, announcementSchema as v, studentSchema as p } from "@olinfo/quizms/models";
2
+ import { validate as F } from "@olinfo/quizms/utils";
3
+ import { serverTimestamp as i, Timestamp as s } from "firebase/firestore";
4
+ import { cloneDeepWith as m, omit as S, isDate as h, isString as C } from "lodash-es";
5
+ import { websiteSchema as D } from "../../models/website.js";
6
+ function o(t) {
7
+ return m(S(t, "id"), (e) => {
8
+ if (h(e))
9
+ return s.fromDate(e);
10
+ if (C(e))
11
+ return e.trim();
14
12
  });
15
13
  }
16
- function a(r) {
17
- return T(r, (t, e, n) => {
18
- e === null ? t[n] = void 0 : e instanceof m ? t[n] = e.toDate() : w(e) ? t[n] = a(e) : t[n] = e;
14
+ function T(t) {
15
+ return m(t, (e) => {
16
+ if (e instanceof s)
17
+ return e.toDate();
19
18
  });
20
19
  }
21
- function s(r, t) {
22
- const e = a({ ...t.data(), id: t.id });
23
- return h(r, e);
20
+ function n(t, e) {
21
+ const c = T({ ...e.data(), id: e.id });
22
+ return F(t, c);
24
23
  }
25
- function o(r) {
24
+ function r(t) {
26
25
  return {
27
- toFirestore: (t) => i(t),
28
- fromFirestore: (t) => s(r, t)
26
+ toFirestore: (e) => o(e),
27
+ fromFirestore: (e) => n(t, e)
29
28
  };
30
29
  }
31
- const W = o(f), q = o(d), z = o(p), B = o(u), E = o(A), G = {
32
- toFirestore(r) {
30
+ const x = r(a), W = r(u), j = r(f), k = r(d), q = r(D), y = {
31
+ toFirestore(t) {
33
32
  return {
34
- ...i(r),
35
- createdAt: c()
33
+ ...o(t),
34
+ createdAt: i()
36
35
  };
37
36
  },
38
- fromFirestore: (r) => s(F, r)
39
- }, H = {
40
- toFirestore(r) {
37
+ fromFirestore: (t) => n(v, t)
38
+ }, z = {
39
+ toFirestore(t) {
41
40
  return {
42
- ...i(r),
43
- updatedAt: c()
41
+ ...o(t),
42
+ updatedAt: i()
44
43
  };
45
44
  },
46
- fromFirestore: (r) => s(S, r)
45
+ fromFirestore: (t) => n(p, t)
47
46
  };
48
47
  export {
49
- G as announcementConverter,
50
- W as contestConverter,
51
- q as participationConverter,
52
- H as studentConverter,
53
- z as studentRestoreConvert,
54
- B as variantConverter,
55
- E as websiteConverter
48
+ y as announcementConverter,
49
+ x as contestConverter,
50
+ z as studentConverter,
51
+ j as studentRestoreConvert,
52
+ k as variantConverter,
53
+ W as venueConverter,
54
+ q as websiteConverter
56
55
  };
57
56
  //# sourceMappingURL=converters.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"converters.js","sources":["../../../../src/web/common/converters.ts"],"sourcesContent":["import {\n type Announcement,\n announcementSchema,\n contestSchema,\n participationSchema,\n type Student,\n studentRestoreSchema,\n studentSchema,\n variantSchema,\n} from \"@olinfo/quizms/models\";\nimport { validate } from \"@olinfo/quizms/utils\";\nimport {\n type DocumentSnapshot,\n type FirestoreDataConverter,\n serverTimestamp,\n Timestamp,\n} from \"firebase/firestore\";\nimport { cloneDeepWith, isDate, isObject, isString, omit, transform } from \"lodash-es\";\nimport type z from \"zod\";\n\nimport { websiteSchema } from \"~/models/website\";\n\nfunction convertToFirestore(data: object) {\n return cloneDeepWith(omit(data, \"id\"), (value) => {\n if (isDate(value)) {\n return Timestamp.fromDate(value);\n }\n if (isString(value)) {\n return value.trim();\n }\n if (value === undefined) {\n return null;\n }\n });\n}\n\nfunction convertFromFirestore(data: object) {\n return transform(data, (result: any, value: any, key: string | number) => {\n if (value === null) {\n result[key] = undefined;\n } else if (value instanceof Timestamp) {\n result[key] = value.toDate();\n } else if (isObject(value)) {\n result[key] = convertFromFirestore(value);\n } else {\n result[key] = value;\n }\n });\n}\n\nfunction parse<T>(schema: z.core.$ZodType<T>, snapshot: DocumentSnapshot): T {\n const data = convertFromFirestore({ ...snapshot.data(), id: snapshot.id });\n return validate(schema, data);\n}\n\nfunction converter<T extends object>(schema: z.core.$ZodType<T>): FirestoreDataConverter<T> {\n return {\n toFirestore: (data) => convertToFirestore(data),\n fromFirestore: (snapshot) => parse(schema, snapshot),\n };\n}\n\nexport const contestConverter = converter(contestSchema);\nexport const participationConverter = converter(participationSchema);\nexport const studentRestoreConvert = converter(studentRestoreSchema);\nexport const variantConverter = converter(variantSchema);\nexport const websiteConverter = converter(websiteSchema);\n\nexport const announcementConverter: FirestoreDataConverter<Announcement> = {\n toFirestore(data) {\n return {\n ...convertToFirestore(data),\n createdAt: serverTimestamp(),\n };\n },\n fromFirestore: (snapshot) => parse(announcementSchema, snapshot),\n};\n\nexport const studentConverter: FirestoreDataConverter<Student> = {\n toFirestore(data) {\n return {\n ...convertToFirestore(data),\n updatedAt: serverTimestamp(),\n };\n },\n fromFirestore: (snapshot) => parse(studentSchema, snapshot),\n};\n"],"names":["convertToFirestore","data","cloneDeepWith","omit","value","isDate","Timestamp","isString","convertFromFirestore","transform","result","key","isObject","parse","schema","snapshot","validate","converter","contestConverter","contestSchema","participationConverter","participationSchema","studentRestoreConvert","studentRestoreSchema","variantConverter","variantSchema","websiteConverter","websiteSchema","announcementConverter","serverTimestamp","announcementSchema","studentConverter","studentSchema"],"mappings":";;;;;AAsBA,SAASA,EAAmBC,GAAc;AACxC,SAAOC,EAAcC,EAAKF,GAAM,IAAI,GAAG,CAACG,MAAU;AAChD,QAAIC,EAAOD,CAAK;AACd,aAAOE,EAAU,SAASF,CAAK;AAEjC,QAAIG,EAASH,CAAK;AAChB,aAAOA,EAAM,KAAA;AAEf,QAAIA,MAAU;AACZ,aAAO;AAAA,EAEX,CAAC;AACH;AAEA,SAASI,EAAqBP,GAAc;AAC1C,SAAOQ,EAAUR,GAAM,CAACS,GAAaN,GAAYO,MAAyB;AACxE,IAAIP,MAAU,OACZM,EAAOC,CAAG,IAAI,SACLP,aAAiBE,IAC1BI,EAAOC,CAAG,IAAIP,EAAM,OAAA,IACXQ,EAASR,CAAK,IACvBM,EAAOC,CAAG,IAAIH,EAAqBJ,CAAK,IAExCM,EAAOC,CAAG,IAAIP;AAAA,EAElB,CAAC;AACH;AAEA,SAASS,EAASC,GAA4BC,GAA+B;AAC3E,QAAMd,IAAOO,EAAqB,EAAE,GAAGO,EAAS,QAAQ,IAAIA,EAAS,IAAI;AACzE,SAAOC,EAASF,GAAQb,CAAI;AAC9B;AAEA,SAASgB,EAA4BH,GAAuD;AAC1F,SAAO;AAAA,IACL,aAAa,CAACb,MAASD,EAAmBC,CAAI;AAAA,IAC9C,eAAe,CAACc,MAAaF,EAAMC,GAAQC,CAAQ;AAAA,EAAA;AAEvD;AAEO,MAAMG,IAAmBD,EAAUE,CAAa,GAC1CC,IAAyBH,EAAUI,CAAmB,GACtDC,IAAwBL,EAAUM,CAAoB,GACtDC,IAAmBP,EAAUQ,CAAa,GAC1CC,IAAmBT,EAAUU,CAAa,GAE1CC,IAA8D;AAAA,EACzE,YAAY3B,GAAM;AAChB,WAAO;AAAA,MACL,GAAGD,EAAmBC,CAAI;AAAA,MAC1B,WAAW4B,EAAA;AAAA,IAAgB;AAAA,EAE/B;AAAA,EACA,eAAe,CAACd,MAAaF,EAAMiB,GAAoBf,CAAQ;AACjE,GAEagB,IAAoD;AAAA,EAC/D,YAAY9B,GAAM;AAChB,WAAO;AAAA,MACL,GAAGD,EAAmBC,CAAI;AAAA,MAC1B,WAAW4B,EAAA;AAAA,IAAgB;AAAA,EAE/B;AAAA,EACA,eAAe,CAACd,MAAaF,EAAMmB,GAAejB,CAAQ;AAC5D;"}
1
+ {"version":3,"file":"converters.js","sources":["../../../../src/web/common/converters.ts"],"sourcesContent":["import {\n type Announcement,\n announcementSchema,\n contestSchema,\n type Student,\n studentRestoreSchema,\n studentSchema,\n variantSchema,\n venueSchema,\n} from \"@olinfo/quizms/models\";\nimport { validate } from \"@olinfo/quizms/utils\";\nimport {\n type DocumentSnapshot,\n type FirestoreDataConverter,\n serverTimestamp,\n Timestamp,\n} from \"firebase/firestore\";\nimport { cloneDeepWith, isDate, isString, omit } from \"lodash-es\";\nimport type z from \"zod\";\n\nimport { websiteSchema } from \"~/models/website\";\n\nfunction convertToFirestore(data: object) {\n return cloneDeepWith(omit(data, \"id\"), (value) => {\n if (isDate(value)) {\n return Timestamp.fromDate(value);\n }\n if (isString(value)) {\n return value.trim();\n }\n });\n}\n\nfunction convertFromFirestore(data: object) {\n return cloneDeepWith(data, (value) => {\n if (value instanceof Timestamp) {\n return value.toDate();\n }\n });\n}\n\nfunction parse<T>(schema: z.core.$ZodType<T>, snapshot: DocumentSnapshot): T {\n const data = convertFromFirestore({ ...snapshot.data(), id: snapshot.id });\n return validate(schema, data);\n}\n\nfunction converter<T extends object>(schema: z.core.$ZodType<T>): FirestoreDataConverter<T> {\n return {\n toFirestore: (data) => convertToFirestore(data),\n fromFirestore: (snapshot) => parse(schema, snapshot),\n };\n}\n\nexport const contestConverter = converter(contestSchema);\nexport const venueConverter = converter(venueSchema);\nexport const studentRestoreConvert = converter(studentRestoreSchema);\nexport const variantConverter = converter(variantSchema);\nexport const websiteConverter = converter(websiteSchema);\n\nexport const announcementConverter: FirestoreDataConverter<Announcement> = {\n toFirestore(data) {\n return {\n ...convertToFirestore(data),\n createdAt: serverTimestamp(),\n };\n },\n fromFirestore: (snapshot) => parse(announcementSchema, snapshot),\n};\n\nexport const studentConverter: FirestoreDataConverter<Student> = {\n toFirestore(data) {\n return {\n ...convertToFirestore(data),\n updatedAt: serverTimestamp(),\n };\n },\n fromFirestore: (snapshot) => parse(studentSchema, snapshot),\n};\n"],"names":["convertToFirestore","data","cloneDeepWith","omit","value","isDate","Timestamp","isString","convertFromFirestore","parse","schema","snapshot","validate","converter","contestConverter","contestSchema","venueConverter","venueSchema","studentRestoreConvert","studentRestoreSchema","variantConverter","variantSchema","websiteConverter","websiteSchema","announcementConverter","serverTimestamp","announcementSchema","studentConverter","studentSchema"],"mappings":";;;;;AAsBA,SAASA,EAAmBC,GAAc;AACxC,SAAOC,EAAcC,EAAKF,GAAM,IAAI,GAAG,CAACG,MAAU;AAChD,QAAIC,EAAOD,CAAK;AACd,aAAOE,EAAU,SAASF,CAAK;AAEjC,QAAIG,EAASH,CAAK;AAChB,aAAOA,EAAM,KAAA;AAAA,EAEjB,CAAC;AACH;AAEA,SAASI,EAAqBP,GAAc;AAC1C,SAAOC,EAAcD,GAAM,CAACG,MAAU;AACpC,QAAIA,aAAiBE;AACnB,aAAOF,EAAM,OAAA;AAAA,EAEjB,CAAC;AACH;AAEA,SAASK,EAASC,GAA4BC,GAA+B;AAC3E,QAAMV,IAAOO,EAAqB,EAAE,GAAGG,EAAS,QAAQ,IAAIA,EAAS,IAAI;AACzE,SAAOC,EAASF,GAAQT,CAAI;AAC9B;AAEA,SAASY,EAA4BH,GAAuD;AAC1F,SAAO;AAAA,IACL,aAAa,CAACT,MAASD,EAAmBC,CAAI;AAAA,IAC9C,eAAe,CAACU,MAAaF,EAAMC,GAAQC,CAAQ;AAAA,EAAA;AAEvD;AAEO,MAAMG,IAAmBD,EAAUE,CAAa,GAC1CC,IAAiBH,EAAUI,CAAW,GACtCC,IAAwBL,EAAUM,CAAoB,GACtDC,IAAmBP,EAAUQ,CAAa,GAC1CC,IAAmBT,EAAUU,CAAa,GAE1CC,IAA8D;AAAA,EACzE,YAAYvB,GAAM;AAChB,WAAO;AAAA,MACL,GAAGD,EAAmBC,CAAI;AAAA,MAC1B,WAAWwB,EAAA;AAAA,IAAgB;AAAA,EAE/B;AAAA,EACA,eAAe,CAACd,MAAaF,EAAMiB,GAAoBf,CAAQ;AACjE,GAEagB,IAAoD;AAAA,EAC/D,YAAY1B,GAAM;AAChB,WAAO;AAAA,MACL,GAAGD,EAAmBC,CAAI;AAAA,MAC1B,WAAWwB,EAAA;AAAA,IAAgB;AAAA,EAE/B;AAAA,EACA,eAAe,CAACd,MAAaF,EAAMmB,GAAejB,CAAQ;AAC5D;"}
@@ -1,40 +1,40 @@
1
- import { jsxs as a, Fragment as u, jsx as e } from "react/jsx-runtime";
1
+ import { jsxs as n, Fragment as u, jsx as e } from "react/jsx-runtime";
2
2
  import { useEffect as f } from "react";
3
3
  import { Title as p } from "@olinfo/quizms/components";
4
- import { Navbar as h, NavbarBrand as b, Form as w, UsernameField as g, CurrentPasswordField as x, SubmitButton as N } from "@olinfo/react-components";
5
- import { getAuth as S, signInWithCustomToken as v } from "firebase/auth";
6
- import { useSearch as A } from "wouter";
7
- import { useAuth as F } from "../hooks/auth.js";
4
+ import { Navbar as h, NavbarBrand as b, Form as w, UsernameField as g, CurrentPasswordField as x, SubmitButton as L } from "@olinfo/react-components";
5
+ import { getAuth as N, signInWithCustomToken as S } from "firebase/auth";
6
+ import { useSearch as v } from "wouter";
7
+ import { useAuth as A } from "../hooks/auth.js";
8
8
  import "firebase/firestore";
9
9
  import "lodash-es";
10
10
  import "react-error-boundary";
11
11
  import "swr";
12
- import { useDb as L } from "./base-login.js";
13
- import { teacherLogin as P } from "./api.js";
14
- function q({ allowedRole: s, children: n }) {
15
- const i = L(), t = new URLSearchParams(A());
12
+ import { useDb as F } from "./base-login.js";
13
+ import { adminLogin as P, teacherLogin as k } from "./api.js";
14
+ function z({ allowedRole: t, children: s }) {
15
+ const i = F(), a = new URLSearchParams(v());
16
16
  f(() => {
17
17
  const r = new URL(window.location.href);
18
18
  r.searchParams.delete("username"), r.searchParams.delete("password"), window.history.replaceState(void 0, "", r.href);
19
19
  }, []);
20
20
  const m = {
21
- username: t.get("username") ?? "",
22
- password: t.get("password") ?? ""
21
+ username: a.get("username") ?? "",
22
+ password: a.get("password") ?? ""
23
23
  }, c = async (r) => {
24
- const l = await P(r), d = S(i.app);
25
- await v(d, l);
26
- }, o = F(s);
27
- return o ? n(o) : /* @__PURE__ */ a(u, { children: [
24
+ const d = t === "admin" ? await P(r) : await k(r), l = N(i.app);
25
+ await S(l, d);
26
+ }, o = A(t);
27
+ return o ? s(o) : /* @__PURE__ */ n(u, { children: [
28
28
  /* @__PURE__ */ e(h, { color: "bg-base-300 text-base-content", children: /* @__PURE__ */ e(b, { children: /* @__PURE__ */ e("div", { className: "flex items-center h-full font-bold", children: /* @__PURE__ */ e(p, {}) }) }) }),
29
- /* @__PURE__ */ a(w, { defaultValue: m, onSubmit: c, className: "p-4 pb-8", children: [
29
+ /* @__PURE__ */ n(w, { defaultValue: m, onSubmit: c, className: "p-4 pb-8", children: [
30
30
  /* @__PURE__ */ e("h1", { className: "mb-2 text-xl font-bold", children: "Accedi alla gestione gara" }),
31
31
  /* @__PURE__ */ e(g, { field: "username" }),
32
32
  /* @__PURE__ */ e(x, { field: "password" }),
33
- /* @__PURE__ */ e(N, { children: "Accedi" })
33
+ /* @__PURE__ */ e(L, { children: "Accedi" })
34
34
  ] })
35
35
  ] });
36
36
  }
37
37
  export {
38
- q as default
38
+ z as default
39
39
  };
40
40
  //# sourceMappingURL=token-login.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"token-login.js","sources":["../../../../src/web/common/token-login.tsx"],"sourcesContent":["import { type ReactNode, useEffect } from \"react\";\n\nimport { Title } from \"@olinfo/quizms/components\";\nimport {\n CurrentPasswordField,\n Form,\n Navbar,\n NavbarBrand,\n SubmitButton,\n UsernameField,\n} from \"@olinfo/react-components\";\nimport { getAuth, signInWithCustomToken, type User } from \"firebase/auth\";\nimport { useSearch } from \"wouter\";\n\nimport { useAuth } from \"~/web/hooks\";\n\nimport { teacherLogin } from \"./api\";\nimport { useDb } from \"./base-login\";\n\ntype Props = {\n allowedRole: \"teacher\" | \"admin\";\n children: (auth: { user: User; claims: Record<string, string> }) => ReactNode;\n};\n\nexport default function TokenLogin({ allowedRole, children }: Props) {\n const db = useDb();\n const params = new URLSearchParams(useSearch());\n\n useEffect(() => {\n const url = new URL(window.location.href);\n url.searchParams.delete(\"username\");\n url.searchParams.delete(\"password\");\n window.history.replaceState(undefined, \"\", url.href);\n }, []);\n\n const defaultCredential = {\n username: params.get(\"username\") ?? \"\",\n password: params.get(\"password\") ?? \"\",\n };\n\n const signIn = async (credential: { username: string; password: string }) => {\n const token = await teacherLogin(credential);\n\n const auth = getAuth(db.app);\n await signInWithCustomToken(auth, token);\n };\n\n const auth = useAuth(allowedRole);\n if (auth) {\n return children(auth);\n }\n\n return (\n <>\n <Navbar color=\"bg-base-300 text-base-content\">\n <NavbarBrand>\n <div className=\"flex items-center h-full font-bold\">\n <Title />\n </div>\n </NavbarBrand>\n </Navbar>\n <Form defaultValue={defaultCredential} onSubmit={signIn} className=\"p-4 pb-8\">\n <h1 className=\"mb-2 text-xl font-bold\">Accedi alla gestione gara</h1>\n <UsernameField field=\"username\" />\n <CurrentPasswordField field=\"password\" />\n <SubmitButton>Accedi</SubmitButton>\n </Form>\n </>\n );\n}\n"],"names":["TokenLogin","allowedRole","children","db","useDb","params","useSearch","useEffect","url","defaultCredential","signIn","credential","token","teacherLogin","auth","getAuth","signInWithCustomToken","useAuth","jsxs","Fragment","jsx","Navbar","NavbarBrand","Title","Form","UsernameField","CurrentPasswordField","SubmitButton"],"mappings":";;;;;;;;;;;;;AAwBA,SAAwBA,EAAW,EAAE,aAAAC,GAAa,UAAAC,KAAmB;AACnE,QAAMC,IAAKC,EAAA,GACLC,IAAS,IAAI,gBAAgBC,GAAW;AAE9C,EAAAC,EAAU,MAAM;AACd,UAAMC,IAAM,IAAI,IAAI,OAAO,SAAS,IAAI;AACxC,IAAAA,EAAI,aAAa,OAAO,UAAU,GAClCA,EAAI,aAAa,OAAO,UAAU,GAClC,OAAO,QAAQ,aAAa,QAAW,IAAIA,EAAI,IAAI;AAAA,EACrD,GAAG,CAAA,CAAE;AAEL,QAAMC,IAAoB;AAAA,IACxB,UAAUJ,EAAO,IAAI,UAAU,KAAK;AAAA,IACpC,UAAUA,EAAO,IAAI,UAAU,KAAK;AAAA,EAAA,GAGhCK,IAAS,OAAOC,MAAuD;AAC3E,UAAMC,IAAQ,MAAMC,EAAaF,CAAU,GAErCG,IAAOC,EAAQZ,EAAG,GAAG;AAC3B,UAAMa,EAAsBF,GAAMF,CAAK;AAAA,EACzC,GAEME,IAAOG,EAAQhB,CAAW;AAChC,SAAIa,IACKZ,EAASY,CAAI,IAIpB,gBAAAI,EAAAC,GAAA,EACE,UAAA;AAAA,IAAA,gBAAAC,EAACC,GAAA,EAAO,OAAM,iCACZ,UAAA,gBAAAD,EAACE,GAAA,EACC,UAAA,gBAAAF,EAAC,OAAA,EAAI,WAAU,sCACb,UAAA,gBAAAA,EAACG,GAAA,EAAM,EAAA,CACT,GACF,GACF;AAAA,sBACCC,GAAA,EAAK,cAAcf,GAAmB,UAAUC,GAAQ,WAAU,YACjE,UAAA;AAAA,MAAA,gBAAAU,EAAC,MAAA,EAAG,WAAU,0BAAyB,UAAA,6BAAyB;AAAA,MAChE,gBAAAA,EAACK,GAAA,EAAc,OAAM,WAAA,CAAW;AAAA,MAChC,gBAAAL,EAACM,GAAA,EAAqB,OAAM,WAAA,CAAW;AAAA,MACvC,gBAAAN,EAACO,KAAa,UAAA,SAAA,CAAM;AAAA,IAAA,EAAA,CACtB;AAAA,EAAA,GACF;AAEJ;"}
1
+ {"version":3,"file":"token-login.js","sources":["../../../../src/web/common/token-login.tsx"],"sourcesContent":["import { type ReactNode, useEffect } from \"react\";\n\nimport { Title } from \"@olinfo/quizms/components\";\nimport {\n CurrentPasswordField,\n Form,\n Navbar,\n NavbarBrand,\n SubmitButton,\n UsernameField,\n} from \"@olinfo/react-components\";\nimport { getAuth, signInWithCustomToken, type User } from \"firebase/auth\";\nimport { useSearch } from \"wouter\";\n\nimport { useAuth } from \"~/web/hooks\";\n\nimport { adminLogin, teacherLogin } from \"./api\";\nimport { useDb } from \"./base-login\";\n\ntype Props = {\n allowedRole: \"teacher\" | \"admin\";\n children: (auth: { user: User; claims: Record<string, string> }) => ReactNode;\n};\n\nexport default function TokenLogin({ allowedRole, children }: Props) {\n const db = useDb();\n const params = new URLSearchParams(useSearch());\n\n useEffect(() => {\n const url = new URL(window.location.href);\n url.searchParams.delete(\"username\");\n url.searchParams.delete(\"password\");\n window.history.replaceState(undefined, \"\", url.href);\n }, []);\n\n const defaultCredential = {\n username: params.get(\"username\") ?? \"\",\n password: params.get(\"password\") ?? \"\",\n };\n\n const signIn = async (credential: { username: string; password: string }) => {\n const token =\n allowedRole === \"admin\" ? await adminLogin(credential) : await teacherLogin(credential);\n\n const auth = getAuth(db.app);\n await signInWithCustomToken(auth, token);\n };\n\n const auth = useAuth(allowedRole);\n if (auth) {\n return children(auth);\n }\n\n return (\n <>\n <Navbar color=\"bg-base-300 text-base-content\">\n <NavbarBrand>\n <div className=\"flex items-center h-full font-bold\">\n <Title />\n </div>\n </NavbarBrand>\n </Navbar>\n <Form defaultValue={defaultCredential} onSubmit={signIn} className=\"p-4 pb-8\">\n <h1 className=\"mb-2 text-xl font-bold\">Accedi alla gestione gara</h1>\n <UsernameField field=\"username\" />\n <CurrentPasswordField field=\"password\" />\n <SubmitButton>Accedi</SubmitButton>\n </Form>\n </>\n );\n}\n"],"names":["TokenLogin","allowedRole","children","db","useDb","params","useSearch","useEffect","url","defaultCredential","signIn","credential","token","adminLogin","teacherLogin","auth","getAuth","signInWithCustomToken","useAuth","jsxs","Fragment","jsx","Navbar","NavbarBrand","Title","Form","UsernameField","CurrentPasswordField","SubmitButton"],"mappings":";;;;;;;;;;;;;AAwBA,SAAwBA,EAAW,EAAE,aAAAC,GAAa,UAAAC,KAAmB;AACnE,QAAMC,IAAKC,EAAA,GACLC,IAAS,IAAI,gBAAgBC,GAAW;AAE9C,EAAAC,EAAU,MAAM;AACd,UAAMC,IAAM,IAAI,IAAI,OAAO,SAAS,IAAI;AACxC,IAAAA,EAAI,aAAa,OAAO,UAAU,GAClCA,EAAI,aAAa,OAAO,UAAU,GAClC,OAAO,QAAQ,aAAa,QAAW,IAAIA,EAAI,IAAI;AAAA,EACrD,GAAG,CAAA,CAAE;AAEL,QAAMC,IAAoB;AAAA,IACxB,UAAUJ,EAAO,IAAI,UAAU,KAAK;AAAA,IACpC,UAAUA,EAAO,IAAI,UAAU,KAAK;AAAA,EAAA,GAGhCK,IAAS,OAAOC,MAAuD;AAC3E,UAAMC,IACJX,MAAgB,UAAU,MAAMY,EAAWF,CAAU,IAAI,MAAMG,EAAaH,CAAU,GAElFI,IAAOC,EAAQb,EAAG,GAAG;AAC3B,UAAMc,EAAsBF,GAAMH,CAAK;AAAA,EACzC,GAEMG,IAAOG,EAAQjB,CAAW;AAChC,SAAIc,IACKb,EAASa,CAAI,IAIpB,gBAAAI,EAAAC,GAAA,EACE,UAAA;AAAA,IAAA,gBAAAC,EAACC,GAAA,EAAO,OAAM,iCACZ,UAAA,gBAAAD,EAACE,GAAA,EACC,UAAA,gBAAAF,EAAC,OAAA,EAAI,WAAU,sCACb,UAAA,gBAAAA,EAACG,GAAA,EAAM,EAAA,CACT,GACF,GACF;AAAA,sBACCC,GAAA,EAAK,cAAchB,GAAmB,UAAUC,GAAQ,WAAU,YACjE,UAAA;AAAA,MAAA,gBAAAW,EAAC,MAAA,EAAG,WAAU,0BAAyB,UAAA,6BAAyB;AAAA,MAChE,gBAAAA,EAACK,GAAA,EAAc,OAAM,WAAA,CAAW;AAAA,MAChC,gBAAAL,EAACM,GAAA,EAAqB,OAAM,WAAA,CAAW;AAAA,MACvC,gBAAAN,EAACO,KAAa,UAAA,SAAA,CAAM;AAAA,IAAA,EAAA,CACtB;AAAA,EAAA,GACF;AAEJ;"}