From 5e827ec95d0f721e62c0d4e8c603bda7ddc0929c Mon Sep 17 00:00:00 2001 From: William Bouchard <46496014+willbouch@users.noreply.github.com> Date: Tue, 23 Sep 2025 11:51:40 -0400 Subject: [PATCH] feat(admin-shared,dashboard,js-sdk,types): refund reasons in dashboard (#13575) CLOSES CORE-1209 This PR just adds the stuff necessary to support refund reasons in the dashboard. It adds the option in the settings tab and allows viewing, creating, editing and deleting refund reasons. I hate to open such a big PR but most of it is copy pasted from the return reasons. Major difference is only the fact that refund reasons don't have a `value` field --- .changeset/quick-rice-deny.md | 9 + .../src/extensions/widgets/constants.ts | 6 + .../settings-layout/settings-layout.tsx | 4 + .../dashboard-app/routes/get-route.map.tsx | 36 +++ .../src/hooks/api/refund-reasons.tsx | 119 ++++++++- .../src/hooks/table/columns/index.ts | 1 + .../use-refund-reason-table-columns.tsx | 32 +++ .../dashboard/src/hooks/table/query/index.ts | 1 + .../query/use-refund-reason-table-query.tsx | 32 +++ .../src/i18n/translations/$schema.json | 252 +++++++++++++----- .../dashboard/src/i18n/translations/en.json | 32 +++ .../refund-reason-create-form/index.ts | 1 + .../refund-reason-create-form.tsx | 131 +++++++++ .../refund-reason-create/index.ts | 1 + .../refund-reason-create.tsx | 10 + .../refund-reason-edit-form/index.ts | 1 + .../refund-reason-edit-form.tsx | 119 +++++++++ .../refund-reason-edit/index.ts | 1 + .../refund-reason-edit/refund-reason-edit.tsx | 33 +++ .../refund-reason-list-table/index.ts | 1 + .../refund-reason-list-table.tsx | 130 +++++++++ .../refund-reason-list/index.ts | 2 + .../refund-reason-list/loader.ts | 16 ++ .../refund-reason-list/refund-reason-list.tsx | 21 ++ .../core/js-sdk/src/admin/refund-reasons.ts | 179 ++++++++++++- packages/core/types/src/http/index.ts | 1 + .../types/src/http/payment/admin/entities.ts | 2 - .../types/src/http/payment/admin/payloads.ts | 5 - .../types/src/http/payment/admin/queries.ts | 2 +- .../types/src/http/payment/admin/responses.ts | 4 +- .../core/types/src/http/payment/common.ts | 30 +-- .../src/http/refund-reason/admin/entities.ts | 3 + .../src/http/refund-reason/admin/index.ts | 4 + .../src/http/refund-reason/admin/payloads.ts | 21 ++ .../src/http/refund-reason/admin/queries.ts | 14 + .../src/http/refund-reason/admin/responses.ts | 20 ++ .../types/src/http/refund-reason/common.ts | 42 +++ .../types/src/http/refund-reason/index.ts | 1 + .../payment/src/models/refund-reason.ts | 2 +- 39 files changed, 1190 insertions(+), 131 deletions(-) create mode 100644 .changeset/quick-rice-deny.md create mode 100644 packages/admin/dashboard/src/hooks/table/columns/use-refund-reason-table-columns.tsx create mode 100644 packages/admin/dashboard/src/hooks/table/query/use-refund-reason-table-query.tsx create mode 100644 packages/admin/dashboard/src/routes/refund-reasons/refund-reason-create/components/refund-reason-create-form/index.ts create mode 100644 packages/admin/dashboard/src/routes/refund-reasons/refund-reason-create/components/refund-reason-create-form/refund-reason-create-form.tsx create mode 100644 packages/admin/dashboard/src/routes/refund-reasons/refund-reason-create/index.ts create mode 100644 packages/admin/dashboard/src/routes/refund-reasons/refund-reason-create/refund-reason-create.tsx create mode 100644 packages/admin/dashboard/src/routes/refund-reasons/refund-reason-edit/components/refund-reason-edit-form/index.ts create mode 100644 packages/admin/dashboard/src/routes/refund-reasons/refund-reason-edit/components/refund-reason-edit-form/refund-reason-edit-form.tsx create mode 100644 packages/admin/dashboard/src/routes/refund-reasons/refund-reason-edit/index.ts create mode 100644 packages/admin/dashboard/src/routes/refund-reasons/refund-reason-edit/refund-reason-edit.tsx create mode 100644 packages/admin/dashboard/src/routes/refund-reasons/refund-reason-list/components/refund-reason-list-table/index.ts create mode 100644 packages/admin/dashboard/src/routes/refund-reasons/refund-reason-list/components/refund-reason-list-table/refund-reason-list-table.tsx create mode 100644 packages/admin/dashboard/src/routes/refund-reasons/refund-reason-list/index.ts create mode 100644 packages/admin/dashboard/src/routes/refund-reasons/refund-reason-list/loader.ts create mode 100644 packages/admin/dashboard/src/routes/refund-reasons/refund-reason-list/refund-reason-list.tsx create mode 100644 packages/core/types/src/http/refund-reason/admin/entities.ts create mode 100644 packages/core/types/src/http/refund-reason/admin/index.ts create mode 100644 packages/core/types/src/http/refund-reason/admin/payloads.ts create mode 100644 packages/core/types/src/http/refund-reason/admin/queries.ts create mode 100644 packages/core/types/src/http/refund-reason/admin/responses.ts create mode 100644 packages/core/types/src/http/refund-reason/common.ts create mode 100644 packages/core/types/src/http/refund-reason/index.ts diff --git a/.changeset/quick-rice-deny.md b/.changeset/quick-rice-deny.md new file mode 100644 index 0000000000..1abd08b519 --- /dev/null +++ b/.changeset/quick-rice-deny.md @@ -0,0 +1,9 @@ +--- +"@medusajs/admin-shared": patch +"@medusajs/dashboard": patch +"@medusajs/js-sdk": patch +"@medusajs/types": patch +"@medusajs/payment": patch +--- + +feat(admin-shared,dashboard,js-sdk,types,payment): refund reasons in dashboard diff --git a/packages/admin/admin-shared/src/extensions/widgets/constants.ts b/packages/admin/admin-shared/src/extensions/widgets/constants.ts index 0137c4214f..eab257487e 100644 --- a/packages/admin/admin-shared/src/extensions/widgets/constants.ts +++ b/packages/admin/admin-shared/src/extensions/widgets/constants.ts @@ -189,6 +189,11 @@ const RETURN_REASON_INJECTION_ZONES = [ "return_reason.list.after", ] as const +const REFUND_REASON_INJECTION_ZONES = [ + "refund_reason.list.before", + "refund_reason.list.after", +] as const + const INVENTORY_ITEM_INJECTION_ZONES = [ "inventory_item.details.before", "inventory_item.details.after", @@ -229,5 +234,6 @@ export const INJECTION_ZONES = [ ...CAMPAIGN_INJECTION_ZONES, ...TAX_INJECTION_ZONES, ...RETURN_REASON_INJECTION_ZONES, + ...REFUND_REASON_INJECTION_ZONES, ...INVENTORY_ITEM_INJECTION_ZONES, ] as const diff --git a/packages/admin/dashboard/src/components/layout/settings-layout/settings-layout.tsx b/packages/admin/dashboard/src/components/layout/settings-layout/settings-layout.tsx index dfdc4900c5..e3951ea657 100644 --- a/packages/admin/dashboard/src/components/layout/settings-layout/settings-layout.tsx +++ b/packages/admin/dashboard/src/components/layout/settings-layout/settings-layout.tsx @@ -43,6 +43,10 @@ const useSettingRoutes = (): INavItem[] => { label: t("returnReasons.domain"), to: "/settings/return-reasons", }, + { + label: t("refundReasons.domain"), + to: "/settings/refund-reasons", + }, { label: t("salesChannels.domain"), to: "/settings/sales-channels", diff --git a/packages/admin/dashboard/src/dashboard-app/routes/get-route.map.tsx b/packages/admin/dashboard/src/dashboard-app/routes/get-route.map.tsx index da0c7fb6f1..23c39c6839 100644 --- a/packages/admin/dashboard/src/dashboard-app/routes/get-route.map.tsx +++ b/packages/admin/dashboard/src/dashboard-app/routes/get-route.map.tsx @@ -1780,6 +1780,42 @@ export function getRouteMap({ }, ], }, + { + path: "refund-reasons", + element: , + handle: { + breadcrumb: () => t("refundReasons.domain"), + }, + children: [ + { + path: "", + lazy: () => + import("../../routes/refund-reasons/refund-reason-list"), + children: [ + { + path: "create", + lazy: () => + import( + "../../routes/refund-reasons/refund-reason-create" + ), + }, + + { + path: ":id", + children: [ + { + path: "edit", + lazy: () => + import( + "../../routes/refund-reasons/refund-reason-edit" + ), + }, + ], + }, + ], + }, + ], + }, ...(settingsRoutes?.[0]?.children || []), ], }, diff --git a/packages/admin/dashboard/src/hooks/api/refund-reasons.tsx b/packages/admin/dashboard/src/hooks/api/refund-reasons.tsx index db889056f0..d63c20a4c2 100644 --- a/packages/admin/dashboard/src/hooks/api/refund-reasons.tsx +++ b/packages/admin/dashboard/src/hooks/api/refund-reasons.tsx @@ -1,29 +1,124 @@ import { HttpTypes } from "@medusajs/types" -import { QueryKey, useQuery, UseQueryOptions } from "@tanstack/react-query" -import { sdk } from "../../lib/client" -import { queryKeysFactory } from "../../lib/query-key-factory" -import { FetchError } from "@medusajs/js-sdk" +import { + useMutation, + UseMutationOptions, + useQuery, + UseQueryOptions, +} from "@tanstack/react-query" -const REFUND_REASON_QUERY_KEY = "refund-reason" as const -export const refundReasonQueryKeys = queryKeysFactory(REFUND_REASON_QUERY_KEY) +import { FetchError } from "@medusajs/js-sdk" +import { sdk } from "../../lib/client" +import { queryClient } from "../../lib/query-client" +import { queryKeysFactory } from "../../lib/query-key-factory" + +const REFUND_REASONS_QUERY_KEY = "refund_reasons" as const +export const refundReasonsQueryKeys = queryKeysFactory(REFUND_REASONS_QUERY_KEY) export const useRefundReasons = ( - query?: HttpTypes.RefundReasonFilters, + query?: HttpTypes.AdminRefundReasonListParams, options?: Omit< UseQueryOptions< - HttpTypes.RefundReasonsResponse, + HttpTypes.AdminRefundReasonListResponse, FetchError, - HttpTypes.RefundReasonsResponse, - QueryKey + HttpTypes.AdminRefundReasonListResponse >, - "queryKey" | "queryFn" + "queryFn" | "queryKey" > ) => { const { data, ...rest } = useQuery({ queryFn: () => sdk.admin.refundReason.list(query), - queryKey: [], + queryKey: refundReasonsQueryKeys.list(query), ...options, }) return { ...data, ...rest } } + +export const useRefundReason = ( + id: string, + query?: HttpTypes.AdminRefundReasonParams, + options?: Omit< + UseQueryOptions< + HttpTypes.AdminRefundReasonResponse, + FetchError, + HttpTypes.AdminRefundReasonResponse + >, + "queryFn" | "queryKey" + > +) => { + const { data, ...rest } = useQuery({ + queryFn: () => sdk.admin.refundReason.retrieve(id, query), + queryKey: refundReasonsQueryKeys.detail(id), + ...options, + }) + + return { ...data, ...rest } +} + +export const useCreateRefundReason = ( + query?: HttpTypes.AdminRefundReasonParams, + options?: UseMutationOptions< + HttpTypes.RefundReasonResponse, + FetchError, + HttpTypes.AdminCreateRefundReason + > +) => { + return useMutation({ + mutationFn: async (data) => sdk.admin.refundReason.create(data, query), + onSuccess: (data, variables, context) => { + queryClient.invalidateQueries({ + queryKey: refundReasonsQueryKeys.lists(), + }) + + options?.onSuccess?.(data, variables, context) + }, + ...options, + }) +} + +export const useUpdateRefundReason = ( + id: string, + options?: UseMutationOptions< + HttpTypes.AdminRefundReasonResponse, + FetchError, + HttpTypes.AdminUpdateRefundReason + > +) => { + return useMutation({ + mutationFn: async (data) => sdk.admin.refundReason.update(id, data), + onSuccess: (data, variables, context) => { + queryClient.invalidateQueries({ + queryKey: refundReasonsQueryKeys.lists(), + }) + queryClient.invalidateQueries({ + queryKey: refundReasonsQueryKeys.detail(data.refund_reason.id), + }) + + options?.onSuccess?.(data, variables, context) + }, + ...options, + }) +} + +export const useDeleteRefundReasonLazy = ( + options?: UseMutationOptions< + HttpTypes.AdminRefundReasonDeleteResponse, + FetchError, + string + > +) => { + return useMutation({ + mutationFn: (id: string) => sdk.admin.refundReason.delete(id), + onSuccess: (data, variables, context) => { + queryClient.invalidateQueries({ + queryKey: refundReasonsQueryKeys.lists(), + }) + queryClient.invalidateQueries({ + queryKey: refundReasonsQueryKeys.details(), + }) + + options?.onSuccess?.(data, variables, context) + }, + ...options, + }) +} diff --git a/packages/admin/dashboard/src/hooks/table/columns/index.ts b/packages/admin/dashboard/src/hooks/table/columns/index.ts index bbeb3d4d62..0095d324b4 100644 --- a/packages/admin/dashboard/src/hooks/table/columns/index.ts +++ b/packages/admin/dashboard/src/hooks/table/columns/index.ts @@ -6,6 +6,7 @@ export * from "./use-order-table-columns" export * from "./use-product-table-columns" export * from "./use-product-tag-table-columns" export * from "./use-product-type-table-columns" +export * from "./use-refund-reason-table-columns" export * from "./use-region-table-columns" export * from "./use-return-reason-table-columns" export * from "./use-tax-rates-table-columns" diff --git a/packages/admin/dashboard/src/hooks/table/columns/use-refund-reason-table-columns.tsx b/packages/admin/dashboard/src/hooks/table/columns/use-refund-reason-table-columns.tsx new file mode 100644 index 0000000000..ba9f27691f --- /dev/null +++ b/packages/admin/dashboard/src/hooks/table/columns/use-refund-reason-table-columns.tsx @@ -0,0 +1,32 @@ +import { HttpTypes } from "@medusajs/types" +import { useMemo } from "react" +import { useTranslation } from "react-i18next" +import { createDataTableColumnHelper } from "@medusajs/ui" +import { DescriptionCell } from "../../../components/table/table-cells/sales-channel/description-cell" + +const columnHelper = createDataTableColumnHelper() + +export const useRefundReasonTableColumns = () => { + const { t } = useTranslation() + + return useMemo( + () => [ + columnHelper.accessor("label", { + header: () => t("fields.label"), + enableSorting: true, + sortLabel: t("fields.label"), + sortAscLabel: t("filters.sorting.alphabeticallyAsc"), + sortDescLabel: t("filters.sorting.alphabeticallyDesc"), + }), + columnHelper.accessor("description", { + header: () => t("fields.description"), + cell: ({ getValue }) => , + enableSorting: true, + sortLabel: t("fields.description"), + sortAscLabel: t("filters.sorting.alphabeticallyAsc"), + sortDescLabel: t("filters.sorting.alphabeticallyDesc"), + }), + ], + [t] + ) +} diff --git a/packages/admin/dashboard/src/hooks/table/query/index.ts b/packages/admin/dashboard/src/hooks/table/query/index.ts index fb5f55c912..92461c3106 100644 --- a/packages/admin/dashboard/src/hooks/table/query/index.ts +++ b/packages/admin/dashboard/src/hooks/table/query/index.ts @@ -6,6 +6,7 @@ export * from "./use-order-table-query" export * from "./use-product-table-query" export * from "./use-product-tag-table-query" export * from "./use-product-type-table-query" +export * from "./use-refund-reason-table-query" export * from "./use-region-table-query" export * from "./use-return-reason-table-query" export * from "./use-shipping-option-table-query" diff --git a/packages/admin/dashboard/src/hooks/table/query/use-refund-reason-table-query.tsx b/packages/admin/dashboard/src/hooks/table/query/use-refund-reason-table-query.tsx new file mode 100644 index 0000000000..578a88b802 --- /dev/null +++ b/packages/admin/dashboard/src/hooks/table/query/use-refund-reason-table-query.tsx @@ -0,0 +1,32 @@ +import { HttpTypes } from "@medusajs/types" +import { useQueryParams } from "../../use-query-params" + +type UseRefundReasonTableQueryProps = { + prefix?: string + pageSize?: number +} + +export const useRefundReasonTableQuery = ({ + prefix, + pageSize = 20, +}: UseRefundReasonTableQueryProps) => { + const queryObject = useQueryParams( + ["offset", "q", "order", "created_at", "updated_at"], + prefix + ) + + const { offset, q, order, created_at, updated_at } = queryObject + const searchParams: HttpTypes.AdminRefundReasonListParams = { + limit: pageSize, + offset: offset ? Number(offset) : 0, + order, + created_at: created_at ? JSON.parse(created_at) : undefined, + updated_at: updated_at ? JSON.parse(updated_at) : undefined, + q, + } + + return { + searchParams, + raw: queryObject, + } +} \ No newline at end of file diff --git a/packages/admin/dashboard/src/i18n/translations/$schema.json b/packages/admin/dashboard/src/i18n/translations/$schema.json index 8a3b0b2417..41209b6049 100644 --- a/packages/admin/dashboard/src/i18n/translations/$schema.json +++ b/packages/admin/dashboard/src/i18n/translations/$schema.json @@ -161,6 +161,9 @@ "noRecordsMessage": { "type": "string" }, + "noRecordsMessageFiltered": { + "type": "string" + }, "unsavedChangesTitle": { "type": "string" }, @@ -229,6 +232,7 @@ "noSearchResultsFor", "noRecordsTitle", "noRecordsMessage", + "noRecordsMessageFiltered", "unsavedChangesTitle", "unsavedChangesDescription", "includesTaxTooltip", @@ -10202,6 +10206,115 @@ ], "additionalProperties": false }, + "refundReasons": { + "type": "object", + "properties": { + "domain": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "calloutHint": { + "type": "string" + }, + "editReason": { + "type": "string" + }, + "create": { + "type": "object", + "properties": { + "header": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "hint": { + "type": "string" + }, + "successToast": { + "type": "string" + } + }, + "required": ["header", "subtitle", "hint", "successToast"], + "additionalProperties": false + }, + "edit": { + "type": "object", + "properties": { + "header": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "successToast": { + "type": "string" + } + }, + "required": ["header", "subtitle", "successToast"], + "additionalProperties": false + }, + "delete": { + "type": "object", + "properties": { + "confirmation": { + "type": "string" + }, + "successToast": { + "type": "string" + } + }, + "required": ["confirmation", "successToast"], + "additionalProperties": false + }, + "fields": { + "type": "object", + "properties": { + "label": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "placeholder": { + "type": "string" + } + }, + "required": ["label", "placeholder"], + "additionalProperties": false + }, + "description": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "placeholder": { + "type": "string" + } + }, + "required": ["label", "placeholder"], + "additionalProperties": false + } + }, + "required": ["label", "description"], + "additionalProperties": false + } + }, + "required": [ + "domain", + "subtitle", + "calloutHint", + "editReason", + "create", + "edit", + "delete", + "fields" + ], + "additionalProperties": false + }, "login": { "type": "object", "properties": { @@ -11554,70 +11667,6 @@ ], "additionalProperties": false }, - "views": { - "type": "object", - "properties": { - "save": { - "type": "string" - }, - "saveAsNew": { - "type": "string" - }, - "updateDefaultForEveryone": { - "type": "string" - }, - "updateViewName": { - "type": "string" - }, - "prompts": { - "type": "object", - "properties": { - "updateDefault": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "description": { - "type": "string" - }, - "confirmText": { - "type": "string" - }, - "cancelText": { - "type": "string" - } - }, - "required": ["title", "description", "confirmText", "cancelText"], - "additionalProperties": false - }, - "updateView": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "description": { - "type": "string" - }, - "confirmText": { - "type": "string" - }, - "cancelText": { - "type": "string" - } - }, - "required": ["title", "description", "confirmText", "cancelText"], - "additionalProperties": false - } - }, - "required": ["updateDefault", "updateView"], - "additionalProperties": false - } - }, - "required": ["save", "saveAsNew", "updateDefaultForEveryone", "updateViewName", "prompts"], - "additionalProperties": false - }, "dateTime": { "type": "object", "properties": { @@ -11681,6 +11730,76 @@ "seconds_other" ], "additionalProperties": false + }, + "views": { + "type": "object", + "properties": { + "save": { + "type": "string" + }, + "saveAsNew": { + "type": "string" + }, + "updateDefaultForEveryone": { + "type": "string" + }, + "updateViewName": { + "type": "string" + }, + "prompts": { + "type": "object", + "properties": { + "updateDefault": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "confirmText": { + "type": "string" + }, + "cancelText": { + "type": "string" + } + }, + "required": ["title", "description", "confirmText", "cancelText"], + "additionalProperties": false + }, + "updateView": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "confirmText": { + "type": "string" + }, + "cancelText": { + "type": "string" + } + }, + "required": ["title", "description", "confirmText", "cancelText"], + "additionalProperties": false + } + }, + "required": ["updateDefault", "updateView"], + "additionalProperties": false + } + }, + "required": [ + "save", + "saveAsNew", + "updateDefaultForEveryone", + "updateViewName", + "prompts" + ], + "additionalProperties": false } }, "required": [ @@ -11724,6 +11843,7 @@ "salesChannels", "apiKeyManagement", "returnReasons", + "refundReasons", "login", "invite", "resetPassword", @@ -11736,8 +11856,8 @@ "statuses", "labels", "fields", - "views", - "dateTime" + "dateTime", + "views" ], "additionalProperties": false } diff --git a/packages/admin/dashboard/src/i18n/translations/en.json b/packages/admin/dashboard/src/i18n/translations/en.json index 3088c16fc7..30eb795f18 100644 --- a/packages/admin/dashboard/src/i18n/translations/en.json +++ b/packages/admin/dashboard/src/i18n/translations/en.json @@ -52,6 +52,7 @@ "noSearchResultsFor": "No search results for <0>'{{query}}'", "noRecordsTitle": "No records", "noRecordsMessage": "There are no records to show", + "noRecordsMessageFiltered": "There are no records to show matching the filters", "unsavedChangesTitle": "Are you sure you want to leave this form?", "unsavedChangesDescription": "You have unsaved changes that will be lost if you exit this form.", "includesTaxTooltip": "Prices in this column are tax inclusive.", @@ -2740,6 +2741,37 @@ } } }, + "refundReasons": { + "domain": "Refund Reasons", + "subtitle": "Manage reasons for issuing refunds.", + "calloutHint": "Manage the reasons to categorize refunds.", + "editReason": "Edit Refund Reason", + "create": { + "header": "Add Refund Reason", + "subtitle": "Specify the most common reasons for refunds.", + "hint": "Create a new refund reason to categorize refunds.", + "successToast": "Refund reason {{label}} was successfully created." + }, + "edit": { + "header": "Edit Refund Reason", + "subtitle": "Edit the value of the refund reason.", + "successToast": "Refund reason {{label}} was successfully updated." + }, + "delete": { + "confirmation": "You are about to delete the refund reason \"{{label}}\". This action cannot be undone.", + "successToast": "Refund reason was successfully deleted." + }, + "fields": { + "label": { + "label": "Label", + "placeholder": "Gesture of goodwill" + }, + "description": { + "label": "Description", + "placeholder": "Customer had a bad shopping experience" + } + } + }, "login": { "forgotPassword": "Forgot password? - <0>Reset", "title": "Welcome to Medusa", diff --git a/packages/admin/dashboard/src/routes/refund-reasons/refund-reason-create/components/refund-reason-create-form/index.ts b/packages/admin/dashboard/src/routes/refund-reasons/refund-reason-create/components/refund-reason-create-form/index.ts new file mode 100644 index 0000000000..732708c4de --- /dev/null +++ b/packages/admin/dashboard/src/routes/refund-reasons/refund-reason-create/components/refund-reason-create-form/index.ts @@ -0,0 +1 @@ +export { RefundReasonCreateForm } from "./refund-reason-create-form" diff --git a/packages/admin/dashboard/src/routes/refund-reasons/refund-reason-create/components/refund-reason-create-form/refund-reason-create-form.tsx b/packages/admin/dashboard/src/routes/refund-reasons/refund-reason-create/components/refund-reason-create-form/refund-reason-create-form.tsx new file mode 100644 index 0000000000..f1852fefb7 --- /dev/null +++ b/packages/admin/dashboard/src/routes/refund-reasons/refund-reason-create/components/refund-reason-create-form/refund-reason-create-form.tsx @@ -0,0 +1,131 @@ +import { zodResolver } from "@hookform/resolvers/zod" +import { Button, Heading, Input, Text, Textarea, toast } from "@medusajs/ui" +import { useForm } from "react-hook-form" +import { useTranslation } from "react-i18next" +import { z } from "zod" +import { Form } from "../../../../../components/common/form" +import { + RouteFocusModal, + useRouteModal, +} from "../../../../../components/modals" +import { KeyboundForm } from "../../../../../components/utilities/keybound-form" +import { useCreateRefundReason } from "../../../../../hooks/api" + +const RefundReasonCreateSchema = z.object({ + label: z.string().min(1), + description: z.string().optional(), +}) + +export const RefundReasonCreateForm = () => { + const { t } = useTranslation() + const { handleSuccess } = useRouteModal() + + const form = useForm>({ + defaultValues: { + label: "", + description: "", + }, + resolver: zodResolver(RefundReasonCreateSchema), + }) + + const { mutateAsync, isPending } = useCreateRefundReason() + + const handleSubmit = form.handleSubmit(async (data) => { + await mutateAsync(data, { + onSuccess: ({ refund_reason }) => { + toast.success( + t("refundReasons.create.successToast", { + label: refund_reason.label, + }) + ) + handleSuccess(`../`) + }, + onError: (error) => { + toast.error(error.message) + }, + }) + }) + + return ( + + + + +
+
+ + {t("refundReasons.create.header")} + + + + {t("refundReasons.create.subtitle")} + + +
+
+ { + return ( + + + {t("refundReasons.fields.label.label")} + + + + + + + ) + }} + /> +
+ { + return ( + + + {t("refundReasons.fields.description.label")} + + +