ssvc-poll/src/lib/survey.ts

129 lines
3.3 KiB
TypeScript

import fs from 'fs';
import path from 'path';
import { v4 as uuidv4 } from 'uuid';
// Define the vote option interface
export interface VoteOptionConfig {
id: string;
label: string;
}
// Define the survey response type
export type VoteOption = string; // Now a string that matches the option id
export interface SurveyResponse {
id: string; // Used only for internal tracking, not associated with the voter
vote: VoteOption;
comment?: string;
timestamp: string;
}
// Path to the data files
const DATA_FILE = path.join(process.cwd(), 'data', 'responses.json');
const TEXT_FILE = path.join(process.cwd(), 'data', 'editable_text.json');
// Ensure the data directory exists
function ensureDataDirectory() {
const dataDir = path.join(process.cwd(), 'data');
if (!fs.existsSync(dataDir)) {
fs.mkdirSync(dataDir, { recursive: true });
}
}
// Get vote options from editable_text.json
export function getVoteOptions(): VoteOptionConfig[] {
ensureDataDirectory();
if (!fs.existsSync(TEXT_FILE)) {
// Default options if file doesn't exist
return [
{ id: 'yes', label: 'Ja, ich stimme zu' },
{ id: 'no', label: 'Nein, ich stimme nicht zu' },
{ id: 'abstain', label: 'Ich enthalte mich' }
];
}
try {
const data = fs.readFileSync(TEXT_FILE, 'utf-8');
const texts = JSON.parse(data);
const voteOptionsEntry = texts.find((text: { id: string }) => text.id === 'vote-options');
if (voteOptionsEntry && Array.isArray(voteOptionsEntry.content)) {
return voteOptionsEntry.content;
}
// Return default options if not found or invalid
return [
{ id: 'yes', label: 'Ja, ich stimme zu' },
{ id: 'no', label: 'Nein, ich stimme nicht zu' },
{ id: 'abstain', label: 'Ich enthalte mich' }
];
} catch (error) {
console.error('Error reading vote options:', error);
// Return default options on error
return [
{ id: 'yes', label: 'Ja, ich stimme zu' },
{ id: 'no', label: 'Nein, ich stimme nicht zu' },
{ id: 'abstain', label: 'Ich enthalte mich' }
];
}
}
// Get all survey responses
export function getAllResponses(): SurveyResponse[] {
ensureDataDirectory();
if (!fs.existsSync(DATA_FILE)) {
return [];
}
const data = fs.readFileSync(DATA_FILE, 'utf-8');
return JSON.parse(data);
}
// Save a new survey response
export function saveResponse(vote: VoteOption, comment?: string): SurveyResponse {
const responses = getAllResponses();
// Create a new response with a random ID (not associated with the voter)
const newResponse: SurveyResponse = {
id: uuidv4(), // Random ID only for internal tracking
vote,
comment,
timestamp: new Date().toISOString(),
};
responses.push(newResponse);
ensureDataDirectory();
fs.writeFileSync(DATA_FILE, JSON.stringify(responses, null, 2));
return newResponse;
}
// Get survey statistics
export function getSurveyStats() {
const responses = getAllResponses();
const voteOptions = getVoteOptions();
// Initialize stats object with total count
const stats: Record<string, number> = {
total: responses.length
};
// Initialize count for each vote option
voteOptions.forEach(option => {
stats[option.id] = 0;
});
// Count votes for each option
responses.forEach(response => {
if (stats[response.vote] !== undefined) {
stats[response.vote]++;
}
});
return stats;
}