-
This commit is contained in:
parent
94064e66f7
commit
b42b3d7602
148
README.md
148
README.md
|
|
@ -0,0 +1,148 @@
|
|||
# Yaltopia Tickets App
|
||||
|
||||
Mobile companion to the Yaltopia Tickets web app: **Scan. Send. Reconcile.**
|
||||
React Native (Expo) with NativeWind (Tailwind), React Native Reusables (shadcn-style), and orange/black theme.
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
Then choose iOS, Android, or Web.
|
||||
|
||||
## API Reference
|
||||
|
||||
Backend API is described in **`swagger.json`** (Yaltopia Invoice System API). Base URLs:
|
||||
|
||||
- Local: `http://localhost:3001/api/v1`
|
||||
- Production: `https://api.yaltopia.com/api/v1`
|
||||
|
||||
Auth: Bearer JWT in `Authorization` header.
|
||||
|
||||
---
|
||||
|
||||
## Integration Task List
|
||||
|
||||
Use this list to wire the app to the live API. Each item maps to swagger endpoints and app screens.
|
||||
|
||||
### Authentication
|
||||
|
||||
- [ ] **Auth API client** — Create `lib/api/auth.ts` (or use a shared client) with:
|
||||
- `POST /auth/register` — register
|
||||
- `POST /auth/login` — login (return access + refresh)
|
||||
- `POST /auth/refresh` — refresh token
|
||||
- `GET /auth/profile` — current user
|
||||
- `POST /auth/logout` — logout
|
||||
- `GET /auth/google`, `GET /auth/google/callback` — Google OAuth (if used)
|
||||
- [ ] **Token storage** — Store access/refresh tokens securely (e.g. expo-secure-store); attach Bearer to requests.
|
||||
- [ ] **Login screen** — Wire `app/login.tsx` to login/register and Google; on success navigate to `/(tabs)` and store tokens.
|
||||
- [ ] **Auth guard** — Protect tab/stack routes: redirect to `/login` when unauthenticated; optional “Remember me”.
|
||||
|
||||
### User & Profile
|
||||
|
||||
- [ ] **Profile API** — `GET /users/me` in `lib/api/users.ts`; return type from swagger `UserResponseDto`.
|
||||
- [ ] **Profile screen** — Load user via `/users/me` in `app/(tabs)/profile.tsx`; show name, email, language; “Manage” → `/notifications`.
|
||||
- [ ] **Profile update** — If backend supports PATCH/PUT for profile, add form and wire in profile screen.
|
||||
|
||||
### Invoices
|
||||
|
||||
- [ ] **Invoices API** — `lib/api/invoices.ts`:
|
||||
- `GET /invoices` (with pagination, filters)
|
||||
- `GET /invoices/stats`
|
||||
- `GET /invoices/{id}`, `POST /invoices`, `PUT /invoices/{id}` (if needed)
|
||||
- `GET /invoices/{id}/pdf`, `PATCH /invoices/{id}/status`
|
||||
- `POST /invoices/share/email`, `POST /invoices/share/link`
|
||||
- [ ] **Home screen** — Replace mock earnings/invoice list with `/invoices` and `/invoices/stats` (and dashboard metrics if used).
|
||||
- [ ] **Invoice detail** — Add `app/invoices/[id].tsx` (or reuse share flow) for view/edit/PDF/share; wire to `GET /invoices/{id}` and PDF endpoint.
|
||||
|
||||
### Scan (Invoice & Payment Receipt)
|
||||
|
||||
- [ ] **Scan API** — `lib/api/scan.ts`:
|
||||
- `POST /scan/invoice` — upload image, return extracted invoice data (match swagger request/response).
|
||||
- `POST /scan/payment-receipt` — upload payment receipt image.
|
||||
- `GET /scan/images/invoice/{invoiceId}`, `GET /scan/images/payment/{paymentId}` if needed.
|
||||
- [ ] **Scan screen** — In `app/(tabs)/scan.tsx`: camera or image picker → upload to `POST /scan/invoice`; show “Extracting…” then result; “Save as new” / “Match to existing” using invoices API.
|
||||
- [ ] **Scan → invoice** — Create or update invoice from scan result; sync with `POST /invoices` or `PUT /invoices/{id}`.
|
||||
|
||||
### Proforma
|
||||
|
||||
- [ ] **Proforma requests API** — `lib/api/proforma-requests.ts`:
|
||||
- `GET /proforma-requests`, `POST /proforma-requests` (create)
|
||||
- `GET /proforma-requests/{id}`, `PUT /proforma-requests/{id}`
|
||||
- `POST /proforma-requests/{id}/items`, `GET /proforma-requests/{id}/items`; items CRUD if in swagger
|
||||
- `GET /proforma-requests/{id}/submissions`, `GET /proforma-requests/submissions/{id}`, revision/revise/close/cancel
|
||||
- `GET /proforma-requests/{id}/comparison-data` if used
|
||||
- [ ] **Proforma list** — In `app/(tabs)/proforma.tsx`: replace mock with `GET /proforma-requests` (pagination, status filter); “Create new” → create request then navigate to detail.
|
||||
- [ ] **Proforma detail** — In `app/proforma/[id].tsx`: load `GET /proforma-requests/{id}` and items; show submissions; “Send to contacts” → share link/email (use share endpoint or deep link from API).
|
||||
- [ ] **Proforma PDF** — If swagger has `GET /proforma/{id}/pdf`, add “Download PDF” on detail.
|
||||
|
||||
### Payments & Payment Requests
|
||||
|
||||
- [ ] **Payments API** — `lib/api/payments.ts`:
|
||||
- `GET /payments` (with pagination, optional `invoiceId` filter)
|
||||
- `GET /payments/{id}`, `POST /payments` (create), `PUT /payments/{id}` (update)
|
||||
- `POST /payments/{id}/flag`, `POST /payments/{paymentId}/associate` (associate to invoice)
|
||||
- [ ] **Payments list** — In `app/(tabs)/payments.tsx`: replace mock with `GET /payments`; show pending vs reconciled (e.g. by `invoiceId` or status from API).
|
||||
- [ ] **Payment detail** — In `app/payments/[id].tsx`: load `GET /payments/{id}`; “Associate to invoice” → pick invoice (from `GET /invoices`) then `POST /payments/{paymentId}/associate`.
|
||||
- [ ] **Payment request flow** — If “payment request” in product means creating a payment record for someone to pay: use `POST /payments` and any “request” endpoint from swagger; add screen or modal as needed.
|
||||
|
||||
### Notifications
|
||||
|
||||
- [ ] **Notifications API** — `lib/api/notifications.ts`:
|
||||
- `POST /notifications/subscribe` (push subscription payload)
|
||||
- `DELETE /notifications/unsubscribe/{endpoint}`
|
||||
- `GET /notifications` — list for current user
|
||||
- `GET /notifications/settings`, `PUT /notifications/settings`
|
||||
- `POST /notifications/invoice/{id}/reminder` (send reminder)
|
||||
- [ ] **Notifications list** — In `app/notifications/index.tsx`: replace mock with `GET /notifications`; mark read if API supports it.
|
||||
- [ ] **Notification settings** — In `app/notifications/settings.tsx`: load `GET /notifications/settings`, save with `PUT /notifications/settings` (invoice reminders, days before due, news, report ready).
|
||||
- [ ] **Push subscription** — On login or app open, register device with `POST /notifications/subscribe` (Expo push token or web push); handle unsubscribe on logout.
|
||||
|
||||
### Dashboard & Reports (optional)
|
||||
|
||||
- [ ] **Dashboard API** — If used: `GET /dashboard/metrics`, `/dashboard/invoice-trends`, `/dashboard/revenue-trends`, `/dashboard/invoice-status`, `/dashboard/sales-purchase`, `/dashboard/scanned-invoices`.
|
||||
- [ ] **Home dashboard** — Optionally show metrics/charts on Home from dashboard endpoints.
|
||||
- [ ] **Reports** — `GET /reports`, `GET /reports/latest`, `POST /reports/generate`, `GET /reports/{id}/download`; add a “Reports” entry in Profile or a dedicated screen if needed.
|
||||
|
||||
### Share & Documents
|
||||
|
||||
- [ ] **Share API** — `GET /share`, `POST /share/email`, `GET /share/view/{token}`, `POST /share/{id}/deactivate`, `GET /share/{id}` if used for proforma/invoice sharing.
|
||||
- [ ] **Documents API** — `POST /documents/upload`, `GET /documents`, `GET /documents/{id}/preview`, `GET /documents/{id}/download`; use for attachments or scanned files if applicable.
|
||||
|
||||
### General
|
||||
|
||||
- [ ] **API client** — Central `lib/api/client.ts`: base URL from env, `Authorization: Bearer`, error handling, 401 → refresh or redirect to login.
|
||||
- [ ] **Environment** — `EXPO_PUBLIC_API_URL` or similar for API base; use in client.
|
||||
- [ ] **Types** — Generate or copy DTOs from `swagger.json` (e.g. into `lib/api/types.ts`) for type-safe requests/responses.
|
||||
- [ ] **Offline / sync** — Optional: queue scan and payment-associate actions when offline; sync when back online (per product spec).
|
||||
|
||||
---
|
||||
|
||||
## Screens (current)
|
||||
|
||||
| Route | Description |
|
||||
|-------|-------------|
|
||||
| `/(tabs)` | Bottom tabs: Home, Scan, Proforma, Payments, Profile |
|
||||
| `/(tabs)/index` | Home — earnings summary, quick actions, invoice list |
|
||||
| `/(tabs)/scan` | Scan invoice — camera placeholder, recent scans |
|
||||
| `/(tabs)/proforma` | Proforma list — create, list requests; tap → detail |
|
||||
| `/(tabs)/payments` | Payments — pending match, reconciled list; tap pending → detail |
|
||||
| `/(tabs)/profile` | Profile — account, notifications link, login, logout |
|
||||
| `/proforma/[id]` | Proforma request detail — items, send to contacts, submissions |
|
||||
| `/payments/[id]` | Payment detail — associate to invoice |
|
||||
| `/notifications` | Notifications list — link to settings |
|
||||
| `/notifications/settings` | Notification settings — toggles |
|
||||
| `/login` | Sign in — email/password, Google |
|
||||
|
||||
---
|
||||
|
||||
## Design
|
||||
|
||||
- **Primary:** Orange `#ea580c` (CTAs, active tab).
|
||||
- **Navbar / tab bar:** Dark `#2d2d2d`; white/orange text.
|
||||
- **Backgrounds:** White / light gray `#f5f5f5`.
|
||||
- **Font:** DM Sans (or system fallback).
|
||||
|
||||
See project plan / `mobile.md` for full design system and copy.
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import { View, ScrollView } from 'react-native';
|
||||
import { router } from 'expo-router';
|
||||
import { Text } from '@/components/ui/text';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
|
|
@ -27,7 +28,7 @@ export default function PaymentsScreen() {
|
|||
<Text className="font-semibold text-gray-900">${pay.amount.toLocaleString()}</Text>
|
||||
<Text className="text-muted-foreground text-sm">{pay.source} · {pay.date}</Text>
|
||||
</View>
|
||||
<Button variant="outline" size="sm">
|
||||
<Button variant="outline" size="sm" onPress={() => router.push(`/payments/${pay.id}`)}>
|
||||
<Text className="font-medium">Match to invoice</Text>
|
||||
</Button>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ export default function ProformaScreen() {
|
|||
|
||||
<Text className="text-muted-foreground mb-2 text-sm">Your proforma requests</Text>
|
||||
{MOCK_PROFORMA.map((pf) => (
|
||||
<Card key={pf.id} className="mb-3">
|
||||
<Pressable key={pf.id} onPress={() => router.push(`/proforma/${pf.id}`)}>
|
||||
<Card className="mb-3">
|
||||
<CardHeader>
|
||||
<CardTitle>{pf.title}</CardTitle>
|
||||
<CardDescription>{pf.description}</CardDescription>
|
||||
|
|
@ -26,11 +27,12 @@ export default function ProformaScreen() {
|
|||
</CardHeader>
|
||||
<CardFooter className="flex-row justify-between">
|
||||
<Text className="text-muted-foreground text-sm">Sent to {pf.sentCount} contacts</Text>
|
||||
<Button variant="outline" size="sm">
|
||||
<Button variant="outline" size="sm" onPress={() => router.push(`/proforma/${pf.id}`)}>
|
||||
<Text className="font-medium">Send to contacts</Text>
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Pressable>
|
||||
))}
|
||||
</ScrollView>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export default function RootLayout() {
|
|||
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
||||
<Stack.Screen name="proforma/[id]" options={{ title: 'Proforma request' }} />
|
||||
<Stack.Screen name="payments/[id]" options={{ title: 'Payment' }} />
|
||||
<Stack.Screen name="notifications/index" options={{ title: 'Notifications' }} />
|
||||
<Stack.Screen name="notifications" options={{ title: 'Notifications' }} />
|
||||
<Stack.Screen name="notifications/settings" options={{ title: 'Notification settings' }} />
|
||||
<Stack.Screen name="login" options={{ title: 'Sign in', headerShown: false }} />
|
||||
</Stack>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user