From 3d040dd37729f9b9b2b396ffb95eec532418be15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Gremaud?= Date: Fri, 16 Oct 2026 02:03:54 +0200 Subject: [PATCH] fix(submissions): top-header icon for live connection (ws) --- polylan_submitter/src/Submissions.vue | 10 +-- .../composables/useSubmissionsWebSocket.ts | 7 +- polylan_submitter/src/layout/AppHeader.vue | 69 +++++++++++++++---- polylan_submitter/src/locales/en.json | 11 +++ polylan_submitter/src/stores/pageHeader.ts | 10 ++- 5 files changed, 81 insertions(+), 26 deletions(-) diff --git a/polylan_submitter/src/Submissions.vue b/polylan_submitter/src/Submissions.vue index 34c58ae..d3b0ca8 100644 --- a/polylan_submitter/src/Submissions.vue +++ b/polylan_submitter/src/Submissions.vue @@ -477,7 +477,7 @@ const loadUserSubmissions = async () => { // Match over (or user moved off it): back to the picker, which auto-enters // the next match when there's only one, so players follow along without a refresh. -const { isConnected: wsConnected } = useSubmissionsWebSocket({ +useSubmissionsWebSocket({ userSubmissions, onScopeUpdate: (scope) => { if (scope.id !== props.scopeId || (scope.is_active && scope.assigned)) return; @@ -557,14 +557,6 @@ onUnmounted(() => {
- -
-
- - {{ wsConnected ? t("submissions.live") : t("submissions.offline") }} -
-
-
diff --git a/polylan_submitter/src/composables/useSubmissionsWebSocket.ts b/polylan_submitter/src/composables/useSubmissionsWebSocket.ts index f365f88..f4e2c65 100644 --- a/polylan_submitter/src/composables/useSubmissionsWebSocket.ts +++ b/polylan_submitter/src/composables/useSubmissionsWebSocket.ts @@ -1,5 +1,6 @@ -import { ref, computed } from 'vue' +import { ref, computed, watch } from 'vue' import { useWebSocket } from '@vueuse/core' +import { usePageHeaderStore } from '@/stores/pageHeader' interface SubmissionUpdate { id: string @@ -107,6 +108,10 @@ export function useSubmissionsWebSocket({ userSubmissions, onScopeUpdate }: Opti }, }) + // Live badge in AppHeader (reset by the router on the next navigation) + const pageHeaderStore = usePageHeaderStore() + watch(isConnected, (connected) => pageHeaderStore.setLive(connected), { immediate: true }) + const handleSubmissionUpdate = (submission: SubmissionUpdate) => { const existingIndex = userSubmissions.value.findIndex((s: any) => s.id === submission.id) diff --git a/polylan_submitter/src/layout/AppHeader.vue b/polylan_submitter/src/layout/AppHeader.vue index ba4f7ec..f2670e5 100644 --- a/polylan_submitter/src/layout/AppHeader.vue +++ b/polylan_submitter/src/layout/AppHeader.vue @@ -11,7 +11,7 @@ const router = useRouter(); const { t } = useI18n(); const userInfo = useUser(); const pageHeaderStore = usePageHeaderStore(); -const { title: dynamicTitle, backRoute: dynamicBackRoute } = storeToRefs(pageHeaderStore); +const { title: dynamicTitle, backRoute: dynamicBackRoute, live } = storeToRefs(pageHeaderStore); const title = computed(() => { if (dynamicTitle.value) return dynamicTitle.value; @@ -29,22 +29,61 @@ const goBack = () => { diff --git a/polylan_submitter/src/locales/en.json b/polylan_submitter/src/locales/en.json index a30074e..1a4354b 100644 --- a/polylan_submitter/src/locales/en.json +++ b/polylan_submitter/src/locales/en.json @@ -260,6 +260,17 @@ "notRunning": "Sync wasn't running.", "stopFailed": "Failed to stop the sync." }, + "liveStatus": { + "liveTitle": "You're connected live", + "liveIntro": "This page updates on its own, you don't need to refresh it:", + "liveSubmissions": "Your submissions update as they're processed (uploaded files, text read from your screenshots).", + "liveMatches": "When your match ends, you're sent back to the match list, and straight into your next match if you have only one.", + "liveNoRefresh": "Just keep this page open between matches.", + "offlineTitle": "Live connection lost", + "offlineIntro": "The page can't get updates right now, so it won't move you to your next match or show processing results on its own.", + "offlineReconnect": "It reconnects automatically, usually within a few seconds.", + "offlineRefresh": "Still offline after a while? Refresh the page. Anything you already submitted is saved." + }, "errorPage": { "notFound": { "title": "Page not found", diff --git a/polylan_submitter/src/stores/pageHeader.ts b/polylan_submitter/src/stores/pageHeader.ts index deb9839..d1f7ddd 100644 --- a/polylan_submitter/src/stores/pageHeader.ts +++ b/polylan_submitter/src/stores/pageHeader.ts @@ -11,6 +11,9 @@ export const usePageHeaderStore = defineStore("pageHeader", () => { // Overrides route.meta.getBackRoute when the right target depends on // fetched data (e.g. skip the scope picker when it would auto-redirect). const backRoute = ref(null); + // Live (websocket) connection state of the page, shown mid-header; null + // when the page has no live connection (no badge at all). + const live = ref(null); const setTitle = (value: string) => { title.value = value; @@ -20,10 +23,15 @@ export const usePageHeaderStore = defineStore("pageHeader", () => { backRoute.value = value; }; + const setLive = (value: boolean | null) => { + live.value = value; + }; + const clear = () => { title.value = ""; backRoute.value = null; + live.value = null; }; - return { title, backRoute, setTitle, setBackRoute, clear }; + return { title, backRoute, live, setTitle, setBackRoute, setLive, clear }; });