feat(web): move tariff lab under /setup/tariff as a sub-tab
The lab lived at /subscriptions/tariff-lab — the wrong neighborhood for a tool that tests the rate card. /setup/tariff is now a small layout with two sub-tabs (composer at the index, lab at /setup/tariff/lab) behind the existing tariff:read gate. Old URLs (/subscriptions/tariff-lab and the original /setup/tariff-lab) redirect, and the tariff-read-only redirect branch on /subscriptions is gone with the tab. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
+36
-14
@@ -117,9 +117,10 @@ function SetupLayout() {
|
||||
}
|
||||
|
||||
/** Subscriptions layout — a standalone top-level section (its own header nav entry),
|
||||
* with tabs for the subscriber catalog, the plan catalog, and the tariff lab. Each
|
||||
* tab is a gated child route; an operator with only subscription:read sees just the
|
||||
* first tab. */
|
||||
* with tabs for the subscriber catalog and the plan catalog. Each tab is a gated
|
||||
* child route; an operator with only subscription:read sees just the first tab.
|
||||
* (The tariff lab moved to /setup/tariff/lab, 2026-07-05 — it tests the tariff, so
|
||||
* it lives with the tariff.) */
|
||||
function SubscriptionsLayout() {
|
||||
const { user } = rootRoute.useRouteContext();
|
||||
const { t } = useTranslation();
|
||||
@@ -129,7 +130,21 @@ function SubscriptionsLayout() {
|
||||
<nav className="mb-4 flex flex-wrap items-center gap-1 border-b border-term-border">
|
||||
{show("subscription:read") && <SetupTab to="/subscriptions" label={t("nav.subscriptions")} exact />}
|
||||
{show("subscription:plan") && <SetupTab to="/subscriptions/plans" label={t("nav.plans")} />}
|
||||
{show("tariff:read") && <SetupTab to="/subscriptions/tariff-lab" label={t("nav.tariffLab")} />}
|
||||
</nav>
|
||||
<Outlet />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/** Tariff layout — the rate-card hub under Setup: the composer (index) and the
|
||||
* pricing LAB as sub-tabs. One tariff:read gate on the parent covers both. */
|
||||
function TariffLayout() {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div>
|
||||
<nav className="mb-2 flex flex-wrap items-center gap-1 border-b border-term-border">
|
||||
<SetupTab to="/setup/tariff" label={t("nav.tariff")} exact />
|
||||
<SetupTab to="/setup/tariff/lab" label={t("nav.tariffLab")} />
|
||||
</nav>
|
||||
<Outlet />
|
||||
</div>
|
||||
@@ -519,7 +534,10 @@ const legacyRedirects = (
|
||||
["/shift", "/shifts"],
|
||||
["/setup/subscriptions", "/subscriptions"],
|
||||
["/setup/plans", "/subscriptions/plans"],
|
||||
["/setup/tariff-lab", "/subscriptions/tariff-lab"],
|
||||
// The tariff lab bounced twice: /setup/tariff-lab → /subscriptions/tariff-lab
|
||||
// (2026-06-21) → /setup/tariff/lab (2026-07-05, back with the tariff it tests).
|
||||
["/setup/tariff-lab", "/setup/tariff/lab"],
|
||||
["/subscriptions/tariff-lab", "/setup/tariff/lab"],
|
||||
["/setup/shifts", "/shifts"],
|
||||
["/setup/reports", "/reports"],
|
||||
] as const
|
||||
@@ -633,8 +651,20 @@ const tariffRoute = createRoute({
|
||||
getParentRoute: () => setupRoute,
|
||||
path: "tariff",
|
||||
beforeLoad: ({ context }) => requirePerm("tariff:read")(context),
|
||||
component: TariffLayout,
|
||||
});
|
||||
const tariffComposerRoute = createRoute({
|
||||
getParentRoute: () => tariffRoute,
|
||||
path: "/",
|
||||
component: () => <TariffComposer />,
|
||||
});
|
||||
// The tariff LAB — lives with the tariff it tests (moved from /subscriptions,
|
||||
// 2026-07-05). The parent's tariff:read gate covers it.
|
||||
const tariffLabRoute = createRoute({
|
||||
getParentRoute: () => tariffRoute,
|
||||
path: "lab",
|
||||
component: () => <TariffLab />,
|
||||
});
|
||||
|
||||
// --- /subscriptions — a standalone top-level section with its own tabs. The catalog
|
||||
// (index), the plan catalog, and the tariff lab live here, not under /setup. ---
|
||||
@@ -651,7 +681,6 @@ const subscriptionsIndexRoute = createRoute({
|
||||
beforeLoad: ({ context }) => {
|
||||
if (can(context.user, "subscription:read")) return;
|
||||
if (can(context.user, "subscription:plan")) throw redirect({ to: "/subscriptions/plans" });
|
||||
if (can(context.user, "tariff:read")) throw redirect({ to: "/subscriptions/tariff-lab" });
|
||||
throw redirect({ to: "/booth" });
|
||||
},
|
||||
component: function SubscriptionsRoute() {
|
||||
@@ -665,12 +694,6 @@ const subscriptionPlansRoute = createRoute({
|
||||
beforeLoad: ({ context }) => requirePerm("subscription:plan")(context),
|
||||
component: () => <SubscriptionPlansManager />,
|
||||
});
|
||||
const tariffLabRoute = createRoute({
|
||||
getParentRoute: () => subscriptionsRoute,
|
||||
path: "tariff-lab",
|
||||
beforeLoad: ({ context }) => requirePerm("tariff:read")(context),
|
||||
component: () => <TariffLab />,
|
||||
});
|
||||
const siteRoute = createRoute({
|
||||
getParentRoute: () => setupRoute,
|
||||
path: "site",
|
||||
@@ -751,11 +774,10 @@ const routeTree = rootRoute.addChildren([
|
||||
subscriptionsRoute.addChildren([
|
||||
subscriptionsIndexRoute,
|
||||
subscriptionPlansRoute,
|
||||
tariffLabRoute,
|
||||
]),
|
||||
setupRoute.addChildren([
|
||||
setupDevicesRoute,
|
||||
tariffRoute,
|
||||
tariffRoute.addChildren([tariffComposerRoute, tariffLabRoute]),
|
||||
siteRoute,
|
||||
usersRoute,
|
||||
rolesRoute,
|
||||
|
||||
Reference in New Issue
Block a user