@olinfo/quizms-firebase 4.0.0-canary.20251207 → 4.0.1
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/package.json.js +1 -1
- package/dist/src/cli/utils/storage.js +30 -27
- package/dist/src/cli/utils/storage.js.map +1 -1
- package/dist/src/functions/api/admin.js +13 -0
- package/dist/src/functions/api/admin.js.map +1 -0
- package/dist/src/functions/api/index.js +16 -13
- package/dist/src/functions/api/index.js.map +1 -1
- package/dist/src/functions/api/schema.js +12 -12
- package/dist/src/functions/api/schema.js.map +1 -1
- package/dist/src/web/entry/student.js +46 -45
- package/dist/src/web/entry/student.js.map +1 -1
- package/package.json +2 -2
package/dist/package.json.js
CHANGED
|
@@ -1,41 +1,44 @@
|
|
|
1
|
-
import { existsSync as
|
|
2
|
-
import { confirm as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { existsSync as h } from "node:fs";
|
|
2
|
+
import { confirm as u } from "@inquirer/prompts";
|
|
3
|
+
import { AsyncPool as w } from "@olinfo/quizms/utils";
|
|
4
|
+
import { fatal as m, success as x } from "@olinfo/quizms/utils-node";
|
|
5
|
+
import { SingleBar as b } from "cli-progress";
|
|
6
|
+
import { partition as y } from "lodash-es";
|
|
7
|
+
import $ from "picocolors";
|
|
8
|
+
async function I(f, i, s, r) {
|
|
9
|
+
const t = new b({
|
|
9
10
|
format: " {bar} {percentage}% | {value}/{total}",
|
|
10
11
|
barCompleteChar: "█",
|
|
11
12
|
barIncompleteChar: "▂"
|
|
12
13
|
}), l = /* @__PURE__ */ new Set();
|
|
13
14
|
t.start(s.length, 0), await Promise.all(
|
|
14
|
-
s.map(async ([
|
|
15
|
-
|
|
16
|
-
`Cannot find ${
|
|
15
|
+
s.map(async ([o, e]) => {
|
|
16
|
+
h(o) || m(
|
|
17
|
+
`Cannot find ${i}. Make sure to generate them first, use \`quizms --help\` for usage.`
|
|
17
18
|
);
|
|
18
|
-
const
|
|
19
|
-
|
|
19
|
+
const g = f.file(e), [d] = await g.exists().catch(() => [!1]);
|
|
20
|
+
d && l.add(e), t.increment();
|
|
20
21
|
})
|
|
21
22
|
), t.stop();
|
|
22
|
-
const [
|
|
23
|
-
|
|
24
|
-
`Files already exist in \`${
|
|
23
|
+
const [a, c] = y(s, ([o, e]) => l.has(e));
|
|
24
|
+
a.length > 0 && !r.skipExisting && !r.force && m(
|
|
25
|
+
`Files already exist in \`${i}\`. Use \`--force\` to overwrite or \`--skip-existing\` to ignore.`
|
|
25
26
|
);
|
|
26
|
-
const n = r.skipExisting ?
|
|
27
|
-
r.force &&
|
|
28
|
-
message: `You are about to import the ${
|
|
29
|
-
|
|
30
|
-
)}. ${
|
|
27
|
+
const n = r.skipExisting ? c : [...a, ...c];
|
|
28
|
+
r.force && a.length > 0 && (await u({
|
|
29
|
+
message: `You are about to import the ${$.bold(
|
|
30
|
+
i
|
|
31
|
+
)}. ${a.length} files will be overwritten, the previous data will be lost. Are you really sure?`,
|
|
31
32
|
default: !1
|
|
32
|
-
}) || m("Command aborted.")), t.start(n.length, 0)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
}) || m("Command aborted.")), t.start(n.length, 0);
|
|
34
|
+
const p = new w(8);
|
|
35
|
+
for (const [o, e] of n)
|
|
36
|
+
p.run(async () => {
|
|
37
|
+
await f.upload(o, { destination: e }), t.increment();
|
|
38
|
+
});
|
|
39
|
+
await p.wait(), t.stop(), x(`${n.length} ${i} imported!`);
|
|
37
40
|
}
|
|
38
41
|
export {
|
|
39
|
-
|
|
42
|
+
I as importStorage
|
|
40
43
|
};
|
|
41
44
|
//# sourceMappingURL=storage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.js","sources":["../../../../src/cli/utils/storage.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\n\nimport type { Bucket } from \"@google-cloud/storage\";\nimport { confirm } from \"@inquirer/prompts\";\nimport { fatal, success } from \"@olinfo/quizms/utils-node\";\nimport { SingleBar } from \"cli-progress\";\nimport { partition } from \"lodash-es\";\nimport pc from \"picocolors\";\n\ntype ImportOptions = {\n skipExisting?: true;\n force?: true;\n};\n\nexport async function importStorage(\n bucket: Bucket,\n collection: string,\n files: [string, string][],\n options: ImportOptions,\n) {\n const bar = new SingleBar({\n format: \" {bar} {percentage}% | {value}/{total}\",\n barCompleteChar: \"\\u2588\",\n barIncompleteChar: \"\\u2582\",\n });\n\n const existingFiles = new Set<string>();\n\n bar.start(files.length, 0);\n await Promise.all(\n files.map(async ([local, remote]) => {\n if (!existsSync(local)) {\n fatal(\n `Cannot find ${collection}. Make sure to generate them first, use \\`quizms --help\\` for usage.`,\n );\n }\n\n const file = bucket.file(remote);\n const [exists] = await file.exists().catch(() => [false]);\n if (exists) {\n existingFiles.add(remote);\n }\n bar.increment();\n }),\n );\n bar.stop();\n\n const [existing, nonExisting] = partition(files, ([_, remote]) => existingFiles.has(remote));\n if (existing.length > 0 && !options.skipExisting && !options.force) {\n fatal(\n `Files already exist in \\`${collection}\\`. Use \\`--force\\` to overwrite or \\`--skip-existing\\` to ignore.`,\n );\n }\n\n const filesToImport = options.skipExisting ? nonExisting : [...existing, ...nonExisting];\n\n if (options.force && existing.length > 0) {\n const confirmed = await confirm({\n message: `You are about to import the ${pc.bold(\n collection,\n )}. ${existing.length} files will be overwritten, the previous data will be lost. Are you really sure?`,\n default: false,\n });\n if (!confirmed) {\n fatal(\"Command aborted.\");\n }\n }\n\n bar.start(filesToImport.length, 0);\n
|
|
1
|
+
{"version":3,"file":"storage.js","sources":["../../../../src/cli/utils/storage.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\n\nimport type { Bucket } from \"@google-cloud/storage\";\nimport { confirm } from \"@inquirer/prompts\";\nimport { AsyncPool } from \"@olinfo/quizms/utils\";\nimport { fatal, success } from \"@olinfo/quizms/utils-node\";\nimport { SingleBar } from \"cli-progress\";\nimport { partition } from \"lodash-es\";\nimport pc from \"picocolors\";\n\ntype ImportOptions = {\n skipExisting?: true;\n force?: true;\n};\n\nexport async function importStorage(\n bucket: Bucket,\n collection: string,\n files: [string, string][],\n options: ImportOptions,\n) {\n const bar = new SingleBar({\n format: \" {bar} {percentage}% | {value}/{total}\",\n barCompleteChar: \"\\u2588\",\n barIncompleteChar: \"\\u2582\",\n });\n\n const existingFiles = new Set<string>();\n\n bar.start(files.length, 0);\n await Promise.all(\n files.map(async ([local, remote]) => {\n if (!existsSync(local)) {\n fatal(\n `Cannot find ${collection}. Make sure to generate them first, use \\`quizms --help\\` for usage.`,\n );\n }\n\n const file = bucket.file(remote);\n const [exists] = await file.exists().catch(() => [false]);\n if (exists) {\n existingFiles.add(remote);\n }\n bar.increment();\n }),\n );\n bar.stop();\n\n const [existing, nonExisting] = partition(files, ([_, remote]) => existingFiles.has(remote));\n if (existing.length > 0 && !options.skipExisting && !options.force) {\n fatal(\n `Files already exist in \\`${collection}\\`. Use \\`--force\\` to overwrite or \\`--skip-existing\\` to ignore.`,\n );\n }\n\n const filesToImport = options.skipExisting ? nonExisting : [...existing, ...nonExisting];\n\n if (options.force && existing.length > 0) {\n const confirmed = await confirm({\n message: `You are about to import the ${pc.bold(\n collection,\n )}. ${existing.length} files will be overwritten, the previous data will be lost. Are you really sure?`,\n default: false,\n });\n if (!confirmed) {\n fatal(\"Command aborted.\");\n }\n }\n\n bar.start(filesToImport.length, 0);\n\n const pool = new AsyncPool(8);\n for (const [local, remote] of filesToImport) {\n void pool.run(async () => {\n await bucket.upload(local, { destination: remote });\n bar.increment();\n });\n }\n await pool.wait();\n\n bar.stop();\n\n success(`${filesToImport.length} ${collection} imported!`);\n}\n"],"names":["importStorage","bucket","collection","files","options","bar","SingleBar","existingFiles","local","remote","existsSync","fatal","file","exists","existing","nonExisting","partition","_","filesToImport","confirm","pc","pool","AsyncPool","success"],"mappings":";;;;;;;AAeA,eAAsBA,EACpBC,GACAC,GACAC,GACAC,GACA;AACA,QAAMC,IAAM,IAAIC,EAAU;AAAA,IACxB,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,mBAAmB;AAAA,EAAA,CACpB,GAEKC,wBAAoB,IAAA;AAE1B,EAAAF,EAAI,MAAMF,EAAM,QAAQ,CAAC,GACzB,MAAM,QAAQ;AAAA,IACZA,EAAM,IAAI,OAAO,CAACK,GAAOC,CAAM,MAAM;AACnC,MAAKC,EAAWF,CAAK,KACnBG;AAAA,QACE,eAAeT,CAAU;AAAA,MAAA;AAI7B,YAAMU,IAAOX,EAAO,KAAKQ,CAAM,GACzB,CAACI,CAAM,IAAI,MAAMD,EAAK,OAAA,EAAS,MAAM,MAAM,CAAC,EAAK,CAAC;AACxD,MAAIC,KACFN,EAAc,IAAIE,CAAM,GAE1BJ,EAAI,UAAA;AAAA,IACN,CAAC;AAAA,EAAA,GAEHA,EAAI,KAAA;AAEJ,QAAM,CAACS,GAAUC,CAAW,IAAIC,EAAUb,GAAO,CAAC,CAACc,GAAGR,CAAM,MAAMF,EAAc,IAAIE,CAAM,CAAC;AAC3F,EAAIK,EAAS,SAAS,KAAK,CAACV,EAAQ,gBAAgB,CAACA,EAAQ,SAC3DO;AAAA,IACE,4BAA4BT,CAAU;AAAA,EAAA;AAI1C,QAAMgB,IAAgBd,EAAQ,eAAeW,IAAc,CAAC,GAAGD,GAAU,GAAGC,CAAW;AAEvF,EAAIX,EAAQ,SAASU,EAAS,SAAS,MACnB,MAAMK,EAAQ;AAAA,IAC9B,SAAS,+BAA+BC,EAAG;AAAA,MACzClB;AAAA,IAAA,CACD,KAAKY,EAAS,MAAM;AAAA,IACrB,SAAS;AAAA,EAAA,CACV,KAECH,EAAM,kBAAkB,IAI5BN,EAAI,MAAMa,EAAc,QAAQ,CAAC;AAEjC,QAAMG,IAAO,IAAIC,EAAU,CAAC;AAC5B,aAAW,CAACd,GAAOC,CAAM,KAAKS;AAC5B,IAAKG,EAAK,IAAI,YAAY;AACxB,YAAMpB,EAAO,OAAOO,GAAO,EAAE,aAAaC,GAAQ,GAClDJ,EAAI,UAAA;AAAA,IACN,CAAC;AAEH,QAAMgB,EAAK,KAAA,GAEXhB,EAAI,KAAA,GAEJkB,EAAQ,GAAGL,EAAc,MAAM,IAAIhB,CAAU,YAAY;AAC3D;"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import o from "node:crypto";
|
|
2
|
+
import * as s from "firebase-functions/logger";
|
|
3
|
+
import { auth as t } from "../common.js";
|
|
4
|
+
import { getUser as n } from "./queries.js";
|
|
5
|
+
const d = async (a, r) => {
|
|
6
|
+
s.info("Admin login request received", { data: r });
|
|
7
|
+
const e = await n(r.username);
|
|
8
|
+
return e ? e.role !== "admin" ? { success: !1, errorCode: "INVALID_ROLE", error: "Utenza non abilitata" } : e.password !== r.password ? { success: !1, errorCode: "INVALID_PASSWORD", error: "Password non corretta" } : { success: !0, data: { token: await t.createCustomToken(o.randomUUID(), { role: "admin" }) } } : { success: !1, errorCode: "USER_NOT_FOUND", error: "Username non esistente" };
|
|
9
|
+
};
|
|
10
|
+
export {
|
|
11
|
+
d as adminLogin
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=admin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin.js","sources":["../../../../src/functions/api/admin.ts"],"sourcesContent":["import crypto from \"node:crypto\";\n\nimport * as logger from \"firebase-functions/logger\";\n\nimport { auth, type Endpoint } from \"~/functions/common\";\n\nimport { getUser } from \"./queries\";\nimport type { AdminLogin } from \"./schema\";\n\nexport const adminLogin: Endpoint<AdminLogin> = async (_request, data) => {\n logger.info(\"Admin login request received\", { data });\n\n const user = await getUser(data.username);\n if (!user) {\n return { success: false, errorCode: \"USER_NOT_FOUND\", error: \"Username non esistente\" };\n }\n\n if (user.role !== \"admin\") {\n return { success: false, errorCode: \"INVALID_ROLE\", error: \"Utenza non abilitata\" };\n }\n if (user.password !== data.password) {\n return { success: false, errorCode: \"INVALID_PASSWORD\", error: \"Password non corretta\" };\n }\n const token = await auth.createCustomToken(crypto.randomUUID(), { role: \"admin\" });\n return { success: true, data: { token } };\n};\n"],"names":["adminLogin","_request","data","logger","user","getUser","auth","crypto"],"mappings":";;;;AASO,MAAMA,IAAmC,OAAOC,GAAUC,MAAS;AACxE,EAAAC,EAAO,KAAK,gCAAgC,EAAE,MAAAD,EAAA,CAAM;AAEpD,QAAME,IAAO,MAAMC,EAAQH,EAAK,QAAQ;AACxC,SAAKE,IAIDA,EAAK,SAAS,UACT,EAAE,SAAS,IAAO,WAAW,gBAAgB,OAAO,uBAAA,IAEzDA,EAAK,aAAaF,EAAK,WAClB,EAAE,SAAS,IAAO,WAAW,oBAAoB,OAAO,wBAAA,IAG1D,EAAE,SAAS,IAAM,MAAM,EAAE,OADlB,MAAMI,EAAK,kBAAkBC,EAAO,cAAc,EAAE,MAAM,SAAS,IAC3C,IAV7B,EAAE,SAAS,IAAO,WAAW,kBAAkB,OAAO,yBAAA;AAWjE;"}
|
|
@@ -1,38 +1,41 @@
|
|
|
1
1
|
import { validate as i } from "@olinfo/quizms/utils";
|
|
2
2
|
import * as t from "firebase-functions/logger";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
3
|
+
import { adminLogin as o } from "./admin.js";
|
|
4
|
+
import { apiRequestSchema as c } from "./schema.js";
|
|
5
|
+
import { studentLogin as n } from "./student.js";
|
|
6
|
+
import { teacherFinalizeParticipation as s, teacherStopParticipation as p, teacherStartParticipation as d, teacherLogin as m } from "./teacher.js";
|
|
7
|
+
async function w(a) {
|
|
7
8
|
t.info(`Received request for action: ${a.data.action}`);
|
|
8
|
-
const r = await
|
|
9
|
+
const r = await f(a);
|
|
9
10
|
return r.success || t.error("Request failed", { request: a, result: r }), r;
|
|
10
11
|
}
|
|
11
|
-
async function
|
|
12
|
+
async function f(a) {
|
|
12
13
|
let r;
|
|
13
14
|
try {
|
|
14
|
-
r = i(
|
|
15
|
+
r = i(c, a.data);
|
|
15
16
|
} catch (e) {
|
|
16
17
|
return t.error("Invalid request", { error: e }), { success: !1, errorCode: "INVALID_REQUEST", error: "Richiesta non valida" };
|
|
17
18
|
}
|
|
18
19
|
try {
|
|
19
20
|
switch (r.action) {
|
|
21
|
+
case "adminLogin":
|
|
22
|
+
return await o(a, r);
|
|
20
23
|
case "studentLogin":
|
|
21
|
-
return await
|
|
24
|
+
return await n(a, r);
|
|
22
25
|
case "teacherLogin":
|
|
23
|
-
return await
|
|
26
|
+
return await m(a, r);
|
|
24
27
|
case "teacherStartParticipation":
|
|
25
|
-
return await
|
|
28
|
+
return await d(a, r);
|
|
26
29
|
case "teacherStopParticipation":
|
|
27
|
-
return await
|
|
30
|
+
return await p(a, r);
|
|
28
31
|
case "teacherFinalizeParticipation":
|
|
29
|
-
return await
|
|
32
|
+
return await s(a, r);
|
|
30
33
|
}
|
|
31
34
|
} catch (e) {
|
|
32
35
|
return t.error("Error processing request", { error: e }), { success: !1, errorCode: "INTERNAL_ERROR", error: "Errore del server" };
|
|
33
36
|
}
|
|
34
37
|
}
|
|
35
38
|
export {
|
|
36
|
-
|
|
39
|
+
w as apiHandler
|
|
37
40
|
};
|
|
38
41
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/functions/api/index.ts"],"sourcesContent":["import { validate } from \"@olinfo/quizms/utils\";\nimport type { CallableRequest } from \"firebase-functions/https\";\nimport * as logger from \"firebase-functions/logger\";\n\nimport { type ApiRequest, apiRequestSchema } from \"./schema\";\nimport { studentLogin } from \"./student\";\nimport {\n teacherFinalizeParticipation,\n teacherLogin,\n teacherStartParticipation,\n teacherStopParticipation,\n} from \"./teacher\";\n\nexport async function apiHandler(request: CallableRequest) {\n logger.info(`Received request for action: ${request.data.action}`);\n const result = await dispatch(request);\n if (!result.success) {\n logger.error(\"Request failed\", { request, result });\n }\n return result;\n}\n\nasync function dispatch(request: CallableRequest) {\n let data: ApiRequest;\n try {\n data = validate(apiRequestSchema, request.data);\n } catch (error) {\n logger.error(\"Invalid request\", { error });\n return { success: false, errorCode: \"INVALID_REQUEST\", error: \"Richiesta non valida\" };\n }\n\n try {\n switch (data.action) {\n case \"studentLogin\":\n return await studentLogin(request, data);\n case \"teacherLogin\":\n return await teacherLogin(request, data);\n case \"teacherStartParticipation\":\n return await teacherStartParticipation(request, data);\n case \"teacherStopParticipation\":\n return await teacherStopParticipation(request, data);\n case \"teacherFinalizeParticipation\":\n return await teacherFinalizeParticipation(request, data);\n }\n } catch (error) {\n logger.error(\"Error processing request\", { error });\n return { success: false, errorCode: \"INTERNAL_ERROR\", error: \"Errore del server\" };\n }\n}\n"],"names":["apiHandler","request","logger","result","dispatch","data","validate","apiRequestSchema","error","studentLogin","teacherLogin","teacherStartParticipation","teacherStopParticipation","teacherFinalizeParticipation"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/functions/api/index.ts"],"sourcesContent":["import { validate } from \"@olinfo/quizms/utils\";\nimport type { CallableRequest } from \"firebase-functions/https\";\nimport * as logger from \"firebase-functions/logger\";\n\nimport { adminLogin } from \"./admin\";\nimport { type ApiRequest, apiRequestSchema } from \"./schema\";\nimport { studentLogin } from \"./student\";\nimport {\n teacherFinalizeParticipation,\n teacherLogin,\n teacherStartParticipation,\n teacherStopParticipation,\n} from \"./teacher\";\n\nexport async function apiHandler(request: CallableRequest) {\n logger.info(`Received request for action: ${request.data.action}`);\n const result = await dispatch(request);\n if (!result.success) {\n logger.error(\"Request failed\", { request, result });\n }\n return result;\n}\n\nasync function dispatch(request: CallableRequest) {\n let data: ApiRequest;\n try {\n data = validate(apiRequestSchema, request.data);\n } catch (error) {\n logger.error(\"Invalid request\", { error });\n return { success: false, errorCode: \"INVALID_REQUEST\", error: \"Richiesta non valida\" };\n }\n\n try {\n switch (data.action) {\n case \"adminLogin\":\n return await adminLogin(request, data);\n case \"studentLogin\":\n return await studentLogin(request, data);\n case \"teacherLogin\":\n return await teacherLogin(request, data);\n case \"teacherStartParticipation\":\n return await teacherStartParticipation(request, data);\n case \"teacherStopParticipation\":\n return await teacherStopParticipation(request, data);\n case \"teacherFinalizeParticipation\":\n return await teacherFinalizeParticipation(request, data);\n }\n } catch (error) {\n logger.error(\"Error processing request\", { error });\n return { success: false, errorCode: \"INTERNAL_ERROR\", error: \"Errore del server\" };\n }\n}\n"],"names":["apiHandler","request","logger","result","dispatch","data","validate","apiRequestSchema","error","adminLogin","studentLogin","teacherLogin","teacherStartParticipation","teacherStopParticipation","teacherFinalizeParticipation"],"mappings":";;;;;;AAcA,eAAsBA,EAAWC,GAA0B;AACzD,EAAAC,EAAO,KAAK,gCAAgCD,EAAQ,KAAK,MAAM,EAAE;AACjE,QAAME,IAAS,MAAMC,EAASH,CAAO;AACrC,SAAKE,EAAO,WACVD,EAAO,MAAM,kBAAkB,EAAE,SAAAD,GAAS,QAAAE,GAAQ,GAE7CA;AACT;AAEA,eAAeC,EAASH,GAA0B;AAChD,MAAII;AACJ,MAAI;AACF,IAAAA,IAAOC,EAASC,GAAkBN,EAAQ,IAAI;AAAA,EAChD,SAASO,GAAO;AACd,WAAAN,EAAO,MAAM,mBAAmB,EAAE,OAAAM,EAAA,CAAO,GAClC,EAAE,SAAS,IAAO,WAAW,mBAAmB,OAAO,uBAAA;AAAA,EAChE;AAEA,MAAI;AACF,YAAQH,EAAK,QAAA;AAAA,MACX,KAAK;AACH,eAAO,MAAMI,EAAWR,GAASI,CAAI;AAAA,MACvC,KAAK;AACH,eAAO,MAAMK,EAAaT,GAASI,CAAI;AAAA,MACzC,KAAK;AACH,eAAO,MAAMM,EAAaV,GAASI,CAAI;AAAA,MACzC,KAAK;AACH,eAAO,MAAMO,EAA0BX,GAASI,CAAI;AAAA,MACtD,KAAK;AACH,eAAO,MAAMQ,EAAyBZ,GAASI,CAAI;AAAA,MACrD,KAAK;AACH,eAAO,MAAMS,EAA6Bb,GAASI,CAAI;AAAA,IAAA;AAAA,EAE7D,SAASG,GAAO;AACd,WAAAN,EAAO,MAAM,4BAA4B,EAAE,OAAAM,EAAA,CAAO,GAC3C,EAAE,SAAS,IAAO,WAAW,kBAAkB,OAAO,oBAAA;AAAA,EAC/D;AACF;"}
|
|
@@ -5,38 +5,38 @@ const i = t.object({
|
|
|
5
5
|
token: t.string(),
|
|
6
6
|
userData: t.record(t.coerce.string()),
|
|
7
7
|
extraData: t.record(t.any())
|
|
8
|
-
})
|
|
9
|
-
t.object({
|
|
8
|
+
}), a = t.object({
|
|
10
9
|
action: t.literal("adminLogin"),
|
|
11
10
|
username: t.string(),
|
|
12
11
|
password: t.string()
|
|
13
|
-
})
|
|
14
|
-
const a = t.object({
|
|
12
|
+
}), e = t.object({
|
|
15
13
|
action: t.literal("teacherLogin"),
|
|
16
14
|
username: t.string(),
|
|
17
15
|
password: t.string()
|
|
18
|
-
}),
|
|
16
|
+
}), n = t.object({
|
|
19
17
|
action: t.literal("teacherStartParticipation"),
|
|
20
18
|
participationId: t.string()
|
|
21
|
-
}),
|
|
19
|
+
}), c = t.object({
|
|
22
20
|
action: t.literal("teacherStopParticipation"),
|
|
23
21
|
participationId: t.string()
|
|
24
22
|
}), r = t.object({
|
|
25
23
|
action: t.literal("teacherFinalizeParticipation"),
|
|
26
24
|
participationId: t.string()
|
|
27
|
-
}),
|
|
28
|
-
i,
|
|
25
|
+
}), s = t.discriminatedUnion("action", [
|
|
29
26
|
a,
|
|
27
|
+
i,
|
|
30
28
|
e,
|
|
31
29
|
n,
|
|
30
|
+
c,
|
|
32
31
|
r
|
|
33
32
|
]);
|
|
34
33
|
export {
|
|
35
|
-
|
|
34
|
+
a as adminLoginSchema,
|
|
35
|
+
s as apiRequestSchema,
|
|
36
36
|
i as studentLoginSchema,
|
|
37
37
|
r as teacherFinalizeParticipationSchema,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
e as teacherLoginSchema,
|
|
39
|
+
n as teacherStartParticipationSchema,
|
|
40
|
+
c as teacherStopParticipationSchema
|
|
41
41
|
};
|
|
42
42
|
//# sourceMappingURL=schema.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sources":["../../../../src/functions/api/schema.ts"],"sourcesContent":["import z from \"zod\";\n\nexport const studentLoginSchema = z.object({\n action: z.literal(\"studentLogin\"),\n contestId: z.string(),\n token: z.string(),\n userData: z.record(z.coerce.string()),\n extraData: z.record(z.any()),\n});\nexport type StudentLogin = z.infer<typeof studentLoginSchema>;\n\nexport const adminLoginSchema = z.object({\n action: z.literal(\"adminLogin\"),\n username: z.string(),\n password: z.string(),\n});\nexport type AdminLogin = z.infer<typeof adminLoginSchema>;\n\nexport const teacherLoginSchema = z.object({\n action: z.literal(\"teacherLogin\"),\n username: z.string(),\n password: z.string(),\n});\nexport type TeacherLogin = z.infer<typeof teacherLoginSchema>;\n\nexport const teacherStartParticipationSchema = z.object({\n action: z.literal(\"teacherStartParticipation\"),\n participationId: z.string(),\n});\nexport type TeacherStartParticipation = z.infer<typeof teacherStartParticipationSchema>;\n\nexport const teacherStopParticipationSchema = z.object({\n action: z.literal(\"teacherStopParticipation\"),\n participationId: z.string(),\n});\nexport type TeacherStopParticipation = z.infer<typeof teacherStopParticipationSchema>;\n\nexport const teacherFinalizeParticipationSchema = z.object({\n action: z.literal(\"teacherFinalizeParticipation\"),\n participationId: z.string(),\n});\nexport type TeacherFinalizeParticipation = z.infer<typeof teacherFinalizeParticipationSchema>;\n\nexport const apiRequestSchema = z.discriminatedUnion(\"action\", [\n studentLoginSchema,\n teacherLoginSchema,\n teacherStartParticipationSchema,\n teacherStopParticipationSchema,\n teacherFinalizeParticipationSchema,\n]);\n\nexport type ApiRequest = z.infer<typeof apiRequestSchema>;\n"],"names":["studentLoginSchema","z","teacherLoginSchema","teacherStartParticipationSchema","teacherStopParticipationSchema","teacherFinalizeParticipationSchema","apiRequestSchema"],"mappings":";AAEO,MAAMA,IAAqBC,EAAE,OAAO;AAAA,EACzC,QAAQA,EAAE,QAAQ,cAAc;AAAA,EAChC,WAAWA,EAAE,OAAA;AAAA,EACb,OAAOA,EAAE,OAAA;AAAA,EACT,UAAUA,EAAE,OAAOA,EAAE,OAAO,QAAQ;AAAA,EACpC,WAAWA,EAAE,OAAOA,EAAE,KAAK;AAC7B,CAAC
|
|
1
|
+
{"version":3,"file":"schema.js","sources":["../../../../src/functions/api/schema.ts"],"sourcesContent":["import z from \"zod\";\n\nexport const studentLoginSchema = z.object({\n action: z.literal(\"studentLogin\"),\n contestId: z.string(),\n token: z.string(),\n userData: z.record(z.coerce.string()),\n extraData: z.record(z.any()),\n});\nexport type StudentLogin = z.infer<typeof studentLoginSchema>;\n\nexport const adminLoginSchema = z.object({\n action: z.literal(\"adminLogin\"),\n username: z.string(),\n password: z.string(),\n});\nexport type AdminLogin = z.infer<typeof adminLoginSchema>;\n\nexport const teacherLoginSchema = z.object({\n action: z.literal(\"teacherLogin\"),\n username: z.string(),\n password: z.string(),\n});\nexport type TeacherLogin = z.infer<typeof teacherLoginSchema>;\n\nexport const teacherStartParticipationSchema = z.object({\n action: z.literal(\"teacherStartParticipation\"),\n participationId: z.string(),\n});\nexport type TeacherStartParticipation = z.infer<typeof teacherStartParticipationSchema>;\n\nexport const teacherStopParticipationSchema = z.object({\n action: z.literal(\"teacherStopParticipation\"),\n participationId: z.string(),\n});\nexport type TeacherStopParticipation = z.infer<typeof teacherStopParticipationSchema>;\n\nexport const teacherFinalizeParticipationSchema = z.object({\n action: z.literal(\"teacherFinalizeParticipation\"),\n participationId: z.string(),\n});\nexport type TeacherFinalizeParticipation = z.infer<typeof teacherFinalizeParticipationSchema>;\n\nexport const apiRequestSchema = z.discriminatedUnion(\"action\", [\n adminLoginSchema,\n studentLoginSchema,\n teacherLoginSchema,\n teacherStartParticipationSchema,\n teacherStopParticipationSchema,\n teacherFinalizeParticipationSchema,\n]);\n\nexport type ApiRequest = z.infer<typeof apiRequestSchema>;\n"],"names":["studentLoginSchema","z","adminLoginSchema","teacherLoginSchema","teacherStartParticipationSchema","teacherStopParticipationSchema","teacherFinalizeParticipationSchema","apiRequestSchema"],"mappings":";AAEO,MAAMA,IAAqBC,EAAE,OAAO;AAAA,EACzC,QAAQA,EAAE,QAAQ,cAAc;AAAA,EAChC,WAAWA,EAAE,OAAA;AAAA,EACb,OAAOA,EAAE,OAAA;AAAA,EACT,UAAUA,EAAE,OAAOA,EAAE,OAAO,QAAQ;AAAA,EACpC,WAAWA,EAAE,OAAOA,EAAE,KAAK;AAC7B,CAAC,GAGYC,IAAmBD,EAAE,OAAO;AAAA,EACvC,QAAQA,EAAE,QAAQ,YAAY;AAAA,EAC9B,UAAUA,EAAE,OAAA;AAAA,EACZ,UAAUA,EAAE,OAAA;AACd,CAAC,GAGYE,IAAqBF,EAAE,OAAO;AAAA,EACzC,QAAQA,EAAE,QAAQ,cAAc;AAAA,EAChC,UAAUA,EAAE,OAAA;AAAA,EACZ,UAAUA,EAAE,OAAA;AACd,CAAC,GAGYG,IAAkCH,EAAE,OAAO;AAAA,EACtD,QAAQA,EAAE,QAAQ,2BAA2B;AAAA,EAC7C,iBAAiBA,EAAE,OAAA;AACrB,CAAC,GAGYI,IAAiCJ,EAAE,OAAO;AAAA,EACrD,QAAQA,EAAE,QAAQ,0BAA0B;AAAA,EAC5C,iBAAiBA,EAAE,OAAA;AACrB,CAAC,GAGYK,IAAqCL,EAAE,OAAO;AAAA,EACzD,QAAQA,EAAE,QAAQ,8BAA8B;AAAA,EAChD,iBAAiBA,EAAE,OAAA;AACrB,CAAC,GAGYM,IAAmBN,EAAE,mBAAmB,UAAU;AAAA,EAC7DC;AAAA,EACAF;AAAA,EACAG;AAAA,EACAC;AAAA,EACAC;AAAA,EACAC;AACF,CAAC;"}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { jsx as t, jsxs as
|
|
1
|
+
import { jsx as t, jsxs as u, Fragment as b } 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 x, StudentFormField as F } from "@olinfo/quizms/components";
|
|
4
4
|
import { StudentProvider as I } from "@olinfo/quizms/student";
|
|
5
|
-
import { Navbar as
|
|
6
|
-
import { signOut as
|
|
5
|
+
import { Navbar as k, NavbarBrand as A, Form as C, SelectField as D, TextField as W, SubmitButton as y } from "@olinfo/react-components";
|
|
6
|
+
import { signOut as E, getAuth as g, signInWithCustomToken as H } from "firebase/auth";
|
|
7
7
|
import { waitForPendingWrites as f } from "firebase/firestore";
|
|
8
8
|
import { isEqual as N } from "lodash-es";
|
|
9
|
-
import { studentLogin as
|
|
9
|
+
import { studentLogin as j } from "../common/api.js";
|
|
10
10
|
import { useDb as S } from "../common/base-login.js";
|
|
11
|
-
import { contestConverter as
|
|
12
|
-
import { useWebsite as
|
|
13
|
-
import { useAuth as
|
|
11
|
+
import { contestConverter as M, studentConverter as P, participationConverter as R } from "../common/converters.js";
|
|
12
|
+
import { useWebsite as T } from "../common/website.js";
|
|
13
|
+
import { useAuth as q } from "../hooks/auth.js";
|
|
14
14
|
import { useCollection as z } from "../hooks/collection.js";
|
|
15
15
|
import { useDocument as h } from "../hooks/document.js";
|
|
16
16
|
import { StudentRestoring as B } from "./student-restoring.js";
|
|
17
|
-
import { FirebaseStatement as
|
|
17
|
+
import { FirebaseStatement as O } from "./student-statement.js";
|
|
18
18
|
import G from "virtual:quizms-firebase-header";
|
|
19
|
-
function
|
|
20
|
-
const e =
|
|
19
|
+
function ut() {
|
|
20
|
+
const e = q("student"), o = T(), [a] = z("contests", M, {
|
|
21
21
|
constraints: { id: o.contests },
|
|
22
22
|
subscribe: !0
|
|
23
23
|
});
|
|
@@ -32,13 +32,13 @@ function mt() {
|
|
|
32
32
|
}
|
|
33
33
|
function L({ contests: e }) {
|
|
34
34
|
const o = S(), a = p(
|
|
35
|
-
async ({ contestId:
|
|
36
|
-
const d = await
|
|
37
|
-
contestId:
|
|
35
|
+
async ({ contestId: n, token: s, ...i }) => {
|
|
36
|
+
const d = await j(o, {
|
|
37
|
+
contestId: n,
|
|
38
38
|
token: s,
|
|
39
39
|
userData: {
|
|
40
|
-
...
|
|
41
|
-
birthDate:
|
|
40
|
+
...i,
|
|
41
|
+
birthDate: i.birthDate ? new Date(i.birthDate) : void 0
|
|
42
42
|
},
|
|
43
43
|
extraData: {
|
|
44
44
|
userAgent: navigator.userAgent,
|
|
@@ -49,36 +49,36 @@ function L({ contests: e }) {
|
|
|
49
49
|
pixelRatio: window.devicePixelRatio,
|
|
50
50
|
darkMode: window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
51
51
|
}
|
|
52
|
-
}),
|
|
53
|
-
await H(
|
|
52
|
+
}), m = g(o.app);
|
|
53
|
+
await H(m, d.token), await document.documentElement.requestFullscreen?.();
|
|
54
54
|
},
|
|
55
55
|
[o]
|
|
56
56
|
), r = w(
|
|
57
57
|
() => ({
|
|
58
|
-
contestId:
|
|
58
|
+
contestId: e.length === 1 ? e[0].id : void 0
|
|
59
59
|
}),
|
|
60
60
|
[e]
|
|
61
61
|
);
|
|
62
|
-
return /* @__PURE__ */
|
|
63
|
-
/* @__PURE__ */ t(
|
|
64
|
-
/* @__PURE__ */
|
|
62
|
+
return /* @__PURE__ */ u(b, { children: [
|
|
63
|
+
/* @__PURE__ */ t(k, { color: "bg-base-300 text-base-content", children: /* @__PURE__ */ t(A, { children: /* @__PURE__ */ t("div", { className: "flex items-center h-full font-bold", children: /* @__PURE__ */ t(x, {}) }) }) }),
|
|
64
|
+
/* @__PURE__ */ u(C, { defaultValue: r, onSubmit: a, className: "p-4 pb-8", children: [
|
|
65
65
|
/* @__PURE__ */ t("h1", { className: "mb-2 text-xl font-bold", children: "Accedi alla gara" }),
|
|
66
66
|
/* @__PURE__ */ t(
|
|
67
|
-
|
|
67
|
+
D,
|
|
68
68
|
{
|
|
69
69
|
field: "contestId",
|
|
70
70
|
label: "Gara",
|
|
71
|
-
options: Object.fromEntries(e.map((
|
|
71
|
+
options: Object.fromEntries(e.map((n) => [n.id, n.name])),
|
|
72
72
|
placeholder: "Seleziona una gara"
|
|
73
73
|
}
|
|
74
74
|
),
|
|
75
|
-
({ contestId:
|
|
76
|
-
const s = e.find((
|
|
75
|
+
({ contestId: n }) => {
|
|
76
|
+
const s = e.find((i) => i.id === n);
|
|
77
77
|
if (s)
|
|
78
|
-
return /* @__PURE__ */
|
|
79
|
-
s.userData.map((
|
|
80
|
-
/* @__PURE__ */ t(
|
|
81
|
-
/* @__PURE__ */ t(
|
|
78
|
+
return /* @__PURE__ */ u(b, { children: [
|
|
79
|
+
s.userData.map((i) => /* @__PURE__ */ t(F, { field: i }, i.name)),
|
|
80
|
+
/* @__PURE__ */ t(W, { field: "token", label: "Codice prova", placeholder: "aaaaa-bbbbb-ccccc" }),
|
|
81
|
+
/* @__PURE__ */ t(y, { children: "Inizia la prova" })
|
|
82
82
|
] });
|
|
83
83
|
}
|
|
84
84
|
] })
|
|
@@ -89,42 +89,43 @@ function V({
|
|
|
89
89
|
participationId: o,
|
|
90
90
|
studentId: a
|
|
91
91
|
}) {
|
|
92
|
-
const r = S(), [
|
|
92
|
+
const r = S(), [n, s] = h(
|
|
93
93
|
`participations/${o}/students`,
|
|
94
94
|
a,
|
|
95
|
-
|
|
95
|
+
P,
|
|
96
96
|
{ subscribe: !0 }
|
|
97
|
-
), [
|
|
97
|
+
), [i] = h("participations", o, R, {
|
|
98
98
|
subscribe: !0
|
|
99
99
|
}), d = w(
|
|
100
|
-
() => e.find((c) => c.id ===
|
|
101
|
-
[e,
|
|
102
|
-
),
|
|
100
|
+
() => e.find((c) => c.id === n.contestId),
|
|
101
|
+
[e, n.contestId]
|
|
102
|
+
), m = p(async () => {
|
|
103
103
|
await f(r);
|
|
104
104
|
}, [r]), l = p(async () => {
|
|
105
|
-
await f(r), await
|
|
105
|
+
await f(r), await E(g(r.app)), window.location.reload();
|
|
106
106
|
}, [r]);
|
|
107
107
|
return v(() => {
|
|
108
|
-
|
|
109
|
-
}, [
|
|
108
|
+
i.token !== n.token && l();
|
|
109
|
+
}, [i.token, n.token, l]), /* @__PURE__ */ u(
|
|
110
110
|
I,
|
|
111
111
|
{
|
|
112
112
|
contest: d,
|
|
113
|
-
participation:
|
|
114
|
-
student:
|
|
113
|
+
participation: i,
|
|
114
|
+
student: n,
|
|
115
115
|
setStudent: async (c) => {
|
|
116
|
-
N(
|
|
116
|
+
N(n, c) || await s({ ...c });
|
|
117
117
|
},
|
|
118
118
|
logout: l,
|
|
119
|
-
onSubmit:
|
|
119
|
+
onSubmit: m,
|
|
120
|
+
enforceFullscreen: !0,
|
|
120
121
|
children: [
|
|
121
122
|
/* @__PURE__ */ t(G, { contestId: d.id }),
|
|
122
|
-
/* @__PURE__ */ t(
|
|
123
|
+
/* @__PURE__ */ t(O, {})
|
|
123
124
|
]
|
|
124
125
|
}
|
|
125
126
|
);
|
|
126
127
|
}
|
|
127
128
|
export {
|
|
128
|
-
|
|
129
|
+
ut as default
|
|
129
130
|
};
|
|
130
131
|
//# 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 subscribe: true,\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} & Student[\"userData\"];\n\nfunction StudentForm({ contests }: { contests: Contest[] }) {\n const db = useDb();\n\n const submit = useCallback(\n async ({ contestId, token, ...userData }: FormStudent) => {\n const data = await studentLogin(db, {\n contestId,\n token,\n userData: {\n ...userData,\n birthDate: userData.birthDate ? new Date(userData.birthDate) : undefined,\n },\n extraData: {\n userAgent: navigator.userAgent,\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, data.token);\n },\n [db],\n );\n\n const defaultValue = useMemo(\n () => ({\n contestId:
|
|
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 subscribe: true,\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} & Student[\"userData\"];\n\nfunction StudentForm({ contests }: { contests: Contest[] }) {\n const db = useDb();\n\n const submit = useCallback(\n async ({ contestId, token, ...userData }: FormStudent) => {\n const data = await studentLogin(db, {\n contestId,\n token,\n userData: {\n ...userData,\n birthDate: userData.birthDate ? new Date(userData.birthDate) : undefined,\n },\n extraData: {\n userAgent: navigator.userAgent,\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, data.token);\n await document.documentElement.requestFullscreen?.();\n },\n [db],\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 { subscribe: true },\n );\n const [participation] = useDocument(\"participations\", participationId, participationConverter, {\n subscribe: true,\n });\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","submit","useCallback","contestId","token","userData","data","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":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olinfo/quizms-firebase",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "Alessandro Bortolin <bortolin.alessandro@outlook.it>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"vite-tsconfig-paths": "^5.1.4",
|
|
57
57
|
"wouter": "^3.8.1",
|
|
58
58
|
"zod": "^3.25.76",
|
|
59
|
-
"@olinfo/quizms": "^4.0.0
|
|
59
|
+
"@olinfo/quizms": "^4.0.0"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
62
|
"react": "~19.1"
|