first commit
This commit is contained in:
@@ -0,0 +1,778 @@
|
||||
@extends('layouts.master')
|
||||
|
||||
@section('content')
|
||||
<div class="max-w-7xl mx-auto px-6 py-8">
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="flex items-center justify-between mb-7">
|
||||
<div>
|
||||
<h1 class="text-slate-900 text-xl font-bold tracking-tight">Student Registrations</h1>
|
||||
<p class="text-slate-500 text-sm mt-0.5">Track registrations and goal scores for today's session.</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2.5">
|
||||
<a href="{{ route('registrations.index') }}"
|
||||
class="flex items-center gap-2 bg-white hover:bg-slate-50 border border-slate-200 text-slate-700 text-sm font-medium px-4 py-2 rounded-lg transition-colors shadow-sm">
|
||||
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M3 6h18"></path>
|
||||
<path d="M3 12h18"></path>
|
||||
<path d="M3 18h18"></path>
|
||||
</svg>
|
||||
|
||||
All Registrations
|
||||
</a>
|
||||
<a href="{{ route('leaderboard') }}"
|
||||
class="flex items-center gap-2 bg-white hover:bg-slate-50 border border-slate-200 text-slate-700 text-sm font-medium px-4 py-2 rounded-lg transition-colors shadow-sm">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/>
|
||||
</svg>
|
||||
Leaderboard
|
||||
</a>
|
||||
<button id="newRegistrationBtn"
|
||||
class="flex items-center gap-2 bg-indigo-600 hover:bg-indigo-700 text-white text-sm font-medium px-4 py-2 rounded-lg transition-colors shadow-sm">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>
|
||||
</svg>
|
||||
New Registration
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- STATS -->
|
||||
<div class="grid grid-cols-3 gap-4 mb-7">
|
||||
<div class="bg-white rounded-xl border border-slate-200 px-5 py-4 flex items-center gap-4 shadow-sm">
|
||||
<div class="w-9 h-9 rounded-lg bg-slate-100 flex items-center justify-center shrink-0">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#64748b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2"/><circle cx="9" cy="7" r="4"/>
|
||||
<path d="M23 21v-2a4 4 0 00-3-3.87"/><path d="M16 3.13a4 4 0 010 7.75"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-2xl font-bold text-slate-900 leading-none">{{ $total }}</p>
|
||||
<p class="text-xs text-slate-500 mt-1 font-medium">Total Registrations</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-xl border border-slate-200 px-5 py-4 flex items-center gap-4 shadow-sm">
|
||||
<div class="w-9 h-9 rounded-lg bg-emerald-50 flex items-center justify-center shrink-0">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#059669" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 000 20M12 2a14.5 14.5 0 010 20M2 12h20"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-2xl font-bold text-slate-900 leading-none">{{ $played }}</p>
|
||||
<p class="text-xs text-emerald-600 mt-1 font-medium">Played Today</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-xl border border-slate-200 px-5 py-4 flex items-center gap-4 shadow-sm">
|
||||
<div class="w-9 h-9 rounded-lg bg-indigo-50 flex items-center justify-center shrink-0">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#6366f1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-2xl font-bold text-slate-900 leading-none">{{ $topScore }}</p>
|
||||
<p class="text-xs text-indigo-600 mt-1 font-medium">Top Score</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TABLE -->
|
||||
<div class="bg-white rounded-xl border border-slate-200 overflow-hidden shadow-sm">
|
||||
<div class="px-5 py-3.5 border-b border-slate-100 flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 text-slate-700 font-semibold text-sm">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/>
|
||||
<line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>
|
||||
</svg>
|
||||
Today's Sessions
|
||||
</div>
|
||||
<span class="text-xs font-medium text-slate-400 bg-slate-100 px-2 py-0.5 rounded-full">{{ $total }} students</span>
|
||||
</div>
|
||||
<table class="w-full text-sm">
|
||||
<thead>
|
||||
<tr class="bg-slate-50 border-b border-slate-100">
|
||||
<th class="px-5 py-3 text-left text-xs font-semibold text-slate-500 uppercase tracking-wider w-16">ID</th>
|
||||
<th class="px-5 py-3 text-left text-xs font-semibold text-slate-500 uppercase tracking-wider">Name</th>
|
||||
<th class="px-5 py-3 text-left text-xs font-semibold text-slate-500 uppercase tracking-wider">Phone</th>
|
||||
<th class="px-5 py-3 text-left text-xs font-semibold text-slate-500 uppercase tracking-wider">Email</th>
|
||||
<th class="px-5 py-3 text-center text-xs font-semibold text-slate-500 uppercase tracking-wider">Today's Shots</th>
|
||||
<th class="px-5 py-3 text-center text-xs font-semibold text-slate-500 uppercase tracking-wider">Total Score</th>
|
||||
<th class="px-5 py-3 text-right text-xs font-semibold text-slate-500 uppercase tracking-wider">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-100">
|
||||
@foreach ($registrations as $reg)
|
||||
<tr class="hover:bg-slate-50/70 transition-colors group"
|
||||
data-session-id="{{ $reg['session_id'] ?? '' }}"
|
||||
data-name="{{ $reg['name'] }}"
|
||||
data-total-score="{{ $reg['total_score'] }}"
|
||||
data-shots="{{ json_encode($reg['today_goals'] ?? []) }}"
|
||||
data-shots-recorded="{{ is_array($reg['today_goals']) ? count($reg['today_goals']) : 0 }}"
|
||||
data-reg-id="{{ $reg['id'] }}">
|
||||
<td class="px-5 py-3.5">
|
||||
<span class="text-xs font-mono text-slate-400">#{{ str_pad($reg['id'], 4, '0', STR_PAD_LEFT) }}</span>
|
||||
</td>
|
||||
<td class="px-5 py-3.5">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded-full bg-indigo-100 flex items-center justify-center shrink-0">
|
||||
<span class="text-xs font-bold text-indigo-600">{{ strtoupper(substr($reg['name'], 0, 1)) }}</span>
|
||||
</div>
|
||||
<span class="font-medium text-slate-800">{{ $reg['name'] }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-5 py-3.5 text-slate-500">{{ $reg['phone'] }}</td>
|
||||
<td class="px-5 py-3.5 text-slate-500">{{ $reg['email'] }}</td>
|
||||
<td class="px-5 py-3.5">
|
||||
<div class="shots-cell flex items-center justify-center gap-1.5">
|
||||
@if(is_null($reg['today_goals']))
|
||||
<span class="text-xs text-slate-400 italic">Not played</span>
|
||||
@else
|
||||
@foreach($reg['today_goals'] as $i => $goal)
|
||||
@if($goal)
|
||||
<div class="w-7 h-7 rounded-full bg-emerald-100 border-2 border-emerald-400 flex items-center justify-center" title="Shot {{ $i+1 }}: Goal">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#059669" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
|
||||
</div>
|
||||
@else
|
||||
<div class="w-7 h-7 rounded-full bg-slate-100 border-2 border-slate-300 flex items-center justify-center" title="Shot {{ $i+1 }}: Miss">
|
||||
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="#94a3b8" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-5 py-3.5 text-center">
|
||||
<div class="inline-flex items-center gap-1 font-bold text-slate-900">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="#6366f1" stroke="none"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>
|
||||
<span class="text-base score-cell">{{ $reg['total_score'] }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-5 py-3.5">
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
@if(is_null($reg['today_goals']))
|
||||
<button class="flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg text-xs font-medium text-indigo-600 bg-indigo-50 hover:bg-indigo-100 border border-indigo-200 transition-colors">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="16"/><line x1="8" y1="12" x2="16" y2="12"/></svg>
|
||||
Record Score
|
||||
</button>
|
||||
@else
|
||||
<span class="text-xs text-slate-400 italic px-1">Played ✓</span>
|
||||
@endif
|
||||
<button class="p-1.5 rounded-lg text-slate-400 hover:text-red-600 hover:bg-red-50 transition-colors opacity-0 group-hover:opacity-100">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 01-2 2H8a2 2 0 01-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/><path d="M9 6V4a1 1 0 011-1h4a1 1 0 011 1v2"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="px-5 py-3 border-t border-slate-100 flex items-center justify-between">
|
||||
<p class="text-xs text-slate-400">Showing <span class="font-medium text-slate-600">{{ $total }}</span> students</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- FLOATING FOOTBALL BTN -->
|
||||
<style>
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translateY(0px); }
|
||||
50% { transform: translateY(-8px); }
|
||||
}
|
||||
#footballBtn { animation: float 2.8s ease-in-out infinite; }
|
||||
#footballBtn:hover { animation: none; transform: translateY(-10px) rotate(12deg); }
|
||||
#footballBtn:active { transform: scale(0.92); }
|
||||
</style>
|
||||
|
||||
<button id="footballBtn" onclick="openScoreboard()" title="View Scoreboard"
|
||||
class="fixed bottom-8 right-8 z-40 w-24 h-24 cursor-pointer bg-transparent border-none outline-none p-0">
|
||||
<img src="{{ asset('assets/wcup.png') }}" alt="Scoreboard" class="w-full h-full object-contain drop-shadow-md">
|
||||
</button>
|
||||
|
||||
<div class="fixed bottom-[7rem] right-8 z-40 pointer-events-none">
|
||||
<span id="footballTooltip" class="bg-slate-900 text-white text-xs font-medium px-2.5 py-1 rounded-lg shadow opacity-0 transition-opacity duration-150 whitespace-nowrap">
|
||||
Scoreboard
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<iframe id="scoreboardFrame" src="" data-src="{{ route('scoreboard') }}"
|
||||
allowfullscreen
|
||||
style="display:none; position:fixed; inset:0; width:100vw; height:100vh; border:none; z-index:9999;"></iframe>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- REGISTRATION MODAL -->
|
||||
<!-- ============================================================ -->
|
||||
<div id="registrationModal" class="fixed inset-0 z-50 hidden items-center justify-center">
|
||||
<!-- Backdrop -->
|
||||
<div id="modalBackdrop" class="absolute inset-0 bg-slate-900/60 backdrop-blur-sm"></div>
|
||||
|
||||
<!-- Panel -->
|
||||
<div class="relative bg-white rounded-2xl shadow-2xl w-full max-w-sm mx-4 overflow-hidden">
|
||||
|
||||
<!-- Top accent bar -->
|
||||
<div class="h-1 bg-gradient-to-r from-indigo-500 via-purple-500 to-indigo-600"></div>
|
||||
|
||||
<div class="p-6">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="flex items-start justify-between mb-6">
|
||||
<div>
|
||||
<h3 class="text-slate-900 font-bold text-lg leading-tight">New Registration</h3>
|
||||
<p id="modalSubtitle" class="text-slate-500 text-xs mt-0.5">Enter the student's phone number to begin.</p>
|
||||
</div>
|
||||
<button id="closeRegistrationModal"
|
||||
class="ml-4 w-7 h-7 rounded-full bg-slate-100 hover:bg-slate-200 flex items-center justify-center text-slate-500 transition-colors shrink-0">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Step indicators -->
|
||||
<div class="flex items-center gap-2 mb-6">
|
||||
<div id="step1dot" class="flex items-center gap-1.5">
|
||||
<div class="w-6 h-6 rounded-full bg-indigo-600 flex items-center justify-center text-white text-xs font-bold">1</div>
|
||||
<span class="text-xs font-medium text-indigo-600">Phone</span>
|
||||
</div>
|
||||
<div class="flex-1 h-px bg-slate-200" id="step1line"></div>
|
||||
<div id="step2dot" class="flex items-center gap-1.5 opacity-40">
|
||||
<div class="w-6 h-6 rounded-full bg-slate-300 flex items-center justify-center text-slate-600 text-xs font-bold">2</div>
|
||||
<span class="text-xs font-medium text-slate-400">Verify</span>
|
||||
</div>
|
||||
<div class="flex-1 h-px bg-slate-200" id="step2line"></div>
|
||||
<div id="step3dot" class="flex items-center gap-1.5 opacity-40">
|
||||
<div class="w-6 h-6 rounded-full bg-slate-300 flex items-center justify-center text-slate-600 text-xs font-bold">3</div>
|
||||
<span class="text-xs font-medium text-slate-400">Details</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- STEP 1: Phone -->
|
||||
<div id="stepPhone">
|
||||
<label class="block text-xs font-semibold text-slate-600 mb-1.5 uppercase tracking-wide">Phone Number</label>
|
||||
<div class="flex items-center border border-slate-200 rounded-xl overflow-hidden focus-within:ring-2 focus-within:ring-indigo-500 focus-within:border-indigo-500 transition-all bg-slate-50">
|
||||
<div class="px-3 py-2.5 border-r border-slate-200 bg-white">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#94a3b8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07A19.5 19.5 0 013.07 9.81 19.79 19.79 0 01.06 1.18 2 2 0 012.03 0h3a2 2 0 012 1.72c.127.96.361 1.903.7 2.81a2 2 0 01-.45 2.11L6.09 7.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0122 14.92z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<input type="tel" id="phone" placeholder="+977 98XXXXXXXX"
|
||||
class="flex-1 px-3 py-2.5 bg-transparent text-sm text-slate-800 placeholder-slate-400 outline-none">
|
||||
</div>
|
||||
<button id="sendOtpBtn"
|
||||
class="mt-4 w-full bg-indigo-600 hover:bg-indigo-700 active:bg-indigo-800 text-white text-sm font-semibold py-2.5 rounded-xl transition-colors flex items-center justify-center gap-2">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/>
|
||||
</svg>
|
||||
Send OTP
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- STEP 2: Verify OTP -->
|
||||
<div id="stepOtp" class="hidden">
|
||||
<div class="bg-indigo-50 border border-indigo-100 rounded-xl px-4 py-3 mb-4 flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded-full bg-indigo-100 flex items-center justify-center shrink-0">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#6366f1" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07A19.5 19.5 0 013.07 9.81 19.79 19.79 0 01.06 1.18 2 2 0 012.03 0h3a2 2 0 012 1.72c.127.96.361 1.903.7 2.81a2 2 0 01-.45 2.11L6.09 7.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0122 14.92z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs font-semibold text-indigo-700">OTP sent to <span id="phoneSentTo" class="font-bold"></span></p>
|
||||
<p class="text-xs text-indigo-500 mt-0.5">Expires in 2 minutes</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dev OTP preview -->
|
||||
<div id="otpPreview" class="hidden bg-amber-50 border border-amber-200 rounded-xl px-4 py-2.5 mb-4 flex items-center gap-2">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#d97706" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
||||
<p class="text-xs font-semibold text-amber-700">Dev — OTP: <span id="otpValue" class="font-mono tracking-widest"></span></p>
|
||||
</div>
|
||||
|
||||
<label class="block text-xs font-semibold text-slate-600 mb-1.5 uppercase tracking-wide">Enter OTP</label>
|
||||
<input type="text" id="otp" maxlength="6" placeholder="— — — — — —"
|
||||
class="w-full border border-slate-200 rounded-xl px-4 py-2.5 text-center text-xl font-mono tracking-[.5em] text-slate-800 bg-slate-50
|
||||
focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 focus:bg-white transition-all placeholder-slate-300">
|
||||
|
||||
<button id="verifyOtpBtn"
|
||||
class="mt-4 w-full bg-emerald-600 hover:bg-emerald-700 active:bg-emerald-800 text-white text-sm font-semibold py-2.5 rounded-xl transition-colors flex items-center justify-center gap-2">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="20 6 9 17 4 12"/>
|
||||
</svg>
|
||||
Verify OTP
|
||||
</button>
|
||||
|
||||
<button id="backToPhone" class="mt-2.5 w-full text-xs text-slate-400 hover:text-slate-600 py-1.5 transition-colors">
|
||||
← Change phone number
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- STEP 3: Extra details (new user only) -->
|
||||
<div id="stepDetails" class="hidden">
|
||||
<div class="bg-emerald-50 border border-emerald-100 rounded-xl px-4 py-3 mb-4 flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded-full bg-emerald-100 flex items-center justify-center shrink-0">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#059669" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="20 6 9 17 4 12"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs font-semibold text-emerald-700">Phone verified!</p>
|
||||
<p class="text-xs text-emerald-600 mt-0.5">New student — please fill in their details.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-slate-600 mb-1.5 uppercase tracking-wide">Full Name <span class="text-red-400">*</span></label>
|
||||
<input type="text" id="regName" placeholder="Student's full name"
|
||||
class="w-full border border-slate-200 rounded-xl px-3 py-2.5 text-sm text-slate-800 bg-slate-50
|
||||
focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 focus:bg-white transition-all placeholder-slate-400">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-slate-600 mb-1.5 uppercase tracking-wide">Email <span class="text-slate-400 font-normal normal-case">(optional)</span></label>
|
||||
<input type="email" id="regEmail" placeholder="student@email.com"
|
||||
class="w-full border border-slate-200 rounded-xl px-3 py-2.5 text-sm text-slate-800 bg-slate-50
|
||||
focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 focus:bg-white transition-all placeholder-slate-400">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button id="submitRegistrationBtn"
|
||||
class="mt-5 w-full bg-indigo-600 hover:bg-indigo-700 text-white text-sm font-semibold py-2.5 rounded-xl transition-colors flex items-center justify-center gap-2">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M16 21v-2a4 4 0 00-4-4H6a4 4 0 00-4 4v2"/><circle cx="9" cy="7" r="4"/><line x1="19" y1="8" x2="19" y2="14"/><line x1="22" y1="11" x2="16" y2="11"/>
|
||||
</svg>
|
||||
Register Student
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Error message -->
|
||||
<div id="modalError" class="hidden mt-3 bg-red-50 border border-red-200 rounded-xl px-4 py-3 flex items-center gap-2">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
||||
<p id="modalErrorText" class="text-xs text-red-600 font-medium"></p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- SHOT RECORDING SIDE PANEL -->
|
||||
<!-- ============================================================ -->
|
||||
<div id="shotPanel"
|
||||
class="fixed top-0 right-0 h-full w-80 bg-white border-l border-slate-200 shadow-2xl z-40
|
||||
transform translate-x-full transition-transform duration-300 ease-in-out
|
||||
flex flex-col">
|
||||
|
||||
<!-- Panel Header -->
|
||||
<div class="px-5 py-4 border-b border-slate-100 flex items-center justify-between bg-slate-50">
|
||||
<div>
|
||||
<p class="text-xs font-semibold text-slate-400 uppercase tracking-wider">Recording Shots For</p>
|
||||
<p id="panelName" class="text-slate-900 font-bold text-base mt-0.5">—</p>
|
||||
</div>
|
||||
<button id="closeShotPanel"
|
||||
class="w-7 h-7 rounded-full bg-slate-200 hover:bg-slate-300 flex items-center justify-center text-slate-500 transition-colors">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Shot Indicators -->
|
||||
<div class="px-5 py-4 border-b border-slate-100">
|
||||
<p class="text-xs font-semibold text-slate-400 uppercase tracking-wider mb-3">Today's Shots</p>
|
||||
<div class="flex items-center gap-3">
|
||||
<div id="shotIndicator1" class="flex-1 h-10 rounded-lg border-2 border-slate-200 bg-slate-50 flex items-center justify-center text-xs font-bold text-slate-400">
|
||||
Shot 1
|
||||
</div>
|
||||
<div id="shotIndicator2" class="flex-1 h-10 rounded-lg border-2 border-slate-200 bg-slate-50 flex items-center justify-center text-xs font-bold text-slate-400">
|
||||
Shot 2
|
||||
</div>
|
||||
<div id="shotIndicator3" class="flex-1 h-10 rounded-lg border-2 border-slate-200 bg-slate-50 flex items-center justify-center text-xs font-bold text-slate-400">
|
||||
Shot 3
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Current Shot -->
|
||||
<div class="flex-1 flex flex-col items-center justify-center px-5 gap-5">
|
||||
<div id="shotReadyState">
|
||||
<p class="text-center text-slate-400 text-xs font-semibold uppercase tracking-wider mb-1">Current Shot</p>
|
||||
<p id="currentShotLabel" class="text-center text-slate-900 font-black text-4xl mb-6">Shot 1</p>
|
||||
|
||||
<div class="flex flex-col gap-3 w-full px-2">
|
||||
<button id="goalBtn"
|
||||
class="w-full py-8 flex flex-col items-center justify-center gap-3 rounded-2xl
|
||||
bg-emerald-50 hover:bg-emerald-100 active:scale-95
|
||||
border-2 border-emerald-300 hover:border-emerald-500
|
||||
transition-all duration-150">
|
||||
<span class="text-5xl">⚽</span>
|
||||
<span class="text-emerald-700 font-black text-base uppercase tracking-widest">Goal</span>
|
||||
<span class="text-emerald-500 text-xs font-semibold">+1 pt</span>
|
||||
</button>
|
||||
|
||||
<button id="missBtn"
|
||||
class="w-full py-8 flex flex-col items-center justify-center gap-3 rounded-2xl
|
||||
bg-red-50 hover:bg-red-100 active:scale-95
|
||||
border-2 border-red-300 hover:border-red-500
|
||||
transition-all duration-150">
|
||||
<span class="text-5xl font-black text-red-500">✕</span>
|
||||
<span class="text-red-700 font-black text-base uppercase tracking-widest">Miss</span>
|
||||
<span class="text-red-400 text-xs font-semibold">0 pts</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Done state (all 3 recorded) -->
|
||||
<div id="shotDoneState" class="hidden text-center">
|
||||
<div class="w-16 h-16 rounded-full bg-emerald-100 flex items-center justify-center mx-auto mb-3">
|
||||
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#059669" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="20 6 9 17 4 12"/>
|
||||
</svg>
|
||||
</div>
|
||||
<p class="text-slate-900 font-bold text-lg">All shots recorded!</p>
|
||||
<p class="text-slate-500 text-sm mt-1">Session score: <span id="sessionScoreDisplay" class="font-bold text-indigo-600"></span> pts</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Total Score Footer -->
|
||||
<div class="px-5 py-4 border-t border-slate-100 bg-slate-50">
|
||||
<div class="flex items-center justify-between">
|
||||
<p class="text-xs font-semibold text-slate-400 uppercase tracking-wider">Cumulative Total</p>
|
||||
<div class="flex items-center gap-1">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="#6366f1" stroke="none">
|
||||
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>
|
||||
</svg>
|
||||
<span id="panelTotalScore" class="text-slate-900 font-black text-xl">0</span>
|
||||
<span class="text-slate-400 text-xs font-medium">pts</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Overlay behind panel -->
|
||||
<div id="shotPanelOverlay"
|
||||
class="fixed inset-0 bg-black/20 z-30 hidden"
|
||||
id="shotPanelOverlay">
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
@push('js')
|
||||
<script>
|
||||
// ── Row selection + Shot panel ───────────────────────────────
|
||||
let selectedSessionId = null;
|
||||
let currentShot = 1;
|
||||
let shotResults = [];
|
||||
let selectedRow = null;
|
||||
|
||||
function openShotPanel(row) {
|
||||
// Deselect previous
|
||||
if (selectedRow) selectedRow.classList.remove('ring-2', 'ring-inset', 'ring-indigo-400', 'bg-indigo-50/40');
|
||||
|
||||
selectedRow = row;
|
||||
row.classList.add('ring-2', 'ring-inset', 'ring-indigo-400', 'bg-indigo-50/40');
|
||||
|
||||
selectedSessionId = row.dataset.sessionId;
|
||||
currentShot = parseInt(row.dataset.shotsRecorded || 0) + 1;
|
||||
shotResults = JSON.parse(row.dataset.shots || '[]');
|
||||
|
||||
document.getElementById('panelName').textContent = row.dataset.name;
|
||||
document.getElementById('panelTotalScore').textContent = row.dataset.totalScore;
|
||||
|
||||
refreshPanel();
|
||||
|
||||
document.getElementById('shotPanel').classList.remove('translate-x-full');
|
||||
document.getElementById('shotPanelOverlay').classList.remove('hidden');
|
||||
}
|
||||
|
||||
function closeShotPanel() {
|
||||
document.getElementById('shotPanel').classList.add('translate-x-full');
|
||||
document.getElementById('shotPanelOverlay').classList.add('hidden');
|
||||
if (selectedRow) selectedRow.classList.remove('ring-2', 'ring-inset', 'ring-indigo-400', 'bg-indigo-50/40');
|
||||
selectedRow = null;
|
||||
}
|
||||
|
||||
function refreshPanel() {
|
||||
// Update indicators
|
||||
for (let i = 1; i <= 3; i++) {
|
||||
const el = document.getElementById('shotIndicator' + i);
|
||||
el.className = 'flex-1 h-10 rounded-lg border-2 flex items-center justify-center text-xs font-bold transition-all';
|
||||
if (i < currentShot) {
|
||||
const goal = shotResults[i - 1];
|
||||
if (goal) {
|
||||
el.classList.add('border-emerald-400', 'bg-emerald-50', 'text-emerald-600');
|
||||
el.innerHTML = '⚽ Goal';
|
||||
} else {
|
||||
el.classList.add('border-red-300', 'bg-red-50', 'text-red-500');
|
||||
el.innerHTML = '✕ Miss';
|
||||
}
|
||||
} else if (i === currentShot) {
|
||||
el.classList.add('border-indigo-400', 'bg-indigo-50', 'text-indigo-600', 'animate-pulse');
|
||||
el.innerHTML = 'Shot ' + i;
|
||||
} else {
|
||||
el.classList.add('border-slate-200', 'bg-slate-50', 'text-slate-400');
|
||||
el.innerHTML = 'Shot ' + i;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentShot > 3) {
|
||||
document.getElementById('shotReadyState').classList.add('hidden');
|
||||
document.getElementById('shotDoneState').classList.remove('hidden');
|
||||
const goals = shotResults.filter(Boolean).length;
|
||||
document.getElementById('sessionScoreDisplay').textContent = goals;
|
||||
} else {
|
||||
document.getElementById('shotReadyState').classList.remove('hidden');
|
||||
document.getElementById('shotDoneState').classList.add('hidden');
|
||||
document.getElementById('currentShotLabel').textContent = 'Shot ' + currentShot;
|
||||
}
|
||||
}
|
||||
|
||||
function recordShot(result) {
|
||||
if (!selectedSessionId || currentShot > 3) return;
|
||||
|
||||
const shotNumber = currentShot;
|
||||
|
||||
$.post("{{ route('registrations.record-shot') }}", {
|
||||
_token: "{{ csrf_token() }}",
|
||||
session_id: selectedSessionId,
|
||||
shot_number: shotNumber,
|
||||
result: result ? 1 : 0,
|
||||
})
|
||||
.done(res => {
|
||||
shotResults.push(result);
|
||||
currentShot++;
|
||||
|
||||
// Update the indicator + panel
|
||||
refreshPanel();
|
||||
|
||||
// Update total score in footer + in the row
|
||||
document.getElementById('panelTotalScore').textContent = res.total_score;
|
||||
if (selectedRow) {
|
||||
selectedRow.dataset.totalScore = res.total_score;
|
||||
selectedRow.dataset.shots = JSON.stringify(shotResults);
|
||||
selectedRow.dataset.shotsRecorded = shotResults.length;
|
||||
|
||||
// Live-update score cell
|
||||
const scoreCell = selectedRow.querySelector('.score-cell');
|
||||
if (scoreCell) scoreCell.textContent = res.total_score;
|
||||
|
||||
// Live-update shot dots
|
||||
const shotsCell = selectedRow.querySelector('.shots-cell');
|
||||
if (shotsCell) {
|
||||
shotsCell.innerHTML = shotResults.map((g, i) =>
|
||||
g ? `<div class="w-7 h-7 rounded-full bg-emerald-100 border-2 border-emerald-400 flex items-center justify-center" title="Shot ${i+1}: Goal">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#059669" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
|
||||
</div>`
|
||||
: `<div class="w-7 h-7 rounded-full bg-slate-100 border-2 border-slate-300 flex items-center justify-center" title="Shot ${i+1}: Miss">
|
||||
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="#94a3b8" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
||||
</div>`
|
||||
).join('');
|
||||
}
|
||||
}
|
||||
})
|
||||
.fail(() => alert('Failed to record shot. Please try again.'));
|
||||
}
|
||||
|
||||
document.getElementById('goalBtn').addEventListener('click', () => recordShot(true));
|
||||
document.getElementById('missBtn').addEventListener('click', () => recordShot(false));
|
||||
document.getElementById('closeShotPanel').addEventListener('click', closeShotPanel);
|
||||
document.getElementById('shotPanelOverlay').addEventListener('click', closeShotPanel);
|
||||
|
||||
// Row click listeners
|
||||
document.querySelectorAll('tr[data-session-id]').forEach(row => {
|
||||
row.classList.add('cursor-pointer');
|
||||
row.addEventListener('click', () => {
|
||||
openShotPanel(row);
|
||||
|
||||
// Sync selected player to scoreboard
|
||||
const regId = row.dataset.regId;
|
||||
if (regId) {
|
||||
$.post("{{ route('scoreboard.select') }}", {
|
||||
_token: "{{ csrf_token() }}",
|
||||
registration_id: regId,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ── Scoreboard ──────────────────────────────────────────────
|
||||
const footballBtn = document.getElementById('footballBtn');
|
||||
const tooltip = document.getElementById('footballTooltip');
|
||||
footballBtn.addEventListener('mouseenter', () => tooltip.style.opacity = 1);
|
||||
footballBtn.addEventListener('mouseleave', () => tooltip.style.opacity = 0);
|
||||
|
||||
function openScoreboard() {
|
||||
const frame = document.getElementById('scoreboardFrame');
|
||||
if (!frame.src || frame.src === window.location.href) frame.src = frame.dataset.src;
|
||||
const req = frame.requestFullscreen || frame.webkitRequestFullscreen || frame.mozRequestFullScreen || frame.msRequestFullscreen;
|
||||
if (req) req.call(frame);
|
||||
}
|
||||
|
||||
['fullscreenchange','webkitfullscreenchange','mozfullscreenchange','MSFullscreenChange'].forEach(e =>
|
||||
document.addEventListener(e, () => {
|
||||
const fs = document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement;
|
||||
document.getElementById('scoreboardFrame').style.display = fs ? 'block' : 'none';
|
||||
})
|
||||
);
|
||||
|
||||
// ── Modal state ──────────────────────────────────────────────
|
||||
const modal = document.getElementById('registrationModal');
|
||||
const stepPhone = document.getElementById('stepPhone');
|
||||
const stepOtp = document.getElementById('stepOtp');
|
||||
const stepDetails = document.getElementById('stepDetails');
|
||||
|
||||
function showModal() {
|
||||
modal.classList.remove('hidden');
|
||||
modal.classList.add('flex');
|
||||
goToStep(1);
|
||||
}
|
||||
|
||||
function hideModal() {
|
||||
modal.classList.add('hidden');
|
||||
modal.classList.remove('flex');
|
||||
clearError();
|
||||
document.getElementById('phone').value = '';
|
||||
document.getElementById('otp').value = '';
|
||||
document.getElementById('regName').value = '';
|
||||
document.getElementById('regEmail').value = '';
|
||||
}
|
||||
|
||||
function goToStep(step) {
|
||||
stepPhone.classList.add('hidden');
|
||||
stepOtp.classList.add('hidden');
|
||||
stepDetails.classList.add('hidden');
|
||||
clearError();
|
||||
|
||||
const subtitles = {
|
||||
1: 'Enter the student\'s phone number to begin.',
|
||||
2: 'Enter the 6-digit OTP sent to the student\'s phone.',
|
||||
3: 'New student — fill in their details to complete registration.'
|
||||
};
|
||||
document.getElementById('modalSubtitle').textContent = subtitles[step];
|
||||
|
||||
// Step indicators
|
||||
const s2 = document.getElementById('step2dot');
|
||||
const s3 = document.getElementById('step3dot');
|
||||
s2.classList.toggle('opacity-40', step < 2);
|
||||
s3.classList.toggle('opacity-40', step < 3);
|
||||
s2.querySelector('div').className = step >= 2
|
||||
? 'w-6 h-6 rounded-full bg-indigo-600 flex items-center justify-center text-white text-xs font-bold'
|
||||
: 'w-6 h-6 rounded-full bg-slate-300 flex items-center justify-center text-slate-600 text-xs font-bold';
|
||||
s3.querySelector('div').className = step >= 3
|
||||
? 'w-6 h-6 rounded-full bg-indigo-600 flex items-center justify-center text-white text-xs font-bold'
|
||||
: 'w-6 h-6 rounded-full bg-slate-300 flex items-center justify-center text-slate-600 text-xs font-bold';
|
||||
|
||||
if (step === 1) stepPhone.classList.remove('hidden');
|
||||
if (step === 2) stepOtp.classList.remove('hidden');
|
||||
if (step === 3) stepDetails.classList.remove('hidden');
|
||||
}
|
||||
|
||||
function showError(msg) {
|
||||
document.getElementById('modalError').classList.remove('hidden');
|
||||
document.getElementById('modalErrorText').textContent = msg;
|
||||
}
|
||||
|
||||
function clearError() {
|
||||
document.getElementById('modalError').classList.add('hidden');
|
||||
}
|
||||
|
||||
// ── Open / Close ─────────────────────────────────────────────
|
||||
document.getElementById('newRegistrationBtn').addEventListener('click', showModal);
|
||||
document.getElementById('closeRegistrationModal').addEventListener('click', hideModal);
|
||||
document.getElementById('modalBackdrop').addEventListener('click', hideModal);
|
||||
document.getElementById('backToPhone').addEventListener('click', () => goToStep(1));
|
||||
|
||||
// ── Send OTP ─────────────────────────────────────────────────
|
||||
document.getElementById('sendOtpBtn').addEventListener('click', function () {
|
||||
const phone = document.getElementById('phone').value.trim();
|
||||
if (!phone) { showError('Please enter a phone number.'); return; }
|
||||
|
||||
this.disabled = true;
|
||||
this.textContent = 'Sending…';
|
||||
|
||||
$.post("{{ route('registrations.send-otp') }}", {
|
||||
_token: "{{ csrf_token() }}",
|
||||
phone: phone
|
||||
})
|
||||
.done(res => {
|
||||
document.getElementById('phoneSentTo').textContent = phone;
|
||||
if (res.otp) {
|
||||
document.getElementById('otpPreview').classList.remove('hidden');
|
||||
document.getElementById('otpValue').textContent = res.otp;
|
||||
}
|
||||
goToStep(2);
|
||||
})
|
||||
.fail(() => showError('Failed to send OTP. Please try again.'))
|
||||
.always(() => {
|
||||
this.disabled = false;
|
||||
this.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg> Send OTP`;
|
||||
});
|
||||
});
|
||||
|
||||
// ── Verify OTP ───────────────────────────────────────────────
|
||||
document.getElementById('verifyOtpBtn').addEventListener('click', function () {
|
||||
const phone = document.getElementById('phone').value.trim();
|
||||
const otp = document.getElementById('otp').value.trim();
|
||||
if (!otp) { showError('Please enter the OTP.'); return; }
|
||||
|
||||
this.disabled = true;
|
||||
this.textContent = 'Verifying…';
|
||||
|
||||
$.post("{{ route('registrations.verify-otp') }}", {
|
||||
_token: "{{ csrf_token() }}",
|
||||
phone: phone,
|
||||
otp: otp
|
||||
})
|
||||
.done(res => {
|
||||
if (res.status === 'session_created') {
|
||||
hideModal();
|
||||
location.reload();
|
||||
} else if (res.status === 'needs_registration') {
|
||||
goToStep(3);
|
||||
}
|
||||
})
|
||||
.fail(xhr => {
|
||||
const res = xhr.responseJSON;
|
||||
if (res?.status === 'blocked') {
|
||||
showError(res.message || 'This student has already played today.');
|
||||
} else if (res?.status === 'invalid_otp') {
|
||||
showError('Invalid OTP. Please try again.');
|
||||
} else {
|
||||
showError('Something went wrong. Please try again.');
|
||||
}
|
||||
})
|
||||
.always(() => {
|
||||
this.disabled = false;
|
||||
this.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg> Verify OTP`;
|
||||
});
|
||||
});
|
||||
|
||||
// ── Submit new registration (step 3) ─────────────────────────
|
||||
document.getElementById('submitRegistrationBtn').addEventListener('click', function () {
|
||||
const name = document.getElementById('regName').value.trim();
|
||||
const email = document.getElementById('regEmail').value.trim();
|
||||
const phone = document.getElementById('phone').value.trim();
|
||||
if (!name) { showError('Please enter the student\'s name.'); return; }
|
||||
|
||||
this.disabled = true;
|
||||
this.textContent = 'Registering…';
|
||||
|
||||
$.post("{{ route('registrations.store') }}", {
|
||||
_token: "{{ csrf_token() }}",
|
||||
phone: phone,
|
||||
name: name,
|
||||
email: email
|
||||
})
|
||||
.done(res => {
|
||||
if (res.status === 'session_created') {
|
||||
hideModal();
|
||||
location.reload();
|
||||
}
|
||||
})
|
||||
.fail(() => showError('Registration failed. Please try again.'))
|
||||
.always(() => {
|
||||
this.disabled = false;
|
||||
this.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 00-4-4H6a4 4 0 00-4 4v2"/><circle cx="9" cy="7" r="4"/><line x1="19" y1="8" x2="19" y2="14"/><line x1="22" y1="11" x2="16" y2="11"/></svg> Register Student`;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
Reference in New Issue
Block a user