# Volana Expo App — UI-Umsetzung des Prototyps ## Kontext `prototype/Volana.dc.html` ist ein interaktiver HTML-Prototyp (DC-Format mit Template-Bindings à la `{{ x }}`, `sc-if`, `sc-for`) der Volana-Konsumenten-Oberfläche: ein dezentraler, zensurresistenter Marktplatz auf Solana (siehe `docs/volana-design-brief.md` für den vollständigen Produkt-Kontext). Der Prototyp enthält Homepage, Browse (Liste/Grid), Listing-Detail, My Orders, Order-Detail, Wallet-Connect-Modal, Checkout-Modal (Review/Pending/Success) und Toasts, inklusive vollständiger Mock-Daten (12 Produkte, 3 Dispute-Resolver, 3 Orders) und Farb-/Theming-Variablen für Light/Dark. Die Expo-App (`app/`) ist aktuell ein leeres Grundgerüst: Expo Router mit `(tabs)`-Gruppe (Home/Explore), HeroUI Native, Uniwind (Tailwind v4 für React Native), React 19 / RN 0.86 / Expo SDK 57. **Ziel dieser Iteration:** Das Design des Prototyps 1:1 in Seiten/Komponenten der Expo-App übertragen — mobil UND auf Web (`react-native-web`, in den Dependencies vorhanden) nahe am Prototyp. Keine echte Funktionalität (kein echtes Wallet, kein Backend) — Mock-Daten reichen. Styling bleibt so nah wie möglich an den HeroUI-Native-Defaults; nur Akzentfarbe, Statusfarben und Radius werden angepasst (Theming), komplexere Komponenten/Seiten bekommen zusätzlich Custom-Styles via `className` (Uniwind/Tailwind) bzw. `StyleSheet` wo nötig. ## Nicht-Ziele - Keine echte Solana-Wallet-Integration (`@solana/connector` o.ä.) — Connect/Disconnect ist gemockt wie im Prototyp. - Kein Backend/On-Chain-Datenfetching — statische Mock-Daten aus dem Prototyp übernommen. - Keine Persistenz von Bestellungen (gekaufte Listings erscheinen nicht dynamisch in "My Orders" — der Prototyp macht das ebenfalls nicht). - Kein manueller Light/Dark-Toggle — die App folgt dem System-Theme (Uniwind unterstützt das nativ). - Kein Footer (im Prototyp vorhanden, in der App nicht nötig). - Keine Pixel-genaue 1:1-Übernahme der Inline-Styles des Prototyps — HeroUI-Native-Komponenten und ihre Standard-Abstände/Formen bleiben so weit wie möglich erhalten. ## Theming Anpassung ausschließlich über CSS-Variablen-Overrides in `src/global.css` (`@layer theme { @variant light {...} @variant dark {...} }`), wie in der HeroUI-Native-Theming-Doku beschrieben. Kein Erstellen neuer Custom-Colors — bestehende semantische Slots werden mit den Prototyp-Werten belegt: | Variable | Dark (Prototyp `--c-*`) | Light (Prototyp `--c-*`) | Verwendung | |---|---|---|---| | `--accent` / `--accent-foreground` | `#b060ff` / weiß | `#7a34d4` / weiß | Primär-CTA, Preis-Hervorhebung, aktive Filter | | `--success` | `#14f195` | `#059669` | "In Stock", "Verified", "Complete", "Final Payment" | | `--warning` | `#f5a623` | `#d97706` | "Low Stock", "Awaiting Confirm" | | `--danger` | `#ff4d4f` | `#dc2626` | "Out of Stock", "Disputed", "Cancel Order" | | `--background` / `--surface` / `--surface-secondary` | leicht lila-stichige Dunkeltöne (`#0e0e1c`/`#171730`/`#1e1e3c`) | helle lila-stichige Töne (`#f7f6fb`/`#ffffff`/`#f0eef8`) | Basis-/Karten-Hintergründe | | `--radius` | Basiswert so gewählt, dass abgeleitete `--radius-lg`/`--radius-xl` in etwa den 8–14px-Radii des Prototyps entsprechen | gleich | Cards, Buttons, Inputs | Die im Prototyp verwendete "Solana-Mainnet"-Grün-Punkt/"Verified"-Optik nutzt direkt `success`, keine eigene Farbe nötig. ## Datenmodell & Mock-Daten Neue Datei `src/data/mock.ts` mit TS-Typen und den Werten 1:1 aus dem Prototyp (`_L`, `_R`, `_O` Arrays in `Volana.dc.html`): ```ts type Currency = 'SOL' | 'USDC'; interface Product { id: number; name: string; desc: string; price: string; priceNum: number; cur: Currency; usd: string; qty: number; seller: string; bg: string; emoji: string; alt: Currency[]; cat: string; } interface Resolver { id: number; name: string; desc: string; fee: string; type: 'Human' | 'DAO' | 'Automated'; wins: number; total: number; } type OrderStatus = 'AwaitingConfirm' | 'Active' | 'Complete' | 'Cancelled' | 'Disputed'; interface Order { id: number; lid: number; name: string; amt: string; status: OrderStatus; date: string; seller: string; emoji: string; } ``` Emojis dienen weiterhin als Platzhalter-"Produktbild" (wie im Prototyp) statt echter Bilder — kein Asset-Aufwand nötig. Helper-Funktionen analog zu `_si` (Status → Label/Farbe) und `_av` (Verfügbarkeit → Label/Farbe) werden als reine Funktionen in `src/data/mock.ts` oder `src/lib/status.ts` nachgebaut. ## State - **`WalletProvider`** (`src/state/wallet.tsx`, React Context): `connected: boolean`, `address: string | null`, `connect(wallet: 'phantom' | 'solflare' | 'backpack')` (setzt eine fixe Mock-Adresse je Wallet, identisch zum Prototyp), `disconnect()`. - **`ModalProvider`** (`src/state/modals.tsx`, React Context): zentraler Zustand für die beiden globalen Overlays: - Wallet-Connect-Sheet: `open`, `pendingListingId` (falls "Buy Now" ohne verbundenes Wallet ausgelöst wurde → nach Connect automatisch Checkout öffnen, wie im Prototyp) - Checkout-Sheet: `open`, `listingId`, `step: 'review' | 'pending' | 'success'`, inkl. simuliertem `setTimeout`-Übergang `pending → success` wie im Prototyp (2.2s) - Bestellungen bleiben statische Mock-Daten (siehe Nicht-Ziele) — kein zusätzlicher Order-State nötig. - Toasts über HeroUI Natives eingebauten `useToast`/`ToastProvider` (Teil von `HeroUINativeProvider`), verwendet für: Wallet verbunden/getrennt, Adresse kopiert, Order storniert/bestätigt. Beide Provider werden in `app/_layout.tsx` um den bestehenden `HeroUINativeProvider` ergänzt. ## Navigation & Screens ``` app/_layout.tsx Root Stack + WalletProvider + ModalProvider; rendert zusätzlich (nur ab `md:`, s.u.) + globale Sheets (WalletConnectSheet, CheckoutSheet) app/(tabs)/_layout.tsx Bottom Tabs: Home | Browse | Orders (Tab-Bar ab `md:` ausgeblendet) app/(tabs)/index.tsx Home app/(tabs)/browse.tsx Browse (ersetzt bisheriges explore.tsx) app/(tabs)/orders.tsx My Orders (Liste) app/listing/[id].tsx Listing-Detail — Stack-Push über den Tabs, eigener Header mit Zurück-Button app/orders/[id].tsx Order-Detail — Stack-Push über den Tabs, eigener Header mit Zurück-Button ``` Wallet-Connect- und Checkout-Overlay sind bewusst **keine Routen**, sondern globale, über `ModalProvider` gesteuerte `BottomSheet`-Komponenten im Root-Layout — "Buy Now" ist von Home, Browse und Listing-Detail auslösbar und muss überall denselben zentralen State treffen (entspricht dem zentralen Component-State im Prototyp). ### Responsive Shell (Mobile vs. Web/Desktop) Umschaltung über Uniwind-Responsive-Utilities (Breakpoint `md:`, ~768px) — funktioniert sowohl nativ (z. B. Tablet-Breite) als auch im Web-Build: - **`TopNav`** (`src/components/TopNav.tsx`): Logo, Suchfeld, "Browse"-/"My Orders"-Links, Wallet-Button/-Pill — analog zur Prototyp-Nav. Klasse `hidden md:flex`, liegt im Root-Layout über allen Screens (auch Listing-/Order-Detail), damit Web-Nutzer durchgehend navigieren können. - **Bottom-Tab-Bar:** in `(tabs)/_layout.tsx` per `useWindowDimensions` (React-Navigation-`tabBarStyle` ist keine Tailwind-Klasse, daher JS-Bedingung statt CSS) ab `md:`-Breite auf `display: 'none'` gesetzt. - **Ergebnis:** Mobile = Bottom-Tabs + Stack-Pushes für Details. Web/Desktop = Top-Nav wie Prototyp, keine Tab-Bar, Navigation über `router.push`. **Grid-Layouts:** React Native kennt kein CSS-Grid (auch nicht im Web-Build, da react-native-web View-Primitives nutzt) — alle "Grid"-Bereiche (Browse-Grid, Featured Listings, Customers-also-bought) werden über `flex-row flex-wrap` + Breiten-Utilities (`w-1/2 md:w-1/3 lg:w-1/4` o. ä.) gebaut, nicht über `display: grid`. **Listing-Detail:** `flex-col md:flex-row` (mobil gestapelt, ab `md:` zweispaltig wie im Prototyp). Die rechte Kauf-Box nutzt auf Web `position: 'sticky'` (von react-native-web unterstützt); nativ scrollt sie regulär mit. ## Screens im Detail ### Home (`app/(tabs)/index.tsx`) Kurzer Hero (Headline + Subline + "Browse Listings"-Button, kein Stats-/"Warum Volana"-/"How it works"-Block), darunter Featured-Listings (4 Karten, `ListingCard` Grid-Variante). ### Browse (`app/(tabs)/browse.tsx`) `SearchField` (Name/Beschreibung), Filter-Reihe (`Chip`-Toggles für Currency All/SOL/USDC und Sort Newest/Price↑/Price↓), `Switch` "In stock only", List/Grid-View-Toggle (Icon-Buttons). Darunter Produktliste aus den gefilterten/sortierten Mock-Daten: - List-View: horizontale Card (Bild-Platzhalter · Preis · Name+Beschreibung · Buy-Button), analog Prototyp-Zeilen-Layout. - Grid-View: 2-spaltige (mobil) / mehr-spaltige (`md:`/`lg:`) vertikale Cards. ### Listing-Detail (`app/listing/[id].tsx`) Bild-Platzhalter (Emoji auf Farbfläche), Titel, Beschreibung, "Verified on Solana"-Zeile mit Copy-Button (Toast "Address copied!"), Info-Grid (Kategorie/Verfügbar/Währung/ID), "Customers also bought" (horizontale/Flex-Wrap-Liste verwandter Produkte). Kauf-Sektion (sticky ab `md:`): Preis, Currency-Umschalter (falls `alt.length > 0`), Resolver-Auswahl (3 selektierbare Cards aus Mock-Resolvern), "Buy Now"-Button (öffnet Wallet-Sheet falls nicht verbunden, sonst Checkout-Sheet), Trust-Badges (Final Payment / Dispute Protection / On-chain Verified). ### Orders (`app/(tabs)/orders.tsx`) Liste von `OrderRow` (Emoji, Name, Seller-Kürzel, Betrag, Datum, Status-`Chip`), Tap → `app/orders/[id].tsx`. ### Order-Detail (`app/orders/[id].tsx`) Header (Datum, Name, Seller, Betrag, Status), 3-Schritt-Fortschrittsanzeige (Payment Held → Seller Confirms → You Confirm Receipt) mit Status-abhängiger Einfärbung wie im Prototyp (`_si`-Logik), Escrow-Info-Box, Aktions-Buttons je Status: `AwaitingConfirm` → Cancel Order (mock, zeigt Toast + navigiert zurück), `Active` → Confirm Receipt (mock, zeigt Toast), immer sichtbar → "View Listing". ## Gemeinsame Komponenten (`src/components/`) - `TopNav` — s. o. - `AppHeader` — einfacher mobiler Screen-Header für Stack-Screens (Titel + Zurück-Button), auf `md:` ggf. ausgeblendet da `TopNav` übernimmt - `ListingCard` — Varianten `list` und `grid` - `StatusChip` — mappt `OrderStatus`/Verfügbarkeit auf Label + Farbe (nutzt `Chip` von HeroUI) - `ResolverCard` — selektierbare Resolver-Option (Listing-Detail + Checkout-Review) - `OrderRow` — Zeile in der Orders-Liste - `WalletConnectSheet` — globales `BottomSheet` mit den drei Mock-Wallets (Phantom/Solflare/Backpack) - `CheckoutSheet` — globales `BottomSheet`, rendert intern je nach `step` Review-/Pending-(Spinner)-/Success-Inhalt ## Verifikation Da keine echte Funktionalität besteht, erfolgt Verifikation visuell: App per `expo start` (Web + iOS/Android-Simulator soweit verfügbar) starten, jede Seite und beide Breakpoints (schmal/mobil, breit/`md:`+) durchklicken, Kernflows prüfen (Home → Browse → Listing → Buy Now ohne Wallet → Connect → Checkout Review → Pending → Success → My Orders; Order-Detail Cancel/Confirm-Aktionen; Such-/Filter-/Sortier-/List-Grid-Umschaltung in Browse).