Updating navigation and logged in checks.
This commit is contained in:
parent
9acde36f50
commit
59e15cfde8
11 changed files with 316 additions and 43 deletions
|
|
@ -15,8 +15,7 @@ const startDate = ref('');
|
|||
const locationLat = ref<number | null>(null);
|
||||
const locationLng = ref<number | null>(null);
|
||||
const searchRadius = ref(500);
|
||||
const timeLimitPerLeg = ref(30);
|
||||
const timeDeductionPenalty = ref(60);
|
||||
const rules = ref<string[]>(['']);
|
||||
|
||||
const mapContainer = ref<HTMLDivElement | null>(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(() => {
|
|||
</div>
|
||||
|
||||
<h2>Game Rules</h2>
|
||||
<p><small>Add rules for participants to follow during the game</small></p>
|
||||
|
||||
<label for="timeLimitPerLeg">Time Limit per Leg (minutes)</label>
|
||||
<input id="timeLimitPerLeg" v-model.number="timeLimitPerLeg" type="number" min="1" />
|
||||
<div v-for="(rule, index) in rules" :key="index" class="grid" style="grid-template-columns: 1fr auto;">
|
||||
<label :for="`rule-${index}`">
|
||||
Rule {{ index + 1 }}
|
||||
<input
|
||||
:id="`rule-${index}`"
|
||||
v-model="rules[index]"
|
||||
type="text"
|
||||
placeholder="Enter a game rule..."
|
||||
/>
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
@click="removeRule(index)"
|
||||
class="contrast"
|
||||
style="margin-top: 1.8rem; width: 3rem;"
|
||||
v-if="rules.length > 1"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<label for="timeDeductionPenalty">Navigation Warning Penalty (seconds)</label>
|
||||
<input id="timeDeductionPenalty" v-model.number="timeDeductionPenalty" type="number" min="0" />
|
||||
<button type="button" @click="addRule" class="secondary">
|
||||
+ Add Another Rule
|
||||
</button>
|
||||
|
||||
<div class="grid">
|
||||
<div class="grid" style="margin-top: 2rem;">
|
||||
<button type="submit" :disabled="loading">
|
||||
{{ loading ? 'Creating...' : 'Create Game' }}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -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(() => {
|
|||
|
||||
<template>
|
||||
<main class="container">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ul>
|
||||
<li><strong>Welcome, {{ authStore.user?.name }}</strong></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><button @click="authStore.logout()" class="secondary">Logout</button></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<section>
|
||||
<div class="grid">
|
||||
<h1>My Games</h1>
|
||||
|
|
@ -79,9 +92,13 @@ onMounted(() => {
|
|||
· {{ game._count?.teams || 0 }} teams
|
||||
</small>
|
||||
</footer>
|
||||
<RouterLink :to="`/games/${game.id}`" role="button">View</RouterLink>
|
||||
<RouterLink v-if="game.status === 'DRAFT'" :to="`/games/${game.id}/edit`" role="button" class="secondary">Edit</RouterLink>
|
||||
<RouterLink v-if="game.status === 'LIVE'" :to="`/games/${game.id}/live`" role="button">Live Dashboard</RouterLink>
|
||||
<div class="card-actions">
|
||||
<RouterLink :to="`/games/${game.id}`" role="button">View</RouterLink>
|
||||
<RouterLink v-if="game.status === 'DRAFT'" :to="`/games/${game.id}/edit`" role="button" class="secondary">Edit</RouterLink>
|
||||
<RouterLink v-if="game.status === 'LIVE'" :to="`/games/${game.id}/live`" role="button">Live</RouterLink>
|
||||
<button v-if="game.status === 'ENDED'" @click="archiveGame(game.id)" class="secondary">Archive</button>
|
||||
<button v-if="game.status === 'ARCHIVED'" @click="unarchiveGame(game.id)" class="secondary">Unarchive</button>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -99,4 +116,11 @@ onMounted(() => {
|
|||
.status.live { background: var(--pico-ins-background-color); }
|
||||
.status.ended { background: var(--pico-muted-color); color: var(--pico-muted-border-color); }
|
||||
.status.archived { background: var(--pico-muted-color); color: var(--pico-muted-border-color); }
|
||||
|
||||
.card-actions {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -196,7 +196,10 @@ onUnmounted(() => {
|
|||
<p><small>Total route distance: {{ getTotalDistance().toFixed(2) }} km</small></p>
|
||||
|
||||
<article v-if="legs.length" v-for="(leg, index) in legs" :key="leg.id">
|
||||
<h3>Leg {{ index + 1 }}</h3>
|
||||
<div class="leg-header">
|
||||
<h3>Leg {{ index + 1 }}</h3>
|
||||
<button @click="deleteLeg(leg.id)" class="secondary">Delete</button>
|
||||
</div>
|
||||
<p>{{ leg.description }}</p>
|
||||
<footer>
|
||||
<small>
|
||||
|
|
@ -207,7 +210,6 @@ onUnmounted(() => {
|
|||
</span>
|
||||
</small>
|
||||
</footer>
|
||||
<button @click="deleteLeg(leg.id)" class="secondary">Delete</button>
|
||||
</article>
|
||||
<p v-else>No legs added yet</p>
|
||||
</article>
|
||||
|
|
@ -265,4 +267,15 @@ onUnmounted(() => {
|
|||
border-radius: var(--pico-border-radius);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.leg-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.leg-header h3 {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -145,15 +145,16 @@ onMounted(() => {
|
|||
|
||||
<dt>Search Radius</dt>
|
||||
<dd>{{ game.searchRadius || 500 }} meters</dd>
|
||||
|
||||
<dt>Time Limit per Leg</dt>
|
||||
<dd>{{ game.timeLimitPerLeg || 30 }} minutes</dd>
|
||||
|
||||
<dt>Time Deduction Penalty</dt>
|
||||
<dd>{{ game.timeDeductionPenalty || 60 }} seconds</dd>
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
<section v-if="game.rules?.length">
|
||||
<h2>Rules</h2>
|
||||
<ul>
|
||||
<li v-for="(rule, index) in game.rules" :key="index">{{ rule }}</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section v-if="game.legs?.length">
|
||||
<h2>Legs ({{ game.legs.length }})</h2>
|
||||
<table>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue