big ui refractor

This commit is contained in:
Rene Kievits
2025-12-23 02:23:44 +01:00
parent 4428a2b7be
commit eaed23a678
62 changed files with 2662 additions and 815 deletions

View File

@@ -1,4 +1,4 @@
export const PORT = process.env.PORT || 3000;
export const MONGO_URI = process.env.MONGO_URI || 'mongodb://mongo:27017/zenkanji' || 'mongodb://192.168.0.26:27017/zenkanji';
export const SRS_TIMINGS_HOURS = [0, 0, 4, 8, 23, 47];
export const SRS_TIMINGS_HOURS = [0, 2, 4, 8, 23, 47];
export const JWT_SECRET = process.env.JWT_SECRET;

View File

@@ -97,7 +97,11 @@ export const processLesson = async (user, subjectId) => {
if (!item) throw new Error('Item not found');
item.srsLevel = 1;
item.nextReview = new Date();
const nextReview = new Date();
nextReview.setUTCHours(nextReview.getUTCHours() + 2);
nextReview.setUTCMinutes(0, 0, 0);
item.nextReview = nextReview;
await item.save();
return { success: true, item };

View File

@@ -7,7 +7,6 @@ export const syncWithWaniKani = async (user) => {
console.log(`Starting sync for user: ${user._id}`);
// 1. Fetch all assigned Kanji Subject IDs
let allSubjectIds = [];
let nextUrl = 'https://api.wanikani.com/v2/assignments?subject_types=kanji&started=true';
@@ -26,26 +25,22 @@ export const syncWithWaniKani = async (user) => {
if (allSubjectIds.length === 0) return { count: 0, message: "No unlocked kanji found." };
// 2. Filter out items we already have
const existingItems = await StudyItem.find({ userId: user._id }).select('wkSubjectId');
const existingIds = new Set(existingItems.map(i => i.wkSubjectId));
const newIds = allSubjectIds.filter(id => !existingIds.has(id));
console.log(`Found ${newIds.length} new items.`);
// 3. Process in chunks
const CHUNK_SIZE = 50; // Reduced chunk size to accommodate secondary radical fetches
const CHUNK_SIZE = 50;
for (let i = 0; i < newIds.length; i += CHUNK_SIZE) {
const chunk = newIds.slice(i, i + CHUNK_SIZE);
// A. Fetch Kanji Details
const subRes = await fetch(`https://api.wanikani.com/v2/subjects?ids=${chunk.join(',')}`, {
headers: { Authorization: `Bearer ${apiKey}` }
});
const subJson = await subRes.json();
const kanjiDataList = subJson.data;
// B. Identify all needed Radicals
const radicalIdsToFetch = new Set();
kanjiDataList.forEach(k => {
if (k.data.component_subject_ids) {
@@ -53,11 +48,9 @@ export const syncWithWaniKani = async (user) => {
}
});
// C. Fetch Radical Details (if any)
const radicalMap = new Map();
if (radicalIdsToFetch.size > 0) {
const rIds = Array.from(radicalIdsToFetch);
// Fetch radicals in sub-chunks if necessary (max 100 per req)
for (let j = 0; j < rIds.length; j += 100) {
const rChunk = rIds.slice(j, j + 100);
const rRes = await fetch(`https://api.wanikani.com/v2/subjects?ids=${rChunk.join(',')}`, {
@@ -68,7 +61,6 @@ export const syncWithWaniKani = async (user) => {
rJson.data.forEach(r => {
const primaryMeaning = r.data.meanings.find(m => m.primary)?.meaning || 'Unknown';
const char = r.data.characters;
// Find SVG image if no character exists
const image = !char && r.data.character_images
? r.data.character_images.find(img => img.content_type === 'image/svg+xml' && !img.metadata.inline_styles)?.url
: null;
@@ -82,14 +74,12 @@ export const syncWithWaniKani = async (user) => {
}
}
// D. Build Database Objects
const operations = kanjiDataList.map(d => {
const readings = d.data.readings || [];
// Map the IDs to our fetched radical data
const itemRadicals = (d.data.component_subject_ids || [])
.map(rid => radicalMap.get(rid))
.filter(Boolean); // Remove any not found
.filter(Boolean);
return {
userId: user._id,
@@ -97,12 +87,12 @@ export const syncWithWaniKani = async (user) => {
char: d.data.characters,
meaning: d.data.meanings.find(m => m.primary)?.meaning || 'Unknown',
level: d.data.level,
srsLevel: 1,
srsLevel: 0,
nextReview: Date.now(),
onyomi: readings.filter(r => r.type === 'onyomi').map(r => r.reading),
kunyomi: readings.filter(r => r.type === 'kunyomi').map(r => r.reading),
nanori: readings.filter(r => r.type === 'nanori').map(r => r.reading),
radicals: itemRadicals, // Save them
radicals: itemRadicals,
stats: { correct: 0, total: 0 }
};
});

View File

@@ -28,5 +28,6 @@ export const getSRSDate = (level) => {
if (hoursToAdd === 0) return null;
now.setUTCHours(now.getUTCHours() + hoursToAdd);
now.setUTCMinutes(0, 0, 0);
return now;
};