Fixed in local code and verified. Root cause: - The petsitter dashboard used its own older failed-payout banner copy and routed sitters to `/petsitter/bookings`. - The bookings/messages surfaces already treated failed payouts as a payment-details problem, so the dashboard drifted away from the intended action and wording. Implementation: - Added a small shared helper for failed-payout alert content so sitter surfaces use one title/description/CTA model. - Updated the dashboard failed-payout card to point to `/petsitter/payments` instead of bookings. - Switched bookings/messages to the same helper so the copy and CTA stay consistent. - Updated petsitter payout translations in en/de/fr/es/it/nl for the new title, singular/plural description, and CTA label. Regression coverage: - `tests/unit/lib/petsitter-failed-payout-alert.test.ts` - Adjacent non-bug check in the same test file: no alert is returned when failed payout count is `0`. - Nearby existing check rerun: `tests/unit/lib/petsitter-dashboard-capacity.test.ts` Commands run: - `pnpm exec vitest run tests/unit/lib/petsitter-failed-payout-alert.test.ts tests/unit/lib/petsitter-dashboard-capacity.test.ts` -> pass - `pnpm exec eslint src/lib/petsitter-failed-payout-alert.ts tests/unit/lib/petsitter-failed-payout-alert.test.ts src/app/[market]/petsitter/dashboard/page.tsx src/app/[market]/petsitter/bookings/page.tsx src/app/[market]/petsitter/messages/page.tsx src/lib/translations/petsitter/en/stripe.ts src/lib/translations/petsitter/de/stripe.ts src/lib/translations/petsitter/fr.ts src/lib/translations/petsitter/es.ts src/lib/translations/petsitter/it.ts src/lib/translations/petsitter/nl.ts` -> pass (existing dashboard `any` warnings only; no new lint errors) - `pnpm exec tsc --noEmit --pretty false` -> pass - `node scripts/check-translations.mjs` -> pass Visual verification: - Reproduction result: partially confirmed from live staging issue payload and screenshot evidence; direct staging route replay was auth-gated in this environment. - Seeded a local payout scenario, marked one payout as `failed`, and logged in as `test-payout-sitter@holidog.local` on `http://localhost:3010/at/petsitter/dashboard`. - Confirmed the alert now shows the updated failed-payout message and a direct payment-details CTA. - Confirmed the CTA navigates to `http://localhost:3010/at/petsitter/payments`. - Console check: no console messages on the verified dashboard load. - Network check: core dashboard/page assets returned `200`; only a non-critical aborted polling request (`/api/events/poll`) appeared during page activity. Artifacts: - Screenshot upload to the QA thread was blocked in this environment: the QA hub host `qa.staging.holidog.com` does not resolve here, and the staging support-attachment presign flow requires an authenticated staging session that is not available to this automation path. - Local evidence files: - `/tmp/qa-fix-188-after.png` -> full-page dashboard after fix - `/tmp/qa-fix-188-detail.png` -> viewport screenshot showing the corrected payout alert and CTA Residual risk: - Low. The code path is covered by a focused regression test and verified in-browser. Remaining limitation is evidence attachment upload from this environment, which is documented above.
Standalone QA Hub
Issue #71
/at/petsitter/dashboard · 2026-03-10 13:38:16
completed
high
Screenshot
Stored at legacy-import/issues/188/1773072709912-a95f33fe-7301-4262-b73e-aef86f97c35c.png
Metadata
Selector candidates
[
{
"matches": 5,
"score": 76,
"selector": "div.rounded-lg.shadow-sm.border",
"strategy": "class"
},
{
"matches": 219,
"score": 60,
"selector": "div:nth-of-type(1)",
"strategy": "nth-of-type"
},
{
"matches": 3,
"score": 58,
"selector": "#action-required-section \u003e div \u003e div \u003e div:nth-of-type(1)",
"strategy": "ancestor-path"
}
]
Target fingerprint
{
"ancestorPath": [
"#action-required-section",
"div",
"div"
],
"ariaLabel": null,
"className": "rounded-lg shadow-sm border border-gray-100 border-l-4 p-5 border-l-red-500 bg-red-50",
"href": null,
"id": null,
"name": null,
"role": null,
"tagName": "div",
"textSample": "Payout Issue Alert 2 payouts have failed. Please update your payment details or contact support. 2 Bookings"
}
Secondary signal
{
"hasFiberInstance": true,
"reactComponentStack": [
"div",
"ew",
"section",
"eC",
"Content",
"o",
"eV",
"x",
"c",
"f",
"T",
"E"
],
"reactOwnerStack": [],
"source": "react-fiber"
}
Layout evidence
bbox:
{
"bottom": 434,
"height": 127,
"left": 529,
"right": 1711,
"top": 307,
"width": 1182,
"x": 529,
"y": 307
}
viewport:
{
"height": 1120,
"width": 1920
}
scroll:
{
"x": 0,
"y": 0
}
screenshotMarks:
[]
DOM excerpt
<div class="rounded-lg shadow-sm border border-gray-100 border-l-4 p-5 border-l-red-500 bg-red-50"><div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4"><div class="flex-1"><div class="flex items-center gap-2 mb-1"><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-triangle-alert w-4 h-4 text-red-500" aria-hidden="true"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"></path><path d="M12 9v4"></path><path d="M12 17h.01"></path></svg><h3 class="font-bold text-gray-900">Payout Issue Alert</h3></div><p class="text-sm text-gray-600 mb-3">2 payouts have failed. Please update your payment details or contact support.</p><span class="inline-flex bg-white border border-gray-200 text-gray-700 text-xs font-semibold px-2 py-0.5 rounded">2</span></div><div class="flex flex-col gap-2 md:flex-row md:gap-3"><a class="px-6 py-2.5 bg-[#7FBCE6] hover:bg-[#5FA5D1] text-white font-semibold rounded-lg transition-colors whitespace-nowrap text-center" href="/at/petsitter/bookings">Bookings</a></div></div></div>
Thread
qa-user
2026-03-10 13:38:13