1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-07-25 07:49:37 +02:00

Add new dashboard

This commit is contained in:
Sean Morley 2024-12-03 14:00:48 -05:00
parent 88dbd41b92
commit a39e22b0a8
13 changed files with 181 additions and 11 deletions

View file

@ -444,7 +444,6 @@
headers: {
'Content-Type': 'application/json'
},
credentials: 'include',
body: JSON.stringify(adventure)
});
let data = await res.json();

View file

@ -294,7 +294,8 @@
"join_discord_desc": "um Ihre eigenen Fotos zu teilen. \nVeröffentlichen Sie sie im",
"photo_by": "Foto von",
"change_password_error": "Passwort kann nicht geändert werden. \nUngültiges aktuelles Passwort oder ungültiges neues Passwort.",
"current_password": "Aktuelles Passwort"
"current_password": "Aktuelles Passwort",
"password_change_lopout_warning": "Nach der Passwortänderung werden Sie abgemeldet."
},
"checklist": {
"add_item": "Artikel hinzufügen",

View file

@ -294,7 +294,8 @@
"join_discord": "Join the Discord",
"join_discord_desc": "to share your own photos. Post them in the #travel-share channel.",
"current_password": "Current Password",
"change_password_error": "Unable to change password. Invalid current password or invalid new password."
"change_password_error": "Unable to change password. Invalid current password or invalid new password.",
"password_change_lopout_warning": "You will be logged out after changing your password."
},
"collection": {
"collection_created": "Collection created successfully!",

View file

@ -294,7 +294,8 @@
"join_discord_desc": "para compartir tus propias fotos. \nPublicarlos en el",
"photo_by": "Foto por",
"change_password_error": "No se puede cambiar la contraseña. \nContraseña actual no válida o contraseña nueva no válida.",
"current_password": "Contraseña actual"
"current_password": "Contraseña actual",
"password_change_lopout_warning": "Se cerrará su sesión después de cambiar su contraseña."
},
"checklist": {
"add_item": "Agregar artículo",

View file

@ -294,7 +294,8 @@
"join_discord_desc": "pour partager vos propres photos. \nPostez-les dans le",
"photo_by": "Photo par",
"change_password_error": "Impossible de changer le mot de passe. \nMot de passe actuel invalide ou nouveau mot de passe invalide.",
"current_password": "Mot de passe actuel"
"current_password": "Mot de passe actuel",
"password_change_lopout_warning": "Vous serez déconnecté après avoir modifié votre mot de passe."
},
"checklist": {
"add_item": "Ajouter un article",

View file

@ -294,7 +294,8 @@
"join_discord_desc": "per condividere le tue foto. \nPubblicateli in",
"photo_by": "Foto di",
"change_password_error": "Impossibile modificare la password. \nPassword attuale non valida o nuova password non valida.",
"current_password": "password attuale"
"current_password": "password attuale",
"password_change_lopout_warning": "Verrai disconnesso dopo aver modificato la password."
},
"checklist": {
"add_item": "Aggiungi articolo",

View file

@ -294,7 +294,8 @@
"join_discord_desc": "om uw eigen foto's te delen. \nPlaats ze in de",
"photo_by": "Foto door",
"change_password_error": "Kan wachtwoord niet wijzigen. \nOngeldig huidig wachtwoord of ongeldig nieuw wachtwoord.",
"current_password": "Huidig wachtwoord"
"current_password": "Huidig wachtwoord",
"password_change_lopout_warning": "Na het wijzigen van uw wachtwoord wordt u uitgelogd."
},
"checklist": {
"add_item": "Artikel toevoegen",

View file

@ -294,7 +294,8 @@
"join_discord": "Dołącz do Discorda",
"join_discord_desc": "aby podzielić się swoimi zdjęciami. Zamieść je w kanale #travel-share.",
"change_password_error": "Nie można zmienić hasła. \nNieprawidłowe bieżące hasło lub nieprawidłowe nowe hasło.",
"current_password": "Aktualne hasło"
"current_password": "Aktualne hasło",
"password_change_lopout_warning": "Po zmianie hasła nastąpi wylogowanie."
},
"collection": {
"collection_created": "Kolekcja została pomyślnie utworzona!",

View file

@ -294,7 +294,8 @@
"join_discord_desc": "för att dela dina egna foton. \nLägg upp dem i",
"photo_by": "Foto av",
"change_password_error": "Det går inte att ändra lösenord. \nOgiltigt nuvarande lösenord eller ogiltigt nytt lösenord.",
"current_password": "Aktuellt lösenord"
"current_password": "Aktuellt lösenord",
"password_change_lopout_warning": "Du kommer att loggas ut efter att du har ändrat ditt lösenord."
},
"checklist": {
"add_item": "Lägg till objekt",

View file

@ -294,7 +294,8 @@
"join_discord_desc": "分享您自己的照片。\n将它们张贴在",
"photo_by": "摄影:",
"change_password_error": "无法更改密码。\n当前密码无效或新密码无效。",
"current_password": "当前密码"
"current_password": "当前密码",
"password_change_lopout_warning": "更改密码后您将退出。"
},
"checklist": {
"add_item": "添加项目",

View file

@ -0,0 +1,53 @@
import { redirect } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
const PUBLIC_SERVER_URL = process.env['PUBLIC_SERVER_URL'];
import type { Adventure } from '$lib/types';
const serverEndpoint = PUBLIC_SERVER_URL || 'http://localhost:8000';
export const load = (async (event) => {
if (!event.locals.user) {
return redirect(302, '/login');
} else {
let adventures: Adventure[] = [];
let initialFetch = await event.fetch(`${serverEndpoint}/api/adventures/`, {
headers: {
Cookie: `sessionid=${event.cookies.get('sessionid')}`
},
credentials: 'include'
});
let stats = null;
let res = await event.fetch(`${serverEndpoint}/api/stats/counts/`, {
headers: {
Cookie: `sessionid=${event.cookies.get('sessionid')}`
}
});
if (!res.ok) {
console.error('Failed to fetch user stats');
} else {
stats = await res.json();
}
if (!initialFetch.ok) {
let error_message = await initialFetch.json();
console.error(error_message);
console.error('Failed to fetch visited adventures');
return redirect(302, '/login');
} else {
let res = await initialFetch.json();
let visited = res.results as Adventure[];
// only get the first 3 adventures or less if there are less than 3
adventures = visited.slice(0, 3);
}
return {
props: {
adventures,
stats
}
};
}
}) satisfies PageServerLoad;

View file

@ -0,0 +1,107 @@
<script lang="ts">
import AdventureCard from '$lib/components/AdventureCard.svelte';
import type { PageData } from './$types';
export let data: PageData;
// Mock data
const user = data.user;
const recentAdventures = data.props.adventures;
const stats = data.props.stats;
console.log(stats);
const inspirationQuote = 'The world is a book, and those who do not travel read only one page.';
const inspirationImage = 'https://picsum.photos/seed/inspiration/800/400';
</script>
<div class="container mx-auto p-4">
<!-- Welcome Message -->
<div class="mb-8">
<h1 class="text-4xl font-extrabold">Welcome back, {user?.first_name}!</h1>
</div>
<!-- Stats -->
<div class="stats shadow mb-8 w-full bg-neutral">
<div class="stat">
<div class="stat-figure text-primary">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
class="inline-block w-8 h-8 stroke-current"
><path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4m0 0L9 7"
></path></svg
>
</div>
<div class="stat-title text-neutral-content">Countries Visited</div>
<div class="stat-value text-primary">{stats.country_count}</div>
</div>
<div class="stat">
<div class="stat-figure text-secondary">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
class="inline-block w-8 h-8 stroke-current"
><path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
></path></svg
>
</div>
<div class="stat-title text-neutral-content">Total Adventures</div>
<div class="stat-value text-secondary">{stats.adventure_count}</div>
</div>
<div class="stat">
<div class="stat-figure text-success">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
class="inline-block w-8 h-8 stroke-current"
><path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4"
></path></svg
>
</div>
<div class="stat-title text-neutral-content">Total Visited Regions</div>
<div class="stat-value text-success">{stats.visited_region_count}</div>
</div>
</div>
<!-- Recent Adventures -->
<h2 class="text-3xl font-semibold mb-4">Recent Adventures</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-8">
{#each recentAdventures as adventure}
<AdventureCard {adventure} type="someType" user={data.user} />
{/each}
</div>
<!-- Inspiration -->
<div class="card lg:card-side bg-base-100 shadow-xl mb-8">
<figure class="lg:w-1/2">
<img src={inspirationImage} alt="Inspiration" class="w-full h-full object-cover" />
</figure>
<div class="card-body lg:w-1/2">
<h2 class="card-title">Get Inspired</h2>
<p class="text-lg italic">"{inspirationQuote}"</p>
<div class="card-actions justify-end">
<button class="btn btn-primary">Plan Your Next Adventure</button>
</div>
</div>
</div>
</div>
<svelte:head>
<title>Dashboard | AdventureLog</title>
<meta name="description" content="Home dashboard for AdventureLog." />
</svelte:head>

View file

@ -151,7 +151,9 @@
placeholder={$t('settings.confirm_new_password')}
class="block mb-2 input input-bordered w-full max-w-xs"
/>
<button class="py-2 px-4 btn btn-primary mt-2">{$t('settings.password_change')}</button>
<div class="tooltip tooltip-warning" data-tip={$t('settings.password_change_lopout_warning')}>
<button class="py-2 px-4 btn btn-primary mt-2">{$t('settings.password_change')}</button>
</div>
<br />
</form>
</div>