From 59e15cfde8a8a56bdb6f8c69be0d07ec6a117b88 Mon Sep 17 00:00:00 2001 From: Brian McGonagill Date: Thu, 19 Mar 2026 13:59:30 -0500 Subject: [PATCH] Updating navigation and logged in checks. --- backend/Dockerfile | 2 +- backend/prisma/schema.prisma | 3 +- backend/src/routes/games.ts | 17 ++- frontend/src/App.vue | 2 + frontend/src/components/NavBar.vue | 199 ++++++++++++++++++++++++++ frontend/src/main.ts | 9 +- frontend/src/pages/CreateGamePage.vue | 46 ++++-- frontend/src/pages/DashboardPage.vue | 48 +++++-- frontend/src/pages/EditGamePage.vue | 17 ++- frontend/src/pages/GamePage.vue | 13 +- frontend/src/types/index.ts | 3 +- 11 files changed, 316 insertions(+), 43 deletions(-) create mode 100644 frontend/src/components/NavBar.vue diff --git a/backend/Dockerfile b/backend/Dockerfile index e607721..229ee9d 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -14,4 +14,4 @@ COPY . . EXPOSE 3001 -CMD ["sh", "-c", "npx prisma db push && npm run dev"] +CMD ["sh", "-c", "npx prisma db push --accept-data-loss && npm run dev"] diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma index 4ed3053..91ef566 100644 --- a/backend/prisma/schema.prisma +++ b/backend/prisma/schema.prisma @@ -30,8 +30,7 @@ model Game { locationLat Float? locationLng Float? searchRadius Float? - timeLimitPerLeg Int? - timeDeductionPenalty Int? + rules String? status GameStatus @default(DRAFT) inviteCode String? @unique createdAt DateTime @default(now()) diff --git a/backend/src/routes/games.ts b/backend/src/routes/games.ts index 3455f7b..19d4acf 100644 --- a/backend/src/routes/games.ts +++ b/backend/src/routes/games.ts @@ -82,7 +82,12 @@ router.get('/:id', async (req: AuthRequest, res: Response) => { return res.status(403).json({ error: 'Access denied' }); } - res.json(game); + const result = { + ...game, + rules: game.rules ? JSON.parse(game.rules) : [] + }; + + res.json(result); } catch (error) { console.error('Get game error:', error); res.status(500).json({ error: 'Failed to get game' }); @@ -93,7 +98,7 @@ router.post('/', authenticate, async (req: AuthRequest, res: Response) => { try { const { name, description, prizeDetails, visibility, startDate, - locationLat, locationLng, searchRadius, timeLimitPerLeg, timeDeductionPenalty + locationLat, locationLng, searchRadius, rules } = req.body; if (!name) { @@ -116,8 +121,7 @@ router.post('/', authenticate, async (req: AuthRequest, res: Response) => { locationLat, locationLng, searchRadius, - timeLimitPerLeg, - timeDeductionPenalty, + rules: rules ? JSON.stringify(rules) : null, gameMasterId: req.user!.id, inviteCode } @@ -135,7 +139,7 @@ router.put('/:id', authenticate, async (req: AuthRequest, res: Response) => { const id = req.params.id as string; const { name, description, prizeDetails, visibility, startDate, - locationLat, locationLng, searchRadius, timeLimitPerLeg, timeDeductionPenalty, status + locationLat, locationLng, searchRadius, rules, status } = req.body; const game = await prisma.game.findUnique({ where: { id } }); @@ -158,8 +162,7 @@ router.put('/:id', authenticate, async (req: AuthRequest, res: Response) => { locationLat, locationLng, searchRadius, - timeLimitPerLeg, - timeDeductionPenalty, + rules: rules ? JSON.stringify(rules) : undefined, status } }); diff --git a/frontend/src/App.vue b/frontend/src/App.vue index a78fb6f..02fdee5 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,7 +1,9 @@ diff --git a/frontend/src/components/NavBar.vue b/frontend/src/components/NavBar.vue new file mode 100644 index 0000000..e0c6e59 --- /dev/null +++ b/frontend/src/components/NavBar.vue @@ -0,0 +1,199 @@ + + + + + diff --git a/frontend/src/main.ts b/frontend/src/main.ts index 4a4f2bf..4dda871 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -2,11 +2,16 @@ import { createApp } from 'vue' import { createPinia } from 'pinia' import router from './router' import App from './App.vue' +import { useAuthStore } from './stores/auth' import './style.css' const app = createApp(App) +const pinia = createPinia() -app.use(createPinia()) +app.use(pinia) app.use(router) -app.mount('#app') +const authStore = useAuthStore() +authStore.init().then(() => { + app.mount('#app') +}) diff --git a/frontend/src/pages/CreateGamePage.vue b/frontend/src/pages/CreateGamePage.vue index 9834865..fd735f0 100644 --- a/frontend/src/pages/CreateGamePage.vue +++ b/frontend/src/pages/CreateGamePage.vue @@ -15,8 +15,7 @@ const startDate = ref(''); const locationLat = ref(null); const locationLng = ref(null); const searchRadius = ref(500); -const timeLimitPerLeg = ref(30); -const timeDeductionPenalty = ref(60); +const rules = ref(['']); const mapContainer = ref(null); let map: L.Map | null = null; @@ -46,6 +45,14 @@ function initMap() { }); } +function addRule() { + rules.value.push(''); +} + +function removeRule(index: number) { + rules.value.splice(index, 1); +} + async function handleSubmit() { error.value = ''; @@ -59,6 +66,8 @@ async function handleSubmit() { return; } + const filteredRules = rules.value.filter(r => r.trim() !== ''); + loading.value = true; try { @@ -71,8 +80,7 @@ async function handleSubmit() { locationLat: locationLat.value || undefined, locationLng: locationLng.value || undefined, searchRadius: searchRadius.value, - timeLimitPerLeg: timeLimitPerLeg.value, - timeDeductionPenalty: timeDeductionPenalty.value + rules: filteredRules.length > 0 ? filteredRules : undefined }); router.push(`/games/${response.data.id}/edit`); @@ -144,14 +152,34 @@ onUnmounted(() => {

Game Rules

+

Add rules for participants to follow during the game

- - +
+ + +
- - + -
+
diff --git a/frontend/src/pages/DashboardPage.vue b/frontend/src/pages/DashboardPage.vue index cff6b2e..7f8eaa6 100644 --- a/frontend/src/pages/DashboardPage.vue +++ b/frontend/src/pages/DashboardPage.vue @@ -32,6 +32,28 @@ async function loadGames() { } } +async function archiveGame(gameId: string) { + if (!confirm('Are you sure you want to archive this game?')) return; + + try { + await gameService.archive(gameId); + await loadGames(); + } catch (err) { + alert('Failed to archive game'); + } +} + +async function unarchiveGame(gameId: string) { + if (!confirm('Are you sure you want to unarchive this game?')) return; + + try { + await gameService.unarchive(gameId); + await loadGames(); + } catch (err) { + alert('Failed to unarchive game'); + } +} + onMounted(() => { loadGames(); }); @@ -39,15 +61,6 @@ onMounted(() => {