feat(dashboard): Pickup option changes (#11306)
**What** - update the create and edit shipping option flows to support pickup (shipping) option - modify "mark as delivered" for pickup case --- CLOSES CMRC-906 CMRC-907
This commit is contained in:
@@ -4806,6 +4806,9 @@
|
||||
"markAsShipped": {
|
||||
"type": "string"
|
||||
},
|
||||
"markAsPickedUp": {
|
||||
"type": "string"
|
||||
},
|
||||
"markAsDelivered": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -4915,13 +4918,17 @@
|
||||
},
|
||||
"fulfillmentDelivered": {
|
||||
"type": "string"
|
||||
},
|
||||
"fulfillmentPickedUp": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"created",
|
||||
"canceled",
|
||||
"fulfillmentShipped",
|
||||
"fulfillmentDelivered"
|
||||
"fulfillmentDelivered",
|
||||
"fulfillmentPickedUp"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
@@ -4952,6 +4959,7 @@
|
||||
"available",
|
||||
"inStock",
|
||||
"markAsShipped",
|
||||
"markAsPickedUp",
|
||||
"markAsDelivered",
|
||||
"itemsToFulfillDesc",
|
||||
"locationDescription",
|
||||
@@ -5754,6 +5762,23 @@
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"pickupOptions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"edit": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"header": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["header"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["edit"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"shippingOptions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -5779,6 +5804,25 @@
|
||||
"required": ["header", "hint", "label", "successToast"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"pickup": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"header": {
|
||||
"type": "string"
|
||||
},
|
||||
"hint": {
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"successToast": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["header", "hint", "label", "successToast"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"returns": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -5815,7 +5859,7 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["shipping", "returns", "tabs", "action"],
|
||||
"required": ["shipping", "pickup", "returns", "tabs", "action"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"delete": {
|
||||
@@ -5996,6 +6040,12 @@
|
||||
"shipping_other": {
|
||||
"type": "string"
|
||||
},
|
||||
"pickup_one": {
|
||||
"type": "string"
|
||||
},
|
||||
"pickup_other": {
|
||||
"type": "string"
|
||||
},
|
||||
"returns_one": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -6006,6 +6056,8 @@
|
||||
"required": [
|
||||
"shipping_one",
|
||||
"shipping_other",
|
||||
"pickup_one",
|
||||
"pickup_other",
|
||||
"returns_one",
|
||||
"returns_other"
|
||||
],
|
||||
@@ -6201,6 +6253,7 @@
|
||||
"fulfillmentSets",
|
||||
"sidebar",
|
||||
"salesChannels",
|
||||
"pickupOptions",
|
||||
"shippingOptions",
|
||||
"serviceZones"
|
||||
],
|
||||
|
||||
@@ -1281,6 +1281,7 @@
|
||||
"available": "Available",
|
||||
"inStock": "In stock",
|
||||
"markAsShipped": "Mark as shipped",
|
||||
"markAsPickedUp": "Mark as picked up",
|
||||
"markAsDelivered": "Mark as delivered",
|
||||
"itemsToFulfillDesc": "Choose items and quantities to fulfill",
|
||||
"locationDescription": "Choose which location you want to fulfill items from.",
|
||||
@@ -1310,7 +1311,8 @@
|
||||
"created": "Fulfillment created successfully",
|
||||
"canceled": "Fulfillment successfully canceled",
|
||||
"fulfillmentShipped": "Cannot cancel an already shipped fulfillment",
|
||||
"fulfillmentDelivered": "Fulfillment marked as delivered successfully"
|
||||
"fulfillmentDelivered": "Fulfillment marked as delivered successfully",
|
||||
"fulfillmentPickedUp": "Fulfillment marked as picked up successfully"
|
||||
},
|
||||
"trackingLabel": "Tracking",
|
||||
"shippingFromLabel": "Shipping from",
|
||||
@@ -1520,6 +1522,11 @@
|
||||
"action": "Connect sales channels",
|
||||
"successToast": "Sales channels were successfully updated."
|
||||
},
|
||||
"pickupOptions": {
|
||||
"edit": {
|
||||
"header": "Edit Pickup Option"
|
||||
}
|
||||
},
|
||||
"shippingOptions": {
|
||||
"create": {
|
||||
"shipping": {
|
||||
@@ -1528,6 +1535,12 @@
|
||||
"label": "Shipping options",
|
||||
"successToast": "Shipping option {{name}} was successfully created."
|
||||
},
|
||||
"pickup": {
|
||||
"header": "Create Pickup Option for {{zone}}",
|
||||
"hint": "Create a new pickup option to define how products are picked up from this location.",
|
||||
"label": "Pickup options",
|
||||
"successToast": "Pickup option {{name}} was successfully created."
|
||||
},
|
||||
"returns": {
|
||||
"header": "Create a Return Option for {{zone}}",
|
||||
"hint": "Create a new return option to define how products are returned to this location.",
|
||||
@@ -1591,6 +1604,8 @@
|
||||
"count": {
|
||||
"shipping_one": "{{count}} shipping option",
|
||||
"shipping_other": "{{count}} shipping options",
|
||||
"pickup_one": "{{count}} pickup option",
|
||||
"pickup_other": "{{count}} pickup options",
|
||||
"returns_one": "{{count}} return option",
|
||||
"returns_other": "{{count}} return options"
|
||||
},
|
||||
|
||||
@@ -195,12 +195,14 @@ type ServiceZoneOptionsProps = {
|
||||
zone: HttpTypes.AdminServiceZone
|
||||
locationId: string
|
||||
fulfillmentSetId: string
|
||||
type: FulfillmentSetType
|
||||
}
|
||||
|
||||
function ServiceZoneOptions({
|
||||
zone,
|
||||
locationId,
|
||||
fulfillmentSetId,
|
||||
type,
|
||||
}: ServiceZoneOptionsProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
@@ -216,7 +218,7 @@ function ServiceZoneOptions({
|
||||
<div className="flex flex-col gap-y-4 px-6 py-4">
|
||||
<div className="item-center flex justify-between">
|
||||
<span className="text-ui-fg-subtle txt-small self-center font-medium">
|
||||
{t("stockLocations.shippingOptions.create.shipping.label")}
|
||||
{t(`stockLocations.shippingOptions.create.${type}.label`)}
|
||||
</span>
|
||||
<LinkButton
|
||||
to={`/settings/locations/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${zone.id}/shipping-option/create`}
|
||||
@@ -274,9 +276,15 @@ type ServiceZoneProps = {
|
||||
zone: HttpTypes.AdminServiceZone
|
||||
locationId: string
|
||||
fulfillmentSetId: string
|
||||
type: FulfillmentSetType
|
||||
}
|
||||
|
||||
function ServiceZone({ zone, locationId, fulfillmentSetId }: ServiceZoneProps) {
|
||||
function ServiceZone({
|
||||
zone,
|
||||
locationId,
|
||||
fulfillmentSetId,
|
||||
type,
|
||||
}: ServiceZoneProps) {
|
||||
const { t } = useTranslation()
|
||||
const prompt = usePrompt()
|
||||
const [open, setOpen] = useState(true)
|
||||
@@ -368,7 +376,7 @@ function ServiceZone({ zone, locationId, fulfillmentSetId }: ServiceZoneProps) {
|
||||
/>
|
||||
<span>·</span>
|
||||
<Text className="text-ui-fg-subtle txt-small">
|
||||
{t("stockLocations.shippingOptions.fields.count.shipping", {
|
||||
{t(`stockLocations.shippingOptions.fields.count.${type}`, {
|
||||
count: shippingOptionsCount,
|
||||
})}
|
||||
</Text>
|
||||
@@ -427,6 +435,7 @@ function ServiceZone({ zone, locationId, fulfillmentSetId }: ServiceZoneProps) {
|
||||
<ServiceZoneOptions
|
||||
fulfillmentSetId={fulfillmentSetId}
|
||||
locationId={locationId}
|
||||
type={type}
|
||||
zone={zone}
|
||||
/>
|
||||
)}
|
||||
@@ -570,6 +579,7 @@ function FulfillmentSet(props: FulfillmentSetProps) {
|
||||
{fulfillmentSet?.service_zones.map((zone) => (
|
||||
<ServiceZone
|
||||
zone={zone}
|
||||
type={type}
|
||||
key={zone.id}
|
||||
locationId={locationId}
|
||||
fulfillmentSetId={fulfillmentSet.id}
|
||||
|
||||
@@ -10,7 +10,10 @@ import { Combobox } from "../../../../../components/inputs/combobox"
|
||||
import { useComboboxData } from "../../../../../hooks/use-combobox-data"
|
||||
import { sdk } from "../../../../../lib/client"
|
||||
import { formatProvider } from "../../../../../lib/format-provider"
|
||||
import { ShippingOptionPriceType } from "../../../common/constants"
|
||||
import {
|
||||
FulfillmentSetType,
|
||||
ShippingOptionPriceType,
|
||||
} from "../../../common/constants"
|
||||
import { CreateShippingOptionSchema } from "./schema"
|
||||
|
||||
type CreateShippingOptionDetailsFormProps = {
|
||||
@@ -20,6 +23,7 @@ type CreateShippingOptionDetailsFormProps = {
|
||||
locationId: string
|
||||
fulfillmentProviderOptions: HttpTypes.AdminFulfillmentProviderOption[]
|
||||
selectedProviderId?: string
|
||||
type: FulfillmentSetType
|
||||
}
|
||||
|
||||
export const CreateShippingOptionDetailsForm = ({
|
||||
@@ -29,9 +33,12 @@ export const CreateShippingOptionDetailsForm = ({
|
||||
locationId,
|
||||
fulfillmentProviderOptions,
|
||||
selectedProviderId,
|
||||
type,
|
||||
}: CreateShippingOptionDetailsFormProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const isPickup = type === FulfillmentSetType.Pickup
|
||||
|
||||
const shippingProfiles = useComboboxData({
|
||||
queryFn: (params) => sdk.admin.shippingProfile.list(params),
|
||||
queryKey: ["shipping_profiles"],
|
||||
@@ -63,7 +70,7 @@ export const CreateShippingOptionDetailsForm = ({
|
||||
<Heading>
|
||||
{t(
|
||||
`stockLocations.shippingOptions.create.${
|
||||
isReturn ? "returns" : "shipping"
|
||||
isPickup ? "pickup" : isReturn ? "returns" : "shipping"
|
||||
}.header`,
|
||||
{
|
||||
zone: zone.name,
|
||||
@@ -73,54 +80,56 @@ export const CreateShippingOptionDetailsForm = ({
|
||||
<Text size="small" className="text-ui-fg-subtle">
|
||||
{t(
|
||||
`stockLocations.shippingOptions.create.${
|
||||
isReturn ? "returns" : "shipping"
|
||||
isReturn ? "returns" : isPickup ? "pickup" : "shipping"
|
||||
}.hint`
|
||||
)}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="price_type"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t("stockLocations.shippingOptions.fields.priceType.label")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<RadioGroup
|
||||
className="grid grid-cols-1 gap-4 md:grid-cols-2"
|
||||
{...field}
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<RadioGroup.ChoiceBox
|
||||
className="flex-1"
|
||||
value={ShippingOptionPriceType.FlatRate}
|
||||
label={t(
|
||||
"stockLocations.shippingOptions.fields.priceType.options.fixed.label"
|
||||
)}
|
||||
description={t(
|
||||
"stockLocations.shippingOptions.fields.priceType.options.fixed.hint"
|
||||
)}
|
||||
/>
|
||||
<RadioGroup.ChoiceBox
|
||||
className="flex-1"
|
||||
value={ShippingOptionPriceType.Calculated}
|
||||
label={t(
|
||||
"stockLocations.shippingOptions.fields.priceType.options.calculated.label"
|
||||
)}
|
||||
description={t(
|
||||
"stockLocations.shippingOptions.fields.priceType.options.calculated.hint"
|
||||
)}
|
||||
/>
|
||||
</RadioGroup>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
{!isPickup && (
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="price_type"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t("stockLocations.shippingOptions.fields.priceType.label")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<RadioGroup
|
||||
className="grid grid-cols-1 gap-4 md:grid-cols-2"
|
||||
{...field}
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<RadioGroup.ChoiceBox
|
||||
className="flex-1"
|
||||
value={ShippingOptionPriceType.FlatRate}
|
||||
label={t(
|
||||
"stockLocations.shippingOptions.fields.priceType.options.fixed.label"
|
||||
)}
|
||||
description={t(
|
||||
"stockLocations.shippingOptions.fields.priceType.options.fixed.hint"
|
||||
)}
|
||||
/>
|
||||
<RadioGroup.ChoiceBox
|
||||
className="flex-1"
|
||||
value={ShippingOptionPriceType.Calculated}
|
||||
label={t(
|
||||
"stockLocations.shippingOptions.fields.priceType.options.calculated.label"
|
||||
)}
|
||||
description={t(
|
||||
"stockLocations.shippingOptions.fields.priceType.options.calculated.hint"
|
||||
)}
|
||||
/>
|
||||
</RadioGroup>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<Form.Field
|
||||
@@ -238,16 +247,21 @@ export const CreateShippingOptionDetailsForm = ({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
<SwitchBox
|
||||
control={form.control}
|
||||
name="enabled_in_store"
|
||||
label={t("stockLocations.shippingOptions.fields.enableInStore.label")}
|
||||
description={t(
|
||||
"stockLocations.shippingOptions.fields.enableInStore.hint"
|
||||
)}
|
||||
/>
|
||||
{!isPickup && (
|
||||
<>
|
||||
<Divider />
|
||||
<SwitchBox
|
||||
control={form.control}
|
||||
name="enabled_in_store"
|
||||
label={t(
|
||||
"stockLocations.shippingOptions.fields.enableInStore.label"
|
||||
)}
|
||||
description={t(
|
||||
"stockLocations.shippingOptions.fields.enableInStore.hint"
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -12,7 +12,10 @@ import {
|
||||
import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
|
||||
import { useCreateShippingOptions } from "../../../../../hooks/api/shipping-options"
|
||||
import { castNumber } from "../../../../../lib/cast-number"
|
||||
import { ShippingOptionPriceType } from "../../../common/constants"
|
||||
import {
|
||||
FulfillmentSetType,
|
||||
ShippingOptionPriceType,
|
||||
} from "../../../common/constants"
|
||||
import { buildShippingOptionPriceRules } from "../../../common/utils/price-rule-helpers"
|
||||
import { CreateShippingOptionDetailsForm } from "./create-shipping-option-details-form"
|
||||
import { CreateShippingOptionsPricesForm } from "./create-shipping-options-prices-form"
|
||||
@@ -31,12 +34,14 @@ type CreateShippingOptionFormProps = {
|
||||
zone: HttpTypes.AdminServiceZone
|
||||
locationId: string
|
||||
isReturn?: boolean
|
||||
type: FulfillmentSetType
|
||||
}
|
||||
|
||||
export function CreateShippingOptionsForm({
|
||||
zone,
|
||||
isReturn,
|
||||
locationId,
|
||||
type,
|
||||
}: CreateShippingOptionFormProps) {
|
||||
const [activeTab, setActiveTab] = useState<Tab>(Tab.DETAILS)
|
||||
const [validDetails, setValidDetails] = useState(false)
|
||||
@@ -309,13 +314,14 @@ export function CreateShippingOptionsForm({
|
||||
form={form}
|
||||
zone={zone}
|
||||
isReturn={isReturn}
|
||||
type={type}
|
||||
locationId={locationId}
|
||||
fulfillmentProviderOptions={fulfillmentProviderOptions || []}
|
||||
selectedProviderId={selectedProviderId}
|
||||
/>
|
||||
</ProgressTabs.Content>
|
||||
<ProgressTabs.Content value={Tab.PRICING} className="size-full">
|
||||
<CreateShippingOptionsPricesForm form={form} />
|
||||
<CreateShippingOptionsPricesForm form={form} type={type} />
|
||||
</ProgressTabs.Content>
|
||||
</RouteFocusModal.Body>
|
||||
<RouteFocusModal.Footer>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useMemo, useState } from "react"
|
||||
import { useEffect, useMemo, useState } from "react"
|
||||
import { UseFormReturn, useWatch } from "react-hook-form"
|
||||
|
||||
import { DataGrid } from "../../../../../components/data-grid"
|
||||
@@ -12,18 +12,24 @@ import { useRegions } from "../../../../../hooks/api/regions"
|
||||
import { useStore } from "../../../../../hooks/api/store"
|
||||
import { ConditionalPriceForm } from "../../../common/components/conditional-price-form"
|
||||
import { ShippingOptionPriceProvider } from "../../../common/components/shipping-option-price-provider"
|
||||
import { CONDITIONAL_PRICES_STACKED_MODAL_ID } from "../../../common/constants"
|
||||
import {
|
||||
FulfillmentSetType,
|
||||
CONDITIONAL_PRICES_STACKED_MODAL_ID,
|
||||
} from "../../../common/constants"
|
||||
import { useShippingOptionPriceColumns } from "../../../common/hooks/use-shipping-option-price-columns"
|
||||
import { ConditionalPriceInfo } from "../../../common/types"
|
||||
import { CreateShippingOptionSchema } from "./schema"
|
||||
|
||||
type PricingPricesFormProps = {
|
||||
form: UseFormReturn<CreateShippingOptionSchema>
|
||||
type: FulfillmentSetType
|
||||
}
|
||||
|
||||
export const CreateShippingOptionsPricesForm = ({
|
||||
form,
|
||||
type,
|
||||
}: PricingPricesFormProps) => {
|
||||
const isPickup = type === FulfillmentSetType.Pickup
|
||||
const { getIsOpen, setIsOpen } = useStackedModal()
|
||||
const [selectedPrice, setSelectedPrice] =
|
||||
useState<ConditionalPriceInfo | null>(null)
|
||||
@@ -80,6 +86,25 @@ export const CreateShippingOptionsPricesForm = ({
|
||||
[currencies, regions]
|
||||
)
|
||||
|
||||
/**
|
||||
* Prefill prices with 0 if createing a pickup (shipping) option
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (!isLoading && isPickup) {
|
||||
if (currencies.length > 0) {
|
||||
currencies.forEach((currency) => {
|
||||
form.setValue(`currency_prices.${currency}`, "0")
|
||||
})
|
||||
}
|
||||
|
||||
if (regions.length > 0) {
|
||||
regions.forEach((region) => {
|
||||
form.setValue(`region_prices.${region.id}`, "0")
|
||||
})
|
||||
}
|
||||
}
|
||||
}, [isLoading, isPickup])
|
||||
|
||||
if (isStoreError) {
|
||||
throw storeError
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { RouteFocusModal } from "../../../components/modals"
|
||||
import { useStockLocation } from "../../../hooks/api/stock-locations"
|
||||
import { CreateShippingOptionsForm } from "./components/create-shipping-options-form"
|
||||
import { LOC_CREATE_SHIPPING_OPTION_FIELDS } from "./constants"
|
||||
import { FulfillmentSetType } from "../common/constants"
|
||||
|
||||
export function LocationServiceZoneShippingOptionCreate() {
|
||||
const { location_id, fset_id, zone_id } = useParams()
|
||||
@@ -15,9 +16,18 @@ export function LocationServiceZoneShippingOptionCreate() {
|
||||
fields: LOC_CREATE_SHIPPING_OPTION_FIELDS,
|
||||
})
|
||||
|
||||
const zone = stock_location?.fulfillment_sets
|
||||
?.find((f) => f.id === fset_id)
|
||||
?.service_zones?.find((z) => z.id === zone_id)
|
||||
const fulfillmentSet = stock_location?.fulfillment_sets?.find(
|
||||
(f) => f.id === fset_id
|
||||
)
|
||||
|
||||
if (!isPending && !isFetching && !fulfillmentSet) {
|
||||
throw json(
|
||||
{ message: `Fulfillment set with ID ${fset_id} was not found` },
|
||||
404
|
||||
)
|
||||
}
|
||||
|
||||
const zone = fulfillmentSet?.service_zones?.find((z) => z.id === zone_id)
|
||||
|
||||
if (!isPending && !isFetching && !zone) {
|
||||
throw json(
|
||||
@@ -37,6 +47,7 @@ export function LocationServiceZoneShippingOptionCreate() {
|
||||
zone={zone}
|
||||
isReturn={isReturn}
|
||||
locationId={location_id!}
|
||||
type={fulfillmentSet!.type as FulfillmentSetType}
|
||||
/>
|
||||
)}
|
||||
</RouteFocusModal>
|
||||
|
||||
@@ -15,11 +15,15 @@ import { useComboboxData } from "../../../../../hooks/use-combobox-data"
|
||||
import { sdk } from "../../../../../lib/client"
|
||||
import { pick } from "../../../../../lib/common"
|
||||
import { isOptionEnabledInStore } from "../../../../../lib/shipping-options"
|
||||
import { ShippingOptionPriceType } from "../../../common/constants"
|
||||
import {
|
||||
FulfillmentSetType,
|
||||
ShippingOptionPriceType,
|
||||
} from "../../../common/constants"
|
||||
|
||||
type EditShippingOptionFormProps = {
|
||||
locationId: string
|
||||
shippingOption: HttpTypes.AdminShippingOption
|
||||
type: FulfillmentSetType
|
||||
}
|
||||
|
||||
const EditShippingOptionSchema = zod.object({
|
||||
@@ -32,10 +36,13 @@ const EditShippingOptionSchema = zod.object({
|
||||
export const EditShippingOptionForm = ({
|
||||
locationId,
|
||||
shippingOption,
|
||||
type,
|
||||
}: EditShippingOptionFormProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { handleSuccess } = useRouteModal()
|
||||
|
||||
const isPickup = type === FulfillmentSetType.Pickup
|
||||
|
||||
const shippingProfiles = useComboboxData({
|
||||
queryFn: (params) => sdk.admin.shippingProfile.list(params),
|
||||
queryKey: ["shipping_profiles"],
|
||||
@@ -108,46 +115,48 @@ export const EditShippingOptionForm = ({
|
||||
<RouteDrawer.Body>
|
||||
<div className="flex flex-col gap-y-8">
|
||||
<div className="flex flex-col gap-y-8">
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="price_type"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t(
|
||||
"stockLocations.shippingOptions.fields.priceType.label"
|
||||
)}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<RadioGroup {...field} onValueChange={field.onChange}>
|
||||
<RadioGroup.ChoiceBox
|
||||
className="flex-1"
|
||||
value={ShippingOptionPriceType.FlatRate}
|
||||
label={t(
|
||||
"stockLocations.shippingOptions.fields.priceType.options.fixed.label"
|
||||
)}
|
||||
description={t(
|
||||
"stockLocations.shippingOptions.fields.priceType.options.fixed.hint"
|
||||
)}
|
||||
/>
|
||||
<RadioGroup.ChoiceBox
|
||||
className="flex-1"
|
||||
value={ShippingOptionPriceType.Calculated}
|
||||
label={t(
|
||||
"stockLocations.shippingOptions.fields.priceType.options.calculated.label"
|
||||
)}
|
||||
description={t(
|
||||
"stockLocations.shippingOptions.fields.priceType.options.calculated.hint"
|
||||
)}
|
||||
/>
|
||||
</RadioGroup>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
{!isPickup && (
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="price_type"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t(
|
||||
"stockLocations.shippingOptions.fields.priceType.label"
|
||||
)}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<RadioGroup {...field} onValueChange={field.onChange}>
|
||||
<RadioGroup.ChoiceBox
|
||||
className="flex-1"
|
||||
value={ShippingOptionPriceType.FlatRate}
|
||||
label={t(
|
||||
"stockLocations.shippingOptions.fields.priceType.options.fixed.label"
|
||||
)}
|
||||
description={t(
|
||||
"stockLocations.shippingOptions.fields.priceType.options.fixed.hint"
|
||||
)}
|
||||
/>
|
||||
<RadioGroup.ChoiceBox
|
||||
className="flex-1"
|
||||
value={ShippingOptionPriceType.Calculated}
|
||||
label={t(
|
||||
"stockLocations.shippingOptions.fields.priceType.options.calculated.label"
|
||||
)}
|
||||
description={t(
|
||||
"stockLocations.shippingOptions.fields.priceType.options.calculated.hint"
|
||||
)}
|
||||
/>
|
||||
</RadioGroup>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="grid gap-y-4">
|
||||
<Form.Field
|
||||
@@ -193,18 +202,21 @@ export const EditShippingOptionForm = ({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
<SwitchBox
|
||||
control={form.control}
|
||||
name="enabled_in_store"
|
||||
label={t(
|
||||
"stockLocations.shippingOptions.fields.enableInStore.label"
|
||||
)}
|
||||
description={t(
|
||||
"stockLocations.shippingOptions.fields.enableInStore.hint"
|
||||
)}
|
||||
/>
|
||||
{!isPickup && (
|
||||
<>
|
||||
<Divider />
|
||||
<SwitchBox
|
||||
control={form.control}
|
||||
name="enabled_in_store"
|
||||
label={t(
|
||||
"stockLocations.shippingOptions.fields.enableInStore.label"
|
||||
)}
|
||||
description={t(
|
||||
"stockLocations.shippingOptions.fields.enableInStore.hint"
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</RouteDrawer.Body>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { json, useParams } from "react-router-dom"
|
||||
import { RouteDrawer } from "../../../components/modals"
|
||||
import { useShippingOptions } from "../../../hooks/api/shipping-options"
|
||||
import { EditShippingOptionForm } from "./components/edit-region-form"
|
||||
import { FulfillmentSetType } from "../common/constants"
|
||||
|
||||
export const LocationServiceZoneShippingOptionEdit = () => {
|
||||
const { t } = useTranslation()
|
||||
@@ -14,6 +15,7 @@ export const LocationServiceZoneShippingOptionEdit = () => {
|
||||
const { shipping_options, isPending, isFetching, isError, error } =
|
||||
useShippingOptions({
|
||||
id: so_id,
|
||||
fields: "+service_zone.fulfillment_set.type",
|
||||
})
|
||||
|
||||
const shippingOption = shipping_options?.find((so) => so.id === so_id)
|
||||
@@ -29,15 +31,27 @@ export const LocationServiceZoneShippingOptionEdit = () => {
|
||||
throw error
|
||||
}
|
||||
|
||||
const isPickup =
|
||||
shippingOption?.service_zone.fulfillment_set.type ===
|
||||
FulfillmentSetType.Pickup
|
||||
|
||||
return (
|
||||
<RouteDrawer>
|
||||
<RouteDrawer.Header>
|
||||
<Heading>{t("stockLocations.shippingOptions.edit.header")}</Heading>
|
||||
<Heading>
|
||||
{t(
|
||||
`stockLocations.${isPickup ? "pickupOptions" : "shippingOptions"}.edit.header`
|
||||
)}
|
||||
</Heading>
|
||||
</RouteDrawer.Header>
|
||||
{shippingOption && (
|
||||
<EditShippingOptionForm
|
||||
shippingOption={shippingOption}
|
||||
locationId={location_id!}
|
||||
type={
|
||||
shippingOption.service_zone.fulfillment_set
|
||||
.type as FulfillmentSetType
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</RouteDrawer>
|
||||
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
import { useStockLocation } from "../../../../../hooks/api/stock-locations"
|
||||
import { formatProvider } from "../../../../../lib/format-provider"
|
||||
import { getLocaleAmount } from "../../../../../lib/money-amount-helpers"
|
||||
import { FulfillmentSetType } from "../../../../locations/common/constants"
|
||||
|
||||
type OrderFulfillmentSectionProps = {
|
||||
order: AdminOrder
|
||||
@@ -213,6 +214,10 @@ const Fulfillment = ({
|
||||
|
||||
const showLocation = !!fulfillment.location_id
|
||||
|
||||
const isPickUpFulfillment =
|
||||
fulfillment.shipping_option?.service_zone.fulfillment_set.type ===
|
||||
FulfillmentSetType.Pickup
|
||||
|
||||
const { stock_location, isError, error } = useStockLocation(
|
||||
fulfillment.location_id!,
|
||||
undefined,
|
||||
@@ -222,7 +227,9 @@ const Fulfillment = ({
|
||||
)
|
||||
|
||||
let statusText = fulfillment.requires_shipping
|
||||
? "Awaiting shipping"
|
||||
? isPickUpFulfillment
|
||||
? "Awaiting pickup"
|
||||
: "Awaiting shipping"
|
||||
: "Awaiting delivery"
|
||||
let statusColor: "blue" | "green" | "red" = "blue"
|
||||
let statusTimestamp = fulfillment.created_at
|
||||
@@ -251,7 +258,9 @@ const Fulfillment = ({
|
||||
!fulfillment.canceled_at &&
|
||||
!fulfillment.shipped_at &&
|
||||
!fulfillment.delivered_at &&
|
||||
fulfillment.requires_shipping
|
||||
fulfillment.requires_shipping &&
|
||||
!isPickUpFulfillment
|
||||
|
||||
const showDeliveryButton =
|
||||
!fulfillment.canceled_at && !fulfillment.delivered_at
|
||||
|
||||
@@ -267,7 +276,13 @@ const Fulfillment = ({
|
||||
if (res) {
|
||||
await markAsDelivered(undefined, {
|
||||
onSuccess: () => {
|
||||
toast.success(t("orders.fulfillment.toast.fulfillmentDelivered"))
|
||||
toast.success(
|
||||
t(
|
||||
isPickUpFulfillment
|
||||
? "orders.fulfillment.toast.fulfillmentPickedUp"
|
||||
: "orders.fulfillment.toast.fulfillmentDelivered"
|
||||
)
|
||||
)
|
||||
},
|
||||
onError: (e) => {
|
||||
toast.error(e.message)
|
||||
@@ -431,7 +446,11 @@ const Fulfillment = ({
|
||||
<div className="bg-ui-bg-subtle flex items-center justify-end gap-x-2 rounded-b-xl px-4 py-4">
|
||||
{showDeliveryButton && (
|
||||
<Button onClick={handleMarkAsDelivered} variant="secondary">
|
||||
{t("orders.fulfillment.markAsDelivered")}
|
||||
{t(
|
||||
isPickUpFulfillment
|
||||
? "orders.fulfillment.markAsPickedUp"
|
||||
: "orders.fulfillment.markAsDelivered"
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ const DEFAULT_RELATIONS = [
|
||||
"*promotion",
|
||||
"*shipping_methods",
|
||||
"*fulfillments",
|
||||
"+fulfillments.shipping_option.service_zone.fulfillment_set.type",
|
||||
"*fulfillments.items",
|
||||
"*fulfillments.labels",
|
||||
"*fulfillments.labels",
|
||||
|
||||
Reference in New Issue
Block a user