fix(opus): wrong frontend ordering points -> rank-points
This commit is contained in:
parent
3e04f8312a
commit
779393106d
@ -126,17 +126,10 @@ const goHome = () => {
|
|||||||
<h1 class="text-xl font-bold">Opus Magnum Puzzle Submitter</h1>
|
<h1 class="text-xl font-bold">Opus Magnum Puzzle Submitter</h1>
|
||||||
<div class="flex-1"></div>
|
<div class="flex-1"></div>
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-4">
|
||||||
<div
|
<div v-if="userInfo?.is_authenticated" class="flex items-center gap-2">
|
||||||
v-if="userInfo?.is_authenticated"
|
|
||||||
class="flex items-center gap-2"
|
|
||||||
>
|
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<span class="font-medium">{{ userInfo.username }}</span>
|
<span class="font-medium">{{ userInfo.username }}</span>
|
||||||
<span
|
<span v-if="userInfo.is_superuser" class="badge badge-warning badge-xs ml-1">Admin</span>
|
||||||
v-if="userInfo.is_superuser"
|
|
||||||
class="badge badge-warning badge-xs ml-1"
|
|
||||||
>Admin</span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="text-sm text-base-content/70">Not logged in</div>
|
<div v-else class="text-sm text-base-content/70">Not logged in</div>
|
||||||
@ -158,10 +151,7 @@ const goHome = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="isLoading" class="flex justify-center items-center min-h-[400px]">
|
||||||
v-if="isLoading"
|
|
||||||
class="flex justify-center items-center min-h-[400px]"
|
|
||||||
>
|
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<span class="loading loading-spinner loading-lg"></span>
|
<span class="loading loading-spinner loading-lg"></span>
|
||||||
<p class="mt-4 text-base-content/70">Loading puzzles...</p>
|
<p class="mt-4 text-base-content/70">Loading puzzles...</p>
|
||||||
@ -210,12 +200,8 @@ const goHome = () => {
|
|||||||
|
|
||||||
<!-- Puzzles Grid -->
|
<!-- Puzzles Grid -->
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
<PuzzleCard
|
<PuzzleCard v-for="puzzle in puzzlesStore.puzzles" :key="puzzle.id" :puzzle="puzzle"
|
||||||
v-for="puzzle in puzzlesStore.puzzles"
|
:responses="responsesByPuzzle[puzzle.id] || []" />
|
||||||
:key="puzzle.id"
|
|
||||||
:puzzle="puzzle"
|
|
||||||
:responses="responsesByPuzzle[puzzle.id] || []"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Empty State -->
|
<!-- Empty State -->
|
||||||
@ -234,18 +220,12 @@ const goHome = () => {
|
|||||||
<div class="modal-box max-w-6xl">
|
<div class="modal-box max-w-6xl">
|
||||||
<div class="flex justify-between items-center mb-4">
|
<div class="flex justify-between items-center mb-4">
|
||||||
<h3 class="font-bold text-lg">Submit Solution</h3>
|
<h3 class="font-bold text-lg">Submit Solution</h3>
|
||||||
<button
|
<button @click="closeSubmissionModal" class="btn btn-sm btn-circle btn-ghost">
|
||||||
@click="closeSubmissionModal"
|
|
||||||
class="btn btn-sm btn-circle btn-ghost"
|
|
||||||
>
|
|
||||||
<i class="mdi mdi-close"></i>
|
<i class="mdi mdi-close"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SubmissionForm
|
<SubmissionForm :puzzles="puzzlesStore.puzzles" :find-puzzle-by-name="findPuzzleByName" />
|
||||||
:puzzles="puzzlesStore.puzzles"
|
|
||||||
:find-puzzle-by-name="findPuzzleByName"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-backdrop" @click="closeSubmissionModal"></div>
|
<div class="modal-backdrop" @click="closeSubmissionModal"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -101,7 +101,7 @@ const getPuzzleRanking = (puzzleId: number) => {
|
|||||||
points: response.points,
|
points: response.points,
|
||||||
rank_points: response.rank_points || 0,
|
rank_points: response.rank_points || 0,
|
||||||
};
|
};
|
||||||
});
|
}).reverse();
|
||||||
};
|
};
|
||||||
|
|
||||||
const togglePuzzleExpanded = (puzzleId: number) => {
|
const togglePuzzleExpanded = (puzzleId: number) => {
|
||||||
@ -186,7 +186,7 @@ onMounted(() => {
|
|||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<p class="text-sm text-base-content/70 mb-1">Current Rank</p>
|
<p class="text-sm text-base-content/70 mb-1">Current Rank</p>
|
||||||
<p v-if="userInfo.rank !== null" class="text-4xl font-bold text-primary">
|
<p v-if="userInfo.rank !== null" class="text-4xl font-bold text-primary">
|
||||||
#{{ userInfo.rank }}
|
<RankBadge :rank="userInfo.rank" />
|
||||||
</p>
|
</p>
|
||||||
<p v-else class="text-2xl text-base-content/50">No rank yet</p>
|
<p v-else class="text-2xl text-base-content/50">No rank yet</p>
|
||||||
</div>
|
</div>
|
||||||
@ -223,158 +223,162 @@ onMounted(() => {
|
|||||||
<span class="loading loading-spinner loading-lg"></span>
|
<span class="loading loading-spinner loading-lg"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="!resultsData" class="text-center py-8">
|
<div v-else-if="!resultsData" class="text-center py-8">
|
||||||
<p class="text-base-content/70">No results available yet</p>
|
<p class="text-base-content/70">No results available yet</p>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-else class="space-y-6">
|
|
||||||
<!-- Tabs -->
|
|
||||||
<div class="tabs tabs-boxed">
|
|
||||||
<button @click="selectedTab = 'overall'" :class="[
|
|
||||||
'tab',
|
|
||||||
selectedTab === 'overall' ? 'tab-active' : '',
|
|
||||||
]">
|
|
||||||
<i class="mdi mdi-chart-line mr-2"></i>
|
|
||||||
Overall Ranking
|
|
||||||
</button>
|
|
||||||
<button @click="selectedTab = 'byPuzzle'" :class="[
|
|
||||||
'tab',
|
|
||||||
selectedTab === 'byPuzzle' ? 'tab-active' : '',
|
|
||||||
]">
|
|
||||||
<i class="mdi mdi-puzzle mr-2"></i>
|
|
||||||
By Puzzle
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Overall Ranking -->
|
|
||||||
<div v-show="selectedTab === 'overall'" class="space-y-4">
|
|
||||||
<div v-if="getOverallRanking().length === 0" class="text-center py-8">
|
|
||||||
<p class="text-base-content/70">No submissions yet</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="overflow-x-auto">
|
<div v-else class="space-y-6">
|
||||||
<table class="table table-zebra w-full">
|
<!-- Tabs -->
|
||||||
<thead>
|
<div class="tabs tabs-boxed">
|
||||||
<tr>
|
<button @click="selectedTab = 'overall'" :class="[
|
||||||
<th>Rank</th>
|
'tab',
|
||||||
<th>Player</th>
|
selectedTab === 'overall' ? 'tab-active' : '',
|
||||||
<th class="text-right">Puzzles Solved</th>
|
]">
|
||||||
<th class="text-right">Total Points</th>
|
<i class="mdi mdi-chart-line mr-2"></i>
|
||||||
</tr>
|
Overall Ranking
|
||||||
</thead>
|
</button>
|
||||||
<tbody>
|
<button @click="selectedTab = 'byPuzzle'" :class="[
|
||||||
<tr v-for="(user, index) in getOverallRanking()" :key="user.username">
|
'tab',
|
||||||
<td class="font-bold">
|
selectedTab === 'byPuzzle' ? 'tab-active' : '',
|
||||||
<RankBadge :rank="index + 1" />
|
]">
|
||||||
</td>
|
<i class="mdi mdi-puzzle mr-2"></i>
|
||||||
<td class="font-medium">{{ user.username }}</td>
|
By Puzzle
|
||||||
<td class="text-right">{{ user.puzzlesSolved }}</td>
|
</button>
|
||||||
<td class="text-right font-bold">{{ user.totalPoints }}</td>
|
</div>
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- By Puzzle Ranking -->
|
<!-- Overall Ranking -->
|
||||||
<div v-show="selectedTab === 'byPuzzle'" class="space-y-6">
|
<div v-show="selectedTab === 'overall'" class="space-y-4">
|
||||||
<div v-for="puzzle in resultsData.puzzles" :key="puzzle.id" class="card bg-base-100 border border-base-300">
|
<div v-if="getOverallRanking().length === 0" class="text-center py-8">
|
||||||
<button @click="togglePuzzleExpanded(puzzle.id)"
|
<p class="text-base-content/70">No submissions yet</p>
|
||||||
class="btn btn-ghost btn-lg w-full justify-start text-lg font-bold hover:bg-primary/20 rounded-b-none">
|
|
||||||
<i :class="['mdi mr-2', expandedPuzzleId === puzzle.id ? 'mdi-chevron-down' : 'mdi-chevron-right']"></i>
|
|
||||||
{{ puzzle.title }}
|
|
||||||
<span class="ml-auto badge badge-sm">
|
|
||||||
{{ getPuzzleRanking(puzzle.id).length }} submissions
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- Expanded Details -->
|
|
||||||
<div v-if="expandedPuzzleId === puzzle.id" class="card-body">
|
|
||||||
<div v-if="getPuzzleRanking(puzzle.id).length === 0" class="text-center py-8">
|
|
||||||
<p class="text-base-content/70 text-lg">No submissions yet</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="space-y-6">
|
<div v-else class="overflow-x-auto">
|
||||||
<!-- Top 3 Podium -->
|
<table class="table table-zebra w-full">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
<thead>
|
||||||
<div v-for="(response, index) in getPuzzleRanking(puzzle.id).slice(0, 3)" :key="index"
|
<tr>
|
||||||
class="card bg-base-200">
|
<th>Rank</th>
|
||||||
<div class="card-body p-4">
|
<th>Player</th>
|
||||||
<div class="text-xs text-base-content/70 font-bold">
|
<th class="text-right">Puzzles Solved</th>
|
||||||
{{ index === 0 ? '🏆 1st Place' : index === 1 ? '🥈 2nd Place' : '🥉 3rd Place' }}
|
<th class="text-right">Total Points</th>
|
||||||
</div>
|
</tr>
|
||||||
<h4 class="font-bold text-lg">{{ response.username }}</h4>
|
</thead>
|
||||||
<div class="divider my-2"></div>
|
<tbody>
|
||||||
<div class="space-y-2 text-sm">
|
<tr v-for="(user, index) in getOverallRanking()" :key="user.username">
|
||||||
<div class="flex justify-between">
|
<td class="font-bold">
|
||||||
<span>Cost</span>
|
<RankBadge :rank="index + 1" />
|
||||||
<span class="badge badge-sm">{{ response.cost || 'N/A' }}</span>
|
</td>
|
||||||
</div>
|
<td class="font-medium">{{ user.username }}</td>
|
||||||
<div class="flex justify-between">
|
<td class="text-right">{{ user.puzzlesSolved }}</td>
|
||||||
<span>Cycles</span>
|
<td class="text-right font-bold">{{ user.totalPoints }}</td>
|
||||||
<span class="badge badge-sm">{{ response.cycles || 'N/A' }}</span>
|
</tr>
|
||||||
</div>
|
</tbody>
|
||||||
<div class="flex justify-between">
|
</table>
|
||||||
<span>Area</span>
|
</div>
|
||||||
<span class="badge badge-sm">{{ response.area || 'N/A' }}</span>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="flex justify-between pt-2 border-t">
|
<!-- By Puzzle Ranking -->
|
||||||
<span>Total (with coef.)</span>
|
<div v-show="selectedTab === 'byPuzzle'" class="space-y-6">
|
||||||
<span class="badge badge-sm">{{ response.points || 'N/A' }}</span>
|
<div v-for="puzzle in resultsData.puzzles" :key="puzzle.id"
|
||||||
</div>
|
class="card bg-base-100 border border-base-300">
|
||||||
<div class="flex justify-between pt-2 border-t">
|
<button @click="togglePuzzleExpanded(puzzle.id)"
|
||||||
<span class="font-bold">Points</span>
|
class="btn btn-ghost btn-lg w-full justify-start text-lg font-bold hover:bg-primary/20 rounded-b-none">
|
||||||
<span class="badge badge-primary">{{ response.rank_points }} pts</span>
|
<i
|
||||||
|
:class="['mdi mr-2', expandedPuzzleId === puzzle.id ? 'mdi-chevron-down' : 'mdi-chevron-right']"></i>
|
||||||
|
{{ puzzle.title }}
|
||||||
|
<span class="ml-auto badge badge-sm">
|
||||||
|
{{ getPuzzleRanking(puzzle.id).length }} submissions
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Expanded Details -->
|
||||||
|
<div v-if="expandedPuzzleId === puzzle.id" class="card-body">
|
||||||
|
<div v-if="getPuzzleRanking(puzzle.id).length === 0" class="text-center py-8">
|
||||||
|
<p class="text-base-content/70 text-lg">No submissions yet</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="space-y-6">
|
||||||
|
<!-- Top 3 Podium -->
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||||
|
<div v-for="(response, index) in getPuzzleRanking(puzzle.id).slice(0, 3)" :key="index"
|
||||||
|
class="card bg-base-200">
|
||||||
|
<div class="card-body p-4">
|
||||||
|
<div class="text-xs text-base-content/70 font-bold">
|
||||||
|
{{ index === 0 ? '🏆 1st Place' : index === 1 ? '🥈 2nd Place' : '🥉 3rd Place' }}
|
||||||
|
</div>
|
||||||
|
<h4 class="font-bold text-lg">{{ response.username }}</h4>
|
||||||
|
<div class="divider my-2"></div>
|
||||||
|
<div class="space-y-2 text-sm">
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span>Cost</span>
|
||||||
|
<span class="badge badge-sm">{{ response.cost || 'N/A' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span>Cycles</span>
|
||||||
|
<span class="badge badge-sm">{{ response.cycles || 'N/A' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span>Area</span>
|
||||||
|
<span class="badge badge-sm">{{ response.area || 'N/A' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between pt-2 border-t">
|
||||||
|
<span>Total (with coef.)</span>
|
||||||
|
<span class="badge badge-sm">{{ response.points || 'N/A' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between pt-2 border-t">
|
||||||
|
<span class="font-bold">Points</span>
|
||||||
|
<span class="badge badge-primary">{{ response.rank_points }} pts</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Full Ranking Table -->
|
<!-- Full Ranking Table -->
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table table-zebra w-full table-sm">
|
<table class="table table-zebra w-full table-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="w-12">Rank</th>
|
<th class="w-12">Rank</th>
|
||||||
<th>Player</th>
|
<th>Player</th>
|
||||||
<th class="text-center">Cost</th>
|
<th class="text-center">Cost</th>
|
||||||
<th class="text-center">Cycles</th>
|
<th class="text-center">Cycles</th>
|
||||||
<th class="text-center">Area</th>
|
<th class="text-center">Area</th>
|
||||||
<th class="text-center">Total (with coef.)</th>
|
<th class="text-center">Total (with coef.)</th>
|
||||||
<th class="text-right">Points</th>
|
<th class="text-right">Points</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(response, index) in getPuzzleRanking(puzzle.id)" :key="index"
|
<tr v-for="(response, index) in getPuzzleRanking(puzzle.id)" :key="index"
|
||||||
:class="{ 'bg-primary/10': index < 3 }">
|
:class="{ 'bg-primary/10': index < 3 }">
|
||||||
<td class="font-bold">
|
<td class="font-bold">
|
||||||
<span v-if="index === 0" class="badge badge-warning">🏆</span>
|
<span v-if="index === 0" class="badge badge-warning">🏆</span>
|
||||||
<span v-else-if="index === 1" class="badge">🥈</span>
|
<span v-else-if="index === 1" class="badge">🥈</span>
|
||||||
<span v-else-if="index === 2" class="badge">🥉</span>
|
<span v-else-if="index === 2" class="badge">🥉</span>
|
||||||
<span v-else>#{{ index + 1 }}</span>
|
<span v-else>#{{ index + 1 }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="font-medium">{{ response.username }}</td>
|
<td class="font-medium">{{ response.username }}</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<span v-if="response.cost" class="badge badge-sm">{{ response.cost }}</span>
|
<span v-if="response.cost" class="badge badge-sm">{{ response.cost }}</span>
|
||||||
<span v-else class="text-base-content/40">—</span>
|
<span v-else class="text-base-content/40">—</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<span v-if="response.cycles" class="badge badge-sm">{{ response.cycles }}</span>
|
<span v-if="response.cycles" class="badge badge-sm">{{ response.cycles }}</span>
|
||||||
<span v-else class="text-base-content/40">—</span>
|
<span v-else class="text-base-content/40">—</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<span v-if="response.area" class="badge badge-sm">{{ response.area }}</span>
|
<span v-if="response.area" class="badge badge-sm">{{ response.area }}</span>
|
||||||
<span v-else class="text-base-content/40">—</span>
|
<span v-else class="text-base-content/40">—</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<span v-if="response.points" class="badge badge-sm">{{ response.points }}</span>
|
<span v-if="response.points" class="badge badge-sm">{{ response.points }}</span>
|
||||||
<span v-else class="text-base-content/40">—</span>
|
<span v-else class="text-base-content/40">—</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-right font-bold text-primary text-lg">{{ response.rank_points }}</td>
|
<td class="text-right font-bold text-primary text-lg">{{ response.rank_points }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -382,8 +386,6 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user