Introduced a new hook `useTopbarClockVisibility` in `artifacts/teaboy-os/src/components/clock.tsx` to manage the visibility of the top bar clock, separate from the home clock widget. Updated `artifacts/teaboy-os/src/pages/home.tsx` to utilize this new hook, allowing the eye icon to toggle the top bar clock's visibility.
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 08cff793-79ae-45ad-9958-d029baf1737d
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/PwtbShH
Replit-Helium-Checkpoint-Created: true
Added a dedicated Eye/EyeOff icon button next to the existing
ClockStylePicker in the home top bar. Clicking it instantly hides or
shows the home wall-clock widget without opening any popover.
- Wired to the existing useHomeClockVisibility hook so it stays in
sync with the toggle inside the clock-style popover (same storage
key + custom event).
- Reuses existing locale keys home.clockStyle.hideWidget /
home.clockStyle.showWidget for aria-label and title (flips with
state).
- aria-pressed reflects hidden state for accessibility.
- No new locale keys, no changes to default position behavior, and
the popover toggle is left intact as requested.
Files:
- artifacts/teaboy-os/src/pages/home.tsx (added Eye/EyeOff imports
and the new icon button between ClockStylePicker and the language
toggle).
Added a dedicated Eye/EyeOff icon button next to the existing
ClockStylePicker in the home top bar. Clicking it instantly hides or
shows the home wall-clock widget without opening any popover.
- Wired to the existing useHomeClockVisibility hook so it stays in
sync with the toggle inside the clock-style popover (same storage
key + custom event).
- Reuses existing locale keys home.clockStyle.hideWidget /
home.clockStyle.showWidget for aria-label and title (flips with
state).
- aria-pressed reflects hidden state for accessibility.
- No new locale keys, no changes to default position behavior, and
the popover toggle is left intact as requested.
Files:
- artifacts/teaboy-os/src/pages/home.tsx (added Eye/EyeOff imports
and the new icon button between ClockStylePicker and the language
toggle).
Added a dedicated Eye/EyeOff icon button next to the existing
ClockStylePicker in the home top bar. Clicking it instantly hides or
shows the home wall-clock widget without opening any popover.
- Wired to the existing useHomeClockVisibility hook so it stays in
sync with the toggle inside the clock-style popover (same storage
key + custom event).
- Reuses existing locale keys home.clockStyle.hideWidget /
home.clockStyle.showWidget for aria-label and title (flips with
state).
- aria-pressed reflects hidden state for accessibility.
- No new locale keys, no changes to default position behavior, and
the popover toggle is left intact as requested.
Files:
- artifacts/teaboy-os/src/pages/home.tsx (added Eye/EyeOff imports
and the new icon button between ClockStylePicker and the language
toggle).
Added a dedicated Eye/EyeOff icon button next to the existing
ClockStylePicker in the home top bar. Clicking it instantly hides or
shows the home wall-clock widget without opening any popover.
- Wired to the existing useHomeClockVisibility hook so it stays in
sync with the toggle inside the clock-style popover (same storage
key + custom event).
- Reuses existing locale keys home.clockStyle.hideWidget /
home.clockStyle.showWidget for aria-label and title (flips with
state).
- aria-pressed reflects hidden state for accessibility.
- No new locale keys, no changes to default position behavior, and
the popover toggle is left intact as requested.
Files:
- artifacts/teaboy-os/src/pages/home.tsx (added Eye/EyeOff imports
and the new icon button between ClockStylePicker and the language
toggle).
Update home component logic to correctly pin the clock to the far-left position in RTL layouts when it's unset or dragged to the end of the app list, ensuring it occupies the first two columns.
Update home component logic to correctly pin the clock to the far-left position in RTL layouts when it's unset or dragged to the end of the app list, ensuring it occupies the first two columns.
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: a6f7b52f-d48d-41b0-9435-36a5f4524394
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/PwtbShH
Replit-Helium-Checkpoint-Created: true
Remove the 'X' close button from the clock widget and refactor its props, simplifying the component by removing unused `onHide` and `hideLabel` functionalities.
Add global CSS rules to `index.css` to hide scrollbars using `scrollbar-width: none`, `-ms-overflow-style: none`, and `::-webkit-scrollbar` properties, ensuring scrolling remains functional via mouse wheel or touch.
Per user request, the home page no longer shows the time-of-day greeting
("مساء الخير، {name}") nor the day-name + Gregorian date subtitle. The
apps grid (and the admin stats row when applicable) now sits directly
under the top bar.
Changes (artifacts/teaboy-os/src/pages/home.tsx):
- Removed the entire greeting block (the wrapper div, the <h1> greeting
and the date <p>) from the Main Content section.
- Removed the now-unused `dayName`, `gregorianDate` and `greeting`
locals plus the `formatWeekday` and `greetingKey` imports.
- Kept `displayName` (still used in the avatar header) and the
`home.greeting.*` translation keys (left in place; cheap to keep and
avoids touching unrelated locale files).
Mid-task fix:
- First pass also dropped `displayName` which broke the avatar
(`displayName is not defined`). Restored it; `displayName` is needed
by the user-card initials and name labels.
Validation:
- `pnpm --filter @workspace/api-server test` — 18/18 pass
- `pnpm --filter @workspace/teaboy-os test:e2e` — 3/3 pass
Notes:
- Pre-existing TypeScript errors in admin.tsx / clock-style-picker.tsx /
clock.tsx are unrelated to this task (codegen drift from earlier
tasks).
Per user request, the home page no longer shows the time-of-day greeting
("مساء الخير، {name}") nor the day-name + Gregorian date subtitle. The
apps grid (and the admin stats row when applicable) now sits directly
under the top bar.
Changes (artifacts/teaboy-os/src/pages/home.tsx):
- Removed the entire greeting block (the wrapper div, the <h1> greeting
and the date <p>) from the Main Content section.
- Removed the now-unused `dayName`, `gregorianDate` and `greeting`
locals plus the `formatWeekday` and `greetingKey` imports.
- Kept `displayName` (still used in the avatar header) and the
`home.greeting.*` translation keys (left in place; cheap to keep and
avoids touching unrelated locale files).
Mid-task fix:
- First pass also dropped `displayName` which broke the avatar
(`displayName is not defined`). Restored it; `displayName` is needed
by the user-card initials and name labels.
Validation:
- `pnpm --filter @workspace/api-server test` — 18/18 pass
- `pnpm --filter @workspace/teaboy-os test:e2e` — 3/3 pass
Notes:
- Pre-existing TypeScript errors in admin.tsx / clock-style-picker.tsx /
clock.tsx are unrelated to this task (codegen drift from earlier
tasks).
Per user request, the home page no longer shows the time-of-day greeting
("مساء الخير، {name}") nor the day-name + Gregorian date subtitle. The
apps grid (and the admin stats row when applicable) now sits directly
under the top bar.
Changes (artifacts/teaboy-os/src/pages/home.tsx):
- Removed the entire greeting block (the wrapper div, the <h1> greeting
and the date <p>) from the Main Content section.
- Removed the now-unused `dayName`, `gregorianDate` and `greeting`
locals plus the `formatWeekday` and `greetingKey` imports.
- Kept `displayName` (still used in the avatar header) and the
`home.greeting.*` translation keys (left in place; cheap to keep and
avoids touching unrelated locale files).
Mid-task fix:
- First pass also dropped `displayName` which broke the avatar
(`displayName is not defined`). Restored it; `displayName` is needed
by the user-card initials and name labels.
Validation:
- `pnpm --filter @workspace/api-server test` — 18/18 pass
- `pnpm --filter @workspace/teaboy-os test:e2e` — 3/3 pass
Notes:
- Pre-existing TypeScript errors in admin.tsx / clock-style-picker.tsx /
clock.tsx are unrelated to this task (codegen drift from earlier
tasks).
Per user request, the home page no longer shows the time-of-day greeting
("مساء الخير، {name}") nor the day-name + Gregorian date subtitle. The
apps grid (and the admin stats row when applicable) now sits directly
under the top bar.
Changes (artifacts/teaboy-os/src/pages/home.tsx):
- Removed the entire greeting block (the wrapper div, the <h1> greeting
and the date <p>) from the Main Content section.
- Removed the now-unused `dayName`, `gregorianDate` and `greeting`
locals plus the `formatWeekday` and `greetingKey` imports.
- Kept `displayName` (still used in the avatar header) and the
`home.greeting.*` translation keys (left in place; cheap to keep and
avoids touching unrelated locale files).
Mid-task fix:
- First pass also dropped `displayName` which broke the avatar
(`displayName is not defined`). Restored it; `displayName` is needed
by the user-card initials and name labels.
Validation:
- `pnpm --filter @workspace/api-server test` — 18/18 pass
- `pnpm --filter @workspace/teaboy-os test:e2e` — 3/3 pass
Notes:
- Pre-existing TypeScript errors in admin.tsx / clock-style-picker.tsx /
clock.tsx are unrelated to this task (codegen drift from earlier
tasks).
Original task #58 was to add a dismissible hint when the home clock is
hidden. The hint was implemented and verified end-to-end (EN + AR/RTL),
but the user then asked to remove it. This commit removes the hint and
also removes the "تطبيقاتي · N" / "My Apps · N" header above the apps
grid per the user's request to show the apps directly.
Changes:
- artifacts/teaboy-os/src/pages/home.tsx
- Removed the hidden-clock hint UI block, its session-storage state
(clockHintDismissed) and the related useEffect/dismiss helper.
- Removed the unused Clock-icon lucide import.
- Removed the "My Apps" heading row (h3 + count) above the apps grid.
- artifacts/teaboy-os/src/locales/en.json, ar.json
- Removed the new keys: home.clockStyle.hiddenHint,
hiddenHintAction, dismissHint.
Rebase notes:
- Rebased onto main (a5a7a87). Two conflicts:
* artifacts/teaboy-os/public/opengraph.jpg — binary asset unrelated
to this task; took main's version (--ours during rebase).
* artifacts/teaboy-os/src/pages/home.tsx — main re-styled the apps
grid header (flex/gap layout with inline " · N" count) and added
a useGridCols() hook. My commit removes that header entirely per
user request, so kept the user-requested removal while preserving
main's useGridCols() addition. No semantic divergence — just the
deletion still applies cleanly to the new header markup.
Notes:
- Clock can still be hidden via the X on the clock tile and shown
again via the clock-style popover in the top bar (existing behavior).
- Translation key home.myApps is still defined but no longer used on
the home page; left in place to avoid touching other consumers.
- Pre-existing TypeScript errors on AuthUser.clockStyle/clockHour12
in chat.tsx/home.tsx are unrelated to this task.
Original task #58 was to add a dismissible hint when the home clock is
hidden. The hint was implemented and verified end-to-end (EN + AR/RTL),
but the user then asked to remove it. This commit removes the hint and
also removes the "تطبيقاتي · N" / "My Apps · N" header above the apps
grid per the user's request to show the apps directly.
Changes:
- artifacts/teaboy-os/src/pages/home.tsx
- Removed the hidden-clock hint UI block, its session-storage state
(clockHintDismissed) and the related useEffect/dismiss helper.
- Removed the unused Clock-icon lucide import.
- Removed the "My Apps" heading row (h3 + count) above the apps grid.
- artifacts/teaboy-os/src/locales/en.json, ar.json
- Removed the new keys: home.clockStyle.hiddenHint,
hiddenHintAction, dismissHint.
Rebase notes:
- Rebased onto main (a05249f). Two conflicts:
* artifacts/teaboy-os/public/opengraph.jpg — binary asset unrelated
to this task; took main's version (--ours during rebase).
* artifacts/teaboy-os/src/pages/home.tsx — main re-styled the apps
grid header (flex/gap layout with inline " · N" count) and added
a useGridCols() hook. My commit removes that header entirely per
user request, so kept the user-requested removal while preserving
main's useGridCols() addition. No semantic divergence — just the
deletion still applies cleanly to the new header markup.
Notes:
- Clock can still be hidden via the X on the clock tile and shown
again via the clock-style popover in the top bar (existing behavior).
- Translation key home.myApps is still defined but no longer used on
the home page; left in place to avoid touching other consumers.
- Pre-existing TypeScript errors on AuthUser.clockStyle/clockHour12
in chat.tsx/home.tsx are unrelated to this task.
Replit-Task-Id: 14544719-933c-49f8-84a0-6577d06fbc14
Original ask (Arabic):
- Why does a small "4" appear on the left of the home page?
- Make the clock movable to all positions, default to the visual-left,
remove its frame, and keep it parallel/aligned with the app icons.
Changes:
- artifacts/teaboy-os/src/pages/home.tsx
- My Apps header: replaced `justify-between` with `gap-2`, prefixed
the count with "·" so it now reads "تطبيقاتي · 5" / "MY APPS · 5"
inline with the title. The standalone count badge that floated to
the opposite edge in RTL is gone.
- SortableClockTile inner box: removed the `bg-white/85
dark:bg-white/10 backdrop-blur-md` and the `icon-tile` rounded card
classes. The analog clock face now renders directly on the
wallpaper. Outer width/height (78px compact, 168px large) and the
hover/active scale animation are preserved so grid alignment with
the app icons is unchanged.
- Default clock position is now language-aware: when no per-user
saved position exists, the clock defaults to the visually-leftmost
cell of the first row — last DOM index in RTL (Arabic),
first DOM index in LTR (English).
- artifacts/teaboy-os/src/components/clock.tsx
- `readHomeClockPosition` now returns -1 as the "unset" sentinel
instead of 0, so home.tsx can apply a language-aware default
without overwriting saved positions.
Verification:
- Manual e2e: confirmed header has the inline count, clock has no
frame, RTL default position is on the visual-left, drag-and-drop
still persists across reload, long-press still toggles compact ↔
large. All passed.
Out of scope: no server-side persistence; no changes to the topbar
clock, the dock, or the clock-style picker.
Original ask (Arabic):
- Why does a small "4" appear on the left of the home page?
- Make the clock movable to all positions, default to the visual-left,
remove its frame, and keep it parallel/aligned with the app icons.
Changes:
- artifacts/teaboy-os/src/pages/home.tsx
- My Apps header: replaced `justify-between` with `gap-2`, prefixed
the count with "·" so it now reads "تطبيقاتي · 5" / "MY APPS · 5"
inline with the title. The standalone count badge that floated to
the opposite edge in RTL is gone.
- SortableClockTile inner box: removed the `bg-white/85
dark:bg-white/10 backdrop-blur-md` and the `icon-tile` rounded card
classes. The analog clock face now renders directly on the
wallpaper. Outer width/height (78px compact, 168px large) and the
hover/active scale animation are preserved so grid alignment with
the app icons is unchanged.
- Default clock position is now language-aware: when no per-user
saved position exists, the clock defaults to the visually-leftmost
cell of the first row — last DOM index in RTL (Arabic),
first DOM index in LTR (English).
- artifacts/teaboy-os/src/components/clock.tsx
- `readHomeClockPosition` now returns -1 as the "unset" sentinel
instead of 0, so home.tsx can apply a language-aware default
without overwriting saved positions.
Verification:
- Manual e2e: confirmed header has the inline count, clock has no
frame, RTL default position is on the visual-left, drag-and-drop
still persists across reload, long-press still toggles compact ↔
large. All passed.
Out of scope: no server-side persistence; no changes to the topbar
clock, the dock, or the clock-style picker.
Original ask (Arabic):
- Why does a small "4" appear on the left of the home page?
- Make the clock movable to all positions, default to the visual-left,
remove its frame, and keep it parallel/aligned with the app icons.
Changes:
- artifacts/teaboy-os/src/pages/home.tsx
- My Apps header: replaced `justify-between` with `gap-2`, prefixed
the count with "·" so it now reads "تطبيقاتي · 5" / "MY APPS · 5"
inline with the title. The standalone count badge that floated to
the opposite edge in RTL is gone.
- SortableClockTile inner box: removed the `bg-white/85
dark:bg-white/10 backdrop-blur-md` and the `icon-tile` rounded card
classes. The analog clock face now renders directly on the
wallpaper. Outer width/height (78px compact, 168px large) and the
hover/active scale animation are preserved so grid alignment with
the app icons is unchanged.
- Default clock position is now language-aware: when no per-user
saved position exists, the clock defaults to the visually-leftmost
cell of the first row — last DOM index in RTL (Arabic),
first DOM index in LTR (English).
- artifacts/teaboy-os/src/components/clock.tsx
- `readHomeClockPosition` now returns -1 as the "unset" sentinel
instead of 0, so home.tsx can apply a language-aware default
without overwriting saved positions.
Verification:
- Manual e2e: confirmed header has the inline count, clock has no
frame, RTL default position is on the visual-left, drag-and-drop
still persists across reload, long-press still toggles compact ↔
large. All passed.
Out of scope: no server-side persistence; no changes to the topbar
clock, the dock, or the clock-style picker.
Original ask (Arabic):
- Why does a small "4" appear on the left of the home page?
- Make the clock movable to all positions, default to the visual-left,
remove its frame, and keep it parallel/aligned with the app icons.
Changes:
- artifacts/teaboy-os/src/pages/home.tsx
- My Apps header: replaced `justify-between` with `gap-2`, prefixed
the count with "·" so it now reads "تطبيقاتي · 5" / "MY APPS · 5"
inline with the title. The standalone count badge that floated to
the opposite edge in RTL is gone.
- SortableClockTile inner box: removed the `bg-white/85
dark:bg-white/10 backdrop-blur-md` and the `icon-tile` rounded card
classes. The analog clock face now renders directly on the
wallpaper. Outer width/height (78px compact, 168px large) and the
hover/active scale animation are preserved so grid alignment with
the app icons is unchanged.
- Default clock position is now language-aware: when no per-user
saved position exists, the clock defaults to the visually-leftmost
cell of the first row — last DOM index in RTL (Arabic),
first DOM index in LTR (English).
- artifacts/teaboy-os/src/components/clock.tsx
- `readHomeClockPosition` now returns -1 as the "unset" sentinel
instead of 0, so home.tsx can apply a language-aware default
without overwriting saved positions.
Verification:
- Manual e2e: confirmed header has the inline count, clock has no
frame, RTL default position is on the visual-left, drag-and-drop
still persists across reload, long-press still toggles compact ↔
large. All passed.
Out of scope: no server-side persistence; no changes to the topbar
clock, the dock, or the clock-style picker.
Original ask (Arabic):
- Why does a small "4" appear on the left of the home page?
- Make the clock movable to all positions, default to the visual-left,
remove its frame, and keep it parallel/aligned with the app icons.
Changes:
- artifacts/teaboy-os/src/pages/home.tsx
- My Apps header: replaced `justify-between` with `gap-2`, prefixed
the count with "·" so it now reads "تطبيقاتي · 5" / "MY APPS · 5"
inline with the title. The standalone count badge that floated to
the opposite edge in RTL is gone.
- SortableClockTile inner box: removed the `bg-white/85
dark:bg-white/10 backdrop-blur-md` and the `icon-tile` rounded card
classes. The analog clock face now renders directly on the
wallpaper. Outer width/height (78px compact, 168px large) and the
hover/active scale animation are preserved so grid alignment with
the app icons is unchanged.
- Default clock position is now language-aware: when no per-user
saved position exists, the clock defaults to the visually-leftmost
cell of the first row — last DOM index in RTL (Arabic),
first DOM index in LTR (English).
- artifacts/teaboy-os/src/components/clock.tsx
- `readHomeClockPosition` now returns -1 as the "unset" sentinel
instead of 0, so home.tsx can apply a language-aware default
without overwriting saved positions.
Verification:
- Manual e2e: confirmed header has the inline count, clock has no
frame, RTL default position is on the visual-left, drag-and-drop
still persists across reload, long-press still toggles compact ↔
large. All passed.
Out of scope: no server-side persistence; no changes to the topbar
clock, the dock, or the clock-style picker.
Original ask (Arabic):
- Why does a small "4" appear on the left of the home page?
- Make the clock movable to all positions, default to the visual-left,
remove its frame, and keep it parallel/aligned with the app icons.
Changes:
- artifacts/teaboy-os/src/pages/home.tsx
- My Apps header: replaced `justify-between` with `gap-2`, prefixed
the count with "·" so it now reads "تطبيقاتي · 5" / "MY APPS · 5"
inline with the title. The standalone count badge that floated to
the opposite edge in RTL is gone.
- SortableClockTile inner box: removed the `bg-white/85
dark:bg-white/10 backdrop-blur-md` and the `icon-tile` rounded card
classes. The analog clock face now renders directly on the
wallpaper. Outer width/height (78px compact, 168px large) and the
hover/active scale animation are preserved so grid alignment with
the app icons is unchanged.
- Default clock position is now language-aware: when no per-user
saved position exists, the clock defaults to the visually-leftmost
cell of the first row — last DOM index in RTL (Arabic),
first DOM index in LTR (English).
- artifacts/teaboy-os/src/components/clock.tsx
- `readHomeClockPosition` now returns -1 as the "unset" sentinel
instead of 0, so home.tsx can apply a language-aware default
without overwriting saved positions.
Verification:
- Manual e2e: confirmed header has the inline count, clock has no
frame, RTL default position is on the visual-left, drag-and-drop
still persists across reload, long-press still toggles compact ↔
large. All passed.
Out of scope: no server-side persistence; no changes to the topbar
clock, the dock, or the clock-style picker.
Task #57: add an automated check that exercises the same flow that was
previously only manually verified — drag the home-page clock tile to a new
grid slot, long-press to flip it from compact to large, reload, and assert
both the position and size survive.
Implementation
- New Playwright spec at
artifacts/teaboy-os/tests/home-clock-persistence.spec.mjs, mirroring the
conventions of the existing leave-group-successor.spec.mjs (DB-seeded
user, UI login, cleanup in afterAll).
- Drives a real pointer drag that satisfies dnd-kit's 8px activation
threshold, then a separate long-press (>500ms, no movement) to trigger
the size toggle in home.tsx without aborting the timer.
- Asserts both per-user localStorage keys are written
(teaboy:home-clock-position:<id> and teaboy:home-clock-size:<id>) and
that, after page.reload(), the clock tile still has col-span-2 / row-span-2
classes and lives at the persisted index in the grid (not just in
storage).
Verification
- Ran the new spec in isolation: 1 passed.
- Ran the full validation workflow (api-server tests + teaboy-os
test:e2e): 18 + 3 passed.
No production code changes.
Task #57: add an automated check that exercises the same flow that was
previously only manually verified — drag the home-page clock tile to a new
grid slot, long-press to flip it from compact to large, reload, and assert
both the position and size survive.
Implementation
- New Playwright spec at
artifacts/teaboy-os/tests/home-clock-persistence.spec.mjs, mirroring the
conventions of the existing leave-group-successor.spec.mjs (DB-seeded
user, UI login, cleanup in afterAll).
- Drives a real pointer drag that satisfies dnd-kit's 8px activation
threshold, then a separate long-press (>500ms, no movement) to trigger
the size toggle in home.tsx without aborting the timer.
- Asserts both per-user localStorage keys are written
(teaboy:home-clock-position:<id> and teaboy:home-clock-size:<id>) and
that, after page.reload(), the clock tile still has col-span-2 / row-span-2
classes and lives at the persisted index in the grid (not just in
storage).
Verification
- Ran the new spec in isolation: 1 passed.
- Ran the full validation workflow (api-server tests + teaboy-os
test:e2e): 18 + 3 passed.
No production code changes.
Replit-Task-Id: bd8d8372-358c-4676-b842-956dc0813cb8
Original task: #56 — Let users hide or show the home clock with one tap.
Changes:
- artifacts/teaboy-os/src/pages/home.tsx: Added a small dismiss "×"
button overlay on the SortableClockTile. The button stops pointer
propagation so it does not trigger drag or the existing long-press
size toggle. It calls setHomeClockVisible(false) (now destructured
from useHomeClockVisibility) to hide the tile in one tap. The button
uses absolute positioning with `end-1` so it works in both LTR and
RTL. It is always visible at large size and revealed on hover/focus
at compact size to keep the tile clean.
- artifacts/teaboy-os/src/locales/{en,ar}.json: Added
`home.clockStyle.hideWidget` ("Hide clock" / "إخفاء الساعة") used
as the button's aria-label and tooltip.
Re-showing the clock is handled by the existing toggle in the clock
style picker popover (already bilingual), so users can bring the
clock back later. Hiding/showing keeps the persisted grid position.
Notes / deviations:
- Did not add a context-menu since long-press is already used for the
size toggle on the same tile and would conflict.
- Pre-existing TypeScript errors in unrelated files (admin.tsx,
clock-style-picker.tsx codegen drift) are not addressed here.
Original task: #56 — Let users hide or show the home clock with one tap.
Changes:
- artifacts/teaboy-os/src/pages/home.tsx: Added a small dismiss "×"
button overlay on the SortableClockTile. The button stops pointer
propagation so it does not trigger drag or the existing long-press
size toggle. It calls setHomeClockVisible(false) (now destructured
from useHomeClockVisibility) to hide the tile in one tap. The button
uses absolute positioning with `end-1` so it works in both LTR and
RTL. It is always visible at large size and revealed on hover/focus
at compact size to keep the tile clean.
- artifacts/teaboy-os/src/locales/{en,ar}.json: Added
`home.clockStyle.hideWidget` ("Hide clock" / "إخفاء الساعة") used
as the button's aria-label and tooltip.
Re-showing the clock is handled by the existing toggle in the clock
style picker popover (already bilingual), so users can bring the
clock back later. Hiding/showing keeps the persisted grid position.
Notes / deviations:
- Did not add a context-menu since long-press is already used for the
size toggle on the same tile and would conflict.
- Pre-existing TypeScript errors in unrelated files (admin.tsx,
clock-style-picker.tsx codegen drift) are not addressed here.
Replit-Task-Id: 87bb057d-dc81-4916-8bb1-b24e34ff4794
- Refactor AnalogClockWidget: Latin 1-12 digits (was Roman), `size`
(px) prop with scale-based interior, optional `showLabels`.
- Add useHomeClockSize (compact|large) and useHomeClockPosition hooks
in clock.tsx — both persist to localStorage and broadcast a custom
event so consumers stay in sync within the tab.
- home.tsx: introduce SortableClockTile that participates in the same
dnd-kit grid as app icons via id `__clock`. App ids now prefixed
`app-` so they don't collide. Long-press (500ms) toggles
compact↔large; large = col-span-2 row-span-2. Custom pointer
handlers chain with dnd-kit's listener so drag still works.
- handleDragEnd computes new app order excluding the clock and only
fires updateOrder when app order actually changed.
- Remove the standalone AnalogClockWidget block above the apps grid;
clock now lives inside the grid.
- When homeClockVisible is false, the clock is also excluded from
sortable items (no dnd-kit warnings).
- e2e test passed: in-grid placement, Latin digits, long-press
resize, drag-reorder, position persists across reload.
- Refactor AnalogClockWidget: Latin 1-12 digits (was Roman), `size`
(px) prop with scale-based interior, optional `showLabels`.
- Add useHomeClockSize (compact|large) and useHomeClockPosition hooks
in clock.tsx — both persist to localStorage and broadcast a custom
event so consumers stay in sync within the tab.
- home.tsx: introduce SortableClockTile that participates in the same
dnd-kit grid as app icons via id `__clock`. App ids now prefixed
`app-` so they don't collide. Long-press (500ms) toggles
compact↔large; large = col-span-2 row-span-2. Custom pointer
handlers chain with dnd-kit's listener so drag still works.
- handleDragEnd computes new app order excluding the clock and only
fires updateOrder when app order actually changed.
- Remove the standalone AnalogClockWidget block above the apps grid;
clock now lives inside the grid.
- When homeClockVisible is false, the clock is also excluded from
sortable items (no dnd-kit warnings).
- e2e test passed: in-grid placement, Latin digits, long-press
resize, drag-reorder, position persists across reload.
- Refactor AnalogClockWidget: Latin 1-12 digits (was Roman), `size`
(px) prop with scale-based interior, optional `showLabels`.
- Add useHomeClockSize (compact|large) and useHomeClockPosition hooks
in clock.tsx — both persist to localStorage and broadcast a custom
event so consumers stay in sync within the tab.
- home.tsx: introduce SortableClockTile that participates in the same
dnd-kit grid as app icons via id `__clock`. App ids now prefixed
`app-` so they don't collide. Long-press (500ms) toggles
compact↔large; large = col-span-2 row-span-2. Custom pointer
handlers chain with dnd-kit's listener so drag still works.
- handleDragEnd computes new app order excluding the clock and only
fires updateOrder when app order actually changed.
- Remove the standalone AnalogClockWidget block above the apps grid;
clock now lives inside the grid.
- When homeClockVisible is false, the clock is also excluded from
sortable items (no dnd-kit warnings).
- e2e test passed: in-grid placement, Latin digits, long-press
resize, drag-reorder, position persists across reload.
- Refactor AnalogClockWidget: Latin 1-12 digits (was Roman), `size`
(px) prop with scale-based interior, optional `showLabels`.
- Add useHomeClockSize (compact|large) and useHomeClockPosition hooks
in clock.tsx — both persist to localStorage and broadcast a custom
event so consumers stay in sync within the tab.
- home.tsx: introduce SortableClockTile that participates in the same
dnd-kit grid as app icons via id `__clock`. App ids now prefixed
`app-` so they don't collide. Long-press (500ms) toggles
compact↔large; large = col-span-2 row-span-2. Custom pointer
handlers chain with dnd-kit's listener so drag still works.
- handleDragEnd computes new app order excluding the clock and only
fires updateOrder when app order actually changed.
- Remove the standalone AnalogClockWidget block above the apps grid;
clock now lives inside the grid.
- When homeClockVisible is false, the clock is also excluded from
sortable items (no dnd-kit warnings).
- e2e test passed: in-grid placement, Latin digits, long-press
resize, drag-reorder, position persists across reload.
- Refactor AnalogClockWidget: Latin 1-12 digits (was Roman), `size`
(px) prop with scale-based interior, optional `showLabels`.
- Add useHomeClockSize (compact|large) and useHomeClockPosition hooks
in clock.tsx — both persist to localStorage and broadcast a custom
event so consumers stay in sync within the tab.
- home.tsx: introduce SortableClockTile that participates in the same
dnd-kit grid as app icons via id `__clock`. App ids now prefixed
`app-` so they don't collide. Long-press (500ms) toggles
compact↔large; large = col-span-2 row-span-2. Custom pointer
handlers chain with dnd-kit's listener so drag still works.
- handleDragEnd computes new app order excluding the clock and only
fires updateOrder when app order actually changed.
- Remove the standalone AnalogClockWidget block above the apps grid;
clock now lives inside the grid.
- When homeClockVisible is false, the clock is also excluded from
sortable items (no dnd-kit warnings).
- e2e test passed: in-grid placement, Latin digits, long-press
resize, drag-reorder, position persists across reload.
- Refactor AnalogClockWidget: Latin 1-12 digits (was Roman), `size`
(px) prop with scale-based interior, optional `showLabels`.
- Add useHomeClockSize (compact|large) and useHomeClockPosition hooks
in clock.tsx — both persist to localStorage and broadcast a custom
event so consumers stay in sync within the tab.
- home.tsx: introduce SortableClockTile that participates in the same
dnd-kit grid as app icons via id `__clock`. App ids now prefixed
`app-` so they don't collide. Long-press (500ms) toggles
compact↔large; large = col-span-2 row-span-2. Custom pointer
handlers chain with dnd-kit's listener so drag still works.
- handleDragEnd computes new app order excluding the clock and only
fires updateOrder when app order actually changed.
- Remove the standalone AnalogClockWidget block above the apps grid;
clock now lives inside the grid.
- When homeClockVisible is false, the clock is also excluded from
sortable items (no dnd-kit warnings).
- e2e test passed: in-grid placement, Latin digits, long-press
resize, drag-reorder, position persists across reload.
Background:
Task #53 fixed the login/register session persistence race by explicitly
awaiting `req.session.save` before responding. Other session-mutating
endpoints (notably `/auth/logout`) still relied on express-session's
default end-hook, which can flush the response before the store write
finishes — producing intermittent "still logged in" / "logged out"
glitches on the immediate next request.
Changes:
- New shared helper `artifacts/api-server/src/lib/session.ts` exporting
`saveSession(req)` and `destroySession(req)` — promise wrappers around
`req.session.save` / `req.session.destroy` so handlers can `await`
store persistence before flushing the HTTP response. Documented the
rationale in the file so future session-mutating routes use the same
safe pattern.
- `artifacts/api-server/src/routes/auth.ts`:
- `/auth/register` and `/auth/login` now use `await saveSession(req)`
in place of the inline ad-hoc Promise wrapper.
- `/auth/logout` is now async and `await`s `destroySession(req)`
before responding, closing the same race for the destroy path.
- Audited remaining routes: only `auth.ts` mutates `req.session`; all
other handlers only read `req.session.userId`, so no further changes
are needed.
Notes / deviations:
- Pre-existing TypeScript errors in unrelated files (conversations,
notes, users, api-zod exports) were left untouched — out of scope.
- New test file `artifacts/api-server/tests/auth-session-persistence.test.mjs`
covers the acceptance criterion: login / register / logout each
followed by an immediate `/auth/me` probe to assert the session was
persisted (or destroyed) before the response was flushed. Modeled on
the existing leave-test pattern. Full suite: 18/18 passing.
Background:
Task #53 fixed the login/register session persistence race by explicitly
awaiting `req.session.save` before responding. Other session-mutating
endpoints (notably `/auth/logout`) still relied on express-session's
default end-hook, which can flush the response before the store write
finishes — producing intermittent "still logged in" / "logged out"
glitches on the immediate next request.
Changes:
- New shared helper `artifacts/api-server/src/lib/session.ts` exporting
`saveSession(req)` and `destroySession(req)` — promise wrappers around
`req.session.save` / `req.session.destroy` so handlers can `await`
store persistence before flushing the HTTP response. Documented the
rationale in the file so future session-mutating routes use the same
safe pattern.
- `artifacts/api-server/src/routes/auth.ts`:
- `/auth/register` and `/auth/login` now use `await saveSession(req)`
in place of the inline ad-hoc Promise wrapper.
- `/auth/logout` is now async and `await`s `destroySession(req)`
before responding, closing the same race for the destroy path.
- Audited remaining routes: only `auth.ts` mutates `req.session`; all
other handlers only read `req.session.userId`, so no further changes
are needed.
Notes / deviations:
- Pre-existing TypeScript errors in unrelated files (conversations,
notes, users, api-zod exports) were left untouched — out of scope.
- New test file `artifacts/api-server/tests/auth-session-persistence.test.mjs`
covers the acceptance criterion: login / register / logout each
followed by an immediate `/auth/me` probe to assert the session was
persisted (or destroyed) before the response was flushed. Modeled on
the existing leave-test pattern. Full suite: 18/18 passing.
Replit-Task-Id: 11b72d21-d7c2-42cb-a4d9-f1197cfad4c5
Original task: investigate why "sole admin leaving with an invalid
successor returns 400 and does not leave" intermittently returned 401
instead of 400 in the API test suite.
Root cause:
express-session 1.19.0 wraps res.end and calls req.session.save()
asynchronously. Its writetop() helper synchronously flushes headers
(including Set-Cookie) and writes the body chunk before save completes,
only deferring the final _end until after the store write. With
Content-Length set, fetch sees the full body and resolves immediately,
so the test's next request (POST /conversations/:id/leave) frequently
arrived before connect-pg-simple finished inserting the session row in
Postgres. requireAuth then read no session, express-session generated a
brand-new sid, and the request was rejected with 401.
This was reproduced ~50% of the time across 10 runs and confirmed via
server-side logging showing the cookie sid not matching the freshly
generated server sid (proving store.get returned nothing).
Fix:
Explicitly await req.session.save() in the /auth/login and
/auth/register handlers after assigning req.session.userId. This
guarantees the session is persisted in Postgres before the response is
sent, eliminating the race for any client that immediately makes a
follow-up authenticated request.
Verification:
Ran the API test suite 15 consecutive times after the fix; all 15 runs
pass cleanly (15/15 tests). The full validation workflow also passes
the api-server tests on the post-fix run.
Files changed:
- artifacts/api-server/src/routes/auth.ts (await session.save in
/auth/login and /auth/register)
- artifacts/api-server/src/middlewares/auth.ts (no behavior change;
diagnostic logging added during debug was removed)