# Project export: Eatinerary

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: Cal Hacks 10.0
- Tagline: What you want to eat tonight
- Devpost: https://devpost.com/software/eatinerary
- GitHub: https://github.com/EggsInAJar/Cal-Hacks-10.0
- Team: 4 GitHub contributor(s) — CandymanAndy (18 commits), EggsInAJar (6 commits), “Sreeram (6 commits), Zaimanator64 (1 commits)

## Devpost submission (written by the team)

### Inspiration

"What do you want to eat tonight?" A timeless question that we seek to answer.

### What it does

Using preferences and history, we intelligently suggest places, new and old, that we're sure our users will enjoy.

### How we built it

Convex DB and backend using OpenAI, React/JS frontend using Google Maps API.

### Challenges we ran into

Convex was a steep learning curve for us. The Google Maps API didn't work with React, so we had to jerry rig some vanilla JS instead.

### Accomplishments we're proud of

Being able to efficiently parallelize work in some cases, and work together to get over difficulty working with new technology.

### What we learned

Besides all the ideas and technologies we got to explore, we also learned a lot from the really talented students/judges around us.

### What's next

Our website cuts corners in a lot of places. We will next flesh this out, improve on our restaurant selection algorithm, and finish our social functionality.

## README (from the GitHub repository)

No README available.

## Detected evidence (automated analysis)

Indexed codebase: 49 recognized source files, 75 KB.
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- OpenAI (technology) — detected in the code
- React (technology) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (57 of 57)

```
.env.local
.gitignore
convex/_generated/api.d.ts
convex/_generated/api.js
convex/_generated/dataModel.d.ts
convex/_generated/server.d.ts
convex/_generated/server.js
my-app/.env
my-app/.eslintrc.cjs
my-app/.gitignore
my-app/convex/_generated/api.d.ts
my-app/convex/_generated/api.js
my-app/convex/_generated/dataModel.d.ts
my-app/convex/_generated/server.d.ts
my-app/convex/_generated/server.js
my-app/convex/auth.config.js
my-app/convex/controllers/chatgpt_controllers.ts
my-app/convex/controllers/dalle_controllers.ts
my-app/convex/controllers/profile_controllers.ts
my-app/convex/controllers/suggestions_controllers.js
my-app/convex/findRestaurants.js
my-app/convex/helpers/dalle_helpers.ts
my-app/convex/helpers/profile_helpers.ts
my-app/convex/helpers/suggestions_helpers.ts
my-app/convex/preferences/general.js
my-app/convex/README.md
my-app/convex/restaurants.js
my-app/convex/routes/dalle_routes.ts
my-app/convex/routes/profile_routes.ts
my-app/convex/routes/suggestions_routes.ts
my-app/convex/schema.ts
my-app/convex/tasks.js
my-app/convex/tsconfig.json
my-app/convex/users/general.js
my-app/convex/users/preferences.js
my-app/index.html
my-app/package.json
my-app/README.md
my-app/sampleData.jsonl
my-app/src/App.css
my-app/src/App.jsx
my-app/src/badge.js
my-app/src/components/profileDropdown.css
my-app/src/components/profileDropdown.jsx
my-app/src/components/restaurantcard.css
my-app/src/components/restaurantcard.jsx
my-app/src/components/RestaurantMap.css
my-app/src/components/RestaurantMap.jsx
my-app/src/components/RestaurantMapOLD.jsx
my-app/src/index.css
my-app/src/main.jsx
my-app/src/pages/Friends.jsx
my-app/src/pages/Home.jsx
my-app/src/pages/NoPage.jsx
my-app/src/pages/Preferences.css
my-app/src/pages/Preferences.jsx
my-app/vite.config.js
```

### Dependencies

- my-app/package.json: @clerk/clerk-react@^4.27.1, @types/node@^20.8.9, @types/react@^18.2.15, @types/react-dom@^18.2.7, @vitejs/plugin-react@^4.0.3, bootstrap@^5.3.2, convex@^1.5.1, eslint@^8.45.0, eslint-plugin-react@^7.32.2, eslint-plugin-react-hooks@^4.6.0, eslint-plugin-react-refresh@^0.4.3, fetch@^1.1.0, million@^2.6.4, node-fetch@^3.3.2, openai@^4.14.1, react@^18.2.0, react-bootstrap@^2.9.1, react-dom@^18.2.0, react-router-dom@^6.17.0, ts-node@^10.9.1, typescript@^5.2.2, vite@^4.4.5

### Recent commits (newest first)

- Merge pull request #5 from EggsInAJar/preference-algorithm
- Integrating card frontend to backend
- Removed node_modules directory
- Merged main into branch
- Added query to get user preferences. Added basic action with OpenAI set up
- Merge pull request #4 from EggsInAJar/uifixes
- ui bugs
- Merge branch 'main' into uifixes
- fixing merge conflicts
- ui cleanup and food board base implementation
- Fixed getUserPreferences integration
- Delete node_modules directory
- Maybe fixed?
- Preferences route completed
- Merge branch 'main' of https://github.com/EggsInAJar/Cal-Hacks-10.0
- Updates to controllers
- Merge pull request #3 from EggsInAJar/Merrick-functions
- Merged main into this branch
- ui fixes from previous and routes set up
- travis scott

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

### my-app/package.json

```
{
  "name": "my-app",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
    "preview": "vite preview"
  },
  "dependencies": {
    "@clerk/clerk-react": "^4.27.1",
    "@types/node": "^20.8.9",
    "bootstrap": "^5.3.2",
    "convex": "^1.5.1",
    "fetch": "^1.1.0",
    "node-fetch": "^3.3.2",
    "openai": "^4.14.1",
    "million": "^2.6.4",
    "react": "^18.2.0",
    "typescript": "^5.2.2",
    "react-bootstrap": "^2.9.1",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.17.0"
  },
  "devDependencies": {
    "@types/react": "^18.2.15",
    "@types/react-dom": "^18.2.7",
    "@vitejs/plugin-react": "^4.0.3",
    "eslint": "^8.45.0",
    "eslint-plugin-react": "^7.32.2",
    "eslint-plugin-react-hooks": "^4.6.0",
    "eslint-plugin-react-refresh": "^0.4.3",
    "ts-node": "^10.9.1",
    "vite": "^4.4.5"
  }
}

```

### my-app/src/main.jsx

```javascript
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./index.css";
import { ConvexReactClient } from "convex/react";
import { ClerkProvider, useAuth } from "@clerk/clerk-react";
import { ConvexProviderWithClerk } from "convex/react-clerk";
import { Authenticated, Unauthenticated } from "convex/react";
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import Preferences from './pages/Preferences'
import Friends from './pages/Friends'
import NoPage from './pages/NoPage'

const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL);

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <BrowserRouter>
      <ClerkProvider publishableKey="pk_test_bmVlZGVkLWh5ZW5hLTY3LmNsZXJrLmFjY291bnRzLmRldiQ">
        <ConvexProviderWithClerk client={convex} useAuth={useAuth}>
          <Routes>
            {/* <Authenticated> */}
              <Route index element={<App />} />
              <Route path="/home" element = {<App />} />
              <Route path="/preferences" element={<Preferences />} />
              <Route path="/friends" element={<Friends />} />
              <Route path="*" element={<NoPage />} />
            {/* </Authenticated> */}
          </Routes>
        </ConvexProviderWithClerk>
      </ClerkProvider>
    </BrowserRouter>
  </React.StrictMode>
);
```

### 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.5.1.
 * 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;

```

### my-app/src/App.jsx

```javascript
import { useEffect, useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
import './components/profileDropdown.css';
import { useQuery } from "convex/react";
import { useAction } from "convex/react";
import { api } from "../convex/_generated/api";
import { SignInButton, SignOutButton } from "@clerk/clerk-react";
import { useConvexAuth } from "convex/react";
import { useUser } from "@clerk/clerk-react";
import { Authenticated, Unauthenticated, AuthLoading } from "convex/react";
import RestaurantCard from './components/restaurantcard';
import RestaurantImage from './assets/restaurant.jpg';
import RestaurantMap from "./components/RestaurantMap";
import ProfileDropdown from './components/profileDropdown';

function App() {
  const { isLoading, isAuthenticated } = useConvexAuth();
  const { user } = useUser();

  const tasks = useQuery(api.tasks.get);
  const findRestaurants = useAction(api.findRestaurants.findRestaurants);
  const getPreferredRestaurants = useAction(api.controllers.suggestions_controllers.getPreferredRestaurants);

  const [restaurants, setRestaurants] = useState([]);
  const [cardInfo, setCardInfo] = useState([]);
  const [count, setCount] = useState(0)
  const [location, setLocation] = useState({})


  useEffect(() => {
    // Get User Location
    navigator.geolocation.getCurrentPosition(
      (position) => {
        const pos = {
          lat: position.coords.latitude,
          lng: position.coords.longitude,
        };
        setLocation(pos);
      },
      () => {
        // Handle location error
        console.error('Error getting location');
        setLocation({}); // Set default location to empty
      }
    );

    console.log(getPreferredRestaurants({user_id: "4efwrqe9gpmhxew40rcqqctm9k5zecg"}))
  }, []);

  useEffect(() => {
    // Find Restaurants Based on Location
    async function fetchData() {
      const result = await findRestaurants({location: `${location.lat}, ${location.lng}`, radius: 500});
      setRestaurants(result);
      console.log(result)
    }
    fetchData();
  }, [location]);

  useEffect(() => {
    console.log('entered')
    let card = [];
    for (let i = 0; i < restaurants.length; i++) {
      let temp = {name: restaurants[i].name};

      try {
      const photoReference = restaurants[i].photos[0].photo_reference;
      console.log(photoReference)
      const maxWidth = 200;  // You can specify the desired width of the image
      
      temp.image = `https://maps.googleapis.com/maps/api/place/photo?maxwidth=${maxWidth}&photoreference=${photoReference}&key=AIzaSyC2Lp98v2BVcvGfVTKA3SUYqIrED86_F6E`;
      } catch (error) {
        temp.image = RestaurantImage;
      }

      temp.description = restaurants[i].vicinity;

      temp.cuisine = "$".repeat(restaurants[i].price_level);

      card.push(temp);
    }
    setCardInfo(card);
    console.log(card)
  }, [restaurants]);

  const sampleData = [
    {
      name: 'The Fancy Fork',
      cuisine: 'Italian',
      description: 'An exquisite Italian experience with a modern twist!',
      image: RestaurantImage,
    },
    {
      name: 'Sushi Hub',
      cuisine: 'Japanese',
      description: 'Fresh and authentic sushi crafted by experienced chefs.',
      image: RestaurantImage,
    },
    {
      name: 'Curry Palace',
      cuisine: 'Indian',
      description: 'Aromatic Indian dishes that bring the flavors of the East.',
      image: RestaurantImage,
    },
    {
      name: 'Cur Pal',
      cuisine: 'Indi',
      description: 'Aromatic dishes that bring the flavors of the East.',
      image: RestaurantImage,
    },
    {
      name: 'The Fancy Fork',
      cuisine: 'Italian',
      description: 'An exquisite Italian experience with a modern twist!',
      image: RestaurantImage,
    },
    {
      name: 'Sushi Hub',
      cuisine: 'Japanese',
      description: 'Fresh and authentic sushi crafted by experienced chefs.',
      image: RestaurantImage,
    },
    {
      name: 'Curry Palace',
      cuisine: 'Indian',
      description: 'Aromatic Indian dishes that bring the flavors of the East.',
      image: RestaurantImage,
    },
    {
      name: 'Cur Pal',
      cuisine: 'Indi',
      description: 'Aromatic dishes that bring the flavors of the East.',
      image: RestaurantImage,
    },
  ];

  return (
    <div>
     {/* <Authenticated>
        <div>
          <a href="https://vitejs.dev" target="_blank">
            <img src={viteLogo} className="logo" alt="Vite logo" />
          </a>
          <a href="https://react.dev" target="_blank">
            <img src={reactLogo} className="logo react" alt="React logo" />
          </a>
        </div>

        <h1>Vite + React</h1>
        <div className="card">
          <button onClick={() => setCount((count) => count + 1)}>
            count is {count}
          </button>
          <p>
            Edit <code>src/App.jsx</code> and save to test HMR
          </p>
        </div>
        <p className="read-the-docs">
          Click on the Vite and React logos to learn more
        </p>
      </Authenticated> */}


      <Authenticated>
        <div className = "mapBackground">
          <RestaurantMap location={location} restaurants={restaurants}></RestaurantMap>
        </div>
        <div className='parent'>
          <div className='leftSide'>
            <div className='scroll'>
              {cardInfo.map((item, index) => (
                <RestaurantCard key={index} item={item} />
              ))}
            </div>
          </div>
        <div className = 'rightSide'></div>
        <div className = 'spacer'>
          
        </div>

        </div>
      </Authenticated>

     <div className="App">
      <Unauthenticated>
        <div className="unauthtitle">
          Eatinerary
          <SignInButton>
            <button className="signInButton">
              Sign In
            </button>
          </SignInButton> 
        <header className="App-header"
[truncated — 795 more characters]
```

### my-app/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.5.1.
 * 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;

```

### my-app/vite.config.js

```javascript
import million from 'million/compiler';
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [million.vite({ auto: true }), react()],
})

```

### my-app/index.html

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Eatinerary | Find Places to Eat!</title>
    <script defer
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyC2Lp98v2BVcvGfVTKA3SUYqIrED86_F6E">
    </script>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html>

```

### my-app/convex/auth.config.js

```javascript
export default {
    providers: [
      {
        domain: "https://needed-hyena-67.clerk.accounts.dev/",
        applicationID: "convex",
      },
    ]
  };
```

### my-app/src/badge.js

```javascript
import { useUser } from "@clerk/clerk-react";

export default function Badge() {
  const { user } = useUser();
  return <span>Logged in as {user.fullName}</span>;
}
```

### my-app/convex/tasks.js

```javascript
import { query } from "./_generated/server";

export const get = query({
  args: {},
  handler: async (ctx) => {
    return await ctx.db.query("tasks").collect();
  },
});
```

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