Yaltopia-Tickets-App/app/invoices/[id].tsx
“kirukib” 3b471df8d5 feat: finalize app with swagger-based pages, Lucide icons, mobile UI
- Add Lucide React Native icon library and use across tabs and screens
- Mobile-like design: rounded cards (xl/2xl), section dividers, icon chips, chevrons
- New pages from swagger: register, invoices/[id], reports, documents, settings
- Invoice detail: amount, bill to, items, Share/PDF actions (GET /invoices/{id})
- Register screen with link to login (POST /auth/register)
- Reports list with mock data and download (GET /reports)
- Documents list with upload CTA (GET /documents)
- Settings: notifications link, language, about
- Profile: links to Notifications, Reports, Documents, Settings
- Home: invoice rows navigate to /invoices/[id]
- Login ↔ Register navigation
- Keep orange (#ea580c) and dark navbar (#2d2d2d) theme throughout
- README: update screens table with new routes

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-22 23:04:04 +03:00

101 lines
4.8 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 (
<ScrollView
className="flex-1 bg-[#f5f5f5]"
contentContainerStyle={{ padding: 20, paddingBottom: 40 }}
showsVerticalScrollIndicator={false}
>
<Card className="mb-4 overflow-hidden rounded-xl border border-border bg-white">
<CardContent className="p-5">
<View className="flex-row items-center justify-between">
<View className="flex-row items-center gap-2">
<FileText color={PRIMARY} size={22} strokeWidth={2} />
<Text className="font-semibold text-gray-900">Invoice #{invoice?.invoiceNumber ?? id}</Text>
</View>
<View className="rounded-full bg-amber-500/20 px-2.5 py-1">
<Text className="text-xs font-medium text-amber-700">{invoice?.status ?? 'Waiting'}</Text>
</View>
</View>
<Text className="text-muted-foreground mt-2 text-sm">Amount due</Text>
<Text className="mt-1 text-2xl font-bold text-gray-900">${invoice?.amount.toLocaleString() ?? '—'}</Text>
<View className="mt-3 flex-row gap-4">
<View className="flex-row items-center gap-1.5">
<Calendar color="#71717a" size={16} strokeWidth={2} />
<Text className="text-muted-foreground text-sm">Due {invoice?.dueDate ?? '—'}</Text>
</View>
<View className="flex-row items-center gap-1.5">
<Calendar color="#71717a" size={16} strokeWidth={2} />
<Text className="text-muted-foreground text-sm">Issued {invoice?.createdAt ?? '—'}</Text>
</View>
</View>
</CardContent>
</Card>
<Card className="mb-4 overflow-hidden rounded-xl border border-border bg-white">
<CardHeader className="pb-2">
<View className="flex-row items-center gap-2">
<User color="#71717a" size={18} strokeWidth={2} />
<CardTitle className="text-base">Bill to</CardTitle>
</View>
</CardHeader>
<CardContent>
<Text className="font-medium text-gray-900">{invoice?.recipient ?? '—'}</Text>
<Text className="text-muted-foreground text-sm">{invoice?.recipientEmail ?? '—'}</Text>
</CardContent>
</Card>
<Card className="mb-4 overflow-hidden rounded-xl border border-border bg-white">
<CardHeader className="pb-2">
<CardTitle className="text-base">Items</CardTitle>
</CardHeader>
<CardContent className="gap-2">
{MOCK_ITEMS.map((item, i) => (
<View key={i} className="flex-row justify-between border-b border-border py-2 last:border-0">
<Text className="text-gray-700">{item.description} × {item.qty}</Text>
<Text className="font-medium text-gray-900">${item.total.toLocaleString()}</Text>
</View>
))}
<View className="mt-2 border-t border-border pt-3">
<View className="flex-row justify-between">
<Text className="font-semibold text-gray-900">Total</Text>
<Text className="font-semibold text-gray-900">${invoice?.amount.toLocaleString() ?? '1,540'}</Text>
</View>
</View>
</CardContent>
</Card>
<View className="flex-row gap-3">
<Button variant="outline" className="min-h-12 flex-1 rounded-xl border-border" onPress={() => {}}>
<Share2 color={PRIMARY} size={20} strokeWidth={2} />
<Text className="ml-2 font-medium text-gray-700">Share</Text>
</Button>
<Button variant="outline" className="min-h-12 flex-1 rounded-xl border-border" onPress={() => {}}>
<Download color={PRIMARY} size={20} strokeWidth={2} />
<Text className="ml-2 font-medium text-gray-700">PDF</Text>
</Button>
</View>
<Button variant="ghost" className="mt-4 rounded-xl" onPress={() => router.back()}>
<ChevronRight className="rotate-180" color="#71717a" size={20} strokeWidth={2} />
<Text className="ml-2 font-medium text-muted-foreground">Back</Text>
</Button>
</ScrollView>
);
}