Implemented fix for the mobile client messages route. Root cause: - The /client/messages screen kept its in-memory thread state when the conversation query param disappeared. - On mobile, that allowed /client/messages (for example with unrelated params like ?pen=true) to continue showing the last open conversation instead of the messages list. Implementation: - Reset selectedBookingId, showThread, and stale in-memory messages when conversation is no longer present in src/app/[market]/client/messages/messages-client.tsx. - Added a regression guard in tests/unit/messaging/client-messages-route-reset-regression.test.ts. Regression tests run: - pnpm vitest run tests/unit/messaging/client-messages-route-reset-regression.test.ts tests/unit/messaging/petsitter-messages-visibility-regression.test.ts tests/unit/messaging/mobile-scroll-regression.test.ts - Result: 14 tests passed. Visual verification: - Mobile viewport: 402x680. - Verified that starting from /at/client/messages?conversation=booking:149&pen=true and removing the conversation query returns the UI to the messages list at /at/client/messages?pen=true. Screenshots saved locally: - /home/tarasowski/Coding/projects/holidog-3002/tmp/qa-127/qa-127-thread-mobile.png - /home/tarasowski/Coding/projects/holidog-3002/tmp/qa-127/qa-127-list-mobile.png
Standalone QA Hub
Issue #30
/at/client/messages · 2026-03-10 11:56:08
completed
critical
Screenshot
Stored at legacy-import/issues/127/1772475205848-95c4a942-13d1-4705-8ec3-6fd13dc53cbe.png
Metadata
Selector candidates
[
{
"matches": 1,
"score": 76,
"selector": "div.mx-auto.flex.h-full",
"strategy": "class"
},
{
"matches": 71,
"score": 60,
"selector": "div:nth-of-type(1)",
"strategy": "nth-of-type"
},
{
"matches": 0,
"score": 58,
"selector": "body \u003e div \u003e footer \u003e nav \u003e div \u003e div:nth-of-type(1)",
"strategy": "ancestor-path"
}
]
Target fingerprint
{
"ancestorPath": [
"html",
"body",
"div",
"footer",
"nav",
"div"
],
"ariaLabel": null,
"className": "mx-auto flex h-full max-w-xl items-center justify-between px-2 py-1.5",
"href": null,
"id": null,
"name": null,
"role": null,
"tagName": "div",
"textSample": "Home Suchen Nachrichten Anfragen Profil Menü"
}
Secondary signal
{
"hasFiberInstance": true,
"reactComponentStack": [
"div",
"nav",
"R",
"O",
"W",
"footer",
"i",
"c",
"s",
"x",
"f",
"T"
],
"reactOwnerStack": [],
"source": "react-fiber"
}
Layout evidence
bbox:
{
"bottom": 680,
"height": 57,
"left": 0,
"right": 402,
"top": 623,
"width": 402,
"x": 0,
"y": 623
}
viewport:
{
"height": 680,
"width": 402
}
scroll:
{
"x": 0,
"y": 415
}
screenshotMarks:
[]
DOM excerpt
<div class="mx-auto flex h-full max-w-xl items-center justify-between px-2 py-1.5"><button type="button" class="relative flex min-w-0 flex-col items-center gap-0.5 rounded-lg px-2 py-1 transition-colors duration-200 text-muted-foreground hover:text-foreground" aria-label="Home"><div class="relative"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-house h-[20px] w-[20px] flex-shrink-0" aria-hidden="true"><path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8"></path><path d="M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path></svg></div><span class="text-[9px] font-medium tracking-tight whitespace-nowrap mt-0.5">Home</span></button><button type="button" class="relative flex min-w-0 flex-col items-center gap-0.5 rounded-lg px-2 py-1 transition-colors duration-200 text-muted-foreground hover:text-foreground" aria-label="Suchen"><div class="relative"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-search h-[20px] w-[20px] flex-shrink-0" aria-hidden="true"><path d="m21 21-4.34-4.34"></path><circle cx="11" cy="11" r="8"></circle></svg></div><span class="text-[9px] font-medium tracking-tight whitespace-nowrap mt-0.5">Suchen</span></button><button type="button" aria-disabled="false" class="relative flex min-w-0 flex-col items-center gap-0.5 rounded-lg px-2 py-1 transition-colors duration-200 text-button-secondary" aria-label="Nachrichten"><div class="relative"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-message-square h-[20px] w-[20px] flex-shrink-0" aria-hidden="true"><path d="M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z"></path></svg></div><span class="text-[9px] font-medium tracking-tight whitespace-nowrap mt-0.5">Nachrichten</span></button><button type="button" aria-disabled="false" class="relative flex min-w-0 flex-col items-center gap-0.5 rounded-lg px-2 py-1 transition-colors duration-200 text-muted-foreground hover:text-foreground" aria-label="Anfragen"><div class="relative"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-wallet-cards h-[20px] w-[20px] flex-shrink-0" aria-hidden="true"><rect width="18" height="18" x="3" y="3" rx="2"></rect><path d="M3 9a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2"></path><path d="M3 11h3c.8 0 1.6.3 2.1.9l1.1.9c1.6 1.6 4.1 1.6 5.7 0l1.1-.9c.5-.5 1.3-.9 2.1-.9H21"></path></svg></div><span class="text-[9px] font-medium tracking-tight whitespace-nowrap mt-0.5">Anfragen</span></button><button type="button" class="relative flex min-w-0 flex-col items-center gap-0.5 rounded-lg px-2 py-1 transition-colors duration-200 text-muted-foreground hover:text-foreground" aria-label="Profil"><div class="relative"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-user h-[20px] w-[20px] flex-shrink-0" aria-hidden="true"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg></div><span class="text-[9px] font-medium tracking-tight whitespace-nowrap mt-0.5">Profil</span></button><button type="button" aria-label="Menü" class="flex min-w-0 flex-col items-center gap-0.5 rounded-lg px-2 py-1 transition-colors duration-200 text-muted-foreground hover:text-foreground"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-menu h-[20px] w-[20px] flex-shrink-0" aria-hidden="true" data-sentry-element="MenuIcon" data-sentry-source-file="ClientBottomNav.tsx"><path d="M4 12h16"></path><path d="M4 18h16"></path><path d="M4 6h16"></path></svg><span class="text-[9px] font-medium tracking-tight whitespace-nowrap mt-0.5">Menü</span></button></div>
Thread
qa-user
2026-03-10 11:56:08
qa-user
2026-03-10 12:01:32
Visual check after route reset: mobile messages list is shown at /at/client/messages?pen=true.
qa-127-list-mobile.png
qa-user
2026-03-10 12:01:32
Visual check before route reset: mobile thread view still open.
qa-127-thread-mobile.png