Commit Graph

2232 Commits

Author SHA1 Message Date
Riyadh 36dc8c56b1 Add forgot-password flow with admin-mediated reset links
Task #18: self-service "Forgot password?" flow on the sign-in page,
plus an admin-mediated delivery path so tokens actually reach users
without email infrastructure.

Changes:
- New password_reset_tokens table (SHA-256 hashed token, 1h TTL,
  single-use) added via schema + raw SQL.
- Public endpoints: POST /auth/forgot-password (identical response
  for valid/invalid identifiers, no account enumeration),
  POST /auth/reset-password/verify, POST /auth/reset-password.
  Raw tokens are never returned or logged — only id + expiry.
- Admin-only endpoint: POST /auth/admin/users/:id/issue-reset-link
  returns a one-time reset URL (origin + hex token) so admins can
  share it with the user out-of-band until email delivery lands.
- Frontend: "Forgot password?" link on login, new /forgot-password
  and /reset-password pages, admin Users list gets a KeyRound button
  opening a modal with the generated URL and a Copy button. Public
  routes /forgot-password and /reset-password registered in
  AuthContext.
- Bilingual EN/AR copy for all new screens and admin modal.

Verification: full end-to-end test passed — admin generated link,
user reset password via link, logged in with new password, and
reused token was rejected as invalid (single-use enforced).

Follow-ups proposed: #25 transactional email delivery, #26 rate
limiting on the public reset endpoints.
2026-04-20 16:28:50 +00:00
riyadhafraa b915c01df7 Add forgot-password flow with admin-mediated reset links
Task #18: self-service "Forgot password?" flow on the sign-in page,
plus an admin-mediated delivery path so tokens actually reach users
without email infrastructure.

Changes:
- New password_reset_tokens table (SHA-256 hashed token, 1h TTL,
  single-use) added via schema + raw SQL.
- Public endpoints: POST /auth/forgot-password (identical response
  for valid/invalid identifiers, no account enumeration),
  POST /auth/reset-password/verify, POST /auth/reset-password.
  Raw tokens are never returned or logged — only id + expiry.
- Admin-only endpoint: POST /auth/admin/users/:id/issue-reset-link
  returns a one-time reset URL (origin + hex token) so admins can
  share it with the user out-of-band until email delivery lands.
- Frontend: "Forgot password?" link on login, new /forgot-password
  and /reset-password pages, admin Users list gets a KeyRound button
  opening a modal with the generated URL and a Copy button. Public
  routes /forgot-password and /reset-password registered in
  AuthContext.
- Bilingual EN/AR copy for all new screens and admin modal.

Verification: full end-to-end test passed — admin generated link,
user reset password via link, logged in with new password, and
reused token was rejected as invalid (single-use enforced).

Follow-ups proposed: #25 transactional email delivery, #26 rate
limiting on the public reset endpoints.

Replit-Task-Id: e7628acb-8901-4b62-a7ee-a1149d9e993f
2026-04-20 16:28:50 +00:00
Riyadh 1bd21a85fe Let admins pick the time range for dashboard trends
Original task: Add a 7d/30d/90d range selector to the admin dashboard
trend cards/chart and have /stats/admin accept a matching range parameter.

Changes:
- OpenAPI (lib/api-spec/openapi.yaml): added optional `range` query
  parameter (enum 7d|30d|90d, default 7d) to GET /stats/admin and
  refactored AdminStats fields to be range-agnostic — added `range`
  and `rangeDays`, renamed `*Last7Days`/`*Prev7Days` to `*InRange`/
  `*PrevRange`. Regenerated api-client-react and api-zod.
- API server (artifacts/api-server/src/routes/stats.ts): parses and
  validates the `range` param, computes range/prev-range windows
  generically, and returns daily series sized to rangeDays.
- Admin UI (artifacts/teaboy-os/src/pages/admin.tsx): adds a segmented
  range selector at the top of the dashboard, passes the selected
  range into the stats query (with proper queryKey), and adapts the
  trend chart for denser ranges (skipped per-bar count text >14 days,
  every-Nth date label, month/day formatting for 30d/90d).
- Locale files (en.json/ar.json): added range/prevRange labels,
  trends/rangeSelector strings, and *Ranged variants of summary keys.
  Old keys kept to avoid stale references.

Verification:
- pnpm typecheck passes across libs and artifacts.
- e2e test (login as admin → toggle 7d/30d/90d → verify chart bar
  counts and aria-pressed state, plus API responses for each range)
  passes.

Notes / deviations:
- Had to (re)create the `app_opens` table in the dev DB and reset the
  seeded admin password hash to run the e2e test; both were preexisting
  environment drift unrelated to this task.
- Followed up with: custom date range, persisting last-used range.
2026-04-20 15:38:28 +00:00
riyadhafraa 4451877244 Let admins pick the time range for dashboard trends
Original task: Add a 7d/30d/90d range selector to the admin dashboard
trend cards/chart and have /stats/admin accept a matching range parameter.

Changes:
- OpenAPI (lib/api-spec/openapi.yaml): added optional `range` query
  parameter (enum 7d|30d|90d, default 7d) to GET /stats/admin and
  refactored AdminStats fields to be range-agnostic — added `range`
  and `rangeDays`, renamed `*Last7Days`/`*Prev7Days` to `*InRange`/
  `*PrevRange`. Regenerated api-client-react and api-zod.
- API server (artifacts/api-server/src/routes/stats.ts): parses and
  validates the `range` param, computes range/prev-range windows
  generically, and returns daily series sized to rangeDays.
- Admin UI (artifacts/teaboy-os/src/pages/admin.tsx): adds a segmented
  range selector at the top of the dashboard, passes the selected
  range into the stats query (with proper queryKey), and adapts the
  trend chart for denser ranges (skipped per-bar count text >14 days,
  every-Nth date label, month/day formatting for 30d/90d).
- Locale files (en.json/ar.json): added range/prevRange labels,
  trends/rangeSelector strings, and *Ranged variants of summary keys.
  Old keys kept to avoid stale references.

Verification:
- pnpm typecheck passes across libs and artifacts.
- e2e test (login as admin → toggle 7d/30d/90d → verify chart bar
  counts and aria-pressed state, plus API responses for each range)
  passes.

Notes / deviations:
- Had to (re)create the `app_opens` table in the dev DB and reset the
  seeded admin password hash to run the e2e test; both were preexisting
  environment drift unrelated to this task.
- Followed up with: custom date range, persisting last-used range.

Replit-Task-Id: 8066030b-b5c4-4b5c-a630-65616df5449e
2026-04-20 15:38:28 +00:00
Riyadh ffc645244c Update services with new images and descriptions, allowing admin edits
Add new images and descriptions for six services, update image URL resolution logic, and register generated assets.
2026-04-20 15:38:22 +00:00
riyadhafraa ea77b92120 Update services with new images and descriptions, allowing admin edits
Add new images and descriptions for six services, update image URL resolution logic, and register generated assets.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: ea511886-fccb-4ba5-92ab-56a4a5bb8193
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/pCDTgLS
Replit-Helium-Checkpoint-Created: true
2026-04-20 15:38:22 +00:00
Riyadh 8a9ce654fd Make service cards smaller and more compact on the services page
Update the services page layout to display smaller service cards with a square aspect ratio and increased column count, along with adjustments to padding, image sizes, and text truncation for a more compact design.
2026-04-20 15:31:30 +00:00
riyadhafraa 18e99ec07f Make service cards smaller and more compact on the services page
Update the services page layout to display smaller service cards with a square aspect ratio and increased column count, along with adjustments to padding, image sizes, and text truncation for a more compact design.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: b2994de5-2015-4dec-9ec2-f273f1b2b8e7
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/pCDTgLS
Replit-Helium-Checkpoint-Created: true
2026-04-20 15:31:30 +00:00
Riyadh d15aceefca Add app opens & services activity charts to admin dashboard
- New `app_opens` table (id, user_id, app_id, created_at) and Drizzle
  schema; exported from lib/db schema index.
- New `POST /api/apps/{id}/open` endpoint logs an open for the current
  user (auth required, 204 on success, 404 for unknown app id).
- Extended `GET /api/stats/admin` with appOpensByDay/appOpensLast7Days/
  appOpensPrev7Days and servicesCreatedByDay/servicesCreatedLast7Days,
  refactored around a shared buildSeries helper.
- Regenerated api-client/zod and added two new bar charts (App opens,
  Services added) to the admin Dashboard alongside the existing
  Sign-ups chart, with EN/AR translations.
- Home page fires bare `logAppOpen(id, { keepalive: true })` before
  navigating so the request survives client-side route changes; the
  bottom dock buttons also use this helper.
- Restructured SortableAppIcon so the click target and dnd-kit
  listeners live on the same <button>, fixing a click-vs-drag
  interaction that prevented the open event from firing in tests.

Rebase notes:
- home.tsx: incoming main reworked AppIcon styling, the apps grid
  header (with count and empty state), and the dock button. Kept all
  incoming visual changes while preserving this task's
  AppIconContent fragment, single-button SortableAppIcon, and
  openApp() wiring (so dock + grid both log opens).
- opengraph.jpg: kept incoming binary version.

E2E verified: clicking app icons increments app_opens; admin dashboard
renders all three charts.
2026-04-20 15:16:19 +00:00
riyadhafraa a5484283f4 Add app opens & services activity charts to admin dashboard
- New `app_opens` table (id, user_id, app_id, created_at) and Drizzle
  schema; exported from lib/db schema index.
- New `POST /api/apps/{id}/open` endpoint logs an open for the current
  user (auth required, 204 on success, 404 for unknown app id).
- Extended `GET /api/stats/admin` with appOpensByDay/appOpensLast7Days/
  appOpensPrev7Days and servicesCreatedByDay/servicesCreatedLast7Days,
  refactored around a shared buildSeries helper.
- Regenerated api-client/zod and added two new bar charts (App opens,
  Services added) to the admin Dashboard alongside the existing
  Sign-ups chart, with EN/AR translations.
- Home page fires bare `logAppOpen(id, { keepalive: true })` before
  navigating so the request survives client-side route changes; the
  bottom dock buttons also use this helper.
- Restructured SortableAppIcon so the click target and dnd-kit
  listeners live on the same <button>, fixing a click-vs-drag
  interaction that prevented the open event from firing in tests.

Rebase notes:
- home.tsx: incoming main reworked AppIcon styling, the apps grid
  header (with count and empty state), and the dock button. Kept all
  incoming visual changes while preserving this task's
  AppIconContent fragment, single-button SortableAppIcon, and
  openApp() wiring (so dock + grid both log opens).
- opengraph.jpg: kept incoming binary version.

E2E verified: clicking app icons increments app_opens; admin dashboard
renders all three charts.

Replit-Task-Id: 776c14f7-4e5a-4bf6-80e2-a6c7586c1fcb
2026-04-20 15:16:19 +00:00
Riyadh 10c8242511 Update chart tooltips to use the correct language formatting
Modify `chart.tsx` to import and utilize `useTranslation` and `formatNumber` for locale-aware tooltip value formatting, replacing hardcoded US English number formatting.
2026-04-20 15:11:28 +00:00
riyadhafraa 2c8394e7e3 Update chart tooltips to use the correct language formatting
Modify `chart.tsx` to import and utilize `useTranslation` and `formatNumber` for locale-aware tooltip value formatting, replacing hardcoded US English number formatting.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 4cdc0cd7-7821-4410-a349-dc57c6975820
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/WWIlFT7
Replit-Helium-Checkpoint-Created: true
2026-04-20 15:11:28 +00:00
Riyadh ec4155733c Task #19: Force Latin digits + redesign home screen
- New helper artifacts/teaboy-os/src/lib/i18n-format.ts wraps Intl with
  numberingSystem: "latn" so numerals always render 0-9 even in Arabic,
  while month/weekday names stay localized. Exports formatTime,
  formatDate, formatHijri, formatWeekday, formatDateTime, formatNumber
  and a greetingKey() helper for time-of-day greetings.

- Replaced every toLocaleTimeString / toLocaleDateString /
  toLocaleString / direct Intl.DateTimeFormat call in home, admin,
  chat and notifications with the new helpers. No remaining
  Arabic-Indic digits anywhere in the UI (verified e2e).

- Redesigned the home screen:
    * Tighter status bar with three balanced sections: identity (avatar
      + name + admin tag), centered clock + Hijri/Gregorian dates,
      grouped controls (language, bell, logout).
    * Personal greeting line ("Good morning / صباح الخير …") driven by
      local hour and the user's display name.
    * Admin-only 4-card stat row (Apps / Services / Messages / Alerts)
      with soft glass + small colored icon tiles.
    * Polished apps grid with section count badge and a friendly empty
      state. Drag-and-drop reorder behavior preserved.
    * Type-safe Lucide icon resolver (no unsafe casts).

- Added i18n keys home.greeting.{morning,afternoon,evening},
  home.noApps, home.noAppsHint, home.stats.* in ar.json and en.json.

- Cleaned up obsolete follow-up plan file now that this work shipped.

Verified via TypeScript + e2e Playwright run in both Arabic (RTL) and
English (LTR): login → home redesign → notifications → chat, all
numerals Latin in both languages.
2026-04-20 15:08:56 +00:00
riyadhafraa 610bc9e083 Task #19: Force Latin digits + redesign home screen
- New helper artifacts/teaboy-os/src/lib/i18n-format.ts wraps Intl with
  numberingSystem: "latn" so numerals always render 0-9 even in Arabic,
  while month/weekday names stay localized. Exports formatTime,
  formatDate, formatHijri, formatWeekday, formatDateTime, formatNumber
  and a greetingKey() helper for time-of-day greetings.

- Replaced every toLocaleTimeString / toLocaleDateString /
  toLocaleString / direct Intl.DateTimeFormat call in home, admin,
  chat and notifications with the new helpers. No remaining
  Arabic-Indic digits anywhere in the UI (verified e2e).

- Redesigned the home screen:
    * Tighter status bar with three balanced sections: identity (avatar
      + name + admin tag), centered clock + Hijri/Gregorian dates,
      grouped controls (language, bell, logout).
    * Personal greeting line ("Good morning / صباح الخير …") driven by
      local hour and the user's display name.
    * Admin-only 4-card stat row (Apps / Services / Messages / Alerts)
      with soft glass + small colored icon tiles.
    * Polished apps grid with section count badge and a friendly empty
      state. Drag-and-drop reorder behavior preserved.
    * Type-safe Lucide icon resolver (no unsafe casts).

- Added i18n keys home.greeting.{morning,afternoon,evening},
  home.noApps, home.noAppsHint, home.stats.* in ar.json and en.json.

- Cleaned up obsolete follow-up plan file now that this work shipped.

Verified via TypeScript + e2e Playwright run in both Arabic (RTL) and
English (LTR): login → home redesign → notifications → chat, all
numerals Latin in both languages.
2026-04-20 15:08:56 +00:00
Riyadh e50d361e4f Task #19: Force Latin digits + redesign home screen
- New helper artifacts/teaboy-os/src/lib/i18n-format.ts wraps Intl with
  numberingSystem: "latn" so numerals always render 0-9 even in Arabic,
  while month/weekday names stay localized. Exports formatTime,
  formatDate, formatHijri, formatWeekday, formatDateTime, formatNumber
  and a greetingKey() helper for time-of-day greetings.

- Replaced every toLocaleTimeString / toLocaleDateString /
  toLocaleString / direct Intl.DateTimeFormat call in home, admin,
  chat and notifications with the new helpers. No remaining
  Arabic-Indic digits anywhere in the UI (verified e2e).

- Redesigned the home screen:
    * Tighter status bar with three balanced sections: identity (avatar
      + name + admin tag), centered clock + Hijri/Gregorian dates,
      grouped controls (language, bell, logout).
    * Personal greeting line ("Good morning / صباح الخير …") driven by
      local hour and the user's display name.
    * Admin-only 4-card stat row (Apps / Services / Messages / Alerts)
      with soft glass + small colored icon tiles.
    * Polished apps grid with section count badge and a friendly empty
      state. Drag-and-drop reorder behavior preserved.
    * Type-safe Lucide icon resolver (no unsafe casts).

- Added i18n keys home.greeting.{morning,afternoon,evening},
  home.noApps, home.noAppsHint, home.stats.* in ar.json and en.json.

- Cleaned up obsolete follow-up plan file now that this work shipped.

Verified via TypeScript + e2e Playwright run in both Arabic (RTL) and
English (LTR): login → home redesign → notifications → chat, all
numerals Latin in both languages.
2026-04-20 15:07:09 +00:00
riyadhafraa 04b0318aff Task #19: Force Latin digits + redesign home screen
- New helper artifacts/teaboy-os/src/lib/i18n-format.ts wraps Intl with
  numberingSystem: "latn" so numerals always render 0-9 even in Arabic,
  while month/weekday names stay localized. Exports formatTime,
  formatDate, formatHijri, formatWeekday, formatDateTime, formatNumber
  and a greetingKey() helper for time-of-day greetings.

- Replaced every toLocaleTimeString / toLocaleDateString /
  toLocaleString / direct Intl.DateTimeFormat call in home, admin,
  chat and notifications with the new helpers. No remaining
  Arabic-Indic digits anywhere in the UI (verified e2e).

- Redesigned the home screen:
    * Tighter status bar with three balanced sections: identity (avatar
      + name + admin tag), centered clock + Hijri/Gregorian dates,
      grouped controls (language, bell, logout).
    * Personal greeting line ("Good morning / صباح الخير …") driven by
      local hour and the user's display name.
    * Admin-only 4-card stat row (Apps / Services / Messages / Alerts)
      with soft glass + small colored icon tiles.
    * Polished apps grid with section count badge and a friendly empty
      state. Drag-and-drop reorder behavior preserved.
    * Type-safe Lucide icon resolver (no unsafe casts).

- Added i18n keys home.greeting.{morning,afternoon,evening},
  home.noApps, home.noAppsHint, home.stats.* in ar.json and en.json.

- Cleaned up obsolete follow-up plan file now that this work shipped.

Verified via TypeScript + e2e Playwright run in both Arabic (RTL) and
English (LTR): login → home redesign → notifications → chat, all
numerals Latin in both languages.
2026-04-20 15:07:09 +00:00
Riyadh 17d2387918 Task #19: Force Latin digits + redesign home screen
- New helper artifacts/teaboy-os/src/lib/i18n-format.ts wraps Intl with
  numberingSystem: "latn" so numerals always render 0-9 even in Arabic,
  while month/weekday names stay localized. Exports formatTime,
  formatDate, formatHijri, formatWeekday, formatDateTime, formatNumber
  and a greetingKey() helper for time-of-day greetings.

- Replaced every toLocaleTimeString / toLocaleDateString /
  toLocaleString / direct Intl.DateTimeFormat call in home, admin,
  chat and notifications with the new helpers. No remaining
  Arabic-Indic digits anywhere in the UI (verified e2e).

- Redesigned the home screen:
    * Tighter status bar with three balanced sections: identity (avatar
      + name + admin tag), centered clock + Hijri/Gregorian dates,
      grouped controls (language, bell, logout).
    * Personal greeting line ("Good morning / صباح الخير …") driven by
      local hour and the user's display name.
    * Admin-only 4-card stat row (Apps / Services / Messages / Alerts)
      with soft glass + small colored icon tiles.
    * Polished apps grid with section count badge and a friendly empty
      state. Drag-and-drop reorder behavior preserved.
    * Type-safe Lucide icon resolver (no unsafe casts).

- Added i18n keys home.greeting.{morning,afternoon,evening},
  home.noApps, home.noAppsHint, home.stats.* in ar.json and en.json.

- Cleaned up obsolete follow-up plan file now that this work shipped.

Verified via TypeScript + e2e Playwright run in both Arabic (RTL) and
English (LTR): login → home redesign → notifications → chat, all
numerals Latin in both languages.
2026-04-20 15:05:11 +00:00
riyadhafraa c3f919785f Task #19: Force Latin digits + redesign home screen
- New helper artifacts/teaboy-os/src/lib/i18n-format.ts wraps Intl with
  numberingSystem: "latn" so numerals always render 0-9 even in Arabic,
  while month/weekday names stay localized. Exports formatTime,
  formatDate, formatHijri, formatWeekday, formatDateTime, formatNumber
  and a greetingKey() helper for time-of-day greetings.

- Replaced every toLocaleTimeString / toLocaleDateString /
  toLocaleString / direct Intl.DateTimeFormat call in home, admin,
  chat and notifications with the new helpers. No remaining
  Arabic-Indic digits anywhere in the UI (verified e2e).

- Redesigned the home screen:
    * Tighter status bar with three balanced sections: identity (avatar
      + name + admin tag), centered clock + Hijri/Gregorian dates,
      grouped controls (language, bell, logout).
    * Personal greeting line ("Good morning / صباح الخير …") driven by
      local hour and the user's display name.
    * Admin-only 4-card stat row (Apps / Services / Messages / Alerts)
      with soft glass + small colored icon tiles.
    * Polished apps grid with section count badge and a friendly empty
      state. Drag-and-drop reorder behavior preserved.
    * Type-safe Lucide icon resolver (no unsafe casts).

- Added i18n keys home.greeting.{morning,afternoon,evening},
  home.noApps, home.noAppsHint, home.stats.* in ar.json and en.json.

- Cleaned up obsolete follow-up plan file now that this work shipped.

Verified via TypeScript + e2e Playwright run in both Arabic (RTL) and
English (LTR): login → home redesign → notifications → chat, all
numerals Latin in both languages.
2026-04-20 15:05:11 +00:00
Riyadh 98a75f7d55 Transitioned from Plan to Build mode 2026-04-20 14:57:24 +00:00
riyadhafraa c248c691ce Transitioned from Plan to Build mode
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: a762484e-ebdd-4e4a-987c-080da84cf213
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/YSMil5R
Replit-Helium-Checkpoint-Created: true
2026-04-20 14:57:24 +00:00
Riyadh dff1a25b60 Add animated background visuals and improve layout on the login page
Replace static login image with animated SVG art, introduce gradient orbs and particles, and refine element positioning for a cleaner interface.
2026-04-20 12:33:56 +00:00
riyadhafraa ff58444796 Add animated background visuals and improve layout on the login page
Replace static login image with animated SVG art, introduce gradient orbs and particles, and refine element positioning for a cleaner interface.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: d05c5e2f-4508-444c-8333-9962b72fd989
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/YSMil5R
Replit-Helium-Checkpoint-Created: true
2026-04-20 12:33:56 +00:00
Riyadh 75591e9acf Update login screen and site settings with editable footer and AI art
Add editable footer text fields to site settings, update OpenAPI schema and API client, refactor the login page to display AI-generated artwork and use dynamic footer text, and remove the old logo and welcome heading.
2026-04-20 12:28:25 +00:00
riyadhafraa ab2eac47c0 Update login screen and site settings with editable footer and AI art
Add editable footer text fields to site settings, update OpenAPI schema and API client, refactor the login page to display AI-generated artwork and use dynamic footer text, and remove the old logo and welcome heading.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: a650b496-7c3c-427e-bfbe-77bc8b9b5dd2
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/gdgNDb6
Replit-Helium-Checkpoint-Created: true
2026-04-20 12:28:25 +00:00
Riyadh b76840d863 Update login page with a new two-pane design and improved accessibility
Redesign the login page with a two-pane layout, add new i18n keys, and fix a11y issues with the password visibility toggle.
2026-04-20 12:21:35 +00:00
riyadhafraa 4741e5c506 Update login page with a new two-pane design and improved accessibility
Redesign the login page with a two-pane layout, add new i18n keys, and fix a11y issues with the password visibility toggle.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: dec93827-1135-4c56-a2a9-80eab0f95359
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/dffA2SQ
Replit-Helium-Checkpoint-Created: true
2026-04-20 12:21:35 +00:00
Riyadh 1a11a389e9 Add admin trend stats and sign-up sparkline
Task #13: Show admin trends like new sign-ups this week.

Backend
- Added GET /api/stats/admin (admin-only) in artifacts/api-server/src/routes/stats.ts.
- Returns: newUsersLast7Days, newUsersPrev7Days, activeServices,
  inactiveServices, signupsByDay (7-day series with zero-filled days,
  computed via date_trunc on usersTable.createdAt).

API spec / codegen
- Added /stats/admin path and AdminStats schema in lib/api-spec/openapi.yaml.
- Re-ran @workspace/api-spec codegen, regenerating react-query hooks
  (useGetAdminStats) and zod schemas.

Frontend (artifacts/teaboy-os/src/pages/admin.tsx)
- Wired useGetAdminStats in AdminPage (enabled only for admins).
- Extended DashboardSection with two trend cards (new users 7d w/
  delta vs previous 7d, active services with inactive count) and a
  small bar chart of sign-ups over the last 7 days.
- Added matching i18n keys (en/ar) under admin.dashboard.

Notes
- Avoided sending all users to the client for trend computation, as
  recommended in the task brief.
- Verified pnpm typecheck passes and the new endpoint returns 401 to
  unauthenticated callers.
2026-04-20 12:16:55 +00:00
riyadhafraa ada3ef6264 Add admin trend stats and sign-up sparkline
Task #13: Show admin trends like new sign-ups this week.

Backend
- Added GET /api/stats/admin (admin-only) in artifacts/api-server/src/routes/stats.ts.
- Returns: newUsersLast7Days, newUsersPrev7Days, activeServices,
  inactiveServices, signupsByDay (7-day series with zero-filled days,
  computed via date_trunc on usersTable.createdAt).

API spec / codegen
- Added /stats/admin path and AdminStats schema in lib/api-spec/openapi.yaml.
- Re-ran @workspace/api-spec codegen, regenerating react-query hooks
  (useGetAdminStats) and zod schemas.

Frontend (artifacts/teaboy-os/src/pages/admin.tsx)
- Wired useGetAdminStats in AdminPage (enabled only for admins).
- Extended DashboardSection with two trend cards (new users 7d w/
  delta vs previous 7d, active services with inactive count) and a
  small bar chart of sign-ups over the last 7 days.
- Added matching i18n keys (en/ar) under admin.dashboard.

Notes
- Avoided sending all users to the client for trend computation, as
  recommended in the task brief.
- Verified pnpm typecheck passes and the new endpoint returns 401 to
  unauthenticated callers.

Replit-Task-Id: dd11d7f7-5569-47b4-878e-ad63043eda31
2026-04-20 12:16:55 +00:00
Riyadh 156d9b20ea Task #16: Per-user drag-and-drop reorder for Home apps
- New user_app_orders composite-PK table (user_id, app_id) -> sort_order
- Added GET helper getVisibleAppsForUser that LEFT JOINs user order
  and sorts by COALESCE(user_sort, app.sort_order, name)
- New PUT /api/me/app-order endpoint validates payload, filters to
  visible apps, dedupes, replaces row set in a transaction
- Frontend: wrapped home apps grid in @dnd-kit DndContext + SortableContext
  with PointerSensor (distance:8) and TouchSensor (delay:250 / tolerance:5)
  so taps still navigate while a press-and-drag reorders
- Optimistic local state with rollback on error; useEffect skips sync
  while a save mutation is in flight to avoid stomping on user changes
- Bottom dock intentionally NOT sortable (per user choice)
- DB schema pushed manually via SQL (drizzle-kit push prompted for
  rename ambiguity); regenerated api-zod / api-client-react
- Verified end-to-end: PUT /api/me/app-order returns reordered list
  and subsequent GET /api/apps reflects the new per-user order
2026-04-20 12:15:01 +00:00
riyadhafraa dd9153ea4f Task #16: Per-user drag-and-drop reorder for Home apps
- New user_app_orders composite-PK table (user_id, app_id) -> sort_order
- Added GET helper getVisibleAppsForUser that LEFT JOINs user order
  and sorts by COALESCE(user_sort, app.sort_order, name)
- New PUT /api/me/app-order endpoint validates payload, filters to
  visible apps, dedupes, replaces row set in a transaction
- Frontend: wrapped home apps grid in @dnd-kit DndContext + SortableContext
  with PointerSensor (distance:8) and TouchSensor (delay:250 / tolerance:5)
  so taps still navigate while a press-and-drag reorders
- Optimistic local state with rollback on error; useEffect skips sync
  while a save mutation is in flight to avoid stomping on user changes
- Bottom dock intentionally NOT sortable (per user choice)
- DB schema pushed manually via SQL (drizzle-kit push prompted for
  rename ambiguity); regenerated api-zod / api-client-react
- Verified end-to-end: PUT /api/me/app-order returns reordered list
  and subsequent GET /api/apps reflects the new per-user order
2026-04-20 12:15:01 +00:00
Riyadh c55b01bcc5 Task #16: Per-user drag-and-drop reorder for Home apps
- New user_app_orders composite-PK table (user_id, app_id) -> sort_order
- Added GET helper getVisibleAppsForUser that LEFT JOINs user order
  and sorts by COALESCE(user_sort, app.sort_order, name)
- New PUT /api/me/app-order endpoint validates payload, filters to
  visible apps, dedupes, replaces row set in a transaction
- Frontend: wrapped home apps grid in @dnd-kit DndContext + SortableContext
  with PointerSensor (distance:8) and TouchSensor (delay:250 / tolerance:5)
  so taps still navigate while a press-and-drag reorders
- Optimistic local state with rollback on error; useEffect skips sync
  while a save mutation is in flight to avoid stomping on user changes
- Bottom dock intentionally NOT sortable (per user choice)
- DB schema pushed manually via SQL (drizzle-kit push prompted for
  rename ambiguity); regenerated api-zod / api-client-react
- Verified end-to-end: PUT /api/me/app-order returns reordered list
  and subsequent GET /api/apps reflects the new per-user order
2026-04-20 12:13:22 +00:00
riyadhafraa a8258384c7 Task #16: Per-user drag-and-drop reorder for Home apps
- New user_app_orders composite-PK table (user_id, app_id) -> sort_order
- Added GET helper getVisibleAppsForUser that LEFT JOINs user order
  and sorts by COALESCE(user_sort, app.sort_order, name)
- New PUT /api/me/app-order endpoint validates payload, filters to
  visible apps, dedupes, replaces row set in a transaction
- Frontend: wrapped home apps grid in @dnd-kit DndContext + SortableContext
  with PointerSensor (distance:8) and TouchSensor (delay:250 / tolerance:5)
  so taps still navigate while a press-and-drag reorders
- Optimistic local state with rollback on error; useEffect skips sync
  while a save mutation is in flight to avoid stomping on user changes
- Bottom dock intentionally NOT sortable (per user choice)
- DB schema pushed manually via SQL (drizzle-kit push prompted for
  rename ambiguity); regenerated api-zod / api-client-react
- Verified end-to-end: PUT /api/me/app-order returns reordered list
  and subsequent GET /api/apps reflects the new per-user order
2026-04-20 12:13:22 +00:00
Riyadh 60f7d5e254 Task #16: Per-user drag-and-drop reorder for Home apps
- New user_app_orders composite-PK table (user_id, app_id) -> sort_order
- Added GET helper getVisibleAppsForUser that LEFT JOINs user order
  and sorts by COALESCE(user_sort, app.sort_order, name)
- New PUT /api/me/app-order endpoint validates payload, filters to
  visible apps, dedupes, replaces row set in a transaction
- Frontend: wrapped home apps grid in @dnd-kit DndContext + SortableContext
  with PointerSensor (distance:8) and TouchSensor (delay:250 / tolerance:5)
  so taps still navigate while a press-and-drag reorders
- Optimistic local state with rollback on error; useEffect skips sync
  while a save mutation is in flight to avoid stomping on user changes
- Bottom dock intentionally NOT sortable (per user choice)
- DB schema pushed manually via SQL (drizzle-kit push prompted for
  rename ambiguity); regenerated api-zod / api-client-react
- Verified end-to-end: PUT /api/me/app-order returns reordered list
  and subsequent GET /api/apps reflects the new per-user order
2026-04-20 12:12:06 +00:00
riyadhafraa 3df6eb7c54 Task #16: Per-user drag-and-drop reorder for Home apps
- New user_app_orders composite-PK table (user_id, app_id) -> sort_order
- Added GET helper getVisibleAppsForUser that LEFT JOINs user order
  and sorts by COALESCE(user_sort, app.sort_order, name)
- New PUT /api/me/app-order endpoint validates payload, filters to
  visible apps, dedupes, replaces row set in a transaction
- Frontend: wrapped home apps grid in @dnd-kit DndContext + SortableContext
  with PointerSensor (distance:8) and TouchSensor (delay:250 / tolerance:5)
  so taps still navigate while a press-and-drag reorders
- Optimistic local state with rollback on error; useEffect skips sync
  while a save mutation is in flight to avoid stomping on user changes
- Bottom dock intentionally NOT sortable (per user choice)
- DB schema pushed manually via SQL (drizzle-kit push prompted for
  rename ambiguity); regenerated api-zod / api-client-react
- Verified end-to-end: PUT /api/me/app-order returns reordered list
  and subsequent GET /api/apps reflects the new per-user order
2026-04-20 12:12:06 +00:00
Riyadh 101bf7a44a Task #16: Per-user drag-and-drop reorder for Home apps
- New user_app_orders composite-PK table (user_id, app_id) -> sort_order
- Added GET helper getVisibleAppsForUser that LEFT JOINs user order
  and sorts by COALESCE(user_sort, app.sort_order, name)
- New PUT /api/me/app-order endpoint validates payload, filters to
  visible apps, dedupes, replaces row set in a transaction
- Frontend: wrapped home apps grid in @dnd-kit DndContext + SortableContext
  with PointerSensor (distance:8) and TouchSensor (delay:250 / tolerance:5)
  so taps still navigate while a press-and-drag reorders
- Optimistic local state with rollback on error; useEffect skips sync
  while a save mutation is in flight to avoid stomping on user changes
- Bottom dock intentionally NOT sortable (per user choice)
- DB schema pushed manually via SQL (drizzle-kit push prompted for
  rename ambiguity); regenerated api-zod / api-client-react
- Verified end-to-end: PUT /api/me/app-order returns reordered list
  and subsequent GET /api/apps reflects the new per-user order
2026-04-20 12:10:42 +00:00
riyadhafraa d6c8b08086 Task #16: Per-user drag-and-drop reorder for Home apps
- New user_app_orders composite-PK table (user_id, app_id) -> sort_order
- Added GET helper getVisibleAppsForUser that LEFT JOINs user order
  and sorts by COALESCE(user_sort, app.sort_order, name)
- New PUT /api/me/app-order endpoint validates payload, filters to
  visible apps, dedupes, replaces row set in a transaction
- Frontend: wrapped home apps grid in @dnd-kit DndContext + SortableContext
  with PointerSensor (distance:8) and TouchSensor (delay:250 / tolerance:5)
  so taps still navigate while a press-and-drag reorders
- Optimistic local state with rollback on error; useEffect skips sync
  while a save mutation is in flight to avoid stomping on user changes
- Bottom dock intentionally NOT sortable (per user choice)
- DB schema pushed manually via SQL (drizzle-kit push prompted for
  rename ambiguity); regenerated api-zod / api-client-react
- Verified end-to-end: PUT /api/me/app-order returns reordered list
  and subsequent GET /api/apps reflects the new per-user order
2026-04-20 12:10:42 +00:00
Riyadh 8354156099 Add ability to reorder apps on the home screen
Implements drag-and-drop functionality for reordering apps using @dnd-kit, adds a new `userAppOrdersTable` to the database schema to store user-specific app order preferences, and introduces a new API endpoint `/api/me/app-order` for updating these preferences.
2026-04-20 12:09:14 +00:00
riyadhafraa abcc32fb66 Add ability to reorder apps on the home screen
Implements drag-and-drop functionality for reordering apps using @dnd-kit, adds a new `userAppOrdersTable` to the database schema to store user-specific app order preferences, and introduces a new API endpoint `/api/me/app-order` for updating these preferences.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: e782e35b-00f5-4b9b-8931-63051a25df80
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/PrQkd7G
Replit-Helium-Checkpoint-Created: true
2026-04-20 12:09:14 +00:00
Riyadh c46115ea2d Transitioned from Plan to Build mode 2026-04-20 12:04:18 +00:00
riyadhafraa 4eb1a18f35 Transitioned from Plan to Build mode
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 84afb6df-0eea-453b-b40b-fc644319120f
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/PrQkd7G
Replit-Helium-Checkpoint-Created: true
2026-04-20 12:04:18 +00:00
Riyadh b0a9b32b12 Show real stats on the admin Dashboard page
Replaces the "Dashboard widgets coming soon." placeholder in the admin
landing page with a real at-a-glance overview.

Changes:
- artifacts/teaboy-os/src/pages/admin.tsx
  - Added a new DashboardSection component rendered for section==="dashboard".
  - Section shows four glass-panel stat cards: total apps, total services,
    total users, and registration open/closed status (with green/rose tint).
  - Added a recent-activity panel with the latest user (by createdAt) and
    the latest app (by createdAt + localized name), each with a formatted
    date.
  - Wired in useGetAppSettings (already imported) to drive the registration
    status card; reused existing useListApps / useListServices / useListUsers
    queries — no new endpoints.
  - Imported App, Service, UserProfile, AppSettings types from
    @workspace/api-client-react to keep DashboardSection strictly typed.
- artifacts/teaboy-os/src/locales/{en,ar}.json
  - Added admin.dashboard.* keys (totalApps, totalServices, totalUsers,
    registration, open, closed, recentActivity, latestUser, latestApp,
    none) in both English and Arabic. Old `admin.dashboardSoon` key was
    kept to avoid breaking other potential consumers.

Styling uses existing `glass-panel`, lucide icons already in the file, and
logical CSS spacing (gap-3, me-1) so layout stays correct in both LTR and
RTL. Date formatting uses the active i18n language locale.

No backend or schema changes. tsc --noEmit passes for teaboy-os.
2026-04-20 11:54:09 +00:00
riyadhafraa 5b832934fa Show real stats on the admin Dashboard page
Replaces the "Dashboard widgets coming soon." placeholder in the admin
landing page with a real at-a-glance overview.

Changes:
- artifacts/teaboy-os/src/pages/admin.tsx
  - Added a new DashboardSection component rendered for section==="dashboard".
  - Section shows four glass-panel stat cards: total apps, total services,
    total users, and registration open/closed status (with green/rose tint).
  - Added a recent-activity panel with the latest user (by createdAt) and
    the latest app (by createdAt + localized name), each with a formatted
    date.
  - Wired in useGetAppSettings (already imported) to drive the registration
    status card; reused existing useListApps / useListServices / useListUsers
    queries — no new endpoints.
  - Imported App, Service, UserProfile, AppSettings types from
    @workspace/api-client-react to keep DashboardSection strictly typed.
- artifacts/teaboy-os/src/locales/{en,ar}.json
  - Added admin.dashboard.* keys (totalApps, totalServices, totalUsers,
    registration, open, closed, recentActivity, latestUser, latestApp,
    none) in both English and Arabic. Old `admin.dashboardSoon` key was
    kept to avoid breaking other potential consumers.

Styling uses existing `glass-panel`, lucide icons already in the file, and
logical CSS spacing (gap-3, me-1) so layout stays correct in both LTR and
RTL. Date formatting uses the active i18n language locale.

No backend or schema changes. tsc --noEmit passes for teaboy-os.

Replit-Task-Id: 01f9c3eb-0f31-4351-93cc-1f3ffc098761
2026-04-20 11:54:09 +00:00
Riyadh 5c45ddce6e Real image upload for services + placeholder
Task: Replace the admin "paste an image URL" field with a real upload
control backed by App Storage, store the returned objectPath in
services.image_url, serve via /api/storage/objects/*, and add a
placeholder when no image is set so service cards keep consistent height.

Changes:
- artifacts/teaboy-os/src/lib/image-url.ts (new): resolveServiceImageUrl
  helper that maps stored "/objects/<id>" paths to "/api/storage/objects/<id>"
  for rendering, and passes through any legacy http/https URLs unchanged.
- artifacts/teaboy-os/src/pages/admin.tsx: ServiceImageUploader now
  stores the bare objectPath returned by the upload (resp.objectPath)
  in services.imageUrl instead of a pre-prefixed URL, and uses the
  helper to render the preview.
- artifacts/teaboy-os/src/pages/services.tsx: always renders the image
  area at a fixed 16:10 aspect; shows the resolved image when present,
  otherwise renders a centered ImageIcon placeholder so all cards keep
  the same height.

Notes:
- App Storage server routes (request-url, /storage/objects/*,
  /storage/public-objects/*) and the @workspace/object-storage-web
  client were already wired up by an earlier task; this change builds
  on top of them.
- Backward compatible with any existing services.image_url values that
  already contain absolute URLs.
- Typecheck passes (pnpm --filter @workspace/teaboy-os exec tsc --noEmit).
2026-04-20 11:49:48 +00:00
riyadhafraa f246e4caad Real image upload for services + placeholder
Task: Replace the admin "paste an image URL" field with a real upload
control backed by App Storage, store the returned objectPath in
services.image_url, serve via /api/storage/objects/*, and add a
placeholder when no image is set so service cards keep consistent height.

Changes:
- artifacts/teaboy-os/src/lib/image-url.ts (new): resolveServiceImageUrl
  helper that maps stored "/objects/<id>" paths to "/api/storage/objects/<id>"
  for rendering, and passes through any legacy http/https URLs unchanged.
- artifacts/teaboy-os/src/pages/admin.tsx: ServiceImageUploader now
  stores the bare objectPath returned by the upload (resp.objectPath)
  in services.imageUrl instead of a pre-prefixed URL, and uses the
  helper to render the preview.
- artifacts/teaboy-os/src/pages/services.tsx: always renders the image
  area at a fixed 16:10 aspect; shows the resolved image when present,
  otherwise renders a centered ImageIcon placeholder so all cards keep
  the same height.

Notes:
- App Storage server routes (request-url, /storage/objects/*,
  /storage/public-objects/*) and the @workspace/object-storage-web
  client were already wired up by an earlier task; this change builds
  on top of them.
- Backward compatible with any existing services.image_url values that
  already contain absolute URLs.
- Typecheck passes (pnpm --filter @workspace/teaboy-os exec tsc --noEmit).

Replit-Task-Id: 4f4c9f6f-6528-4f11-bb61-f3d85388e7ea
2026-04-20 11:49:48 +00:00
Riyadh 7bf8ec9844 Improve admin interface and ensure consistent font usage across the website
Load IBM Plex Mono font and enhance admin sidebar styling.
2026-04-20 11:49:02 +00:00
riyadhafraa 86d7396536 Improve admin interface and ensure consistent font usage across the website
Load IBM Plex Mono font and enhance admin sidebar styling.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 756193ec-ca75-40ac-b04c-6f06f55c99f8
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/PrQkd7G
Replit-Helium-Checkpoint-Created: true
2026-04-20 11:49:02 +00:00
Riyadh 16091523fe Update dependencies to resolve lockfile inconsistencies
Correct mismatched dependency versions in pnpm-lock.yaml for react and react-dom to align with manifest specifications.
2026-04-20 11:44:43 +00:00
riyadhafraa 2dcc9cb60e Update dependencies to resolve lockfile inconsistencies
Correct mismatched dependency versions in pnpm-lock.yaml for react and react-dom to align with manifest specifications.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 8c4b9081-af83-4599-910e-8c654cd1609f
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/g3CniBE
Replit-Helium-Checkpoint-Created: true
2026-04-20 11:44:43 +00:00
Riyadh 77f590ca62 Show day name with Hijri and Gregorian dates in home status bar
Task #6: Display today's day name plus Hijri and Gregorian dates in
the home page status bar so users see both calendars at a glance.

Changes (artifacts/teaboy-os/src/pages/home.tsx):
- Compute three values from the existing `time` state via
  Intl.DateTimeFormat:
    * dayName        -> weekday: "long" (ar-SA / en-US)
    * hijriDate      -> ar-SA-u-ca-islamic-umalqura
                        / en-US-u-ca-islamic-umalqura
    * gregorianDate  -> ar-SA-u-ca-gregory / en-US
- Replaced the single time line in the topbar with a 3-row stack:
    Row 1: time (existing bold mono)
    Row 2: day · hijri (small muted)
    Row 3: gregorian   (small muted)
- Added `min-w-0`, `truncate`, and `gap-2` on the topbar flex so
  the date column shrinks gracefully on narrow widths and never
  pushes the username/controls off-screen. Username max-width
  reduced from max-w-32 to max-w-24 to give the centre slot room.

Auto-refresh:
- The existing 1-second `setInterval` already drives the `time`
  state, so all three values naturally roll over at midnight.

Localization:
- ar mode -> ar-SA = Arabic-Indic numerals on all three values.
- en mode -> en-US = Latin numerals.
- No new i18n keys required (separator is a neutral middle dot).

Out of scope (untouched): time format, other status-bar controls,
calendar view, calendar toggle.

Verification: tsc --noEmit passes for teaboy-os. Layout reviewed for
both LTR and RTL: each row truncates within the centre slot and the
flex gap prevents collisions with neighbouring elements.

Re-review fix: previous attempt used a single whitespace-nowrap row
which could overflow on narrow widths; switched to stacked rows with
truncation per the code-review feedback.
2026-04-20 11:44:10 +00:00
riyadhafraa 4b29e593b0 Show day name with Hijri and Gregorian dates in home status bar
Task #6: Display today's day name plus Hijri and Gregorian dates in
the home page status bar so users see both calendars at a glance.

Changes (artifacts/teaboy-os/src/pages/home.tsx):
- Compute three values from the existing `time` state via
  Intl.DateTimeFormat:
    * dayName        -> weekday: "long" (ar-SA / en-US)
    * hijriDate      -> ar-SA-u-ca-islamic-umalqura
                        / en-US-u-ca-islamic-umalqura
    * gregorianDate  -> ar-SA-u-ca-gregory / en-US
- Replaced the single time line in the topbar with a 3-row stack:
    Row 1: time (existing bold mono)
    Row 2: day · hijri (small muted)
    Row 3: gregorian   (small muted)
- Added `min-w-0`, `truncate`, and `gap-2` on the topbar flex so
  the date column shrinks gracefully on narrow widths and never
  pushes the username/controls off-screen. Username max-width
  reduced from max-w-32 to max-w-24 to give the centre slot room.

Auto-refresh:
- The existing 1-second `setInterval` already drives the `time`
  state, so all three values naturally roll over at midnight.

Localization:
- ar mode -> ar-SA = Arabic-Indic numerals on all three values.
- en mode -> en-US = Latin numerals.
- No new i18n keys required (separator is a neutral middle dot).

Out of scope (untouched): time format, other status-bar controls,
calendar view, calendar toggle.

Verification: tsc --noEmit passes for teaboy-os. Layout reviewed for
both LTR and RTL: each row truncates within the centre slot and the
flex gap prevents collisions with neighbouring elements.

Re-review fix: previous attempt used a single whitespace-nowrap row
which could overflow on narrow widths; switched to stacked rows with
truncation per the code-review feedback.

Replit-Task-Id: 7c9442ee-4a8d-403a-8bea-1ce8c6d859e9
2026-04-20 11:44:10 +00:00