convex-polls 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +513 -0
  3. package/dist/client/_generated/_ignore.d.ts +1 -0
  4. package/dist/client/_generated/_ignore.d.ts.map +1 -0
  5. package/dist/client/_generated/_ignore.js +3 -0
  6. package/dist/client/_generated/_ignore.js.map +1 -0
  7. package/dist/client/index.d.ts +184 -0
  8. package/dist/client/index.d.ts.map +1 -0
  9. package/dist/client/index.js +128 -0
  10. package/dist/client/index.js.map +1 -0
  11. package/dist/component/_generated/api.d.ts +36 -0
  12. package/dist/component/_generated/api.d.ts.map +1 -0
  13. package/dist/component/_generated/api.js +31 -0
  14. package/dist/component/_generated/api.js.map +1 -0
  15. package/dist/component/_generated/component.d.ts +118 -0
  16. package/dist/component/_generated/component.d.ts.map +1 -0
  17. package/dist/component/_generated/component.js +11 -0
  18. package/dist/component/_generated/component.js.map +1 -0
  19. package/dist/component/_generated/dataModel.d.ts +46 -0
  20. package/dist/component/_generated/dataModel.d.ts.map +1 -0
  21. package/dist/component/_generated/dataModel.js +11 -0
  22. package/dist/component/_generated/dataModel.js.map +1 -0
  23. package/dist/component/_generated/server.d.ts +121 -0
  24. package/dist/component/_generated/server.d.ts.map +1 -0
  25. package/dist/component/_generated/server.js +78 -0
  26. package/dist/component/_generated/server.js.map +1 -0
  27. package/dist/component/convex.config.d.ts +3 -0
  28. package/dist/component/convex.config.d.ts.map +1 -0
  29. package/dist/component/convex.config.js +3 -0
  30. package/dist/component/convex.config.js.map +1 -0
  31. package/dist/component/polls.d.ts +78 -0
  32. package/dist/component/polls.d.ts.map +1 -0
  33. package/dist/component/polls.js +235 -0
  34. package/dist/component/polls.js.map +1 -0
  35. package/dist/component/schema.d.ts +92 -0
  36. package/dist/component/schema.d.ts.map +1 -0
  37. package/dist/component/schema.js +38 -0
  38. package/dist/component/schema.js.map +1 -0
  39. package/dist/component/votes.d.ts +15 -0
  40. package/dist/component/votes.d.ts.map +1 -0
  41. package/dist/component/votes.js +105 -0
  42. package/dist/component/votes.js.map +1 -0
  43. package/dist/react/index.d.ts +27 -0
  44. package/dist/react/index.d.ts.map +1 -0
  45. package/dist/react/index.js +33 -0
  46. package/dist/react/index.js.map +1 -0
  47. package/package.json +107 -0
  48. package/src/client/_generated/_ignore.ts +1 -0
  49. package/src/client/index.test.ts +90 -0
  50. package/src/client/index.ts +259 -0
  51. package/src/client/setup.test.ts +26 -0
  52. package/src/component/_generated/api.ts +52 -0
  53. package/src/component/_generated/component.ts +145 -0
  54. package/src/component/_generated/dataModel.ts +60 -0
  55. package/src/component/_generated/server.ts +156 -0
  56. package/src/component/convex.config.ts +3 -0
  57. package/src/component/polls.test.ts +202 -0
  58. package/src/component/polls.ts +268 -0
  59. package/src/component/schema.ts +46 -0
  60. package/src/component/setup.test.ts +11 -0
  61. package/src/component/votes.test.ts +356 -0
  62. package/src/component/votes.ts +153 -0
  63. package/src/react/index.ts +85 -0
  64. package/src/test.ts +18 -0
@@ -0,0 +1,78 @@
1
+ export declare const create: import("convex/server").RegisteredMutation<"public", {
2
+ config?: {
3
+ allowMultipleVotes?: boolean | undefined;
4
+ allowChangeVote?: boolean | undefined;
5
+ showResultsBeforeVote?: boolean | undefined;
6
+ closesAt?: number | undefined;
7
+ maxVotesPerUser?: number | undefined;
8
+ } | undefined;
9
+ description?: string | undefined;
10
+ title: string;
11
+ options: string[];
12
+ createdBy: string;
13
+ }, Promise<import("convex/values").GenericId<"polls">>>;
14
+ export declare const get: import("convex/server").RegisteredQuery<"public", {
15
+ voterId?: string | undefined;
16
+ pollId: import("convex/values").GenericId<"polls">;
17
+ }, Promise<{
18
+ results: {
19
+ id: string;
20
+ text: string;
21
+ votes: number;
22
+ percentage: number;
23
+ }[];
24
+ totalVotes: number;
25
+ userVotes: string[];
26
+ _id: import("convex/values").GenericId<"polls">;
27
+ _creationTime: number;
28
+ description?: string | undefined;
29
+ closedAt?: number | undefined;
30
+ status: "active" | "closed" | "scheduled";
31
+ config: {
32
+ closesAt?: number | undefined;
33
+ maxVotesPerUser?: number | undefined;
34
+ allowMultipleVotes: boolean;
35
+ allowChangeVote: boolean;
36
+ showResultsBeforeVote: boolean;
37
+ };
38
+ title: string;
39
+ options: {
40
+ id: string;
41
+ text: string;
42
+ }[];
43
+ createdBy: string;
44
+ createdAt: number;
45
+ } | null>>;
46
+ export declare const list: import("convex/server").RegisteredQuery<"public", {
47
+ status?: "active" | "closed" | "scheduled" | undefined;
48
+ createdBy?: string | undefined;
49
+ limit?: number | undefined;
50
+ }, Promise<{
51
+ totalVotes: number;
52
+ _id: import("convex/values").GenericId<"polls">;
53
+ _creationTime: number;
54
+ description?: string | undefined;
55
+ closedAt?: number | undefined;
56
+ status: "active" | "closed" | "scheduled";
57
+ config: {
58
+ closesAt?: number | undefined;
59
+ maxVotesPerUser?: number | undefined;
60
+ allowMultipleVotes: boolean;
61
+ allowChangeVote: boolean;
62
+ showResultsBeforeVote: boolean;
63
+ };
64
+ title: string;
65
+ options: {
66
+ id: string;
67
+ text: string;
68
+ }[];
69
+ createdBy: string;
70
+ createdAt: number;
71
+ }[]>>;
72
+ export declare const close: import("convex/server").RegisteredMutation<"public", {
73
+ pollId: import("convex/values").GenericId<"polls">;
74
+ }, Promise<null>>;
75
+ export declare const remove: import("convex/server").RegisteredMutation<"public", {
76
+ pollId: import("convex/values").GenericId<"polls">;
77
+ }, Promise<null>>;
78
+ //# sourceMappingURL=polls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"polls.d.ts","sourceRoot":"","sources":["../../src/component/polls.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,MAAM;;;;;;;;;;;;uDAoEjB,CAAC;AAyBH,eAAO,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA4Cd,CAAC;AAgBH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;KA6Df,CAAC;AAEH,eAAO,MAAM,KAAK;;iBAmBhB,CAAC;AAEH,eAAO,MAAM,MAAM;;iBAsBjB,CAAC"}
@@ -0,0 +1,235 @@
1
+ import { v } from "convex/values";
2
+ import { mutation, query } from "./_generated/server.js";
3
+ import { optionValidator, configValidator, statusValidator, } from "./schema.js";
4
+ export const create = mutation({
5
+ args: {
6
+ title: v.string(),
7
+ description: v.optional(v.string()),
8
+ options: v.array(v.string()),
9
+ createdBy: v.string(),
10
+ config: v.optional(v.object({
11
+ allowMultipleVotes: v.optional(v.boolean()),
12
+ allowChangeVote: v.optional(v.boolean()),
13
+ showResultsBeforeVote: v.optional(v.boolean()),
14
+ closesAt: v.optional(v.number()),
15
+ maxVotesPerUser: v.optional(v.number()),
16
+ })),
17
+ },
18
+ returns: v.id("polls"),
19
+ handler: async (ctx, args) => {
20
+ if (args.title.trim().length === 0) {
21
+ throw new Error("Poll title cannot be empty.");
22
+ }
23
+ if (args.options.length < 2) {
24
+ throw new Error("A poll requires at least 2 options.");
25
+ }
26
+ for (const opt of args.options) {
27
+ if (opt.trim().length === 0) {
28
+ throw new Error("Poll options cannot be empty.");
29
+ }
30
+ }
31
+ const uniqueTexts = new Set(args.options.map((o) => o.trim().toLowerCase()));
32
+ if (uniqueTexts.size !== args.options.length) {
33
+ throw new Error("Duplicate option text is not allowed. Each option must be unique.");
34
+ }
35
+ const options = args.options.map((text, i) => ({
36
+ id: `opt_${i}`,
37
+ text,
38
+ }));
39
+ const config = {
40
+ allowMultipleVotes: args.config?.allowMultipleVotes ?? false,
41
+ allowChangeVote: args.config?.allowChangeVote ?? false,
42
+ showResultsBeforeVote: args.config?.showResultsBeforeVote ?? true,
43
+ closesAt: args.config?.closesAt,
44
+ maxVotesPerUser: args.config?.maxVotesPerUser,
45
+ };
46
+ if (config.maxVotesPerUser !== undefined &&
47
+ config.maxVotesPerUser < 1) {
48
+ throw new Error("maxVotesPerUser must be at least 1.");
49
+ }
50
+ const pollId = await ctx.db.insert("polls", {
51
+ title: args.title.trim(),
52
+ description: args.description?.trim(),
53
+ options,
54
+ createdBy: args.createdBy,
55
+ status: "active",
56
+ config,
57
+ createdAt: Date.now(),
58
+ });
59
+ return pollId;
60
+ },
61
+ });
62
+ const pollResultValidator = v.object({
63
+ id: v.string(),
64
+ text: v.string(),
65
+ votes: v.number(),
66
+ percentage: v.number(),
67
+ });
68
+ const pollWithResultsValidator = v.object({
69
+ _id: v.id("polls"),
70
+ _creationTime: v.number(),
71
+ title: v.string(),
72
+ description: v.optional(v.string()),
73
+ options: v.array(optionValidator),
74
+ createdBy: v.string(),
75
+ status: statusValidator,
76
+ config: configValidator,
77
+ createdAt: v.number(),
78
+ closedAt: v.optional(v.number()),
79
+ results: v.array(pollResultValidator),
80
+ totalVotes: v.number(),
81
+ userVotes: v.array(v.string()),
82
+ });
83
+ export const get = query({
84
+ args: {
85
+ pollId: v.id("polls"),
86
+ voterId: v.optional(v.string()),
87
+ },
88
+ returns: v.union(v.null(), pollWithResultsValidator),
89
+ handler: async (ctx, args) => {
90
+ const poll = await ctx.db.get(args.pollId);
91
+ if (!poll)
92
+ return null;
93
+ const allVotes = await ctx.db
94
+ .query("votes")
95
+ .withIndex("by_poll", (q) => q.eq("pollId", args.pollId))
96
+ .collect();
97
+ const voteCounts = {};
98
+ const userVoteOptionIds = [];
99
+ for (const vote of allVotes) {
100
+ voteCounts[vote.optionId] = (voteCounts[vote.optionId] ?? 0) + 1;
101
+ if (args.voterId && vote.voterId === args.voterId) {
102
+ userVoteOptionIds.push(vote.optionId);
103
+ }
104
+ }
105
+ const totalVotes = allVotes.length;
106
+ const results = poll.options.map((opt) => {
107
+ const count = voteCounts[opt.id] ?? 0;
108
+ return {
109
+ id: opt.id,
110
+ text: opt.text,
111
+ votes: count,
112
+ percentage: totalVotes > 0 ? (count / totalVotes) * 100 : 0,
113
+ };
114
+ });
115
+ return {
116
+ ...poll,
117
+ results,
118
+ totalVotes,
119
+ userVotes: userVoteOptionIds,
120
+ };
121
+ },
122
+ });
123
+ const pollListItemValidator = v.object({
124
+ _id: v.id("polls"),
125
+ _creationTime: v.number(),
126
+ title: v.string(),
127
+ description: v.optional(v.string()),
128
+ options: v.array(optionValidator),
129
+ createdBy: v.string(),
130
+ status: statusValidator,
131
+ config: configValidator,
132
+ createdAt: v.number(),
133
+ closedAt: v.optional(v.number()),
134
+ totalVotes: v.number(),
135
+ });
136
+ export const list = query({
137
+ args: {
138
+ status: v.optional(statusValidator),
139
+ createdBy: v.optional(v.string()),
140
+ limit: v.optional(v.number()),
141
+ },
142
+ returns: v.array(pollListItemValidator),
143
+ handler: async (ctx, args) => {
144
+ const limit = args.limit ?? 50;
145
+ let polls;
146
+ if (args.status !== undefined && args.createdBy !== undefined) {
147
+ const allMatching = await ctx.db
148
+ .query("polls")
149
+ .withIndex("by_status", (q) => q.eq("status", args.status))
150
+ .order("desc")
151
+ .collect();
152
+ polls = allMatching
153
+ .filter((p) => p.createdBy === args.createdBy)
154
+ .slice(0, limit);
155
+ }
156
+ else if (args.status !== undefined) {
157
+ polls = await ctx.db
158
+ .query("polls")
159
+ .withIndex("by_status", (q) => q.eq("status", args.status))
160
+ .order("desc")
161
+ .take(limit);
162
+ }
163
+ else if (args.createdBy !== undefined) {
164
+ polls = await ctx.db
165
+ .query("polls")
166
+ .withIndex("by_creator", (q) => q.eq("createdBy", args.createdBy))
167
+ .order("desc")
168
+ .take(limit);
169
+ }
170
+ else {
171
+ polls = await ctx.db.query("polls").order("desc").take(limit);
172
+ }
173
+ const now = Date.now();
174
+ const results = [];
175
+ for (const poll of polls) {
176
+ // Skip expired polls when filtering for "active"
177
+ if (args.status === "active" &&
178
+ poll.config.closesAt &&
179
+ now > poll.config.closesAt) {
180
+ continue;
181
+ }
182
+ const voteCount = await ctx.db
183
+ .query("votes")
184
+ .withIndex("by_poll", (q) => q.eq("pollId", poll._id))
185
+ .collect();
186
+ results.push({
187
+ ...poll,
188
+ totalVotes: voteCount.length,
189
+ });
190
+ }
191
+ return results;
192
+ },
193
+ });
194
+ export const close = mutation({
195
+ args: {
196
+ pollId: v.id("polls"),
197
+ },
198
+ returns: v.null(),
199
+ handler: async (ctx, args) => {
200
+ const poll = await ctx.db.get(args.pollId);
201
+ if (!poll) {
202
+ throw new Error("Poll not found. The poll may have been deleted.");
203
+ }
204
+ if (poll.status === "closed") {
205
+ throw new Error("Poll is already closed.");
206
+ }
207
+ await ctx.db.patch(args.pollId, {
208
+ status: "closed",
209
+ closedAt: Date.now(),
210
+ });
211
+ return null;
212
+ },
213
+ });
214
+ export const remove = mutation({
215
+ args: {
216
+ pollId: v.id("polls"),
217
+ },
218
+ returns: v.null(),
219
+ handler: async (ctx, args) => {
220
+ const poll = await ctx.db.get(args.pollId);
221
+ if (!poll) {
222
+ throw new Error("Poll not found. The poll may have been deleted.");
223
+ }
224
+ const votes = await ctx.db
225
+ .query("votes")
226
+ .withIndex("by_poll", (q) => q.eq("pollId", args.pollId))
227
+ .collect();
228
+ for (const vote of votes) {
229
+ await ctx.db.delete(vote._id);
230
+ }
231
+ await ctx.db.delete(args.pollId);
232
+ return null;
233
+ },
234
+ });
235
+ //# sourceMappingURL=polls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"polls.js","sourceRoot":"","sources":["../../src/component/polls.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ export declare const optionValidator: import("convex/values").VObject<{
2
+ id: string;
3
+ text: string;
4
+ }, {
5
+ id: import("convex/values").VString<string, "required">;
6
+ text: import("convex/values").VString<string, "required">;
7
+ }, "required", "id" | "text">;
8
+ export declare const configValidator: import("convex/values").VObject<{
9
+ closesAt?: number | undefined;
10
+ maxVotesPerUser?: number | undefined;
11
+ allowMultipleVotes: boolean;
12
+ allowChangeVote: boolean;
13
+ showResultsBeforeVote: boolean;
14
+ }, {
15
+ allowMultipleVotes: import("convex/values").VBoolean<boolean, "required">;
16
+ allowChangeVote: import("convex/values").VBoolean<boolean, "required">;
17
+ showResultsBeforeVote: import("convex/values").VBoolean<boolean, "required">;
18
+ closesAt: import("convex/values").VFloat64<number | undefined, "optional">;
19
+ maxVotesPerUser: import("convex/values").VFloat64<number | undefined, "optional">;
20
+ }, "required", "allowMultipleVotes" | "allowChangeVote" | "showResultsBeforeVote" | "closesAt" | "maxVotesPerUser">;
21
+ export declare const statusValidator: import("convex/values").VUnion<"active" | "closed" | "scheduled", [import("convex/values").VLiteral<"active", "required">, import("convex/values").VLiteral<"closed", "required">, import("convex/values").VLiteral<"scheduled", "required">], "required", never>;
22
+ declare const _default: import("convex/server").SchemaDefinition<{
23
+ polls: import("convex/server").TableDefinition<import("convex/values").VObject<{
24
+ description?: string | undefined;
25
+ closedAt?: number | undefined;
26
+ config: {
27
+ closesAt?: number | undefined;
28
+ maxVotesPerUser?: number | undefined;
29
+ allowMultipleVotes: boolean;
30
+ allowChangeVote: boolean;
31
+ showResultsBeforeVote: boolean;
32
+ };
33
+ createdBy: string;
34
+ options: {
35
+ id: string;
36
+ text: string;
37
+ }[];
38
+ title: string;
39
+ status: "active" | "closed" | "scheduled";
40
+ createdAt: number;
41
+ }, {
42
+ title: import("convex/values").VString<string, "required">;
43
+ description: import("convex/values").VString<string | undefined, "optional">;
44
+ options: import("convex/values").VArray<{
45
+ id: string;
46
+ text: string;
47
+ }[], import("convex/values").VObject<{
48
+ id: string;
49
+ text: string;
50
+ }, {
51
+ id: import("convex/values").VString<string, "required">;
52
+ text: import("convex/values").VString<string, "required">;
53
+ }, "required", "id" | "text">, "required">;
54
+ createdBy: import("convex/values").VString<string, "required">;
55
+ status: import("convex/values").VUnion<"active" | "closed" | "scheduled", [import("convex/values").VLiteral<"active", "required">, import("convex/values").VLiteral<"closed", "required">, import("convex/values").VLiteral<"scheduled", "required">], "required", never>;
56
+ config: import("convex/values").VObject<{
57
+ closesAt?: number | undefined;
58
+ maxVotesPerUser?: number | undefined;
59
+ allowMultipleVotes: boolean;
60
+ allowChangeVote: boolean;
61
+ showResultsBeforeVote: boolean;
62
+ }, {
63
+ allowMultipleVotes: import("convex/values").VBoolean<boolean, "required">;
64
+ allowChangeVote: import("convex/values").VBoolean<boolean, "required">;
65
+ showResultsBeforeVote: import("convex/values").VBoolean<boolean, "required">;
66
+ closesAt: import("convex/values").VFloat64<number | undefined, "optional">;
67
+ maxVotesPerUser: import("convex/values").VFloat64<number | undefined, "optional">;
68
+ }, "required", "allowMultipleVotes" | "allowChangeVote" | "showResultsBeforeVote" | "closesAt" | "maxVotesPerUser">;
69
+ createdAt: import("convex/values").VFloat64<number, "required">;
70
+ closedAt: import("convex/values").VFloat64<number | undefined, "optional">;
71
+ }, "required", "config" | "createdBy" | "description" | "options" | "title" | "status" | "createdAt" | "closedAt" | "config.allowMultipleVotes" | "config.allowChangeVote" | "config.showResultsBeforeVote" | "config.closesAt" | "config.maxVotesPerUser">, {
72
+ by_status: ["status", "_creationTime"];
73
+ by_creator: ["createdBy", "_creationTime"];
74
+ }, {}, {}>;
75
+ votes: import("convex/server").TableDefinition<import("convex/values").VObject<{
76
+ pollId: import("convex/values").GenericId<"polls">;
77
+ voterId: string;
78
+ optionId: string;
79
+ votedAt: number;
80
+ }, {
81
+ pollId: import("convex/values").VId<import("convex/values").GenericId<"polls">, "required">;
82
+ optionId: import("convex/values").VString<string, "required">;
83
+ voterId: import("convex/values").VString<string, "required">;
84
+ votedAt: import("convex/values").VFloat64<number, "required">;
85
+ }, "required", "pollId" | "voterId" | "optionId" | "votedAt">, {
86
+ by_poll: ["pollId", "_creationTime"];
87
+ by_poll_voter: ["pollId", "voterId", "_creationTime"];
88
+ by_poll_option: ["pollId", "optionId", "_creationTime"];
89
+ }, {}, {}>;
90
+ }, true>;
91
+ export default _default;
92
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/component/schema.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,eAAe;;;;;;6BAG1B,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;;;;;;;;mHAM1B,CAAC;AAEH,eAAO,MAAM,eAAe,mQAI3B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEF,wBAuBG"}
@@ -0,0 +1,38 @@
1
+ import { defineSchema, defineTable } from "convex/server";
2
+ import { v } from "convex/values";
3
+ export const optionValidator = v.object({
4
+ id: v.string(),
5
+ text: v.string(),
6
+ });
7
+ export const configValidator = v.object({
8
+ allowMultipleVotes: v.boolean(),
9
+ allowChangeVote: v.boolean(),
10
+ showResultsBeforeVote: v.boolean(),
11
+ closesAt: v.optional(v.number()),
12
+ maxVotesPerUser: v.optional(v.number()),
13
+ });
14
+ export const statusValidator = v.union(v.literal("active"), v.literal("closed"), v.literal("scheduled"));
15
+ export default defineSchema({
16
+ polls: defineTable({
17
+ title: v.string(),
18
+ description: v.optional(v.string()),
19
+ options: v.array(optionValidator),
20
+ createdBy: v.string(),
21
+ status: statusValidator,
22
+ config: configValidator,
23
+ createdAt: v.number(),
24
+ closedAt: v.optional(v.number()),
25
+ })
26
+ .index("by_status", ["status"])
27
+ .index("by_creator", ["createdBy"]),
28
+ votes: defineTable({
29
+ pollId: v.id("polls"),
30
+ optionId: v.string(),
31
+ voterId: v.string(),
32
+ votedAt: v.number(),
33
+ })
34
+ .index("by_poll", ["pollId"])
35
+ .index("by_poll_voter", ["pollId", "voterId"])
36
+ .index("by_poll_option", ["pollId", "optionId"]),
37
+ });
38
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/component/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,CAAC,EAAE,MAAM,eAAe,CAAC;AAElC,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;CACjB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,kBAAkB,EAAE,CAAC,CAAC,OAAO,EAAE;IAC/B,eAAe,EAAE,CAAC,CAAC,OAAO,EAAE;IAC5B,qBAAqB,EAAE,CAAC,CAAC,OAAO,EAAE;IAClC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAChC,eAAe,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;CACxC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CACpC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EACnB,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EACnB,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CACvB,CAAC;AAEF,eAAe,YAAY,CAAC;IAC1B,KAAK,EAAE,WAAW,CAAC;QACjB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;QACjB,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QACnC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC;QACjC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;QACrB,MAAM,EAAE,eAAe;QACvB,MAAM,EAAE,eAAe;QACvB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;QACrB,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;KACjC,CAAC;SACC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC;SAC9B,KAAK,CAAC,YAAY,EAAE,CAAC,WAAW,CAAC,CAAC;IAErC,KAAK,EAAE,WAAW,CAAC;QACjB,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC;QACrB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;QACpB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;QACnB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;KACpB,CAAC;SACC,KAAK,CAAC,SAAS,EAAE,CAAC,QAAQ,CAAC,CAAC;SAC5B,KAAK,CAAC,eAAe,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;SAC7C,KAAK,CAAC,gBAAgB,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;CACnD,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ export declare const castVote: import("convex/server").RegisteredMutation<"public", {
2
+ pollId: import("convex/values").GenericId<"polls">;
3
+ optionId: string;
4
+ voterId: string;
5
+ }, Promise<null>>;
6
+ export declare const removeVote: import("convex/server").RegisteredMutation<"public", {
7
+ pollId: import("convex/values").GenericId<"polls">;
8
+ optionId: string;
9
+ voterId: string;
10
+ }, Promise<null>>;
11
+ export declare const getUserVotes: import("convex/server").RegisteredQuery<"public", {
12
+ pollId: import("convex/values").GenericId<"polls">;
13
+ voterId: string;
14
+ }, Promise<string[]>>;
15
+ //# sourceMappingURL=votes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"votes.d.ts","sourceRoot":"","sources":["../../src/component/votes.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,QAAQ;;;;iBAiFnB,CAAC;AAEH,eAAO,MAAM,UAAU;;;;iBAoCrB,CAAC;AAEH,eAAO,MAAM,YAAY;;;qBAgBvB,CAAC"}
@@ -0,0 +1,105 @@
1
+ import { v } from "convex/values";
2
+ import { mutation, query } from "./_generated/server.js";
3
+ export const castVote = mutation({
4
+ args: {
5
+ pollId: v.id("polls"),
6
+ optionId: v.string(),
7
+ voterId: v.string(),
8
+ },
9
+ returns: v.null(),
10
+ handler: async (ctx, args) => {
11
+ if (!args.voterId.trim()) {
12
+ throw new Error("Voter ID is required.");
13
+ }
14
+ const poll = await ctx.db.get(args.pollId);
15
+ if (!poll) {
16
+ throw new Error("Poll not found. The poll may have been deleted.");
17
+ }
18
+ if (poll.status === "closed") {
19
+ throw new Error("This poll is closed and no longer accepting votes.");
20
+ }
21
+ if (poll.config.closesAt && Date.now() > poll.config.closesAt) {
22
+ throw new Error("This poll has expired and is no longer accepting votes.");
23
+ }
24
+ const validOptionIds = poll.options.map((o) => o.id);
25
+ if (!validOptionIds.includes(args.optionId)) {
26
+ throw new Error(`Invalid option "${args.optionId}". Valid options: ${validOptionIds.join(", ")}`);
27
+ }
28
+ const existingVotes = await ctx.db
29
+ .query("votes")
30
+ .withIndex("by_poll_voter", (q) => q.eq("pollId", args.pollId).eq("voterId", args.voterId))
31
+ .collect();
32
+ if (!poll.config.allowMultipleVotes && !poll.config.allowChangeVote) {
33
+ if (existingVotes.length > 0) {
34
+ throw new Error("You have already voted on this poll. This poll does not allow changing or adding votes.");
35
+ }
36
+ }
37
+ if (!poll.config.allowMultipleVotes && poll.config.allowChangeVote) {
38
+ for (const oldVote of existingVotes) {
39
+ await ctx.db.delete(oldVote._id);
40
+ }
41
+ }
42
+ if (poll.config.allowMultipleVotes) {
43
+ const alreadyVotedForOption = existingVotes.some((v) => v.optionId === args.optionId);
44
+ if (alreadyVotedForOption) {
45
+ throw new Error("You have already voted for this option.");
46
+ }
47
+ const maxVotes = poll.config.maxVotesPerUser ?? poll.options.length;
48
+ if (existingVotes.length >= maxVotes) {
49
+ throw new Error(`You can only vote for up to ${maxVotes} option${maxVotes === 1 ? "" : "s"} on this poll.`);
50
+ }
51
+ }
52
+ await ctx.db.insert("votes", {
53
+ pollId: args.pollId,
54
+ optionId: args.optionId,
55
+ voterId: args.voterId,
56
+ votedAt: Date.now(),
57
+ });
58
+ return null;
59
+ },
60
+ });
61
+ export const removeVote = mutation({
62
+ args: {
63
+ pollId: v.id("polls"),
64
+ optionId: v.string(),
65
+ voterId: v.string(),
66
+ },
67
+ returns: v.null(),
68
+ handler: async (ctx, args) => {
69
+ if (!args.voterId.trim()) {
70
+ throw new Error("Voter ID is required.");
71
+ }
72
+ const poll = await ctx.db.get(args.pollId);
73
+ if (!poll) {
74
+ throw new Error("Poll not found. The poll may have been deleted.");
75
+ }
76
+ if (poll.status === "closed") {
77
+ throw new Error("Cannot remove votes from a closed poll.");
78
+ }
79
+ const votes = await ctx.db
80
+ .query("votes")
81
+ .withIndex("by_poll_voter", (q) => q.eq("pollId", args.pollId).eq("voterId", args.voterId))
82
+ .collect();
83
+ const voteToRemove = votes.find((v) => v.optionId === args.optionId);
84
+ if (!voteToRemove) {
85
+ throw new Error("No vote found for this option.");
86
+ }
87
+ await ctx.db.delete(voteToRemove._id);
88
+ return null;
89
+ },
90
+ });
91
+ export const getUserVotes = query({
92
+ args: {
93
+ pollId: v.id("polls"),
94
+ voterId: v.string(),
95
+ },
96
+ returns: v.array(v.string()),
97
+ handler: async (ctx, args) => {
98
+ const votes = await ctx.db
99
+ .query("votes")
100
+ .withIndex("by_poll_voter", (q) => q.eq("pollId", args.pollId).eq("voterId", args.voterId))
101
+ .collect();
102
+ return votes.map((v) => v.optionId);
103
+ },
104
+ });
105
+ //# sourceMappingURL=votes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"votes.js","sourceRoot":"","sources":["../../src/component/votes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { FunctionReference } from "convex/server";
2
+ import type { PollWithResults, PollListItem } from "../client/index.js";
3
+ export interface PollApi {
4
+ get: FunctionReference<"query", "public">;
5
+ list: FunctionReference<"query", "public">;
6
+ castVote: FunctionReference<"mutation", "public">;
7
+ removeVote: FunctionReference<"mutation", "public">;
8
+ getUserVotes: FunctionReference<"query", "public">;
9
+ }
10
+ export declare function usePoll(api: PollApi, pollId: string, voterId?: string): {
11
+ poll: PollWithResults | null | undefined;
12
+ isLoading: boolean;
13
+ vote: (optionId: string) => Promise<null>;
14
+ removeVote: (optionId: string) => Promise<null>;
15
+ hasVoted: boolean;
16
+ userVotes: string[];
17
+ };
18
+ export declare function usePollList(api: Pick<PollApi, "list">, args?: {
19
+ status?: "active" | "closed" | "scheduled";
20
+ createdBy?: string;
21
+ limit?: number;
22
+ }): {
23
+ polls: PollListItem[];
24
+ isLoading: boolean;
25
+ };
26
+ export type { PollWithResults, PollListItem } from "../client/index.js";
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACb,MAAM,oBAAoB,CAAC;AAI5B,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,iBAAiB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC1C,IAAI,EAAE,iBAAiB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC3C,QAAQ,EAAE,iBAAiB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAClD,UAAU,EAAE,iBAAiB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACpD,YAAY,EAAE,iBAAiB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;CACpD;AAID,wBAAgB,OAAO,CACrB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,GACf;IACD,IAAI,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,CAAC;IACzC,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB,CA0BA;AAID,wBAAgB,WAAW,CACzB,GAAG,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,EAC1B,IAAI,CAAC,EAAE;IACL,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GACA;IACD,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;CACpB,CASA;AAGD,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}