diff --git a/src/app.ts b/src/app.ts
index bf00075..b6ad391 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -2,10 +2,9 @@ import { getUserId } from "./identity";
import {
addOption,
toggleVote,
- deleteOption,
setDeadline,
clearDeadline,
- createViewModel,
+ getDeadline,
} from "./state";
import { initSync } from "./sync";
import { StatusBar } from "./components/StatusBar";
@@ -48,18 +47,13 @@ export function initApp(container: HTMLElement): () => void {
const actions = {
addOption: (label: string) => {
- const vm = createViewModel(getViewModelParams());
- if (vm.votingClosed) return;
+ if (isVotingClosed()) return;
return addOption(sync.options, label, userId);
},
toggleVote: (optionId: string) => {
- const vm = createViewModel(getViewModelParams());
- if (vm.votingClosed) return;
+ if (isVotingClosed()) return;
toggleVote(sync.votes, userId, optionId);
},
- deleteOption: (optionId: string) => {
- deleteOption(sync.options, sync.votes, optionId);
- },
startDeadline: (durationMs: number) => {
setDeadline(sync.deadlineMap, durationMs);
},
@@ -68,18 +62,10 @@ export function initApp(container: HTMLElement): () => void {
},
};
- function getViewModelParams() {
- return {
- yTitle: sync.yTitle,
- options: sync.options,
- votes: sync.votes,
- deadlineMap: sync.deadlineMap,
- roomId,
- shareUrl,
- connectionStatus: sync.getConnectionStatus(),
- peerCount: sync.getPeerCount(),
- userId,
- };
+ function isVotingClosed() {
+ const deadline = getDeadline(sync.deadlineMap);
+ const votingClosed = deadline !== null && Date.now() >= deadline;
+ return votingClosed;
}
// --- Build UI ---
@@ -112,10 +98,7 @@ export function initApp(container: HTMLElement): () => void {
if (result && !result.ok) return result.error;
return null;
});
- const pollList = PollList(sync.options, sync.votes, userId, () => {
- const vm = createViewModel(getViewModelParams());
- return vm.votingClosed;
- }, actions.toggleVote, actions.deleteOption);
+ const pollList = PollList(sync.options, sync.votes, userId, isVotingClosed, actions.toggleVote);
const deadlineTimer = DeadlineTimer(
sync.deadlineMap,
actions.startDeadline,
diff --git a/src/components/PollList.ts b/src/components/PollList.ts
index 5c99505..4828495 100644
--- a/src/components/PollList.ts
+++ b/src/components/PollList.ts
@@ -9,7 +9,6 @@ export function PollList(
userId: string,
isVotingClosed: () => boolean,
onVote: (optionId: string) => void,
- onDelete: (optionId: string) => void,
): HTMLElement {
var currentOptions : { [x: string]: any; } | undefined = undefined
@@ -112,7 +111,6 @@ export function PollList(
totalVotes: total,
votingClosed,
onVote,
- onDelete,
});
const currentEl = list.children[i] as HTMLElement | undefined;
diff --git a/src/components/PollOption.ts b/src/components/PollOption.ts
index c10ef22..70eff3b 100644
--- a/src/components/PollOption.ts
+++ b/src/components/PollOption.ts
@@ -8,11 +8,10 @@ export interface PollOptionProps {
totalVotes: number;
votingClosed: boolean;
onVote: (id: string) => void;
- onDelete: (id: string) => void;
}
export function PollOption(props: PollOptionProps): HTMLElement {
- const { id, name, votes, voted, totalVotes, votingClosed, onVote, onDelete } = props;
+ const { id, name, votes, voted, totalVotes, votingClosed, onVote } = props;
const row = document.createElement("div");
row.className = `poll-option${voted ? " poll-option--voted" : ""}`;
@@ -30,17 +29,11 @@ export function PollOption(props: PollOptionProps): HTMLElement {
-
`;
row.querySelector(".poll-option__vote-btn")!.addEventListener("click", () => onVote(id));
- row.querySelector(".poll-option__delete-btn")!.addEventListener("click", () => onDelete(id));
return row;
}
diff --git a/src/state.ts b/src/state.ts
index 65fd560..0d08971 100644
--- a/src/state.ts
+++ b/src/state.ts
@@ -11,25 +11,6 @@ export interface OptionRecord {
createdBy: string;
}
-export interface PollOptionViewModel extends OptionRecord {
- voteCount: number;
- isVotedByMe: boolean;
- percentage: number;
-}
-
-export interface PollViewModel {
- title: string;
- roomId: string;
- shareUrl: string;
- connectionStatus: ConnectionStatus;
- peerCount: number;
- options: PollOptionViewModel[];
- totalVotes: number;
- myVoteOptionId: string | null;
- deadline: number | null;
- votingClosed: boolean;
-}
-
// --- Helpers ---
export function createOptionId(): string {
@@ -104,20 +85,6 @@ export function toggleVote(
}
}
-export function deleteOption(
- options: Y.Map,
- votes: Y.Map,
- optionId: string,
-): void {
- options.delete(optionId);
- // Clean up votes pointing to this option
- for (const [userId, votedOptionId] of votes.entries()) {
- if (votedOptionId === optionId) {
- votes.delete(userId);
- }
- }
-}
-
// --- Deadline ---
export function setDeadline(
@@ -135,73 +102,3 @@ export function getDeadline(deadlineMap: Y.Map): number | null {
const val = deadlineMap.get("deadline");
return typeof val === "number" ? val : null;
}
-
-// --- ViewModel ---
-
-export function createViewModel(params: {
- yTitle: Y.Text;
- options: Y.Map;
- votes: Y.Map;
- deadlineMap: Y.Map;
- roomId: string;
- shareUrl: string;
- connectionStatus: ConnectionStatus;
- peerCount: number;
- userId: string;
-}): PollViewModel {
- const {
- yTitle,
- options,
- votes,
- deadlineMap,
- roomId,
- shareUrl,
- connectionStatus,
- peerCount,
- userId,
- } = params;
-
- // Tally votes per option
- const tally = new Map();
- for (const optionId of votes.values()) {
- tally.set(optionId, (tally.get(optionId) ?? 0) + 1);
- }
-
- let totalVotes = 0;
- for (const count of tally.values()) {
- totalVotes += count;
- }
-
- const myVoteOptionId = votes.get(userId) ?? null;
- const deadline = getDeadline(deadlineMap);
- const votingClosed = deadline !== null && Date.now() >= deadline;
-
- // Sort by votes desc, then alphabetically
- const sortedOptions = Array.from(options.values()).sort((a, b) => {
- const aVotes = tally.get(a.id) ?? 0;
- const bVotes = tally.get(b.id) ?? 0;
- if (bVotes !== aVotes) return bVotes - aVotes;
- return a.label.localeCompare(b.label);
- });
-
- return {
- title: getPollTitle(yTitle),
- roomId,
- shareUrl,
- connectionStatus,
- peerCount,
- myVoteOptionId,
- totalVotes,
- deadline,
- votingClosed,
- options: sortedOptions.map((option) => ({
- ...option,
- voteCount: tally.get(option.id) ?? 0,
- isVotedByMe: myVoteOptionId === option.id,
- percentage:
- totalVotes > 0
- ? Math.round(((tally.get(option.id) ?? 0) / totalVotes) * 100)
- : 0,
- })),
- };
-}