# Project export: Eden AI

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 12.0
- Tagline: Booking a trip without booking a trip!
- Devpost: https://devpost.com/software/eden-ai
- GitHub: https://github.com/jasonsgca/CalHacks_12.0
- Demo: https://www.loom.com/share/50b7431092324648baa3d93f24381f41
- Video: https://www.youtube.com/embed/DMRb-i5pchw?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — Jason (9 commits)

## Devpost submission (written by the team)

### Inspiration

Drawing inspiration from Airbnb’s success, we developed a next-generation platform that integrates artificial intelligence to deliver a more seamless and personalized travel experience, with wellness in mind.

### What it does

The application analyzes your daily behavior using pre-existing data from third-party providers to plan and book a personalized trip. It intelligently recommends the ideal duration and destination to help you decompress, recharge, and return to your routine refreshed.

### How we built it

We used Google AI Studio to help us with develop the code with the the idea we had in mind.

### Challenges we ran into

There was a stage when Google AI Studio couldn’t fully understand our prompts and stalled our progress. After digging into how the system handled code and external files by analyzing the code it wrote, especially image rendering, we realized it was pulling visuals from the wrong source. Once we clearly directed it to use SourceB instead of the default SourceA, the AI was finally able to execute our idea.

### Accomplishments we're proud of

We are proud to have created a real, functional product that helps professionals and individuals recover from the pressures of their daily environments. Burnout culture is a growing issue, and we are honored to contribute to the mental wellness by offering a tool that truly makes a difference.

### What we learned

We learned that there many AI agents out there that can assist with developing code and analyzing them. We also learned that the wifi connection at hackathons may not be the most reliable, but the vibes of all the hackers and participants were amazing.

### What's next

The next step for Eden AI is to conduct live user testing to gather feedback and refine the product through further development and engineering. We look forward to bring this product to the market in the near future!

## README (from the GitHub repository)


EDEN AI is an intelligent wellness platform that helps users detect burnout and discover personalized recovery getaways. Using behavioral and contextual data, like calendar activity, work hours, and lifestyle trends, the AI curates restful trips designed to restore work–life balance. Each recommendation highlights destinations focused on mindfulness, nature, or digital detox experiences, paired with dynamic pricing and wellness tags. 
Built with React, Firebase, and OpenAI/Gemini APIs, EDEN AI blends emotional intelligence with modern design to make well-being actionable. It’s not just a travel app, it’s an AI companion that reminds you when to pause, recharge, and rediscover balance.

By understanding your daily patterns, from work intensity to personal downtime, EDEN AI gently intervenes before burnout strikes. It learns when you’re stretched too thin and recommends restorative escapes that align with your lifestyle. Whether it’s a mountain retreat, a coastal reset, or a mindful city getaway, EDEN AI helps you recharge purposefully and return with clarity, balance, and renewed energy.

Built with the assistance of Google Gemini AI. 

CalHacks 12.0 submission - Jason Low & Roy Margallo

@sdhu @harshitaarora
thank you for the opportunity for us to participate in this challenge! 


## Detected evidence (automated analysis)

Indexed codebase: 18 recognized source files, 94 KB.
- HTML (language) — detected in the code
- React (technology) — detected in the code
- TypeScript (language) — detected in the code
- Google Gemini (technology) — claimed on Devpost, not found in the code
- JavaScript (language) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (21 of 21)

```
App.tsx
components/ApiKeyScreen.tsx
components/Dashboard.tsx
components/FuturisticSearchBar.tsx
components/Header.tsx
components/Icon.tsx
components/LoginScreen.tsx
components/MapView.tsx
components/RelaxationPlanner.tsx
components/Spinner.tsx
components/SuggestionCard.tsx
constants.ts
index.html
index.tsx
metadata.json
package.json
README.md
services/geminiService.ts
tsconfig.json
types.ts
vite.config.ts
```

### Dependencies

- package.json: @google/genai@^1.27.0, @types/node@^22.14.0, @vitejs/plugin-react@^5.0.0, react@^19.2.0, react-dom@^19.2.0, typescript@~5.8.2, vite@^6.2.0

### Recent commits (newest first)

- Update README.md
- Update README.md
- Update README.md
- Update README.md
- Update README.md
- Update README.md
- Update README.md
- Add files via upload
- Initial commit

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

### package.json

```
{
  "name": "copy-of-v2-eden-ai---burnout-prevention-getaways",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "@google/genai": "^1.27.0"
  },
  "devDependencies": {
    "@types/node": "^22.14.0",
    "@vitejs/plugin-react": "^5.0.0",
    "typescript": "~5.8.2",
    "vite": "^6.2.0"
  }
}

```

### index.tsx

```typescript

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

const rootElement = document.getElementById('root');
if (!rootElement) {
  throw new Error("Could not find root element to mount to");
}

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

```

### App.tsx

```typescript
import React, { useState, useCallback } from 'react';
import LoginModal from './components/LoginScreen';
import Dashboard from './components/Dashboard';
import { UserProfile } from './types';
import { GUEST_PROFILE } from './constants';

const App: React.FC = () => {
  const [userProfile, setUserProfile] = useState<UserProfile>(GUEST_PROFILE);
  const [isLoginModalOpen, setIsLoginModalOpen] = useState(false);

  const handleLogin = useCallback((profile: UserProfile) => {
    setUserProfile(profile);
    setIsLoginModalOpen(false);
  }, []);

  const handleLogout = useCallback(() => {
    setUserProfile(GUEST_PROFILE);
  }, []);
  
  const openLoginModal = useCallback(() => setIsLoginModalOpen(true), []);
  const closeLoginModal = useCallback(() => setIsLoginModalOpen(false), []);

  return (
    <div className="min-h-screen antialiased" style={{ fontFamily: "'Inter', sans-serif" }}>
      <Dashboard user={userProfile} onSignInClick={openLoginModal} onLogout={handleLogout} />
      {isLoginModalOpen && (
        <LoginModal onLogin={handleLogin} onClose={closeLoginModal} />
      )}
    </div>
  );
};

export default App;
```

### vite.config.ts

```typescript
import path from 'path';
import { defineConfig, loadEnv } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig(({ mode }) => {
    const env = loadEnv(mode, '.', '');
    return {
      server: {
        port: 3000,
        host: '0.0.0.0',
      },
      plugins: [react()],
      define: {
        'process.env.API_KEY': JSON.stringify(env.GEMINI_API_KEY),
        'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY)
      },
      resolve: {
        alias: {
          '@': path.resolve(__dirname, '.'),
        }
      }
    };
});

```

### types.ts

```typescript
export interface UserProfile {
  name: string;
  jobTitle: string;
  company: string;
  location: string;
  workHours: string;
  commute: string;
  eatingHabits: string;
  calendarSummary: string;
  searchHistory: string[];
  preferences: string[];
  avatarUrl: string;
}

export interface GetawaySuggestion {
  id: string;
  title: string;
  location: string;
  description: string;
  imageUrls: string[];
  pricePerNight: number;
  tags: string[];
  latitude: number;
  longitude: number;
}

export interface Accommodation {
  name: string;
  rating: number;
  pricePerNight: number;
  description: string;
  hostedBy: string;
}
```

### constants.ts

```typescript

import { UserProfile } from './types';

export const FRANCESCA_PROFILE: UserProfile = {
  name: "Francesca Rossi",
  jobTitle: "Senior Software Engineer",
  company: "CalCodes",
  location: "San Francisco, CA",
  workHours: ">80 hours/week",
  commute: "1.5 hours daily, heavy traffic",
  eatingHabits: "Quick meals at office cafeteria, frequent coffee shop visits for focus.",
  calendarSummary: "Back-to-back meetings, project deadlines every two weeks. Next free weekend is in 10 days.",
  searchHistory: [
    "quiet cabin rentals near Lake Tahoe",
    "best weekend hiking Big Sur",
    "mindfulness and yoga retreats California",
    "gourmet cooking classes SF",
    "how to prevent burnout software engineer"
  ],
  preferences: ["Hiking", "Nature", "Quiet places", "Good food", "Yoga", "Digital detox"],
  avatarUrl: "https://picsum.photos/seed/francesca/200/200"
};

export const GUEST_PROFILE: UserProfile = {
  name: "Explorer",
  jobTitle: "N/A",
  company: "N/A",
  location: "San Francisco, CA", // Default for initial search
  workHours: "N/A",
  commute: "N/A",
  eatingHabits: "N/A",
  calendarSummary: "N/A",
  searchHistory: [],
  preferences: [],
  avatarUrl: "https://picsum.photos/seed/explorer/200/200",
};

```

### 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>Eden AI</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/>
    <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
  <script type="importmap">
{
  "imports": {
    "react/": "https://aistudiocdn.com/react@^19.2.0/",
    "react": "https://aistudiocdn.com/react@^19.2.0",
    "react-dom/": "https://aistudiocdn.com/react-dom@^19.2.0/",
    "@google/genai": "https://aistudiocdn.com/@google/genai@^1.27.0"
  }
}
</script>
<style>
  body {
    font-family: 'Inter', sans-serif;
  }
  .text-glow {
    text-shadow: 0 0 8px rgba(56, 189, 248, 0.8);
  }
  .card-glow:hover {
    box-shadow: 0 0 15px rgba(56, 189, 248, 0.4), 0 0 5px rgba(56, 189, 248, 0.6);
  }
  .leaflet-popup-content-wrapper, .leaflet-popup-tip {
    background: #0f172a;
    color: #e2e8f0;
    border: 1px solid #0ea5e9;
    border-radius: 4px;
    box-shadow: 0 0 10px rgba(14, 165, 233, 0.5);
  }
  @keyframes fadeIn {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: translateY(0); }
  }
  .animate-fade-in {
    animation: fadeIn 0.5s ease-in-out forwards;
  }
  @keyframes pulse-glow {
    0%, 100% {
      box-shadow: 0 0 15px rgba(56, 189, 248, 0.3), 0 0 5px rgba(56, 189, 248, 0.4);
      border-color: rgba(56, 189, 248, 0.7);
    }
    50% {
      box-shadow: 0 0 25px rgba(56, 189, 248, 0.6), 0 0 10px rgba(56, 189, 248, 0.8);
      border-color: rgba(56, 189, 248, 1);
    }
  }
  .animate-pulse-glow {
      animation: pulse-glow 2.5s infinite ease-in-out;
  }
</style>
<link rel="stylesheet" href="/index.css">
</head>
  <body class="bg-slate-900 text-slate-200">
    <div id="root"></div>
    <script type="module" src="/index.tsx"></script>
  </body>
</html>
```

### components/Spinner.tsx

```typescript

import React from 'react';

const Spinner: React.FC = () => {
  return (
    <svg 
      className="animate-spin h-10 w-10 text-cyan-400" 
      xmlns="http://www.w3.org/2000/svg" 
      fill="none" 
      viewBox="0 0 24 24"
    >
      <circle 
        className="opacity-25" 
        cx="12" 
        cy="12" 
        r="10" 
        stroke="currentColor" 
        strokeWidth="4"
      ></circle>
      <path 
        className="opacity-75" 
        fill="currentColor" 
        d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
      ></path>
    </svg>
  );
};

export default Spinner;
```

### components/ApiKeyScreen.tsx

```typescript
import React from 'react';
import Icon from './Icon';

interface ApiKeyScreenProps {
  onKeySelect: () => void;
}

declare const window: {
  aistudio?: {
    openSelectKey: () => Promise<void>;
  }
} & Window;

const ApiKeyScreen: React.FC<ApiKeyScreenProps> = ({ onKeySelect }) => {
  const handleSelectKey = async () => {
    // Assuming window.aistudio is available based on App.tsx logic
    if (window.aistudio && typeof window.aistudio.openSelectKey === 'function') {
      await window.aistudio.openSelectKey();
      onKeySelect(); // Assume success to handle race condition
    } else {
      alert("API key selection feature is not available in this environment.");
    }
  };

  return (
    <div className="flex flex-col items-center justify-center min-h-screen bg-slate-900 p-4">
      <div className="w-full max-w-md p-8 space-y-6 bg-slate-800/50 backdrop-blur-sm border border-cyan-400/30 rounded-lg text-center">
        <Icon name="key" className="w-16 h-16 text-cyan-400 mx-auto" />
        <h1 className="mt-4 text-3xl font-bold text-slate-100 text-glow">Gemini API Key Required</h1>
        <p className="mt-2 text-slate-300">
          To use Eden AI, you need to select your Gemini API key. Your key is stored securely and only used to communicate with the Gemini API.
        </p>
        <button
          onClick={handleSelectKey}
          className="w-full mt-6 flex items-center justify-center py-3 px-4 bg-cyan-500/20 border border-cyan-500/80 rounded-md text-base font-medium text-cyan-200 hover:bg-cyan-400/30 hover:border-cyan-400 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-slate-900 focus:ring-cyan-500 transition-all duration-200 ease-in-out transform hover:scale-105"
        >
          Select Gemini API Key
        </button>
      </div>
    </div>
  );
};

export default ApiKeyScreen;
```

### components/Header.tsx

```typescript
import React from 'react';
import { UserProfile } from '../types';

interface HeaderProps {
  user: UserProfile;
  isGuest?: boolean;
  onSignInClick: () => void;
  onLogout: () => void;
}

const Header: React.FC<HeaderProps> = ({ user, isGuest, onSignInClick, onLogout }) => {
  return (
    <header className="bg-slate-900/80 backdrop-blur-sm sticky top-0 z-10 border-b border-cyan-400/20">
      <div className="container mx-auto px-4 sm:px-6 lg:px-8">
        <div className="flex items-center justify-between h-16">
          <div className="flex items-center">
             <svg className="w-8 h-8 text-cyan-400" fill="none" viewBox="0 0 24 24" strokeWidth="1.5" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
            <span className="ml-3 text-xl font-bold text-slate-200 uppercase tracking-wider">Eden AI</span>
          </div>
          <div className="flex items-center">
            {isGuest ? (
              <button
                onClick={onSignInClick}
                className="px-4 py-2 text-sm font-medium text-slate-200 bg-slate-700/50 border border-cyan-400/50 rounded-md hover:bg-cyan-400/20 transition-colors"
              >
                Sign In
              </button>
            ) : (
              <div className="flex items-center">
                <span className="hidden sm:block text-sm font-medium text-slate-300 mr-3">{user.name}</span>
                <img 
                  className="h-9 w-9 rounded-full object-cover border-2 border-slate-600 group-hover:border-cyan-400 transition" 
                  src={user.avatarUrl} 
                  alt="User avatar" 
                />
                <button
                  onClick={onLogout}
                  className="ml-4 px-3 py-2 text-xs font-medium text-slate-300 bg-transparent border border-slate-600 rounded-md hover:bg-slate-700/50 hover:border-slate-500 transition-colors"
                >
                  Sign Out
                </button>
              </div>
            )}
          </div>
        </div>
      </div>
    </header>
  );
};

export default Header;
```

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