diff --git a/api/app/Http/Controllers/MatchController.php b/api/app/Http/Controllers/MatchController.php index 444ccc9..bcedc9a 100644 --- a/api/app/Http/Controllers/MatchController.php +++ b/api/app/Http/Controllers/MatchController.php @@ -10,7 +10,7 @@ use App\Http\Requests\StoreMatchRequest; use Illuminate\Support\Facades\DB; class MatchController extends Controller -{ +{ public function index(Request $request) { $query = MatchGame::query()->with(['winner', 'player1', 'player2']); @@ -29,9 +29,9 @@ class MatchController extends Controller } public function store(StoreMatchRequest $request) - { + { $validated = $request->validated(); - $user = $request->user(); + $user = $request->user(); $stake = $validated['stake']; if ($user->coins_balance < $stake) { @@ -43,7 +43,7 @@ class MatchController extends Controller ->orWhere('player2_user_id', $user->id); })->whereIn('status', ['Pending', 'Playing'])->exists(); - if ($activeMatch) { + if ($activeMatch) { return response()->json(['message' => 'You already have an active match.'], 400); } @@ -61,7 +61,7 @@ class MatchController extends Controller 'type' => $validated['type'], 'status' => 'Pending', 'player1_user_id' => $user->id, - 'player2_user_id' => $GHOST_ID, + 'player2_user_id' => $GHOST_ID, 'winner_user_id' => $GHOST_ID, 'loser_user_id' => $GHOST_ID, 'stake' => $stake, @@ -129,7 +129,7 @@ class MatchController extends Controller 'match_id' => $match->id, 'coin_transaction_type_id' => $stakeType->id, 'transaction_datetime' => now(), - 'coins' => -$match->stake, + 'coins' => -$match->stake, ]); $match->update([ @@ -163,7 +163,7 @@ class MatchController extends Controller ]); return DB::transaction(function () use ($match, $data) { - + if (isset($data['status']) && $data['status'] === 'Ended') { $data['ended_at'] = now(); } @@ -171,7 +171,7 @@ class MatchController extends Controller $match->update($data); if ($match->status === 'Ended' && $match->stake > 0 && $match->winner_user_id) { - + $payoutType = CoinTransactionType::firstOrCreate( ['name' => 'Match payout'], ['type' => 'C'] // Credit @@ -232,7 +232,7 @@ class MatchController extends Controller 'type' => $request->type, 'status' => 'Pending', 'player1_user_id' => $user->id, - 'player2_user_id' => $GHOST_ID, + 'player2_user_id' => $GHOST_ID, 'winner_user_id' => null, 'loser_user_id' => null, 'stake' => $stake, @@ -255,16 +255,21 @@ class MatchController extends Controller public function open(Request $request) { - $type = $request->query('type', '9'); - $GHOST_ID = 1; + // FIX: Allow matches where P2 is NULL OR 'Ghost' (ID 1) + $query = MatchGame::where('status', 'Pending') + ->where(function($q) { + $q->whereNull('player2_user_id') + ->orWhere('player2_user_id', 1); // 1 = Ghost ID + }); - $matches = MatchGame::where('status', 'Pending') - ->where('player2_user_id', $GHOST_ID) - ->where('type', $type) - ->with('player1') - ->orderBy('began_at', 'asc') + if ($request->has('type')) { + $query->where('type', $request->type); + } + + $matches = $query->with('player1:id,nickname') + ->orderBy('began_at', 'desc') ->paginate(10); return response()->json($matches); } -} \ No newline at end of file +} diff --git a/api/routes/api.php b/api/routes/api.php index d04aa94..7698599 100644 --- a/api/routes/api.php +++ b/api/routes/api.php @@ -58,10 +58,11 @@ Route::prefix('v1')->group(function () { }); Route::prefix('matches')->group(function () { - Route::apiResource('/', MatchController::class)->parameters(['' => 'match']); - Route::post('/{match}/join', [MatchController::class, 'join']); - Route::post('host', [MatchController::class, 'host']); // <--- NOVA + Route::post('host', [MatchController::class, 'host']); Route::get('open', [MatchController::class, 'open']); + Route::post('/{match}/join', [MatchController::class, 'join']); + Route::post('/{match}/start', [MatchController::class, 'start']); // Changed to /start to be explicit + Route::apiResource('/', MatchController::class)->parameters(['' => 'match']); }); // Admin Routes diff --git a/frontend/package.json b/frontend/package.json index 11ff168..1204dbd 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,7 +16,7 @@ "dependencies": { "@tailwindcss/vite": "^4.1.17", "@tanstack/vue-table": "^8.21.3", - "@vueuse/core": "^14.0.0", + "@vueuse/core": "^14.1.0", "axios": "^1.13.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -24,7 +24,7 @@ "lucide-react": "^0.562.0", "lucide-vue-next": "^0.554.0", "pinia": "^3.0.3", - "reka-ui": "^2.6.0", + "reka-ui": "^2.7.0", "socket.io-client": "^4.8.1", "tailwind-merge": "^3.4.0", "tailwindcss": "^4.1.17", diff --git a/frontend/src/components/layout/NavBar.vue b/frontend/src/components/layout/NavBar.vue index 60230b9..2970722 100644 --- a/frontend/src/components/layout/NavBar.vue +++ b/frontend/src/components/layout/NavBar.vue @@ -92,4 +92,4 @@ watch(() => userLoggedIn, async (isLoggedIn) => { userStore.coins = 0 } }, { immediate: true }) - \ No newline at end of file + diff --git a/frontend/src/components/ui/label/Label.vue b/frontend/src/components/ui/label/Label.vue new file mode 100644 index 0000000..b20aec0 --- /dev/null +++ b/frontend/src/components/ui/label/Label.vue @@ -0,0 +1,29 @@ + + + diff --git a/frontend/src/components/ui/label/index.js b/frontend/src/components/ui/label/index.js new file mode 100644 index 0000000..38eaa35 --- /dev/null +++ b/frontend/src/components/ui/label/index.js @@ -0,0 +1 @@ +export { default as Label } from "./Label.vue"; diff --git a/frontend/src/components/ui/switch/Switch.vue b/frontend/src/components/ui/switch/Switch.vue new file mode 100644 index 0000000..215ffac --- /dev/null +++ b/frontend/src/components/ui/switch/Switch.vue @@ -0,0 +1,49 @@ + + + diff --git a/frontend/src/components/ui/switch/index.js b/frontend/src/components/ui/switch/index.js new file mode 100644 index 0000000..c986f8a --- /dev/null +++ b/frontend/src/components/ui/switch/index.js @@ -0,0 +1 @@ +export { default as Switch } from "./Switch.vue"; diff --git a/frontend/src/pages/game/MultiplayerMatchPage.vue b/frontend/src/pages/game/MultiplayerMatchPage.vue new file mode 100644 index 0000000..003506c --- /dev/null +++ b/frontend/src/pages/game/MultiplayerMatchPage.vue @@ -0,0 +1,112 @@ + + + diff --git a/frontend/src/pages/home/HomePage.vue b/frontend/src/pages/home/HomePage.vue index a94705b..fb52f5d 100644 --- a/frontend/src/pages/home/HomePage.vue +++ b/frontend/src/pages/home/HomePage.vue @@ -1,18 +1,24 @@ diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index b2c0293..efc2070 100644 --- a/frontend/src/router/index.js +++ b/frontend/src/router/index.js @@ -10,6 +10,7 @@ import TestAllAnimations from '@/pages/TestAllAnimations.vue' import TestGameBoard from '@/pages/TestGameBoard.vue' import SinglePlayerGamePage from '@/pages/game/SinglePlayerGamePage.vue' import MultiplayerGamePage from '@/pages/game/MultiplayerGamePage.vue' +import MultiplayerMatchPage from '@/pages/game/MultiplayerMatchPage.vue' import RegisterPage from '@/pages/register/RegisterPage.vue' import CoinsPurchasePage from '@/pages/purchase/CoinPurchasePage.vue' import { useAuthStore } from '@/stores/auth' @@ -54,6 +55,12 @@ const router = createRouter({ component: MultiplayerGamePage, meta: { requiresAuth: true } }, + { + path: '/match/:id', + name: 'multiplayer-match', + component: MultiplayerMatchPage, + meta: { requiresAuth: true } + }, { path: '/user', component: UserPage, diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..c93be32 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "DADProject", + "lockfileVersion": 3, + "requires": true, + "packages": {} +}