diff --git a/app/Http/Controllers/CommentController.php b/app/Http/Controllers/CommentController.php index ee1c61c..da69aae 100644 --- a/app/Http/Controllers/CommentController.php +++ b/app/Http/Controllers/CommentController.php @@ -19,7 +19,8 @@ class CommentController extends Controller 'comment' => $c->comment, 'author' => auth()->user()->name, 'created_at_human' => $c->created_at->diffForHumans(), - ]); + ]) + ->values(); // ← add this return response()->json(['comments' => $comments]); } diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index 0825bb9..d52156f 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -2,26 +2,28 @@ namespace App\Http\Controllers; +use App\Models\Country; use App\Models\Registration; use Carbon\Carbon; use Illuminate\Http\Request; class HomeController extends Controller { - public function index() + public function index(Request $request) { $user = auth()->user(); return match ($user->role) { - 'admin' => $this->adminDashboard(), - 'counselor' => $this->counselorDashboard(), + 'admin' => $this->adminDashboard($request), + 'counselor' => $this->counselorDashboard($request), default => abort(403, 'Unauthorized action.'), }; } - public function adminDashboard() + public function adminDashboard(Request $request) { - $today = Carbon::today(); + $today = Carbon::today(); + $search = trim($request->input('search', '')); $query = Registration::with([ 'sessions' => function ($q) use ($today) { @@ -30,16 +32,21 @@ class HomeController extends Controller ]) ->whereHas('sessions', function ($q) use ($today) { $q->whereDate('play_date', $today); - }) - ->orderBy('created_at', 'desc') - ->paginate(10); + }); + + if ($search) { + $query->where(function ($q) use ($search) { + $q->where('name', 'like', "%{$search}%") + ->orWhere('phone', 'like', "%{$search}%") + ->orWhere('email', 'like', "%{$search}%"); + }); + } + + $query = $query->orderBy('created_at', 'desc')->paginate(10)->withQueryString(); $registrations = $query->getCollection()->map(function ($student) { - $todaySession = $student->sessions->first(); - - $todayGoals = null; - + $todayGoals = null; if ($todaySession) { $todayGoals = $todaySession->shots ->sortBy('shot_number') @@ -47,7 +54,6 @@ class HomeController extends Controller ->values() ->toArray(); } - return [ 'id' => $student->id, 'name' => $student->name, @@ -56,41 +62,51 @@ class HomeController extends Controller 'today_goals' => $todayGoals, 'total_score' => $student->total_score, 'session_id' => $todaySession?->id, + 'country_id' => $student->country_id, ]; }); $query->setCollection($registrations); $data['registrations'] = $query; + $data['search'] = $search; $data['total'] = Registration::count(); $data['played'] = $registrations->filter(fn($r) => !empty($r['today_goals']) && count($r['today_goals']) >= 3)->count(); $data['topScore'] = $registrations->max('total_score') ?? 0; + $data['countries'] = Country::where('status', 1)->orderBy('title')->get(['id','title','country_flag']); return view('dashboard.admin', $data); } - public function counselorDashboard() + public function counselorDashboard(Request $request) { - $today = Carbon::today(); + $today = Carbon::today(); + $search = trim($request->input('search', '')); $query = Registration::with([ 'sessions' => function ($q) use ($today) { $q->whereDate('play_date', $today)->with('shots'); }, - 'comments' + 'comments', + 'country' ]) ->whereHas('sessions', function ($q) use ($today) { $q->whereDate('play_date', $today); - }) - ->orderBy('created_at', 'desc') - ->paginate(10); + }); + + if ($search) { + $query->where(function ($q) use ($search) { + $q->where('name', 'like', "%{$search}%") + ->orWhere('phone', 'like', "%{$search}%") + ->orWhere('email', 'like', "%{$search}%"); + }); + } + + $query = $query->orderBy('created_at', 'desc')->paginate(10)->withQueryString(); $registrations = $query->getCollection()->map(function ($student) { - $todaySession = $student->sessions->first(); - - $todayGoals = null; - + $todayGoals = null; if ($todaySession) { $todayGoals = $todaySession->shots ->sortBy('shot_number') @@ -98,7 +114,6 @@ class HomeController extends Controller ->values() ->toArray(); } - return [ 'id' => $student->id, 'name' => $student->name, @@ -107,6 +122,10 @@ class HomeController extends Controller 'today_goals' => $todayGoals, 'total_score' => $student->total_score, 'session_id' => $todaySession?->id, + 'country_id' => $student->country_id, + 'country_title' => $student->country?->title ?? '', // add + 'country_flag' => $student->country?->country_flag ?? '', // add + 'status' => $student->status ?? 'warm', // add if not there 'comment_count' => $student->comments->count(), ]; }); @@ -114,9 +133,11 @@ class HomeController extends Controller $query->setCollection($registrations); $data['registrations'] = $query; + $data['search'] = $search; $data['total'] = Registration::count(); $data['played'] = $registrations->filter(fn($r) => !empty($r['today_goals']) && count($r['today_goals']) >= 3)->count(); $data['topScore'] = $registrations->max('total_score') ?? 0; + $data['countries'] = Country::where('status', 1)->orderBy('title')->get(['id','title','country_flag']); return view('dashboard.counselor', $data); } diff --git a/app/Http/Controllers/RegistrationController.php b/app/Http/Controllers/RegistrationController.php index e3b9615..b7d5a38 100644 --- a/app/Http/Controllers/RegistrationController.php +++ b/app/Http/Controllers/RegistrationController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers; +use App\Models\Country; use App\Models\GameSession; use App\Models\GameShot; use App\Models\Registration; @@ -10,13 +11,28 @@ use Illuminate\Support\Facades\Cache; class RegistrationController extends Controller { - public function index() + public function index(Request $request) { - $registrations = Registration::orderBy('id', 'desc')->paginate(20); + $search = trim($request->input('search', '')); - return view('registrations', compact('registrations')); + $query = Registration::with(['sessions.shots', 'comments']); + + if ($search) { + $query->where(function ($q) use ($search) { + $q->where('name', 'like', "%{$search}%") + ->orWhere('phone', 'like', "%{$search}%") + ->orWhere('email', 'like', "%{$search}%"); + }); + } + + $registrations = $query->orderBy('id', 'desc')->paginate(20)->withQueryString(); + + $data['registrations'] = $registrations; + $data['search'] = $search; + $data['countries'] = Country::where('status', 1)->orderBy('title')->get(['id','title','country_flag']); + + return view('registrations', $data); } - public function create() { return view('registrations.create'); @@ -311,5 +327,51 @@ class RegistrationController extends Controller return view('leaderboard', $data); } + + public function history($id) + { + $reg = Registration::with(['sessions.shots'])->findOrFail($id); + + $sessions = $reg->sessions + ->sortByDesc('play_date') + ->map(fn($s) => [ + 'date' => $s->play_date, + 'score' => $s->score, + 'shots' => $s->shots->sortBy('shot_number')->map(fn($sh) => (bool)$sh->result)->values(), + ])->values(); + + return response()->json(['sessions' => $sessions]); + } + + public function updateCountry(Request $request, $id) + { + $request->validate([ + 'country_id' => 'required|exists:countries,id', + ]); + + $registration = Registration::findOrFail($id); + $registration->update(['country_id' => $request->country_id]); + + return response()->json([ + 'status' => 'ok', + 'country_id' => $registration->country_id, + 'country_name' => $registration->country->title, + ]); + } + + public function updateStatus(Request $request, $id) + { + $request->validate([ + 'status' => 'required|in:hot,warm,cold', + ]); + + $registration = Registration::findOrFail($id); + $registration->update(['status' => $request->status]); + + return response()->json([ + 'status' => 'ok', + 'value' => $registration->status, + ]); + } } \ No newline at end of file diff --git a/app/Http/Controllers/ScoreboardController.php b/app/Http/Controllers/ScoreboardController.php index 979513b..b772c59 100644 --- a/app/Http/Controllers/ScoreboardController.php +++ b/app/Http/Controllers/ScoreboardController.php @@ -4,6 +4,7 @@ namespace App\Http\Controllers; use App\Models\Registration; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Cache; class ScoreboardController extends Controller { @@ -15,34 +16,41 @@ class ScoreboardController extends Controller public function select(Request $request) { $request->validate(['registration_id' => 'required|exists:registrations,id']); - session(['scoreboard_player_id' => $request->registration_id]); + Cache::put('scoreboard_selected_player', $request->registration_id, now()->endOfDay()); return response()->json(['status' => 'ok']); } public function state() { - $id = session('scoreboard_player_id'); + $id = Cache::get('scoreboard_selected_player'); if (!$id) { return response()->json(['player' => null, 'leaderboard' => $this->leaderboard()]); } $reg = Registration::with([ - 'sessions' => fn($q) => $q->whereDate('play_date', today())->with('shots') + 'sessions' => fn($q) => $q->orderByDesc('play_date')->with('shots') ])->findOrFail($id); - $todaySession = $reg->sessions->first(); + $todaySession = $reg->sessions->firstWhere('play_date', today()->toDateString()); $shots = $todaySession ? $todaySession->shots->sortBy('shot_number')->map(fn($s) => (bool)$s->result)->values()->toArray() : []; + $history = $reg->sessions->map(fn($s) => [ + 'date' => $s->play_date, + 'score' => $s->score, + 'shots' => $s->shots->sortBy('shot_number')->map(fn($sh) => (bool)$sh->result)->values()->toArray(), + ])->toArray(); + return response()->json([ 'player' => [ - 'id' => $reg->id, - 'name' => $reg->name, - 'total_score' => $reg->total_score, - 'shots' => $shots, + 'id' => $reg->id, + 'name' => $reg->name, + 'total_score' => $reg->total_score, + 'shots' => $shots, 'session_score' => $todaySession?->calculateScore() ?? 0, + 'history' => $history, ], 'leaderboard' => $this->leaderboard(), ]); @@ -55,9 +63,10 @@ class ScoreboardController extends Controller ->get(['id', 'name', 'total_score']) ->map(fn($r, $i) => [ 'rank' => $i + 1, + 'id' => $r->id, 'name' => $r->name, 'total_score' => $r->total_score, ]) ->toArray(); } -} +} \ No newline at end of file diff --git a/app/Models/Country.php b/app/Models/Country.php new file mode 100644 index 0000000..8723e59 --- /dev/null +++ b/app/Models/Country.php @@ -0,0 +1,16 @@ +hasMany(Registration::class); + } +} + diff --git a/app/Models/Registration.php b/app/Models/Registration.php index 09b351f..40f98d6 100644 --- a/app/Models/Registration.php +++ b/app/Models/Registration.php @@ -10,6 +10,8 @@ class Registration extends Model 'name', 'email', 'phone', + 'country_id', + 'status', 'total_score', ]; @@ -31,6 +33,11 @@ class Registration extends Model return $this->hasMany(Comment::class); } + public function country() + { + return $this->belongsTo(\App\Models\Country::class); + } + /* |--------------------------- | Helper methods diff --git a/database/migrations/2026_06_10_104707_create_countries_table.php b/database/migrations/2026_06_10_104707_create_countries_table.php new file mode 100644 index 0000000..bef9a13 --- /dev/null +++ b/database/migrations/2026_06_10_104707_create_countries_table.php @@ -0,0 +1,30 @@ +id(); + $table->string('title'); + $table->string('country_flag')->nullable(); + $table->boolean('status')->default(true); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('countries'); + } +}; diff --git a/database/migrations/2026_06_10_104953_add_countries_and_status_to_registrations_table.php b/database/migrations/2026_06_10_104953_add_countries_and_status_to_registrations_table.php new file mode 100644 index 0000000..43c478d --- /dev/null +++ b/database/migrations/2026_06_10_104953_add_countries_and_status_to_registrations_table.php @@ -0,0 +1,30 @@ +unsignedBigInteger('country_id')->nullable(); + $table->enum('status', ['hot', 'warm', 'cold'])->default('warm'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('registrations', function (Blueprint $table) { + $table->dropColumn(['country_id', 'status']); + }); + + } +}; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 6b901f8..82591c3 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -15,11 +15,14 @@ class DatabaseSeeder extends Seeder */ public function run(): void { + $this->call([ + countries_seeder::class, + ]); // User::factory(10)->create(); - User::factory()->create([ - 'name' => 'Test User', - 'email' => 'test@example.com', - ]); + // User::factory()->create([ + // 'name' => 'Test User', + // 'email' => 'test@example.com', + // ]); } } diff --git a/database/seeders/countries_seeder.php b/database/seeders/countries_seeder.php new file mode 100644 index 0000000..24018df --- /dev/null +++ b/database/seeders/countries_seeder.php @@ -0,0 +1,309 @@ +truncate(); + + DB::table('countries')->insert([ + [ + 'id' => 1, + 'title' => 'United States', + 'country_flag' => 'https://flagcdn.com/w80/us.png', + 'status' => 1, + ], + [ + 'id' => 2, + 'title' => 'Mexico', + 'country_flag' => 'https://flagcdn.com/w80/mx.png', + 'status' => 1, + ], + [ + 'id' => 3, + 'title' => 'Canada', + 'country_flag' => 'https://flagcdn.com/w80/ca.png', + 'status' => 1, + ], + [ + 'id' => 4, + 'title' => 'Japan', + 'country_flag' => 'https://flagcdn.com/w80/jp.png', + 'status' => 1, + ], + [ + 'id' => 5, + 'title' => 'Iran', + 'country_flag' => 'https://flagcdn.com/w80/ir.png', + 'status' => 1, + ], + [ + 'id' => 6, + 'title' => 'South Korea', + 'country_flag' => 'https://flagcdn.com/w80/kr.png', + 'status' => 1, + ], + [ + 'id' => 7, + 'title' => 'Australia', + 'country_flag' => 'https://flagcdn.com/w80/au.png', + 'status' => 1, + ], + [ + 'id' => 8, + 'title' => 'Saudi Arabia', + 'country_flag' => 'https://flagcdn.com/w80/sa.png', + 'status' => 1, + ], + [ + 'id' => 9, + 'title' => 'Qatar', + 'country_flag' => 'https://flagcdn.com/w80/qa.png', + 'status' => 1, + ], + [ + 'id' => 10, + 'title' => 'Uzbekistan', + 'country_flag' => 'https://flagcdn.com/w80/uz.png', + 'status' => 1, + ], + [ + 'id' => 11, + 'title' => 'Jordan', + 'country_flag' => 'https://flagcdn.com/w80/jo.png', + 'status' => 1, + ], + [ + 'id' => 12, + 'title' => 'Iraq', + 'country_flag' => 'https://flagcdn.com/w80/iq.png', + 'status' => 1, + ], + [ + 'id' => 13, + 'title' => 'Argentina', + 'country_flag' => 'countries/ZQLg2ALI9Ez25ZqiFA2u5LRox2lmn66MOkr9Ywqr.png', + 'status' => 1, + ], + [ + 'id' => 14, + 'title' => 'Brazil', + 'country_flag' => 'https://flagcdn.com/w80/br.png', + 'status' => 1, + ], + [ + 'id' => 15, + 'title' => 'Uruguay', + 'country_flag' => 'https://flagcdn.com/w80/uy.png', + 'status' => 1, + ], + [ + 'id' => 16, + 'title' => 'Colombia', + 'country_flag' => 'https://flagcdn.com/w80/co.png', + 'status' => 1, + ], + [ + 'id' => 17, + 'title' => 'Ecuador', + 'country_flag' => 'https://flagcdn.com/w80/ec.png', + 'status' => 1, + ], + [ + 'id' => 18, + 'title' => 'Paraguay', + 'country_flag' => 'https://flagcdn.com/w80/py.png', + 'status' => 1, + ], + [ + 'id' => 19, + 'title' => 'New Zealand', + 'country_flag' => 'https://flagcdn.com/w80/nz.png', + 'status' => 1, + ], + [ + 'id' => 20, + 'title' => 'Morocco', + 'country_flag' => 'https://flagcdn.com/w80/ma.png', + 'status' => 1, + ], + [ + 'id' => 21, + 'title' => 'Senegal', + 'country_flag' => 'https://flagcdn.com/w80/sn.png', + 'status' => 1, + ], + [ + 'id' => 22, + 'title' => 'Egypt', + 'country_flag' => 'https://flagcdn.com/w80/eg.png', + 'status' => 1, + ], + [ + 'id' => 23, + 'title' => 'Algeria', + 'country_flag' => 'https://flagcdn.com/w80/dz.png', + 'status' => 1, + ], + [ + 'id' => 24, + 'title' => 'Tunisia', + 'country_flag' => 'https://flagcdn.com/w80/tn.png', + 'status' => 1, + ], + [ + 'id' => 25, + 'title' => 'South Africa', + 'country_flag' => 'https://flagcdn.com/w80/za.png', + 'status' => 1, + ], + [ + 'id' => 26, + 'title' => 'Ivory Coast', + 'country_flag' => 'https://flagcdn.com/w80/ci.png', + 'status' => 1, + ], + [ + 'id' => 27, + 'title' => 'Ghana', + 'country_flag' => 'https://flagcdn.com/w80/gh.png', + 'status' => 1, + ], + [ + 'id' => 28, + 'title' => 'Cape Verde', + 'country_flag' => 'https://flagcdn.com/w80/cv.png', + 'status' => 1, + ], + [ + 'id' => 29, + 'title' => 'DR Congo', + 'country_flag' => 'https://flagcdn.com/w80/cd.png', + 'status' => 1, + ], + [ + 'id' => 30, + 'title' => 'England', + 'country_flag' => 'https://upload.wikimedia.org/wikipedia/en/thumb/b/be/Flag_of_England.svg/120px-Flag_of_England.svg.png', + 'status' => 1, + ], + [ + 'id' => 31, + 'title' => 'France', + 'country_flag' => 'https://flagcdn.com/w80/fr.png', + 'status' => 1, + ], + [ + 'id' => 32, + 'title' => 'Spain', + 'country_flag' => 'https://flagcdn.com/w80/es.png', + 'status' => 1, + ], + [ + 'id' => 33, + 'title' => 'Germany', + 'country_flag' => 'https://flagcdn.com/w80/de.png', + 'status' => 1, + ], + [ + 'id' => 34, + 'title' => 'Portugal', + 'country_flag' => 'https://flagcdn.com/w80/pt.png', + 'status' => 1, + ], + [ + 'id' => 35, + 'title' => 'Netherlands', + 'country_flag' => 'https://flagcdn.com/w80/nl.png', + 'status' => 1, + ], + [ + 'id' => 36, + 'title' => 'Belgium', + 'country_flag' => 'https://flagcdn.com/w80/be.png', + 'status' => 1, + ], + [ + 'id' => 37, + 'title' => 'Croatia', + 'country_flag' => 'https://flagcdn.com/w80/hr.png', + 'status' => 1, + ], + [ + 'id' => 38, + 'title' => 'Switzerland', + 'country_flag' => 'https://flagcdn.com/w80/ch.png', + 'status' => 1, + ], + [ + 'id' => 39, + 'title' => 'Austria', + 'country_flag' => 'https://flagcdn.com/w80/at.png', + 'status' => 1, + ], + [ + 'id' => 40, + 'title' => 'Scotland', + 'country_flag' => 'https://upload.wikimedia.org/wikipedia/commons/thumb/1/10/Flag_of_Scotland.svg/120px-Flag_of_Scotland.svg.png', + 'status' => 1, + ], + [ + 'id' => 41, + 'title' => 'Norway', + 'country_flag' => 'https://flagcdn.com/w80/no.png', + 'status' => 1, + ], + [ + 'id' => 42, + 'title' => 'Bosnia and Herzegovina', + 'country_flag' => 'https://flagcdn.com/w80/ba.png', + 'status' => 1, + ], + [ + 'id' => 43, + 'title' => 'Sweden', + 'country_flag' => 'https://flagcdn.com/w80/se.png', + 'status' => 1, + ], + [ + 'id' => 44, + 'title' => 'Türkiye', + 'country_flag' => 'https://flagcdn.com/w80/tr.png', + 'status' => 1, + ], + [ + 'id' => 45, + 'title' => 'Czechia', + 'country_flag' => 'https://flagcdn.com/w80/cz.png', + 'status' => 1, + ], + [ + 'id' => 46, + 'title' => 'Panama', + 'country_flag' => 'https://flagcdn.com/w80/pa.png', + 'status' => 1, + ], + [ + 'id' => 47, + 'title' => 'Curaçao', + 'country_flag' => 'https://flagcdn.com/w80/cw.png', + 'status' => 1, + ], + [ + 'id' => 48, + 'title' => 'Haiti', + 'country_flag' => 'https://flagcdn.com/w80/ht.png', + 'status' => 1, + ], + ]); + } +} diff --git a/resources/views/dashboard/admin.blade.php b/resources/views/dashboard/admin.blade.php index 7a4732d..d15ec95 100644 --- a/resources/views/dashboard/admin.blade.php +++ b/resources/views/dashboard/admin.blade.php @@ -7,35 +7,38 @@
Track registrations and goal scores for today's session.
+View registrations and manage student comments.
View registrations and manage student comments.