211 lines
7.6 KiB
PHP
Raw Normal View History

2025-04-08 09:47:55 +08:00
@props([
// name of the input field for use in forms
'name' => 'pin-code-'.uniqid(),
// total number of boxes to display
'total_digits' => config('bladewind.code.total_digits', 4),
'totalDigits' => config('bladewind.code.total_digits', 4),
/*
what function should be called when the user is done entering the verification code.
this should just be the function name without parenthesis and parameters.
example: verifyPin ... when the user is done entering the code Bladewind will call verifyPin(code)
note that the code is passed to your function as the only parameter so you need to expect a parameter
when defining your function... using the above example: verifyPin = (pin_code) => {}
*/
'on_verify' => null,
'onVerify' => null,
// error message to display when pin is wrong
'error_message' => 'You entered a wrong code',
'errorMessage' => 'You entered a wrong code',
// should input text be masked to hide code
'mask' => config('bladewind.code.mask', false),
// after how many seconds should the link to resend a code be displayed
'timer' => null,
// boxes can either be big or regular
'size' => config('bladewind.code.size', 'regular'),
])
@php
// reset variables for Laravel 8 support
$total_digits = $totalDigits;
$error_message = $errorMessage;
//--------------------------------------------------------------------
$name = preg_replace('/[\s-]/', '_', $name);
$mask = parseBladewindVariable($mask);
$input_css = ($size !== 'big') ? " w-14 text-xl" : "w-[75px] text-5xl";
$cloak_size = ($size == 'big') ? " h-24" : "h-16";
@endphp
<div class="dv-{{ $name }} relative">
<div class="flex {{ $name }}-boxes">
<div class="flex space-x-2 mx-auto">
@for ($x = 0; $x < $total_digits; $x++)
<x-bladewind::input
numeric="true"
type="{{ ($mask) ? 'password' : 'text' }}"
with_dots="false"
add_clearing="false"
onkeydown="hidePinError('{{ $name }}')"
onkeyup="moveCursorNext('{{ $name }}', {{ $x }}, {{ $total_digits }}, '{{ $on_verify }}', event)"
class="shadow-sm text-center font-light text-black dark:text-dark-400 focus:!border-primary-600 {{$input_css}} {{ $name }}-pin-code {{ $name }}-pcode{{ $x }}"
maxlength="1"
/>
@endfor
</div>
</div>
<div class="text-center text-sm text-error-500 my-6 hidden bw-{{ $name }}-pin-error">
{!! $error_message !!}
</div>
<div class="text-center tracking-wider text-sm my-6 bw-{{ $name }}-pin-timer">
<div class="countdown hidden"><span class="minutes"></span>:<span class="seconds"></span></div>
<div class="done"></div>
</div>
<div class="bg-transparent hidden absolute w-full z-40 flex items-center justify-center top-0 {{$cloak_size}} bw-{{ $name }}-pin-spinner">
<x-bladewind::spinner/>
</div>
<div class="bg-transparent flex items-center justify-center w-full text-center hidden absolute top-0 z-40 {{$cloak_size}} bw-{{ $name }}-pin-valid">
<x-bladewind::icon name="check-circle" type="solid" class="!size-9 text-green-500 mx-auto"/>
</div>
<div class="bg-transparent hidden w-full absolute top-0 {{$cloak_size}} bw-{{ $name }}-pin-cloak"></div>
</div>
<x-bladewind::input type="hidden" name="{{ $name }}"/>
<script>
var moveCursorNext = (name, index, total_digits, user_function, evt) => {
if (evt.key === 'Backspace') {
if (index > 0) {
domEl(`.${name}-pcode${index}`).value = '';
index--;
}
} else {
if (domEl(`.${name}-pcode${index}`).value) {
index++
}
}
(index < total_digits) ? domEl(`.${name}-pcode${index}`).focus() : setPin(name, user_function);
}
var setPin = (name, user_function) => {
domEl(`.${name}`).value = '';
domEls(`.${name}-pin-code`).forEach((el) => {
domEl(`.${name}`).value += el.value;
});
let pin_code = domEl(`.${name}`).value;
(user_function) ? callUserFunction(`${user_function}('${pin_code}','${name}')`) : doNothing();
}
var clearPin = (name) => {
domEls(`.${name}-pin-code`).forEach((el) => {
el.value = '';
});
domEl(`.${name}-pcode0`).focus();
}
var showPinError = (name, autoHide = true) => {
unhide(`.bw-${name}-pin-error`);
if (autoHide) setTimeout(() => {
hidePinError(name);
}, 10000);
}
var hidePinError = (name) => {
hide(`.bw-${name}-pin-error`);
}
var showSpinner = (name) => {
hide(`.bw-${name}-pin-valid`);
unhide(`.bw-${name}-pin-spinner`);
domEl(`.${name}-pcode0`).focus();
domEl(`.${name}-pcode0`).blur();
}
var hideSpinner = (name) => {
hide(`.bw-${name}-pin-spinner`);
}
var showPinSuccess = (name) => {
hide(`.bw-${name}-pin-spinner`);
unhide(`.bw-${name}-pin-valid`);
loseFocus(name);
}
var loseFocus = (name) => {
domEl(`.${name}-pcode0`).focus();
domEl(`.${name}-pcode0`).blur();
}
var setFocus = (name) => {
domEl(`.${name}-pcode0`).focus();
}
var disablePin = (name) => {
loseFocus(name);
unhide(`.bw-${name}-pin-cloak`);
}
var enablePin = (name) => {
hide(`.bw-${name}-pin-cloak`);
setFocus(name);
}
var bw_timer_interval;
var showTimer = (name, duration = 60) => {
let minutes_ = Math.floor(duration / 60);
let seconds_ = (duration % 60);
let countdown_div = domEl(`.bw-${name}-pin-timer .countdown`);
let minutes_span = domEl(`.bw-${name}-pin-timer .minutes`);
let seconds_span = domEl(`.bw-${name}-pin-timer .seconds`);
let done_div = domEl(`.bw-${name}-pin-timer .done`);
unhide(`.bw-${name}-pin-timer .countdown`);
disablePin(name);
countdown({
name: name,
minutes: minutes_,
seconds: seconds_,
countdownDiv: countdown_div,
minutesSpan: minutes_span,
secondsSpan: seconds_span,
doneDiv: done_div,
});
}
var countdown = (options = {}) => {
let name = options.name;
options.minutesSpan.innerHTML = options.minutes;
options.secondsSpan.innerHTML = options.seconds;
options.doneDiv.innerHTML = '';
unhide(options.countdownDiv, true);
bw_timer_interval = setInterval(() => {
if (options.seconds !== 0) {
options.seconds--;
options.secondsSpan.innerHTML = (options.seconds < 10) ? `0${options.seconds}` : options.seconds;
} else {
if (options.minutes !== 0) {
options.minutes--;
options.seconds = 60;
options.minutesSpan.innerHTML = options.minutes;
} else {
clearInterval(bw_timer_interval);
options.secondsSpan.innerHTML = options.minutesSpan.innerHTML = '';
if (domEl('.bw-code-timer-done')) {
hide(options.countdownDiv, true);
options.doneDiv.innerHTML = domEl('.bw-code-timer-done').innerHTML;
enablePin(name);
}
}
}
}, 1000);
}
@if(is_numeric($timer)) showTimer('{{$name}}', {{$timer}}); @endif
</script>