Adds a public funnel landing at `/` and moves the login to `/login`, rebuilt around the panel's own colors instead of an invented palette. Landing (`src/components/landing/`, one section per file, no props): - Seven funnel sections composed by `LandingPage`. The hero's eight swatches are literally `PIE_COLORS` from `DashboardPage`, the same hex values the seed hands to avatars and services, so "your colors become your numbers" is literal. - `BrandMark` becomes the single source for the logo, replicating `public/favicon.svg`. Blue is the action surface, orange only ever marks. - `NotebookVisual` is the one deliberate exception to the palette: it is what the product replaces. - Copy drops all system vocabulary; motion comes from `src/lib/motion.ts` with a single easing, and reduced-motion resolves `initial` to the final state so a never-firing `whileInView` cannot leave a section invisible forever. Routing and bundle: - `homePathFor` is the single definition of each role's destination. - Landing, login, dashboard and calendar load lazily. Eager, the login dragged framer-motion (~40 KB gz) into every panel load and the landing downloaded recharts + FullCalendar (~187 KB gz) without charting anything. `clsx` is pinned to the `react` chunk because Rollup otherwise assigns it to `charts`, making the entry import 111 KB gz for a 200-byte utility. Responsiveness (iPhone/iPad), verified with `npm run audit:responsive`: - No touch form field below 16px, `dvh` height utilities, safe-area insets, and 40px touch targets keyed off `pointer: coarse` rather than `sm:`. - New `.ld-gutter`: `.safe-x` lives outside `@layer` and beats Tailwind's `px-*`, so it left the login's side padding at 0 on anything but an iPhone in landscape. No overflow check could see it — there was no overflow, just zero margin. The audit now guards it with a `gutter` check. - `shell-height` no longer fires on pages that legitimately scroll; the static `raw-viewport-unit` scan covers those instead. Production build: - The Dockerfile now sets `VITE_DEMO_UI=1` as a build arg. `DEMO` is a build-time constant, so without it Vite eliminated the magic login and the "Ver como…" switcher: the deployed landing promised "no registration" and led to an empty form. Verified by building both ways and diffing the bundle. - Service worker cache bumped to v2 so the orphaned pre-landing chunks get purged from returning visitors' caches. Verified: typecheck clean; unit 39/39, e2e 33/33, admin 17/17, booking 12/12, landing 13/13 (WebKit), PWA passed against the real production build. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
146 lines
5.1 KiB
Markdown
146 lines
5.1 KiB
Markdown
# Task 3 Report: Add Install Detection and UI
|
|
|
|
## Status
|
|
|
|
Implemented Task 3 only. The install hook detects standalone mode, Chromium's deferred install event, and iOS Safari instructions. The reusable prompt is rendered once in each required shell surface and uses the existing modal/button/icon patterns.
|
|
|
|
## Changed files
|
|
|
|
- `src/lib/useInstallPrompt.ts`: added the browser-only install state hook, local deferred-event type, event listener lifecycle, install action, and dismissal behavior.
|
|
- `src/components/InstallAppPrompt.tsx`: added the reusable Chromium/iOS install action and iOS instructions modal.
|
|
- `src/index.css`: added `.safe-area-bottom` using `env(safe-area-inset-bottom)`.
|
|
- `src/pages/LoginPage.tsx`: added one compact install action below the login form.
|
|
- `src/components/AppShell.tsx`: added one install action to the mobile header.
|
|
- `src/components/AdminShell.tsx`: added one install action to the mobile header.
|
|
|
|
## Verification
|
|
|
|
### Typecheck
|
|
|
|
Command:
|
|
|
|
```text
|
|
npm.cmd run typecheck
|
|
```
|
|
|
|
Output:
|
|
|
|
```text
|
|
> [email protected] typecheck
|
|
> tsc -b --noEmit
|
|
```
|
|
|
|
Exit code: `0`.
|
|
|
|
### Production build
|
|
|
|
Command:
|
|
|
|
```text
|
|
npm.cmd run build
|
|
```
|
|
|
|
Output summary:
|
|
|
|
```text
|
|
Preflight OK: Node v26.4.0.
|
|
vite v5.4.21 building for production...
|
|
✓ 2465 modules transformed.
|
|
✓ built in 4.08s
|
|
```
|
|
|
|
Exit code: `0`.
|
|
|
|
### Diff validation
|
|
|
|
Command:
|
|
|
|
```text
|
|
git diff --check
|
|
```
|
|
|
|
Result: no whitespace errors. Git emitted only existing LF/CRLF conversion notices for worktree files.
|
|
|
|
## Self-review
|
|
|
|
- The hook uses a local `BeforeInstallPromptEvent` interface and does not add an unsafe global declaration.
|
|
- `beforeinstallprompt` and `appinstalled` listeners are removed on unmount.
|
|
- Standalone detection suppresses the CTA, and unsupported browsers remain unchanged.
|
|
- iOS instructions are limited to Safari and the existing `Modal` owns backdrop/Escape close behavior.
|
|
- The safe-area utility is applied only inside the iOS modal content.
|
|
- Each shell renders exactly one prompt instance outside `SidebarContent`, avoiding duplicate listeners from the desktop/mobile sidebar duplication.
|
|
- The accessible action text remains `Instalar AgendaMax` in every supported prompt.
|
|
- No Task 4 tests or documentation changes were added.
|
|
|
|
## Concerns
|
|
|
|
- No browser-level visual/manual check was run; verification was limited to the required typecheck, production build, and diff inspection.
|
|
- `git diff --check` reports line-ending notices from the existing Windows worktree configuration, not whitespace failures.
|
|
|
|
## Preserved worktree changes
|
|
|
|
Existing `.superpowers/sdd/*` changes and untracked `graphify-out/*` artifacts were not reverted or staged.
|
|
|
|
## Review Fixes
|
|
|
|
- `src/lib/useInstallPrompt.ts`: added a ref-based in-flight guard so rapid clicks can invoke the native prompt only once. The deferred event is restored when `prompt()` or `userChoice` fails, the error is contained, and the state returns to `available` for retry. `appinstalled` now clears dismissal before setting `installed`.
|
|
- `src/components/Modal.tsx`: added `aria-label="Cerrar"` to the shared icon-only close button.
|
|
- `src/components/InstallAppPrompt.tsx`: added an explicit `compact` presentation. Header instances use a fixed icon button with a screen-reader label and tooltip, while Login keeps the full visible action label.
|
|
- `src/components/AppShell.tsx` and `src/components/AdminShell.tsx`: enabled the compact prompt presentation in the narrow mobile headers.
|
|
|
|
## Review Fix Verification
|
|
|
|
### Typecheck
|
|
|
|
Command:
|
|
|
|
```text
|
|
npm.cmd run typecheck
|
|
```
|
|
|
|
Output:
|
|
|
|
```text
|
|
> [email protected] typecheck
|
|
> tsc -b --noEmit
|
|
```
|
|
|
|
Exit code: `0`.
|
|
|
|
### Production build
|
|
|
|
Command:
|
|
|
|
```text
|
|
npm.cmd run build
|
|
```
|
|
|
|
Output summary:
|
|
|
|
```text
|
|
Preflight OK: Node v26.4.0.
|
|
vite v5.4.21 building for production...
|
|
✓ 2465 modules transformed.
|
|
✓ built in 3.95s
|
|
```
|
|
|
|
Exit code: `0`.
|
|
|
|
### Diff inspection
|
|
|
|
`git diff --check` reported no whitespace errors. The only messages were existing Windows LF/CRLF conversion notices. The implementation diff contains only the hook, shared prompt, shared modal accessibility, and two mobile header call-site fixes described above.
|
|
|
|
## Review Fix Self-Review
|
|
|
|
- A second click while `installInFlight.current` is true returns immediately, including clicks occurring after React has scheduled the deferred-event state update.
|
|
- Failed native prompt or choice promises no longer produce an unhandled rejection and restore the captured event for a retryable `available` state.
|
|
- A later `appinstalled` event overrides any prior dismissal and returns the hook state as `installed`.
|
|
- Both modal close mechanisms remain intact, and the icon-only close control now has an accessible name.
|
|
- Header install controls are compact without hiding the action from assistive technology; the full accessible name remains `Instalar AgendaMax`.
|
|
- No unrelated worktree files were modified or staged, and no Task 4 tests or documentation were added.
|
|
|
|
## Remaining Concerns
|
|
|
|
- No browser-level visual/manual check was run; verification is limited to typecheck, production build, and source diff inspection.
|
|
- The existing Windows worktree continues to emit LF/CRLF conversion notices during Git operations.
|