Add rider/driver role selection after sign-up
- users.role column (+ migration in seed script) - /(api)/user: GET role by clerkId, PATCH to set role - Role selection screen; drivers get placeholder driver-home - Root index routes by role; hardened location handling on home
This commit is contained in:
+36
-14
@@ -48,24 +48,37 @@ const Home = () => {
|
||||
|
||||
useEffect(() => {
|
||||
const requestLocation = async () => {
|
||||
let { status } = await Location.requestForegroundPermissionsAsync();
|
||||
try {
|
||||
let { status } = await Location.requestForegroundPermissionsAsync();
|
||||
|
||||
if (status !== "granted") return setHasPermissions(false);
|
||||
if (status !== "granted") return setHasPermissions(false);
|
||||
|
||||
setHasPermissions(true);
|
||||
setHasPermissions(true);
|
||||
|
||||
let location = await Location.getCurrentPositionAsync();
|
||||
let location = await Location.getCurrentPositionAsync();
|
||||
|
||||
const address = await Location.reverseGeocodeAsync({
|
||||
longitude: location.coords?.longitude,
|
||||
latitude: location.coords?.latitude,
|
||||
});
|
||||
let addressText = "Unknown location";
|
||||
try {
|
||||
const address = await Location.reverseGeocodeAsync({
|
||||
longitude: location.coords?.longitude,
|
||||
latitude: location.coords?.latitude,
|
||||
});
|
||||
if (address[0]) {
|
||||
addressText = `${address[0].name}, ${address[0].region}`;
|
||||
}
|
||||
} catch (geocodeErr) {
|
||||
console.log("[REVERSE_GEOCODE]: ", geocodeErr);
|
||||
}
|
||||
|
||||
setUserLocation({
|
||||
latitude: location.coords.latitude,
|
||||
longitude: location.coords.longitude,
|
||||
address: `${address[0].name}, ${address[0].region}`,
|
||||
});
|
||||
setUserLocation({
|
||||
latitude: location.coords.latitude,
|
||||
longitude: location.coords.longitude,
|
||||
address: addressText,
|
||||
});
|
||||
} catch (err) {
|
||||
console.log("[LOCATION]: ", err);
|
||||
setHasPermissions(false);
|
||||
}
|
||||
};
|
||||
|
||||
requestLocation();
|
||||
@@ -143,7 +156,16 @@ const Home = () => {
|
||||
</Text>
|
||||
|
||||
<View className="flex flex-row items-center bg-transparent h-[300px]">
|
||||
{hasPermissions && <Map />}
|
||||
{hasPermissions ? (
|
||||
<Map />
|
||||
) : (
|
||||
<View className="flex-1 items-center justify-center bg-white rounded-2xl h-full">
|
||||
<Text className="text-general-200 text-center font-JakartaMedium px-5">
|
||||
Location access is off.{"\n"}Enable it in your device
|
||||
settings to see nearby drivers.
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<Text className="text-xl font-JakartaBold mt-5 mb-3">
|
||||
|
||||
@@ -7,6 +7,11 @@ const RootLayout = () => {
|
||||
<Stack.Screen name="find-ride" options={{ headerShown: false }} />
|
||||
<Stack.Screen name="confirm-ride" options={{ headerShown: false }} />
|
||||
<Stack.Screen name="book-ride" options={{ headerShown: false }} />
|
||||
<Stack.Screen name="role" options={{ headerShown: false }} />
|
||||
<Stack.Screen
|
||||
name="driver-home"
|
||||
options={{ headerShown: false, gestureEnabled: false }}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { useClerk, useUser } from "@clerk/clerk-expo";
|
||||
import { Image, Text, View } from "react-native";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
|
||||
import { CustomButton } from "@/components/custom-button";
|
||||
import { images } from "@/constants";
|
||||
|
||||
// Placeholder driver home. The driver experience (going online, accepting
|
||||
// rides) is not built yet — drivers are registered here and managed in the
|
||||
// database for now.
|
||||
const DriverHome = () => {
|
||||
const { user } = useUser();
|
||||
const { signOut } = useClerk();
|
||||
|
||||
return (
|
||||
<SafeAreaView className="flex-1 bg-white justify-center items-center px-7">
|
||||
<Image
|
||||
source={images.check}
|
||||
alt="Registered"
|
||||
className="w-[110px] h-[110px] mb-5"
|
||||
/>
|
||||
|
||||
<Text className="text-2xl font-JakartaBold text-center">
|
||||
You're registered as a driver, {user?.firstName || "there"}!
|
||||
</Text>
|
||||
|
||||
<Text className="text-base text-general-200 font-Jakarta text-center mt-3">
|
||||
Driver mode is coming soon. We'll contact you at{" "}
|
||||
{user?.emailAddresses[0]?.emailAddress} once your account is activated.
|
||||
</Text>
|
||||
|
||||
<CustomButton
|
||||
title="Sign Out"
|
||||
onPress={() => signOut()}
|
||||
className="mt-10"
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
export default DriverHome;
|
||||
@@ -0,0 +1,77 @@
|
||||
import { useUser } from "@clerk/clerk-expo";
|
||||
import { router } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import { Alert, Text, TouchableOpacity, View } from "react-native";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
|
||||
import { fetchAPI } from "@/lib/fetch";
|
||||
|
||||
const RoleSelection = () => {
|
||||
const { user } = useUser();
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
const chooseRole = async (role: "rider" | "driver") => {
|
||||
if (!user?.id || saving) return;
|
||||
|
||||
setSaving(true);
|
||||
|
||||
try {
|
||||
const { error } = await fetchAPI("/(api)/user", {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ clerkId: user.id, role }),
|
||||
});
|
||||
|
||||
if (error) throw new Error(error);
|
||||
|
||||
router.replace(
|
||||
role === "driver" ? "/(root)/driver-home" : "/(root)/(tabs)/home",
|
||||
);
|
||||
} catch (err) {
|
||||
console.log("[ROLE_SELECT]: ", err);
|
||||
Alert.alert("Error", "Could not save your choice. Please try again.");
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView className="flex-1 bg-white justify-center px-7">
|
||||
<Text className="text-3xl font-JakartaExtraBold text-center">
|
||||
How will you use Waseel?
|
||||
</Text>
|
||||
|
||||
<Text className="text-base text-general-200 font-Jakarta text-center mt-3 mb-10">
|
||||
You can change this later by contacting support.
|
||||
</Text>
|
||||
|
||||
<TouchableOpacity
|
||||
onPress={() => chooseRole("rider")}
|
||||
disabled={saving}
|
||||
className="bg-primary-500 rounded-2xl p-7 mb-5 items-center"
|
||||
>
|
||||
<Text className="text-5xl mb-3">🧍</Text>
|
||||
<Text className="text-2xl font-JakartaBold text-white">
|
||||
I'm a Rider
|
||||
</Text>
|
||||
<Text className="text-sm font-Jakarta text-white/80 text-center mt-2">
|
||||
Book rides and get around Lebanon
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
onPress={() => chooseRole("driver")}
|
||||
disabled={saving}
|
||||
className="bg-general-600 rounded-2xl p-7 items-center"
|
||||
>
|
||||
<Text className="text-5xl mb-3">🚗</Text>
|
||||
<Text className="text-2xl font-JakartaBold">I'm a Driver</Text>
|
||||
<Text className="text-sm font-Jakarta text-general-200 text-center mt-2">
|
||||
Give rides and earn money
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
export default RoleSelection;
|
||||
Reference in New Issue
Block a user