# Project export: Recipeer

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: TreeHacks 2024
- Tagline: Make sustainable recipes with your friends!
- Devpost: https://devpost.com/software/recipeer-1vatje
- GitHub: https://github.com/gracelhu/Recipeer
- Video: https://www.youtube.com/embed/cTsCJhTmOHY?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — mariacemo (12 commits), neozoid (5 commits), Grace Hu (1 commits)

## Devpost submission (written by the team)

### Inspiration

Recipeer was designed with two purposes in mind: We wanted to encourage sustainability by reusing ingredients that would otherwise go to waste. We also wanted to bring people together through food

### What it does

Recipeer is a mobile app to make ingredients by combining recipes from you and your friends. After logging in, the user is prompted to upload a photo from their phone's camera roll, and AI scans the image for ingredients. The user's info and ingredients are used to create their profile, which they can use to connect with other people on the platform. Users can create events, where they can invite their friends and use AI to generate meal ideas based on the combinations of the ingredient each people has in stock.

### How we built it

As Recipeer is designed as a mobile app, we developed the front end using React Native. For our backend, where we stored ingredients, recipes, and users, we used Convex. Finally, we used Gemini's API for AI calls, both for image transcription and as a text transformer.

### Accomplishments we're proud of

We really stepped out of our comfort zones and completed this application using 2 technologies that we had no previous experience with: React Native and Convex. It was fascinating hearing about all the innovative tech here at the hackathon, and we wanted to try it out ourselves- so we decided on Convex for backend! One of our members attended the pre-hackathon mobile app workshop, which helped us kickstart our React Native journey this weekend! It has been a one of a kind learning experience! Challenges and what we learned Coding after flying in from out of state is hard! Might be easier to come in a day early. It took our team some time to settle on a solid wireframe of our idea - the extra time from the bullet point above might help with that. The scope of our project involved making a full-stack application - in the future, it might be good to find ways to tighten the scope for smoother development.

## README (from the GitHub repository)

## See our DevPost: <br>
https://devpost.com/software/recipeer-1vatje

## Inspiration <br>
Recipeer was designed with two purposes in mind:
1. We wanted to encourage sustainability by reusing ingredients that would otherwise go to waste.
2. We also wanted to bring people together through food

## What it does <br>
Recipeer is a mobile app to make ingredients by combining recipes from you and your friends. After logging in, the user is prompted to upload a photo from their phone's camera roll, and AI scans the image for ingredients. The user's info and ingredients are used to create their profile, which they can use to connect with other people on the platform. Users can create events, where they can invite their friends and use AI to generate meal ideas based on the combinations of the ingredient each people has in stock.

## How we built it <br>
As Recipeer is designed as a mobile app, we developed the front end using React Native. For our backend, where we stored ingredients, recipes, and users, we used Convex. Finally, we used Gemini's API for AI calls, both for image transcription and as a text transformer.

## Youtube Demo <br>
https://www.youtube.com/watch?v=cTsCJhTmOHY

## Tools & Technologies <br>
Gemini API, React Native, Convex


## Detected evidence (automated analysis)

Indexed codebase: 26 recognized source files, 73 KB.
- CSS (language) — detected in the code
- Google Gemini (technology) — detected in the code
- JavaScript (language) — detected in the code
- React (technology) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (34 of 34)

```
README.md
treehacks/.gitignore
treehacks/App.js
treehacks/app.json
treehacks/assets/fonts/Pretendard-ExtraBold.otf
treehacks/assets/fonts/Pretendard-Regular.otf
treehacks/assets/fonts/Pretendard-SemiBold.otf
treehacks/babel.config.js
treehacks/convex/_generated/api.d.ts
treehacks/convex/_generated/api.js
treehacks/convex/_generated/dataModel.d.ts
treehacks/convex/_generated/server.d.ts
treehacks/convex/_generated/server.js
treehacks/convex/convex_functions.js
treehacks/convex/README.md
treehacks/convex/tsconfig.json
treehacks/index.css
treehacks/navigator/BottomNavigation.js
treehacks/package.json
treehacks/react-native.config.js
treehacks/screens/CreateEvent.js
treehacks/screens/Events.js
treehacks/screens/Login.js
treehacks/screens/Profile.js
treehacks/screens/RadioButtonImage.js
treehacks/screens/RecipeGenerator.js
treehacks/screens/Recipes.js
treehacks/screens/SavedRecipes.js
treehacks/screens/scrapcode.txt
treehacks/screens/Search.js
treehacks/screens/Settings.js
treehacks/screens/Signup.js
treehacks/screens/UploadPic_NotSetup.js
treehacks/screens/UploadPic_Setup.js
```

### Dependencies

- treehacks/package.json: @babel/core@^7.20.0, @google/generative-ai@^0.2.1, @react-native-community/datetimepicker@7.6.1, @react-navigation/bottom-tabs@^6.5.12, @react-navigation/native@^6.1.12, @react-navigation/native-stack@^6.9.18, convex@^1.9.0, devlop@^1.1.0, expo@~50.0.7, expo-font@~11.10.3, expo-image-picker@~14.7.1, expo-status-bar@~1.11.1, formik@^2.4.5, react@18.2.0, react-datetime-picker@^5.6.0, react-dom@^18.2.0, react-markdown@^9.0.1, react-native@0.73.4, react-native-date-picker@^4.3.6, react-native-dotenv@^3.4.10, react-native-get-random-values@^1.10.0, react-native-image-picker@^7.1.0, react-native-markdown-display@^7.0.2, react-native-pager-view@6.2.3, react-native-paper@^5.12.3, react-native-paper-tabs@^0.10.4, react-native-safe-area-context@4.8.2, react-native-screens@~3.29.0, react-native-tab-view@^3.5.2, remarkable@^2.0.1

### Recent commits (newest first)

- modified CreateEvent page
- much progress
- added fetching allergies convex function + changed default profile pic + displayed friends & allergies in table on profile
- added a cute little ingredient list edit button
- displayed ingredient list on user profile
- modified convex database scheme
- changed profile icon :D
- created userInfo context variable
- added 3 pretty buttons on profile page :D
- added feature where user can change their profile pic!
- made basic settings page
- added touchable settings icon to user profile
- added RecipeGenerator page, styled user profile more, added arrows in CreateEvent
- added more error message checkers in create account page
- added conditionals to handleCreateUser func
- fixed handleCreateUser bug
- app now writes user credentials to convex db
- wrote createUser convex function
- little arrow CSS changes
- throw 'passwords don't match' for sign up page

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

### treehacks/package.json

```
{
  "name": "treehacks",
  "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": {
    "@google/generative-ai": "^0.2.1",
    "@react-native-community/datetimepicker": "7.6.1",
    "@react-navigation/bottom-tabs": "^6.5.12",
    "@react-navigation/native": "^6.1.12",
    "@react-navigation/native-stack": "^6.9.18",
    "convex": "^1.9.0",
    "devlop": "^1.1.0",
    "expo": "~50.0.7",
    "expo-font": "~11.10.3",
    "expo-image-picker": "~14.7.1",
    "expo-status-bar": "~1.11.1",
    "formik": "^2.4.5",
    "react": "18.2.0",
    "react-datetime-picker": "^5.6.0",
    "react-dom": "^18.2.0",
    "react-markdown": "^9.0.1",
    "react-native": "0.73.4",
    "react-native-date-picker": "^4.3.6",
    "react-native-dotenv": "^3.4.10",
    "react-native-get-random-values": "^1.10.0",
    "react-native-image-picker": "^7.1.0",
    "react-native-markdown-display": "^7.0.2",
    "react-native-pager-view": "6.2.3",
    "react-native-paper": "^5.12.3",
    "react-native-paper-tabs": "^0.10.4",
    "react-native-safe-area-context": "4.8.2",
    "react-native-screens": "~3.29.0",
    "react-native-tab-view": "^3.5.2",
    "remarkable": "^2.0.1"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0"
  },
  "private": true
}

```

### treehacks/App.js

```javascript
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import React, { createContext, useState } from 'react';
import {NavigationContainer} from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import BottomNavigation from './navigator/BottomNavigation';
import Login from './screens/Login';
import Signup from './screens/Signup';
import UploadPic_Setup from './screens/UploadPic_Setup';
import UploadPic_NotSetup from './screens/UploadPic_NotSetup';
import CreateEvent from './screens/CreateEvent';
import Events from './screens/Events';
import Recipes from './screens/Recipes';
import { ConvexProvider, ConvexReactClient } from "convex/react";
import "react-native-get-random-values";
import { CONVEX_URL } from "@env";
import Settings from './screens/Settings';
import Search from './screens/Search';


const convex = new ConvexReactClient(CONVEX_URL, {
  unsavedChangesWarning: false,
});

const Stack = createNativeStackNavigator();

export const UserContext = createContext();

export default function App() {
  const [userInfo, setUserInfo] = 
  useState({ username: '', password: '', email: '', allergies: [], ingredients: [], events: [], usernamesOfFriends: []});
  return (
    <UserContext.Provider value={{ userInfo, setUserInfo }}>
    <ConvexProvider client={convex}>
      <NavigationContainer>
      <Stack.Navigator screenOptions={{headerShown: false}}>
          <Stack.Screen name="login">
             {(props) => <Login {...props}/>}
            </Stack.Screen>
          <Stack.Screen name="signup">
            {(props) => <Signup {...props}/>}
          </Stack.Screen>
          <Stack.Screen name="upload">
              {(props) => <UploadPic_Setup {...props}/>}
            </Stack.Screen> 
          <Stack.Screen name="upload_notsetup">
              {(props) => <UploadPic_NotSetup {...props}/>}
          </Stack.Screen> 
          <Stack.Screen name="dashboard">
            {(props) => <BottomNavigation {...props}/>  }
            </Stack.Screen> 
          <Stack.Screen name="createevent" component={CreateEvent} />
          <Stack.Screen name="recipes" component={Recipes} />
          <Stack.Screen name="events" component={Events} />
          <Stack.Screen name="settings" component={Settings}></Stack.Screen>
          <Stack.Screen name="search" component={Search}></Stack.Screen>
      </Stack.Navigator>
    </NavigationContainer>
    </ConvexProvider>
    </UserContext.Provider>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'pink',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

```

### treehacks/convex/_generated/server.js

```javascript
/* eslint-disable */
/**
 * Generated utilities for implementing server-side Convex query and mutation functions.
 *
 * THIS CODE IS AUTOMATICALLY GENERATED.
 *
 * Generated by convex@1.9.0.
 * To regenerate, run `npx convex dev`.
 * @module
 */

import {
  actionGeneric,
  httpActionGeneric,
  queryGeneric,
  mutationGeneric,
  internalActionGeneric,
  internalMutationGeneric,
  internalQueryGeneric,
} from "convex/server";

/**
 * Define a query in this Convex app's public API.
 *
 * This function will be allowed to read your Convex database and will be accessible from the client.
 *
 * @param func - The query function. It receives a {@link QueryCtx} as its first argument.
 * @returns The wrapped query. Include this as an `export` to name it and make it accessible.
 */
export const query = queryGeneric;

/**
 * Define a query that is only accessible from other Convex functions (but not from the client).
 *
 * This function will be allowed to read from your Convex database. It will not be accessible from the client.
 *
 * @param func - The query function. It receives a {@link QueryCtx} as its first argument.
 * @returns The wrapped query. Include this as an `export` to name it and make it accessible.
 */
export const internalQuery = internalQueryGeneric;

/**
 * Define a mutation in this Convex app's public API.
 *
 * This function will be allowed to modify your Convex database and will be accessible from the client.
 *
 * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
 * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
 */
export const mutation = mutationGeneric;

/**
 * Define a mutation that is only accessible from other Convex functions (but not from the client).
 *
 * This function will be allowed to modify your Convex database. It will not be accessible from the client.
 *
 * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
 * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
 */
export const internalMutation = internalMutationGeneric;

/**
 * Define an action in this Convex app's public API.
 *
 * An action is a function which can execute any JavaScript code, including non-deterministic
 * code and code with side-effects, like calling third-party services.
 * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive.
 * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.
 *
 * @param func - The action. It receives an {@link ActionCtx} as its first argument.
 * @returns The wrapped action. Include this as an `export` to name it and make it accessible.
 */
export const action = actionGeneric;

/**
 * Define an action that is only accessible from other Convex functions (but not from the client).
 *
 * @param func - The function. It receives an {@link ActionCtx} as its first argument.
 * @returns The wrapped function. Include this as an `export` to name it and make it accessible.
 */
export const internalAction = internalActionGeneric;

/**
 * Define a Convex HTTP action.
 *
 * @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object
 * as its second.
 * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`.
 */
export const httpAction = httpActionGeneric;

```

### treehacks/react-native.config.js

```javascript
module.exports = {
    project: {
      ios: {},
      android: {},
    },
    assets: ['./assets/fonts'],
  };
```

### treehacks/babel.config.js

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


```

### treehacks/index.css

```css
/*@font-face {
    font-family: 'Pretendard SemiBold';
    src: url('./Pretendard-SemiBold.otf') format('otf');
  } */

  @font-face {
    font-family: 'Pretendard ExtraBold';
    src: url('./Pretendard-ExtraBold.otf') format('opentype');
  }
```

### treehacks/screens/Search.js

```javascript
import { View, Text} from 'react-native'
import React from 'react'

const Search = () => {
    return (
        <View>
            <Text>Hello wotld</Text>
        </View>
    )
}

export default Search;
```

### treehacks/screens/SavedRecipes.js

```javascript
import React from 'react';
import { View, Text } from 'react-native';

const SavedRecipes = () => {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Saved Recipes</Text>
    </View>
  );
};

export default SavedRecipes;

```

### treehacks/screens/RecipeGenerator.js

```javascript
import React from 'react';
import { View, Text } from 'react-native';

const RecipeGenerator = () => {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Recipe Generator</Text>
    </View>
  );
};

export default RecipeGenerator;

```

### treehacks/screens/RadioButtonImage.js

```javascript
import React, { useState } from 'react';
import { View, TouchableOpacity, Image, Text } from 'react-native';

const RadioButtonImage = ({
  imageUrl,
  onPress,
  value,
  selectedValue,
  disabled,
  imageStyle,
  textStyle,
}) => {
  const [isSelected, setIsSelected] = useState(value === selectedValue);

  const handlePress = () => {
    if (!disabled && onPress) {
      onPress(value);
      setIsSelected(!isSelected);
    }
  };

  const opacity = isSelected ? 0.5 : 1;

  return (
    <TouchableOpacity onPress={handlePress} disabled={disabled}>
      <View style={{ flexDirection: 'row', alignItems: 'center' }}>
        <Image source={{ uri: imageUrl }} style={[{ opacity }, imageStyle]} />
        {textStyle && <Text style={textStyle}>{value}</Text>}
      </View>
    </TouchableOpacity>
  );
};

export default RadioButtonImage;

```

[15 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]