- remove unnecessary / deprecated code

This commit is contained in:
2026-05-06 19:34:13 +02:00
parent 5ecb5f1076
commit 424799692a
4 changed files with 9 additions and 138 deletions

View File

@@ -2,10 +2,9 @@ import { getUserId } from "./identity";
import { import {
addOption, addOption,
toggleVote, toggleVote,
deleteOption,
setDeadline, setDeadline,
clearDeadline, clearDeadline,
createViewModel, getDeadline,
} from "./state"; } from "./state";
import { initSync } from "./sync"; import { initSync } from "./sync";
import { StatusBar } from "./components/StatusBar"; import { StatusBar } from "./components/StatusBar";
@@ -48,18 +47,13 @@ export function initApp(container: HTMLElement): () => void {
const actions = { const actions = {
addOption: (label: string) => { addOption: (label: string) => {
const vm = createViewModel(getViewModelParams()); if (isVotingClosed()) return;
if (vm.votingClosed) return;
return addOption(sync.options, label, userId); return addOption(sync.options, label, userId);
}, },
toggleVote: (optionId: string) => { toggleVote: (optionId: string) => {
const vm = createViewModel(getViewModelParams()); if (isVotingClosed()) return;
if (vm.votingClosed) return;
toggleVote(sync.votes, userId, optionId); toggleVote(sync.votes, userId, optionId);
}, },
deleteOption: (optionId: string) => {
deleteOption(sync.options, sync.votes, optionId);
},
startDeadline: (durationMs: number) => { startDeadline: (durationMs: number) => {
setDeadline(sync.deadlineMap, durationMs); setDeadline(sync.deadlineMap, durationMs);
}, },
@@ -68,18 +62,10 @@ export function initApp(container: HTMLElement): () => void {
}, },
}; };
function getViewModelParams() { function isVotingClosed() {
return { const deadline = getDeadline(sync.deadlineMap);
yTitle: sync.yTitle, const votingClosed = deadline !== null && Date.now() >= deadline;
options: sync.options, return votingClosed;
votes: sync.votes,
deadlineMap: sync.deadlineMap,
roomId,
shareUrl,
connectionStatus: sync.getConnectionStatus(),
peerCount: sync.getPeerCount(),
userId,
};
} }
// --- Build UI --- // --- Build UI ---
@@ -112,10 +98,7 @@ export function initApp(container: HTMLElement): () => void {
if (result && !result.ok) return result.error; if (result && !result.ok) return result.error;
return null; return null;
}); });
const pollList = PollList(sync.options, sync.votes, userId, () => { const pollList = PollList(sync.options, sync.votes, userId, isVotingClosed, actions.toggleVote);
const vm = createViewModel(getViewModelParams());
return vm.votingClosed;
}, actions.toggleVote, actions.deleteOption);
const deadlineTimer = DeadlineTimer( const deadlineTimer = DeadlineTimer(
sync.deadlineMap, sync.deadlineMap,
actions.startDeadline, actions.startDeadline,

View File

@@ -9,7 +9,6 @@ export function PollList(
userId: string, userId: string,
isVotingClosed: () => boolean, isVotingClosed: () => boolean,
onVote: (optionId: string) => void, onVote: (optionId: string) => void,
onDelete: (optionId: string) => void,
): HTMLElement { ): HTMLElement {
var currentOptions : { [x: string]: any; } | undefined = undefined var currentOptions : { [x: string]: any; } | undefined = undefined
@@ -112,7 +111,6 @@ export function PollList(
totalVotes: total, totalVotes: total,
votingClosed, votingClosed,
onVote, onVote,
onDelete,
}); });
const currentEl = list.children[i] as HTMLElement | undefined; const currentEl = list.children[i] as HTMLElement | undefined;

View File

@@ -8,11 +8,10 @@ export interface PollOptionProps {
totalVotes: number; totalVotes: number;
votingClosed: boolean; votingClosed: boolean;
onVote: (id: string) => void; onVote: (id: string) => void;
onDelete: (id: string) => void;
} }
export function PollOption(props: PollOptionProps): HTMLElement { 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"); const row = document.createElement("div");
row.className = `poll-option${voted ? " poll-option--voted" : ""}`; row.className = `poll-option${voted ? " poll-option--voted" : ""}`;
@@ -30,17 +29,11 @@ export function PollOption(props: PollOptionProps): HTMLElement {
<button class="poll-option__vote-btn" aria-pressed="${voted}"${votingClosed ? " disabled" : ""}> <button class="poll-option__vote-btn" aria-pressed="${voted}"${votingClosed ? " disabled" : ""}>
${voted ? "Voted" : "Vote"} ${voted ? "Voted" : "Vote"}
</button> </button>
<button class="poll-option__delete-btn" aria-label="Remove option">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 2l10 10M12 2L2 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
</svg>
</button>
</div> </div>
</div> </div>
`; `;
row.querySelector(".poll-option__vote-btn")!.addEventListener("click", () => onVote(id)); row.querySelector(".poll-option__vote-btn")!.addEventListener("click", () => onVote(id));
row.querySelector(".poll-option__delete-btn")!.addEventListener("click", () => onDelete(id));
return row; return row;
} }

View File

@@ -11,25 +11,6 @@ export interface OptionRecord {
createdBy: string; 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 --- // --- Helpers ---
export function createOptionId(): string { export function createOptionId(): string {
@@ -104,20 +85,6 @@ export function toggleVote(
} }
} }
export function deleteOption(
options: Y.Map<OptionRecord>,
votes: Y.Map<string>,
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 --- // --- Deadline ---
export function setDeadline( export function setDeadline(
@@ -135,73 +102,3 @@ export function getDeadline(deadlineMap: Y.Map<unknown>): number | null {
const val = deadlineMap.get("deadline"); const val = deadlineMap.get("deadline");
return typeof val === "number" ? val : null; return typeof val === "number" ? val : null;
} }
// --- ViewModel ---
export function createViewModel(params: {
yTitle: Y.Text;
options: Y.Map<OptionRecord>;
votes: Y.Map<string>;
deadlineMap: Y.Map<unknown>;
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<string, number>();
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,
})),
};
}