Skip to content
Open
110 changes: 70 additions & 40 deletions apps/expo/src/app/driver/become-driver.tsx
Original file line number Diff line number Diff line change
@@ -1,94 +1,124 @@
import React, { useState } from "react";
import { Image, Modal, ScrollView, Text, TouchableOpacity, View } from "react-native";
import { useRouter } from "expo-router";
import {
AntDesign,
} from "@expo/vector-icons";
Image,
LogBox,
Modal,
Text,
TouchableOpacity,
View,
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { useRouter } from "expo-router";
import { AntDesign, Ionicons } from "@expo/vector-icons";

import { api } from "~/utils/api";
import { RiderNavbar } from "~/components/Navbar/RiderNavbar";

const DriverProfile = () => {
LogBox.ignoreLogs([
"TRPCClientError: You are not a driver yet",
"Modal with 'formSheet' presentation style and 'transparent' value is not supported.",
]);

const BecomeDriver = () => {
const router = useRouter();
const [visible, setVisible] = useState(false);
const [capacity, setCapacity] = useState(1);
const utils = api.useContext();
const riderQuery = api.rider.profile.useQuery();
const becomeDriver = api.rider.becomeDriver.useMutation({
onSuccess: () => {
router.push('/driver/profile');
void utils.driver.profile.refetch();
},
});

return (
<>
<Modal
animationType="slide"
transparent={true}
visible={visible}
onRequestClose={() => {
setVisible(!visible);
}}
presentationStyle="formSheet"
transparent={true}
>
<View className="absolute bottom-0 h-1/3 w-full rounded-t-3xl bg-amber-500 px-5 py-5">
<Text className="px-2 py-2 text-xl font-bold">Passenger Capacity</Text>
<View className="flex-row justify-between mt-3">
<View className="mx-2 rounded-lg bg-white px-5 h-10 w-1/2 items-center">
<View className="absolute bottom-0 h-1/3 w-full rounded-t-3xl bg-amber-500 px-5 py-5">
<Text className="px-2 py-2 text-xl font-bold">
Passenger Capacity
</Text>
<View className="mt-3 flex-row justify-between">
<View className="mx-2 h-10 w-1/2 items-center rounded-lg bg-white px-5">
<Text className="mt-2 text-base">{capacity}</Text>
</View>
<View className="flex-row w-2/5 justify-between pr-2">
<TouchableOpacity className="bg-white justify-center items-center rounded-lg w-16" onPress={() => setCapacity(capacity<10 ? capacity+1 : capacity)}>
<View className="w-2/5 flex-row justify-between pr-2">
<TouchableOpacity
className="w-16 items-center justify-center rounded-lg bg-white"
onPress={() =>
setCapacity(capacity < 10 ? capacity + 1 : capacity)
}
>
<Text>➕</Text>
</TouchableOpacity>
<TouchableOpacity className="bg-white justify-center items-center rounded-lg w-16" onPress={() => setCapacity(capacity>1 ? capacity-1 : capacity)}>
<TouchableOpacity
className="w-16 items-center justify-center rounded-lg bg-white"
onPress={() =>
setCapacity(capacity > 1 ? capacity - 1 : capacity)
}
>
<Text>➖</Text>
</TouchableOpacity>
</View>
</View>

<View className="mt-8">
<TouchableOpacity
<TouchableOpacity
className="mx-2 my-4 w-36 flex-row items-center self-end rounded-lg bg-white px-6 py-2"
onPress={() => {
setVisible(!visible);
becomeDriver.mutate({capacity: capacity});
becomeDriver.mutate({ capacity: capacity });
}}
>
<View className="pr-2">
<AntDesign name="checkcircle" size={24} color="green" />
</View>
<Text className="font-bold">Confirm</Text>

</TouchableOpacity>
</View>
</View>
</Modal>
<View className="pb-5 pl-7 pt-20">
<Text className="text-2xl font-bold text-amber-400">Profile</Text>
</View>
<ScrollView className="mb-5">
<View className="mx-2 flex-row">
<View className="justify-center px-5 py-5">

<SafeAreaView className="h-full bg-amber-400">
<TouchableOpacity
className="ml-6 mt-6 w-10 items-center rounded-full bg-white"
onPress={() => void router.back()}
>
<Ionicons name="arrow-back" size={36} color="black" />
</TouchableOpacity>
<View className="mb-5 flex-auto">
<View className="flex-auto items-center justify-center bg-amber-400">
<Image
source={{ uri: riderQuery.data?.avatarUrl }}
className="h-24 w-24 rounded-full"
/>
</View>
<View className="flex-col justify-center pl-5">
<Text className="text-xl font-bold">{riderQuery.data?.name}</Text>
</View>
</View>
<View className="items-center">
<Text className="text-center">You are not a driver yet.{"\n"}Become driver to earn extra money!</Text>
<TouchableOpacity onPress={() => setVisible(true)}>
<View className="mt-5 h-12 w-40 bg-amber-400 rounded-xl items-center justify-center">
<Text className="text-white font-bold text-base">Become Driver</Text>
<View className="items-center">
<Text className="mt-4 text-center text-xl font-semibold">
You are not a driver yet.{"\n"}Become driver to earn extra
money!
</Text>
<TouchableOpacity
className="mt-12"
onPress={() => setVisible(true)}
>
<View className="h-12 w-40 items-center justify-center rounded-xl bg-white">
<Text className="text-base font-bold text-amber-500">
Become Driver
</Text>
</View>
</TouchableOpacity>
</View>
</TouchableOpacity>
</View>
</View>

</ScrollView>
<RiderNavbar />
</SafeAreaView>
</>
);
};

export default DriverProfile;
export default BecomeDriver;
160 changes: 156 additions & 4 deletions apps/expo/src/app/driver/home.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,166 @@
import { Text } from "react-native";
import {
ScrollView,
Text,
TextInput,
TouchableOpacity,
View,
} from "react-native";
import { type Region } from "react-native-maps";
import { SafeAreaView } from "react-native-safe-area-context";
import { Link } from "expo-router";
import { Feather } from "@expo/vector-icons";
import DateTimePicker from "@react-native-community/datetimepicker";
import { atom, useAtom } from "jotai";

import { api } from "~/utils/api";
import { DriverNavbar } from "~/components/Navbar/DriverNavbar";

export type Location = {
name: string;
longitude: number;
latitude: number;
};

export const createLocationsAtom = atom<Location[]>([]);
export const addLocationAtom = atom<Region | null>(null);
export const addLocationNameAtom = atom<string>("");

const MILLIS_PER_DAY = 1000 * 86400;
export const dateAtom = atom(new Date(Date.now() + MILLIS_PER_DAY));

const HomePage = () => {
const [locations, setLocations] = useAtom(createLocationsAtom);
const [addLocation, setAddLocation] = useAtom(addLocationAtom);
const [locationName, setLocationName] = useAtom(addLocationNameAtom);
const [date, setDate] = useAtom(dateAtom);
const addRideMutation = api.driver.create.useMutation();

const handleAddLocation = () => {
setLocations((prev) => [
...prev,
{
name: locationName,
longitude: addLocation?.longitude ?? 0,
latitude: addLocation?.latitude ?? 0,
},
]);
setLocationName("");
setAddLocation(null);
};

const handleAddRide = () => {
addRideMutation.mutate({
departAt: date,
locations,
});
};

return (
<SafeAreaView>
<Text>Home Page</Text>
<>
<SafeAreaView className="flex-auto">
<View className="mt-6 pb-5 pl-7">
<Text className="text-2xl font-bold text-amber-400">Trip</Text>
</View>

<View className="mx-4 mt-2 items-center">
<View className=" w-full items-center rounded-2xl bg-amber-100 p-4">
<Text className="mt-2 text-center text-xl font-semibold">
Create a trip !
</Text>
<TextInput
className="mt-4 h-8 w-60 rounded-2xl bg-white px-2"
placeholder="name"
value={locationName}
onChangeText={(text) => setLocationName(text)}
/>
<Link href="/driver/set-location" asChild>
<TouchableOpacity className="mt-4 h-8 w-60 justify-center rounded-2xl bg-white px-2">
{addLocation ? (
<Text>
({addLocation?.latitude.toFixed(4)},{" "}
{addLocation?.longitude.toFixed(4)})
</Text>
) : (
<View className="h-full justify-center">
<Text className="text-gray-400">Location</Text>
</View>
)}
</TouchableOpacity>
</Link>
<TouchableOpacity
className="mt-4 rounded-xl bg-amber-400 p-2"
onPress={() => handleAddLocation()}
>
<Text className="font-semibold">Add a location</Text>
</TouchableOpacity>
</View>
</View>

<View className="mx-4 mt-4 flex-auto rounded-2xl bg-amber-100">
<View className="mt-2 items-center border-b border-b-amber-400 p-1">
<View className="h-10 w-56 flex-row items-center justify-center rounded-xl">
<Text className=" text-lg font-semibold">Depart Time</Text>
<DateTimePicker
className="text-sm"
testID="dateTimePicker"
mode="datetime"
value={date}
onChange={(_, selectedDate) => {
const currentDate = selectedDate || date;
setDate(currentDate);
}}
display="default"
/>
</View>
</View>
<ScrollView className="">
<View className="items-center gap-2 py-4">
{locations.map((location, id) => (
<View className="flex-row items-center gap-2">
<View
key={location.name}
className="w-56 flex-row rounded-lg bg-white p-2"
>
<View className="px-1">
<Text className="text-lg">{id + 1}.</Text>
</View>
<View>
<Text className="text-lg font-semibold">
{location.name}
</Text>
<Text className="text-base">
({location.latitude.toFixed(4)},{" "}
{location.longitude.toFixed(4)})
</Text>
</View>
</View>
<TouchableOpacity
onPress={() =>
setLocations((prev) => {
const newLocations = [...prev];
newLocations.splice(id, 1);
return newLocations;
})
}
>
<Feather name="minus-circle" size={24} color="black" />
</TouchableOpacity>
</View>
))}
</View>
</ScrollView>
</View>
<TouchableOpacity
className="mx-4 mt-2 rounded-xl bg-amber-400"
onPress={() => handleAddRide()}
>
<Text className="p-2 text-center text-base font-semibold">
Add ride
</Text>
</TouchableOpacity>
</SafeAreaView>
<DriverNavbar />
</SafeAreaView>
</>
);
};

Expand Down
29 changes: 24 additions & 5 deletions apps/expo/src/app/driver/profile.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useState } from "react";
import { Image, ScrollView, Text, TouchableOpacity, View } from "react-native";
import { Link, useRouter } from "expo-router";
import { SafeAreaView } from "react-native-safe-area-context";
import { Link } from "expo-router";
import {
Feather,
FontAwesome5,
Expand All @@ -15,26 +16,44 @@ import { DriverNavbar } from "~/components/Navbar/DriverNavbar";
import { RatingStars } from "~/components/RatingStars";
import { useObjectState } from "~/hooks/useObjectState";
import SignOut from "~/screens/auth/SignOut";
import BecomeDriver from "./become-driver";

type ModalTypes = "Bio" | "Rules" | "Capacity" | "none";

const DriverProfile = () => {
const ProfilePage = () => {
const [visibleModal, setVisibleModal] = useState<ModalTypes>("none");
const [profile, updateProfile] = useObjectState({
bio: "",
rules: "",
capacity: "",
});
const router = useRouter();

const profileQuery = api.driver.profile.useQuery(undefined, {
onSuccess: (data) => {
updateProfile({ ...data, capacity: data.capacity.toString() });
},
onError: (err) => {
console.log("here is an error", err);
},
retry(failureCount, error) {
if (error.data?.code === "UNAUTHORIZED") return false;
return failureCount < 2;
},
});

if (profileQuery.isLoading) {
return (
<SafeAreaView className="h-full items-center justify-center">
<Image
source={{ uri: "https://hackmd.io/_uploads/H1uca9p8h.gif" }}
style={{ width: 400, height: 300 }}
/>
</SafeAreaView>
);
}

if (profileQuery.data == null) {
router.push("/driver/become-driver");
return <BecomeDriver />;
}

return (
Expand Down Expand Up @@ -158,4 +177,4 @@ const DriverProfile = () => {
);
};

export default DriverProfile;
export default ProfilePage;
Loading