Created
July 20, 2025 22:15
-
-
Save Pismice/2351d6825043d0c50fb101538151b6f5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script lang="ts"> | |
import { enhance } from '$app/forms'; | |
import { goto } from '$app/navigation'; | |
import { profilePictureTimestamp, refreshProfilePicture } from '$lib/stores/profilePicture.js'; | |
import * as m from '$lib/paraglide/messages'; | |
import { ConsoleLogWriter } from 'drizzle-orm'; | |
import { flushSync } from 'svelte'; | |
type UserWithProfilePicture = { | |
firstname: string; | |
lastname: string; | |
id: string; | |
username: string; | |
email: string; | |
telephone?: string | null; | |
hasProfilePicture: boolean; | |
emailVerified: boolean; | |
phoneVerified: boolean; | |
}; | |
let { data }: { data: { user: UserWithProfilePicture } } = $props(); | |
let selectedFile = $state<File | null>(null); | |
let lol = $state('lol'); | |
let displayLol = $derived(lol); | |
let isResendingEmail = $state(false); | |
let emailMessage = $state<string | null>(null); | |
let emailMessageType = $state<'success' | 'error' | null>(null); | |
// Phone verification states | |
let phoneNumber = $state(''); | |
let countryCode = $state('+33'); | |
let fullPhoneNumber = $state(data.user.telephone || ''); | |
let showConfirmationModal = $state(false); | |
let script: HTMLScriptElement; | |
let captchaToken = $state(''); | |
// Modal states for complete verification flow | |
let modalStep = $state< | |
'confirm' | 'sending' | 'code_sent' | 'enter_code' | 'verifying' | 'success' | 'error' | |
>('confirm'); | |
let modalMessage = $state(''); | |
let modalMessageType = $state<'success' | 'error' | null>(null); | |
let tempPhoneNumber = $state(''); | |
let verificationCode = $state(''); | |
// Country codes with flags | |
const countryCodes = [ | |
{ code: '+33', country: 'FR', flag: '🇫🇷', name: m.france() }, | |
{ code: '+39', country: 'IT', flag: '🇮🇹', name: m.italy() }, | |
{ code: '+41', country: 'CH', flag: '🇨🇭', name: m.switzerland() }, | |
{ code: '+43', country: 'AT', flag: '🇦🇹', name: m.austria() }, | |
{ code: '+49', country: 'DE', flag: '🇩🇪', name: m.germany() } | |
]; | |
const sortedCountryCodes = countryCodes.sort((a, b) => a.name.localeCompare(b.name)); | |
// TODO delete | |
$effect(() => { | |
console.log('lol changed in effect:', lol); | |
const h2 = document.querySelector('h4'); | |
if (h2) h2.textContent = lol; | |
}); | |
// Update fullPhoneNumber when country code or phone number changes | |
$effect(() => { | |
// Remove leading zero from phone number before combining with country code | |
const cleanPhoneNumber = phoneNumber.replace(/^0/, ''); | |
fullPhoneNumber = countryCode + cleanPhoneNumber.replace(/\s/g, ''); // Also remove spaces | |
}); | |
// Parse existing telephone number if user has one | |
$effect(() => { | |
if (data.user.telephone) { | |
const existingPhone = data.user.telephone; | |
const matchingCountry = countryCodes.find((c) => existingPhone.startsWith(c.code)); | |
if (matchingCountry) { | |
countryCode = matchingCountry.code; | |
let localNumber = existingPhone.substring(matchingCountry.code.length); | |
// Add leading zero for display if the country code is Swiss (+41) and number doesn't start with 0 | |
if (matchingCountry.code === '+41' && !localNumber.startsWith('0')) { | |
localNumber = '0' + localNumber; | |
} | |
// Format the phone number with spaces for display | |
phoneNumber = formatPhoneNumber(localNumber); | |
} else { | |
// Fallback if no matching country code found | |
countryCode = '+33'; | |
const fallbackNumber = existingPhone.replace(/^\+\d+/, ''); | |
phoneNumber = formatPhoneNumber(fallbackNumber); | |
} | |
} | |
}); | |
// Format phone number with spaces (Swiss style: "079 548 17 17") | |
function formatPhoneNumber(value: string): string { | |
// Remove all non-digits | |
const digits = value.replace(/\D/g, ''); | |
// Apply Swiss formatting: XXX XXX XX XX | |
if (digits.length <= 3) { | |
return digits; | |
} else if (digits.length <= 6) { | |
return `${digits.slice(0, 3)} ${digits.slice(3)}`; | |
} else if (digits.length <= 8) { | |
return `${digits.slice(0, 3)} ${digits.slice(3, 6)} ${digits.slice(6)}`; | |
} else { | |
return `${digits.slice(0, 3)} ${digits.slice(3, 6)} ${digits.slice(6, 8)} ${digits.slice(8, 10)}`; | |
} | |
} | |
// Handle phone number input formatting | |
function handlePhoneInput(event: Event) { | |
const target = event.target as HTMLInputElement; | |
const cursorPosition = target.selectionStart || 0; | |
const oldValue = target.value; | |
const newValue = formatPhoneNumber(target.value); | |
// Update the bound value | |
phoneNumber = newValue; | |
// Calculate new cursor position | |
const digitsBefore = oldValue.slice(0, cursorPosition).replace(/\D/g, '').length; | |
let newCursorPosition = 0; | |
let digitCount = 0; | |
for (let i = 0; i < newValue.length && digitCount < digitsBefore; i++) { | |
if (/\d/.test(newValue[i])) { | |
digitCount++; | |
} | |
newCursorPosition = i + 1; | |
} | |
// Set cursor position after the DOM updates | |
setTimeout(() => { | |
target.setSelectionRange(newCursorPosition, newCursorPosition); | |
}, 0); | |
} | |
function handleFileChange(event: Event) { | |
console.log(selectedFile?.name); | |
const target = event.target as HTMLInputElement; | |
selectedFile = target.files?.[0] || null; | |
lol = 'c plus des lol'; | |
console.log(selectedFile?.name); | |
} | |
// Handle send verification code with confirmation | |
function handleSendVerificationCodeUI() { | |
script = document.createElement('script'); | |
script.src = 'https://www.google.com/recaptcha/api.js'; | |
script.async = true; | |
script.defer = true; | |
document.head.appendChild(script); | |
script.onerror = () => { | |
console.error('Failed to load reCAPTCHA script'); | |
}; | |
// Make reCAPTCHA callback globally available | |
(window as any).onRecaptchaValidated = (token: string) => { | |
captchaToken = token; | |
}; | |
tempPhoneNumber = fullPhoneNumber; | |
modalStep = 'confirm'; | |
modalMessage = ''; | |
verificationCode = ''; | |
captchaToken = ''; // Reset captcha token | |
showConfirmationModal = true; | |
} | |
// Confirm and send verification code | |
async function confirmAndSendCode() { | |
if (!captchaToken) { | |
alert('Please complete the CAPTCHA'); | |
return; | |
} | |
modalStep = 'sending'; | |
modalMessage = 'Envoi du SMS en cours...'; | |
try { | |
const formData = new FormData(); | |
formData.append('phoneNumber', tempPhoneNumber); | |
formData.append('captchaToken', captchaToken); // Add captcha token to form data | |
const response = await fetch('?/updateAndSendVerification', { | |
method: 'POST', | |
body: formData | |
}); | |
const result = await response.json(); | |
if (result.type === 'success') { | |
modalStep = 'enter_code'; | |
modalMessage = result.data?.message || 'Code envoyé avec succès !'; | |
// Update the user's phone number in the UI | |
data.user.telephone = tempPhoneNumber; | |
data.user.phoneVerified = false; | |
} else { | |
modalStep = 'error'; | |
modalMessage = result.data?.message || "Erreur lors de l'envoi du SMS"; | |
} | |
} catch (error) { | |
modalStep = 'error'; | |
modalMessage = 'Erreur de connexion. Veuillez réessayer.'; | |
} | |
} | |
// Verify the entered code | |
async function verifyCode() { | |
if (!verificationCode || verificationCode.length !== 6) { | |
modalMessage = 'Veuillez saisir un code à 6 chiffres'; | |
modalMessageType = 'error'; | |
return; | |
} | |
modalStep = 'verifying'; | |
modalMessage = 'Vérification du code...'; | |
modalMessageType = null; | |
try { | |
const formData = new FormData(); | |
formData.append('verificationCode', verificationCode); | |
const response = await fetch('?/verifyPhoneCode', { | |
method: 'POST', | |
body: formData | |
}); | |
const result = await response.json(); | |
if (result.type === 'success') { | |
modalStep = 'success'; | |
modalMessage = result.data?.message || 'Numéro vérifié avec succès !'; | |
modalMessageType = 'success'; | |
data.user.phoneVerified = true; | |
goto('/account'); // Redirect to account page after success | |
} else { | |
modalStep = 'enter_code'; | |
modalMessage = result.data?.message || 'Code incorrect'; | |
modalMessageType = 'error'; | |
} | |
} catch (error) { | |
modalStep = 'error'; | |
modalMessage = 'Erreur de connexion. Veuillez réessayer.'; | |
modalMessageType = 'error'; | |
} | |
} | |
// Close modal | |
function closeModal() { | |
showConfirmationModal = false; | |
modalStep = 'confirm'; | |
modalMessage = ''; | |
modalMessageType = null; | |
verificationCode = ''; | |
} | |
</script> | |
<h1 class="card-title mb-6 text-2xl">{m.settings()}</h1> | |
<!-- Profile Picture Section --> | |
<div class="mb-8 flex items-center gap-6"> | |
<div class="avatar"> | |
<div class="h-24 w-24 rounded-full"> | |
{#if data.user.hasProfilePicture} | |
<img | |
src="/api/image/profile/{data.user.id}?t={$profilePictureTimestamp}" | |
alt={data.user.username} | |
class="h-full w-full object-cover" | |
/> | |
{:else} | |
<div class="bg-base-300 flex h-full w-full items-center justify-center"> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
class="text-base-content/50 h-12 w-12" | |
fill="none" | |
viewBox="0 0 24 24" | |
stroke="currentColor" | |
> | |
<path | |
stroke-linecap="round" | |
stroke-linejoin="round" | |
stroke-width="2" | |
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" | |
/> | |
</svg> | |
</div> | |
{/if} | |
</div> | |
</div> | |
<div class="flex-1"> | |
<h2 class="text-xl font-semibold">{m.hello_user({ username: data.user.username })}</h2> | |
<p class="text-base-content/70">{data.user.firstname} {data.user.lastname}</p> | |
</div> | |
</div> | |
<!-- TODO DELETE --> | |
<h4>{displayLol}</h4> | |
{#key lol} | |
<h2>{lol}</h2> | |
{/key} | |
<button | |
onclick={() => { | |
lol = 'button clicked!'; | |
console.log('lol is now:', lol); | |
}} | |
> | |
Test lol update | |
</button> | |
{#if selectedFile} | |
<h2>{selectedFile.name}</h2> | |
{:else} | |
<h2>pas de file name</h2> | |
{/if} | |
<!-- Profile Picture Upload Form --> | |
<div class="divider">{m.profile_picture()}</div> | |
<form | |
method="post" | |
action="?/uploadProfilePicture" | |
enctype="multipart/form-data" | |
use:enhance={() => { | |
return ({ result }) => { | |
if (result.type === 'success') { | |
// Update global timestamp to force image refresh everywhere | |
refreshProfilePicture(); | |
data.user.hasProfilePicture = true; | |
//selectedFile = null; | |
} | |
}; | |
}} | |
class="space-y-4" | |
> | |
<div class="form-control"> | |
<label class="label" for="profilePicture"> | |
<span class="label-text">{m.change_profile_picture()}</span> | |
</label> | |
<div class="relative"> | |
<input | |
type="file" | |
id="profilePicture" | |
name="profilePicture" | |
accept="image/*" | |
onchange={handleFileChange} | |
style="position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0;" | |
/> | |
<label for="profilePicture" class="btn btn-outline w-full cursor-pointer"> | |
{selectedFile ? selectedFile.name : m.select_photo()} | |
</label> | |
</div> | |
<span class="label label-text-alt">{m.accepted_formats()}</span> | |
</div> | |
<button type="submit" class="btn btn-primary" disabled={!selectedFile}> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
class="mr-2 h-5 w-5" | |
fill="none" | |
viewBox="0 0 24 24" | |
stroke="currentColor" | |
> | |
<path | |
stroke-linecap="round" | |
stroke-linejoin="round" | |
stroke-width="2" | |
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" | |
/> | |
</svg> | |
{m.update_photo()} | |
</button> | |
</form> | |
<!-- Email Verification Section --> | |
<div class="divider">{m.email_verification()}</div> | |
<div class="space-y-4"> | |
{#if data.user.emailVerified} | |
<div class="alert alert-success"> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
class="h-6 w-6 shrink-0 stroke-current" | |
fill="none" | |
viewBox="0 0 24 24" | |
> | |
<path | |
stroke-linecap="round" | |
stroke-linejoin="round" | |
stroke-width="2" | |
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" | |
/> | |
</svg> | |
<span>{m.your_email_verified({ email: data.user.email })}</span> | |
</div> | |
{:else} | |
<div class="alert alert-warning"> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
class="h-6 w-6 shrink-0 stroke-current" | |
fill="none" | |
viewBox="0 0 24 24" | |
> | |
<path | |
stroke-linecap="round" | |
stroke-linejoin="round" | |
stroke-width="2" | |
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16c-.77.833.192 2.5 1.732 2.5z" | |
/> | |
</svg> | |
<div> | |
<p> | |
{m.your_email_not_verified({ email: data.user.email })} | |
</p> | |
<p class="text-sm opacity-75"> | |
{m.verify_email_access()} | |
</p> | |
</div> | |
</div> | |
<form | |
method="post" | |
action="?/resendVerificationEmail" | |
use:enhance={() => { | |
isResendingEmail = true; | |
emailMessage = null; | |
emailMessageType = null; | |
return ({ result }) => { | |
isResendingEmail = false; | |
if (result.type === 'success') { | |
emailMessage = | |
(result.data as any)?.message || 'Email de confirmation envoyé avec succès'; | |
emailMessageType = 'success'; | |
} else if (result.type === 'failure') { | |
emailMessage = (result.data as any)?.message || "Erreur lors de l'envoi de l'email"; | |
emailMessageType = 'error'; | |
} | |
// Clear message after 5 seconds | |
setTimeout(() => { | |
emailMessage = null; | |
emailMessageType = null; | |
}, 5000); | |
}; | |
}} | |
class="mt-4" | |
> | |
<button type="submit" class="btn btn-outline btn-primary" disabled={isResendingEmail}> | |
{#if isResendingEmail} | |
<span class="loading loading-spinner loading-sm mr-2"></span> | |
{m.sending_in_progress()} | |
{:else} | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
class="mr-2 h-5 w-5" | |
fill="none" | |
viewBox="0 0 24 24" | |
stroke="currentColor" | |
> | |
<path | |
stroke-linecap="round" | |
stroke-linejoin="round" | |
stroke-width="2" | |
d="M3 8l7.89 4.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" | |
/> | |
</svg> | |
{m.resend_verification_email()} | |
{/if} | |
</button> | |
</form> | |
{#if emailMessage} | |
<div class="alert {emailMessageType === 'success' ? 'alert-success' : 'alert-error'} mt-4"> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
class="h-6 w-6 shrink-0 stroke-current" | |
fill="none" | |
viewBox="0 0 24 24" | |
> | |
{#if emailMessageType === 'success'} | |
<path | |
stroke-linecap="round" | |
stroke-linejoin="round" | |
stroke-width="2" | |
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" | |
/> | |
{:else} | |
<path | |
stroke-linecap="round" | |
stroke-linejoin="round" | |
stroke-width="2" | |
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" | |
/> | |
{/if} | |
</svg> | |
<span>{emailMessage}</span> | |
</div> | |
{/if} | |
{/if} | |
</div> | |
<!-- Phone Number Verification Section --> | |
<div class="divider">{m.phone_verification()}</div> | |
<div class="space-y-4"> | |
<!-- Phone Number Input Form --> | |
<div class="space-y-4"> | |
<div class="form-control"> | |
<label class="label" for="phoneNumber"> | |
<span class="label-text">{m.phone_number()}</span> | |
</label> | |
<div class="flex gap-2"> | |
<!-- Country Code Selector --> | |
<select | |
bind:value={countryCode} | |
class="select select-bordered w-32 flex-shrink-0" | |
aria-label="Country code" | |
> | |
{#each sortedCountryCodes as country} | |
<option value={country.code}> | |
{country.flag} | |
{country.code} | |
</option> | |
{/each} | |
</select> | |
<!-- Phone Number Input --> | |
<input | |
type="tel" | |
id="phoneNumber" | |
bind:value={phoneNumber} | |
oninput={handlePhoneInput} | |
placeholder="079 548 17 17" | |
class="input input-bordered flex-1" | |
/> | |
</div> | |
<span class="label label-text-alt"> | |
{#if data.user.telephone} | |
{m.current_number({ phone: data.user.telephone })} | |
{:else} | |
{m.enter_phone_number()} | |
{/if} | |
</span> | |
</div> | |
</div> | |
<!-- Phone Verification Status --> | |
{#if data.user.telephone && data.user.phoneVerified} | |
<div class="alert alert-success"> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
class="h-6 w-6 shrink-0 stroke-current" | |
fill="none" | |
viewBox="0 0 24 24" | |
> | |
<path | |
stroke-linecap="round" | |
stroke-linejoin="round" | |
stroke-width="2" | |
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" | |
/> | |
</svg> | |
<span>{m.your_phone_verified({ phone: data.user.telephone })}</span> | |
</div> | |
{:else if data.user.telephone && !data.user.phoneVerified} | |
<div class="alert alert-warning"> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
class="h-6 w-6 shrink-0 stroke-current" | |
fill="none" | |
viewBox="0 0 24 24" | |
> | |
<path | |
stroke-linecap="round" | |
stroke-linejoin="round" | |
stroke-width="2" | |
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16c-.77.833.192 2.5 1.732 2.5z" | |
/> | |
</svg> | |
<div> | |
<p> | |
{m.your_phone_not_verified({ phone: data.user.telephone })} | |
</p> | |
<p class="text-sm opacity-75"> | |
{m.verify_phone_access()} | |
</p> | |
</div> | |
</div> | |
{:else} | |
<div class="alert alert-info"> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
class="h-6 w-6 shrink-0 stroke-current" | |
fill="none" | |
viewBox="0 0 24 24" | |
> | |
<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" | |
/> | |
</svg> | |
<span>{m.add_phone_verification()}</span> | |
</div> | |
{/if} | |
<!-- Send Verification Code Button --> | |
{#if phoneNumber.trim()} | |
<button | |
type="button" | |
class="btn btn-outline btn-primary" | |
onclick={handleSendVerificationCodeUI} | |
> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
class="mr-2 h-5 w-5" | |
fill="none" | |
viewBox="0 0 24 24" | |
stroke="currentColor" | |
> | |
<path | |
stroke-linecap="round" | |
stroke-linejoin="round" | |
stroke-width="2" | |
d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" | |
/> | |
</svg> | |
{fullPhoneNumber === data.user.telephone | |
? m.resend_verification_code() | |
: m.send_verification_code()} | |
</button> | |
{/if} | |
</div> | |
<!-- Logout Section --> | |
<div class="divider">{m.actions()}</div> | |
<form method="post" action="?/logout" use:enhance> | |
<button class="btn btn-error"> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
class="mr-2 h-5 w-5" | |
fill="none" | |
viewBox="0 0 24 24" | |
stroke="currentColor" | |
> | |
<path | |
stroke-linecap="round" | |
stroke-linejoin="round" | |
stroke-width="2" | |
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" | |
/> | |
</svg> | |
{m.sign_out()} | |
</button> | |
</form> | |
<!-- Phone Verification Modal --> | |
{#if showConfirmationModal} | |
<div class="modal modal-open"> | |
<div class="modal-box"> | |
{#if modalStep === 'confirm'} | |
<h3 class="mb-4 text-lg font-bold">Confirmer l'envoi du code de vérification</h3> | |
<div class="py-4"> | |
<p class="mb-2"> | |
Vous êtes sur le point d'envoyer un code de vérification SMS au numéro: | |
</p> | |
<p class="text-primary text-lg font-bold">{tempPhoneNumber}</p> | |
{#if tempPhoneNumber !== data.user.telephone && data.user.telephone} | |
<div class="alert alert-warning mt-4"> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
class="h-6 w-6 shrink-0 stroke-current" | |
fill="none" | |
viewBox="0 0 24 24" | |
> | |
<path | |
stroke-linecap="round" | |
stroke-linejoin="round" | |
stroke-width="2" | |
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16c-.77.833.192 2.5 1.732 2.5z" | |
/> | |
</svg> | |
<div> | |
<p class="font-semibold">Attention: Changement de numéro</p> | |
<p class="text-sm"> | |
Votre numéro actuel ({data.user.telephone}) sera remplacé par ce nouveau numéro. | |
</p> | |
</div> | |
</div> | |
{/if} | |
</div> | |
<!-- reCAPTCHA widget --> | |
<div | |
class="g-recaptcha" | |
data-sitekey="6LeYV3QrAAAAAGWnwNjNXoOXvrCnOqTKIzgeEWUU" | |
data-callback="onRecaptchaValidated" | |
></div> | |
<div class="modal-action"> | |
<button class="btn btn-ghost" onclick={closeModal}>Annuler</button> | |
<button class="btn btn-primary" onclick={confirmAndSendCode} disabled={!captchaToken}> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
class="mr-2 h-5 w-5" | |
fill="none" | |
viewBox="0 0 24 24" | |
stroke="currentColor" | |
> | |
<path | |
stroke-linecap="round" | |
stroke-linejoin="round" | |
stroke-width="2" | |
d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" | |
/> | |
</svg> | |
Confirmer et envoyer | |
</button> | |
</div> | |
{:else if modalStep === 'sending'} | |
<h3 class="mb-4 text-lg font-bold">Envoi en cours...</h3> | |
<div class="py-4 text-center"> | |
<span class="loading loading-spinner loading-lg"></span> | |
<p class="mt-4">{modalMessage}</p> | |
</div> | |
{:else if modalStep === 'enter_code'} | |
<h3 class="mb-4 text-lg font-bold">Saisir le code de vérification</h3> | |
<div class="py-4"> | |
{#if modalMessage && modalMessageType === 'success'} | |
<div class="alert alert-success mb-4"> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
class="h-6 w-6 shrink-0 stroke-current" | |
fill="none" | |
viewBox="0 0 24 24" | |
> | |
<path | |
stroke-linecap="round" | |
stroke-linejoin="round" | |
stroke-width="2" | |
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" | |
/> | |
</svg> | |
<span>{modalMessage}</span> | |
</div> | |
{:else if modalMessage && modalMessageType === 'error'} | |
<div class="alert alert-error mb-4"> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
class="h-6 w-6 shrink-0 stroke-current" | |
fill="none" | |
viewBox="0 0 24 24" | |
> | |
<path | |
stroke-linecap="round" | |
stroke-linejoin="round" | |
stroke-width="2" | |
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" | |
/> | |
</svg> | |
<span>{modalMessage}</span> | |
</div> | |
{/if} | |
<p class="mb-4"> | |
Un code à 6 chiffres a été envoyé au numéro <strong>{tempPhoneNumber}</strong> | |
</p> | |
<div class="form-control"> | |
<label class="label" for="modalVerificationCode"> | |
<span class="label-text">Code de vérification</span> | |
</label> | |
<input | |
type="text" | |
id="modalVerificationCode" | |
bind:value={verificationCode} | |
placeholder="123456" | |
maxlength="6" | |
inputmode="numeric" | |
class="input input-bordered w-full" | |
/> | |
</div> | |
</div> | |
<div class="modal-action"> | |
<button class="btn btn-ghost" onclick={closeModal}>Annuler</button> | |
<button | |
class="btn btn-primary" | |
disabled={verificationCode.length !== 6} | |
onclick={verifyCode} | |
> | |
Vérifier le code | |
</button> | |
</div> | |
{:else if modalStep === 'verifying'} | |
<h3 class="mb-4 text-lg font-bold">Vérification en cours...</h3> | |
<div class="py-4 text-center"> | |
<span class="loading loading-spinner loading-lg"></span> | |
<p class="mt-4">{modalMessage}</p> | |
</div> | |
{:else if modalStep === 'success'} | |
<h3 class="mb-4 text-lg font-bold">Succès !</h3> | |
<div class="py-4"> | |
<div class="alert alert-success"> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
class="h-6 w-6 shrink-0 stroke-current" | |
fill="none" | |
viewBox="0 0 24 24" | |
> | |
<path | |
stroke-linecap="round" | |
stroke-linejoin="round" | |
stroke-width="2" | |
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" | |
/> | |
</svg> | |
<span>{modalMessage}</span> | |
</div> | |
</div> | |
{:else if modalStep === 'error'} | |
<h3 class="mb-4 text-lg font-bold">Erreur</h3> | |
<div class="py-4"> | |
<div class="alert alert-error"> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
class="h-6 w-6 shrink-0 stroke-current" | |
fill="none" | |
viewBox="0 0 24 24" | |
> | |
<path | |
stroke-linecap="round" | |
stroke-linejoin="round" | |
stroke-width="2" | |
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" | |
/> | |
</svg> | |
<span>{modalMessage}</span> | |
</div> | |
</div> | |
<div class="modal-action"> | |
<button class="btn btn-primary" onclick={closeModal}>Fermer</button> | |
</div> | |
{/if} | |
</div> | |
<div | |
class="modal-backdrop" | |
role="button" | |
tabindex="0" | |
onclick={modalStep === 'sending' || modalStep === 'verifying' ? undefined : closeModal} | |
onkeydown={(e) => | |
e.key === 'Escape' && modalStep !== 'sending' && modalStep !== 'verifying' && closeModal()} | |
></div> | |
</div> | |
{/if} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment