a tool for shared writing and social publishing
1"use server";
2import { cookies } from "next/headers";
3import { v7 } from "uuid";
4import { getIdentityData } from "./getIdentityData";
5import { supabaseServerClient } from "supabase/serverClient";
6
7export async function getPollData(entity_sets: string[]) {
8 let voter_token = (await cookies()).get("poll_voter_token")?.value;
9
10 const { data: polls, error } = await supabaseServerClient
11 .from("poll_votes_on_entity")
12 .select(
13 `
14 poll_entity,
15 voter_token,
16 option_entity,
17 entities!poll_votes_on_entity_poll_entity_fkey!inner(set)
18 `,
19 )
20 .in("entities.set", entity_sets);
21
22 if (error) throw error;
23
24 let pollVotes = polls
25 .reduce<
26 Array<{
27 poll_entity: string;
28 votes: { option_entity: string; voter_token: string }[];
29 }>
30 >((acc, p) => {
31 let x = acc.find((a) => a.poll_entity === p.poll_entity);
32 if (!x)
33 acc.push({
34 poll_entity: p.poll_entity,
35 votes: [p],
36 });
37 else x.votes.push(p);
38 return acc;
39 }, [])
40 .map((poll) => {
41 return {
42 poll_entity: poll.poll_entity,
43 unique_votes: poll.votes.reduce<string[]>((acc, v) => {
44 if (!acc.includes(v.voter_token)) acc.push(v.voter_token);
45 return acc;
46 }, []).length,
47 votesByOption: poll.votes.reduce<{
48 [key: string]: number;
49 }>((acc, v) => {
50 if (!acc[v.option_entity]) acc[v.option_entity] = 0;
51 acc[v.option_entity] = acc[v.option_entity] + 1;
52 return acc;
53 }, {}),
54 };
55 });
56
57 return {
58 pollVotes,
59 polls: polls.map((p) => ({
60 poll_votes_on_entity: {
61 ...p,
62 voter_token: voter_token === p.voter_token ? voter_token : undefined,
63 },
64 })),
65 voter_token,
66 };
67}
68
69export async function voteOnPoll(
70 poll_entity: string,
71 option_entities: string[],
72) {
73 let voter_token = (await cookies()).get("poll_voter_token")?.value;
74 if (!voter_token) {
75 let identity = await getIdentityData();
76 if (identity) voter_token = identity.id;
77 else voter_token = v7();
78 (await cookies()).set("poll_voter_token", voter_token, {
79 maxAge: 60 * 60 * 24 * 365,
80 secure: process.env.NODE_ENV === "production",
81 httpOnly: true,
82 sameSite: "lax",
83 });
84 }
85 const { data: existingVotes, error: selectError } = await supabaseServerClient
86 .from("poll_votes_on_entity")
87 .select("*")
88 .eq("poll_entity", poll_entity);
89
90 if (selectError) throw selectError;
91
92 const existingVote = existingVotes?.find(
93 (v) => v.voter_token === voter_token,
94 );
95
96 if (existingVote) {
97 const { error: deleteError } = await supabaseServerClient
98 .from("poll_votes_on_entity")
99 .delete()
100 .eq("voter_token", voter_token)
101 .eq("poll_entity", poll_entity);
102
103 if (deleteError) throw deleteError;
104 }
105
106 const { error: insertError } = await supabaseServerClient
107 .from("poll_votes_on_entity")
108 .insert(
109 option_entities.map((option_entity) => ({
110 option_entity,
111 poll_entity,
112 voter_token,
113 })),
114 );
115
116 if (insertError) throw insertError;
117
118 return;
119}