Files
zen-kanji/client/src/stores/appStore.js
Rene Kievits 6438660b03 init
2025-12-18 01:30:52 +01:00

137 lines
3.2 KiB
JavaScript

import { defineStore } from 'pinia';
const BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000';
export const useAppStore = defineStore('app', {
state: () => ({
token: localStorage.getItem('zen_token') || '',
user: null,
queue: [],
collection: [],
stats: {
distribution: {},
forecast: [],
queueLength: 0,
streak: {},
accuracy: {},
ghosts: []
},
batchSize: 20,
drawingAccuracy: 10,
loading: false
}),
actions: {
async login(apiKey) {
const res = await fetch(`${BASE_URL}/api/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ apiKey })
});
const data = await res.json();
if (!res.ok) throw new Error(data.error || 'Login failed');
this.token = data.token;
this.user = data.user;
if (data.user.settings) {
this.batchSize = data.user.settings.batchSize || 20;
this.drawingAccuracy = data.user.settings.drawingAccuracy || 10;
}
localStorage.setItem('zen_token', data.token);
await this.fetchStats();
return data;
},
async logout() {
try {
if (this.token) {
await fetch(`${BASE_URL}/api/auth/logout`, {
method: 'POST',
headers: this.getHeaders()
});
}
} catch (e) {
console.error("Logout error:", e);
} finally {
this.clearData();
}
},
clearData() {
this.token = '';
this.user = null;
this.queue = [];
this.stats = {};
localStorage.removeItem('zen_token');
},
getHeaders() {
return {
'Authorization': `Bearer ${this.token}`,
'Content-Type': 'application/json'
};
},
async sync() {
const res = await fetch(`${BASE_URL}/api/sync`, {
method: 'POST',
headers: this.getHeaders(),
body: JSON.stringify({})
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
return data;
},
async fetchStats() {
if (!this.token) return;
const res = await fetch(`${BASE_URL}/api/stats`, { headers: this.getHeaders() });
if (res.status === 401) return this.logout();
const data = await res.json();
this.stats = data;
return data;
},
async fetchQueue(sortMode = 'shuffled') {
if (!this.token) return;
const res = await fetch(`${BASE_URL}/api/queue?limit=${this.batchSize}&sort=${sortMode}`, {
headers: this.getHeaders()
});
if (res.status === 401) return this.logout();
this.queue = await res.json();
},
async fetchCollection() {
if (!this.token) return;
const res = await fetch(`${BASE_URL}/api/collection`, { headers: this.getHeaders() });
if (res.status === 401) return this.logout();
this.collection = await res.json();
},
async submitReview(subjectId, success) {
const res = await fetch(`${BASE_URL}/api/review`, {
method: 'POST',
headers: this.getHeaders(),
body: JSON.stringify({ subjectId, success })
});
if (res.status === 401) return this.logout();
return await res.json();
},
async saveSettings(settings) {
if (settings.batchSize) this.batchSize = settings.batchSize;
if (settings.drawingAccuracy) this.drawingAccuracy = settings.drawingAccuracy;
await fetch(`${BASE_URL}/api/settings`, {
method: 'POST',
headers: this.getHeaders(),
body: JSON.stringify(settings)
});
}
}
});