246 lines
9.1 KiB
JavaScript
246 lines
9.1 KiB
JavaScript
import { pb } from './pb';
|
|
|
|
// ── Topics ──────────────────────────────────────────────────────────────────
|
|
|
|
export async function getTopics() {
|
|
return pb.collection('topics').getFullList();
|
|
}
|
|
|
|
export async function saveTopics(topics) {
|
|
const existing = await pb.collection('topics').getFullList({ fields: 'id' });
|
|
await Promise.all(existing.map(r => pb.collection('topics').delete(r.id)));
|
|
return Promise.all(topics.map(t => pb.collection('topics').create({
|
|
id: t.id,
|
|
label: t.label,
|
|
type: t.type,
|
|
description: t.description,
|
|
})));
|
|
}
|
|
|
|
export async function upsertTopic(topic) {
|
|
try {
|
|
await pb.collection('topics').getOne(topic.id);
|
|
return pb.collection('topics').update(topic.id, topic);
|
|
} catch {
|
|
return pb.collection('topics').create({ id: topic.id, ...topic });
|
|
}
|
|
}
|
|
|
|
// ── Relations ────────────────────────────────────────────────────────────────
|
|
|
|
export async function getRelations() {
|
|
return pb.collection('relations').getFullList();
|
|
}
|
|
|
|
export async function saveRelations(relations) {
|
|
const existing = await pb.collection('relations').getFullList({ fields: 'id' });
|
|
await Promise.all(existing.map(r => pb.collection('relations').delete(r.id)));
|
|
return Promise.all(relations.map(r => pb.collection('relations').create(r)));
|
|
}
|
|
|
|
export async function addRelation(relation) {
|
|
return pb.collection('relations').create(relation);
|
|
}
|
|
|
|
export async function removeRelation(source, target, type) {
|
|
const records = await pb.collection('relations').getFullList({
|
|
filter: `source="${source}" && target="${target}" && type="${type}"`,
|
|
});
|
|
return Promise.all(records.map(r => pb.collection('relations').delete(r.id)));
|
|
}
|
|
|
|
// ── Content ──────────────────────────────────────────────────────────────────
|
|
|
|
export async function getContent(topicId) {
|
|
try {
|
|
const r = await pb.collection('content').getFirstListItem(`topic_id="${topicId}"`);
|
|
return r.data;
|
|
} catch { return null; }
|
|
}
|
|
|
|
export async function setContent(topicId, data) {
|
|
try {
|
|
const r = await pb.collection('content').getFirstListItem(`topic_id="${topicId}"`);
|
|
return pb.collection('content').update(r.id, { data });
|
|
} catch {
|
|
return pb.collection('content').create({ topic_id: topicId, data });
|
|
}
|
|
}
|
|
|
|
export async function deleteContent(topicId) {
|
|
try {
|
|
const r = await pb.collection('content').getFirstListItem(`topic_id="${topicId}"`);
|
|
return pb.collection('content').delete(r.id);
|
|
} catch { /* no record, nothing to do */ }
|
|
}
|
|
|
|
// ── Quiz Banks ───────────────────────────────────────────────────────────────
|
|
|
|
export async function getQuizBank(topicId) {
|
|
try {
|
|
const r = await pb.collection('quiz_banks').getFirstListItem(`topic_id="${topicId}"`);
|
|
return r.questions || [];
|
|
} catch { return []; }
|
|
}
|
|
|
|
export async function setQuizBank(topicId, questions) {
|
|
try {
|
|
const r = await pb.collection('quiz_banks').getFirstListItem(`topic_id="${topicId}"`);
|
|
return pb.collection('quiz_banks').update(r.id, { questions });
|
|
} catch {
|
|
return pb.collection('quiz_banks').create({ topic_id: topicId, questions });
|
|
}
|
|
}
|
|
|
|
export async function deleteQuestionFromBank(topicId, questionId) {
|
|
const questions = await getQuizBank(topicId);
|
|
return setQuizBank(topicId, questions.filter(q => q.id !== questionId));
|
|
}
|
|
|
|
// ── Sources ──────────────────────────────────────────────────────────────────
|
|
|
|
export async function getSources() {
|
|
return pb.collection('sources').getFullList();
|
|
}
|
|
|
|
export async function addSource(source) {
|
|
return pb.collection('sources').create(source);
|
|
}
|
|
|
|
export async function updateSourceStatus(id, status, error = '') {
|
|
return pb.collection('sources').update(id, { status, error });
|
|
}
|
|
|
|
export async function deleteSource(id) {
|
|
return pb.collection('sources').delete(id);
|
|
}
|
|
|
|
// ── Team Members ─────────────────────────────────────────────────────────────
|
|
|
|
export async function getTeamMembers() {
|
|
return pb.collection('team_members').getFullList();
|
|
}
|
|
|
|
export async function addTeamMember(member) {
|
|
return pb.collection('team_members').create(member);
|
|
}
|
|
|
|
export async function updateTeamMember(id, data) {
|
|
return pb.collection('team_members').update(id, data);
|
|
}
|
|
|
|
export async function deleteTeamMember(id) {
|
|
return pb.collection('team_members').delete(id);
|
|
}
|
|
|
|
// ── Quiz Results ─────────────────────────────────────────────────────────────
|
|
|
|
export async function getQuizResult(userId, weekNumber) {
|
|
try {
|
|
return await pb.collection('quiz_results').getFirstListItem(
|
|
`user_id="${userId}" && week_number=${weekNumber}`
|
|
);
|
|
} catch { return null; }
|
|
}
|
|
|
|
export async function saveQuizResult(userId, weekNumber, result) {
|
|
return pb.collection('quiz_results').create({
|
|
user_id: userId,
|
|
week_number: weekNumber,
|
|
score: result.score,
|
|
total: result.total,
|
|
percentage: result.percentage,
|
|
time_used: result.timeUsed,
|
|
completed_at: result.completedAt,
|
|
breakdown: result.breakdown,
|
|
points_earned: result.pointsEarned,
|
|
});
|
|
}
|
|
|
|
// ── Quiz Cache ────────────────────────────────────────────────────────────────
|
|
|
|
export async function getCachedQuiz(userId, weekNumber) {
|
|
try {
|
|
return await pb.collection('quiz_cache').getFirstListItem(
|
|
`user_id="${userId}" && week_number=${weekNumber}`
|
|
);
|
|
} catch { return null; }
|
|
}
|
|
|
|
export async function setCachedQuiz(userId, weekNumber, quiz) {
|
|
try {
|
|
const r = await pb.collection('quiz_cache').getFirstListItem(
|
|
`user_id="${userId}" && week_number=${weekNumber}`
|
|
);
|
|
return pb.collection('quiz_cache').update(r.id, { questions: quiz.questions, meta: quiz.meta });
|
|
} catch {
|
|
return pb.collection('quiz_cache').create({
|
|
user_id: userId, week_number: weekNumber, questions: quiz.questions, meta: quiz.meta,
|
|
});
|
|
}
|
|
}
|
|
|
|
// ── Learn Progress ────────────────────────────────────────────────────────────
|
|
|
|
export async function getLearnDone(userId, weekNumber) {
|
|
try {
|
|
const r = await pb.collection('learn_progress').getFirstListItem(
|
|
`user_id="${userId}" && week_number=${weekNumber}`
|
|
);
|
|
return r.done;
|
|
} catch { return false; }
|
|
}
|
|
|
|
export async function setLearnDone(userId, weekNumber) {
|
|
try {
|
|
const r = await pb.collection('learn_progress').getFirstListItem(
|
|
`user_id="${userId}" && week_number=${weekNumber}`
|
|
);
|
|
return pb.collection('learn_progress').update(r.id, { done: true });
|
|
} catch {
|
|
return pb.collection('learn_progress').create({ user_id: userId, week_number: weekNumber, done: true });
|
|
}
|
|
}
|
|
|
|
// ── Leaderboard ───────────────────────────────────────────────────────────────
|
|
|
|
export async function getLeaderboard() {
|
|
return pb.collection('leaderboard').getFullList({ sort: '-points' });
|
|
}
|
|
|
|
export async function upsertLeaderboardEntry(userId, name, pointsDelta, testsCompletedDelta = 0) {
|
|
try {
|
|
const r = await pb.collection('leaderboard').getFirstListItem(`user_id="${userId}"`);
|
|
return pb.collection('leaderboard').update(r.id, {
|
|
points: (r.points || 0) + pointsDelta,
|
|
tests_completed: (r.tests_completed || 0) + testsCompletedDelta,
|
|
});
|
|
} catch {
|
|
return pb.collection('leaderboard').create({
|
|
user_id: userId,
|
|
name,
|
|
points: pointsDelta,
|
|
tests_completed: testsCompletedDelta,
|
|
learnings_completed: 0,
|
|
});
|
|
}
|
|
}
|
|
|
|
// ── Settings ──────────────────────────────────────────────────────────────────
|
|
|
|
export async function getSetting(key, defaultValue = null) {
|
|
try {
|
|
const r = await pb.collection('settings').getFirstListItem(`key="${key}"`);
|
|
return r.value ?? defaultValue;
|
|
} catch { return defaultValue; }
|
|
}
|
|
|
|
export async function setSetting(key, value) {
|
|
try {
|
|
const r = await pb.collection('settings').getFirstListItem(`key="${key}"`);
|
|
return pb.collection('settings').update(r.id, { value: String(value) });
|
|
} catch {
|
|
return pb.collection('settings').create({ key, value: String(value) });
|
|
}
|
|
}
|