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),
|
/** 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
|
* with tabs for the subscriber catalog and the plan catalog. Each tab is a gated
|
||||||
* tab is a gated child route; an operator with only subscription:read sees just the
|
* child route; an operator with only subscription:read sees just the first tab.
|
||||||
* 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() {
|
function SubscriptionsLayout() {
|
||||||
const { user } = rootRoute.useRouteContext();
|
const { user } = rootRoute.useRouteContext();
|
||||||
const { t } = useTranslation();
|
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">
|
<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:read") && <SetupTab to="/subscriptions" label={t("nav.subscriptions")} exact />}
|
||||||
{show("subscription:plan") && <SetupTab to="/subscriptions/plans" label={t("nav.plans")} />}
|
{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>
|
</nav>
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</div>
|
</div>
|
||||||
@@ -519,7 +534,10 @@ const legacyRedirects = (
|
|||||||
["/shift", "/shifts"],
|
["/shift", "/shifts"],
|
||||||
["/setup/subscriptions", "/subscriptions"],
|
["/setup/subscriptions", "/subscriptions"],
|
||||||
["/setup/plans", "/subscriptions/plans"],
|
["/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/shifts", "/shifts"],
|
||||||
["/setup/reports", "/reports"],
|
["/setup/reports", "/reports"],
|
||||||
] as const
|
] as const
|
||||||
@@ -633,8 +651,20 @@ const tariffRoute = createRoute({
|
|||||||
getParentRoute: () => setupRoute,
|
getParentRoute: () => setupRoute,
|
||||||
path: "tariff",
|
path: "tariff",
|
||||||
beforeLoad: ({ context }) => requirePerm("tariff:read")(context),
|
beforeLoad: ({ context }) => requirePerm("tariff:read")(context),
|
||||||
|
component: TariffLayout,
|
||||||
|
});
|
||||||
|
const tariffComposerRoute = createRoute({
|
||||||
|
getParentRoute: () => tariffRoute,
|
||||||
|
path: "/",
|
||||||
component: () => <TariffComposer />,
|
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
|
// --- /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. ---
|
// (index), the plan catalog, and the tariff lab live here, not under /setup. ---
|
||||||
@@ -651,7 +681,6 @@ const subscriptionsIndexRoute = createRoute({
|
|||||||
beforeLoad: ({ context }) => {
|
beforeLoad: ({ context }) => {
|
||||||
if (can(context.user, "subscription:read")) return;
|
if (can(context.user, "subscription:read")) return;
|
||||||
if (can(context.user, "subscription:plan")) throw redirect({ to: "/subscriptions/plans" });
|
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" });
|
throw redirect({ to: "/booth" });
|
||||||
},
|
},
|
||||||
component: function SubscriptionsRoute() {
|
component: function SubscriptionsRoute() {
|
||||||
@@ -665,12 +694,6 @@ const subscriptionPlansRoute = createRoute({
|
|||||||
beforeLoad: ({ context }) => requirePerm("subscription:plan")(context),
|
beforeLoad: ({ context }) => requirePerm("subscription:plan")(context),
|
||||||
component: () => <SubscriptionPlansManager />,
|
component: () => <SubscriptionPlansManager />,
|
||||||
});
|
});
|
||||||
const tariffLabRoute = createRoute({
|
|
||||||
getParentRoute: () => subscriptionsRoute,
|
|
||||||
path: "tariff-lab",
|
|
||||||
beforeLoad: ({ context }) => requirePerm("tariff:read")(context),
|
|
||||||
component: () => <TariffLab />,
|
|
||||||
});
|
|
||||||
const siteRoute = createRoute({
|
const siteRoute = createRoute({
|
||||||
getParentRoute: () => setupRoute,
|
getParentRoute: () => setupRoute,
|
||||||
path: "site",
|
path: "site",
|
||||||
@@ -751,11 +774,10 @@ const routeTree = rootRoute.addChildren([
|
|||||||
subscriptionsRoute.addChildren([
|
subscriptionsRoute.addChildren([
|
||||||
subscriptionsIndexRoute,
|
subscriptionsIndexRoute,
|
||||||
subscriptionPlansRoute,
|
subscriptionPlansRoute,
|
||||||
tariffLabRoute,
|
|
||||||
]),
|
]),
|
||||||
setupRoute.addChildren([
|
setupRoute.addChildren([
|
||||||
setupDevicesRoute,
|
setupDevicesRoute,
|
||||||
tariffRoute,
|
tariffRoute.addChildren([tariffComposerRoute, tariffLabRoute]),
|
||||||
siteRoute,
|
siteRoute,
|
||||||
usersRoute,
|
usersRoute,
|
||||||
rolesRoute,
|
rolesRoute,
|
||||||
|
|||||||
Reference in New Issue
Block a user