forked from quic-issues/427e7578-d7bf-49c8-aee9-2dd999e25316
Implementation, thanks amp
This commit is contained in:
157
app/src/lib/stores/polls.svelte.ts
Normal file
157
app/src/lib/stores/polls.svelte.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import { loadAllPolls, savePoll, deletePoll as dbDeletePoll, loadPoll } from '$lib/db.js';
|
||||
import type { Poll, PollOption, Vote, RoleAssignment } from '$lib/types.js';
|
||||
import { getUserId } from '$lib/crypto.js';
|
||||
|
||||
let polls = $state<Poll[]>([]);
|
||||
let loading = $state(true);
|
||||
|
||||
export function getPolls() {
|
||||
return {
|
||||
get all() { return polls; },
|
||||
get loading() { return loading; },
|
||||
get owned() {
|
||||
const id = currentUserId;
|
||||
return id ? polls.filter((p) => p.ownerId === id) : [];
|
||||
},
|
||||
get participating() {
|
||||
const id = currentUserId;
|
||||
return id ? polls.filter((p) => p.ownerId !== id) : [];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let currentUserId: string | null = null;
|
||||
|
||||
export async function initPolls(): Promise<void> {
|
||||
loading = true;
|
||||
currentUserId = await getUserId();
|
||||
polls = await loadAllPolls();
|
||||
loading = false;
|
||||
}
|
||||
|
||||
export async function createPoll(data: {
|
||||
title: string;
|
||||
description: string;
|
||||
anonymous: boolean;
|
||||
visibility: Poll['visibility'];
|
||||
options?: string[];
|
||||
}): Promise<Poll> {
|
||||
const userId = await getUserId();
|
||||
const now = Date.now();
|
||||
|
||||
const poll: Poll = {
|
||||
id: crypto.randomUUID(),
|
||||
ownerId: userId,
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
anonymous: data.anonymous,
|
||||
status: 'draft',
|
||||
visibility: data.visibility,
|
||||
createdAt: now,
|
||||
options: (data.options ?? []).map((text) => ({
|
||||
id: crypto.randomUUID(),
|
||||
text,
|
||||
addedBy: userId,
|
||||
addedAt: now
|
||||
})),
|
||||
votes: [],
|
||||
roles: []
|
||||
};
|
||||
|
||||
await savePoll(poll);
|
||||
polls = [...polls, poll];
|
||||
return poll;
|
||||
}
|
||||
|
||||
export async function updatePollInStore(poll: Poll): Promise<void> {
|
||||
await savePoll(poll);
|
||||
polls = polls.map((p) => (p.id === poll.id ? poll : p));
|
||||
}
|
||||
|
||||
export function getPollById(id: string): Poll | undefined {
|
||||
return polls.find((p) => p.id === id);
|
||||
}
|
||||
|
||||
export async function refreshPoll(id: string): Promise<Poll | undefined> {
|
||||
const poll = await loadPoll(id);
|
||||
if (poll) {
|
||||
polls = polls.map((p) => (p.id === id ? poll : p));
|
||||
if (!polls.find((p) => p.id === id)) {
|
||||
polls = [...polls, poll];
|
||||
}
|
||||
}
|
||||
return poll;
|
||||
}
|
||||
|
||||
export async function deletePollFromStore(id: string): Promise<void> {
|
||||
await dbDeletePoll(id);
|
||||
polls = polls.filter((p) => p.id !== id);
|
||||
}
|
||||
|
||||
export async function addOptionToPoll(pollId: string, text: string): Promise<PollOption | null> {
|
||||
const poll = getPollById(pollId);
|
||||
if (!poll || poll.status !== 'open') return null;
|
||||
|
||||
const userId = await getUserId();
|
||||
const option: PollOption = {
|
||||
id: crypto.randomUUID(),
|
||||
text,
|
||||
addedBy: userId,
|
||||
addedAt: Date.now()
|
||||
};
|
||||
|
||||
const updated = { ...poll, options: [...poll.options, option] };
|
||||
await updatePollInStore(updated);
|
||||
return option;
|
||||
}
|
||||
|
||||
export async function castVote(pollId: string, optionId: string): Promise<Vote | null> {
|
||||
const poll = getPollById(pollId);
|
||||
if (!poll || poll.status !== 'open') return null;
|
||||
|
||||
const userId = await getUserId();
|
||||
const vote: Vote = {
|
||||
optionId,
|
||||
voterId: poll.anonymous ? null : userId,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
// Remove previous vote by this user (for vote changes)
|
||||
const filteredVotes = poll.anonymous
|
||||
? poll.votes // Can't deduplicate anonymous votes by voterId
|
||||
: poll.votes.filter((v) => v.voterId !== userId);
|
||||
|
||||
const updated = { ...poll, votes: [...filteredVotes, vote] };
|
||||
await updatePollInStore(updated);
|
||||
return vote;
|
||||
}
|
||||
|
||||
export async function setPollStatus(pollId: string, status: Poll['status']): Promise<void> {
|
||||
const poll = getPollById(pollId);
|
||||
if (!poll) return;
|
||||
|
||||
const updated = {
|
||||
...poll,
|
||||
status,
|
||||
...(status === 'closed' ? { closedAt: Date.now() } : {})
|
||||
};
|
||||
await updatePollInStore(updated);
|
||||
}
|
||||
|
||||
export async function setRole(pollId: string, userId: string, role: RoleAssignment['role']): Promise<void> {
|
||||
const poll = getPollById(pollId);
|
||||
if (!poll) return;
|
||||
|
||||
const roles = poll.roles.filter((r) => r.userId !== userId);
|
||||
roles.push({ userId, role });
|
||||
const updated = { ...poll, roles };
|
||||
await updatePollInStore(updated);
|
||||
}
|
||||
|
||||
export async function removeRole(pollId: string, userId: string): Promise<void> {
|
||||
const poll = getPollById(pollId);
|
||||
if (!poll) return;
|
||||
|
||||
const updated = { ...poll, roles: poll.roles.filter((r) => r.userId !== userId) };
|
||||
await updatePollInStore(updated);
|
||||
}
|
||||
Reference in New Issue
Block a user