feat(dashboard): move shipping profile to locations (#7777)

This commit is contained in:
Frane Polić authored and GitHub committed 2024-06-20 06:47:40 +00:00
1 parent 48963f55ef
commit 79a8f0ef2c
10 files changed
+189 -62

No files matched your search

@@ -53,10 +53,6 @@ const useSettingRoutes = (): NavItemProps[] => {
label: t("productTypes.domain"), label: t("productTypes.domain"),
to: "/settings/product-types", to: "/settings/product-types",
}, },
{
label: t("shippingProfile.domain"),
to: "/settings/shipping-profiles",
},
{ {
label: t("stockLocations.domain"), label: t("stockLocations.domain"),
to: "/settings/locations", to: "/settings/locations",
@@ -804,6 +804,14 @@
"shipping": "Shipping was successfully enabled." "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": { "salesChannels": {
"header": "Sales Channels", "header": "Sales Channels",
"label": "Connected sales channels", "label": "Connected sales channels",
@@ -747,6 +747,48 @@ export const RouteMap: RouteObject[] = [
path: "create", path: "create",
lazy: () => import("../../routes/locations/location-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", path: ":location_id",
lazy: () => import("../../routes/locations/location-detail"), 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", path: "publishable-api-keys",
element: <Outlet />, element: <Outlet />,
@@ -48,7 +48,11 @@ export const InventoryItemVariantsSection = ({
size="2xsmall" size="2xsmall"
variant="transparent" variant="transparent"
type="button" 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" /> <ArrowUpRightOnBox className="text-ui-fg-muted" />
</IconButton> </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 { useStockLocations } from "../../../hooks/api/stock-locations"
import LocationListItem from "./components/location-list-item/location-list-item" import LocationListItem from "./components/location-list-item/location-list-item"
@@ -30,28 +33,105 @@ export function LocationList() {
} }
return ( return (
<div className="flex flex-col gap-y-3"> <div className="flex flex-col gap-y-2">
{before.widgets.map((w, i) => { <div className="flex flex-col gap-x-4 gap-y-3 xl:flex-row xl:items-start">
return ( <div className="flex w-full flex-col gap-y-3">
<div key={i}> {before.widgets.map((w, i) => {
<w.Component /> 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> </div>
) {after.widgets.map((w, i) => {
})} return (
<LocationListHeader /> <div key={i}>
<div className="flex flex-col gap-3 lg:col-span-2"> <w.Component />
{stockLocations.map((location) => ( </div>
<LocationListItem key={location.id} location={location} /> )
))} })}
</div>
<div className="flex w-full max-w-[100%] flex-col gap-y-3 xl:mt-0 xl:max-w-[400px]">
<LinksSection />
</div>
</div> </div>
{after.widgets.map((w, i) => {
return (
<div key={i}>
<w.Component />
</div>
)
})}
<Outlet /> <Outlet />
</div> </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" />} {!hasPrices && <NoRecords className="h-60" />}
{displayPrices.map((price) => { {displayPrices.map((price) => {
return ( 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"> <span className="font-medium">
{price.currency_code.toUpperCase()} {price.currency_code.toUpperCase()}
</span> </span>
@@ -6,8 +6,8 @@ import * as zod from "zod"
import { Form } from "../../../../../components/common/form" import { Form } from "../../../../../components/common/form"
import { import {
RouteFocusModal, RouteFocusModal,
useRouteModal, useRouteModal,
} from "../../../../../components/route-modal" } from "../../../../../components/route-modal"
import { useCreateShippingProfile } from "../../../../../hooks/api/shipping-profiles" import { useCreateShippingProfile } from "../../../../../hooks/api/shipping-profiles"
@@ -45,7 +45,9 @@ export function CreateShippingProfileForm() {
dismissLabel: t("actions.close"), dismissLabel: t("actions.close"),
}) })
handleSuccess(`/settings/shipping-profiles/${shipping_profile.id}`) handleSuccess(
`/settings/locations/shipping-profiles/${shipping_profile.id}`
)
}, },
onError: (error) => { onError: (error) => {
toast.error(t("general.error"), { toast.error(t("general.error"), {
@@ -45,7 +45,7 @@ export const ShippingProfileGeneralSection = ({
dismissLabel: t("actions.close"), dismissLabel: t("actions.close"),
}) })
navigate("/settings/shipping-profiles", { replace: true }) navigate("/settings/locations/shipping-profiles", { replace: true })
}, },
onError: (error) => { onError: (error) => {
toast.error(t("general.error"), { toast.error(t("general.error"), {
@@ -1 +1,2 @@
export { shippingProfileLoader as loader } from "./loader"
export { ShippingProfileDetail as Component } from "./shipping-profile-detail" 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))
)
}