91 lines
2.9 KiB
Vue
91 lines
2.9 KiB
Vue
<script setup lang="ts">
|
|
import { computed, onMounted, ref } from "vue";
|
|
import { useRouter } from "vue-router";
|
|
import { useI18n } from "vue-i18n";
|
|
import { useTitle } from "@vueuse/core";
|
|
import { gamesApiListEventGames, submissionsApiListAvailableScopes } from "@/api";
|
|
import type { ScopeOut } from "@/api/types.gen";
|
|
|
|
interface Props {
|
|
eventPath: string;
|
|
gamePath: string;
|
|
}
|
|
|
|
const props = defineProps<Props>();
|
|
|
|
const router = useRouter();
|
|
const { t } = useI18n();
|
|
useTitle(computed(() => t("submissionsSelect.title")));
|
|
|
|
const gameName = ref("");
|
|
const scopes = ref<ScopeOut[]>([]);
|
|
const loading = ref(true);
|
|
const notAssigned = ref(false);
|
|
|
|
const scopeRoute = (scope: ScopeOut) => ({
|
|
name: "submissions",
|
|
params: { eventPath: props.eventPath, gamePath: props.gamePath, scopeId: scope.id },
|
|
});
|
|
|
|
const goToScope = (scope: ScopeOut) => {
|
|
router.push(scopeRoute(scope));
|
|
};
|
|
|
|
onMounted(async () => {
|
|
const [gamesResponse, scopesResponse] = await Promise.all([
|
|
gamesApiListEventGames({ path: { event_path: props.eventPath } }),
|
|
submissionsApiListAvailableScopes({
|
|
path: { event_path: props.eventPath, game_path: props.gamePath },
|
|
}),
|
|
]);
|
|
|
|
gameName.value = gamesResponse.data?.find((game) => game.path === props.gamePath)?.name ?? "";
|
|
|
|
const availableScopes = scopesResponse.data ?? [];
|
|
|
|
// Mirrors the server-side behavior this replaced: skip the picker
|
|
// straight to the only option, or bounce out if there's nothing to pick.
|
|
if (availableScopes.length === 1) {
|
|
router.replace(scopeRoute(availableScopes[0]));
|
|
return;
|
|
}
|
|
if (availableScopes.length === 0) {
|
|
notAssigned.value = true;
|
|
loading.value = false;
|
|
return;
|
|
}
|
|
|
|
scopes.value = availableScopes;
|
|
loading.value = false;
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="flex-1 bg-base-200 flex items-center justify-center p-4">
|
|
<div v-if="loading" class="flex justify-center py-20">
|
|
<span class="loading loading-spinner loading-lg"></span>
|
|
</div>
|
|
<div v-else-if="notAssigned" class="text-center max-w-md">
|
|
<i class="mdi mdi-account-alert-outline text-6xl text-warning"></i>
|
|
<h2 class="text-2xl font-semibold mt-4">{{ t("submissionsSelect.notAssignedTitle") }}</h2>
|
|
<p class="text-base-content/70 mt-2">{{ t("submissionsSelect.notAssignedMessage") }}</p>
|
|
</div>
|
|
<div v-else class="card bg-base-100 shadow-lg w-full max-w-md">
|
|
<div class="card-body">
|
|
<h2 class="card-title">{{ t("submissionsSelect.title") }}</h2>
|
|
<p class="text-base-content/70 mb-2">
|
|
{{ t("submissionsSelect.description", { game: gameName }) }}
|
|
</p>
|
|
|
|
<div class="flex flex-col gap-2 mt-2">
|
|
<button v-for="scope in scopes" :key="scope.id" @click="goToScope(scope)"
|
|
class="btn btn-outline justify-start">
|
|
<i class="mdi mdi-sword-cross mr-2"></i>
|
|
{{ scope.name }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|