profile.html 250 lignes · 11180 octets
{% extends "base.html" %}

{% block title %}{{ page_title }}{% endblock %}

{% block navbar %}
{% include "components/navbar.html" %}
{% endblock %}

{% block content %}
<div class="container mx-auto px-4 py-8">
    <!-- Breadcrumb -->
    <div class="text-sm breadcrumbs mb-6">
        <ul>
            <li><a href="/">{{ breadcrumb_home }}</a></li>
            <li><a href="/profile">{{ breadcrumb_settings }}</a></li>
            <li>{{ breadcrumb_profile }}</li>
        </ul>
    </div>

    <!-- Page Header -->
    <div class="mb-8">
        <h1 class="text-3xl font-bold mb-2">{{ title }}</h1>
        <p class="text-base-content/70">{{ subtitle }}</p>
    </div>

    <!-- Profile Form Card -->
    <div class="card bg-base-100 shadow-xl max-w-2xl">
        <div class="card-body">
            <h2 class="card-title mb-4">{{ account_info }}</h2>
            
            <form id="profileForm" class="space-y-6"
                data-saved="{{ profile_saved }}"
                data-error="{{ profile_error }}"
                data-network="{{ network_error }}"
                data-saving="{{ saving }}"
                data-save-label="{{ save_button }}">
                <input type="hidden" name="csrf_token" value="{{ csrf_token }}">

                <div class="form-control">
                    <label class="label" for="username">
                        <span class="label-text font-semibold">{{ username_label }}</span>
                        <span class="label-text-alt text-warning">{{ username_public }}</span>
                    </label>
                    <input
                        type="text"
                        id="username"
                        name="username"
                        value="{{ username }}"
                        placeholder="{{ username_placeholder }}"
                        class="input input-bordered w-full"
                        minlength="3"
                        maxlength="39"
                        pattern="[a-z0-9-]+"
                        title="{{ username_pattern }}"
                        required
                    >
                    <label class="label">
                        <span class="label-text-alt">{{ username_help }}</span>
                    </label>
                </div>

                <div class="form-control">
                    <label class="label">
                        <span class="label-text font-semibold">{{ email_label }}</span>
                        <span class="label-text-alt text-info">{{ email_used_for }}</span>
                    </label>
                    <input
                        type="email"
                        value="{{ email }}"
                        class="input input-bordered w-full"
                        readonly
                    >
                    <label class="label">
                        <span class="label-text-alt">{{ email_warning }}</span>
                    </label>
                </div>

                <div class="card-actions justify-end">
                    <a href="/profile" class="btn btn-ghost">{{ cancel }}</a>
                    <button type="submit" class="btn btn-primary">{{ save_button }}</button>
                </div>
            </form>
        </div>
    </div>

    <div class="card bg-base-100 shadow-xl max-w-2xl mt-6">
        <div class="card-body">
            <h2 class="card-title mb-4">{{ email_change_title }}</h2>
            <div class="alert alert-info mb-4">
                <span>{{ email_change_info }}</span>
            </div>
            <div id="email-change-alert" class="hidden alert mb-4">
                <span id="email-change-alert-text"></span>
            </div>
            <form id="emailChangeForm" class="space-y-4"
                data-error="{{ email_change_error }}"
                data-network="{{ network_error }}"
                data-saving="{{ saving }}"
                data-submit-label="{{ request_button }}">
                <div class="form-control">
                    <label class="label" for="new-email">
                        <span class="label-text font-semibold">{{ new_email_label }}</span>
                    </label>
                    <input
                        type="email"
                        id="new-email"
                        name="new_email"
                        placeholder="{{ email_placeholder }}"
                        class="input input-bordered w-full"
                        required
                        autocomplete="email"
                    >
                </div>
                <div class="form-control">
                    <label class="label" for="current-password">
                        <span class="label-text font-semibold">{{ current_password_label }}</span>
                    </label>
                    <input
                        type="password"
                        id="current-password"
                        name="current_password"
                        class="input input-bordered w-full"
                        required
                        autocomplete="current-password"
                    >
                </div>
                <div class="card-actions justify-end">
                    <button type="submit" class="btn btn-primary">{{ request_button }}</button>
                </div>
            </form>
        </div>
    </div>

    <!-- Additional Info Card -->
    <div class="card bg-base-200 shadow-xl max-w-2xl mt-6">
        <div class="card-body">
            <h3 class="card-title text-base">Informations supplémentaires</h3>
            <div class="grid grid-cols-2 gap-4 text-sm">
                <div>
                    <p class="text-base-content/70">{{ account_created }}</p>
                    <p class="font-medium">{{ created_at }}</p>
                </div>
                <div>
                    <p class="text-base-content/70">{{ roles_label }}</p>
                    <p class="font-medium">{{ roles }}</p>
                </div>
                <div>
                    <p class="text-base-content/70">ID Utilisateur</p>
                    <p class="font-mono text-xs">{{ user_id }}</p>
                </div>
            </div>
        </div>
    </div>

    <!-- Quick Links -->
    <div class="mt-8 flex gap-4 flex-wrap">
        <a href="/settings/password" class="btn btn-outline btn-secondary">
            <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" /></svg>
            Changer mon mot de passe
        </a>
        <a href="/settings/sessions" class="btn btn-outline">
            <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" /></svg>
            Gérer mes sessions
        </a>
        <a href="/settings/preferences" class="btn btn-outline">
            <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01" /></svg>
            Préférences d'affichage
        </a>
        <a href="/settings/security" class="btn btn-outline btn-warning">
            <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" /></svg>
            Sécurité 2FA
        </a>
    </div>
</div>

<script>
document.getElementById('profileForm').addEventListener('submit', async function(e) {
    e.preventDefault();
    const submitBtn = this.querySelector('button[type="submit"]');
    const username = document.getElementById('username').value;
    submitBtn.disabled = true;
    submitBtn.textContent = this.dataset.saving;
    try {
        const response = await fetch('/profile', {
            method: 'PUT',
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json',
                'X-CSRF-Token': '{{ csrf_token }}',
            },
            credentials: 'include',
            body: JSON.stringify({ username })
        });
        const result = await response.json().catch(() => ({}));
        if (response.ok) {
            alert(this.dataset.saved);
            window.location.reload();
        } else {
            alert(result.error || result.message || this.dataset.error);
            submitBtn.disabled = false;
            submitBtn.textContent = this.dataset.saveLabel;
        }
    } catch (error) {
        alert(this.dataset.network);
        submitBtn.disabled = false;
        submitBtn.textContent = this.dataset.saveLabel;
    }
});

document.getElementById('emailChangeForm').addEventListener('submit', async function(e) {
    e.preventDefault();
    const submitBtn = this.querySelector('button[type="submit"]');
    const alertBox = document.getElementById('email-change-alert');
    const alertText = document.getElementById('email-change-alert-text');
    submitBtn.disabled = true;
    submitBtn.textContent = this.dataset.saving;
    alertBox.classList.add('hidden');
    try {
        const response = await fetch('/api/v1/auth/email-change', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json',
            },
            credentials: 'include',
            body: JSON.stringify({
                new_email: document.getElementById('new-email').value,
                current_password: document.getElementById('current-password').value
            })
        });
        const result = await response.json().catch(() => ({}));
        alertBox.classList.remove('hidden', 'alert-success', 'alert-error');
        if (response.ok) {
            alertBox.classList.add('alert-success');
            alertText.textContent = result.message || '';
            this.reset();
        } else {
            alertBox.classList.add('alert-error');
            alertText.textContent = result.error || result.message || this.dataset.error;
        }
    } catch (error) {
        alertBox.classList.remove('hidden', 'alert-success');
        alertBox.classList.add('alert-error');
        alertText.textContent = this.dataset.network;
    }
    submitBtn.disabled = false;
    submitBtn.textContent = this.dataset.submitLabel;
});
</script>
{% endblock %}