diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 88f220f..d7f224a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing to Ember -***Thank you for considering contributing to Ember!*** +**_Thank you for considering contributing to Ember!_** We welcome contributions from the community to help us make this project even better and more impactful. Whether you're a developer, designer, writer, or have other skills, your input is valuable. diff --git a/README.md b/README.md index e9c23ca..ab4833d 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,32 @@ # Ember -***A Carbon Footprint App with Monetisation Strategies*** +**_A Carbon Footprint App with Monetisation Strategies_** ![designs](assets/designs.png) - Welcome to Ember, your all-in-one platform for sustainable living. -- We offer eco-friendly transit solutions, gamified sustainability challenges, a thriving community hub, incentives for green actions, a green marketplace, and carbon offset options. + +- We offer eco-friendly transit solutions, gamified sustainability challenges, a thriving community hub, incentives for green actions, a green marketplace, and carbon offset options. - Our monetization strategies include advertisements, coupons, an eco-products marketplace, and location-based services. -***Join us in the movement towards a greener future today!*** +**_Join us in the movement towards a greener future today!_** ### Mechanism + ![Mechanism](assets/mechanism.png) ### Technology Stack + - Frontend: React-Native, TailwindCSS - Backend: django REST - Machine Learning: PyTorch - ### Reference- Problem Statement + Urban areas face challenges like traffic congestion, air pollution, and carbon emissions due to increased private vehicle usage. + - To promote eco-friendly transportation options (walking, biking, carpooling, public transit), we need an innovative mobile app that uses gamification and social elements to motivate users, reduce private car dependence, and create -sustainable cities. + sustainable cities. - Daily challenges, leaderboards, and a supportive community foster engagement, while real-time incentives, optimized route planning, and carbon footprint tracking enhance the experience and environmental impact awareness. - With an intuitive interface and seamless integration, the application must -revolutionize urban commuting habits for greener, healthier, and vibrant spaces. - - + revolutionize urban commuting habits for greener, healthier, and vibrant spaces. diff --git a/client/App.js b/client/App.js index e67ec25..8298d42 100644 --- a/client/App.js +++ b/client/App.js @@ -1,6 +1,6 @@ -import React from 'react'; -import Navigation from './components/Navigation'; +import React from 'react' +import Navigation from './components/Navigation' export default function App() { - return ; -} \ No newline at end of file + return +} diff --git a/client/app.config.js b/client/app.config.js index 98a8a42..93eaa68 100644 --- a/client/app.config.js +++ b/client/app.config.js @@ -1,41 +1,40 @@ -import "dotenv/config"; +import 'dotenv/config' export default { - "expo": { - "name": "client", - "slug": "client", - "version": "1.0.0", - "orientation": "portrait", - "icon": "./assets/ember.jpeg", - "userInterfaceStyle": "light", - "splash": { - "image": "./assets/ember.jpeg", - "resizeMode": "contain", - "backgroundColor": "#ffffff" + expo: { + name: 'client', + slug: 'client', + version: '1.0.0', + orientation: 'portrait', + icon: './assets/ember.jpeg', + userInterfaceStyle: 'light', + splash: { + image: './assets/ember.jpeg', + resizeMode: 'contain', + backgroundColor: '#ffffff' }, - "assetBundlePatterns": [ - "**/*" - ], - "ios": { - "supportsTablet": true + assetBundlePatterns: ['**/*'], + ios: { + supportsTablet: true }, - "android": { - "adaptiveIcon": { - "foregroundImage": "./assets/ember.jpeg", - "backgroundColor": "#ffffff" + android: { + adaptiveIcon: { + foregroundImage: './assets/ember.jpeg', + backgroundColor: '#ffffff' } }, - "web": { - "favicon": "./assets/ember.jpeg" + web: { + favicon: './assets/ember.jpeg' }, - "plugins": [ + plugins: [ [ - "expo-image-picker", + 'expo-image-picker', { - "photosPermission": "The app accesses your photos to let you share them with your friends." + photosPermission: + 'The app accesses your photos to let you share them with your friends.' } ] ], - "extra": { + extra: { apiKey: process.env.API_KEY, authDomain: process.env.AUTH_DOMAIN, projectId: process.env.PROJECT_ID, diff --git a/client/babel.config.js b/client/babel.config.js index 98ac332..8cff467 100644 --- a/client/babel.config.js +++ b/client/babel.config.js @@ -1,7 +1,7 @@ module.exports = function (api) { - api.cache(true); + api.cache(true) return { - presets: ["babel-preset-expo"], - plugins: ["nativewind/babel", "react-native-reanimated/plugin"], - }; -}; + presets: ['babel-preset-expo'], + plugins: ['nativewind/babel', 'react-native-reanimated/plugin'] + } +} diff --git a/client/components/Navigation.js b/client/components/Navigation.js index 4debdcd..1b523c1 100644 --- a/client/components/Navigation.js +++ b/client/components/Navigation.js @@ -1,10 +1,10 @@ -import React from 'react'; -import { useAuth } from '../hooks/useAuth'; -import UserStack from './userStack'; -import AuthStack from './authStack'; +import React from 'react' +import { useAuth } from '../hooks/useAuth' +import UserStack from './userStack' +import AuthStack from './authStack' export default function Navigation() { - const { user } = useAuth(); + const { user } = useAuth() - return user ? : ; -} \ No newline at end of file + return user ? : +} diff --git a/client/components/authStack.js b/client/components/authStack.js index 24a8b18..7aad19b 100644 --- a/client/components/authStack.js +++ b/client/components/authStack.js @@ -1,33 +1,33 @@ -import React from 'react'; -import { NavigationContainer } from '@react-navigation/native'; -import { createStackNavigator } from '@react-navigation/stack'; +import React from 'react' +import { NavigationContainer } from '@react-navigation/native' +import { createStackNavigator } from '@react-navigation/stack' -import HomeScreen from "../screens/HomeScreen"; -import Login from "../screens/Login"; -import Signup from "../screens/Signup"; +import HomeScreen from '../screens/HomeScreen' +import Login from '../screens/Login' +import Signup from '../screens/Signup' -const Stack = createStackNavigator(); +const Stack = createStackNavigator() export default function AuthStack() { - return ( - - - - - - - - ); - } + return ( + + + + + + + + ) +} diff --git a/client/components/userStack.js b/client/components/userStack.js index ff04e7b..a5dadc8 100644 --- a/client/components/userStack.js +++ b/client/components/userStack.js @@ -1,53 +1,51 @@ -import React from 'react'; -import { NavigationContainer } from '@react-navigation/native'; -import { createStackNavigator } from '@react-navigation/stack'; +import React from 'react' +import { NavigationContainer } from '@react-navigation/native' +import { createStackNavigator } from '@react-navigation/stack' -import Dashboard from '../screens/Dashboard'; -import TransitScreen from '../screens/TransitScreen'; -import Profile from '../screens/Profile'; -import Statistics from '../screens/Statistics'; -import Chat from '../screens/Chat'; -import Post from '../screens/Post'; +import Dashboard from '../screens/Dashboard' +import TransitScreen from '../screens/TransitScreen' +import Profile from '../screens/Profile' +import Statistics from '../screens/Statistics' +import Chat from '../screens/Chat' +import Post from '../screens/Post' -const Stack = createStackNavigator(); +const Stack = createStackNavigator() export default function UserStack() { - return ( - - - - - - - - - - - - ); - } - \ No newline at end of file + return ( + + + + + + + + + + + ) +} diff --git a/client/firebaseConfig.js b/client/firebaseConfig.js index 63813fd..ca414e6 100644 --- a/client/firebaseConfig.js +++ b/client/firebaseConfig.js @@ -1,8 +1,8 @@ -import { initializeApp } from "firebase/app"; -import { getAuth } from "firebase/auth"; -import { getFirestore } from "firebase/firestore"; -import Constants from "expo-constants"; -import { getStorage } from "firebase/storage"; +import { initializeApp } from 'firebase/app' +import { getAuth } from 'firebase/auth' +import { getFirestore } from 'firebase/firestore' +import Constants from 'expo-constants' +import { getStorage } from 'firebase/storage' const firebaseConfig = { apiKey: Constants.expoConfig.extra.apiKey, @@ -10,10 +10,10 @@ const firebaseConfig = { projectId: Constants.expoConfig.extra.projectId, storageBucket: Constants.expoConfig.extra.storageBucket, messagingSenderId: Constants.expoConfig.extra.messagingSenderId, - appId: Constants.expoConfig.extra.appId, -}; + appId: Constants.expoConfig.extra.appId +} -initializeApp(firebaseConfig); -export const auth = getAuth(); -export const database = getFirestore(); -export const storage= getStorage(); \ No newline at end of file +initializeApp(firebaseConfig) +export const auth = getAuth() +export const database = getFirestore() +export const storage = getStorage() diff --git a/client/hooks/useAuth.js b/client/hooks/useAuth.js index d672092..d2cd332 100644 --- a/client/hooks/useAuth.js +++ b/client/hooks/useAuth.js @@ -1,26 +1,26 @@ -import React, { useEffect,useState } from "react"; -import { getAuth, onAuthStateChanged, User } from "firebase/auth"; -import { auth } from "../firebaseConfig"; +import React, { useEffect, useState } from 'react' +import { getAuth, onAuthStateChanged, User } from 'firebase/auth' +import { auth } from '../firebaseConfig' export function useAuth() { - const [user, setUser] = useState(); + const [user, setUser] = useState() useEffect(() => { const unsubscribeFromAuthStateChanged = onAuthStateChanged(auth, (user) => { if (user) { // User is signed in, see docs for a list of available properties // https://firebase.google.com/docs/reference/js/firebase.User - setUser(user); + setUser(user) } else { // User is signed out - setUser(undefined); + setUser(undefined) } - }); + }) - return unsubscribeFromAuthStateChanged; - }, []); + return unsubscribeFromAuthStateChanged + }, []) return { - user, - }; -} \ No newline at end of file + user + } +} diff --git a/client/metro.config.js b/client/metro.config.js index 948c810..7ff83b8 100644 --- a/client/metro.config.js +++ b/client/metro.config.js @@ -1,6 +1,6 @@ -const { getDefaultConfig } = require('@expo/metro-config'); +const { getDefaultConfig } = require('@expo/metro-config') -const defaultConfig = getDefaultConfig(__dirname); -defaultConfig.resolver.sourceExts.push('cjs'); +const defaultConfig = getDefaultConfig(__dirname) +defaultConfig.resolver.sourceExts.push('cjs') -module.exports = defaultConfig; +module.exports = defaultConfig diff --git a/client/screens/Chat.js b/client/screens/Chat.js index 7e90604..17f6f4e 100644 --- a/client/screens/Chat.js +++ b/client/screens/Chat.js @@ -1,41 +1,36 @@ -import React, { - useState, - useEffect, - useLayoutEffect, - useCallback, -} from "react"; -import { TouchableOpacity, Text, View, StyleSheet } from "react-native"; +import React, { useState, useEffect, useLayoutEffect, useCallback } from 'react' +import { TouchableOpacity, Text, View, StyleSheet } from 'react-native' import { GiftedChat, Bubble, InputToolbar, - Send, -} from "react-native-gifted-chat"; + Send +} from 'react-native-gifted-chat' import { collection, addDoc, orderBy, query, - onSnapshot, -} from "firebase/firestore"; -import { signOut } from "firebase/auth"; -import { auth, database } from "../firebaseConfig"; -import { useNavigation } from "@react-navigation/native"; -import { AntDesign } from "@expo/vector-icons"; -import moment from "moment"; + onSnapshot +} from 'firebase/firestore' +import { signOut } from 'firebase/auth' +import { auth, database } from '../firebaseConfig' +import { useNavigation } from '@react-navigation/native' +import { AntDesign } from '@expo/vector-icons' +import moment from 'moment' export default function Chat() { - const [messages, setMessages] = useState([]); - const navigation = useNavigation(); + const [messages, setMessages] = useState([]) + const navigation = useNavigation() const onSignOut = () => { - signOut(auth).catch((error) => console.log("Error logging out: ", error)); - }; + signOut(auth).catch((error) => console.log('Error logging out: ', error)) + } useLayoutEffect(() => { navigation.setOptions({ headerRight: () => ( - + - ), - }); - }, [navigation]); + ) + }) + }, [navigation]) useLayoutEffect(() => { - const collectionRef = collection(database, "chats"); - const q = query(collectionRef, orderBy("createdAt", "desc")); + const collectionRef = collection(database, 'chats') + const q = query(collectionRef, orderBy('createdAt', 'desc')) const unsubscribe = onSnapshot(q, (querySnapshot) => { - console.log("querySnapshot unsubscribe"); + console.log('querySnapshot unsubscribe') setMessages( querySnapshot.docs.map((doc) => ({ _id: doc.data()._id, createdAt: doc.data().createdAt.toDate(), text: doc.data().text, - user: doc.data().user, + user: doc.data().user })) - ); - }); - return unsubscribe; - }, []); + ) + }) + return unsubscribe + }, []) const onSend = useCallback((messages = []) => { setMessages((previousMessages) => GiftedChat.append(previousMessages, messages) - ); + ) - const { _id, createdAt, text, user } = messages[0]; - addDoc(collection(database, "chats"), { + const { _id, createdAt, text, user } = messages[0] + addDoc(collection(database, 'chats'), { _id, createdAt, text, - user, - }); - }, []); + user + }) + }, []) const renderBubble = (props) => { const formattedTime = moment(props.currentMessage.createdAt).format( - "h:mm A" - ); + 'h:mm A' + ) return ( {props.currentMessage.text} {formattedTime} - ); - }; + ) + } return ( onSend(messages)} messagesContainerStyle={{ - backgroundColor: "#EEE7E1", - borderRadius: 20, + backgroundColor: '#EEE7E1', + borderRadius: 20 }} textInputStyle={{ - backgroundColor: "white", + backgroundColor: 'white', borderRadius: 20, paddingHorizontal: 12, marginTop: 6, borderWidth: 0.5, - borderColor: "grey", + borderColor: 'grey' }} renderInputToolbar={(props) => ( )} renderBubble={renderBubble} user={{ _id: auth?.currentUser?.email, - avatar: "https://i.pravatar.cc/700", + avatar: 'https://i.pravatar.cc/700' }} /> - ); + ) } const styles = StyleSheet.create({ bubble: { padding: 15, borderRadius: 15, - backgroundColor: "#f0f0f0", + backgroundColor: '#f0f0f0' }, rightBubble: { - backgroundColor: "#EDFFE0", + backgroundColor: '#EDFFE0' }, timeText: { fontSize: 10, - color: "#888", - marginTop: 3, - }, -}); + color: '#888', + marginTop: 3 + } +}) diff --git a/client/screens/Dashboard.js b/client/screens/Dashboard.js index 1c174bb..8f9f211 100644 --- a/client/screens/Dashboard.js +++ b/client/screens/Dashboard.js @@ -152,16 +152,14 @@ const Dashboard = ({ navigation }) => { - navigation.navigate('Post')} - > - - Create Post + navigation.navigate('Post')}> + + Create Post diff --git a/client/screens/HomeScreen.js b/client/screens/HomeScreen.js index 3921eea..8f5a06d 100644 --- a/client/screens/HomeScreen.js +++ b/client/screens/HomeScreen.js @@ -1,53 +1,53 @@ -import React from "react"; -import { View, Text, TouchableOpacity, Image } from "react-native"; -import { useNavigation } from "@react-navigation/native"; +import React from 'react' +import { View, Text, TouchableOpacity, Image } from 'react-native' +import { useNavigation } from '@react-navigation/native' export default function HomeScreen() { - const navigation = useNavigation(); + const navigation = useNavigation() const handleLoginPress = () => { - navigation.navigate("Login"); - }; + navigation.navigate('Login') + } return ( - + ember - + Get Started {/* */} - ); + ) } diff --git a/client/screens/Image.js b/client/screens/Image.js index 3ba1983..6c7fc5a 100644 --- a/client/screens/Image.js +++ b/client/screens/Image.js @@ -1,95 +1,105 @@ -import React, { useState, useEffect } from 'react'; -import { View, Text, TextInput, TouchableOpacity, Image, StyleSheet, Alert,Platform,Button } from 'react-native'; -import { getDoc, setDoc, doc } from 'firebase/firestore'; -import { auth, database, storage } from '../firebaseConfig'; -import { AntDesign } from '@expo/vector-icons'; -import { useNavigation } from '@react-navigation/native'; -import * as ImagePicker from "expo-image-picker"; -import * as FileSystem from 'expo-file-system'; +import React, { useState, useEffect } from 'react' +import { + View, + Text, + TextInput, + TouchableOpacity, + Image, + StyleSheet, + Alert, + Platform, + Button +} from 'react-native' +import { getDoc, setDoc, doc } from 'firebase/firestore' +import { auth, database, storage } from '../firebaseConfig' +import { AntDesign } from '@expo/vector-icons' +import { useNavigation } from '@react-navigation/native' +import * as ImagePicker from 'expo-image-picker' +import * as FileSystem from 'expo-file-system' export default function ImageUpload() { - const [image, setImage] = useState(null); - const [uploading, setUploading] = useState(false); - const navigation = useNavigation(); // Initialize the useNavigation hook + const [image, setImage] = useState(null) + const [uploading, setUploading] = useState(false) + const navigation = useNavigation() - const pickImage = async () => { - // No permissions request is necessary for launching the image library - let result = await ImagePicker.launchImageLibraryAsync({ - mediaTypes: ImagePicker.MediaTypeOptions.All, - allowsEditing: true, - aspect: [4, 3], - quality: 1, - }); - - console.log(result); - - if (!result.canceled) { - setImage(result.assets[0].uri); - } - }; - - const uploadImage = async () => { - setUploading(true); - try { + const pickImage = async () => { + // No permissions request is necessary for launching the image library + let result = await ImagePicker.launchImageLibraryAsync({ + mediaTypes: ImagePicker.MediaTypeOptions.All, + allowsEditing: true, + aspect: [4, 3], + quality: 1 + }) + + console.log(result) + + if (!result.canceled) { + setImage(result.assets[0].uri) + } + } - const uri= await FileSystem.getInfoAsync(image); - const blob = await new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest(); - xhr.onload = function() { - resolve(xhr.response); - }; - xhr.onerror = function(e) { - console.log(e); - reject(new TypeError("Network request failed")); - }; - xhr.responseType = "blob"; - xhr.open("GET", uri, true); - xhr.send(null); - }); - const fileName = image.substring(image.lastIndexOf('/') + 1); - const ref = storage.ref().child(fileName); - const snapshot = await ref.put(blob); - setUploading(false); - Alert.alert("Success"); - setImage(null); - blob.close(); + const uploadImage = async () => { + setUploading(true) + try { + const uri = await FileSystem.getInfoAsync(image) + const blob = await new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + xhr.onload = function () { + resolve(xhr.response) } - catch(err){ - console.log(err); - setUploading(false); + xhr.onerror = function (e) { + console.log(e) + reject(new TypeError('Network request failed')) } + xhr.responseType = 'blob' + xhr.open('GET', uri, true) + xhr.send(null) + }) + const fileName = image.substring(image.lastIndexOf('/') + 1) + const ref = storage.ref().child(fileName) + const snapshot = await ref.put(blob) + setUploading(false) + Alert.alert('Success') + setImage(null) + blob.close() + } catch (err) { + console.log(err) + setUploading(false) } + } - - return ( - -