193 lines
8.2 KiB
PHP
193 lines
8.2 KiB
PHP
@extends('layouts.app')
|
|
|
|
@section('styles')
|
|
<style>
|
|
.otp-input:focus {
|
|
outline: none;
|
|
box-shadow: 0 0 0 4px rgba(0, 105, 72, 0.1);
|
|
}
|
|
.glow-button {
|
|
box-shadow: 0 4px 14px 0 rgba(0, 105, 72, 0.25);
|
|
}
|
|
</style>
|
|
@endsection
|
|
|
|
@section('header-back')
|
|
<a href="{{ route('verification.index') }}" class="hover:opacity-80 transition-opacity active:scale-95 transition-transform flex items-center justify-center p-2 rounded-full">
|
|
<x-app-icon name="arrow_back" class="w-6 h-6 text-primary" />
|
|
</a>
|
|
@endsection
|
|
|
|
@section('content')
|
|
<main class="w-full max-w-md px-container-padding flex-1 flex flex-col mt-16 pb-xl">
|
|
<!-- Progress Indicator -->
|
|
<div class="mt-base flex gap-xs justify-center">
|
|
<div class="h-1.5 w-12 rounded-full bg-primary"></div>
|
|
<div class="h-1.5 w-12 rounded-full bg-primary"></div>
|
|
<div class="h-1.5 w-12 rounded-full bg-outline-variant"></div>
|
|
</div>
|
|
|
|
<!-- Hero Content -->
|
|
<div class="mt-2xl text-center">
|
|
<div class="inline-flex items-center justify-center w-20 h-20 rounded-full bg-secondary-container mb-lg">
|
|
<x-app-icon name="app_registration" class="w-10 h-10 text-primary" />
|
|
</div>
|
|
<h2 class="font-headline-xl text-headline-xl text-on-surface mb-sm">Belgiňizi tassyklaň</h2>
|
|
|
|
<p class="font-body-md text-body-md text-on-surface-variant max-w-[280px] mx-auto">
|
|
Şu belgä iberilen 4 sanly kody giriziň: <span class="font-semibold text-on-surface">+933 {{ $phone }}</span>
|
|
</p>
|
|
</div>
|
|
|
|
@if ($errors->any())
|
|
<div class="text-error text-center mt-md">
|
|
{{ $errors->first() }}
|
|
</div>
|
|
@endif
|
|
|
|
@if (session('status'))
|
|
<div class="text-primary text-center mt-md">
|
|
{{ session('status') }}
|
|
</div>
|
|
@endif
|
|
|
|
<form action="{{ route('verification.verify') }}" method="POST" id="otp-form">
|
|
@csrf
|
|
<input type="hidden" name="phone" value="{{ $phone }}">
|
|
<input type="hidden" name="otp" id="otp-hidden">
|
|
|
|
<!-- OTP Inputs -->
|
|
<div class="mt-2xl flex justify-center gap-md" id="otp-container">
|
|
<input autofocus autocomplete="one-time-code" class="otp-input w-16 h-20 text-center font-otp-digit text-otp-digit rounded border border-outline-variant bg-surface-container-lowest outline-none focus:outline-none focus:border-primary focus:ring-0 transition-all" inputmode="numeric" maxlength="1" type="text"/>
|
|
<input class="otp-input w-16 h-20 text-center font-otp-digit text-otp-digit rounded border border-outline-variant bg-surface-container-lowest outline-none focus:outline-none focus:border-primary focus:ring-0 transition-all" inputmode="numeric" maxlength="1" type="text"/>
|
|
<input class="otp-input w-16 h-20 text-center font-otp-digit text-otp-digit rounded border border-outline-variant bg-surface-container-lowest outline-none focus:outline-none focus:border-primary focus:ring-0 transition-all" inputmode="numeric" maxlength="1" type="text"/>
|
|
<input class="otp-input w-16 h-20 text-center font-otp-digit text-otp-digit rounded border border-outline-variant bg-surface-container-lowest outline-none focus:outline-none focus:border-primary focus:ring-0 transition-all" inputmode="numeric" maxlength="1" type="text"/>
|
|
</div>
|
|
|
|
<!-- Actions -->
|
|
<div class="mt-2xl space-y-md">
|
|
<button type="submit" id="verify-btn" class="glow-button w-full h-14 bg-primary text-on-primary font-label-md text-label-md rounded-full hover:opacity-90 active:scale-[0.98] transition-all">
|
|
Tassykla
|
|
</button>
|
|
</div>
|
|
</form>
|
|
<div class="text-center mt-md">
|
|
<form action="{{ route('verification.resend') }}" method="POST" class="inline" id="resend-form">
|
|
@csrf
|
|
<button type="button" id="resend-btn" class="font-label-md text-label-md text-primary hover:underline transition-all flex items-center justify-center gap-1 mx-auto">
|
|
<span id="countdown-text" class="text-on-surface-variant font-mono text-sm">(02:00)</span>
|
|
<span>Kody täzeden iber</span>
|
|
</button>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Info Card -->
|
|
<div class="mt-auto mb-xl p-md rounded border border-outline-variant bg-surface-container-low">
|
|
<div class="flex gap-sm">
|
|
<x-app-icon name="info" class="w-6 h-6 text-on-surface-variant" />
|
|
<p class="font-body-sm text-body-sm text-on-surface-variant">
|
|
SMS kody 2 minutdan 5 minuda çenli baryp biler, garaşmagyňyzy Sizden haýyş edýäris.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
@endsection
|
|
|
|
@section('scripts')
|
|
<script>
|
|
const inputs = document.querySelectorAll('.otp-input');
|
|
const hiddenOtp = document.getElementById('otp-hidden');
|
|
const form = document.getElementById('otp-form');
|
|
const verifyBtn = document.getElementById('verify-btn');
|
|
|
|
const focusFirstOtp = () => {
|
|
const firstEmpty = [...inputs].find((input) => !input.value) ?? inputs[0];
|
|
firstEmpty?.focus();
|
|
};
|
|
|
|
focusFirstOtp();
|
|
|
|
inputs.forEach((input, index) => {
|
|
input.addEventListener('input', (e) => {
|
|
if (e.target.value.length === 1 && index < inputs.length - 1) {
|
|
inputs[index + 1].focus();
|
|
}
|
|
});
|
|
|
|
input.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Backspace' && !e.target.value && index > 0) {
|
|
inputs[index - 1].focus();
|
|
}
|
|
});
|
|
});
|
|
|
|
verifyBtn.addEventListener('click', () => {
|
|
let code = '';
|
|
inputs.forEach(input => code += input.value);
|
|
if (code.length === 4) {
|
|
hiddenOtp.value = code;
|
|
|
|
verifyBtn.innerHTML = '<span class="flex items-center justify-center gap-sm"><svg class="animate-spin h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg> Tassyklanýar...</span>';
|
|
|
|
setTimeout(() => {
|
|
form.submit();
|
|
}, 500); // small delay to show animation
|
|
} else {
|
|
alert('Haýyş, 4 sanly kody giriziň.');
|
|
}
|
|
});
|
|
|
|
// Resend OTP Countdown Logic
|
|
const resendBtn = document.getElementById('resend-btn');
|
|
const resendForm = document.getElementById('resend-form');
|
|
const countdownText = document.getElementById('countdown-text');
|
|
let timeLeft = 120; // 2 minutes
|
|
|
|
let storedTime = sessionStorage.getItem('resend_timeout');
|
|
|
|
// Reset timer if we just came from a successful resend
|
|
const isResent = {{ session('status') ? 'true' : 'false' }};
|
|
if (isResent) {
|
|
sessionStorage.setItem('resend_timeout', Date.now().toString());
|
|
storedTime = sessionStorage.getItem('resend_timeout');
|
|
}
|
|
|
|
if (storedTime) {
|
|
let elapsed = Math.floor((Date.now() - parseInt(storedTime)) / 1000);
|
|
timeLeft = Math.max(120 - elapsed, 0);
|
|
} else {
|
|
sessionStorage.setItem('resend_timeout', Date.now().toString());
|
|
}
|
|
|
|
const updateCountdown = () => {
|
|
if (timeLeft > 0) {
|
|
let m = Math.floor(timeLeft / 60);
|
|
let s = timeLeft % 60;
|
|
countdownText.innerText = `(0${m}:${s < 10 ? '0' : ''}${s})`;
|
|
countdownText.style.display = 'inline';
|
|
timeLeft--;
|
|
} else {
|
|
countdownText.style.display = 'none';
|
|
}
|
|
};
|
|
|
|
updateCountdown();
|
|
let timerId = setInterval(() => {
|
|
if (timeLeft > 0) {
|
|
updateCountdown();
|
|
} else {
|
|
updateCountdown(); // Call one last time to hide it
|
|
clearInterval(timerId);
|
|
}
|
|
}, 1000);
|
|
|
|
resendBtn.addEventListener('click', (e) => {
|
|
if (timeLeft > 0) {
|
|
alert('SMS kody 2 minutdan 5 minuda çenli baryp biler, garaşmagyňyzy Sizden haýyş edýäris.');
|
|
} else {
|
|
sessionStorage.removeItem('resend_timeout');
|
|
resendForm.submit();
|
|
}
|
|
});
|
|
</script>
|
|
@endsection |