# Project export: Stan 4 Sustainability

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 11.0
- Tagline: Support your favorite celebrities? Save the Earth? COUNT US IN! Stan 4 Sustainability is a platform to help offset your favorite celebrities’ carbon footprint through YOUR own actions.
- Devpost: https://devpost.com/software/stan-4-sustainability
- GitHub: https://github.com/nicolemzh/calhacks-final
- Team: 3 GitHub contributor(s) — Deleena Ghosh (6 commits), mahnoor-k (2 commits), nicolemzh (1 commits)

## Devpost submission (written by the team)

### Inspiration

We're a team of three women passionate about sustainability and making a positive impact on our planet. During Cal Hacks, we wanted to build something people would enjoy using, while also promoting behavior that's good for the environment-- like recycling, walking, and taking public transportation. We were inspired by the recent controversies surrounding excessive carbon footprints of celebrities, and we know the impact of huge fanbases coming together. We decided to connect the two to help fans make a real change by reducing their own carbon footprint.

### What it does

We created a webpage that allows users to visualize the CO2 emissions of celebrities by analyzing publicly accessibly flight data. Then, we allow users to input their own data by tracking steps, distance traveled through biking or taking public transportation, and even inputting product barcodes of recyclable items. We display progress bars showing each fanbase, and how close they are to reaching their goal.

### How we built it

We built our webpage using Github, VSCode, Javascript for the backend, and React, Typescript, HTML/CSS for the frontend

### Challenges we ran into

Our limited knowledge was a challenge at first, but we came together to research APIs and learn by doing

### Accomplishments we're proud of

We're proud of our unique features, like inputting barcode data, calculating CO2 emissions from large datasets, and connecting all the components together :)

### What we learned

This is our first hackathon! We learned so much about project ideation and full-stack development through this project. It's our first time writing code in Javascript and using React, interact with new APIs, and making a fully functional webpage.

### What's next

We want to incentivize users to actually upload their data by creating raffles for concert tickets or movies for the fanbase with the most data. We also want to implement a login system and some more features to prevent individuals from uploading fake data.

## README (from the GitHub repository)

# Stan 4 Sustainability
Support your favorite celebrities? Save the Earth? COUNT US IN! Stan 4 Sustainability is a platform to help offset your favorite celebrities’ carbon footprint through YOUR own actions.

## Inspiration
We're a team of three women passionate about sustainability and making a positive impact on our planet. During Cal Hacks 11.0, we wanted to build something people would enjoy using, while also promoting behavior that's good for the environment-- like recycling, walking, and taking public transportation. We were inspired by the recent controversies surrounding excessive carbon footprints of celebrities, and we know the impact of huge fanbases coming together. We decided to connect the two to help fans make a real change by reducing their own carbon footprint.

## What it does
We created a webpage that allows users to visualize the CO2 emissions of celebrities by analyzing publicly accessibly flight data. Then, we allow users to input their own data by tracking steps, distance traveled through biking or taking public transportation, and even inputting product barcodes of recyclable items. We display progress bars showing each fanbase, and how close they are to reaching their goal.

## How we built it
We built our webpage using Javascript, Express.js, and Node.js for the backend, and React, Typescript, HTML/CSS for the frontend

## Built With
- climatiq
- openfoodfacts
- css
- html
- javascript
- json
- mjs
- opensky
- react
- typescript


## Detected evidence (automated analysis)

Indexed codebase: 29 recognized source files, 43 KB.
- CSS (language) — detected in the code
- Express (technology) — 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
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (41 of 41)

```
calhacks-flight/cal.mjs
calhacks-flight/flights.json
calhacks-flight/health-data.mjs
calhacks-flight/index.mjs
calhacks-flight/sample-data-generator.js
calhacks-flight/stats.js
calhacks-flight/user_inputs.json
my-react-app/.gitignore
my-react-app/components.json
my-react-app/eslint.config.js
my-react-app/index.html
my-react-app/package.json
my-react-app/postcss.config.js
my-react-app/README.md
my-react-app/src/App.css
my-react-app/src/App.tsx
my-react-app/src/components/celebritychart.css
my-react-app/src/components/celebritychart.tsx
my-react-app/src/components/fansubmissionform.tsx
my-react-app/src/components/navbar.css
my-react-app/src/components/navbar.tsx
my-react-app/src/components/ui/marquee.tsx
my-react-app/src/components/userchart.css
my-react-app/src/components/userchart.tsx
my-react-app/src/index.css
my-react-app/src/lib/utils.ts
my-react-app/src/main.tsx
my-react-app/src/screens/about.css
my-react-app/src/screens/about.tsx
my-react-app/src/screens/fanData.css
my-react-app/src/screens/fanData.tsx
my-react-app/src/screens/home.css
my-react-app/src/screens/home.tsx
my-react-app/src/vite-env.d.ts
my-react-app/tailwind.config.js
my-react-app/tsconfig.app.json
my-react-app/tsconfig.json
my-react-app/tsconfig.node.json
my-react-app/vite.config.ts
package.json
README.md
```

### Dependencies

- my-react-app/package.json: @emotion/react@^11.13.3, @emotion/styled@^11.13.0, @eslint/js@^9.11.1, @mui/material@^6.1.4, @radix-ui/react-icons@^1.3.0, @types/node@^22.7.7, @types/react@^18.3.10, @types/react-dom@^18.3.0, @vitejs/plugin-react@^4.3.2, autoprefixer@^10.4.20, class-variance-authority@^0.7.0, clsx@^2.1.1, eslint@^9.11.1, eslint-plugin-react-hooks@^5.1.0-rc.0, eslint-plugin-react-refresh@^0.4.12, globals@^15.9.0, lucide-react@^0.453.0, postcss@^8.4.47, react@^18.3.1, react-confetti@^6.1.0, react-dom@^18.3.1, tailwind-merge@^2.5.4, tailwindcss@^3.4.14, tailwindcss-animate@^1.0.7, typescript@^5.5.3, typescript-eslint@^8.7.0, vite@^5.4.9
- package.json: axios@^1.7.7, body-parser@^1.20.3, chart.js@^4.4.5, cheerio@^1.0.0, cors@^2.8.5, dotenv@^16.4.5, express@^4.21.1, multer@^1.4.5-lts.1, node-fetch@^3.3.2, openai@^4.68.1, react-chartjs-2@^5.2.0, react-router-dom@^6.27.0

### Recent commits (newest first)

- removed key
- removed key
- Update README.md
- Update README.md
- finished front/backend
- finished front/backend
- all user input connection
- cleaned up code:
- cleaned up code
- frontend and backend connected for fan emissions
- connected backend and frontend fan emissions
- statistics added
- fixed merge conflicts
- health data implemented
- updating the frontend
- frontend
- merging flights
- emissions calculation backend done
- Initial commit

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

### package.json

```
{

  "name": "calhacks-flight",

  "version": "1.0.0",

  "main": "index.mjs",

  "scripts": {

    "test": "echo \"Error: no test specified\" && exit 1"

  },

  "keywords": [],

  "author": "",

  "license": "ISC",

  "dependencies": {

    "axios": "^1.7.7",

    "body-parser": "^1.20.3",

    "chart.js": "^4.4.5",

    "cheerio": "^1.0.0",

    "cors": "^2.8.5",

    "dotenv": "^16.4.5",

    "express": "^4.21.1",

    "multer": "^1.4.5-lts.1",

    "node-fetch": "^3.3.2",

    "openai": "^4.68.1",

    "react-chartjs-2": "^5.2.0",

    "react-router-dom": "^6.27.0"

  },

  "description": ""

}


```

### my-react-app/package.json

```
{
  "name": "my-react-app",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "@emotion/react": "^11.13.3",
    "@emotion/styled": "^11.13.0",
    "@mui/material": "^6.1.4",
    "@radix-ui/react-icons": "^1.3.0",
    "class-variance-authority": "^0.7.0",
    "clsx": "^2.1.1",
    "lucide-react": "^0.453.0",
    "react": "^18.3.1",
    "react-confetti": "^6.1.0",
    "react-dom": "^18.3.1",
    "tailwind-merge": "^2.5.4",
    "tailwindcss-animate": "^1.0.7"
  },
  "devDependencies": {
    "@eslint/js": "^9.11.1",
    "@types/node": "^22.7.7",
    "@types/react": "^18.3.10",
    "@types/react-dom": "^18.3.0",
    "@vitejs/plugin-react": "^4.3.2",
    "autoprefixer": "^10.4.20",
    "eslint": "^9.11.1",
    "eslint-plugin-react-hooks": "^5.1.0-rc.0",
    "eslint-plugin-react-refresh": "^0.4.12",
    "globals": "^15.9.0",
    "postcss": "^8.4.47",
    "tailwindcss": "^3.4.14",
    "typescript": "^5.5.3",
    "typescript-eslint": "^8.7.0",
    "vite": "^5.4.9"
  }
}

```

### calhacks-flight/index.mjs

```
import express from 'express';
import cors from 'cors';
import fs from 'fs';

const app = express();
const port = 3000;

app.use(cors()); // cors needed so noor doesn't run into issues

app.get('/', (req, res) => {
  res.send('Welcome to the Carbon Footprint API!');
});


// mapping between celebrity and plane types
const celebToJet = {
  'TAYLOR_SWIFT': 'FALCON_7X',
  'DRAKE': 'BOEING_767',
  'TRAVIS_SCOTT': 'EMBRAER_190',
  'JAY_Z': 'CHALLENGER_850',
  'OPRAH': 'GULFSTREAM_650',
  'DR_PHIL': 'GULFSTREAM_IV',
  'JIM_CARREY': 'GULFSTREAM_V',
  'TOM_CRUISE': 'CHALLENGER_350',
};

// mapping between private jet ids and plane types
const idToJet = {
  'N621MM': 'FALCON_7X',
  'N767CJ': 'BOEING_767',
  'N713TS': 'EMBRAER_190',
  'N444SC': 'CHALLENGER_850',
  'N54QW': 'GULFSTREAM_650',
  'N4DP': 'GULFSTREAM_IV',
  'N162JC': 'GULFSTREAM_V',
  'N350XX': 'CHALLENGER_350',
};

// mapping between plane type and fuel consumption per hour * co2 constant converter
const jetEmissionRates = {
  'FALCON_7X': 1170.04 * 3.0, // note that taylor swift was manually adjusted. true constant value is 3.16.
  'BOEING_767': 3573.95 * 3.16,
  'EMBRAER_190': 1960.20 * 3.16,
  'CHALLENGER_850': 1051.52 * 3.16,
  'GULFSTREAM_650': 1528.65 * 3.16,
  'GULFSTREAM_IV': 1580.32 * 3.16,
  'GULFSTREAM_V': 1519.53 * 3.16,
  'CHALLENGER_350': 902.60 * 3.16,
};

function calculateCarbonFootprint(planeType, distance) {
  const emissionRatePerHour = jetEmissionRates[planeType];
  if (!emissionRatePerHour) {
    return 0;
  }
  const flightDuration = distance / 500;
  return emissionRatePerHour * flightDuration;
}

// coordinate distance calculations
function calculateDistance(departureCoords, arrivalCoords) {
  const R = 6371;
  const lat1 = departureCoords.latitude;
  const lon1 = departureCoords.longitude;
  const lat2 = arrivalCoords.latitude;
  const lon2 = arrivalCoords.longitude;

  const lat1Rad = lat1 * (Math.PI / 180);
  const lon1Rad = lon1 * (Math.PI / 180);
  const lat2Rad = lat2 * (Math.PI / 180);
  const lon2Rad = lon2 * (Math.PI / 180);

  const dlat = lat2Rad - lat1Rad;
  const dlon = lon2Rad - lon1Rad;

  const a =
    Math.sin(dlat / 2) * Math.sin(dlat / 2) +
    Math.cos(lat1Rad) *
      Math.cos(lat2Rad) *
      Math.sin(dlon / 2) *
      Math.sin(dlon / 2);
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

  return R * c;
}

// api information for frontend to access data
app.get('/carbon-footprint/:celebrity', async (req, res) => {
  const celebrity = req.params.celebrity.toUpperCase();

  if (!celebToJet[celebrity]) {
    return res.status(404).json({
      success: false,
      message: 'Celebrity not found',
    });
  }

  const celebJet = celebToJet[celebrity];

  const flightData = JSON.parse(fs.readFileSync('flights.json', 'utf8'));
  let totalEmissions = 0;

  for (const flight of flightData) {
    const planeId = flight.callsign;
    const distance = calculateDistance(flight.departureCoords, flight.arrivalCoords);

    const planeType = idToJet[planeId];
    if (!planeType || planeType !== celebJet) {
      continue;
    }

    const carbonFootprint = calculateCarbonFootprint(planeType, distance);
    if (!isNaN(carbonFootprint)) {
      totalEmissions += carbonFootprint;
    }
  }
  res.json({
    success: true,
    celebrity,
    totalEmissions: totalEmissions.toFixed(2), 
  });
});

// starting server
app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

```

### my-react-app/src/main.tsx

```typescript
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.tsx'
import './index.css'

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <App />
  </StrictMode>,
)

```

### my-react-app/src/App.tsx

```typescript
import { useState } from 'react'
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Home from './screens/home';
import About from './screens/about'; 
import FanData from './screens/fanData'; 
import NavBar from './components/navbar'; 
import './App.css'

function App() {
  const [count, setCount] = useState(0)

  return (
    <>
    <div>
      <Router>
        <NavBar />
        <Routes>
          <Route path="/home" element={<Home />} />
          <Route path="/about" element={<About />} />
          <Route path="/fandata" element={<FanData />} />
        </Routes>
      </Router>
    </div>
    </>
  )
}

export default App

```

### my-react-app/postcss.config.js

```javascript
export default {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}

```

### my-react-app/vite.config.ts

```typescript
import path from "path"
import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"
 
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
})
```

### my-react-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>Vite + React + TS</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

```

### my-react-app/eslint.config.js

```javascript
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'

export default tseslint.config(
  { ignores: ['dist'] },
  {
    extends: [js.configs.recommended, ...tseslint.configs.recommended],
    files: ['**/*.{ts,tsx}'],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
    },
    plugins: {
      'react-hooks': reactHooks,
      'react-refresh': reactRefresh,
    },
    rules: {
      ...reactHooks.configs.recommended.rules,
      'react-refresh/only-export-components': [
        'warn',
        { allowConstantExport: true },
      ],
    },
  },
)

```

### my-react-app/tailwind.config.js

```javascript
/** @type {import('tailwindcss').Config} */
export default {
    darkMode: ["class"],
    content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
  	extend: {
  		borderRadius: {
  			lg: 'var(--radius)',
  			md: 'calc(var(--radius) - 2px)',
  			sm: 'calc(var(--radius) - 4px)'
  		},
  		colors: {
  			background: 'hsl(var(--background))',
  			foreground: 'hsl(var(--foreground))',
  			card: {
  				DEFAULT: 'hsl(var(--card))',
  				foreground: 'hsl(var(--card-foreground))'
  			},
  			popover: {
  				DEFAULT: 'hsl(var(--popover))',
  				foreground: 'hsl(var(--popover-foreground))'
  			},
  			primary: {
  				DEFAULT: 'hsl(var(--primary))',
  				foreground: 'hsl(var(--primary-foreground))'
  			},
  			secondary: {
  				DEFAULT: 'hsl(var(--secondary))',
  				foreground: 'hsl(var(--secondary-foreground))'
  			},
  			muted: {
  				DEFAULT: 'hsl(var(--muted))',
  				foreground: 'hsl(var(--muted-foreground))'
  			},
  			accent: {
  				DEFAULT: 'hsl(var(--accent))',
  				foreground: 'hsl(var(--accent-foreground))'
  			},
  			destructive: {
  				DEFAULT: 'hsl(var(--destructive))',
  				foreground: 'hsl(var(--destructive-foreground))'
  			},
  			border: 'hsl(var(--border))',
  			input: 'hsl(var(--input))',
  			ring: 'hsl(var(--ring))',
  			chart: {
  				'1': 'hsl(var(--chart-1))',
  				'2': 'hsl(var(--chart-2))',
  				'3': 'hsl(var(--chart-3))',
  				'4': 'hsl(var(--chart-4))',
  				'5': 'hsl(var(--chart-5))'
  			}
  		},
  		keyframes: {
  			marquee: {
  				from: {
  					transform: 'translateX(0)'
  				},
  				to: {
  					transform: 'translateX(calc(-100% - var(--gap)))'
  				}
  			},
  			'marquee-vertical': {
  				from: {
  					transform: 'translateY(0)'
  				},
  				to: {
  					transform: 'translateY(calc(-100% - var(--gap)))'
  				}
  			}
  		},
  		animation: {
  			marquee: 'marquee var(--duration) infinite linear',
  			'marquee-vertical': 'marquee-vertical var(--duration) linear infinite'
  		}
  	}
  },
  plugins: [require("tailwindcss-animate")],
}
```

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