From 493d242c1259cdc68ecdce5f0f9d7885cbd67094 Mon Sep 17 00:00:00 2001
From: Kasper Fabricius Kristensen
<45367945+kasperkristensen@users.noreply.github.com>
Date: Fri, 15 Nov 2024 14:13:03 +0100
Subject: [PATCH] fix(dashboard): Add Breadcrumb components (#10079)
**What**
- Adds Breadcrumb component to all routes that needs breadcrumbs.
- The Breadcrumb components use a combination of loader data and useQuery to ensure that the displayed value is kept up to date if the underlying data is changed via a mutation.
- Also fixes a couple of places where the breadcrumb was not setup correctly.
Resolves CMRC-688
---
.changeset/big-horses-sneeze.md | 5 +
.../src/components/layout/shell/shell.tsx | 14 +-
.../dashboard/src/hooks/api/products.tsx | 17 +-
.../src/hooks/api/shipping-profiles.tsx | 13 +-
.../dashboard/src/providers/providers.tsx | 1 -
.../providers/router-provider/route-map.tsx | 538 ++++++++++++------
.../api-key-management-detail/breadcrumb.tsx | 24 +
.../api-key-management-detail/index.ts | 1 +
.../api-key-management-detail/loader.ts | 6 +-
.../campaigns/campaign-detail/breadcrumb.tsx | 29 +
.../campaign-detail/campaign-detail.tsx | 3 +-
.../campaigns/campaign-detail/constants.ts | 1 +
.../routes/campaigns/campaign-detail/index.ts | 1 +
.../campaigns/campaign-detail/loader.ts | 9 +-
.../categories/category-detail/breadcrumb.tsx | 29 +
.../categories/category-detail/index.ts | 1 +
.../categories/category-detail/loader.ts | 6 +-
.../collection-detail/breadcrumb.tsx | 23 +
.../collections/collection-detail/index.ts | 1 +
.../collections/collection-detail/loader.ts | 7 +-
.../customer-group-detail/breadcrumb.tsx | 31 +
.../customer-group-detail/constants.ts | 1 +
.../customer-group-detail.tsx | 3 +-
.../customer-group-detail/index.ts | 1 +
.../customer-group-detail/loader.ts | 10 +-
.../customers/customer-detail/breadcrumb.tsx | 29 +
.../routes/customers/customer-detail/index.ts | 1 +
.../customers/customer-detail/loader.ts | 7 +-
.../inventory/inventory-detail/breadcrumb.tsx | 31 +
.../inventory/inventory-detail/constants.ts | 2 +
.../inventory/inventory-detail/index.ts | 1 +
.../inventory-detail/inventory-detail.tsx | 3 +-
.../inventory/inventory-detail/loader.ts | 10 +-
.../locations/location-detail/breadcrumb.tsx | 31 +
.../{const.ts => constants.ts} | 2 +-
.../routes/locations/location-detail/index.ts | 1 +
.../locations/location-detail/loader.ts | 31 +-
.../location-detail/location-detail.tsx | 8 +-
.../routes/orders/order-detail/breadcrumb.tsx | 27 +
.../src/routes/orders/order-detail/index.ts | 1 +
.../src/routes/orders/order-detail/loader.ts | 6 +-
.../price-list-detail/breadcrumb.tsx | 23 +
.../price-lists/price-list-detail/index.ts | 1 +
.../price-lists/price-list-detail/loader.ts | 7 +-
.../product-tag-detail/breadcrumb.tsx | 23 +
.../product-tags/product-tag-detail/index.ts | 1 +
.../product-tags/product-tag-detail/loader.ts | 5 +-
.../product-type-detail/breadcrumb.tsx | 24 +
.../product-type-detail/index.ts | 1 +
.../product-type-detail/loader.ts | 7 +-
.../product-variant-detail/breadcrumb.tsx | 31 +
.../product-variant-detail/index.ts | 1 +
.../product-variant-detail/loader.ts | 5 +-
.../products/product-detail/breadcrumb.tsx | 29 +
.../routes/products/product-detail/index.ts | 1 +
.../routes/products/product-detail/loader.ts | 12 +-
.../promotion-detail/breadcrumb.tsx | 22 +
.../promotions/promotion-detail/index.ts | 1 +
.../promotions/promotion-detail/loader.ts | 7 +-
.../regions/region-detail/breadcrumb.tsx | 27 +
.../routes/regions/region-detail/constants.ts | 2 +
.../src/routes/regions/region-detail/index.ts | 1 +
.../routes/regions/region-detail/loader.ts | 3 +-
.../regions/region-detail/region-detail.tsx | 3 +-
.../reservation-detail/breadcrumb.tsx | 29 +
.../reservations/reservation-detail/index.ts | 1 +
.../reservations/reservation-detail/loader.ts | 7 +-
.../sales-channel-detail/breadcrumb.tsx | 23 +
.../sales-channel-detail/index.ts | 1 +
.../sales-channel-detail/loader.ts | 6 +-
.../shipping-profile-detail/breadcrumb.tsx | 27 +
.../shipping-profile-detail/index.ts | 1 +
.../shipping-profile-detail/loader.ts | 11 +-
.../shipping-profile-detail.tsx | 13 +-
.../tax-region-detail/breadcrumb.tsx | 29 +
.../tax-regions/tax-region-detail/index.ts | 1 +
.../tax-regions/tax-region-detail/loader.ts | 6 +-
.../tax-region-province-detail/breadcrumb.tsx | 32 ++
.../tax-region-province-detail/index.ts | 1 +
.../tax-region-province-detail/loader.ts | 6 +-
.../routes/users/user-detail/breadcrumb.tsx | 24 +
.../src/routes/users/user-detail/index.ts | 1 +
.../src/routes/users/user-detail/loader.ts | 6 +-
.../workflow-execution-detail/breadcrumb.tsx | 26 +
.../workflow-execution-detail/index.ts | 2 +
.../workflow-execution-detail/loader.ts | 11 +-
86 files changed, 1123 insertions(+), 344 deletions(-)
create mode 100644 .changeset/big-horses-sneeze.md
create mode 100644 packages/admin/dashboard/src/routes/api-key-management/api-key-management-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/campaigns/campaign-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/campaigns/campaign-detail/constants.ts
create mode 100644 packages/admin/dashboard/src/routes/categories/category-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/collections/collection-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/constants.ts
create mode 100644 packages/admin/dashboard/src/routes/customers/customer-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/inventory/inventory-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/inventory/inventory-detail/constants.ts
create mode 100644 packages/admin/dashboard/src/routes/locations/location-detail/breadcrumb.tsx
rename packages/admin/dashboard/src/routes/locations/location-detail/{const.ts => constants.ts} (90%)
create mode 100644 packages/admin/dashboard/src/routes/orders/order-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/price-lists/price-list-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/product-tags/product-tag-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/product-types/product-type-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/product-variants/product-variant-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/products/product-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/promotions/promotion-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/regions/region-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/regions/region-detail/constants.ts
create mode 100644 packages/admin/dashboard/src/routes/reservations/reservation-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/sales-channels/sales-channel-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/shipping-profiles/shipping-profile-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/tax-regions/tax-region-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/tax-regions/tax-region-province-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/users/user-detail/breadcrumb.tsx
create mode 100644 packages/admin/dashboard/src/routes/workflow-executions/workflow-execution-detail/breadcrumb.tsx
diff --git a/.changeset/big-horses-sneeze.md b/.changeset/big-horses-sneeze.md
new file mode 100644
index 0000000000000..e294a5c0dd03e
--- /dev/null
+++ b/.changeset/big-horses-sneeze.md
@@ -0,0 +1,5 @@
+---
+"@medusajs/dashboard": patch
+---
+
+fix(dashboard): Ensure Breadcrumbs don't display stale data
diff --git a/packages/admin/dashboard/src/components/layout/shell/shell.tsx b/packages/admin/dashboard/src/components/layout/shell/shell.tsx
index 727a790a7b710..26c7603cb570c 100644
--- a/packages/admin/dashboard/src/components/layout/shell/shell.tsx
+++ b/packages/admin/dashboard/src/components/layout/shell/shell.tsx
@@ -2,7 +2,7 @@ import * as Dialog from "@radix-ui/react-dialog"
import { SidebarLeft, TriangleRightMini, XMark } from "@medusajs/icons"
import { IconButton, clx } from "@medusajs/ui"
-import { PropsWithChildren } from "react"
+import { PropsWithChildren, ReactNode } from "react"
import { useTranslation } from "react-i18next"
import { Link, Outlet, UIMatch, useMatches } from "react-router-dom"
@@ -45,18 +45,20 @@ const Gutter = ({ children }: PropsWithChildren) => {
const Breadcrumbs = () => {
const matches = useMatches() as unknown as UIMatch<
unknown,
- { crumb?: (data?: unknown) => string }
+ {
+ breadcrumb?: (match?: UIMatch) => string | ReactNode
+ }
>[]
const crumbs = matches
- .filter((match) => Boolean(match.handle?.crumb))
+ .filter((match) => match.handle?.breadcrumb)
.map((match) => {
const handle = match.handle
- let label: string | null = null
+ let label: string | ReactNode | undefined = undefined
try {
- label = handle.crumb!(match.data)
+ label = handle.breadcrumb?.(match)
} catch (error) {
// noop
}
@@ -70,7 +72,7 @@ const Breadcrumbs = () => {
path: match.pathname,
}
})
- .filter(Boolean) as { label: string; path: string }[]
+ .filter(Boolean) as { label: string | ReactNode; path: string }[]
return (
,
options?: Omit<
- UseQueryOptions,
+ UseQueryOptions<
+ HttpTypes.AdminProductResponse,
+ FetchError,
+ HttpTypes.AdminProductResponse,
+ QueryKey
+ >,
"queryFn" | "queryKey"
>
) => {
@@ -302,9 +307,13 @@ export const useUpdateProduct = (
) => {
return useMutation({
mutationFn: (payload) => sdk.admin.product.update(id, payload),
- onSuccess: (data, variables, context) => {
- queryClient.invalidateQueries({ queryKey: productsQueryKeys.lists() })
- queryClient.invalidateQueries({ queryKey: productsQueryKeys.detail(id) })
+ onSuccess: async (data, variables, context) => {
+ await queryClient.invalidateQueries({
+ queryKey: productsQueryKeys.lists(),
+ })
+ await queryClient.invalidateQueries({
+ queryKey: productsQueryKeys.detail(id),
+ })
options?.onSuccess?.(data, variables, context)
},
diff --git a/packages/admin/dashboard/src/hooks/api/shipping-profiles.tsx b/packages/admin/dashboard/src/hooks/api/shipping-profiles.tsx
index 07aa0d860ca67..c7834e37e20f4 100644
--- a/packages/admin/dashboard/src/hooks/api/shipping-profiles.tsx
+++ b/packages/admin/dashboard/src/hooks/api/shipping-profiles.tsx
@@ -40,11 +40,14 @@ export const useCreateShippingProfile = (
export const useShippingProfile = (
id: string,
query?: Record,
- options?: UseQueryOptions<
- HttpTypes.AdminShippingProfileResponse,
- FetchError,
- HttpTypes.AdminShippingProfileResponse,
- QueryKey
+ options?: Omit<
+ UseQueryOptions<
+ HttpTypes.AdminShippingProfileResponse,
+ FetchError,
+ HttpTypes.AdminShippingProfileResponse,
+ QueryKey
+ >,
+ "queryFn" | "queryKey"
>
) => {
const { data, ...rest } = useQuery({
diff --git a/packages/admin/dashboard/src/providers/providers.tsx b/packages/admin/dashboard/src/providers/providers.tsx
index 588215d637b5b..c52ad0ad97f40 100644
--- a/packages/admin/dashboard/src/providers/providers.tsx
+++ b/packages/admin/dashboard/src/providers/providers.tsx
@@ -2,7 +2,6 @@ import { Toaster, TooltipProvider } from "@medusajs/ui"
import { QueryClientProvider } from "@tanstack/react-query"
import type { PropsWithChildren } from "react"
import { HelmetProvider } from "react-helmet-async"
-
import { I18n } from "../components/utilities/i18n"
import {
DashboardExtensionManager,
diff --git a/packages/admin/dashboard/src/providers/router-provider/route-map.tsx b/packages/admin/dashboard/src/providers/router-provider/route-map.tsx
index 33449aa70e5d6..5ad5068a60822 100644
--- a/packages/admin/dashboard/src/providers/router-provider/route-map.tsx
+++ b/packages/admin/dashboard/src/providers/router-provider/route-map.tsx
@@ -1,5 +1,5 @@
-import { AdminProductCategoryResponse, HttpTypes } from "@medusajs/types"
-import { Outlet, RouteObject } from "react-router-dom"
+import { HttpTypes } from "@medusajs/types"
+import { Outlet, RouteObject, UIMatch } from "react-router-dom"
import { t } from "i18next"
import { ProtectedRoute } from "../../components/authentication/protected-route"
@@ -7,12 +7,7 @@ import { MainLayout } from "../../components/layout/main-layout"
import { PublicLayout } from "../../components/layout/public-layout"
import { SettingsLayout } from "../../components/layout/settings-layout"
import { ErrorBoundary } from "../../components/utilities/error-boundary"
-import { getCountryByIso2 } from "../../lib/data/countries"
-import {
- getProvinceByIso2,
- isProvinceInCountry,
-} from "../../lib/data/country-states"
-import { productLoader } from "../../routes/products/product-detail/loader"
+import { TaxRegionDetailBreadcrumb } from "../../routes/tax-regions/tax-region-detail/breadcrumb"
import { taxRegionLoader } from "../../routes/tax-regions/tax-region-detail/loader"
import { RouteExtensions } from "./route-extensions"
import { SettingsExtensions } from "./settings-extensions"
@@ -34,7 +29,7 @@ export const RouteMap: RouteObject[] = [
path: "/products",
errorElement: ,
handle: {
- crumb: () => t("products.domain"),
+ breadcrumb: () => t("products.domain"),
},
children: [
{
@@ -58,11 +53,20 @@ export const RouteMap: RouteObject[] = [
{
path: ":id",
errorElement: ,
- Component: Outlet,
- loader: productLoader,
- handle: {
- crumb: (data: HttpTypes.AdminProductResponse) =>
- data.product.title,
+ lazy: async () => {
+ const { Breadcrumb, loader } = await import(
+ "../../routes/products/product-detail"
+ )
+
+ return {
+ Component: Outlet,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -134,13 +138,21 @@ export const RouteMap: RouteObject[] = [
},
{
path: "variants/:variant_id",
- lazy: () =>
- import(
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
"../../routes/product-variants/product-variant-detail"
- ),
- handle: {
- crumb: (data: HttpTypes.AdminProductVariantResponse) =>
- data.variant.title,
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ // eslint-disable-next-line max-len
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -172,7 +184,7 @@ export const RouteMap: RouteObject[] = [
path: "/categories",
errorElement: ,
handle: {
- crumb: () => t("categories.domain"),
+ breadcrumb: () => t("categories.domain"),
},
children: [
{
@@ -193,10 +205,20 @@ export const RouteMap: RouteObject[] = [
},
{
path: ":id",
- lazy: () => import("../../routes/categories/category-detail"),
- handle: {
- crumb: (data: AdminProductCategoryResponse) =>
- data.product_category.name,
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
+ "../../routes/categories/category-detail"
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -226,7 +248,7 @@ export const RouteMap: RouteObject[] = [
path: "/orders",
errorElement: ,
handle: {
- crumb: () => t("orders.domain"),
+ breadcrumb: () => t("orders.domain"),
},
children: [
{
@@ -235,7 +257,21 @@ export const RouteMap: RouteObject[] = [
},
{
path: ":id",
- lazy: () => import("../../routes/orders/order-detail"),
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
+ "../../routes/orders/order-detail"
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
+ },
children: [
{
path: "fulfillment",
@@ -289,7 +325,7 @@ export const RouteMap: RouteObject[] = [
path: "/promotions",
errorElement: ,
handle: {
- crumb: () => t("promotions.domain"),
+ breadcrumb: () => t("promotions.domain"),
},
children: [
{
@@ -302,10 +338,20 @@ export const RouteMap: RouteObject[] = [
},
{
path: ":id",
- lazy: () => import("../../routes/promotions/promotion-detail"),
- handle: {
- // TODO: Re-add type when it's available again
- crumb: (data: any) => data.promotion?.code,
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
+ "../../routes/promotions/promotion-detail"
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -330,7 +376,9 @@ export const RouteMap: RouteObject[] = [
{
path: "/campaigns",
errorElement: ,
- handle: { crumb: () => t("campaigns.domain") },
+ handle: {
+ breadcrumb: () => t("campaigns.domain"),
+ },
children: [
{
path: "",
@@ -343,8 +391,21 @@ export const RouteMap: RouteObject[] = [
},
{
path: ":id",
- lazy: () => import("../../routes/campaigns/campaign-detail"),
- handle: { crumb: (data: any) => data.campaign.name },
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
+ "../../routes/campaigns/campaign-detail"
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
+ },
children: [
{
path: "edit",
@@ -373,7 +434,7 @@ export const RouteMap: RouteObject[] = [
path: "/collections",
errorElement: ,
handle: {
- crumb: () => t("collections.domain"),
+ breadcrumb: () => t("collections.domain"),
},
children: [
{
@@ -389,11 +450,20 @@ export const RouteMap: RouteObject[] = [
},
{
path: ":id",
- lazy: () =>
- import("../../routes/collections/collection-detail"),
- handle: {
- crumb: (data: { collection: HttpTypes.AdminCollection }) =>
- data.collection.title,
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
+ "../../routes/collections/collection-detail"
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -416,7 +486,7 @@ export const RouteMap: RouteObject[] = [
path: "/price-lists",
errorElement: ,
handle: {
- crumb: () => t("priceLists.domain"),
+ breadcrumb: () => t("priceLists.domain"),
},
children: [
{
@@ -432,11 +502,20 @@ export const RouteMap: RouteObject[] = [
},
{
path: ":id",
- lazy: () =>
- import("../../routes/price-lists/price-list-detail"),
- handle: {
- crumb: (data: HttpTypes.AdminPriceListResponse) =>
- data.price_list.title,
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
+ "../../routes/price-lists/price-list-detail"
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -469,7 +548,7 @@ export const RouteMap: RouteObject[] = [
path: "/customers",
errorElement: ,
handle: {
- crumb: () => t("customers.domain"),
+ breadcrumb: () => t("customers.domain"),
},
children: [
{
@@ -485,10 +564,20 @@ export const RouteMap: RouteObject[] = [
},
{
path: ":id",
- lazy: () => import("../../routes/customers/customer-detail"),
- handle: {
- // Re-add type when it's available again
- crumb: (data: any) => data.customer.email,
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
+ "../../routes/customers/customer-detail"
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -515,7 +604,7 @@ export const RouteMap: RouteObject[] = [
path: "/customer-groups",
errorElement: ,
handle: {
- crumb: () => t("customerGroups.domain"),
+ breadcrumb: () => t("customerGroups.domain"),
},
children: [
{
@@ -534,12 +623,20 @@ export const RouteMap: RouteObject[] = [
},
{
path: ":id",
- lazy: () =>
- import("../../routes/customer-groups/customer-group-detail"),
- handle: {
- crumb: (data: {
- customer_group: HttpTypes.AdminCustomerGroup
- }) => data.customer_group.name,
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
+ "../../routes/customer-groups/customer-group-detail"
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -571,7 +668,7 @@ export const RouteMap: RouteObject[] = [
path: "/reservations",
errorElement: ,
handle: {
- crumb: () => t("reservations.domain"),
+ breadcrumb: () => t("reservations.domain"),
},
children: [
{
@@ -588,16 +685,20 @@ export const RouteMap: RouteObject[] = [
},
{
path: ":id",
- lazy: () =>
- import("../../routes/reservations/reservation-detail"),
- handle: {
- crumb: ({ reservation }: any) => {
- return (
- reservation?.inventory_item?.title ??
- reservation?.inventory_item?.sku ??
- reservation?.id
- )
- },
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
+ "../../routes/reservations/reservation-detail"
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -620,7 +721,7 @@ export const RouteMap: RouteObject[] = [
path: "/inventory",
errorElement: ,
handle: {
- crumb: () => t("inventory.domain"),
+ breadcrumb: () => t("inventory.domain"),
},
children: [
{
@@ -636,10 +737,20 @@ export const RouteMap: RouteObject[] = [
},
{
path: ":id",
- lazy: () => import("../../routes/inventory/inventory-detail"),
- handle: {
- crumb: (data: HttpTypes.AdminInventoryItemResponse) =>
- data.inventory_item.title ?? data.inventory_item.sku,
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
+ "../../routes/inventory/inventory-detail"
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -691,7 +802,7 @@ export const RouteMap: RouteObject[] = [
{
path: "/settings",
handle: {
- crumb: () => t("app.nav.settings.header"),
+ breadcrumb: () => t("app.nav.settings.header"),
},
element: ,
children: [
@@ -705,7 +816,7 @@ export const RouteMap: RouteObject[] = [
errorElement: ,
lazy: () => import("../../routes/profile/profile-detail"),
handle: {
- crumb: () => t("profile.domain"),
+ breadcrumb: () => t("profile.domain"),
},
children: [
{
@@ -719,7 +830,7 @@ export const RouteMap: RouteObject[] = [
errorElement: ,
element: ,
handle: {
- crumb: () => t("regions.domain"),
+ breadcrumb: () => t("regions.domain"),
},
children: [
{
@@ -734,10 +845,20 @@ export const RouteMap: RouteObject[] = [
},
{
path: ":id",
- lazy: () => import("../../routes/regions/region-detail"),
- handle: {
- crumb: (data: { region: HttpTypes.AdminRegion }) =>
- data.region.name,
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
+ "../../routes/regions/region-detail"
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -758,7 +879,7 @@ export const RouteMap: RouteObject[] = [
errorElement: ,
lazy: () => import("../../routes/store/store-detail"),
handle: {
- crumb: () => t("store.domain"),
+ breadcrumb: () => t("store.domain"),
},
children: [
{
@@ -780,7 +901,7 @@ export const RouteMap: RouteObject[] = [
errorElement: ,
element: ,
handle: {
- crumb: () => t("users.domain"),
+ breadcrumb: () => t("users.domain"),
},
children: [
{
@@ -795,9 +916,20 @@ export const RouteMap: RouteObject[] = [
},
{
path: ":id",
- lazy: () => import("../../routes/users/user-detail"),
- handle: {
- crumb: (data: HttpTypes.AdminUserResponse) => data.user.email,
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
+ "../../routes/users/user-detail"
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -817,7 +949,7 @@ export const RouteMap: RouteObject[] = [
errorElement: ,
element: ,
handle: {
- crumb: () => t("salesChannels.domain"),
+ breadcrumb: () => t("salesChannels.domain"),
},
children: [
{
@@ -836,11 +968,20 @@ export const RouteMap: RouteObject[] = [
},
{
path: ":id",
- lazy: () =>
- import("../../routes/sales-channels/sales-channel-detail"),
- handle: {
- crumb: (data: HttpTypes.AdminSalesChannelResponse) =>
- data.sales_channel.name,
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
+ "../../routes/sales-channels/sales-channel-detail"
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -871,7 +1012,7 @@ export const RouteMap: RouteObject[] = [
errorElement: ,
element: ,
handle: {
- crumb: () => t("locations.domain"),
+ breadcrumb: () => t("locations.domain"),
},
children: [
{
@@ -886,7 +1027,7 @@ export const RouteMap: RouteObject[] = [
path: "shipping-profiles",
element: ,
handle: {
- crumb: () => t("shippingProfile.domain"),
+ breadcrumb: () => t("shippingProfile.domain"),
},
children: [
{
@@ -906,24 +1047,42 @@ export const RouteMap: RouteObject[] = [
],
},
{
- path: ":id",
- handle: {
- crumb: (data: HttpTypes.AdminShippingProfileResponse) =>
- data.shipping_profile.name,
- },
- lazy: () =>
- import(
+ path: ":shipping_profile_id",
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
"../../routes/shipping-profiles/shipping-profile-detail"
- ),
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ // eslint-disable-next-line max-len
+ match: UIMatch
+ ) => ,
+ },
+ }
+ },
},
],
},
{
path: ":location_id",
- lazy: () => import("../../routes/locations/location-detail"),
- handle: {
- crumb: (data: HttpTypes.AdminStockLocationResponse) =>
- data.stock_location.name,
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
+ "../../routes/locations/location-detail"
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -1013,7 +1172,7 @@ export const RouteMap: RouteObject[] = [
errorElement: ,
element: ,
handle: {
- crumb: () => t("productTags.domain"),
+ breadcrumb: () => t("productTags.domain"),
},
children: [
{
@@ -1030,11 +1189,20 @@ export const RouteMap: RouteObject[] = [
},
{
path: ":id",
- lazy: () =>
- import("../../routes/product-tags/product-tag-detail"),
- handle: {
- crumb: (data: HttpTypes.AdminProductTagResponse) =>
- data.product_tag.value,
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
+ "../../routes/product-tags/product-tag-detail"
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -1051,7 +1219,7 @@ export const RouteMap: RouteObject[] = [
errorElement: ,
element: ,
handle: {
- crumb: () => t("workflowExecutions.domain"),
+ breadcrumb: () => t("workflowExecutions.domain"),
},
children: [
{
@@ -1063,18 +1231,20 @@ export const RouteMap: RouteObject[] = [
},
{
path: ":id",
- lazy: () =>
- import(
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
"../../routes/workflow-executions/workflow-execution-detail"
- ),
- handle: {
- crumb: (data: { workflow: any }) => {
- if (!data) {
- return ""
- }
+ )
- return data.workflow.name
- },
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
},
],
@@ -1084,7 +1254,7 @@ export const RouteMap: RouteObject[] = [
errorElement: ,
element: ,
handle: {
- crumb: () => t("productTypes.domain"),
+ breadcrumb: () => t("productTypes.domain"),
},
children: [
{
@@ -1101,11 +1271,20 @@ export const RouteMap: RouteObject[] = [
},
{
path: ":id",
- lazy: () =>
- import("../../routes/product-types/product-type-detail"),
- handle: {
- crumb: (data: HttpTypes.AdminProductTypeResponse) =>
- data.product_type.value,
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
+ "../../routes/product-types/product-type-detail"
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -1121,7 +1300,7 @@ export const RouteMap: RouteObject[] = [
path: "publishable-api-keys",
element: ,
handle: {
- crumb: () => t("apiKeyManagement.domain.publishable"),
+ breadcrumb: () => t("apiKeyManagement.domain.publishable"),
},
children: [
{
@@ -1148,14 +1327,20 @@ export const RouteMap: RouteObject[] = [
},
{
path: ":id",
- lazy: () =>
- import(
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
"../../routes/api-key-management/api-key-management-detail"
- ),
- handle: {
- crumb: (data: HttpTypes.AdminApiKeyResponse) => {
- return data.api_key.title
- },
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -1180,7 +1365,7 @@ export const RouteMap: RouteObject[] = [
path: "secret-api-keys",
element: ,
handle: {
- crumb: () => t("apiKeyManagement.domain.secret"),
+ breadcrumb: () => t("apiKeyManagement.domain.secret"),
},
children: [
{
@@ -1207,14 +1392,20 @@ export const RouteMap: RouteObject[] = [
},
{
path: ":id",
- lazy: () =>
- import(
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
"../../routes/api-key-management/api-key-management-detail"
- ),
- handle: {
- crumb: (data: HttpTypes.AdminApiKeyResponse) => {
- return data.api_key.title
- },
+ )
+
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -1232,7 +1423,7 @@ export const RouteMap: RouteObject[] = [
path: "tax-regions",
element: ,
handle: {
- crumb: () => t("taxRegions.domain"),
+ breadcrumb: () => t("taxRegions.domain"),
},
children: [
{
@@ -1251,19 +1442,22 @@ export const RouteMap: RouteObject[] = [
Component: Outlet,
loader: taxRegionLoader,
handle: {
- crumb: (data: HttpTypes.AdminTaxRegionResponse) => {
- return (
- getCountryByIso2(data.tax_region.country_code)
- ?.display_name ||
- data.tax_region.country_code?.toUpperCase()
- )
- },
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
},
children: [
{
path: "",
- lazy: () =>
- import("../../routes/tax-regions/tax-region-detail"),
+ lazy: async () => {
+ const { Component } = await import(
+ "../../routes/tax-regions/tax-region-detail"
+ )
+
+ return {
+ Component,
+ }
+ },
children: [
{
path: "provinces/create",
@@ -1304,26 +1498,20 @@ export const RouteMap: RouteObject[] = [
},
{
path: "provinces/:province_id",
- lazy: () =>
- import(
+ lazy: async () => {
+ const { Component, Breadcrumb, loader } = await import(
"../../routes/tax-regions/tax-region-province-detail"
- ),
- handle: {
- crumb: (data: HttpTypes.AdminTaxRegionResponse) => {
- const countryCode =
- data.tax_region.country_code?.toUpperCase()
- const provinceCode =
- data.tax_region.province_code?.toUpperCase()
-
- const isValid = isProvinceInCountry(
- countryCode,
- provinceCode
- )
+ )
- return isValid
- ? getProvinceByIso2(provinceCode)
- : provinceCode
- },
+ return {
+ Component,
+ loader,
+ handle: {
+ breadcrumb: (
+ match: UIMatch
+ ) => ,
+ },
+ }
},
children: [
{
@@ -1364,7 +1552,7 @@ export const RouteMap: RouteObject[] = [
path: "return-reasons",
element: ,
handle: {
- crumb: () => t("returnReasons.domain"),
+ breadcrumb: () => t("returnReasons.domain"),
},
children: [
{
diff --git a/packages/admin/dashboard/src/routes/api-key-management/api-key-management-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/api-key-management/api-key-management-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..255f7cc7aa1b0
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/api-key-management/api-key-management-detail/breadcrumb.tsx
@@ -0,0 +1,24 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+
+import { useApiKey } from "../../../hooks/api"
+
+type ApiKeyManagementDetailBreadcrumbProps =
+ UIMatch
+
+export const ApiKeyManagementDetailBreadcrumb = (
+ props: ApiKeyManagementDetailBreadcrumbProps
+) => {
+ const { id } = props.params || {}
+
+ const { api_key } = useApiKey(id!, {
+ initialData: props.data,
+ enabled: Boolean(id),
+ })
+
+ if (!api_key) {
+ return null
+ }
+
+ return {api_key.title}
+}
diff --git a/packages/admin/dashboard/src/routes/api-key-management/api-key-management-detail/index.ts b/packages/admin/dashboard/src/routes/api-key-management/api-key-management-detail/index.ts
index 710a7b5175286..7ee3210445dea 100644
--- a/packages/admin/dashboard/src/routes/api-key-management/api-key-management-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/api-key-management/api-key-management-detail/index.ts
@@ -1,2 +1,3 @@
export { ApiKeyManagementDetail as Component } from "./api-key-management-detail"
+export { ApiKeyManagementDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { apiKeyLoader as loader } from "./loader"
diff --git a/packages/admin/dashboard/src/routes/api-key-management/api-key-management-detail/loader.ts b/packages/admin/dashboard/src/routes/api-key-management/api-key-management-detail/loader.ts
index 34c06f43d7e74..f7daf2c83704c 100644
--- a/packages/admin/dashboard/src/routes/api-key-management/api-key-management-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/api-key-management/api-key-management-detail/loader.ts
@@ -1,6 +1,5 @@
import { LoaderFunctionArgs } from "react-router-dom"
-import { HttpTypes } from "@medusajs/types"
import { apiKeysQueryKeys } from "../../../hooks/api/api-keys"
import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client"
@@ -14,8 +13,5 @@ export const apiKeyLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.id
const query = apiKeyDetailQuery(id!)
- return (
- queryClient.getQueryData(query.queryKey) ??
- (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/campaigns/campaign-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..9b46fc0129281
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/breadcrumb.tsx
@@ -0,0 +1,29 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+import { useCampaign } from "../../../hooks/api"
+import { CAMPAIGN_DETAIL_FIELDS } from "./constants"
+
+type CampaignDetailBreadcrumbProps = UIMatch
+
+export const CampaignDetailBreadcrumb = (
+ props: CampaignDetailBreadcrumbProps
+) => {
+ const { id } = props.params || {}
+
+ const { campaign } = useCampaign(
+ id!,
+ {
+ fields: CAMPAIGN_DETAIL_FIELDS,
+ },
+ {
+ initialData: props.data,
+ enabled: Boolean(id),
+ }
+ )
+
+ if (!campaign) {
+ return null
+ }
+
+ return {campaign.name}
+}
diff --git a/packages/admin/dashboard/src/routes/campaigns/campaign-detail/campaign-detail.tsx b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/campaign-detail.tsx
index 4c1d588d51678..a802e4e998521 100644
--- a/packages/admin/dashboard/src/routes/campaigns/campaign-detail/campaign-detail.tsx
+++ b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/campaign-detail.tsx
@@ -11,6 +11,7 @@ import { TwoColumnPageSkeleton } from "../../../components/common/skeleton"
import { TwoColumnPage } from "../../../components/layout/pages"
import { useDashboardExtension } from "../../../extensions"
import { CampaignConfigurationSection } from "./components/campaign-configuration-section"
+import { CAMPAIGN_DETAIL_FIELDS } from "./constants"
export const CampaignDetail = () => {
const initialData = useLoaderData() as Awaited<
@@ -20,7 +21,7 @@ export const CampaignDetail = () => {
const { id } = useParams()
const { campaign, isLoading, isError, error } = useCampaign(
id!,
- { fields: "+promotions.id" },
+ { fields: CAMPAIGN_DETAIL_FIELDS },
{ initialData }
)
diff --git a/packages/admin/dashboard/src/routes/campaigns/campaign-detail/constants.ts b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/constants.ts
new file mode 100644
index 0000000000000..d449a2d442412
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/constants.ts
@@ -0,0 +1 @@
+export const CAMPAIGN_DETAIL_FIELDS = "+promotions.id"
diff --git a/packages/admin/dashboard/src/routes/campaigns/campaign-detail/index.ts b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/index.ts
index d44b9e434d12b..4cf39a3b47660 100644
--- a/packages/admin/dashboard/src/routes/campaigns/campaign-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/index.ts
@@ -1,2 +1,3 @@
+export { CampaignDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { CampaignDetail as Component } from "./campaign-detail"
export { campaignLoader as loader } from "./loader"
diff --git a/packages/admin/dashboard/src/routes/campaigns/campaign-detail/loader.ts b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/loader.ts
index 0361e3bc633e0..852f79af0b850 100644
--- a/packages/admin/dashboard/src/routes/campaigns/campaign-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/loader.ts
@@ -1,15 +1,15 @@
-import { AdminCampaignResponse } from "@medusajs/types"
import { LoaderFunctionArgs } from "react-router-dom"
import { campaignsQueryKeys } from "../../../hooks/api/campaigns"
import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client"
+import { CAMPAIGN_DETAIL_FIELDS } from "./constants"
const campaignDetailQuery = (id: string) => ({
queryKey: campaignsQueryKeys.detail(id),
queryFn: async () =>
sdk.admin.campaign.retrieve(id, {
- fields: "+promotions.id",
+ fields: CAMPAIGN_DETAIL_FIELDS,
}),
})
@@ -17,8 +17,5 @@ export const campaignLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.id
const query = campaignDetailQuery(id!)
- return (
- queryClient.getQueryData(query.queryKey) ??
- (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/categories/category-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/categories/category-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..9eb94decc0313
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/categories/category-detail/breadcrumb.tsx
@@ -0,0 +1,29 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+import { useProductCategory } from "../../../hooks/api"
+
+type CategoryDetailBreadcrumbProps =
+ UIMatch
+
+export const CategoryDetailBreadcrumb = (
+ props: CategoryDetailBreadcrumbProps
+) => {
+ const { id } = props.params || {}
+
+ const { product_category } = useProductCategory(
+ id!,
+ {
+ fields: "name",
+ },
+ {
+ initialData: props.data,
+ enabled: Boolean(id),
+ }
+ )
+
+ if (!product_category) {
+ return null
+ }
+
+ return {product_category.name}
+}
diff --git a/packages/admin/dashboard/src/routes/categories/category-detail/index.ts b/packages/admin/dashboard/src/routes/categories/category-detail/index.ts
index 8e305c712c96a..f69036910917d 100644
--- a/packages/admin/dashboard/src/routes/categories/category-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/categories/category-detail/index.ts
@@ -1,2 +1,3 @@
+export { CategoryDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { CategoryDetail as Component } from "./category-detail"
export { categoryLoader as loader } from "./loader"
diff --git a/packages/admin/dashboard/src/routes/categories/category-detail/loader.ts b/packages/admin/dashboard/src/routes/categories/category-detail/loader.ts
index 979cb76d8adb2..27c62b55615e6 100644
--- a/packages/admin/dashboard/src/routes/categories/category-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/categories/category-detail/loader.ts
@@ -1,4 +1,3 @@
-import { AdminProductCategoryResponse } from "@medusajs/types"
import { LoaderFunctionArgs } from "react-router-dom"
import { categoriesQueryKeys } from "../../../hooks/api/categories"
@@ -14,8 +13,5 @@ export const categoryLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.id
const query = categoryDetailQuery(id!)
- return (
- queryClient.getQueryData(query.queryKey) ??
- (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/collections/collection-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/collections/collection-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..677ca48b009b1
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/collections/collection-detail/breadcrumb.tsx
@@ -0,0 +1,23 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+import { useCollection } from "../../../hooks/api"
+
+type CollectionDetailBreadcrumbProps =
+ UIMatch
+
+export const CollectionDetailBreadcrumb = (
+ props: CollectionDetailBreadcrumbProps
+) => {
+ const { id } = props.params || {}
+
+ const { collection } = useCollection(id!, {
+ initialData: props.data,
+ enabled: Boolean(id),
+ })
+
+ if (!collection) {
+ return null
+ }
+
+ return {collection.title}
+}
diff --git a/packages/admin/dashboard/src/routes/collections/collection-detail/index.ts b/packages/admin/dashboard/src/routes/collections/collection-detail/index.ts
index d993cc2b01ec0..c4932aae15a14 100644
--- a/packages/admin/dashboard/src/routes/collections/collection-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/collections/collection-detail/index.ts
@@ -1,2 +1,3 @@
+export { CollectionDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { CollectionDetail as Component } from "./collection-detail"
export { collectionLoader as loader } from "./loader"
diff --git a/packages/admin/dashboard/src/routes/collections/collection-detail/loader.ts b/packages/admin/dashboard/src/routes/collections/collection-detail/loader.ts
index 7d5dee3b23ffb..e922557266ee4 100644
--- a/packages/admin/dashboard/src/routes/collections/collection-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/collections/collection-detail/loader.ts
@@ -1,4 +1,3 @@
-import { HttpTypes } from "@medusajs/types"
import { LoaderFunctionArgs } from "react-router-dom"
import { collectionsQueryKeys } from "../../../hooks/api/collections"
@@ -14,9 +13,5 @@ export const collectionLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.id
const query = collectionDetailQuery(id!)
- return (
- queryClient.getQueryData<{ collection: HttpTypes.AdminCollection }>(
- query.queryKey
- ) ?? (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..de9232747b011
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/breadcrumb.tsx
@@ -0,0 +1,31 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+
+import { useCustomerGroup } from "../../../hooks/api"
+import { CUSTOMER_GROUP_DETAIL_FIELDS } from "./constants"
+
+type CustomerGroupDetailBreadcrumbProps =
+ UIMatch
+
+export const CustomerGroupDetailBreadcrumb = (
+ props: CustomerGroupDetailBreadcrumbProps
+) => {
+ const { id } = props.params || {}
+
+ const { customer_group } = useCustomerGroup(
+ id!,
+ {
+ fields: CUSTOMER_GROUP_DETAIL_FIELDS,
+ },
+ {
+ initialData: props.data,
+ enabled: Boolean(id),
+ }
+ )
+
+ if (!customer_group) {
+ return null
+ }
+
+ return {customer_group.name}
+}
diff --git a/packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/constants.ts b/packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/constants.ts
new file mode 100644
index 0000000000000..bd1ebdf4baa6e
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/constants.ts
@@ -0,0 +1 @@
+export const CUSTOMER_GROUP_DETAIL_FIELDS = "+customers.id"
diff --git a/packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/customer-group-detail.tsx b/packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/customer-group-detail.tsx
index 17d79633ac746..65c81efaabf60 100644
--- a/packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/customer-group-detail.tsx
+++ b/packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/customer-group-detail.tsx
@@ -8,6 +8,7 @@ import { customerGroupLoader } from "./loader"
import { SingleColumnPageSkeleton } from "../../../components/common/skeleton"
import { useDashboardExtension } from "../../../extensions"
+import { CUSTOMER_GROUP_DETAIL_FIELDS } from "./constants"
export const CustomerGroupDetail = () => {
const initialData = useLoaderData() as Awaited<
@@ -18,7 +19,7 @@ export const CustomerGroupDetail = () => {
const { customer_group, isLoading, isError, error } = useCustomerGroup(
id!,
{
- fields: "+customers.id",
+ fields: CUSTOMER_GROUP_DETAIL_FIELDS,
},
{ initialData }
)
diff --git a/packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/index.ts b/packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/index.ts
index c1f4e53399bd9..2765f2827faa6 100644
--- a/packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/index.ts
@@ -1,2 +1,3 @@
+export { CustomerGroupDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { CustomerGroupDetail as Component } from "./customer-group-detail"
export { customerGroupLoader as loader } from "./loader"
diff --git a/packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/loader.ts b/packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/loader.ts
index 8538ead153f83..7d43ad6d4fa8d 100644
--- a/packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/customer-groups/customer-group-detail/loader.ts
@@ -1,14 +1,14 @@
-import { HttpTypes } from "@medusajs/types"
import { LoaderFunctionArgs } from "react-router-dom"
import { productsQueryKeys } from "../../../hooks/api/products"
import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client"
+import { CUSTOMER_GROUP_DETAIL_FIELDS } from "./constants"
const customerGroupDetailQuery = (id: string) => ({
queryKey: productsQueryKeys.detail(id),
queryFn: async () =>
sdk.admin.customerGroup.retrieve(id, {
- fields: "+customers.id",
+ fields: CUSTOMER_GROUP_DETAIL_FIELDS,
}),
})
@@ -16,9 +16,5 @@ export const customerGroupLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.id
const query = customerGroupDetailQuery(id!)
- return (
- queryClient.getQueryData<{
- customer_group: HttpTypes.AdminCustomerGroup
- }>(query.queryKey) ?? (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/customers/customer-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/customers/customer-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..8278c4250f3cc
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/customers/customer-detail/breadcrumb.tsx
@@ -0,0 +1,29 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+
+import { useCustomer } from "../../../hooks/api"
+
+type CustomerDetailBreadcrumbProps = UIMatch
+
+export const CustomerDetailBreadcrumb = (
+ props: CustomerDetailBreadcrumbProps
+) => {
+ const { id } = props.params || {}
+
+ const { customer } = useCustomer(id!, undefined, {
+ initialData: props.data,
+ enabled: Boolean(id),
+ })
+
+ if (!customer) {
+ return null
+ }
+
+ const name = [customer.first_name, customer.last_name]
+ .filter(Boolean)
+ .join(" ")
+
+ const display = name || customer.email
+
+ return {display}
+}
diff --git a/packages/admin/dashboard/src/routes/customers/customer-detail/index.ts b/packages/admin/dashboard/src/routes/customers/customer-detail/index.ts
index bed23b93e7de2..edd694dd101eb 100644
--- a/packages/admin/dashboard/src/routes/customers/customer-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/customers/customer-detail/index.ts
@@ -1,2 +1,3 @@
+export { CustomerDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { CustomerDetail as Component } from "./customer-detail"
export { customerLoader as loader } from "./loader"
diff --git a/packages/admin/dashboard/src/routes/customers/customer-detail/loader.ts b/packages/admin/dashboard/src/routes/customers/customer-detail/loader.ts
index 51e19f22f24c0..eebfaa84f9378 100644
--- a/packages/admin/dashboard/src/routes/customers/customer-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/customers/customer-detail/loader.ts
@@ -2,7 +2,6 @@ import { LoaderFunctionArgs } from "react-router-dom"
import { productsQueryKeys } from "../../../hooks/api/products"
import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client"
-import { HttpTypes } from "@medusajs/types"
const customerDetailQuery = (id: string) => ({
queryKey: productsQueryKeys.detail(id),
@@ -13,9 +12,5 @@ export const customerLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.id
const query = customerDetailQuery(id!)
- return (
- queryClient.getQueryData<{ customer: HttpTypes.AdminCustomer }>(
- query.queryKey
- ) ?? (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/inventory/inventory-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/inventory/inventory-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..9e9f7a30b1188
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/inventory/inventory-detail/breadcrumb.tsx
@@ -0,0 +1,31 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+
+import { useInventoryItem } from "../../../hooks/api"
+import { INVENTORY_DETAIL_FIELDS } from "./constants"
+
+type InventoryDetailBreadcrumbProps =
+ UIMatch
+
+export const InventoryDetailBreadcrumb = (
+ props: InventoryDetailBreadcrumbProps
+) => {
+ const { id } = props.params || {}
+
+ const { inventory_item } = useInventoryItem(
+ id!,
+ {
+ fields: INVENTORY_DETAIL_FIELDS,
+ },
+ {
+ initialData: props.data,
+ enabled: Boolean(id),
+ }
+ )
+
+ if (!inventory_item) {
+ return null
+ }
+
+ return {inventory_item.title ?? inventory_item.sku ?? id}
+}
diff --git a/packages/admin/dashboard/src/routes/inventory/inventory-detail/constants.ts b/packages/admin/dashboard/src/routes/inventory/inventory-detail/constants.ts
new file mode 100644
index 0000000000000..5e4988ae0e4d9
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/inventory/inventory-detail/constants.ts
@@ -0,0 +1,2 @@
+export const INVENTORY_DETAIL_FIELDS =
+ "*variants,*variants.product,*variants.options"
diff --git a/packages/admin/dashboard/src/routes/inventory/inventory-detail/index.ts b/packages/admin/dashboard/src/routes/inventory/inventory-detail/index.ts
index 730d046ba45b1..205367ecd5948 100644
--- a/packages/admin/dashboard/src/routes/inventory/inventory-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/inventory/inventory-detail/index.ts
@@ -1,2 +1,3 @@
+export { InventoryDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { InventoryDetail as Component } from "./inventory-detail"
export { inventoryItemLoader as loader } from "./loader"
diff --git a/packages/admin/dashboard/src/routes/inventory/inventory-detail/inventory-detail.tsx b/packages/admin/dashboard/src/routes/inventory/inventory-detail/inventory-detail.tsx
index d68a413a90489..43a6b0dd5146b 100644
--- a/packages/admin/dashboard/src/routes/inventory/inventory-detail/inventory-detail.tsx
+++ b/packages/admin/dashboard/src/routes/inventory/inventory-detail/inventory-detail.tsx
@@ -11,6 +11,7 @@ import { InventoryItemVariantsSection } from "./components/inventory-item-varian
import { inventoryItemLoader } from "./loader"
import { useDashboardExtension } from "../../../extensions"
+import { INVENTORY_DETAIL_FIELDS } from "./constants"
export const InventoryDetail = () => {
const { id } = useParams()
@@ -27,7 +28,7 @@ export const InventoryDetail = () => {
} = useInventoryItem(
id!,
{
- fields: "*variants,*variants.product,*variants.options",
+ fields: INVENTORY_DETAIL_FIELDS,
},
{
initialData,
diff --git a/packages/admin/dashboard/src/routes/inventory/inventory-detail/loader.ts b/packages/admin/dashboard/src/routes/inventory/inventory-detail/loader.ts
index d51f996d2edbc..7c55e44035054 100644
--- a/packages/admin/dashboard/src/routes/inventory/inventory-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/inventory/inventory-detail/loader.ts
@@ -1,15 +1,15 @@
import { LoaderFunctionArgs } from "react-router-dom"
-import { HttpTypes } from "@medusajs/types"
import { inventoryItemsQueryKeys } from "../../../hooks/api/inventory"
import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client"
+import { INVENTORY_DETAIL_FIELDS } from "./constants"
const inventoryDetailQuery = (id: string) => ({
queryKey: inventoryItemsQueryKeys.detail(id),
queryFn: async () =>
sdk.admin.inventoryItem.retrieve(id, {
- fields: "*variants,*variants.product,*variants.options",
+ fields: INVENTORY_DETAIL_FIELDS,
}),
})
@@ -17,9 +17,5 @@ export const inventoryItemLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.id
const query = inventoryDetailQuery(id!)
- return (
- queryClient.getQueryData(
- query.queryKey
- ) ?? (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/locations/location-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/locations/location-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..efdff21669584
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/locations/location-detail/breadcrumb.tsx
@@ -0,0 +1,31 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+
+import { useStockLocation } from "../../../hooks/api/stock-locations"
+import { LOCATION_DETAILS_FIELD } from "./constants"
+
+type LocationDetailBreadcrumbProps =
+ UIMatch
+
+export const LocationDetailBreadcrumb = (
+ props: LocationDetailBreadcrumbProps
+) => {
+ const { location_id } = props.params || {}
+
+ const { stock_location } = useStockLocation(
+ location_id!,
+ {
+ fields: LOCATION_DETAILS_FIELD,
+ },
+ {
+ initialData: props.data,
+ enabled: Boolean(location_id),
+ }
+ )
+
+ if (!stock_location) {
+ return null
+ }
+
+ return {stock_location.name}
+}
diff --git a/packages/admin/dashboard/src/routes/locations/location-detail/const.ts b/packages/admin/dashboard/src/routes/locations/location-detail/constants.ts
similarity index 90%
rename from packages/admin/dashboard/src/routes/locations/location-detail/const.ts
rename to packages/admin/dashboard/src/routes/locations/location-detail/constants.ts
index c15c45a951360..78f963317d20a 100644
--- a/packages/admin/dashboard/src/routes/locations/location-detail/const.ts
+++ b/packages/admin/dashboard/src/routes/locations/location-detail/constants.ts
@@ -1,2 +1,2 @@
-export const detailsFields =
+export const LOCATION_DETAILS_FIELD =
"name,*sales_channels,*address,fulfillment_sets.type,fulfillment_sets.name,*fulfillment_sets.service_zones.geo_zones,*fulfillment_sets.service_zones,*fulfillment_sets.service_zones.shipping_options,*fulfillment_sets.service_zones.shipping_options.rules,*fulfillment_sets.service_zones.shipping_options.shipping_profile,*fulfillment_providers"
diff --git a/packages/admin/dashboard/src/routes/locations/location-detail/index.ts b/packages/admin/dashboard/src/routes/locations/location-detail/index.ts
index 7aab908774ceb..4f04ed8d2487e 100644
--- a/packages/admin/dashboard/src/routes/locations/location-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/locations/location-detail/index.ts
@@ -1,2 +1,3 @@
+export { LocationDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { locationLoader as loader } from "./loader"
export { LocationDetail as Component } from "./location-detail"
diff --git a/packages/admin/dashboard/src/routes/locations/location-detail/loader.ts b/packages/admin/dashboard/src/routes/locations/location-detail/loader.ts
index 07d435ef146ce..7c1bc859a2272 100644
--- a/packages/admin/dashboard/src/routes/locations/location-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/locations/location-detail/loader.ts
@@ -1,38 +1,23 @@
-import { HttpTypes } from "@medusajs/types"
-import { LoaderFunctionArgs, redirect } from "react-router-dom"
+import { LoaderFunctionArgs } from "react-router-dom"
-import { FetchError } from "@medusajs/js-sdk"
import { stockLocationsQueryKeys } from "../../../hooks/api/stock-locations"
import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client"
-import { detailsFields } from "./const"
+import { LOCATION_DETAILS_FIELD } from "./constants"
const locationQuery = (id: string) => ({
queryKey: stockLocationsQueryKeys.detail(id, {
- fields: detailsFields,
+ fields: LOCATION_DETAILS_FIELD,
}),
- queryFn: async () => {
- return await sdk.admin.stockLocation
- .retrieve(id, {
- fields: detailsFields,
- })
- .catch((error: FetchError) => {
- if (error.status === 401) {
- throw redirect("/login")
- }
-
- throw error
- })
- },
+ queryFn: async () =>
+ sdk.admin.stockLocation.retrieve(id, {
+ fields: LOCATION_DETAILS_FIELD,
+ }),
})
export const locationLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.location_id
const query = locationQuery(id!)
- return (
- queryClient.getQueryData<{ stock_location: HttpTypes.AdminStockLocation }>(
- query.queryKey
- ) ?? (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/locations/location-detail/location-detail.tsx b/packages/admin/dashboard/src/routes/locations/location-detail/location-detail.tsx
index 9af3ee7389deb..e7a60dbb57ddf 100644
--- a/packages/admin/dashboard/src/routes/locations/location-detail/location-detail.tsx
+++ b/packages/admin/dashboard/src/routes/locations/location-detail/location-detail.tsx
@@ -9,7 +9,7 @@ import { TwoColumnPageSkeleton } from "../../../components/common/skeleton"
import { TwoColumnPage } from "../../../components/layout/pages"
import { useDashboardExtension } from "../../../extensions"
import LocationsFulfillmentProvidersSection from "./components/location-fulfillment-providers-section/location-fulfillment-providers-section"
-import { detailsFields } from "./const"
+import { LOCATION_DETAILS_FIELD } from "./constants"
export const LocationDetail = () => {
const initialData = useLoaderData() as Awaited<
@@ -22,7 +22,11 @@ export const LocationDetail = () => {
isPending: isLoading,
isError,
error,
- } = useStockLocation(location_id!, { fields: detailsFields }, { initialData })
+ } = useStockLocation(
+ location_id!,
+ { fields: LOCATION_DETAILS_FIELD },
+ { initialData }
+ )
const { getWidgets } = useDashboardExtension()
diff --git a/packages/admin/dashboard/src/routes/orders/order-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/orders/order-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..36ca4db27792c
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/orders/order-detail/breadcrumb.tsx
@@ -0,0 +1,27 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+import { useOrder } from "../../../hooks/api"
+import { DEFAULT_FIELDS } from "./constants"
+
+type OrderDetailBreadcrumbProps = UIMatch
+
+export const OrderDetailBreadcrumb = (props: OrderDetailBreadcrumbProps) => {
+ const { id } = props.params || {}
+
+ const { order } = useOrder(
+ id!,
+ {
+ fields: DEFAULT_FIELDS,
+ },
+ {
+ initialData: props.data,
+ enabled: Boolean(id),
+ }
+ )
+
+ if (!order) {
+ return null
+ }
+
+ return #{order.display_id}
+}
diff --git a/packages/admin/dashboard/src/routes/orders/order-detail/index.ts b/packages/admin/dashboard/src/routes/orders/order-detail/index.ts
index 72ffee80e5c53..bff005715aa3b 100644
--- a/packages/admin/dashboard/src/routes/orders/order-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/orders/order-detail/index.ts
@@ -1,2 +1,3 @@
+export { OrderDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { orderLoader as loader } from "./loader"
export { OrderDetail as Component } from "./order-detail"
diff --git a/packages/admin/dashboard/src/routes/orders/order-detail/loader.ts b/packages/admin/dashboard/src/routes/orders/order-detail/loader.ts
index febd09579e565..036cb5aecb0cb 100644
--- a/packages/admin/dashboard/src/routes/orders/order-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/orders/order-detail/loader.ts
@@ -1,6 +1,5 @@
import { LoaderFunctionArgs } from "react-router-dom"
-import { HttpTypes } from "@medusajs/types"
import { ordersQueryKeys } from "../../../hooks/api/orders"
import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client"
@@ -18,8 +17,5 @@ export const orderLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.id
const query = orderDetailQuery(id!)
- return (
- queryClient.getQueryData(query.queryKey) ??
- (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/price-lists/price-list-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/price-lists/price-list-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..89c3f1fa236f4
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/price-lists/price-list-detail/breadcrumb.tsx
@@ -0,0 +1,23 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+
+import { usePriceList } from "../../../hooks/api"
+
+type PriceListDetailBreadcrumbProps = UIMatch
+
+export const PriceListDetailBreadcrumb = (
+ props: PriceListDetailBreadcrumbProps
+) => {
+ const { id } = props.params || {}
+
+ const { price_list } = usePriceList(id!, undefined, {
+ initialData: props.data,
+ enabled: Boolean(id),
+ })
+
+ if (!price_list) {
+ return null
+ }
+
+ return {price_list.title}
+}
diff --git a/packages/admin/dashboard/src/routes/price-lists/price-list-detail/index.ts b/packages/admin/dashboard/src/routes/price-lists/price-list-detail/index.ts
index a15288c41fe42..0b5c80147e975 100644
--- a/packages/admin/dashboard/src/routes/price-lists/price-list-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/price-lists/price-list-detail/index.ts
@@ -1,2 +1,3 @@
+export { PriceListDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { pricingLoader as loader } from "./loader"
export { PriceListDetails as Component } from "./price-list-detail"
diff --git a/packages/admin/dashboard/src/routes/price-lists/price-list-detail/loader.ts b/packages/admin/dashboard/src/routes/price-lists/price-list-detail/loader.ts
index 08c23dc251653..4a03d34672c49 100644
--- a/packages/admin/dashboard/src/routes/price-lists/price-list-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/price-lists/price-list-detail/loader.ts
@@ -1,4 +1,3 @@
-import { HttpTypes } from "@medusajs/types"
import { LoaderFunctionArgs } from "react-router-dom"
import { priceListsQueryKeys } from "../../../hooks/api/price-lists"
import { sdk } from "../../../lib/client"
@@ -13,9 +12,5 @@ export const pricingLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.id
const query = pricingDetailQuery(id!)
- return (
- queryClient.getQueryData(
- query.queryKey
- ) ?? (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/product-tags/product-tag-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/product-tags/product-tag-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..34a5fa2344d75
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/product-tags/product-tag-detail/breadcrumb.tsx
@@ -0,0 +1,23 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+import { useProductTag } from "../../../hooks/api"
+
+type ProductTagDetailBreadcrumbProps =
+ UIMatch
+
+export const ProductTagDetailBreadcrumb = (
+ props: ProductTagDetailBreadcrumbProps
+) => {
+ const { id } = props.params || {}
+
+ const { product_tag } = useProductTag(id!, undefined, {
+ initialData: props.data,
+ enabled: Boolean(id),
+ })
+
+ if (!product_tag) {
+ return null
+ }
+
+ return {product_tag.value}
+}
diff --git a/packages/admin/dashboard/src/routes/product-tags/product-tag-detail/index.ts b/packages/admin/dashboard/src/routes/product-tags/product-tag-detail/index.ts
index 5464ac6b2e0d1..67290d2aae17c 100644
--- a/packages/admin/dashboard/src/routes/product-tags/product-tag-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/product-tags/product-tag-detail/index.ts
@@ -1,2 +1,3 @@
+export { ProductTagDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { productTagLoader as loader } from "./loader"
export { ProductTagDetail as Component } from "./product-tag-detail"
diff --git a/packages/admin/dashboard/src/routes/product-tags/product-tag-detail/loader.ts b/packages/admin/dashboard/src/routes/product-tags/product-tag-detail/loader.ts
index 896faa6016bb6..d11a3a7f235f1 100644
--- a/packages/admin/dashboard/src/routes/product-tags/product-tag-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/product-tags/product-tag-detail/loader.ts
@@ -13,8 +13,5 @@ export const productTagLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.id
const query = productTagDetailQuery(id!)
- return (
- queryClient.getQueryData(query.queryKey) ??
- (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/product-types/product-type-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/product-types/product-type-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..dcc0e8353b147
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/product-types/product-type-detail/breadcrumb.tsx
@@ -0,0 +1,24 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+
+import { useProductType } from "../../../hooks/api"
+
+type ProductTypeDetailBreadcrumbProps =
+ UIMatch
+
+export const ProductTypeDetailBreadcrumb = (
+ props: ProductTypeDetailBreadcrumbProps
+) => {
+ const { id } = props.params || {}
+
+ const { product_type } = useProductType(id!, undefined, {
+ initialData: props.data,
+ enabled: Boolean(id),
+ })
+
+ if (!product_type) {
+ return null
+ }
+
+ return {product_type.value}
+}
diff --git a/packages/admin/dashboard/src/routes/product-types/product-type-detail/index.ts b/packages/admin/dashboard/src/routes/product-types/product-type-detail/index.ts
index 098bfbc1edcb1..83df010a8bb04 100644
--- a/packages/admin/dashboard/src/routes/product-types/product-type-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/product-types/product-type-detail/index.ts
@@ -1,2 +1,3 @@
+export { ProductTypeDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { productTypeLoader as loader } from "./loader"
export { ProductTypeDetail as Component } from "./product-type-detail"
diff --git a/packages/admin/dashboard/src/routes/product-types/product-type-detail/loader.ts b/packages/admin/dashboard/src/routes/product-types/product-type-detail/loader.ts
index 15f5142903e07..9bdbd5595f6fd 100644
--- a/packages/admin/dashboard/src/routes/product-types/product-type-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/product-types/product-type-detail/loader.ts
@@ -1,6 +1,5 @@
import { LoaderFunctionArgs } from "react-router-dom"
-import { HttpTypes } from "@medusajs/types"
import { productTypesQueryKeys } from "../../../hooks/api/product-types"
import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client"
@@ -14,9 +13,5 @@ export const productTypeLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.id
const query = productTypeDetailQuery(id!)
- return (
- queryClient.getQueryData(
- query.queryKey
- ) ?? (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/product-variants/product-variant-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/product-variants/product-variant-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..730ee435ab399
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/product-variants/product-variant-detail/breadcrumb.tsx
@@ -0,0 +1,31 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+import { useProductVariant } from "../../../hooks/api"
+import { VARIANT_DETAIL_FIELDS } from "./constants"
+
+type ProductVariantDetailBreadcrumbProps =
+ UIMatch
+
+export const ProductVariantDetailBreadcrumb = (
+ props: ProductVariantDetailBreadcrumbProps
+) => {
+ const { id, variant_id } = props.params || {}
+
+ const { variant } = useProductVariant(
+ id!,
+ variant_id!,
+ {
+ fields: VARIANT_DETAIL_FIELDS,
+ },
+ {
+ initialData: props.data,
+ enabled: Boolean(id) && Boolean(variant_id),
+ }
+ )
+
+ if (!variant) {
+ return null
+ }
+
+ return {variant.title}
+}
diff --git a/packages/admin/dashboard/src/routes/product-variants/product-variant-detail/index.ts b/packages/admin/dashboard/src/routes/product-variants/product-variant-detail/index.ts
index aca57b8850722..73598d513f71e 100644
--- a/packages/admin/dashboard/src/routes/product-variants/product-variant-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/product-variants/product-variant-detail/index.ts
@@ -1,2 +1,3 @@
+export { ProductVariantDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { variantLoader as loader } from "./loader"
export { ProductVariantDetail as Component } from "./product-variant-detail"
diff --git a/packages/admin/dashboard/src/routes/product-variants/product-variant-detail/loader.ts b/packages/admin/dashboard/src/routes/product-variants/product-variant-detail/loader.ts
index 0a9167c330e17..973bcb3a91b23 100644
--- a/packages/admin/dashboard/src/routes/product-variants/product-variant-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/product-variants/product-variant-detail/loader.ts
@@ -21,8 +21,5 @@ export const variantLoader = async ({ params }: LoaderFunctionArgs) => {
const query = variantDetailQuery(productId!, variantId!)
- return (
- queryClient.getQueryData(query.queryKey) ??
- (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/products/product-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/products/product-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..1abc880571c47
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/products/product-detail/breadcrumb.tsx
@@ -0,0 +1,29 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+import { useProduct } from "../../../hooks/api"
+import { PRODUCT_DETAIL_FIELDS } from "./constants"
+
+type ProductDetailBreadcrumbProps = UIMatch
+
+export const ProductDetailBreadcrumb = (
+ props: ProductDetailBreadcrumbProps
+) => {
+ const { id } = props.params || {}
+
+ const { product } = useProduct(
+ id!,
+ {
+ fields: PRODUCT_DETAIL_FIELDS,
+ },
+ {
+ initialData: props.data,
+ enabled: Boolean(id),
+ }
+ )
+
+ if (!product) {
+ return null
+ }
+
+ return {product.title}
+}
diff --git a/packages/admin/dashboard/src/routes/products/product-detail/index.ts b/packages/admin/dashboard/src/routes/products/product-detail/index.ts
index afc54745c9306..eeb6d5461b1b8 100644
--- a/packages/admin/dashboard/src/routes/products/product-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/products/product-detail/index.ts
@@ -1,2 +1,3 @@
+export { ProductDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { productLoader as loader } from "./loader"
export { ProductDetail as Component } from "./product-detail"
diff --git a/packages/admin/dashboard/src/routes/products/product-detail/loader.ts b/packages/admin/dashboard/src/routes/products/product-detail/loader.ts
index bf659944a71ea..fa1375a7004d6 100644
--- a/packages/admin/dashboard/src/routes/products/product-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/products/product-detail/loader.ts
@@ -6,7 +6,7 @@ import { queryClient } from "../../../lib/query-client"
import { PRODUCT_DETAIL_FIELDS } from "./constants"
const productDetailQuery = (id: string) => ({
- queryKey: productsQueryKeys.detail(id),
+ queryKey: productsQueryKeys.detail(id, { fields: PRODUCT_DETAIL_FIELDS }),
queryFn: async () =>
sdk.admin.product.retrieve(id, { fields: PRODUCT_DETAIL_FIELDS }),
})
@@ -15,8 +15,10 @@ export const productLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.id
const query = productDetailQuery(id!)
- return (
- queryClient.getQueryData(query.queryKey) ??
- (await queryClient.fetchQuery(query))
- )
+ const response = await queryClient.ensureQueryData({
+ ...query,
+ staleTime: 90000,
+ })
+
+ return response
}
diff --git a/packages/admin/dashboard/src/routes/promotions/promotion-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/promotions/promotion-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..4cc936851412e
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/promotions/promotion-detail/breadcrumb.tsx
@@ -0,0 +1,22 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+import { usePromotion } from "../../../hooks/api"
+
+type PromotionDetailBreadcrumbProps = UIMatch
+
+export const PromotionDetailBreadcrumb = (
+ props: PromotionDetailBreadcrumbProps
+) => {
+ const { id } = props.params || {}
+
+ const { promotion } = usePromotion(id!, {
+ initialData: props.data,
+ enabled: Boolean(id),
+ })
+
+ if (!promotion) {
+ return null
+ }
+
+ return {promotion.code}
+}
diff --git a/packages/admin/dashboard/src/routes/promotions/promotion-detail/index.ts b/packages/admin/dashboard/src/routes/promotions/promotion-detail/index.ts
index a40fbfe52a56a..d2ee0b33b3004 100644
--- a/packages/admin/dashboard/src/routes/promotions/promotion-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/promotions/promotion-detail/index.ts
@@ -1,2 +1,3 @@
+export { PromotionDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { promotionLoader as loader } from "./loader.ts"
export { PromotionDetail as Component } from "./promotion-detail.tsx"
diff --git a/packages/admin/dashboard/src/routes/promotions/promotion-detail/loader.ts b/packages/admin/dashboard/src/routes/promotions/promotion-detail/loader.ts
index b476693132825..49d53da68b731 100644
--- a/packages/admin/dashboard/src/routes/promotions/promotion-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/promotions/promotion-detail/loader.ts
@@ -1,4 +1,3 @@
-import { HttpTypes } from "@medusajs/types"
import { LoaderFunctionArgs } from "react-router-dom"
import { promotionsQueryKeys } from "../../../hooks/api/promotions"
import { sdk } from "../../../lib/client"
@@ -13,9 +12,5 @@ export const promotionLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.id
const query = promotionDetailQuery(id!)
- return (
- queryClient.getQueryData(
- query.queryKey
- ) ?? (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/regions/region-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/regions/region-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..c6673aaae3b24
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/regions/region-detail/breadcrumb.tsx
@@ -0,0 +1,27 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+import { useRegion } from "../../../hooks/api/regions"
+import { REGION_DETAIL_FIELDS } from "./constants"
+
+type RegionDetailBreadcrumbProps = UIMatch
+
+export const RegionDetailBreadcrumb = (props: RegionDetailBreadcrumbProps) => {
+ const { id } = props.params || {}
+
+ const { region } = useRegion(
+ id!,
+ {
+ fields: REGION_DETAIL_FIELDS,
+ },
+ {
+ initialData: props.data,
+ enabled: Boolean(id),
+ }
+ )
+
+ if (!region) {
+ return null
+ }
+
+ return {region.name}
+}
diff --git a/packages/admin/dashboard/src/routes/regions/region-detail/constants.ts b/packages/admin/dashboard/src/routes/regions/region-detail/constants.ts
new file mode 100644
index 0000000000000..f8b82634f55e3
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/regions/region-detail/constants.ts
@@ -0,0 +1,2 @@
+export const REGION_DETAIL_FIELDS =
+ "*payment_providers,*countries,+automatic_taxes"
diff --git a/packages/admin/dashboard/src/routes/regions/region-detail/index.ts b/packages/admin/dashboard/src/routes/regions/region-detail/index.ts
index 17c680a88e302..c72b9957582ce 100644
--- a/packages/admin/dashboard/src/routes/regions/region-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/regions/region-detail/index.ts
@@ -1,2 +1,3 @@
+export { RegionDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { regionLoader as loader } from "./loader"
export { RegionDetail as Component } from "./region-detail"
diff --git a/packages/admin/dashboard/src/routes/regions/region-detail/loader.ts b/packages/admin/dashboard/src/routes/regions/region-detail/loader.ts
index 4a0bb909a1e5d..470d78c7e2815 100644
--- a/packages/admin/dashboard/src/routes/regions/region-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/regions/region-detail/loader.ts
@@ -3,12 +3,13 @@ import { LoaderFunctionArgs } from "react-router-dom"
import { regionsQueryKeys } from "../../../hooks/api/regions"
import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client"
+import { REGION_DETAIL_FIELDS } from "./constants"
const regionQuery = (id: string) => ({
queryKey: regionsQueryKeys.detail(id),
queryFn: async () =>
sdk.admin.region.retrieve(id, {
- fields: "*payment_providers,*countries,+automatic_taxes",
+ fields: REGION_DETAIL_FIELDS,
}),
})
diff --git a/packages/admin/dashboard/src/routes/regions/region-detail/region-detail.tsx b/packages/admin/dashboard/src/routes/regions/region-detail/region-detail.tsx
index 386c2e7b90e91..b9d20d5160cdd 100644
--- a/packages/admin/dashboard/src/routes/regions/region-detail/region-detail.tsx
+++ b/packages/admin/dashboard/src/routes/regions/region-detail/region-detail.tsx
@@ -9,6 +9,7 @@ import { SingleColumnPageSkeleton } from "../../../components/common/skeleton"
import { SingleColumnPage } from "../../../components/layout/pages"
import { useDashboardExtension } from "../../../extensions"
import { usePricePreferences } from "../../../hooks/api/price-preferences"
+import { REGION_DETAIL_FIELDS } from "./constants"
export const RegionDetail = () => {
const initialData = useLoaderData() as Awaited<
@@ -23,7 +24,7 @@ export const RegionDetail = () => {
error: regionError,
} = useRegion(
id!,
- { fields: "*payment_providers,*countries,+automatic_taxes" },
+ { fields: REGION_DETAIL_FIELDS },
{
initialData,
}
diff --git a/packages/admin/dashboard/src/routes/reservations/reservation-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/reservations/reservation-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..b3076f0e84482
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/reservations/reservation-detail/breadcrumb.tsx
@@ -0,0 +1,29 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+
+import { useReservationItem } from "../../../hooks/api"
+
+type ReservationDetailBreadcrumbProps =
+ UIMatch
+
+export const ReservationDetailBreadcrumb = (
+ props: ReservationDetailBreadcrumbProps
+) => {
+ const { id } = props.params || {}
+
+ const { reservation } = useReservationItem(id!, undefined, {
+ initialData: props.data,
+ enabled: Boolean(id),
+ })
+
+ if (!reservation) {
+ return null
+ }
+
+ const display =
+ reservation?.inventory_item?.title ??
+ reservation?.inventory_item?.sku ??
+ reservation.id
+
+ return {display}
+}
diff --git a/packages/admin/dashboard/src/routes/reservations/reservation-detail/index.ts b/packages/admin/dashboard/src/routes/reservations/reservation-detail/index.ts
index ef0430880c833..bffc3f474fff7 100644
--- a/packages/admin/dashboard/src/routes/reservations/reservation-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/reservations/reservation-detail/index.ts
@@ -1,2 +1,3 @@
+export { ReservationDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { reservationItemLoader as loader } from "./loader"
export { ReservationDetail as Component } from "./reservation-detail"
diff --git a/packages/admin/dashboard/src/routes/reservations/reservation-detail/loader.ts b/packages/admin/dashboard/src/routes/reservations/reservation-detail/loader.ts
index dedf1c4622ba0..1088cfb4f8c25 100644
--- a/packages/admin/dashboard/src/routes/reservations/reservation-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/reservations/reservation-detail/loader.ts
@@ -1,4 +1,3 @@
-import { HttpTypes } from "@medusajs/types"
import { LoaderFunctionArgs } from "react-router-dom"
import { reservationItemsQueryKeys } from "../../../hooks/api/reservations"
import { sdk } from "../../../lib/client"
@@ -13,9 +12,5 @@ export const reservationItemLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.id
const query = reservationDetailQuery(id!)
- return (
- queryClient.getQueryData(
- query.queryKey
- ) ?? (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/sales-channels/sales-channel-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/sales-channels/sales-channel-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..1c2254c8a4d8f
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/sales-channels/sales-channel-detail/breadcrumb.tsx
@@ -0,0 +1,23 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+import { useSalesChannel } from "../../../hooks/api/sales-channels"
+
+type SalesChannelDetailBreadcrumbProps =
+ UIMatch
+
+export const SalesChannelDetailBreadcrumb = (
+ props: SalesChannelDetailBreadcrumbProps
+) => {
+ const { id } = props.params || {}
+
+ const { sales_channel } = useSalesChannel(id!, {
+ initialData: props.data,
+ enabled: Boolean(id),
+ })
+
+ if (!sales_channel) {
+ return null
+ }
+
+ return {sales_channel.name}
+}
diff --git a/packages/admin/dashboard/src/routes/sales-channels/sales-channel-detail/index.ts b/packages/admin/dashboard/src/routes/sales-channels/sales-channel-detail/index.ts
index 8d5a59045f7b8..a56aa3df7dfd0 100644
--- a/packages/admin/dashboard/src/routes/sales-channels/sales-channel-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/sales-channels/sales-channel-detail/index.ts
@@ -1,2 +1,3 @@
+export { SalesChannelDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { salesChannelLoader as loader } from "./loader"
export { SalesChannelDetail as Component } from "./sales-channel-detail"
diff --git a/packages/admin/dashboard/src/routes/sales-channels/sales-channel-detail/loader.ts b/packages/admin/dashboard/src/routes/sales-channels/sales-channel-detail/loader.ts
index 5c58f64764ad5..7fdea88a57ac5 100644
--- a/packages/admin/dashboard/src/routes/sales-channels/sales-channel-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/sales-channels/sales-channel-detail/loader.ts
@@ -1,6 +1,5 @@
import { LoaderFunctionArgs } from "react-router-dom"
-import { AdminSalesChannelResponse } from "@medusajs/types"
import { productsQueryKeys } from "../../../hooks/api/products"
import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client"
@@ -14,8 +13,5 @@ export const salesChannelLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.id
const query = salesChannelDetailQuery(id!)
- return (
- queryClient.getQueryData(query.queryKey) ??
- (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profile-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profile-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..af6337d943ec8
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profile-detail/breadcrumb.tsx
@@ -0,0 +1,27 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+import { useShippingProfile } from "../../../hooks/api/shipping-profiles"
+
+type ShippingProfileDetailBreadcrumbProps =
+ UIMatch
+
+export const ShippingProfileDetailBreadcrumb = (
+ props: ShippingProfileDetailBreadcrumbProps
+) => {
+ const { shipping_profile_id } = props.params || {}
+
+ const { shipping_profile } = useShippingProfile(
+ shipping_profile_id!,
+ undefined,
+ {
+ initialData: props.data,
+ enabled: Boolean(shipping_profile_id),
+ }
+ )
+
+ if (!shipping_profile) {
+ return null
+ }
+
+ return {shipping_profile.name}
+}
diff --git a/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profile-detail/index.ts b/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profile-detail/index.ts
index c3508861c895f..5bc8051bf19ac 100644
--- a/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profile-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profile-detail/index.ts
@@ -1,2 +1,3 @@
+export { ShippingProfileDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { shippingProfileLoader as loader } from "./loader"
export { ShippingProfileDetail as Component } from "./shipping-profile-detail"
diff --git a/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profile-detail/loader.ts b/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profile-detail/loader.ts
index 2c5115afc2f4f..9e215a59cd9b3 100644
--- a/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profile-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profile-detail/loader.ts
@@ -1,9 +1,8 @@
-import { HttpTypes } from "@medusajs/types"
import { LoaderFunctionArgs } from "react-router-dom"
+import { shippingProfileQueryKeys } from "../../../hooks/api/shipping-profiles"
import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client"
-import { shippingProfileQueryKeys } from "../../../hooks/api/shipping-profiles"
const shippingProfileQuery = (id: string) => ({
queryKey: shippingProfileQueryKeys.detail(id),
@@ -11,12 +10,8 @@ const shippingProfileQuery = (id: string) => ({
})
export const shippingProfileLoader = async ({ params }: LoaderFunctionArgs) => {
- const id = params.id
+ const id = params.shipping_profile_id
const query = shippingProfileQuery(id!)
- return (
- queryClient.getQueryData<{
- shipping_profile: HttpTypes.AdminShippingProfile
- }>(query.queryKey) ?? (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profile-detail/shipping-profile-detail.tsx b/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profile-detail/shipping-profile-detail.tsx
index 7210c26f9be57..1103360114a9c 100644
--- a/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profile-detail/shipping-profile-detail.tsx
+++ b/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profile-detail/shipping-profile-detail.tsx
@@ -1,4 +1,4 @@
-import { useParams } from "react-router-dom"
+import { useLoaderData, useParams } from "react-router-dom"
import { SingleColumnPageSkeleton } from "../../../components/common/skeleton"
import { useShippingProfile } from "../../../hooks/api/shipping-profiles"
@@ -6,12 +6,19 @@ import { ShippingProfileGeneralSection } from "./components/shipping-profile-gen
import { SingleColumnPage } from "../../../components/layout/pages"
import { useDashboardExtension } from "../../../extensions"
+import { shippingProfileLoader } from "./loader"
export const ShippingProfileDetail = () => {
- const { id } = useParams()
+ const { shipping_profile_id } = useParams()
+
+ const initialData = useLoaderData() as Awaited<
+ ReturnType
+ >
const { shipping_profile, isLoading, isError, error } = useShippingProfile(
- id!
+ shipping_profile_id!,
+ undefined,
+ { initialData }
)
const { getWidgets } = useDashboardExtension()
diff --git a/packages/admin/dashboard/src/routes/tax-regions/tax-region-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/tax-regions/tax-region-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..df240d548c0c4
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/tax-regions/tax-region-detail/breadcrumb.tsx
@@ -0,0 +1,29 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+
+import { useTaxRegion } from "../../../hooks/api"
+import { getCountryByIso2 } from "../../../lib/data/countries"
+
+type TaxRegionDetailBreadcrumbProps = UIMatch
+
+export const TaxRegionDetailBreadcrumb = (
+ props: TaxRegionDetailBreadcrumbProps
+) => {
+ const { id } = props.params || {}
+
+ const { tax_region } = useTaxRegion(id!, undefined, {
+ initialData: props.data,
+ enabled: Boolean(id),
+ })
+
+ if (!tax_region) {
+ return null
+ }
+
+ return (
+
+ {getCountryByIso2(tax_region.country_code)?.display_name ||
+ tax_region.country_code?.toUpperCase()}
+
+ )
+}
diff --git a/packages/admin/dashboard/src/routes/tax-regions/tax-region-detail/index.ts b/packages/admin/dashboard/src/routes/tax-regions/tax-region-detail/index.ts
index 38f10d7514a1a..5da2958b44616 100644
--- a/packages/admin/dashboard/src/routes/tax-regions/tax-region-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/tax-regions/tax-region-detail/index.ts
@@ -1,4 +1,5 @@
export * from "./tax-region-detail"
+export { TaxRegionDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { taxRegionLoader as loader } from "./loader"
export { TaxRegionDetail as Component } from "./tax-region-detail"
diff --git a/packages/admin/dashboard/src/routes/tax-regions/tax-region-detail/loader.ts b/packages/admin/dashboard/src/routes/tax-regions/tax-region-detail/loader.ts
index f9acdc3e6f58c..e7a57fbd7c2e1 100644
--- a/packages/admin/dashboard/src/routes/tax-regions/tax-region-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/tax-regions/tax-region-detail/loader.ts
@@ -1,4 +1,3 @@
-import { AdminTaxRegionResponse } from "@medusajs/types"
import { LoaderFunctionArgs } from "react-router-dom"
import { taxRegionsQueryKeys } from "../../../hooks/api/tax-regions"
import { sdk } from "../../../lib/client"
@@ -13,8 +12,5 @@ export const taxRegionLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.id
const query = taxRegionDetailQuery(id!)
- return (
- queryClient.getQueryData(query.queryKey) ??
- (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/tax-regions/tax-region-province-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/tax-regions/tax-region-province-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..fd8ab170f52e1
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/tax-regions/tax-region-province-detail/breadcrumb.tsx
@@ -0,0 +1,32 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+
+import { useTaxRegion } from "../../../hooks/api"
+import {
+ getProvinceByIso2,
+ isProvinceInCountry,
+} from "../../../lib/data/country-states"
+
+type TaxRegionDetailBreadcrumbProps = UIMatch
+
+export const TaxRegionDetailBreadcrumb = (
+ props: TaxRegionDetailBreadcrumbProps
+) => {
+ const { province_id } = props.params || {}
+
+ const { tax_region } = useTaxRegion(province_id!, undefined, {
+ initialData: props.data,
+ enabled: Boolean(province_id),
+ })
+
+ if (!tax_region) {
+ return null
+ }
+
+ const countryCode = tax_region.country_code?.toUpperCase()
+ const provinceCode = tax_region.province_code?.toUpperCase()
+
+ const isValid = isProvinceInCountry(countryCode, provinceCode)
+
+ return {isValid ? getProvinceByIso2(provinceCode) : provinceCode}
+}
diff --git a/packages/admin/dashboard/src/routes/tax-regions/tax-region-province-detail/index.ts b/packages/admin/dashboard/src/routes/tax-regions/tax-region-province-detail/index.ts
index 38f10d7514a1a..5da2958b44616 100644
--- a/packages/admin/dashboard/src/routes/tax-regions/tax-region-province-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/tax-regions/tax-region-province-detail/index.ts
@@ -1,4 +1,5 @@
export * from "./tax-region-detail"
+export { TaxRegionDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { taxRegionLoader as loader } from "./loader"
export { TaxRegionDetail as Component } from "./tax-region-detail"
diff --git a/packages/admin/dashboard/src/routes/tax-regions/tax-region-province-detail/loader.ts b/packages/admin/dashboard/src/routes/tax-regions/tax-region-province-detail/loader.ts
index 5d8a3155e8aa9..84d2f4d182851 100644
--- a/packages/admin/dashboard/src/routes/tax-regions/tax-region-province-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/tax-regions/tax-region-province-detail/loader.ts
@@ -1,4 +1,3 @@
-import { AdminTaxRegionResponse } from "@medusajs/types"
import { LoaderFunctionArgs } from "react-router-dom"
import { taxRegionsQueryKeys } from "../../../hooks/api/tax-regions"
import { sdk } from "../../../lib/client"
@@ -13,8 +12,5 @@ export const taxRegionLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.province_id
const query = taxRegionDetailQuery(id!)
- return (
- queryClient.getQueryData(query.queryKey) ??
- (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/users/user-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/users/user-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..0262e874ead10
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/users/user-detail/breadcrumb.tsx
@@ -0,0 +1,24 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+import { useUser } from "../../../hooks/api/users"
+
+type UserDetailBreadcrumbProps = UIMatch
+
+export const UserDetailBreadcrumb = (props: UserDetailBreadcrumbProps) => {
+ const { id } = props.params || {}
+
+ const { user } = useUser(id!, undefined, {
+ initialData: props.data,
+ enabled: Boolean(id),
+ })
+
+ if (!user) {
+ return null
+ }
+
+ const name = [user.first_name, user.last_name].filter(Boolean).join(" ")
+
+ const display = name || user.email
+
+ return {display}
+}
diff --git a/packages/admin/dashboard/src/routes/users/user-detail/index.ts b/packages/admin/dashboard/src/routes/users/user-detail/index.ts
index d91450c4f035f..2d6cb45999d7a 100644
--- a/packages/admin/dashboard/src/routes/users/user-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/users/user-detail/index.ts
@@ -1,2 +1,3 @@
+export { UserDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
export { userLoader as loader } from "./loader"
export { UserDetail as Component } from "./user-detail"
diff --git a/packages/admin/dashboard/src/routes/users/user-detail/loader.ts b/packages/admin/dashboard/src/routes/users/user-detail/loader.ts
index 4851460d64a76..1f4ed87891842 100644
--- a/packages/admin/dashboard/src/routes/users/user-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/users/user-detail/loader.ts
@@ -1,6 +1,5 @@
import { LoaderFunctionArgs } from "react-router-dom"
-import { HttpTypes } from "@medusajs/types"
import { productsQueryKeys } from "../../../hooks/api/products"
import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client"
@@ -14,8 +13,5 @@ export const userLoader = async ({ params }: LoaderFunctionArgs) => {
const id = params.id
const query = userDetailQuery(id!)
- return (
- queryClient.getQueryData(query.queryKey) ??
- (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}
diff --git a/packages/admin/dashboard/src/routes/workflow-executions/workflow-execution-detail/breadcrumb.tsx b/packages/admin/dashboard/src/routes/workflow-executions/workflow-execution-detail/breadcrumb.tsx
new file mode 100644
index 0000000000000..4da7426c5692c
--- /dev/null
+++ b/packages/admin/dashboard/src/routes/workflow-executions/workflow-execution-detail/breadcrumb.tsx
@@ -0,0 +1,26 @@
+import { HttpTypes } from "@medusajs/types"
+import { UIMatch } from "react-router-dom"
+
+import { useWorkflowExecution } from "../../../hooks/api"
+
+type WorkflowExecutionDetailBreadcrumbProps =
+ UIMatch
+
+export const WorkflowExecutionDetailBreadcrumb = (
+ props: WorkflowExecutionDetailBreadcrumbProps
+) => {
+ const { id } = props.params || {}
+
+ const { workflow_execution } = useWorkflowExecution(id!, {
+ initialData: props.data,
+ enabled: Boolean(id),
+ })
+
+ if (!workflow_execution) {
+ return null
+ }
+
+ const cleanId = workflow_execution.id.replace("wf_exec_", "")
+
+ return {cleanId}
+}
diff --git a/packages/admin/dashboard/src/routes/workflow-executions/workflow-execution-detail/index.ts b/packages/admin/dashboard/src/routes/workflow-executions/workflow-execution-detail/index.ts
index 2289190872954..d243329092374 100644
--- a/packages/admin/dashboard/src/routes/workflow-executions/workflow-execution-detail/index.ts
+++ b/packages/admin/dashboard/src/routes/workflow-executions/workflow-execution-detail/index.ts
@@ -1 +1,3 @@
+export { WorkflowExecutionDetailBreadcrumb as Breadcrumb } from "./breadcrumb"
+export { workflowExecutionLoader as loader } from "./loader"
export { ExecutionDetail as Component } from "./workflow-detail"
diff --git a/packages/admin/dashboard/src/routes/workflow-executions/workflow-execution-detail/loader.ts b/packages/admin/dashboard/src/routes/workflow-executions/workflow-execution-detail/loader.ts
index d8f331dfc06bd..816063aed43af 100644
--- a/packages/admin/dashboard/src/routes/workflow-executions/workflow-execution-detail/loader.ts
+++ b/packages/admin/dashboard/src/routes/workflow-executions/workflow-execution-detail/loader.ts
@@ -1,6 +1,5 @@
import { LoaderFunctionArgs } from "react-router-dom"
-import { HttpTypes } from "@medusajs/types"
import { workflowExecutionsQueryKeys } from "../../../hooks/api/workflow-executions"
import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client"
@@ -10,13 +9,11 @@ const executionDetailQuery = (id: string) => ({
queryFn: async () => sdk.admin.workflowExecution.retrieve(id),
})
-export const executionLoader = async ({ params }: LoaderFunctionArgs) => {
+export const workflowExecutionLoader = async ({
+ params,
+}: LoaderFunctionArgs) => {
const id = params.id
const query = executionDetailQuery(id!)
- return (
- queryClient.getQueryData(
- query.queryKey
- ) ?? (await queryClient.fetchQuery(query))
- )
+ return queryClient.ensureQueryData(query)
}