first commit

This commit is contained in:
2026-06-10 10:46:22 +05:45
commit 473bdd627b
136 changed files with 19074 additions and 0 deletions
@@ -0,0 +1,315 @@
<?php
namespace App\Http\Controllers;
use App\Models\GameSession;
use App\Models\GameShot;
use App\Models\Registration;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
class RegistrationController extends Controller
{
public function index()
{
$registrations = Registration::orderBy('id', 'desc')->paginate(20);
return view('registrations', compact('registrations'));
}
public function create()
{
return view('registrations.create');
}
/*
|-------------------------------------------------
| STORE (ONLY USED AFTER OTP FOR NEW USERS)
|-------------------------------------------------
*/
public function store(Request $request)
{
$request->validate([
'phone' => 'required',
'name' => 'required',
'email' => 'nullable|email'
]);
$registration = Registration::create([
'name' => $request->name,
'email' => $request->email,
'phone' => $request->phone,
'total_score' => 0
]);
$session = GameSession::create([
'registration_id' => $registration->id,
'play_date' => today(),
'score' => 0,
]);
return response()->json([
'status' => 'session_created',
'registration' => [
'id' => $registration->id,
'name' => $registration->name,
'email' => $registration->email,
'phone' => $registration->phone,
'total_score' => 0,
'today_goals' => [],
'session_id' => $session->id,
]
]);
}
/*
|-------------------------------------------------
| SEND OTP
|-------------------------------------------------
*/
public function sendOtp(Request $request)
{
$request->validate([
'phone' => 'required'
]);
$phone = $request->phone;
$otp = rand(100000, 999999);
Cache::put("otp_$phone", $otp, now()->addMinutes(2));
return response()->json([
'status' => true,
'otp' => $otp // remove in production
]);
}
/*
|-------------------------------------------------
| VERIFY OTP (CORE LOGIC)
|-------------------------------------------------
*/
public function verifyOtp(Request $request)
{
$request->validate([
'phone' => 'required',
'otp' => 'required'
]);
$phone = $request->phone;
$cachedOtp = Cache::get("otp_$phone");
if (!$cachedOtp || $cachedOtp != $request->otp) {
return response()->json([
'status' => 'invalid_otp',
'message' => 'Invalid OTP'
], 422);
}
Cache::forget("otp_$phone");
$registration = Registration::where('phone', $phone)->first();
/*
| CASE 1: NEW USER
*/
if (!$registration) {
return response()->json([
'status' => 'needs_registration',
'phone' => $phone
]);
}
/*
| CASE 2: ALREADY PLAYED TODAY
*/
$todaySession = $registration->sessions()
->whereDate('play_date', today())
->first();
if ($todaySession && $todaySession->isComplete()) {
return response()->json([
'status' => 'blocked',
'message' => 'This student has already completed today\'s session.',
], 409);
}
// Session exists but shots not recorded yet — return it
if ($todaySession) {
return response()->json([
'status' => 'session_created',
'registration' => [
'id' => $registration->id,
'name' => $registration->name,
'email' => $registration->email,
'phone' => $registration->phone,
'total_score' => $registration->total_score,
'today_goals' => $todaySession->getShotArray(),
'session_id' => $todaySession->id,
]
]);
}
/*
| CASE 3: CREATE SESSION IMMEDIATELY
*/
$session = GameSession::create([
'registration_id' => $registration->id,
'play_date' => today(),
'score' => 0,
]);
return response()->json([
'status' => 'session_created',
'registration' => [
'id' => $registration->id,
'name' => $registration->name,
'email' => $registration->email,
'phone' => $registration->phone,
'total_score' => $registration->total_score,
'today_goals' => [],
'session_id' => $session->id,
]
]);
}
public function resendOtp(Request $request)
{
$request->validate([
'phone' => 'required'
]);
$phone = $request->phone;
$cooldownKey = 'otp_cooldown_' . $phone;
if (Cache::has($cooldownKey)) {
return response()->json([
'status' => false,
'message' => 'Please wait before resending OTP'
], 429);
}
$otp = rand(100000, 999999);
Cache::put("otp_$phone", $otp, now()->addMinutes(2));
Cache::put($cooldownKey, true, now()->addSeconds(30));
return response()->json([
'status' => true,
'message' => 'OTP resent successfully',
'otp' => $otp
]);
}
public function getRegistrationJson($id)
{
$registration = Registration::with('sessions.shots')->findOrFail($id);
return response()->json([
'registration' => [
'id' => $registration->id,
'name' => $registration->name,
'email' => $registration->email,
'phone' => $registration->phone,
'total_score' => $registration->total_score,
'today_goals' => optional(
$registration->sessions()->whereDate('play_date', today())->first()
)?->getShotArray()
]
]);
}
public function recordShot(Request $request)
{
$request->validate([
'session_id' => 'required|exists:game_sessions,id',
'shot_number' => 'required|integer|in:1,2,3',
'result' => 'required|boolean',
]);
$session = GameSession::with('registration')->findOrFail($request->session_id);
if ($session->shots()->where('shot_number', $request->shot_number)->exists()) {
return response()->json(['status' => 'error', 'message' => 'Shot already recorded.'], 409);
}
GameShot::create([
'game_session_id' => $session->id,
'shot_number' => $request->shot_number,
'result' => $request->result,
]);
$sessionScore = $session->calculateScore();
$session->update(['score' => $sessionScore]);
$registration = $session->registration;
$registration->update(['total_score' => $registration->sessions()->sum('score')]);
return response()->json([
'status' => 'ok',
'total_score' => $registration->fresh()->total_score,
]);
}
public function recordShots(Request $request)
{
$request->validate([
'session_id' => 'required|exists:game_sessions,id',
'shots' => 'required|array|size:3',
'shots.*' => 'boolean',
]);
$session = GameSession::with('registration')->findOrFail($request->session_id);
// Prevent re-recording
if ($session->isComplete()) {
return response()->json([
'status' => 'error',
'message' => 'Shots already recorded for this session.'
], 409);
}
// Store the 3 shots
foreach ($request->shots as $index => $result) {
GameShot::create([
'game_session_id' => $session->id,
'shot_number' => $index + 1,
'result' => $result,
]);
}
// Recalculate and update scores
$sessionScore = $session->calculateScore();
$session->update(['score' => $sessionScore]);
$registration = $session->registration;
$registration->increment('total_score', $sessionScore);
return response()->json([
'status' => 'ok',
'session_score' => $sessionScore,
'total_score' => $registration->fresh()->total_score,
]);
}
//Leaderboard
public function leaderboard()
{
$students = Registration::withCount('sessions')
->orderByDesc('total_score')
->orderBy('name')
->paginate(20);
$maxScore = Registration::max('total_score') ?? 0;
$total = Registration::count();
$data['students'] = $students;
$data['maxScore'] = $maxScore;
$data['total'] = $total;
return view('leaderboard', $data);
}
}