diff --git a/README.md b/README.md index 78bd365..cb71015 100644 --- a/README.md +++ b/README.md @@ -125,16 +125,21 @@ Use this list to wire the app to the live API. Each item maps to swagger endpoin | Route | Description | |-------|-------------| | `/(tabs)` | Bottom tabs: Home, Scan, Proforma, Payments, Profile | -| `/(tabs)/index` | Home — earnings summary, quick actions, invoice list | +| `/(tabs)/index` | Home — earnings summary, quick actions, invoice list; tap invoice → detail | | `/(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 | +| `/(tabs)/profile` | Profile — account, notifications, reports, documents, settings, login, logout | | `/proforma/[id]` | Proforma request detail — items, send to contacts, submissions | | `/payments/[id]` | Payment detail — associate to invoice | +| `/invoices/[id]` | Invoice detail — amount, bill to, items, Share, PDF (swagger: GET /invoices/{id}) | | `/notifications` | Notifications list — link to settings | -| `/notifications/settings` | Notification settings — toggles | -| `/login` | Sign in — email/password, Google | +| `/notifications/settings` | Notification settings — toggles (swagger: GET/PUT /notifications/settings) | +| `/reports` | Reports list — monthly reports, download PDF (swagger: GET /reports) | +| `/documents` | Documents list — upload, view (swagger: GET /documents) | +| `/settings` | App settings — notifications link, language, about | +| `/login` | Sign in — email/password, Google; link to register (swagger: POST /auth/login) | +| `/register` | Create account (swagger: POST /auth/register) | --- diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index 6d0f7ad..6deaff5 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -1,5 +1,5 @@ import { Tabs } from 'expo-router'; -import { View } from 'react-native'; +import { Home, ScanLine, FileText, Wallet, User } from '@/lib/icons'; const NAV_BG = '#2d2d2d'; const ACTIVE_TINT = '#ea580c'; @@ -11,11 +11,12 @@ export default function TabsLayout() { screenOptions={{ headerStyle: { backgroundColor: NAV_BG }, headerTintColor: '#ffffff', - headerTitleStyle: { fontWeight: '600' }, - tabBarStyle: { backgroundColor: NAV_BG }, + headerTitleStyle: { fontWeight: '600', fontSize: 18 }, + tabBarStyle: { backgroundColor: NAV_BG, paddingTop: 8 }, tabBarActiveTintColor: ACTIVE_TINT, tabBarInactiveTintColor: INACTIVE_TINT, - tabBarLabelStyle: { fontSize: 12 }, + tabBarLabelStyle: { fontSize: 11 }, + tabBarShowLabel: true, }} > , }} /> , }} /> , }} /> , }} /> , }} /> diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index a14ad81..ad1e19a 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -1,10 +1,12 @@ import { View, ScrollView, Pressable } from 'react-native'; import { Text } from '@/components/ui/text'; import { Button } from '@/components/ui/button'; -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Card, CardContent } from '@/components/ui/card'; import { EARNINGS_SUMMARY, MOCK_INVOICES, MOCK_USER } from '@/lib/mock-data'; import { router } from 'expo-router'; +import { Camera, Send, ChevronRight, Wallet, DollarSign, Clock } from '@/lib/icons'; +const PRIMARY = '#ea580c'; const statusColor: Record = { Waiting: 'bg-amber-500/20 text-amber-700', Paid: 'bg-emerald-500/20 text-emerald-700', @@ -14,88 +16,131 @@ const statusColor: Record = { export default function HomeScreen() { return ( - - + + Hi {MOCK_USER.name}, - Take a look at your last activity. + Take a look at your last activity. - - + + Earnings balance - ${EARNINGS_SUMMARY.balance.toLocaleString()} + ${EARNINGS_SUMMARY.balance.toLocaleString()} - - router.push('/(tabs)/payments')}> - Waiting for pay - ${EARNINGS_SUMMARY.waitingAmount.toLocaleString()} - {EARNINGS_SUMMARY.waitingCount} Waiting invoice + + router.push('/(tabs)/payments')} + > + + + + + Waiting for pay + ${EARNINGS_SUMMARY.waitingAmount.toLocaleString()} + {EARNINGS_SUMMARY.waitingCount} Waiting invoice + - - Paid this month - ${EARNINGS_SUMMARY.paidThisMonth.toLocaleString()} - {EARNINGS_SUMMARY.paidCount} Paid invoice + + + + + + Paid this month + ${EARNINGS_SUMMARY.paidThisMonth.toLocaleString()} + {EARNINGS_SUMMARY.paidCount} Paid invoice + - + - - - - - {['All', 'Draft', 'Waiting', 'Paid', 'Unpaid'].map((filter) => ( - - - {filter} - - - ))} - + + + {['All', 'Draft', 'Waiting', 'Paid', 'Unpaid'].map((filter) => ( + + + {filter} + + + ))} + + - Today + + + Today + + {MOCK_INVOICES.filter((i) => i.status === 'Waiting').map((inv) => ( - - - - {inv.recipient} - Invoice #{inv.invoiceNumber} - Due {inv.dueDate} - - - ${inv.amount.toLocaleString()} - - {inv.status} + router.push(`/invoices/${inv.id}`)}> + + + + {inv.recipient} + Invoice #{inv.invoiceNumber} · Due {inv.dueDate} - - - + + ${inv.amount.toLocaleString()} + + {inv.status} + + + + + + ))} - Yesterday + + + Yesterday + + {MOCK_INVOICES.filter((i) => i.status === 'Paid').map((inv) => ( - - - - {inv.recipient} - Invoice #{inv.invoiceNumber} - {inv.dueDate} - - - ${inv.amount.toLocaleString()} - - {inv.status} + router.push(`/invoices/${inv.id}`)}> + + + + {inv.recipient} + Invoice #{inv.invoiceNumber} · {inv.dueDate} - - - + + ${inv.amount.toLocaleString()} + + {inv.status} + + + + + + ))} ); diff --git a/app/(tabs)/payments.tsx b/app/(tabs)/payments.tsx index bc1eed4..6ea253d 100644 --- a/app/(tabs)/payments.tsx +++ b/app/(tabs)/payments.tsx @@ -4,53 +4,70 @@ import { Text } from '@/components/ui/text'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; import { MOCK_PAYMENTS } from '@/lib/mock-data'; +import { ScanLine, Link2, CheckCircle2, Wallet, ChevronRight } from '@/lib/icons'; + +const PRIMARY = '#ea580c'; export default function PaymentsScreen() { const matched = MOCK_PAYMENTS.filter((p) => p.matched); const pending = MOCK_PAYMENTS.filter((p) => !p.matched); return ( - - + + Match payment SMS (e.g. bank or Telebirr) to invoices for quick reconciliation. - - Pending match + + + Pending match + {pending.map((pay) => ( - - - - - ${pay.amount.toLocaleString()} - {pay.source} · {pay.date} - - + + + + + + ${pay.amount.toLocaleString()} + {pay.source} · {pay.date} + + ))} - Reconciled + + + Reconciled + {matched.map((pay) => ( - - - - - ${pay.amount.toLocaleString()} - - {pay.source} · {pay.date} {pay.reference && `· ${pay.reference}`} - - - - Matched - + + + + + + ${pay.amount.toLocaleString()} + + {pay.source} · {pay.date} {pay.reference && `· ${pay.reference}`} + + + + Matched + + ))} diff --git a/app/(tabs)/profile.tsx b/app/(tabs)/profile.tsx index c37852f..056d219 100644 --- a/app/(tabs)/profile.tsx +++ b/app/(tabs)/profile.tsx @@ -4,54 +4,115 @@ import { Text } from '@/components/ui/text'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { MOCK_USER } from '@/lib/mock-data'; +import { User, Mail, Globe, Bell, ChevronRight, Info, LogOut, LogIn, FileText, FolderOpen, Settings } from '@/lib/icons'; + +const PRIMARY = '#ea580c'; export default function ProfileScreen() { return ( - + {MOCK_USER.name[0]} {MOCK_USER.name} - {MOCK_USER.email} + {MOCK_USER.email} - - - Account + + + Account - - - Email + + + + + Email + {MOCK_USER.email} - - Language + + + + Language + English - router.push('/notifications')} className="flex-row justify-between py-2"> - Notifications - Manage + router.push('/notifications')} + className="flex-row items-center justify-between border-b border-border py-3" + > + + + Notifications + + + Manage + + + + router.push('/reports')} + className="flex-row items-center justify-between border-b border-border py-3" + > + + + Reports + + + + router.push('/documents')} + className="flex-row items-center justify-between border-b border-border py-3" + > + + + Documents + + + + router.push('/settings')} + className="flex-row items-center justify-between py-3" + > + + + Settings + + - - - About + + + + + About + - + Yaltopia Tickets App — Scan. Send. Reconcile. Companion to the Yaltopia Tickets web app. - - ); diff --git a/app/(tabs)/proforma.tsx b/app/(tabs)/proforma.tsx index 90dc33c..7a4a727 100644 --- a/app/(tabs)/proforma.tsx +++ b/app/(tabs)/proforma.tsx @@ -4,32 +4,48 @@ import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter } from '@/components/ui/card'; import { MOCK_PROFORMA } from '@/lib/mock-data'; import { router } from 'expo-router'; +import { Plus, Send, FileText, ChevronRight, Calendar } from '@/lib/icons'; + +const PRIMARY = '#ea580c'; export default function ProformaScreen() { return ( - - + + Create or select proforma requests and share with contacts via email or SMS. - - Your proforma requests + + + Your proforma requests + {MOCK_PROFORMA.map((pf) => ( router.push(`/proforma/${pf.id}`)}> - - - {pf.title} - {pf.description} - Deadline: {pf.deadline} · {pf.itemCount} items + + + {pf.title} + {pf.description} + + + Deadline {pf.deadline} · {pf.itemCount} items + - + Sent to {pf.sentCount} contacts - + + + Send to contacts + + diff --git a/app/(tabs)/scan.tsx b/app/(tabs)/scan.tsx index e359995..755eb7c 100644 --- a/app/(tabs)/scan.tsx +++ b/app/(tabs)/scan.tsx @@ -1,55 +1,64 @@ import { View, ScrollView } from 'react-native'; import { Text } from '@/components/ui/text'; import { Button } from '@/components/ui/button'; -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Card, CardContent } from '@/components/ui/card'; +import { Camera, FileText, ChevronRight } from '@/lib/icons'; + +const PRIMARY = '#ea580c'; export default function ScanScreen() { return ( - - + + Capture paper or digital invoices with your camera. We'll extract vendor, amount, date, and line items. - - - - 📷 + + + + Scan invoice - + Tap below to open camera and capture an invoice - - Recent scans - - - - - Acme Corp - Invoice #101 - Scanned Sep 12, 2022 · $1,240 - - - Pending - + + + Recent scans + + + + + Acme Corp - Invoice #101 + Scanned Sep 12, 2022 · $1,240 + + Pending + + - - - - - Tech Supplies Ltd - Invoice #88 - Scanned Sep 11, 2022 · $890 - - - Saved - + + + + Tech Supplies Ltd - Invoice #88 + Scanned Sep 11, 2022 · $890 + + Saved + + diff --git a/app/_layout.tsx b/app/_layout.tsx index 8d90a3d..5adccfe 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -25,6 +25,11 @@ export default function RootLayout() { + + + + + diff --git a/app/documents/index.tsx b/app/documents/index.tsx new file mode 100644 index 0000000..47503b5 --- /dev/null +++ b/app/documents/index.tsx @@ -0,0 +1,53 @@ +import { View, ScrollView, Pressable } from 'react-native'; +import { router } from 'expo-router'; +import { Text } from '@/components/ui/text'; +import { Card, CardContent } from '@/components/ui/card'; +import { Button } from '@/components/ui/button'; +import { FileText, ChevronRight, FolderOpen, Upload } from '@/lib/icons'; +import { MOCK_DOCUMENTS } from '@/lib/mock-data'; + +const PRIMARY = '#ea580c'; + +export default function DocumentsScreen() { + return ( + + + + Documents + + + Uploaded invoices, scans, and attachments. Synced with your account. + + + + + {MOCK_DOCUMENTS.map((d) => ( + + + + + + + + {d.name} + {d.size} · {d.uploadedAt} + + + + + + ))} + + + + ); +} diff --git a/app/invoices/[id].tsx b/app/invoices/[id].tsx new file mode 100644 index 0000000..ff4b661 --- /dev/null +++ b/app/invoices/[id].tsx @@ -0,0 +1,100 @@ +import { View, ScrollView } from 'react-native'; +import { useLocalSearchParams, router } from 'expo-router'; +import { Text } from '@/components/ui/text'; +import { Button } from '@/components/ui/button'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { FileText, Calendar, User, Share2, Download, ChevronRight } from '@/lib/icons'; +import { MOCK_INVOICES } from '@/lib/mock-data'; + +const PRIMARY = '#ea580c'; +const MOCK_ITEMS = [ + { description: 'Marketing Landing Page Package', qty: 1, unitPrice: 1000, total: 1000 }, + { description: 'Instagram Post Initial Design', qty: 4, unitPrice: 100, total: 400 }, +]; + +export default function InvoiceDetailScreen() { + const { id } = useLocalSearchParams<{ id: string }>(); + const invoice = MOCK_INVOICES.find((i) => i.id === id); + + return ( + + + + + + + Invoice #{invoice?.invoiceNumber ?? id} + + + {invoice?.status ?? 'Waiting'} + + + Amount due + ${invoice?.amount.toLocaleString() ?? '—'} + + + + Due {invoice?.dueDate ?? '—'} + + + + Issued {invoice?.createdAt ?? '—'} + + + + + + + + + + Bill to + + + + {invoice?.recipient ?? '—'} + {invoice?.recipientEmail ?? '—'} + + + + + + Items + + + {MOCK_ITEMS.map((item, i) => ( + + {item.description} × {item.qty} + ${item.total.toLocaleString()} + + ))} + + + Total + ${invoice?.amount.toLocaleString() ?? '1,540'} + + + + + + + + + + + + ); +} diff --git a/app/login.tsx b/app/login.tsx index 1669f8e..6bacc5f 100644 --- a/app/login.tsx +++ b/app/login.tsx @@ -1,29 +1,39 @@ -import { View, ScrollView } from 'react-native'; +import { View, ScrollView, Pressable } from 'react-native'; import { router } from 'expo-router'; import { Text } from '@/components/ui/text'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; +import { Mail, ArrowLeft } from '@/lib/icons'; export default function LoginScreen() { return ( - - Yaltopia Tickets - + + Yaltopia Tickets + - Sign in - Use the same account as the web app. + Sign in + Use the same account as the web app. - - - ); diff --git a/app/notifications/index.tsx b/app/notifications/index.tsx index 1290072..0e95005 100644 --- a/app/notifications/index.tsx +++ b/app/notifications/index.tsx @@ -2,6 +2,7 @@ import { View, ScrollView, Pressable } from 'react-native'; import { router } from 'expo-router'; import { Text } from '@/components/ui/text'; import { Card, CardContent } from '@/components/ui/card'; +import { Bell, Settings, ChevronRight } from '@/lib/icons'; const MOCK_NOTIFICATIONS = [ { id: '1', title: 'Invoice reminder', body: 'Invoice #2 to Robin Murray is due in 2 days.', time: '2h ago', read: false }, @@ -13,8 +14,12 @@ export default function NotificationsScreen() { return ( - Notifications - router.push('/notifications/settings')}> + + + Notifications + + router.push('/notifications/settings')}> + Settings diff --git a/app/register.tsx b/app/register.tsx new file mode 100644 index 0000000..3cc4a35 --- /dev/null +++ b/app/register.tsx @@ -0,0 +1,40 @@ +import { View, ScrollView, Pressable } from 'react-native'; +import { router } from 'expo-router'; +import { Text } from '@/components/ui/text'; +import { Button } from '@/components/ui/button'; +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; +import { Mail, ArrowLeft, UserPlus } from '@/lib/icons'; + +export default function RegisterScreen() { + return ( + + Yaltopia Tickets + + + Create account + Register with the same account format as the web app. + + + + + + + router.push('/login')} className="mt-2"> + Already have an account? Sign in + + + + ); +} diff --git a/app/reports/index.tsx b/app/reports/index.tsx new file mode 100644 index 0000000..908fa7b --- /dev/null +++ b/app/reports/index.tsx @@ -0,0 +1,54 @@ +import { View, ScrollView, Pressable } 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'; +import { FileText, Download, ChevronRight, BarChart3 } from '@/lib/icons'; +import { MOCK_REPORTS } from '@/lib/mock-data'; + +const PRIMARY = '#ea580c'; + +export default function ReportsScreen() { + return ( + + + + Reports + + + Monthly reports and PDF exports. Generate from the web app or view here. + + + {MOCK_REPORTS.map((r) => ( + + + + + + + + {r.title} + {r.period} + Generated {r.generatedAt} + + + + + + + + + + + ))} + + + + ); +} diff --git a/app/settings.tsx b/app/settings.tsx new file mode 100644 index 0000000..5fa6e39 --- /dev/null +++ b/app/settings.tsx @@ -0,0 +1,72 @@ +import { View, ScrollView, Pressable } from 'react-native'; +import { router } from 'expo-router'; +import { Text } from '@/components/ui/text'; +import { Button } from '@/components/ui/button'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Settings, Bell, Globe, ChevronRight, Info } from '@/lib/icons'; + +const PRIMARY = '#ea580c'; + +export default function SettingsScreen() { + return ( + + + + Settings + + + + + Preferences + + + router.push('/notifications/settings')} + > + + + Notifications + + + + + + + Language + + English + + + + + + + + + About + + + + + Yaltopia Tickets App v1.0 — Scan. Send. Reconcile. + + + + + + + API: Invoices, Proforma, Payments, Reports, Documents, Notifications — see swagger.json and README for integration. + + + + + + ); +} diff --git a/lib/icons.tsx b/lib/icons.tsx new file mode 100644 index 0000000..5ac3f5c --- /dev/null +++ b/lib/icons.tsx @@ -0,0 +1,37 @@ +/** + * Re-export Lucide icons for consistent use. Use these with color="#ea580c" for primary, "#ffffff" on dark bar. + */ +export { + Home, + ScanLine, + FileText, + Wallet, + User, + Camera, + Send, + ChevronRight, + Bell, + Settings, + LogOut, + LogIn, + Plus, + Link2, + CheckCircle2, + Clock, + Copy, + Calendar, + Menu, + ArrowLeft, + MoreVertical, + AlertCircle, + DollarSign, + Mail, + Globe, + Info, + FolderOpen, + Share2, + Download, + BarChart3, + Upload, + UserPlus, +} from 'lucide-react-native'; diff --git a/lib/mock-data.ts b/lib/mock-data.ts index d88a418..2f52c2f 100644 --- a/lib/mock-data.ts +++ b/lib/mock-data.ts @@ -92,3 +92,13 @@ export const EARNINGS_SUMMARY = { paidThisMonth: 4120, paidCount: 4, }; + +export const MOCK_REPORTS = [ + { id: 'r1', title: 'September 2022', period: 'Sep 1 – Sep 30, 2022', generatedAt: 'Oct 1, 2022', downloadUrl: '#' }, + { id: 'r2', title: 'August 2022', period: 'Aug 1 – Aug 31, 2022', generatedAt: 'Sep 1, 2022', downloadUrl: '#' }, +]; + +export const MOCK_DOCUMENTS = [ + { id: 'd1', name: 'Invoice #2 - Robin Murray.pdf', size: '124 KB', uploadedAt: 'Sep 8, 2022' }, + { id: 'd2', name: 'Scan - Acme Corp.pdf', size: '89 KB', uploadedAt: 'Sep 12, 2022' }, +]; diff --git a/package-lock.json b/package-lock.json index 90beee3..5568cda 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "expo-linking": "^8.0.11", "expo-router": "^6.0.23", "expo-status-bar": "~3.0.9", + "lucide-react-native": "^0.575.0", "nativewind": "^4.2.2", "react": "19.1.0", "react-dom": "19.1.0", @@ -28,6 +29,7 @@ "react-native-reanimated": "^4.2.2", "react-native-safe-area-context": "^5.6.2", "react-native-screens": "^4.23.0", + "react-native-svg": "^15.15.3", "react-native-web": "^0.21.0", "tailwind-merge": "^3.5.0", "tailwindcss-animate": "^1.0.7" @@ -4143,6 +4145,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, "node_modules/bplist-creator": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz", @@ -4740,6 +4748,56 @@ "hyphenate-style-name": "^1.0.3" } }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-tree/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -4870,6 +4928,61 @@ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "license": "MIT" }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dotenv": { "version": "16.4.7", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", @@ -4924,6 +5037,18 @@ "node": ">= 0.8" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/env-editor": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.2.tgz", @@ -7344,6 +7469,17 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react-native": { + "version": "0.575.0", + "resolved": "https://registry.npmjs.org/lucide-react-native/-/lucide-react-native-0.575.0.tgz", + "integrity": "sha512-kdGcjF4Rm1YKuNs3IaW5lDAqVKn9RBj1Fmjt3JBr08PMIXpVV7iL0ICNF/awiPZQicHlx/v9xgyZZS4TAFxDNg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-native": "*", + "react-native-svg": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0" + } + }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -7359,6 +7495,12 @@ "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", "license": "Apache-2.0" }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "license": "CC0-1.0" + }, "node_modules/memoize-one": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", @@ -7977,6 +8119,18 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/nullthrows": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", @@ -9171,6 +9325,21 @@ "react-native": "*" } }, + "node_modules/react-native-svg": { + "version": "15.15.3", + "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.15.3.tgz", + "integrity": "sha512-/k4KYwPBLGcx2f5d4FjE+vCScK7QOX14cl2lIASJ28u4slHHtIhL0SZKU7u9qmRBHxTCKPoPBtN6haT1NENJNA==", + "license": "MIT", + "dependencies": { + "css-select": "^5.1.0", + "css-tree": "^1.1.3", + "warn-once": "0.1.1" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-web": { "version": "0.21.2", "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.2.tgz", diff --git a/package.json b/package.json index 22ffac9..5ea8068 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "expo-linking": "^8.0.11", "expo-router": "^6.0.23", "expo-status-bar": "~3.0.9", + "lucide-react-native": "^0.575.0", "nativewind": "^4.2.2", "react": "19.1.0", "react-dom": "19.1.0", @@ -29,6 +30,7 @@ "react-native-reanimated": "^4.2.2", "react-native-safe-area-context": "^5.6.2", "react-native-screens": "^4.23.0", + "react-native-svg": "^15.15.3", "react-native-web": "^0.21.0", "tailwind-merge": "^3.5.0", "tailwindcss-animate": "^1.0.7"