feat: add daily history tab and fetch daily character history for user profile
All checks were successful
Build Docker Image / build (push) Successful in 1m11s
All checks were successful
Build Docker Image / build (push) Successful in 1m11s
This commit is contained in:
@@ -2,8 +2,8 @@ import { fail, redirect } from '@sveltejs/kit';
|
||||
import type { Actions, PageServerLoad } from './$types';
|
||||
import { auth } from '$lib/server/auth';
|
||||
import { db } from '$lib/server/db';
|
||||
import { session } from '$lib/server/db/auth.schema';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { session, userCharacterHistory, characterHistory, character } from '$lib/server/db/schema';
|
||||
import { eq, desc } from 'drizzle-orm';
|
||||
import { APIError } from 'better-auth/api';
|
||||
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
@@ -17,9 +17,27 @@ export const load: PageServerLoad = async (event) => {
|
||||
.from(session)
|
||||
.where(eq(session.userId, event.locals.user.id));
|
||||
|
||||
// Fetch daily history for this user
|
||||
const dailyHistory = await db
|
||||
.select({
|
||||
id: userCharacterHistory.id,
|
||||
characterId: characterHistory.characterId,
|
||||
date: characterHistory.date,
|
||||
tryCount: userCharacterHistory.tryCount,
|
||||
won: characterHistory.won,
|
||||
characterName: character.name,
|
||||
characterImage: character.pictureUrl
|
||||
})
|
||||
.from(userCharacterHistory)
|
||||
.innerJoin(characterHistory, eq(userCharacterHistory.characterHistoryId, characterHistory.id))
|
||||
.innerJoin(character, eq(characterHistory.characterId, character.id))
|
||||
.where(eq(userCharacterHistory.userId, event.locals.user.id))
|
||||
.orderBy(desc(characterHistory.date));
|
||||
|
||||
return {
|
||||
user: event.locals.user,
|
||||
sessions: userSessions
|
||||
sessions: userSessions,
|
||||
dailyHistory: dailyHistory
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -10,13 +10,14 @@
|
||||
let { data, form }: Props = $props();
|
||||
|
||||
let isLoading = $state(false);
|
||||
let activeTab = $state<'profile' | 'password' | 'sessions'>('profile');
|
||||
let activeTab = $state<'profile' | 'password' | 'sessions' | 'daily'>('profile');
|
||||
let name = $state('');
|
||||
let showSuccess = $state(false);
|
||||
let oldPassword = $state('');
|
||||
let newPassword = $state('');
|
||||
let confirmPassword = $state('');
|
||||
let sessions = $state<any[]>([]);
|
||||
let dailyHistory = $state<any[]>([]);
|
||||
let tabsElement: HTMLDivElement | undefined;
|
||||
|
||||
$effect(() => {
|
||||
@@ -27,6 +28,10 @@
|
||||
sessions = (data as any).sessions || [];
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
dailyHistory = (data as any).dailyHistory || [];
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (form && form.success === true) {
|
||||
showSuccess = true;
|
||||
@@ -36,7 +41,7 @@
|
||||
}
|
||||
});
|
||||
|
||||
const handleTabChange = (tab: 'profile' | 'password' | 'sessions') => {
|
||||
const handleTabChange = (tab: 'profile' | 'password' | 'sessions' | 'daily') => {
|
||||
activeTab = tab;
|
||||
};
|
||||
|
||||
@@ -83,6 +88,14 @@
|
||||
>
|
||||
Mot de passe
|
||||
</button>
|
||||
<button
|
||||
onclick={() => handleTabChange('daily')}
|
||||
class="px-4 py-3 font-semibold uppercase tracking-[0.1em] transition {activeTab === 'daily'
|
||||
? 'border-b-2 border-amber-300 text-amber-100'
|
||||
: 'text-slate-400 hover:text-slate-100'}"
|
||||
>
|
||||
Historique Daily
|
||||
</button>
|
||||
<button
|
||||
onclick={() => handleTabChange('sessions')}
|
||||
class="px-4 py-3 font-semibold uppercase tracking-[0.1em] transition {activeTab === 'sessions'
|
||||
@@ -268,6 +281,70 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Daily History Tab -->
|
||||
{#if activeTab === 'daily'}
|
||||
<div class="rounded-3xl border border-white/10 bg-white/5 p-6 shadow-[0_24px_60px_rgba(0,0,0,0.45)] backdrop-blur sm:p-8">
|
||||
<h2 class="mb-6 text-2xl font-bold uppercase tracking-[0.2em] text-amber-50">
|
||||
Historique des Daily
|
||||
</h2>
|
||||
|
||||
{#if dailyHistory.length === 0}
|
||||
<p class="text-center text-slate-400">Aucun historique disponible</p>
|
||||
{:else}
|
||||
<div class="space-y-4">
|
||||
{#each dailyHistory as day}
|
||||
<div class="flex items-center gap-4 rounded-lg border border-white/10 bg-white/5 p-4">
|
||||
<!-- Character Image -->
|
||||
<div class="flex-shrink-0">
|
||||
{#if day.characterImage}
|
||||
<img
|
||||
src={day.characterImage}
|
||||
alt={day.characterName}
|
||||
class="h-16 w-16 rounded-lg border border-white/20 object-cover"
|
||||
/>
|
||||
{:else}
|
||||
<div class="flex h-16 w-16 items-center justify-center rounded-lg border border-white/20 bg-slate-700">
|
||||
<span class="text-xs text-slate-400">N/A</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Character Info -->
|
||||
<div class="flex-1">
|
||||
<p class="font-semibold text-white">{day.characterName}</p>
|
||||
<p class="text-xs text-slate-400">
|
||||
{new Date(day.date).toLocaleDateString('fr-FR', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Status and Tries -->
|
||||
<div class="flex flex-col items-end gap-2">
|
||||
<div class="flex items-center gap-2">
|
||||
{#if day.won === 1}
|
||||
<span class="rounded-full bg-green-900/30 px-3 py-1 text-xs font-semibold text-green-300">
|
||||
✓ Gagné
|
||||
</span>
|
||||
{:else}
|
||||
<span class="rounded-full bg-red-900/30 px-3 py-1 text-xs font-semibold text-red-300">
|
||||
✗ Perdu
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
<p class="text-xs text-slate-400">
|
||||
{day.tryCount} {day.tryCount === 1 ? 'tentative' : 'tentatives'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Sessions Tab -->
|
||||
{#if activeTab === 'sessions'}
|
||||
<div class="rounded-3xl border border-white/10 bg-white/5 p-6 shadow-[0_24px_60px_rgba(0,0,0,0.45)] backdrop-blur sm:p-8">
|
||||
|
||||
Reference in New Issue
Block a user