From 3abad7ec316bcdc5878d08581afc88e8569e001b Mon Sep 17 00:00:00 2001 From: Azalea <22280294+hykilpikonna@users.noreply.github.com> Date: Wed, 19 Nov 2025 15:34:25 +0800 Subject: [PATCH] [+] Save user data --- src/lib/server/user.ts | 14 +++++++++++--- src/lib/user.ts | 15 +++++++++++++++ src/routes/api/user/+server.ts | 19 +++++++++++++++++++ src/routes/song/[slug]/+page.svelte | 14 +++++--------- src/shared/types.ts | 10 ++++++++-- 5 files changed, 58 insertions(+), 14 deletions(-) create mode 100644 src/lib/user.ts create mode 100644 src/routes/api/user/+server.ts diff --git a/src/lib/server/user.ts b/src/lib/server/user.ts index 0b7bf9d..82f28582 100644 --- a/src/lib/server/user.ts +++ b/src/lib/server/user.ts @@ -1,5 +1,5 @@ import { db } from "./db" -import type { UserDocument } from "../../shared/types.ts"; +import type { UserDocument, UserData } from "../../shared/types.ts"; const users = db.collection("users") @@ -42,5 +42,13 @@ export async function createSyncCode(session: string): Promise { return code } - - \ No newline at end of file +/** + * Update user data. + * @param session Session token + * @param data Data to update (partial) + */ +export async function updateUserData(session: string, data: Partial): Promise { + const user = await login(session) + const newData = { ...(user.data || {}), ...data } + await users.updateOne({ _id: user._id }, { $set: { data: newData } }) +} \ No newline at end of file diff --git a/src/lib/user.ts b/src/lib/user.ts new file mode 100644 index 0000000..24ce017 --- /dev/null +++ b/src/lib/user.ts @@ -0,0 +1,15 @@ +import type { UserData } from "../shared/types"; + +/** + * Save user data to the server. + * @param data Partial user data to update + */ +export async function saveUserData(data: Partial) { + await fetch('/api/user', { + method: 'POST', + body: JSON.stringify(data), + headers: { + 'Content-Type': 'application/json' + } + }) +} diff --git a/src/routes/api/user/+server.ts b/src/routes/api/user/+server.ts new file mode 100644 index 0000000..7d9b34d --- /dev/null +++ b/src/routes/api/user/+server.ts @@ -0,0 +1,19 @@ +import { json } from '@sveltejs/kit' +import { updateUserData } from '$lib/server/user' +import type { RequestHandler } from './$types' + +export const POST: RequestHandler = async ({ request, cookies }) => { + const session = cookies.get('session') + if (!session) { + return json({ error: 'Unauthorized' }, { status: 401 }) + } + + try { + const data = await request.json() + await updateUserData(session, data) + return json({ success: true }) + } catch (e) { + console.error('Failed to update user data', e) + return json({ error: 'Internal Server Error' }, { status: 500 }) + } +} diff --git a/src/routes/song/[slug]/+page.svelte b/src/routes/song/[slug]/+page.svelte index 24b9d91..89e524d 100644 --- a/src/routes/song/[slug]/+page.svelte +++ b/src/routes/song/[slug]/+page.svelte @@ -3,12 +3,12 @@ import type { PageProps } from "./$types" import { LinearProgress } from "m3-svelte"; import { onMount } from "svelte"; - import type { LyricSegment } from "../../../shared/types.ts"; + import { typingSettingsDefault, type LyricSegment } from "../../../shared/types.ts"; import { isKana, isKanji, toHiragana, toKatakana } from "wanakana"; import { composeList, fuzzyEquals } from "./IMEHelper.ts"; import MenuItem from "../../../components/material3/MenuItem.svelte"; import "../../../shared/ext.ts" - import { browser } from "$app/environment"; + import { saveUserData } from "$lib/user"; let { data }: PageProps = $props() @@ -19,13 +19,9 @@ let hiddenInput: HTMLInputElement let inp = $state("") - // Settings stored in localStorage - let settingDefaults = { - isFuri: true, - allKata: false - } - let settings = $state(browser ? (localStorage.getItem('kashi-dash-settings')?.let((it) => JSON.parse(it)) ?? settingDefaults) : settingDefaults) - $effect(() => { if (browser) localStorage.setItem('kashi-dash-settings', JSON.stringify(settings)) }) + // Settings stored in user data + let settings = $state(data.user.data?.typingSettings ?? typingSettingsDefault) + $effect(() => { saveUserData({ typingSettings: settings }) }) const preprocessKana = (kana: string) => settings.allKata ? toKatakana(kana) : kana // Process each line into segments with swi (start word index) and kanji/kana diff --git a/src/shared/types.ts b/src/shared/types.ts index 31b8d9e..9f3fbd9 100644 --- a/src/shared/types.ts +++ b/src/shared/types.ts @@ -56,7 +56,13 @@ export interface UserDocument { data?: UserData } +export const typingSettingsDefault = { + isFuri: true, + allKata: false +} + export interface UserData { - myPlaylists?: number[] - playHistory?: GameStats[] + myPlaylists?: number[] + playHistory?: GameStats[] + typingSettings?: typeof typingSettingsDefault } \ No newline at end of file