add new lesson mode and started code refraction
This commit is contained in:
@@ -3,134 +3,200 @@ 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
|
||||
}),
|
||||
state: () => ({
|
||||
token: localStorage.getItem('zen_token') || '',
|
||||
user: null,
|
||||
queue: [],
|
||||
lessonQueue: [],
|
||||
collection: [],
|
||||
stats: {
|
||||
distribution: {},
|
||||
forecast: [],
|
||||
queueLength: 0,
|
||||
lessonCount: 0,
|
||||
streak: {},
|
||||
accuracy: {},
|
||||
ghosts: [],
|
||||
},
|
||||
batchSize: parseInt(localStorage.getItem('zen_batch_size'), 10) || 20,
|
||||
drawingAccuracy: parseInt(localStorage.getItem('zen_drawing_accuracy'), 10) || 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 })
|
||||
});
|
||||
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');
|
||||
const data = await res.json();
|
||||
if (!res.ok) throw new Error(data.error || 'Login failed');
|
||||
|
||||
this.token = data.token;
|
||||
this.user = data.user;
|
||||
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;
|
||||
}
|
||||
if (data.user.settings) {
|
||||
this.batchSize = data.user.settings.batchSize || 20;
|
||||
this.drawingAccuracy = data.user.settings.drawingAccuracy || 10;
|
||||
|
||||
localStorage.setItem('zen_token', data.token);
|
||||
// Persist settings to local storage on login
|
||||
localStorage.setItem('zen_batch_size', this.batchSize);
|
||||
localStorage.setItem('zen_drawing_accuracy', this.drawingAccuracy);
|
||||
}
|
||||
|
||||
await this.fetchStats();
|
||||
return data;
|
||||
},
|
||||
localStorage.setItem('zen_token', data.token);
|
||||
|
||||
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();
|
||||
}
|
||||
},
|
||||
await this.fetchStats();
|
||||
return data;
|
||||
},
|
||||
|
||||
clearData() {
|
||||
this.token = '';
|
||||
this.user = null;
|
||||
this.queue = [];
|
||||
this.stats = {};
|
||||
localStorage.removeItem('zen_token');
|
||||
},
|
||||
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();
|
||||
}
|
||||
},
|
||||
|
||||
getHeaders() {
|
||||
return {
|
||||
'Authorization': `Bearer ${this.token}`,
|
||||
'Content-Type': 'application/json'
|
||||
};
|
||||
},
|
||||
clearData() {
|
||||
this.token = '';
|
||||
this.user = null;
|
||||
this.queue = [];
|
||||
this.stats = {};
|
||||
localStorage.removeItem('zen_token');
|
||||
localStorage.removeItem('zen_batch_size');
|
||||
localStorage.removeItem('zen_drawing_accuracy');
|
||||
},
|
||||
|
||||
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;
|
||||
},
|
||||
getHeaders() {
|
||||
return {
|
||||
Authorization: `Bearer ${this.token}`,
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
},
|
||||
|
||||
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 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 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 fetchStats() {
|
||||
if (!this.token) return null;
|
||||
|
||||
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();
|
||||
},
|
||||
const res = await fetch(`${BASE_URL}/api/stats`, { headers: this.getHeaders() });
|
||||
if (res.status === 401) {
|
||||
await this.logout();
|
||||
return null;
|
||||
}
|
||||
|
||||
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();
|
||||
},
|
||||
const data = await res.json();
|
||||
this.stats = data;
|
||||
return data;
|
||||
},
|
||||
|
||||
async saveSettings(settings) {
|
||||
if (settings.batchSize) this.batchSize = settings.batchSize;
|
||||
if (settings.drawingAccuracy) this.drawingAccuracy = settings.drawingAccuracy;
|
||||
async fetchQueue(sortMode = 'shuffled') {
|
||||
if (!this.token) return;
|
||||
|
||||
await fetch(`${BASE_URL}/api/settings`, {
|
||||
method: 'POST',
|
||||
headers: this.getHeaders(),
|
||||
body: JSON.stringify(settings)
|
||||
});
|
||||
}
|
||||
}
|
||||
const res = await fetch(`${BASE_URL}/api/queue?limit=${this.batchSize}&sort=${sortMode}`, {
|
||||
headers: this.getHeaders(),
|
||||
});
|
||||
|
||||
if (res.status === 401) {
|
||||
await this.logout();
|
||||
return;
|
||||
}
|
||||
|
||||
this.queue = await res.json();
|
||||
},
|
||||
|
||||
async fetchLessonQueue() {
|
||||
if (!this.token) return;
|
||||
|
||||
const res = await fetch(`${BASE_URL}/api/lessons?limit=${this.batchSize}`, {
|
||||
headers: this.getHeaders(),
|
||||
});
|
||||
|
||||
if (res.status === 401) {
|
||||
await this.logout();
|
||||
return;
|
||||
}
|
||||
|
||||
this.lessonQueue = await res.json();
|
||||
},
|
||||
|
||||
async fetchCollection() {
|
||||
if (!this.token) return;
|
||||
|
||||
const res = await fetch(`${BASE_URL}/api/collection`, { headers: this.getHeaders() });
|
||||
|
||||
if (res.status === 401) {
|
||||
await this.logout();
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
await this.logout();
|
||||
return null;
|
||||
}
|
||||
|
||||
return res.json();
|
||||
},
|
||||
|
||||
async submitLesson(subjectId) {
|
||||
const res = await fetch(`${BASE_URL}/api/lesson`, {
|
||||
method: 'POST',
|
||||
headers: this.getHeaders(),
|
||||
body: JSON.stringify({ subjectId }),
|
||||
});
|
||||
|
||||
if (res.status === 401) {
|
||||
await this.logout();
|
||||
return null;
|
||||
}
|
||||
|
||||
return res.json();
|
||||
},
|
||||
|
||||
async saveSettings(settings) {
|
||||
if (settings.batchSize !== undefined) {
|
||||
this.batchSize = settings.batchSize;
|
||||
localStorage.setItem('zen_batch_size', settings.batchSize);
|
||||
}
|
||||
if (settings.drawingAccuracy !== undefined) {
|
||||
this.drawingAccuracy = settings.drawingAccuracy;
|
||||
localStorage.setItem('zen_drawing_accuracy', settings.drawingAccuracy);
|
||||
}
|
||||
|
||||
await fetch(`${BASE_URL}/api/settings`, {
|
||||
method: 'POST',
|
||||
headers: this.getHeaders(),
|
||||
body: JSON.stringify(settings),
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user