feat(dashboard): move shipping profile to locations (#7777)
This commit is contained in:
@@ -53,10 +53,6 @@ const useSettingRoutes = (): NavItemProps[] => {
|
||||
label: t("productTypes.domain"),
|
||||
to: "/settings/product-types",
|
||||
},
|
||||
{
|
||||
label: t("shippingProfile.domain"),
|
||||
to: "/settings/shipping-profiles",
|
||||
},
|
||||
{
|
||||
label: t("stockLocations.domain"),
|
||||
to: "/settings/locations",
|
||||
|
||||
@@ -804,6 +804,14 @@
|
||||
"shipping": "Shipping was successfully enabled."
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
"shippingConfiguration": "Shipping configuration",
|
||||
"shippingProfiles": "Shipping profiles",
|
||||
"shippingProfilesDesc": "Shipping rules for different types of products",
|
||||
"shippingOptionTypes": "Shipping Option Types",
|
||||
"shippingOptionTypesDesc": "Group options based on characteristic"
|
||||
|
||||
},
|
||||
"salesChannels": {
|
||||
"header": "Sales Channels",
|
||||
"label": "Connected sales channels",
|
||||
|
||||
@@ -747,6 +747,48 @@ export const RouteMap: RouteObject[] = [
|
||||
path: "create",
|
||||
lazy: () => import("../../routes/locations/location-create"),
|
||||
},
|
||||
{
|
||||
path: "shipping-profiles",
|
||||
element: <Outlet />,
|
||||
handle: {
|
||||
crumb: () => "Shipping Profiles",
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
lazy: () =>
|
||||
import(
|
||||
"../../routes/shipping-profiles/shipping-profiles-list"
|
||||
),
|
||||
children: [
|
||||
{
|
||||
path: "create",
|
||||
lazy: () =>
|
||||
import(
|
||||
"../../routes/shipping-profiles/shipping-profile-create"
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: ":id",
|
||||
handle: {
|
||||
crumb: (data) => data.shipping_profile.name,
|
||||
},
|
||||
lazy: () =>
|
||||
import(
|
||||
"../../routes/shipping-profiles/shipping-profile-detail"
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "shipping-option-types",
|
||||
element: <Outlet />,
|
||||
handle: {
|
||||
crumb: () => "Shipping Option Types",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: ":location_id",
|
||||
lazy: () => import("../../routes/locations/location-detail"),
|
||||
@@ -900,38 +942,7 @@ export const RouteMap: RouteObject[] = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "shipping-profiles",
|
||||
element: <Outlet />,
|
||||
handle: {
|
||||
crumb: () => "Shipping Profiles",
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
lazy: () =>
|
||||
import(
|
||||
"../../routes/shipping-profiles/shipping-profiles-list"
|
||||
),
|
||||
children: [
|
||||
{
|
||||
path: "create",
|
||||
lazy: () =>
|
||||
import(
|
||||
"../../routes/shipping-profiles/shipping-profile-create"
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: ":id",
|
||||
lazy: () =>
|
||||
import(
|
||||
"../../routes/shipping-profiles/shipping-profile-detail"
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
path: "publishable-api-keys",
|
||||
element: <Outlet />,
|
||||
|
||||
@@ -48,7 +48,11 @@ export const InventoryItemVariantsSection = ({
|
||||
size="2xsmall"
|
||||
variant="transparent"
|
||||
type="button"
|
||||
onClick={() => navigate(`/products/${variant.product.id}`)} // TODO: navigate to variant details when implemented
|
||||
onClick={() =>
|
||||
navigate(
|
||||
`/products/${variant.product.id}/variants/${variant.id}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<ArrowUpRightOnBox className="text-ui-fg-muted" />
|
||||
</IconButton>
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { Outlet, useLoaderData } from "react-router-dom"
|
||||
import { Outlet, useLoaderData, useNavigate } from "react-router-dom"
|
||||
import { Container, Heading, IconButton } from "@medusajs/ui"
|
||||
import { ArrowUpRightOnBox, Buildings, ShoppingBag } from "@medusajs/icons"
|
||||
import { useTranslation } from "react-i18next"
|
||||
|
||||
import { useStockLocations } from "../../../hooks/api/stock-locations"
|
||||
import LocationListItem from "./components/location-list-item/location-list-item"
|
||||
@@ -30,28 +33,105 @@ export function LocationList() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-y-3">
|
||||
{before.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
<div className="flex flex-col gap-y-2">
|
||||
<div className="flex flex-col gap-x-4 gap-y-3 xl:flex-row xl:items-start">
|
||||
<div className="flex w-full flex-col gap-y-3">
|
||||
{before.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<LocationListHeader />
|
||||
<div className="flex flex-col gap-3 lg:col-span-2">
|
||||
{stockLocations.map((location) => (
|
||||
<LocationListItem key={location.id} location={location} />
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<LocationListHeader />
|
||||
<div className="flex flex-col gap-3 lg:col-span-2">
|
||||
{stockLocations.map((location) => (
|
||||
<LocationListItem key={location.id} location={location} />
|
||||
))}
|
||||
{after.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="flex w-full max-w-[100%] flex-col gap-y-3 xl:mt-0 xl:max-w-[400px]">
|
||||
<LinksSection />
|
||||
</div>
|
||||
</div>
|
||||
{after.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<Outlet />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const LinksSection = () => {
|
||||
const { t } = useTranslation()
|
||||
const navigate = useNavigate()
|
||||
|
||||
return (
|
||||
<Container className="p-0">
|
||||
<div className="flex items-center justify-between px-6 py-4">
|
||||
<Heading level="h2">
|
||||
{t("stockLocations.sidebar.shippingConfiguration")}
|
||||
</Heading>
|
||||
</div>
|
||||
|
||||
<div className="txt-small flex flex-col gap-2 px-2 pb-2">
|
||||
<div className="shadow-elevation-card-rest bg-ui-bg-component rounded-md px-4 py-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="shadow-elevation-card-rest rounded-md">
|
||||
<ShoppingBag />
|
||||
</div>
|
||||
<div className="flex flex-1 flex-col">
|
||||
<span className="text-ui-fg-base font-medium">
|
||||
{t("stockLocations.sidebar.shippingProfiles")}
|
||||
</span>
|
||||
<span className="text-ui-fg-subtle">
|
||||
{t("stockLocations.sidebar.shippingProfilesDesc")}
|
||||
</span>
|
||||
</div>
|
||||
<IconButton
|
||||
size="2xsmall"
|
||||
variant="transparent"
|
||||
type="button"
|
||||
onClick={() => navigate(`/settings/locations/shipping-profiles`)}
|
||||
>
|
||||
<ArrowUpRightOnBox className="text-ui-fg-muted" />
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="txt-small flex flex-col gap-2 px-2 pb-2">
|
||||
<div className="shadow-elevation-card-rest bg-ui-bg-component rounded-md px-4 py-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="shadow-elevation-card-rest rounded-md">
|
||||
<Buildings />
|
||||
</div>
|
||||
<div className="flex flex-1 flex-col">
|
||||
<span className="text-ui-fg-base font-medium">
|
||||
{t("stockLocations.sidebar.shippingOptionTypes")}
|
||||
</span>
|
||||
<span className="text-ui-fg-subtle">
|
||||
{t("stockLocations.sidebar.shippingOptionTypesDesc")}
|
||||
</span>
|
||||
</div>
|
||||
<IconButton
|
||||
size="2xsmall"
|
||||
variant="transparent"
|
||||
type="button"
|
||||
onClick={() =>
|
||||
navigate(`/settings/locations/shipping-option-types`)
|
||||
}
|
||||
>
|
||||
<ArrowUpRightOnBox className="text-ui-fg-muted" />
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -51,7 +51,10 @@ export function VariantPricesSection({ variant }: VariantPricesSectionProps) {
|
||||
{!hasPrices && <NoRecords className="h-60" />}
|
||||
{displayPrices.map((price) => {
|
||||
return (
|
||||
<div className="txt-small text-ui-fg-subtle flex justify-between px-6 py-4">
|
||||
<div
|
||||
key={price.id}
|
||||
className="txt-small text-ui-fg-subtle flex justify-between px-6 py-4"
|
||||
>
|
||||
<span className="font-medium">
|
||||
{price.currency_code.toUpperCase()}
|
||||
</span>
|
||||
|
||||
@@ -6,8 +6,8 @@ import * as zod from "zod"
|
||||
|
||||
import { Form } from "../../../../../components/common/form"
|
||||
import {
|
||||
RouteFocusModal,
|
||||
useRouteModal,
|
||||
RouteFocusModal,
|
||||
useRouteModal,
|
||||
} from "../../../../../components/route-modal"
|
||||
import { useCreateShippingProfile } from "../../../../../hooks/api/shipping-profiles"
|
||||
|
||||
@@ -45,7 +45,9 @@ export function CreateShippingProfileForm() {
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
|
||||
handleSuccess(`/settings/shipping-profiles/${shipping_profile.id}`)
|
||||
handleSuccess(
|
||||
`/settings/locations/shipping-profiles/${shipping_profile.id}`
|
||||
)
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(t("general.error"), {
|
||||
|
||||
@@ -45,7 +45,7 @@ export const ShippingProfileGeneralSection = ({
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
|
||||
navigate("/settings/shipping-profiles", { replace: true })
|
||||
navigate("/settings/locations/shipping-profiles", { replace: true })
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(t("general.error"), {
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export { shippingProfileLoader as loader } from "./loader"
|
||||
export { ShippingProfileDetail as Component } from "./shipping-profile-detail"
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import { LoaderFunctionArgs } from "react-router-dom"
|
||||
|
||||
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),
|
||||
queryFn: async () => sdk.admin.shippingProfile.retrieve(id),
|
||||
})
|
||||
|
||||
export const shippingProfileLoader = async ({ params }: LoaderFunctionArgs) => {
|
||||
const id = params.id
|
||||
const query = shippingProfileQuery(id!)
|
||||
|
||||
return (
|
||||
queryClient.getQueryData<{
|
||||
shipping_profile: HttpTypes.AdminShippingProfile
|
||||
}>(query.queryKey) ?? (await queryClient.fetchQuery(query))
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user