wedance-shared 1.0.158 → 1.0.161

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/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./types/index.js";
2
2
  export * from "./utils/date.js";
3
3
  export * from "./utils/string.js";
4
+ export * from "./utils/ticket.js";
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./types/index.js";
2
2
  export * from "./utils/date.js";
3
3
  export * from "./utils/string.js";
4
+ export * from "./utils/ticket.js";
4
5
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC"}
@@ -11,4 +11,5 @@ export * from "./support.js";
11
11
  export * from "./coupons.js";
12
12
  export * from "./checkin.js";
13
13
  export * from "./pass.js";
14
+ export * from "./poll.js";
14
15
  export * from "./festivals/index.js";
@@ -12,6 +12,7 @@ export * from "./support.js";
12
12
  export * from "./coupons.js";
13
13
  export * from "./checkin.js";
14
14
  export * from "./pass.js";
15
+ export * from "./poll.js";
15
16
  // Re-export from subdirectories
16
17
  export * from "./festivals/index.js";
17
18
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAE1B,gCAAgC;AAChC,cAAc,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAE1B,gCAAgC;AAChC,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1,102 @@
1
+ import { LanguageCode } from "./other.js";
2
+ /**
3
+ * Mirrors the `{ fi, en }` shape already used by `Organizer.description`.
4
+ */
5
+ export type LocalizedText = {
6
+ en: string;
7
+ fi: string;
8
+ };
9
+ export type PollQuestionType = "single_choice" | "multi_choice" | "text";
10
+ export type PollQuestionOption = {
11
+ /** Stable human-readable slug, e.g. "weekly". Never renamed after publish. */
12
+ id: string;
13
+ label: LocalizedText;
14
+ };
15
+ export type PollQuestion = {
16
+ /** Stable slug, unique within the poll, e.g. "q1". */
17
+ id: string;
18
+ type: PollQuestionType;
19
+ body: LocalizedText;
20
+ /** Present for "single" and "multi". Omitted for "text". */
21
+ options?: PollQuestionOption[];
22
+ /** "multi" only. Omit for no limit. */
23
+ maxSelections?: number;
24
+ isRequired: boolean;
25
+ };
26
+ /**
27
+ * Row shape for `public.polls`.
28
+ */
29
+ export type Poll = {
30
+ id: string;
31
+ title: LocalizedText;
32
+ description: LocalizedText | null;
33
+ questions: PollQuestion[];
34
+ startsAt: string;
35
+ endsAt: string;
36
+ createdAt: string;
37
+ updatedAt: string;
38
+ status: "draft" | "published" | "archived";
39
+ };
40
+ /**
41
+ * Answer value per question type:
42
+ * - "single" → option id
43
+ * - "multi" → option ids
44
+ * - "text" → the raw text
45
+ */
46
+ export type PollAnswerValue = string | string[];
47
+ export type PollAnswers = Record<string, PollAnswerValue>;
48
+ /**
49
+ * Row shape for `public.poll_responses`.
50
+ */
51
+ export type PollResponse = {
52
+ id: string;
53
+ pollId: string;
54
+ userId: string;
55
+ answers: PollAnswers;
56
+ /** Snapshot of the user's city at submit time. */
57
+ city: string | null;
58
+ /** Language the app was in when answering. */
59
+ language: LanguageCode | null;
60
+ createdAt: string;
61
+ };
62
+ /** `GET /polls/active` — null when no poll is running. */
63
+ export type ActivePollResponse = {
64
+ poll: Poll;
65
+ hasAnswered: boolean;
66
+ } | null;
67
+ /** `POST /polls/:id/responses` */
68
+ export type SubmitPollResponseInput = {
69
+ answers: PollAnswers;
70
+ language?: LanguageCode;
71
+ };
72
+ export type PollOptionTally = {
73
+ optionId: string;
74
+ count: number;
75
+ /** 0–100, rounded to one decimal. */
76
+ percentage: number;
77
+ };
78
+ export type PollQuestionResults = {
79
+ questionId: string;
80
+ type: PollQuestionType;
81
+ /** Choice questions only. */
82
+ tallies?: PollOptionTally[];
83
+ /** Text questions only — admin-visible, for manual quote selection. */
84
+ textAnswers?: {
85
+ text: string;
86
+ city: string | null;
87
+ language: LanguageCode | null;
88
+ }[];
89
+ /** Responses that answered this question. */
90
+ answeredCount: number;
91
+ };
92
+ /** `GET /polls/:id/results` — admin only. */
93
+ export type PollResults = {
94
+ pollId: string;
95
+ totalResponses: number;
96
+ /** Response counts per city, descending. */
97
+ byCity: {
98
+ city: string;
99
+ count: number;
100
+ }[];
101
+ questions: PollQuestionResults[];
102
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=poll.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"poll.js","sourceRoot":"","sources":["../../src/types/poll.ts"],"names":[],"mappings":""}
@@ -78,7 +78,12 @@ export type TicketTransfer = {
78
78
  toUserId: string;
79
79
  timestamp: Timestamp;
80
80
  };
81
- export type EventTicket = {
81
+ /**
82
+ * Fields shared by every product sold through the `ticket_types` table, regardless
83
+ * of `productType`. Exported so consumers can type "any ticket" for forms and table
84
+ * rows without narrowing; use {@link TicketType} when the variant matters.
85
+ */
86
+ export type TicketTypeBase = {
82
87
  id: string;
83
88
  /**
84
89
  * ID from firebase firestore
@@ -89,7 +94,6 @@ export type EventTicket = {
89
94
  */
90
95
  externalEventTicketId: string | null | undefined;
91
96
  price_details: MonetaryAmount;
92
- eventId: string;
93
97
  quantity: number;
94
98
  showQuantity: boolean;
95
99
  /**
@@ -117,6 +121,20 @@ export type EventTicket = {
117
121
  * Promotional period for the ticket
118
122
  */
119
123
  promotionalPeriod: PromotionalPeriod | null;
124
+ organizerId: string;
125
+ };
126
+ /**
127
+ * A ticket sold for one specific event. The only variant currently written in
128
+ * production — the server hardcodes `product_type = 'event'` on insert.
129
+ */
130
+ export type EventTicketType = TicketTypeBase & {
131
+ productType: "event";
132
+ eventId: string;
133
+ credits?: never;
134
+ validityDays?: never;
135
+ validFrom?: never;
136
+ validUntil?: never;
137
+ seriesId?: never;
120
138
  /**
121
139
  * @deprecated Replaced by name
122
140
  */
@@ -125,14 +143,77 @@ export type EventTicket = {
125
143
  * @deprecated Replaced by price_details
126
144
  */
127
145
  price?: number;
128
- productType: ProductType;
129
- credits: number | null;
146
+ };
147
+ /**
148
+ * Single-class drop-in. May be attached to a specific event, or sold standalone
149
+ * and redeemed against any qualifying class.
150
+ */
151
+ export type DropInTicketType = TicketTypeBase & {
152
+ productType: "drop_in";
153
+ eventId: string | null;
154
+ credits?: never;
155
+ seriesId?: never;
156
+ validityDays?: never;
157
+ validFrom?: never;
158
+ validUntil?: never;
159
+ };
160
+ /**
161
+ * A bundle of N classes. Not tied to any event.
162
+ */
163
+ export type PassTicketType = TicketTypeBase & {
164
+ productType: "pass";
165
+ eventId: null;
166
+ /**
167
+ * Number of classes the pass is worth. Required and non-nullable: a pass with
168
+ * no credit count is a misconfiguration, not a meaningful state. Encoding this
169
+ * in the type prevents the `credits ?? 1` fallback that silently turned a
170
+ * 10-class pass into a 1-credit pass.
171
+ */
172
+ credits: number;
130
173
  validityDays: number | null;
131
174
  validFrom: string | null;
132
175
  validUntil: string | null;
133
- organizerId: string;
134
- seriesId: string | null;
176
+ seriesId?: never;
177
+ };
178
+ /**
179
+ * Unlimited access for a period. Deliberately has **no** `credits` field —
180
+ * "unlimited" is expressed structurally by the field's absence rather than by a
181
+ * `null` that would be indistinguishable from a misconfigured pass.
182
+ */
183
+ export type MembershipTicketType = TicketTypeBase & {
184
+ productType: "membership";
185
+ eventId: null;
186
+ credits?: never;
187
+ validityDays: number | null;
188
+ validFrom: string | null;
189
+ validUntil: string | null;
190
+ seriesId?: never;
191
+ };
192
+ /**
193
+ * Enrollment in a course series. Always belongs to a series; `credits` is
194
+ * nullable here because a course may grant a fixed number of sessions or cover
195
+ * the whole series.
196
+ */
197
+ export type CourseTicketType = TicketTypeBase & {
198
+ productType: "course";
199
+ eventId: null;
200
+ seriesId: string;
201
+ credits: number | null;
202
+ validityDays?: never;
203
+ validFrom?: never;
204
+ validUntil?: never;
135
205
  };
206
+ /**
207
+ * Anything sellable from the `ticket_types` table, discriminated on
208
+ * `productType`. Narrow with a `switch (t.productType)` or with the
209
+ * `is*TicketType` guards before reading variant-specific fields.
210
+ */
211
+ export type TicketType = EventTicketType | DropInTicketType | PassTicketType | MembershipTicketType | CourseTicketType;
212
+ /**
213
+ * @deprecated Prefer the explicit {@link EventTicketType}, or {@link TicketType}
214
+ * when the product may not be an event. Retained for backward compatibility.
215
+ */
216
+ export type EventTicket = EventTicketType;
136
217
  export type ProductType = "event" | "drop_in" | "pass" | "membership" | "course";
137
218
  export type EventTicketStatus = "published" | "draft" | "sold-out" | "unavailable";
138
219
  export type PromotionalPeriod = {
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Narrowing helpers for the {@link TicketType} discriminated union.
3
+ *
4
+ * At an API boundary the value arrives as `unknown` (parsed JSON), so narrow in
5
+ * two steps:
6
+ *
7
+ * ```ts
8
+ * const json: unknown = await res.json();
9
+ * if (!isTicketType(json)) throw new Error("not a ticket type");
10
+ * // json is TicketType here
11
+ * if (isPassTicketType(json)) {
12
+ * json.credits; // number — required and non-nullable on a pass
13
+ * }
14
+ * ```
15
+ *
16
+ * Inside code that already holds a `TicketType`, prefer an exhaustive
17
+ * `switch (t.productType)` over chained guards — the compiler will then flag any
18
+ * variant added later.
19
+ */
20
+ import type { CourseTicketType, DropInTicketType, EventTicketType, MembershipTicketType, PassTicketType, TicketType } from "../types/ticket.js";
21
+ /**
22
+ * Shallow structural check for use at API boundaries where the value is
23
+ * `unknown`. Verifies the discriminant and the fields common to every variant —
24
+ * it does not validate variant-specific fields, so it is a gate against
25
+ * malformed payloads rather than a full schema validation.
26
+ */
27
+ export declare const isTicketType: (value: unknown) => value is TicketType;
28
+ export declare const isEventTicketType: (t: TicketType) => t is EventTicketType;
29
+ export declare const isDropInTicketType: (t: TicketType) => t is DropInTicketType;
30
+ export declare const isPassTicketType: (t: TicketType) => t is PassTicketType;
31
+ export declare const isMembershipTicketType: (t: TicketType) => t is MembershipTicketType;
32
+ export declare const isCourseTicketType: (t: TicketType) => t is CourseTicketType;
@@ -0,0 +1,28 @@
1
+ const PRODUCT_TYPES = [
2
+ "event",
3
+ "drop_in",
4
+ "pass",
5
+ "membership",
6
+ "course"
7
+ ];
8
+ /**
9
+ * Shallow structural check for use at API boundaries where the value is
10
+ * `unknown`. Verifies the discriminant and the fields common to every variant —
11
+ * it does not validate variant-specific fields, so it is a gate against
12
+ * malformed payloads rather than a full schema validation.
13
+ */
14
+ export const isTicketType = (value) => {
15
+ if (typeof value !== "object" || value === null)
16
+ return false;
17
+ const candidate = value;
18
+ return (typeof candidate.id === "string" &&
19
+ typeof candidate.name === "string" &&
20
+ typeof candidate.productType === "string" &&
21
+ PRODUCT_TYPES.includes(candidate.productType));
22
+ };
23
+ export const isEventTicketType = (t) => t.productType === "event";
24
+ export const isDropInTicketType = (t) => t.productType === "drop_in";
25
+ export const isPassTicketType = (t) => t.productType === "pass";
26
+ export const isMembershipTicketType = (t) => t.productType === "membership";
27
+ export const isCourseTicketType = (t) => t.productType === "course";
28
+ //# sourceMappingURL=ticket.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ticket.js","sourceRoot":"","sources":["../../src/utils/ticket.ts"],"names":[],"mappings":"AA6BA,MAAM,aAAa,GAA2B;IAC5C,OAAO;IACP,SAAS;IACT,MAAM;IACN,YAAY;IACZ,QAAQ;CACT,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAc,EAAuB,EAAE;IAClE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,SAAS,GAAG,KAAgC,CAAC;IACnD,OAAO,CACL,OAAO,SAAS,CAAC,EAAE,KAAK,QAAQ;QAChC,OAAO,SAAS,CAAC,IAAI,KAAK,QAAQ;QAClC,OAAO,SAAS,CAAC,WAAW,KAAK,QAAQ;QACzC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,WAA0B,CAAC,CAC7D,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAa,EAAwB,EAAE,CACvE,CAAC,CAAC,WAAW,KAAK,OAAO,CAAC;AAE5B,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAa,EAAyB,EAAE,CACzE,CAAC,CAAC,WAAW,KAAK,SAAS,CAAC;AAE9B,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAa,EAAuB,EAAE,CACrE,CAAC,CAAC,WAAW,KAAK,MAAM,CAAC;AAE3B,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,CAAa,EACc,EAAE,CAAC,CAAC,CAAC,WAAW,KAAK,YAAY,CAAC;AAE/D,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAa,EAAyB,EAAE,CACzE,CAAC,CAAC,WAAW,KAAK,QAAQ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wedance-shared",
3
- "version": "1.0.158",
3
+ "version": "1.0.161",
4
4
  "description": "This repository contains shared TypeScript types and interfaces used across multiple WeDance applications:",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",