@olinfo/quizms-firebase 4.0.0 → 4.1.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/functions.d.ts +2 -11
- package/dist/functions.js +2 -2
- package/dist/package.json.js +1 -1
- package/dist/src/cli/files/functions-index.js +4 -4
- package/dist/src/cli/files/functions-index.js.map +1 -1
- package/dist/src/cli/init.js +8 -8
- package/dist/src/cli/init.js.map +1 -1
- package/dist/src/cli/update-scores.js +21 -32
- package/dist/src/cli/update-scores.js.map +1 -1
- package/dist/src/cli/utils/collection.js +20 -18
- package/dist/src/cli/utils/collection.js.map +1 -1
- package/dist/src/cli/utils/converters-admin.js +31 -32
- package/dist/src/cli/utils/converters-admin.js.map +1 -1
- package/dist/src/cli/utils/region-finder.js +6 -5
- package/dist/src/cli/utils/region-finder.js.map +1 -1
- package/dist/src/cli/utils/storage.js +26 -35
- package/dist/src/cli/utils/storage.js.map +1 -1
- package/dist/src/cli/utils/users.js +13 -12
- package/dist/src/cli/utils/users.js.map +1 -1
- package/dist/src/functions/api/admin.js +28 -0
- package/dist/src/functions/api/admin.js.map +1 -0
- package/dist/src/functions/api/index.js +26 -34
- package/dist/src/functions/api/index.js.map +1 -1
- package/dist/src/functions/api/queries.js +5 -5
- package/dist/src/functions/api/student.js +62 -72
- package/dist/src/functions/api/student.js.map +1 -1
- package/dist/src/functions/api/teacher.js +104 -111
- package/dist/src/functions/api/teacher.js.map +1 -1
- package/dist/src/functions/api/trpc.js +18 -0
- package/dist/src/functions/api/trpc.js.map +1 -0
- package/dist/src/functions/submissions.js +1 -1
- package/dist/src/functions/submissions.js.map +1 -1
- package/dist/src/models/user.js +2 -2
- package/dist/src/models/user.js.map +1 -1
- package/dist/src/models/website.js +1 -1
- package/dist/src/models/website.js.map +1 -1
- package/dist/src/vite/preset.js +3 -4
- package/dist/src/vite/preset.js.map +1 -1
- package/dist/src/web/admin/announcements.js +9 -10
- package/dist/src/web/admin/announcements.js.map +1 -1
- package/dist/src/web/admin/school-table.js +7 -8
- package/dist/src/web/admin/school-table.js.map +1 -1
- package/dist/src/web/common/api.js +32 -35
- package/dist/src/web/common/api.js.map +1 -1
- package/dist/src/web/common/converters.js +35 -36
- package/dist/src/web/common/converters.js.map +1 -1
- package/dist/src/web/common/token-login.js +11 -11
- package/dist/src/web/common/token-login.js.map +1 -1
- package/dist/src/web/entry/admin.js +5 -7
- package/dist/src/web/entry/admin.js.map +1 -1
- package/dist/src/web/entry/student-restoring.js +18 -20
- package/dist/src/web/entry/student-restoring.js.map +1 -1
- package/dist/src/web/entry/student.js +70 -76
- package/dist/src/web/entry/student.js.map +1 -1
- package/dist/src/web/entry/teacher.js +68 -68
- package/dist/src/web/entry/teacher.js.map +1 -1
- package/dist/src/web/hooks/collection.js +29 -30
- package/dist/src/web/hooks/collection.js.map +1 -1
- package/dist/src/web/hooks/document.js +35 -36
- package/dist/src/web/hooks/document.js.map +1 -1
- package/dist/src/web/hooks/subscription.js +26 -22
- package/dist/src/web/hooks/subscription.js.map +1 -1
- package/package.json +23 -19
- package/dist/src/functions/api/schema.js +0 -42
- package/dist/src/functions/api/schema.js.map +0 -1
|
@@ -1,47 +1,44 @@
|
|
|
1
|
-
import { jsx as t, jsxs as u, Fragment as
|
|
1
|
+
import { jsx as t, jsxs as u, Fragment as f } from "react/jsx-runtime";
|
|
2
2
|
import { useMemo as w, useCallback as p, useEffect as v } from "react";
|
|
3
|
-
import { Title as
|
|
3
|
+
import { Title as F, StudentFormField as x } from "@olinfo/quizms/components";
|
|
4
4
|
import { StudentProvider as I } from "@olinfo/quizms/student";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
5
|
+
import { useUserAgent as k } from "@olinfo/quizms/utils";
|
|
6
|
+
import { Navbar as A, NavbarBrand as C, Form as W, SelectField as y, TextField as E, SubmitButton as H } from "@olinfo/react-components";
|
|
7
|
+
import { signOut as N, getAuth as g, signInWithCustomToken as D } from "firebase/auth";
|
|
8
|
+
import { waitForPendingWrites as h } from "firebase/firestore";
|
|
9
|
+
import { isEqual as T } from "lodash-es";
|
|
9
10
|
import { studentLogin as j } from "../common/api.js";
|
|
10
11
|
import { useDb as S } from "../common/base-login.js";
|
|
11
12
|
import { contestConverter as M, studentConverter as P, participationConverter as R } from "../common/converters.js";
|
|
12
|
-
import { useWebsite as
|
|
13
|
-
import { useAuth as
|
|
14
|
-
import { useCollection as
|
|
15
|
-
import { useDocument as
|
|
16
|
-
import { StudentRestoring as
|
|
17
|
-
import { FirebaseStatement as
|
|
18
|
-
import
|
|
19
|
-
function
|
|
20
|
-
const e =
|
|
21
|
-
constraints: { id:
|
|
22
|
-
subscribe: !0
|
|
13
|
+
import { useWebsite as q } from "../common/website.js";
|
|
14
|
+
import { useAuth as z } from "../hooks/auth.js";
|
|
15
|
+
import { useCollection as B } from "../hooks/collection.js";
|
|
16
|
+
import { useDocument as b } from "../hooks/document.js";
|
|
17
|
+
import { StudentRestoring as O } from "./student-restoring.js";
|
|
18
|
+
import { FirebaseStatement as G } from "./student-statement.js";
|
|
19
|
+
import L from "virtual:quizms-firebase-header";
|
|
20
|
+
function lt() {
|
|
21
|
+
const e = z("student"), s = q(), [o] = B("contests", M, {
|
|
22
|
+
constraints: { id: s.contests }
|
|
23
23
|
});
|
|
24
|
-
return e ? /* @__PURE__ */ t(
|
|
24
|
+
return e ? /* @__PURE__ */ t(O, { user: e.user, children: /* @__PURE__ */ t(
|
|
25
25
|
V,
|
|
26
26
|
{
|
|
27
|
-
contests:
|
|
27
|
+
contests: o,
|
|
28
28
|
participationId: e.claims.participationId,
|
|
29
29
|
studentId: e.claims.studentId
|
|
30
30
|
}
|
|
31
|
-
) }) : /* @__PURE__ */ t(
|
|
31
|
+
) }) : /* @__PURE__ */ t(U, { contests: o });
|
|
32
32
|
}
|
|
33
|
-
function
|
|
34
|
-
const
|
|
35
|
-
async ({ contestId:
|
|
36
|
-
const
|
|
37
|
-
contestId:
|
|
38
|
-
token:
|
|
39
|
-
userData:
|
|
40
|
-
...i,
|
|
41
|
-
birthDate: i.birthDate ? new Date(i.birthDate) : void 0
|
|
42
|
-
},
|
|
33
|
+
function U({ contests: e }) {
|
|
34
|
+
const s = S(), o = k(), d = p(
|
|
35
|
+
async ({ contestId: r, token: a, ...n }) => {
|
|
36
|
+
const l = await j({
|
|
37
|
+
contestId: r,
|
|
38
|
+
token: a,
|
|
39
|
+
userData: n,
|
|
43
40
|
extraData: {
|
|
44
|
-
userAgent:
|
|
41
|
+
userAgent: o,
|
|
45
42
|
windowWidth: window.innerWidth,
|
|
46
43
|
windowHeight: window.innerHeight,
|
|
47
44
|
screenWidth: window.screen.availWidth,
|
|
@@ -49,36 +46,36 @@ function L({ contests: e }) {
|
|
|
49
46
|
pixelRatio: window.devicePixelRatio,
|
|
50
47
|
darkMode: window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
51
48
|
}
|
|
52
|
-
}),
|
|
53
|
-
await
|
|
49
|
+
}), c = g(s.app);
|
|
50
|
+
await D(c, l), o.hasFullscreen && await document.documentElement.requestFullscreen?.();
|
|
54
51
|
},
|
|
55
|
-
[o]
|
|
56
|
-
),
|
|
52
|
+
[s, o]
|
|
53
|
+
), i = w(
|
|
57
54
|
() => ({
|
|
58
55
|
contestId: e.length === 1 ? e[0].id : void 0
|
|
59
56
|
}),
|
|
60
57
|
[e]
|
|
61
58
|
);
|
|
62
|
-
return /* @__PURE__ */ u(
|
|
63
|
-
/* @__PURE__ */ t(
|
|
64
|
-
/* @__PURE__ */ u(
|
|
59
|
+
return /* @__PURE__ */ u(f, { children: [
|
|
60
|
+
/* @__PURE__ */ t(A, { color: "bg-base-300 text-base-content", children: /* @__PURE__ */ t(C, { children: /* @__PURE__ */ t("div", { className: "flex items-center h-full font-bold", children: /* @__PURE__ */ t(F, {}) }) }) }),
|
|
61
|
+
/* @__PURE__ */ u(W, { defaultValue: i, onSubmit: d, className: "p-4 pb-8", children: [
|
|
65
62
|
/* @__PURE__ */ t("h1", { className: "mb-2 text-xl font-bold", children: "Accedi alla gara" }),
|
|
66
63
|
/* @__PURE__ */ t(
|
|
67
|
-
|
|
64
|
+
y,
|
|
68
65
|
{
|
|
69
66
|
field: "contestId",
|
|
70
67
|
label: "Gara",
|
|
71
|
-
options: Object.fromEntries(e.map((
|
|
68
|
+
options: Object.fromEntries(e.map((r) => [r.id, r.name])),
|
|
72
69
|
placeholder: "Seleziona una gara"
|
|
73
70
|
}
|
|
74
71
|
),
|
|
75
|
-
({ contestId:
|
|
76
|
-
const
|
|
77
|
-
if (
|
|
78
|
-
return /* @__PURE__ */ u(
|
|
79
|
-
|
|
80
|
-
/* @__PURE__ */ t(
|
|
81
|
-
/* @__PURE__ */ t(
|
|
72
|
+
({ contestId: r }) => {
|
|
73
|
+
const a = e.find((n) => n.id === r);
|
|
74
|
+
if (a)
|
|
75
|
+
return /* @__PURE__ */ u(f, { children: [
|
|
76
|
+
a.userData.map((n) => /* @__PURE__ */ t(x, { field: n }, n.name)),
|
|
77
|
+
/* @__PURE__ */ t(E, { field: "token", label: "Codice prova", placeholder: "aaaaa-bbbbb-ccccc" }),
|
|
78
|
+
/* @__PURE__ */ t(H, { children: "Inizia la prova" })
|
|
82
79
|
] });
|
|
83
80
|
}
|
|
84
81
|
] })
|
|
@@ -86,46 +83,43 @@ function L({ contests: e }) {
|
|
|
86
83
|
}
|
|
87
84
|
function V({
|
|
88
85
|
contests: e,
|
|
89
|
-
participationId:
|
|
90
|
-
studentId:
|
|
86
|
+
participationId: s,
|
|
87
|
+
studentId: o
|
|
91
88
|
}) {
|
|
92
|
-
const
|
|
93
|
-
`participations/${
|
|
94
|
-
|
|
95
|
-
P
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}, [r]), l = p(async () => {
|
|
105
|
-
await f(r), await E(g(r.app)), window.location.reload();
|
|
106
|
-
}, [r]);
|
|
89
|
+
const d = S(), [i, r] = b(
|
|
90
|
+
`participations/${s}/students`,
|
|
91
|
+
o,
|
|
92
|
+
P
|
|
93
|
+
), [a] = b("participations", s, R), n = w(
|
|
94
|
+
() => e.find((m) => m.id === i.contestId),
|
|
95
|
+
[e, i.contestId]
|
|
96
|
+
), l = p(async () => {
|
|
97
|
+
await h(d);
|
|
98
|
+
}, [d]), c = p(async () => {
|
|
99
|
+
await h(d), await N(g(d.app)), window.location.reload();
|
|
100
|
+
}, [d]);
|
|
107
101
|
return v(() => {
|
|
108
|
-
|
|
109
|
-
}, [
|
|
102
|
+
a.token !== i.token && c();
|
|
103
|
+
}, [a.token, i.token, c]), /* @__PURE__ */ u(
|
|
110
104
|
I,
|
|
111
105
|
{
|
|
112
|
-
contest:
|
|
113
|
-
participation:
|
|
114
|
-
student:
|
|
115
|
-
setStudent: async (
|
|
116
|
-
|
|
106
|
+
contest: n,
|
|
107
|
+
participation: a,
|
|
108
|
+
student: i,
|
|
109
|
+
setStudent: async (m) => {
|
|
110
|
+
T(i, m) || await r({ ...m });
|
|
117
111
|
},
|
|
118
|
-
logout:
|
|
119
|
-
onSubmit:
|
|
112
|
+
logout: c,
|
|
113
|
+
onSubmit: l,
|
|
120
114
|
enforceFullscreen: !0,
|
|
121
115
|
children: [
|
|
122
|
-
/* @__PURE__ */ t(
|
|
123
|
-
/* @__PURE__ */ t(
|
|
116
|
+
/* @__PURE__ */ t(L, { contestId: n.id }),
|
|
117
|
+
/* @__PURE__ */ t(G, {})
|
|
124
118
|
]
|
|
125
119
|
}
|
|
126
120
|
);
|
|
127
121
|
}
|
|
128
122
|
export {
|
|
129
|
-
|
|
123
|
+
lt as default
|
|
130
124
|
};
|
|
131
125
|
//# 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 {\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\";\nimport { isEqual } from \"lodash-es\";\n\nimport { studentLogin } from \"~/web/common/api\";\nimport { useDb } from \"~/web/common/base-login\";\nimport {\n contestConverter,\n participationConverter,\n studentConverter,\n} 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
|
|
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\";\nimport { isEqual } from \"lodash-es\";\n\nimport { studentLogin } from \"~/web/common/api\";\nimport { useDb } from \"~/web/common/base-login\";\nimport {\n contestConverter,\n participationConverter,\n studentConverter,\n} 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 participationId={auth.claims.participationId}\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 participationId,\n studentId,\n}: {\n contests: Contest[];\n participationId: string;\n studentId: string;\n}) {\n const db = useDb();\n\n const [student, setStudent] = useDocument(\n `participations/${participationId}/students`,\n studentId,\n studentConverter,\n );\n const [participation] = useDocument(\"participations\", participationId, participationConverter);\n\n const contest = useMemo(\n () => contests.find((c) => c.id === student.contestId)!,\n [contests, student.contestId],\n );\n\n const onSubmit = useCallback(async () => {\n await waitForPendingWrites(db);\n }, [db]);\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 (participation.token !== student.token) {\n void logout();\n }\n }, [participation.token, student.token, logout]);\n\n const setStudentAndSubmission = async (newStudent: Student) => {\n if (!isEqual(student, newStudent)) {\n await setStudent({ ...newStudent });\n }\n };\n\n return (\n <StudentProvider\n contest={contest}\n participation={participation}\n student={student}\n setStudent={setStudentAndSubmission}\n logout={logout}\n onSubmit={onSubmit}\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","participationId","studentId","student","setStudent","useDocument","studentConverter","participation","participationConverter","onSubmit","waitForPendingWrites","logout","signOut","useEffect","StudentProvider","newStudent","isEqual","Header","FirebaseStatement"],"mappings":";;;;;;;;;;;;;;;;;;;AAiCA,SAAwBA,KAAe;AACrC,QAAMC,IAAOC,EAAQ,SAAS,GAExBC,IAAUC,EAAA,GACV,CAACC,CAAQ,IAAIC,EAAc,YAAYC,GAAkB;AAAA,IAC7D,aAAa,EAAE,IAAIJ,EAAQ,SAAA;AAAA,EAAS,CACrC;AAED,SAAIF,IAEA,gBAAAO,EAACC,GAAA,EAAiB,MAAMR,EAAK,MAC3B,UAAA,gBAAAO;AAAA,IAACE;AAAA,IAAA;AAAA,MACC,UAAAL;AAAA,MACA,iBAAiBJ,EAAK,OAAO;AAAA,MAC7B,WAAWA,EAAK,OAAO;AAAA,IAAA;AAAA,EAAA,GAE3B,IAIG,gBAAAO,EAACG,KAAY,UAAAN,GAAoB;AAC1C;AAOA,SAASM,EAAY,EAAE,UAAAN,KAAqC;AAC1D,QAAMO,IAAKC,EAAA,GACLC,IAAKC,EAAA,GAELC,IAASC;AAAA,IACb,OAAO,EAAE,WAAAC,GAAW,OAAAC,GAAO,GAAGC,QAA4B;AACxD,YAAMC,IAAY,MAAMC,EAAa;AAAA,QACnC,WAAAJ;AAAA,QACA,OAAAC;AAAA,QACA,UAAAC;AAAA,QACA,WAAW;AAAA,UACT,WAAWN;AAAA,UACX,aAAa,OAAO;AAAA,UACpB,cAAc,OAAO;AAAA,UACrB,aAAa,OAAO,OAAO;AAAA,UAC3B,cAAc,OAAO,OAAO;AAAA,UAC5B,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO,WAAW,8BAA8B,EAAE;AAAA,QAAA;AAAA,MAC9D,CACD,GAEKb,IAAOsB,EAAQX,EAAG,GAAG;AAC3B,YAAMY,EAAsBvB,GAAMoB,CAAS,GACvCP,EAAG,iBACL,MAAM,SAAS,gBAAgB,oBAAA;AAAA,IAEnC;AAAA,IACA,CAACF,GAAIE,CAAE;AAAA,EAAA,GAGHW,IAAeC;AAAA,IACnB,OAAO;AAAA,MACL,WAAWrB,EAAS,WAAW,IAAIA,EAAS,CAAC,EAAE,KAAK;AAAA,IAAA;AAAA,IAEtD,CAACA,CAAQ;AAAA,EAAA;AAGX,SACE,gBAAAsB,EAAAC,GAAA,EACE,UAAA;AAAA,IAAA,gBAAApB,EAACqB,GAAA,EAAO,OAAM,iCACZ,UAAA,gBAAArB,EAACsB,GAAA,EACC,UAAA,gBAAAtB,EAAC,OAAA,EAAI,WAAU,sCACb,UAAA,gBAAAA,EAACuB,GAAA,EAAM,EAAA,CACT,GACF,GACF;AAAA,sBACCC,GAAA,EAAK,cAAAP,GAA4B,UAAUT,GAAQ,WAAU,YAC5D,UAAA;AAAA,MAAA,gBAAAR,EAAC,MAAA,EAAG,WAAU,0BAAyB,UAAA,oBAAgB;AAAA,MACvD,gBAAAA;AAAA,QAACyB;AAAA,QAAA;AAAA,UACC,OAAM;AAAA,UACN,OAAM;AAAA,UACN,SAAS,OAAO,YAAY5B,EAAS,IAAI,CAAC6B,MAAM,CAACA,EAAE,IAAIA,EAAE,IAAI,CAAC,CAAC;AAAA,UAC/D,aAAY;AAAA,QAAA;AAAA,MAAA;AAAA,MAEb,CAAC,EAAE,WAAAhB,EAAA,MAAgB;AAClB,cAAMiB,IAAU9B,EAAS,KAAK,CAAC6B,MAAMA,EAAE,OAAOhB,CAAS;AACvD,YAAKiB;AACL,iBACE,gBAAAR,EAAAC,GAAA,EACG,UAAA;AAAA,YAAAO,EAAQ,SAAS,IAAI,CAACC,wBACpBC,GAAA,EAAkC,OAAAD,EAAA,GAAZA,EAAM,IAAoB,CAClD;AAAA,8BACAE,GAAA,EAAU,OAAM,SAAQ,OAAM,gBAAe,aAAY,qBAAoB;AAAA,YAC9E,gBAAA9B,EAAC+B,KAAa,UAAA,kBAAA,CAAe;AAAA,UAAA,GAC/B;AAAA,MAEJ;AAAA,IAAA,EAAA,CACF;AAAA,EAAA,GACF;AAEJ;AAEA,SAAS7B,EAAa;AAAA,EACpB,UAAAL;AAAA,EACA,iBAAAmC;AAAA,EACA,WAAAC;AACF,GAIG;AACD,QAAM7B,IAAKC,EAAA,GAEL,CAAC6B,GAASC,CAAU,IAAIC;AAAA,IAC5B,kBAAkBJ,CAAe;AAAA,IACjCC;AAAA,IACAI;AAAA,EAAA,GAEI,CAACC,CAAa,IAAIF,EAAY,kBAAkBJ,GAAiBO,CAAsB,GAEvFZ,IAAUT;AAAA,IACd,MAAMrB,EAAS,KAAK,CAAC6B,MAAMA,EAAE,OAAOQ,EAAQ,SAAS;AAAA,IACrD,CAACrC,GAAUqC,EAAQ,SAAS;AAAA,EAAA,GAGxBM,IAAW/B,EAAY,YAAY;AACvC,UAAMgC,EAAqBrC,CAAE;AAAA,EAC/B,GAAG,CAACA,CAAE,CAAC,GAEDsC,IAASjC,EAAY,YAAY;AACrC,UAAMgC,EAAqBrC,CAAE,GAC7B,MAAMuC,EAAQ5B,EAAQX,EAAG,GAAG,CAAC,GAC7B,OAAO,SAAS,OAAA;AAAA,EAClB,GAAG,CAACA,CAAE,CAAC;AAEP,SAAAwC,EAAU,MAAM;AACd,IAAIN,EAAc,UAAUJ,EAAQ,SAC7BQ,EAAA;AAAA,EAET,GAAG,CAACJ,EAAc,OAAOJ,EAAQ,OAAOQ,CAAM,CAAC,GAS7C,gBAAAvB;AAAA,IAAC0B;AAAA,IAAA;AAAA,MACC,SAAAlB;AAAA,MACA,eAAAW;AAAA,MACA,SAAAJ;AAAA,MACA,YAX4B,OAAOY,MAAwB;AAC7D,QAAKC,EAAQb,GAASY,CAAU,KAC9B,MAAMX,EAAW,EAAE,GAAGW,GAAY;AAAA,MAEtC;AAAA,MAQI,QAAAJ;AAAA,MACA,UAAAF;AAAA,MACA,mBAAmB;AAAA,MACnB,UAAA;AAAA,QAAA,gBAAAxC,EAACgD,GAAA,EAAO,WAAWrB,EAAQ,GAAA,CAAI;AAAA,0BAC9BsB,GAAA,CAAA,CAAkB;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGzB;"}
|
|
@@ -1,88 +1,88 @@
|
|
|
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 { finalizeParticipation as
|
|
8
|
-
import { useDb as
|
|
9
|
-
import { contestConverter as
|
|
10
|
-
import
|
|
11
|
-
import { useWebsite as
|
|
1
|
+
import { jsx as d } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback as g } from "react";
|
|
3
|
+
import { TeacherProvider as h } from "@olinfo/quizms/teacher";
|
|
4
|
+
import { signOut as w, getAuth as y } from "firebase/auth";
|
|
5
|
+
import { writeBatch as f, doc as u, serverTimestamp as b } from "firebase/firestore";
|
|
6
|
+
import { getStorage as C, getBytes as P, ref as R } from "firebase/storage";
|
|
7
|
+
import { finalizeParticipation as A, stopParticipation as I, startParticipation as S } from "../common/api.js";
|
|
8
|
+
import { useDb as l } from "../common/base-login.js";
|
|
9
|
+
import { contestConverter as k, participationConverter as v, studentRestoreConvert as B, studentConverter as T, announcementConverter as $, variantConverter as j } from "../common/converters.js";
|
|
10
|
+
import x from "../common/token-login.js";
|
|
11
|
+
import { useWebsite as z } from "../common/website.js";
|
|
12
12
|
import "lodash-es";
|
|
13
13
|
import "react-error-boundary";
|
|
14
14
|
import "swr";
|
|
15
15
|
import { useCollection as c } from "../hooks/collection.js";
|
|
16
|
-
import { useDocument as
|
|
17
|
-
import { FirebaseStatement as
|
|
16
|
+
import { useDocument as D } from "../hooks/document.js";
|
|
17
|
+
import { FirebaseStatement as E } from "./student-statement.js";
|
|
18
18
|
function rt() {
|
|
19
|
-
return /* @__PURE__ */
|
|
19
|
+
return /* @__PURE__ */ d(x, { allowedRole: "teacher", children: ({ user: t, claims: e }) => /* @__PURE__ */ d(O, { user: t, schoolId: e.schoolId }) });
|
|
20
20
|
}
|
|
21
|
-
function
|
|
22
|
-
const
|
|
23
|
-
constraints: { id:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return /* @__PURE__ */ u(
|
|
32
|
-
g,
|
|
21
|
+
function O({ user: t, schoolId: e }) {
|
|
22
|
+
const r = l(), s = z(), [a] = c("contests", k, {
|
|
23
|
+
constraints: { id: s.contests }
|
|
24
|
+
}), [m] = c("participations", v, {
|
|
25
|
+
constraints: { contestId: s.contests, schoolId: e }
|
|
26
|
+
}), [n] = c("variants", j), i = g(async () => {
|
|
27
|
+
await w(y(r.app)), window.location.reload();
|
|
28
|
+
}, [r]);
|
|
29
|
+
return /* @__PURE__ */ d(
|
|
30
|
+
h,
|
|
33
31
|
{
|
|
34
|
-
participations:
|
|
35
|
-
contests:
|
|
36
|
-
startParticipation: (...
|
|
37
|
-
stopParticipation: (...
|
|
38
|
-
finalizeParticipation: (...
|
|
39
|
-
variants:
|
|
40
|
-
logout:
|
|
41
|
-
statementComponent: () => /* @__PURE__ */
|
|
42
|
-
getPdfStatements: (
|
|
43
|
-
useAnnouncements:
|
|
44
|
-
useStudents:
|
|
45
|
-
useStudentRestores:
|
|
32
|
+
participations: m,
|
|
33
|
+
contests: a,
|
|
34
|
+
startParticipation: (...o) => S(t, ...o),
|
|
35
|
+
stopParticipation: (...o) => I(t, ...o),
|
|
36
|
+
finalizeParticipation: (...o) => A(t, ...o),
|
|
37
|
+
variants: n,
|
|
38
|
+
logout: i,
|
|
39
|
+
statementComponent: () => /* @__PURE__ */ d(E, {}),
|
|
40
|
+
getPdfStatements: (o, p) => F(r, o, p),
|
|
41
|
+
useAnnouncements: L,
|
|
42
|
+
useStudents: W,
|
|
43
|
+
useStudentRestores: G
|
|
46
44
|
}
|
|
47
45
|
);
|
|
48
46
|
}
|
|
49
|
-
async function
|
|
50
|
-
const s =
|
|
51
|
-
|
|
52
|
-
async (
|
|
47
|
+
async function F(t, e, r) {
|
|
48
|
+
const s = C(t.app), a = await Promise.all(
|
|
49
|
+
r.map(
|
|
50
|
+
async (m) => [m, await P(R(s, `statements/${e}/${m}/statement.pdf`))]
|
|
53
51
|
)
|
|
54
52
|
);
|
|
55
|
-
return Object.fromEntries(
|
|
53
|
+
return Object.fromEntries(a);
|
|
56
54
|
}
|
|
57
|
-
function
|
|
58
|
-
|
|
55
|
+
function L(t) {
|
|
56
|
+
const [e] = c("announcements", $, {
|
|
57
|
+
arrayConstraints: {
|
|
58
|
+
contestIds: t
|
|
59
|
+
},
|
|
60
|
+
orderBy: ["createdAt", "desc"]
|
|
61
|
+
});
|
|
62
|
+
return e;
|
|
59
63
|
}
|
|
60
|
-
function
|
|
61
|
-
return c(`participations/${
|
|
62
|
-
orderBy: "createdAt"
|
|
63
|
-
subscribe: !0
|
|
64
|
+
function W(t) {
|
|
65
|
+
return c(`participations/${t}/students`, T, {
|
|
66
|
+
orderBy: "createdAt"
|
|
64
67
|
});
|
|
65
68
|
}
|
|
66
|
-
function
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
for (const m of s)
|
|
76
|
-
m.studentId === r && m.id !== e && p.update(d(t, "studentRestores", m.id), { status: "revoked" });
|
|
77
|
-
await p.commit();
|
|
69
|
+
function G(t) {
|
|
70
|
+
const e = l(), [r] = D("participations", t, v), [s] = c("studentRestores", B, {
|
|
71
|
+
constraints: { participationId: t, token: r.token, status: "pending" },
|
|
72
|
+
orderBy: "createdAt"
|
|
73
|
+
}), a = async (n, i) => {
|
|
74
|
+
const o = f(e);
|
|
75
|
+
for (const p of s)
|
|
76
|
+
p.studentId === n && p.id !== i && o.update(u(e, "studentRestores", p.id), { status: "revoked" });
|
|
77
|
+
await o.commit();
|
|
78
78
|
};
|
|
79
|
-
return [s, async (
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
uid:
|
|
83
|
-
updatedAt:
|
|
84
|
-
}),
|
|
85
|
-
},
|
|
79
|
+
return [s, async (n) => {
|
|
80
|
+
const i = f(e);
|
|
81
|
+
i.update(u(e, `/participations/${t}/students`, n.studentId), {
|
|
82
|
+
uid: n.id,
|
|
83
|
+
updatedAt: b()
|
|
84
|
+
}), i.delete(u(e, "studentRestores", n.id)), await i.commit(), await a(n.studentId, n.id);
|
|
85
|
+
}, a];
|
|
86
86
|
}
|
|
87
87
|
export {
|
|
88
88
|
rt as default
|
|
@@ -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 } from \"firebase/auth\";\nimport { doc, type Firestore, serverTimestamp, writeBatch } from \"firebase/firestore\";\nimport { getBytes, getStorage, ref } from \"firebase/storage\";\n\nimport { finalizeParticipation, startParticipation, stopParticipation } from \"~/web/common/api\";\nimport { useDb } from \"~/web/common/base-login\";\nimport {\n contestConverter,\n participationConverter,\n studentConverter,\n studentRestoreConvert,\n variantConverter,\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 {({ claims }) => <TeacherInner schoolId={claims.schoolId} />}\n </TokenLogin>\n );\n}\n\nfunction TeacherInner({ schoolId }: { schoolId: string }) {\n const db = useDb();\n\n const website = useWebsite();\n const [contests] = useCollection(\"contests\", contestConverter, {\n constraints: { id: website.contests },\n
|
|
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 { finalizeParticipation, startParticipation, stopParticipation } from \"~/web/common/api\";\nimport { useDb } from \"~/web/common/base-login\";\nimport {\n announcementConverter,\n contestConverter,\n participationConverter,\n studentConverter,\n studentRestoreConvert,\n variantConverter,\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 [participations] = useCollection(\"participations\", participationConverter, {\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 participations={participations}\n contests={contests}\n startParticipation={(...args) => startParticipation(user, ...args)}\n stopParticipation={(...args) => stopParticipation(user, ...args)}\n finalizeParticipation={(...args) => finalizeParticipation(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(participationId: string) {\n return useCollection(`participations/${participationId}/students`, studentConverter, {\n orderBy: \"createdAt\",\n });\n}\n\nfunction useStudentRestores(\n participationId: string,\n): readonly [\n StudentRestore[],\n (request: StudentRestore) => Promise<void>,\n (studentId: string) => Promise<void>,\n] {\n const db = useDb();\n\n const [participation] = useDocument(\"participations\", participationId, participationConverter);\n\n const [studentRestores] = useCollection(\"studentRestores\", studentRestoreConvert, {\n constraints: { participationId, token: participation.token, 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, `/participations/${participationId}/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","participations","participationConverter","variants","variantConverter","logout","useCallback","signOut","getAuth","TeacherProvider","args","startParticipation","stopParticipation","finalizeParticipation","FirebaseStatement","contestId","variantIds","getPdfStatements","useAnnouncements","useStudents","useStudentRestores","storage","getStorage","files","id","getBytes","ref","announcements","announcementConverter","participationId","studentConverter","participation","useDocument","studentRestores","studentRestoreConvert","reject","studentId","excludeRestoreId","batch","writeBatch","studentRestore","doc","request","serverTimestamp"],"mappings":"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"}
|
|
@@ -11,56 +11,55 @@ const d = {
|
|
|
11
11
|
rollbackOnError: !0,
|
|
12
12
|
populateCache: !0
|
|
13
13
|
};
|
|
14
|
-
function j(
|
|
15
|
-
const e = E(), { showBoundary:
|
|
16
|
-
revalidateIfStale: !
|
|
17
|
-
revalidateOnFocus: !
|
|
18
|
-
revalidateOnMount: !
|
|
19
|
-
revalidateOnReconnect: !
|
|
14
|
+
function j(a, t, r) {
|
|
15
|
+
const e = E(), { showBoundary: s } = R(), i = g(e, a).withConverter(t), m = $(e, a, t, r), p = {
|
|
16
|
+
revalidateIfStale: !1,
|
|
17
|
+
revalidateOnFocus: !1,
|
|
18
|
+
revalidateOnMount: !1,
|
|
19
|
+
revalidateOnReconnect: !1,
|
|
20
20
|
suspense: !0
|
|
21
|
-
}, f = `${
|
|
22
|
-
(
|
|
23
|
-
[
|
|
21
|
+
}, f = `${a}?${JSON.stringify(r)}`, { data: y, mutate: n } = q(f, () => D(m), p), b = C(
|
|
22
|
+
(o) => x(i, o, n, r),
|
|
23
|
+
[i, n, r]
|
|
24
24
|
);
|
|
25
25
|
return w(
|
|
26
26
|
f,
|
|
27
|
-
(
|
|
28
|
-
|
|
29
|
-
const p = B(
|
|
27
|
+
(o) => {
|
|
28
|
+
const h = B(
|
|
30
29
|
m,
|
|
31
|
-
(
|
|
30
|
+
(c) => {
|
|
32
31
|
try {
|
|
33
|
-
|
|
34
|
-
} catch (
|
|
35
|
-
|
|
32
|
+
o(c.docs.map((u) => u.data()));
|
|
33
|
+
} catch (u) {
|
|
34
|
+
s(u);
|
|
36
35
|
}
|
|
37
36
|
},
|
|
38
|
-
(
|
|
37
|
+
(c) => s(c)
|
|
39
38
|
);
|
|
40
|
-
return () =>
|
|
39
|
+
return () => h();
|
|
41
40
|
},
|
|
42
|
-
(
|
|
43
|
-
), [y,
|
|
41
|
+
(o) => n(o, d)
|
|
42
|
+
), [y, b];
|
|
44
43
|
}
|
|
45
|
-
async function x(
|
|
44
|
+
async function x(a, t, r, e) {
|
|
46
45
|
await r(
|
|
47
|
-
async (
|
|
48
|
-
const
|
|
49
|
-
return await S(
|
|
46
|
+
async (s) => {
|
|
47
|
+
const i = O(a, t.id);
|
|
48
|
+
return await S(i, t), l(s, t, e);
|
|
50
49
|
},
|
|
51
50
|
{
|
|
52
51
|
...d,
|
|
53
|
-
optimisticData: (
|
|
52
|
+
optimisticData: (s) => l(s, t, e)
|
|
54
53
|
}
|
|
55
54
|
);
|
|
56
55
|
}
|
|
57
|
-
function l(
|
|
58
|
-
if (!
|
|
59
|
-
let e =
|
|
56
|
+
function l(a, t, r) {
|
|
57
|
+
if (!a) return [t];
|
|
58
|
+
let e = a.filter((s) => t.id !== s.id);
|
|
60
59
|
return e.push(t), e = k(e, [r?.orderBy ?? "id"]), r?.limit && (e = e.slice(0, r.limit)), e;
|
|
61
60
|
}
|
|
62
|
-
async function D(
|
|
63
|
-
return (await v(
|
|
61
|
+
async function D(a) {
|
|
62
|
+
return (await v(a)).docs.map((r) => r.data({ serverTimestamps: "estimate" }));
|
|
64
63
|
}
|
|
65
64
|
export {
|
|
66
65
|
j as useCollection
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collection.js","sources":["../../../../src/web/hooks/collection.ts"],"sourcesContent":["import { useCallback } from \"react\";\n\nimport {\n type CollectionReference,\n collection,\n doc,\n type FirestoreDataConverter,\n getDocs,\n onSnapshot,\n type Query,\n setDoc,\n} from \"firebase/firestore\";\nimport { sortBy } from \"lodash-es\";\nimport { useErrorBoundary } from \"react-error-boundary\";\nimport useSWR, { type KeyedMutator, type MutatorOptions, type SWRConfiguration } from \"swr\";\n\nimport { useDb } from \"~/web/common/base-login\";\nimport query, { type QueryOption } from \"~/web/common/query\";\n\nimport { useSubscriptionListener } from \"./subscription\";\n\nconst mutationConfig: MutatorOptions = {\n revalidate: false,\n rollbackOnError: true,\n populateCache: true,\n};\n\
|
|
1
|
+
{"version":3,"file":"collection.js","sources":["../../../../src/web/hooks/collection.ts"],"sourcesContent":["import { useCallback } from \"react\";\n\nimport {\n type CollectionReference,\n collection,\n doc,\n type FirestoreDataConverter,\n getDocs,\n onSnapshot,\n type Query,\n setDoc,\n} from \"firebase/firestore\";\nimport { sortBy } from \"lodash-es\";\nimport { useErrorBoundary } from \"react-error-boundary\";\nimport useSWR, { type KeyedMutator, type MutatorOptions, type SWRConfiguration } from \"swr\";\n\nimport { useDb } from \"~/web/common/base-login\";\nimport query, { type QueryOption } from \"~/web/common/query\";\n\nimport { useSubscriptionListener } from \"./subscription\";\n\nconst mutationConfig: MutatorOptions = {\n revalidate: false,\n rollbackOnError: true,\n populateCache: true,\n};\n\nexport function useCollection<T extends { id: string }>(\n path: string,\n converter: FirestoreDataConverter<T>,\n options?: QueryOption<T>,\n) {\n const db = useDb();\n const { showBoundary } = useErrorBoundary();\n\n const ref = collection(db, path).withConverter(converter);\n const q = query(db, path, converter, options);\n\n const swrConfig: SWRConfiguration = {\n revalidateIfStale: false,\n revalidateOnFocus: false,\n revalidateOnMount: false,\n revalidateOnReconnect: false,\n suspense: true,\n };\n\n const key = `${path}?${JSON.stringify(options)}`;\n const { data, mutate } = useSWR<T[]>(key, () => fetcher(q), swrConfig);\n\n const setData = useCallback(\n (newDoc: T) => setDocument(ref, newDoc, mutate, options),\n [ref, mutate, options],\n );\n\n useSubscriptionListener<T[]>(\n key,\n (setData) => {\n const unsubscribe = onSnapshot(\n q,\n (snap) => {\n try {\n setData(snap.docs.map((doc) => doc.data()));\n } catch (err) {\n showBoundary(err);\n }\n },\n (error) => showBoundary(error),\n );\n return () => unsubscribe();\n },\n (data) => mutate(data, mutationConfig),\n );\n\n return [data as T[], setData] as const;\n}\n\nasync function setDocument<T extends { id: string }>(\n ref: CollectionReference<T>,\n newDoc: T,\n mutator: KeyedMutator<T[]>,\n options?: QueryOption<T>,\n): Promise<void> {\n await mutator(\n async (prev) => {\n const docRef = doc(ref, newDoc.id);\n await setDoc(docRef, newDoc);\n return merge(prev, newDoc, options);\n },\n {\n ...mutationConfig,\n optimisticData: (prev) => merge(prev, newDoc, options),\n },\n );\n}\n\nfunction merge<T extends { id: string }>(\n prev: T[] | undefined,\n newDoc: T,\n options?: QueryOption<T>,\n) {\n if (!prev) return [newDoc];\n let coll = prev.filter((doc) => newDoc.id !== doc.id);\n coll.push(newDoc);\n coll = sortBy(coll, [options?.orderBy ?? \"id\"]);\n if (options?.limit) coll = coll.slice(0, options.limit);\n return coll;\n}\n\nasync function fetcher<T>(ref: Query<T>) {\n const snapshot = await getDocs(ref);\n return snapshot.docs.map((doc) => doc.data({ serverTimestamps: \"estimate\" }));\n}\n"],"names":["mutationConfig","useCollection","path","converter","options","db","useDb","showBoundary","useErrorBoundary","ref","collection","q","query","swrConfig","key","data","mutate","useSWR","fetcher","setData","useCallback","newDoc","setDocument","useSubscriptionListener","unsubscribe","onSnapshot","snap","doc","err","error","mutator","prev","docRef","setDoc","merge","coll","sortBy","getDocs"],"mappings":";;;;;;;;AAqBA,MAAMA,IAAiC;AAAA,EACrC,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,eAAe;AACjB;AAEO,SAASC,EACdC,GACAC,GACAC,GACA;AACA,QAAMC,IAAKC,EAAA,GACL,EAAE,cAAAC,EAAA,IAAiBC,EAAA,GAEnBC,IAAMC,EAAWL,GAAIH,CAAI,EAAE,cAAcC,CAAS,GAClDQ,IAAIC,EAAMP,GAAIH,GAAMC,GAAWC,CAAO,GAEtCS,IAA8B;AAAA,IAClC,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,uBAAuB;AAAA,IACvB,UAAU;AAAA,EAAA,GAGNC,IAAM,GAAGZ,CAAI,IAAI,KAAK,UAAUE,CAAO,CAAC,IACxC,EAAE,MAAAW,GAAM,QAAAC,EAAA,IAAWC,EAAYH,GAAK,MAAMI,EAAQP,CAAC,GAAGE,CAAS,GAE/DM,IAAUC;AAAA,IACd,CAACC,MAAcC,EAAYb,GAAKY,GAAQL,GAAQZ,CAAO;AAAA,IACvD,CAACK,GAAKO,GAAQZ,CAAO;AAAA,EAAA;AAGvB,SAAAmB;AAAA,IACET;AAAA,IACA,CAACK,MAAY;AACX,YAAMK,IAAcC;AAAA,QAClBd;AAAA,QACA,CAACe,MAAS;AACR,cAAI;AACFP,YAAAA,EAAQO,EAAK,KAAK,IAAI,CAACC,MAAQA,EAAI,KAAA,CAAM,CAAC;AAAA,UAC5C,SAASC,GAAK;AACZ,YAAArB,EAAaqB,CAAG;AAAA,UAClB;AAAA,QACF;AAAA,QACA,CAACC,MAAUtB,EAAasB,CAAK;AAAA,MAAA;AAE/B,aAAO,MAAML,EAAA;AAAA,IACf;AAAA,IACA,CAACT,MAASC,EAAOD,GAAMf,CAAc;AAAA,EAAA,GAGhC,CAACe,GAAaI,CAAO;AAC9B;AAEA,eAAeG,EACbb,GACAY,GACAS,GACA1B,GACe;AACf,QAAM0B;AAAA,IACJ,OAAOC,MAAS;AACd,YAAMC,IAASL,EAAIlB,GAAKY,EAAO,EAAE;AACjC,mBAAMY,EAAOD,GAAQX,CAAM,GACpBa,EAAMH,GAAMV,GAAQjB,CAAO;AAAA,IACpC;AAAA,IACA;AAAA,MACE,GAAGJ;AAAA,MACH,gBAAgB,CAAC+B,MAASG,EAAMH,GAAMV,GAAQjB,CAAO;AAAA,IAAA;AAAA,EACvD;AAEJ;AAEA,SAAS8B,EACPH,GACAV,GACAjB,GACA;AACA,MAAI,CAAC2B,EAAM,QAAO,CAACV,CAAM;AACzB,MAAIc,IAAOJ,EAAK,OAAO,CAACJ,MAAQN,EAAO,OAAOM,EAAI,EAAE;AACpD,SAAAQ,EAAK,KAAKd,CAAM,GAChBc,IAAOC,EAAOD,GAAM,CAAC/B,GAAS,WAAW,IAAI,CAAC,GAC1CA,GAAS,UAAO+B,IAAOA,EAAK,MAAM,GAAG/B,EAAQ,KAAK,IAC/C+B;AACT;AAEA,eAAejB,EAAWT,GAAe;AAEvC,UADiB,MAAM4B,EAAQ5B,CAAG,GAClB,KAAK,IAAI,CAACkB,MAAQA,EAAI,KAAK,EAAE,kBAAkB,WAAA,CAAY,CAAC;AAC9E;"}
|