import { ClaimReason, Order, StockLocationDTO } from "@medusajs/medusa" import { useAdminStockLocations, useAdminCreateClaim } from "medusa-react" import { useEffect } from "react" import { Controller, useForm, useWatch } from "react-hook-form" import { useTranslation } from "react-i18next" import Spinner from "../../../../components/atoms/spinner" import Button from "../../../../components/fundamentals/button" import Modal from "../../../../components/molecules/modal" import LayeredModal, { useLayeredModal, } from "../../../../components/molecules/modal/layered-modal" import Select from "../../../../components/molecules/select/next-select/select" import { AddressPayload } from "../../../../components/templates/address-form" import useImperativeDialog from "../../../../hooks/use-imperative-dialog" import useNotification from "../../../../hooks/use-notification" import { useFeatureFlag } from "../../../../providers/feature-flag-provider" import { getErrorMessage } from "../../../../utils/error-messages" import { nestedForm } from "../../../../utils/nested-form" import ClaimTypeForm, { ClaimTypeFormType, } from "../../components/claim-type-form" import ItemsToReturnForm, { ItemsToReturnFormType, } from "../../components/items-to-return-form" import ItemsToSendForm, { ItemsToSendFormType, } from "../../components/items-to-send-form" import { RefundAmountFormType } from "../../components/refund-amount-form" import { ClaimSummary } from "../../components/rma-summaries" import SendNotificationForm, { SendNotificationFormType, } from "../../components/send-notification-form" import ShippingAddressForm from "../../components/shipping-address-form" import ShippingForm, { ShippingFormType } from "../../components/shipping-form" import { getDefaultClaimValues } from "../utils/get-default-values" export type CreateClaimFormType = { notification: SendNotificationFormType return_items: ItemsToReturnFormType additional_items: ItemsToSendFormType return_shipping: ShippingFormType selected_location?: { value: string label: string } replacement_shipping: ShippingFormType shipping_address: AddressPayload claim_type: ClaimTypeFormType refund_amount: RefundAmountFormType } type Props = { order: Order onClose: () => void } const RegisterClaimMenu = ({ order, onClose }: Props) => { const context = useLayeredModal() const { mutate, isLoading } = useAdminCreateClaim(order.id) const { t } = useTranslation() const { isFeatureEnabled } = useFeatureFlag() const isLocationFulfillmentEnabled = isFeatureEnabled("inventoryService") && isFeatureEnabled("stockLocationService") const { stock_locations, refetch: refetchLocations, isLoading: isLoadingLocations, } = useAdminStockLocations( {}, { enabled: isLocationFulfillmentEnabled, } ) useEffect(() => { if (isLocationFulfillmentEnabled) { refetchLocations() } }, [isLocationFulfillmentEnabled, refetchLocations]) const form = useForm({ defaultValues: getDefaultClaimValues(order), }) const { handleSubmit, reset, formState: { isDirty }, setError, control, } = form const notification = useNotification() const dialog = useImperativeDialog() useEffect(() => { reset(getDefaultClaimValues(order)) }, [order, reset]) const handleClose = () => { context.reset() onClose() } const onCancel = async () => { let shouldClose = true if (isDirty) { shouldClose = await dialog({ heading: t( "claim-are-you-sure-you-want-to-close", "Are you sure you want to close?" ), text: t( "claim-you-have-unsaved-changes-are-you-sure-you-want-to-close", "You have unsaved changes, are you sure you want to close?" ), }) } if (shouldClose) { handleClose() } } const onSubmit = handleSubmit((data) => { const type = data.claim_type.type const returnShipping = data.return_shipping const refundAmount = data.refund_amount?.amount const returnLocation = data.selected_location?.value const replacementShipping = type === "replace" && data.replacement_shipping.option ? { option_id: data.replacement_shipping.option.value.id, /** * We set the price to 0 as we don't want to make the shippng price * affect the refund amount currently. This is a temporary solution, * and users should instead use the refund amount field to specify * the amount to refund when they receive the returned items if they * wish to deduct the cost of shipping. */ price: 0, } : undefined const items = data.return_items.items .filter((item) => item.return) .map((item) => ({ item_id: item.item_id, quantity: item.quantity, note: item.return_reason_details.note || undefined, reason: item.return_reason_details.reason?.value as ClaimReason, })) const returnItemsMissingReason = items.filter((item) => !item.reason) if (returnItemsMissingReason.length > 0) { returnItemsMissingReason.forEach((item) => { const index = items.findIndex((i) => i.item_id === item.item_id) setError( `return_items.items.${index}.return_reason_details`, { type: "manual", message: t( "claim-please-select-a-reason", "Please select a reason" ), }, { shouldFocus: true } ) }) return } if (type === "replace" && !data.replacement_shipping.option) { setError( `replacement_shipping.option`, { type: "manual", message: t( "claim-a-shipping-method-for-replacement-items-is-required", "A shipping method for replacement items is required" ), }, { shouldFocus: true } ) return } mutate( { claim_items: items, type: type, return_shipping: returnShipping.option ? { option_id: returnShipping.option.value.id, price: 0, } : undefined, additional_items: type === "replace" ? data.additional_items.items.map((item) => ({ quantity: item.quantity, variant_id: item.variant_id, })) : undefined, no_notification: !data.notification.send_notification, refund_amount: type === "refund" && refundAmount !== undefined ? refundAmount : undefined, shipping_address: type === "replace" ? { address_1: data.shipping_address.address_1, address_2: data.shipping_address.address_2 || undefined, city: data.shipping_address.city, country_code: data.shipping_address.country_code.value, company: data.shipping_address.company || undefined, first_name: data.shipping_address.first_name, last_name: data.shipping_address.last_name, phone: data.shipping_address.phone || undefined, postal_code: data.shipping_address.postal_code, province: data.shipping_address.province || undefined, } : undefined, return_location_id: returnLocation, shipping_methods: replacementShipping ? [replacementShipping] : undefined, }, { onSuccess: () => { notification( t("claim-successfully-created-claim", "Successfully created claim"), t( "claim-created", "A claim for order #{{display_id}} was successfully created", { display_id: order.display_id, } ), "success" ) handleClose() }, onError: (err) => { notification( t("claim-error-creating-claim", "Error creating claim"), getErrorMessage(err), "error" ) }, } ) }) const watchedType = useWatch({ control: form.control, name: "claim_type.type", }) const watchedItems = useWatch({ control: form.control, name: "return_items.items", }) return (

{t("claim-create-claim", "Create Claim")}

{isLocationFulfillmentEnabled && (

{t("claim-location", "Location")}

{t( "claim-choose-which-location-you-want-to-return-the-items-to", "Choose which location you want to return the items to." )}

{isLoadingLocations ? ( ) : ( { return (