Yes
This commit is contained in:
11
resources/css/app.css
Normal file
11
resources/css/app.css
Normal file
@@ -0,0 +1,11 @@
|
||||
@import 'tailwindcss';
|
||||
|
||||
@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php';
|
||||
@source '../../storage/framework/views/*.php';
|
||||
@source '../**/*.blade.php';
|
||||
@source '../**/*.js';
|
||||
|
||||
@theme {
|
||||
--font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
|
||||
'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
}
|
||||
1
resources/js/app.js
Normal file
1
resources/js/app.js
Normal file
@@ -0,0 +1 @@
|
||||
//
|
||||
135
resources/views/layouts/app.blade.php
Normal file
135
resources/views/layouts/app.blade.php
Normal file
@@ -0,0 +1,135 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="light" lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>OTP Verification</title>
|
||||
<!-- Fonts -->
|
||||
<link href="https://fonts.googleapis.com" rel="preconnect"/>
|
||||
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&family=Plus+Jakarta+Sans:wght@600;700;800&family=JetBrains+Mono:wght@700&display=swap" rel="stylesheet"/>
|
||||
<!-- Material Symbols -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<script id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
"colors": {
|
||||
"on-tertiary-fixed-variant": "#7f2928",
|
||||
"on-primary-fixed-variant": "#005137",
|
||||
"tertiary-container": "#ba5551",
|
||||
"background": "#f8f9ff",
|
||||
"secondary-fixed": "#d5e6df",
|
||||
"on-tertiary-container": "#fffbff",
|
||||
"tertiary-fixed": "#ffdad7",
|
||||
"surface": "#f8f9ff",
|
||||
"on-primary-container": "#f5fff7",
|
||||
"tertiary": "#9b3e3b",
|
||||
"surface-container-high": "#dfe9fa",
|
||||
"on-primary-fixed": "#002114",
|
||||
"outline-variant": "#bccac0",
|
||||
"inverse-on-surface": "#eaf1ff",
|
||||
"primary-fixed": "#85f8c4",
|
||||
"on-error": "#ffffff",
|
||||
"surface-container": "#e5eeff",
|
||||
"on-secondary-fixed": "#101e1a",
|
||||
"on-background": "#121c28",
|
||||
"primary-container": "#00855d",
|
||||
"tertiary-fixed-dim": "#ffb3ae",
|
||||
"on-secondary-fixed-variant": "#3b4a44",
|
||||
"on-tertiary-fixed": "#410004",
|
||||
"on-tertiary": "#ffffff",
|
||||
"outline": "#6d7a72",
|
||||
"surface-container-highest": "#d9e3f4",
|
||||
"error": "#ba1a1a",
|
||||
"primary": "#006948",
|
||||
"surface-tint": "#006c4a",
|
||||
"surface-container-low": "#eef4ff",
|
||||
"surface-container-lowest": "#ffffff",
|
||||
"error-container": "#ffdad6",
|
||||
"on-secondary-container": "#566660",
|
||||
"on-primary": "#ffffff",
|
||||
"surface-variant": "#d9e3f4",
|
||||
"secondary": "#52625c",
|
||||
"on-error-container": "#93000a",
|
||||
"inverse-primary": "#68dba9",
|
||||
"on-surface": "#121c28",
|
||||
"secondary-container": "#d3e3dc",
|
||||
"inverse-surface": "#27313e",
|
||||
"on-secondary": "#ffffff",
|
||||
"surface-bright": "#f8f9ff",
|
||||
"primary-fixed-dim": "#68dba9",
|
||||
"on-surface-variant": "#3d4a42",
|
||||
"secondary-fixed-dim": "#bacac3",
|
||||
"surface-dim": "#d1dbec"
|
||||
},
|
||||
"borderRadius": {
|
||||
"DEFAULT": "1rem",
|
||||
"lg": "2rem",
|
||||
"xl": "3rem",
|
||||
"full": "9999px"
|
||||
},
|
||||
"spacing": {
|
||||
"sm": "12px",
|
||||
"xl": "32px",
|
||||
"2xl": "48px",
|
||||
"gutter": "12px",
|
||||
"container-padding": "20px",
|
||||
"md": "16px",
|
||||
"base": "8px",
|
||||
"xs": "4px",
|
||||
"lg": "24px"
|
||||
},
|
||||
"fontFamily": {
|
||||
"body-md": ["Inter"],
|
||||
"headline-xl": ["Plus Jakarta Sans"],
|
||||
"label-md": ["Inter"],
|
||||
"headline-lg-mobile": ["Plus Jakarta Sans"],
|
||||
"headline-lg": ["Plus Jakarta Sans"],
|
||||
"otp-digit": ["Plus Jakarta Sans"],
|
||||
"body-sm": ["Inter"],
|
||||
"mono": ["JetBrains Mono"]
|
||||
},
|
||||
"fontSize": {
|
||||
"body-md": ["16px", {"lineHeight": "24px", "fontWeight": "400"}],
|
||||
"headline-xl": ["32px", {"lineHeight": "40px", "letterSpacing": "-0.02em", "fontWeight": "700"}],
|
||||
"label-md": ["14px", {"lineHeight": "20px", "letterSpacing": "0.05em", "fontWeight": "600"}],
|
||||
"headline-lg-mobile": ["22px", {"lineHeight": "28px", "fontWeight": "600"}],
|
||||
"headline-lg": ["24px", {"lineHeight": "32px", "letterSpacing": "-0.01em", "fontWeight": "600"}],
|
||||
"otp-digit": ["28px", {"lineHeight": "36px", "fontWeight": "600"}],
|
||||
"body-sm": ["14px", {"lineHeight": "20px", "fontWeight": "400"}]
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.material-symbols-outlined {
|
||||
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||||
}
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
</style>
|
||||
@yield('styles')
|
||||
</head>
|
||||
<body class="bg-background text-on-background font-body-md min-h-screen flex flex-col items-center overflow-x-hidden">
|
||||
<!-- TopAppBar Section -->
|
||||
<header class="flex items-center justify-between px-container-padding h-16 w-full z-50 fixed top-0 bg-background">
|
||||
@yield('header-back')
|
||||
<h1 class="font-headline-lg-mobile text-headline-lg-mobile font-bold text-primary">Verification</h1>
|
||||
<div class="w-10"></div> <!-- Spacer for center alignment -->
|
||||
</header>
|
||||
|
||||
@yield('content')
|
||||
|
||||
<!-- Subtle atmospheric background elements -->
|
||||
<div class="fixed top-0 right-0 -z-10 w-64 h-64 bg-primary/5 rounded-full blur-[80px] pointer-events-none"></div>
|
||||
<div class="fixed bottom-0 left-0 -z-10 w-96 h-96 bg-secondary-container/10 rounded-full blur-[100px] pointer-events-none"></div>
|
||||
|
||||
@yield('scripts')
|
||||
</body>
|
||||
</html>
|
||||
173
resources/views/verification/congratulations.blade.php
Normal file
173
resources/views/verification/congratulations.blade.php
Normal file
@@ -0,0 +1,173 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
.confetti-canvas {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
z-index: 10;
|
||||
}
|
||||
.coupon-cutout {
|
||||
mask-image: radial-gradient(circle at 0 50%, transparent 10px, black 11px),
|
||||
radial-gradient(circle at 100% 50%, transparent 10px, black 11px);
|
||||
mask-composite: intersect;
|
||||
-webkit-mask-image: radial-gradient(circle at 0 50%, transparent 12px, black 13px),
|
||||
radial-gradient(circle at 100% 50%, transparent 12px, black 13px);
|
||||
}
|
||||
.float-animation {
|
||||
animation: float 6s ease-in-out infinite;
|
||||
}
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translateY(0px); }
|
||||
50% { transform: translateY(-10px); }
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('header-back')
|
||||
<!-- No back button on success screen -->
|
||||
<div class="w-10"></div>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<canvas class="confetti-canvas" id="confetti"></canvas>
|
||||
|
||||
<main class="flex-grow flex flex-col items-center justify-center px-container-padding pt-24 pb-32 mt-16 w-full">
|
||||
<!-- Success Indicator -->
|
||||
<div class="mb-xl relative">
|
||||
<div class="w-24 h-24 bg-primary-fixed rounded-full flex items-center justify-center text-primary-container shadow-[0_0_40px_rgba(0,105,72,0.2)]">
|
||||
<span class="material-symbols-outlined !text-5xl" style="font-variation-settings: 'FILL' 1;">check_circle</span>
|
||||
</div>
|
||||
<!-- Decorative Sparks -->
|
||||
<div class="absolute -top-2 -right-2 text-primary opacity-50"><span class="material-symbols-outlined !text-xl">auto_awesome</span></div>
|
||||
</div>
|
||||
|
||||
<!-- Typography Block -->
|
||||
<div class="text-center mb-2xl">
|
||||
<h2 class="font-headline-xl text-headline-xl text-on-surface mb-sm">Congratulations!</h2>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant max-w-[280px] mx-auto">Your coupon code is ready to use.</p>
|
||||
</div>
|
||||
|
||||
<!-- Styled Coupon Card -->
|
||||
<div class="w-full max-w-sm relative float-animation">
|
||||
<div class="bg-surface-container-highest coupon-cutout rounded-lg p-lg flex flex-col items-center border border-outline-variant/30">
|
||||
<div class="text-on-surface-variant font-label-md text-label-md mb-md uppercase tracking-widest">Limited Offer Code</div>
|
||||
<div class="bg-surface-container-lowest border-2 border-dashed border-primary/30 rounded-md px-xl py-lg w-full text-center mb-md group transition-all hover:border-primary">
|
||||
<span class="font-mono text-4xl font-bold text-primary tracking-widest" id="couponCode">{{ $code }}</span>
|
||||
</div>
|
||||
<button class="flex items-center gap-2 text-primary font-label-md text-label-md hover:bg-primary-container/10 px-md py-sm rounded-full transition-colors active:scale-95" onclick="copyCode()">
|
||||
<span class="material-symbols-outlined" id="copyIcon">content_copy</span>
|
||||
<span id="copyText">Copy Code</span>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Shadow Depth -->
|
||||
<div class="absolute -bottom-4 left-1/2 -translate-x-1/2 w-[80%] h-4 bg-primary/10 blur-xl rounded-full -z-10"></div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="w-full max-w-sm mt-2xl flex flex-col gap-md">
|
||||
<button class="w-full bg-primary text-on-primary py-md rounded-full font-label-md text-label-md shadow-[0_4px_12px_rgba(0,105,72,0.3)] hover:opacity-90 active:scale-95 transition-all">
|
||||
Redeem Now
|
||||
</button>
|
||||
<a href="{{ route('verification.index') }}" class="w-full text-center bg-transparent text-primary py-md rounded-full font-label-md text-label-md hover:bg-primary/5 active:scale-95 transition-all">
|
||||
Back to Home
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Info Card -->
|
||||
<div class="mt-2xl w-full max-w-sm bg-secondary-container/30 border border-secondary-container rounded-lg p-md flex gap-md items-start">
|
||||
<span class="material-symbols-outlined text-secondary">info</span>
|
||||
<p class="font-body-sm text-body-sm text-on-secondary-container">
|
||||
This coupon is valid for the next 24 hours only. Make sure to apply it during checkout to enjoy your discount.
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
// Confetti Logic
|
||||
const canvas = document.getElementById('confetti');
|
||||
const ctx = canvas.getContext('2d');
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
|
||||
let particles = [];
|
||||
const colors = ['#006948', '#85f8c4', '#68dba9', '#00855d', '#ffdad7'];
|
||||
|
||||
class Particle {
|
||||
constructor() {
|
||||
this.x = Math.random() * canvas.width;
|
||||
this.y = Math.random() * canvas.height - canvas.height;
|
||||
this.size = Math.random() * 8 + 4;
|
||||
this.speed = Math.random() * 3 + 2;
|
||||
this.color = colors[Math.floor(Math.random() * colors.length)];
|
||||
this.rotation = Math.random() * 360;
|
||||
this.rotationSpeed = Math.random() * 10 - 5;
|
||||
}
|
||||
update() {
|
||||
this.y += this.speed;
|
||||
this.rotation += this.rotationSpeed;
|
||||
if (this.y > canvas.height) {
|
||||
this.y = -20;
|
||||
this.x = Math.random() * canvas.width;
|
||||
}
|
||||
}
|
||||
draw() {
|
||||
ctx.save();
|
||||
ctx.translate(this.x, this.y);
|
||||
ctx.rotate(this.rotation * Math.PI / 180);
|
||||
ctx.fillStyle = this.color;
|
||||
ctx.fillRect(-this.size / 2, -this.size / 2, this.size, this.size);
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
|
||||
function initConfetti() {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
particles.push(new Particle());
|
||||
}
|
||||
}
|
||||
|
||||
function animateConfetti() {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
particles.forEach(p => {
|
||||
p.update();
|
||||
p.draw();
|
||||
});
|
||||
requestAnimationFrame(animateConfetti);
|
||||
}
|
||||
|
||||
initConfetti();
|
||||
animateConfetti();
|
||||
|
||||
// Copy Functionality
|
||||
function copyCode() {
|
||||
const code = document.getElementById('couponCode').innerText;
|
||||
navigator.clipboard.writeText(code);
|
||||
|
||||
const btnText = document.getElementById('copyText');
|
||||
const btnIcon = document.getElementById('copyIcon');
|
||||
|
||||
btnText.innerText = 'Copied!';
|
||||
btnIcon.innerText = 'check';
|
||||
|
||||
setTimeout(() => {
|
||||
btnText.innerText = 'Copy Code';
|
||||
btnIcon.innerText = 'content_copy';
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
// Handle window resize
|
||||
window.addEventListener('resize', () => {
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
particles = [];
|
||||
initConfetti();
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
111
resources/views/verification/index.blade.php
Normal file
111
resources/views/verification/index.blade.php
Normal file
@@ -0,0 +1,111 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
.soft-glow-btn {
|
||||
box-shadow: 0 4px 14px 0 rgba(0, 105, 72, 0.3);
|
||||
}
|
||||
.focused-input-glow:focus-within {
|
||||
box-shadow: 0 0 0 4px rgba(0, 105, 72, 0.1);
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('header-back')
|
||||
<div class="w-10"></div>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<main class="flex-grow pt-2xl px-container-padding pb-xl flex flex-col mt-16 max-w-md mx-auto w-full">
|
||||
<!-- Progress Indicator -->
|
||||
<div class="flex gap-xs mb-2xl justify-center">
|
||||
<div class="h-1.5 w-8 rounded-full bg-primary"></div>
|
||||
<div class="h-1.5 w-8 rounded-full bg-outline-variant"></div>
|
||||
<div class="h-1.5 w-8 rounded-full bg-outline-variant"></div>
|
||||
</div>
|
||||
|
||||
<!-- Headline & Subtext -->
|
||||
<section class="space-y-base mb-2xl">
|
||||
<h2 class="font-headline-xl text-headline-xl text-on-background">Enter your phone number</h2>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant">We'll send a 4-digit code to verify your account.</p>
|
||||
</section>
|
||||
|
||||
<!-- Phone Input Block -->
|
||||
<form action="{{ route('verification.send') }}" method="POST" class="flex-grow flex flex-col" id="phone-form">
|
||||
@csrf
|
||||
<div class="space-y-md flex-grow">
|
||||
<div class="group relative flex items-center bg-surface-container-lowest border border-outline-variant rounded-DEFAULT h-16 px-md transition-all duration-300 focused-input-glow focus-within:border-primary">
|
||||
<!-- Country Code Selector (Simulated) -->
|
||||
<button type="button" class="flex items-center gap-xs pr-md border-r border-outline-variant mr-md hover:bg-surface-container-low transition-colors h-10 rounded-sm">
|
||||
<span class="font-label-md text-label-md text-on-surface">+993</span>
|
||||
</button>
|
||||
|
||||
<!-- Actual Input -->
|
||||
<input id="phone-input" name="phone_visual" class="bg-transparent border-none focus:ring-0 w-full font-otp-digit text-otp-digit text-on-surface placeholder:text-outline-variant" placeholder="6X XX XX XX" type="tel" value="{{ old('phone_visual') }}"/>
|
||||
<input type="hidden" name="phone" id="phone-hidden" value="{{ old('phone') }}">
|
||||
</div>
|
||||
|
||||
@error('phone')
|
||||
<p class="text-error text-sm">{{ $message }}</p>
|
||||
@enderror
|
||||
|
||||
<div class="flex items-start gap-sm bg-secondary-container/30 p-md rounded-DEFAULT border border-secondary-container">
|
||||
<span class="material-symbols-outlined text-on-secondary-container mt-0.5" data-icon="info">info</span>
|
||||
<p class="font-body-sm text-body-sm text-on-secondary-container">
|
||||
Message and data rates may apply. You will receive one SMS code for verification purposes.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer Action -->
|
||||
<div class="mt-2xl">
|
||||
<button type="submit" class="w-full bg-primary text-on-primary h-14 rounded-lg font-label-md text-label-md uppercase tracking-widest soft-glow-btn hover:opacity-90 transition-all active:scale-[0.98]">
|
||||
Send Code
|
||||
</button>
|
||||
<button type="button" class="w-full mt-md text-primary font-label-md text-label-md h-12 hover:bg-primary/5 transition-colors rounded-DEFAULT">
|
||||
Try another method
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</main>
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
const input = document.getElementById('phone-input');
|
||||
const hiddenInput = document.getElementById('phone-hidden');
|
||||
const form = document.getElementById('phone-form');
|
||||
|
||||
input.addEventListener('input', (e) => {
|
||||
let value = e.target.value.replace(/\D/g, '');
|
||||
// format: K X XX XX XX
|
||||
// max 8 digits
|
||||
value = value.substring(0, 8);
|
||||
|
||||
let formatted = '';
|
||||
if (value.length > 0) {
|
||||
formatted += value.substring(0, 1);
|
||||
}
|
||||
if (value.length > 1) {
|
||||
formatted += value.substring(1, 2);
|
||||
}
|
||||
if (value.length > 2) {
|
||||
formatted += ' ' + value.substring(2, 4);
|
||||
}
|
||||
if (value.length > 4) {
|
||||
formatted += ' ' + value.substring(4, 6);
|
||||
}
|
||||
if (value.length > 6) {
|
||||
formatted += ' ' + value.substring(6, 8);
|
||||
}
|
||||
|
||||
e.target.value = formatted;
|
||||
|
||||
if (value.length === 8) {
|
||||
hiddenInput.value = '+993 ' + value.substring(0, 1) + value.substring(1, 2) + ' ' + value.substring(2, 4) + ' ' + value.substring(4, 6) + ' ' + value.substring(6, 8);
|
||||
} else {
|
||||
hiddenInput.value = '';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
121
resources/views/verification/verify.blade.php
Normal file
121
resources/views/verification/verify.blade.php
Normal file
@@ -0,0 +1,121 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
.otp-input:focus {
|
||||
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">
|
||||
<span class="material-symbols-outlined text-primary" data-icon="arrow_back">arrow_back</span>
|
||||
</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">
|
||||
<span class="material-symbols-outlined text-primary text-4xl" data-icon="app_registration">app_registration</span>
|
||||
</div>
|
||||
<h2 class="font-headline-xl text-headline-xl text-on-surface mb-sm">Verify your number</h2>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant max-w-[280px] mx-auto">
|
||||
Enter the 4-digit code sent to <span class="font-semibold text-on-surface">{{ $phone }}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@if ($errors->any())
|
||||
<div class="text-error text-center mt-md">
|
||||
{{ $errors->first() }}
|
||||
</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 autocomplete="one-time-code" class="otp-input w-16 h-20 text-center font-otp-digit text-otp-digit rounded-DEFAULT border-outline-variant bg-surface-container-lowest 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-DEFAULT border-outline-variant bg-surface-container-lowest 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-DEFAULT border-outline-variant bg-surface-container-lowest 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-DEFAULT border-outline-variant bg-surface-container-lowest 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="button" 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">
|
||||
Verify
|
||||
</button>
|
||||
<div class="text-center">
|
||||
<button type="button" class="font-label-md text-label-md text-primary hover:underline transition-all">
|
||||
Resend Code
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Info Card -->
|
||||
<div class="mt-auto mb-xl p-md rounded-DEFAULT border border-outline-variant bg-surface-container-low">
|
||||
<div class="flex gap-sm">
|
||||
<span class="material-symbols-outlined text-on-surface-variant" data-icon="info">info</span>
|
||||
<p class="font-body-sm text-body-sm text-on-surface-variant">
|
||||
We use this to keep your account secure. Your number will not be shared with others.
|
||||
</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');
|
||||
|
||||
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> Verifying...</span>';
|
||||
|
||||
setTimeout(() => {
|
||||
form.submit();
|
||||
}, 500); // small delay to show animation
|
||||
} else {
|
||||
alert('Please enter a 4-digit code.');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
223
resources/views/welcome.blade.php
Normal file
223
resources/views/welcome.blade.php
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user