Skip to content

Commit a4faae0

Browse files
fix(feedback): stop the Sentry report button covering "Next" on mobile
Sentry's feedback integration ran with `autoInject: true`, which plants a fixed 50px actor button in the bottom-right corner. On a 390x844 viewport that landed on top of the lesson footer's primary action: the actor at (324,778,50x50) covered roughly 72% of the "Next" button at (338,796,40x40), so tapping to advance a lesson opened a bug report instead. Reporting a bug is a rare action, so it no longer holds prime thumb real estate. `autoInject` is off and the trigger is ours: - `components/shared/feedback-button.tsx` renders a 44px icon-only puck that rests dimmed (opacity .45) on the right edge at 62% height, clear of both the dashboard header and any bottom action bar. Measured clearance from "Next" is 259px. - It can be dragged anywhere, snaps to the nearest edge, clamps inside the viewport (respecting `env(safe-area-inset-*)` via a probe element), and remembers where it was parked in localStorage. - Opening lives on `click`, not `pointerup`, so Enter and Space work; a drag sets a flag that suppresses the trailing click. Arrow keys reposition it, since dragging is pointer-only. - Position moves via `transform` only, never a layout property, and the transition list drops `transform` mid-drag so the puck tracks the finger exactly and eases only when snapping home. Reduced motion is honoured. - `components/user-nav.tsx` gains a "Report a problem" item: the discoverable entry point, at zero screen cost. Availability and reduced-motion are read through `useSyncExternalStore` with a `false` server snapshot, so the puck can't appear in the first client render where the server rendered nothing. The dialog itself was English-only for Spanish tenants; it's built outside React so it can't reach next-intl, but `<html lang>` is server-rendered and readable at init, so the form strings are now localized too. The dialog also follows the app's resolved theme rather than the OS, which was wrong whenever a user had overridden the theme in-app. Verified in Chrome at 390x844 against the seeded student on a real lesson page: bug reproduced with `autoInject` flipped back on (overlap true), then gone after (overlap false); drag snaps and persists across navigation; keyboard nudges move it 62px per press; dialog opens and reads correctly in both en and es. Build, typecheck and lint clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FJ4dqwXuyKUPtg11ni5BSb
1 parent a6c88d3 commit a4faae0

7 files changed

Lines changed: 503 additions & 3 deletions

File tree

app/[locale]/layout.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Geist, Geist_Mono, Noto_Sans } from "next/font/google";
33
import "../globals.css";
44
import { Toaster } from "@/components/ui/sonner";
55
import { RouteProgress } from "@/components/shared/route-progress";
6+
import { FeedbackButton } from "@/components/shared/feedback-button";
67
import { ThemeProvider } from "@/components/theme-provider";
78
import { TenantProvider } from "@/components/tenant/tenant-provider"
89
import { TenantCssVars } from "@/components/tenant/tenant-css-vars";
@@ -170,6 +171,7 @@ export default async function RootLayout({
170171
<TenantCssVars />
171172
<RouteProgress />
172173
{children}
174+
<FeedbackButton />
173175
<Toaster />
174176
</TenantProvider>
175177
</ThemeProvider>

0 commit comments

Comments
 (0)