# Project export: SlugPool

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: CruzHacks 2024
- Tagline: Helping Slugs ride together!
- Devpost: https://devpost.com/software/slugpool
- GitHub: https://github.com/ch4xm/SlugPool
- Team: 4 GitHub contributor(s) — Ch4zm (44 commits), Daksh Shah (32 commits), Sean Singh (20 commits), Srinidhi Srinivasan (7 commits)

## Devpost submission (written by the team)

### Inspiration

For the past few quarters, we have personally dealt with and seen a lot of students struggling to find a mode of transportation back home. There would be constant Reddit posts asking if there was someone going to their hometown that could give them a ride, and many people around us kept asking if there was a way for us to give them a ride back home. Some of ourselves have often utilized this economical method of transportation as we live quite close to each other. We knew that this was a big problem for fellow Slugs, so we created SlugPool, a ride-sharing app built specifically for UC Santa Cruz.

### What it does

There are two main parts that SlugPool implements. One is a list of carpool drivers that are available. It’s stylized in a cell format that includes the driver’s name, phone number, how many seats they have, where they’re coming from, where they’re going to, and how much they charge for gas (if applicable). The user can register to carpool others by using the “+” button on the right of the navigation screen and filling in the necessary details. The second part is a map that shows exactly where whichever carpool driver you choose is so that you’re prepared and not left clueless as to where they may be.

### How we built it

We created our app using React Native, a JS framework for cross-platform mobile app development. We used GitHub to synchronize our changes and work together efficiently.

### Challenges we ran into

One of the main challenges we ran into was working with React.js. It was a beginner's experience for all of us because we weren’t used to that framework, so it took some time to learn and get comfortable with. Once we had that down, however, making the project became a lot smoother. Getting the map view and location permissions working also took some time. We also struggled a bit with database authentication

### Accomplishments we're proud of

One of the main accomplishments we’re proud of is actually building this app. Considering, like mentioned before, it was kind of a beginner’s experience for all of us, we made a very good amount of progress. In addition, one of our other main accomplishments was implementing an icon tracker that happened to be a hand drawn slug. That definitely took some time but it was something we got working, and we’re glad we got it working because it really adds the UCSC touch to the project.

### What we learned

Through creating our app, we learned valuable skills such as how to use the React Native platform to create a basic app, as well as using a navigation map widget. We learned how to create custom UI components and a tab bar for navigation, as well as combine everything to make a seamless app. Furthermore, we learned how to dynamically create a list of items sourced from a database/local storage.

### What's next

SlugLoop has a lot of potential for the future. There are many things we did not have time to implement. One thing we hope to implement is allowing users to select a pickup location by simply dragging a marker to the location. Another goal of ours is simple UI improvements in order to make the UX flow better. We also plan on creating simple chat functionality so people can chat through the app if they prefer.

## README (from the GitHub repository)


Run `npm install` inside the project directory to automatically install the required node modules.

## Detected evidence (automated analysis)

Indexed codebase: 9 recognized source files, 23 KB.
- Firebase (technology) — detected in the code
- JavaScript (language) — detected in the code
- React (technology) — detected in the code

## Codebase structure (from repository index)

### Files (14 of 14)

```
.env
.gitignore
App.js
app.json
babel.config.js
eas.json
metro.config.js
package.json
README.md
scripts/Context.js
scripts/firebase_auth.js
scripts/firebase_db.js
scripts/firebase_initialize.js
scripts/local_storage.js
```

### Dependencies

- package.json: @babel/core@^7.20.0, @react-native-async-storage/async-storage@1.21.0, @react-native-firebase/app@^18.7.3, @react-navigation/bottom-tabs@^6.5.11, @react-navigation/native@^6.1.9, @react-navigation/native-stack@^6.9.17, @react-navigation/stack@^6.3.20, crypto@^1.0.1, dotenv@^16.3.2, expo@^50.0.2, expo-location@~16.5.2, expo-status-bar@~1.11.1, firebase@^10.7.2, os@^0.1.2, path@^0.12.7, react@18.2.0, react-native@0.73.2, react-native-firebase@^5.6.0, react-native-geolocation-service@^5.3.1, react-native-gesture-handler@^2.14.1, react-native-get-location@^4.0.1, react-native-maps@1.8.0, react-native-safe-area-context@^4.8.2, react-native-screens@~3.29.0

### Recent commits (newest first)

- fix button not showing
- Merge branch 'master' of github.com:ch4xm/SlugPool
- fix the adding carpool thing, thank you daksh for changing random things
- Merge branch 'master' of github.com:ch4xm/SlugPool
- fixed thingy
- Merge branch 'master' of github.com:ch4xm/SlugPool
- i
- Merge branch 'master' of github.com:ch4xm/SlugPool
- merged
- Merge branch 'master' of github.com:ch4xm/SlugPool
- add marker dragging
- i
- merged
- i
- adding carpools works
- Merge branch 'master' of github.com:ch4xm/SlugPool
- add draggable marker
- Merge branch 'master' of github.com:ch4xm/SlugPool
- idfk
- Merge branch 'master' of github.com:ch4xm/SlugPool

## Key source files (fetched from GitHub, selected and truncated for size)

### package.json

```
{
  "name": "slugpool",
  "version": "1.0.0",
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web"
  },
  "dependencies": {
    "@react-native-async-storage/async-storage": "1.21.0",
    "@react-native-firebase/app": "^18.7.3",
    "@react-navigation/bottom-tabs": "^6.5.11",
    "@react-navigation/native": "^6.1.9",
    "@react-navigation/native-stack": "^6.9.17",
    "@react-navigation/stack": "^6.3.20",
    "crypto": "^1.0.1",
    "dotenv": "^16.3.2",
    "expo": "^50.0.2",
    "expo-location": "~16.5.2",
    "expo-status-bar": "~1.11.1",
    "firebase": "^10.7.2",
    "os": "^0.1.2",
    "path": "^0.12.7",
    "react": "18.2.0",
    "react-native": "0.73.2",
    "react-native-firebase": "^5.6.0",
    "react-native-geolocation-service": "^5.3.1",
    "react-native-gesture-handler": "^2.14.1",
    "react-native-get-location": "^4.0.1",
    "react-native-maps": "1.8.0",
    "react-native-safe-area-context": "^4.8.2",
    "react-native-screens": "~3.29.0"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0"
  },
  "private": true
}

```

### App.js

```javascript
import { StatusBar } from 'expo-status-bar';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { FlatList, Pressable, StyleSheet, Text, View, Image, TouchableHighlight, Modal, TextInput } from 'react-native';
import MapView, { Marker} from 'react-native-maps';
import { Ionicons } from '@expo/vector-icons';
// import GetLocation from 'react-native-get-location'
import * as Location from 'expo-location';
import React, { useState, useEffect } from 'react';
//react navigation
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { createStackNavigator } from '@react-navigation/stack';
import { NavigationContainer, useRoute, useNavigation } from '@react-navigation/native';
import AsyncStorage from '@react-native-async-storage/async-storage';

import { ScrollView } from 'react-native-gesture-handler';

import { addCarpool } from './scripts/local_storage';
import { removeCarpool } from './scripts/local_storage';



const Tab = createBottomTabNavigator();


function BottomNavigator() {

  return (
    <Tab.Navigator>
      <Tab.Screen name='Map' component={MapScreen} options={{ headerShown: false, tabBarLabel: "Home", tabBarIcon: ({ color, size }) => (<Ionicons name="home" color={color} size={size} />), }}></Tab.Screen>
      <Tab.Screen name='Carpool' component={CarpoolScreen} options={{ tabBarLabel: "Active Carpools", tabBarIcon: ({ color, size }) => (<Ionicons name="car" color={color} size={size} />), }}></Tab.Screen>
    </Tab.Navigator>
  )
}

const PermissionsRequesterScreen = () => {
  const navigation = useNavigation();
  const route = useRoute();

  const [location, setLocation] = useState(null);
  const [errorMsg, setErrorMsg] = useState(null);

  const requestLocation = async () => {
    let { status } = await Location.requestForegroundPermissionsAsync();
    if (status !== 'granted') {
      setErrorMsg('Permission to access location was denied');
      return;
    }

    let location = await Location.getCurrentPositionAsync({});
    setLocation(location);
    console.log("location: " + location.coords.latitude + ", " + location.coords.longitude);
    navigation.navigate('home', { screen: 'Map', params: { latitude1: location.coords.latitude, longitude1: location.coords.longitude } });
  };

  let text = 'Waiting..';
  if (errorMsg) {
    text = errorMsg;
  } else if (location) {
    text = JSON.stringify(location);
  }

  return (
    <View style={styles.container}>
      <Text>Permissions Requester</Text>
      <Text>Location: {text}</Text>
      <Pressable onPress={requestLocation} style={styles.button}>
        <Text>Request location</Text>
      </Pressable>
    </View>
  );
}

const requestLocation = () => {
  const [location, setLocation] = useState(null);
  const [errorMsg, setErrorMsg] = useState(null);

  useEffect(() => {
    (async () => {

      let { status } = await Location.requestForegroundPermissionsAsync();
      if (status !== 'granted') {
        setErrorMsg('Permission to access location was denied');
        return;
      }

      let location = await Location.getCurrentPositionAsync({});
      setLocation(location);
      console.log("location: " + location.coords.latitude + ", " + location.coords.longitude);
    })();
  }, []);

  let text = 'Waiting..';
  if (errorMsg) {
    text = errorMsg;
  } else if (location) {
    text = JSON.stringify(location);
    navigation.navigate('home', { latitude: location.coords.latitude, longitude: location.coords.longitude });
  }
};

// const Map = () => {
//   const [pin, setPin] = useState({
//     latitude: 37.78825,
//     longitude: -122.4324,
//   });

//   return (
//     <MapView>
//       <Marker
//         draggable
//         coordinate={pin}
//         onDragEnd={e => {
//           setPin(e.nativeEvent.coordinate);
//         }} />
//     </MapView>
//   );
// };

function MapScreen({ route }) {
  const insets = useSafeAreaInsets();
  const [settingsVisible, setSettingsVisible] = useState(false);
  const [modalVisible, setModalVisible] = useState(false);
  const [location, setLocation] = useState(null);
  const [region, setRegion] = useState({
    latitude: 36.99285817795091, // default values
    longitude: -122.0601453639741,
    latitudeDelta: 0.0922,
    longitudeDelta: 0.0421,
  });

  const [markers, setMarkers] = useState([
    { key: '1', coordinate: { latitude: 36.997581997695235, longitude: -122.05199753503847 } },
    { key: '2', coordinate: { latitude: 36.97509991759613, longitude: -122.05207727758082 } },
    // Add more markers as needed
  ]);

  // const [markerPosition, setMarkerPosition] = useState({
  //   latitude: 37.78825,
  //   longitude: -122.4324,
  // });
  
  // Function to add a new marker
  const addMarker = (newCoordinate) => {
    const newMarker = {
      key: markers.length.toString(), // Assign a unique key
      coordinate: newCoordinate,
    };

    setMarkers([...markers, newMarker]);
  };

  useEffect(() => {
    var intervalCount = 0;
    const maxIterations = 5;
    

    const fetchLocation = async () => {
      let { status } = await Location.requestForegroundPermissionsAsync();
      if (status === 'granted') {
        let fetchedLocation = await Location.getCurrentPositionAsync();
        setLocation(fetchedLocation.coords);
        setRegion({
          latitude: fetchedLocation.coords.latitude,
          longitude: fetchedLocation.coords.longitude,
          latitudeDelta: 0.0922,
          longitudeDelta: 0.0421,
        });
      }

      intervalCount += 1;
      if (intervalCount >= maxIterations) {
        clearInterval(intervalId);
      }
    };

    const intervalId = setInterval(fetchLocation, 500); // Fetch location every 2.5 seconds

    return () => clearInterval(intervalId); // Cleanup interval on component unmount
  }, []);

  const onRegionChange = (region) => {
    console.log(region)
  }

  const [ Username, SetUsername ] 
[truncated — 9796 more characters]
```

### babel.config.js

```javascript
module.exports = function(api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
  };
};

```

### metro.config.js

```javascript
const { getDefaultConfig } = require('@expo/metro-config');

const defaultConfig = getDefaultConfig(__dirname);
defaultConfig.resolver.sourceExts.push('cjs');

module.exports = defaultConfig;

```

### scripts/firebase_initialize.js

```javascript
//firebase
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";

const firebaseConfig = {
  apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
  authDomain: "slugpool-cruzhacks24.firebaseapp.com",
  projectId: "slugpool-cruzhacks24",
  storageBucket: "slugpool-cruzhacks24.appspot.com",
  messagingSenderId: "1057846058539",
  appId: "1:1057846058539:web:0c8ccc6e592fa1fe0fd46e"
};

const app = initializeApp(firebaseConfig);

export const auth = getAuth(app);
```

### scripts/firebase_auth.js

```javascript
import {
    signInWithPopup,
    GoogleAuthProvider,
    signOut,
    onAuthStateChanged
} from "firebase/auth";
import {auth} from "./firebase_initialize";
import { resolveUri } from "expo-asset/build/AssetSources";

const AuthContext = createContext();
export const AuthContextProvider = ( { children } ) => {
    const GoogleSignIn = () => {
        const provider = GoogleAuthProvider();
        signInWithPopup(auth, provider)
            .then((result) => {
                const credential = GoogleAuthProvider.credentialFromResult(result);
                const token = credential.accessToken;

                
            }).catch((error) => {
                const errorCode = error.code;
                const errorMessage = error.message;
                const email = error.customData.email;
                const credential = GoogleAuthProvider.credentialFromError(error);
            });
    };

    const SignOut = () => {
        signOut(auth);
    }

    return(
        <AuthContext.Provider value={ { GoogleLogIn, SignOut, User } }>
            { children }
        </AuthContext.Provider>
    )

}

export const UserAuth = () => {
    return useContext( AuthContext );
}

export default GoogleSignIn;
```

### scripts/firebase_db.js

```javascript
import {auth} from "./firebase_initialize";

const db = getFirestore(app);
function CreateCarpool() {
    const [pickup, setPickup] = useState('');
    const [dropoff, setDropoff] = useState('');
    const [capacity, setCapacity] = useState('');
    const [date, setDate] = useState('');
    const [time, setTime] = useState('');
    const [phone, setPhone] = useState('');
    const [car, setCar] = useState('');

    const setCarpool = async(event) => {
        event.preventDefault();
    
        if(pickup === '' || dropoff === '' || capacity === '' || date === '' || time === '' || phone === '' || car === '') {
            alert("Please fill out all fields");
            return;
        }

        const {uid, displayName} = auth.currentUser;

        await addDoc(collection(db, "carpools"), {
            displayName: displayName,
            pickup: pickup,
            dropoff: dropoff,
            capacity: capacity,
            date: date,
            time: time,
            phone: phone,
            car: car,
            uid: uid,
        });

        
    
    }
}

// //pickup place, dropoff place, capacity, date, time, contact info, car description
// const DeleteCarpool = async(event) => {
//     event.preventDefault();

//     if()
// }

// const JoinCarpool = async(event) => {
// }

// const LeaveCarpool = async(event) => {
// }
```

### scripts/local_storage.js

```javascript
import AsyncStorage from "@react-native-async-storage/async-storage";

export const addCarpool = (value) => {
    //username, pickup place, dropoff place, capacity, date, time, contact info, car description
    const data = {
        username: value[0],
        pickup: value[1],
        dropoff: value[2],
        capacity: value[3],
        date: value[4],
        time: value[5],
        contactInfo: value[6],
        car: value[7],
        passengerArr: value[8]
    }
    AsyncStorage.setItem(value[0], JSON.stringify(data));
}

export const addPassenger = (carpool_username, passenger) => {
    let tmp = AsyncStorage.getItem(JSON.parse(carpool_username));

    if (tmp.passengerArr.includes(passenger)) {
        console.log('Passenger is already in the carpool group');
    } else if (tmp.passengerArr.length >= tmp.capacity) {
        console.log('Carpool is full');
    } else {
        tmp.passengerArr.push(passenger);
    }

    AsyncStorage.setItem(carpool_username, JSON.stringify(tmp));
}

export const removeCarpool = async (username, cInfo) => {
    if(await AsyncStorage.getItem(username) != null && await AsyncStorage.getItem(username).contactInfo == cInfo) {
        await AsyncStorage.removeItem(username);
    }
}

export const removePassenger = (carpool_username, passenger) => {
    let tmp = AsyncStorage.getItem(JSON.parse(carpool_username));

    tmp.passengerArr = tmp.passengerArr.filter(item => item !== passenger);

    AsyncStorage.setItem(carpool_username, JSON.stringify(tmp));
}

```

### scripts/Context.js

```javascript
import { useEffect, useState } from "react";
import { useContext } from "react";
import { createContext } from "react";


import { signOut } from "firebase/auth";
import { signInWithPopup } from "firebase/auth";
import { GoogleAuthProvider } from "firebase/auth";
import { onAuthStateChanged } from "firebase/auth";

import { auth } from "./Firebase";
import { auth2 } from "./Firebase";

import { db } from "./Firebase";

const AuthContext = createContext();

var a;

export const AuthContextProvider = ( { children } ) => {
    const[ User, setUser ] = useState();

    const [ UserID, SetUserID ] = useState();

    const GoogleLogIn = () => {
        const provider = new GoogleAuthProvider();
        signInWithPopup( auth, provider )
          .then((result) => {
            // This gives you a Google Access Token. You can use it to access the Google API.
            const credential = GoogleAuthProvider.credentialFromResult(result);
            const token = credential.accessToken;
            
            // The signed-in user info.
            const user = result.user;
            // IdP data available using getAdditionalUserInfo(result)

            console.log( user.uid );

            a = user.uid;

            console.log( user.uid );

            localStorage.setItem( "UserID", user.uid );
            localStorage.setItem( "UserName", user.displayName );
            localStorage.setItem( "UserEmail", user.email );

            // ...
        }).catch((error) => {
          // Handle Errors here.
          const errorCode = error.code;
          const errorMessage = error.message;
          // The email of the user's account used.
          const email = error.customData.email;
          // The AuthCredential type that was used.
          const credential = GoogleAuthProvider.credentialFromError(error);
          // ...
        });
      
    }


    const SignOut = () => {
        signOut( auth );
    }
  
    useEffect(() => {
      const unsub = onAuthStateChanged( auth, ( currentUser ) => {
        setUser( currentUser );
        console.log( 'User', currentUser )
      } );
      
      return () => {
        unsub();
      };
    }, []);

    return(
        <AuthContext.Provider value={ { GoogleLogIn, SignOut, User } }>
            { children }
        </AuthContext.Provider>
    )
}

export const UserAuth = () => {
    return useContext( AuthContext );
}

export { a };
```