315 lines
9.2 KiB
PHP
315 lines
9.2 KiB
PHP
<?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);
|
|
}
|
|
|
|
} |