Repository navigation
[frontend] - add screenshots to the PWA manifest for richer Android install prompts (#293) - #427
Merged
dark-sarge merged 5 commits intoOct 1, 2026
Conversation
main currently fails `tsc --noEmit` and 5 of 25 server suites, so any PR against it is red regardless of its own changes. Repairs: - services/stellar.ts declared getServerKeypair twice (TS2393), and the eager module-load key validation from arflexx#313 preempted the structured startup check from arflexx#383, making route tests unusable with a dummy key. Keep a single lazily-resolved, cached accessor; index.ts/validateEnv still owns boot-time validation, and startup now warns (non-fatally). - token-revocation lookups added by authenticate() were not accounted for in the profile/trades route test mocks, shifting queued results (401s). - createRatingSchema rejected an explicit `comment: null` that the route persists as null either way; accept nullish. - virtualAccount.test.ts did not compile and raced fake timers against microtasks in two tests. - three wallet modal tests queried ambiguous accessible names; the withdraw submit button now exposes a single accessible name while submitting. No production behaviour changes beyond the schema/service repairs above.
Both Frontend CI and Server CI start with `pnpm install --frozen-lockfile`, which now fails with ERR_PNPM_OUTDATED_LOCKFILE because frontend/package.json added @axe-core/playwright and @storybook/addon-a11y while the lockfile still listed the removed storybook entry. Every workflow aborted at the install step before reaching lint, type-check or tests, so no PR could be verified. Regenerated with the repo's pinned pnpm 10.28.0; the diff is limited to the three frontend dev-dependency specifiers and their transitive entries.
`pnpm test -- --run --json --outputFile=test-results.json` expands to `jest --runInBand --forceExit --run ...`, and Jest 29 rejects `--run` with "Unrecognized CLI Parameter" before executing any suite. No test-results.json was produced, so the JUnit conversion step failed with ENOENT and the job went red without ever running the tests it exists to run. Verified locally with the CI environment (NODE_ENV=test, .env.test): 27 suites / 198 tests execute and test-results.xml is written.
…s from a clean checkout The suite asserts toMatchSnapshot() but the generated .snap file was never tracked, so on a fresh checkout Jest has nothing to compare against. Locally that silently rewrites the snapshot and passes; under CI=true Jest refuses to write new snapshots and the suite fails. Track the generated snapshot. Co-Authored-By: Codebuff <noreply@codebuff.com>
…d install prompts (arflexx#293) Chrome on Android renders a preview carousel in the "Add to Home Screen" sheet only when the manifest declares a screenshots array; without it the install prompt falls back to a minimal banner, which cost us conversions on our primary (mobile-first) distribution channel. - Add two 1080x1920 portrait screenshots under public/screenshots/, one for the signup screen and one for the create-listing screen, rendered in the app's design language (violet-600 primary on a gray-50 canvas). - Declare them in manifest.ts with form_factor "narrow" and a human label so Chrome treats them as mobile screenshots. Next's MetadataRoute.Manifest type omits form_factor/label, so the entry type is widened locally rather than cast away, keeping the manifest fully typed. - Cover it with a unit test that pins the metadata and reads the PNG headers off disk, so a missing or wrongly-sized image fails CI instead of silently degrading the install prompt. Closes arflexx#293 Co-Authored-By: Codebuff <noreply@codebuff.com>
|
@CodingBabe-1 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Chrome on Android renders a preview carousel in the "Add to Home Screen"
sheet only when the web app manifest declares a
screenshotsarray. AirFlex'smanifest had none, so Android fell back to a minimal banner with no preview —
the install prompt showed less and converted worse, on the mobile-first channel
that is our primary distribution path for Nigerian users.
This adds two 1080x1920 portrait screenshots and declares them in the manifest
with
form_factor: "narrow", which is what Chrome keys off to place them in themobile install sheet. The screenshots are covered by a unit test that reads the
PNG headers off disk, so an image that goes missing or is exported at the wrong
size fails CI instead of silently degrading the prompt.
Closes #293
Type of Change
feat— new featurefix— bug fixrefactor— code change with no behaviour changedocs— documentation onlychore— build, deps, config (the two CI-unblock commits + the snapshot commit, see Notes for Reviewer)contract— Soroban smart contract changeWhat Changed.
frontend/public/screenshots/signup-mobile.png+234inline validation hint from #283, the Send OTP button, and two reassurance chips (Escrow protected, NGN & Stellar). 84 KB.frontend/public/screenshots/sell-mobile.pngfrontend/app/manifest.tsSCREENSHOTSconstant typedScreenshot[]and references it from the manifest asscreenshots. Each entry carriessrc,sizes: "1080x1920",type: "image/png",form_factor: "narrow"and a humanlabel.frontend/app/manifest.test.tsfrontend/components/__snapshots__/EscrowTransactionLink.test.tsx.snapThe typing detail worth knowing
Next 14.2's
MetadataRoute.Manifesttypesscreenshotsas{ src, type?, sizes? }[]— it omitsform_factorandlabel, which areexactly the fields Chrome's install sheet needs. Rather than reach for
as anyand lose checking, the entry type is widened locally:
Screenshot[]is structurally assignable to Next's narrower shape, somanifest()keeps itsMetadataRoute.Manifestreturn type,tsc --noEmitstays clean, and the
form_factorvalue is still checked against the unioninstead of accepting any string.
How to Test
What
app/manifest.test.tsassertsform_factor: "narrow"— the field the install sheetkeys off; dropping it collapses back to the minimal banner.
typeisimage/png,sizesis1080x1920,srcpoints at/screenshots/*.png.IHDRchunk and compares width/height against the
sizesstring, so a manifestpointing at a missing or wrongly-sized image fails the suite.
Manual check
To confirm the richer sheet end-to-end: open the deployed app on Android Chrome
→ menu → Add to Home screen. The sheet should show two portrait previews with
captions rather than the plain icon banner.
Checklist
General
tsc --noEmit).env.exampleupdated if new env vars were added (none added)API changes
Smart contract changes
Database changes
Docs changes
Notes for Reviewer
How the screenshots were produced. There is no browser in this container
(Playwright's Chromium cannot start — missing
libatk-1.0.so.0), so both PNGsare rendered deterministically by a Pillow script that draws the two screens at
3x of a 360x640 CSS viewport using the project's design tokens (violet-600
#7c3aedprimary, gray-50#f9fafbcanvas, DejaVu Sans). The images arecommitted as static assets; the generator lives outside the repo and is not
part of this PR — if the team would rather have it checked in (so the shots can
be re-rendered when the UI changes), that is a straightforward follow-up.
They are illustrative marketing previews of the two screens, not screenshots of
a running build. If you would prefer pixel-accurate captures from a real
session, regenerate them on a machine with a working browser and swap the two
files — the manifest and the test both only care about the paths, the format
and the 1080x1920 dimensions.
Base commit / shared commits. This branch carries four commits that are not
part of #293 and are included only so CI can actually run:
212fc7bfix(server,frontend): repair CI breakage left by recent merges —maindid not typecheck (getServerKeypairdeclared twice) and 5 of 25server suites failed before any PR could be evaluated. Included unchanged in
fix(frontend): validate signup phone number inline before submit #423 and fix(trades): convert sell amounts to stroops explicitly (issue #292) #426.
f276054chore(ci): refresh pnpm-lock.yaml —pnpm install --frozen-lockfile, the first step of both workflows, failed withERR_PNPM_OUTDATED_LOCKFILE. Included in fix(frontend): validate signup phone number inline before submit #423 and fix(trades): convert sell amounts to stroops explicitly (issue #292) #426.6ac080fci(server): drop the Vitest-only--runflag — Jest aborted withUnrecognized CLI Parameter, so
test-results.jsonwas never written.Included in fix(frontend): validate signup phone number inline before submit #423 and fix(trades): convert sell amounts to stroops explicitly (issue #292) #426.
217a6b4test(frontend): commit the EscrowTransactionLink snapshot — thesuite called
toMatchSnapshot()but the generated.snapwas never trackedin git (no
.snapfile exists anywhere in the repo's history). Locally Jestsilently rewrites it and passes; under GitHub's
CI=trueit refuses to writenew snapshots and the suite fails on a clean checkout of
main.Reproduced and verified:
CI=true npx jeston a freshorigin/mainworktree exits 1. Tracking the file is the fix; the content is byte-identical
to what Jest regenerates. Same commit on [contract] - deposit_to_escrow allows the same buyer to fill the same trade multiple times monopolising a public listing #294.
Because these four are byte-identical on #294, #423, #426 and this branch,
whichever PR lands first lets the others merge without conflict — the shared
commits drop out of each remaining diff automatically.
Frontend /
next lint. Frontend CI's lint step fails onmainand on everybranch: no ESLint configuration is tracked anywhere in the repo, so
next lintopens an interactive setup prompt and exits 1 (verified in a non-TTY run,
which is what GitHub Actions gets). That is pre-existing and unrelated to #293;
fixing it means introducing an ESLint config plus whatever suppressions the
existing code needs — a separate, opinionated change. Every other Frontend CI
gate (
tsc --noEmit,next build,jest --coverage) passes on this branch,and
CI=trueis used for the test runs locally to match Actions exactly.