feat: create return reason (#8516)
* feat: create and edit return reasons * add prop to hide data table header * make return reasons searchable * hide table header
This commit is contained in:
1
.github/teams.yml
vendored
1
.github/teams.yml
vendored
@@ -12,3 +12,4 @@
|
||||
- "@sradevski"
|
||||
- "@edast"
|
||||
- "@thetutlage"
|
||||
- "@christiananese"
|
||||
|
||||
@@ -52,6 +52,10 @@ export interface DataTableRootProps<TData> {
|
||||
* Whether the table is empty due to no results from the active query
|
||||
*/
|
||||
noResults?: boolean
|
||||
/**
|
||||
* Whether to display the tables header
|
||||
*/
|
||||
noHeader?: boolean
|
||||
/**
|
||||
* The layout of the table
|
||||
*/
|
||||
@@ -80,6 +84,7 @@ export const DataTableRoot = <TData,>({
|
||||
commands,
|
||||
count = 0,
|
||||
noResults = false,
|
||||
noHeader = false,
|
||||
layout = "fit",
|
||||
}: DataTableRootProps<TData>) => {
|
||||
const { t } = useTranslation()
|
||||
@@ -133,64 +138,66 @@ export const DataTableRoot = <TData,>({
|
||||
>
|
||||
{!noResults ? (
|
||||
<Table className="relative w-full">
|
||||
<Table.Header className="border-t-0">
|
||||
{table.getHeaderGroups().map((headerGroup) => {
|
||||
return (
|
||||
<Table.Row
|
||||
key={headerGroup.id}
|
||||
className={clx({
|
||||
"relative border-b-0 [&_th:last-of-type]:w-[1%] [&_th:last-of-type]:whitespace-nowrap":
|
||||
hasActions,
|
||||
"[&_th:first-of-type]:w-[1%] [&_th:first-of-type]:whitespace-nowrap":
|
||||
hasSelect,
|
||||
})}
|
||||
>
|
||||
{headerGroup.headers.map((header, index) => {
|
||||
const isActionHeader = header.id === "actions"
|
||||
const isSelectHeader = header.id === "select"
|
||||
const isSpecialHeader = isActionHeader || isSelectHeader
|
||||
{!noHeader && (
|
||||
<Table.Header className="border-t-0">
|
||||
{table.getHeaderGroups().map((headerGroup) => {
|
||||
return (
|
||||
<Table.Row
|
||||
key={headerGroup.id}
|
||||
className={clx({
|
||||
"relative border-b-0 [&_th:last-of-type]:w-[1%] [&_th:last-of-type]:whitespace-nowrap":
|
||||
hasActions,
|
||||
"[&_th:first-of-type]:w-[1%] [&_th:first-of-type]:whitespace-nowrap":
|
||||
hasSelect,
|
||||
})}
|
||||
>
|
||||
{headerGroup.headers.map((header, index) => {
|
||||
const isActionHeader = header.id === "actions"
|
||||
const isSelectHeader = header.id === "select"
|
||||
const isSpecialHeader = isActionHeader || isSelectHeader
|
||||
|
||||
const firstHeader = headerGroup.headers.findIndex(
|
||||
(h) => h.id !== "select"
|
||||
)
|
||||
const isFirstHeader =
|
||||
firstHeader !== -1
|
||||
? header.id === headerGroup.headers[firstHeader].id
|
||||
: index === 0
|
||||
const firstHeader = headerGroup.headers.findIndex(
|
||||
(h) => h.id !== "select"
|
||||
)
|
||||
const isFirstHeader =
|
||||
firstHeader !== -1
|
||||
? header.id === headerGroup.headers[firstHeader].id
|
||||
: index === 0
|
||||
|
||||
const isStickyHeader = isSelectHeader || isFirstHeader
|
||||
const isStickyHeader = isSelectHeader || isFirstHeader
|
||||
|
||||
return (
|
||||
<Table.HeaderCell
|
||||
data-table-header-id={header.id}
|
||||
key={header.id}
|
||||
style={{
|
||||
width: !isSpecialHeader
|
||||
? `${colWidth}%`
|
||||
: undefined,
|
||||
}}
|
||||
className={clx({
|
||||
"bg-ui-bg-base sticky left-0 after:absolute after:inset-y-0 after:right-0 after:h-full after:w-px after:bg-transparent after:content-['']":
|
||||
isStickyHeader,
|
||||
"left-[68px]":
|
||||
isStickyHeader && hasSelect && !isSelectHeader,
|
||||
"after:bg-ui-border-base":
|
||||
showStickyBorder &&
|
||||
isStickyHeader &&
|
||||
!isSpecialHeader,
|
||||
})}
|
||||
>
|
||||
{flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</Table.HeaderCell>
|
||||
)
|
||||
})}
|
||||
</Table.Row>
|
||||
)
|
||||
})}
|
||||
</Table.Header>
|
||||
return (
|
||||
<Table.HeaderCell
|
||||
data-table-header-id={header.id}
|
||||
key={header.id}
|
||||
style={{
|
||||
width: !isSpecialHeader
|
||||
? `${colWidth}%`
|
||||
: undefined,
|
||||
}}
|
||||
className={clx({
|
||||
"bg-ui-bg-base sticky left-0 after:absolute after:inset-y-0 after:right-0 after:h-full after:w-px after:bg-transparent after:content-['']":
|
||||
isStickyHeader,
|
||||
"left-[68px]":
|
||||
isStickyHeader && hasSelect && !isSelectHeader,
|
||||
"after:bg-ui-border-base":
|
||||
showStickyBorder &&
|
||||
isStickyHeader &&
|
||||
!isSpecialHeader,
|
||||
})}
|
||||
>
|
||||
{flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</Table.HeaderCell>
|
||||
)
|
||||
})}
|
||||
</Table.Row>
|
||||
)
|
||||
})}
|
||||
</Table.Header>
|
||||
)}
|
||||
<Table.Body className="border-b-0">
|
||||
{table.getRowModel().rows.map((row) => {
|
||||
const to = navigateTo ? navigateTo(row) : undefined
|
||||
|
||||
@@ -32,6 +32,7 @@ export const DataTable = <TData,>({
|
||||
queryObject = {},
|
||||
pageSize,
|
||||
isLoading = false,
|
||||
noHeader = false,
|
||||
layout = "fit",
|
||||
noRecords: noRecordsProps = {},
|
||||
}: DataTableProps<TData>) => {
|
||||
@@ -84,6 +85,7 @@ export const DataTable = <TData,>({
|
||||
navigateTo={navigateTo}
|
||||
commands={commands}
|
||||
noResults={noResults}
|
||||
noHeader={noHeader}
|
||||
layout={layout}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,25 +1,30 @@
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import { Badge } from "@medusajs/ui"
|
||||
import { createColumnHelper } from "@tanstack/react-table"
|
||||
import { useMemo } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { TextCell } from "../../../components/table/table-cells/common/text-cell"
|
||||
|
||||
const columnHelper = createColumnHelper<HttpTypes.AdminReturnReason>()
|
||||
|
||||
export const useReturnReasonTableColumns = () => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return useMemo(
|
||||
() => [
|
||||
columnHelper.accessor("value", {
|
||||
header: () => t("fields.value"),
|
||||
cell: ({ getValue }) => <TextCell text={getValue()} />,
|
||||
cell: ({ getValue }) => <Badge size="2xsmall">{getValue()}</Badge>,
|
||||
}),
|
||||
columnHelper.accessor("label", {
|
||||
header: () => t("fields.createdAt"),
|
||||
cell: ({ getValue }) => <TextCell text={getValue()} />,
|
||||
cell: ({ row }) => {
|
||||
const { label, description } = row.original
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col justify-center py-4">
|
||||
<span className="truncate font-medium">{label}</span>
|
||||
<span className="truncate">
|
||||
{description ? description : "-"}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
}),
|
||||
],
|
||||
[t]
|
||||
[]
|
||||
)
|
||||
}
|
||||
|
||||
@@ -166,7 +166,8 @@
|
||||
"goToPublishableApiKeys": "Publishable API Keys",
|
||||
"goToSecretApiKeys": "Secret API Keys",
|
||||
"goToWorkflows": "Workflows",
|
||||
"goToProfile": "Profile"
|
||||
"goToProfile": "Profile",
|
||||
"goToReturnReasons": "Return reasons"
|
||||
}
|
||||
},
|
||||
"menus": {
|
||||
@@ -2104,6 +2105,7 @@
|
||||
},
|
||||
"returnReasons": {
|
||||
"domain": "Return Reasons",
|
||||
"subtitle": "Manage reasons for returned items.",
|
||||
"calloutHint": "Manage the reasons to categorize returns.",
|
||||
"editReason": "Edit Return Reason",
|
||||
"create": {
|
||||
@@ -2113,6 +2115,8 @@
|
||||
"successToast": "Return reason {{label}} was successfully created."
|
||||
},
|
||||
"edit": {
|
||||
"header": "Edit Return Reason",
|
||||
"subtitle": "Edit the value of the return reason.",
|
||||
"successToast": "Return reason {{label}} was successfully updated."
|
||||
},
|
||||
"delete": {
|
||||
|
||||
@@ -264,6 +264,14 @@ export const useGlobalShortcuts = () => {
|
||||
type: "settingShortcut",
|
||||
to: "/settings/locations",
|
||||
},
|
||||
{
|
||||
keys: {
|
||||
Mac: ["G", ",", "M"],
|
||||
},
|
||||
label: t("app.keyboardShortcuts.settings.goToReturnReasons"),
|
||||
type: "settingShortcut",
|
||||
to: "/settings/return-reasons",
|
||||
},
|
||||
{
|
||||
keys: {
|
||||
Mac: ["G", ",", "J"],
|
||||
|
||||
@@ -1304,6 +1304,28 @@ export const RouteMap: RouteObject[] = [
|
||||
path: "",
|
||||
lazy: () =>
|
||||
import("../../routes/return-reasons/return-reason-list"),
|
||||
children: [
|
||||
{
|
||||
path: "create",
|
||||
lazy: () =>
|
||||
import(
|
||||
"../../routes/return-reasons/return-reason-create"
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
path: ":id",
|
||||
children: [
|
||||
{
|
||||
path: "edit",
|
||||
lazy: () =>
|
||||
import(
|
||||
"../../routes/return-reasons/return-reason-edit"
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./return-reason-create-form"
|
||||
@@ -0,0 +1,156 @@
|
||||
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 { useCreateReturnReason } from "../../../../../hooks/api/return-reasons"
|
||||
|
||||
const ReturnReasonCreateSchema = z.object({
|
||||
value: z.string().min(1),
|
||||
label: z.string().min(1),
|
||||
description: z.string().optional(),
|
||||
})
|
||||
|
||||
export const ReturnReasonCreateForm = () => {
|
||||
const { t } = useTranslation()
|
||||
const { handleSuccess } = useRouteModal()
|
||||
|
||||
const form = useForm<z.infer<typeof ReturnReasonCreateSchema>>({
|
||||
defaultValues: {
|
||||
value: "",
|
||||
label: "",
|
||||
description: "",
|
||||
},
|
||||
resolver: zodResolver(ReturnReasonCreateSchema),
|
||||
})
|
||||
|
||||
const { mutateAsync, isPending } = useCreateReturnReason()
|
||||
|
||||
const handleSubmit = form.handleSubmit(async (data) => {
|
||||
await mutateAsync(data, {
|
||||
onSuccess: ({ return_reason }) => {
|
||||
toast.success(
|
||||
t("returnReasons.create.successToast", {
|
||||
label: return_reason.label,
|
||||
})
|
||||
)
|
||||
handleSuccess(`../`)
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(error.message)
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
return (
|
||||
<RouteFocusModal.Form form={form}>
|
||||
<form
|
||||
className="flex size-full flex-col overflow-hidden"
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<RouteFocusModal.Header />
|
||||
<RouteFocusModal.Body className="flex flex-1 justify-center overflow-auto px-6 py-16">
|
||||
<div className="flex w-full max-w-[720px] flex-col gap-y-8">
|
||||
<div className="flex flex-col gap-y-1">
|
||||
<RouteFocusModal.Title asChild>
|
||||
<Heading>{t("returnReasons.create.header")}</Heading>
|
||||
</RouteFocusModal.Title>
|
||||
<RouteFocusModal.Description asChild>
|
||||
<Text size="small" className="text-ui-fg-subtle">
|
||||
{t("returnReasons.create.subtitle")}
|
||||
</Text>
|
||||
</RouteFocusModal.Description>
|
||||
</div>
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="value"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label
|
||||
tooltip={t("returnReasons.fields.value.tooltip")}
|
||||
>
|
||||
{t("returnReasons.fields.value.label")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t(
|
||||
"returnReasons.fields.value.placeholder"
|
||||
)}
|
||||
/>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="label"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t("returnReasons.fields.label.label")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t(
|
||||
"returnReasons.fields.label.placeholder"
|
||||
)}
|
||||
/>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="description"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label optional>
|
||||
{t("returnReasons.fields.description.label")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<Textarea
|
||||
{...field}
|
||||
placeholder={t(
|
||||
"returnReasons.fields.description.placeholder"
|
||||
)}
|
||||
/>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</RouteFocusModal.Body>
|
||||
<RouteFocusModal.Footer>
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
<RouteFocusModal.Close asChild>
|
||||
<Button size="small" variant="secondary" type="button">
|
||||
{t("actions.cancel")}
|
||||
</Button>
|
||||
</RouteFocusModal.Close>
|
||||
<Button size="small" type="submit" isLoading={isPending}>
|
||||
{t("actions.save")}
|
||||
</Button>
|
||||
</div>
|
||||
</RouteFocusModal.Footer>
|
||||
</form>
|
||||
</RouteFocusModal.Form>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { ReturnReasonCreate as Component } from "./return-reason-create"
|
||||
@@ -0,0 +1,10 @@
|
||||
import { RouteFocusModal } from "../../../components/modals"
|
||||
import { ReturnReasonCreateForm } from "./components/return-reason-create-form"
|
||||
|
||||
export const ReturnReasonCreate = () => {
|
||||
return (
|
||||
<RouteFocusModal>
|
||||
<ReturnReasonCreateForm />
|
||||
</RouteFocusModal>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./return-reason-edit-form"
|
||||
@@ -0,0 +1,140 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import { Button, Input, 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 { RouteDrawer, useRouteModal } from "../../../../../components/modals"
|
||||
import { useUpdateReturnReason } from "../../../../../hooks/api/return-reasons"
|
||||
|
||||
type ReturnReasonEditFormProps = {
|
||||
returnReason: HttpTypes.AdminReturnReason
|
||||
}
|
||||
|
||||
const ReturnReasonEditSchema = z.object({
|
||||
value: z.string().min(1),
|
||||
label: z.string().min(1),
|
||||
description: z.string().optional(),
|
||||
})
|
||||
|
||||
export const ReturnReasonEditForm = ({
|
||||
returnReason,
|
||||
}: ReturnReasonEditFormProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { handleSuccess } = useRouteModal()
|
||||
|
||||
const form = useForm<z.infer<typeof ReturnReasonEditSchema>>({
|
||||
defaultValues: {
|
||||
value: returnReason.value,
|
||||
label: returnReason.label,
|
||||
description: returnReason.description ?? undefined,
|
||||
},
|
||||
resolver: zodResolver(ReturnReasonEditSchema),
|
||||
})
|
||||
|
||||
const { mutateAsync, isPending } = useUpdateReturnReason(returnReason.id)
|
||||
|
||||
const handleSubmit = form.handleSubmit(async (data) => {
|
||||
await mutateAsync(data, {
|
||||
onSuccess: ({ return_reason }) => {
|
||||
toast.success(
|
||||
t("returnReasons.edit.successToast", {
|
||||
label: return_reason.label,
|
||||
})
|
||||
)
|
||||
handleSuccess()
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(error.message)
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
return (
|
||||
<RouteDrawer.Form form={form}>
|
||||
<form
|
||||
className="flex size-full flex-col overflow-hidden"
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<RouteDrawer.Body className="flex flex-1 flex-col gap-y-4 overflow-auto">
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="value"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label tooltip={t("returnReasons.fields.value.tooltip")}>
|
||||
{t("returnReasons.fields.value.label")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("returnReasons.fields.value.placeholder")}
|
||||
/>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="label"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t("returnReasons.fields.label.label")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("returnReasons.fields.label.placeholder")}
|
||||
/>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="description"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label optional>
|
||||
{t("returnReasons.fields.description.label")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<Textarea
|
||||
{...field}
|
||||
placeholder={t(
|
||||
"returnReasons.fields.description.placeholder"
|
||||
)}
|
||||
/>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</RouteDrawer.Body>
|
||||
<RouteDrawer.Footer>
|
||||
<div className="flex items-center justify-end gap-x-2">
|
||||
<RouteDrawer.Close asChild>
|
||||
<Button variant="secondary" size="small" type="button">
|
||||
{t("actions.cancel")}
|
||||
</Button>
|
||||
</RouteDrawer.Close>
|
||||
<Button size="small" type="submit" isLoading={isPending}>
|
||||
{t("actions.save")}
|
||||
</Button>
|
||||
</div>
|
||||
</RouteDrawer.Footer>
|
||||
</form>
|
||||
</RouteDrawer.Form>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { ReturnReasonEdit as Component } from "./return-reason-edit"
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Heading } from "@medusajs/ui"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { useParams } from "react-router-dom"
|
||||
import { RouteDrawer } from "../../../components/modals"
|
||||
import { useReturnReason } from "../../../hooks/api/return-reasons"
|
||||
import { ReturnReasonEditForm } from "./components/return-reason-edit-form"
|
||||
|
||||
export const ReturnReasonEdit = () => {
|
||||
const { id } = useParams()
|
||||
const { t } = useTranslation()
|
||||
|
||||
const { return_reason, isPending, isError, error } = useReturnReason(id!)
|
||||
|
||||
const ready = !isPending && !!return_reason
|
||||
|
||||
if (isError) {
|
||||
throw error
|
||||
}
|
||||
|
||||
return (
|
||||
<RouteDrawer>
|
||||
<RouteDrawer.Header>
|
||||
<RouteDrawer.Title asChild>
|
||||
<Heading>{t("returnReasons.edit.header")}</Heading>
|
||||
</RouteDrawer.Title>
|
||||
<RouteDrawer.Description className="sr-only">
|
||||
{t("returnReasons.edit.subtitle")}
|
||||
</RouteDrawer.Description>
|
||||
</RouteDrawer.Header>
|
||||
{ready && <ReturnReasonEditForm returnReason={return_reason} />}
|
||||
</RouteDrawer>
|
||||
)
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Trash } from "@medusajs/icons"
|
||||
import { PencilSquare, Trash } from "@medusajs/icons"
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import { Button, Container, Heading } from "@medusajs/ui"
|
||||
import { Button, Container, Heading, Text } from "@medusajs/ui"
|
||||
import { keepPreviousData } from "@tanstack/react-query"
|
||||
import { createColumnHelper } from "@tanstack/react-table"
|
||||
import { useMemo } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { Link, useLoaderData } from "react-router-dom"
|
||||
import { Link } from "react-router-dom"
|
||||
|
||||
import { ActionMenu } from "../../../../../components/common/action-menu"
|
||||
import { DataTable } from "../../../../../components/table/data-table"
|
||||
@@ -14,7 +14,6 @@ import { useReturnReasonTableColumns } from "../../../../../hooks/table/columns"
|
||||
import { useReturnReasonTableQuery } from "../../../../../hooks/table/query"
|
||||
import { useDataTable } from "../../../../../hooks/use-data-table"
|
||||
import { useDeleteReturnReasonAction } from "../../../common/hooks/use-delete-return-reason-action"
|
||||
import { returnReasonListLoader } from "../../loader"
|
||||
|
||||
const PAGE_SIZE = 20
|
||||
|
||||
@@ -24,14 +23,9 @@ export const ReturnReasonListTable = () => {
|
||||
pageSize: PAGE_SIZE,
|
||||
})
|
||||
|
||||
const initialData = useLoaderData() as Awaited<
|
||||
ReturnType<typeof returnReasonListLoader>
|
||||
>
|
||||
|
||||
const { return_reasons, count, isPending, isError, error } = useReturnReasons(
|
||||
searchParams,
|
||||
{
|
||||
initialData,
|
||||
placeholderData: keepPreviousData,
|
||||
}
|
||||
)
|
||||
@@ -53,7 +47,12 @@ export const ReturnReasonListTable = () => {
|
||||
return (
|
||||
<Container className="divide-y px-0 py-0">
|
||||
<div className="flex items-center justify-between px-6 py-4">
|
||||
<Heading>{t("returnReasons.domain")}</Heading>
|
||||
<div>
|
||||
<Heading>{t("returnReasons.domain")}</Heading>
|
||||
<Text className="text-ui-fg-subtle" size="small">
|
||||
{t("returnReasons.subtitle")}
|
||||
</Text>
|
||||
</div>
|
||||
<Button variant="secondary" size="small" asChild>
|
||||
<Link to="create">{t("actions.create")}</Link>
|
||||
</Button>
|
||||
@@ -65,7 +64,9 @@ export const ReturnReasonListTable = () => {
|
||||
isLoading={isPending}
|
||||
columns={columns}
|
||||
pageSize={PAGE_SIZE}
|
||||
noHeader={true}
|
||||
pagination
|
||||
search
|
||||
/>
|
||||
</Container>
|
||||
)
|
||||
@@ -84,7 +85,7 @@ const ReturnReasonRowActions = ({
|
||||
return (
|
||||
<ActionMenu
|
||||
groups={[
|
||||
/* {
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
icon: <PencilSquare />,
|
||||
@@ -92,7 +93,7 @@ const ReturnReasonRowActions = ({
|
||||
to: `${returnReason.id}/edit`,
|
||||
},
|
||||
],
|
||||
}, */
|
||||
},
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
|
||||
@@ -2489,25 +2489,29 @@ export interface FilterableOrderItemProps
|
||||
*/
|
||||
export interface FilterableOrderReturnReasonProps
|
||||
extends BaseFilterable<FilterableOrderReturnReasonProps> {
|
||||
/**
|
||||
* Find return reasons through this search term
|
||||
*/
|
||||
q?: string
|
||||
/**
|
||||
* The IDs to filter the return reasons by.
|
||||
*/
|
||||
id?: string | string[]
|
||||
id?: string | string[] | OperatorMap<string | string[]>
|
||||
|
||||
/**
|
||||
* Filter the return reason by their value.
|
||||
*/
|
||||
value?: string | string[]
|
||||
value?: string | string[] | OperatorMap<string | string[]>
|
||||
|
||||
/**
|
||||
* Filter the return reason by their label.
|
||||
*/
|
||||
label?: string
|
||||
label?: string | OperatorMap<string>
|
||||
|
||||
/**
|
||||
* Filter the return reason by their description.
|
||||
*/
|
||||
description?: string
|
||||
description?: string | OperatorMap<string>
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { DAL } from "@medusajs/types"
|
||||
import {
|
||||
DALUtils,
|
||||
Searchable,
|
||||
createPsqlIndexStatementHelper,
|
||||
generateEntityId,
|
||||
} from "@medusajs/utils"
|
||||
@@ -46,10 +47,12 @@ export default class ReturnReason {
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
id: string
|
||||
|
||||
@Searchable()
|
||||
@Property({ columnType: "text" })
|
||||
@ValueIndex.MikroORMIndex()
|
||||
value: string
|
||||
|
||||
@Searchable()
|
||||
@Property({ columnType: "text" })
|
||||
label: string
|
||||
|
||||
@@ -67,7 +70,7 @@ export default class ReturnReason {
|
||||
cascade: [Cascade.PERSIST],
|
||||
})
|
||||
parent_return_reason?: Rel<ReturnReason> | null
|
||||
|
||||
Searchable
|
||||
@OneToMany(
|
||||
() => ReturnReason,
|
||||
(return_reason) => return_reason.parent_return_reason,
|
||||
|
||||
Reference in New Issue
Block a user