fix: use vue-query; make less useless api call
This commit is contained in:
@@ -3,4 +3,5 @@ import { defineConfig } from '@hey-api/openapi-ts';
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
input: `http://localhost:7777/api/openapi.json`,
|
input: `http://localhost:7777/api/openapi.json`,
|
||||||
output: 'src/api/',
|
output: 'src/api/',
|
||||||
|
plugins: ['@hey-api/typescript', '@hey-api/sdk', '@tanstack/vue-query'],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,6 +12,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/vite": "^4.1.16",
|
"@tailwindcss/vite": "^4.1.16",
|
||||||
|
"@tanstack/query-persist-client-core": "^5.104.3",
|
||||||
|
"@tanstack/query-sync-storage-persister": "^5.104.3",
|
||||||
|
"@tanstack/vue-query": "^5.104.3",
|
||||||
"@tanstack/vue-table": "^8.21.3",
|
"@tanstack/vue-table": "^8.21.3",
|
||||||
"@vueuse/core": "^14.0.0",
|
"@vueuse/core": "^14.0.0",
|
||||||
"dayjs": "^1.11.20",
|
"dayjs": "^1.11.20",
|
||||||
|
|||||||
Generated
+74
@@ -11,6 +11,15 @@ importers:
|
|||||||
'@tailwindcss/vite':
|
'@tailwindcss/vite':
|
||||||
specifier: ^4.1.16
|
specifier: ^4.1.16
|
||||||
version: 4.1.16(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.4))
|
version: 4.1.16(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.4))
|
||||||
|
'@tanstack/query-persist-client-core':
|
||||||
|
specifier: ^5.104.3
|
||||||
|
version: 5.104.3
|
||||||
|
'@tanstack/query-sync-storage-persister':
|
||||||
|
specifier: ^5.104.3
|
||||||
|
version: 5.104.3
|
||||||
|
'@tanstack/vue-query':
|
||||||
|
specifier: ^5.104.3
|
||||||
|
version: 5.104.3(vue@3.5.22(typescript@5.9.3))
|
||||||
'@tanstack/vue-table':
|
'@tanstack/vue-table':
|
||||||
specifier: ^8.21.3
|
specifier: ^8.21.3
|
||||||
version: 8.21.3(vue@3.5.22(typescript@5.9.3))
|
version: 8.21.3(vue@3.5.22(typescript@5.9.3))
|
||||||
@@ -515,10 +524,32 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: ^5.2.0 || ^6 || ^7
|
vite: ^5.2.0 || ^6 || ^7
|
||||||
|
|
||||||
|
'@tanstack/match-sorter-utils@9.2.6':
|
||||||
|
resolution: {integrity: sha512-DIpUSOhPfQ7u/qfUi/Wgm0wBO56MyBYXGvnlI0NcauDRPqdBUlAZZjW2Dxm92m+k1UWVhKw8YJ4f47+75Aujyw==}
|
||||||
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
|
'@tanstack/query-core@5.104.3':
|
||||||
|
resolution: {integrity: sha512-DZY9TuJAOgU3UyHUhXb4CcTYEHNZszlwkPg4VViIwTxOKzLprPUU+rbaPZQd3srqkGOtpaDdKpW972UV/LKlcg==}
|
||||||
|
|
||||||
|
'@tanstack/query-persist-client-core@5.104.3':
|
||||||
|
resolution: {integrity: sha512-6nhc/QbMpkKeuAM81SFSdcsJ9B8dm3fGHPODbau2cRSDyqcXiSl7sXQM7POVktch/YdgIGYPIQyZOQQaRarHMA==}
|
||||||
|
|
||||||
|
'@tanstack/query-sync-storage-persister@5.104.3':
|
||||||
|
resolution: {integrity: sha512-sNM9X7QZdTHBlzHuNxuHQjECn3/zncuMgw5pesOFXu8XQ01UXBGASdMKZSRaxfNOhigRjm5souHhfmByN97NEg==}
|
||||||
|
|
||||||
'@tanstack/table-core@8.21.3':
|
'@tanstack/table-core@8.21.3':
|
||||||
resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==}
|
resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
'@tanstack/vue-query@5.104.3':
|
||||||
|
resolution: {integrity: sha512-bdVlhyEFPllLfHioHx8kwtCAQ1YJQrvYczlsNzyiYFsp6n5yz9isNXiy6MIu+QGmG+RyghVdnp1UmiNDqLS22g==}
|
||||||
|
peerDependencies:
|
||||||
|
'@vue/composition-api': ^1.1.2
|
||||||
|
vue: ^2.6.0 || ^3.3.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@vue/composition-api':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@tanstack/vue-table@8.21.3':
|
'@tanstack/vue-table@8.21.3':
|
||||||
resolution: {integrity: sha512-rusRyd77c5tDPloPskctMyPLFEQUeBzxdQ+2Eow4F7gDPlPOB1UnnhzfpdvqZ8ZyX2rRNGmqNnQWm87OI2OQPw==}
|
resolution: {integrity: sha512-rusRyd77c5tDPloPskctMyPLFEQUeBzxdQ+2Eow4F7gDPlPOB1UnnhzfpdvqZ8ZyX2rRNGmqNnQWm87OI2OQPw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@@ -961,6 +992,9 @@ packages:
|
|||||||
regenerator-runtime@0.13.11:
|
regenerator-runtime@0.13.11:
|
||||||
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
|
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
|
||||||
|
|
||||||
|
remove-accents@0.5.0:
|
||||||
|
resolution: {integrity: sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==}
|
||||||
|
|
||||||
resolve-pkg-maps@1.0.0:
|
resolve-pkg-maps@1.0.0:
|
||||||
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
|
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
|
||||||
|
|
||||||
@@ -1072,6 +1106,17 @@ packages:
|
|||||||
vscode-uri@3.1.0:
|
vscode-uri@3.1.0:
|
||||||
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
|
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
|
||||||
|
|
||||||
|
vue-demi@0.14.10:
|
||||||
|
resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
'@vue/composition-api': ^1.0.0-rc.1
|
||||||
|
vue: ^3.0.0-0 || ^2.6.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@vue/composition-api':
|
||||||
|
optional: true
|
||||||
|
|
||||||
vue-i18n@11.4.12:
|
vue-i18n@11.4.12:
|
||||||
resolution: {integrity: sha512-yvArvvo3ErLKFNlQrZUGmRkxL/ctM5xFYtE9FxTKiE/PalWP1bnTopBgbSRGLluYEyYSNl1Pt8l2J7zVavbXww==}
|
resolution: {integrity: sha512-yvArvvo3ErLKFNlQrZUGmRkxL/ctM5xFYtE9FxTKiE/PalWP1bnTopBgbSRGLluYEyYSNl1Pt8l2J7zVavbXww==}
|
||||||
engines: {node: '>= 22'}
|
engines: {node: '>= 22'}
|
||||||
@@ -1445,8 +1490,31 @@ snapshots:
|
|||||||
tailwindcss: 4.1.16
|
tailwindcss: 4.1.16
|
||||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.4)
|
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.4)
|
||||||
|
|
||||||
|
'@tanstack/match-sorter-utils@9.2.6':
|
||||||
|
dependencies:
|
||||||
|
remove-accents: 0.5.0
|
||||||
|
|
||||||
|
'@tanstack/query-core@5.104.3': {}
|
||||||
|
|
||||||
|
'@tanstack/query-persist-client-core@5.104.3':
|
||||||
|
dependencies:
|
||||||
|
'@tanstack/query-core': 5.104.3
|
||||||
|
|
||||||
|
'@tanstack/query-sync-storage-persister@5.104.3':
|
||||||
|
dependencies:
|
||||||
|
'@tanstack/query-core': 5.104.3
|
||||||
|
'@tanstack/query-persist-client-core': 5.104.3
|
||||||
|
|
||||||
'@tanstack/table-core@8.21.3': {}
|
'@tanstack/table-core@8.21.3': {}
|
||||||
|
|
||||||
|
'@tanstack/vue-query@5.104.3(vue@3.5.22(typescript@5.9.3))':
|
||||||
|
dependencies:
|
||||||
|
'@tanstack/match-sorter-utils': 9.2.6
|
||||||
|
'@tanstack/query-core': 5.104.3
|
||||||
|
'@vue/devtools-api': 6.6.4
|
||||||
|
vue: 3.5.22(typescript@5.9.3)
|
||||||
|
vue-demi: 0.14.10(vue@3.5.22(typescript@5.9.3))
|
||||||
|
|
||||||
'@tanstack/vue-table@8.21.3(vue@3.5.22(typescript@5.9.3))':
|
'@tanstack/vue-table@8.21.3(vue@3.5.22(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tanstack/table-core': 8.21.3
|
'@tanstack/table-core': 8.21.3
|
||||||
@@ -1863,6 +1931,8 @@ snapshots:
|
|||||||
|
|
||||||
regenerator-runtime@0.13.11: {}
|
regenerator-runtime@0.13.11: {}
|
||||||
|
|
||||||
|
remove-accents@0.5.0: {}
|
||||||
|
|
||||||
resolve-pkg-maps@1.0.0: {}
|
resolve-pkg-maps@1.0.0: {}
|
||||||
|
|
||||||
rfdc@1.4.1: {}
|
rfdc@1.4.1: {}
|
||||||
@@ -1962,6 +2032,10 @@ snapshots:
|
|||||||
|
|
||||||
vscode-uri@3.1.0: {}
|
vscode-uri@3.1.0: {}
|
||||||
|
|
||||||
|
vue-demi@0.14.10(vue@3.5.22(typescript@5.9.3)):
|
||||||
|
dependencies:
|
||||||
|
vue: 3.5.22(typescript@5.9.3)
|
||||||
|
|
||||||
vue-i18n@11.4.12(vue@3.5.22(typescript@5.9.3)):
|
vue-i18n@11.4.12(vue@3.5.22(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@intlify/core-base': 11.4.12
|
'@intlify/core-base': 11.4.12
|
||||||
|
|||||||
@@ -1,20 +1,14 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted } from "vue";
|
import { computed } from "vue";
|
||||||
import { RouterView, useRoute } from "vue-router";
|
import { RouterView, useRoute } from "vue-router";
|
||||||
import AppHeader from "@/layout/AppHeader.vue";
|
import AppHeader from "@/layout/AppHeader.vue";
|
||||||
import AppFooter from "@/layout/AppFooter.vue";
|
import AppFooter from "@/layout/AppFooter.vue";
|
||||||
import { useUserStore } from "@/stores/user";
|
|
||||||
|
|
||||||
const userStore = useUserStore();
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
// Embed routes (e.g. place/embed) are meant to be dropped into an <iframe>
|
// Embed routes (e.g. place/embed) are meant to be dropped into an <iframe>
|
||||||
// as-is - the header/footer chrome would just eat into the fixed space a
|
// as-is - the header/footer chrome would just eat into the fixed space a
|
||||||
// stream overlay or OBS browser source gives it.
|
// stream overlay or OBS browser source gives it.
|
||||||
const isEmbed = computed(() => route.meta.embed === true);
|
const isEmbed = computed(() => route.meta.embed === true);
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
userStore.loadUserData();
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, computed } from "vue";
|
import { ref, computed } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useTitle } from "@vueuse/core";
|
import { useTitle } from "@vueuse/core";
|
||||||
import { gamesApiListEventGames } from "./api";
|
import { useQuery } from "@tanstack/vue-query";
|
||||||
|
import { eventGamesQuery } from "@/queries";
|
||||||
import type { GamesApiListEventGamesResponse } from "./api/types.gen";
|
import type { GamesApiListEventGamesResponse } from "./api/types.gen";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -16,8 +17,7 @@ const router = useRouter();
|
|||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
useTitle(computed(() => t("home.title")));
|
useTitle(computed(() => t("home.title")));
|
||||||
|
|
||||||
const games = ref<GamesApiListEventGamesResponse | undefined>();
|
const { data: games, isPending: loading } = useQuery(eventGamesQuery(props.eventPath));
|
||||||
const loading = ref(true);
|
|
||||||
const hasSteamGames = computed(() => games.value?.some((game) => game.steam_app_id) ?? false);
|
const hasSteamGames = computed(() => games.value?.some((game) => game.steam_app_id) ?? false);
|
||||||
const imageErrors = ref<Set<number>>(new Set());
|
const imageErrors = ref<Set<number>>(new Set());
|
||||||
|
|
||||||
@@ -40,15 +40,6 @@ const goToGame = (game: GamesApiListEventGamesResponse[number]) => {
|
|||||||
router.push(`/${props.eventPath}${path}`);
|
router.push(`/${props.eventPath}${path}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
const gamesResponse = await gamesApiListEventGames({
|
|
||||||
path: { event_path: props.eventPath },
|
|
||||||
});
|
|
||||||
if (gamesResponse.data) {
|
|
||||||
games.value = gamesResponse.data;
|
|
||||||
}
|
|
||||||
loading.value = false;
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ import Results from "@/components/Results.vue";
|
|||||||
import Winners from "@/components/Winners.vue";
|
import Winners from "@/components/Winners.vue";
|
||||||
import PuzzleResults from "@/components/PuzzleResults.vue";
|
import PuzzleResults from "@/components/PuzzleResults.vue";
|
||||||
import TopUsersLeaderboard from "@/components/TopUsersLeaderboard.vue";
|
import TopUsersLeaderboard from "@/components/TopUsersLeaderboard.vue";
|
||||||
import { polylanSubmitterApiGetUserInfo, opusMagnumApiGetCollection } from "@/api";
|
import { opusMagnumApiGetCollection } from "@/api";
|
||||||
import { apiService, errorHelpers } from "@/services/apiService";
|
import { apiService, errorHelpers } from "@/services/apiService";
|
||||||
import { usePuzzlesStore } from "@/stores/puzzles";
|
import { usePuzzlesStore } from "@/stores/puzzles";
|
||||||
import { useSubmissionsStore } from "@/stores/submissions";
|
import { useSubmissionsStore } from "@/stores/submissions";
|
||||||
|
import { queryClient, userQuery } from "@/queries";
|
||||||
import { provideEventPath } from "@/composables/useEventPath";
|
import { provideEventPath } from "@/composables/useEventPath";
|
||||||
import type { PuzzleResponse, UserInfo, SteamCollection } from "@/types";
|
import type { PuzzleResponse, UserInfo, SteamCollection } from "@/types";
|
||||||
import { useCountdown } from "@vueuse/core";
|
import { useCountdown } from "@vueuse/core";
|
||||||
@@ -74,13 +75,7 @@ async function initialize() {
|
|||||||
|
|
||||||
// Load user info
|
// Load user info
|
||||||
console.log("Loading user info...");
|
console.log("Loading user info...");
|
||||||
const userResponse = await polylanSubmitterApiGetUserInfo();
|
userInfo.value = (await queryClient.fetchQuery(userQuery()).catch(() => null)) as UserInfo | null;
|
||||||
if (userResponse.data) {
|
|
||||||
userInfo.value = userResponse.data as UserInfo;
|
|
||||||
console.log("User info loaded:", userResponse.data);
|
|
||||||
} else if (userResponse.error) {
|
|
||||||
console.warn("User info error:", userResponse.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load collection data
|
// Load collection data
|
||||||
console.log("Loading collection...");
|
console.log("Loading collection...");
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onUnmounted, computed } from "vue";
|
import { ref, onMounted, onUnmounted, computed } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { storeToRefs } from "pinia";
|
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useTitle } from "@vueuse/core";
|
import { useTitle } from "@vueuse/core";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useQueryClient } from "@tanstack/vue-query";
|
||||||
|
import { useUser } from "@/composables/useUser";
|
||||||
|
import { eventGamesQuery } from "@/queries";
|
||||||
import { usePageHeaderStore } from "@/stores/pageHeader";
|
import { usePageHeaderStore } from "@/stores/pageHeader";
|
||||||
import { gamesApiListEventGames, submissionsApiListAvailableScopes, submissionsApiCreateSubmission, submissionsApiListUserSubmissions, submissionsApiCreateImageCrop, submissionsApiDeleteImageCrop, submissionsApiProcessFileOcr, submissionsApiProcessCropOcr } from "@/api";
|
import { submissionsApiListAvailableScopes, submissionsApiCreateSubmission, submissionsApiListUserSubmissions, submissionsApiCreateImageCrop, submissionsApiDeleteImageCrop, submissionsApiProcessFileOcr, submissionsApiProcessCropOcr } from "@/api";
|
||||||
import { useSubmissionsWebSocket } from "@/composables/useSubmissionsWebSocket";
|
import { useSubmissionsWebSocket } from "@/composables/useSubmissionsWebSocket";
|
||||||
import { provideEventPath } from "@/composables/useEventPath";
|
import { provideEventPath } from "@/composables/useEventPath";
|
||||||
|
|
||||||
@@ -31,8 +32,8 @@ const gameSteamId = ref("");
|
|||||||
|
|
||||||
useTitle(computed(() => t("submissions.pageTitle", { game: gameName.value, scope: scopeName.value })));
|
useTitle(computed(() => t("submissions.pageTitle", { game: gameName.value, scope: scopeName.value })));
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const queryClient = useQueryClient();
|
||||||
const { userInfo } = storeToRefs(userStore);
|
const userInfo = useUser();
|
||||||
|
|
||||||
const uploadedFiles = ref<File[]>([]);
|
const uploadedFiles = ref<File[]>([]);
|
||||||
const isDragover = ref(false);
|
const isDragover = ref(false);
|
||||||
@@ -503,17 +504,16 @@ const handlePasteOnUploadArea = (event: ClipboardEvent) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
userStore.loadUserData();
|
|
||||||
loadUserSubmissions();
|
loadUserSubmissions();
|
||||||
|
|
||||||
const [gamesResponse, scopesResponse] = await Promise.all([
|
const [games, scopesResponse] = await Promise.all([
|
||||||
gamesApiListEventGames({ path: { event_path: props.eventPath } }),
|
queryClient.ensureQueryData(eventGamesQuery(props.eventPath)),
|
||||||
submissionsApiListAvailableScopes({
|
submissionsApiListAvailableScopes({
|
||||||
path: { event_path: props.eventPath, game_path: props.gamePath },
|
path: { event_path: props.eventPath, game_path: props.gamePath },
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const game = gamesResponse.data?.find((g) => g.path === props.gamePath);
|
const game = games.find((g) => g.path === props.gamePath);
|
||||||
if (game) {
|
if (game) {
|
||||||
gameName.value = game.name;
|
gameName.value = game.name;
|
||||||
gameImage.value = game.image ?? "";
|
gameImage.value = game.image ?? "";
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ import { computed, onMounted, ref } from "vue";
|
|||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useTitle } from "@vueuse/core";
|
import { useTitle } from "@vueuse/core";
|
||||||
import { gamesApiListEventGames, submissionsApiListAvailableScopes } from "@/api";
|
import { submissionsApiListAvailableScopes } from "@/api";
|
||||||
|
import { useQueryClient } from "@tanstack/vue-query";
|
||||||
|
import { eventGamesQuery } from "@/queries";
|
||||||
import type { ScopeOut } from "@/api/types.gen";
|
import type { ScopeOut } from "@/api/types.gen";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -14,6 +16,7 @@ interface Props {
|
|||||||
const props = defineProps<Props>();
|
const props = defineProps<Props>();
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
useTitle(computed(() => t("submissionsSelect.title")));
|
useTitle(computed(() => t("submissionsSelect.title")));
|
||||||
|
|
||||||
@@ -32,14 +35,14 @@ const goToScope = (scope: ScopeOut) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const [gamesResponse, scopesResponse] = await Promise.all([
|
const [games, scopesResponse] = await Promise.all([
|
||||||
gamesApiListEventGames({ path: { event_path: props.eventPath } }),
|
queryClient.ensureQueryData(eventGamesQuery(props.eventPath)),
|
||||||
submissionsApiListAvailableScopes({
|
submissionsApiListAvailableScopes({
|
||||||
path: { event_path: props.eventPath, game_path: props.gamePath },
|
path: { event_path: props.eventPath, game_path: props.gamePath },
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
gameName.value = gamesResponse.data?.find((game) => game.path === props.gamePath)?.name ?? "";
|
gameName.value = games.find((game) => game.path === props.gamePath)?.name ?? "";
|
||||||
|
|
||||||
const availableScopes = scopesResponse.data ?? [];
|
const availableScopes = scopesResponse.data ?? [];
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,947 @@
|
|||||||
|
// This file is auto-generated by @hey-api/openapi-ts
|
||||||
|
|
||||||
|
import { type DefaultError, type InfiniteData, infiniteQueryOptions, queryOptions, type UseMutationOptions } from '@tanstack/vue-query';
|
||||||
|
|
||||||
|
import { client } from '../client.gen';
|
||||||
|
import { animationsApiPuzzleResults, animationsApiResults, animationsApiTopSubmissions, clockApiCurrentState, clockApiMyStats, gamesApiListEventGames, gamesApiListEventSteamGames, gamesApiListGames, marketApiBetHistory, marketApiCloseMarket, marketApiCreateBet, marketApiGetUserPoints, marketApiListMarkets, marketApiListUserBets, marketApiResolveMarket, noitaApiGetLeaderboard, noitaApiGetResults, noitaApiSubmitLogFile, type Options, opusMagnumApiCreateSubmission, opusMagnumApiDeleteSubmission, opusMagnumApiGetCollection, opusMagnumApiGetStats, opusMagnumApiGetSubmission, opusMagnumApiListPuzzles, opusMagnumApiListResponsesNeedingValidation, opusMagnumApiListSubmissions, opusMagnumApiValidateAuto, opusMagnumApiValidateResponse, opusMagnumApiValidateSubmission, placeApiCanvas, placeApiEvolutionGif, polylanSubmitterApiClearCache, polylanSubmitterApiGetUserInfo, polylanSubmitterApiHealthCheck, submissionsApiCreateImageCrop, submissionsApiCreateSubmission, submissionsApiDeleteImageCrop, submissionsApiGetSubmission, submissionsApiListAvailableScopes, submissionsApiListMyScopes, submissionsApiListSubmissionsByGame, submissionsApiListUserSubmissions, submissionsApiProcessCropOcr, submissionsApiProcessFileOcr } from '../sdk.gen';
|
||||||
|
import type { AnimationsApiPuzzleResultsData, AnimationsApiPuzzleResultsResponse, AnimationsApiResultsData, AnimationsApiResultsResponse, AnimationsApiTopSubmissionsData, AnimationsApiTopSubmissionsResponse, ClockApiCurrentStateData, ClockApiCurrentStateResponse, ClockApiMyStatsData, ClockApiMyStatsResponse, GamesApiListEventGamesData, GamesApiListEventGamesResponse, GamesApiListEventSteamGamesData, GamesApiListEventSteamGamesResponse, GamesApiListGamesData, GamesApiListGamesResponse, MarketApiBetHistoryData, MarketApiBetHistoryResponse, MarketApiCloseMarketData, MarketApiCreateBetData, MarketApiCreateBetResponse, MarketApiGetUserPointsData, MarketApiGetUserPointsResponse, MarketApiListMarketsData, MarketApiListMarketsResponse, MarketApiListUserBetsData, MarketApiListUserBetsResponse, MarketApiResolveMarketData, MarketApiResolveMarketResponse, NoitaApiGetLeaderboardData, NoitaApiGetLeaderboardResponse, NoitaApiGetResultsData, NoitaApiGetResultsResponse, NoitaApiSubmitLogFileData, NoitaApiSubmitLogFileError, NoitaApiSubmitLogFileResponse, OpusMagnumApiCreateSubmissionData, OpusMagnumApiCreateSubmissionResponse, OpusMagnumApiDeleteSubmissionData, OpusMagnumApiGetCollectionData, OpusMagnumApiGetCollectionResponse, OpusMagnumApiGetStatsData, OpusMagnumApiGetSubmissionData, OpusMagnumApiGetSubmissionResponse, OpusMagnumApiListPuzzlesData, OpusMagnumApiListPuzzlesResponse, OpusMagnumApiListResponsesNeedingValidationData, OpusMagnumApiListResponsesNeedingValidationResponse, OpusMagnumApiListSubmissionsData, OpusMagnumApiListSubmissionsResponse, OpusMagnumApiValidateAutoData, OpusMagnumApiValidateAutoResponse, OpusMagnumApiValidateResponseData, OpusMagnumApiValidateResponseResponse, OpusMagnumApiValidateSubmissionData, OpusMagnumApiValidateSubmissionResponse, PlaceApiCanvasData, PlaceApiEvolutionGifData, PolylanSubmitterApiClearCacheData, PolylanSubmitterApiGetUserInfoData, PolylanSubmitterApiGetUserInfoResponse, PolylanSubmitterApiHealthCheckData, SubmissionsApiCreateImageCropData, SubmissionsApiCreateImageCropResponse, SubmissionsApiCreateSubmissionData, SubmissionsApiCreateSubmissionError, SubmissionsApiCreateSubmissionResponse, SubmissionsApiDeleteImageCropData, SubmissionsApiDeleteImageCropResponse, SubmissionsApiGetSubmissionData, SubmissionsApiGetSubmissionResponse, SubmissionsApiListAvailableScopesData, SubmissionsApiListAvailableScopesError, SubmissionsApiListAvailableScopesResponse, SubmissionsApiListMyScopesData, SubmissionsApiListMyScopesError, SubmissionsApiListMyScopesResponse, SubmissionsApiListSubmissionsByGameData, SubmissionsApiListSubmissionsByGameResponse, SubmissionsApiListUserSubmissionsData, SubmissionsApiListUserSubmissionsError, SubmissionsApiListUserSubmissionsResponse, SubmissionsApiProcessCropOcrData, SubmissionsApiProcessCropOcrResponse, SubmissionsApiProcessFileOcrData, SubmissionsApiProcessFileOcrResponse } from '../types.gen';
|
||||||
|
|
||||||
|
export type QueryKey<TOptions extends Options> = [
|
||||||
|
Pick<TOptions, 'baseUrl' | 'body' | 'headers' | 'path' | 'query'> & {
|
||||||
|
_id: string;
|
||||||
|
_infinite?: boolean;
|
||||||
|
tags?: ReadonlyArray<string>;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const createQueryKey = <TOptions extends Options>(id: string, options?: TOptions, infinite?: boolean, tags?: ReadonlyArray<string>): [
|
||||||
|
QueryKey<TOptions>[0]
|
||||||
|
] => {
|
||||||
|
const params: QueryKey<TOptions>[0] = { _id: id, baseUrl: options?.baseUrl || (options?.client ?? client).getConfig().baseUrl } as QueryKey<TOptions>[0];
|
||||||
|
if (infinite) {
|
||||||
|
params._infinite = infinite;
|
||||||
|
}
|
||||||
|
if (tags) {
|
||||||
|
params.tags = tags;
|
||||||
|
}
|
||||||
|
if (options?.body) {
|
||||||
|
params.body = options.body;
|
||||||
|
}
|
||||||
|
if (options?.headers) {
|
||||||
|
params.headers = options.headers;
|
||||||
|
}
|
||||||
|
if (options?.path) {
|
||||||
|
params.path = options.path;
|
||||||
|
}
|
||||||
|
if (options?.query) {
|
||||||
|
params.query = options.query;
|
||||||
|
}
|
||||||
|
return [params];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const polylanSubmitterApiHealthCheckQueryKey = (options?: Options<PolylanSubmitterApiHealthCheckData>) => createQueryKey('polylanSubmitterApiHealthCheck', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Health Check
|
||||||
|
*
|
||||||
|
* Health check endpoint
|
||||||
|
*/
|
||||||
|
export const polylanSubmitterApiHealthCheckOptions = (options?: Options<PolylanSubmitterApiHealthCheckData>) => queryOptions<unknown, DefaultError, unknown, ReturnType<typeof polylanSubmitterApiHealthCheckQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await polylanSubmitterApiHealthCheck({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: polylanSubmitterApiHealthCheckQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear Cache
|
||||||
|
*
|
||||||
|
* Clear API caches (admin only). Pass event_path to clear just that event's keys.
|
||||||
|
*/
|
||||||
|
export const polylanSubmitterApiClearCacheMutation = (options?: Partial<Options<PolylanSubmitterApiClearCacheData>>): UseMutationOptions<unknown, DefaultError, Options<PolylanSubmitterApiClearCacheData>> => {
|
||||||
|
const mutationOptions: UseMutationOptions<unknown, DefaultError, Options<PolylanSubmitterApiClearCacheData>> = {
|
||||||
|
mutationFn: async (fnOptions) => {
|
||||||
|
const { data } = await polylanSubmitterApiClearCache({
|
||||||
|
...options,
|
||||||
|
...fnOptions,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const polylanSubmitterApiGetUserInfoQueryKey = (options?: Options<PolylanSubmitterApiGetUserInfoData>) => createQueryKey('polylanSubmitterApiGetUserInfo', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get User Info
|
||||||
|
*
|
||||||
|
* Get current user information
|
||||||
|
*/
|
||||||
|
export const polylanSubmitterApiGetUserInfoOptions = (options?: Options<PolylanSubmitterApiGetUserInfoData>) => queryOptions<PolylanSubmitterApiGetUserInfoResponse, DefaultError, PolylanSubmitterApiGetUserInfoResponse, ReturnType<typeof polylanSubmitterApiGetUserInfoQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await polylanSubmitterApiGetUserInfo({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: polylanSubmitterApiGetUserInfoQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const gamesApiListGamesQueryKey = (options?: Options<GamesApiListGamesData>) => createQueryKey('gamesApiListGames', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List Games
|
||||||
|
*/
|
||||||
|
export const gamesApiListGamesOptions = (options?: Options<GamesApiListGamesData>) => queryOptions<GamesApiListGamesResponse, DefaultError, GamesApiListGamesResponse, ReturnType<typeof gamesApiListGamesQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await gamesApiListGames({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: gamesApiListGamesQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const opusMagnumApiListPuzzlesQueryKey = (options: Options<OpusMagnumApiListPuzzlesData>) => createQueryKey('opusMagnumApiListPuzzles', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List Puzzles
|
||||||
|
*
|
||||||
|
* Get list of available puzzles
|
||||||
|
*/
|
||||||
|
export const opusMagnumApiListPuzzlesOptions = (options: Options<OpusMagnumApiListPuzzlesData>) => queryOptions<OpusMagnumApiListPuzzlesResponse, DefaultError, OpusMagnumApiListPuzzlesResponse, ReturnType<typeof opusMagnumApiListPuzzlesQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await opusMagnumApiListPuzzles({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: opusMagnumApiListPuzzlesQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const opusMagnumApiGetCollectionQueryKey = (options: Options<OpusMagnumApiGetCollectionData>) => createQueryKey('opusMagnumApiGetCollection', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Collection
|
||||||
|
*
|
||||||
|
* Get the active collection details
|
||||||
|
*/
|
||||||
|
export const opusMagnumApiGetCollectionOptions = (options: Options<OpusMagnumApiGetCollectionData>) => queryOptions<OpusMagnumApiGetCollectionResponse, DefaultError, OpusMagnumApiGetCollectionResponse, ReturnType<typeof opusMagnumApiGetCollectionQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await opusMagnumApiGetCollection({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: opusMagnumApiGetCollectionQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const opusMagnumApiListSubmissionsQueryKey = (options: Options<OpusMagnumApiListSubmissionsData>) => createQueryKey('opusMagnumApiListSubmissions', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List Submissions
|
||||||
|
*
|
||||||
|
* Get paginated list of submissions
|
||||||
|
*/
|
||||||
|
export const opusMagnumApiListSubmissionsOptions = (options: Options<OpusMagnumApiListSubmissionsData>) => queryOptions<OpusMagnumApiListSubmissionsResponse, DefaultError, OpusMagnumApiListSubmissionsResponse, ReturnType<typeof opusMagnumApiListSubmissionsQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await opusMagnumApiListSubmissions({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: opusMagnumApiListSubmissionsQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
const createInfiniteParams = <K extends Pick<QueryKey<Options>[0], 'body' | 'headers' | 'path' | 'query'>>(queryKey: QueryKey<Options>, page: K) => {
|
||||||
|
const params = { ...queryKey[0] };
|
||||||
|
if (page.body) {
|
||||||
|
params.body = {
|
||||||
|
...queryKey[0].body as any,
|
||||||
|
...page.body as any
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (page.headers) {
|
||||||
|
params.headers = {
|
||||||
|
...queryKey[0].headers,
|
||||||
|
...page.headers
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (page.path) {
|
||||||
|
params.path = {
|
||||||
|
...queryKey[0].path as any,
|
||||||
|
...page.path as any
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (page.query) {
|
||||||
|
params.query = {
|
||||||
|
...queryKey[0].query as any,
|
||||||
|
...page.query as any
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return params as unknown as typeof page;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const opusMagnumApiListSubmissionsInfiniteQueryKey = (options: Options<OpusMagnumApiListSubmissionsData>): QueryKey<Options<OpusMagnumApiListSubmissionsData>> => createQueryKey('opusMagnumApiListSubmissions', options, true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List Submissions
|
||||||
|
*
|
||||||
|
* Get paginated list of submissions
|
||||||
|
*/
|
||||||
|
export const opusMagnumApiListSubmissionsInfiniteOptions = (options: Options<OpusMagnumApiListSubmissionsData>) => infiniteQueryOptions<OpusMagnumApiListSubmissionsResponse, DefaultError, InfiniteData<OpusMagnumApiListSubmissionsResponse>, QueryKey<Options<OpusMagnumApiListSubmissionsData>>, number | Pick<QueryKey<Options<OpusMagnumApiListSubmissionsData>>[0], 'body' | 'headers' | 'path' | 'query'>>(
|
||||||
|
// @ts-ignore
|
||||||
|
{
|
||||||
|
queryFn: async ({ pageParam, queryKey, signal }) => {
|
||||||
|
// @ts-ignore
|
||||||
|
const page: Pick<QueryKey<Options<OpusMagnumApiListSubmissionsData>>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : {
|
||||||
|
query: {
|
||||||
|
offset: pageParam
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const params = createInfiniteParams(queryKey, page);
|
||||||
|
const { data } = await opusMagnumApiListSubmissions({
|
||||||
|
...options,
|
||||||
|
...params,
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: opusMagnumApiListSubmissionsInfiniteQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create Submission
|
||||||
|
*
|
||||||
|
* Create a new submission with multiple puzzle responses
|
||||||
|
*/
|
||||||
|
export const opusMagnumApiCreateSubmissionMutation = (options?: Partial<Options<OpusMagnumApiCreateSubmissionData>>): UseMutationOptions<OpusMagnumApiCreateSubmissionResponse, DefaultError, Options<OpusMagnumApiCreateSubmissionData>> => {
|
||||||
|
const mutationOptions: UseMutationOptions<OpusMagnumApiCreateSubmissionResponse, DefaultError, Options<OpusMagnumApiCreateSubmissionData>> = {
|
||||||
|
mutationFn: async (fnOptions) => {
|
||||||
|
const { data } = await opusMagnumApiCreateSubmission({
|
||||||
|
...options,
|
||||||
|
...fnOptions,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete Submission
|
||||||
|
*
|
||||||
|
* Delete a submission (admin only)
|
||||||
|
*/
|
||||||
|
export const opusMagnumApiDeleteSubmissionMutation = (options?: Partial<Options<OpusMagnumApiDeleteSubmissionData>>): UseMutationOptions<unknown, DefaultError, Options<OpusMagnumApiDeleteSubmissionData>> => {
|
||||||
|
const mutationOptions: UseMutationOptions<unknown, DefaultError, Options<OpusMagnumApiDeleteSubmissionData>> = {
|
||||||
|
mutationFn: async (fnOptions) => {
|
||||||
|
const { data } = await opusMagnumApiDeleteSubmission({
|
||||||
|
...options,
|
||||||
|
...fnOptions,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const opusMagnumApiGetSubmissionQueryKey = (options: Options<OpusMagnumApiGetSubmissionData>) => createQueryKey('opusMagnumApiGetSubmission', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Submission
|
||||||
|
*
|
||||||
|
* Get detailed submission by ID
|
||||||
|
*/
|
||||||
|
export const opusMagnumApiGetSubmissionOptions = (options: Options<OpusMagnumApiGetSubmissionData>) => queryOptions<OpusMagnumApiGetSubmissionResponse, DefaultError, OpusMagnumApiGetSubmissionResponse, ReturnType<typeof opusMagnumApiGetSubmissionQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await opusMagnumApiGetSubmission({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: opusMagnumApiGetSubmissionQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate Response
|
||||||
|
*
|
||||||
|
* Manually validate a puzzle response
|
||||||
|
*/
|
||||||
|
export const opusMagnumApiValidateResponseMutation = (options?: Partial<Options<OpusMagnumApiValidateResponseData>>): UseMutationOptions<OpusMagnumApiValidateResponseResponse, DefaultError, Options<OpusMagnumApiValidateResponseData>> => {
|
||||||
|
const mutationOptions: UseMutationOptions<OpusMagnumApiValidateResponseResponse, DefaultError, Options<OpusMagnumApiValidateResponseData>> = {
|
||||||
|
mutationFn: async (fnOptions) => {
|
||||||
|
const { data } = await opusMagnumApiValidateResponse({
|
||||||
|
...options,
|
||||||
|
...fnOptions,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate Auto
|
||||||
|
*
|
||||||
|
* Try to auto validate a puzzle response
|
||||||
|
*/
|
||||||
|
export const opusMagnumApiValidateAutoMutation = (options?: Partial<Options<OpusMagnumApiValidateAutoData>>): UseMutationOptions<OpusMagnumApiValidateAutoResponse, DefaultError, Options<OpusMagnumApiValidateAutoData>> => {
|
||||||
|
const mutationOptions: UseMutationOptions<OpusMagnumApiValidateAutoResponse, DefaultError, Options<OpusMagnumApiValidateAutoData>> = {
|
||||||
|
mutationFn: async (fnOptions) => {
|
||||||
|
const { data } = await opusMagnumApiValidateAuto({
|
||||||
|
...options,
|
||||||
|
...fnOptions,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const opusMagnumApiListResponsesNeedingValidationQueryKey = (options: Options<OpusMagnumApiListResponsesNeedingValidationData>) => createQueryKey('opusMagnumApiListResponsesNeedingValidation', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List Responses Needing Validation
|
||||||
|
*
|
||||||
|
* Get all responses that need manual validation
|
||||||
|
*/
|
||||||
|
export const opusMagnumApiListResponsesNeedingValidationOptions = (options: Options<OpusMagnumApiListResponsesNeedingValidationData>) => queryOptions<OpusMagnumApiListResponsesNeedingValidationResponse, DefaultError, OpusMagnumApiListResponsesNeedingValidationResponse, ReturnType<typeof opusMagnumApiListResponsesNeedingValidationQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await opusMagnumApiListResponsesNeedingValidation({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: opusMagnumApiListResponsesNeedingValidationQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate Submission
|
||||||
|
*
|
||||||
|
* Mark entire submission as validated
|
||||||
|
*/
|
||||||
|
export const opusMagnumApiValidateSubmissionMutation = (options?: Partial<Options<OpusMagnumApiValidateSubmissionData>>): UseMutationOptions<OpusMagnumApiValidateSubmissionResponse, DefaultError, Options<OpusMagnumApiValidateSubmissionData>> => {
|
||||||
|
const mutationOptions: UseMutationOptions<OpusMagnumApiValidateSubmissionResponse, DefaultError, Options<OpusMagnumApiValidateSubmissionData>> = {
|
||||||
|
mutationFn: async (fnOptions) => {
|
||||||
|
const { data } = await opusMagnumApiValidateSubmission({
|
||||||
|
...options,
|
||||||
|
...fnOptions,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const opusMagnumApiGetStatsQueryKey = (options: Options<OpusMagnumApiGetStatsData>) => createQueryKey('opusMagnumApiGetStats', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Stats
|
||||||
|
*
|
||||||
|
* Get submission statistics
|
||||||
|
*/
|
||||||
|
export const opusMagnumApiGetStatsOptions = (options: Options<OpusMagnumApiGetStatsData>) => queryOptions<unknown, DefaultError, unknown, ReturnType<typeof opusMagnumApiGetStatsQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await opusMagnumApiGetStats({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: opusMagnumApiGetStatsQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const animationsApiResultsQueryKey = (options: Options<AnimationsApiResultsData>) => createQueryKey('animationsApiResults', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Results
|
||||||
|
*/
|
||||||
|
export const animationsApiResultsOptions = (options: Options<AnimationsApiResultsData>) => queryOptions<AnimationsApiResultsResponse, DefaultError, AnimationsApiResultsResponse, ReturnType<typeof animationsApiResultsQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await animationsApiResults({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: animationsApiResultsQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const animationsApiTopSubmissionsQueryKey = (options: Options<AnimationsApiTopSubmissionsData>) => createQueryKey('animationsApiTopSubmissions', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Top Submissions
|
||||||
|
*
|
||||||
|
* Get tournament top submissions for each puzzle. Only available when tournament is closed.
|
||||||
|
*/
|
||||||
|
export const animationsApiTopSubmissionsOptions = (options: Options<AnimationsApiTopSubmissionsData>) => queryOptions<AnimationsApiTopSubmissionsResponse, DefaultError, AnimationsApiTopSubmissionsResponse, ReturnType<typeof animationsApiTopSubmissionsQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await animationsApiTopSubmissions({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: animationsApiTopSubmissionsQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const animationsApiPuzzleResultsQueryKey = (options: Options<AnimationsApiPuzzleResultsData>) => createQueryKey('animationsApiPuzzleResults', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puzzle Results
|
||||||
|
*
|
||||||
|
* Get tournament results organized by puzzle with coefficients. Only available when tournament is closed.
|
||||||
|
*/
|
||||||
|
export const animationsApiPuzzleResultsOptions = (options: Options<AnimationsApiPuzzleResultsData>) => queryOptions<AnimationsApiPuzzleResultsResponse, DefaultError, AnimationsApiPuzzleResultsResponse, ReturnType<typeof animationsApiPuzzleResultsQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await animationsApiPuzzleResults({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: animationsApiPuzzleResultsQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const noitaApiGetResultsQueryKey = (options: Options<NoitaApiGetResultsData>) => createQueryKey('noitaApiGetResults', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Results
|
||||||
|
*/
|
||||||
|
export const noitaApiGetResultsOptions = (options: Options<NoitaApiGetResultsData>) => queryOptions<NoitaApiGetResultsResponse, DefaultError, NoitaApiGetResultsResponse, ReturnType<typeof noitaApiGetResultsQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await noitaApiGetResults({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: noitaApiGetResultsQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const noitaApiGetLeaderboardQueryKey = (options: Options<NoitaApiGetLeaderboardData>) => createQueryKey('noitaApiGetLeaderboard', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Leaderboard
|
||||||
|
*
|
||||||
|
* Get the global leaderboard for all users ranked by total score.
|
||||||
|
*
|
||||||
|
* Uses Window functions to rank users by their total score in descending order.
|
||||||
|
*/
|
||||||
|
export const noitaApiGetLeaderboardOptions = (options: Options<NoitaApiGetLeaderboardData>) => queryOptions<NoitaApiGetLeaderboardResponse, DefaultError, NoitaApiGetLeaderboardResponse, ReturnType<typeof noitaApiGetLeaderboardQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await noitaApiGetLeaderboard({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: noitaApiGetLeaderboardQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit Log File
|
||||||
|
*
|
||||||
|
* Submit a Noita run file (log file, screenshot, or video).
|
||||||
|
*
|
||||||
|
* Accepts:
|
||||||
|
* - Text files (.txt) for polylan_mod_log.txt
|
||||||
|
* - Images (.png, .jpg, .gif)
|
||||||
|
* - Videos (.mp4, .webm)
|
||||||
|
*
|
||||||
|
* Max file size: 256 MB
|
||||||
|
*/
|
||||||
|
export const noitaApiSubmitLogFileMutation = (options?: Partial<Options<NoitaApiSubmitLogFileData>>): UseMutationOptions<NoitaApiSubmitLogFileResponse, NoitaApiSubmitLogFileError, Options<NoitaApiSubmitLogFileData>> => {
|
||||||
|
const mutationOptions: UseMutationOptions<NoitaApiSubmitLogFileResponse, NoitaApiSubmitLogFileError, Options<NoitaApiSubmitLogFileData>> = {
|
||||||
|
mutationFn: async (fnOptions) => {
|
||||||
|
const { data } = await noitaApiSubmitLogFile({
|
||||||
|
...options,
|
||||||
|
...fnOptions,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const gamesApiListEventGamesQueryKey = (options: Options<GamesApiListEventGamesData>) => createQueryKey('gamesApiListEventGames', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List Event Games
|
||||||
|
*/
|
||||||
|
export const gamesApiListEventGamesOptions = (options: Options<GamesApiListEventGamesData>) => queryOptions<GamesApiListEventGamesResponse, DefaultError, GamesApiListEventGamesResponse, ReturnType<typeof gamesApiListEventGamesQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await gamesApiListEventGames({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: gamesApiListEventGamesQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const gamesApiListEventSteamGamesQueryKey = (options: Options<GamesApiListEventSteamGamesData>) => createQueryKey('gamesApiListEventSteamGames', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List Event Steam Games
|
||||||
|
*
|
||||||
|
* The event's Steam games with their store info (price, discount, blurb).
|
||||||
|
*/
|
||||||
|
export const gamesApiListEventSteamGamesOptions = (options: Options<GamesApiListEventSteamGamesData>) => queryOptions<GamesApiListEventSteamGamesResponse, DefaultError, GamesApiListEventSteamGamesResponse, ReturnType<typeof gamesApiListEventSteamGamesQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await gamesApiListEventSteamGames({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: gamesApiListEventSteamGamesQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const submissionsApiListMyScopesQueryKey = (options: Options<SubmissionsApiListMyScopesData>) => createQueryKey('submissionsApiListMyScopes', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List My Scopes
|
||||||
|
*/
|
||||||
|
export const submissionsApiListMyScopesOptions = (options: Options<SubmissionsApiListMyScopesData>) => queryOptions<SubmissionsApiListMyScopesResponse, SubmissionsApiListMyScopesError, SubmissionsApiListMyScopesResponse, ReturnType<typeof submissionsApiListMyScopesQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await submissionsApiListMyScopes({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: submissionsApiListMyScopesQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const submissionsApiListAvailableScopesQueryKey = (options: Options<SubmissionsApiListAvailableScopesData>) => createQueryKey('submissionsApiListAvailableScopes', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List Available Scopes
|
||||||
|
*
|
||||||
|
* Scopes the current user may submit to for this game - superusers see
|
||||||
|
* every active scope, everyone else only the ones assigned to them. Used
|
||||||
|
* by the submissions-select and submissions-detail pages, both to list
|
||||||
|
* scopes and (for the detail page) to confirm the requested scope_id is
|
||||||
|
* one the current user is actually allowed to see.
|
||||||
|
*/
|
||||||
|
export const submissionsApiListAvailableScopesOptions = (options: Options<SubmissionsApiListAvailableScopesData>) => queryOptions<SubmissionsApiListAvailableScopesResponse, SubmissionsApiListAvailableScopesError, SubmissionsApiListAvailableScopesResponse, ReturnType<typeof submissionsApiListAvailableScopesQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await submissionsApiListAvailableScopes({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: submissionsApiListAvailableScopesQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create Submission
|
||||||
|
*/
|
||||||
|
export const submissionsApiCreateSubmissionMutation = (options?: Partial<Options<SubmissionsApiCreateSubmissionData>>): UseMutationOptions<SubmissionsApiCreateSubmissionResponse, SubmissionsApiCreateSubmissionError, Options<SubmissionsApiCreateSubmissionData>> => {
|
||||||
|
const mutationOptions: UseMutationOptions<SubmissionsApiCreateSubmissionResponse, SubmissionsApiCreateSubmissionError, Options<SubmissionsApiCreateSubmissionData>> = {
|
||||||
|
mutationFn: async (fnOptions) => {
|
||||||
|
const { data } = await submissionsApiCreateSubmission({
|
||||||
|
...options,
|
||||||
|
...fnOptions,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const submissionsApiListUserSubmissionsQueryKey = (options: Options<SubmissionsApiListUserSubmissionsData>) => createQueryKey('submissionsApiListUserSubmissions', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List User Submissions
|
||||||
|
*/
|
||||||
|
export const submissionsApiListUserSubmissionsOptions = (options: Options<SubmissionsApiListUserSubmissionsData>) => queryOptions<SubmissionsApiListUserSubmissionsResponse, SubmissionsApiListUserSubmissionsError, SubmissionsApiListUserSubmissionsResponse, ReturnType<typeof submissionsApiListUserSubmissionsQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await submissionsApiListUserSubmissions({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: submissionsApiListUserSubmissionsQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const submissionsApiListSubmissionsByGameQueryKey = (options: Options<SubmissionsApiListSubmissionsByGameData>) => createQueryKey('submissionsApiListSubmissionsByGame', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List Submissions By Game
|
||||||
|
*/
|
||||||
|
export const submissionsApiListSubmissionsByGameOptions = (options: Options<SubmissionsApiListSubmissionsByGameData>) => queryOptions<SubmissionsApiListSubmissionsByGameResponse, DefaultError, SubmissionsApiListSubmissionsByGameResponse, ReturnType<typeof submissionsApiListSubmissionsByGameQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await submissionsApiListSubmissionsByGame({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: submissionsApiListSubmissionsByGameQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const submissionsApiGetSubmissionQueryKey = (options: Options<SubmissionsApiGetSubmissionData>) => createQueryKey('submissionsApiGetSubmission', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Submission
|
||||||
|
*/
|
||||||
|
export const submissionsApiGetSubmissionOptions = (options: Options<SubmissionsApiGetSubmissionData>) => queryOptions<SubmissionsApiGetSubmissionResponse, DefaultError, SubmissionsApiGetSubmissionResponse, ReturnType<typeof submissionsApiGetSubmissionQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await submissionsApiGetSubmission({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: submissionsApiGetSubmissionQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create Image Crop
|
||||||
|
*/
|
||||||
|
export const submissionsApiCreateImageCropMutation = (options?: Partial<Options<SubmissionsApiCreateImageCropData>>): UseMutationOptions<SubmissionsApiCreateImageCropResponse, DefaultError, Options<SubmissionsApiCreateImageCropData>> => {
|
||||||
|
const mutationOptions: UseMutationOptions<SubmissionsApiCreateImageCropResponse, DefaultError, Options<SubmissionsApiCreateImageCropData>> = {
|
||||||
|
mutationFn: async (fnOptions) => {
|
||||||
|
const { data } = await submissionsApiCreateImageCrop({
|
||||||
|
...options,
|
||||||
|
...fnOptions,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete Image Crop
|
||||||
|
*/
|
||||||
|
export const submissionsApiDeleteImageCropMutation = (options?: Partial<Options<SubmissionsApiDeleteImageCropData>>): UseMutationOptions<SubmissionsApiDeleteImageCropResponse, DefaultError, Options<SubmissionsApiDeleteImageCropData>> => {
|
||||||
|
const mutationOptions: UseMutationOptions<SubmissionsApiDeleteImageCropResponse, DefaultError, Options<SubmissionsApiDeleteImageCropData>> = {
|
||||||
|
mutationFn: async (fnOptions) => {
|
||||||
|
const { data } = await submissionsApiDeleteImageCrop({
|
||||||
|
...options,
|
||||||
|
...fnOptions,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process File Ocr
|
||||||
|
*/
|
||||||
|
export const submissionsApiProcessFileOcrMutation = (options?: Partial<Options<SubmissionsApiProcessFileOcrData>>): UseMutationOptions<SubmissionsApiProcessFileOcrResponse, DefaultError, Options<SubmissionsApiProcessFileOcrData>> => {
|
||||||
|
const mutationOptions: UseMutationOptions<SubmissionsApiProcessFileOcrResponse, DefaultError, Options<SubmissionsApiProcessFileOcrData>> = {
|
||||||
|
mutationFn: async (fnOptions) => {
|
||||||
|
const { data } = await submissionsApiProcessFileOcr({
|
||||||
|
...options,
|
||||||
|
...fnOptions,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process Crop Ocr
|
||||||
|
*/
|
||||||
|
export const submissionsApiProcessCropOcrMutation = (options?: Partial<Options<SubmissionsApiProcessCropOcrData>>): UseMutationOptions<SubmissionsApiProcessCropOcrResponse, DefaultError, Options<SubmissionsApiProcessCropOcrData>> => {
|
||||||
|
const mutationOptions: UseMutationOptions<SubmissionsApiProcessCropOcrResponse, DefaultError, Options<SubmissionsApiProcessCropOcrData>> = {
|
||||||
|
mutationFn: async (fnOptions) => {
|
||||||
|
const { data } = await submissionsApiProcessCropOcr({
|
||||||
|
...options,
|
||||||
|
...fnOptions,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const clockApiCurrentStateQueryKey = (options: Options<ClockApiCurrentStateData>) => createQueryKey('clockApiCurrentState', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current State
|
||||||
|
*/
|
||||||
|
export const clockApiCurrentStateOptions = (options: Options<ClockApiCurrentStateData>) => queryOptions<ClockApiCurrentStateResponse, DefaultError, ClockApiCurrentStateResponse, ReturnType<typeof clockApiCurrentStateQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await clockApiCurrentState({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: clockApiCurrentStateQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const clockApiMyStatsQueryKey = (options: Options<ClockApiMyStatsData>) => createQueryKey('clockApiMyStats', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* My Stats
|
||||||
|
*/
|
||||||
|
export const clockApiMyStatsOptions = (options: Options<ClockApiMyStatsData>) => queryOptions<ClockApiMyStatsResponse, DefaultError, ClockApiMyStatsResponse, ReturnType<typeof clockApiMyStatsQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await clockApiMyStats({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: clockApiMyStatsQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const placeApiCanvasQueryKey = (options: Options<PlaceApiCanvasData>) => createQueryKey('placeApiCanvas', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Canvas
|
||||||
|
*
|
||||||
|
* The one-time full-grid load. Every placement after that arrives as a
|
||||||
|
* single websocket message, never a re-fetch.
|
||||||
|
*/
|
||||||
|
export const placeApiCanvasOptions = (options: Options<PlaceApiCanvasData>) => queryOptions<unknown, DefaultError, unknown, ReturnType<typeof placeApiCanvasQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await placeApiCanvas({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: placeApiCanvasQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const placeApiEvolutionGifQueryKey = (options: Options<PlaceApiEvolutionGifData>) => createQueryKey('placeApiEvolutionGif', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evolution Gif
|
||||||
|
*
|
||||||
|
* Admin-only: replays the full placement history as an animated GIF.
|
||||||
|
*/
|
||||||
|
export const placeApiEvolutionGifOptions = (options: Options<PlaceApiEvolutionGifData>) => queryOptions<unknown, DefaultError, unknown, ReturnType<typeof placeApiEvolutionGifQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await placeApiEvolutionGif({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: placeApiEvolutionGifQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const marketApiListMarketsQueryKey = (options: Options<MarketApiListMarketsData>) => createQueryKey('marketApiListMarkets', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List Markets
|
||||||
|
*
|
||||||
|
* List all markets (excludes draft markets).
|
||||||
|
*/
|
||||||
|
export const marketApiListMarketsOptions = (options: Options<MarketApiListMarketsData>) => queryOptions<MarketApiListMarketsResponse, DefaultError, MarketApiListMarketsResponse, ReturnType<typeof marketApiListMarketsQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await marketApiListMarkets({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: marketApiListMarketsQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const marketApiListUserBetsQueryKey = (options: Options<MarketApiListUserBetsData>) => createQueryKey('marketApiListUserBets', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List User Bets
|
||||||
|
*
|
||||||
|
* List all bets placed by the current user.
|
||||||
|
*/
|
||||||
|
export const marketApiListUserBetsOptions = (options: Options<MarketApiListUserBetsData>) => queryOptions<MarketApiListUserBetsResponse, DefaultError, MarketApiListUserBetsResponse, ReturnType<typeof marketApiListUserBetsQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await marketApiListUserBets({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: marketApiListUserBetsQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const marketApiGetUserPointsQueryKey = (options: Options<MarketApiGetUserPointsData>) => createQueryKey('marketApiGetUserPoints', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get User Points
|
||||||
|
*
|
||||||
|
* Get the current user's points balance for this event.
|
||||||
|
*/
|
||||||
|
export const marketApiGetUserPointsOptions = (options: Options<MarketApiGetUserPointsData>) => queryOptions<MarketApiGetUserPointsResponse, DefaultError, MarketApiGetUserPointsResponse, ReturnType<typeof marketApiGetUserPointsQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await marketApiGetUserPoints({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: marketApiGetUserPointsQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const marketApiBetHistoryQueryKey = (options: Options<MarketApiBetHistoryData>) => createQueryKey('marketApiBetHistory', options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bet History
|
||||||
|
*
|
||||||
|
* Points added to each option over time (anonymous, one entry per bet placed/increased).
|
||||||
|
*/
|
||||||
|
export const marketApiBetHistoryOptions = (options: Options<MarketApiBetHistoryData>) => queryOptions<MarketApiBetHistoryResponse, DefaultError, MarketApiBetHistoryResponse, ReturnType<typeof marketApiBetHistoryQueryKey>>({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await marketApiBetHistory({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: marketApiBetHistoryQueryKey(options)
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close Market
|
||||||
|
*
|
||||||
|
* Close a market. Admin only.
|
||||||
|
*/
|
||||||
|
export const marketApiCloseMarketMutation = (options?: Partial<Options<MarketApiCloseMarketData>>): UseMutationOptions<unknown, DefaultError, Options<MarketApiCloseMarketData>> => {
|
||||||
|
const mutationOptions: UseMutationOptions<unknown, DefaultError, Options<MarketApiCloseMarketData>> = {
|
||||||
|
mutationFn: async (fnOptions) => {
|
||||||
|
const { data } = await marketApiCloseMarket({
|
||||||
|
...options,
|
||||||
|
...fnOptions,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve Market
|
||||||
|
*
|
||||||
|
* Resolve a market with a winning option. Admin only.
|
||||||
|
*/
|
||||||
|
export const marketApiResolveMarketMutation = (options?: Partial<Options<MarketApiResolveMarketData>>): UseMutationOptions<MarketApiResolveMarketResponse, DefaultError, Options<MarketApiResolveMarketData>> => {
|
||||||
|
const mutationOptions: UseMutationOptions<MarketApiResolveMarketResponse, DefaultError, Options<MarketApiResolveMarketData>> = {
|
||||||
|
mutationFn: async (fnOptions) => {
|
||||||
|
const { data } = await marketApiResolveMarket({
|
||||||
|
...options,
|
||||||
|
...fnOptions,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create Bet
|
||||||
|
*
|
||||||
|
* Place a bet on a market option.
|
||||||
|
*/
|
||||||
|
export const marketApiCreateBetMutation = (options?: Partial<Options<MarketApiCreateBetData>>): UseMutationOptions<MarketApiCreateBetResponse, DefaultError, Options<MarketApiCreateBetData>> => {
|
||||||
|
const mutationOptions: UseMutationOptions<MarketApiCreateBetResponse, DefaultError, Options<MarketApiCreateBetData>> = {
|
||||||
|
mutationFn: async (fnOptions) => {
|
||||||
|
const { data } = await marketApiCreateBet({
|
||||||
|
...options,
|
||||||
|
...fnOptions,
|
||||||
|
throwOnError: true
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mutationOptions;
|
||||||
|
};
|
||||||
@@ -2,7 +2,8 @@
|
|||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import RankBadge from "./RankBadge.vue";
|
import RankBadge from "./RankBadge.vue";
|
||||||
import { animationsApiResults, polylanSubmitterApiClearCache, polylanSubmitterApiGetUserInfo } from "@/api";
|
import { animationsApiResults, polylanSubmitterApiClearCache } from "@/api";
|
||||||
|
import { queryClient, userQuery } from "@/queries";
|
||||||
import { useEventPath } from "@/composables/useEventPath";
|
import { useEventPath } from "@/composables/useEventPath";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@@ -142,8 +143,7 @@ const clearCache = async () => {
|
|||||||
|
|
||||||
const loadUserData = async () => {
|
const loadUserData = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await polylanSubmitterApiGetUserInfo();
|
const user = await queryClient.fetchQuery(userQuery());
|
||||||
const user = response.data;
|
|
||||||
if (user?.is_authenticated) {
|
if (user?.is_authenticated) {
|
||||||
userInfo.value.username = user.username ?? "";
|
userInfo.value.username = user.username ?? "";
|
||||||
userInfo.value.isStaff = user.is_staff || false;
|
userInfo.value.isStaff = user.is_staff || false;
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { computed } from "vue";
|
||||||
|
import { useQuery } from "@tanstack/vue-query";
|
||||||
|
import { userQuery } from "@/queries";
|
||||||
|
|
||||||
|
export const useUser = () => {
|
||||||
|
const { data } = useQuery(userQuery());
|
||||||
|
|
||||||
|
return computed(() => ({
|
||||||
|
username: data.value?.username ?? "",
|
||||||
|
isAuthenticated: data.value?.is_authenticated ?? false,
|
||||||
|
isStaff: data.value?.is_staff ?? false,
|
||||||
|
}));
|
||||||
|
};
|
||||||
@@ -3,14 +3,13 @@ import { computed } from "vue";
|
|||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUser } from "@/composables/useUser";
|
||||||
import { usePageHeaderStore } from "@/stores/pageHeader";
|
import { usePageHeaderStore } from "@/stores/pageHeader";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const userStore = useUserStore();
|
const userInfo = useUser();
|
||||||
const { userInfo } = storeToRefs(userStore);
|
|
||||||
const pageHeaderStore = usePageHeaderStore();
|
const pageHeaderStore = usePageHeaderStore();
|
||||||
const { title: dynamicTitle, backRoute: dynamicBackRoute } = storeToRefs(pageHeaderStore);
|
const { title: dynamicTitle, backRoute: dynamicBackRoute } = storeToRefs(pageHeaderStore);
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,19 @@
|
|||||||
import { createApp } from "vue";
|
import { createApp } from "vue";
|
||||||
|
import { VueQueryPlugin } from "@tanstack/vue-query";
|
||||||
import App from "@/App.vue";
|
import App from "@/App.vue";
|
||||||
import { router } from "@/router";
|
import { router } from "@/router";
|
||||||
import { pinia } from "@/stores";
|
import { pinia } from "@/stores";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
|
import { onQueryCacheRestored, queryClient, restoreQueryCache } from "@/queries";
|
||||||
import "@/style.css";
|
import "@/style.css";
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
app.use(pinia);
|
app.use(pinia);
|
||||||
|
app.use(VueQueryPlugin, {
|
||||||
|
queryClient,
|
||||||
|
clientPersister: restoreQueryCache,
|
||||||
|
clientPersisterOnSuccess: onQueryCacheRestored,
|
||||||
|
});
|
||||||
app.use(router);
|
app.use(router);
|
||||||
app.use(i18n);
|
app.use(i18n);
|
||||||
app.mount("#app");
|
app.mount("#app");
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { QueryClient } from "@tanstack/vue-query";
|
||||||
|
import { persistQueryClient } from "@tanstack/query-persist-client-core";
|
||||||
|
import { createSyncStoragePersister } from "@tanstack/query-sync-storage-persister";
|
||||||
|
import {
|
||||||
|
gamesApiListEventGamesOptions,
|
||||||
|
polylanSubmitterApiGetUserInfoOptions,
|
||||||
|
polylanSubmitterApiGetUserInfoQueryKey,
|
||||||
|
} from "@/api/@tanstack/vue-query.gen";
|
||||||
|
|
||||||
|
// Exported (not just provided by VueQueryPlugin) so Pinia stores can
|
||||||
|
// fetchQuery() through the same cache.
|
||||||
|
export const queryClient = new QueryClient();
|
||||||
|
|
||||||
|
// Login/logout are full-page redirects, so the user can't change within a
|
||||||
|
// page load - only refetched once after a reload (see restoreQueryCache).
|
||||||
|
export const userQuery = () => ({
|
||||||
|
...polylanSubmitterApiGetUserInfoOptions(),
|
||||||
|
staleTime: Infinity,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Games only change when staff enable/disable one, a few minutes of
|
||||||
|
// staleness is fine.
|
||||||
|
export const eventGamesQuery = (eventPath: string) => ({
|
||||||
|
...gamesApiListEventGamesOptions({ path: { event_path: eventPath } }),
|
||||||
|
staleTime: 5 * 60 * 1000,
|
||||||
|
});
|
||||||
|
|
||||||
|
const PERSISTED_QUERIES = new Set(["polylanSubmitterApiGetUserInfo", "gamesApiListEventGames"]);
|
||||||
|
|
||||||
|
// Restores user + games from localStorage before the app mounts, so pages
|
||||||
|
// render right away on reload instead of waiting on the API.
|
||||||
|
export const restoreQueryCache = (client: QueryClient) =>
|
||||||
|
persistQueryClient({
|
||||||
|
queryClient: client,
|
||||||
|
persister: createSyncStoragePersister({ storage: window.localStorage }),
|
||||||
|
dehydrateOptions: {
|
||||||
|
shouldDehydrateQuery: (query) =>
|
||||||
|
query.state.status === "success" &&
|
||||||
|
PERSISTED_QUERIES.has((query.queryKey[0] as { _id: string })._id),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// The restored user is only a placeholder until the real one comes back.
|
||||||
|
export const onQueryCacheRestored = (client: QueryClient) =>
|
||||||
|
client.invalidateQueries({ queryKey: polylanSubmitterApiGetUserInfoQueryKey() });
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { polylanSubmitterApiGetUserInfo, marketApiListMarkets, marketApiListUserBets, marketApiGetUserPoints } from '@/api'
|
import { marketApiListMarkets, marketApiListUserBets, marketApiGetUserPoints } from '@/api'
|
||||||
import type { Market } from '@/types'
|
import type { Market } from '@/types'
|
||||||
|
import { queryClient, userQuery } from '@/queries'
|
||||||
import type { UserInfoOut, UserBetSchema } from '@/api/types.gen'
|
import type { UserInfoOut, UserBetSchema } from '@/api/types.gen'
|
||||||
|
|
||||||
export const useMarketStore = defineStore('market', () => {
|
export const useMarketStore = defineStore('market', () => {
|
||||||
@@ -15,15 +16,7 @@ export const useMarketStore = defineStore('market', () => {
|
|||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
const loadUserInfo = async () => {
|
const loadUserInfo = async () => {
|
||||||
try {
|
userInfo.value = await queryClient.fetchQuery(userQuery()).catch(() => undefined)
|
||||||
const response = await polylanSubmitterApiGetUserInfo()
|
|
||||||
if (response.data) {
|
|
||||||
userInfo.value = response.data
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
error.value = 'Failed to load user info'
|
|
||||||
console.error('Error loading user info:', err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadMarkets = async (eventPath: string) => {
|
const loadMarkets = async (eventPath: string) => {
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import {
|
|||||||
noitaApiGetResults,
|
noitaApiGetResults,
|
||||||
noitaApiGetLeaderboard,
|
noitaApiGetLeaderboard,
|
||||||
noitaApiSubmitLogFile,
|
noitaApiSubmitLogFile,
|
||||||
polylanSubmitterApiGetUserInfo,
|
|
||||||
polylanSubmitterApiClearCache,
|
polylanSubmitterApiClearCache,
|
||||||
} from '@/api'
|
} from '@/api'
|
||||||
import type { ObjectivResultOut, LeaderboardEntryOut } from '@/api/types.gen'
|
import type { ObjectivResultOut, LeaderboardEntryOut } from '@/api/types.gen'
|
||||||
|
import { queryClient, userQuery } from '@/queries'
|
||||||
|
|
||||||
export type Objective = ObjectivResultOut
|
export type Objective = ObjectivResultOut
|
||||||
|
|
||||||
@@ -80,14 +80,10 @@ export const useNoitaStore = defineStore('noita', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const loadUserData = async (eventPath: string) => {
|
const loadUserData = async (eventPath: string) => {
|
||||||
try {
|
const user = await queryClient.fetchQuery(userQuery()).catch(() => undefined)
|
||||||
const response = await polylanSubmitterApiGetUserInfo()
|
if (user?.is_authenticated) {
|
||||||
if (response.data?.is_authenticated) {
|
userInfo.value.username = user.username ?? ''
|
||||||
userInfo.value.username = response.data.username ?? ''
|
userInfo.value.isStaff = user.is_staff || false
|
||||||
userInfo.value.isStaff = response.data.is_staff || false
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Error fetching user info:', err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all([fetchUserResults(eventPath), fetchLeaderboard(eventPath)])
|
await Promise.all([fetchUserResults(eventPath), fetchLeaderboard(eventPath)])
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
import { defineStore } from 'pinia'
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import { polylanSubmitterApiGetUserInfo } from '@/api'
|
|
||||||
|
|
||||||
interface UserInfo {
|
|
||||||
username: string
|
|
||||||
isAuthenticated: boolean
|
|
||||||
isStaff: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useUserStore = defineStore('user', () => {
|
|
||||||
const userInfo = ref<UserInfo>({
|
|
||||||
username: '',
|
|
||||||
isAuthenticated: false,
|
|
||||||
isStaff: false,
|
|
||||||
})
|
|
||||||
const isLoading = ref(false)
|
|
||||||
const error = ref<string>('')
|
|
||||||
|
|
||||||
const loadUserData = async () => {
|
|
||||||
isLoading.value = true
|
|
||||||
try {
|
|
||||||
const response = await polylanSubmitterApiGetUserInfo()
|
|
||||||
if (response.data) {
|
|
||||||
const user = response.data
|
|
||||||
userInfo.value.isAuthenticated = user.is_authenticated || false
|
|
||||||
userInfo.value.username = user.username || ''
|
|
||||||
userInfo.value.isStaff = user.is_staff || false
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
error.value = 'Failed to fetch user info'
|
|
||||||
console.error('Error fetching user info:', err)
|
|
||||||
} finally {
|
|
||||||
isLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
userInfo,
|
|
||||||
isLoading,
|
|
||||||
error,
|
|
||||||
loadUserData,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
Reference in New Issue
Block a user