Skip to content
Extraits de code Groupes Projets

Comparer les révisions

Les modifications sont affichées comme si la révision source était fusionnée avec la révision cible. En savoir plus sur la comparaison des révisions.

Source

Sélectionner le projet cible
No results found

Cible

Sélectionner le projet cible
  • sbibauw/languagelab
1 résultat
Afficher les modifications
Validations sur la source (5)
......@@ -8,6 +8,16 @@
"users": "Users",
"studies": "Studies"
},
"tutor": {
"profile": "My profile",
"update": "Update",
"updatedSuccessfully": "Profile updated successfully",
"updateError": "Error updating profile",
"userNotFound": "User not found",
"selectGender": "Select your gender",
"bio": "Biography",
"availabilities": "Availabilities"
},
"availability": "Availability",
"language": "Language",
"register": "Sign up",
......@@ -49,7 +59,8 @@
"noCurrentOrFutureSessions": "No session in progress or planned",
"pastSessions": "Completed sessions",
"plannedSessions": "Scheduled sessions",
"sessionAdded": "You have been added to a session with {users}"
"sessionAdded": "You have been added to a session with {users}",
"birthdate": "Birthdate"
},
"signup": {
"title": "Register",
......
......@@ -13,6 +13,16 @@
"users": "Utilisateurs",
"sessions": "Sessions",
"studies": "Études"
},
"tutor": {
"profile": "Mon profil",
"updatedSuccessfully": "Profil mis à jour avec succès",
"updateError": "Erreur lors de la mise à jour du profil",
"userNotFound": "Utilisateur non trouvé",
"update": "Confirmer",
"selectGender": "Sélectionnez votre genre",
"bio": "Biographie",
"availabilities": "Disponibilités"
}
},
"chatbox": {
......@@ -49,7 +59,8 @@
"actions": "Actions",
"date": "Date",
"participants": "Participants",
"sessionAdded": "Vous avez été ajouté à une session avec {users}"
"sessionAdded": "Vous avez été ajouté à une session avec {users}",
"birthdate": "Date de naissance"
},
"login": {
"email": "E-mail",
......
......@@ -51,7 +51,7 @@
</div>
<div class="navbar-end hidden sm:flex">
<ul class="menu menu-horizontal p-0 flex items-center">
{#if user}
{#if user?.type === 2}
<li>
<details>
<summary class="px-3">
......@@ -71,33 +71,64 @@
</ul>
</details>
</li>
{#if user?.type === 0}
<li>
<details>
<summary class="p-3">
<Icon src={Cog6Tooth} class="h-5 w-5" />
</summary>
<ul class="menu menu-sm dropdown-content absolute right-0 z-10">
<li>
<a data-sveltekit-reload href="/admin/users">
{$t('header.admin.users')}
</a>
</li>
<li>
<a data-sveltekit-reload href="/admin/sessions">
{$t('header.admin.sessions')}
</a>
</li>
<li>
<a data-sveltekit-reload href="/admin/studies">
{$t('header.admin.studies')}
</a>
</li>
</ul>
</details>
</li>
{/if}
{:else}
{/if}
{#if user?.type === 1}
<li>
<details>
<summary class="px-3">
<img
src={`https://gravatar.com/avatar/${user.emailHash}?d=identicon`}
alt={''}
class="rounded-full border text-sm size-8 border-neutral-400"
/>
{user.nickname}
</summary>
<ul class="menu menu-sm dropdown-content absolute right-0">
<li>
<a data-sveltekit-reload href="/logout" class="whitespace-nowrap">
{$t('header.signout')}
</a>
</li>
<li>
<a data-sveltekit-reload href="/tutor/profile" class="whitespace-nowrap">
{$t('header.tutor.profile')}
</a>
</li>
</ul>
</details>
</li>
{/if}
{#if user?.type === 0}
<li>
<details>
<summary class="p-3">
<Icon src={Cog6Tooth} class="h-5 w-5" />
</summary>
<ul class="menu menu-sm dropdown-content absolute right-0 z-10">
<li>
<a data-sveltekit-reload href="/admin/users">
{$t('header.admin.users')}
</a>
</li>
<li>
<a data-sveltekit-reload href="/admin/sessions">
{$t('header.admin.sessions')}
</a>
</li>
<li>
<a data-sveltekit-reload href="/admin/studies">
{$t('header.admin.studies')}
</a>
</li>
<li>
<a data-sveltekit-reload href="/logout" class="whitespace-nowrap">
{$t('header.signout')}
</a>
</li>
</ul>
</details>
</li>
{:else if !user}
<li>
<a
class="btn btn-sm my-auto"
......
<script lang="ts">
import { t } from '$lib/services/i18n';
import { patchUserAPI } from '$lib/api/users';
import type { PageData } from './$types';
let { data }: { data: PageData } = $props();
const formatBirthdate = (dateStr: string | Date | undefined): string => {
if (!dateStr) return '';
const date = new Date(dateStr);
if (!isNaN(date.getTime())) return date.toISOString().split('T')[0];
if (typeof dateStr === 'string') {
const [day, month, year] = dateStr.split('/');
if (year?.length === 4) return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`;
}
return '';
};
let email = data.user?.email || '';
let nickname = data.user?.nickname || '';
let birthdate = formatBirthdate(data.user?.birthdate ?? undefined);
let gender = data.user?.gender || '';
let bio = data.user?.bio || '';
let availabilities = data.user?.availabilities
? JSON.stringify(data.user.availabilities, null, 2)
: '';
async function updateProfile() {
try {
const parsedAvailabilities = availabilities ? JSON.parse(availabilities) : [];
const updateData = {
email,
nickname,
birthdate,
gender,
bio,
availabilities: parsedAvailabilities
};
let success = false;
if (data.user) {
success = await patchUserAPI(fetch, data.user.id, updateData);
} else {
throw new Error($t('header.tutor.userNotFound'));
}
if (success) {
alert($t('header.tutor.updatedSuccessfully'));
} else {
alert($t('header.tutor.updateError'));
}
} catch (error) {
console.error('Update failed:', error);
alert(error instanceof Error ? error.message : $t('errors.updateFailed'));
}
}
</script>
<h1 class="text-3xl font-bold text-center mb-8 text-primary">
{$t('header.tutor.profile')}
</h1>
<div class="card bg-base-100 shadow-xl max-w-2xl mx-auto p-8">
<form on:submit|preventDefault={updateProfile} class="space-y-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="form-control">
<label class="label" for="email">
<span class="label-text">{$t('home.email')}</span>
</label>
<input
type="email"
id="email"
bind:value={email}
class="input input-bordered focus:input-primary"
required
/>
</div>
<div class="form-control">
<label class="label" for="nickname">
<span class="label-text">{$t('home.nickname')}</span>
</label>
<input
type="text"
id="nickname"
bind:value={nickname}
class="input input-bordered focus:input-primary"
required
/>
</div>
<div class="form-control">
<label class="label" for="birthdate">
<span class="label-text">{$t('home.birthdate')}</span>
</label>
<input
type="date"
id="birthdate"
bind:value={birthdate}
class="input input-bordered focus:input-primary"
required
/>
</div>
<div class="form-control">
<label class="label" for="gender">
<span class="label-text">{$t('users.gender')}</span>
</label>
<select
id="gender"
bind:value={gender}
class="select select-bordered focus:select-primary"
required
>
<option value="" disabled>{$t('header.tutor.selectGender')}</option>
<option value="male">{$t('users.genders.male')}</option>
<option value="female">{$t('users.genders.female')}</option>
<option value="other">{$t('users.genders.other')}</option>
</select>
</div>
</div>
<div class="form-control">
<label class="label" for="bio">
<span class="label-text">{$t('register.bio')}</span>
</label>
<textarea
id="bio"
rows="4"
bind:value={bio}
placeholder={$t('header.tutor.bio')}
class="textarea textarea-bordered focus:textarea-primary h-24"
required
></textarea>
</div>
<div class="form-control">
<label class="label" for="availabilities">
<span class="label-text">
{$t('register.availabilities')}
<span class="text-xs text-info ml-2">(JSON format)</span>
</span>
</label>
<textarea
id="availabilities"
rows="4"
bind:value={availabilities}
placeholder={$t('header.tutor.availabilities')}
class="textarea textarea-bordered focus:textarea-primary font-mono h-32"
required
></textarea>
</div>
<button type="submit" class="btn btn-primary w-full mt-6 text-lg">
{$t('header.tutor.update')}
</button>
</form>
</div>