Files
427e7578-d7bf-49c8-aee9-2dd…/p2p-poll/composables/usePoll.ts
2026-03-18 20:09:20 +01:00

81 lines
2.2 KiB
TypeScript

// composables/usePoll.ts
import { ref, onMounted, onUnmounted } from 'vue';
import * as Y from 'yjs';
export const usePoll = () => {
// Reactive Vue state to drive the UI
const pollData = ref<Record<string, number>>({});
const isConnected = ref(false);
const connectedPeers = ref(1); // 1 = just you initially
let ydoc: Y.Doc;
let provider: any;
let yMap: Y.Map<number>;
onMounted(async () => {
// 1. Initialize the Yjs document
ydoc = new Y.Doc();
// 2. Connect via WebRTC.
// 'nuxt-p2p-poll-demo-room' is the shared room name.
// Anyone using this exact string will sync together.
const { WebrtcProvider } = await import('y-webrtc');
provider = new WebrtcProvider('nuxt-p2p-poll-demo-room', ydoc);
// Track connection status
provider.on('synced', (arg: {synced: boolean}) => {
isConnected.value = arg.synced;
});
provider.on('peers', (data: any) => {
// data.webrtcPeers contains the connected peer IDs
connectedPeers.value = data.webrtcPeers.length + 1; // +1 for self
});
// 3. Define our shared state structure. We'll use a Map
// where the Key is the Poll Option (string) and Value is the Vote Count (number)
yMap = ydoc.getMap<number>('shared-poll');
// 4. Listen for changes from other peers and update our Vue reactive state
yMap.observe(() => {
pollData.value = yMap.toJSON();
});
// Initial load in case data already exists in the room
pollData.value = yMap.toJSON();
});
onUnmounted(() => {
// Clean up when the component is destroyed
if (provider) {
provider.disconnect();
}
if (ydoc) {
ydoc.destroy();
}
});
// Action: Add a new option to the poll
const addOption = (optionName: string) => {
const trimmedName = optionName.trim();
if (trimmedName && !yMap.has(trimmedName)) {
yMap.set(trimmedName, 0); // Initialize with 0 votes
}
};
// Action: Vote for an existing option
const vote = (optionName: string) => {
if (yMap.has(optionName)) {
const currentVotes = yMap.get(optionName) || 0;
yMap.set(optionName, currentVotes + 1);
}
};
return {
pollData,
isConnected,
connectedPeers,
addOption,
vote
};
};