From 7310a349c59eff9c157d747e0ed062db3991e0e3 Mon Sep 17 00:00:00 2001 From: kirukib Date: Fri, 7 Aug 2026 01:21:32 +0300 Subject: [PATCH] Add Gishen mobile app with complete demo shopping and care flows. Ship Expo Router screens, seeded stores, and polished UX so auth, shop, checkout, prescriptions, loyalty, family, and account processes work end-to-end offline. Co-authored-by: Cursor --- .gitignore | 23 + README.md | 31 + app.json | 73 + app/(root)/(screens)/_layout.tsx | 13 + app/(root)/(screens)/about.tsx | 96 + app/(root)/(screens)/addresses.tsx | 136 + app/(root)/(screens)/branches.tsx | 146 + app/(root)/(screens)/checkout.tsx | 445 + app/(root)/(screens)/contact.tsx | 143 + app/(root)/(screens)/emergency-contacts.tsx | 143 + app/(root)/(screens)/family/index.tsx | 94 + app/(root)/(screens)/family/invite.tsx | 85 + app/(root)/(screens)/loyalty.tsx | 167 + app/(root)/(screens)/orders/[id].tsx | 240 + app/(root)/(screens)/orders/index.tsx | 107 + app/(root)/(screens)/prescription/[id].tsx | 211 + .../(screens)/prescription/calendar/[id].tsx | 265 + app/(root)/(screens)/prescription/list.tsx | 109 + app/(root)/(screens)/prescription/review.tsx | 222 + app/(root)/(screens)/prescription/scan.tsx | 196 + app/(root)/(screens)/product/[id].tsx | 439 + app/(root)/(screens)/profiles/join.tsx | 60 + app/(root)/(screens)/profiles/switch.tsx | 134 + app/(root)/(screens)/search.tsx | 111 + app/(root)/(screens)/shop.tsx | 91 + app/(root)/(screens)/subscriptions/index.tsx | 255 + app/(root)/(screens)/tracking/[id].tsx | 122 + app/(root)/(tabs)/_layout.tsx | 5 + app/(root)/(tabs)/cart.tsx | 183 + app/(root)/(tabs)/favorites.tsx | 61 + app/(root)/(tabs)/index.tsx | 247 + app/(root)/(tabs)/profile.tsx | 307 + app/(root)/_layout.tsx | 13 + app/(root)/auth/_layout.tsx | 5 + app/(root)/auth/language.tsx | 58 + app/(root)/auth/otp.tsx | 135 + app/(root)/auth/welcome.tsx | 71 + app/_layout.tsx | 49 + app/global.css | 3 + app/index.tsx | 10 + assets/adaptive-icon.png | Bin 0 -> 45894 bytes assets/icon.png | Bin 0 -> 45894 bytes assets/logo/gishen-logo.png | Bin 0 -> 27604 bytes assets/splash-icon.png | Bin 0 -> 45894 bytes babel.config.js | 16 + components/maps/AppMap.tsx | 2 + components/maps/AppMap.web.tsx | 62 + components/ui/Avatar.tsx | 60 + components/ui/Badge.tsx | 138 + components/ui/Button.tsx | 200 + components/ui/Card.tsx | 221 + components/ui/CategoryTile.tsx | 109 + components/ui/Chip.tsx | 138 + components/ui/EmptyState.tsx | 61 + components/ui/Field.tsx | 232 + components/ui/FloatingTabBar.tsx | 140 + components/ui/Header.tsx | 76 + components/ui/ProductCard.tsx | 262 + components/ui/QtyStepper.tsx | 83 + components/ui/Screen.tsx | 63 + components/ui/SearchField.tsx | 119 + components/ui/StickyBar.tsx | 62 + components/ui/Text.tsx | 27 + docs/BACKEND_SPEC.md | 135 + lib/api/client.ts | 34 + lib/commerce.ts | 21 + lib/data/branches.ts | 142 + lib/data/brand.ts | 38 + lib/data/clinical.ts | 322 + lib/data/products.ts | 997 ++ lib/data/seed.ts | 291 + lib/i18n.ts | 24 + lib/notifications.ts | 72 + lib/routes.ts | 52 + lib/stores/addressStore.ts | 103 + lib/stores/authStore.ts | 228 + lib/stores/cartStore.ts | 80 + lib/stores/emergencyContactStore.ts | 54 + lib/stores/familyStore.ts | 67 + lib/stores/favoritesStore.ts | 34 + lib/stores/langStore.ts | 23 + lib/stores/locationStore.ts | 59 + lib/stores/ordersStore.ts | 174 + lib/stores/prescriptionStore.ts | 165 + lib/stores/profileModeStore.ts | 109 + lib/stores/subscriptionStore.ts | 91 + lib/theme.ts | 168 + lib/utils.ts | 11 + locales/am/common.json | 84 + locales/en/common.json | 84 + metro.config.js | 6 + nativewind-env.d.ts | 1 + package-lock.json | 10409 ++++++++++++++++ package.json | 51 + tailwind.config.js | 40 + tsconfig.json | 11 + 96 files changed, 21555 insertions(+) create mode 100644 .gitignore create mode 100644 app.json create mode 100644 app/(root)/(screens)/_layout.tsx create mode 100644 app/(root)/(screens)/about.tsx create mode 100644 app/(root)/(screens)/addresses.tsx create mode 100644 app/(root)/(screens)/branches.tsx create mode 100644 app/(root)/(screens)/checkout.tsx create mode 100644 app/(root)/(screens)/contact.tsx create mode 100644 app/(root)/(screens)/emergency-contacts.tsx create mode 100644 app/(root)/(screens)/family/index.tsx create mode 100644 app/(root)/(screens)/family/invite.tsx create mode 100644 app/(root)/(screens)/loyalty.tsx create mode 100644 app/(root)/(screens)/orders/[id].tsx create mode 100644 app/(root)/(screens)/orders/index.tsx create mode 100644 app/(root)/(screens)/prescription/[id].tsx create mode 100644 app/(root)/(screens)/prescription/calendar/[id].tsx create mode 100644 app/(root)/(screens)/prescription/list.tsx create mode 100644 app/(root)/(screens)/prescription/review.tsx create mode 100644 app/(root)/(screens)/prescription/scan.tsx create mode 100644 app/(root)/(screens)/product/[id].tsx create mode 100644 app/(root)/(screens)/profiles/join.tsx create mode 100644 app/(root)/(screens)/profiles/switch.tsx create mode 100644 app/(root)/(screens)/search.tsx create mode 100644 app/(root)/(screens)/shop.tsx create mode 100644 app/(root)/(screens)/subscriptions/index.tsx create mode 100644 app/(root)/(screens)/tracking/[id].tsx create mode 100644 app/(root)/(tabs)/_layout.tsx create mode 100644 app/(root)/(tabs)/cart.tsx create mode 100644 app/(root)/(tabs)/favorites.tsx create mode 100644 app/(root)/(tabs)/index.tsx create mode 100644 app/(root)/(tabs)/profile.tsx create mode 100644 app/(root)/_layout.tsx create mode 100644 app/(root)/auth/_layout.tsx create mode 100644 app/(root)/auth/language.tsx create mode 100644 app/(root)/auth/otp.tsx create mode 100644 app/(root)/auth/welcome.tsx create mode 100644 app/_layout.tsx create mode 100644 app/global.css create mode 100644 app/index.tsx create mode 100644 assets/adaptive-icon.png create mode 100644 assets/icon.png create mode 100644 assets/logo/gishen-logo.png create mode 100644 assets/splash-icon.png create mode 100644 babel.config.js create mode 100644 components/maps/AppMap.tsx create mode 100644 components/maps/AppMap.web.tsx create mode 100644 components/ui/Avatar.tsx create mode 100644 components/ui/Badge.tsx create mode 100644 components/ui/Button.tsx create mode 100644 components/ui/Card.tsx create mode 100644 components/ui/CategoryTile.tsx create mode 100644 components/ui/Chip.tsx create mode 100644 components/ui/EmptyState.tsx create mode 100644 components/ui/Field.tsx create mode 100644 components/ui/FloatingTabBar.tsx create mode 100644 components/ui/Header.tsx create mode 100644 components/ui/ProductCard.tsx create mode 100644 components/ui/QtyStepper.tsx create mode 100644 components/ui/Screen.tsx create mode 100644 components/ui/SearchField.tsx create mode 100644 components/ui/StickyBar.tsx create mode 100644 components/ui/Text.tsx create mode 100644 docs/BACKEND_SPEC.md create mode 100644 lib/api/client.ts create mode 100644 lib/commerce.ts create mode 100644 lib/data/branches.ts create mode 100644 lib/data/brand.ts create mode 100644 lib/data/clinical.ts create mode 100644 lib/data/products.ts create mode 100644 lib/data/seed.ts create mode 100644 lib/i18n.ts create mode 100644 lib/notifications.ts create mode 100644 lib/routes.ts create mode 100644 lib/stores/addressStore.ts create mode 100644 lib/stores/authStore.ts create mode 100644 lib/stores/cartStore.ts create mode 100644 lib/stores/emergencyContactStore.ts create mode 100644 lib/stores/familyStore.ts create mode 100644 lib/stores/favoritesStore.ts create mode 100644 lib/stores/langStore.ts create mode 100644 lib/stores/locationStore.ts create mode 100644 lib/stores/ordersStore.ts create mode 100644 lib/stores/prescriptionStore.ts create mode 100644 lib/stores/profileModeStore.ts create mode 100644 lib/stores/subscriptionStore.ts create mode 100644 lib/theme.ts create mode 100644 lib/utils.ts create mode 100644 locales/am/common.json create mode 100644 locales/en/common.json create mode 100644 metro.config.js create mode 100644 nativewind-env.d.ts create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 tailwind.config.js create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dbff946 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +node_modules/ +.expo/ +dist/ +npm-debug.* +*.jks +*.p8 +*.p12 +*.key +*.mobileprovision +*.orig.* +web-build/ +.expo-export-check/ +.expo-export-ios/ +.DS_Store +*.log +.env +.env.local + +# @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb +# The following patterns were generated by expo-cli + +expo-env.d.ts +# @end expo-cli \ No newline at end of file diff --git a/README.md b/README.md index e69de29..70191db 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,31 @@ +# Gishen Pharmacy — Mobile + +React Native (Expo) customer app for Gishen Pharmacy. + +## Stack + +- Expo SDK 53 + expo-router +- NativeWind / Tailwind +- Zustand + AsyncStorage +- i18next (`en` / `am`) + +## Run + +```bash +npm install --legacy-peer-deps +npx expo start +``` + +## Brand + +Colors and logo from Gishen-Ecom (`#A8C73A` / `#141414`). + +## Backend + +Living contract: [`docs/BACKEND_SPEC.md`](docs/BACKEND_SPEC.md) — update whenever features change. + +## Demo + +- OTP: any 4+ digits (hint `1234`) +- Org join codes: `GISHEN-BANK`, `GISHEN-NGO` +- Payments: Chapa / Telebirr / M-Pesa; pay-at-branch only for pickup diff --git a/app.json b/app.json new file mode 100644 index 0000000..c239ca7 --- /dev/null +++ b/app.json @@ -0,0 +1,73 @@ +{ + "expo": { + "name": "Gishen Pharmacy", + "slug": "gishen-mob", + "version": "1.0.0", + "orientation": "portrait", + "icon": "./assets/icon.png", + "scheme": "gishen", + "userInterfaceStyle": "light", + "newArchEnabled": true, + "splash": { + "image": "./assets/splash-icon.png", + "resizeMode": "contain", + "backgroundColor": "#F6F7F2" + }, + "ios": { + "supportsTablet": true, + "bundleIdentifier": "com.gishen.pharmacy", + "infoPlist": { + "NSCameraUsageDescription": "Gishen needs camera access to scan prescriptions.", + "NSPhotoLibraryUsageDescription": "Gishen needs photo access to upload prescriptions.", + "NSLocationWhenInUseUsageDescription": "Gishen uses your location to find the nearest branch.", + "NSFaceIDUsageDescription": "Gishen uses biometrics to unlock the app securely.", + "ITSAppUsesNonExemptEncryption": false + } + }, + "android": { + "adaptiveIcon": { + "foregroundImage": "./assets/adaptive-icon.png", + "backgroundColor": "#F6F7F2" + }, + "package": "com.gishen.pharmacy", + "permissions": [ + "CAMERA", + "ACCESS_FINE_LOCATION", + "RECEIVE_BOOT_COMPLETED", + "VIBRATE" + ] + }, + "plugins": [ + "expo-router", + "expo-font", + [ + "expo-camera", + { + "cameraPermission": "Allow Gishen to scan prescriptions." + } + ], + [ + "expo-location", + { + "locationWhenInUsePermission": "Allow Gishen to find nearby branches." + } + ], + [ + "expo-notifications", + { + "icon": "./assets/icon.png", + "color": "#A8C73A" + } + ], + "expo-local-authentication" + ], + "experiments": { + "typedRoutes": true + }, + "extra": { + "router": { + "origin": false + } + } + } +} diff --git a/app/(root)/(screens)/_layout.tsx b/app/(root)/(screens)/_layout.tsx new file mode 100644 index 0000000..4773c55 --- /dev/null +++ b/app/(root)/(screens)/_layout.tsx @@ -0,0 +1,13 @@ +import { Stack } from "expo-router"; +import { colors } from "@/lib/theme"; + +export default function ScreensLayout() { + return ( + + ); +} diff --git a/app/(root)/(screens)/about.tsx b/app/(root)/(screens)/about.tsx new file mode 100644 index 0000000..a1c7c75 --- /dev/null +++ b/app/(root)/(screens)/about.tsx @@ -0,0 +1,96 @@ +import { Image, Linking, ScrollView, View } from "react-native"; +import { Badge } from "@/components/ui/Badge"; +import { Button } from "@/components/ui/Button"; +import { Card, InfoRow } from "@/components/ui/Card"; +import { AppHeader } from "@/components/ui/Header"; +import { Screen } from "@/components/ui/Screen"; +import { Text } from "@/components/ui/Text"; +import { brand } from "@/lib/data/brand"; +import { colors, gutter } from "@/lib/theme"; + +export default function AboutScreen() { + return ( + + + + + + + + {brand.name} + + Est. {brand.founded} · {brand.branchCount} branches + + + + + + + + + + + + Our story + + {brand.story} + + + + + Purpose + + {brand.purpose} + + + + + Vision + + {brand.vision} + + + + + Mission + + {brand.mission} + + + + + + + + + + +