# Project export: Goalseek

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: New year's resolutions are often abandoned because it is hard to schedule new habits into our busy schedules. Goalseek takes the scheduling burden off of your hands so you can focus on your growth.
- Devpost: https://devpost.com/software/goalseek
- GitHub: https://github.com/ben-mathew/goalseek
- Team: 0 GitHub contributor(s) — 

## Devpost submission (written by the team)

### Inspiration

I've personally faced challenges fully committing to lofty goals like going to the gym and lifting more. Between my own behavior and my friends', I've noticed that we are all pretty organized people. We diligently use calendars to manage our time. However, these lofty goals do not usually make it onto these calendars. There is a mental barrier here that I wanted to tackle. My thesis is that if people are told when they have time to achieve their goals, they will be more likely to achieve them.

### What it does

Users can input the name of their goal, how long the goal will take them (e.g. 30 minutes), when they'd like to work on this goal, and how often per week they would like to work on this goal. From here, these configs are sent to Google's Calendar API. We scan users' calendars for open blocks in their specified time of day and then schedule these goals.

### How we built it

React, Google Calendar API, Google Maps API, Express

### Challenges we ran into

Token management for OAuth gave us some trouble, along with converting between various datatypes based on responses from APIs

### Accomplishments we're proud of

This was my first full-stack project, so I am proud of myself for sticking through it and delivering something.

### What we learned

This project helped me get better at parsing API documentation and stitching together a wide variety of resources to help me make progress. This project also helped me better understand the importance of authentication and how tokens are handed off between parties.

### What's next

I want to do more work integrating Google Maps into the app so that scheduling can take into account the distance that needs to be traveled by people. I am also curious if this would be more successful as a Chrome extension rather than a website.

## README (from the GitHub repository)

# Getting Started with Create React App

This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).

## Available Scripts

In the project directory, you can run:

### `npm start`

Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.

The page will reload when you make changes.\
You may also see any lint errors in the console.

### `npm test`

Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.

### `npm run build`

Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.

The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!

See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.

### `npm run eject`

**Note: this is a one-way operation. Once you `eject`, you can't go back!**

If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.

Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.

You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.

## Learn More

You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).

To learn React, check out the [React documentation](https://reactjs.org/).

### Code Splitting

This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)

### Analyzing the Bundle Size

This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)

### Making a Progressive Web App

This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)

### Advanced Configuration

This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)

### Deployment

This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)

### `npm run build` fails to minify

This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)


## Detected evidence (automated analysis)

Indexed codebase: 10 recognized source files, 19 KB.
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- React (technology) — detected in the code
- Express (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (14 of 14)

```
.gitignore
package.json
public/index.html
public/manifest.json
public/robots.txt
README.md
src/App.css
src/App.js
src/App.test.js
src/components/login.js
src/index.css
src/index.js
src/reportWebVitals.js
src/setupTests.js
```

### Dependencies

- package.json: @react-oauth/google@^0.12.1, @testing-library/jest-dom@^5.17.0, @testing-library/react@^13.4.0, @testing-library/user-event@^13.5.0, axios@^1.6.7, react@^18.2.0, react-dom@^18.2.0, react-scripts@5.0.1, web-vitals@^2.1.4

### Recent commits (newest first)

- final
- creating slots
- Initialize project using Create React App

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

### package.json

```
{
  "name": "goalseek",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@react-oauth/google": "^0.12.1",
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "axios": "^1.6.7",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

```

### src/index.js

```javascript
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { GoogleOAuthProvider } from '@react-oauth/google';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <GoogleOAuthProvider clientId="880946832206-lrnd6k3itau1mgin0ohabusgc9ve3d3p.apps.googleusercontent.com">
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </GoogleOAuthProvider>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

```

### src/App.js

```javascript
// import logo from './logo.svg';
// import './App.css';

// function App() {
//   return (
//     <div className="App">
//       <header className="App-header">
//         <img src={logo} className="App-logo" alt="logo" />
//         <p>
//           Edit <code>src/App.js</code> and save to reload.
//         </p>
//         <a
//           className="App-link"
//           href="https://reactjs.org"
//           target="_blank"
//           rel="noopener noreferrer"
//         >
//           Learn React
//         </a>
//       </header>
//     </div>
//   );
// }

// export default App;

/*App.js*/

// import React from 'react';
// import { GoogleLogin } from '@react-oauth/google';

// function App() {
//     const responseMessage = (response) => {
//         console.log(response);
//     };
//     const errorMessage = (error) => {
//         console.log(error);
//     };
//     return (
//         <div>
//             <h2>React Google Login</h2>
//             <br />
//             <br />
//             <GoogleLogin onSuccess={responseMessage} onError={errorMessage} />
//         </div>
//     )
// }
// export default App;

/*App.js*/

import React, { useState, useEffect } from 'react';
import { googleLogout, useGoogleLogin } from '@react-oauth/google';
import axios from 'axios';

function App() {
    const [ user, setUser ] = useState([]);
    const [ profile, setProfile ] = useState([]);
    const [ goal, setGoal ] = useState('');
    const [ description, setDescription ] = useState('');
    const [ duration, setDuration] = useState('');
    const [ timeOfDay, setTimeOfDay ] = useState('');
    const [ recurrance, setRecurrance ] = useState('');

    const login = useGoogleLogin({
        onSuccess: (codeResponse) => setUser(codeResponse),
        onError: (error) => console.log('Login Failed:', error)
    });

    useEffect(
        () => {
            if (user) {
                axios
                    .get(`https://www.googleapis.com/oauth2/v1/userinfo?access_token=${user.access_token}`, {
                        headers: {
                            Authorization: `Bearer ${user.access_token}`,
                            Accept: 'application/json'
                        }
                    })
                    .then((res) => {
                        setProfile(res.data);
                    })
                    .catch((err) => console.log(err));
            }
        },
        [ user ]
    );

    // log out function to log the user out of google and set the profile array to null
    const logOut = () => {
        googleLogout();
        setProfile(null);
    };

    const handleSubmit = (e) => {
      e.preventDefault()
      console.log(user, profile, goal, description, duration, timeOfDay, recurrance)
    }

    async function inserisciTurni(goal, description, duration, availableTimeSlots) {
        console.log(user.access_token);
        var accessToken = user.access_token; // Please set your access token.
        var calendarioselezionato = "primary" // Please set your calendar ID.
        const start = availableTimeSlots[0].start
        console.log("STARTTT"+ start)
        const startTimeString = availableTimeSlots[0].start; // Assuming this is a date string
        const startDate = new Date(Date.parse(startTimeString));
      
        var evento = {
          "summary": goal,
        //   "summary": "hello",
          "description": description,
        //   "description": "desc",
          "start": {
            "dateTime": startTimeString,
          },
          "end": {
            "dateTime": "2024-02-18T17:00:00-08:00",
          },
        //   "recurrence": [
        //     'RRULE:FREQ=WEEKLY;COUNT=2'
        //   ]
        };
        var res = await axios.post(
          `https://www.googleapis.com/calendar/v3/calendars/${calendarioselezionato}/events`,
          JSON.stringify(evento),
          {headers: {authorization: `Bearer ${accessToken}`, "Content-Type": "application/json"}}
        );
        console.log(res.data);
        console.log("printing events this week")
        findAvailableTimeSlots()
        // getEventsForWeek()
      }

    async function getEventsForWeek() {
        const today = new Date();
        console.log("TODAY: " + today)
        const endOfWeek = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 7);
        console.log("EOW: " + endOfWeek)
        
        var accessToken = user.access_token
        var calendarId = "primary"
        const response = await axios.get(
          `https://www.googleapis.com/calendar/v3/calendars/${calendarId}/events?singleEvents=true`,
          {
            headers: { Authorization: `Bearer ${accessToken}` },
            params: {
              timeMin: today,
              timeMax: endOfWeek,
            },
            orderBy: "startTime",
            singleEvents: true
          }
        );
        
        // return response.data.items || [];
        console.log(response)
        console.log(response.data.items)
        return response.data.items
      }

      async function findAvailableTimeSlots(goal, description, duration) {
        const accessToken = user.access_token;
        const calendarId = "primary";
        const events = await getEventsForWeek(calendarId, accessToken);
        const availableTimeSlots = [];
      
        // Sort events by start time
        events.sort((a, b) => new Date(a.start.dateTime) - new Date(b.start.dateTime));
        console.log("SIZE OF EVENTS " + events.length)
      
        let previousEndTime = new Date();
        previousEndTime.setHours(6, 0, 0, 0);
      
        for (const event of events) {
          const currDate = new Date(event.start.dateTime)
          if (currDate.getDate() != previousEndTime.getDate()) { // new date, new slots
            previousEndTime = currDate;
            previousEndTime.setHours(6, 0, 0, 0);
          }
          console.log("current date " + currDate)
          console.log("previ
[truncated — 5744 more characters]
```

### src/setupTests.js

```javascript
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

```

### src/App.test.js

```javascript
import { render, screen } from '@testing-library/react';
import App from './App';

test('renders learn react link', () => {
  render(<App />);
  const linkElement = screen.getByText(/learn react/i);
  expect(linkElement).toBeInTheDocument();
});

```

### src/reportWebVitals.js

```javascript
const reportWebVitals = onPerfEntry => {
  if (onPerfEntry && onPerfEntry instanceof Function) {
    import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
      getCLS(onPerfEntry);
      getFID(onPerfEntry);
      getFCP(onPerfEntry);
      getLCP(onPerfEntry);
      getTTFB(onPerfEntry);
    });
  }
};

export default reportWebVitals;

```

### src/index.css

```css
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
    monospace;
}

```

### src/App.css

```css
.App {
  text-align: center;
}

.App-logo {
  height: 40vmin;
  pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
  .App-logo {
    animation: App-logo-spin infinite 20s linear;
  }
}

.App-header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}

.App-link {
  color: #61dafb;
}

@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

```

### public/index.html

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>
</html>

```