84 lines
2.1 KiB
JavaScript
84 lines
2.1 KiB
JavaScript
// api/feedback/store.js
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const DATA_DIR = path.resolve(__dirname, '../../data');
|
|
const FEEDBACK_FILE = path.join(DATA_DIR, 'feedback.json');
|
|
const MAX_ENTRIES = 10000;
|
|
|
|
function ensureFile() {
|
|
if (!fs.existsSync(DATA_DIR)) {
|
|
fs.mkdirSync(DATA_DIR, { recursive: true });
|
|
}
|
|
if (!fs.existsSync(FEEDBACK_FILE)) {
|
|
fs.writeFileSync(FEEDBACK_FILE, '[]', 'utf-8');
|
|
}
|
|
}
|
|
|
|
function readAll() {
|
|
ensureFile();
|
|
try {
|
|
return JSON.parse(fs.readFileSync(FEEDBACK_FILE, 'utf-8'));
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
function writeAll(entries) {
|
|
ensureFile();
|
|
fs.writeFileSync(FEEDBACK_FILE, JSON.stringify(entries, null, 2), 'utf-8');
|
|
}
|
|
|
|
function addFeedback({ docPath, vote, suggestion }) {
|
|
const entries = readAll();
|
|
const entry = {
|
|
id: Date.now().toString(36) + Math.random().toString(36).slice(2, 6),
|
|
docPath,
|
|
vote,
|
|
suggestion: suggestion || null,
|
|
timestamp: new Date().toISOString(),
|
|
};
|
|
entries.push(entry);
|
|
if (entries.length > MAX_ENTRIES) {
|
|
entries.splice(0, entries.length - MAX_ENTRIES);
|
|
}
|
|
writeAll(entries);
|
|
return entry;
|
|
}
|
|
|
|
function getStats() {
|
|
const entries = readAll();
|
|
const total = entries.length;
|
|
const yes = entries.filter(e => e.vote === 'yes').length;
|
|
const no = entries.filter(e => e.vote === 'no').length;
|
|
const withSuggestion = entries.filter(e => e.suggestion).length;
|
|
|
|
const byPath = {};
|
|
for (const e of entries) {
|
|
if (!byPath[e.docPath]) {
|
|
byPath[e.docPath] = { path: e.docPath, yes: 0, no: 0, suggestions: [] };
|
|
}
|
|
if (e.vote === 'yes') byPath[e.docPath].yes++;
|
|
else byPath[e.docPath].no++;
|
|
if (e.suggestion) {
|
|
byPath[e.docPath].suggestions.push({ text: e.suggestion, time: e.timestamp });
|
|
}
|
|
}
|
|
|
|
return {
|
|
total,
|
|
yes,
|
|
no,
|
|
helpfulRate: total > 0 ? Math.round((yes / total) * 100) : 0,
|
|
withSuggestion,
|
|
byPath: Object.values(byPath).sort((a, b) => (b.yes + b.no) - (a.yes + a.no)),
|
|
};
|
|
}
|
|
|
|
function getRecent(limit = 50) {
|
|
const entries = readAll();
|
|
return entries.slice(-limit).reverse();
|
|
}
|
|
|
|
module.exports = { addFeedback, getStats, getRecent };
|