# Project export: SmartRation

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: UC Berkeley AI Hackathon 2025
- Tagline: AI-powered meal planning for low-income families to stretch every dollar and cut food waste.
- Devpost: https://devpost.com/software/smartration
- GitHub: https://github.com/Sodbayar-ganbat/hackathon-project.git
- Video: https://www.youtube.com/embed/1EAjBhhn2Ms?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 2 GitHub contributor(s) — Sodbayar Ganbat (19 commits), Robert Flores (1 commits)

## Devpost submission (written by the team)

### Inspiration

We wanted to tackle two huge pain points for under-resourced households: stretching a tight grocery budget and minimizing food waste. By combining off-the-shelf OCR and computer-vision models with powerful LLMs, we realized you could turn a simple snap of your fridge plus yesterday’s receipt into a fully personalized, budget-smart meal plan.

### What it does

SmartRation packs five core features into one seamless dashboard: FoodGPT Chat Assistant – Ask for recipe ideas, cooking tips, dietary advice, and personalized meal suggestions in natural language. – Handles follow-up questions about allergies, household size, spice tolerance, and budget limits. Upload Receipt OCR – Snap or upload your grocery receipt to instantly extract items, quantities, and prices. – Automatically logs your spending to inform every downstream feature. AI Meal Plans – Generate a 7-day, 3-meals-per-day plan tailored to your budget, preferences, and what’s in your fridge. – Slide through daily cards, pick between variations, or hit “Regenerate” for fresh ideas. Smart Shopping List Generator – Based on your remaining ingredients, meal plan, and spending cap, build a budget-optimized shopping list. – Group items by store sections or preferred grocery APIs (Kroger, Walmart, etc.) for the fastest trip. Saved & Rated Meals – Bookmark your favorite dishes and rate each meal after you cook it. – View past successes at any time and let FoodGPT learn from your ratings to refine future recommendations.

### How we built it

Frontend: typescript, tailwind css, shadn UI. Backend: Supabase for auth, Postgres tables (profiles, receipts, meal_plans, foodgpt_messages) with RLS. OCR: Google Vision Cloud API LLM: Anthropic Claude 2

### Challenges we ran into

We had trouble training the OCR to recognize different receipt formats and types to improve its accuracy. We had to become prompt engineers for claude and its uses to create a curated shopping list and our own fine-tuned chatbot.

### Accomplishments we're proud of

We're proud of the accuracy of our image detection software and our use of 3 apis.

### What we learned

We learned a lot about prompt engineering and how providing excellent context is most beneficial. We learned about creating an amazing impact in such a short period. We all feel motivated by this to continue to create and learn.

### What's next

We want to continue making our OCR detection more accurate and then integrate grocery shop apis to further get accurate food details. We want to get a customer and user base going so that our app creates value for those who need it.

## README (from the GitHub repository)

# Hackathon Project

Welcome to the hackathon project repository!

## Getting Started

This repository is ready for your hackathon project. You can start adding your code, documentation, and other project files.

## Project Structure

```
.
├── README.md
├── .gitignore
└── [Your project files will go here]
```

## Contributing

1. Make your changes
2. Commit your changes with descriptive commit messages
3. Push to your branch
4. Create a pull request if working with a team

## License

[Add your license information here] 

## Detected evidence (automated analysis)

Indexed codebase: 68 recognized source files, 359 KB.
- Anthropic (technology) — detected in the code
- CSS (language) — detected in the code
- Next.js (technology) — detected in the code
- React (technology) — detected in the code
- SQL (language) — detected in the code
- Supabase (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (75 of 75)

```
.gitignore
README.md
smartration/.gitignore
smartration/app/about/page.tsx
smartration/app/actions.ts
smartration/app/api/auth/check-onboarding/route.ts
smartration/app/api/auth/refresh/route.ts
smartration/app/api/auth/resend-verification/route.ts
smartration/app/api/foodgpt/route.ts
smartration/app/api/meal-plan/route.ts
smartration/app/api/meals/check-saved/route.ts
smartration/app/api/meals/rate/route.ts
smartration/app/api/meals/save/route.ts
smartration/app/api/meals/saved/[id]/route.ts
smartration/app/api/meals/saved/route.ts
smartration/app/api/profile/route.ts
smartration/app/api/shopping-list/generate/route.ts
smartration/app/auth/callback/route.ts
smartration/app/contact/page.tsx
smartration/app/dashboard/ai-meal-plans/page.tsx
smartration/app/dashboard/analytics/page.tsx
smartration/app/dashboard/foodgpt/page.tsx
smartration/app/dashboard/history/loading.tsx
smartration/app/dashboard/history/page.tsx
smartration/app/dashboard/meal-plans/page.tsx
smartration/app/dashboard/page.tsx
smartration/app/dashboard/profile/page.tsx
smartration/app/dashboard/saved-meals/page.tsx
smartration/app/dashboard/shopping-list/page.tsx
smartration/app/dashboard/upload-receipt/page.tsx
smartration/app/dashboard/upload/page.tsx
smartration/app/email-verified/page.tsx
smartration/app/globals.css
smartration/app/how-it-works/page.tsx
smartration/app/layout.tsx
smartration/app/login/page.tsx
smartration/app/onboarding/page.tsx
smartration/app/page.tsx
smartration/app/results/page.tsx
smartration/app/signup/page.tsx
smartration/app/upload/page.tsx
smartration/app/verify-email/page.tsx
smartration/components.json
smartration/components/dashboard-layout.tsx
smartration/components/footer.tsx
smartration/components/header.tsx
smartration/components/image-uploader.tsx
smartration/components/ui/badge.tsx
smartration/components/ui/button.tsx
smartration/components/ui/card.tsx
smartration/components/ui/checkbox.tsx
smartration/components/ui/input.tsx
smartration/components/ui/label.tsx
smartration/components/ui/progress.tsx
smartration/components/ui/radio-group.tsx
smartration/components/ui/separator.tsx
smartration/components/ui/slider.tsx
smartration/components/ui/tabs.tsx
smartration/components/ui/textarea.tsx
smartration/eslint.config.mjs
smartration/lib/auth-context.ts
smartration/lib/claude-ai.ts
smartration/lib/supabase-server.ts
smartration/lib/supabase.ts
smartration/lib/utils.ts
smartration/lib/vision-api.ts
smartration/middleware.ts
smartration/migration_fix_foreign_keys.sql
smartration/next.config.ts
smartration/package.json
smartration/postcss.config.mjs
smartration/README.md
smartration/SUPABASE_SETUP.md
smartration/tsconfig.json
smartration/weekly_meal_plans.sql
```

### Dependencies

- smartration/package.json: @anthropic-ai/sdk@^0.54.0, @eslint/eslintrc@^3, @google-cloud/vision@^5.2.0, @radix-ui/react-checkbox@^1.3.2, @radix-ui/react-label@^2.1.7, @radix-ui/react-progress@^1.1.7, @radix-ui/react-radio-group@^1.3.7, @radix-ui/react-separator@^1.1.7, @radix-ui/react-slider@^1.3.5, @radix-ui/react-slot@^1.2.3, @radix-ui/react-tabs@^1.1.12, @supabase/auth-helpers-nextjs@^0.10.0, @supabase/ssr@^0.6.1, @supabase/supabase-js@^2.50.0, @tailwindcss/postcss@^4, @types/node@^20, @types/react@^19, @types/react-dom@^19, class-variance-authority@^0.7.1, clsx@^2.1.1, eslint@^9, eslint-config-next@15.2.4, lucide-react@^0.522.0, next@15.2.4, react@^19.0.0, react-dom@^19.0.0, tailwind-merge@^3.3.1, tailwindcss@^4, tw-animate-css@^1.3.4, typescript@^5

### Recent commits (newest first)

- actually finished
- finished project
- Merge pull request #7 from Sodbayar-ganbat/claudeMealPlanner
- finished dashboard
- fixing dashboard
- receipts work
- Merge pull request #5 from Sodbayar-ganbat/newLand
- my progres sos far
- saving landing page
- saving progress
- incorporated claude
- adding upload to dashboard
- Merge pull request #4 from Sodbayar-ganbat/dashboard
- added dashboard
- Add lib folder
- got sign up to work
- added google vision functionality finally
- added google vision
- updated code that runs
- added starter page

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

### smartration/SUPABASE_SETUP.md

```markdown
# Supabase Setup Guide for SmartRation

## Prerequisites
1. A Supabase account (sign up at https://supabase.com)
2. A Supabase project created
3. A Google Cloud Vision API key

## Step 1: Get Your Supabase Credentials

1. Go to your Supabase project dashboard
2. Navigate to **Settings** → **API**
3. Copy the following values:
   - **Project URL** (looks like: `https://your-project-id.supabase.co`)
   - **Anon/Public Key** (starts with `eyJ...`)

## Step 2: Get Your Google Vision API Key

1. Go to the [Google Cloud Console](https://console.cloud.google.com/)
2. Create a new project or select an existing one
3. Enable the Cloud Vision API
4. Go to **APIs & Services** → **Credentials**
5. Create a new API key
6. Copy the API key (starts with `AIza...`)

## Step 3: Configure Environment Variables

Create a `.env.local` file in your project root with the following variables:

```env
# Supabase Configuration
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key

# Google Cloud Vision API
GOOGLE_VISION_API_KEY=your_google_vision_api_key
```

Replace the values with your actual credentials:
- `your_supabase_project_url`: Your Supabase project URL
- `your_supabase_anon_key`: Your Supabase anon/public key
- `your_google_vision_api_key`: Your Google Vision API key

## Step 4: Configure Authentication Settings

1. In your Supabase dashboard, go to **Authentication** → **Settings**
2. Configure the following:
   - **Site URL**: `http://localhost:3000` (for development)
   - **Redirect URLs**: Add the following URLs:
     - `http://localhost:3000/auth/callback`
     - `http://localhost:3000/verify-email`
     - `http://localhost:3000/email-verified`
     - `http://localhost:3000/onboarding`
   - **Email Templates**: Customize if desired

## Step 5: Enable Email Authentication

1. Go to **Authentication** → **Providers**
2. Make sure **Email** provider is enabled
3. Configure email settings as needed

## Step 6: Create Database Tables

Create these tables in your Supabase database:

```sql
-- Users profile table with onboarding data
CREATE TABLE profiles (
  id UUID REFERENCES auth.users(id) PRIMARY KEY,
  full_name TEXT,
  email TEXT,
  onboarding_data JSONB,
  onboarding_completed BOOLEAN DEFAULT FALSE,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Receipts table
CREATE TABLE receipts (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  user_id UUID REFERENCES auth.users(id),
  store_name TEXT,
  total_amount DECIMAL(10,2),
  receipt_date DATE,
  items JSONB,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Meal plans table
CREATE TABLE meal_plans (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  user_id UUID REFERENCES auth.users(id),
  receipt_id UUID REFERENCES receipts(id),
  meal_plan JSONB,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
```

## Step 7: Set Up Row Level Security (RLS)

Enable RLS on your tables and crea
[truncated — 2370 more characters]
```

### smartration/package.json

```
{
  "name": "smartration",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev --turbopack",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@anthropic-ai/sdk": "^0.54.0",
    "@google-cloud/vision": "^5.2.0",
    "@radix-ui/react-checkbox": "^1.3.2",
    "@radix-ui/react-label": "^2.1.7",
    "@radix-ui/react-progress": "^1.1.7",
    "@radix-ui/react-radio-group": "^1.3.7",
    "@radix-ui/react-separator": "^1.1.7",
    "@radix-ui/react-slider": "^1.3.5",
    "@radix-ui/react-slot": "^1.2.3",
    "@radix-ui/react-tabs": "^1.1.12",
    "@supabase/auth-helpers-nextjs": "^0.10.0",
    "@supabase/ssr": "^0.6.1",
    "@supabase/supabase-js": "^2.50.0",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "lucide-react": "^0.522.0",
    "next": "15.2.4",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "tailwind-merge": "^3.3.1"
  },
  "devDependencies": {
    "@eslint/eslintrc": "^3",
    "@tailwindcss/postcss": "^4",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "eslint": "^9",
    "eslint-config-next": "15.2.4",
    "tailwindcss": "^4",
    "tw-animate-css": "^1.3.4",
    "typescript": "^5"
  }
}

```

### smartration/app/layout.tsx

```typescript
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import Header from "@/components/header";
import Footer from "@/components/footer";
import { AuthProvider } from "@/lib/auth-context";

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

export const metadata: Metadata = {
  title: "SmartRation - AI-Powered Meal Planning",
  description: "Smart meal planning for budget-conscious living. Upload fridge photos and receipts to get personalized meal plans.",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body
        className={`${geistSans.variable} ${geistMono.variable} antialiased`}
        suppressHydrationWarning={true}
      >
        <AuthProvider>
          <div className="flex flex-col min-h-screen">
            <Header />
            <main className="flex-1">
              {children}
            </main>
            <Footer />
          </div>
        </AuthProvider>
      </body>
    </html>
  );
}

```

### smartration/app/page.tsx

```typescript
"use client"

import Link from "next/link"
import { Button } from "@/components/ui/button"
import { Card } from "@/components/ui/card"
import {
  ArrowRight,
  Receipt,
  Utensils,
  Brain,
  TrendingUp,
  DollarSign,
  ChefHat,
  Camera,
  ShoppingCart,
} from "lucide-react"
import { useEffect } from "react"

export default function Home() {
  useEffect(() => {
    const observerOptions = {
      threshold: 0.1,
      rootMargin: '0px 0px -50px 0px'
    };

    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          entry.target.classList.add('animate');
        } else {
          // Remove animate class when element goes out of view to allow re-triggering
          entry.target.classList.remove('animate');
        }
      });
    }, observerOptions);

    const animatedElements = document.querySelectorAll('.scroll-animate, .fall-animate');
    animatedElements.forEach(el => observer.observe(el));

    return () => {
      animatedElements.forEach(el => observer.unobserve(el));
    };
  }, []);

  return (
    <div className="gradient-bg">
      {/* Hero Section */}
      <section className="w-full py-12 md:py-24 lg:py-32">
        <div className="max-w-7xl mx-auto px-4 md:px-6">
          <div className="grid gap-6 lg:grid-cols-1 lg:gap-12 items-center">
            <div className="space-y-6 text-center">
              <div className="space-y-2">
                <h1 className="text-4xl font-bold tracking-tighter sm:text-5xl md:text-6xl lg:text-7xl">
                  <span className="hero-title">SmartRation</span>
                </h1>
                <p className="text-lg hero-subtitle md:text-xl lg:text-2xl">
                  AI-Powered Meal Planning for Sustainable Living
                </p>
              </div>
              <p className="hero-subtitle md:text-lg lg:text-xl leading-relaxed max-w-4xl mx-auto">
                Transform your grocery receipts into intelligent meal plans. Our
                advanced AI analyzes your purchases, creates sustainable recipes,
                and helps you save money while making the most of your ingredients.
              </p>
              <div className="flex flex-col gap-3 sm:flex-row justify-center">
                <Link href="/upload">
                  <button className="btn-style5-black text-lg px-8 py-3">
                    Start Planning
                    <ArrowRight className="ml-2 h-5 w-5" />
                  </button>
                </Link>
                <Link href="/how-it-works">
                  <button className="btn-style5-black text-lg px-8 py-3">
                    See How It Works
                  </button>
                </Link>
              </div>
            </div>
          </div>
        </div>
      </section>

      {/* Features Section */}
      <section className="w-full py-16 md:py-24">
        <div className="max-w-7xl mx-auto px-4 md:px-6">
          <div className="text-center mb-16">
            <h2 className="text-3xl font-bold tracking-tighter sm:text-4xl md:text-5xl mb-4 gradient-text-white">
              Why Choose <span className="text-green-400">SmartRation</span>?
            </h2>
            <p className="max-w-3xl mx-auto gradient-text-light md:text-xl">
              Our AI-powered platform combines cutting-edge technology with
              practical meal planning to revolutionize how you approach food and
              budgeting.
            </p>
          </div>

          <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
            <div className="holographic-card-gradient rounded-2xl p-8 text-center scroll-animate">
              <div className="flex h-20 w-20 items-center justify-center rounded-full icon-container mx-auto mb-6">
                <Brain className="h-10 w-10" />
              </div>
              <h3 className="text-xl font-bold mb-4">AI-Powered Analysis</h3>
              <p>
                Our advanced AI analyzes your receipts, identifies ingredients,
                and creates personalized meal plans that maximize your grocery
                budget.
              </p>
            </div>

            <div className="holographic-card-gradient rounded-2xl p-8 text-center scroll-animate">
              <div className="flex h-20 w-20 items-center justify-center rounded-full icon-container mx-auto mb-6">
                <TrendingUp className="h-10 w-10" />
              </div>
              <h3 className="text-xl font-bold mb-4">Smart Budgeting</h3>
              <p>
                Get detailed cost analysis, spending insights, and recommendations
                to optimize your grocery budget and reduce unnecessary expenses.
              </p>
            </div>

            <div className="holographic-card-gradient rounded-2xl p-8 text-center scroll-animate">
              <div className="flex h-20 w-20 items-center justify-center rounded-full icon-container mx-auto mb-6">
                <ChefHat className="h-10 w-10" />
              </div>
              <h3 className="text-xl font-bold mb-4">Sustainable Recipes</h3>
              <p>
                Access thousands of AI-generated recipes that minimize food waste,
                use ingredients efficiently, and adapt to your dietary preferences.
              </p>
            </div>
          </div>
        </div>
      </section>

      {/* How It Works Section */}
      <section className="w-full py-16 md:py-24">
        <div className="max-w-7xl mx-auto px-4 md:px-6">
          <div className="text-center mb-16">
            <h2 className="text-3xl font-bold tracking-tighter sm:text-4xl md:text-5xl mb-4 gradient-text-white">
              How <span className="text-green-400">SmartRation</span> Works
            </h2>
            <p className="max-w-3xl mx-auto gradient-text-light md:text-xl">
              From receipt to meal plan in minutes. Our intelligent system
              processes your d
[truncated — 8774 more characters]
```

### smartration/app/email-verified/page.tsx

```typescript
"use client"

import Link from 'next/link'
import { Button } from '@/components/ui/button'
import { CheckCircle } from 'lucide-react'

export default function EmailVerifiedPage() {
  return (
    <div className="min-h-screen bg-white flex items-center justify-center">
      <div className="text-center">
        <h1 className="text-2xl font-bold text-gray-900">Verified</h1>
      </div>
    </div>
  )
} 
```

### smartration/app/verify-email/page.tsx

```typescript
"use client"

import { useState, useEffect } from 'react'
import { useRouter } from 'next/navigation'
import Link from 'next/link'
import { Button } from '@/components/ui/button'
import { Card } from '@/components/ui/card'
import { Mail, ArrowLeft } from 'lucide-react'
import { useAuth } from '@/lib/auth-context'

export default function VerifyEmailPage() {
  const router = useRouter()
  const { user, loading } = useAuth()
  const [email, setEmail] = useState('')

  useEffect(() => {
    if (!loading) {
      // If user is logged in and verified, redirect to email verified page
      if (user && user.email_confirmed_at) {
        router.push('/email-verified')
        return
      }

      // If user is logged in but not verified, set their email
      if (user) {
        setEmail(user.email || '')
      } else {
        // If no user is logged in, try to get email from localStorage
        const onboardingUser = localStorage.getItem('onboarding_user')
        if (onboardingUser) {
          const userData = JSON.parse(onboardingUser)
          setEmail(userData.email || '')
        } else {
          // If no user data in localStorage, redirect to signup
          router.push('/signup')
        }
      }
    }
  }, [user, loading, router])

  const handleResendEmail = async () => {
    try {
      // Resend verification email
      const { error } = await fetch('/api/auth/resend-verification', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ email }),
      }).then(res => res.json())

      if (error) {
        console.error('Error resending email:', error)
      }
    } catch (error) {
      console.error('Error resending email:', error)
    }
  }

  if (loading) {
    return (
      <div className="min-h-screen bg-green-50 flex items-center justify-center">
        <div className="text-center">
          <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-green-600 mx-auto"></div>
          <p className="mt-2 text-gray-600">Loading...</p>
        </div>
      </div>
    )
  }

  return (
    <div className="min-h-screen bg-green-50 flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
      <div className="max-w-md w-full space-y-8">
        <div className="text-center">
          <Link href="/login" className="inline-flex items-center text-green-600 hover:text-green-700 mb-4">
            <ArrowLeft className="h-4 w-4 mr-2" />
            Back to Login
          </Link>
          <Mail className="h-16 w-16 text-green-600 mx-auto mb-4" />
          <h2 className="text-3xl font-bold text-gray-900">Verify your email</h2>
          <p className="mt-2 text-sm text-gray-600">
            We've sent a verification link to your email address
          </p>
        </div>

        <Card className="p-6">
          <div className="space-y-6">
            <div className="text-center">
              <p className="text-sm text-gray-600 mb-4">
                Please check your email at <strong>{email}</strong> and click the verification link to continue.
              </p>
              <p className="text-xs text-gray-500 mb-4">
                If you don't see the email, check your spam folder.
              </p>
              <p className="text-sm text-gray-600 font-medium">
                After clicking the verification link, come back here and sign in to your account.
              </p>
            </div>

            <div className="space-y-4">
              <Button
                onClick={handleResendEmail}
                variant="outline"
                className="w-full"
              >
                Resend verification email
              </Button>
            </div>

            <div className="text-center">
              <p className="text-sm text-gray-600">
                Already verified?{' '}
                <Link href="/login" className="font-medium text-green-600 hover:text-green-700">
                  Sign in
                </Link>
              </p>
            </div>
          </div>
        </Card>
      </div>
    </div>
  )
} 
```

### smartration/app/dashboard/page.tsx

```typescript
"use client"

import { useState, useEffect } from "react"
import { useRouter } from "next/navigation"
import { Card } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Upload, ChefHat, Heart, MessageSquare, ShoppingCart, ArrowRight } from "lucide-react"
import DashboardLayout from "@/components/dashboard-layout"
import { useAuth } from "@/lib/auth-context"

export default function DashboardPage() {
  const router = useRouter()
  const { user, loading } = useAuth()

  useEffect(() => {
    if (!loading && !user) {
      router.push("/login")
      return
    }
  }, [user, loading, router])

  if (loading) {
    return (
      <DashboardLayout>
        <div className="flex items-center justify-center min-h-[60vh]">
          <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-green-500"></div>
        </div>
      </DashboardLayout>
    )
  }

  if (!user) {
    return null // Will redirect to login
  }

  // Get user's first name from metadata or email
  const firstName = user.user_metadata?.full_name?.split(' ')[0] || 
                   user.user_metadata?.name?.split(' ')[0] || 
                   user.email?.split('@')[0] || 
                   'User'

  const quickActions = [
    {
      title: "Upload Receipt",
      description: "Scan your grocery receipt to generate meal plans",
      icon: Upload,
      href: "/dashboard/upload",
      color: "bg-gradient-to-br from-green-500 to-emerald-500"
    },
    {
      title: "AI Meal Plans",
      description: "View your personalized meal plans",
      icon: ChefHat,
      href: "/dashboard/ai-meal-plans",
      color: "bg-gradient-to-br from-blue-500 to-sky-500"
    },
    {
      title: "Shopping List",
      description: "Generate AI-powered shopping lists based on your preferences",
      icon: ShoppingCart,
      href: "/dashboard/shopping-list",
      color: "bg-gradient-to-br from-indigo-500 to-purple-500"
    },
    {
      title: "Saved Meals",
      description: "Your favorite meals and recipes",
      icon: Heart,
      href: "/dashboard/saved-meals",
      color: "bg-gradient-to-br from-red-500 to-rose-500"
    },
    {
      title: "FoodGPT",
      description: "Get cooking advice and recipe help",
      icon: MessageSquare,
      href: "/dashboard/foodgpt",
      color: "bg-gradient-to-br from-purple-500 to-fuchsia-500"
    }
  ]

  function ActionCard({ action }: { action: typeof quickActions[0] }) {
    return (
      <div
        className="group relative cursor-pointer w-[350px]"
        onClick={() => router.push(action.href)}
      >
        <Card className="p-6 lg:p-8 border-2 border-gray-200 bg-white hover:border-green-400 hover:shadow-lg transition-all duration-300 h-full flex flex-col rounded-2xl">
          <div className="flex-1">
            <div className={`p-3 rounded-xl text-white ${action.color} inline-block mb-6 shadow-md`}>
              <action.icon className="h-7 w-7" />
            </div>
            <h3 className="text-xl font-semibold text-gray-900 mb-2">{action.title}</h3>
            <p className="text-gray-600">{action.description}</p>
          </div>
          <div className="mt-6 flex items-center text-green-600 font-semibold">
            <span>Go to {action.title}</span>
            <ArrowRight className="h-5 w-5 ml-2 transform group-hover:translate-x-1 transition-transform" />
          </div>
        </Card>
      </div>
    );
  }

  return (
    <DashboardLayout>
      <div className="max-w-none mx-auto space-y-8">
        {/* Welcome */}
        <div className="bg-gradient-to-r from-green-50 to-blue-50 rounded-2xl p-8 lg:p-12 shadow-sm border border-gray-200 text-center">
          <h1 className="text-4xl lg:text-5xl font-bold text-gray-900 mb-3">Welcome back, {firstName}</h1>
          <p className="text-gray-600 text-lg">Your smart kitchen assistant is ready to help you eat well and save money.</p>
        </div>

        {/* Quick Actions */}
        <div className="space-y-8">
          {/* first row of 3 */}
          <div className="flex justify-center gap-8">
            {quickActions.slice(0, 3).map((action, i) => (
              <ActionCard key={i} action={action} />
            ))}
          </div>

          {/* second row of remaining actions, centered */}
          <div className="flex justify-center gap-8">
            {quickActions.slice(3).map((action, i) => (
              <ActionCard key={i + 3} action={action} />
            ))}
          </div>
        </div>
      </div>
    </DashboardLayout>
  )
} 
```

### smartration/app/upload/page.tsx

```typescript
"use client"

import type React from "react"

import { useState } from "react"
import { useRouter } from "next/navigation"
import { Button } from "@/components/ui/button"
import { Card } from "@/components/ui/card"
import { Receipt, CheckCircle } from "lucide-react"
import { processImages } from "@/app/actions"
import ImageUploader from "@/components/image-uploader"

interface ReceiptItem {
  name: string
  price: number
  quantity?: number
}

interface ReceiptData {
  items: ReceiptItem[]
  total: number
  store?: string
  date?: string
}

export default function UploadPage() {
  const router = useRouter()
  const [receiptImage, setReceiptImage] = useState<File | null>(null)
  const [isLoading, setIsLoading] = useState(false)
  const [receiptData, setReceiptData] = useState<ReceiptData | null>(null)
  const [isProcessing, setIsProcessing] = useState(false)

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault()

    if (!receiptImage) {
      alert("Please upload a receipt photo")
      return
    }

    setIsProcessing(true)

    try {
      // Process the receipt image using Google Cloud Vision API
      const result = await processImages(null, receiptImage)
      
      if (result.success && result.receiptData) {
        setReceiptData(result.receiptData)
      }
    } catch (error) {
      console.error("Error processing image:", error)
      alert("There was an error processing your image. Please try again.")
    } finally {
      setIsProcessing(false)
    }
  }

  const handleGenerateMealPlan = () => {
    setIsLoading(true)
    // Navigate to results page
    router.push("/results")
  }

  return (
    <div className="max-w-7xl mx-auto px-4 py-8">
      <h1 className="text-3xl font-bold text-center mb-8">Upload Your Receipt</h1>

      <div className="max-w-3xl mx-auto">
        {!receiptData ? (
          <Card className="p-6">
            <form onSubmit={handleSubmit} className="space-y-8">
              <div className="space-y-4">
                <h2 className="text-xl font-semibold">Receipt Photo</h2>
                <p className="text-gray-500">
                  Upload a clear photo of your grocery receipt so we can identify purchased items and their costs.
                </p>
                <ImageUploader
                  icon={<Receipt className="h-8 w-8 text-green-600" />}
                  label="Upload Receipt Photo"
                  onChange={(file) => setReceiptImage(file)}
                />
              </div>

              <Button
                type="submit"
                className="w-full bg-green-600 hover:bg-green-700 text-white"
                disabled={isProcessing || !receiptImage}
              >
                {isProcessing ? "Processing Receipt..." : "Process Receipt"}
              </Button>
            </form>
          </Card>
        ) : (
          <Card className="p-6">
            <div className="space-y-6">
              <div className="flex items-center gap-2 text-green-600">
                <CheckCircle className="h-5 w-5" />
                <h2 className="text-xl font-semibold">Receipt Processed Successfully!</h2>
              </div>

              {receiptData.store && (
                <div>
                  <h3 className="font-medium text-gray-900">Store: {receiptData.store}</h3>
                </div>
              )}

              {receiptData.date && (
                <div>
                  <h3 className="font-medium text-gray-900">Date: {receiptData.date}</h3>
                </div>
              )}

              <div>
                <h3 className="font-medium text-gray-900 mb-3">Items Found:</h3>
                <div className="space-y-2">
                  {receiptData.items.map((item, index) => (
                    <div key={index} className="flex justify-between items-center p-2 bg-gray-50 rounded">
                      <span className="text-gray-700">{item.name}</span>
                      <span className="font-medium">${item.price.toFixed(2)}</span>
                    </div>
                  ))}
                </div>
              </div>

              <div className="border-t pt-4">
                <div className="flex justify-between items-center">
                  <span className="text-lg font-semibold">Total:</span>
                  <span className="text-lg font-bold text-green-600">${receiptData.total.toFixed(2)}</span>
                </div>
              </div>

              <Button
                onClick={handleGenerateMealPlan}
                className="w-full bg-green-600 hover:bg-green-700 text-white"
                disabled={isLoading}
              >
                {isLoading ? "Generating Meal Plan..." : "Generate Meal Plan"}
              </Button>
            </div>
          </Card>
        )}
      </div>
    </div>
  )
}

```

### smartration/app/about/page.tsx

```typescript
import Link from "next/link"
import { Button } from "@/components/ui/button"
import { Card } from "@/components/ui/card"
import { ArrowRight, Brain, HeartHandshake, Lightbulb, Target } from "lucide-react"

export default function AboutPage() {
  return (
    <div className="max-w-7xl mx-auto px-4 py-8">
      <h1 className="text-3xl font-bold text-center mb-8">About SmartRation</h1>

      <div className="max-w-3xl mx-auto">
        <Card className="p-8 mb-8">
          <h2 className="text-2xl font-bold mb-4">Our Mission</h2>
          <p className="text-gray-600 mb-6">
            SmartRation was created for the UC Berkeley AI Hackathon with a mission to help underpaid, low-income
            individuals and families maximize their food budgets through intelligent meal planning. By combining receipt
            scanning technology with refrigerator content analysis, we create personalized meal plans that reduce food
            waste and stretch grocery budgets further.
          </p>

          <div className="grid grid-cols-1 md:grid-cols-2 gap-6 mt-8">
            <div className="flex items-start">
              <div className="flex-shrink-0 mr-4">
                <div className="h-10 w-10 rounded-full bg-green-100 flex items-center justify-center">
                  <Target className="h-5 w-5 text-green-600" />
                </div>
              </div>
              <div>
                <h3 className="text-lg font-semibold mb-2">Our Goal</h3>
                <p className="text-gray-600">
                  To reduce food insecurity by helping people make the most of their available food resources through
                  AI-powered meal planning.
                </p>
              </div>
            </div>

            <div className="flex items-start">
              <div className="flex-shrink-0 mr-4">
                <div className="h-10 w-10 rounded-full bg-green-100 flex items-center justify-center">
                  <HeartHandshake className="h-5 w-5 text-green-600" />
                </div>
              </div>
              <div>
                <h3 className="text-lg font-semibold mb-2">Our Impact</h3>
                <p className="text-gray-600">
                  By reducing food waste and optimizing grocery budgets, we aim to help families save up to 25% on their
                  food expenses.
                </p>
              </div>
            </div>
          </div>
        </Card>

        <Card className="p-8 mb-8">
          <h2 className="text-2xl font-bold mb-4">The Technology</h2>
          <p className="text-gray-600 mb-6">
            SmartRation leverages cutting-edge AI technologies to deliver personalized meal planning:
          </p>

          <div className="space-y-6">
            <div className="flex items-start">
              <div className="flex-shrink-0 mr-4">
                <div className="h-10 w-10 rounded-full bg-green-100 flex items-center justify-center">
                  <Brain className="h-5 w-5 text-green-600" />
                </div>
              </div>
              <div>
                <h3 className="text-lg font-semibold mb-2">AI-Powered Analysis</h3>
                <p className="text-gray-600">
                  Our system uses computer vision and OCR (Optical Character Recognition) to identify food items in your
                  refrigerator and extract purchase information from receipts.
                </p>
              </div>
            </div>

            <div className="flex items-start">
              <div className="flex-shrink-0 mr-4">
                <div className="h-10 w-10 rounded-full bg-green-100 flex items-center justify-center">
                  <Lightbulb className="h-5 w-5 text-green-600" />
                </div>
              </div>
              <div>
                <h3 className="text-lg font-semibold mb-2">Smart Meal Planning</h3>
                <p className="text-gray-600">
                  Using large language models and nutritional databases, we generate meal plans that maximize the use of
                  available ingredients while ensuring nutritional balance and variety.
                </p>
              </div>
            </div>
          </div>
        </Card>

        <Card className="p-8">
          <h2 className="text-2xl font-bold mb-4">The Team</h2>
          <p className="text-gray-600 mb-6">
            SmartRation was developed by a team of UC Berkeley students passionate about using technology to address
            real-world problems. Our diverse backgrounds in computer science, nutrition, and social impact drive our
            commitment to creating accessible solutions for food insecurity.
          </p>

          <div className="text-center mt-8">
            <Link href="/contact">
              <Button className="bg-green-600 hover:bg-green-700 text-white">
                Contact Us
                <ArrowRight className="ml-2 h-4 w-4" />
              </Button>
            </Link>
          </div>
        </Card>
      </div>
    </div>
  )
}

```

### smartration/app/login/page.tsx

```typescript
"use client"

import { useState } from 'react'
import { useRouter } from 'next/navigation'
import Link from 'next/link'
import { Button } from '@/components/ui/button'
import { Card } from '@/components/ui/card'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { useAuth } from '@/lib/auth-context'
import { ArrowLeft, Mail, Lock, Eye, EyeOff } from 'lucide-react'

export default function LoginPage() {
  const router = useRouter()
  const { signIn } = useAuth()
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')
  const [isLoading, setIsLoading] = useState(false)
  const [error, setError] = useState('')
  const [showPassword, setShowPassword] = useState(false)

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault()
    setError('')

    setIsLoading(true)

    try {
      console.log('Attempting to sign in...')
      const { data, error } = await signIn(email, password)
      
      if (error) {
        console.error('Sign in error:', error)
        setError(error.message)
      } else {
        console.log('Sign in successful, redirecting to dashboard...')
        // Redirect to dashboard instead of upload
        router.push('/dashboard')
      }
    } catch (err) {
      console.error('Unexpected error:', err)
      setError('An unexpected error occurred')
    } finally {
      setIsLoading(false)
    }
  }

  return (
    <div className="min-h-screen bg-gray-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8">
      <div className="sm:mx-auto sm:w-full sm:max-w-md">
        <div className="flex justify-center">
          <Link href="/" className="flex items-center gap-2">
            <ArrowLeft className="h-5 w-5 text-gray-400" />
            <span className="text-sm text-gray-500">Back to home</span>
          </Link>
        </div>
        <div className="text-center mt-4">
          <h2 className="text-3xl font-bold text-gray-900">Welcome back</h2>
          <p className="mt-2 text-sm text-gray-600">
            Sign in to your SmartRation account
          </p>
        </div>
        </div>

      <div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
        <Card className="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
          <form className="space-y-6" onSubmit={handleSubmit}>
            <div>
              <Label htmlFor="email" className="flex items-center">
                <Mail className="h-4 w-4 mr-2" />
                Email address
              </Label>
              <div className="mt-1">
              <Input
                id="email"
                  name="email"
                type="email"
                  autoComplete="email"
                  required
                value={email}
                onChange={(e) => setEmail(e.target.value)}
                placeholder="Enter your email"
              />
              </div>
            </div>

            <div>
              <Label htmlFor="password" className="flex items-center">
                <Lock className="h-4 w-4 mr-2" />
                Password
              </Label>
              <div className="relative mt-1">
                <Input
                  id="password"
                  type={showPassword ? 'text' : 'password'}
                  value={password}
                  onChange={(e) => setPassword(e.target.value)}
                  placeholder="Enter your password"
                  required
                  className="pr-10"
                />
                <button
                  type="button"
                  onClick={() => setShowPassword(!showPassword)}
                  className="absolute inset-y-0 right-0 pr-3 flex items-center"
                >
                  {showPassword ? (
                    <EyeOff className="h-4 w-4 text-gray-400" />
                  ) : (
                    <Eye className="h-4 w-4 text-gray-400" />
                  )}
                </button>
              </div>
            </div>

            {error && (
              <div className="text-red-600 text-sm bg-red-50 p-3 rounded-md">
                {error}
              </div>
            )}

            <Button
              type="submit"
              className="w-full bg-green-600 hover:bg-green-700 text-white"
              disabled={isLoading}
            >
              {isLoading ? 'Signing In...' : 'Sign In'}
            </Button>
          </form>

          <div className="mt-6">
            <div className="relative">
              <div className="absolute inset-0 flex items-center">
                <div className="w-full border-t border-gray-300" />
              </div>
              <div className="relative flex justify-center text-sm">
                <span className="px-2 bg-white text-gray-500">Don't have an account?</span>
              </div>
            </div>

            <div className="mt-6">
              <Link
                href="/signup"
                className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-green-600 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500"
              >
                Create new account
              </Link>
            </div>
          </div>
        </Card>
      </div>
    </div>
  )
}

```

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