@tietokilta/ilmomasiina-client 2.0.0-alpha42
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/LICENSE +22 -0
- package/README.md +19 -0
- package/dist/api.d.ts +17 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +63 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/locales/en.json +132 -0
- package/dist/locales/fi.json +132 -0
- package/dist/locales/index.d.ts +267 -0
- package/dist/locales/index.d.ts.map +1 -0
- package/dist/locales/index.js +14 -0
- package/dist/modules/editSignup/actions.d.ts +13 -0
- package/dist/modules/editSignup/actions.d.ts.map +1 -0
- package/dist/modules/editSignup/actions.js +23 -0
- package/dist/modules/editSignup/index.d.ts +13 -0
- package/dist/modules/editSignup/index.d.ts.map +1 -0
- package/dist/modules/editSignup/index.js +82 -0
- package/dist/modules/editSignup/state.d.ts +19 -0
- package/dist/modules/editSignup/state.d.ts.map +1 -0
- package/dist/modules/editSignup/state.js +6 -0
- package/dist/modules/eventList/index.d.ts +18 -0
- package/dist/modules/eventList/index.d.ts.map +1 -0
- package/dist/modules/eventList/index.js +59 -0
- package/dist/modules/singleEvent/actions.d.ts +6 -0
- package/dist/modules/singleEvent/actions.d.ts.map +1 -0
- package/dist/modules/singleEvent/actions.js +11 -0
- package/dist/modules/singleEvent/index.d.ts +26 -0
- package/dist/modules/singleEvent/index.d.ts.map +1 -0
- package/dist/modules/singleEvent/index.js +60 -0
- package/dist/utils/abortable.d.ts +29 -0
- package/dist/utils/abortable.d.ts.map +1 -0
- package/dist/utils/abortable.js +85 -0
- package/dist/utils/errorMessage.d.ts +16 -0
- package/dist/utils/errorMessage.d.ts.map +1 -0
- package/dist/utils/errorMessage.js +45 -0
- package/dist/utils/eventListUtils.d.ts +31 -0
- package/dist/utils/eventListUtils.d.ts.map +1 -0
- package/dist/utils/eventListUtils.js +68 -0
- package/dist/utils/localizedEvent.d.ts +10 -0
- package/dist/utils/localizedEvent.d.ts.map +1 -0
- package/dist/utils/localizedEvent.js +58 -0
- package/dist/utils/signupState.d.ts +20 -0
- package/dist/utils/signupState.d.ts.map +1 -0
- package/dist/utils/signupState.js +26 -0
- package/dist/utils/signupUtils.d.ts +26 -0
- package/dist/utils/signupUtils.d.ts.map +1 -0
- package/dist/utils/signupUtils.js +81 -0
- package/dist/utils/stateContext.d.ts +10 -0
- package/dist/utils/stateContext.d.ts.map +1 -0
- package/dist/utils/stateContext.js +30 -0
- package/dist/utils/useShallowMemo.d.ts +3 -0
- package/dist/utils/useShallowMemo.d.ts.map +1 -0
- package/dist/utils/useShallowMemo.js +32 -0
- package/package.json +46 -0
- package/src/locales/en.json +132 -0
- package/src/locales/fi.json +132 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.SingleEventProvider = exports.useSingleEventState = exports.SingleEventContextProvider = exports.beginSignup = exports.useSingleEventContext = void 0;
|
|
30
|
+
const react_1 = __importStar(require("react"));
|
|
31
|
+
const api_1 = require("../../api");
|
|
32
|
+
const abortable_1 = require("../../utils/abortable");
|
|
33
|
+
const localizedEvent_1 = require("../../utils/localizedEvent");
|
|
34
|
+
const signupUtils_1 = require("../../utils/signupUtils");
|
|
35
|
+
const stateContext_1 = require("../../utils/stateContext");
|
|
36
|
+
const useShallowMemo_1 = __importDefault(require("../../utils/useShallowMemo"));
|
|
37
|
+
const { Provider, useStateContext } = (0, stateContext_1.createStateContext)();
|
|
38
|
+
exports.SingleEventContextProvider = Provider;
|
|
39
|
+
exports.useSingleEventContext = useStateContext;
|
|
40
|
+
var actions_1 = require("./actions");
|
|
41
|
+
Object.defineProperty(exports, "beginSignup", { enumerable: true, get: function () { return actions_1.beginSignup; } });
|
|
42
|
+
function useSingleEventState({ slug, language }) {
|
|
43
|
+
const fetchEvent = (0, abortable_1.useAbortablePromise)((signal) => (0, api_1.apiFetch)(`events/${slug}`, { signal }), [slug]);
|
|
44
|
+
const event = fetchEvent.result;
|
|
45
|
+
const localizedEvent = (0, react_1.useMemo)(() => (event && language ? (0, localizedEvent_1.getLocalizedEvent)(event, language) : event), [event, language]);
|
|
46
|
+
const signupsByQuota = (0, react_1.useMemo)(() => localizedEvent && (0, signupUtils_1.getSignupsByQuota)(localizedEvent), [localizedEvent]);
|
|
47
|
+
return (0, useShallowMemo_1.default)({
|
|
48
|
+
event,
|
|
49
|
+
localizedEvent,
|
|
50
|
+
signupsByQuota,
|
|
51
|
+
pending: fetchEvent.pending,
|
|
52
|
+
error: fetchEvent.error,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
exports.useSingleEventState = useSingleEventState;
|
|
56
|
+
function SingleEventProvider({ slug, language, children }) {
|
|
57
|
+
const state = useSingleEventState({ slug, language });
|
|
58
|
+
return react_1.default.createElement(Provider, { value: state }, children);
|
|
59
|
+
}
|
|
60
|
+
exports.SingleEventProvider = SingleEventProvider;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Returns an AbortSignal and a function that aborts the signal. */
|
|
2
|
+
export declare function abortable(): [AbortSignal, () => void];
|
|
3
|
+
/** Like useEffect, but instead of accepting a cleanup function, provides an AbortSignal that is aborted
|
|
4
|
+
* upon unmount or deps change.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useAbortableEffect(effect: (signal: AbortSignal) => void, deps?: any[]): void;
|
|
7
|
+
export type PromiseState<R> = {
|
|
8
|
+
result: undefined;
|
|
9
|
+
error: undefined;
|
|
10
|
+
pending: true;
|
|
11
|
+
} | {
|
|
12
|
+
result: R;
|
|
13
|
+
error: undefined;
|
|
14
|
+
pending: false;
|
|
15
|
+
} | {
|
|
16
|
+
result: undefined;
|
|
17
|
+
error: object;
|
|
18
|
+
pending: false;
|
|
19
|
+
};
|
|
20
|
+
/** Wraps a Promise, ignoring DOMExceptions with name='AbortError' as if the promise was left pending. */
|
|
21
|
+
export declare function ignoreAbort<R>(promise: Promise<R>): Promise<R>;
|
|
22
|
+
/** Returns the state of an async effect, and provides to it an AbortSignal that is aborted
|
|
23
|
+
* upon unmount or deps change.
|
|
24
|
+
*
|
|
25
|
+
* DOMExceptions with name='AbortError' are ignored, as if the promise was left pending.
|
|
26
|
+
* Unmounting or deps changes also return the state to pending.
|
|
27
|
+
*/
|
|
28
|
+
export declare function useAbortablePromise<R>(effect: (signal: AbortSignal) => Promise<R>, deps?: any[]): PromiseState<R>;
|
|
29
|
+
//# sourceMappingURL=abortable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abortable.d.ts","sourceRoot":"","sources":["../../src/utils/abortable.ts"],"names":[],"mappings":"AAEA,oEAAoE;AACpE,wBAAgB,SAAS,IAAI,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC,CAIrD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,QAOrF;AAED,MAAM,MAAM,YAAY,CAAC,CAAC,IACtB;IACE,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,IAAI,CAAC;CACf,GACD;IACE,MAAM,EAAE,CAAC,CAAC;IACV,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,KAAK,CAAC;CAChB,GACD;IACE,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,KAAK,CAAC;CAChB,CAAC;AAEN,yGAAyG;AACzG,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAO9D;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,mBA2C/F"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useAbortablePromise = exports.ignoreAbort = exports.useAbortableEffect = exports.abortable = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
/** Returns an AbortSignal and a function that aborts the signal. */
|
|
6
|
+
function abortable() {
|
|
7
|
+
const controller = new AbortController();
|
|
8
|
+
const abort = () => controller.abort();
|
|
9
|
+
return [controller.signal, abort];
|
|
10
|
+
}
|
|
11
|
+
exports.abortable = abortable;
|
|
12
|
+
/** Like useEffect, but instead of accepting a cleanup function, provides an AbortSignal that is aborted
|
|
13
|
+
* upon unmount or deps change.
|
|
14
|
+
*/
|
|
15
|
+
function useAbortableEffect(effect, deps) {
|
|
16
|
+
(0, react_1.useEffect)(() => {
|
|
17
|
+
const [signal, abort] = abortable();
|
|
18
|
+
effect(signal);
|
|
19
|
+
return abort;
|
|
20
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
21
|
+
}, deps);
|
|
22
|
+
}
|
|
23
|
+
exports.useAbortableEffect = useAbortableEffect;
|
|
24
|
+
/** Wraps a Promise, ignoring DOMExceptions with name='AbortError' as if the promise was left pending. */
|
|
25
|
+
function ignoreAbort(promise) {
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
promise.then(resolve, (error) => {
|
|
28
|
+
if (error instanceof DOMException && error.name === "AbortError")
|
|
29
|
+
return;
|
|
30
|
+
reject(error);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
exports.ignoreAbort = ignoreAbort;
|
|
35
|
+
/** Returns the state of an async effect, and provides to it an AbortSignal that is aborted
|
|
36
|
+
* upon unmount or deps change.
|
|
37
|
+
*
|
|
38
|
+
* DOMExceptions with name='AbortError' are ignored, as if the promise was left pending.
|
|
39
|
+
* Unmounting or deps changes also return the state to pending.
|
|
40
|
+
*/
|
|
41
|
+
function useAbortablePromise(effect, deps) {
|
|
42
|
+
const [state, setState] = (0, react_1.useState)({
|
|
43
|
+
result: undefined,
|
|
44
|
+
error: undefined,
|
|
45
|
+
pending: true,
|
|
46
|
+
});
|
|
47
|
+
// Track promise from latest effect call, ignore updates from other promises
|
|
48
|
+
const pendingPromise = (0, react_1.useRef)();
|
|
49
|
+
useAbortableEffect((signal) => {
|
|
50
|
+
const promise = ignoreAbort(effect(signal));
|
|
51
|
+
pendingPromise.current = promise;
|
|
52
|
+
promise.then((result) => {
|
|
53
|
+
if (pendingPromise.current !== promise)
|
|
54
|
+
return;
|
|
55
|
+
pendingPromise.current = undefined;
|
|
56
|
+
setState({
|
|
57
|
+
result,
|
|
58
|
+
error: undefined,
|
|
59
|
+
pending: false,
|
|
60
|
+
});
|
|
61
|
+
}, (error) => {
|
|
62
|
+
if (pendingPromise.current !== promise)
|
|
63
|
+
return;
|
|
64
|
+
pendingPromise.current = undefined;
|
|
65
|
+
setState({
|
|
66
|
+
result: undefined,
|
|
67
|
+
error,
|
|
68
|
+
pending: false,
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
signal.addEventListener("abort", () => {
|
|
72
|
+
if (pendingPromise.current !== promise)
|
|
73
|
+
return;
|
|
74
|
+
pendingPromise.current = undefined;
|
|
75
|
+
setState({
|
|
76
|
+
result: undefined,
|
|
77
|
+
error: undefined,
|
|
78
|
+
pending: true,
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
82
|
+
}, deps);
|
|
83
|
+
return state;
|
|
84
|
+
}
|
|
85
|
+
exports.useAbortablePromise = useAbortablePromise;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ApiError } from "../api";
|
|
2
|
+
/** Returns possible localization keys, in priority order, for an error title.
|
|
3
|
+
*
|
|
4
|
+
* @param error The API error object thrown.
|
|
5
|
+
* @param prefix Optional translation key prefix that specializes the error message to the relevant app function.
|
|
6
|
+
* Don't end this with a period.
|
|
7
|
+
*/
|
|
8
|
+
export declare function errorTitle<TKey = string>(error: ApiError, prefix?: string): TKey[];
|
|
9
|
+
/** Returns possible localization keys, in priority order, for an error description.
|
|
10
|
+
*
|
|
11
|
+
* @param error The API error object thrown.
|
|
12
|
+
* @param prefix Optional translation key prefix that specializes the error message to the relevant app function.
|
|
13
|
+
* Don't end this with a period.
|
|
14
|
+
*/
|
|
15
|
+
export declare function errorDesc<TKey = string>(error: ApiError, prefix?: string): TKey[];
|
|
16
|
+
//# sourceMappingURL=errorMessage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errorMessage.d.ts","sourceRoot":"","sources":["../../src/utils/errorMessage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AA4BlC;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,GAAG,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,CAElF;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,GAAG,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,CAEjF"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.errorDesc = exports.errorTitle = void 0;
|
|
4
|
+
function errorString(part, error, prefix) {
|
|
5
|
+
// First try e.g. errors.SignupsClosed, then errors.403, then errors.default
|
|
6
|
+
const types = [];
|
|
7
|
+
if (error.code)
|
|
8
|
+
types.push(error.code);
|
|
9
|
+
if (error.status)
|
|
10
|
+
types.push(String(error.status));
|
|
11
|
+
types.push("default");
|
|
12
|
+
// First try e.g. editSignup.errors.default, then errors.default
|
|
13
|
+
const prefixes = [];
|
|
14
|
+
if (prefix)
|
|
15
|
+
prefixes.push(prefix);
|
|
16
|
+
prefixes.push("errors");
|
|
17
|
+
// Order, same examples:
|
|
18
|
+
// - editSignup.errors.SignupsClosed
|
|
19
|
+
// - errors.SignupsClosed
|
|
20
|
+
// - editSignup.errors.403
|
|
21
|
+
// - errors.403
|
|
22
|
+
// - editSignup.errors.default
|
|
23
|
+
// - errors.default
|
|
24
|
+
return types.flatMap((type) => prefixes.map((pre) => `${pre}.${type}.${part}`));
|
|
25
|
+
}
|
|
26
|
+
/** Returns possible localization keys, in priority order, for an error title.
|
|
27
|
+
*
|
|
28
|
+
* @param error The API error object thrown.
|
|
29
|
+
* @param prefix Optional translation key prefix that specializes the error message to the relevant app function.
|
|
30
|
+
* Don't end this with a period.
|
|
31
|
+
*/
|
|
32
|
+
function errorTitle(error, prefix) {
|
|
33
|
+
return errorString("title", error, prefix);
|
|
34
|
+
}
|
|
35
|
+
exports.errorTitle = errorTitle;
|
|
36
|
+
/** Returns possible localization keys, in priority order, for an error description.
|
|
37
|
+
*
|
|
38
|
+
* @param error The API error object thrown.
|
|
39
|
+
* @param prefix Optional translation key prefix that specializes the error message to the relevant app function.
|
|
40
|
+
* Don't end this with a period.
|
|
41
|
+
*/
|
|
42
|
+
function errorDesc(error, prefix) {
|
|
43
|
+
return errorString("description", error, prefix);
|
|
44
|
+
}
|
|
45
|
+
exports.errorDesc = errorDesc;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { EventID, EventSlug, QuotaID, UserEventListItem, UserEventListResponse } from "@tietokilta/ilmomasiina-models";
|
|
2
|
+
import { SignupStateInfo } from "./signupState";
|
|
3
|
+
export interface EventTableOptions {
|
|
4
|
+
/** If true, quotas are not placed on separate rows. */
|
|
5
|
+
compact?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export type EventRow = {
|
|
8
|
+
id: EventID;
|
|
9
|
+
type: "event";
|
|
10
|
+
slug: EventSlug;
|
|
11
|
+
title: string;
|
|
12
|
+
date: Date | null;
|
|
13
|
+
signupState: SignupStateInfo;
|
|
14
|
+
signupCount?: number;
|
|
15
|
+
quotaSize?: number | null;
|
|
16
|
+
totalSignupCount: number;
|
|
17
|
+
totalQuotaSize: number | null;
|
|
18
|
+
};
|
|
19
|
+
export type QuotaRow = {
|
|
20
|
+
type: "quota" | "openquota" | "waitlist";
|
|
21
|
+
id: QuotaID;
|
|
22
|
+
title?: string;
|
|
23
|
+
signupCount: number;
|
|
24
|
+
quotaSize: number | null;
|
|
25
|
+
};
|
|
26
|
+
export type TableRow = EventRow | QuotaRow;
|
|
27
|
+
/** Converts an event to rows to be shown in the event list. */
|
|
28
|
+
export declare function eventToRows(event: UserEventListItem, { compact }?: EventTableOptions): TableRow[];
|
|
29
|
+
/** Converts a list of events to a flat list of rows to be shown in the event list. */
|
|
30
|
+
export declare function eventsToRows(events: UserEventListResponse, options?: EventTableOptions): TableRow[];
|
|
31
|
+
//# sourceMappingURL=eventListUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eventListUtils.d.ts","sourceRoot":"","sources":["../../src/utils/eventListUtils.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,OAAO,EACP,SAAS,EACT,OAAO,EACP,iBAAiB,EACjB,qBAAqB,EACtB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAA4B,eAAe,EAAE,MAAM,eAAe,CAAC;AAE1E,MAAM,WAAW,iBAAiB;IAChC,uDAAuD;IACvD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,WAAW,EAAE,eAAe,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAAC;AACF,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,OAAO,GAAG,WAAW,GAAG,UAAU,CAAC;IACzC,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC;AACF,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE3C,+DAA+D;AAC/D,wBAAgB,WAAW,CAAC,KAAK,EAAE,iBAAiB,EAAE,EAAE,OAAO,EAAE,GAAE,iBAAsB,cA2DxF;AAED,sFAAsF;AACtF,wBAAgB,YAAY,CAAC,MAAM,EAAE,qBAAqB,EAAE,OAAO,CAAC,EAAE,iBAAiB,cAEtF"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.eventsToRows = exports.eventToRows = void 0;
|
|
7
|
+
const every_1 = __importDefault(require("lodash-es/every"));
|
|
8
|
+
const sumBy_1 = __importDefault(require("lodash-es/sumBy"));
|
|
9
|
+
const signupState_1 = require("./signupState");
|
|
10
|
+
/** Converts an event to rows to be shown in the event list. */
|
|
11
|
+
function eventToRows(event, { compact } = {}) {
|
|
12
|
+
const { id, slug, title, date, registrationStartDate, registrationEndDate, quotas, openQuotaSize } = event;
|
|
13
|
+
const state = (0, signupState_1.signupState)(registrationStartDate, registrationEndDate);
|
|
14
|
+
// Event row
|
|
15
|
+
const rows = [
|
|
16
|
+
{
|
|
17
|
+
type: "event",
|
|
18
|
+
id,
|
|
19
|
+
signupState: state,
|
|
20
|
+
slug,
|
|
21
|
+
title,
|
|
22
|
+
date: date ? new Date(date) : null,
|
|
23
|
+
signupCount: quotas.length < 2 ? (0, sumBy_1.default)(quotas, "signupCount") : undefined,
|
|
24
|
+
quotaSize: quotas.length === 1 ? quotas[0].size : undefined,
|
|
25
|
+
totalSignupCount: (0, sumBy_1.default)(quotas, "signupCount") ?? 0,
|
|
26
|
+
totalQuotaSize: (0, every_1.default)(quotas, "size") ? (0, sumBy_1.default)(quotas, "size") : null,
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
// We're done for compact format and events without a signup
|
|
30
|
+
if (compact || state.state === signupState_1.SignupState.disabled)
|
|
31
|
+
return rows;
|
|
32
|
+
// Multiple quotas go on their own rows
|
|
33
|
+
if (quotas.length > 1) {
|
|
34
|
+
quotas.forEach((quota) => rows.push({
|
|
35
|
+
type: "quota",
|
|
36
|
+
id: quota.id,
|
|
37
|
+
title: quota.title,
|
|
38
|
+
signupCount: quota.size ? Math.min(quota.signupCount, quota.size) : quota.signupCount,
|
|
39
|
+
quotaSize: quota.size,
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
const overflow = (0, sumBy_1.default)(quotas, (quota) => (quota.size ? Math.max(0, quota.signupCount - quota.size) : 0));
|
|
43
|
+
// Open quota
|
|
44
|
+
if (openQuotaSize > 0) {
|
|
45
|
+
rows.push({
|
|
46
|
+
type: "openquota",
|
|
47
|
+
id: `${event.id} openquota`,
|
|
48
|
+
signupCount: Math.min(overflow, openQuotaSize),
|
|
49
|
+
quotaSize: openQuotaSize,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
// Queue/waitlist
|
|
53
|
+
if (overflow > openQuotaSize) {
|
|
54
|
+
rows.push({
|
|
55
|
+
type: "waitlist",
|
|
56
|
+
id: `${event.id} waitlist`,
|
|
57
|
+
signupCount: overflow - openQuotaSize,
|
|
58
|
+
quotaSize: null,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return rows;
|
|
62
|
+
}
|
|
63
|
+
exports.eventToRows = eventToRows;
|
|
64
|
+
/** Converts a list of events to a flat list of rows to be shown in the event list. */
|
|
65
|
+
function eventsToRows(events, options) {
|
|
66
|
+
return events.flatMap((event) => eventToRows(event, options));
|
|
67
|
+
}
|
|
68
|
+
exports.eventsToRows = eventsToRows;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SignupForEdit, SignupForEditResponse, UserEventListItem, UserEventResponse } from "@tietokilta/ilmomasiina-models";
|
|
2
|
+
type EventForEditSignup = SignupForEditResponse["event"];
|
|
3
|
+
/** Overrides localized properties in the event and quotas with localized versions. */
|
|
4
|
+
export declare function getLocalizedEventListItem(event: UserEventListItem, language: string): UserEventListItem;
|
|
5
|
+
/** Overrides localized properties in the event, quotas and questions with localized versions. */
|
|
6
|
+
export declare function getLocalizedEvent<E extends UserEventResponse | EventForEditSignup>(event: E, language: string): E;
|
|
7
|
+
/** Overrides localized properties in the quota of the edited signup with localized versions. */
|
|
8
|
+
export declare function getLocalizedQuotaForEditSignup({ event, signup: { quota } }: SignupForEditResponse, language: string): SignupForEdit["quota"];
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=localizedEvent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localizedEvent.d.ts","sourceRoot":"","sources":["../../src/utils/localizedEvent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,gCAAgC,CAAC;AAExC,KAAK,kBAAkB,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAEzD,sFAAsF;AACtF,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CAevG;AAED,iGAAiG;AACjG,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,iBAAiB,GAAG,kBAAkB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,CAoBjH;AAED,gGAAgG;AAChG,wBAAgB,8BAA8B,CAC5C,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,qBAAqB,EACnD,QAAQ,EAAE,MAAM,GACf,aAAa,CAAC,OAAO,CAAC,CAUxB"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getLocalizedQuotaForEditSignup = exports.getLocalizedEvent = exports.getLocalizedEventListItem = void 0;
|
|
4
|
+
/** Overrides localized properties in the event and quotas with localized versions. */
|
|
5
|
+
function getLocalizedEventListItem(event, language) {
|
|
6
|
+
const locale = event.languages[language] ?? event;
|
|
7
|
+
return {
|
|
8
|
+
...event,
|
|
9
|
+
title: locale.title || event.title,
|
|
10
|
+
location: locale.location || event.location,
|
|
11
|
+
price: locale.price || event.price,
|
|
12
|
+
webpageUrl: locale.webpageUrl || event.webpageUrl,
|
|
13
|
+
facebookUrl: locale.facebookUrl || event.facebookUrl,
|
|
14
|
+
description: locale.description || event.description,
|
|
15
|
+
quotas: event.quotas.map((quota, index) => ({
|
|
16
|
+
...quota,
|
|
17
|
+
title: locale.quotas[index]?.title || quota.title,
|
|
18
|
+
})),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
exports.getLocalizedEventListItem = getLocalizedEventListItem;
|
|
22
|
+
/** Overrides localized properties in the event, quotas and questions with localized versions. */
|
|
23
|
+
function getLocalizedEvent(event, language) {
|
|
24
|
+
const locale = event.languages[language] ?? event;
|
|
25
|
+
return {
|
|
26
|
+
...event,
|
|
27
|
+
title: locale.title || event.title,
|
|
28
|
+
location: locale.location || event.location,
|
|
29
|
+
price: locale.price || event.price,
|
|
30
|
+
webpageUrl: locale.webpageUrl || event.webpageUrl,
|
|
31
|
+
facebookUrl: locale.facebookUrl || event.facebookUrl,
|
|
32
|
+
description: locale.description || event.description,
|
|
33
|
+
questions: event.questions.map((question, index) => ({
|
|
34
|
+
...question,
|
|
35
|
+
question: locale.questions[index]?.question || question.question,
|
|
36
|
+
options: locale.questions[index]?.options || question.options,
|
|
37
|
+
})),
|
|
38
|
+
quotas: event.quotas.map((quota, index) => ({
|
|
39
|
+
...quota,
|
|
40
|
+
title: locale.quotas[index]?.title || quota.title,
|
|
41
|
+
})),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
exports.getLocalizedEvent = getLocalizedEvent;
|
|
45
|
+
/** Overrides localized properties in the quota of the edited signup with localized versions. */
|
|
46
|
+
function getLocalizedQuotaForEditSignup({ event, signup: { quota } }, language) {
|
|
47
|
+
const locale = event.languages[language];
|
|
48
|
+
// Short circuit: don't attempt anything if we don't have the locale.
|
|
49
|
+
if (!locale)
|
|
50
|
+
return quota;
|
|
51
|
+
// This is a bit unfortunate, but we have to find the quota manually.
|
|
52
|
+
const quotaIndex = event.quotas.findIndex((q) => q.id === quota.id);
|
|
53
|
+
return {
|
|
54
|
+
...quota,
|
|
55
|
+
title: locale.quotas[quotaIndex]?.title ?? quota.title,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
exports.getLocalizedQuotaForEditSignup = getLocalizedQuotaForEditSignup;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare enum SignupState {
|
|
2
|
+
disabled = "disabled",
|
|
3
|
+
not_opened = "not_opened",
|
|
4
|
+
open = "open",
|
|
5
|
+
closed = "closed"
|
|
6
|
+
}
|
|
7
|
+
export type SignupStateInfo = {
|
|
8
|
+
state: SignupState.disabled;
|
|
9
|
+
} | {
|
|
10
|
+
state: SignupState.not_opened;
|
|
11
|
+
opens: Date;
|
|
12
|
+
} | {
|
|
13
|
+
state: SignupState.open;
|
|
14
|
+
closes: Date;
|
|
15
|
+
} | {
|
|
16
|
+
state: SignupState.closed;
|
|
17
|
+
closed: Date;
|
|
18
|
+
};
|
|
19
|
+
export declare function signupState(starts: string | null, closes: string | null): SignupStateInfo;
|
|
20
|
+
//# sourceMappingURL=signupState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signupState.d.ts","sourceRoot":"","sources":["../../src/utils/signupState.ts"],"names":[],"mappings":"AAAA,oBAAY,WAAW;IACrB,QAAQ,aAAa;IACrB,UAAU,eAAe;IACzB,IAAI,SAAS;IACb,MAAM,WAAW;CAClB;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAA;CAAE,GAC/B;IAAE,KAAK,EAAE,WAAW,CAAC,UAAU,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GAC9C;IAAE,KAAK,EAAE,WAAW,CAAC,IAAI,CAAC;IAAC,MAAM,EAAE,IAAI,CAAA;CAAE,GACzC;IAAE,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC;IAAC,MAAM,EAAE,IAAI,CAAA;CAAE,CAAC;AAEhD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,eAAe,CAkBzF"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.signupState = exports.SignupState = void 0;
|
|
4
|
+
var SignupState;
|
|
5
|
+
(function (SignupState) {
|
|
6
|
+
SignupState["disabled"] = "disabled";
|
|
7
|
+
SignupState["not_opened"] = "not_opened";
|
|
8
|
+
SignupState["open"] = "open";
|
|
9
|
+
SignupState["closed"] = "closed";
|
|
10
|
+
})(SignupState || (exports.SignupState = SignupState = {}));
|
|
11
|
+
function signupState(starts, closes) {
|
|
12
|
+
if (starts === null || closes === null) {
|
|
13
|
+
return { state: SignupState.disabled };
|
|
14
|
+
}
|
|
15
|
+
const signupOpens = new Date(starts);
|
|
16
|
+
const signupCloses = new Date(closes);
|
|
17
|
+
const now = new Date();
|
|
18
|
+
if (now < signupOpens) {
|
|
19
|
+
return { state: SignupState.not_opened, opens: signupOpens };
|
|
20
|
+
}
|
|
21
|
+
if (now < signupCloses) {
|
|
22
|
+
return { state: SignupState.open, closes: signupCloses };
|
|
23
|
+
}
|
|
24
|
+
return { state: SignupState.closed, closed: signupCloses };
|
|
25
|
+
}
|
|
26
|
+
exports.signupState = signupState;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { AdminEventResponse, QuotaID, QuotaWithSignupCount, UserEventResponse } from "@tietokilta/ilmomasiina-models";
|
|
2
|
+
import { SignupStatus } from "@tietokilta/ilmomasiina-models";
|
|
3
|
+
export type AnyEventSchema = AdminEventResponse | UserEventResponse;
|
|
4
|
+
/** Grabs the signup type from {Admin,User}EventSchema and adds a reference to the quota. */
|
|
5
|
+
export type SignupWithQuota<Ev extends AnyEventSchema = AnyEventSchema> = Ev["quotas"][number]["signups"][number] & {
|
|
6
|
+
quota: Ev["quotas"][number];
|
|
7
|
+
};
|
|
8
|
+
export declare function getSignupsAsList<Ev extends AnyEventSchema>(event: Ev): SignupWithQuota<Ev>[];
|
|
9
|
+
/** Computes the number of signups in the open quota and queue. */
|
|
10
|
+
export declare function countOverflowSignups(quotas: QuotaWithSignupCount[], openQuotaSize: number): {
|
|
11
|
+
openQuotaCount: number;
|
|
12
|
+
queueCount: number;
|
|
13
|
+
};
|
|
14
|
+
/** Expands the quota type from {Admin,User}EventSchema, makes quota properties nullable and adds references to quota. */
|
|
15
|
+
export type QuotaSignups<Ev extends AnyEventSchema = AnyEventSchema> = Omit<Ev["quotas"][number], "id" | "title" | "size"> & {
|
|
16
|
+
type: SignupStatus;
|
|
17
|
+
id: QuotaID | null;
|
|
18
|
+
title: string | null;
|
|
19
|
+
size: number | null;
|
|
20
|
+
signups: SignupWithQuota<Ev>[];
|
|
21
|
+
};
|
|
22
|
+
/** Gathers all signups of an event into their assigned quotas, the open quota, and the queue. */
|
|
23
|
+
export declare function getSignupsByQuota(event: AnyEventSchema): QuotaSignups[];
|
|
24
|
+
/** Formats an answer for display. */
|
|
25
|
+
export declare function stringifyAnswer(answer: string | string[] | undefined): string;
|
|
26
|
+
//# sourceMappingURL=signupUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signupUtils.d.ts","sourceRoot":"","sources":["../../src/utils/signupUtils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,kBAAkB,EAClB,OAAO,EACP,oBAAoB,EACpB,iBAAiB,EAClB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAG9D,MAAM,MAAM,cAAc,GAAG,kBAAkB,GAAG,iBAAiB,CAAC;AAEpE,4FAA4F;AAC5F,MAAM,MAAM,eAAe,CAAC,EAAE,SAAS,cAAc,GAAG,cAAc,IAAI,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,GAAG;IAClH,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;CAC7B,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,EAAE,SAAS,cAAc,EAAE,KAAK,EAAE,EAAE,GAAG,eAAe,CAAC,EAAE,CAAC,EAAE,CAQ5F;AAED,kEAAkE;AAClE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB,EAAE,EAAE,aAAa,EAAE,MAAM;;;EAMzF;AAED,yHAAyH;AACzH,MAAM,MAAM,YAAY,CAAC,EAAE,SAAS,cAAc,GAAG,cAAc,IAAI,IAAI,CACzE,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EACpB,IAAI,GAAG,OAAO,GAAG,MAAM,CACxB,GAAG;IACF,IAAI,EAAE,YAAY,CAAC;IACnB,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,eAAe,CAAC,EAAE,CAAC,EAAE,CAAC;CAChC,CAAC;AAEF,iGAAiG;AACjG,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,GAAG,YAAY,EAAE,CAuDvE;AAED,qCAAqC;AACrC,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,UAEpE"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.stringifyAnswer = exports.getSignupsByQuota = exports.countOverflowSignups = exports.getSignupsAsList = void 0;
|
|
7
|
+
const sumBy_1 = __importDefault(require("lodash-es/sumBy"));
|
|
8
|
+
const ilmomasiina_models_1 = require("@tietokilta/ilmomasiina-models");
|
|
9
|
+
const signupState_1 = require("./signupState");
|
|
10
|
+
function getSignupsAsList(event) {
|
|
11
|
+
return event.quotas.flatMap((quota) => quota.signups?.map((signup) => ({
|
|
12
|
+
...signup,
|
|
13
|
+
quota,
|
|
14
|
+
})) ?? []);
|
|
15
|
+
}
|
|
16
|
+
exports.getSignupsAsList = getSignupsAsList;
|
|
17
|
+
/** Computes the number of signups in the open quota and queue. */
|
|
18
|
+
function countOverflowSignups(quotas, openQuotaSize) {
|
|
19
|
+
const overflow = (0, sumBy_1.default)(quotas, (quota) => Math.max(0, quota.signupCount - (quota.size ?? Infinity)));
|
|
20
|
+
return {
|
|
21
|
+
openQuotaCount: Math.min(overflow, openQuotaSize),
|
|
22
|
+
queueCount: Math.max(overflow - openQuotaSize, 0),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
exports.countOverflowSignups = countOverflowSignups;
|
|
26
|
+
/** Gathers all signups of an event into their assigned quotas, the open quota, and the queue. */
|
|
27
|
+
function getSignupsByQuota(event) {
|
|
28
|
+
const signupsDisabled = (0, signupState_1.signupState)(event.registrationStartDate, event.registrationEndDate).state === signupState_1.SignupState.disabled;
|
|
29
|
+
const signups = getSignupsAsList(event);
|
|
30
|
+
const quotas = [
|
|
31
|
+
...event.quotas
|
|
32
|
+
// If the event does not have signups, only show quotas that somehow still have signups within.
|
|
33
|
+
.filter((quota) => !signupsDisabled || quota.signupCount > 0)
|
|
34
|
+
.map((quota) => {
|
|
35
|
+
const quotaSignups = signups.filter((signup) => signup.quota.id === quota.id && signup.status === "in-quota");
|
|
36
|
+
return {
|
|
37
|
+
...quota,
|
|
38
|
+
type: ilmomasiina_models_1.SignupStatus.IN_QUOTA,
|
|
39
|
+
signups: quotaSignups,
|
|
40
|
+
// Trust signupCount and size, unless we have concrete information that more signups exist
|
|
41
|
+
signupCount: Math.max(quotaSignups.length, Math.min(quota.signupCount, quota.size ?? Infinity)),
|
|
42
|
+
};
|
|
43
|
+
}),
|
|
44
|
+
];
|
|
45
|
+
const { openQuotaCount, queueCount } = countOverflowSignups(event.quotas, event.openQuotaSize);
|
|
46
|
+
const openSignups = signups.filter((signup) => signup.status === "in-open");
|
|
47
|
+
// Open quota is shown if the event has one, or if signups have been assigned there nevertheless.
|
|
48
|
+
const openQuota = openSignups.length > 0 || (!signupsDisabled && event.openQuotaSize > 0)
|
|
49
|
+
? [
|
|
50
|
+
{
|
|
51
|
+
type: ilmomasiina_models_1.SignupStatus.IN_OPEN_QUOTA,
|
|
52
|
+
id: null,
|
|
53
|
+
title: null,
|
|
54
|
+
size: event.openQuotaSize,
|
|
55
|
+
signups: openSignups,
|
|
56
|
+
signupCount: Math.max(openQuotaCount, openSignups.length),
|
|
57
|
+
},
|
|
58
|
+
]
|
|
59
|
+
: [];
|
|
60
|
+
const queueSignups = signups.filter((signup) => signup.status === "in-queue");
|
|
61
|
+
// Queue is shown if signups have been assigned there.
|
|
62
|
+
const queue = queueSignups.length > 0
|
|
63
|
+
? [
|
|
64
|
+
{
|
|
65
|
+
type: ilmomasiina_models_1.SignupStatus.IN_QUEUE,
|
|
66
|
+
id: null,
|
|
67
|
+
title: null,
|
|
68
|
+
size: null,
|
|
69
|
+
signups: queueSignups,
|
|
70
|
+
signupCount: Math.max(queueCount, queueSignups.length),
|
|
71
|
+
},
|
|
72
|
+
]
|
|
73
|
+
: [];
|
|
74
|
+
return [...quotas, ...openQuota, ...queue];
|
|
75
|
+
}
|
|
76
|
+
exports.getSignupsByQuota = getSignupsByQuota;
|
|
77
|
+
/** Formats an answer for display. */
|
|
78
|
+
function stringifyAnswer(answer) {
|
|
79
|
+
return Array.isArray(answer) ? answer.join(", ") : (answer ?? "");
|
|
80
|
+
}
|
|
81
|
+
exports.stringifyAnswer = stringifyAnswer;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
export declare const MISSING: unique symbol;
|
|
3
|
+
/** Creates a React context and an associated hook that only works inside the Provider. */
|
|
4
|
+
export declare function createStateContext<State>(): {
|
|
5
|
+
Context: import("react").Context<typeof MISSING | State>;
|
|
6
|
+
Provider: import("react").Provider<typeof MISSING | State>;
|
|
7
|
+
useStateContext: () => State;
|
|
8
|
+
createThunk: <A extends any[], R>(action: (state: State) => (...args: A) => R) => () => (...args: A) => R;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=stateContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stateContext.d.ts","sourceRoot":"","sources":["../../src/utils/stateContext.tsx"],"names":[],"mappings":";AAEA,eAAO,MAAM,OAAO,eAAoB,CAAC;AAEzC,0FAA0F;AAC1F,wBAAgB,kBAAkB,CAAC,KAAK;;;;sDAWmB,KAAK;EAa/D"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createStateContext = exports.MISSING = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
exports.MISSING = Symbol("missing");
|
|
6
|
+
/** Creates a React context and an associated hook that only works inside the Provider. */
|
|
7
|
+
function createStateContext() {
|
|
8
|
+
const Context = (0, react_1.createContext)(exports.MISSING);
|
|
9
|
+
/** React hook that fetches the state via a context. */
|
|
10
|
+
function useStateContext() {
|
|
11
|
+
const context = (0, react_1.useContext)(Context);
|
|
12
|
+
if (context === exports.MISSING)
|
|
13
|
+
throw new Error("useStateContext used outside corresponding Provider");
|
|
14
|
+
return context;
|
|
15
|
+
}
|
|
16
|
+
/** Wraps a function into a React hook that provides it with state. */
|
|
17
|
+
function createThunk(action) {
|
|
18
|
+
return () => {
|
|
19
|
+
const state = useStateContext();
|
|
20
|
+
return action(state);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
Context,
|
|
25
|
+
Provider: Context.Provider,
|
|
26
|
+
useStateContext,
|
|
27
|
+
createThunk,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
exports.createStateContext = createStateContext;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useShallowMemo.d.ts","sourceRoot":"","sources":["../../src/utils/useShallowMemo.ts"],"names":[],"mappings":"AAwBA,uGAAuG;AACvG,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAIrD"}
|