feat: switch to spa

This commit is contained in:
2026-09-17 00:56:17 +02:00
parent 15590e5162
commit d104480188
23 changed files with 327 additions and 171 deletions
+43 -19
View File
@@ -1,35 +1,35 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, computed } from "vue";
import { useRouter } from "vue-router";
import { storeToRefs } from "pinia";
import { useI18n } from "vue-i18n";
import { useTitle } from "@vueuse/core";
import { useUserStore } from "@/stores/user";
import { submissionsApiCreateSubmission, submissionsApiListUserSubmissions, submissionsApiCreateImageCrop, submissionsApiDeleteImageCrop, submissionsApiProcessFileOcr, submissionsApiProcessCropOcr } from "@/api";
import { usePageHeaderStore } from "@/stores/pageHeader";
import { gamesApiListEventGames, submissionsApiListAvailableScopes, submissionsApiCreateSubmission, submissionsApiListUserSubmissions, submissionsApiCreateImageCrop, submissionsApiDeleteImageCrop, submissionsApiProcessFileOcr, submissionsApiProcessCropOcr } from "@/api";
import { useSubmissionsWebSocket } from "@/composables/useSubmissionsWebSocket";
import { provideEventPath } from "@/composables/useEventPath";
interface Props {
eventPath: string;
gamePath: string;
scopeId: string;
scopeName?: string;
gameName?: string;
gamePath?: string;
gameImage?: string;
gameSteamId?: string;
}
const props = withDefaults(defineProps<Props>(), {
scopeName: "Match",
gameName: "Game",
gamePath: "",
gameImage: "",
gameSteamId: "",
});
const props = defineProps<Props>();
provideEventPath(props.eventPath);
const router = useRouter();
const { t } = useI18n();
useTitle(computed(() => t("submissions.pageTitle", { game: props.gameName, scope: props.scopeName })));
const pageHeaderStore = usePageHeaderStore();
const scopeName = ref("Match");
const gameName = ref("Game");
const gameImage = ref("");
const gameSteamId = ref("");
useTitle(computed(() => t("submissions.pageTitle", { game: gameName.value, scope: scopeName.value })));
const userStore = useUserStore();
const { userInfo } = storeToRefs(userStore);
@@ -333,11 +333,11 @@ const processCropOcr = async (cropId: string) => {
};
const getGameHeaderImage = () => {
if (props.gameImage) {
return props.gameImage;
if (gameImage.value) {
return gameImage.value;
}
if (props.gameSteamId) {
return `https://cdn.akamai.steamstatic.com/steam/apps/${props.gameSteamId}/header.jpg`;
if (gameSteamId.value) {
return `https://cdn.akamai.steamstatic.com/steam/apps/${gameSteamId.value}/header.jpg`;
}
return null;
};
@@ -502,10 +502,34 @@ const handlePasteOnUploadArea = (event: ClipboardEvent) => {
}
};
onMounted(() => {
onMounted(async () => {
userStore.loadUserData();
loadUserSubmissions();
const [gamesResponse, scopesResponse] = await Promise.all([
gamesApiListEventGames({ path: { event_path: props.eventPath } }),
submissionsApiListAvailableScopes({
path: { event_path: props.eventPath, game_path: props.gamePath },
}),
]);
const game = gamesResponse.data?.find((g) => g.path === props.gamePath);
if (game) {
gameName.value = game.name;
gameImage.value = game.image ?? "";
gameSteamId.value = game.steam_app_id ? String(game.steam_app_id) : "";
}
const scope = scopesResponse.data?.find((s) => s.id === props.scopeId);
if (!scope) {
// Not in the list of scopes this user may access - bounce back to
// the picker rather than rendering a page for data we can't show.
router.replace({ name: "submissions-select", params: { eventPath: props.eventPath, gamePath: props.gamePath } });
return;
}
scopeName.value = scope.name;
pageHeaderStore.setTitle(t("submissions.pageTitle", { game: gameName.value, scope: scopeName.value }));
// Add paste listener (only processes if hovering upload area)
window.addEventListener('paste', handlePasteOnUploadArea);
});