Firebase is not installed and no config files exist yet. I have all the information I need. Here is the complete implementation plan.

---

## Implementation Plan

### Icon Verification (lucide-react 0.383.0)

All requested icons are confirmed present as named exports:

| Subject | Icon Component | Import Name |
|---|---|---|
| Math | Calculator | `Calculator` |
| English | BookOpen | `BookOpen` |
| Arabic | PenLine | `PenLine` |
| Science | Microscope | `Microscope` |
| Art | Palette | `Palette` |
| PE | Trophy | `Trophy` |
| Islamic Studies | Moon | `Moon` |
| Story Time | BookMarked | `BookMarked` |
| Phonics | BookOpen | `BookOpen` |

Additional UI icons also confirmed: `Clock`, `AlertTriangle`, `Bell`, `Calendar`, `Plus`, `X`, `Heart`, `Sparkles`.

For kid avatars (replacing lion/butterfly emojis): use `User` with a styled colored circle background — there is no animal icon for lion or butterfly. The cleanest approach is a colored initial-letter avatar (CSS circle with the kid's `color` as background) rather than forcing an icon that doesn't match the originals.

---

### Complete File List

**Files to modify (4):**

1. `src/data/constants.js`
2. `src/hooks/useTasks.js`
3. `src/App.jsx`
4. `src/App.css`

**Files to create (5):**

5. `src/lib/firebase.js` — Firebase init with graceful localStorage fallback
6. `src/hooks/useFirebaseTasks.js` — Firebase-aware task hook replacing useTasks
7. `.env.local` — local Firebase env vars (never committed)
8. `.gitignore` — exclude `.env.local`, `node_modules`, `dist`
9. `vercel.json` — Vercel deployment config (SPA routing)

**No changes needed:**

- `src/main.jsx` — no changes required
- `vite.config.js` — no changes required
- `index.html` — only the favicon emoji can optionally be swapped for an SVG data URI, not required

---

### Step-by-Step Implementation

#### Step 1 — Install Firebase

```
npm install firebase
```

Firebase modular SDK (v9+) is what you want. It tree-shakes well with Vite.

#### Step 2 — `src/data/constants.js`

Three changes:
- Remove `emoji` field from each kid in `KIDS` (or keep it as a fallback string for the `<title>` tag, but remove it from the UI render path)
- Replace `SUBJECT_ICONS` emoji map with a component-map approach — **do not** store JSX in constants. Instead export a plain string-keyed object mapping to lucide component references, or handle the mapping inside a small helper in App.jsx. The cleanest pattern: keep `SUBJECT_ICONS` as an object but map to string keys that App.jsx resolves to components via a lookup table defined alongside the import.
- Change `SOURCES` to `["Telegram", "Edunation"]`
- Update `EMPTY_FORM` default `source` in App.jsx from `"Notebook"` to `"Telegram"` (since Notebook will no longer be a valid option)
- Remove `"Done ✓"` text label emoji from `STATUSES` — change to `"Done"` since the checkmark will be a lucide `Check` icon inline

#### Step 3 — `src/lib/firebase.js`

```js
// Pattern: try to init Firebase, export null if env vars missing
const FIREBASE_READY = !!(
  import.meta.env.VITE_FIREBASE_API_KEY &&
  import.meta.env.VITE_FIREBASE_DATABASE_URL
);
```

The `FIREBASE_READY` flag checks both `VITE_FIREBASE_API_KEY` and `VITE_FIREBASE_DATABASE_URL` because Realtime Database (not Firestore) needs the databaseURL explicitly — it is not inferred from the project config alone.

Export pattern:
```js
export { database, FIREBASE_READY };
// database is null when FIREBASE_READY === false
```

Use dynamic import is NOT needed here since Vite handles dead-code elimination on `import.meta.env` constants at build time. Use a regular conditional init with a try/catch.

#### Step 4 — `src/hooks/useFirebaseTasks.js`

This replaces `useTasks.js` entirely. Architecture:

```
useFirebaseTasks()
  ├─ if FIREBASE_READY:
  │   ├─ ref(database, "tasks")
  │   ├─ onValue() listener → setTasks()
  │   ├─ addTask → push() to Firebase (no local setTasks, listener handles it)
  │   ├─ updateStatus / updateTask → update() patch
  │   └─ removeTask → remove()
  └─ else (localStorage fallback):
      └─ identical logic to current useTasks.js
```

Key gotcha: Firebase Realtime Database `onValue` fires immediately with current data, so you do not need a separate "load" step. The listener replaces the `useState` initializer. Return an `isLoading` boolean (`true` until first snapshot fires) so App.jsx can show a subtle loading state.

The `id` field: `Date.now()` works fine for localStorage but for Firebase use `push()` which auto-generates a key. Store the Firebase key as the task's `id` so `updateStatus`/`removeTask` can reference it by path.

#### Step 5 — `src/App.jsx`

Define an icon lookup table at the top of the file (not in constants, since it's JSX-adjacent):

```jsx
import { Calculator, BookOpen, PenLine, Microscope, Palette, Trophy, Moon, BookMarked, Clock, AlertTriangle, Bell, Calendar, Plus, X, Heart, Sparkles } from "lucide-react";

const SUBJECT_ICON_MAP = {
  Math: Calculator,
  English: BookOpen,
  Phonics: BookOpen,
  Arabic: PenLine,
  Science: Microscope,
  Art: Palette,
  PE: Trophy,
  "Islamic Studies": Moon,
  "Story Time": BookMarked,
};

function SubjectIcon({ subject, size = 18, ...props }) {
  const Icon = SUBJECT_ICON_MAP[subject];
  return Icon ? <Icon size={size} {...props} /> : <BookOpen size={size} {...props} />;
}
```

Emoji replacement locations in App.jsx (line references from the file you provided):

| Location | Old | New |
|---|---|---|
| Line 97 `header-date` | static date string | Add `<Clock>` icon + live clock via `useEffect` with `setInterval(1000)` |
| Line 131 `kid-emoji` span | `{k.emoji}` | Replace with colored initial avatar div |
| Line 167 `.section-label` | `📅 This Week` | `<Calendar size={14} />` + ` This Week` |
| Line 248 day-task-chip | `{SUBJECT_ICONS[t.subject]}` | `<SubjectIcon subject={t.subject} size={13} />` |
| Line 289 tab buttons | `📝 Homework` / `🎨 Projects` | lucide icons inline |
| Line 321 form-title | `➕` + `{kid.emoji}` | `<Plus size={14} />` + remove kid emoji |
| Line 337 subject select options | `{SUBJECT_ICONS[s]}` | Cannot render SVG in `<option>` — **remove icons from select options entirely**, just show the text. This is a known HTML limitation. |
| Line 401 type-toggle buttons | `📝` / `🎨` | Lucide inline |
| Line 438 empty-state emoji div | `🎉` / `🌟` | `<Sparkles>` for both |
| Line 514 task-due | `⚠` / `🔔` / `📅` | `<AlertTriangle>` / `<Bell>` / `<Calendar>` |
| Line 559 footer | `❤` | `<Heart size={12} fill="currentColor" />` |

Live clock implementation:
```jsx
const [clock, setClock] = useState(() => new Date());
useEffect(() => {
  const id = setInterval(() => setClock(new Date()), 1000);
  return () => clearInterval(id);
}, []);
```

Display `clock.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", second: "2-digit" })` in the header alongside the date.

#### Step 6 — `src/App.css`

Changes needed for SVG icons vs emojis:

**Kid avatar** — replace `.kid-emoji` font-size rule with an initial-letter avatar:
```css
.kid-avatar {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  font-weight: 900;
  color: white;
  margin: 0 auto 5px;
  flex-shrink: 0;
}
```
At mobile breakpoint (520px) scale to `38px`.

**Task icon box** — the current `.task-icon` uses `font-size: 22px` for emoji. SVG does not use font-size. Change to:
```css
.task-icon {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  /* Remove font-size: 22px */
}
.task-icon svg {
  display: block; /* prevents inline baseline gap */
}
```

**Inline SVG alignment** — anywhere a lucide icon appears next to text, the parent needs `display: flex; align-items: center; gap: 5px`. The `.section-label`, `.tab-btn`, `.day-task-chip`, and `.task-due` spans all need this. Add:
```css
.section-label,
.tab-btn,
.day-task-chip,
.task-due {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
```
`.day-task-chip` is currently `display: inline` — change to `inline-flex`.

**Empty state** — `.empty-emoji` uses `font-size: 44px` for emoji display. Replace with:
```css
.empty-icon {
  display: flex;
  justify-content: center;
  margin-bottom: 10px;
  color: inherit; /* inherits from parent which has kid.light context */
}
```

**Clock display** — add:
```css
.header-clock {
  font-size: 13px;
  font-weight: 700;
  opacity: 0.9;
  font-variant-numeric: tabular-nums; /* prevents layout shift as digits change */
  letter-spacing: 0.5px;
}
.header-date-row {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
}
```

#### Step 7 — `.env.local`

```
VITE_FIREBASE_API_KEY=your_key_here
VITE_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
VITE_FIREBASE_DATABASE_URL=https://your_project-default-rtdb.firebaseio.com
VITE_FIREBASE_PROJECT_ID=your_project_id
VITE_FIREBASE_APP_ID=your_app_id
```

Only `VITE_FIREBASE_API_KEY` and `VITE_FIREBASE_DATABASE_URL` are strictly required by the FIREBASE_READY check, but include all five for completeness.

#### Step 8 — `.gitignore`

```
node_modules
dist
.env.local
.env*.local
```

#### Step 9 — `vercel.json`

```json
{
  "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
}
```

Vite builds to `dist/` by default and Vercel auto-detects Vite projects, so no `buildCommand` or `outputDirectory` override is needed unless you have a custom vite.config output path (you don't).

In the Vercel dashboard, set the five `VITE_FIREBASE_*` environment variables under Project Settings > Environment Variables. They must be prefixed `VITE_` for Vite to expose them to the client bundle.

---

### Gotchas to Watch For

1. **SVG in `<option>` tags is impossible.** Browsers strip all HTML from `<option>` elements. Remove the icon from the subject `<select>` options — plain text only. The `SubjectIcon` component is only usable outside of `<select>`.

2. **Firebase Realtime Database vs Firestore.** You said Realtime Database. The import path is `firebase/database`, not `firebase/firestore`. The `databaseURL` in the config is mandatory and must be explicitly set — unlike Firestore which infers the endpoint from `projectId`. Use `ref`, `onValue`, `push`, `update`, `remove` from `firebase/database`.

3. **Task ID strategy changes with Firebase.** Currently `Date.now()` is used as the id. With Firebase `push()`, the key is a string like `"-O1abc..."`. The `removeTask` and `updateTask` functions must use this key as the database path segment. When reading from `onValue`, the snapshot's `.val()` returns an object keyed by these push IDs — you must convert it to an array: `Object.entries(val).map(([id, data]) => ({ id, ...data }))`.

4. **`EMPTY_FORM.source` default breaks silently.** Currently hardcoded to `"Notebook"` which will not exist in the new `["Telegram", "Edunation"]` array. Change the default to `"Telegram"` in App.jsx line 22.

5. **`font-variant-numeric: tabular-nums` on the clock.** Without this, the live clock causes a subtle layout reflow every second as variable-width digits change (e.g., `1` vs `8`). Always set this on clock elements.

6. **Firebase cold-start flicker.** The `onValue` listener takes ~200-400ms to fire the first time. Without an `isLoading` guard, the task list briefly renders as empty (hitting the empty state UI) before data arrives. Return `isLoading: true` from `useFirebaseTasks` until the first snapshot, and render a skeleton or nothing in App.jsx.

7. **`"Done ✓"` label in STATUSES.** Currently the status dropdown options render this literal string including the checkmark character. After removing emojis, clean this up to just `"Done"` in constants.js, since you can render a lucide `Check` icon next to it in the badge display.

8. **Vercel and env vars at build time.** Vite bakes `import.meta.env.VITE_*` into the static bundle at build time — they are not runtime env vars. This means if the env vars are not set in Vercel before building, `FIREBASE_READY` will be `false` in the deployed bundle and it will fall back to localStorage. Set them in Vercel before triggering the first deploy.

---

### Critical Files for Implementation

- `/Users/khalidbinkalban/ascs-homework-tracker/src/App.jsx`
- `/Users/khalidbinkalban/ascs-homework-tracker/src/hooks/useTasks.js`
- `/Users/khalidbinkalban/ascs-homework-tracker/src/data/constants.js`
- `/Users/khalidbinkalban/ascs-homework-tracker/src/App.css`
- `/Users/khalidbinkalban/ascs-homework-tracker/src/lib/firebase.js` (to be created)

Prompt:
I'm about to update a React + Vite app at /Users/khalidbinkalban/ascs-homework-tracker with these changes:

1. Replace ALL emojis with SVG icons (using lucide-react which is already installed at ^0.383.0)
2. Change SOURCES constant to only ["Telegram", "Edunation"]
3. Add live clock (updates every second)
4. Add Firebase Realtime Database for real-time sync between devices
5. Deploy to Vercel for a shareable URL

Current files:
- src/data/constants.js — has KIDS (with emoji field), SUBJECTS, STATUSES, SOURCES, SUBJECT_ICONS (emoji map), DAYS, SAMPLE_TASKS
- src/hooks/useTasks.js — localStorage-based task management
- src/App.jsx — main component using emojis throughout
- src/App.css — styling
- src/main.jsx — entry point

I need to know:
1. Exact list of all files to create/modify
2. Which lucide-react icons to use for each subject (Math→Calculator, English→BookOpen, Arabic→PenLine, Science→Microscope, Art→Palette, PE→Trophy, Islamic Studies→Moon, Story Time→BookMarked, Phonics→BookOpen) — confirm these exist in lucide-react 0.383
3. Best approach for Firebase Realtime Database integration with a localStorage fallback when Firebase env vars aren't set
4. What FIREBASE_READY flag logic should look like
5. What CSS changes are needed for SVG icons vs emoji (kid avatar sizing, task icon sizing, inline SVG alignment)

Return a concise implementation plan with exact file list and any gotchas to watch for.


Good, I have the full plan. Let me now implement everything in parallel.


Bash

which vercel 2>/dev/null || npx vercel --version 2>/dev/null | head -1 || echo "vercel-not-found"


To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.


Command running in background with ID: b8hh930x5. Output is being written to: /private/tmp/claude-501/-Users-khalidbinkalban/b8a417d9-4c38-43aa-9f78-45d2d13b63d0/tasks/b8hh930x5.output


cat /private/tmp/claude-501/-Users-khalidbinkalban/b8a417d9-4c38-43aa-9f78-45d2d13b63d0/tasks/b8hh930x5.output 2>/dev/null || echo "pending"


vercel not found


Now let me write all files in parallel:


Write

export const KIDS = [
  {
    id: "abdulla",
    name: "Abdulla",
    grade: "Grade 2",
    color: "#1D9E75",
    light: "#E1F5EE",
    dark: "#0F6E56",
  },
  {
    id: "salama",
    name: "Salama",
    grade: "KG 1",
    color: "#D4537E",
    light: "#FBEAF0",
    dark: "#993556",
  },
];

export const SUBJECTS = {
  abdulla: ["Math", "English", "Arabic", "Science", "Islamic Studies", "Art", "PE"],
  salama: ["Phonics", "Math", "Arabic", "Islamic Studies", "Art", "PE", "Story Time"],
};

export const STATUSES = [
  { id: "new", label: "New", bg: "#E6F1FB", text: "#185FA5", dot: "#378ADD" },
  { id: "inprogress", label: "In Progress", bg: "#FAEEDA", text: "#854F0B", dot: "#EF9F27" },
  { id: "completed", label: "Done", bg: "#EAF3DE", text: "#3B6D11", dot: "#639922" },
];

export const SOURCES = ["Telegram", "Edunation"];

export const DAYS = ["Mon", "Tue", "Wed", "Thu", "Fri"];

export const SAMPLE_TASKS = {
  abdulla: [
    {
      id: 1,
      subject: "Math",
      title: "Addition worksheet p.12",
      status: "inprogress",
      source: "Telegram",
      type: "homework",
    },
    {
      id: 2,
      subject: "English",
      title: "Read pages 10–15 and answer questions",
      status: "new",
      source: "Edunation",
      type: "homework",
    },
    {
      id: 3,
      subject: "Science",
      title: "Solar System Poster",
      status: "new",
      source: "Telegram",
      type: "project",
    },
  ],
  salama: [
    {
      id: 1,
      subject: "Phonics",
      title: "Letter B practice sheet",
      status: "completed",
      source: "Edunation",
      type: "homework",
    },
    {
      id: 2,
      subject: "Math",
      title: "Count to 20 worksheet",
      status: "new",
      source: "Edunation",
      type: "homework",
    },
    {
      id: 3,
      subject: "Art",
      title: "My Family Drawing",
      status: "inprogress",
      source: "Telegram",
      type: "project",
    },
  ],
};


The file /Users/khalidbinkalban/ascs-homework-tracker/src/data/constants.js has been updated successfully.

export const KIDS = [
  {
    id: "abdulla",
    name: "Abdulla",
    grade: "Grade 2",
    color: "#1D9E75",
    light: "#E1F5EE",
    dark: "#0F6E56",
  },
  {
    id: "salama",
    name: "Salama",
    grade: "KG 1",
    color: "#D4537E",
    light: "#FBEAF0",
    dark: "#993556",
  },
];

export const SUBJECTS = {
  abdulla: ["Math", "English", "Arabic", "Science", "Islamic Studies", "Art", "PE"],
  salama: ["Phonics", "Math", "Arabic", "Islamic Studies", "Art", "PE", "Story Time"],
};

export const STATUSES = [
  { id: "new", label: "New", bg: "#E6F1FB", text: "#185FA5", dot: "#378ADD" },
  { id: "inprogress", label: "In Progress", bg: "#FAEEDA", text: "#854F0B", dot: "#EF9F27" },
  { id: "completed", label: "Done", bg: "#EAF3DE", text: "#3B6D11", dot: "#639922" },
];

export const SOURCES = ["Telegram", "Edunation"];

export const DAYS = ["Mon", "Tue", "Wed", "Thu", "Fri"];

export const SAMPLE_TASKS = {
  abdulla: [
    {
      id: 1,
      subject: "Math",
      title: "Addition worksheet p.12",
      status: "inprogress",
      source: "Telegram",
      type: "homework",
    },
    {
      id: 2,
      subject: "English",
      title: "Read pages 10–15 and answer questions",
      status: "new",
      source: "Edunation",
      type: "homework",
    },
    {
      id: 3,
      subject: "Science",
      title: "Solar System Poster",
      status: "new",
      source: "Telegram",
      type: "project",
    },
  ],
  salama: [
    {
      id: 1,
      subject: "Phonics",
      title: "Letter B practice sheet",
      status: "completed",
      source: "Edunation",
      type: "homework",
    },
    {
      id: 2,
      subject: "Math",
      title: "Count to 20 worksheet",
      status: "new",
      source: "Edunation",
      type: "homework",
    },
    {
      id: 3,
      subject: "Art",
      title: "My Family Drawing",
      status: "inprogress",
      source: "Telegram",
      type: "project",
    },
  ],
};

id: "abdulla",
name: "Abdulla",
grade: "Grade 2",
-    emoji: "🦁",
color: "#1D9E75",
light: "#E1F5EE",
dark: "#0F6E56",

id: "salama",
name: "Salama",
grade: "KG 1",
-    emoji: "🦋",
color: "#D4537E",
light: "#FBEAF0",
dark: "#993556",

-  { id: "completed", label: "Done ✓", bg: "#EAF3DE", text: "#3B6D11", dot: "#639922" },

+export const SOURCES = ["Telegram", "Edunation"];

subject: "Science",
title: "Solar System Poster",
status: "new",
-      source: "Class WhatsApp",
+      source: "Telegram",
type: "project",
},
],

subject: "Math",
title: "Count to 20 worksheet",
status: "new",
-      source: "School App",
+      source: "Edunation",
type: "homework",
},
{

subject: "Art",
title: "My Family Drawing",
status: "inprogress",
-      source: "Verbal (Teacher)",
+      source: "Telegram",
type: "project",
},
],

export const KIDS = [
  {
    id: "abdulla",
    name: "Abdulla",
    grade: "Grade 2",
    emoji: "🦁",
    color: "#1D9E75",
    light: "#E1F5EE",
    dark: "#0F6E56",
  },
  {
    id: "salama",
    name: "Salama",
    grade: "KG 1",
    emoji: "🦋",
    color: "#D4537E",
    light: "#FBEAF0",
    dark: "#993556",
  },
];

export const SUBJECTS = {
  abdulla: ["Math", "English", "Arabic", "Science", "Islamic Studies", "Art", "PE"],
  salama: ["Phonics", "Math", "Arabic", "Islamic Studies", "Art", "PE", "Story Time"],
};

export const STATUSES = [
  { id: "new", label: "New", bg: "#E6F1FB", text: "#185FA5", dot: "#378ADD" },
  { id: "inprogress", label: "In Progress", bg: "#FAEEDA", text: "#854F0B", dot: "#EF9F27" },
  { id: "completed", label: "Done ✓", bg: "#EAF3DE", text: "#3B6D11", dot: "#639922" },
];

export const SOURCES = [
  "Teacher Portal",
  "Class WhatsApp",
  "Notebook",
  "Email",
  "Verbal (Teacher)",
  "School App",
  "Printed Sheet",
];

export const SUBJECT_ICONS = {
  Math: "🔢",
  English: "📖",
  Phonics: "📖",
  Arabic: "✍",
  Science: "🔬",
  Art: "🎨",
  PE: "⚽",
  "Islamic Studies": "🌙",
  "Story Time": "📚",
};

export const DAYS = ["Mon", "Tue", "Wed", "Thu", "Fri"];

export const SAMPLE_TASKS = {
  abdulla: [
    {
      id: 1,
      subject: "Math",
      title: "Addition worksheet p.12",
      status: "inprogress",
      source: "Notebook",
      type: "homework",
    },
    {
      id: 2,
      subject: "English",
      title: "Read pages 10–15 and answer questions",
      status: "new",
      source: "Teacher Portal",
      type: "homework",
    },
    {
      id: 3,
      subject: "Science",
      title: "Solar System Poster",
      status: "new",
      source: "Class WhatsApp",
      type: "project",
    },
  ],
  salama: [
    {
      id: 1,
      subject: "Phonics",
      title: "Letter B practice sheet",
      status: "completed",
      source: "Notebook",
      type: "homework",
    },
    {
      id: 2,
      subject: "Math",
      title: "Count to 20 worksheet",
      status: "new",
      source: "School App",
      type: "homework",
    },
    {
      id: 3,
      subject: "Art",
      title: "My Family Drawing",
      status: "inprogress",
      source: "Verbal (Teacher)",
      type: "project",
    },
  ],
};


<task-notification>
<task-id>b8hh930x5</task-id>
<tool-use-id>toolu_01KfVVcLnjP5RQ7CKKfqust4</tool-use-id>
<output-file>/private/tmp/claude-501/-Users-khalidbinkalban/b8a417d9-4c38-43aa-9f78-45d2d13b63d0/tasks/b8hh930x5.output</output-file>
<status>completed</status>
<summary>Background command "which vercel 2>/dev/null || npx vercel --version 2>/dev/null | head -1 || echo "vercel-not-found"" completed (exit code 0)</summary>
</task-notification>


import { initializeApp } from "firebase/app";
import { getDatabase } from "firebase/database";

export const FIREBASE_READY = !!(
  import.meta.env.VITE_FIREBASE_API_KEY &&
  import.meta.env.VITE_FIREBASE_DATABASE_URL
);

let database = null;

if (FIREBASE_READY) {
  try {
    const app = initializeApp({
      apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
      authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
      databaseURL: import.meta.env.VITE_FIREBASE_DATABASE_URL,
      projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
      storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
      messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
      appId: import.meta.env.VITE_FIREBASE_APP_ID,
    });
    database = getDatabase(app);
  } catch (e) {
    console.warn("Firebase init failed:", e);
  }
}

export { database };


File created successfully at: /Users/khalidbinkalban/ascs-homework-tracker/src/lib/firebase.js

import { initializeApp } from "firebase/app";
import { getDatabase } from "firebase/database";

export const FIREBASE_READY = !!(
  import.meta.env.VITE_FIREBASE_API_KEY &&
  import.meta.env.VITE_FIREBASE_DATABASE_URL
);

let database = null;

if (FIREBASE_READY) {
  try {
    const app = initializeApp({
      apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
      authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
      databaseURL: import.meta.env.VITE_FIREBASE_DATABASE_URL,
      projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
      storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
      messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
      appId: import.meta.env.VITE_FIREBASE_APP_ID,
    });
    database = getDatabase(app);
  } catch (e) {
    console.warn("Firebase init failed:", e);
  }
}

export { database };


VITE_FIREBASE_API_KEY=your_api_key_here
VITE_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
VITE_FIREBASE_DATABASE_URL=https://your_project-default-rtdb.firebaseio.com
VITE_FIREBASE_PROJECT_ID=your_project_id
VITE_FIREBASE_STORAGE_BUCKET=your_project.appspot.com
VITE_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
VITE_FIREBASE_APP_ID=your_app_id


File created successfully at: /Users/khalidbinkalban/ascs-homework-tracker/.env.example

VITE_FIREBASE_API_KEY=your_api_key_here
VITE_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
VITE_FIREBASE_DATABASE_URL=https://your_project-default-rtdb.firebaseio.com
VITE_FIREBASE_PROJECT_ID=your_project_id
VITE_FIREBASE_STORAGE_BUCKET=your_project.appspot.com
VITE_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
VITE_FIREBASE_APP_ID=your_app_id


node_modules
dist
.env.local
.env*.local
.DS_Store


File created successfully at: /Users/khalidbinkalban/ascs-homework-tracker/.gitignore

node_modules
dist
.env.local
.env*.local
.DS_Store


{
  "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
}


File created successfully at: /Users/khalidbinkalban/ascs-homework-tracker/vercel.json


export function LionAvatar({ size = 44 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
      {/* Mane rays */}
      {Array.from({ length: 12 }, (_, i) => {
        const angle = (i * 30 * Math.PI) / 180 - Math.PI / 2;
        return (
          <line
            key={i}
            x1={22 + 13 * Math.cos(angle)}
            y1={22 + 13 * Math.sin(angle)}
            x2={22 + 20 * Math.cos(angle)}
            y2={22 + 20 * Math.sin(angle)}
            stroke="#E89530"
            strokeWidth="3.5"
            strokeLinecap="round"
          />
        );
      })}
      {/* Face */}
      <circle cx="22" cy="22" r="13" fill="#F5B84A" />
      {/* Ears */}
      <circle cx="11" cy="12" r="4.5" fill="#E89530" />
      <circle cx="33" cy="12" r="4.5" fill="#E89530" />
      <circle cx="11" cy="12" r="2.5" fill="#F5B84A" />
      <circle cx="33" cy="12" r="2.5" fill="#F5B84A" />
      {/* Eyes */}
      <ellipse cx="17.5" cy="20" rx="2.6" ry="2.3" fill="white" />
      <ellipse cx="26.5" cy="20" rx="2.6" ry="2.3" fill="white" />
      <circle cx="18" cy="20.5" r="1.4" fill="#1A0A00" />
      <circle cx="27" cy="20.5" r="1.4" fill="#1A0A00" />
      <circle cx="18.4" cy="20.1" r="0.55" fill="white" />
      <circle cx="27.4" cy="20.1" r="0.55" fill="white" />
      {/* Nose */}
      <ellipse cx="22" cy="25" rx="2.3" ry="1.6" fill="#C87030" />
      {/* Mouth */}
      <path d="M19.8 27 Q22 29 24.2 27" stroke="#C87030" strokeWidth="1.2" fill="none" strokeLinecap="round" />
      <path d="M22 26 L22 25" stroke="#C87030" strokeWidth="1" strokeLinecap="round" />
      {/* Whiskers */}
      <line x1="10" y1="25.5" x2="18.5" y2="24.5" stroke="#D09040" strokeWidth="0.8" opacity="0.55" />
      <line x1="10" y1="27.5" x2="18.5" y2="26.5" stroke="#D09040" strokeWidth="0.8" opacity="0.55" />
      <line x1="34" y1="25.5" x2="25.5" y2="24.5" stroke="#D09040" strokeWidth="0.8" opacity="0.55" />
      <line x1="34" y1="27.5" x2="25.5" y2="26.5" stroke="#D09040" strokeWidth="0.8" opacity="0.55" />
    </svg>
  );
}

export function ButterflyAvatar({ color = "#D4537E", size = 44 }) {
  const dark = "#7A2B4A";
  return (
    <svg width={size} height={size} viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
      {/* Upper wings */}
      <ellipse cx="13" cy="19" rx="11.5" ry="8.5" fill={color} transform="rotate(-18 13 19)" />
      <ellipse cx="31" cy="19" rx="11.5" ry="8.5" fill={color} transform="rotate(18 31 19)" />
      {/* Lower wings */}
      <ellipse cx="14.5" cy="30" rx="8" ry="6" fill={color} opacity="0.78" transform="rotate(18 14.5 30)" />
      <ellipse cx="29.5" cy="30" rx="8" ry="6" fill={color} opacity="0.78" transform="rotate(-18 29.5 30)" />
      {/* Wing shine */}
      <ellipse cx="12" cy="18" rx="5" ry="3.5" fill="white" opacity="0.22" transform="rotate(-18 12 18)" />
      <ellipse cx="32" cy="18" rx="5" ry="3.5" fill="white" opacity="0.22" transform="rotate(18 32 18)" />
      {/* Wing dots */}
      <circle cx="9" cy="23" r="2.8" fill="white" opacity="0.28" />
      <circle cx="35" cy="23" r="2.8" fill="white" opacity="0.28" />
      <circle cx="9" cy="23" r="1.3" fill={dark} opacity="0.3" />
      <circle cx="35" cy="23" r="1.3" fill={dark} opacity="0.3" />
      {/* Body */}
      <ellipse cx="22" cy="25" rx="2.4" ry="10" fill={dark} />
      {/* Head */}
      <circle cx="22" cy="14.5" r="3.2" fill={dark} />
      {/* Eye dots */}
      <circle cx="20.5" cy="13.8" r="0.9" fill="white" opacity="0.7" />
      <circle cx="23.5" cy="13.8" r="0.9" fill="white" opacity="0.7" />
      {/* Antennae */}
      <path d="M20.5 12 C19 9.5 17 7.5 14.5 5.5" stroke={dark} strokeWidth="1.3" fill="none" strokeLinecap="round" />
      <path d="M23.5 12 C25 9.5 27 7.5 29.5 5.5" stroke={dark} strokeWidth="1.3" fill="none" strokeLinecap="round" />
      <circle cx="14.5" cy="5" r="2" fill={dark} />
      <circle cx="29.5" cy="5" r="2" fill={dark} />
    </svg>
  );
}

export function KidAvatar({ id, size = 44 }) {
  if (id === "abdulla") return <LionAvatar size={size} />;
  return <ButterflyAvatar size={size} />;
}


File created successfully at: /Users/khalidbinkalban/ascs-homework-tracker/src/icons/KidAvatar.jsx

export function LionAvatar({ size = 44 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
      {/* Mane rays */}
      {Array.from({ length: 12 }, (_, i) => {
        const angle = (i * 30 * Math.PI) / 180 - Math.PI / 2;
        return (
          <line
            key={i}
            x1={22 + 13 * Math.cos(angle)}
            y1={22 + 13 * Math.sin(angle)}
            x2={22 + 20 * Math.cos(angle)}
            y2={22 + 20 * Math.sin(angle)}
            stroke="#E89530"
            strokeWidth="3.5"
            strokeLinecap="round"
          />
        );
      })}
      {/* Face */}
      <circle cx="22" cy="22" r="13" fill="#F5B84A" />
      {/* Ears */}
      <circle cx="11" cy="12" r="4.5" fill="#E89530" />
      <circle cx="33" cy="12" r="4.5" fill="#E89530" />
      <circle cx="11" cy="12" r="2.5" fill="#F5B84A" />
      <circle cx="33" cy="12" r="2.5" fill="#F5B84A" />
      {/* Eyes */}
      <ellipse cx="17.5" cy="20" rx="2.6" ry="2.3" fill="white" />
      <ellipse cx="26.5" cy="20" rx="2.6" ry="2.3" fill="white" />
      <circle cx="18" cy="20.5" r="1.4" fill="#1A0A00" />
      <circle cx="27" cy="20.5" r="1.4" fill="#1A0A00" />
      <circle cx="18.4" cy="20.1" r="0.55" fill="white" />
      <circle cx="27.4" cy="20.1" r="0.55" fill="white" />
      {/* Nose */}
      <ellipse cx="22" cy="25" rx="2.3" ry="1.6" fill="#C87030" />
      {/* Mouth */}
      <path d="M19.8 27 Q22 29 24.2 27" stroke="#C87030" strokeWidth="1.2" fill="none" strokeLinecap="round" />
      <path d="M22 26 L22 25" stroke="#C87030" strokeWidth="1" strokeLinecap="round" />
      {/* Whiskers */}
      <line x1="10" y1="25.5" x2="18.5" y2="24.5" stroke="#D09040" strokeWidth="0.8" opacity="0.55" />
      <line x1="10" y1="27.5" x2="18.5" y2="26.5" stroke="#D09040" strokeWidth="0.8" opacity="0.55" />
      <line x1="34" y1="25.5" x2="25.5" y2="24.5" stroke="#D09040" strokeWidth="0.8" opacity="0.55" />
      <line x1="34" y1="27.5" x2="25.5" y2="26.5" stroke="#D09040" strokeWidth="0.8" opacity="0.55" />
    </svg>
  );
}

export function ButterflyAvatar({ color = "#D4537E", size = 44 }) {
  const dark = "#7A2B4A";
  return (
    <svg width={size} height={size} viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
      {/* Upper wings */}
      <ellipse cx="13" cy="19" rx="11.5" ry="8.5" fill={color} transform="rotate(-18 13 19)" />
      <ellipse cx="31" cy="19" rx="11.5" ry="8.5" fill={color} transform="rotate(18 31 19)" />
      {/* Lower wings */}
      <ellipse cx="14.5" cy="30" rx="8" ry="6" fill={color} opacity="0.78" transform="rotate(18 14.5 30)" />
      <ellipse cx="29.5" cy="30" rx="8" ry="6" fill={color} opacity="0.78" transform="rotate(-18 29.5 30)" />
      {/* Wing shine */}
      <ellipse cx="12" cy="18" rx="5" ry="3.5" fill="white" opacity="0.22" transform="rotate(-18 12 18)" />
      <ellipse cx="32" cy="18" rx="5" ry="3.5" fill="white" opacity="0.22" transform="rotate(18 32 18)" />
      {/* Wing dots */}
      <circle cx="9" cy="23" r="2.8" fill="white" opacity="0.28" />
      <circle cx="35" cy="23" r="2.8" fill="white" opacity="0.28" />
      <circle cx="9" cy="23" r="1.3" fill={dark} opacity="0.3" />
      <circle cx="35" cy="23" r="1.3" fill={dark} opacity="0.3" />
      {/* Body */}
      <ellipse cx="22" cy="25" rx="2.4" ry="10" fill={dark} />
      {/* Head */}
      <circle cx="22" cy="14.5" r="3.2" fill={dark} />
      {/* Eye dots */}
      <circle cx="20.5" cy="13.8" r="0.9" fill="white" opacity="0.7" />
      <circle cx="23.5" cy="13.8" r="0.9" fill="white" opacity="0.7" />
      {/* Antennae */}
      <path d="M20.5 12 C19 9.5 17 7.5 14.5 5.5" stroke={dark} strokeWidth="1.3" fill="none" strokeLinecap="round" />
      <path d="M23.5 12 C25 9.5 27 7.5 29.5 5.5" stroke={dark} strokeWidth="1.3" fill="none" strokeLinecap="round" />
      <circle cx="14.5" cy="5" r="2" fill={dark} />
      <circle cx="29.5" cy="5" r="2" fill={dark} />
    </svg>
  );
}

export function KidAvatar({ id, size = 44 }) {
  if (id === "abdulla") return <LionAvatar size={size} />;
  return <ButterflyAvatar size={size} />;
}


import {
  Calculator,
  BookOpen,
  PenLine,
  Microscope,
  Palette,
  Trophy,
  Moon,
  BookMarked,
} from "lucide-react";

const ICON_MAP = {
  Math: Calculator,
  English: BookOpen,
  Phonics: BookOpen,
  Arabic: PenLine,
  Science: Microscope,
  Art: Palette,
  PE: Trophy,
  "Islamic Studies": Moon,
  "Story Time": BookMarked,
};

export function SubjectIcon({ subject, size = 18, color, strokeWidth = 1.8, style }) {
  const Icon = ICON_MAP[subject] || BookOpen;
  return <Icon size={size} color={color} strokeWidth={strokeWidth} style={style} />;
}


File created successfully at: /Users/khalidbinkalban/ascs-homework-tracker/src/icons/SubjectIcon.jsx

import {
  Calculator,
  BookOpen,
  PenLine,
  Microscope,
  Palette,
  Trophy,
  Moon,
  BookMarked,
} from "lucide-react";

const ICON_MAP = {
  Math: Calculator,
  English: BookOpen,
  Phonics: BookOpen,
  Arabic: PenLine,
  Science: Microscope,
  Art: Palette,
  PE: Trophy,
  "Islamic Studies": Moon,
  "Story Time": BookMarked,
};

export function SubjectIcon({ subject, size = 18, color, strokeWidth = 1.8, style }) {
  const Icon = ICON_MAP[subject] || BookOpen;
  return <Icon size={size} color={color} strokeWidth={strokeWidth} style={style} />;
}


import { useState, useEffect } from "react";
import { ref, onValue, set } from "firebase/database";
import { database, FIREBASE_READY } from "../lib/firebase";
import { SAMPLE_TASKS } from "../data/constants";

function getWeekDates() {
  const today = new Date();
  const monday = new Date(today);
  monday.setDate(today.getDate() - ((today.getDay() + 6) % 7));
  return Array.from({ length: 5 }, (_, i) => {
    const d = new Date(monday);
    d.setDate(monday.getDate() + i);
    return d;
  });
}

function seedTasks() {
  const week = getWeekDates();
  return {
    abdulla: SAMPLE_TASKS.abdulla.map((t, i) => ({
      ...t,
      due: week[i + 1]?.toISOString().split("T")[0] || week[2].toISOString().split("T")[0],
    })),
    salama: SAMPLE_TASKS.salama.map((t, i) => ({
      ...t,
      due: week[i]?.toISOString().split("T")[0] || week[0].toISOString().split("T")[0],
    })),
  };
}

export function useTasks() {
  const [tasks, setTasks] = useState(() => {
    if (FIREBASE_READY) return { abdulla: [], salama: [] };
    try {
      const saved = localStorage.getItem("ascs_tasks");
      return saved ? JSON.parse(saved) : seedTasks();
    } catch {
      return seedTasks();
    }
  });
  const [synced, setSynced] = useState(!FIREBASE_READY);

  // Firebase real-time listener
  useEffect(() => {
    if (!FIREBASE_READY || !database) return;
    const tasksRef = ref(database, "tasks");
    const unsub = onValue(tasksRef, (snapshot) => {
      const data = snapshot.val();
      if (data) {
        setTasks(data);
      } else {
        const seeded = seedTasks();
        set(tasksRef, seeded);
        setTasks(seeded);
      }
      setSynced(true);
    });
    return () => unsub();
  }, []);

  // localStorage persistence (offline fallback)
  useEffect(() => {
    if (!FIREBASE_READY) {
      localStorage.setItem("ascs_tasks", JSON.stringify(tasks));
    }
  }, [tasks]);

  function save(newTasks) {
    setTasks(newTasks);
    if (FIREBASE_READY && database) {
      set(ref(database, "tasks"), newTasks);
    }
  }

  function addTask(kidId, task) {
    save({
      ...tasks,
      [kidId]: [...(tasks[kidId] || []), { ...task, id: Date.now() }],
    });
  }

  function updateStatus(kidId, taskId, status) {
    save({
      ...tasks,
      [kidId]: tasks[kidId].map((t) => (t.id === taskId ? { ...t, status } : t)),
    });
  }

  function removeTask(kidId, taskId) {
    save({
      ...tasks,
      [kidId]: tasks[kidId].filter((t) => t.id !== taskId),
    });
  }

  function updateTask(kidId, taskId, changes) {
    save({
      ...tasks,
      [kidId]: tasks[kidId].map((t) => (t.id === taskId ? { ...t, ...changes } : t)),
    });
  }

  return { tasks, synced, addTask, updateStatus, removeTask, updateTask };
}


The file /Users/khalidbinkalban/ascs-homework-tracker/src/hooks/useTasks.js has been updated successfully.

import { useState, useEffect } from "react";
import { ref, onValue, set } from "firebase/database";
import { database, FIREBASE_READY } from "../lib/firebase";
import { SAMPLE_TASKS } from "../data/constants";

function getWeekDates() {
  const today = new Date();
  const monday = new Date(today);
  monday.setDate(today.getDate() - ((today.getDay() + 6) % 7));
  return Array.from({ length: 5 }, (_, i) => {
    const d = new Date(monday);
    d.setDate(monday.getDate() + i);
    return d;
  });
}

function seedTasks() {
  const week = getWeekDates();
  return {
    abdulla: SAMPLE_TASKS.abdulla.map((t, i) => ({
      ...t,
      due: week[i + 1]?.toISOString().split("T")[0] || week[2].toISOString().split("T")[0],
    })),
    salama: SAMPLE_TASKS.salama.map((t, i) => ({
      ...t,
      due: week[i]?.toISOString().split("T")[0] || week[0].toISOString().split("T")[0],
    })),
  };
}

export function useTasks() {
  const [tasks, setTasks] = useState(() => {
    if (FIREBASE_READY) return { abdulla: [], salama: [] };
    try {
      const saved = localStorage.getItem("ascs_tasks");
      return saved ? JSON.parse(saved) : seedTasks();
    } catch {
      return seedTasks();
    }
  });
  const [synced, setSynced] = useState(!FIREBASE_READY);

  // Firebase real-time listener
  useEffect(() => {
    if (!FIREBASE_READY || !database) return;
    const tasksRef = ref(database, "tasks");
    const unsub = onValue(tasksRef, (snapshot) => {
      const data = snapshot.val();
      if (data) {
        setTasks(data);
      } else {
        const seeded = seedTasks();
        set(tasksRef, seeded);
        setTasks(seeded);
      }
      setSynced(true);
    });
    return () => unsub();
  }, []);

  // localStorage persistence (offline fallback)
  useEffect(() => {
    if (!FIREBASE_READY) {
      localStorage.setItem("ascs_tasks", JSON.stringify(tasks));
    }
  }, [tasks]);

  function save(newTasks) {
    setTasks(newTasks);
    if (FIREBASE_READY && database) {
      set(ref(database, "tasks"), newTasks);
    }
  }

  function addTask(kidId, task) {
    save({
      ...tasks,
      [kidId]: [...(tasks[kidId] || []), { ...task, id: Date.now() }],
    });
  }

  function updateStatus(kidId, taskId, status) {
    save({
      ...tasks,
      [kidId]: tasks[kidId].map((t) => (t.id === taskId ? { ...t, status } : t)),
    });
  }

  function removeTask(kidId, taskId) {
    save({
      ...tasks,
      [kidId]: tasks[kidId].filter((t) => t.id !== taskId),
    });
  }

  function updateTask(kidId, taskId, changes) {
    save({
      ...tasks,
      [kidId]: tasks[kidId].map((t) => (t.id === taskId ? { ...t, ...changes } : t)),
    });
  }

  return { tasks, synced, addTask, updateStatus, removeTask, updateTask };
}

+import { ref, onValue, set } from "firebase/database";

+import { database, FIREBASE_READY } from "../lib/firebase";

-  monday.setDate(today.getDate() - ((day + 6) % 7));

+  monday.setDate(today.getDate() - ((today.getDay() + 6) % 7));

+    if (FIREBASE_READY) return { abdulla: [], salama: [] };

+  const [synced, setSynced] = useState(!FIREBASE_READY);

-    localStorage.setItem("ascs_tasks", JSON.stringify(tasks));

+    if (!FIREBASE_READY || !database) return;

+    const tasksRef = ref(database, "tasks");

+    const unsub = onValue(tasksRef, (snapshot) => {

+  // localStorage persistence (offline fallback)

+      localStorage.setItem("ascs_tasks", JSON.stringify(tasks));

+      set(ref(database, "tasks"), newTasks);

-      [kidId]: [...prev[kidId], { ...task, id: Date.now() }],

-      [kidId]: prev[kidId].map((t) => (t.id === taskId ? { ...t, status } : t)),

+      [kidId]: tasks[kidId].map((t) => (t.id === taskId ? { ...t, status } : t)),

-      [kidId]: prev[kidId].filter((t) => t.id !== taskId),

+      [kidId]: tasks[kidId].filter((t) => t.id !== taskId),

-      [kidId]: prev[kidId].map((t) => (t.id === taskId ? { ...t, ...changes } : t)),

+      [kidId]: tasks[kidId].map((t) => (t.id === taskId ? { ...t, ...changes } : t)),

-  return { tasks, addTask, updateStatus, removeTask, updateTask };

+  return { tasks, synced, addTask, updateStatus, removeTask, updateTask };

import { useState, useEffect } from "react";
import { SAMPLE_TASKS } from "../data/constants";

function getWeekDates() {
  const today = new Date();
  const day = today.getDay();
  const monday = new Date(today);
  monday.setDate(today.getDate() - ((day + 6) % 7));
  return Array.from({ length: 5 }, (_, i) => {
    const d = new Date(monday);
    d.setDate(monday.getDate() + i);
    return d;
  });
}

function seedTasks() {
  const week = getWeekDates();
  return {
    abdulla: SAMPLE_TASKS.abdulla.map((t, i) => ({
      ...t,
      due: week[i + 1]?.toISOString().split("T")[0] || week[2].toISOString().split("T")[0],
    })),
    salama: SAMPLE_TASKS.salama.map((t, i) => ({
      ...t,
      due: week[i]?.toISOString().split("T")[0] || week[0].toISOString().split("T")[0],
    })),
  };
}

export function useTasks() {
  const [tasks, setTasks] = useState(() => {
    try {
      const saved = localStorage.getItem("ascs_tasks");
      return saved ? JSON.parse(saved) : seedTasks();
    } catch {
      return seedTasks();
    }
  });

  useEffect(() => {
    localStorage.setItem("ascs_tasks", JSON.stringify(tasks));
  }, [tasks]);

  function addTask(kidId, task) {
    setTasks((prev) => ({
      ...prev,
      [kidId]: [...prev[kidId], { ...task, id: Date.now() }],
    }));
  }

  function updateStatus(kidId, taskId, status) {
    setTasks((prev) => ({
      ...prev,
      [kidId]: prev[kidId].map((t) => (t.id === taskId ? { ...t, status } : t)),
    }));
  }

  function removeTask(kidId, taskId) {
    setTasks((prev) => ({
      ...prev,
      [kidId]: prev[kidId].filter((t) => t.id !== taskId),
    }));
  }

  function updateTask(kidId, taskId, changes) {
    setTasks((prev) => ({
      ...prev,
      [kidId]: prev[kidId].map((t) => (t.id === taskId ? { ...t, ...changes } : t)),
    }));
  }

  return { tasks, addTask, updateStatus, removeTask, updateTask };
}


import { useState, useEffect } from "react";
import {
  Calendar,
  FileText,
  Layers,
  Plus,
  X,
  Check,
  AlertTriangle,
  Bell,
  Heart,
  GraduationCap,
  Send,
  Wifi,
  Clock,
} from "lucide-react";
import { KIDS, DAYS, STATUSES, SUBJECTS, SOURCES } from "./data/constants";
import { useTasks } from "./hooks/useTasks";
import { FIREBASE_READY } from "./lib/firebase";
import { KidAvatar } from "./icons/KidAvatar";
import { SubjectIcon } from "./icons/SubjectIcon";
import "./App.css";

function getWeekDates() {
  const today = new Date();
  const monday = new Date(today);
  monday.setDate(today.getDate() - ((today.getDay() + 6) % 7));
  return Array.from({ length: 5 }, (_, i) => {
    const d = new Date(monday);
    d.setDate(monday.getDate() + i);
    return d;
  });
}

function useLiveClock() {
  const [now, setNow] = useState(() => new Date());
  useEffect(() => {
    const id = setInterval(() => setNow(new Date()), 1000);
    return () => clearInterval(id);
  }, []);
  return now;
}

function SourceIcon({ source, size = 11 }) {
  if (source === "Telegram") return <Send size={size} style={{ flexShrink: 0 }} />;
  if (source === "Edunation") return <GraduationCap size={size} style={{ flexShrink: 0 }} />;
  return null;
}

const EMPTY_FORM = {
  subject: "",
  title: "",
  status: "new",
  due: "",
  source: "Telegram",
  type: "homework",
};

export default function App() {
  const [activeKid, setActiveKid] = useState("abdulla");
  const [activeDay, setActiveDay] = useState(() => {
    const d = new Date().getDay();
    return d >= 1 && d <= 5 ? d - 1 : 0;
  });
  const [activeTab, setActiveTab] = useState("homework");
  const [showForm, setShowForm] = useState(false);
  const [form, setForm] = useState(EMPTY_FORM);

  const { tasks, synced, addTask, updateStatus, removeTask } = useTasks();
  const today = useLiveClock();
  const weekDates = getWeekDates();
  const kid = KIDS.find((k) => k.id === activeKid);
  const kidTasks = tasks[activeKid] || [];
  const filtered = kidTasks.filter((t) => t.type === activeTab);
  const dayTasks = kidTasks.filter(
    (t) => new Date(t.due + "T00:00:00").toDateString() === weekDates[activeDay]?.toDateString()
  );

  const stats = {
    new: kidTasks.filter((t) => t.status === "new").length,
    inprogress: kidTasks.filter((t) => t.status === "inprogress").length,
    completed: kidTasks.filter((t) => t.status === "completed").length,
  };

  const totalDone = stats.completed;
  const progressPct = kidTasks.length > 0 ? Math.round((totalDone / kidTasks.length) * 100) : 0;

  function handleAddTask() {
    if (!form.title || !form.subject || !form.due) return;
    addTask(activeKid, form);
    setForm(EMPTY_FORM);
    setShowForm(false);
    setActiveTab(form.type);
  }

  function openForm() {
    setForm({ ...EMPTY_FORM, type: activeTab });
    setShowForm(true);
    setTimeout(() => {
      document.querySelector(".form-card")?.scrollIntoView({ behavior: "smooth", block: "nearest" });
    }, 80);
  }

  // Loading screen while Firebase syncs
  if (!synced) {
    return (

ASCS

Syncing homework tracker…

    );
  }

  return (

      {/* Header */}
      <header
        className="header"
        style={{ background: `linear-gradient(135deg, ${kid.color} 0%, #185FA5 100%)` }}
      >

ASCS

American School of Creativity Science

Homework Tracker

              {today.toLocaleDateString("en-US", {
                weekday: "short",
                month: "short",
                day: "numeric",
                year: "numeric",
              })}

              <Clock size={11} style={{ opacity: 0.8 }} />

                {today.toLocaleTimeString("en-US", {
                  hour: "2-digit",
                  minute: "2-digit",
                  second: "2-digit",
                })}

            {FIREBASE_READY && (

                <Wifi size={10} />
                Live

            )}

        {/* Progress bar */}

            {kid.name}'s Overall Progress
            {progressPct}%

            <div className="progress-fill" style={{ width: `${progressPct}%` }} />

      {/* Kid Switcher */}

        {KIDS.map((k) => {
          const kTasks = tasks[k.id] || [];
          const kDone = kTasks.filter((t) => t.status === "completed").length;
          const kPct = kTasks.length > 0 ? Math.round((kDone / kTasks.length) * 100) : 0;
          return (
            <button
              key={k.id}
              className={`kid-btn ${activeKid === k.id ? "active" : ""}`}
              style={{
                borderColor: activeKid === k.id ? k.color : "transparent",
                background: activeKid === k.id ? k.light : "#f5f7fa",
              }}
              onClick={() => setActiveKid(k.id)}
            >

                <KidAvatar id={k.id} size={activeKid === k.id ? 46 : 40} />

              {k.name}
              {k.grade}

                <div className="kid-mini-fill" style={{ width: `${kPct}%`, background: k.color }} />

                {STATUSES.map((s) => {
                  const cnt = kTasks.filter((t) => t.status === s.id).length;
                  return cnt > 0 ? (

                      {cnt}

                  ) : null;
                })}

            </button>
          );
        })}

      {/* Weekly Calendar */}

          <Calendar size={13} strokeWidth={2} />
          This Week

          {weekDates.map((d, i) => {
            const isToday = d.toDateString() === today.toDateString();
            const dayCount = kidTasks.filter(
              (t) => new Date(t.due + "T00:00:00").toDateString() === d.toDateString()
            ).length;
            const doneCount = kidTasks.filter(
              (t) =>
                new Date(t.due + "T00:00:00").toDateString() === d.toDateString() &&
                t.status === "completed"
            ).length;
            return (
              <button
                key={i}
                className={`day-btn ${activeDay === i ? "active" : ""} ${isToday ? "today" : ""}`}
                style={{
                  borderColor:
                    activeDay === i ? kid.color : isToday ? kid.color + "66" : "#e5e8f0",
                  background:
                    activeDay === i ? kid.color : isToday ? kid.light : "white",
                }}
                onClick={() => setActiveDay(i)}
              >

                  {DAYS[i]}

                  {d.getDate()}

                {dayCount > 0 && (

                    {doneCount}/{dayCount}

                )}
              </button>
            );
          })}

        {dayTasks.length > 0 && (
          <div
            className="day-summary"
            style={{ borderLeft: `3px solid ${kid.color}` }}
          >

              Due{" "}
              {weekDates[activeDay]?.toLocaleDateString("en-US", {
                weekday: "short",
                month: "short",
                day: "numeric",
              })}
              :

              {dayTasks.map((t) => {
                const st = STATUSES.find((s) => s.id === t.status);
                return (

                    <SubjectIcon subject={t.subject} size={11} strokeWidth={2} />
                    {t.title.length > 28 ? t.title.slice(0, 28) + "…" : t.title}

                );
              })}

        )}

      {/* Stats */}

        {STATUSES.map((s) => (
          <div key={s.id} className="stat-card" style={{ background: s.bg, borderTop: `3px solid ${s.dot}` }}>

            {stats[s.id]}
            {s.label}

        ))}

      {/* Tabs + Add button */}

        {["homework", "project"].map((tab) => (
          <button
            key={tab}
            className={`tab-btn ${activeTab === tab ? "active" : ""}`}
            style={{
              background: activeTab === tab ? kid.color : "#f0f2f5",
              color: activeTab === tab ? "white" : "#666",
              boxShadow: activeTab === tab ? `0 4px 14px ${kid.color}44` : "none",
            }}
            onClick={() => setActiveTab(tab)}
          >
            {tab === "homework" ? <FileText size={14} strokeWidth={2} /> : <Layers size={14} strokeWidth={2} />}
            {tab === "homework" ? "Homework" : "Projects"}

              {kidTasks.filter((t) => t.type === tab).length}

          </button>
        ))}
        <button
          className="add-btn"
          style={{ background: kid.color, boxShadow: `0 4px 14px ${kid.color}66` }}
          onClick={openForm}
        >
          <Plus size={18} strokeWidth={2.5} />
          Add
        </button>

      {/* Add Form */}
      {showForm && (

              <Plus size={15} strokeWidth={2.5} />
              New {form.type === "homework" ? "Homework" : "Project"} for {kid.name}

            <button className="form-close" onClick={() => setShowForm(false)}>
              <X size={13} />
            </button>

              Subject
              <select
                value={form.subject}
                onChange={(e) => setForm((f) => ({ ...f, subject: e.target.value }))}
                style={{ borderColor: form.subject ? kid.color : "#ddd" }}
              >
                <option value="">Select subject…</option>
                {SUBJECTS[activeKid].map((s) => (
                  <option key={s}>{s}</option>
                ))}
              </select>

              Status
              <select
                value={form.status}
                onChange={(e) => setForm((f) => ({ ...f, status: e.target.value }))}
                style={{ borderColor: kid.color }}
              >
                {STATUSES.map((s) => (
                  <option key={s.id} value={s.id}>{s.label}</option>
                ))}
              </select>

              Assignment description
              <input
                placeholder="e.g. Read chapter 3 and answer questions…"
                value={form.title}
                onChange={(e) => setForm((f) => ({ ...f, title: e.target.value }))}
                style={{ borderColor: form.title ? kid.color : "#ddd" }}
              />

              Due Date
              <input
                type="date"
                value={form.due}
                onChange={(e) => setForm((f) => ({ ...f, due: e.target.value }))}
                style={{ borderColor: form.due ? kid.color : "#ddd" }}
              />

              Source
              <select
                value={form.source}
                onChange={(e) => setForm((f) => ({ ...f, source: e.target.value }))}
                style={{ borderColor: kid.color }}
              >
                {SOURCES.map((s) => (
                  <option key={s}>{s}</option>
                ))}
              </select>

              Type

                {["homework", "project"].map((t) => (
                  <button
                    key={t}
                    className={`type-opt ${form.type === t ? "selected" : ""}`}
                    style={{
                      background: form.type === t ? kid.color : "transparent",
                      color: form.type === t ? "white" : "#666",
                      borderColor: form.type === t ? kid.color : "#ddd",
                    }}
                    onClick={() => setForm((f) => ({ ...f, type: t }))}
                    type="button"
                  >
                    {t === "homework"
                      ? <><FileText size={13} strokeWidth={2} /> Homework</>
                      : <><Layers size={13} strokeWidth={2} /> Project</>
                    }
                  </button>
                ))}

            <button
              className="save-btn"
              style={{
                background: form.title && form.subject && form.due ? kid.color : "#ccc",
                boxShadow: form.title && form.subject && form.due ? `0 4px 14px ${kid.color}55` : "none",
              }}
              onClick={handleAddTask}
              disabled={!form.title || !form.subject || !form.due}
            >
              <Check size={16} strokeWidth={2.5} />
              Save Assignment
            </button>
            <button className="cancel-btn" onClick={() => setShowForm(false)}>
              Cancel
            </button>

      )}

      {/* Task List */}

        {filtered.length === 0 ? (

              {activeTab === "homework"
                ? <FileText size={44} strokeWidth={1.2} />
                : <Layers size={44} strokeWidth={1.2} />
              }

              No {activeTab}s yet!

Tap + Add to get started

            <button
              className="empty-add-btn"
              style={{ background: kid.color, boxShadow: `0 4px 14px ${kid.color}55` }}
              onClick={openForm}
            >
              <Plus size={14} strokeWidth={2.5} />
              Add {activeTab === "homework" ? "Homework" : "Project"}
            </button>

        ) : (
          filtered.map((task) => {
            const st = STATUSES.find((s) => s.id === task.status);
            const dueDate = new Date(task.due + "T00:00:00");
            const isOverdue = dueDate < today && task.status !== "completed";
            const isDueToday = dueDate.toDateString() === today.toDateString();
            return (
              <div
                key={task.id}
                className={`task-card ${isOverdue ? "overdue" : ""} ${task.status === "completed" ? "done" : ""}`}
                style={{
                  borderLeft: `4px solid ${isOverdue ? "#E24B4A" : task.status === "completed" ? "#639922" : kid.color}`,
                }}
              >

                  <SubjectIcon subject={task.subject} size={20} color={kid.dark} strokeWidth={1.7} />

                    {task.title}

                      <SubjectIcon subject={task.subject} size={10} color={kid.dark} strokeWidth={2} />
                      {task.subject}

                      {st.label}

                      {isOverdue
                        ? <AlertTriangle size={11} strokeWidth={2} />
                        : isDueToday
                        ? <Bell size={11} strokeWidth={2} />
                        : <Calendar size={11} strokeWidth={2} />
                      }
                      {isOverdue ? "Overdue · " : isDueToday ? "Today · " : ""}
                      {dueDate.toLocaleDateString("en-US", { month: "short", day: "numeric" })}

                      <SourceIcon source={task.source} size={10} />
                      {task.source}

                  <select
                    value={task.status}
                    style={{ borderColor: kid.color + "88", color: kid.dark }}
                    onChange={(e) => updateStatus(activeKid, task.id, e.target.value)}
                  >
                    {STATUSES.map((s) => (
                      <option key={s.id} value={s.id}>{s.label}</option>
                    ))}
                  </select>
                  <button className="remove-btn" onClick={() => removeTask(activeKid, task.id)} title="Remove">
                    <X size={11} strokeWidth={2.5} />
                  </button>

            );
          })
        )}

        ASCS Homework Tracker
        •
        <Heart size={12} fill="currentColor" style={{ color: "#F87171" }} />
        for Abdulla & Salama

  );
}


The file /Users/khalidbinkalban/ascs-homework-tracker/src/App.jsx has been updated successfully.

import { useState, useEffect } from "react";
import {
  Calendar,
  FileText,
  Layers,
  Plus,
  X,
  Check,
  AlertTriangle,
  Bell,
  Heart,
  GraduationCap,
  Send,
  Wifi,
  Clock,
} from "lucide-react";
import { KIDS, DAYS, STATUSES, SUBJECTS, SOURCES } from "./data/constants";
import { useTasks } from "./hooks/useTasks";
import { FIREBASE_READY } from "./lib/firebase";
import { KidAvatar } from "./icons/KidAvatar";
import { SubjectIcon } from "./icons/SubjectIcon";
import "./App.css";

function getWeekDates() {
  const today = new Date();
  const monday = new Date(today);
  monday.setDate(today.getDate() - ((today.getDay() + 6) % 7));
  return Array.from({ length: 5 }, (_, i) => {
    const d = new Date(monday);
    d.setDate(monday.getDate() + i);
    return d;
  });
}

function useLiveClock() {
  const [now, setNow] = useState(() => new Date());
  useEffect(() => {
    const id = setInterval(() => setNow(new Date()), 1000);
    return () => clearInterval(id);
  }, []);
  return now;
}

function SourceIcon({ source, size = 11 }) {
  if (source === "Telegram") return <Send size={size} style={{ flexShrink: 0 }} />;
  if (source === "Edunation") return <GraduationCap size={size} style={{ flexShrink: 0 }} />;
  return null;
}

const EMPTY_FORM = {
  subject: "",
  title: "",
  status: "new",
  due: "",
  source: "Telegram",
  type: "homework",
};

export default function App() {
  const [activeKid, setActiveKid] = useState("abdulla");
  const [activeDay, setActiveDay] = useState(() => {
    const d = new Date().getDay();
    return d >= 1 && d <= 5 ? d - 1 : 0;
  });
  const [activeTab, setActiveTab] = useState("homework");
  const [showForm, setShowForm] = useState(false);
  const [form, setForm] = useState(EMPTY_FORM);

  const { tasks, synced, addTask, updateStatus, removeTask } = useTasks();
  const today = useLiveClock();
  const weekDates = getWeekDates();
  const kid = KIDS.find((k) => k.id === activeKid);
  const kidTasks = tasks[activeKid] || [];
  const filtered = kidTasks.filter((t) => t.type === activeTab);
  const dayTasks = kidTasks.filter(
    (t) => new Date(t.due + "T00:00:00").toDateString() === weekDates[activeDay]?.toDateString()
  );

  const stats = {
    new: kidTasks.filter((t) => t.status === "new").length,
    inprogress: kidTasks.filter((t) => t.status === "inprogress").length,
    completed: kidTasks.filter((t) => t.status === "completed").length,
  };

  const totalDone = stats.completed;
  const progressPct = kidTasks.length > 0 ? Math.round((totalDone / kidTasks.length) * 100) : 0;

  function handleAddTask() {
    if (!form.title || !form.subject || !form.due) return;
    addTask(activeKid, form);
    setForm(EMPTY_FORM);
    setShowForm(false);
    setActiveTab(form.type);
  }

  function openForm() {
    setForm({ ...EMPTY_FORM, type: activeTab });
    setShowForm(true);
    setTimeout(() => {
      document.querySelector(".form-card")?.scrollIntoView({ behavior: "smooth", block: "nearest" });
    }, 80);
  }

  // Loading screen while Firebase syncs
  if (!synced) {
    return (

ASCS

Syncing homework tracker…

    );
  }

  return (

      {/* Header */}
      <header
        className="header"
        style={{ background: `linear-gradient(135deg, ${kid.color} 0%, #185FA5 100%)` }}
      >

ASCS

American School of Creativity Science

Homework Tracker

              {today.toLocaleDateString("en-US", {
                weekday: "short",
                month: "short",
                day: "numeric",
                year: "numeric",
              })}

              <Clock size={11} style={{ opacity: 0.8 }} />

                {today.toLocaleTimeString("en-US", {
                  hour: "2-digit",
                  minute: "2-digit",
                  second: "2-digit",
                })}

            {FIREBASE_READY && (

                <Wifi size={10} />
                Live

            )}

        {/* Progress bar */}

            {kid.name}'s Overall Progress
            {progressPct}%

            <div className="progress-fill" style={{ width: `${progressPct}%` }} />

      {/* Kid Switcher */}

        {KIDS.map((k) => {
          const kTasks = tasks[k.id] || [];
          const kDone = kTasks.filter((t) => t.status === "completed").length;
          const kPct = kTasks.length > 0 ? Math.round((kDone / kTasks.length) * 100) : 0;
          return (
            <button
              key={k.id}
              className={`kid-btn ${activeKid === k.id ? "active" : ""}`}
              style={{
                borderColor: activeKid === k.id ? k.color : "transparent",
                background: activeKid === k.id ? k.light : "#f5f7fa",
              }}
              onClick={() => setActiveKid(k.id)}
            >

                <KidAvatar id={k.id} size={activeKid === k.id ? 46 : 40} />

              {k.name}
              {k.grade}

                <div className="kid-mini-fill" style={{ width: `${kPct}%`, background: k.color }} />

                {STATUSES.map((s) => {
                  const cnt = kTasks.filter((t) => t.status === s.id).length;
                  return cnt > 0 ? (

                      {cnt}

                  ) : null;
                })}

            </button>
          );
        })}

      {/* Weekly Calendar */}

          <Calendar size={13} strokeWidth={2} />
          This Week

          {weekDates.map((d, i) => {
            const isToday = d.toDateString() === today.toDateString();
            const dayCount = kidTasks.filter(
              (t) => new Date(t.due + "T00:00:00").toDateString() === d.toDateString()
            ).length;
            const doneCount = kidTasks.filter(
              (t) =>
                new Date(t.due + "T00:00:00").toDateString() === d.toDateString() &&
                t.status === "completed"
            ).length;
            return (
              <button
                key={i}
                className={`day-btn ${activeDay === i ? "active" : ""} ${isToday ? "today" : ""}`}
                style={{
                  borderColor:
                    activeDay === i ? kid.color : isToday ? kid.color + "66" : "#e5e8f0",
                  background:
                    activeDay === i ? kid.color : isToday ? kid.light : "white",
                }}
                onClick={() => setActiveDay(i)}
              >

                  {DAYS[i]}

                  {d.getDate()}

                {dayCount > 0 && (

                    {doneCount}/{dayCount}

                )}
              </button>
            );
          })}

        {dayTasks.length > 0 && (
          <div
            className="day-summary"
            style={{ borderLeft: `3px solid ${kid.color}` }}
          >

              Due{" "}
              {weekDates[activeDay]?.toLocaleDateString("en-US", {
                weekday: "short",
                month: "short",
                day: "numeric",
              })}
              :

              {dayTasks.map((t) => {
                const st = STATUSES.find((s) => s.id === t.status);
                return (

                    <SubjectIcon subject={t.subject} size={11} strokeWidth={2} />
                    {t.title.length > 28 ? t.title.slice(0, 28) + "…" : t.title}

                );
              })}

        )}

      {/* Stats */}

        {STATUSES.map((s) => (
          <div key={s.id} className="stat-card" style={{ background: s.bg, borderTop: `3px solid ${s.dot}` }}>

            {stats[s.id]}
            {s.label}

        ))}

      {/* Tabs + Add button */}

        {["homework", "project"].map((tab) => (
          <button
            key={tab}
            className={`tab-btn ${activeTab === tab ? "active" : ""}`}
            style={{
              background: activeTab === tab ? kid.color : "#f0f2f5",
              color: activeTab === tab ? "white" : "#666",
              boxShadow: activeTab === tab ? `0 4px 14px ${kid.color}44` : "none",
            }}
            onClick={() => setActiveTab(tab)}
          >
            {tab === "homework" ? <FileText size={14} strokeWidth={2} /> : <Layers size={14} strokeWidth={2} />}
            {tab === "homework" ? "Homework" : "Projects"}

              {kidTasks.filter((t) => t.type === tab).length}

          </button>
        ))}
        <button
          className="add-btn"
          style={{ background: kid.color, boxShadow: `0 4px 14px ${kid.color}66` }}
          onClick={openForm}
        >
          <Plus size={18} strokeWidth={2.5} />
          Add
        </button>

      {/* Add Form */}
      {showForm && (

              <Plus size={15} strokeWidth={2.5} />
              New {form.type === "homework" ? "Homework" : "Project"} for {kid.name}

            <button className="form-close" onClick={() => setShowForm(false)}>
              <X size={13} />
            </button>

              Subject
              <select
                value={form.subject}
                onChange={(e) => setForm((f) => ({ ...f, subject: e.target.value }))}
                style={{ borderColor: form.subject ? kid.color : "#ddd" }}
              >
                <option value="">Select subject…</option>
                {SUBJECTS[activeKid].map((s) => (
                  <option key={s}>{s}</option>
                ))}
              </select>

              Status
              <select
                value={form.status}
                onChange={(e) => setForm((f) => ({ ...f, status: e.target.value }))}
                style={{ borderColor: kid.color }}
              >
                {STATUSES.map((s) => (
                  <option key={s.id} value={s.id}>{s.label}</option>
                ))}
              </select>

              Assignment description
              <input
                placeholder="e.g. Read chapter 3 and answer questions…"
                value={form.title}
                onChange={(e) => setForm((f) => ({ ...f, title: e.target.value }))}
                style={{ borderColor: form.title ? kid.color : "#ddd" }}
              />

              Due Date
              <input
                type="date"
                value={form.due}
                onChange={(e) => setForm((f) => ({ ...f, due: e.target.value }))}
                style={{ borderColor: form.due ? kid.color : "#ddd" }}
              />

              Source
              <select
                value={form.source}
                onChange={(e) => setForm((f) => ({ ...f, source: e.target.value }))}
                style={{ borderColor: kid.color }}
              >
                {SOURCES.map((s) => (
                  <option key={s}>{s}</option>
                ))}
              </select>

              Type

                {["homework", "project"].map((t) => (
                  <button
                    key={t}
                    className={`type-opt ${form.type === t ? "selected" : ""}`}
                    style={{
                      background: form.type === t ? kid.color : "transparent",
                      color: form.type === t ? "white" : "#666",
                      borderColor: form.type === t ? kid.color : "#ddd",
                    }}
                    onClick={() => setForm((f) => ({ ...f, type: t }))}
                    type="button"
                  >
                    {t === "homework"
                      ? <><FileText size={13} strokeWidth={2} /> Homework</>
                      : <><Layers size={13} strokeWidth={2} /> Project</>
                    }
                  </button>
                ))}

            <button
              className="save-btn"
              style={{
                background: form.title && form.subject && form.due ? kid.color : "#ccc",
                boxShadow: form.title && form.subject && form.due ? `0 4px 14px ${kid.color}55` : "none",
              }}
              onClick={handleAddTask}
              disabled={!form.title || !form.subject || !form.due}
            >
              <Check size={16} strokeWidth={2.5} />
              Save Assignment
            </button>
            <button className="cancel-btn" onClick={() => setShowForm(false)}>
              Cancel
            </button>

      )}

      {/* Task List */}

        {filtered.length === 0 ? (

              {activeTab === "homework"
                ? <FileText size={44} strokeWidth={1.2} />
                : <Layers size={44} strokeWidth={1.2} />
              }

              No {activeTab}s yet!

Tap + Add to get started

            <button
              className="empty-add-btn"
              style={{ background: kid.color, boxShadow: `0 4px 14px ${kid.color}55` }}
              onClick={openForm}
            >
              <Plus size={14} strokeWidth={2.5} />
              Add {activeTab === "homework" ? "Homework" : "Project"}
            </button>

        ) : (
          filtered.map((task) => {
            const st = STATUSES.find((s) => s.id === task.status);
            const dueDate = new Date(task.due + "T00:00:00");
            const isOverdue = dueDate < today && task.status !== "completed";
            const isDueToday = dueDate.toDateString() === today.toDateString();
            return (
              <div
                key={task.id}
                className={`task-card ${isOverdue ? "overdue" : ""} ${task.status === "completed" ? "done" : ""}`}
                style={{
                  borderLeft: `4px solid ${isOverdue ? "#E24B4A" : task.status === "completed" ? "#639922" : kid.color}`,
                }}
              >

                  <SubjectIcon subject={task.subject} size={20} color={kid.dark} strokeWidth={1.7} />

                    {task.title}

                      <SubjectIcon subject={task.subject} size={10} color={kid.dark} strokeWidth={2} />
                      {task.subject}

                      {st.label}

                      {isOverdue
                        ? <AlertTriangle size={11} strokeWidth={2} />
                        : isDueToday
                        ? <Bell size={11} strokeWidth={2} />
                        : <Calendar size={11} strokeWidth={2} />
                      }
                      {isOverdue ? "Overdue · " : isDueToday ? "Today · " : ""}
                      {dueDate.toLocaleDateString("en-US", { month: "short", day: "numeric" })}

                      <SourceIcon source={task.source} size={10} />
                      {task.source}

                  <select
                    value={task.status}
                    style={{ borderColor: kid.color + "88", color: kid.dark }}
                    onChange={(e) => updateStatus(activeKid, task.id, e.target.value)}
                  >
                    {STATUSES.map((s) => (
                      <option key={s.id} value={s.id}>{s.label}</option>
                    ))}
                  </select>
                  <button className="remove-btn" onClick={() => removeTask(activeKid, task.id)} title="Remove">
                    <X size={11} strokeWidth={2.5} />
                  </button>

            );
          })
        )}

        ASCS Homework Tracker
        •
        <Heart size={12} fill="currentColor" style={{ color: "#F87171" }} />
        for Abdulla & Salama

  );
}

-import { KIDS, DAYS, STATUSES, SUBJECTS, SOURCES, SUBJECT_ICONS } from "./data/constants";

+import { useState, useEffect } from "react";

+import { KIDS, DAYS, STATUSES, SUBJECTS, SOURCES } from "./data/constants";

import { useTasks } from "./hooks/useTasks";

+import { FIREBASE_READY } from "./lib/firebase";

+import { KidAvatar } from "./icons/KidAvatar";

+import { SubjectIcon } from "./icons/SubjectIcon";

+  const [now, setNow] = useState(() => new Date());

+    const id = setInterval(() => setNow(new Date()), 1000);

+function SourceIcon({ source, size = 11 }) {

+  if (source === "Telegram") return <Send size={size} style={{ flexShrink: 0 }} />;

+  if (source === "Edunation") return <GraduationCap size={size} style={{ flexShrink: 0 }} />;

const [activeTab, setActiveTab] = useState("homework");

const [showForm, setShowForm] = useState(false);

const [form, setForm] = useState(EMPTY_FORM);

-  const [editingId, setEditingId] = useState(null);

-  const { tasks, addTask, updateStatus, removeTask, updateTask } = useTasks();

+  const { tasks, synced, addTask, updateStatus, removeTask } = useTasks();

const kid = KIDS.find((k) => k.id === activeKid);

const kidTasks = tasks[activeKid] || [];

-  const totalDone = kidTasks.filter((t) => t.status === "completed").length;

setForm({ ...EMPTY_FORM, type: activeTab });

-  const todayStr = today.toLocaleDateString("en-US", {

+  // Loading screen while Firebase syncs

+        <div className="loading-inner">

+          <div className="loading-spinner" />

-          background: `linear-gradient(135deg, ${kid.color} 0%, #185FA5 100%)`,

+        style={{ background: `linear-gradient(135deg, ${kid.color} 0%, #185FA5 100%)` }}

+          <div className="header-date-col">

+            <div className="header-date">

+              {today.toLocaleDateString("en-US", {

+            <div className="header-clock">

+              <Clock size={11} style={{ opacity: 0.8 }} />

+                {today.toLocaleTimeString("en-US", {

+              <div className="sync-badge">

-              className="progress-fill"

-              style={{ width: `${progressPct}%` }}

+            <div className="progress-fill" style={{ width: `${progressPct}%` }} />

-              <span className="kid-name" style={{ color: k.color }}>

+              <div className="kid-avatar-wrap">

+                <KidAvatar id={k.id} size={activeKid === k.id ? 46 : 40} />

-                  className="kid-mini-fill"

-                    background: k.color,

+                <div className="kid-mini-fill" style={{ width: `${kPct}%`, background: k.color }} />

-                      className="badge"

-                      style={{ background: s.bg, color: s.text }}

+                    <span key={s.id} className="badge" style={{ background: s.bg, color: s.text }}>

+        <div className="section-label">

+          <Calendar size={13} strokeWidth={2} />

const isToday = d.toDateString() === today.toDateString();

-            const dayTaskCount = kidTasks.filter(

+            const dayCount = kidTasks.filter(

-                      ? kid.color + "66"

+                    activeDay === i ? kid.color : isToday ? kid.color + "66" : "#e5e8f0",

+                    color: activeDay === i ? "white" : isToday ? kid.color : "#222",

color: activeDay === i ? "white" : kid.dark,

-                    {doneCount}/{dayTaskCount}

+                    {doneCount}/{dayCount}

-            style={{ background: kid.light, borderLeft: `3px solid ${kid.color}` }}

+            style={{ borderLeft: `3px solid ${kid.color}` }}

<span className="day-summary-label" style={{ color: kid.dark }}>

const st = STATUSES.find((s) => s.id === t.status);

<span key={t.id} className="day-task-chip" style={{ background: st.bg, color: st.text }}>

-                    {SUBJECT_ICONS[t.subject] || "📚"} {t.title.length > 28 ? t.title.slice(0, 28) + "…" : t.title}

+                    <SubjectIcon subject={t.subject} size={11} strokeWidth={2} />

+                    {t.title.length > 28 ? t.title.slice(0, 28) + "…" : t.title}

-            style={{ background: s.bg, borderTop: `3px solid ${s.dot}` }}

+          <div key={s.id} className="stat-card" style={{ background: s.bg, borderTop: `3px solid ${s.dot}` }}>

<span className="stat-dot" style={{ background: s.dot }} />

-            <span className="stat-num" style={{ color: s.text }}>

-            <span className="stat-label" style={{ color: s.text }}>

-            {tab === "homework" ? "📝 Homework" : "🎨 Projects"}

+            {tab === "homework" ? <FileText size={14} strokeWidth={2} /> : <Layers size={14} strokeWidth={2} />}

+            {tab === "homework" ? "Homework" : "Projects"}

color: activeTab === tab ? "white" : "#666",

-            boxShadow: `0 4px 14px ${kid.color}66`,

+          style={{ background: kid.color, boxShadow: `0 4px 14px ${kid.color}66` }}

+          <Plus size={18} strokeWidth={2.5} />

<div className="form-card" style={{ borderColor: kid.color + "55" }}>

<div className="form-title" style={{ color: kid.color }}>

-              ➕ New {form.type === "homework" ? "Homework" : "Project"} for {kid.name} {kid.emoji}

+              <Plus size={15} strokeWidth={2.5} />

+              New {form.type === "homework" ? "Homework" : "Project"} for {kid.name}

-                    {SUBJECT_ICONS[s]} {s}

+                  <option key={s}>{s}</option>

-                  <option key={s.id} value={s.id}>

+                  <option key={s.id} value={s.id}>{s.label}</option>

-                    {t === "homework" ? "📝 Homework" : "🎨 Project"}

+                      ? <><FileText size={13} strokeWidth={2} /> Homework</>

+                      : <><Layers size={13} strokeWidth={2} /> Project</>

-                  form.title && form.subject && form.due ? kid.color : "#ccc",

-                  form.title && form.subject && form.due

+                background: form.title && form.subject && form.due ? kid.color : "#ccc",

+                boxShadow: form.title && form.subject && form.due ? `0 4px 14px ${kid.color}55` : "none",

disabled={!form.title || !form.subject || !form.due}

+              <Check size={16} strokeWidth={2.5} />

style={{ background: kid.light, borderColor: kid.color + "33" }}

-            <div className="empty-emoji">

-              {activeTab === "homework" ? "🎉" : "🌟"}

+            <div className="empty-icon" style={{ color: kid.color }}>

+              {activeTab === "homework"

+                ? <FileText size={44} strokeWidth={1.2} />

+                : <Layers size={44} strokeWidth={1.2} />

<div className="empty-title" style={{ color: kid.dark }}>

-              + Add {activeTab === "homework" ? "Homework" : "Project"}

+              <Plus size={14} strokeWidth={2.5} />

+              Add {activeTab === "homework" ? "Homework" : "Project"}

const st = STATUSES.find((s) => s.id === task.status);

const dueDate = new Date(task.due + "T00:00:00");

-              dueDate < today && task.status !== "completed";

+            const isOverdue = dueDate < today && task.status !== "completed";

-                  className="task-icon"

-                  style={{ background: kid.light }}

-                  {SUBJECT_ICONS[task.subject] || "📚"}

+                <div className="task-icon" style={{ background: kid.light }}>

+                  <SubjectIcon subject={task.subject} size={20} color={kid.dark} strokeWidth={1.7} />

-                        task.status === "completed"

-                          ? "line-through"

-                      color: task.status === "completed" ? "#aaa" : "#222",

+                      textDecoration: task.status === "completed" ? "line-through" : "none",

+                      color: task.status === "completed" ? "#aaa" : "#1a1a1a",

-                      className="badge subject-badge"

-                      style={{ background: kid.light, color: kid.dark }}

+                    <span className="badge subject-badge" style={{ background: kid.light, color: kid.dark }}>

+                      <SubjectIcon subject={task.subject} size={10} color={kid.dark} strokeWidth={2} />

-                      className="badge status-badge"

-                      style={{ background: st.bg, color: st.text }}

-                        className="badge-dot"

-                        style={{ background: st.dot }}

+                    <span className="badge status-badge" style={{ background: st.bg, color: st.text }}>

+                      <span className="badge-dot" style={{ background: st.dot }} />

-                        color: isOverdue

-                        fontWeight: isDueToday || isOverdue ? 600 : 400,

+                        color: isOverdue ? "#E24B4A" : isDueToday ? "#EF9F27" : "#999",

+                        fontWeight: isOverdue || isDueToday ? 600 : 400,

-                      {isOverdue ? "⚠ " : isDueToday ? "🔔 " : "📅 "}

+                        ? <AlertTriangle size={11} strokeWidth={2} />

-                      {dueDate.toLocaleDateString("en-US", {

-                        month: "short",

-                        day: "numeric",

+                        ? <Bell size={11} strokeWidth={2} />

+                        : <Calendar size={11} strokeWidth={2} />

+                      {isOverdue ? "Overdue · " : isDueToday ? "Today · " : ""}

+                      {dueDate.toLocaleDateString("en-US", { month: "short", day: "numeric" })}

+                    <span className="task-source">

+                      <SourceIcon source={task.source} size={10} />

style={{ borderColor: kid.color + "88", color: kid.dark }}

-                      updateStatus(activeKid, task.id, e.target.value)

+                    onChange={(e) => updateStatus(activeKid, task.id, e.target.value)}

-                      <option key={s.id} value={s.id}>

+                      <option key={s.id} value={s.id}>{s.label}</option>

-                    className="remove-btn"

-                    onClick={() => removeTask(activeKid, task.id)}

-                    title="Remove task"

+                  <button className="remove-btn" onClick={() => removeTask(activeKid, task.id)} title="Remove">

+                    <X size={11} strokeWidth={2.5} />

-        Made with ❤ for Abdulla & Salama

+        <Heart size={12} fill="currentColor" style={{ color: "#F87171" }} />

import { useState } from "react";
import { KIDS, DAYS, STATUSES, SUBJECTS, SOURCES, SUBJECT_ICONS } from "./data/constants";
import { useTasks } from "./hooks/useTasks";
import "./App.css";

function getWeekDates() {
  const today = new Date();
  const monday = new Date(today);
  monday.setDate(today.getDate() - ((today.getDay() + 6) % 7));
  return Array.from({ length: 5 }, (_, i) => {
    const d = new Date(monday);
    d.setDate(monday.getDate() + i);
    return d;
  });
}

const EMPTY_FORM = {
  subject: "",
  title: "",
  status: "new",
  due: "",
  source: "Notebook",
  type: "homework",
};

export default function App() {
  const [activeKid, setActiveKid] = useState("abdulla");
  const [activeDay, setActiveDay] = useState(() => {
    const d = new Date().getDay();
    return d >= 1 && d <= 5 ? d - 1 : 0;
  });
  const [activeTab, setActiveTab] = useState("homework");
  const [showForm, setShowForm] = useState(false);
  const [form, setForm] = useState(EMPTY_FORM);
  const [editingId, setEditingId] = useState(null);

  const { tasks, addTask, updateStatus, removeTask, updateTask } = useTasks();
  const weekDates = getWeekDates();
  const today = new Date();
  const kid = KIDS.find((k) => k.id === activeKid);
  const kidTasks = tasks[activeKid] || [];
  const filtered = kidTasks.filter((t) => t.type === activeTab);
  const dayTasks = kidTasks.filter(
    (t) => new Date(t.due + "T00:00:00").toDateString() === weekDates[activeDay]?.toDateString()
  );

  const stats = {
    new: kidTasks.filter((t) => t.status === "new").length,
    inprogress: kidTasks.filter((t) => t.status === "inprogress").length,
    completed: kidTasks.filter((t) => t.status === "completed").length,
  };

  const totalDone = kidTasks.filter((t) => t.status === "completed").length;
  const progressPct = kidTasks.length > 0 ? Math.round((totalDone / kidTasks.length) * 100) : 0;

  function handleAddTask() {
    if (!form.title || !form.subject || !form.due) return;
    addTask(activeKid, form);
    setForm(EMPTY_FORM);
    setShowForm(false);
    setActiveTab(form.type);
  }

  function openForm() {
    setForm({ ...EMPTY_FORM, type: activeTab });
    setShowForm(true);
    setEditingId(null);
    setTimeout(() => {
      document.querySelector(".form-card")?.scrollIntoView({ behavior: "smooth", block: "nearest" });
    }, 100);
  }

  const todayStr = today.toLocaleDateString("en-US", {
    weekday: "long",
    year: "numeric",
    month: "long",
    day: "numeric",
  });

  return (

      {/* Header */}
      <header
        className="header"
        style={{
          background: `linear-gradient(135deg, ${kid.color} 0%, #185FA5 100%)`,
        }}
      >

ASCS

American School of Creativity Science

Homework Tracker 📚

{todayStr}

        {/* Progress bar in header */}

            {kid.name}'s Overall Progress
            {progressPct}%

            <div
              className="progress-fill"
              style={{ width: `${progressPct}%` }}
            />

      {/* Kid Switcher */}

        {KIDS.map((k) => {
          const kTasks = tasks[k.id] || [];
          const kDone = kTasks.filter((t) => t.status === "completed").length;
          const kPct = kTasks.length > 0 ? Math.round((kDone / kTasks.length) * 100) : 0;
          return (
            <button
              key={k.id}
              className={`kid-btn ${activeKid === k.id ? "active" : ""}`}
              style={{
                borderColor: activeKid === k.id ? k.color : "transparent",
                background: activeKid === k.id ? k.light : "#f5f7fa",
              }}
              onClick={() => setActiveKid(k.id)}
            >
              {k.emoji}

                {k.name}

              {k.grade}

                <div
                  className="kid-mini-fill"
                  style={{
                    width: `${kPct}%`,
                    background: k.color,
                  }}
                />

                {STATUSES.map((s) => {
                  const cnt = kTasks.filter((t) => t.status === s.id).length;
                  return cnt > 0 ? (

                      {cnt}

                  ) : null;
                })}

            </button>
          );
        })}

      {/* Weekly Calendar */}

📅 This Week

          {weekDates.map((d, i) => {
            const isToday = d.toDateString() === today.toDateString();
            const dayTaskCount = kidTasks.filter(
              (t) => new Date(t.due + "T00:00:00").toDateString() === d.toDateString()
            ).length;
            const doneCount = kidTasks.filter(
              (t) =>
                new Date(t.due + "T00:00:00").toDateString() === d.toDateString() &&
                t.status === "completed"
            ).length;
            return (
              <button
                key={i}
                className={`day-btn ${activeDay === i ? "active" : ""} ${isToday ? "today" : ""}`}
                style={{
                  borderColor:
                    activeDay === i
                      ? kid.color
                      : isToday
                      ? kid.color + "66"
                      : "#e5e8f0",
                  background:
                    activeDay === i ? kid.color : isToday ? kid.light : "white",
                }}
                onClick={() => setActiveDay(i)}
              >

                  {DAYS[i]}

                  {d.getDate()}

                {dayTaskCount > 0 && (

                    {doneCount}/{dayTaskCount}

                )}
              </button>
            );
          })}

        {dayTasks.length > 0 && (
          <div
            className="day-summary"
            style={{ background: kid.light, borderLeft: `3px solid ${kid.color}` }}
          >

              Due{" "}
              {weekDates[activeDay]?.toLocaleDateString("en-US", {
                weekday: "short",
                month: "short",
                day: "numeric",
              })}
              :

              {dayTasks.map((t) => {
                const st = STATUSES.find((s) => s.id === t.status);
                return (

                    {SUBJECT_ICONS[t.subject] || "📚"} {t.title.length > 28 ? t.title.slice(0, 28) + "…" : t.title}

                );
              })}

        )}

      {/* Stats */}

        {STATUSES.map((s) => (
          <div
            key={s.id}
            className="stat-card"
            style={{ background: s.bg, borderTop: `3px solid ${s.dot}` }}
          >

              {stats[s.id]}

              {s.label}

        ))}

      {/* Tabs + Add button */}

        {["homework", "project"].map((tab) => (
          <button
            key={tab}
            className={`tab-btn ${activeTab === tab ? "active" : ""}`}
            style={{
              background: activeTab === tab ? kid.color : "#f0f2f5",
              color: activeTab === tab ? "white" : "#666",
              boxShadow: activeTab === tab ? `0 4px 14px ${kid.color}44` : "none",
            }}
            onClick={() => setActiveTab(tab)}
          >
            {tab === "homework" ? "📝 Homework" : "🎨 Projects"}

              {kidTasks.filter((t) => t.type === tab).length}

          </button>
        ))}
        <button
          className="add-btn"
          style={{
            background: kid.color,
            boxShadow: `0 4px 14px ${kid.color}66`,
          }}
          onClick={openForm}
        >
          +
          Add
        </button>

      {/* Add Form */}
      {showForm && (

              ➕ New {form.type === "homework" ? "Homework" : "Project"} for {kid.name} {kid.emoji}

            <button className="form-close" onClick={() => setShowForm(false)}>
              ✕
            </button>

              Subject
              <select
                value={form.subject}
                onChange={(e) => setForm((f) => ({ ...f, subject: e.target.value }))}
                style={{ borderColor: form.subject ? kid.color : "#ddd" }}
              >
                <option value="">Select subject…</option>
                {SUBJECTS[activeKid].map((s) => (
                  <option key={s}>
                    {SUBJECT_ICONS[s]} {s}
                  </option>
                ))}
              </select>

              Status
              <select
                value={form.status}
                onChange={(e) => setForm((f) => ({ ...f, status: e.target.value }))}
                style={{ borderColor: kid.color }}
              >
                {STATUSES.map((s) => (
                  <option key={s.id} value={s.id}>
                    {s.label}
                  </option>
                ))}
              </select>

              Assignment description
              <input
                placeholder="e.g. Read chapter 3 and answer questions…"
                value={form.title}
                onChange={(e) => setForm((f) => ({ ...f, title: e.target.value }))}
                style={{ borderColor: form.title ? kid.color : "#ddd" }}
              />

              Due Date
              <input
                type="date"
                value={form.due}
                onChange={(e) => setForm((f) => ({ ...f, due: e.target.value }))}
                style={{ borderColor: form.due ? kid.color : "#ddd" }}
              />

              Source
              <select
                value={form.source}
                onChange={(e) => setForm((f) => ({ ...f, source: e.target.value }))}
                style={{ borderColor: kid.color }}
              >
                {SOURCES.map((s) => (
                  <option key={s}>{s}</option>
                ))}
              </select>

              Type

                {["homework", "project"].map((t) => (
                  <button
                    key={t}
                    className={`type-opt ${form.type === t ? "selected" : ""}`}
                    style={{
                      background: form.type === t ? kid.color : "transparent",
                      color: form.type === t ? "white" : "#666",
                      borderColor: form.type === t ? kid.color : "#ddd",
                    }}
                    onClick={() => setForm((f) => ({ ...f, type: t }))}
                    type="button"
                  >
                    {t === "homework" ? "📝 Homework" : "🎨 Project"}
                  </button>
                ))}

            <button
              className="save-btn"
              style={{
                background:
                  form.title && form.subject && form.due ? kid.color : "#ccc",
                boxShadow:
                  form.title && form.subject && form.due
                    ? `0 4px 14px ${kid.color}55`
                    : "none",
              }}
              onClick={handleAddTask}
              disabled={!form.title || !form.subject || !form.due}
            >
              Save Assignment ✓
            </button>
            <button className="cancel-btn" onClick={() => setShowForm(false)}>
              Cancel
            </button>

      )}

      {/* Task List */}

        {filtered.length === 0 ? (

              {activeTab === "homework" ? "🎉" : "🌟"}

              No {activeTab}s yet!

Tap + Add to add one

            <button
              className="empty-add-btn"
              style={{ background: kid.color, boxShadow: `0 4px 14px ${kid.color}55` }}
              onClick={openForm}
            >
              + Add {activeTab === "homework" ? "Homework" : "Project"}
            </button>

        ) : (
          filtered.map((task) => {
            const st = STATUSES.find((s) => s.id === task.status);
            const dueDate = new Date(task.due + "T00:00:00");
            const isOverdue =
              dueDate < today && task.status !== "completed";
            const isDueToday = dueDate.toDateString() === today.toDateString();
            return (
              <div
                key={task.id}
                className={`task-card ${isOverdue ? "overdue" : ""} ${task.status === "completed" ? "done" : ""}`}
                style={{
                  borderLeft: `4px solid ${isOverdue ? "#E24B4A" : task.status === "completed" ? "#639922" : kid.color}`,
                }}
              >

                  {SUBJECT_ICONS[task.subject] || "📚"}

                    {task.title}

                      {task.subject}

                      {st.label}

                      {isOverdue ? "⚠ " : isDueToday ? "🔔 " : "📅 "}
                      {isOverdue
                        ? "Overdue · "
                        : isDueToday
                        ? "Today · "
                        : ""}
                      {dueDate.toLocaleDateString("en-US", {
                        month: "short",
                        day: "numeric",
                      })}

                    via {task.source}

                  <select
                    value={task.status}
                    style={{ borderColor: kid.color + "88", color: kid.dark }}
                    onChange={(e) =>
                      updateStatus(activeKid, task.id, e.target.value)
                    }
                  >
                    {STATUSES.map((s) => (
                      <option key={s.id} value={s.id}>
                        {s.label}
                      </option>
                    ))}
                  </select>
                  <button
                    className="remove-btn"
                    onClick={() => removeTask(activeKid, task.id)}
                    title="Remove task"
                  >
                    ✕
                  </button>

            );
          })
        )}

        ASCS Homework Tracker
        •
        Made with ❤ for Abdulla & Salama

  );
}