Skip to content

Commit

Permalink
Merge branch 'develop' into feat/receive-return-e2e
Browse files Browse the repository at this point in the history
  • Loading branch information
fPolic authored Aug 1, 2024
2 parents 17ec1d9 + 7ae1d80 commit 01fe6f5
Show file tree
Hide file tree
Showing 45 changed files with 1,414 additions and 333 deletions.
51 changes: 51 additions & 0 deletions packages/admin-next/dashboard/src/hooks/api/payments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ import {
} from "@tanstack/react-query"
import { client, sdk } from "../../lib/client"
import { queryClient } from "../../lib/query-client"
import { queryKeysFactory } from "../../lib/query-key-factory"
import { PaymentProvidersListRes } from "../../types/api-responses"
import { ordersQueryKeys } from "./orders"

const PAYMENT_QUERY_KEY = "payment" as const
export const paymentQueryKeys = queryKeysFactory(PAYMENT_QUERY_KEY)

export const usePaymentProviders = (
query?: Record<string, any>,
options?: Omit<
Expand All @@ -32,6 +36,28 @@ export const usePaymentProviders = (
return { ...data, ...rest }
}

export const usePayment = (
id: string,
query?: HttpTypes.AdminPaymentFilters,
options?: Omit<
UseQueryOptions<
HttpTypes.AdminPaymentResponse,
Error,
HttpTypes.AdminPaymentResponse,
QueryKey
>,
"queryKey" | "queryFn"
>
) => {
const { data, ...rest } = useQuery({
queryFn: () => sdk.admin.payment.retrieve(id, query),
queryKey: paymentQueryKeys.detail(id),
...options,
})

return { ...data, ...rest }
}

export const useCapturePayment = (
paymentId: string,
options?: UseMutationOptions<
Expand All @@ -56,3 +82,28 @@ export const useCapturePayment = (
...options,
})
}

export const useRefundPayment = (
paymentId: string,
options?: UseMutationOptions<
HttpTypes.AdminPaymentResponse,
Error,
HttpTypes.AdminRefundPayment
>
) => {
return useMutation({
mutationFn: (payload) => sdk.admin.payment.refund(paymentId, payload),
onSuccess: (data, variables, context) => {
queryClient.invalidateQueries({
queryKey: ordersQueryKeys.details(),
})

queryClient.invalidateQueries({
queryKey: ordersQueryKeys.lists(),
})

options?.onSuccess?.(data, variables, context)
},
...options,
})
}
5 changes: 4 additions & 1 deletion packages/admin-next/dashboard/src/i18n/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,10 @@
"requiresAction": "Requires action"
},
"capturePayment": "Payment of {{amount}} will be captured.",
"capturePaymentSuccess": "Payment of {{amount}} successfully captured"
"capturePaymentSuccess": "Payment of {{amount}} successfully captured",
"createRefund": "Create Refund",
"refundPaymentSuccess": "Refund of amount {{amount}} successful",
"createRefundWrongQuantity": "Quantity should be a number between 1 and {{number}}"
},

"edits": {
Expand Down
2 changes: 1 addition & 1 deletion packages/admin-next/dashboard/src/lib/client/payments.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getRequest } from "./common"
import { PaymentProvidersListRes } from "../../types/api-responses"
import { getRequest } from "./common"

async function listPaymentProviders(query?: Record<string, any>) {
return getRequest<PaymentProvidersListRes, Record<string, any>>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,11 @@ export const RouteMap: RouteObject[] = [
lazy: () =>
import("../../routes/orders/order-create-return"),
},
{
path: "payments/:paymentId/refund",
lazy: () =>
import("../../routes/orders/order-create-refund"),
},
],
},
],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { zodResolver } from "@hookform/resolvers/zod"
import { HttpTypes } from "@medusajs/types"
import { Button, CurrencyInput, toast } from "@medusajs/ui"
import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next"
import * as zod from "zod"
import { Form } from "../../../../../components/common/form"
import { RouteDrawer, useRouteModal } from "../../../../../components/modals"
import { useRefundPayment } from "../../../../../hooks/api"
import { getCurrencySymbol } from "../../../../../lib/data/currencies"
import { formatCurrency } from "../../../../../lib/format-currency"

type CreateRefundFormProps = {
payment: HttpTypes.AdminPayment
}

const CreateRefundSchema = zod.object({
amount: zod.number(),
})

export const CreateRefundForm = ({ payment }: CreateRefundFormProps) => {
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const paymentAmount = payment.amount as unknown as number

const form = useForm<zod.infer<typeof CreateRefundSchema>>({
defaultValues: {
amount: paymentAmount,
},
resolver: zodResolver(CreateRefundSchema),
})

const { mutateAsync, isPending } = useRefundPayment(payment.id)

const handleSubmit = form.handleSubmit(async (data) => {
await mutateAsync(
{
amount: data.amount,
},
{
onSuccess: () => {
toast.success(
t("orders.payment.refundPaymentSuccess", {
amount: formatCurrency(data.amount, payment.currency_code),
})
)

handleSuccess()
},
onError: (error) => {
toast.error(error.message)
},
}
)
})

return (
<RouteDrawer.Form form={form}>
<form onSubmit={handleSubmit} className="flex flex-1 flex-col">
<RouteDrawer.Body>
<div className="flex flex-col gap-y-4">
<Form.Field
control={form.control}
name="amount"
rules={{
required: true,
min: 0,
max: paymentAmount,
}}
render={({ field: { onChange, ...field } }) => {
return (
<Form.Item>
<Form.Label>{t("fields.amount")}</Form.Label>

<Form.Control>
<CurrencyInput
{...field}
min={0}
onChange={(e) => {
const val =
e.target.value === ""
? null
: Number(e.target.value)

onChange(val)

if (val && !isNaN(val)) {
if (val < 0 || val > paymentAmount) {
form.setError(`amount`, {
type: "manual",
message: t(
"orders.payment.createRefundWrongQuantity",
{ number: paymentAmount }
),
})
} else {
form.clearErrors(`amount`)
}
}
}}
code={payment.currency_code}
symbol={getCurrencySymbol(payment.currency_code)}
value={field.value}
/>
</Form.Control>

<Form.ErrorMessage />
</Form.Item>
)
}}
/>
</div>
</RouteDrawer.Body>

<RouteDrawer.Footer>
<div className="flex items-center justify-end gap-x-2">
<RouteDrawer.Close asChild>
<Button variant="secondary" size="small">
{t("actions.cancel")}
</Button>
</RouteDrawer.Close>

<Button
isLoading={isPending}
type="submit"
variant="primary"
size="small"
disabled={!!Object.keys(form.formState.errors || {}).length}
>
{t("actions.save")}
</Button>
</div>
</RouteDrawer.Footer>
</form>
</RouteDrawer.Form>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./create-refund-form"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { OrderCreateRefund as Component } from "./order-create-refund"
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Heading } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { useParams } from "react-router-dom"
import { RouteDrawer } from "../../../components/modals"
import { usePayment } from "../../../hooks/api"
import { CreateRefundForm } from "./components/create-refund-form"

export const OrderCreateRefund = () => {
const { t } = useTranslation()
const params = useParams()
const { payment, isLoading, isError, error } = usePayment(params.paymentId!)

if (isError) {
throw error
}

return (
<RouteDrawer>
<RouteDrawer.Header>
<Heading>{t("orders.payment.createRefund")}</Heading>
</RouteDrawer.Header>

{!isLoading && payment && <CreateRefundForm payment={payment} />}
</RouteDrawer>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export const OrderPaymentSection = ({ order }: OrderPaymentSectionProps) => {
<Header />

<PaymentBreakdown
order={order}
payments={payments}
refunds={refunds}
currencyCode={order.currency_code}
Expand Down Expand Up @@ -77,7 +78,6 @@ const Refund = ({
currencyCode: string
}) => {
const { t } = useTranslation()
const hasPayment = refund.payment_id !== null

const BadgeComponent = (
<Badge size="2xsmall" className="cursor-default select-none capitalize">
Expand All @@ -93,17 +93,20 @@ const Refund = ({

return (
<div className="bg-ui-bg-subtle text-ui-fg-subtle grid grid-cols-[1fr_1fr_1fr_1fr_20px] items-center gap-x-4 px-6 py-4">
<div>
{hasPayment && <ArrowDownRightMini className="text-ui-fg-muted" />}
<Text size="small" leading="compact" weight="plus">
{t("orders.payment.refund")}
</Text>
</div>
<div className="flex items-center justify-end">
<Text size="small" leading="compact">
{format(new Date(refund.created_at), "dd MMM, yyyy, HH:mm:ss")}
</Text>
<div className="flex flex-row">
<div className="self-center pr-3">
<ArrowDownRightMini className="text-ui-fg-muted" />
</div>
<div>
<Text size="small" leading="compact" weight="plus">
{t("orders.payment.refund")}
</Text>
<Text size="small" leading="compact">
{format(new Date(refund.created_at), "dd MMM, yyyy, HH:mm:ss")}
</Text>
</div>
</div>
<div className="flex items-center justify-end"></div>
<div className="flex items-center justify-end">{Render}</div>
<div className="flex items-center justify-end">
<Text size="small" leading="compact">
Expand All @@ -115,10 +118,12 @@ const Refund = ({
}

const Payment = ({
order,
payment,
refunds,
currencyCode,
}: {
order: HttpTypes.AdminOrder
payment: MedusaPayment
refunds: MedusaRefund[]
currencyCode: string
Expand All @@ -135,6 +140,7 @@ const Payment = ({
}),
confirmText: t("actions.confirm"),
cancelText: t("actions.cancel"),
variant: "confirmation",
})

if (!res) {
Expand Down Expand Up @@ -204,7 +210,7 @@ const Payment = ({
{
label: t("orders.payment.refund"),
icon: <XCircle />,
to: `/orders/${payment.order_id}/refund?paymentId=${payment.id}`,
to: `/orders/${order.id}/payments/${payment.id}/refund`,
disabled: !payment.captured_at,
},
],
Expand Down Expand Up @@ -236,10 +242,12 @@ const Payment = ({
}

const PaymentBreakdown = ({
order,
payments,
refunds,
currencyCode,
}: {
order: HttpTypes.AdminOrder
payments: MedusaPayment[]
refunds: MedusaRefund[]
currencyCode: string
Expand Down Expand Up @@ -271,6 +279,7 @@ const PaymentBreakdown = ({
return (
<Payment
key={event.id}
order={order}
payment={event}
refunds={refunds.filter(
(refund) => refund.payment_id === event.id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { batchLinkProductsToCollectionStep } from "../steps/batch-link-products-

export const batchLinkProductsToCollectionWorkflowId =
"batch-link-products-to-collection"

export const batchLinkProductsToCollectionWorkflow = createWorkflow(
batchLinkProductsToCollectionWorkflowId,
(input: WorkflowData<LinkWorkflowInput>): WorkflowData<void> => {
Expand Down
Loading

0 comments on commit 01fe6f5

Please sign in to comment.