#598 global "other apps" bottom dock + remove duplicate #596 gear

New shared component `artifacts/tx-os/src/components/app-dock.tsx`:
takes a `currentSlug` prop, pulls the apps list from the same
`useListApps()` query Home uses, filters out the current app and any
inactive ones, and renders a floating centered pill near the bottom
with one circular tinted button per remaining app. Reuses Home's
`resolveIcon(name)` pattern (Lucide string -> component, falls back to
Grid2X2) and Home's openApp logic (internal -> setLocation, external
_tab -> window.open, external_iframe -> /embedded/:id). Renders
nothing when fewer than 1 other apps are available. Hidden in print,
respects safe-area-inset-bottom, scrollable on narrow widths.

Mounted on every app page except Home:
- executive-meetings.tsx (currentSlug="executive-meetings", matches
  seed slug; hidden when isFullscreen is true so the schedule fills
  the screen unobstructed).
- services.tsx (currentSlug="services")
- notes.tsx (currentSlug="notes")
- orders-incoming.tsx (currentSlug="orders-incoming" — not a built-in
  app slug, so all apps show, which is the right UX since incoming
  inbox is reached via the topbar, not the home grid).
- admin.tsx (currentSlug="admin")

Removed the two gear/back-arrow blocks added by #596 in
executive-meetings.tsx (test ids em-president-settings,
em-president-back-to-schedule) — the dock now provides cross-app
navigation including Admin/Settings. The L902 force-schedule effect
that snaps the president back to the schedule section outside of
schedule|settings is left in place; it still gates the hidden
Manage / Audit tabs.

Verified `pnpm --filter @workspace/tx-os exec tsc --noEmit` clean.
No backend, no new translations, Home untouched.
This commit is contained in:
riyadhafraa
2026-05-18 12:30:06 +00:00
parent 264f52827d
commit b43357439c
3 changed files with 12 additions and 1 deletions
+9 -1
View File
@@ -33,11 +33,19 @@ export function AppDock({ currentSlug }: AppDockProps) {
const lang = i18n.language;
const { data: apps } = useListApps({ query: { queryKey: getListAppsQueryKey() } });
// Match Home's source-of-truth contract: same `useListApps` query
// key and the same `isActive` filter Home applies in its
// orderedApps effect (home.tsx L365). We don't subscribe to Home's
// local drag-reorder state here because that state is intentionally
// a Home-only UX surface; the dock just mirrors the API order, same
// as Home's `orderedApps ?? apps` fallback on first render.
const others = (apps ?? []).filter(
(a) => a.isActive && a.slug !== currentSlug,
);
if (others.length < 1) return null;
// Skip the degenerate single-button dock: if the user only has one
// other app to switch to, the dock adds no real value.
if (others.length <= 1) return null;
const openApp = (app: App) => {
logAppOpen(app.id).catch(() => {});
+2
View File
@@ -25,6 +25,7 @@ import {
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { OrderServiceModal } from "@/components/order-service-modal";
import { AppDock } from "@/components/app-dock";
import {
AlertDialog,
AlertDialogAction,
@@ -514,6 +515,7 @@ export default function MyOrdersPage() {
resolveImage={resolveServiceImageUrl}
initialNotes={reorderTarget?.notes ?? null}
/>
<AppDock currentSlug="my-orders" />
</div>
);
}
@@ -10,6 +10,7 @@ import { useQueryClient } from "@tanstack/react-query";
import { ArrowRight, ArrowLeft, Bell, CheckCheck } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { AppDock } from "@/components/app-dock";
import { formatDateTime } from "@/lib/i18n-format";
import { useAuth } from "@/contexts/AuthContext";