feat(dashboard,admin-shared): Add injection zones to regions, shipping profiles, and locations (#7467)
This commit is contained in:
1 parent
ebc4215f16
commit
0b0e210f67
63 files changed
+418
-267
No files matched your search
@@ -85,6 +85,29 @@ const GIFT_CARD_INJECTION_ZONES = [
|
||||
"custom_gift_card.after",
|
||||
] as const
|
||||
|
||||
const REGION_INJECTION_ZONES = [
|
||||
"region.details.before",
|
||||
"region.details.after",
|
||||
"region.list.before",
|
||||
"region.list.after",
|
||||
] as const
|
||||
|
||||
const SHIPPING_PROFILE_INJECTION_ZONES = [
|
||||
"shipping_profile.details.before",
|
||||
"shipping_profile.details.after",
|
||||
"shipping_profile.list.before",
|
||||
"shipping_profile.list.after",
|
||||
] as const
|
||||
|
||||
const LOCATION_INJECTION_ZONES = [
|
||||
"location.details.before",
|
||||
"location.details.after",
|
||||
"location.details.side.before",
|
||||
"location.details.side.after",
|
||||
"location.list.before",
|
||||
"location.list.after",
|
||||
] as const
|
||||
|
||||
const LOGIN_INJECTION_ZONES = ["login.before", "login.after"] as const
|
||||
|
||||
/**
|
||||
@@ -103,5 +126,8 @@ export const INJECTION_ZONES = [
|
||||
...DISCOUNT_INJECTION_ZONES,
|
||||
...PROMOTION_INJECTION_ZONES,
|
||||
...GIFT_CARD_INJECTION_ZONES,
|
||||
...REGION_INJECTION_ZONES,
|
||||
...SHIPPING_PROFILE_INJECTION_ZONES,
|
||||
...LOCATION_INJECTION_ZONES,
|
||||
...LOGIN_INJECTION_ZONES,
|
||||
] as const
|
||||
+2
-2
@@ -54,8 +54,8 @@ const useSettingRoutes = (): NavItemProps[] => {
|
||||
to: "/settings/shipping-profiles",
|
||||
},
|
||||
{
|
||||
label: t("shipping.domain"),
|
||||
to: "/settings/shipping",
|
||||
label: t("location.domain"),
|
||||
to: "/settings/locations",
|
||||
},
|
||||
],
|
||||
[t]
|
||||
|
||||
@@ -675,8 +675,8 @@
|
||||
"invalidEmail": "Email must be a valid email address."
|
||||
}
|
||||
},
|
||||
"shipping": {
|
||||
"title": "Location & Shipping",
|
||||
"location": {
|
||||
"title": "Locations & Shipping",
|
||||
"domain": "Location & Shipping",
|
||||
"description": "Choose where you ship and how much you charge for shipping at checkout. Define shipping options specific for your locations.",
|
||||
"createLocation": "Create location",
|
||||
|
||||
@@ -682,33 +682,33 @@ export const RouteMap: RouteObject[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "shipping",
|
||||
path: "locations",
|
||||
element: <Outlet />,
|
||||
handle: {
|
||||
crumb: () => "Location & Shipping",
|
||||
crumb: () => "Locations & Shipping",
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
lazy: () => import("../../routes/shipping/location-list"),
|
||||
lazy: () => import("../../routes/locations/location-list"),
|
||||
},
|
||||
{
|
||||
path: "create",
|
||||
lazy: () => import("../../routes/shipping/location-create"),
|
||||
lazy: () => import("../../routes/locations/location-create"),
|
||||
},
|
||||
{
|
||||
path: ":location_id",
|
||||
lazy: () => import("../../routes/shipping/location-details"),
|
||||
lazy: () => import("../../routes/locations/location-details"),
|
||||
children: [
|
||||
{
|
||||
path: "edit",
|
||||
lazy: () => import("../../routes/shipping/location-edit"),
|
||||
lazy: () => import("../../routes/locations/location-edit"),
|
||||
},
|
||||
{
|
||||
path: "sales-channels/edit",
|
||||
lazy: () =>
|
||||
import(
|
||||
"../../routes/shipping/location-add-sales-channels"
|
||||
"../../routes/locations/location-add-sales-channels"
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -717,7 +717,7 @@ export const RouteMap: RouteObject[] = [
|
||||
{
|
||||
path: "service-zones/create",
|
||||
lazy: () =>
|
||||
import("../../routes/shipping/service-zone-create"),
|
||||
import("../../routes/locations/service-zone-create"),
|
||||
},
|
||||
{
|
||||
path: "service-zone/:zone_id",
|
||||
@@ -725,13 +725,15 @@ export const RouteMap: RouteObject[] = [
|
||||
{
|
||||
path: "edit",
|
||||
lazy: () =>
|
||||
import("../../routes/shipping/service-zone-edit"),
|
||||
import(
|
||||
"../../routes/locations/service-zone-edit"
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "edit-areas",
|
||||
lazy: () =>
|
||||
import(
|
||||
"../../routes/shipping/service-zone-areas-edit"
|
||||
"../../routes/locations/service-zone-areas-edit"
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -741,7 +743,7 @@ export const RouteMap: RouteObject[] = [
|
||||
path: "create",
|
||||
lazy: () =>
|
||||
import(
|
||||
"../../routes/shipping/shipping-options-create"
|
||||
"../../routes/locations/shipping-options-create"
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -751,14 +753,14 @@ export const RouteMap: RouteObject[] = [
|
||||
path: "edit",
|
||||
lazy: () =>
|
||||
import(
|
||||
"../../routes/shipping/shipping-option-edit"
|
||||
"../../routes/locations/shipping-option-edit"
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "edit-pricing",
|
||||
lazy: () =>
|
||||
import(
|
||||
"../../routes/shipping/shipping-options-edit-pricing"
|
||||
"../../routes/locations/shipping-options-edit-pricing"
|
||||
),
|
||||
},
|
||||
],
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+3
-3
@@ -55,7 +55,7 @@ export const CreateLocationForm = () => {
|
||||
address: values.address,
|
||||
})
|
||||
|
||||
handleSuccess("/settings/shipping")
|
||||
handleSuccess("/settings/locations")
|
||||
|
||||
toast.success(t("general.success"), {
|
||||
description: t("locations.toast.create"),
|
||||
@@ -92,10 +92,10 @@ export const CreateLocationForm = () => {
|
||||
<div className="flex w-full max-w-[720px] flex-col gap-y-8 px-2 py-16">
|
||||
<div>
|
||||
<Heading className="capitalize">
|
||||
{t("shipping.createLocation")}
|
||||
{t("location.createLocation")}
|
||||
</Heading>
|
||||
<Text size="small" className="text-ui-fg-subtle">
|
||||
{t("shipping.createLocationDetailsHint")}
|
||||
{t("location.createLocationDetailsHint")}
|
||||
</Text>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+44
-44
@@ -1,12 +1,3 @@
|
||||
import { useNavigate } from "react-router-dom"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { useMemo, useState } from "react"
|
||||
import {
|
||||
FulfillmentSetDTO,
|
||||
ServiceZoneDTO,
|
||||
ShippingOptionDTO,
|
||||
StockLocationDTO,
|
||||
} from "@medusajs/types"
|
||||
import {
|
||||
ChevronDownMini,
|
||||
CurrencyDollar,
|
||||
@@ -15,6 +6,12 @@ import {
|
||||
Plus,
|
||||
Trash,
|
||||
} from "@medusajs/icons"
|
||||
import {
|
||||
FulfillmentSetDTO,
|
||||
ServiceZoneDTO,
|
||||
ShippingOptionDTO,
|
||||
StockLocationDTO,
|
||||
} from "@medusajs/types"
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
@@ -25,19 +22,22 @@ import {
|
||||
toast,
|
||||
usePrompt,
|
||||
} from "@medusajs/ui"
|
||||
import { useMemo, useState } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
|
||||
import { ActionMenu } from "../../../../../components/common/action-menu"
|
||||
import { countries as staticCountries } from "../../../../../lib/countries"
|
||||
import { NoRecords } from "../../../../../components/common/empty-table-content"
|
||||
import { ListSummary } from "../../../../../components/common/list-summary"
|
||||
import { useDeleteShippingOption } from "../../../../../hooks/api/shipping-options"
|
||||
import {
|
||||
useCreateFulfillmentSet,
|
||||
useDeleteFulfillmentSet,
|
||||
useDeleteServiceZone,
|
||||
useDeleteStockLocation,
|
||||
} from "../../../../../hooks/api/stock-locations"
|
||||
import { useDeleteShippingOption } from "../../../../../hooks/api/shipping-options"
|
||||
import { countries as staticCountries } from "../../../../../lib/countries"
|
||||
import { formatProvider } from "../../../../../lib/format-provider"
|
||||
import { NoRecords } from "../../../../../components/common/empty-table-content"
|
||||
import { ListSummary } from "../../../../../components/common/list-summary"
|
||||
import {
|
||||
isOptionEnabledInStore,
|
||||
isReturnOption,
|
||||
@@ -103,7 +103,7 @@ function ShippingOption({
|
||||
const handleDelete = async () => {
|
||||
const res = await prompt({
|
||||
title: t("general.areYouSure"),
|
||||
description: t("shipping.shippingOptions.deleteWarning", {
|
||||
description: t("location.shippingOptions.deleteWarning", {
|
||||
name: option.name,
|
||||
}),
|
||||
confirmText: t("actions.delete"),
|
||||
@@ -118,7 +118,7 @@ function ShippingOption({
|
||||
await deleteOption()
|
||||
|
||||
toast.success(t("general.success"), {
|
||||
description: t("shipping.shippingOptions.toast.delete", {
|
||||
description: t("location.shippingOptions.toast.delete", {
|
||||
name: option.name,
|
||||
}),
|
||||
dismissLabel: t("actions.close"),
|
||||
@@ -141,7 +141,7 @@ function ShippingOption({
|
||||
</div>
|
||||
{isInStore && (
|
||||
<Badge className="mr-4" color="purple">
|
||||
{t("shipping.shippingOptions.inStore")}
|
||||
{t("location.shippingOptions.inStore")}
|
||||
</Badge>
|
||||
)}
|
||||
<ActionMenu
|
||||
@@ -150,13 +150,13 @@ function ShippingOption({
|
||||
actions: [
|
||||
{
|
||||
icon: <PencilSquare />,
|
||||
label: t("shipping.serviceZone.editOption"),
|
||||
to: `/settings/shipping/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${option.service_zone_id}/shipping-option/${option.id}/edit`,
|
||||
label: t("location.serviceZone.editOption"),
|
||||
to: `/settings/locations/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${option.service_zone_id}/shipping-option/${option.id}/edit`,
|
||||
},
|
||||
{
|
||||
label: t("shipping.serviceZone.editPrices"),
|
||||
label: t("location.serviceZone.editPrices"),
|
||||
icon: <CurrencyDollar />,
|
||||
to: `/settings/shipping/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${option.service_zone_id}/shipping-option/${option.id}/edit-pricing`,
|
||||
to: `/settings/locations/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${option.service_zone_id}/shipping-option/${option.id}/edit-pricing`,
|
||||
},
|
||||
{
|
||||
label: t("actions.delete"),
|
||||
@@ -196,18 +196,18 @@ function ServiceZoneOptions({
|
||||
<div className="mt-4 flex flex-col border-t border-dashed px-6 py-4">
|
||||
<div className="item-center flex justify-between">
|
||||
<span className="text-ui-fg-subtle txt-small self-center font-medium">
|
||||
{t("shipping.serviceZone.shippingOptions")}
|
||||
{t("location.serviceZone.shippingOptions")}
|
||||
</span>
|
||||
<Button
|
||||
className="text-ui-fg-interactive txt-small px-0 font-medium hover:bg-transparent active:bg-transparent"
|
||||
variant="transparent"
|
||||
onClick={() =>
|
||||
navigate(
|
||||
`/settings/shipping/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${zone.id}/shipping-option/create`
|
||||
`/settings/locations/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${zone.id}/shipping-option/create`
|
||||
)
|
||||
}
|
||||
>
|
||||
{t("shipping.serviceZone.addOption")}
|
||||
{t("location.serviceZone.addOption")}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -228,18 +228,18 @@ function ServiceZoneOptions({
|
||||
<div className="-mb-4 flex flex-col border-t border-dashed px-6 py-4">
|
||||
<div className="item-center flex justify-between">
|
||||
<span className="text-ui-fg-subtle txt-small self-center font-medium">
|
||||
{t("shipping.serviceZone.returnOptions")}
|
||||
{t("location.serviceZone.returnOptions")}
|
||||
</span>
|
||||
<Button
|
||||
className="text-ui-fg-interactive txt-small px-0 font-medium hover:bg-transparent active:bg-transparent"
|
||||
variant="transparent"
|
||||
onClick={() =>
|
||||
navigate(
|
||||
`/settings/shipping/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${zone.id}/shipping-option/create?is_return`
|
||||
`/settings/locations/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${zone.id}/shipping-option/create?is_return`
|
||||
)
|
||||
}
|
||||
>
|
||||
{t("shipping.serviceZone.addOption")}
|
||||
{t("location.serviceZone.addOption")}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -280,7 +280,7 @@ function ServiceZone({ zone, locationId, fulfillmentSetId }: ServiceZoneProps) {
|
||||
const handleDelete = async () => {
|
||||
const res = await prompt({
|
||||
title: t("general.areYouSure"),
|
||||
description: t("shipping.serviceZone.deleteWarning", {
|
||||
description: t("location.serviceZone.deleteWarning", {
|
||||
name: zone.name,
|
||||
}),
|
||||
confirmText: t("actions.delete"),
|
||||
@@ -295,7 +295,7 @@ function ServiceZone({ zone, locationId, fulfillmentSetId }: ServiceZoneProps) {
|
||||
await deleteZone()
|
||||
|
||||
toast.success(t("general.success"), {
|
||||
description: t("shipping.serviceZone.toast.delete", {
|
||||
description: t("location.serviceZone.toast.delete", {
|
||||
name: zone.name,
|
||||
}),
|
||||
dismissLabel: t("actions.close"),
|
||||
@@ -350,14 +350,14 @@ function ServiceZone({ zone, locationId, fulfillmentSetId }: ServiceZoneProps) {
|
||||
<span>·</span>
|
||||
<Text className="text-ui-fg-subtle txt-small">
|
||||
{shippingOptionsCount}{" "}
|
||||
{t("shipping.serviceZone.optionsLength", {
|
||||
{t("location.serviceZone.optionsLength", {
|
||||
count: shippingOptionsCount,
|
||||
})}
|
||||
</Text>
|
||||
<span>·</span>
|
||||
<Text className="text-ui-fg-subtle txt-small">
|
||||
{returnOptionsCount}{" "}
|
||||
{t("shipping.serviceZone.returnOptionsLength", {
|
||||
{t("location.serviceZone.returnOptionsLength", {
|
||||
count: returnOptionsCount,
|
||||
})}
|
||||
</Text>
|
||||
@@ -389,12 +389,12 @@ function ServiceZone({ zone, locationId, fulfillmentSetId }: ServiceZoneProps) {
|
||||
{
|
||||
label: t("actions.edit"),
|
||||
icon: <PencilSquare />,
|
||||
to: `/settings/shipping/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${zone.id}/edit`,
|
||||
to: `/settings/locations/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${zone.id}/edit`,
|
||||
},
|
||||
{
|
||||
label: t("shipping.serviceZone.areas.manage"),
|
||||
label: t("location.serviceZone.areas.manage"),
|
||||
icon: <Map />,
|
||||
to: `/settings/shipping/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${zone.id}/edit-areas`,
|
||||
to: `/settings/locations/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${zone.id}/edit-areas`,
|
||||
},
|
||||
{
|
||||
label: t("actions.delete"),
|
||||
@@ -469,7 +469,7 @@ function FulfillmentSet(props: FulfillmentSetProps) {
|
||||
const handleDelete = async () => {
|
||||
const res = await prompt({
|
||||
title: t("general.areYouSure"),
|
||||
description: t("shipping.fulfillmentSet.disableWarning", {
|
||||
description: t("location.fulfillmentSet.disableWarning", {
|
||||
name: fulfillmentSet?.name,
|
||||
}),
|
||||
confirmText: t("actions.delete"),
|
||||
@@ -484,7 +484,7 @@ function FulfillmentSet(props: FulfillmentSetProps) {
|
||||
await deleteFulfillmentSet()
|
||||
|
||||
toast.success(t("general.success"), {
|
||||
description: t("shipping.fulfillmentSet.toast.disable", {
|
||||
description: t("location.fulfillmentSet.toast.disable", {
|
||||
name: fulfillmentSet?.name,
|
||||
}),
|
||||
dismissLabel: t("actions.close"),
|
||||
@@ -502,7 +502,7 @@ function FulfillmentSet(props: FulfillmentSetProps) {
|
||||
<div className="flex flex-col divide-y">
|
||||
<div className="flex items-center justify-between px-6 py-4">
|
||||
<Text size="large" weight="plus" className="flex-1" as="div">
|
||||
{t(`shipping.fulfillmentSet.${type}.offers`)}
|
||||
{t(`location.fulfillmentSet.${type}.offers`)}
|
||||
</Text>
|
||||
<div className="flex items-center gap-4">
|
||||
<StatusBadge color={fulfillmentSetExists ? "green" : "red"}>
|
||||
@@ -517,10 +517,10 @@ function FulfillmentSet(props: FulfillmentSetProps) {
|
||||
actions: [
|
||||
{
|
||||
icon: <Plus />,
|
||||
label: t("shipping.fulfillmentSet.addZone"),
|
||||
label: t("location.fulfillmentSet.addZone"),
|
||||
onClick: () =>
|
||||
navigate(
|
||||
`/settings/shipping/${locationId}/fulfillment-set/${fulfillmentSet.id}/service-zones/create`
|
||||
`/settings/locations/${locationId}/fulfillment-set/${fulfillmentSet.id}/service-zones/create`
|
||||
),
|
||||
disabled: !fulfillmentSetExists,
|
||||
},
|
||||
@@ -543,7 +543,7 @@ function FulfillmentSet(props: FulfillmentSetProps) {
|
||||
{fulfillmentSetExists && !hasServiceZones && (
|
||||
<div className="text-ui-fg-muted txt-medium flex flex-col items-center justify-center gap-y-4 py-8">
|
||||
<NoRecords
|
||||
message={t("shipping.fulfillmentSet.placeholder")}
|
||||
message={t("location.fulfillmentSet.placeholder")}
|
||||
className="h-fit"
|
||||
/>
|
||||
|
||||
@@ -551,11 +551,11 @@ function FulfillmentSet(props: FulfillmentSetProps) {
|
||||
variant="secondary"
|
||||
onClick={() =>
|
||||
navigate(
|
||||
`/settings/shipping/${locationId}/fulfillment-set/${fulfillmentSet.id}/service-zones/create`
|
||||
`/settings/locations/${locationId}/fulfillment-set/${fulfillmentSet.id}/service-zones/create`
|
||||
)
|
||||
}
|
||||
>
|
||||
{t("shipping.fulfillmentSet.addZone")}
|
||||
{t("location.fulfillmentSet.addZone")}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
@@ -586,7 +586,7 @@ const Actions = ({ location }: { location: StockLocationDTO }) => {
|
||||
const handleDelete = async () => {
|
||||
const res = await prompt({
|
||||
title: t("general.areYouSure"),
|
||||
description: t("shipping.deleteLocationWarning", {
|
||||
description: t("location.deleteLocationWarning", {
|
||||
name: location.name,
|
||||
}),
|
||||
verificationText: location.name,
|
||||
@@ -602,7 +602,7 @@ const Actions = ({ location }: { location: StockLocationDTO }) => {
|
||||
try {
|
||||
await mutateAsync(undefined)
|
||||
toast.success(t("general.success"), {
|
||||
description: t("shipping.toast.delete"),
|
||||
description: t("location.toast.delete"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
} catch (e) {
|
||||
@@ -611,7 +611,7 @@ const Actions = ({ location }: { location: StockLocationDTO }) => {
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
}
|
||||
navigate("/settings/shipping", { replace: true })
|
||||
navigate("/settings/locations", { replace: true })
|
||||
}
|
||||
|
||||
return (
|
||||
File renamed without changes.
+5
-5
@@ -1,11 +1,11 @@
|
||||
import { Channels, PencilSquare } from "@medusajs/icons"
|
||||
import { StockLocationDTO } from "@medusajs/types"
|
||||
import { Heading, Text } from "@medusajs/ui"
|
||||
import { Trans, useTranslation } from "react-i18next"
|
||||
import { StockLocationDTO } from "@medusajs/types"
|
||||
import { Channels, PencilSquare } from "@medusajs/icons"
|
||||
|
||||
import { useSalesChannels } from "../../../../../hooks/api/sales-channels"
|
||||
import { ActionMenu } from "../../../../../components/common/action-menu"
|
||||
import { ListSummary } from "../../../../../components/common/list-summary"
|
||||
import { useSalesChannels } from "../../../../../hooks/api/sales-channels"
|
||||
|
||||
type Props = {
|
||||
location: StockLocationDTO
|
||||
@@ -20,7 +20,7 @@ function LocationsSalesChannelsSection({ location }: Props) {
|
||||
return (
|
||||
<div className="shadow-elevation-card-rest bg-ui-bg-base rounded-md p-4">
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<Heading level="h2">{t("shipping.salesChannels.title")}</Heading>
|
||||
<Heading level="h2">{t("location.salesChannels.title")}</Heading>
|
||||
<ActionMenu
|
||||
groups={[
|
||||
{
|
||||
@@ -43,7 +43,7 @@ function LocationsSalesChannelsSection({ location }: Props) {
|
||||
</div>
|
||||
{noChannels ? (
|
||||
<Text size="small" leading="compact" className="text-ui-fg-subtle">
|
||||
{t("shipping.salesChannels.placeholder")}
|
||||
{t("location.salesChannels.placeholder")}
|
||||
</Text>
|
||||
) : (
|
||||
<ListSummary
|
||||
File renamed without changes.
File renamed without changes.
+92
@@ -0,0 +1,92 @@
|
||||
import { Outlet, useLoaderData, useParams } from "react-router-dom"
|
||||
|
||||
import { JsonViewSection } from "../../../components/common/json-view-section"
|
||||
import { useStockLocation } from "../../../hooks/api/stock-locations"
|
||||
import { LocationGeneralSection } from "./components/location-general-section"
|
||||
import LocationsSalesChannelsSection from "./components/location-sales-channels-section/locations-sales-channels-section"
|
||||
import { locationLoader } from "./loader"
|
||||
|
||||
import after from "virtual:medusa/widgets/location/details/after"
|
||||
import before from "virtual:medusa/widgets/location/details/before"
|
||||
import sideAfter from "virtual:medusa/widgets/location/details/side/after"
|
||||
import sideBefore from "virtual:medusa/widgets/location/details/side/before"
|
||||
|
||||
export const LocationDetails = () => {
|
||||
const initialData = useLoaderData() as Awaited<
|
||||
ReturnType<typeof locationLoader>
|
||||
>
|
||||
|
||||
const { location_id } = useParams()
|
||||
const {
|
||||
stock_location: location,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useStockLocation(
|
||||
location_id!,
|
||||
{
|
||||
fields:
|
||||
"name,*sales_channels,address.city,address.country_code,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",
|
||||
},
|
||||
{
|
||||
initialData,
|
||||
}
|
||||
)
|
||||
|
||||
// TODO: Move to loading.tsx and set as Suspense fallback for the route
|
||||
if (isLoading || !location) {
|
||||
return <div>Loading...</div>
|
||||
}
|
||||
|
||||
if (isError) {
|
||||
throw error
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-y-3">
|
||||
{before.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component data={location} />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<div className="flex flex-col gap-x-4 lg:flex-row xl:items-start">
|
||||
<div className="flex w-full flex-col gap-y-2">
|
||||
<LocationGeneralSection location={location} />
|
||||
{after.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component data={location} />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<div className="hidden xl:block">
|
||||
<JsonViewSection data={location} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="hidden w-full max-w-[400px] flex-col gap-y-2 xl:flex">
|
||||
{sideBefore.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component data={location} />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<LocationsSalesChannelsSection location={location} />
|
||||
{sideAfter.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component data={location} />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<div className="xl:hidden">
|
||||
<JsonViewSection data={location} />
|
||||
</div>
|
||||
</div>
|
||||
<Outlet />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+15
-15
@@ -1,3 +1,9 @@
|
||||
import { Buildings, PencilSquare, Trash } from "@medusajs/icons"
|
||||
import {
|
||||
FulfillmentSetDTO,
|
||||
SalesChannelDTO,
|
||||
StockLocationDTO,
|
||||
} from "@medusajs/types"
|
||||
import {
|
||||
Button,
|
||||
Container,
|
||||
@@ -6,19 +12,13 @@ import {
|
||||
toast,
|
||||
usePrompt,
|
||||
} from "@medusajs/ui"
|
||||
import {
|
||||
FulfillmentSetDTO,
|
||||
SalesChannelDTO,
|
||||
StockLocationDTO,
|
||||
} from "@medusajs/types"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { Buildings, PencilSquare, Trash } from "@medusajs/icons"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
|
||||
import { countries } from "../../../../../lib/countries"
|
||||
import { ActionMenu } from "../../../../../components/common/action-menu"
|
||||
import { useDeleteStockLocation } from "../../../../../hooks/api/stock-locations"
|
||||
import { BadgeListSummary } from "../../../../../components/common/badge-list-summary"
|
||||
import { useDeleteStockLocation } from "../../../../../hooks/api/stock-locations"
|
||||
import { countries } from "../../../../../lib/countries"
|
||||
|
||||
type SalesChannelsProps = {
|
||||
salesChannels?: SalesChannelDTO[]
|
||||
@@ -37,7 +37,7 @@ function SalesChannels(props: SalesChannelsProps) {
|
||||
className="text-ui-fg-subtle flex-1"
|
||||
as="div"
|
||||
>
|
||||
{t(`shipping.fulfillmentSet.salesChannels`)}
|
||||
{t(`location.fulfillmentSet.salesChannels`)}
|
||||
</Text>
|
||||
<div className="flex-1 text-left">
|
||||
{salesChannels?.length ? (
|
||||
@@ -80,7 +80,7 @@ function FulfillmentSet(props: FulfillmentSetProps) {
|
||||
className="text-ui-fg-subtle flex-1"
|
||||
as="div"
|
||||
>
|
||||
{t(`shipping.fulfillmentSet.${type}.title`)}
|
||||
{t(`location.fulfillmentSet.${type}.title`)}
|
||||
</Text>
|
||||
<div className="flex-1 text-left">
|
||||
<StatusBadge color={fulfillmentSetExists ? "green" : "red"}>
|
||||
@@ -107,7 +107,7 @@ function Location(props: LocationProps) {
|
||||
const handleDelete = async () => {
|
||||
const result = await prompt({
|
||||
title: t("general.areYouSure"),
|
||||
description: t("shipping.deleteLocation.confirm", {
|
||||
description: t("location.deleteLocation.confirm", {
|
||||
name: location.name,
|
||||
}),
|
||||
confirmText: t("actions.remove"),
|
||||
@@ -122,7 +122,7 @@ function Location(props: LocationProps) {
|
||||
await deleteLocation()
|
||||
|
||||
toast.success(t("general.success"), {
|
||||
description: t("shipping.deleteLocation.success", {
|
||||
description: t("location.deleteLocation.success", {
|
||||
name: location.name,
|
||||
}),
|
||||
dismissLabel: t("general.close"),
|
||||
@@ -169,10 +169,10 @@ function Location(props: LocationProps) {
|
||||
{
|
||||
label: t("actions.edit"),
|
||||
icon: <PencilSquare />,
|
||||
to: `/settings/shipping/${location.id}/edit`,
|
||||
to: `/settings/locations/${location.id}/edit`,
|
||||
},
|
||||
{
|
||||
label: t("shipping.deleteLocation.label"),
|
||||
label: t("location.deleteLocation.label"),
|
||||
icon: <Trash />,
|
||||
onClick: handleDelete,
|
||||
},
|
||||
@@ -182,7 +182,7 @@ function Location(props: LocationProps) {
|
||||
/>
|
||||
<Button
|
||||
className="text-ui-fg-interactive rounded-none pl-5 hover:bg-transparent active:bg-transparent"
|
||||
onClick={() => navigate(`/settings/shipping/${location.id}`)}
|
||||
onClick={() => navigate(`/settings/locations/${location.id}`)}
|
||||
variant="transparent"
|
||||
>
|
||||
{t("actions.viewDetails")}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,62 @@
|
||||
import { Button, Container, Heading, Text } from "@medusajs/ui"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { Link, Outlet, useLoaderData } from "react-router-dom"
|
||||
|
||||
import { useStockLocations } from "../../../hooks/api/stock-locations"
|
||||
import Location from "./components/location/location"
|
||||
import { locationListFields } from "./const"
|
||||
import { shippingListLoader } from "./loader"
|
||||
|
||||
import after from "virtual:medusa/widgets/location/list/after"
|
||||
import before from "virtual:medusa/widgets/location/list/before"
|
||||
|
||||
export function LocationList() {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const initialData = useLoaderData() as Awaited<
|
||||
ReturnType<typeof shippingListLoader>
|
||||
>
|
||||
|
||||
const { stock_locations: stockLocations = [], isPending } = useStockLocations(
|
||||
{
|
||||
fields: locationListFields,
|
||||
},
|
||||
{ initialData }
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-y-3">
|
||||
{before.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<Container className="flex h-fit items-center justify-between p-8">
|
||||
<div>
|
||||
<Heading className="mb-2">{t("location.title")}</Heading>
|
||||
<Text className="text-ui-fg-subtle txt-small">
|
||||
{t("location.description")}
|
||||
</Text>
|
||||
</div>
|
||||
<Button size="small" variant="secondary" asChild>
|
||||
<Link to="create">{t("location.createLocation")}</Link>
|
||||
</Button>
|
||||
</Container>
|
||||
<div className="flex flex-col gap-3 lg:col-span-2">
|
||||
{stockLocations.map((location) => (
|
||||
<Location key={location.id} location={location} />
|
||||
))}
|
||||
</div>
|
||||
{after.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<Outlet />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+16
-16
@@ -1,12 +1,14 @@
|
||||
import { useForm } from "react-hook-form"
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import {
|
||||
ColumnDef,
|
||||
createColumnHelper,
|
||||
RowSelectionState,
|
||||
} from "@tanstack/react-table"
|
||||
import { useForm } from "react-hook-form"
|
||||
import * as zod from "zod"
|
||||
|
||||
import { XMarkMini } from "@medusajs/icons"
|
||||
import { HttpTypes, ServiceZoneDTO } from "@medusajs/types"
|
||||
import {
|
||||
Alert,
|
||||
Badge,
|
||||
@@ -17,23 +19,21 @@ import {
|
||||
Text,
|
||||
toast,
|
||||
} from "@medusajs/ui"
|
||||
import { ServiceZoneDTO, HttpTypes } from "@medusajs/types"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { XMarkMini } from "@medusajs/icons"
|
||||
|
||||
import { useEffect, useMemo, useState } from "react"
|
||||
import { SplitView } from "../../../../../components/layout/split-view"
|
||||
import {
|
||||
RouteFocusModal,
|
||||
useRouteModal,
|
||||
} from "../../../../../components/route-modal"
|
||||
import { SplitView } from "../../../../../components/layout/split-view"
|
||||
import { useUpdateServiceZone } from "../../../../../hooks/api/stock-locations"
|
||||
import { useEffect, useMemo, useState } from "react"
|
||||
import { useCountryTableQuery } from "../../../../regions/common/hooks/use-country-table-query"
|
||||
import { useCountries } from "../../../../regions/common/hooks/use-countries"
|
||||
import { countries as staticCountries } from "../../../../../lib/countries"
|
||||
import { useDataTable } from "../../../../../hooks/use-data-table"
|
||||
import { useCountryTableColumns } from "../../../../regions/common/hooks/use-country-table-columns"
|
||||
import { DataTable } from "../../../../../components/table/data-table"
|
||||
import { useUpdateServiceZone } from "../../../../../hooks/api/stock-locations"
|
||||
import { useDataTable } from "../../../../../hooks/use-data-table"
|
||||
import { countries as staticCountries } from "../../../../../lib/countries"
|
||||
import { useCountries } from "../../../../regions/common/hooks/use-countries"
|
||||
import { useCountryTableColumns } from "../../../../regions/common/hooks/use-country-table-columns"
|
||||
import { useCountryTableQuery } from "../../../../regions/common/hooks/use-country-table-query"
|
||||
|
||||
const PREFIX = "ac"
|
||||
const PAGE_SIZE = 50
|
||||
@@ -215,7 +215,7 @@ export function EditServiceZoneAreasForm({
|
||||
<SplitView.Content className="mx-auto max-w-[720px]">
|
||||
<div className="container w-fit px-1 py-8">
|
||||
<Heading className="mt-8 text-2xl">
|
||||
{t("shipping.serviceZone.editAreasTitle", {
|
||||
{t("location.serviceZone.editAreasTitle", {
|
||||
zone: zone.name,
|
||||
})}
|
||||
</Heading>
|
||||
@@ -224,10 +224,10 @@ export function EditServiceZoneAreasForm({
|
||||
<div className="container flex items-center justify-between py-8 pr-1">
|
||||
<div>
|
||||
<Text weight="plus">
|
||||
{t("shipping.serviceZone.areas.title")}
|
||||
{t("location.serviceZone.areas.title")}
|
||||
</Text>
|
||||
<Text className="text-ui-fg-subtle mt-2">
|
||||
{t("shipping.serviceZone.areas.description")}
|
||||
{t("location.serviceZone.areas.description")}
|
||||
</Text>
|
||||
</div>
|
||||
<Button
|
||||
@@ -235,7 +235,7 @@ export function EditServiceZoneAreasForm({
|
||||
variant="secondary"
|
||||
type="button"
|
||||
>
|
||||
{t("shipping.serviceZone.areas.manage")}
|
||||
{t("location.serviceZone.areas.manage")}
|
||||
</Button>
|
||||
</div>
|
||||
{!!selectedCountries.length && (
|
||||
@@ -268,7 +268,7 @@ export function EditServiceZoneAreasForm({
|
||||
)}
|
||||
{showAreasError && (
|
||||
<Alert dismissible variant="error">
|
||||
{t("shipping.serviceZone.areas.error")}
|
||||
{t("location.serviceZone.areas.error")}
|
||||
</Alert>
|
||||
)}
|
||||
</SplitView.Content>
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+20
-20
@@ -1,12 +1,14 @@
|
||||
import { useForm } from "react-hook-form"
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import {
|
||||
ColumnDef,
|
||||
createColumnHelper,
|
||||
RowSelectionState,
|
||||
} from "@tanstack/react-table"
|
||||
import { useForm } from "react-hook-form"
|
||||
import * as zod from "zod"
|
||||
|
||||
import { XMarkMini } from "@medusajs/icons"
|
||||
import { FulfillmentSetDTO, HttpTypes } from "@medusajs/types"
|
||||
import {
|
||||
Alert,
|
||||
Badge,
|
||||
@@ -18,24 +20,22 @@ import {
|
||||
Text,
|
||||
toast,
|
||||
} from "@medusajs/ui"
|
||||
import { FulfillmentSetDTO, HttpTypes } from "@medusajs/types"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { XMarkMini } from "@medusajs/icons"
|
||||
|
||||
import { useEffect, useMemo, useState } from "react"
|
||||
import { Form } from "../../../../../components/common/form"
|
||||
import { SplitView } from "../../../../../components/layout/split-view"
|
||||
import {
|
||||
RouteFocusModal,
|
||||
useRouteModal,
|
||||
} from "../../../../../components/route-modal"
|
||||
import { Form } from "../../../../../components/common/form"
|
||||
import { SplitView } from "../../../../../components/layout/split-view"
|
||||
import { useCreateServiceZone } from "../../../../../hooks/api/stock-locations"
|
||||
import { useEffect, useMemo, useState } from "react"
|
||||
import { useCountryTableQuery } from "../../../../regions/common/hooks/use-country-table-query"
|
||||
import { useCountries } from "../../../../regions/common/hooks/use-countries"
|
||||
import { countries as staticCountries } from "../../../../../lib/countries"
|
||||
import { useDataTable } from "../../../../../hooks/use-data-table"
|
||||
import { useCountryTableColumns } from "../../../../regions/common/hooks/use-country-table-columns"
|
||||
import { DataTable } from "../../../../../components/table/data-table"
|
||||
import { useCreateServiceZone } from "../../../../../hooks/api/stock-locations"
|
||||
import { useDataTable } from "../../../../../hooks/use-data-table"
|
||||
import { countries as staticCountries } from "../../../../../lib/countries"
|
||||
import { useCountries } from "../../../../regions/common/hooks/use-countries"
|
||||
import { useCountryTableColumns } from "../../../../regions/common/hooks/use-country-table-columns"
|
||||
import { useCountryTableQuery } from "../../../../regions/common/hooks/use-country-table-query"
|
||||
|
||||
const PREFIX = "ac"
|
||||
const PAGE_SIZE = 50
|
||||
@@ -211,7 +211,7 @@ export function CreateServiceZoneForm({
|
||||
<SplitView.Content className="mx-auto max-w-[720px]">
|
||||
<div className="container w-fit px-1 py-8">
|
||||
<Heading className="mb-12 mt-8 text-2xl">
|
||||
{t("shipping.fulfillmentSet.create.title", {
|
||||
{t("location.fulfillmentSet.create.title", {
|
||||
fulfillmentSet: fulfillmentSet.name,
|
||||
})}
|
||||
</Heading>
|
||||
@@ -224,7 +224,7 @@ export function CreateServiceZoneForm({
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t("shipping.serviceZone.create.zoneName")}
|
||||
{t("location.serviceZone.create.zoneName")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<Input placeholder={t("fields.name")} {...field} />
|
||||
@@ -239,10 +239,10 @@ export function CreateServiceZoneForm({
|
||||
|
||||
<Alert>
|
||||
<Text weight="plus">
|
||||
{t("shipping.serviceZone.create.subtitle")}
|
||||
{t("location.serviceZone.create.subtitle")}
|
||||
</Text>
|
||||
<Text className="text-ui-fg-subtle mt-2">
|
||||
{t("shipping.serviceZone.create.description")}
|
||||
{t("location.serviceZone.create.description")}
|
||||
</Text>
|
||||
</Alert>
|
||||
|
||||
@@ -250,10 +250,10 @@ export function CreateServiceZoneForm({
|
||||
<div className="container flex items-center justify-between py-8 pr-1">
|
||||
<div>
|
||||
<Text weight="plus">
|
||||
{t("shipping.serviceZone.areas.title")}
|
||||
{t("location.serviceZone.areas.title")}
|
||||
</Text>
|
||||
<Text className="text-ui-fg-subtle mt-2">
|
||||
{t("shipping.serviceZone.areas.description")}
|
||||
{t("location.serviceZone.areas.description")}
|
||||
</Text>
|
||||
</div>
|
||||
<Button
|
||||
@@ -261,7 +261,7 @@ export function CreateServiceZoneForm({
|
||||
variant="secondary"
|
||||
type="button"
|
||||
>
|
||||
{t("shipping.serviceZone.areas.manage")}
|
||||
{t("location.serviceZone.areas.manage")}
|
||||
</Button>
|
||||
</div>
|
||||
{!!selectedCountries.length && (
|
||||
@@ -294,7 +294,7 @@ export function CreateServiceZoneForm({
|
||||
)}
|
||||
{showAreasError && (
|
||||
<Alert dismissible variant="error">
|
||||
{t("shipping.serviceZone.areas.error")}
|
||||
{t("location.serviceZone.areas.error")}
|
||||
</Alert>
|
||||
)}
|
||||
</SplitView.Content>
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+3
-3
@@ -1,8 +1,8 @@
|
||||
import { ServiceZoneDTO } from "@medusajs/types"
|
||||
import { Alert, Button, Input, Text, toast } from "@medusajs/ui"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import * as zod from "zod"
|
||||
import { ServiceZoneDTO } from "@medusajs/types"
|
||||
|
||||
import { Form } from "../../../../../components/common/form"
|
||||
import {
|
||||
@@ -88,10 +88,10 @@ export const EditServiceZoneForm = ({
|
||||
</div>
|
||||
<Alert>
|
||||
<Text weight="plus">
|
||||
{t("shipping.serviceZone.create.subtitle")}
|
||||
{t("location.serviceZone.create.subtitle")}
|
||||
</Text>
|
||||
<Text className="text-ui-fg-subtle mt-2">
|
||||
{t("shipping.serviceZone.create.description")}
|
||||
{t("location.serviceZone.create.description")}
|
||||
</Text>
|
||||
</Alert>
|
||||
</div>
|
||||
File renamed without changes.
File renamed without changes.
+2
-2
@@ -3,8 +3,8 @@ import { useTranslation } from "react-i18next"
|
||||
import { json, useParams } from "react-router-dom"
|
||||
|
||||
import { RouteDrawer } from "../../../components/route-modal"
|
||||
import { EditServiceZoneForm } from "./components/edit-region-form"
|
||||
import { useStockLocation } from "../../../hooks/api/stock-locations"
|
||||
import { EditServiceZoneForm } from "./components/edit-region-form"
|
||||
|
||||
export const ServiceZoneEdit = () => {
|
||||
const { t } = useTranslation()
|
||||
@@ -36,7 +36,7 @@ export const ServiceZoneEdit = () => {
|
||||
return (
|
||||
<RouteDrawer>
|
||||
<RouteDrawer.Header>
|
||||
<Heading>{t("shipping.serviceZone.edit.title")}</Heading>
|
||||
<Heading>{t("location.serviceZone.edit.title")}</Heading>
|
||||
</RouteDrawer.Header>
|
||||
{!isPending && zone && (
|
||||
<EditServiceZoneForm
|
||||
+12
-12
@@ -9,12 +9,12 @@ import {
|
||||
RouteDrawer,
|
||||
useRouteModal,
|
||||
} from "../../../../../components/route-modal"
|
||||
import { useShippingProfiles } from "../../../../../hooks/api/shipping-profiles"
|
||||
import { useUpdateShippingOptions } from "../../../../../hooks/api/shipping-options"
|
||||
import { useFulfillmentProviders } from "../../../../../hooks/api/fulfillment-providers"
|
||||
import { isOptionEnabledInStore } from "../../../../../lib/shipping-options"
|
||||
import { formatProvider } from "../../../../../lib/format-provider"
|
||||
import { useUpdateShippingOptions } from "../../../../../hooks/api/shipping-options"
|
||||
import { useShippingProfiles } from "../../../../../hooks/api/shipping-profiles"
|
||||
import { pick } from "../../../../../lib/common"
|
||||
import { formatProvider } from "../../../../../lib/format-provider"
|
||||
import { isOptionEnabledInStore } from "../../../../../lib/shipping-options"
|
||||
|
||||
enum ShippingAllocation {
|
||||
FlatRate = "flat",
|
||||
@@ -118,26 +118,26 @@ export const EditShippingOptionForm = ({
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t("shipping.shippingOptions.create.allocation")}
|
||||
{t("location.shippingOptions.create.allocation")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<RadioGroup {...field} onValueChange={field.onChange}>
|
||||
<RadioGroup.ChoiceBox
|
||||
className="flex-1"
|
||||
value={ShippingAllocation.FlatRate}
|
||||
label={t("shipping.shippingOptions.create.fixed")}
|
||||
label={t("location.shippingOptions.create.fixed")}
|
||||
description={t(
|
||||
"shipping.shippingOptions.create.fixedDescription"
|
||||
"location.shippingOptions.create.fixedDescription"
|
||||
)}
|
||||
/>
|
||||
<RadioGroup.ChoiceBox
|
||||
className="flex-1"
|
||||
value={ShippingAllocation.Calculated}
|
||||
label={t(
|
||||
"shipping.shippingOptions.create.calculated"
|
||||
"location.shippingOptions.create.calculated"
|
||||
)}
|
||||
description={t(
|
||||
"shipping.shippingOptions.create.calculatedDescription"
|
||||
"location.shippingOptions.create.calculatedDescription"
|
||||
)}
|
||||
/>
|
||||
</RadioGroup>
|
||||
@@ -173,7 +173,7 @@ export const EditShippingOptionForm = ({
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t("shipping.shippingOptions.create.profile")}
|
||||
{t("location.shippingOptions.create.profile")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<Select {...field} onValueChange={onChange}>
|
||||
@@ -203,7 +203,7 @@ export const EditShippingOptionForm = ({
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t("shipping.shippingOptions.edit.provider")}
|
||||
{t("location.shippingOptions.edit.provider")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<Select {...field} onValueChange={onChange}>
|
||||
@@ -236,7 +236,7 @@ export const EditShippingOptionForm = ({
|
||||
<Form.Item>
|
||||
<div className="flex items-center justify-between">
|
||||
<Form.Label>
|
||||
{t("shipping.shippingOptions.create.enable")}
|
||||
{t("location.shippingOptions.create.enable")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<Switch
|
||||
File renamed without changes.
File renamed without changes.
+2
-2
@@ -3,8 +3,8 @@ import { useTranslation } from "react-i18next"
|
||||
import { json, useParams, useSearchParams } from "react-router-dom"
|
||||
|
||||
import { RouteDrawer } from "../../../components/route-modal"
|
||||
import { EditShippingOptionForm } from "./components/edit-region-form"
|
||||
import { useShippingOptions } from "../../../hooks/api/shipping-options"
|
||||
import { EditShippingOptionForm } from "./components/edit-region-form"
|
||||
|
||||
export const ShippingOptionEdit = () => {
|
||||
const { t } = useTranslation()
|
||||
@@ -31,7 +31,7 @@ export const ShippingOptionEdit = () => {
|
||||
return (
|
||||
<RouteDrawer>
|
||||
<RouteDrawer.Header>
|
||||
<Heading>{t("shipping.shippingOptions.edit.title")}</Heading>
|
||||
<Heading>{t("location.shippingOptions.edit.title")}</Heading>
|
||||
</RouteDrawer.Header>
|
||||
{!isPending && shippingOption && (
|
||||
<EditShippingOptionForm
|
||||
+22
-22
@@ -1,8 +1,9 @@
|
||||
import { useForm } from "react-hook-form"
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import React, { useEffect } from "react"
|
||||
import { useForm } from "react-hook-form"
|
||||
import * as zod from "zod"
|
||||
|
||||
import { ServiceZoneDTO } from "@medusajs/types"
|
||||
import {
|
||||
Button,
|
||||
Heading,
|
||||
@@ -10,26 +11,25 @@ import {
|
||||
ProgressStatus,
|
||||
ProgressTabs,
|
||||
RadioGroup,
|
||||
Select,
|
||||
Switch,
|
||||
Text,
|
||||
clx,
|
||||
Select,
|
||||
} from "@medusajs/ui"
|
||||
import { ServiceZoneDTO } from "@medusajs/types"
|
||||
import { useTranslation } from "react-i18next"
|
||||
|
||||
import { Form } from "../../../../../components/common/form"
|
||||
import {
|
||||
RouteFocusModal,
|
||||
useRouteModal,
|
||||
} from "../../../../../components/route-modal"
|
||||
import { Form } from "../../../../../components/common/form"
|
||||
import { CreateShippingOptionsPricesForm } from "./create-shipping-options-prices-form"
|
||||
import { useFulfillmentProviders } from "../../../../../hooks/api/fulfillment-providers"
|
||||
import { useRegions } from "../../../../../hooks/api/regions"
|
||||
import { useCreateShippingOptions } from "../../../../../hooks/api/shipping-options"
|
||||
import { useShippingProfiles } from "../../../../../hooks/api/shipping-profiles"
|
||||
import { getDbAmount } from "../../../../../lib/money-amount-helpers"
|
||||
import { useFulfillmentProviders } from "../../../../../hooks/api/fulfillment-providers"
|
||||
import { formatProvider } from "../../../../../lib/format-provider"
|
||||
import { useRegions } from "../../../../../hooks/api/regions"
|
||||
import { getDbAmount } from "../../../../../lib/money-amount-helpers"
|
||||
import { CreateShippingOptionsPricesForm } from "./create-shipping-options-prices-form"
|
||||
|
||||
enum Tab {
|
||||
DETAILS = "details",
|
||||
@@ -230,7 +230,7 @@ export function CreateShippingOptionsForm({
|
||||
className="w-full max-w-[200px]"
|
||||
>
|
||||
<span className="w-full cursor-auto overflow-hidden text-ellipsis whitespace-nowrap">
|
||||
{t("shipping.shippingOptions.create.details")}
|
||||
{t("location.shippingOptions.create.details")}
|
||||
</span>
|
||||
</ProgressTabs.Trigger>
|
||||
{!isCalculatedPriceType && (
|
||||
@@ -241,7 +241,7 @@ export function CreateShippingOptionsForm({
|
||||
disabled={!canMoveToPricing}
|
||||
>
|
||||
<span className="w-full overflow-hidden text-ellipsis whitespace-nowrap">
|
||||
{t("shipping.shippingOptions.create.pricing")}
|
||||
{t("location.shippingOptions.create.pricing")}
|
||||
</span>
|
||||
</ProgressTabs.Trigger>
|
||||
)}
|
||||
@@ -286,7 +286,7 @@ export function CreateShippingOptionsForm({
|
||||
<div className="container mx-auto w-[720px] px-1 py-8">
|
||||
<Heading className="mb-12 mt-8 text-2xl">
|
||||
{t(
|
||||
`shipping.${
|
||||
`location.${
|
||||
isReturn ? "returnOptions" : "shippingOptions"
|
||||
}.create.title`,
|
||||
{
|
||||
@@ -298,10 +298,10 @@ export function CreateShippingOptionsForm({
|
||||
{!isReturn && (
|
||||
<div>
|
||||
<Text weight="plus">
|
||||
{t("shipping.shippingOptions.create.subtitle")}
|
||||
{t("location.shippingOptions.create.subtitle")}
|
||||
</Text>
|
||||
<Text className="text-ui-fg-subtle mb-8 mt-2">
|
||||
{t("shipping.shippingOptions.create.description")}
|
||||
{t("location.shippingOptions.create.description")}
|
||||
</Text>
|
||||
</div>
|
||||
)}
|
||||
@@ -313,7 +313,7 @@ export function CreateShippingOptionsForm({
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t("shipping.shippingOptions.create.allocation")}
|
||||
{t("location.shippingOptions.create.allocation")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<RadioGroup
|
||||
@@ -324,19 +324,19 @@ export function CreateShippingOptionsForm({
|
||||
<RadioGroup.ChoiceBox
|
||||
className="flex-1"
|
||||
value={ShippingAllocation.FlatRate}
|
||||
label={t("shipping.shippingOptions.create.fixed")}
|
||||
label={t("location.shippingOptions.create.fixed")}
|
||||
description={t(
|
||||
"shipping.shippingOptions.create.fixedDescription"
|
||||
"location.shippingOptions.create.fixedDescription"
|
||||
)}
|
||||
/>
|
||||
<RadioGroup.ChoiceBox
|
||||
className="flex-1"
|
||||
value={ShippingAllocation.Calculated}
|
||||
label={t(
|
||||
"shipping.shippingOptions.create.calculated"
|
||||
"location.shippingOptions.create.calculated"
|
||||
)}
|
||||
description={t(
|
||||
"shipping.shippingOptions.create.calculatedDescription"
|
||||
"location.shippingOptions.create.calculatedDescription"
|
||||
)}
|
||||
/>
|
||||
</RadioGroup>
|
||||
@@ -374,7 +374,7 @@ export function CreateShippingOptionsForm({
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t("shipping.shippingOptions.create.profile")}
|
||||
{t("location.shippingOptions.create.profile")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<Select {...field} onValueChange={onChange}>
|
||||
@@ -405,7 +405,7 @@ export function CreateShippingOptionsForm({
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t("shipping.shippingOptions.edit.provider")}
|
||||
{t("location.shippingOptions.edit.provider")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<Select {...field} onValueChange={onChange}>
|
||||
@@ -437,7 +437,7 @@ export function CreateShippingOptionsForm({
|
||||
<Form.Item>
|
||||
<div className="flex items-center justify-between">
|
||||
<Form.Label>
|
||||
{t("shipping.shippingOptions.create.enable")}
|
||||
{t("location.shippingOptions.create.enable")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<Switch
|
||||
@@ -449,7 +449,7 @@ export function CreateShippingOptionsForm({
|
||||
</div>
|
||||
<Form.Hint className="!mt-1">
|
||||
{t(
|
||||
"shipping.shippingOptions.create.enableDescription"
|
||||
"location.shippingOptions.create.enableDescription"
|
||||
)}
|
||||
</Form.Hint>
|
||||
<Form.ErrorMessage />
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+4
-4
@@ -11,8 +11,8 @@ import {
|
||||
Heading,
|
||||
StatusBadge,
|
||||
Text,
|
||||
toast,
|
||||
Tooltip,
|
||||
toast,
|
||||
usePrompt,
|
||||
} from "@medusajs/ui"
|
||||
import { format } from "date-fns"
|
||||
@@ -21,10 +21,10 @@ import { Link } from "react-router-dom"
|
||||
import { ActionMenu } from "../../../../../components/common/action-menu"
|
||||
import { Skeleton } from "../../../../../components/common/skeleton"
|
||||
import { Thumbnail } from "../../../../../components/common/thumbnail"
|
||||
import { useCancelFulfillment } from "../../../../../hooks/api/fulfillment"
|
||||
import { useStockLocation } from "../../../../../hooks/api/stock-locations"
|
||||
import { formatProvider } from "../../../../../lib/format-provider"
|
||||
import { getLocaleAmount } from "../../../../../lib/money-amount-helpers"
|
||||
import { useStockLocation } from "../../../../../hooks/api/stock-locations"
|
||||
import { useCancelFulfillment } from "../../../../../hooks/api/fulfillment"
|
||||
|
||||
type OrderFulfillmentSectionProps = {
|
||||
order: OrderDTO & { fulfillments: FulfillmentDTO[] }
|
||||
@@ -285,7 +285,7 @@ const Fulfillment = ({
|
||||
</Text>
|
||||
{stock_location ? (
|
||||
<Link
|
||||
to={`/settings/shipping/${stock_location.id}`}
|
||||
to={`/settings/locations/${stock_location.id}`}
|
||||
className="text-ui-fg-interactive hover:text-ui-fg-interactive-hover transition-fg"
|
||||
>
|
||||
<Text size="small" leading="compact">
|
||||
|
||||
@@ -6,6 +6,9 @@ import { RegionCountrySection } from "./components/region-country-section"
|
||||
import { RegionGeneralSection } from "./components/region-general-section"
|
||||
import { regionLoader } from "./loader"
|
||||
|
||||
import after from "virtual:medusa/widgets/region/details/after"
|
||||
import before from "virtual:medusa/widgets/region/details/before"
|
||||
|
||||
export const RegionDetail = () => {
|
||||
const initialData = useLoaderData() as Awaited<
|
||||
ReturnType<typeof regionLoader>
|
||||
@@ -36,8 +39,22 @@ export const RegionDetail = () => {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-y-2">
|
||||
{before.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component data={region} />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<RegionGeneralSection region={region} />
|
||||
<RegionCountrySection region={region} />
|
||||
{after.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component data={region} />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<JsonViewSection data={region} />
|
||||
<Outlet />
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,28 @@
|
||||
import { Outlet } from "react-router-dom"
|
||||
|
||||
import { RegionListTable } from "./components/region-list-table"
|
||||
|
||||
import after from "virtual:medusa/widgets/region/list/after"
|
||||
import before from "virtual:medusa/widgets/region/list/before"
|
||||
|
||||
export const RegionList = () => {
|
||||
return (
|
||||
<div className="flex flex-col gap-y-2">
|
||||
{before.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<RegionListTable />
|
||||
{after.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<Outlet />
|
||||
</div>
|
||||
)
|
||||
|
||||
+18
@@ -1,4 +1,5 @@
|
||||
import { useParams } from "react-router-dom"
|
||||
|
||||
import { JsonViewSection } from "../../../components/common/json-view-section"
|
||||
import {
|
||||
GeneralSectionSkeleton,
|
||||
@@ -7,6 +8,9 @@ import {
|
||||
import { useShippingProfile } from "../../../hooks/api/shipping-profiles"
|
||||
import { ShippingProfileGeneralSection } from "./components/shipping-profile-general-section"
|
||||
|
||||
import after from "virtual:medusa/widgets/shipping_profile/details/after"
|
||||
import before from "virtual:medusa/widgets/shipping_profile/details/before"
|
||||
|
||||
export const ShippingProfileDetail = () => {
|
||||
const { id } = useParams()
|
||||
|
||||
@@ -29,7 +33,21 @@ export const ShippingProfileDetail = () => {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-y-2">
|
||||
{before.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component data={shipping_profile} />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<ShippingProfileGeneralSection profile={shipping_profile} />
|
||||
{after.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component data={shipping_profile} />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<JsonViewSection data={shipping_profile} />
|
||||
</div>
|
||||
)
|
||||
|
||||
+18
@@ -1,10 +1,28 @@
|
||||
import { Outlet } from "react-router-dom"
|
||||
|
||||
import { ShippingProfileListTable } from "./components/shipping-profile-list-table"
|
||||
|
||||
import after from "virtual:medusa/widgets/shipping_profile/list/after"
|
||||
import before from "virtual:medusa/widgets/shipping_profile/list/before"
|
||||
|
||||
export const ShippingProfileList = () => {
|
||||
return (
|
||||
<div className="flex flex-col gap-y-2">
|
||||
{before.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<ShippingProfileListTable />
|
||||
{after.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<Outlet />
|
||||
</div>
|
||||
)
|
||||
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
import { Outlet, useLoaderData, useParams } from "react-router-dom"
|
||||
|
||||
import { JsonViewSection } from "../../../components/common/json-view-section"
|
||||
import { LocationGeneralSection } from "./components/location-general-section"
|
||||
import { useStockLocation } from "../../../hooks/api/stock-locations"
|
||||
import LocationsSalesChannelsSection from "./components/location-sales-channels-section/locations-sales-channels-section"
|
||||
import { locationLoader } from "./loader"
|
||||
|
||||
export const LocationDetails = () => {
|
||||
const initialData = useLoaderData() as Awaited<
|
||||
ReturnType<typeof locationLoader>
|
||||
>
|
||||
|
||||
const { location_id } = useParams()
|
||||
const {
|
||||
stock_location: location,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useStockLocation(
|
||||
location_id!,
|
||||
{
|
||||
fields:
|
||||
"name,*sales_channels,address.city,address.country_code,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",
|
||||
},
|
||||
{
|
||||
initialData,
|
||||
}
|
||||
)
|
||||
|
||||
// TODO: Move to loading.tsx and set as Suspense fallback for the route
|
||||
if (isLoading || !location) {
|
||||
return <div>Loading...</div>
|
||||
}
|
||||
|
||||
if (isError) {
|
||||
throw error
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-x-4 xl:flex-row xl:items-start">
|
||||
<div className="flex w-full flex-col gap-y-2">
|
||||
<LocationGeneralSection location={location} />
|
||||
<div className="flex w-full flex-col gap-y-2 xl:hidden">
|
||||
<LocationsSalesChannelsSection location={location} />
|
||||
</div>
|
||||
<JsonViewSection data={location} />
|
||||
</div>
|
||||
<div className="hidden w-full max-w-[400px] flex-col gap-y-2 xl:flex">
|
||||
<LocationsSalesChannelsSection location={location} />
|
||||
</div>
|
||||
<Outlet />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import { Button, Container, Heading, Text } from "@medusajs/ui"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { Link, Outlet, useLoaderData } from "react-router-dom"
|
||||
|
||||
import { shippingListLoader } from "./loader"
|
||||
import { useStockLocations } from "../../../hooks/api/stock-locations"
|
||||
import Location from "./components/location/location"
|
||||
import { locationListFields } from "./const"
|
||||
|
||||
export function LocationList() {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const initialData = useLoaderData() as Awaited<
|
||||
ReturnType<typeof shippingListLoader>
|
||||
>
|
||||
|
||||
let { stock_locations: stockLocations = [], isPending } = useStockLocations(
|
||||
{
|
||||
fields: locationListFields,
|
||||
},
|
||||
{ initialData }
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="py-4">
|
||||
<Container className="mb-4 flex h-fit items-center justify-between p-8">
|
||||
<div>
|
||||
<Heading className="mb-2">{t("shipping.title")}</Heading>
|
||||
<Text className="text-ui-fg-subtle txt-small">
|
||||
{t("shipping.description")}
|
||||
</Text>
|
||||
</div>
|
||||
<Button size="small" variant="secondary" asChild>
|
||||
<Link to="create">{t("shipping.createLocation")}</Link>
|
||||
</Button>
|
||||
</Container>
|
||||
<div className="flex flex-col gap-4 lg:col-span-2">
|
||||
{stockLocations.map((location) => (
|
||||
<Location key={location.id} location={location} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<Outlet />
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user