-
This commit is contained in:
parent
4efcacaeba
commit
94064e66f7
|
|
@ -1,4 +1,5 @@
|
||||||
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 { Text } from '@/components/ui/text';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
|
@ -28,10 +29,10 @@ export default function ProfileScreen() {
|
||||||
<Text className="text-muted-foreground">Language</Text>
|
<Text className="text-muted-foreground">Language</Text>
|
||||||
<Text className="text-gray-900">English</Text>
|
<Text className="text-gray-900">English</Text>
|
||||||
</View>
|
</View>
|
||||||
<View className="flex-row justify-between py-2">
|
<Pressable onPress={() => router.push('/notifications')} className="flex-row justify-between py-2">
|
||||||
<Text className="text-muted-foreground">Notifications</Text>
|
<Text className="text-muted-foreground">Notifications</Text>
|
||||||
<Text className="text-gray-900">On</Text>
|
<Text className="text-primary font-medium">Manage</Text>
|
||||||
</View>
|
</Pressable>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|
@ -46,6 +47,9 @@ export default function ProfileScreen() {
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
<Button variant="outline" className="mt-2" onPress={() => router.push('/login')}>
|
||||||
|
<Text className="font-medium">Sign in (different account)</Text>
|
||||||
|
</Button>
|
||||||
<Button variant="destructive" className="mt-2">
|
<Button variant="destructive" className="mt-2">
|
||||||
<Text className="font-medium">Log out</Text>
|
<Text className="font-medium">Log out</Text>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,20 @@ export default function RootLayout() {
|
||||||
<SafeAreaProvider>
|
<SafeAreaProvider>
|
||||||
<View className="flex-1 bg-background">
|
<View className="flex-1 bg-background">
|
||||||
<StatusBar style="light" />
|
<StatusBar style="light" />
|
||||||
<Stack screenOptions={{ headerShown: false }} />
|
<Stack
|
||||||
|
screenOptions={{
|
||||||
|
headerStyle: { backgroundColor: '#2d2d2d' },
|
||||||
|
headerTintColor: '#ffffff',
|
||||||
|
headerTitleStyle: { fontWeight: '600' },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<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/settings" options={{ title: 'Notification settings' }} />
|
||||||
|
<Stack.Screen name="login" options={{ title: 'Sign in', headerShown: false }} />
|
||||||
|
</Stack>
|
||||||
<PortalHost />
|
<PortalHost />
|
||||||
</View>
|
</View>
|
||||||
</SafeAreaProvider>
|
</SafeAreaProvider>
|
||||||
|
|
|
||||||
30
app/login.tsx
Normal file
30
app/login.tsx
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
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, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function LoginScreen() {
|
||||||
|
return (
|
||||||
|
<ScrollView className="flex-1 bg-background" contentContainerStyle={{ padding: 16, paddingVertical: 48 }}>
|
||||||
|
<Text className="mb-6 text-center text-2xl font-bold text-gray-900">Yaltopia Tickets</Text>
|
||||||
|
<Card className="mb-4">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Sign in</CardTitle>
|
||||||
|
<CardDescription>Use the same account as the web app.</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="gap-3">
|
||||||
|
<Button className="bg-primary">
|
||||||
|
<Text className="text-primary-foreground font-medium">Email & password</Text>
|
||||||
|
</Button>
|
||||||
|
<Button variant="outline">
|
||||||
|
<Text className="font-medium">Continue with Google</Text>
|
||||||
|
</Button>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
<Button variant="ghost" onPress={() => router.back()}>
|
||||||
|
<Text className="font-medium">Back</Text>
|
||||||
|
</Button>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
}
|
||||||
33
app/notifications/index.tsx
Normal file
33
app/notifications/index.tsx
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
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';
|
||||||
|
|
||||||
|
const MOCK_NOTIFICATIONS = [
|
||||||
|
{ id: '1', title: 'Invoice reminder', body: 'Invoice #2 to Robin Murray is due in 2 days.', time: '2h ago', read: false },
|
||||||
|
{ id: '2', title: 'Payment received', body: 'Payment of $500 received for Invoice #4.', time: '1d ago', read: true },
|
||||||
|
{ id: '3', title: 'Proforma submission', body: 'Vendor A submitted a quote for Marketing Landing Page.', time: '2d ago', read: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function NotificationsScreen() {
|
||||||
|
return (
|
||||||
|
<ScrollView className="flex-1 bg-background" contentContainerStyle={{ padding: 16, paddingBottom: 32 }}>
|
||||||
|
<View className="mb-4 flex-row items-center justify-between">
|
||||||
|
<Text className="text-xl font-semibold text-gray-900">Notifications</Text>
|
||||||
|
<Pressable onPress={() => router.push('/notifications/settings')}>
|
||||||
|
<Text className="text-primary font-medium">Settings</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{MOCK_NOTIFICATIONS.map((n) => (
|
||||||
|
<Card key={n.id} className={`mb-2 ${!n.read ? 'border-primary/30' : ''}`}>
|
||||||
|
<CardContent className="py-3">
|
||||||
|
<Text className="font-semibold text-gray-900">{n.title}</Text>
|
||||||
|
<Text className="text-muted-foreground mt-1 text-sm">{n.body}</Text>
|
||||||
|
<Text className="text-muted-foreground mt-1 text-xs">{n.time}</Text>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
}
|
||||||
41
app/notifications/settings.tsx
Normal file
41
app/notifications/settings.tsx
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { View, ScrollView, Switch } from 'react-native';
|
||||||
|
import { router } from 'expo-router';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { Text } from '@/components/ui/text';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function NotificationSettingsScreen() {
|
||||||
|
const [invoiceReminders, setInvoiceReminders] = useState(true);
|
||||||
|
const [daysBeforeDue, setDaysBeforeDue] = useState(2);
|
||||||
|
const [newsAlerts, setNewsAlerts] = useState(true);
|
||||||
|
const [reportReady, setReportReady] = useState(true);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ScrollView className="flex-1 bg-background" contentContainerStyle={{ padding: 16, paddingBottom: 32 }}>
|
||||||
|
<Card className="mb-4">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Notification settings</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="gap-4">
|
||||||
|
<View className="flex-row items-center justify-between">
|
||||||
|
<Text className="text-gray-900">Invoice reminders</Text>
|
||||||
|
<Switch value={invoiceReminders} onValueChange={setInvoiceReminders} />
|
||||||
|
</View>
|
||||||
|
<View className="flex-row items-center justify-between">
|
||||||
|
<Text className="text-gray-900">News & announcements</Text>
|
||||||
|
<Switch value={newsAlerts} onValueChange={setNewsAlerts} />
|
||||||
|
</View>
|
||||||
|
<View className="flex-row items-center justify-between">
|
||||||
|
<Text className="text-gray-900">Report ready</Text>
|
||||||
|
<Switch value={reportReady} onValueChange={setReportReady} />
|
||||||
|
</View>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Button variant="outline" onPress={() => router.back()}>
|
||||||
|
<Text className="font-medium">Back</Text>
|
||||||
|
</Button>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
}
|
||||||
44
app/payments/[id].tsx
Normal file
44
app/payments/[id].tsx
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
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';
|
||||||
|
|
||||||
|
export default function PaymentDetailScreen() {
|
||||||
|
const { id } = useLocalSearchParams<{ id: string }>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ScrollView className="flex-1 bg-background" contentContainerStyle={{ padding: 16, paddingBottom: 32 }}>
|
||||||
|
<Card className="mb-4">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Payment #{id ?? '—'}</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="gap-2">
|
||||||
|
<View className="flex-row justify-between py-2">
|
||||||
|
<Text className="text-muted-foreground">Amount</Text>
|
||||||
|
<Text className="font-semibold text-gray-900">$2,000.00</Text>
|
||||||
|
</View>
|
||||||
|
<View className="flex-row justify-between py-2">
|
||||||
|
<Text className="text-muted-foreground">Source</Text>
|
||||||
|
<Text className="text-gray-900">Telebirr</Text>
|
||||||
|
</View>
|
||||||
|
<View className="flex-row justify-between py-2">
|
||||||
|
<Text className="text-muted-foreground">Date</Text>
|
||||||
|
<Text className="text-gray-900">Sep 11, 2022</Text>
|
||||||
|
</View>
|
||||||
|
<View className="flex-row justify-between py-2">
|
||||||
|
<Text className="text-muted-foreground">Associated invoice</Text>
|
||||||
|
<Text className="text-amber-600">Not linked</Text>
|
||||||
|
</View>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Button className="mb-3 bg-primary" onPress={() => {}}>
|
||||||
|
<Text className="text-primary-foreground font-medium">Associate to invoice</Text>
|
||||||
|
</Button>
|
||||||
|
<Button variant="outline" onPress={() => router.back()}>
|
||||||
|
<Text className="font-medium">Back to payments</Text>
|
||||||
|
</Button>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
}
|
||||||
66
app/proforma/[id].tsx
Normal file
66
app/proforma/[id].tsx
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
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, CardDescription } from '@/components/ui/card';
|
||||||
|
|
||||||
|
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 },
|
||||||
|
];
|
||||||
|
const MOCK_SUBTOTAL = 1400;
|
||||||
|
const MOCK_TAX = 140;
|
||||||
|
const MOCK_TOTAL = 1540;
|
||||||
|
|
||||||
|
export default function ProformaDetailScreen() {
|
||||||
|
const { id } = useLocalSearchParams<{ id: string }>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ScrollView className="flex-1 bg-background" contentContainerStyle={{ padding: 16, paddingBottom: 32 }}>
|
||||||
|
<Card className="mb-4">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Proforma Request #{id ?? '—'}</CardTitle>
|
||||||
|
<CardDescription>Marketing Landing Page Package</CardDescription>
|
||||||
|
<Text className="text-muted-foreground mt-1 text-sm">Deadline: Sep 20, 2022 · OPEN</Text>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="gap-2">
|
||||||
|
{MOCK_ITEMS.map((item, i) => (
|
||||||
|
<View key={i} className="flex-row justify-between py-2">
|
||||||
|
<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-2">
|
||||||
|
<View className="flex-row justify-between">
|
||||||
|
<Text className="text-muted-foreground">Subtotal</Text>
|
||||||
|
<Text className="text-gray-900">${MOCK_SUBTOTAL.toLocaleString()}</Text>
|
||||||
|
</View>
|
||||||
|
<View className="flex-row justify-between">
|
||||||
|
<Text className="text-muted-foreground">Tax (10%)</Text>
|
||||||
|
<Text className="text-gray-900">${MOCK_TAX.toLocaleString()}</Text>
|
||||||
|
</View>
|
||||||
|
<View className="flex-row justify-between">
|
||||||
|
<Text className="font-semibold text-gray-900">Total</Text>
|
||||||
|
<Text className="font-semibold text-gray-900">${MOCK_TOTAL.toLocaleString()}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Button className="mb-3 bg-primary" onPress={() => {}}>
|
||||||
|
<Text className="text-primary-foreground font-medium">Send to contacts</Text>
|
||||||
|
</Button>
|
||||||
|
<Button variant="outline" onPress={() => router.back()}>
|
||||||
|
<Text className="font-medium">Back to list</Text>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Text className="text-muted-foreground mt-6 mb-2 text-sm">Submissions (mock)</Text>
|
||||||
|
<Card>
|
||||||
|
<CardContent className="py-3">
|
||||||
|
<Text className="font-medium text-gray-900">Vendor A — $1,450</Text>
|
||||||
|
<Text className="text-muted-foreground text-sm">Submitted Sep 15, 2022</Text>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
}
|
||||||
11540
swagger.json
Normal file
11540
swagger.json
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user