Skip to content

Feat/marketing landing - #95

Merged
evan-taylor merged 10 commits into
devfrom
feat/marketing-landing
Apr 21, 2026
Merged

Feat/marketing landing#95
evan-taylor merged 10 commits into
devfrom
feat/marketing-landing

Conversation

@dfed25

@dfed25 dfed25 commented Apr 18, 2026

Copy link
Copy Markdown
Collaborator

Linked Issues

Closes #
Linear: (e.g., POLY-123)

Summary

Briefly explain the change and why.

How to Test

Steps to verify locally:

  • npm run lint
  • npm run typecheck
  • npm test
  • Manual flow:
    1. npm run dev:backend (in terminal A)
    2. npm run dev (in terminal B)
    3. Verify the change: <describe expected behavior/screens>

Checklist

  • Tests added/updated (if applicable)
  • Lint/tests pass locally (npm run lint)
  • Docs updated (README/ADR/changelog if needed)
  • Follows conventional commit format
  • No merge conflicts with dev

Screenshots / Demos

(if UI or visible behavior - attach images, videos, or GIFs)

Summary by CodeRabbit

  • New Features

    • Added a web landing experience with hero, value propositions, social proof, and app download flows (QR, email, App Store badge).
    • Web flows now show in-app prompts/alerts when saving or creating listings instead of forcing login redirects.
  • Documentation

    • Published Privacy Policy and Terms of Service pages accessible from the site.
  • Chores

    • Standardized routing/navigation to use /home as the primary landing route.

dfed25 added 4 commits April 13, 2026 21:59
Expo resolves @sentry/react-native/expo relative to the frontend package; it was only on the root workspace so Vercel installs did not expose the plugin and expo export failed.

Made-with: Cursor
- Add web-only landing at / with value props, CTAs, and App Store compliance
- Desktop: QR code and mailto draft for the download link
- Narrow web: official App Store badge linking to APP_STORE_URL
- Rename (tabs)/index to home so / is the landing without route conflicts
- Point in-app "home" navigation and post-auth default to /home
- Register root index in the stack; dedupe @sentry/react-native in package.json
- Refresh lockfile so workspace resolves expo-blur for typecheck/bundling

Made-with: Cursor
@vercel

vercel Bot commented Apr 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
poly-buys Ready Ready Preview, Comment Apr 21, 2026 2:13am

@coderabbitai

coderabbitai Bot commented Apr 18, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@evan-taylor has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 35 minutes and 19 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 35 minutes and 19 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 90eaf3aa-0850-48fa-a978-964896af25b7

📥 Commits

Reviewing files that changed from the base of the PR and between d441cfd and 3b4fc10.

📒 Files selected for processing (26)
  • TERMS_OF_SERVICE.md
  • frontend/app/auth/login.tsx
  • frontend/app/privacy.web.tsx
  • frontend/app/terms.web.tsx
  • frontend/components/LandingScreen.web.tsx
  • frontend/components/landing/AppleIcon.tsx
  • frontend/components/landing/Brand.tsx
  • frontend/components/landing/Button.tsx
  • frontend/components/landing/DownloadButton.tsx
  • frontend/components/landing/Eyebrow.tsx
  • frontend/components/landing/GetApp.tsx
  • frontend/components/landing/Hero.tsx
  • frontend/components/landing/LegalDocument.web.tsx
  • frontend/components/landing/ListingCard.tsx
  • frontend/components/landing/Nav.tsx
  • frontend/components/landing/SectionHead.tsx
  • frontend/components/landing/Ticker.tsx
  • frontend/components/landing/Why.tsx
  • frontend/components/landing/cx.ts
  • frontend/components/landing/data.ts
  • frontend/components/landing/helpers.ts
  • frontend/components/landing/icons.tsx
  • frontend/components/landing/index.ts
  • frontend/components/landing/styles.ts
  • frontend/components/landing/useRevealOnVisible.ts
  • frontend/components/landing/useScrolled.ts
📝 Walkthrough

Walkthrough

Introduces a web-only landing page and moves root routing targets from / to /home across the app; adds web/legal pages and many landing-page components, adjusts tab route naming to home, and updates multiple web prompt/login redirect behaviors to use /home.

Changes

Cohort / File(s) Summary
Landing & landing components
frontend/app/index.tsx, frontend/components/LandingScreen.tsx, frontend/components/LandingScreen.web.tsx, frontend/components/landing/*, frontend/components/landing/index.ts
Adds a web landing page and a large set of landing UI pieces (Nav, Hero, Ticker, Why, GetApp, Footer, DownloadButton, styles, data, helpers, icons, components, hook). Review CSS, accessibility, asset loading (QR), and platform-specific code paths.
Legal content & pages
PRIVACY_POLICY.md, TERMS_OF_SERVICE.md, frontend/components/landing/legalContent.ts, frontend/components/landing/LegalDocument.web.tsx, frontend/app/privacy.web.tsx, frontend/app/terms.web.tsx, frontend/app/privacy.tsx, frontend/app/terms.tsx
Adds structured legal documents and web routes that render them; also adds non-web redirects for privacy/terms. Verify content, metadata injection, and sibling navigation links.
Routing / Tab layout changes
frontend/app/(tabs)/_layout.tsx, frontend/app/_layout.tsx, frontend/app/index.tsx, frontend/app/l/[id].tsx
Changes web header base route to /home, renames native tab trigger to home, adds top-level index Stack.Screen, and updates fallback redirects to /home. Check tab naming impact and stack routing ordering.
Redirect / prompt updates (multiple tabs & screens)
frontend/app/(tabs)/home.tsx, frontend/app/(tabs)/inbox.tsx, frontend/app/(tabs)/my-listings.tsx, frontend/app/(tabs)/settings.tsx, frontend/app/account-settings.tsx, frontend/components/ListingUnavailable.tsx, frontend/app/listings/new.tsx
Replaces many redirect targets and OpenInAppPrompt secondary actions to point at /home; web save/create flows now show in-app prompts or modals instead of redirecting to login. Review UX/consistency and router.replace usage.
Auth changes
frontend/app/auth/login.tsx, frontend/app/auth/login.web.tsx
Changes post-auth fallback redirect default to /home; adds a web-specific login route that redirects to the landing / (web-only Redirect). Verify post-auth redirect validation and web redirect behavior.
Listing route behavior
frontend/app/l/[id].tsx
Fallback for missing/invalid id now redirects to /home.
Assets / types / dependencies / lint
frontend/types/assets.d.ts, frontend/package.json, .eslintrc.js, frontend/constants/app.ts
Adds PNG module types, adds @types/react-dom devDependency, lint override for landing files (disables react-native/no-raw-text), and documents APP_STORE_URL. Check build/typechain and lint scope.
Misc content / small edits
frontend/components/ListingUnavailable.tsx, frontend/components/LandingScreen.tsx
Small navigation link updates to /home and new LandingScreen addition; verify link targets and platform conditional behavior.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • SamanSP1386

Poem

🐰 I hopped through routes and stitched a brand new dome,
A landing for the web — now callers find /home.
Tabs renamed, prompts pointed, legal pages dressed in chrome,
QR codes and App Store links — the meadow feels like home. 🥕✨

🚥 Pre-merge checks | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is largely incomplete; it contains only template placeholders with unfilled sections (linked issues, summary explanation, and test verification steps remain as placeholders), unchecked checklist items, and no supporting details or screenshots. Fill in all required template sections: specify the linked issues/PRs, provide a clear summary of what was implemented and why, detail the testing steps, confirm checklist items, and add screenshots/demos showing the landing page and routing behavior.
Docstring Coverage ⚠️ Warning Docstring coverage is 23.91% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title "Feat/marketing landing" is overly vague and generic, using a feature category prefix without conveying the specific main change or scope clearly. Use a more descriptive title that clearly states the primary change, such as "Add web marketing landing page and adjust web authentication routing" or "Implement landing page with web-only auth redirects".

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/marketing-landing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@dfed25

dfed25 commented Apr 19, 2026

Copy link
Copy Markdown
Collaborator Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Apr 19, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@evan-taylor

Copy link
Copy Markdown
Collaborator

@dfed25 this has button to sign in/sign up, but we want to not allow anyone to sign in or signup on web. We want to actually not allow people to visit that route on web.

- Add auth/login.web.tsx so /auth/login always redirects to / on web
- Remove Sign in header link and Sign up button from LandingScreen
- Clarify copy: sign-in is app-only; web is browse-focused

Made-with: Cursor
Resolve login.tsx: keep dev successRedirect sync for post-onboarding redirect,
default postAuthRedirect to /home (marketing feed route).

Made-with: Cursor

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (4)
frontend/app/index.tsx (1)

5-11: Consider redirecting authenticated web users to /home.

Currently, any visit to / on web renders the marketing LandingScreen, even for signed-in users who have previously used the browse experience. If that's the intent (web = marketing landing regardless of auth state), this is fine. Otherwise, consider reading the auth/session and redirecting authenticated web visitors to /home so they aren't re-shown the marketing page on every root visit.

Please confirm the desired behavior. If authenticated web users should skip the landing, something like the following would work:

Optional redirect for authenticated web users
-import { Redirect } from 'expo-router';
-import { Platform } from 'react-native';
-import LandingScreen from '../components/LandingScreen';
-
-export default function IndexRoute() {
-  if (Platform.OS !== 'web') {
-    return <Redirect href="/home" />;
-  }
-
-  return <LandingScreen />;
-}
+import { Redirect } from 'expo-router';
+import { Platform } from 'react-native';
+import LandingScreen from '../components/LandingScreen';
+import { useAuth } from '../hooks/useAuth';
+
+export default function IndexRoute() {
+  const { isAuthenticated } = useAuth();
+  if (Platform.OS !== 'web') {
+    return <Redirect href="/home" />;
+  }
+  if (isAuthenticated) {
+    return <Redirect href="/home" />;
+  }
+  return <LandingScreen />;
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/app/index.tsx` around lines 5 - 11, IndexRoute currently always
returns LandingScreen on web; modify it to check the user's
authentication/session state and redirect authenticated web users to "/home"
instead of rendering LandingScreen. Specifically, inside IndexRoute (the
Platform.OS !== 'web' branch can remain), call your existing auth/session
accessor (e.g., currentUser(), useSession(), getAuthState()) and, if it
indicates an authenticated user on web, return <Redirect href="/home" />;
otherwise continue to render <LandingScreen />; ensure you use the same Redirect
and LandingScreen symbols shown so behavior is consistent across platforms.
frontend/components/LandingScreen.tsx (3)

71-74: Consider an anchor to /home in the top bar for parity with the tabs layout.

The tabs WebHeaderLayout makes the "PolyBuys" brand a Link to /home, but here the same brand text is a plain <Text> with no action. For consistency and to give web visitors an easy "back to marketplace" affordance from the landing (e.g., after scrolling), consider wrapping it in a Link href="/home" pressable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/components/LandingScreen.tsx` around lines 71 - 74, Replace the
plain brand Text in LandingScreen.tsx with a pressable Link to "/home" so the
top bar matches WebHeaderLayout behavior: wrap or replace the Text with a Link
(e.g., Link href="/home") preserving the styles from styles.brandMark and
keeping it inside the same SafeAreaView/View topology (topBar -> brandMark).
Ensure the Link is keyboard accessible and retains the existing style and layout
so clicking the brand navigates back to the marketplace.

144-156: App Store badge tap may leave a stranded web tab.

On mobile web (non-desktop), tapping the App Store badge calls Linking.openURL(APP_STORE_URL). On iOS Safari this generally navigates the current tab; on some browsers it will open a new tab. Consider using an <a href={APP_STORE_URL} target="_blank" rel="noopener noreferrer"> via the Link/anchor pattern on web so clicks get native browser semantics (new tab, middle-click, right-click → copy, proper SEO), and fall back to Linking.openURL only for native. This also improves accessibility for assistive tech that treats anchors differently from pressables.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/components/LandingScreen.tsx` around lines 144 - 156, The Pressable
currently always calls Linking.openURL(APP_STORE_URL) which on web can navigate
the current tab; update LandingScreen.tsx to render a web anchor for web builds
and keep the Pressable for native: detect web (Platform.OS === 'web' or
react-native-web check) and when on web output an <a href={APP_STORE_URL}
target="_blank" rel="noopener noreferrer" aria-label="Download on the App
Store"> wrapping the <img> (use APP_STORE_BADGE_URI and styles.appStoreBadge) to
preserve native browser semantics, accessibility and SEO, and for non-web
platforms keep the existing Pressable that calls Linking.openURL(APP_STORE_URL)
with the same accessibilityRole/Label and styles.

22-29: Third-party QR service: reliability and privacy trade-off.

Fetching the QR code from api.qrserver.com means:

  • Every desktop-web visitor's IP and User-Agent are exposed to a third party.
  • If that service is down/rate-limited/discontinued, the QR silently breaks.
  • It adds an external dependency with no integrity check (no CSP/SRI on images).

Consider generating the QR locally (e.g., qrcode package → data URL at build time, since the URL is static) or hosting a pre-generated PNG as a static asset. The target URL is APP_STORE_URL, which is a compile-time constant, so a static asset is the simplest fix.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/components/LandingScreen.tsx` around lines 22 - 29, The QR image
currently comes from an external service via the qrCodeImageUri function which
exposes visitor metadata and is fragile; change it to use a locally-generated
asset or a build-time data URL instead: either pre-generate a PNG for
APP_STORE_URL and serve it from your static assets (update qrCodeImageUri to
return that asset path) or generate a data-URL at build time using the "qrcode"
package and have qrCodeImageUri return that constant data URL (ensure
APP_STORE_URL is used as the source), removing any runtime fetch to
api.qrserver.com and adjusting types where qrCodeImageUri is referenced in the
component.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/app/`(tabs)/home.tsx:
- Around line 201-205: The handleToggleSave callback currently redirects
unauthenticated users to /auth/login via router.replace even on web; update
handleToggleSave to check isWeb when !isAuthenticated and, if isWeb, do not call
router.replace but instead surface an app-only message (e.g., trigger the
existing app-only toast/modal or set a local state to show the UI hint) and
return; only call router.replace('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/auth/login?...') for non-web platforms.
Reference handleToggleSave, isAuthenticated, isWeb and router.replace when
making the change.

In `@frontend/components/LandingScreen.tsx`:
- Line 15: Landing page currently imports APP_STORE_URL (used in
LandingScreen.tsx for QR, email link, and App Store badge) which is a
placeholder value in frontend/constants/app.ts
('https://polybuys.com/download'); before shipping, either replace APP_STORE_URL
with the official App Store deep/link or confirm that
https://polybuys.com/download exists and reliably redirects to the App Store (or
serves a valid interstitial). Update the constant in frontend/constants/app.ts
to the canonical App Store URL (or an approved redirecting/interstitial URL),
then verify LandingScreen.tsx (references to APP_STORE_URL) shows the correct
link in the QR, the "Email the download link" flow, and the badge; if you cannot
supply a verified canonical URL, block the PR and leave APP_STORE_URL unchanged
until a valid URL is provided.

---

Nitpick comments:
In `@frontend/app/index.tsx`:
- Around line 5-11: IndexRoute currently always returns LandingScreen on web;
modify it to check the user's authentication/session state and redirect
authenticated web users to "/home" instead of rendering LandingScreen.
Specifically, inside IndexRoute (the Platform.OS !== 'web' branch can remain),
call your existing auth/session accessor (e.g., currentUser(), useSession(),
getAuthState()) and, if it indicates an authenticated user on web, return
<Redirect href="/home" />; otherwise continue to render <LandingScreen />;
ensure you use the same Redirect and LandingScreen symbols shown so behavior is
consistent across platforms.

In `@frontend/components/LandingScreen.tsx`:
- Around line 71-74: Replace the plain brand Text in LandingScreen.tsx with a
pressable Link to "/home" so the top bar matches WebHeaderLayout behavior: wrap
or replace the Text with a Link (e.g., Link href="/home") preserving the styles
from styles.brandMark and keeping it inside the same SafeAreaView/View topology
(topBar -> brandMark). Ensure the Link is keyboard accessible and retains the
existing style and layout so clicking the brand navigates back to the
marketplace.
- Around line 144-156: The Pressable currently always calls
Linking.openURL(APP_STORE_URL) which on web can navigate the current tab; update
LandingScreen.tsx to render a web anchor for web builds and keep the Pressable
for native: detect web (Platform.OS === 'web' or react-native-web check) and
when on web output an <a href={APP_STORE_URL} target="_blank" rel="noopener
noreferrer" aria-label="Download on the App Store"> wrapping the <img> (use
APP_STORE_BADGE_URI and styles.appStoreBadge) to preserve native browser
semantics, accessibility and SEO, and for non-web platforms keep the existing
Pressable that calls Linking.openURL(APP_STORE_URL) with the same
accessibilityRole/Label and styles.
- Around line 22-29: The QR image currently comes from an external service via
the qrCodeImageUri function which exposes visitor metadata and is fragile;
change it to use a locally-generated asset or a build-time data URL instead:
either pre-generate a PNG for APP_STORE_URL and serve it from your static assets
(update qrCodeImageUri to return that asset path) or generate a data-URL at
build time using the "qrcode" package and have qrCodeImageUri return that
constant data URL (ensure APP_STORE_URL is used as the source), removing any
runtime fetch to api.qrserver.com and adjusting types where qrCodeImageUri is
referenced in the component.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ea7dcc04-067a-409a-a6a7-201df4ab6f1e

📥 Commits

Reviewing files that changed from the base of the PR and between 5dfa982 and 23910d5.

📒 Files selected for processing (15)
  • frontend/app/(tabs)/_layout.tsx
  • frontend/app/(tabs)/home.tsx
  • frontend/app/(tabs)/inbox.tsx
  • frontend/app/(tabs)/my-listings.tsx
  • frontend/app/(tabs)/settings.tsx
  • frontend/app/_layout.tsx
  • frontend/app/account-settings.tsx
  • frontend/app/auth/login.tsx
  • frontend/app/auth/login.web.tsx
  • frontend/app/index.tsx
  • frontend/app/l/[id].tsx
  • frontend/app/listings/new.tsx
  • frontend/components/LandingScreen.tsx
  • frontend/components/ListingUnavailable.tsx
  • frontend/package.json

Comment thread frontend/app/(tabs)/home.tsx
useWindowDimensions,
} from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { APP_STORE_URL } from '../constants/app';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

APP_STORE_URL is still a placeholder.

Per frontend/constants/app.ts, APP_STORE_URL is defined as 'https://polybuys.com/download' with a TODO to replace it with the actual App Store URL. Shipping the marketing landing with a placeholder link means the QR, "Email the download link", and the App Store badge all point to a non-canonical URL. Please confirm polybuys.com/download exists and either redirects to the App Store or is a valid interstitial before releasing this page publicly, or block this PR on updating APP_STORE_URL.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/components/LandingScreen.tsx` at line 15, Landing page currently
imports APP_STORE_URL (used in LandingScreen.tsx for QR, email link, and App
Store badge) which is a placeholder value in frontend/constants/app.ts
('https://polybuys.com/download'); before shipping, either replace APP_STORE_URL
with the official App Store deep/link or confirm that
https://polybuys.com/download exists and reliably redirects to the App Store (or
serves a valid interstitial). Update the constant in frontend/constants/app.ts
to the canonical App Store URL (or an approved redirecting/interstitial URL),
then verify LandingScreen.tsx (references to APP_STORE_URL) shows the correct
link in the QR, the "Email the download link" flow, and the badge; if you cannot
supply a verified canonical URL, block the PR and leave APP_STORE_URL unchanged
until a valid URL is provided.

- index: redirect authenticated web users to /home; show boot spinner while auth loads
- LandingScreen: brand Link to /home; static QR asset (no third-party API); App Store
  badge uses Link target=_blank on web
- types/assets.d.ts: declare *.png for Metro image imports
- constants: document APP_STORE_URL + QR regeneration
- home: web save/create no longer hits blocked /auth/login; use app-only alerts

Made-with: Cursor

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
frontend/app/auth/login.tsx (2)

310-321: ⚠️ Potential issue | 🟡 Minor

Web secondary action still navigates to '/'.

"Back to home" calls router.replace('/') while the rest of the file (and PR) standardizes on '/home'. For consistency with the new routing targets, this should also use '/home'.

Also worth confirming with the reviewer feedback on the PR (evan-taylor): if web users shouldn't be able to reach /auth/login at all, this whole web branch may be dead code once the route-blocking lands — consider redirecting unconditionally here instead of rendering OpenInAppPrompt.

🔧 Proposed fix
-        onSecondaryAction={() => router.replace('/')}
+        onSecondaryAction={() => router.replace('/home')}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/app/auth/login.tsx` around lines 310 - 321, The web branch rendering
OpenInAppPrompt uses router.replace('/') for the "Back to home" action; update
the onSecondaryAction to call router.replace('/home') to match the new routing
convention (locate the isWeb check and the OpenInAppPrompt usage and change its
onSecondaryAction). Also, consider the reviewer note that /auth/login may be
unreachable after route-blocking—if so, replace the entire isWeb branch with an
unconditional redirect (use router.replace('/home') or
router.replace(postAuthRedirect ?? '/home')) instead of rendering
OpenInAppPrompt.

382-385: ⚠️ Potential issue | 🟠 Major

finishAndRedirect still targets '/' — inconsistent with the /home migration.

This PR moves root routing targets from '/' to '/home' (and the fallback on Line 73 was updated accordingly), but finishAndRedirect hard-codes setSuccessRedirect('/'). After a new user completes the profile + push steps, they'll be routed to '/' instead of postAuthRedirect / '/home', which undoes the intent of the fallback change and ignores any valid returnTo.

🔧 Proposed fix
-  const finishAndRedirect = () => {
-    setSuccessRedirect('/');
-    setStep('success');
-  };
+  const finishAndRedirect = () => {
+    setSuccessRedirect(postAuthRedirect);
+    setStep('success');
+  };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/app/auth/login.tsx` around lines 382 - 385, finishAndRedirect
currently hard-codes setSuccessRedirect('/') which contradicts the migration to
'/home' and ignores any returnTo/postAuthRedirect. Update finishAndRedirect to
set the success redirect to the negotiated post-auth path instead of '/', e.g.
call setSuccessRedirect(postAuthRedirect ?? '/home') (or the equivalent variable
that holds returnTo/postAuthRedirect) and then setStep('success'); keep the rest
of the function unchanged and reference the finishAndRedirect function and
setSuccessRedirect call when making the change.
🧹 Nitpick comments (4)
frontend/components/landing/helpers.ts (1)

9-9: Prefer window.open over assigning location.href for mailto:.

Setting window.location.href to a mailto: URL can unload the current SPA in some browsers (noticeably on iOS Safari / some desktop Chrome configurations where no mail handler is registered, leaving the user on a blank page). Using window.open(url, '_self') (or a transient <a> click) is the more reliable pattern and keeps history intact if the OS handoff is cancelled.

♻️ Proposed change
-  window.location.href = `mailto:?subject=${subject}&body=${body}`;
+  window.open(`mailto:?subject=${subject}&body=${body}`, '_self');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/components/landing/helpers.ts` at line 9, Replace the direct
assignment to window.location.href for the mailto flow with a window.open call
or a transient anchor click to avoid unloading the SPA; locate the line that
sets window.location.href = `mailto:?subject=${subject}&body=${body}` and change
it to open the same mailto URL using window.open(mailtoUrl, '_self') (or
programmatically create, click, and remove an <a> element) so the mail handoff
is attempted without leaving the app or creating a blank history entry.
frontend/components/landing/LegalDocument.web.tsx (3)

14-14: Nit: document prop shadows the global document.

The destructured document parameter shadows the DOM document global inside this component. Not a bug today (no window.document usage here), but it can trip up future edits (e.g., adding a document.querySelector call) and confuse readers/linters. Consider renaming to doc or legalDocument.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/components/landing/LegalDocument.web.tsx` at line 14, The parameter
name document in the LegalDocumentPage function shadows the global DOM document;
rename the prop to something like legalDocument or doc across the component
signature (LegalDocumentPage({ document, siblingHref, siblingLabel } ->
LegalDocumentPage({ legalDocument, siblingHref, siblingLabel })) and update
every usage inside the component body that referenced document to the new
identifier, and then update all call sites/JSX props that pass the document prop
to use the new prop name (and update the LegalDocumentPageProps/type
accordingly) to avoid future global shadowing and linter warnings.

53-74: Using text content as React keys is fragile.

paragraph and bullet strings are used as keys for intro, section.paragraphs, and section.bullets. If any legal doc ever contains two identical paragraphs/bullets (easy to happen with short items like "N/A" or repeated clauses), React will warn about duplicate keys and may misbehave on re-render. Since these lists are static and never reordered, the index is a safe and cheap key here.

♻️ Proposed fix
-                {document.intro.map((paragraph) => (
-                  <p key={paragraph}>{paragraph}</p>
+                {document.intro.map((paragraph, i) => (
+                  <p key={i}>{paragraph}</p>
                 ))}
@@
-                    {section.paragraphs?.map((paragraph) => (
-                      <p key={paragraph} className="pb-doc__paragraph">
+                    {section.paragraphs?.map((paragraph, i) => (
+                      <p key={i} className="pb-doc__paragraph">
                         {paragraph}
                       </p>
                     ))}
@@
-                        {section.bullets.map((bullet) => (
-                          <li key={bullet}>{bullet}</li>
+                        {section.bullets.map((bullet, i) => (
+                          <li key={i}>{bullet}</li>
                         ))}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/components/landing/LegalDocument.web.tsx` around lines 53 - 74, The
current key usage in the JSX maps (document.intro.map, section.paragraphs?.map,
section.bullets.map) uses the paragraph/bullet text as the React key which can
produce duplicate-key warnings; change these to use the iteration index as the
key (e.g., use the map index for the <p> in intro, for <p> in
section.paragraphs, and for <li> in section.bullets) since these lists are
static and never reordered, ensuring unique stable keys without relying on
content strings.

29-29: Move <style>{GLOBAL_CSS}</style> into <Head> for consistency.

The expo-router/head Head component supports arbitrary children including <style> tags. For a full-page legal document, keeping global CSS in the document head alongside metadata and font links is cleaner and avoids a brief FOUC on first paint. Since you're already using expo-router/head for document-level tags, placing the style there keeps intent consistent with other head elements.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/components/landing/LegalDocument.web.tsx` at line 29, The inline
style tag <style>{GLOBAL_CSS}</style> should be moved into the document head for
the LegalDocument component: locate the LegalDocument component (and its use of
Head from 'expo-router/head') and place the <style>{GLOBAL_CSS}</style> as a
child of Head (alongside any meta/font links) instead of rendering it directly
in the component body, ensuring global CSS is injected in the head to avoid FOUC
and keep head-level assets together.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/components/landing/Button.tsx`:
- Around line 52-64: The anchor branch in Button.tsx should enforce a safe
default rel when opening a link in a new tab: if 'href' in props and
props.target === "_blank" and props.rel is undefined/null, set rel to "noopener
noreferrer" before rendering; if props.rel is provided, use it unchanged (or
optionally merge to ensure these tokens are present). Update the anchor render
logic in the component that checks 'href'/props to compute a finalRel variable
and pass finalRel to the <a rel={finalRel}> attribute.

In `@frontend/components/landing/DownloadButton.tsx`:
- Around line 30-38: The click handler (handleClick) opens a QR modal on desktop
even when QR_SRC is empty, causing a useless empty scan flow; change the logic
to treat an empty QR_SRC as unavailable and fall back to APP_STORE_URL: in
handleClick check both touchPrimary and whether QR_SRC is truthy (e.g., QR_SRC
&& QR_SRC.length) before opening the modal via setModalOpen(true), and if QR_SRC
is falsy navigate to APP_STORE_URL instead; apply the same truthy-QR_SRC check
to the duplicate desktop flow referenced around the other handler (lines
~108-115) so both entry points fallback to APP_STORE_URL when QR_SRC is empty.
- Around line 71-90: The modal currently sets aria-modal and focuses closeBtnRef
but does not trap Tab focus, allowing focus to escape; inside the useEffect in
DownloadButton add a focus-trap: collect all focusable elements inside cardRef
(e.g., querySelectorAll for anchors, buttons, inputs, [tabindex]), and add a
keydown handler that intercepts Tab/Shift+Tab to cycle focus to the first/last
focusable element accordingly (keeping existing Escape handler logic using
onKey), or alternatively integrate an existing dialog primitive/focus-trap
utility and attach it when the modal mounts and remove it on cleanup; ensure you
reference closeBtnRef and cardRef so initial focus and the trap target are the
same and remove the trap in the return cleanup along with existing listeners.

In `@frontend/components/landing/Nav.tsx`:
- Line 14: Update the Brand link in Nav.tsx so it points to the new app home
route: change the Brand component's href prop from "/" to "/home" (the JSX
element is Brand href="/" ariaLabel="PolyBuys home" inside the Nav component) so
the landing navigation sends users to /home instead of the old root route.

In `@TERMS_OF_SERVICE.md`:
- Line 58: The relative markdown link "[Privacy Policy](./PRIVACY_POLICY.md)" in
TERMS_OF_SERVICE.md can break when the content is rendered on the website;
update that link to the canonical web route (e.g. "/privacy") or include both
references. Replace the existing link target "./PRIVACY_POLICY.md" with
"/privacy" (or add a parenthetical/second link to "/privacy") so the Privacy
Policy resolves correctly when the markdown is served via the LegalDocumentPage
or the /terms route.

---

Outside diff comments:
In `@frontend/app/auth/login.tsx`:
- Around line 310-321: The web branch rendering OpenInAppPrompt uses
router.replace('/') for the "Back to home" action; update the onSecondaryAction
to call router.replace('/home') to match the new routing convention (locate the
isWeb check and the OpenInAppPrompt usage and change its onSecondaryAction).
Also, consider the reviewer note that /auth/login may be unreachable after
route-blocking—if so, replace the entire isWeb branch with an unconditional
redirect (use router.replace('/home') or router.replace(postAuthRedirect ??
'/home')) instead of rendering OpenInAppPrompt.
- Around line 382-385: finishAndRedirect currently hard-codes
setSuccessRedirect('/') which contradicts the migration to '/home' and ignores
any returnTo/postAuthRedirect. Update finishAndRedirect to set the success
redirect to the negotiated post-auth path instead of '/', e.g. call
setSuccessRedirect(postAuthRedirect ?? '/home') (or the equivalent variable that
holds returnTo/postAuthRedirect) and then setStep('success'); keep the rest of
the function unchanged and reference the finishAndRedirect function and
setSuccessRedirect call when making the change.

---

Nitpick comments:
In `@frontend/components/landing/helpers.ts`:
- Line 9: Replace the direct assignment to window.location.href for the mailto
flow with a window.open call or a transient anchor click to avoid unloading the
SPA; locate the line that sets window.location.href =
`mailto:?subject=${subject}&body=${body}` and change it to open the same mailto
URL using window.open(mailtoUrl, '_self') (or programmatically create, click,
and remove an <a> element) so the mail handoff is attempted without leaving the
app or creating a blank history entry.

In `@frontend/components/landing/LegalDocument.web.tsx`:
- Line 14: The parameter name document in the LegalDocumentPage function shadows
the global DOM document; rename the prop to something like legalDocument or doc
across the component signature (LegalDocumentPage({ document, siblingHref,
siblingLabel } -> LegalDocumentPage({ legalDocument, siblingHref, siblingLabel
})) and update every usage inside the component body that referenced document to
the new identifier, and then update all call sites/JSX props that pass the
document prop to use the new prop name (and update the
LegalDocumentPageProps/type accordingly) to avoid future global shadowing and
linter warnings.
- Around line 53-74: The current key usage in the JSX maps (document.intro.map,
section.paragraphs?.map, section.bullets.map) uses the paragraph/bullet text as
the React key which can produce duplicate-key warnings; change these to use the
iteration index as the key (e.g., use the map index for the <p> in intro, for
<p> in section.paragraphs, and for <li> in section.bullets) since these lists
are static and never reordered, ensuring unique stable keys without relying on
content strings.
- Line 29: The inline style tag <style>{GLOBAL_CSS}</style> should be moved into
the document head for the LegalDocument component: locate the LegalDocument
component (and its use of Head from 'expo-router/head') and place the
<style>{GLOBAL_CSS}</style> as a child of Head (alongside any meta/font links)
instead of rendering it directly in the component body, ensuring global CSS is
injected in the head to avoid FOUC and keep head-level assets together.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e6537ddf-2acd-45f6-a103-f221c03155db

📥 Commits

Reviewing files that changed from the base of the PR and between 23910d5 and d441cfd.

⛔ Files ignored due to path filters (2)
  • frontend/assets/images/polybuys-download-qr.png is excluded by !**/*.png
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (42)
  • .eslintrc.js
  • PRIVACY_POLICY.md
  • TERMS_OF_SERVICE.md
  • frontend/app/(tabs)/home.tsx
  • frontend/app/(tabs)/inbox.tsx
  • frontend/app/(tabs)/settings.tsx
  • frontend/app/_layout.tsx
  • frontend/app/account-settings.tsx
  • frontend/app/auth/login.tsx
  • frontend/app/index.tsx
  • frontend/app/listings/new.tsx
  • frontend/app/privacy.tsx
  • frontend/app/privacy.web.tsx
  • frontend/app/terms.tsx
  • frontend/app/terms.web.tsx
  • frontend/components/LandingScreen.tsx
  • frontend/components/LandingScreen.web.tsx
  • frontend/components/landing/AppleIcon.tsx
  • frontend/components/landing/AvatarStack.tsx
  • frontend/components/landing/Brand.tsx
  • frontend/components/landing/Button.tsx
  • frontend/components/landing/DownloadButton.tsx
  • frontend/components/landing/Eyebrow.tsx
  • frontend/components/landing/Footer.tsx
  • frontend/components/landing/GetApp.tsx
  • frontend/components/landing/Hero.tsx
  • frontend/components/landing/LegalDocument.web.tsx
  • frontend/components/landing/ListingCard.tsx
  • frontend/components/landing/Nav.tsx
  • frontend/components/landing/SectionHead.tsx
  • frontend/components/landing/Ticker.tsx
  • frontend/components/landing/Why.tsx
  • frontend/components/landing/cx.ts
  • frontend/components/landing/data.ts
  • frontend/components/landing/helpers.ts
  • frontend/components/landing/index.ts
  • frontend/components/landing/legalContent.ts
  • frontend/components/landing/styles.ts
  • frontend/components/landing/useScrolled.ts
  • frontend/constants/app.ts
  • frontend/package.json
  • frontend/types/assets.d.ts
✅ Files skipped from review due to trivial changes (10)
  • frontend/app/(tabs)/settings.tsx
  • frontend/app/account-settings.tsx
  • frontend/app/privacy.web.tsx
  • frontend/types/assets.d.ts
  • frontend/components/landing/cx.ts
  • .eslintrc.js
  • frontend/constants/app.ts
  • frontend/components/landing/styles.ts
  • frontend/components/landing/legalContent.ts
  • frontend/components/LandingScreen.tsx
🚧 Files skipped from review as they are similar to previous changes (6)
  • frontend/app/listings/new.tsx
  • frontend/package.json
  • frontend/app/(tabs)/inbox.tsx
  • frontend/app/_layout.tsx
  • frontend/app/(tabs)/home.tsx
  • frontend/app/index.tsx

Comment thread frontend/components/landing/Button.tsx
Comment thread frontend/components/landing/DownloadButton.tsx
Comment thread frontend/components/landing/DownloadButton.tsx
Comment thread frontend/components/landing/Nav.tsx Outdated
Comment thread TERMS_OF_SERVICE.md Outdated
@evan-taylor
evan-taylor merged commit d2ceeda into dev Apr 21, 2026
2 of 4 checks passed
@evan-taylor
evan-taylor deleted the feat/marketing-landing branch April 21, 2026 02:12
evan-taylor added a commit that referenced this pull request Apr 21, 2026
* feat: misc frontend UI fixes and improvements

- Fix duplicate sign-in messages on profile tab
- Redirect unauthenticated users to profile on Create Listing (web)
- Fix browser tab title persisting after leaving a listing
- Style placeholder text with lighter grey across profile and create listing forms
- Standardize Create Listing button to brand green (#154734)
- Capitalize category and condition values on listing detail page
- Add profile setup check before creating listings with visible warning banner
- Replace Alert.alert with cross-platform showAlert for web compatibility
- Add Delete button to My Listings with confirmation dialog

* fix: address PR review feedback

- Extract showAlert into shared utils/showAlert.ts module
- Prevent concurrent deletes in my-listings (guard + disable all buttons)
- Fix year reset to empty string in settings signed-out useEffect
- Remove unused Alert/Platform imports from new.tsx

* fix(vercel): declare @sentry/react-native in frontend workspace

Expo resolves @sentry/react-native/expo relative to the frontend package; it was only on the root workspace so Vercel installs did not expose the plugin and expo export failed.

Made-with: Cursor

* fix: address team feedback — auth timeout, seller avatar, download link, image lightbox

- Add 8s timeout + retry button to auth 'checking' step to prevent infinite spinner
- Replace empty grey seller avatar with initials (first letter of name) on listing detail
- Make seller block tappable, navigates to public profile
- Change 'Open in App' to 'Download App' with placeholder App Store URL
- Add download hint link to OpenInAppPrompt component
- Create ImageLightbox component for full-screen uncropped image viewing
- Wrap all listing hero images in Pressable to open lightbox on click
- Support keyboard navigation (Escape, ←, →) in lightbox on web

* fix: address PR feedback for UI components and auth flow

- Fix login retry timer leak

- Fix ImageLightbox filtered array index mismatch and add auto-focus on web

- Improve OpenInAppPrompt link error handling and accessibility labels

- Move APP_STORE_URL and APP_SCHEME to shared constants

* chore: satisfy eslint any warning for lightbox web props

* fixed search

* feat(frontend): dedicated account settings from profile tab

- Add /account-settings stack screen with message notifications, sign out, and delete account
- Profile tab shows a Settings row (and account settings on incomplete profile) linking there
- Web: OpenInAppPrompt for account settings deep link, consistent with profile tab
- Fix typed-route pushes with as never where the generated routes lag

Made-with: Cursor

* red box

* red box

* blocked users

* code rabbit fix

* more fixes

* feat: add Other as a report reason for listing moderation (POLY-70)

* fix: keyboard overlaps input on Create/Edit Listing screens (POLY-75)

* feat: ui changes to save/share buttons

* fix: login redirect bug

* fix: route profileless users to onboarding

Co-authored-by: Evan Taylor <evan-taylor@users.noreply.github.com>

* test: cover login onboarding redirect

* Match UI of MyListing and Home

* chore: remove ios build files from PR

* feat(frontend): dismissible flash banner and safe placement

- Add FlashProvider with bottom-inset positioning above tab/home area
- pointerEvents box-none/auto so banner receives taps; tap or Dismiss clears
- Shorter auto-dismiss when reduce motion is enabled
- Wire create/edit listing, mark sold, and report success to setFlash
- ReportModal optional onReportSuccess for non-blocking confirmation

Made-with: Cursor

* transparent

* more transparent

* chore(frontend): shared report copy; longer flash for reduce motion

- Add feedbackMessages constants for report success (flash + Alert)
- Use REPORT_SUBMITTED_MESSAGE in listing and profile screens
- Increase FLASH_DURATION_REDUCED_MS to 4000 for readability

Made-with: Cursor

* feat: remove tags from UI and backend (POLY-77)

* Remove unrelated changes from PR

* fix: coderabbit errors

* fix(vercel): declare @sentry/react-native in frontend workspace

Expo resolves @sentry/react-native/expo relative to the frontend package; it was only on the root workspace so Vercel installs did not expose the plugin and expo export failed.

Made-with: Cursor

* feat(frontend): polish listing cards (POLY-76)

- Vertical stack: multi-line title (2 lines home, 3 default), condition caption, price
- Clearer hierarchy: dark title, muted condition, bold accent price
- More padding and md card radius; softer shadow; slightly looser grid spacing on home

Made-with: Cursor

* feat(frontend): short description preview on listing cards

- Plain descriptions: up to 2 lines, footnote style, ellipsized
- Multi-line or -/• lists: up to 2 bullet rows with trimmed markers
- Include snippet in accessibility label (capped length)

Made-with: Cursor

* feat(frontend): smarter listing description bullets (heuristics)

- Extract buildDescriptionPreview: newlines/markers, semicolons, then sentences
- Use Intl.Segmenter when available with regex fallback for sentences
- Up to 3 bullets; support numbered line prefixes
- Tests for preview helper; exclude frontend __tests__ from tsc

Made-with: Cursor

* fix(frontend): omit prose after last bulleted line in card preview

- When 2+ lines start with list markers, only those lines become bullets
- descBlock uses overflow hidden as a layout safeguard

Made-with: Cursor

* fix(frontend): numbered lists without space after dot and inline 1. 2.

- Scan for digit+dot boundaries (not decimals like 2.0) across lines and spaces
- Relax line markers so 1.Item matches; run span scan before line-based bullets
- Tests for tight 1.x/2.x lines and single-line numbered lists

Made-with: Cursor

* feat(frontend): one bullet per description line when user uses Enter

- Drop short-line / looksLikeList gate: any 2+ non-empty lines become bullets
- Keep marked-only slice when 2+ lines start with list markers (trailing prose omitted)
- Cap 12 lines, 300 chars per line; strip optional -/1. prefixes per row

Made-with: Cursor

* fix(frontend): trim prose after last bullet (numbered + single dash)

- Numbered items: drop flush lines after first line in each span; keep indented wraps
- One dash bullet + following unmarked lines: show only the marked line
- Tests for numbered tail and single-dash + prose

Made-with: Cursor

* chore(frontend): address CodeRabbit ListingCard + preview tests

- Require listing.condition on ListingCard; exhaustive formatConditionLabel
- Memoize accessibilityLabel from parts; spacing.smPlus for cardDetailsHome
- Tests: 78-char cap and DESC_PREVIEW_BULLET_MAX

Made-with: Cursor

* feat: fixed a ton of stuff, standardize UI (#86)

* feat: fixed a ton of stuff, standardize UI

* fix block user success feedback

Co-authored-by: Evan Taylor <evan-taylor@users.noreply.github.com>

* style format conversation block flow

Co-authored-by: Evan Taylor <evan-taylor@users.noreply.github.com>

* fix listing sold state race checks

Co-authored-by: Evan Taylor <evan-taylor@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Evan Taylor <evan-taylor@users.noreply.github.com>

* feat: update UI themes and improve tab navigation (#87)

- Changed userInterfaceStyle to 'light' in app.json for consistent appearance.
- Refactored theme handling in _layout.tsx to use a custom navigation theme.
- Updated tab navigation styles in (tabs)/_layout.tsx to utilize nativeChrome for better visual consistency.
- Enhanced search and inbox screens to align with new theme settings.
- Added nativeChrome configuration for improved UI elements across the app.

This commit aims to standardize the UI and enhance user experience across different screens.

* feat: implement profile pictures

* fix: coderabbit changes, fix top border on profile page

* feat: add ci/cd for builds (#89)

* feat: add ci/cd for builds

* fix: don't build on backend or docs changes

* fix: inbox search keyboard close (#90)

* feat: fix xcode provisioning on ci/cd (#91)

* fix: add app id to expo (#92)

* feat: run convex deploy and add agent skill (#93)

* feat: run convex deploy and add agent skill

* fix: run convex deploy on manual ci too

* feat: add report and delete for entire conversations

* feat: fix prevent swipe actions from showing through on row press

* feat: add tooltip and add tap to close swipe

* feat: add report and delete for individual messaging

* fix(frontend): keyboard avoidance for price range picker modal

- KeyboardAvoidingView (iOS padding, Android height) above bottom sheet
- ScrollView so presets, inputs, and Apply stay reachable when keyboard is open
- Backdrop as sibling Pressable so sheet scrolling is not blocked
- Safe-area padding on scroll content; cap sheet height for smaller screens

Made-with: Cursor

* chore(frontend): dedupe Sentry dep; dim price picker backdrop

- Remove duplicate @sentry/react-native from package.json
- Restore modal scrim on PriceRangePicker backdrop (rgba 0.35)

Made-with: Cursor

* fix: remove listings when conversation reported, clean up functionality

* fix: no deleting individual messages

* fix: remove tooltip

* feat: redirect new users to home

* feat: redirect to home after logging in

* fix: add code rabbit changes

* fix: onboarding copy so first-time users do not see Welcome back (POLY-86)

* feat: add required field indicators and inline validation to listing creation (POLY-91)

* feat: add date posted metadata to listing cards and detail page (POLY-92)

* fix choppyness (#101)

* feat: add zoom support to listing photos

* fix: address lightbox lint warnings

* chore: rerun ci for listing photo zoom

* fix: address lightbox review feedback

* feat: prevent functionality on web

* fix: ci config setup (#109)

* fix: match Dispatch<SetStateAction> signature for onImagesChange

* Feat/marketing landing (#95)

* fix(vercel): declare @sentry/react-native in frontend workspace

Expo resolves @sentry/react-native/expo relative to the frontend package; it was only on the root workspace so Vercel installs did not expose the plugin and expo export failed.

Made-with: Cursor

* feat(frontend): add marketing landing page and /home feed route

- Add web-only landing at / with value props, CTAs, and App Store compliance
- Desktop: QR code and mailto draft for the download link
- Narrow web: official App Store badge linking to APP_STORE_URL
- Rename (tabs)/index to home so / is the landing without route conflicts
- Point in-app "home" navigation and post-auth default to /home
- Register root index in the stack; dedupe @sentry/react-native in package.json
- Refresh lockfile so workspace resolves expo-blur for typecheck/bundling

Made-with: Cursor

* feat(web): block auth routes and remove login CTAs from landing

- Add auth/login.web.tsx so /auth/login always redirects to / on web
- Remove Sign in header link and Sign up button from LandingScreen
- Clarify copy: sign-in is app-only; web is browse-focused

Made-with: Cursor

* chore(frontend): address CodeRabbit marketing + web auth UX

- index: redirect authenticated web users to /home; show boot spinner while auth loads
- LandingScreen: brand Link to /home; static QR asset (no third-party API); App Store
  badge uses Link target=_blank on web
- types/assets.d.ts: declare *.png for Metro image imports
- constants: document APP_STORE_URL + QR regeneration
- home: web save/create no longer hits blocked /auth/login; use app-only alerts

Made-with: Cursor

* feat: revamp landing page, add legal docs

* fix: board and coderabbit feedback

* fix: feedback

---------

Co-authored-by: Evan Taylor <eltaylor1104@gmail.com>

* Feature/poly 90 button visibility (#108)

* feat: improve search tab and button visibility

* feat: polish search, buttons, and messaging flows

* fix: address ui review feedback

* fix: padding and styling changes

---------

Co-authored-by: Evan Taylor <eltaylor1104@gmail.com>

* fixes

* fix: address listing form validation review feedback

* fix: align home route references with expo router

* feat: add support page and links across the application (#111)

- Introduced a new support page for user assistance, accessible via /support.
- Updated LandingScreen to include a link to the support page and added legal links for Privacy and Terms.
- Enhanced the footer to include a link to the support page.
- Implemented support document retrieval with contact options for user inquiries.
- Adjusted styles for legal links and contact information display.

* fix: restore web browse route targets

* fix: improve keyboard avoidance in chat and price picker

* fix: address keyboard and safety banner review feedback

* featL liquid glass app icon (#112)

* feat: add support page and links across the application

- Introduced a new support page for user assistance, accessible via /support.
- Updated LandingScreen to include a link to the support page and added legal links for Privacy and Terms.
- Enhanced the footer to include a link to the support page.
- Implemented support document retrieval with contact options for user inquiries.
- Adjusted styles for legal links and contact information display.

* feat: add liquid glass app icon

* fix: revert message keyboard avoidance changes

* fix: avoid native driver conflict in price picker

* fix: make profile email read-only

* feat: polish login and profile flows

* fix: tighten profile tab and major selection

* fix: polish frontend login and profile flows

* fix: standardize keyboard chrome across frontend flows

* feat: polish frontend launch readiness

* chore: apply final review hardening updates

* chore: apply final review hardening updates

* fix: address accessibility and profile review comments

* fix: address frontend review findings

* fix: harden native image uploads and backend validation

---------

Co-authored-by: Cole <hackman@calpoly.edu>
Co-authored-by: dfed25 <domfederico21@gmail.com>
Co-authored-by: Jaydon Chen <79879038+jaydonkc@users.noreply.github.com>
Co-authored-by: MatthewPhan <Matthewminhphan@gmail.com>
Co-authored-by: SamanSP1386 <saman.sepehr86@gmail.com>
Co-authored-by: Haixin <haixinhuang502@gmail.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Evan Taylor <evan-taylor@users.noreply.github.com>
Co-authored-by: lheutchy <lheutchy@gmail.com>
Co-authored-by: Taye-Staats <tayestaats@outlook.com>
Co-authored-by: dfed25 <150391626+dfed25@users.noreply.github.com>
Co-authored-by: BoB121isawesome <79879038+BoB121isawesome@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants