Skip to content
This repository has been archived by the owner on Jul 8, 2024. It is now read-only.

Commit

Permalink
feat(mobile): add remaining pages (#117)
Browse files Browse the repository at this point in the history
* [REFACTO]: Update de restaurant selection

* [REFACTO]: Use reals data and fix handle empty arrays in the mobile app

* [REFACTO]: Remove test variables

* [FEATURE]: Add new pages

* [FEATURE]: Add logout btn

* [FEATURE]: Refresh location

* [FEATURE]: Add checkout page

* [FEATURE]: Add module declaration

* [FEATURE] Reorder imports and remove duplicates imports

* [FEATURE]: Add progress bar package

* [FEATURE] Add stripe intent rpc methods

* [FEATURE]: Add payment methods for mobile

* [FEATURE] Fix payment service

* [FEATURE]: Fix mobile payment

* [FEATURE] Add payment on mobile

* [REFACTO] Remove useless custom stripe components

* [FEATURE] Add delivery index page

* fix: fix order creation

* chore: Update order.proto and order.ts to use camelCase for createdAt and updatedAt fields

* feat(list): add product list page

* feat(header): change header to have selected restaurant instead of user address

* feat(address): add a way to change user main address

* feat(order): refactor order page

* feat(step-indicator): what are you doing step indicator (👉👈)

* feat(checkout): change button for better ux

* fix(lint): fix lint issues

* feat(restaurant): add restaurant id page

* feat(basket): improve empty basket message and display restaurant opening hours

* feat: Improve empty basket message and display restaurant opening hours

* feat: Update checkout screen button for better UX

---------

Co-authored-by: Anatole-Godard <[email protected]>
Co-authored-by: anatole-g <[email protected]>
  • Loading branch information
3 people authored Jun 29, 2024
1 parent 3008148 commit ba00ff0
Show file tree
Hide file tree
Showing 73 changed files with 6,722 additions and 3,864 deletions.
3 changes: 3 additions & 0 deletions apps/mobile/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
EXPO_PUBLIC_GOOGLE_MAPS_APIKEY=""
EXPO_PUBLIC_API_URL=""
EXPO_PUBLIC_STRIPE_PUBLISHABLE_KEY=""
3 changes: 1 addition & 2 deletions apps/mobile/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,8 @@ You can use the following tools to help you with the setup:
3. Run `npm install` to install the necessary dependencies. **(make sure to use "npm install" and not "pnpm install")**
4. Run `npm run start` or `npx expo start` to start the microservice. **(make sure to use "npm run start" and not "pnpm run start")**


### 2. Running the app on a physical or virtual device

To test the app on a physical device, scan the QR code displayed in the Expo Developer Tools using the Expo Go app on your Android or iOS device.

To test the app on a virtual device, follow the instructions provided in the Expo Developer Tools to launch the app on an Android Emulator or iOS Simulator.

8 changes: 2 additions & 6 deletions apps/mobile/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"assetBundlePatterns": [
"**/*"
],
"assetBundlePatterns": ["**/*"],
"ios": {
"supportsTablet": true
},
Expand All @@ -29,9 +27,7 @@
"output": "static",
"favicon": "./assets/images/favicon.png"
},
"plugins": [
"expo-router"
],
"plugins": ["expo-router", [ "@stripe/stripe-react-native", { "enableGooglePay": true }]],
"experiments": {
"tsconfigPaths": true,
"typedRoutes": true
Expand Down
55 changes: 0 additions & 55 deletions apps/mobile/app/(app)/basket.tsx

This file was deleted.

99 changes: 99 additions & 0 deletions apps/mobile/app/(app)/basket/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { useNavigation } from "expo-router";
import React, { useEffect, useState } from "react";
import { FlatList, RefreshControl, ScrollView, Text, View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";

import { BasketTaxes } from "@/app/(app)/basket/taxes";
import { BasketHeader } from "@/components/basket/header";
import { ProductBasketCard } from "@/components/product/basket";
import { Button } from "@/components/ui/button";
import { AppHeader } from "@/components/ui/header";
import { useBasket } from "@/hooks/useBasket";
import { isOpenNow } from "@/lib/restaurant";
import { Product } from "@/types/product";

export default function Index() {
const { basket, products, refetch, selectedRestaurant } = useBasket();
const [basketProductList, setBasketProductList] = useState<Product[]>([]);

useEffect(() => {
if (basket.productsList.length === 0) return;
setBasketProductList(
basket.productsList.map((item) => products.find((product) => product.id === item.id)) as Product[],
);
}, [basket.productsList]);

const { goBack, navigate } = useNavigation() as {
navigate: (href: string, params?: any) => void;
goBack: () => void;
};

return (
<View className="relative flex flex-col justify-between w-screen h-screen p-6 pb-16 bg-white">
<View className="absolute bottom-0 left-0 w-screen bg-black h-28" />
<SafeAreaView className="flex flex-col w-full h-full gap-4">
<View className="w-full">
<AppHeader />
</View>

<View className="w-full">
<BasketHeader />
</View>

<ScrollView
className="w-full"
refreshControl={<RefreshControl refreshing={false} onRefresh={() => refetch()} />}
>
<FlatList
className="grow"
data={basketProductList}
renderItem={({ item }) => (
<View className="pb-4">
<ProductBasketCard {...item} />
</View>
)}
ItemSeparatorComponent={() => <View className="h-2" />}
ListEmptyComponent={() => (
<View className="flex items-center justify-center h-20 pb-4">
<Text className="text-lg font-bold">Votre panier est vide</Text>
</View>
)}
ListFooterComponent={() => (
<View className="w-full">
<BasketTaxes />
</View>
)}
/>
</ScrollView>
<View className="absolute bottom-0">
<View className="w-full h-16 bg-white border-t border-neutral-200">
{selectedRestaurant !== null && !isOpenNow(selectedRestaurant?.openinghoursList) && (
<View className="flex flex-col items-center justify-center h-full">
<Text className="text-red-600">Le restaurant {selectedRestaurant.name} est fermé</Text>
<Text className="text-xs text-red-800">{selectedRestaurant.openinghoursList.join(" / ")}</Text>
</View>
)}
</View>

<View className="flex flex-row w-full space-x-4">
<View className="">
<Button onPress={() => goBack()} icon="home" type="secondary" />
</View>
<View className="grow">
<Button
disabled={
basketProductList.length <= 0 ||
!basketProductList[0] ||
(selectedRestaurant !== null && !isOpenNow(selectedRestaurant?.openinghoursList))
}
icon="arrow-right"
onPress={() => navigate(`(app)`, { screen: "checkout/selection/index" })}
title="Étape suivante"
/>
</View>
</View>
</View>
</SafeAreaView>
</View>
);
}
28 changes: 28 additions & 0 deletions apps/mobile/app/(app)/basket/taxes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Text, View } from "react-native";

import { useBasket } from "@/hooks/useBasket";
import { toPrice } from "@/lib/product/toPrice";

export const BasketTaxes = () => {
const { taxes } = useBasket();
return (
<View className="flex flex-col w-full h-full">
<View className="flex flex-row justify-between items-center px-1 bg-[#8CFFD9]/50 h-9">
<Text className="font-bold ml-2 text-[#008D5E]">Livraison</Text>
<View className="bg-[#B6E8D8] h-6 px-2 flex items-center justify-center">
<Text className=" font-bold text-[#008D5E]">
{taxes.delivery > 0 ? toPrice(taxes.delivery) : "On vous l'offre"}
</Text>
</View>
</View>
<View className="flex flex-row justify-between items-center px-1 bg-[#8CFFD9]/50 h-9">
<Text className="font-bold ml-2 text-[#008D5E]">Frais de service</Text>
<View className="bg-[#B6E8D8] h-6 px-2 flex items-center justify-center">
<Text className=" font-bold text-[#008D5E]">
{taxes.service > 0 ? toPrice(taxes.service) : "On vous l'offre"}
</Text>
</View>
</View>
</View>
);
};
47 changes: 47 additions & 0 deletions apps/mobile/app/(app)/checkout/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { useNavigation } from "expo-router";
import React from "react";
import { View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";

import { StepIndicator } from "@/components/basket/step-indicator";
import CheckoutScreen from "@/components/checkout/CheckoutScreen";
import { Button } from "@/components/ui/button";
import { AppHeader } from "@/components/ui/header";

export default function Index() {
const { navigate } = useNavigation() as {
navigate: (href: string, params?: any) => void;
goBack: () => void;
};

return (
<View className="relative flex flex-col justify-between w-screen h-screen p-6 pb-16 bg-white">
<View className="absolute bottom-0 left-0 w-screen bg-black h-28" />
<SafeAreaView className="flex flex-col w-full h-full gap-4">
<View className="w-full">
<AppHeader />
</View>
<View className="w-full ">
<StepIndicator steps={["RÉCAP.", "RÉCUP.", "PAIEMENT"]} currentStep={3} />
</View>
<View className="flex flex-col w-full gap-2">
<CheckoutScreen />
</View>
<View className="absolute bottom-0">
<View className="flex flex-row w-full space-x-4">
<View className="">
<Button
onPress={() => navigate("(app)", { screen: "checkout/selection/index" })}
icon="chevron-left"
type="secondary"
/>
</View>
<View className="grow">
<Button onPress={() => navigate("(app)/home")} type="secondary" title="Retour à l'accueil" />
</View>
</View>
</View>
</SafeAreaView>
</View>
);
}
62 changes: 62 additions & 0 deletions apps/mobile/app/(app)/checkout/selection/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import Icon from "@expo/vector-icons/MaterialCommunityIcons";
import { useNavigation } from "expo-router";
import React from "react";
import { Text, TouchableOpacity, View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";

import { StepIndicator } from "@/components/basket/step-indicator";
import { Button } from "@/components/ui/button";
import { AppHeader } from "@/components/ui/header";

export default function Index() {
const { navigate } = useNavigation() as {
navigate: (href: string, params?: any) => void;
goBack: () => void;
};

return (
<View className="relative flex flex-col justify-between w-screen h-screen p-6 pb-16 bg-white">
<View className="absolute bottom-0 left-0 w-screen bg-black h-28" />
<SafeAreaView className="flex flex-col w-full h-full gap-4">
<View className="w-full">
<AppHeader />
</View>
<View className="w-full ">
<StepIndicator steps={["RÉCAP.", "RÉCUP.", "PAIEMENT"]} currentStep={2} />
</View>
<View className="flex flex-col gap-2">
<Text className="text-lg font-bold">Méthode de livraison</Text>
<View className="flex flex-row items-center h-16 px-6 text-sm font-medium border opacity-50">
<Icon name="circle-outline" size={18} />
<Text className="pl-1 text-sm">Paiement sur place</Text>
</View>
<TouchableOpacity
className="flex flex-row items-center h-16 px-6 text-sm border cursor-pointer "
onPress={() => navigate(`(app)`, { screen: "checkout/index" })}
>
<Icon name="check-circle-outline" size={18} />
<Text className="pl-1 text-sm font-bold">Livraison et paiement par carte</Text>
</TouchableOpacity>
</View>
<View className="absolute bottom-0">
<View className="flex flex-row w-full space-x-4">
<View className="">
<Button
onPress={() => navigate("(app)", { screen: "basket/index" })}
icon="chevron-left"
type="secondary"
/>
</View>
<View className="grow">
<Button
icon="arrow-right"
onPress={() => navigate(`(app)`, { screen: "checkout/index" })}
title="Étape suivante"
/>
</View>
</View>
</View>
</SafeAreaView>
</View>
);
}
Empty file.
Loading

0 comments on commit ba00ff0

Please sign in to comment.