From 79aa4cc48b804fd1c2a465f9bf576d9fbba3e265 Mon Sep 17 00:00:00 2001 From: celine Date: Sat, 27 Apr 2024 11:47:13 +1000 Subject: [PATCH 1/2] added order history page --- app/(tabs)/Orders.tsx | 131 ++++++++++++++++++--- app/(tabs)/_layout.tsx | 31 +++-- app/_layout.tsx | 13 ++- app/orderHistory.tsx | 250 +++++++++++++++++++++++++++++++++++++++++ mock_data.ts | 128 ++++++++++++++++++++- 5 files changed, 519 insertions(+), 34 deletions(-) create mode 100644 app/orderHistory.tsx diff --git a/app/(tabs)/Orders.tsx b/app/(tabs)/Orders.tsx index 6131255..abb2679 100644 --- a/app/(tabs)/Orders.tsx +++ b/app/(tabs)/Orders.tsx @@ -1,33 +1,128 @@ -import { StyleSheet } from "react-native"; +import { + Linking, + SafeAreaView, + ScrollView, + StyleSheet, + TouchableOpacity, +} from "react-native"; import { Text, View } from "@/components/Themed"; +import { SB_COLOR_SCHEME } from "@/constants"; +import { orders } from "@/mock_data"; +import { router } from "expo-router"; export default function OrdersScreen() { return ( - - Orders - - + + + + {/* current order */} + + + + Current + + + + {orders + .filter((order) => order.status == "accepted") + .map((item) => { + return ( + router.navigate("/delivery")} + > + {item.restaurant.name} + + {item.eta.toLocaleTimeString()} |{" "} + {item.deliveryPerson.name} + + + ); + })} + + + {/* completed order */} + + + + Completed + + + + {orders + .filter((order) => order.status == "completed") + .map((item) => { + return ( + + router.navigate({ + pathname: "/orderHistory", + params: { id: item.id }, + }) + } + > + {item.restaurant.name} + + {item.eta.toLocaleDateString()}{" "} + {item.eta.toLocaleTimeString()} |{" "} + {item.deliveryPerson.name} + + + ); + })} + + + + + ); } const styles = StyleSheet.create({ container: { + padding: 32, flex: 1, - alignItems: "center", - justifyContent: "center", }, - title: { - fontSize: 20, - fontWeight: "bold", + scrollView: { + backgroundColor: "white", }, - separator: { - marginVertical: 30, - height: 1, - width: "80%", + item: { + backgroundColor: "#F2F2F7", + borderRadius: 6, + padding: 15, + flex: 1, + flexDirection: "column", + gap: 8, + marginBottom: 8, }, }); diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index 90e4ead..bff41ce 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -48,16 +48,11 @@ export default function TabLayout() { {({ pressed }) => ( - // )} ), + }} /> ( ), + headerRight: () => ( + + + {({ pressed }) => ( + + )} + + + ), }} /> ( ), + headerRight: () => ( + + + {({ pressed }) => ( + + )} + + + ), }} /> {({ pressed }) => ( - // )} diff --git a/app/_layout.tsx b/app/_layout.tsx index 7146eaf..487f311 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -93,13 +93,24 @@ function RootLayoutNav() { options={{ title: "Delivery", headerTintColor: SB_COLOR_SCHEME.SB_PRIMARY, - headerBackVisible: false, + headerBackTitle: "Back", gestureEnabled: false, contentStyle: { backgroundColor: "white", }, }} /> + (); + const [order, setOrder] = useState(); + const [items, setItems] = useState< + { + item: MenuItem | undefined; + count: number; + }[] + >(); + + useEffect(() => { + if (id) { + const ord = orders.find((item) => item.id == id); + setOrder(ord); + const itemIdCounts: { [itemId: string]: number } = {}; + + ord?.items.forEach((item) => { + const itemId = item.id.toString(); + itemIdCounts[itemId] = (itemIdCounts[itemId] || 0) + 1; + }); + + const temp: { + item: MenuItem | undefined; + count: number; + }[] = Object.keys(itemIdCounts).map((itemId) => ({ + item: ord?.items.find((i) => i.id == itemId), + count: itemIdCounts[itemId], + })); + + setItems(temp); + console.log(temp, order); + } + }, []); + + return ( + + + + + + + {order?.deliveryPerson.name} + + {order?.deliveryPerson.carName} + + + + Rate + + + + + + Restaurant + {order?.restaurant.name} + + {order?.restaurant.address.street},{" "} + {order?.restaurant.address.city},{" "} + {order?.restaurant.address.state},{" "} + {order?.restaurant.address.zipCode} + + + + + Rate + + + + + + Delivery Address + + {order?.deliveryAddress} + + + + Delivery Instruction + + {order?.deliveryInstruction} + + + + Order Summary + + {items?.map((item) => { + return ( + + + {item.count}x {item.item?.name} + + + $ + {item.item?.price + ? item.item?.price * item.count + : item.item?.price} + + + ); + })} + + + Delivery Fee + + + ${((order?.netTotal ?? 0) * 0.05).toFixed(2)} + + + + VAT + + ${order?.tax.toFixed(2)} + + + + + Coupon + + + -${order?.discount} + + + + + Total + + + ${order?.netTotal} + + + + + + + + ); +} + +const styles = StyleSheet.create({ + container: { + padding: 32, + flex: 1, + flexDirection: "column", + justifyContent: "center", + alignItems: "center", + width: "100%", + gap: 16, + }, + scrollView: { + backgroundColor: "white", + }, + subtitle: { + fontSize: 15, + fontWeight: "bold", + color: SB_COLOR_SCHEME.SB_PRIMARY, + }, + summaryItem: { + paddingVertical: 16, + display: "flex", + flexDirection: "row", + justifyContent: "space-between", + borderBottomColor: SB_COLOR_SCHEME.SB_SEPARATOR, + borderBottomWidth: 1, + }, +}); diff --git a/mock_data.ts b/mock_data.ts index 8155187..1a6a33d 100644 --- a/mock_data.ts +++ b/mock_data.ts @@ -32,6 +32,7 @@ export interface Address { } export interface Customer { + id: string, name: string; email: string; phone: string; @@ -75,8 +76,43 @@ export interface Order { payment: Payment; deliveryInstruction: string; deliveryAddress: string; + completedAt?: Date; + eta: Date; + deliveryPerson: DeliveryPerson; } +export interface DeliveryPerson { + id: string; + name: string; + carName: string; + phone: string; + avgRating: number; +} + +export const deliverer: DeliveryPerson[] = [ + { + id: '1', + name: 'Henry Earls', + carName: 'Mazda 3 Black', + phone: '0456736543', + avgRating: 4.5 + }, + { + id: '2', + name: 'John Smith', + carName: 'Honda HRV White', + phone: '0456736543', + avgRating: 4.5 + }, + { + id: '3', + name: 'Jason Lee', + carName: 'Honda HRV White', + phone: '0456736543', + avgRating: 4.5 + } +] + // EXAMPLE DATA export const categories: Category[] = [ @@ -169,8 +205,8 @@ export const restaurants: Restaurant[] = [ description: 'Free delivery on order above $20. Free Ice Cream during public holiday', imageUrl: 'https://media-cdn.tripadvisor.com/media/photo-s/14/29/52/54/hong-teh-chinese-restaurant.jpg', menu: [ - { id: '208', name: 'California Roll', description: 'Crab, avocado, cucumber, and sesame seeds', price: 8.99, imageUrl: 'california-roll.jpg' }, - { id: '209', name: 'Spicy Tuna Roll', description: 'Tuna, spicy mayo, cucumber, and tobiko', price: 9.99, imageUrl: 'spicy-tuna.jpg' }, + { id: '208', name: 'Crispy Tofu', description: 'Crab, avocado, cucumber, and sesame seeds', price: 8.99, imageUrl: 'california-roll.jpg' }, + { id: '209', name: 'Spicy Beef Rice', description: 'Tuna, spicy mayo, cucumber, and tobiko', price: 9.99, imageUrl: 'spicy-tuna.jpg' }, // More menu items... ], address: { @@ -258,4 +294,90 @@ export const myCards: Card[] = [ last3Digits: 2345, title: 'Paypal' } -] \ No newline at end of file +] + +export const customers: Customer[] = [ + { + id: '1', + name: 'Celine Husen', + phone: '0456987576', + email: 'cel@sb.com' + }, + { + id: '2', + name: 'Jenny Do', + phone: '0456987576', + email: 'jen@sb.com' + } +] + +export const payment: Payment = { + id: '1', + amount: 84, + type: 'card', + last3Digits: '456', + datePaid: new Date() +} + +export const orders: Order[] = [ + { + id: 'SBE1', + customer: customers[0], + restaurant: restaurants[0], + items: [restaurants[0].menu[0], restaurants[0].menu[1]], + status: 'accepted', + total: 80, + tax: 8, + netTotal: 88, + promoCode: 'SPRING30', + discount: 4, + orderDate: new Date(), + payment, + deliveryInstruction: 'Leave at the door', + deliveryAddress: '1 Daisy Street, Fairy Meadow, NSW 2519', + eta: new Date(), + deliveryPerson: deliverer[0], + }, + { + id: 'SBE2', + customer: customers[0], + restaurant: restaurants[2], + items: [restaurants[2].menu[0], restaurants[2].menu[1]], + status: 'completed', + total: 80, + tax: 8, + netTotal: 88, + promoCode: 'SPRING30', + discount: 4, + orderDate: new Date(), + payment, + deliveryInstruction: 'Leave at the door', + deliveryAddress: '1 Daisy Street, Fairy Meadow, NSW 2519', + eta: new Date(), + deliveryPerson: deliverer[1], + completedAt: new Date() + }, + { + id: 'SBE3', + customer: customers[0], + restaurant: restaurants[1], + items: [restaurants[1].menu[0], restaurants[1].menu[1]], + status: 'completed', + total: 26, + tax: 8, + netTotal: 88, + promoCode: 'SPRING30', + discount: 4, + orderDate: new Date(), + payment, + deliveryInstruction: 'Leave at the door', + deliveryAddress: '1 Daisy Street, Fairy Meadow, NSW 2519', + eta: new Date(), + deliveryPerson: deliverer[2], + completedAt: new Date() + } +] + +export const notifications = [{ + +}] \ No newline at end of file From 68ca641bbd114013f931f13d4ab62fe12f677657 Mon Sep 17 00:00:00 2001 From: celine Date: Sat, 27 Apr 2024 12:17:27 +1000 Subject: [PATCH 2/2] added notifications page --- app/notifications.tsx | 68 ++++++++++++++++++++++++++----------- assets/icons/icon-badge.svg | 3 ++ mock_data.ts | 28 +++++++++++++-- 3 files changed, 77 insertions(+), 22 deletions(-) create mode 100644 assets/icons/icon-badge.svg diff --git a/app/notifications.tsx b/app/notifications.tsx index 685f16a..308df0b 100644 --- a/app/notifications.tsx +++ b/app/notifications.tsx @@ -1,35 +1,65 @@ -import { StatusBar } from 'expo-status-bar'; -import { Platform, StyleSheet } from 'react-native'; +import { StatusBar } from "expo-status-bar"; +import { Platform, SafeAreaView, ScrollView, StyleSheet } from "react-native"; -import EditScreenInfo from '@/components/EditScreenInfo'; -import { Text, View } from '@/components/Themed'; +import EditScreenInfo from "@/components/EditScreenInfo"; +import { Text, View } from "@/components/Themed"; +import { notifications } from "@/mock_data"; +import IconBadge from "../assets/icons/icon-badge.svg"; export default function ModalScreen() { return ( - - Notifications - - + + + + {notifications.sort().map((item) => { + return ( + + + {item.title} + {item.isNew ? : null} + - {/* Use a light status bar on iOS to account for the black space above the modal */} - - + {item.createdAt} + {item.description} + + ); + })} + + + ); } const styles = StyleSheet.create({ container: { flex: 1, - alignItems: 'center', - justifyContent: 'center', + padding: 32, + paddingTop: 20, + width: "100%", }, title: { - fontSize: 20, - fontWeight: 'bold', + fontSize: 15, + fontWeight: "500", + paddingBottom: 4, }, - separator: { - marginVertical: 30, - height: 1, - width: '80%', + item: { + borderRadius: 6, + padding: 15, + flex: 1, + flexDirection: "column", + gap: 8, + marginBottom: 8, + borderBottomWidth: 1, + borderBottomColor: "#F2F2F7", + }, + scrollView: { + backgroundColor: "white", }, }); diff --git a/assets/icons/icon-badge.svg b/assets/icons/icon-badge.svg new file mode 100644 index 0000000..ebeec3f --- /dev/null +++ b/assets/icons/icon-badge.svg @@ -0,0 +1,3 @@ + + + diff --git a/mock_data.ts b/mock_data.ts index 1a6a33d..4bc490d 100644 --- a/mock_data.ts +++ b/mock_data.ts @@ -13,6 +13,14 @@ export interface MenuItem { imageUrl: string; } +export interface Notification { + id: string; + title: string; + description: string; + isNew: boolean; + createdAt: string; +} + export interface Restaurant { id: number; name: string; @@ -378,6 +386,20 @@ export const orders: Order[] = [ } ] -export const notifications = [{ - -}] \ No newline at end of file +export const notifications = [ + { + id: '1', + title: 'Your order has arrived', + description: 'Please contact with the driver to receive the order', + createdAt: new Date().toLocaleString(), + isNew: false, + }, + { + id: '2', + title: "Don't forget to rate the restaurant!", + description: 'Lorem ipsum dolor anet', + createdAt: new Date().toLocaleString(), + isNew: true, + }, + +] \ No newline at end of file