From c0d2d5a9ec10b02d8487ea4255a94ce5561c0896 Mon Sep 17 00:00:00 2001 From: Mo Tarbin Date: Sun, 16 Aug 2026 18:03:34 -0400 Subject: [PATCH] fix: update terminology from "Report a Bug" to "Report an Issue" across multiple components --- public/locales/en/common.json | 2 +- public/locales/en/settings.json | 4 +-- src/queries/ResourceQueries.jsx | 7 +++- src/service/DiagnosticsSession.js | 47 +++++++++++++++++++++---- src/service/ErrorReportService.js | 4 ++- src/views/Modals/ErrorReportModal.jsx | 6 ++-- src/views/Settings/SettingsOverview.jsx | 9 +++-- src/views/components/NavBar.jsx | 4 +-- 8 files changed, 64 insertions(+), 19 deletions(-) diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 8f7fb46..6801e6f 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -30,7 +30,7 @@ "activities": "Activities", "points": "Points", "settings": "Settings", - "reportBug": "Report a Bug" + "reportBug": "Report an Issue" }, "search": { "title": "Search", diff --git a/public/locales/en/settings.json b/public/locales/en/settings.json index ead40df..ba1e81c 100644 --- a/public/locales/en/settings.json +++ b/public/locales/en/settings.json @@ -91,8 +91,8 @@ "description": "Tell us how Donetick is working for you or request a feature." }, "bugReport": { - "title": "Report a Bug", - "description": "Something not working right? Send us the details along with a technical snapshot." + "title": "Report an Issue", + "description": "Tell us what's not working and we'll attach the technical details for you." } } }, diff --git a/src/queries/ResourceQueries.jsx b/src/queries/ResourceQueries.jsx index 343a839..be2a111 100644 --- a/src/queries/ResourceQueries.jsx +++ b/src/queries/ResourceQueries.jsx @@ -1,4 +1,6 @@ import { useQuery } from '@tanstack/react-query' + +import { setServerVersion } from '../service/DiagnosticsSession' import { GetResource } from '../utils/Fetcher' // Helper to check if we have a valid token @@ -13,10 +15,13 @@ const isTokenValid = () => { } export const useResource = () => { - const { data, isLoading, error, refetch } = useQuery({ + const { data, error, isLoading, refetch } = useQuery({ queryKey: ['resource'], queryFn: async () => { const response = await GetResource() + // The backend only names its build here, so this is also where crash + // reports learn which server version the user was talking to. + setServerVersion(response?.api_version, response?.api_commit) return response }, staleTime: 6 * 60 * 60 * 1000, // 6 hours in milliseconds diff --git a/src/service/DiagnosticsSession.js b/src/service/DiagnosticsSession.js index 7d2d3a4..0042419 100644 --- a/src/service/DiagnosticsSession.js +++ b/src/service/DiagnosticsSession.js @@ -5,7 +5,8 @@ * * Deliberately dependency-free — ApiClient imports it on the request path, so * anything imported here would risk a module cycle. Everything is in memory - * and dies with the tab; nothing is persisted. + * and dies with the tab, except the server build, which is remembered across + * launches so a crash before the first API answer still names the backend. */ const SESSION_STARTED_AT = Date.now() @@ -25,6 +26,7 @@ const routeTrail = [] const apiFailures = [] let backgroundedCount = 0 let serverVersion = null +let serverCommit = null // --------------------------------------------------------------------------- // Route trail @@ -67,6 +69,33 @@ export const getPreviousRoute = () => // Server identity // --------------------------------------------------------------------------- +const SERVER_BUILD_KEY = 'diagnostics_server_build' + +// A crash on cold start happens before /resource has answered, and that is +// exactly when knowing which backend the user is on matters most. Carrying the +// last known build across launches keeps the report from saying "not reported". +try { + const cached = JSON.parse(localStorage.getItem(SERVER_BUILD_KEY) || 'null') + serverVersion = cached?.version ?? null + serverCommit = cached?.commit ?? null +} catch { + // corrupt or unavailable storage just means we start without a known build +} + +const rememberServerBuild = (version, commit) => { + if (!version && !commit) return + serverVersion = version || serverVersion + serverCommit = commit || serverCommit + try { + localStorage.setItem( + SERVER_BUILD_KEY, + JSON.stringify({ version: serverVersion, commit: serverCommit }), + ) + } catch { + // storage full or blocked; the in-memory copy still serves this session + } +} + /** * Picks the server build out of response headers. Costs nothing when the * server doesn't send them — the field simply stays null. @@ -74,21 +103,24 @@ export const getPreviousRoute = () => export const recordServerVersionFromResponse = response => { if (serverVersion) return try { - serverVersion = + rememberServerBuild( response?.headers?.get?.('x-donetick-version') || - response?.headers?.get?.('x-api-version') || - null + response?.headers?.get?.('x-api-version'), + null, + ) } catch { // headers may be inaccessible on opaque responses; not worth reporting } } -export const setServerVersion = version => { - if (version) serverVersion = version -} +/** Authoritative source: what /resource reports about the backend build. */ +export const setServerVersion = (version, commit) => + rememberServerBuild(version, commit) export const getServerVersion = () => serverVersion +export const getServerCommit = () => serverCommit + // --------------------------------------------------------------------------- // API failures // --------------------------------------------------------------------------- @@ -176,6 +208,7 @@ export const getSessionDiagnostics = async () => { navigationType: NAVIGATION_TYPE, backgroundedCount, serverVersion, + serverCommit, previousRoute: getPreviousRoute(), routeTrail: getRouteTrail(), apiFailures: getApiFailures(), diff --git a/src/service/ErrorReportService.js b/src/service/ErrorReportService.js index 07c44c9..86ccbda 100644 --- a/src/service/ErrorReportService.js +++ b/src/service/ErrorReportService.js @@ -153,7 +153,9 @@ export const formatErrorReport = report => { session.previousRoute ? `Came from: ${session.previousRoute}` : null, '', `App: ${app.appVersion} · ${app.platform}${app.isNative ? ' (native)' : ''}`, - `Server: ${session.serverVersion ?? 'not reported'}`, + `Server: ${session.serverVersion ?? 'not reported'}${ + session.serverCommit ? ` (${session.serverCommit.slice(0, 8)})` : '' + }`, `Session: ${formatDuration(session.sessionDurationMs)} active · ${ session.navigationType ?? 'unknown' } start · backgrounded ${session.backgroundedCount ?? 0}×`, diff --git a/src/views/Modals/ErrorReportModal.jsx b/src/views/Modals/ErrorReportModal.jsx index 5c8333e..ca8caba 100644 --- a/src/views/Modals/ErrorReportModal.jsx +++ b/src/views/Modals/ErrorReportModal.jsx @@ -1,11 +1,11 @@ import { Browser } from '@capacitor/browser' import { Capacitor } from '@capacitor/core' import { - BugReportRounded, CheckRounded, ContentCopyRounded, ExpandMoreRounded, GitHub, + ReportProblemRounded, } from '@mui/icons-material' import { Box, @@ -165,7 +165,7 @@ const ErrorReportModal = ({ error, errorInfo, onClose, open }) => { } + icon={} color={isBugReport ? 'warning' : 'danger'} /> @@ -175,7 +175,7 @@ const ErrorReportModal = ({ error, errorInfo, onClose, open }) => { level='h4' sx={{ fontWeight: 700, letterSpacing: '-0.01em' }} > - {isBugReport ? 'Report a bug' : 'Report this problem'} + {isBugReport ? 'Report an issue' : 'Report this problem'} { id: 'bugreport', title: t('overview.sections.bugReport.title'), description: t('overview.sections.bugReport.description'), - icon: , + icon: , onSelect: () => setBugReportOpen(true), }, ] diff --git a/src/views/components/NavBar.jsx b/src/views/components/NavBar.jsx index 9b16cc4..f38b6d0 100644 --- a/src/views/components/NavBar.jsx +++ b/src/views/components/NavBar.jsx @@ -2,7 +2,6 @@ import { Capacitor } from '@capacitor/core' import { Archive, ArrowBack, - BugReport, FilterAlt, FolderOpen, History, @@ -10,6 +9,7 @@ import { ListAlt, Logout, MenuRounded, + ReportProblem, SearchRounded, SettingsOutlined, Toll, @@ -305,7 +305,7 @@ const NavBar = () => { }} > - + {t('navigation.reportBug')}