137 lines
3.2 KiB
JavaScript
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)
|
|
});
|
|
}
|
|
}
|
|
});
|