# CA Grow Ops Manager — Frontend

**Version**: 0.1.0  
**Stack**: TypeScript, React, Vite/Next.js, Radix UI/shadcn

---

## Overview

The frontend is a **mobile-first, accessible** web application optimized for low-friction daily use in cultivation facilities. It provides intuitive interfaces for tasks, batches, labor tracking, compliance, and team communication.

---

## Tech Stack

- **Language**: TypeScript 5.x
- **Framework**: React 18.x
- **Build Tool**: Vite or Next.js (to be decided during implementation)
- **Component Library**: Radix UI or shadcn-style accessible primitives
- **Styling**: Tailwind CSS or modern CSS-in-JS
- **State Management**: React Context + hooks (Zustand or Redux Toolkit for complex state)
- **Routing**: React Router (Vite) or Next.js App Router
- **Forms**: React Hook Form + Zod validation
- **API Client**: Axios or Fetch with TypeScript types
- **Testing**: Vitest + React Testing Library

---

## Project Structure

### Vite Option

```
frontend/
├── src/
│   ├── app/                  # App shell
│   │   ├── App.tsx
│   │   ├── Router.tsx
│   │   └── Layout.tsx
│   ├── pages/                # Page components
│   │   ├── Dashboard.tsx
│   │   ├── Tasks/
│   │   │   ├── TasksPage.tsx
│   │   │   ├── TaskDetail.tsx
│   │   │   └── TodayView.tsx
│   │   ├── Batches/
│   │   ├── Labor/
│   │   ├── Compliance/
│   │   └── Settings/
│   ├── components/           # Reusable components
│   │   ├── ui/               # Base UI components (buttons, inputs, etc.)
│   │   ├── tasks/            # Task-specific components
│   │   ├── batches/
│   │   └── shared/           # Shared components (nav, header, etc.)
│   ├── hooks/                # Custom React hooks
│   │   ├── useAuth.ts
│   │   ├── useTasks.ts
│   │   └── useApi.ts
│   ├── lib/                  # Utilities and helpers
│   │   ├── api.ts            # API client
│   │   ├── auth.ts           # Auth helpers
│   │   └── utils.ts
│   ├── types/                # TypeScript types
│   │   ├── api.ts
│   │   └── models.ts
│   ├── styles/               # Global styles
│   │   ├── index.css
│   │   └── tailwind.css
│   └── main.tsx              # Entry point
├── public/                   # Static assets
├── .env.example
├── package.json
├── tsconfig.json
├── vite.config.ts
└── README.md
```

### Next.js Option

```
frontend/
├── app/                      # Next.js App Router
│   ├── layout.tsx
│   ├── page.tsx              # Dashboard
│   ├── tasks/
│   │   ├── page.tsx
│   │   └── [id]/page.tsx
│   ├── batches/
│   ├── labor/
│   └── api/                  # API routes (if needed)
├── components/               # Same as Vite
├── hooks/
├── lib/
├── types/
├── styles/
└── public/
```

---

## Design System

### Component Library (Radix UI / shadcn)

Use accessible primitives for:

- **Buttons**: Primary, secondary, destructive
- **Inputs**: Text, number, date, select
- **Dialogs**: Modals, drawers, alerts
- **Dropdowns**: Menus, selects, comboboxes
- **Tabs**: Navigation, content switching
- **Cards**: Content containers
- **Badges**: Status indicators

### Styling (Tailwind CSS)

```css
/* Design tokens */
:root {
  --color-primary: #10b981;      /* Green for cultivation */
  --color-secondary: #3b82f6;    /* Blue for actions */
  --color-danger: #ef4444;       /* Red for alerts */
  --color-warning: #f59e0b;      /* Orange for warnings */
  --color-success: #10b981;      /* Green for success */
  
  --spacing-xs: 0.25rem;
  --spacing-sm: 0.5rem;
  --spacing-md: 1rem;
  --spacing-lg: 1.5rem;
  --spacing-xl: 2rem;
  
  --font-sans: 'Inter', system-ui, sans-serif;
  --font-mono: 'Fira Code', monospace;
}
```

### Mobile-First Design

- **Big Tap Targets**: Minimum 44×44px for all interactive elements
- **Dark Mode**: Default dark theme with light mode option
- **Responsive Breakpoints**:
  - Mobile: < 640px
  - Tablet: 640px - 1024px
  - Desktop: > 1024px

---

## Key Features

### 1. Today View (Mobile-Optimized)

```tsx
// TodayView.tsx
export const TodayView = () => {
  const { tasks, loading } = useTasks({ dueToday: true });
  
  return (
    <div className="p-4 space-y-4">
      <h1 className="text-2xl font-bold">Today's Tasks</h1>
      {tasks.map(task => (
        <TaskCard key={task.id} task={task} />
      ))}
    </div>
  );
};
```

### 2. Timeclock Widget

```tsx
// TimeclockWidget.tsx
export const TimeclockWidget = () => {
  const { currentShift, clockIn, clockOut } = useTimeclock();
  
  return (
    <Card className="p-6">
      {currentShift ? (
        <div>
          <p>Clocked in: {formatTime(currentShift.clockIn)}</p>
          <Button onClick={clockOut} size="lg">Clock Out</Button>
        </div>
      ) : (
        <Button onClick={clockIn} size="lg">Clock In</Button>
      )}
    </Card>
  );
};
```

### 3. Batch Timeline

```tsx
// BatchTimeline.tsx
export const BatchTimeline = ({ batchId }: { batchId: string }) => {
  const { events } = useBatchTimeline(batchId);
  
  return (
    <div className="space-y-4">
      {events.map(event => (
        <TimelineEvent key={event.id} event={event} />
      ))}
    </div>
  );
};
```

---

## API Integration

### API Client

```typescript
// lib/api.ts
import axios from 'axios';

const api = axios.create({
  baseURL: import.meta.env.VITE_API_URL,
  headers: {
    'Content-Type': 'application/json',
  },
});

// Add auth token to requests
api.interceptors.request.use(config => {
  const token = localStorage.getItem('accessToken');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

// Handle token refresh
api.interceptors.response.use(
  response => response,
  async error => {
    if (error.response?.status === 401) {
      // Attempt token refresh
      const refreshToken = localStorage.getItem('refreshToken');
      if (refreshToken) {
        const { data } = await axios.post('/api/auth/refresh', { refreshToken });
        localStorage.setItem('accessToken', data.accessToken);
        error.config.headers.Authorization = `Bearer ${data.accessToken}`;
        return axios(error.config);
      }
    }
    return Promise.reject(error);
  }
);

export default api;
```

### Custom Hooks

```typescript
// hooks/useTasks.ts
export const useTasks = (filters?: TaskFilters) => {
  const [tasks, setTasks] = useState<Task[]>([]);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    const fetchTasks = async () => {
      const { data } = await api.get('/api/tasks', { params: filters });
      setTasks(data.data);
      setLoading(false);
    };
    fetchTasks();
  }, [filters]);
  
  return { tasks, loading };
};
```

---

## Authentication

### Auth Context

```typescript
// hooks/useAuth.ts
const AuthContext = createContext<AuthContextType | null>(null);

export const AuthProvider = ({ children }: { children: ReactNode }) => {
  const [user, setUser] = useState<User | null>(null);
  
  const login = async (email: string, password: string) => {
    const { data } = await api.post('/api/auth/login', { email, password });
    localStorage.setItem('accessToken', data.accessToken);
    localStorage.setItem('refreshToken', data.refreshToken);
    setUser(data.user);
  };
  
  const logout = () => {
    localStorage.removeItem('accessToken');
    localStorage.removeItem('refreshToken');
    setUser(null);
  };
  
  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
};

export const useAuth = () => {
  const context = useContext(AuthContext);
  if (!context) throw new Error('useAuth must be used within AuthProvider');
  return context;
};
```

---

## Testing

### Component Tests (Vitest + React Testing Library)

```typescript
// TaskCard.test.tsx
import { render, screen } from '@testing-library/react';
import { TaskCard } from './TaskCard';

describe('TaskCard', () => {
  it('renders task name', () => {
    const task = { id: '1', name: 'Water plants', status: 'PENDING' };
    render(<TaskCard task={task} />);
    expect(screen.getByText('Water plants')).toBeInTheDocument();
  });
});
```

---

## Environment Variables

```bash
# API
VITE_API_URL=http://localhost:3000/api

# Auth
VITE_AUTH_ENABLED=true

# Features
VITE_METRC_ENABLED=false
```

---

## Development Workflow

### Setup

```bash
# Install dependencies
npm install

# Set up environment variables
cp .env.example .env

# Start dev server
npm run dev
```

### Scripts

```json
{
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview",
    "test": "vitest",
    "test:ui": "vitest --ui",
    "lint": "eslint src --ext .ts,.tsx",
    "format": "prettier --write src"
  }
}
```

---

## Accessibility

- **WCAG 2.1 AA Compliance**: All components meet accessibility standards
- **Keyboard Navigation**: All interactive elements keyboard-accessible
- **Screen Reader Support**: Proper ARIA labels and roles
- **Focus Management**: Clear focus indicators and logical tab order
- **Color Contrast**: Minimum 4.5:1 contrast ratio for text

---

## Mobile & PWA

### Progressive Web App (Stretch Goal)

```typescript
// vite.config.ts
import { VitePWA } from 'vite-plugin-pwa';

export default defineConfig({
  plugins: [
    VitePWA({
      registerType: 'autoUpdate',
      manifest: {
        name: 'CA Grow Ops Manager',
        short_name: 'Grow Ops',
        theme_color: '#10b981',
        icons: [
          { src: '/icon-192.png', sizes: '192x192', type: 'image/png' },
          { src: '/icon-512.png', sizes: '512x512', type: 'image/png' },
        ],
      },
    }),
  ],
});
```

---

## Next Steps

1. **Choose Build Tool**: Decide between Vite and Next.js
2. **Set Up Project**: Initialize React project with TypeScript
3. **Configure Tailwind**: Set up Tailwind CSS and design tokens
4. **Build Design System**: Implement base UI components
5. **Implement Pages**: Build page components per spec
6. **Write Tests**: Component and integration tests
7. **Deploy**: Set up CI/CD and deploy to staging

---

## Resources

- [React Documentation](https://react.dev)
- [Vite Documentation](https://vitejs.dev)
- [Next.js Documentation](https://nextjs.org/docs)
- [Radix UI Documentation](https://www.radix-ui.com)
- [Tailwind CSS Documentation](https://tailwindcss.com/docs)
- [React Testing Library](https://testing-library.com/react)
