{"id":15293998,"url":"https://github.com/RainerNsa/Dryve","last_synced_at":"2025-10-12T17:31:39.828Z","repository":{"id":257047781,"uuid":"857140911","full_name":"RainerNsa/Dryve","owner":"RainerNsa","description":"Dryve is a modern e-ride hailing application built with a full-stack approach using React Native, featuring secure payment integration. It is designed to provide users with a seamless ride-hailing experience with a user-friendly interface, real-time updates, and reliable payments through Stripe.","archived":false,"fork":false,"pushed_at":"2024-09-20T18:59:40.000Z","size":3498,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-01T14:52:10.956Z","etag":null,"topics":["postgresql","react-native","stripe","tailwindcss","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RainerNsa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-13T22:21:03.000Z","updated_at":"2024-09-20T18:59:44.000Z","dependencies_parsed_at":"2024-10-14T22:40:38.976Z","dependency_job_id":"77684600-6f39-4f6a-9c66-3d71e5927514","html_url":"https://github.com/RainerNsa/Dryve","commit_stats":null,"previous_names":["woldreamz/dryve","rainernsa/dryve"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/RainerNsa/Dryve","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RainerNsa%2FDryve","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RainerNsa%2FDryve/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RainerNsa%2FDryve/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RainerNsa%2FDryve/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RainerNsa","download_url":"https://codeload.github.com/RainerNsa/Dryve/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RainerNsa%2FDryve/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279012191,"owners_count":26085079,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-12T02:00:06.719Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["postgresql","react-native","stripe","tailwindcss","typescript"],"created_at":"2024-09-30T16:54:33.479Z","updated_at":"2025-10-12T17:31:39.015Z","avatar_url":"https://github.com/RainerNsa.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cbr /\u003e\n    \u003ca href=\"https://youtu.be/kmy_YNhl0mw\" target=\"_blank\"\u003e\n      \u003cimg src=\"https://i.ibb.co/Bf04Hpd/Readme-thumbnail-from-JS-Mastery.png\" alt=\"Project Banner\"\u003e\n    \u003c/a\u003e\n  \u003cbr /\u003e\n\n  \u003cdiv\u003e\n    \u003cimg src=\"https://img.shields.io/badge/-React_Native-black?style=for-the-badge\u0026logoColor=white\u0026logo=react\u0026color=61DAFB\" alt=\"reactnative\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/-PostgreSQL-black?style=for-the-badge\u0026logoColor=white\u0026logo=postgresql\u0026color=4169E1\" alt=\"postgresql\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/-Expo-black?style=for-the-badge\u0026logoColor=white\u0026logo=expo\u0026color=000020\" alt=\"expo\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/-Stripe-black?style=for-the-badge\u0026logoColor=white\u0026logo=stripe\u0026color=008CDD\" alt=\"stripe\" /\u003e\n  \u003c/div\u003e\n\n\n\u003ch3 align=\"center\"\u003eFull Stack Uber Clone\u003c/h3\u003e\n\n   \u003cdiv align=\"center\"\u003e\n     Build this project step by step with our detailed tutorial on \u003ca href=\"https://www.youtube.com/@javascriptmastery/videos\" target=\"_blank\"\u003e\u003cb\u003eJavaScript Mastery\u003c/b\u003e\u003c/a\u003e YouTube. Join the JSM family!\n    \u003c/div\u003e\n\u003c/div\u003e\n\n## 📋 \u003ca name=\"table\"\u003eTable of Contents\u003c/a\u003e\n\n1. 🤖 [Introduction](#introduction)\n2. ⚙️ [Tech Stack](#tech-stack)\n3. 🔋 [Features](#features)\n4. 🤸 [Quick Start](#quick-start)\n5. 🕸️ [Snippets (Code to Copy)](#snippets)\n6. 🖇️ [Links](#links)\n7. 📦 [Assets](#assets)\n8. 🚀 [More](#more)\n\n## 🚨 Tutorial\n\nThis repository contains the code corresponding to an in-depth tutorial available on our YouTube\nchannel, \u003ca href=\"https://www.youtube.com/@javascriptmastery/videos\" target=\"_blank\"\u003e\u003cb\u003eJavaScript Mastery\u003c/b\u003e\u003c/a\u003e.\n\nIf you prefer visual learning, this is the perfect resource for you. Follow our tutorial to learn how to build projects\nlike these step-by-step in a beginner-friendly manner!\n\n\u003ca href=\"https://youtu.be/kmy_YNhl0mw\" target=\"_blank\"\u003e\u003cimg src=\"https://github.com/sujatagunale/EasyRead/assets/151519281/1736fca5-a031-4854-8c09-bc110e3bc16d\" /\u003e\u003c/a\u003e\n\n## \u003ca name=\"introduction\"\u003e🤖 Introduction\u003c/a\u003e\n\nBuilt with React Native for handling the user interface, Google Maps for rendering maps with directions, stripe for\nhandling payments, serverless Postgres for managing databases, and styled with TailwindCSS, Uber Clone is a perfect\nmobile app. The primary goal is to demonstrate how to develop full-stack mobile applications to showcase the developer's\nskills in a unique manner that creates a lasting impact.\n\nIf you're getting started and need assistance or face any bugs, join our active Discord community with over **34k+**\nmembers. It's a place where people help each other out.\n\n\u003ca href=\"https://discord.com/invite/n6EdbFJ\" target=\"_blank\"\u003e\u003cimg src=\"https://github.com/sujatagunale/EasyRead/assets/151519281/618f4872-1e10-42da-8213-1d69e486d02e\" /\u003e\u003c/a\u003e\n\n## \u003ca name=\"tech-stack\"\u003e⚙️ Tech Stack\u003c/a\u003e\n\n- React Native\n- Expo\n- Stripe\n- PostgreSQL\n- Google Maps\n- zustand\n- Clerk\n- Tailwind CSS\n\n## \u003ca name=\"features\"\u003e🔋 Features\u003c/a\u003e\n\n👉 **Onboarding Flow**: Seamless user registration and setup process.\n\n👉 **Email Password Authentication with Verification**: Secure login with email verification.\n\n👉 **oAuth Using Google**: Easy login using Google credentials.\n\n👉 **Authorization**: Secure access control for different user roles.\n\n👉 **Home Screen with Live Location \u0026 Google Map**: Real-time location tracking with markers on a map.\n\n👉 **Recent Rides**: View a list of recent rides at a glance.\n\n👉 **Google Places Autocomplete**: Search any place on Earth with autocomplete suggestions.\n\n👉 **Find Rides**: Search for rides by entering 'From' and 'To' locations.\n\n👉 **Select Rides from Map**: Choose available cars near your location from the map.\n\n👉 **Confirm Ride with Detailed Information**: View complete ride details, including time and fare price.\n\n👉 **Pay for Ride Using Stripe**: Make payments using multiple methods like cards and others.\n\n👉 **Create Rides After Successful Payment**: Book a ride after confirming payment.\n\n👉 **Profile**: Manage account details in the profile screen.\n\n👉 **History**: Review all rides booked so far.\n\n👉 **Responsive on Android and iOS**: Optimized for both Android and iOS devices.\n\nand many more, including code architecture and reusability\n\n## \u003ca name=\"quick-start\"\u003e🤸 Quick Start\u003c/a\u003e\n\nFollow these steps to set up the project locally on your machine.\n\n**Prerequisites**\n\nMake sure you have the following installed on your machine:\n\n- [Git](https://git-scm.com/)\n- [Node.js](https://nodejs.org/en)\n- [npm](https://www.npmjs.com/) (Node Package Manager)\n\n**Cloning the Repository**\n\n```bash\ngit clone https://github.com/JavaScript-Mastery-Pro/uber.git\ncd uber\n```\n\n**Installation**\n\nInstall the project dependencies using npm:\n\n```bash\nnpm install\n```\n\n**Set Up Environment Variables**\n\nCreate a new file named `.env` in the root of your project and add the following content:\n\n```env\nEXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=\n\nEXPO_PUBLIC_PLACES_API_KEY=\nEXPO_PUBLIC_DIRECTIONS_API_KEY=\n\nDATABASE_URL=\n\nEXPO_PUBLIC_SERVER_URL=https://uber.dev/\n\nEXPO_PUBLIC_GEOAPIFY_API_KEY=\n\nEXPO_PUBLIC_STRIPE_PUBLISHABLE_KEY=\nSTRIPE_SECRET_KEY=\n```\n\nReplace the placeholder values with your actual Clerk, Stripe, NeonDB, Google Maps, andgeoapify credentials. You can\nobtain these credentials by signing up on\nthe [Clerk](https://clerk.com/), [Stripe](https://stripe.com/in), [NeonDB](https://neon.tech/), [Google Maps](https://console.cloud.google.com/)\nand [geoapify](https://www.geoapify.com/) websites respectively.\n\n**Running the Project**\n\n```bash\nnpx expo start\n```\n\nDownload the [Expo Go](https://expo.dev/go) app and Scan the QR code on your respective device to view the project.\n\n## \u003ca name=\"snippets\"\u003e🕸️ Snippets\u003c/a\u003e\n\nHere are some code snippets from the project to help you get started quickly.\n\n### Setup\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003e.vscode/settings.json\u003c/code\u003e\u003c/summary\u003e\n\n```json\n{\n  \"editor.formatOnPaste\": true,\n  \"editor.formatOnSave\": true,\n  \"[typescriptreact]\": {\n    \"editor.defaultFormatter\": \"esbenp.prettier-vscode\"\n  },\n  \"[typescript]\": {\n    \"editor.defaultFormatter\": \"esbenp.prettier-vscode\"\n  },\n  \"editor.codeActionsOnSave\": {\n    \"source.fixAll.eslint\": \"explicit\"\n  }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003etailwind.config.js\u003c/code\u003e\u003c/summary\u003e\n\n```js\n/** @type {import('tailwindcss').Config} */\nmodule.exports = {\n    content: [\"./app/**/*.{js,jsx,ts,tsx}\", \"./components/**/*.{js,jsx,ts,tsx}\"],\n    theme: {\n        extend: {\n            fontFamily: {\n                Jakarta: [\"Jakarta\", \"sans-serif\"],\n                JakartaBold: [\"Jakarta-Bold\", \"sans-serif\"],\n                JakartaExtraBold: [\"Jakarta-ExtraBold\", \"sans-serif\"],\n                JakartaExtraLight: [\"Jakarta-ExtraLight\", \"sans-serif\"],\n                JakartaLight: [\"Jakarta-Light\", \"sans-serif\"],\n                JakartaMedium: [\"Jakarta-Medium\", \"sans-serif\"],\n                JakartaSemiBold: [\"Jakarta-SemiBold\", \"sans-serif\"],\n            },\n            colors: {\n                primary: {\n                    100: \"#F5F8FF\",\n                    200: \"#EBF4FF\",\n                    300: \"#C3D9FF\",\n                    400: \"#9BBFFF\",\n                    500: \"#0286FF\",\n                    600: \"#6A85E6\",\n                    700: \"#475A99\",\n                    800: \"#364573\",\n                    900: \"#242B4D\",\n                },\n                secondary: {\n                    100: \"#F8F8F8\",\n                    200: \"#F1F1F1\",\n                    300: \"#D9D9D9\",\n                    400: \"#C2C2C2\",\n                    500: \"#AAAAAA\",\n                    600: \"#999999\",\n                    700: \"#666666\",\n                    800: \"#4D4D4D\",\n                    900: \"#333333\",\n                },\n                success: {\n                    100: \"#F0FFF4\",\n                    200: \"#C6F6D5\",\n                    300: \"#9AE6B4\",\n                    400: \"#68D391\",\n                    500: \"#38A169\",\n                    600: \"#2F855A\",\n                    700: \"#276749\",\n                    800: \"#22543D\",\n                    900: \"#1C4532\",\n                },\n                danger: {\n                    100: \"#FFF5F5\",\n                    200: \"#FED7D7\",\n                    300: \"#FEB2B2\",\n                    400: \"#FC8181\",\n                    500: \"#F56565\",\n                    600: \"#E53E3E\",\n                    700: \"#C53030\",\n                    800: \"#9B2C2C\",\n                    900: \"#742A2A\",\n                },\n                warning: {\n                    100: \"#FFFBEB\",\n                    200: \"#FEF3C7\",\n                    300: \"#FDE68A\",\n                    400: \"#FACC15\",\n                    500: \"#EAB308\",\n                    600: \"#CA8A04\",\n                    700: \"#A16207\",\n                    800: \"#854D0E\",\n                    900: \"#713F12\",\n                },\n                general: {\n                    100: \"#CED1DD\",\n                    200: \"#858585\",\n                    300: \"#EEEEEE\",\n                    400: \"#0CC25F\",\n                    500: \"#F6F8FA\",\n                    600: \"#E6F3FF\",\n                    700: \"#EBEBEB\",\n                    800: \"#ADADAD\",\n                },\n            },\n        },\n    },\n    plugins: [],\n};\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003etypes/type.d.ts\u003c/code\u003e\u003c/summary\u003e\n\n```ts\nimport {TextInputProps, TouchableOpacityProps} from \"react-native\";\n\ndeclare interface Driver {\n    driver_id: number;\n    first_name: string;\n    last_name: string;\n    profile_image_url: string;\n    car_image_url: string;\n    car_seats: number;\n    rating: number;\n}\n\ndeclare interface MarkerData {\n    latitude: number;\n    longitude: number;\n    id: number;\n    title: string;\n    profile_image_url: string;\n    car_image_url: string;\n    car_seats: number;\n    rating: number;\n    first_name: string;\n    last_name: string;\n    time?: number;\n    price?: string;\n}\n\ndeclare interface MapProps {\n    destinationLatitude?: number;\n    destinationLongitude?: number;\n    onDriverTimesCalculated?: (driversWithTimes: MarkerData[]) =\u003e void;\n    selectedDriver?: number | null;\n    onMapReady?: () =\u003e void;\n}\n\ndeclare interface Ride {\n    origin_address: string;\n    destination_address: string;\n    origin_latitude: number;\n    origin_longitude: number;\n    destination_latitude: number;\n    destination_longitude: number;\n    ride_time: number;\n    fare_price: number;\n    payment_status: string;\n    driver_id: number;\n    user_email: string;\n    created_at: string;\n    driver: {\n        first_name: string;\n        last_name: string;\n        car_seats: number;\n    };\n}\n\ndeclare interface ButtonProps extends TouchableOpacityProps {\n    title: string;\n    bgVariant?: \"primary\" | \"secondary\" | \"danger\" | \"outline\" | \"success\";\n    textVariant?: \"primary\" | \"default\" | \"secondary\" | \"danger\" | \"success\";\n    IconLeft?: React.ComponentType\u003cany\u003e;\n    IconRight?: React.ComponentType\u003cany\u003e;\n    className?: string;\n}\n\ndeclare interface GoogleInputProps {\n    icon?: string;\n    initialLocation?: string;\n    containerStyle?: string;\n    textInputBackgroundColor?: string;\n    handlePress: ({\n                      latitude,\n                      longitude,\n                      address,\n                  }: {\n        latitude: number;\n        longitude: number;\n        address: string;\n    }) =\u003e void;\n}\n\ndeclare interface InputFieldProps extends TextInputProps {\n    label: string;\n    icon?: any;\n    secureTextEntry?: boolean;\n    labelStyle?: string;\n    containerStyle?: string;\n    inputStyle?: string;\n    iconStyle?: string;\n    className?: string;\n}\n\ndeclare interface PaymentProps {\n    fullName: string;\n    email: string;\n    amount: string;\n    driverId: number;\n    rideTime: number;\n}\n\ndeclare interface LocationStore {\n    userLatitude: number | null;\n    userLongitude: number | null;\n    userAddress: string | null;\n    destinationLatitude: number | null;\n    destinationLongitude: number | null;\n    destinationAddress: string | null;\n    setUserLocation: ({\n                          latitude,\n                          longitude,\n                          address,\n                      }: {\n        latitude: number;\n        longitude: number;\n        address: string;\n    }) =\u003e void;\n    setDestinationLocation: ({\n                                 latitude,\n                                 longitude,\n                                 address,\n                             }: {\n        latitude: number;\n        longitude: number;\n        address: string;\n    }) =\u003e void;\n}\n\ndeclare interface DriverStore {\n    drivers: MarkerData[];\n    selectedDriver: number | null;\n    setSelectedDriver: (driverId: number) =\u003e void;\n    setDrivers: (drivers: MarkerData[]) =\u003e void;\n    clearSelectedDriver: () =\u003e void;\n}\n\ndeclare interface DriverCardProps {\n    item: MarkerData;\n    selected: number;\n    setSelected: () =\u003e void;\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003etypes/image.d.ts\u003c/code\u003e\u003c/summary\u003e\n\n```ts\ndeclare module \"*.png\" {\n    const value: any;\n    export default value;\n}\n\ndeclare module \"*.jpg\" {\n    const value: any;\n    export default value;\n}\n\ndeclare module \"*.jpeg\" {\n    const value: any;\n    export default value;\n}\n\ndeclare module \"*.gif\" {\n    const value: any;\n    export default value;\n}\n\ndeclare module \"*.svg\" {\n    const value: any;\n    export default value;\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003econstants/index.ts\u003c/code\u003e\u003c/summary\u003e\n\n```ts\nimport arrowDown from \"@/assets/icons/arrow-down.png\";\nimport arrowUp from \"@/assets/icons/arrow-up.png\";\nimport backArrow from \"@/assets/icons/back-arrow.png\";\nimport chat from \"@/assets/icons/chat.png\";\nimport checkmark from \"@/assets/icons/check.png\";\nimport close from \"@/assets/icons/close.png\";\nimport dollar from \"@/assets/icons/dollar.png\";\nimport email from \"@/assets/icons/email.png\";\nimport eyecross from \"@/assets/icons/eyecross.png\";\nimport google from \"@/assets/icons/google.png\";\nimport home from \"@/assets/icons/home.png\";\nimport list from \"@/assets/icons/list.png\";\nimport lock from \"@/assets/icons/lock.png\";\nimport map from \"@/assets/icons/map.png\";\nimport marker from \"@/assets/icons/marker.png\";\nimport out from \"@/assets/icons/out.png\";\nimport person from \"@/assets/icons/person.png\";\nimport pin from \"@/assets/icons/pin.png\";\nimport point from \"@/assets/icons/point.png\";\nimport profile from \"@/assets/icons/profile.png\";\nimport search from \"@/assets/icons/search.png\";\nimport selectedMarker from \"@/assets/icons/selected-marker.png\";\nimport star from \"@/assets/icons/star.png\";\nimport target from \"@/assets/icons/target.png\";\nimport to from \"@/assets/icons/to.png\";\nimport check from \"@/assets/images/check.png\";\nimport getStarted from \"@/assets/images/get-started.png\";\nimport message from \"@/assets/images/message.png\";\nimport noResult from \"@/assets/images/no-result.png\";\nimport onboarding1 from \"@/assets/images/onboarding1.png\";\nimport onboarding2 from \"@/assets/images/onboarding2.png\";\nimport onboarding3 from \"@/assets/images/onboarding3.png\";\nimport signUpCar from \"@/assets/images/signup-car.png\";\n\nexport const images = {\n    onboarding1,\n    onboarding2,\n    onboarding3,\n    getStarted,\n    signUpCar,\n    check,\n    noResult,\n    message,\n};\n\nexport const icons = {\n    arrowDown,\n    arrowUp,\n    backArrow,\n    chat,\n    checkmark,\n    close,\n    dollar,\n    email,\n    eyecross,\n    google,\n    home,\n    list,\n    lock,\n    map,\n    marker,\n    out,\n    person,\n    pin,\n    point,\n    profile,\n    search,\n    selectedMarker,\n    star,\n    target,\n    to,\n};\n\nexport const onboarding = [\n    {\n        id: 1,\n        title: \"The perfect ride is just a tap away!\",\n        description:\n            \"Your journey begins with Ryde. Find your ideal ride effortlessly.\",\n        image: images.onboarding1,\n    },\n    {\n        id: 2,\n        title: \"Best car in your hands with Ryde\",\n        description:\n            \"Discover the convenience of finding your perfect ride with Ryde\",\n        image: images.onboarding2,\n    },\n    {\n        id: 3,\n        title: \"Your ride, your way. Let's go!\",\n        description:\n            \"Enter your destination, sit back, and let us take care of the rest.\",\n        image: images.onboarding3,\n    },\n];\n\nexport const data = {\n    onboarding,\n};\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003eRoot Layout Fonts\u003c/code\u003e\u003c/summary\u003e\n\n```ts\nconst [loaded] = useFonts({\n    \"Jakarta-Bold\": require(\"../assets/fonts/PlusJakartaSans-Bold.ttf\"),\n    \"Jakarta-ExtraBold\": require(\"../assets/fonts/PlusJakartaSans-ExtraBold.ttf\"),\n    \"Jakarta-ExtraLight\": require(\"../assets/fonts/PlusJakartaSans-ExtraLight.ttf\"),\n    \"Jakarta-Light\": require(\"../assets/fonts/PlusJakartaSans-Light.ttf\"),\n    \"Jakarta-Medium\": require(\"../assets/fonts/PlusJakartaSans-Medium.ttf\"),\n    \"Jakarta-Regular\": require(\"../assets/fonts/PlusJakartaSans-Regular.ttf\"),\n    \"Jakarta-SemiBold\": require(\"../assets/fonts/PlusJakartaSans-SemiBold.ttf\"),\n});\n```\n\n\u003c/details\u003e\n\n### Components\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003ecomponents/CustomButton\u003c/code\u003e\u003c/summary\u003e\n\n```tsx\nimport {TouchableOpacity, Text} from \"react-native\";\n\nimport {ButtonProps} from \"@/types/type\";\n\nconst getBgVariantStyle = (variant: ButtonProps[\"bgVariant\"]) =\u003e {\n    switch (variant) {\n        case \"secondary\":\n            return \"bg-gray-500\";\n        case \"danger\":\n            return \"bg-red-500\";\n        case \"success\":\n            return \"bg-green-500\";\n        case \"outline\":\n            return \"bg-transparent border-neutral-300 border-[0.5px]\";\n        default:\n            return \"bg-[#0286FF]\";\n    }\n};\n\nconst getTextVariantStyle = (variant: ButtonProps[\"textVariant\"]) =\u003e {\n    switch (variant) {\n        case \"primary\":\n            return \"text-black\";\n        case \"secondary\":\n            return \"text-gray-100\";\n        case \"danger\":\n            return \"text-red-100\";\n        case \"success\":\n            return \"text-green-100\";\n        default:\n            return \"text-white\";\n    }\n};\n\nconst CustomButton = ({\n                          onPress,\n                          title,\n                          bgVariant = \"primary\",\n                          textVariant = \"default\",\n                          IconLeft,\n                          IconRight,\n                          className,\n                          ...props\n                      }: ButtonProps) =\u003e {\n    return (\n        \u003cTouchableOpacity\n            onPress={onPress}\n            className={`w-full rounded-full p-3 flex flex-row justify-center items-center shadow-md shadow-neutral-400/70 ${getBgVariantStyle(bgVariant)} ${className}`}\n            {...props}\n        \u003e\n            {IconLeft \u0026\u0026 \u003cIconLeft/\u003e}\n            \u003cText className={`text-lg font-bold ${getTextVariantStyle(textVariant)}`}\u003e\n                {title}\n            \u003c/Text\u003e\n            {IconRight \u0026\u0026 \u003cIconRight/\u003e}\n        \u003c/TouchableOpacity\u003e\n    );\n};\n\nexport default CustomButton;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003ecomponents/InputField\u003c/code\u003e\u003c/summary\u003e\n\n```tsx\nimport {\n    TextInput,\n    View,\n    Text,\n    Image,\n    KeyboardAvoidingView,\n    TouchableWithoutFeedback,\n    Keyboard,\n    Platform,\n} from \"react-native\";\n\nimport {InputFieldProps} from \"@/types/type\";\n\nconst InputField = ({\n                        label,\n                        icon,\n                        secureTextEntry = false,\n                        labelStyle,\n                        containerStyle,\n                        inputStyle,\n                        iconStyle,\n                        className,\n                        ...props\n                    }: InputFieldProps) =\u003e {\n    return (\n        \u003cKeyboardAvoidingView\n            behavior={Platform.OS === \"ios\" ? \"padding\" : \"height\"}\n        \u003e\n            \u003cTouchableWithoutFeedback onPress={Keyboard.dismiss}\u003e\n                \u003cView className=\"my-2 w-full\"\u003e\n                    \u003cText className={`text-lg font-JakartaSemiBold mb-3 ${labelStyle}`}\u003e\n                        {label}\n                    \u003c/Text\u003e\n                    \u003cView\n                        className={`flex flex-row justify-start items-center relative bg-neutral-100 rounded-full border border-neutral-100 focus:border-primary-500  ${containerStyle}`}\n                    \u003e\n                        {icon \u0026\u0026 (\n                            \u003cImage source={icon} className={`w-6 h-6 ml-4 ${iconStyle}`}/\u003e\n                        )}\n                        \u003cTextInput\n                            className={`rounded-full p-4 font-JakartaSemiBold text-[15px] flex-1 ${inputStyle} text-left`}\n                            secureTextEntry={secureTextEntry}\n                            {...props}\n                        /\u003e\n                    \u003c/View\u003e\n                \u003c/View\u003e\n            \u003c/TouchableWithoutFeedback\u003e\n        \u003c/KeyboardAvoidingView\u003e\n    );\n};\n\nexport default InputField;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003ecomponents/DriverCard.tsx\u003c/code\u003e\u003c/summary\u003e\n\n```tsx\nimport React from \"react\";\nimport {Image, Text, TouchableOpacity, View} from \"react-native\";\n\nimport {icons} from \"@/constants\";\nimport {formatTime} from \"@/lib/utils\";\nimport {DriverCardProps} from \"@/types/type\";\n\nconst DriverCard = ({item, selected, setSelected}: DriverCardProps) =\u003e {\n    return (\n        \u003cTouchableOpacity\n            onPress={setSelected}\n            className={`${\n                selected === item.id ? \"bg-general-600\" : \"bg-white\"\n            } flex flex-row items-center justify-between py-5 px-3 rounded-xl`}\n        \u003e\n            \u003cImage\n                source={{uri: item.profile_image_url}}\n                className=\"w-14 h-14 rounded-full\"\n            /\u003e\n\n            \u003cView className=\"flex-1 flex flex-col items-start justify-center mx-3\"\u003e\n                \u003cView className=\"flex flex-row items-center justify-start mb-1\"\u003e\n                    \u003cText className=\"text-lg font-JakartaRegular\"\u003e{item.title}\u003c/Text\u003e\n\n                    \u003cView className=\"flex flex-row items-center space-x-1 ml-2\"\u003e\n                        \u003cImage source={icons.star} className=\"w-3.5 h-3.5\"/\u003e\n                        \u003cText className=\"text-sm font-JakartaRegular\"\u003e4\u003c/Text\u003e\n                    \u003c/View\u003e\n                \u003c/View\u003e\n\n                \u003cView className=\"flex flex-row items-center justify-start\"\u003e\n                    \u003cView className=\"flex flex-row items-center\"\u003e\n                        \u003cImage source={icons.dollar} className=\"w-4 h-4\"/\u003e\n                        \u003cText className=\"text-sm font-JakartaRegular ml-1\"\u003e\n                            ${item.price}\n                        \u003c/Text\u003e\n                    \u003c/View\u003e\n\n                    \u003cText className=\"text-sm font-JakartaRegular text-general-800 mx-1\"\u003e\n                        |\n                    \u003c/Text\u003e\n\n                    \u003cText className=\"text-sm font-JakartaRegular text-general-800\"\u003e\n                        {formatTime(item.time!)}\n                    \u003c/Text\u003e\n\n                    \u003cText className=\"text-sm font-JakartaRegular text-general-800 mx-1\"\u003e\n                        |\n                    \u003c/Text\u003e\n\n                    \u003cText className=\"text-sm font-JakartaRegular text-general-800\"\u003e\n                        {item.car_seats} seats\n                    \u003c/Text\u003e\n                \u003c/View\u003e\n            \u003c/View\u003e\n\n            \u003cImage\n                source={{uri: item.car_image_url}}\n                className=\"h-14 w-14\"\n                resizeMode=\"contain\"\n            /\u003e\n        \u003c/TouchableOpacity\u003e\n    );\n};\n\nexport default DriverCard;\n```\n\n\u003c/details\u003e\n\n### Utilities\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003elib/fetch.ts\u003c/code\u003e\u003c/summary\u003e\n\n```ts\nimport {useState, useEffect, useCallback} from \"react\";\n\nexport const fetchAPI = async (url: string, options?: RequestInit) =\u003e {\n    try {\n        const response = await fetch(url, options);\n        if (!response.ok) {\n            new Error(`HTTP error! status: ${response.status}`);\n        }\n        return await response.json();\n    } catch (error) {\n        console.error(\"Fetch error:\", error);\n        throw error;\n    }\n};\n\nexport const useFetch = \u003cT\u003e(url: string, options?: RequestInit) =\u003e {\n    const [data, setData] = useState\u003cT | null\u003e(null);\n    const [loading, setLoading] = useState(false);\n    const [error, setError] = useState\u003cstring | null\u003e(null);\n\n    const fetchData = useCallback(async () =\u003e {\n        setLoading(true);\n        setError(null);\n\n        try {\n            const result = await fetchAPI(url, options);\n            setData(result.data);\n        } catch (err) {\n            setError((err as Error).message);\n        } finally {\n            setLoading(false);\n        }\n    }, [url, options]);\n\n    useEffect(() =\u003e {\n        fetchData();\n    }, [fetchData]);\n\n    return {data, loading, error, refetch: fetchData};\n};\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ccode\u003elib/map.ts\u003c/code\u003e\u003c/summary\u003e\n\n```ts\nimport {Driver, MarkerData} from \"@/types/type\";\n\nconst directionsAPI = process.env.EXPO_PUBLIC_GOOGLE_API_KEY;\n\nexport const generateMarkersFromData = ({\n                                            data,\n                                            userLatitude,\n                                            userLongitude,\n                                        }: {\n    data: Driver[];\n    userLatitude: number;\n    userLongitude: number;\n}): MarkerData[] =\u003e {\n    return data.map((driver) =\u003e {\n        const latOffset = (Math.random() - 0.5) * 0.01; // Random offset between -0.005 and 0.005\n        const lngOffset = (Math.random() - 0.5) * 0.01; // Random offset between -0.005 and 0.005\n\n        return {\n            latitude: userLatitude + latOffset,\n            longitude: userLongitude + lngOffset,\n            title: `${driver.first_name} ${driver.last_name}`,\n            ...driver,\n        };\n    });\n};\n\nexport const calculateRegion = ({\n                                    userLatitude,\n                                    userLongitude,\n                                    destinationLatitude,\n                                    destinationLongitude,\n                                }: {\n    userLatitude: number | null;\n    userLongitude: number | null;\n    destinationLatitude?: number | null;\n    destinationLongitude?: number | null;\n}) =\u003e {\n    if (!userLatitude || !userLongitude) {\n        return {\n            latitude: 37.78825,\n            longitude: -122.4324,\n            latitudeDelta: 0.01,\n            longitudeDelta: 0.01,\n        };\n    }\n\n    if (!destinationLatitude || !destinationLongitude) {\n        return {\n            latitude: userLatitude,\n            longitude: userLongitude,\n            latitudeDelta: 0.01,\n            longitudeDelta: 0.01,\n        };\n    }\n\n    const minLat = Math.min(userLatitude, destinationLatitude);\n    const maxLat = Math.max(userLatitude, destinationLatitude);\n    const minLng = Math.min(userLongitude, destinationLongitude);\n    const maxLng = Math.max(userLongitude, destinationLongitude);\n\n    const latitudeDelta = (maxLat - minLat) * 1.3; // Adding some padding\n    const longitudeDelta = (maxLng - minLng) * 1.3; // Adding some padding\n\n    const latitude = (userLatitude + destinationLatitude) / 2;\n    const longitude = (userLongitude + destinationLongitude) / 2;\n\n    return {\n        latitude,\n        longitude,\n        latitudeDelta,\n        longitudeDelta,\n    };\n};\n\nexport const calculateDriverTimes = async ({\n                                               markers,\n                                               userLatitude,\n                                               userLongitude,\n                                               destinationLatitude,\n                                               destinationLongitude,\n                                           }: {\n    markers: MarkerData[];\n    userLatitude: number | null;\n    userLongitude: number | null;\n    destinationLatitude: number | null;\n    destinationLongitude: number | null;\n}) =\u003e {\n    if (\n        !userLatitude ||\n        !userLongitude ||\n        !destinationLatitude ||\n        !destinationLongitude\n    )\n        return;\n\n    try {\n        const timesPromises = markers.map(async (marker) =\u003e {\n            const responseToUser = await fetch(\n                `https://maps.googleapis.com/maps/api/directions/json?origin=${marker.latitude},${marker.longitude}\u0026destination=${userLatitude},${userLongitude}\u0026key=${directionsAPI}`,\n            );\n            const dataToUser = await responseToUser.json();\n            const timeToUser = dataToUser.routes[0].legs[0].duration.value; // Time in seconds\n\n            const responseToDestination = await fetch(\n                `https://maps.googleapis.com/maps/api/directions/json?origin=${userLatitude},${userLongitude}\u0026destination=${destinationLatitude},${destinationLongitude}\u0026key=${directionsAPI}`,\n            );\n            const dataToDestination = await responseToDestination.json();\n            const timeToDestination =\n                dataToDestination.routes[0].legs[0].duration.value; // Time in seconds\n\n            const totalTime = (timeToUser + timeToDestination) / 60; // Total time in minutes\n            const price = (totalTime * 0.5).toFixed(2); // Calculate price based on time\n\n            return {...marker, time: totalTime, price};\n        });\n\n        return await Promise.all(timesPromises);\n    } catch (error) {\n        console.error(\"Error calculating driver times:\", error);\n    }\n};\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003elib/utils.ts\u003c/code\u003e\u003c/summary\u003e\n\n```ts\nimport {Ride} from \"@/types/type\";\n\nexport const sortRides = (rides: Ride[]): Ride[] =\u003e {\n    const result = rides.sort((a, b) =\u003e {\n        const dateA = new Date(`${a.created_at}T${a.ride_time}`);\n        const dateB = new Date(`${b.created_at}T${b.ride_time}`);\n        return dateB.getTime() - dateA.getTime();\n    });\n\n    return result.reverse();\n};\n\nexport function formatTime(minutes: number): string {\n    const formattedMinutes = +minutes?.toFixed(0) || 0;\n\n    if (formattedMinutes \u003c 60) {\n        return `${minutes} min`;\n    } else {\n        const hours = Math.floor(formattedMinutes / 60);\n        const remainingMinutes = formattedMinutes % 60;\n        return `${hours}h ${remainingMinutes}m`;\n    }\n}\n\nexport function formatDate(dateString: string): string {\n    const date = new Date(dateString);\n    const day = date.getDate();\n    const monthNames = [\n        \"January\",\n        \"February\",\n        \"March\",\n        \"April\",\n        \"May\",\n        \"June\",\n        \"July\",\n        \"August\",\n        \"September\",\n        \"October\",\n        \"November\",\n        \"December\",\n    ];\n    const month = monthNames[date.getMonth()];\n    const year = date.getFullYear();\n\n    return `${day \u003c 10 ? \"0\" + day : day} ${month} ${year}`;\n}\n```\n\n\u003c/details\u003e\n\n### Queries\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003eGET Rides SQL Query\u003c/code\u003e\u003c/summary\u003e\n\n```sql\nSELECT\n    rides.ride_id,\n    rides.origin_address,\n    rides.destination_address,\n    rides.origin_latitude,\n    rides.origin_longitude,\n    rides.destination_latitude,\n    rides.destination_longitude,\n    rides.ride_time,\n    rides.fare_price,\n    rides.payment_status,\n    rides.created_at,\n    'driver', json_build_object(\n        'driver_id', drivers.id,\n        'first_name', drivers.first_name,\n        'last_name', drivers.last_name,\n        'profile_image_url', drivers.profile_image_url,\n        'car_image_url', drivers.car_image_url,\n        'car_seats', drivers.car_seats,\n        'rating', drivers.rating\n    ) AS driver \nFROM \n    rides\nINNER JOIN\n    drivers ON rides.driver_id = drivers.id\nWHERE \n    rides.user_email = ${id}\nORDER BY \n    rides.created_at DESC;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003eSEED Drivers Query\u003c/code\u003e\u003c/summary\u003e\n\n```sql\nINSERT INTO drivers (id, first_name, last_name, profile_image_url, car_image_url, car_seats, rating)\nVALUES \n('1', 'James', 'Wilson', 'https://ucarecdn.com/dae59f69-2c1f-48c3-a883-017bcf0f9950/-/preview/1000x666/', 'https://ucarecdn.com/a2dc52b2-8bf7-4e49-9a36-3ffb5229ed02/-/preview/465x466/', 4, '4.80'),\n('2', 'David', 'Brown', 'https://ucarecdn.com/6ea6d83d-ef1a-483f-9106-837a3a5b3f67/-/preview/1000x666/', 'https://ucarecdn.com/a3872f80-c094-409c-82f8-c9ff38429327/-/preview/930x932/', 5, '4.60'),\n('3', 'Michael', 'Johnson', 'https://ucarecdn.com/0330d85c-232e-4c30-bd04-e5e4d0e3d688/-/preview/826x822/', 'https://ucarecdn.com/289764fb-55b6-4427-b1d1-f655987b4a14/-/preview/930x932/', 4, '4.70'),\n('4', 'Robert', 'Green', 'https://ucarecdn.com/fdfc54df-9d24-40f7-b7d3-6f391561c0db/-/preview/626x417/', 'https://ucarecdn.com/b6fb3b55-7676-4ff3-8484-fb115e268d32/-/preview/930x932/', 4, '4.90');\n`````\n\n\u003c/details\u003e\n\n### Schema\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003eCREATE Drivers Table SQL Query\u003c/code\u003e\u003c/summary\u003e\n\n```sql\nCREATE TABLE drivers (\n    id SERIAL PRIMARY KEY,\n    first_name VARCHAR(50) NOT NULL,\n    last_name VARCHAR(50) NOT NULL,\n    profile_image_url TEXT,\n    car_image_url TEXT,\n    car_seats INTEGER NOT NULL CHECK (car_seats \u003e 0),\n    rating DECIMAL(3, 2) CHECK (rating \u003e= 0 AND rating \u003c= 5)\n);\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003eCREATE Rides Table SQL Query\u003c/code\u003e\u003c/summary\u003e\n\n```sql\nCREATE TABLE rides (\n    ride_id SERIAL PRIMARY KEY,\n    origin_address VARCHAR(255) NOT NULL,\n    destination_address VARCHAR(255) NOT NULL,\n    origin_latitude DECIMAL(9, 6) NOT NULL,\n    origin_longitude DECIMAL(9, 6) NOT NULL,\n    destination_latitude DECIMAL(9, 6) NOT NULL,\n    destination_longitude DECIMAL(9, 6) NOT NULL,\n    ride_time INTEGER NOT NULL,\n    fare_price DECIMAL(10, 2) NOT NULL CHECK (fare_price \u003e= 0),\n    payment_status VARCHAR(20) NOT NULL,\n    driver_id INTEGER REFERENCES drivers(id),\n    user_id VARCHAR(100) NOT NULL,\n    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n); \n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003eCREATE Users Table SQL\u003c/code\u003e\u003c/summary\u003e\n\n```sql\nCREATE TABLE users (\n    id SERIAL PRIMARY KEY,\n    name VARCHAR(100) NOT NULL,\n    email VARCHAR(100) UNIQUE NOT NULL,\n    clerk_id VARCHAR(50) UNIQUE NOT NULL\n);\n```\n\n\u003c/details\u003e\n\n### Mock Data\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003eMock Drivers\u003c/code\u003e\u003c/summary\u003e\n\n```js\n[\n    {\n        \"id\": \"1\",\n        \"first_name\": \"James\",\n        \"last_name\": \"Wilson\",\n        \"profile_image_url\": \"https://ucarecdn.com/dae59f69-2c1f-48c3-a883-017bcf0f9950/-/preview/1000x666/\",\n        \"car_image_url\": \"https://ucarecdn.com/a2dc52b2-8bf7-4e49-9a36-3ffb5229ed02/-/preview/465x466/\",\n        \"car_seats\": 4,\n        \"rating\": \"4.80\"\n    },\n    {\n        \"id\": \"2\",\n        \"first_name\": \"David\",\n        \"last_name\": \"Brown\",\n        \"profile_image_url\": \"https://ucarecdn.com/6ea6d83d-ef1a-483f-9106-837a3a5b3f67/-/preview/1000x666/\",\n        \"car_image_url\": \"https://ucarecdn.com/a3872f80-c094-409c-82f8-c9ff38429327/-/preview/930x932/\",\n        \"car_seats\": 5,\n        \"rating\": \"4.60\"\n    },\n    {\n        \"id\": \"3\",\n        \"first_name\": \"Michael\",\n        \"last_name\": \"Johnson\",\n        \"profile_image_url\": \"https://ucarecdn.com/0330d85c-232e-4c30-bd04-e5e4d0e3d688/-/preview/826x822/\",\n        \"car_image_url\": \"https://ucarecdn.com/289764fb-55b6-4427-b1d1-f655987b4a14/-/preview/930x932/\",\n        \"car_seats\": 4,\n        \"rating\": \"4.70\"\n    },\n    {\n        \"id\": \"4\",\n        \"first_name\": \"Robert\",\n        \"last_name\": \"Green\",\n        \"profile_image_url\": \"https://ucarecdn.com/fdfc54df-9d24-40f7-b7d3-6f391561c0db/-/preview/626x417/\",\n        \"car_image_url\": \"https://ucarecdn.com/b6fb3b55-7676-4ff3-8484-fb115e268d32/-/preview/930x932/\",\n        \"car_seats\": 4,\n        \"rating\": \"4.90\"\n    }\n]\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003eMock Rides\u003c/code\u003e\u003c/summary\u003e\n\n```js\n[\n    {\n        \"ride_id\": \"1\",\n        \"origin_address\": \"Kathmandu, Nepal\",\n        \"destination_address\": \"Pokhara, Nepal\",\n        \"origin_latitude\": \"27.717245\",\n        \"origin_longitude\": \"85.323961\",\n        \"destination_latitude\": \"28.209583\",\n        \"destination_longitude\": \"83.985567\",\n        \"ride_time\": 391,\n        \"fare_price\": \"19500.00\",\n        \"payment_status\": \"paid\",\n        \"driver_id\": 2,\n        \"user_id\": \"1\",\n        \"created_at\": \"2024-08-12 05:19:20.620007\",\n        \"driver\": {\n            \"driver_id\": \"2\",\n            \"first_name\": \"David\",\n            \"last_name\": \"Brown\",\n            \"profile_image_url\": \"https://ucarecdn.com/6ea6d83d-ef1a-483f-9106-837a3a5b3f67/-/preview/1000x666/\",\n            \"car_image_url\": \"https://ucarecdn.com/a3872f80-c094-409c-82f8-c9ff38429327/-/preview/930x932/\",\n            \"car_seats\": 5,\n            \"rating\": \"4.60\"\n        }\n    },\n    {\n        \"ride_id\": \"2\",\n        \"origin_address\": \"Jalkot, MH\",\n        \"destination_address\": \"Pune, Maharashtra, India\",\n        \"origin_latitude\": \"18.609116\",\n        \"origin_longitude\": \"77.165873\",\n        \"destination_latitude\": \"18.520430\",\n        \"destination_longitude\": \"73.856744\",\n        \"ride_time\": 491,\n        \"fare_price\": \"24500.00\",\n        \"payment_status\": \"paid\",\n        \"driver_id\": 1,\n        \"user_id\": \"1\",\n        \"created_at\": \"2024-08-12 06:12:17.683046\",\n        \"driver\": {\n            \"driver_id\": \"1\",\n            \"first_name\": \"James\",\n            \"last_name\": \"Wilson\",\n            \"profile_image_url\": \"https://ucarecdn.com/dae59f69-2c1f-48c3-a883-017bcf0f9950/-/preview/1000x666/\",\n            \"car_image_url\": \"https://ucarecdn.com/a2dc52b2-8bf7-4e49-9a36-3ffb5229ed02/-/preview/465x466/\",\n            \"car_seats\": 4,\n            \"rating\": \"4.80\"\n        }\n    },\n    {\n        \"ride_id\": \"3\",\n        \"origin_address\": \"Zagreb, Croatia\",\n        \"destination_address\": \"Rijeka, Croatia\",\n        \"origin_latitude\": \"45.815011\",\n        \"origin_longitude\": \"15.981919\",\n        \"destination_latitude\": \"45.327063\",\n        \"destination_longitude\": \"14.442176\",\n        \"ride_time\": 124,\n        \"fare_price\": \"6200.00\",\n        \"payment_status\": \"paid\",\n        \"driver_id\": 1,\n        \"user_id\": \"1\",\n        \"created_at\": \"2024-08-12 08:49:01.809053\",\n        \"driver\": {\n            \"driver_id\": \"1\",\n            \"first_name\": \"James\",\n            \"last_name\": \"Wilson\",\n            \"profile_image_url\": \"https://ucarecdn.com/dae59f69-2c1f-48c3-a883-017bcf0f9950/-/preview/1000x666/\",\n            \"car_image_url\": \"https://ucarecdn.com/a2dc52b2-8bf7-4e49-9a36-3ffb5229ed02/-/preview/465x466/\",\n            \"car_seats\": 4,\n            \"rating\": \"4.80\"\n        }\n    },\n    {\n        \"ride_id\": \"4\",\n        \"origin_address\": \"Okayama, Japan\",\n        \"destination_address\": \"Osaka, Japan\",\n        \"origin_latitude\": \"34.655531\",\n        \"origin_longitude\": \"133.919795\",\n        \"destination_latitude\": \"34.693725\",\n        \"destination_longitude\": \"135.502254\",\n        \"ride_time\": 159,\n        \"fare_price\": \"7900.00\",\n        \"payment_status\": \"paid\",\n        \"driver_id\": 3,\n        \"user_id\": \"1\",\n        \"created_at\": \"2024-08-12 18:43:54.297838\",\n        \"driver\": {\n            \"driver_id\": \"3\",\n            \"first_name\": \"Michael\",\n            \"last_name\": \"Johnson\",\n            \"profile_image_url\": \"https://ucarecdn.com/0330d85c-232e-4c30-bd04-e5e4d0e3d688/-/preview/826x822/\",\n            \"car_image_url\": \"https://ucarecdn.com/289764fb-55b6-4427-b1d1-f655987b4a14/-/preview/930x932/\",\n            \"car_seats\": 4,\n            \"rating\": \"4.70\"\n        }\n    }\n]\n```\n\n\u003c/details\u003e\n\n### API Endpoints\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003e(api)/ride/create+api.ts\u003c/code\u003e\u003c/summary\u003e\n\n```ts\nimport {neon} from \"@neondatabase/serverless\";\n\nexport async function POST(request: Request) {\n    try {\n        const body = await request.json();\n        const {\n            origin_address,\n            destination_address,\n            origin_latitude,\n            origin_longitude,\n            destination_latitude,\n            destination_longitude,\n            ride_time,\n            fare_price,\n            payment_status,\n            driver_id,\n            user_id,\n        } = body;\n\n        if (\n            !origin_address ||\n            !destination_address ||\n            !origin_latitude ||\n            !origin_longitude ||\n            !destination_latitude ||\n            !destination_longitude ||\n            !ride_time ||\n            !fare_price ||\n            !payment_status ||\n            !driver_id ||\n            !user_id\n        ) {\n            return Response.json(\n                {error: \"Missing required fields\"},\n                {status: 400},\n            );\n        }\n\n        const sql = neon(`${process.env.DATABASE_URL}`);\n\n        const response = await sql`\n        INSERT INTO rides ( \n          origin_address, \n          destination_address, \n          origin_latitude, \n          origin_longitude, \n          destination_latitude, \n          destination_longitude, \n          ride_time, \n          fare_price, \n          payment_status, \n          driver_id, \n          user_id\n        ) VALUES (\n          ${origin_address},\n          ${destination_address},\n          ${origin_latitude},\n          ${origin_longitude},\n          ${destination_latitude},\n          ${destination_longitude},\n          ${ride_time},\n          ${fare_price},\n          ${payment_status},\n          ${driver_id},\n          ${user_id}\n        )\n        RETURNING *;\n        `;\n\n        return Response.json({data: response[0]}, {status: 201});\n    } catch (error) {\n        console.error(\"Error inserting data into recent_rides:\", error);\n        return Response.json({error: \"Internal Server Error\"}, {status: 500});\n    }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003e(api)/ride/[id]+api.ts\u003c/code\u003e\u003c/summary\u003e\n\n```ts\nimport {neon} from \"@neondatabase/serverless\";\n\nexport async function GET(request: Request, {id}: { id: string }) {\n    if (!id)\n        return Response.json({error: \"Missing required fields\"}, {status: 400});\n\n    try {\n        const sql = neon(`${process.env.DATABASE_URL}`);\n        const response = await sql`\n        SELECT\n            rides.ride_id,\n            rides.origin_address,\n            rides.destination_address,\n            rides.origin_latitude,\n            rides.origin_longitude,\n            rides.destination_latitude,\n            rides.destination_longitude,\n            rides.ride_time,\n            rides.fare_price,\n            rides.payment_status,\n            rides.created_at,\n            'driver', json_build_object(\n                'driver_id', drivers.id,\n                'first_name', drivers.first_name,\n                'last_name', drivers.last_name,\n                'profile_image_url', drivers.profile_image_url,\n                'car_image_url', drivers.car_image_url,\n                'car_seats', drivers.car_seats,\n                'rating', drivers.rating\n            ) AS driver \n        FROM \n            rides\n        INNER JOIN\n            drivers ON rides.driver_id = drivers.id\n        WHERE \n            rides.user_id = ${id}\n        ORDER BY \n            rides.created_at DESC;\n        `;\n\n        return Response.json({data: response});\n    } catch (error) {\n        console.error(\"Error fetching recent rides:\", error);\n        return Response.json({error: \"Internal Server Error\"}, {status: 500});\n    }\n}\n```\n\n\u003c/details\u003e\n\n### Screens\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ccode\u003e(root)/book-ride\u003c/code\u003e\u003c/summary\u003e\n\n```tsx\nimport {useUser} from \"@clerk/clerk-expo\";\nimport {Image, Text, View} from \"react-native\";\n\nimport RideLayout from \"@/components/RideLayout\";\nimport {icons} from \"@/constants\";\nimport {formatTime} from \"@/lib/utils\";\nimport {useDriverStore, useLocationStore} from \"@/store\";\n\nconst BookRide = () =\u003e {\n    const {user} = useUser();\n    const {userAddress, destinationAddress} = useLocationStore();\n    const {drivers, selectedDriver} = useDriverStore();\n\n    const driverDetails = drivers?.filter(\n        (driver) =\u003e +driver.id === selectedDriver,\n    )[0];\n\n    return (\n        \u003cRideLayout title=\"Book Ride\"\u003e\n            \u003c\u003e\n                \u003cText className=\"text-xl font-JakartaSemiBold mb-3\"\u003e\n                    Ride Information\n                \u003c/Text\u003e\n\n                \u003cView className=\"flex flex-col w-full items-center justify-center mt-10\"\u003e\n                    \u003cImage\n                        source={{uri: driverDetails?.profile_image_url}}\n                        className=\"w-28 h-28 rounded-full\"\n                    /\u003e\n\n                    \u003cView className=\"flex flex-row items-center justify-center mt-5 space-x-2\"\u003e\n                        \u003cText className=\"text-lg font-JakartaSemiBold\"\u003e\n                            {driverDetails?.title}\n                        \u003c/Text\u003e\n\n                        \u003cView className=\"flex flex-row items-center space-x-0.5\"\u003e\n                            \u003cImage\n                                source={icons.star}\n                                className=\"w-5 h-5\"\n                                resizeMode=\"contain\"\n                            /\u003e\n                            \u003cText className=\"text-lg font-JakartaRegular\"\u003e\n                                {driverDetails?.rating}\n                            \u003c/Text\u003e\n                        \u003c/View\u003e\n                    \u003c/View\u003e\n                \u003c/View\u003e\n\n                \u003cView\n                    className=\"flex flex-col w-full items-start justify-center py-3 px-5 rounded-3xl bg-general-600 mt-5\"\u003e\n                    \u003cView className=\"flex flex-row items-center justify-between w-full border-b border-white py-3\"\u003e\n                        \u003cText className=\"text-lg font-JakartaRegular\"\u003eRide Price\u003c/Text\u003e\n                        \u003cText className=\"text-lg font-JakartaRegular text-[#0CC25F]\"\u003e\n                            ${driverDetails?.price}\n                        \u003c/Text\u003e\n                    \u003c/View\u003e\n\n                    \u003cView className=\"flex flex-row items-center justify-between w-full border-b border-white py-3\"\u003e\n                        \u003cText className=\"text-lg font-JakartaRegular\"\u003ePickup Time\u003c/Text\u003e\n                        \u003cText className=\"text-lg font-JakartaRegular\"\u003e\n                            {formatTime(driverDetails?.time!)}\n                        \u003c/Text\u003e\n                    \u003c/View\u003e\n\n                    \u003cView className=\"flex flex-row items-center justify-between w-full py-3\"\u003e\n                        \u003cText className=\"text-lg font-JakartaRegular\"\u003eCar Seats\u003c/Text\u003e\n                        \u003cText className=\"text-lg font-JakartaRegular\"\u003e\n                            {driverDetails?.car_seats}\n                        \u003c/Text\u003e\n                    \u003c/View\u003e\n                \u003c/View\u003e\n\n                \u003cView className=\"flex flex-col w-full items-start justify-center mt-5\"\u003e\n                    \u003cView\n                        className=\"flex flex-row items-center justify-start mt-3 border-t border-b border-general-700 w-full py-3\"\u003e\n                        \u003cImage source={icons.to} className=\"w-6 h-6\"/\u003e\n                        \u003cText className=\"text-lg font-JakartaRegular ml-2\"\u003e\n                            {userAddress}\n                        \u003c/Text\u003e\n                    \u003c/View\u003e\n\n                    \u003cView className=\"flex flex-row items-center justify-start border-b border-general-700 w-full py-3\"\u003e\n                        \u003cImage source={icons.point} className=\"w-6 h-6\"/\u003e\n                        \u003cText className=\"text-lg font-JakartaRegular ml-2\"\u003e\n                            {destinationAddress}\n                        \u003c/Text\u003e\n                    \u003c/View\u003e\n                \u003c/View\u003e\n            \u003c/\u003e\n        \u003c/RideLayout\u003e\n    );\n};\n\nexport default BookRide;\n```  \n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003e(root)/(tabs)/profile\u003c/code\u003e\u003c/summary\u003e\n\n```tsx\nimport {useUser} from \"@clerk/clerk-expo\";\nimport {Image, ScrollView, Text, View} from \"react-native\";\nimport {SafeAreaView} from \"react-native-safe-area-context\";\n\nimport InputField from \"@/components/input-field\";\n\nconst Profile = () =\u003e {\n    const {user} = useUser();\n\n    return (\n        \u003cSafeAreaView className=\"flex-1\"\u003e\n            \u003cScrollView\n                className=\"px-5\"\n                contentContainerStyle={{paddingBottom: 120}}\n            \u003e\n                \u003cText className=\"text-2xl font-JakartaBold my-5\"\u003eMy profile\u003c/Text\u003e\n\n                \u003cView className=\"flex items-center justify-center my-5\"\u003e\n                    \u003cImage\n                        source={{\n                            uri: user?.externalAccounts[0]?.imageUrl ?? user?.imageUrl,\n                        }}\n                        style={{width: 110, height: 110, borderRadius: 110 / 2}}\n                        className=\" rounded-full h-[110px] w-[110px] border-[3px] border-white shadow-sm shadow-neutral-300\"\n                    /\u003e\n                \u003c/View\u003e\n\n                \u003cView\n                    className=\"flex flex-col items-start justify-center bg-white rounded-lg shadow-sm shadow-neutral-300 px-5 py-3\"\u003e\n                    \u003cView className=\"flex flex-col items-start justify-start w-full\"\u003e\n                        \u003cInputField\n                            label=\"First name\"\n                            placeholder={user?.firstName || \"Not Found\"}\n                            containerStyle=\"w-full\"\n                            inputStyle=\"p-3.5\"\n                            editable={false}\n                        /\u003e\n\n                        \u003cInputField\n                            label=\"Last name\"\n                            placeholder={user?.lastName || \"Not Found\"}\n                            containerStyle=\"w-full\"\n                            inputStyle=\"p-3.5\"\n                            editable={false}\n                        /\u003e\n\n                        \u003cInputField\n                            label=\"Email\"\n                            placeholder={\n                                user?.primaryEmailAddress?.emailAddress || \"Not Found\"\n                            }\n                            containerStyle=\"w-full\"\n                            inputStyle=\"p-3.5\"\n                            editable={false}\n                        /\u003e\n\n                        \u003cInputField\n                            label=\"Phone\"\n                            placeholder={user?.primaryPhoneNumber?.phoneNumber || \"Not Found\"}\n                            containerStyle=\"w-full\"\n                            inputStyle=\"p-3.5\"\n                            editable={false}\n                        /\u003e\n                    \u003c/View\u003e\n                \u003c/View\u003e\n            \u003c/ScrollView\u003e\n        \u003c/SafeAreaView\u003e\n    );\n};\n\nexport default Profile;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003e(root)/(tabs)/chat\u003c/code\u003e\u003c/summary\u003e\n\n```tsx\nimport {Image, ScrollView, Text, View} from \"react-native\";\nimport {SafeAreaView} from \"react-native-safe-area-context\";\n\nimport {images} from \"@/constants\";\n\nconst Chat = () =\u003e {\n    return (\n        \u003cSafeAreaView className=\"flex-1 bg-white p-5\"\u003e\n            \u003cScrollView contentContainerStyle={{flexGrow: 1}}\u003e\n                \u003cText className=\"text-2xl font-JakartaBold\"\u003eChat\u003c/Text\u003e\n                \u003cView className=\"flex-1 h-fit flex justify-center items-center\"\u003e\n                    \u003cImage\n                        source={images.message}\n                        alt=\"message\"\n                        className=\"w-full h-40\"\n                        resizeMode=\"contain\"\n                    /\u003e\n                    \u003cText className=\"text-3xl font-JakartaBold mt-3\"\u003e\n                        No Messages Yet\n                    \u003c/Text\u003e\n                    \u003cText className=\"text-base mt-2 text-center px-7\"\u003e\n                        Start a conversation with your friends and family\n                    \u003c/Text\u003e\n                \u003c/View\u003e\n            \u003c/ScrollView\u003e\n        \u003c/SafeAreaView\u003e\n    );\n};\n\nexport default Chat;\n```\n\n\u003c/details\u003e\n\n### Other\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ccode\u003estore/index.ts\u003c/code\u003e\u003c/summary\u003e\n\n```ts\nimport {create} from \"zustand\";\n\nimport {DriverStore, LocationStore, MarkerData} from \"@/types/type\";\n\nexport const useLocationStore = create\u003cLocationStore\u003e((set) =\u003e ({\n    userLatitude: null,\n    userLongitude: null,\n    userAddress: null,\n    destinationLatitude: null,\n    destinationLongitude: null,\n    destinationAddress: null,\n    setUserLocation: ({\n                          latitude,\n                          longitude,\n                          address,\n                      }: {\n        latitude: number;\n        longitude: number;\n        address: string;\n    }) =\u003e {\n        set(() =\u003e ({\n            userLatitude: latitude,\n            userLongitude: longitude,\n            userAddress: address,\n        }));\n\n        // If driver is selected and now a new location is set, clear the selected driver\n        const {selectedDriver, clearSelectedDriver} = useDriverStore.getState();\n        if (selectedDriver) clearSelectedDriver();\n    },\n\n    setDestinationLocation: ({\n                                 latitude,\n                                 longitude,\n                                 address,\n                             }: {\n        latitude: number;\n        longitude: number;\n        address: string;\n    }) =\u003e {\n        set(() =\u003e ({\n            destinationLatitude: latitude,\n            destinationLongitude: longitude,\n            destinationAddress: address,\n        }));\n\n        // If driver is selected and now a new location is set, clear the selected driver\n        const {selectedDriver, clearSelectedDriver} = useDriverStore.getState();\n        if (selectedDriver) clearSelectedDriver();\n    },\n}));\n\nexport const useDriverStore = create\u003cDriverStore\u003e((set) =\u003e ({\n    drivers: [] as MarkerData[],\n    selectedDriver: null,\n    setSelectedDriver: (driverId: number) =\u003e\n        set(() =\u003e ({selectedDriver: driverId})),\n    setDrivers: (drivers: MarkerData[]) =\u003e set(() =\u003e ({drivers})),\n    clearSelectedDriver: () =\u003e set(() =\u003e ({selectedDriver: null})),\n}));\n```\n\n\u003c/details\u003e\n\n## \u003ca name=\"links\"\u003e🔗 Links\u003c/a\u003e\n\nYou can find important links mentioned in the YouTube video below:\n\n- \u003ca href=\"https://www.nativewind.dev/quick-starts/expo\" target=\"_blank\"\u003eExpo NativeWind Setup\u003c/a\u003e\n- \u003ca href=\"https://www.nativewind.dev/v4/getting-started/typescript\" target=\"_blank\"\u003eTypeScript Support for\n  NativeWind\u003c/a\u003e\n- \u003ca href=\"https://docs.expo.dev/guides/using-eslint/\" target=\"_blank\"\u003eEslint and Prettier Setup\u003c/a\u003e\n- \u003ca href=\"https://jb.gg/JSMastery\" target=\"_blank\"\u003eDownload FREE WebStorm\u003c/a\u003e\n- \u003ca href=\"https://neon.tech/\" target=\"_blank\"\u003eServerless NeonDB\u003c/a\u003e\n- \u003ca href=\"https://go.clerk.com/DtiSBEI\" target=\"_blank\"\u003eClerk Auth\u003c/a\u003e\n- \u003ca href=\"https://courses.jsmastery.pro/course/databases\" target=\"_blank\"\u003eDatabase Mastery Course\u003c/a\u003e\n- \u003ca href=\"https://clerk.com/docs/quickstarts/expo\" target=\"_blank\"\u003eClerk Expo Quickstart\u003c/a\u003e\n- \u003ca href=\"https://clerk.com/docs/custom-flows/oauth-connections\" target=\"_blank\"\u003eClerk Expo OAuth\u003c/a\u003e\n- \u003ca href=\"https://www.geoapify.com/\" target=\"_blank\"\u003eGeoapify Map\u003c/a\u003e\n- \u003ca href=\"https://docs.stripe.com/payments/accept-a-payment?platform=react-native\u0026ui=payment-sheet\" target=\"_blank\"\u003e\n  Stripe React Native SDK\u003c/a\u003e\n- \u003ca href=\"https://docs.stripe.com/payments/accept-a-payment-deferred\" target=\"_blank\"\u003eStripe\u003c/a\u003e\n\n## \u003ca name=\"assets\"\u003e📦 Assets\u003c/a\u003e\n\nAssets used in the project can be\nfound [here](https://drive.google.com/file/d/1ekttG-aCyy4g0SKqLSrEn_uHf2MJMRJ4/view?usp=sharing)\n\n## \u003ca name=\"more\"\u003e🚀 More\u003c/a\u003e\n\n**Advance your skills with Next.js 14 Pro Course**\n\nEnjoyed creating this project? Dive deeper into our PRO courses for a richer learning adventure. They're packed with\ndetailed explanations, cool features, and exercises to boost your skills. Give it a go!\n\n\u003ca href=\"https://jsmastery.pro/next14\" target=\"_blank\"\u003e\n\u003cimg src=\"https://github.com/sujatagunale/EasyRead/assets/151519281/557837ce-f612-4530-ab24-189e75133c71\" alt=\"Project Banner\"\u003e\n\u003c/a\u003e\n\n\u003cbr /\u003e\n\u003cbr /\u003e\n\n**Accelerate your professional journey with the Expert Training program**\n\nAnd if you're hungry for more than just a course and want to understand how we learn and tackle tech challenges, hop\ninto our personalized masterclass. We cover best practices, different web skills, and offer mentorship to boost your\nconfidence. Let's learn and grow together!\n\n\u003ca href=\"https://www.jsmastery.pro/masterclass\" target=\"_blank\"\u003e\n\u003cimg src=\"https://github.com/sujatagunale/EasyRead/assets/151519281/fed352ad-f27b-400d-9b8f-c7fe628acb84\" alt=\"Project Banner\"\u003e\n\u003c/a\u003e\n\n#","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FRainerNsa%2FDryve","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FRainerNsa%2FDryve","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FRainerNsa%2FDryve/lists"}