# Project export: RecycleMagic

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: SO fun
- Devpost: https://devpost.com/software/recyclemagic
- GitHub: https://github.com/AbdurAziz/RecycleMagic
- Team: 3 GitHub contributor(s) — Kevin Wang (9 commits), Abdur Aziz (2 commits), KhanhKhuat1504 (1 commits)

## Devpost submission (written by the team)

### Inspiration

It's difficult to track where recyclables end up in the world.

### What it does

We track recyclables via QR codes on the recyclables when they end up at a recycling plant. If a recycling plant does not have some sort of internet connection, then they can use the Skylo satellite IoT device network.

### How we built it

We used React.JS, Reflex.Dev, Amazon Web Services EC2, Google Firebase, and Skylo.

### Challenges we ran into

We attempted to connect the Skylo satellite network.

### Accomplishments we're proud of

Successfully built 3 web applications and successfully set up UDP servers for data transmission.

## README (from the GitHub repository)

# RecycleMagic

## Detected evidence (automated analysis)

Indexed codebase: 54 recognized source files, 91 KB.
- CSS (language) — detected in the code
- Firebase (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Next.js (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code

## Codebase structure (from repository index)

### Files (76 of 76)

```
.DS_Store
.gitignore
DashboardApp/.gitignore
DashboardApp/.web/.gitignore
DashboardApp/.web/bun.lockb
DashboardApp/.web/bunfig.toml
DashboardApp/.web/components/reflex/radix_themes_color_mode_provider.js
DashboardApp/.web/env.json
DashboardApp/.web/jsconfig.json
DashboardApp/.web/next.config.js
DashboardApp/.web/package.json
DashboardApp/.web/pages/_app.js
DashboardApp/.web/pages/_document.js
DashboardApp/.web/pages/404.js
DashboardApp/.web/pages/index.js
DashboardApp/.web/postcss.config.js
DashboardApp/.web/reflex.install_frontend_packages.cached
DashboardApp/.web/reflex.json
DashboardApp/.web/styles/styles.css
DashboardApp/.web/styles/tailwind.css
DashboardApp/.web/tailwind.config.js
DashboardApp/.web/utils/client_side_routing.js
DashboardApp/.web/utils/components.js
DashboardApp/.web/utils/context.js
DashboardApp/.web/utils/helpers/dataeditor.js
DashboardApp/.web/utils/helpers/debounce.js
DashboardApp/.web/utils/helpers/paste.js
DashboardApp/.web/utils/helpers/range.js
DashboardApp/.web/utils/helpers/throttle.js
DashboardApp/.web/utils/state.js
DashboardApp/.web/utils/stateful_components.js
DashboardApp/.web/utils/theme.js
DashboardApp/readme.md
DashboardApp/recyclemagic/__init__.py
DashboardApp/recyclemagic/firebase-service-account.json
DashboardApp/recyclemagic/firebase.py
DashboardApp/recyclemagic/recyclemagic.py
DashboardApp/requirements.txt
DashboardApp/rxconfig.py
QRScannerApp/.gitignore
QRScannerApp/qr-scanner-app/.gitignore
QRScannerApp/qr-scanner-app/package.json
QRScannerApp/qr-scanner-app/public/index.html
QRScannerApp/qr-scanner-app/public/manifest.json
QRScannerApp/qr-scanner-app/public/robots.txt
QRScannerApp/qr-scanner-app/README.md
QRScannerApp/qr-scanner-app/src/App.css
QRScannerApp/qr-scanner-app/src/App.js
QRScannerApp/qr-scanner-app/src/App.test.js
QRScannerApp/qr-scanner-app/src/components/ResultScreen.js
QRScannerApp/qr-scanner-app/src/components/ScannerScreen.js
QRScannerApp/qr-scanner-app/src/configuration.jsx
QRScannerApp/qr-scanner-app/src/index.css
QRScannerApp/qr-scanner-app/src/index.js
QRScannerApp/qr-scanner-app/src/reportWebVitals.js
QRScannerApp/qr-scanner-app/src/setupTests.js
QRScannerApp/readme.md
README.md
RecycleStaffApp/readme.md
RecycleStaffApp/recycle-staff-scanner/.gitignore
RecycleStaffApp/recycle-staff-scanner/package.json
RecycleStaffApp/recycle-staff-scanner/public/index.html
RecycleStaffApp/recycle-staff-scanner/public/manifest.json
RecycleStaffApp/recycle-staff-scanner/public/robots.txt
RecycleStaffApp/recycle-staff-scanner/README.md
RecycleStaffApp/recycle-staff-scanner/src/App.css
RecycleStaffApp/recycle-staff-scanner/src/App.js
RecycleStaffApp/recycle-staff-scanner/src/App.test.js
RecycleStaffApp/recycle-staff-scanner/src/components/ResultScreen.js
RecycleStaffApp/recycle-staff-scanner/src/components/ScannerScreen.js
RecycleStaffApp/recycle-staff-scanner/src/configuration.jsx
RecycleStaffApp/recycle-staff-scanner/src/index.css
RecycleStaffApp/recycle-staff-scanner/src/index.js
RecycleStaffApp/recycle-staff-scanner/src/reportWebVitals.js
RecycleStaffApp/recycle-staff-scanner/src/setupTests.js
Sensors/udp_server.py
```

### Dependencies

- DashboardApp/.web/package.json: @babel/standalone@7.25.7, @emotion/react@11.13.3, @radix-ui/themes@^3.0.0, @tailwindcss/typography@^0.5.15, autoprefixer@10.4.20, axios@1.7.7, gridjs@6.2.0, gridjs-react@6.1.1, json5@2.2.3, lucide-react@0.359.0, next@14.2.14, next-sitemap@4.2.3, next-themes@0.3.0, postcss@8.4.47, postcss-import@16.1.0, react@18.3.1, react-dom@18.3.1, react-focus-lock@2.13.2, socket.io-client@4.8.0, sonner@1.5.0, tailwindcss@3.4.13, universal-cookie@7.2.0
- DashboardApp/requirements.txt: reflex@==0.6.3
- QRScannerApp/qr-scanner-app/package.json: @emotion/react@^11.13.3, @emotion/styled@^11.13.0, @fontsource/roboto@^5.1.0, @mui/material@^6.1.4, @mui/styled-engine-sc@^6.1.4, @testing-library/jest-dom@^5.17.0, @testing-library/react@^13.4.0, @testing-library/user-event@^13.5.0, @yudiel/react-qr-scanner@^2.0.8, firebase@^10.14.1, react@^18.3.1, react-dom@^18.3.1, react-scripts@5.0.1, styled-components@^6.1.13, web-vitals@^2.1.4
- RecycleStaffApp/recycle-staff-scanner/package.json: @emotion/react@^11.13.3, @emotion/styled@^11.13.0, @fontsource/roboto@^5.1.0, @mui/icons-material@^6.1.4, @mui/material@^6.1.4, @mui/styled-engine-sc@^6.1.4, @testing-library/jest-dom@^5.17.0, @testing-library/react@^13.4.0, @testing-library/user-event@^13.5.0, @yudiel/react-qr-scanner@^2.0.8, firebase@^10.14.1, react@^18.3.1, react-dom@^18.3.1, react-scripts@5.0.1, styled-components@^6.1.13, web-vitals@^2.1.4

### Recent commits (newest first)

- Create udp_server.py
- Finished dashboard
- Added Dashboard app
- Merge pull request #3 from AbdurAziz/QRScanner
- Added staff scanner
- Merge pull request #1 from AbdurAziz/QRScanner
- Finished with firebase
- Prep for components
- Initialized QR scanner app
- Added real folders
- Added folders
- Initial commit

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

### DashboardApp/requirements.txt

```
reflex==0.6.3

```

### DashboardApp/.web/package.json

```
{
  "name": "reflex",
  "scripts": {
    "dev": "next dev",
    "export": "next build",
    "export-sitemap": "next build && next-sitemap",
    "prod": "next start"
  },
  "dependencies": {
    "@babel/standalone": "7.25.7",
    "@emotion/react": "11.13.3",
    "@radix-ui/themes": "^3.0.0",
    "axios": "1.7.7",
    "gridjs": "6.2.0",
    "gridjs-react": "6.1.1",
    "json5": "2.2.3",
    "lucide-react": "0.359.0",
    "next": "14.2.14",
    "next-sitemap": "4.2.3",
    "next-themes": "0.3.0",
    "react": "18.3.1",
    "react-dom": "18.3.1",
    "react-focus-lock": "2.13.2",
    "socket.io-client": "4.8.0",
    "sonner": "1.5.0",
    "universal-cookie": "7.2.0"
  },
  "devDependencies": {
    "@tailwindcss/typography": "^0.5.15",
    "autoprefixer": "10.4.20",
    "postcss": "8.4.47",
    "postcss-import": "16.1.0",
    "tailwindcss": "3.4.13"
  }
}
```

### QRScannerApp/qr-scanner-app/package.json

```
{
  "name": "qr-scanner-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@emotion/react": "^11.13.3",
    "@emotion/styled": "^11.13.0",
    "@fontsource/roboto": "^5.1.0",
    "@mui/material": "^6.1.4",
    "@mui/styled-engine-sc": "^6.1.4",
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "@yudiel/react-qr-scanner": "^2.0.8",
    "firebase": "^10.14.1",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-scripts": "5.0.1",
    "styled-components": "^6.1.13",
    "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"
    ]
  }
}

```

### RecycleStaffApp/recycle-staff-scanner/package.json

```
{
  "name": "qr-scanner-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@emotion/react": "^11.13.3",
    "@emotion/styled": "^11.13.0",
    "@fontsource/roboto": "^5.1.0",
    "@mui/icons-material": "^6.1.4",
    "@mui/material": "^6.1.4",
    "@mui/styled-engine-sc": "^6.1.4",
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "@yudiel/react-qr-scanner": "^2.0.8",
    "firebase": "^10.14.1",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-scripts": "5.0.1",
    "styled-components": "^6.1.13",
    "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"
    ]
  }
}

```

### QRScannerApp/qr-scanner-app/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';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// 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();

```

### RecycleStaffApp/recycle-staff-scanner/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';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// 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();

```

### RecycleStaffApp/recycle-staff-scanner/src/App.js

```javascript
import React, { useState } from 'react';
import './App.css';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import ScannerScreen from './components/ScannerScreen';
import ResultScreen from './components/ResultScreen';

const theme = createTheme({
  palette: {
    mode: 'light', // or 'dark' for dark mode
  },
});

function App() {
  const [scanned, setScanned] = useState(false);
  const [scanResult, setScanResult] = useState(null);

  const handleScan = (result) => {
    if (result) {
      setScanned(true);
      console.log(result);
      setScanResult(result);
    }
  };

  return (
    <ThemeProvider theme={theme}>
      <div className="App">
        <ScannerScreen onScan={handleScan} />
      </div>
    </ThemeProvider>
  );
}

export default App;

```

### QRScannerApp/qr-scanner-app/src/App.js

```javascript
import React, { useState } from 'react';
import './App.css';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import ScannerScreen from './components/ScannerScreen';
import ResultScreen from './components/ResultScreen';

const theme = createTheme({
  palette: {
    mode: 'light', // or 'dark' for dark mode
  },
});

function App() {
  const [scanned, setScanned] = useState(false);
  const [scanResult, setScanResult] = useState(null);

  const handleScan = (result) => {
    if (result) {
      setScanned(true);
      console.log(result);
      setScanResult(result);
    }
  };

  return (
    <ThemeProvider theme={theme}>
      <div className="App">
        {!scanned ? (
          <ScannerScreen onScan={handleScan} />
          //<ResultScreen result={scanResult} />
        ) : (
          <ResultScreen result={scanResult} />
        )}
      </div>
    </ThemeProvider>
  );
}

export default App;

```

### DashboardApp/.web/pages/index.js

```javascript
/** @jsxImportSource @emotion/react */


import { Fragment, useCallback, useContext, useEffect, useState } from "react"
import { ColorModeContext, EventLoopContext } from "/utils/context"
import { Event, getBackendURL, isTrue, refs } from "/utils/state"
import { MoonIcon as LucideMoonIcon, SunIcon as LucideSunIcon, WifiOffIcon as LucideWifiOffIcon } from "lucide-react"
import { keyframes } from "@emotion/react"
import { toast, Toaster } from "sonner"
import env from "/env.json"
import { Box as RadixThemesBox, Card as RadixThemesCard, Container as RadixThemesContainer, Flex as RadixThemesFlex, Grid as RadixThemesGrid, Heading as RadixThemesHeading, IconButton as RadixThemesIconButton } from "@radix-ui/themes"
import { Grid as DataTableGrid } from "gridjs-react"
import "gridjs/dist/theme/mermaid.css"
import NextHead from "next/head"



export function Div_24a2e81d0c5d3cb5b5f786fdef44e514 () {
  const [addEvents, connectErrors] = useContext(EventLoopContext);



  return (
    <div css={({ ["position"] : "fixed", ["width"] : "100vw", ["height"] : "0" })} title={("Connection Error: "+((connectErrors.length > 0) ? connectErrors[connectErrors.length - 1].message : ''))}>
  <Fragment_e521b13e556da291bcec5187a783ea81/>
</div>
  )
}

const pulse = keyframes`
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
`


export function Fragment_eb4ad804ee463e78d3c73fc2a2903123 () {
  const { resolvedColorMode } = useContext(ColorModeContext)



  return (
    <Fragment>
  {isTrue((resolvedColorMode === "light")) ? (
  <Fragment>
  <LucideSunIcon css={({ ["color"] : "var(--current-color)" })}/>
</Fragment>
) : (
  <Fragment>
  <LucideMoonIcon css={({ ["color"] : "var(--current-color)" })}/>
</Fragment>
)}
</Fragment>
  )
}

export function Toaster_9d6e054b03c6e5d1bea1c0a5576b4e6d () {
  const { resolvedColorMode } = useContext(ColorModeContext)


  refs['__toast'] = toast
  const [addEvents, connectErrors] = useContext(EventLoopContext);
  const toast_props = ({ ["description"] : ("Check if server is reachable at "+getBackendURL(env.EVENT).href), ["closeButton"] : true, ["duration"] : 120000, ["id"] : "websocket-error" });
  const [userDismissed, setUserDismissed] = useState(false);
  (useEffect(
() => {
    if ((connectErrors.length >= 2)) {
        if (!userDismissed) {
            toast.error(
                `Cannot connect to server: ${((connectErrors.length > 0) ? connectErrors[connectErrors.length - 1].message : '')}.`,
                {...toast_props, onDismiss: () => setUserDismissed(true)},
            )
        }
    } else {
        toast.dismiss("websocket-error");
        setUserDismissed(false);  // after reconnection reset dismissed state
    }
}
, [connectErrors]))

  return (
    <Toaster closeButton={false} expand={true} position={"bottom-right"} richColors={true} theme={resolvedColorMode}/>
  )
}

export function Iconbutton_52395c54b68ff5a6f498d43b99daaac3 () {
  const { toggleColorMode } = useContext(ColorModeContext)
  const [addEvents, connectErrors] = useContext(EventLoopContext);

  const on_click_9922dd3e837b9e087c86a2522c2c93f8 = useCallback(toggleColorMode, [addEvents, Event, toggleColorMode])


  return (
    <RadixThemesIconButton css={({ ["padding"] : "6px", ["position"] : "fixed", ["top"] : "2rem", ["right"] : "2rem", ["background"] : "transparent", ["color"] : "inherit", ["zIndex"] : "20", ["&:hover"] : ({ ["cursor"] : "pointer" }) })} onClick={on_click_9922dd3e837b9e087c86a2522c2c93f8}>
  <Fragment_eb4ad804ee463e78d3c73fc2a2903123/>
</RadixThemesIconButton>
  )
}

export function Fragment_e521b13e556da291bcec5187a783ea81 () {
  const [addEvents, connectErrors] = useContext(EventLoopContext);



  return (
    <Fragment>
  {isTrue((connectErrors.length > 0)) ? (
  <Fragment>
  <LucideWifiOffIcon css={({ ["color"] : "crimson", ["zIndex"] : 9999, ["position"] : "fixed", ["bottom"] : "33px", ["right"] : "33px", ["animation"] : (pulse+" 1s infinite") })} size={32}/>
</Fragment>
) : (
  <Fragment/>
)}
</Fragment>
  )
}

export default function Component() {

  return (
    <Fragment>
  <Fragment>
  <Div_24a2e81d0c5d3cb5b5f786fdef44e514/>
  <Toaster_9d6e054b03c6e5d1bea1c0a5576b4e6d/>
</Fragment>
  <RadixThemesBox css={({ ["width"] : "100vw", ["padding"] : "0" })}>
  <RadixThemesContainer css={({ ["padding"] : "0", ["width"] : "100%", ["maxWidth"] : "100vw", ["margin"] : "0" })} size={"3"}>
  <Iconbutton_52395c54b68ff5a6f498d43b99daaac3/>
  <RadixThemesFlex align={"start"} className={"rx-Stack"} direction={"column"} gap={"3"}>
  <RadixThemesHeading size={"20"}>
  {"RecycleMagic Dashboard"}
</RadixThemesHeading>
  <RadixThemesFlex css={({ ["flex"] : 1, ["justifySelf"] : "stretch", ["alignSelf"] : "stretch" })}/>
  <RadixThemesGrid css={({ ["templateColumns"] : "repeat(2, 1fr)", ["width"] : "100%" })} gap={"2"}>
  <RadixThemesCard css={({ ["width"] : "100%" })}>
  <RadixThemesHeading>
  {"Welcome!"}
</RadixThemesHeading>
  <ul css={({ ["direction"] : "column", ["listStyleType"] : "disc", ["marginLeft"] : "1.5rem" })}>
  <li>
  {"This is a dashboard for RecycleMagic."}
</li>
  <li>
  {"Data on this page is updated via refresh."}
</li>
  <li>
  {"Email us at kevin@recyclemagic.com for more information."}
</li>
</ul>
</RadixThemesCard>
  <RadixThemesCard css={({ ["width"] : "100%" })}>
  <RadixThemesHeading>
  {"Bottle Waste Management Bin Status"}
</RadixThemesHeading>
  <DataTableGrid columns={["bin_id", "type", "status"]} data={[[517, "SmartBin", "Ready for Pickup"], [444, "SmartBin", "Overflowing"], [367, "Reverse Vending Machine", "Normal"], [987, "Recycling Site", "Normal"], [986, "Recycling Site", "Normal"], [711, "Reverse Vending Machine", "Normal"], [984, "SmartBin", "Normal"], [409, "Recycling Site", "Overflowing"], [947, "SmartBin", "Overflowing"], [556, "Reverse Vending Machine", "Normal"], [515, "Recycling Site", "Overflowing"], [677, "Reverse Vending Machine", "Ready for Pickup"], [737, "SmartBin", "Normal"], [607, "SmartBin", "Normal"], [803, "Smart
[truncated — 4212 more characters]
```

### DashboardApp/rxconfig.py

```python
import reflex as rx

config = rx.Config(
    app_name="recyclemagic",
)
```

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