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

This commit is contained in:
Frane Polić
2024-06-20 08:47:40 +02:00
committed by GitHub
parent 48963f55ef
commit 79a8f0ef2c
10 changed files with 189 additions and 62 deletions

View File

@@ -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",

View File

@@ -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",

View File

@@ -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 />,

View File

@@ -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>

View File

@@ -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>
)
}

View File

@@ -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>

View File

@@ -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"), {

View File

@@ -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"), {

View File

@@ -1 +1,2 @@
export { shippingProfileLoader as loader } from "./loader"
export { ShippingProfileDetail as Component } from "./shipping-profile-detail"

View File

@@ -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))
)
}