@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.
- package/dist/cli.js +14 -14
- package/dist/cli.js.map +1 -1
- package/dist/package.json.js +1 -1
- package/dist/src/cli/definalize.js +17 -17
- package/dist/src/cli/definalize.js.map +1 -1
- package/dist/src/cli/export.js +42 -34
- package/dist/src/cli/export.js.map +1 -1
- package/dist/src/cli/files/firestore-indexes.json.js +1 -1
- package/dist/src/cli/files/firestore.rules.js +27 -27
- package/dist/src/cli/files/firestore.rules.js.map +1 -1
- package/dist/src/cli/files/functions-index.js +3 -3
- package/dist/src/cli/files/functions-index.js.map +1 -1
- package/dist/src/cli/files/storage.rules.js +3 -3
- package/dist/src/cli/files/storage.rules.js.map +1 -1
- package/dist/src/cli/import.js +65 -71
- package/dist/src/cli/import.js.map +1 -1
- package/dist/src/cli/update-scores.js +7 -7
- package/dist/src/cli/update-scores.js.map +1 -1
- package/dist/src/cli/utils/converters-admin.js +23 -22
- package/dist/src/cli/utils/converters-admin.js.map +1 -1
- package/dist/src/functions/api/index.js +18 -18
- package/dist/src/functions/api/index.js.map +1 -1
- package/dist/src/functions/api/queries.js +21 -21
- package/dist/src/functions/api/queries.js.map +1 -1
- package/dist/src/functions/api/student.js +46 -47
- package/dist/src/functions/api/student.js.map +1 -1
- package/dist/src/functions/api/teacher.js +92 -95
- package/dist/src/functions/api/teacher.js.map +1 -1
- package/dist/src/functions/submissions.js +11 -7
- package/dist/src/functions/submissions.js.map +1 -1
- package/dist/src/functions/update-scores.js +14 -14
- package/dist/src/functions/update-scores.js.map +1 -1
- package/dist/src/models/submission.js +13 -0
- package/dist/src/models/submission.js.map +1 -0
- package/dist/src/web/admin/announcements.js +45 -42
- package/dist/src/web/admin/announcements.js.map +1 -1
- package/dist/src/web/admin/contest-settings.js +19 -11
- package/dist/src/web/admin/contest-settings.js.map +1 -1
- package/dist/src/web/admin/context.js.map +1 -1
- package/dist/src/web/admin/dashboard.js +56 -35
- package/dist/src/web/admin/dashboard.js.map +1 -1
- package/dist/src/web/admin/export.js +100 -43
- package/dist/src/web/admin/export.js.map +1 -1
- package/dist/src/web/admin/layout.js +25 -21
- package/dist/src/web/admin/layout.js.map +1 -1
- package/dist/src/web/admin/provider.js +41 -21
- package/dist/src/web/admin/provider.js.map +1 -1
- package/dist/src/web/admin/school-table.js +20 -24
- package/dist/src/web/admin/school-table.js.map +1 -1
- package/dist/src/web/common/api.js +24 -20
- package/dist/src/web/common/api.js.map +1 -1
- package/dist/src/web/common/converters.js +38 -39
- package/dist/src/web/common/converters.js.map +1 -1
- package/dist/src/web/common/token-login.js +18 -18
- package/dist/src/web/common/token-login.js.map +1 -1
- package/dist/src/web/entry/admin.js +22 -13
- package/dist/src/web/entry/admin.js.map +1 -1
- package/dist/src/web/entry/student-statement.js +1 -1
- package/dist/src/web/entry/student-statement.js.map +1 -1
- package/dist/src/web/entry/student.js +80 -75
- package/dist/src/web/entry/student.js.map +1 -1
- package/dist/src/web/entry/teacher.js +63 -62
- package/dist/src/web/entry/teacher.js.map +1 -1
- package/package.json +13 -13
|
@@ -1,25 +1,34 @@
|
|
|
1
1
|
import { jsx as t } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback as
|
|
3
|
-
import { signOut as
|
|
4
|
-
import { AdminProvider as
|
|
5
|
-
import { useDb as
|
|
6
|
-
import { contestConverter as
|
|
7
|
-
import
|
|
2
|
+
import { useCallback as p } from "react";
|
|
3
|
+
import { signOut as c, getAuth as l } from "firebase/auth";
|
|
4
|
+
import { AdminProvider as u } from "../admin/provider.js";
|
|
5
|
+
import { useDb as d } from "../common/base-login.js";
|
|
6
|
+
import { variantConverter as f, contestConverter as v } from "../common/converters.js";
|
|
7
|
+
import C from "../common/token-login.js";
|
|
8
8
|
import "lodash-es";
|
|
9
9
|
import "react-error-boundary";
|
|
10
10
|
import "swr";
|
|
11
|
-
import { useCollection as
|
|
11
|
+
import { useCollection as n } from "../hooks/collection.js";
|
|
12
12
|
import "firebase/firestore";
|
|
13
|
-
function
|
|
14
|
-
return /* @__PURE__ */ t(
|
|
13
|
+
function N() {
|
|
14
|
+
return /* @__PURE__ */ t(C, { allowedRole: "admin", children: (o) => /* @__PURE__ */ t(g, { user: o.user }) });
|
|
15
15
|
}
|
|
16
16
|
function g({ user: o }) {
|
|
17
|
-
const r =
|
|
18
|
-
await
|
|
17
|
+
const r = d(), e = o.displayName ?? "Utente anonimo", [i, m] = n("contests", v), [s] = n("variants", f), a = p(async () => {
|
|
18
|
+
await c(l(r.app)), window.location.reload();
|
|
19
19
|
}, [r]);
|
|
20
|
-
return /* @__PURE__ */ t(
|
|
20
|
+
return /* @__PURE__ */ t(
|
|
21
|
+
u,
|
|
22
|
+
{
|
|
23
|
+
name: e,
|
|
24
|
+
contests: i,
|
|
25
|
+
setContest: m,
|
|
26
|
+
logout: a,
|
|
27
|
+
variants: s
|
|
28
|
+
}
|
|
29
|
+
);
|
|
21
30
|
}
|
|
22
31
|
export {
|
|
23
|
-
|
|
32
|
+
N as default
|
|
24
33
|
};
|
|
25
34
|
//# sourceMappingURL=admin.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin.js","sources":["../../../../src/web/entry/admin.tsx"],"sourcesContent":["import { useCallback } from \"react\";\n\nimport { getAuth, signOut, type User } from \"firebase/auth\";\n\nimport { AdminProvider } from \"~/web/admin/provider\";\nimport { useDb } from \"~/web/common/base-login\";\nimport { contestConverter } from \"~/web/common/converters\";\nimport TokenLogin from \"~/web/common/token-login\";\nimport { useCollection } from \"~/web/hooks\";\n\nexport default function AdminEntry() {\n return <TokenLogin allowedRole=\"admin\">{(auth) => <AdminInner user={auth.user} />}</TokenLogin>;\n}\n\nfunction AdminInner({ user }: { user: User }) {\n const db = useDb();\n const name = user.displayName ?? \"Utente anonimo\";\n\n const [contests, setContest] = useCollection(\"contests\", contestConverter);\n\n const logout = useCallback(async () => {\n await signOut(getAuth(db.app));\n window.location.reload();\n }, [db]);\n\n return <AdminProvider
|
|
1
|
+
{"version":3,"file":"admin.js","sources":["../../../../src/web/entry/admin.tsx"],"sourcesContent":["import { useCallback } from \"react\";\n\nimport { getAuth, signOut, type User } from \"firebase/auth\";\n\nimport { AdminProvider } from \"~/web/admin/provider\";\nimport { useDb } from \"~/web/common/base-login\";\nimport { contestConverter, variantConverter } from \"~/web/common/converters\";\nimport TokenLogin from \"~/web/common/token-login\";\nimport { useCollection } from \"~/web/hooks\";\n\nexport default function AdminEntry() {\n return <TokenLogin allowedRole=\"admin\">{(auth) => <AdminInner user={auth.user} />}</TokenLogin>;\n}\n\nfunction AdminInner({ user }: { user: User }) {\n const db = useDb();\n const name = user.displayName ?? \"Utente anonimo\";\n\n const [contests, setContest] = useCollection(\"contests\", contestConverter);\n\n const [variants] = useCollection(\"variants\", variantConverter);\n\n const logout = useCallback(async () => {\n await signOut(getAuth(db.app));\n window.location.reload();\n }, [db]);\n\n return (\n <AdminProvider\n name={name}\n contests={contests}\n setContest={setContest}\n logout={logout}\n variants={variants}\n />\n );\n}\n"],"names":["AdminEntry","jsx","TokenLogin","auth","AdminInner","user","db","useDb","name","contests","setContest","useCollection","contestConverter","variants","variantConverter","logout","useCallback","signOut","getAuth","AdminProvider"],"mappings":";;;;;;;;;;;;AAUA,SAAwBA,IAAa;AACnC,SAAO,gBAAAC,EAACC,GAAA,EAAW,aAAY,SAAS,UAAA,CAACC,MAAS,gBAAAF,EAACG,GAAA,EAAW,MAAMD,EAAK,KAAA,CAAM,EAAA,CAAG;AACpF;AAEA,SAASC,EAAW,EAAE,MAAAC,KAAwB;AAC5C,QAAMC,IAAKC,EAAA,GACLC,IAAOH,EAAK,eAAe,kBAE3B,CAACI,GAAUC,CAAU,IAAIC,EAAc,YAAYC,CAAgB,GAEnE,CAACC,CAAQ,IAAIF,EAAc,YAAYG,CAAgB,GAEvDC,IAASC,EAAY,YAAY;AACrC,UAAMC,EAAQC,EAAQZ,EAAG,GAAG,CAAC,GAC7B,OAAO,SAAS,OAAA;AAAA,EAClB,GAAG,CAACA,CAAE,CAAC;AAEP,SACE,gBAAAL;AAAA,IAACkB;AAAA,IAAA;AAAA,MACC,MAAAX;AAAA,MACA,UAAAC;AAAA,MACA,YAAAC;AAAA,MACA,QAAAK;AAAA,MACA,UAAAF;AAAA,IAAA;AAAA,EAAA;AAGN;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"student-statement.js","sources":["../../../../src/web/entry/student-statement.tsx"],"sourcesContent":["import { useCallback } from \"react\";\n\nimport { RemoteStatement, useStudent } from \"@olinfo/quizms/student\";\nimport { getDownloadURL, getStorage, ref } from \"firebase/storage\";\n\nimport { useDb } from \"~/web/common/base-login\";\n\nexport function FirebaseStatement() {\n const db = useDb();\n const { student } = useStudent();\n\n const storage = getStorage(db.app);\n\n const getFileUrl = useCallback(\n (fileName: string) => {\n const statementRef = ref(\n storage,\n `statements/${student.contestId}/${student.
|
|
1
|
+
{"version":3,"file":"student-statement.js","sources":["../../../../src/web/entry/student-statement.tsx"],"sourcesContent":["import { useCallback } from \"react\";\n\nimport { RemoteStatement, useStudent } from \"@olinfo/quizms/student\";\nimport { getDownloadURL, getStorage, ref } from \"firebase/storage\";\n\nimport { useDb } from \"~/web/common/base-login\";\n\nexport function FirebaseStatement() {\n const db = useDb();\n const { student } = useStudent();\n\n const storage = getStorage(db.app);\n\n const getFileUrl = useCallback(\n (fileName: string) => {\n const statementRef = ref(\n storage,\n `statements/${student.contestId}/${student.variantId}/${fileName}`,\n );\n return getDownloadURL(statementRef);\n },\n [storage, student],\n );\n\n return (\n <RemoteStatement\n statementUrl={() => getFileUrl(\"statement.txt\")}\n // TODO\n // stylesheetUrl={() => getFileUrl(\"statement.css\")}\n moduleUrl={getFileUrl}\n />\n );\n}\n"],"names":["FirebaseStatement","db","useDb","student","useStudent","storage","getStorage","getFileUrl","useCallback","fileName","statementRef","ref","getDownloadURL","jsx","RemoteStatement"],"mappings":";;;;;AAOO,SAASA,IAAoB;AAClC,QAAMC,IAAKC,EAAA,GACL,EAAE,SAAAC,EAAA,IAAYC,EAAA,GAEdC,IAAUC,EAAWL,EAAG,GAAG,GAE3BM,IAAaC;AAAA,IACjB,CAACC,MAAqB;AACpB,YAAMC,IAAeC;AAAA,QACnBN;AAAA,QACA,cAAcF,EAAQ,SAAS,IAAIA,EAAQ,SAAS,IAAIM,CAAQ;AAAA,MAAA;AAElE,aAAOG,EAAeF,CAAY;AAAA,IACpC;AAAA,IACA,CAACL,GAASF,CAAO;AAAA,EAAA;AAGnB,SACE,gBAAAU;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,cAAc,MAAMP,EAAW,eAAe;AAAA,MAG9C,WAAWA;AAAA,IAAA;AAAA,EAAA;AAGjB;"}
|
|
@@ -1,44 +1,43 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { useMemo as
|
|
3
|
-
import { Title as
|
|
4
|
-
import { StudentProvider as
|
|
5
|
-
import { useUserAgent as
|
|
6
|
-
import { Navbar as A, NavbarBrand as C, Form as
|
|
7
|
-
import { signOut as
|
|
8
|
-
import { waitForPendingWrites as
|
|
9
|
-
import { isEqual as T } from "lodash-es";
|
|
1
|
+
import { jsx as e, jsxs as u, Fragment as p } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo as b, useCallback as f, useEffect as S } from "react";
|
|
3
|
+
import { Title as x, StudentFormField as I } from "@olinfo/quizms/components";
|
|
4
|
+
import { StudentProvider as k } from "@olinfo/quizms/student";
|
|
5
|
+
import { useUserAgent as W } from "@olinfo/quizms/utils";
|
|
6
|
+
import { Navbar as A, NavbarBrand as C, Form as y, SelectField as D, TextField as H, SubmitButton as N } from "@olinfo/react-components";
|
|
7
|
+
import { signOut as E, getAuth as v, signInWithCustomToken as T } from "firebase/auth";
|
|
8
|
+
import { waitForPendingWrites as w } from "firebase/firestore";
|
|
10
9
|
import { studentLogin as j } from "../common/api.js";
|
|
11
|
-
import { useDb as
|
|
12
|
-
import { contestConverter as M, studentConverter as P,
|
|
13
|
-
import { useWebsite as
|
|
14
|
-
import { useAuth as
|
|
15
|
-
import { useCollection as
|
|
16
|
-
import { useDocument as
|
|
17
|
-
import { StudentRestoring as
|
|
10
|
+
import { useDb as g } from "../common/base-login.js";
|
|
11
|
+
import { contestConverter as M, studentConverter as P, venueConverter as R } from "../common/converters.js";
|
|
12
|
+
import { useWebsite as z } from "../common/website.js";
|
|
13
|
+
import { useAuth as B } from "../hooks/auth.js";
|
|
14
|
+
import { useCollection as O } from "../hooks/collection.js";
|
|
15
|
+
import { useDocument as h } from "../hooks/document.js";
|
|
16
|
+
import { StudentRestoring as q } from "./student-restoring.js";
|
|
18
17
|
import { FirebaseStatement as G } from "./student-statement.js";
|
|
19
18
|
import L from "virtual:quizms-firebase-header";
|
|
20
|
-
function
|
|
21
|
-
const
|
|
19
|
+
function me() {
|
|
20
|
+
const t = B("student"), s = z(), [i] = O("contests", M, {
|
|
22
21
|
constraints: { id: s.contests }
|
|
23
22
|
});
|
|
24
|
-
return
|
|
23
|
+
return t ? /* @__PURE__ */ e(q, { user: t.user, children: /* @__PURE__ */ e(
|
|
25
24
|
V,
|
|
26
25
|
{
|
|
27
|
-
contests:
|
|
28
|
-
|
|
29
|
-
studentId:
|
|
26
|
+
contests: i,
|
|
27
|
+
venueId: t.claims.venueId,
|
|
28
|
+
studentId: t.claims.studentId
|
|
30
29
|
}
|
|
31
|
-
) }) : /* @__PURE__ */
|
|
30
|
+
) }) : /* @__PURE__ */ e(U, { contests: i });
|
|
32
31
|
}
|
|
33
|
-
function U({ contests:
|
|
34
|
-
const s =
|
|
35
|
-
async ({ contestId:
|
|
36
|
-
const
|
|
37
|
-
contestId:
|
|
32
|
+
function U({ contests: t }) {
|
|
33
|
+
const s = g(), i = W(), d = f(
|
|
34
|
+
async ({ contestId: o, token: a, ...r }) => {
|
|
35
|
+
const m = await j({
|
|
36
|
+
contestId: o,
|
|
38
37
|
token: a,
|
|
39
|
-
userData:
|
|
38
|
+
userData: r,
|
|
40
39
|
extraData: {
|
|
41
|
-
userAgent:
|
|
40
|
+
userAgent: i,
|
|
42
41
|
windowWidth: window.innerWidth,
|
|
43
42
|
windowHeight: window.innerHeight,
|
|
44
43
|
screenWidth: window.screen.availWidth,
|
|
@@ -46,80 +45,86 @@ function U({ contests: e }) {
|
|
|
46
45
|
pixelRatio: window.devicePixelRatio,
|
|
47
46
|
darkMode: window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
48
47
|
}
|
|
49
|
-
}), c =
|
|
50
|
-
await
|
|
48
|
+
}), c = v(s.app);
|
|
49
|
+
await T(c, m), i.hasFullscreen && await document.documentElement.requestFullscreen?.();
|
|
51
50
|
},
|
|
52
|
-
[s,
|
|
53
|
-
),
|
|
51
|
+
[s, i]
|
|
52
|
+
), n = b(
|
|
54
53
|
() => ({
|
|
55
|
-
contestId:
|
|
54
|
+
contestId: t.length === 1 ? t[0].id : void 0
|
|
56
55
|
}),
|
|
57
|
-
[
|
|
56
|
+
[t]
|
|
58
57
|
);
|
|
59
|
-
return /* @__PURE__ */ u(
|
|
60
|
-
/* @__PURE__ */
|
|
61
|
-
/* @__PURE__ */ u(
|
|
62
|
-
/* @__PURE__ */
|
|
63
|
-
/* @__PURE__ */
|
|
64
|
-
|
|
58
|
+
return /* @__PURE__ */ u(p, { children: [
|
|
59
|
+
/* @__PURE__ */ e(A, { color: "bg-base-300 text-base-content", children: /* @__PURE__ */ e(C, { children: /* @__PURE__ */ e("div", { className: "flex items-center h-full font-bold", children: /* @__PURE__ */ e(x, {}) }) }) }),
|
|
60
|
+
/* @__PURE__ */ u(y, { defaultValue: n, onSubmit: d, className: "p-4 pb-8", children: [
|
|
61
|
+
/* @__PURE__ */ e("h1", { className: "mb-2 text-xl font-bold", children: "Accedi alla gara" }),
|
|
62
|
+
/* @__PURE__ */ e(
|
|
63
|
+
D,
|
|
65
64
|
{
|
|
66
65
|
field: "contestId",
|
|
67
66
|
label: "Gara",
|
|
68
|
-
options: Object.fromEntries(
|
|
67
|
+
options: Object.fromEntries(t.map((o) => [o.id, o.name])),
|
|
69
68
|
placeholder: "Seleziona una gara"
|
|
70
69
|
}
|
|
71
70
|
),
|
|
72
|
-
({ contestId:
|
|
73
|
-
const a =
|
|
71
|
+
({ contestId: o }) => {
|
|
72
|
+
const a = t.find((r) => r.id === o);
|
|
74
73
|
if (a)
|
|
75
|
-
return /* @__PURE__ */ u(
|
|
76
|
-
a.userData.map((
|
|
77
|
-
/* @__PURE__ */
|
|
78
|
-
/* @__PURE__ */
|
|
74
|
+
return /* @__PURE__ */ u(p, { children: [
|
|
75
|
+
a.userData.map((r) => /* @__PURE__ */ e(I, { field: r }, r.name)),
|
|
76
|
+
/* @__PURE__ */ e(H, { field: "token", label: "Codice prova", placeholder: "aaaaa-bbbbb-ccccc" }),
|
|
77
|
+
/* @__PURE__ */ e(N, { children: "Inizia la prova" })
|
|
79
78
|
] });
|
|
80
79
|
}
|
|
81
80
|
] })
|
|
82
81
|
] });
|
|
83
82
|
}
|
|
84
83
|
function V({
|
|
85
|
-
contests:
|
|
86
|
-
|
|
87
|
-
studentId:
|
|
84
|
+
contests: t,
|
|
85
|
+
venueId: s,
|
|
86
|
+
studentId: i
|
|
88
87
|
}) {
|
|
89
|
-
const d =
|
|
90
|
-
`
|
|
91
|
-
|
|
88
|
+
const d = g(), [n, o] = h(
|
|
89
|
+
`venues/${s}/students`,
|
|
90
|
+
i,
|
|
92
91
|
P
|
|
93
|
-
), [a] =
|
|
94
|
-
() =>
|
|
95
|
-
[
|
|
96
|
-
),
|
|
97
|
-
await
|
|
98
|
-
|
|
99
|
-
|
|
92
|
+
), [a] = h("venues", s, R), r = b(
|
|
93
|
+
() => t.find((l) => l.id === n.contestId),
|
|
94
|
+
[t, n.contestId]
|
|
95
|
+
), m = f(async () => {
|
|
96
|
+
await o({
|
|
97
|
+
...n,
|
|
98
|
+
participationWindow: { start: n.participationWindow.start, end: /* @__PURE__ */ new Date() }
|
|
99
|
+
}), await w(d);
|
|
100
|
+
}, [d, n, o]), c = f(async () => {
|
|
101
|
+
await w(d), await E(v(d.app)), window.location.reload();
|
|
100
102
|
}, [d]);
|
|
101
|
-
return
|
|
102
|
-
a.token !==
|
|
103
|
-
}, [a.token,
|
|
104
|
-
|
|
103
|
+
return S(() => {
|
|
104
|
+
a.token !== n.token && c();
|
|
105
|
+
}, [a.token, n.token, c]), /* @__PURE__ */ u(
|
|
106
|
+
k,
|
|
105
107
|
{
|
|
106
|
-
contest:
|
|
107
|
-
|
|
108
|
-
student:
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
contest: r,
|
|
109
|
+
venue: a,
|
|
110
|
+
student: n,
|
|
111
|
+
setAnswer: async (l, F) => {
|
|
112
|
+
await o({
|
|
113
|
+
...n,
|
|
114
|
+
answers: { ...n.answers, [l]: F }
|
|
115
|
+
});
|
|
111
116
|
},
|
|
112
117
|
logout: c,
|
|
113
|
-
|
|
118
|
+
submit: m,
|
|
114
119
|
enforceFullscreen: !0,
|
|
115
120
|
children: [
|
|
116
|
-
/* @__PURE__ */
|
|
117
|
-
/* @__PURE__ */
|
|
121
|
+
/* @__PURE__ */ e(L, { contestId: r.id }),
|
|
122
|
+
/* @__PURE__ */ e(G, {})
|
|
118
123
|
]
|
|
119
124
|
}
|
|
120
125
|
);
|
|
121
126
|
}
|
|
122
127
|
export {
|
|
123
|
-
|
|
128
|
+
me as default
|
|
124
129
|
};
|
|
125
130
|
//# sourceMappingURL=student.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"student.js","sources":["../../../../src/web/entry/student.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo } from \"react\";\n\nimport { StudentFormField, Title } from \"@olinfo/quizms/components\";\nimport type { Contest, Student } from \"@olinfo/quizms/models\";\nimport { StudentProvider } from \"@olinfo/quizms/student\";\nimport { useUserAgent } from \"@olinfo/quizms/utils\";\nimport {\n Form,\n Navbar,\n NavbarBrand,\n SelectField,\n SubmitButton,\n TextField,\n} from \"@olinfo/react-components\";\nimport { getAuth, signInWithCustomToken, signOut } from \"firebase/auth\";\nimport { waitForPendingWrites } from \"firebase/firestore\";\
|
|
1
|
+
{"version":3,"file":"student.js","sources":["../../../../src/web/entry/student.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo } from \"react\";\n\nimport { StudentFormField, Title } from \"@olinfo/quizms/components\";\nimport type { Answer, Contest, Student } from \"@olinfo/quizms/models\";\nimport { StudentProvider } from \"@olinfo/quizms/student\";\nimport { useUserAgent } from \"@olinfo/quizms/utils\";\nimport {\n Form,\n Navbar,\n NavbarBrand,\n SelectField,\n SubmitButton,\n TextField,\n} from \"@olinfo/react-components\";\nimport { getAuth, signInWithCustomToken, signOut } from \"firebase/auth\";\nimport { waitForPendingWrites } from \"firebase/firestore\";\n\nimport { studentLogin } from \"~/web/common/api\";\nimport { useDb } from \"~/web/common/base-login\";\nimport { contestConverter, studentConverter, venueConverter } from \"~/web/common/converters\";\nimport { useWebsite } from \"~/web/common/website\";\nimport { useAuth, useCollection, useDocument } from \"~/web/hooks\";\n\nimport { StudentRestoring } from \"./student-restoring\";\nimport { FirebaseStatement } from \"./student-statement\";\n// @ts-expect-error\nimport Header from \"virtual:quizms-firebase-header\";\n\nexport default function StudentEntry() {\n const auth = useAuth(\"student\");\n\n const website = useWebsite();\n const [contests] = useCollection(\"contests\", contestConverter, {\n constraints: { id: website.contests },\n });\n\n if (auth) {\n return (\n <StudentRestoring user={auth.user}>\n <StudentInner\n contests={contests}\n venueId={auth.claims.venueId}\n studentId={auth.claims.studentId}\n />\n </StudentRestoring>\n );\n }\n\n return <StudentForm contests={contests} />;\n}\n\ntype FormStudent = {\n contestId: string;\n token: string;\n} & Required<NonNullable<Student[\"userData\"]>>;\n\nfunction StudentForm({ contests }: { contests: Contest[] }) {\n const db = useDb();\n const ua = useUserAgent();\n\n const submit = useCallback(\n async ({ contestId, token, ...userData }: FormStudent) => {\n const authToken = await studentLogin({\n contestId,\n token,\n userData,\n extraData: {\n userAgent: ua,\n windowWidth: window.innerWidth,\n windowHeight: window.innerHeight,\n screenWidth: window.screen.availWidth,\n screenHeight: window.screen.availHeight,\n pixelRatio: window.devicePixelRatio,\n darkMode: window.matchMedia(\"(prefers-color-scheme: dark)\").matches,\n },\n });\n\n const auth = getAuth(db.app);\n await signInWithCustomToken(auth, authToken);\n if (ua.hasFullscreen) {\n await document.documentElement.requestFullscreen?.();\n }\n },\n [db, ua],\n );\n\n const defaultValue = useMemo(\n () => ({\n contestId: contests.length === 1 ? contests[0].id : undefined,\n }),\n [contests],\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={defaultValue} onSubmit={submit} className=\"p-4 pb-8\">\n <h1 className=\"mb-2 text-xl font-bold\">Accedi alla gara</h1>\n <SelectField\n field=\"contestId\"\n label=\"Gara\"\n options={Object.fromEntries(contests.map((c) => [c.id, c.name]))}\n placeholder=\"Seleziona una gara\"\n />\n {({ contestId }) => {\n const contest = contests.find((c) => c.id === contestId);\n if (!contest) return;\n return (\n <>\n {contest.userData.map((field) => (\n <StudentFormField key={field.name} field={field} />\n ))}\n <TextField field=\"token\" label=\"Codice prova\" placeholder=\"aaaaa-bbbbb-ccccc\" />\n <SubmitButton>Inizia la prova</SubmitButton>\n </>\n );\n }}\n </Form>\n </>\n );\n}\n\nfunction StudentInner({\n contests,\n venueId,\n studentId,\n}: {\n contests: Contest[];\n venueId: string;\n studentId: string;\n}) {\n const db = useDb();\n\n const [student, setStudent] = useDocument(\n `venues/${venueId}/students`,\n studentId,\n studentConverter,\n );\n const [venue] = useDocument(\"venues\", venueId, venueConverter);\n\n const contest = useMemo(\n () => contests.find((c) => c.id === student.contestId)!,\n [contests, student.contestId],\n );\n\n const submit = useCallback(async () => {\n await setStudent({\n ...student,\n participationWindow: { start: student.participationWindow!.start, end: new Date() },\n });\n await waitForPendingWrites(db);\n }, [db, student, setStudent]);\n\n const logout = useCallback(async () => {\n await waitForPendingWrites(db);\n await signOut(getAuth(db.app));\n window.location.reload();\n }, [db]);\n\n useEffect(() => {\n if (venue.token !== student.token) {\n void logout();\n }\n }, [venue.token, student.token, logout]);\n\n const setAnswer = async (problemId: string, answer: Answer) => {\n await setStudent({\n ...student,\n answers: { ...student.answers, [problemId]: answer },\n });\n };\n\n return (\n <StudentProvider\n contest={contest}\n venue={venue}\n student={student}\n setAnswer={setAnswer}\n logout={logout}\n submit={submit}\n enforceFullscreen={true}>\n <Header contestId={contest.id} />\n <FirebaseStatement />\n </StudentProvider>\n );\n}\n"],"names":["StudentEntry","auth","useAuth","website","useWebsite","contests","useCollection","contestConverter","jsx","StudentRestoring","StudentInner","StudentForm","db","useDb","ua","useUserAgent","submit","useCallback","contestId","token","userData","authToken","studentLogin","getAuth","signInWithCustomToken","defaultValue","useMemo","jsxs","Fragment","Navbar","NavbarBrand","Title","Form","SelectField","c","contest","field","StudentFormField","TextField","SubmitButton","venueId","studentId","student","setStudent","useDocument","studentConverter","venue","venueConverter","waitForPendingWrites","logout","signOut","useEffect","StudentProvider","problemId","answer","Header","FirebaseStatement"],"mappings":"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"}
|
|
@@ -1,59 +1,60 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { useCallback as
|
|
3
|
-
import { TeacherProvider as
|
|
4
|
-
import { signOut as
|
|
5
|
-
import { writeBatch as f, doc as
|
|
6
|
-
import { getStorage as
|
|
7
|
-
import {
|
|
8
|
-
import { useDb as
|
|
9
|
-
import { contestConverter as
|
|
10
|
-
import
|
|
11
|
-
import { useWebsite as
|
|
1
|
+
import { jsx as u } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback as w } from "react";
|
|
3
|
+
import { TeacherProvider as C } from "@olinfo/quizms/teacher";
|
|
4
|
+
import { signOut as g, getAuth as y } from "firebase/auth";
|
|
5
|
+
import { writeBatch as f, doc as p, serverTimestamp as b } from "firebase/firestore";
|
|
6
|
+
import { getStorage as h, getBytes as R, ref as A } from "firebase/storage";
|
|
7
|
+
import { finalizeVenue as S, stopContestWindow as k, startContestWindow as B } from "../common/api.js";
|
|
8
|
+
import { useDb as v } from "../common/base-login.js";
|
|
9
|
+
import { contestConverter as I, venueConverter as l, studentRestoreConvert as T, studentConverter as W, announcementConverter as P, variantConverter as $ } from "../common/converters.js";
|
|
10
|
+
import j from "../common/token-login.js";
|
|
11
|
+
import { useWebsite as x } from "../common/website.js";
|
|
12
12
|
import "lodash-es";
|
|
13
13
|
import "react-error-boundary";
|
|
14
14
|
import "swr";
|
|
15
|
-
import { useCollection as
|
|
16
|
-
import { useDocument as
|
|
17
|
-
import { FirebaseStatement as
|
|
18
|
-
function
|
|
19
|
-
return /* @__PURE__ */
|
|
15
|
+
import { useCollection as d } from "../hooks/collection.js";
|
|
16
|
+
import { useDocument as z } from "../hooks/document.js";
|
|
17
|
+
import { FirebaseStatement as D } from "./student-statement.js";
|
|
18
|
+
function st() {
|
|
19
|
+
return /* @__PURE__ */ u(j, { allowedRole: "teacher", children: ({ user: t, claims: e }) => /* @__PURE__ */ u(E, { user: t, schoolId: e.schoolId }) });
|
|
20
20
|
}
|
|
21
|
-
function
|
|
22
|
-
const
|
|
23
|
-
constraints: { id:
|
|
24
|
-
}), [
|
|
25
|
-
constraints: { contestId:
|
|
26
|
-
}), [
|
|
27
|
-
await
|
|
28
|
-
}, [
|
|
29
|
-
return /* @__PURE__ */
|
|
30
|
-
|
|
21
|
+
function E({ user: t, schoolId: e }) {
|
|
22
|
+
const s = v(), r = x(), [i] = d("contests", I, {
|
|
23
|
+
constraints: { id: r.contests }
|
|
24
|
+
}), [c] = d("venues", l, {
|
|
25
|
+
constraints: { contestId: r.contests, schoolId: e }
|
|
26
|
+
}), [o] = d("variants", $), a = w(async () => {
|
|
27
|
+
await g(y(s.app)), window.location.reload();
|
|
28
|
+
}, [s]);
|
|
29
|
+
return /* @__PURE__ */ u(
|
|
30
|
+
C,
|
|
31
31
|
{
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
32
|
+
name: c[0]?.name ?? e,
|
|
33
|
+
venues: c,
|
|
34
|
+
contests: i,
|
|
35
|
+
startContestWindow: (...n) => B(t, ...n),
|
|
36
|
+
stopContestWindow: (...n) => k(t, ...n),
|
|
37
|
+
finalizeVenue: (...n) => S(t, ...n),
|
|
38
|
+
variants: o,
|
|
39
|
+
logout: a,
|
|
40
|
+
statementComponent: () => /* @__PURE__ */ u(D, {}),
|
|
41
|
+
getPdfStatements: (n, m) => O(s, n, m),
|
|
42
|
+
useAnnouncements: V,
|
|
43
|
+
useStudents: F,
|
|
44
|
+
useStudentRestores: L
|
|
44
45
|
}
|
|
45
46
|
);
|
|
46
47
|
}
|
|
47
|
-
async function
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
async (
|
|
48
|
+
async function O(t, e, s) {
|
|
49
|
+
const r = h(t.app), i = await Promise.all(
|
|
50
|
+
s.map(
|
|
51
|
+
async (c) => [c, await R(A(r, `statements/${e}/${c}/statement.pdf`))]
|
|
51
52
|
)
|
|
52
53
|
);
|
|
53
|
-
return Object.fromEntries(
|
|
54
|
+
return Object.fromEntries(i);
|
|
54
55
|
}
|
|
55
|
-
function
|
|
56
|
-
const [e] =
|
|
56
|
+
function V(t) {
|
|
57
|
+
const [e] = d("announcements", P, {
|
|
57
58
|
arrayConstraints: {
|
|
58
59
|
contestIds: t
|
|
59
60
|
},
|
|
@@ -61,30 +62,30 @@ function L(t) {
|
|
|
61
62
|
});
|
|
62
63
|
return e;
|
|
63
64
|
}
|
|
64
|
-
function
|
|
65
|
-
return
|
|
65
|
+
function F(t) {
|
|
66
|
+
return d(`venues/${t}/students`, W, {
|
|
66
67
|
orderBy: "createdAt"
|
|
67
68
|
});
|
|
68
69
|
}
|
|
69
|
-
function
|
|
70
|
-
const e =
|
|
71
|
-
constraints: {
|
|
70
|
+
function L(t) {
|
|
71
|
+
const e = v(), [s] = z("venues", t, l), [r] = d("studentRestores", T, {
|
|
72
|
+
constraints: { venueId: t, token: s.token ?? void 0, status: "pending" },
|
|
72
73
|
orderBy: "createdAt"
|
|
73
|
-
}),
|
|
74
|
-
const
|
|
75
|
-
for (const
|
|
76
|
-
|
|
77
|
-
await
|
|
74
|
+
}), i = async (o, a) => {
|
|
75
|
+
const n = f(e);
|
|
76
|
+
for (const m of r)
|
|
77
|
+
m.studentId === o && m.id !== a && n.update(p(e, "studentRestores", m.id), { status: "revoked" });
|
|
78
|
+
await n.commit();
|
|
78
79
|
};
|
|
79
|
-
return [
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
uid:
|
|
80
|
+
return [r, async (o) => {
|
|
81
|
+
const a = f(e);
|
|
82
|
+
a.update(p(e, `/venues/${t}/students`, o.studentId), {
|
|
83
|
+
uid: o.id,
|
|
83
84
|
updatedAt: b()
|
|
84
|
-
}),
|
|
85
|
-
},
|
|
85
|
+
}), a.delete(p(e, "studentRestores", o.id)), await a.commit(), await i(o.studentId, o.id);
|
|
86
|
+
}, i];
|
|
86
87
|
}
|
|
87
88
|
export {
|
|
88
|
-
|
|
89
|
+
st as default
|
|
89
90
|
};
|
|
90
91
|
//# sourceMappingURL=teacher.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"teacher.js","sources":["../../../../src/web/entry/teacher.tsx"],"sourcesContent":["import { useCallback } from \"react\";\n\nimport type { StudentRestore } from \"@olinfo/quizms/models\";\nimport { TeacherProvider } from \"@olinfo/quizms/teacher\";\nimport { getAuth, signOut, type User } from \"firebase/auth\";\nimport { doc, type Firestore, serverTimestamp, writeBatch } from \"firebase/firestore\";\nimport { getBytes, getStorage, ref } from \"firebase/storage\";\n\nimport {
|
|
1
|
+
{"version":3,"file":"teacher.js","sources":["../../../../src/web/entry/teacher.tsx"],"sourcesContent":["import { useCallback } from \"react\";\n\nimport type { StudentRestore } from \"@olinfo/quizms/models\";\nimport { TeacherProvider } from \"@olinfo/quizms/teacher\";\nimport { getAuth, signOut, type User } from \"firebase/auth\";\nimport { doc, type Firestore, serverTimestamp, writeBatch } from \"firebase/firestore\";\nimport { getBytes, getStorage, ref } from \"firebase/storage\";\n\nimport { finalizeVenue, startContestWindow, stopContestWindow } from \"~/web/common/api\";\nimport { useDb } from \"~/web/common/base-login\";\nimport {\n announcementConverter,\n contestConverter,\n studentConverter,\n studentRestoreConvert,\n variantConverter,\n venueConverter,\n} from \"~/web/common/converters\";\nimport TokenLogin from \"~/web/common/token-login\";\nimport { useWebsite } from \"~/web/common/website\";\nimport { useCollection, useDocument } from \"~/web/hooks\";\n\nimport { FirebaseStatement } from \"./student-statement\";\n\nexport default function TeacherEntry() {\n return (\n <TokenLogin allowedRole=\"teacher\">\n {({ user, claims }) => <TeacherInner user={user} schoolId={claims.schoolId} />}\n </TokenLogin>\n );\n}\n\nfunction TeacherInner({ user, schoolId }: { user: User; schoolId: string }) {\n const db = useDb();\n\n const website = useWebsite();\n const [contests] = useCollection(\"contests\", contestConverter, {\n constraints: { id: website.contests },\n });\n const [venues] = useCollection(\"venues\", venueConverter, {\n constraints: { contestId: website.contests, schoolId: schoolId },\n });\n const [variants] = useCollection(\"variants\", variantConverter);\n\n const logout = useCallback(async () => {\n await signOut(getAuth(db.app));\n window.location.reload();\n }, [db]);\n\n return (\n <TeacherProvider\n name={venues[0]?.name ?? schoolId}\n venues={venues}\n contests={contests}\n startContestWindow={(...args) => startContestWindow(user, ...args)}\n stopContestWindow={(...args) => stopContestWindow(user, ...args)}\n finalizeVenue={(...args) => finalizeVenue(user, ...args)}\n variants={variants}\n logout={logout}\n statementComponent={() => <FirebaseStatement />}\n getPdfStatements={(contestId, variantIds) => getPdfStatements(db, contestId, variantIds)}\n useAnnouncements={useAnnouncements}\n useStudents={useStudents}\n useStudentRestores={useStudentRestores}\n />\n );\n}\n\nasync function getPdfStatements(\n db: Firestore,\n contestId: string,\n variantIds: string[],\n): Promise<Record<string, ArrayBuffer>> {\n const storage = getStorage(db.app);\n\n const files = await Promise.all(\n variantIds.map(\n async (id) =>\n [id, await getBytes(ref(storage, `statements/${contestId}/${id}/statement.pdf`))] as const,\n ),\n );\n return Object.fromEntries(files);\n}\n\nfunction useAnnouncements(contestId: string) {\n const [announcements] = useCollection(\"announcements\", announcementConverter, {\n arrayConstraints: {\n contestIds: contestId,\n },\n orderBy: [\"createdAt\", \"desc\"],\n });\n return announcements;\n}\n\nfunction useStudents(venueId: string) {\n return useCollection(`venues/${venueId}/students`, studentConverter, {\n orderBy: \"createdAt\",\n });\n}\n\nfunction useStudentRestores(\n venueId: string,\n): readonly [\n StudentRestore[],\n (request: StudentRestore) => Promise<void>,\n (studentId: string) => Promise<void>,\n] {\n const db = useDb();\n\n const [venue] = useDocument(\"venues\", venueId, venueConverter);\n\n const [studentRestores] = useCollection(\"studentRestores\", studentRestoreConvert, {\n constraints: { venueId, token: venue.token ?? undefined, status: \"pending\" },\n orderBy: \"createdAt\",\n });\n\n const reject = async (studentId: string, excludeRestoreId?: string) => {\n const batch = writeBatch(db);\n\n for (const studentRestore of studentRestores) {\n if (studentRestore.studentId === studentId && studentRestore.id !== excludeRestoreId) {\n batch.update(doc(db, \"studentRestores\", studentRestore.id), { status: \"revoked\" });\n }\n }\n\n await batch.commit();\n };\n\n const approve = async (request: StudentRestore) => {\n const batch = writeBatch(db);\n batch.update(doc(db, `/venues/${venueId}/students`, request.studentId), {\n uid: request.id,\n updatedAt: serverTimestamp(),\n });\n batch.delete(doc(db, \"studentRestores\", request.id));\n await batch.commit();\n\n await reject(request.studentId, request.id);\n };\n\n return [studentRestores, approve, reject];\n}\n"],"names":["TeacherEntry","jsx","TokenLogin","user","claims","TeacherInner","schoolId","db","useDb","website","useWebsite","contests","useCollection","contestConverter","venues","venueConverter","variants","variantConverter","logout","useCallback","signOut","getAuth","TeacherProvider","args","startContestWindow","stopContestWindow","finalizeVenue","FirebaseStatement","contestId","variantIds","getPdfStatements","useAnnouncements","useStudents","useStudentRestores","storage","getStorage","files","id","getBytes","ref","announcements","announcementConverter","venueId","studentConverter","venue","useDocument","studentRestores","studentRestoreConvert","reject","studentId","excludeRestoreId","batch","writeBatch","studentRestore","doc","request","serverTimestamp"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olinfo/quizms-firebase",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "Alessandro Bortolin <bortolin.alessandro@outlook.it>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
"dist"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@inquirer/prompts": "^8.
|
|
30
|
-
"@olinfo/react-components": "^0.12.
|
|
31
|
-
"@trpc/client": "^11.
|
|
32
|
-
"@trpc/server": "^11.
|
|
29
|
+
"@inquirer/prompts": "^8.3.0",
|
|
30
|
+
"@olinfo/react-components": "^0.12.2",
|
|
31
|
+
"@trpc/client": "^11.12.0",
|
|
32
|
+
"@trpc/server": "^11.12.0",
|
|
33
33
|
"@types/cli-progress": "^3.11.6",
|
|
34
34
|
"@types/express": "^5.0.6",
|
|
35
35
|
"@types/express-serve-static-core": "^5.1.1",
|
|
@@ -41,10 +41,10 @@
|
|
|
41
41
|
"commander": "^14.0.3",
|
|
42
42
|
"date-fns": "^4.1.0",
|
|
43
43
|
"express": "^5.2.1",
|
|
44
|
-
"fastify": "^5.
|
|
45
|
-
"firebase": "^12.
|
|
46
|
-
"firebase-admin": "^13.
|
|
47
|
-
"firebase-functions": "^7.0
|
|
44
|
+
"fastify": "^5.8.2",
|
|
45
|
+
"firebase": "^12.10.0",
|
|
46
|
+
"firebase-admin": "^13.7.0",
|
|
47
|
+
"firebase-functions": "^7.1.0",
|
|
48
48
|
"lodash-es": "^4.17.23",
|
|
49
49
|
"lucide-react": "^0.562.0",
|
|
50
50
|
"picomatch": "^4.0.3",
|
|
@@ -53,16 +53,16 @@
|
|
|
53
53
|
"rollup-plugin-node-externals": "^8.1.2",
|
|
54
54
|
"rollup-preserve-directives": "^1.1.3",
|
|
55
55
|
"superjson": "^2.2.6",
|
|
56
|
-
"swr": "^2.4.
|
|
56
|
+
"swr": "^2.4.1",
|
|
57
57
|
"tinyglobby": "^0.2.15",
|
|
58
58
|
"vite": "^7.3.1",
|
|
59
59
|
"vite-plugin-dts": "^4.5.4",
|
|
60
60
|
"wouter": "^3.9.0",
|
|
61
61
|
"zod": "^4.3.6",
|
|
62
|
-
"@olinfo/quizms": "^
|
|
62
|
+
"@olinfo/quizms": "^5.0.2"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
|
-
"react": "
|
|
65
|
+
"react": "^19.2.4"
|
|
66
66
|
},
|
|
67
67
|
"postcss": {
|
|
68
68
|
"plugins": {
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
}
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
|
-
"@biomejs/biome": "^2.4.
|
|
73
|
+
"@biomejs/biome": "^2.4.6",
|
|
74
74
|
"@google-cloud/storage": "^7.19.0",
|
|
75
75
|
"@types/react": "^19.2.14",
|
|
76
76
|
"@types/wicg-file-system-access": "^2023.10.7",
|