fix(dashboard,medusa,fulfillment): Move Shipping Profiles to settings (#7090)
**What** - Moves Shipping Profiles to settings - Adds `q` and filters to shipping profile list endpoint - Adds new details page for profiles
This commit is contained in:
1 parent
9bd2d30595
commit
e2fabc1c05
31 files changed
+536
-136
No files matched your search
@@ -84,7 +84,9 @@
|
|||||||
"lastThirtyDays": "Last 30 days",
|
"lastThirtyDays": "Last 30 days",
|
||||||
"lastNinetyDays": "Last 90 days",
|
"lastNinetyDays": "Last 90 days",
|
||||||
"lastTwelveMonths": "Last 12 months",
|
"lastTwelveMonths": "Last 12 months",
|
||||||
"custom": "Custom"
|
"custom": "Custom",
|
||||||
|
"from": "From",
|
||||||
|
"to": "To"
|
||||||
},
|
},
|
||||||
"compare": {
|
"compare": {
|
||||||
"lessThan": "Less than",
|
"lessThan": "Less than",
|
||||||
@@ -673,10 +675,19 @@
|
|||||||
},
|
},
|
||||||
"shippingProfile": {
|
"shippingProfile": {
|
||||||
"domain": "Shipping Profiles",
|
"domain": "Shipping Profiles",
|
||||||
"title": "Create a shipping profile",
|
"create": {
|
||||||
"detailsHint": "Specify the details of the shipping profile",
|
"header": "Create Shipping Profile",
|
||||||
"deleteWaring": "You are about to delete the profile: {{name}}. This action cannot be undone.",
|
"hint": "Create a new shipping profile to group products with similar shipping requirements.",
|
||||||
"typeHint": "Enter shipping profile type, for example: Express, Freight, etc."
|
"successToast": "Shipping profile {{name}} was successfully created."
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"title": "Delete Shipping Profile",
|
||||||
|
"description": "You are about to delete the shipping profile {{name}}. This action cannot be undone.",
|
||||||
|
"successToast": "Shipping profile {{name}} was successfully deleted."
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"type": "Enter shipping profile type, for example: Express, Freight, etc."
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"discounts": {
|
"discounts": {
|
||||||
"domain": "Discounts",
|
"domain": "Discounts",
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { Text } from "@medusajs/ui"
|
import { Text, clx } from "@medusajs/ui"
|
||||||
|
import { ReactNode } from "react"
|
||||||
|
|
||||||
export type SectionRowProps = {
|
export type SectionRowProps = {
|
||||||
title: string
|
title: string
|
||||||
value?: React.ReactNode | string | null
|
value?: ReactNode | string | null
|
||||||
actions?: React.ReactNode
|
actions?: ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SectionRow = ({ title, value, actions }: SectionRowProps) => {
|
export const SectionRow = ({ title, value, actions }: SectionRowProps) => {
|
||||||
@@ -11,9 +12,12 @@ export const SectionRow = ({ title, value, actions }: SectionRowProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`text-ui-fg-subtle grid ${
|
className={clx(
|
||||||
!!actions ? "grid-cols-[1fr_1fr_28px]" : "grid-cols-2"
|
`text-ui-fg-subtle grid grid-cols-2 items-center px-6 py-4`,
|
||||||
} items-center px-6 py-4`}
|
{
|
||||||
|
"grid-cols-[1fr_1fr_28px]": !!actions,
|
||||||
|
}
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<Text size="small" weight="plus" leading="compact">
|
<Text size="small" weight="plus" leading="compact">
|
||||||
{title}
|
{title}
|
||||||
|
|||||||
@@ -1,16 +1,151 @@
|
|||||||
import { clx } from "@medusajs/ui"
|
import { Container, Heading, Text, clx } from "@medusajs/ui"
|
||||||
|
import { CSSProperties, ComponentPropsWithoutRef } from "react"
|
||||||
|
|
||||||
type SkeletonProps = {
|
type SkeletonProps = {
|
||||||
className?: string
|
className?: string
|
||||||
|
style?: CSSProperties
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Skeleton = ({ className }: SkeletonProps) => {
|
export const Skeleton = ({ className, style }: SkeletonProps) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
aria-hidden
|
||||||
className={clx(
|
className={clx(
|
||||||
"bg-ui-bg-component h-3 w-3 animate-pulse rounded-[4px]",
|
"bg-ui-bg-component h-3 w-3 animate-pulse rounded-[4px]",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
style={style}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TextSkeletonProps = {
|
||||||
|
size?: ComponentPropsWithoutRef<typeof Text>["size"]
|
||||||
|
leading?: ComponentPropsWithoutRef<typeof Text>["leading"]
|
||||||
|
characters?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
type HeadingSkeletonProps = {
|
||||||
|
level?: ComponentPropsWithoutRef<typeof Heading>["level"]
|
||||||
|
characters?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const HeadingSkeleton = ({
|
||||||
|
level = "h1",
|
||||||
|
characters = 10,
|
||||||
|
}: HeadingSkeletonProps) => {
|
||||||
|
let charWidth = 9
|
||||||
|
|
||||||
|
switch (level) {
|
||||||
|
case "h1":
|
||||||
|
charWidth = 11
|
||||||
|
break
|
||||||
|
case "h2":
|
||||||
|
charWidth = 10
|
||||||
|
break
|
||||||
|
case "h3":
|
||||||
|
charWidth = 9
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Skeleton
|
||||||
|
className={clx({
|
||||||
|
"h-7": level === "h1",
|
||||||
|
"h-6": level === "h2",
|
||||||
|
"h-5": level === "h3",
|
||||||
|
})}
|
||||||
|
style={{
|
||||||
|
width: `${charWidth * characters}px`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TextSkeleton = ({
|
||||||
|
size = "small",
|
||||||
|
leading = "compact",
|
||||||
|
characters = 10,
|
||||||
|
}: TextSkeletonProps) => {
|
||||||
|
let charWidth = 9
|
||||||
|
|
||||||
|
switch (size) {
|
||||||
|
case "xlarge":
|
||||||
|
charWidth = 13
|
||||||
|
break
|
||||||
|
case "large":
|
||||||
|
charWidth = 11
|
||||||
|
break
|
||||||
|
case "base":
|
||||||
|
charWidth = 10
|
||||||
|
break
|
||||||
|
case "small":
|
||||||
|
charWidth = 9
|
||||||
|
break
|
||||||
|
case "xsmall":
|
||||||
|
charWidth = 8
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Skeleton
|
||||||
|
className={clx({
|
||||||
|
"h-5": size === "xsmall",
|
||||||
|
"h-6": size === "small",
|
||||||
|
"h-7": size === "base",
|
||||||
|
"h-8": size === "xlarge",
|
||||||
|
"!h-5": leading === "compact",
|
||||||
|
})}
|
||||||
|
style={{
|
||||||
|
width: `${charWidth * characters}px`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const IconButtonSkeleton = () => {
|
||||||
|
return <Skeleton className="h-7 w-7 rounded-md" />
|
||||||
|
}
|
||||||
|
|
||||||
|
type GeneralSectionSkeletonProps = {
|
||||||
|
rowCount?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GeneralSectionSkeleton = ({
|
||||||
|
rowCount,
|
||||||
|
}: GeneralSectionSkeletonProps) => {
|
||||||
|
const rows = Array.from({ length: rowCount ?? 0 }, (_, i) => i)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container className="divide-y p-0" aria-hidden>
|
||||||
|
<div className="flex items-center justify-between px-6 py-4">
|
||||||
|
<HeadingSkeleton characters={16} />
|
||||||
|
<IconButtonSkeleton />
|
||||||
|
</div>
|
||||||
|
{rows.map((row) => (
|
||||||
|
<div
|
||||||
|
key={row}
|
||||||
|
className="grid grid-cols-2 items-center px-6 py-4"
|
||||||
|
aria-hidden
|
||||||
|
>
|
||||||
|
<TextSkeleton size="small" leading="compact" characters={12} />
|
||||||
|
<TextSkeleton size="small" leading="compact" characters={24} />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const JsonViewSectionSkeleton = () => {
|
||||||
|
return (
|
||||||
|
<Container className="divide-y p-0" aria-hidden>
|
||||||
|
<div className="flex items-center justify-between px-6 py-4" aria-hidden>
|
||||||
|
<div aria-hidden className="flex items-center gap-x-4">
|
||||||
|
<HeadingSkeleton level="h2" characters={16} />
|
||||||
|
<Skeleton className="h-5 w-12 rounded-md" />
|
||||||
|
</div>
|
||||||
|
<IconButtonSkeleton />
|
||||||
|
</div>
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -148,12 +148,6 @@ const useCoreRoutes = (): Omit<NavItemProps, "pathname">[] => {
|
|||||||
icon: <Envelope />,
|
icon: <Envelope />,
|
||||||
label: t("shipping.domain"),
|
label: t("shipping.domain"),
|
||||||
to: "/shipping",
|
to: "/shipping",
|
||||||
items: [
|
|
||||||
{
|
|
||||||
label: t("shippingProfile.domain"),
|
|
||||||
to: "/shipping-profiles",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -53,6 +53,10 @@ const useSettingRoutes = (): NavItemProps[] => {
|
|||||||
label: t("salesChannels.domain"),
|
label: t("salesChannels.domain"),
|
||||||
to: "/settings/sales-channels",
|
to: "/settings/sales-channels",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: t("shippingProfile.domain"),
|
||||||
|
to: "/settings/shipping-profiles",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
[t]
|
[t]
|
||||||
)
|
)
|
||||||
|
|||||||
+21
-19
@@ -1,12 +1,12 @@
|
|||||||
import { EllipseMiniSolid, XMarkMini } from "@medusajs/icons"
|
import { EllipseMiniSolid, XMarkMini } from "@medusajs/icons"
|
||||||
import { DatePicker, Text, clx } from "@medusajs/ui"
|
import { DatePicker, Text, clx } from "@medusajs/ui"
|
||||||
import * as Popover from "@radix-ui/react-popover"
|
import * as Popover from "@radix-ui/react-popover"
|
||||||
import { format } from "date-fns"
|
|
||||||
import isEqual from "lodash/isEqual"
|
import isEqual from "lodash/isEqual"
|
||||||
import { MouseEvent, useMemo, useState } from "react"
|
import { MouseEvent, useMemo, useState } from "react"
|
||||||
|
|
||||||
import { t } from "i18next"
|
import { t } from "i18next"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
|
import { useDate } from "../../../../hooks/use-date"
|
||||||
import { useSelectedParams } from "../hooks"
|
import { useSelectedParams } from "../hooks"
|
||||||
import { useDataTableFilterContext } from "./context"
|
import { useDataTableFilterContext } from "./context"
|
||||||
import { IFilter } from "./types"
|
import { IFilter } from "./types"
|
||||||
@@ -17,19 +17,19 @@ type DateComparisonOperator = {
|
|||||||
/**
|
/**
|
||||||
* The filtered date must be greater than or equal to this value.
|
* The filtered date must be greater than or equal to this value.
|
||||||
*/
|
*/
|
||||||
gte?: string
|
$gte?: string
|
||||||
/**
|
/**
|
||||||
* The filtered date must be less than or equal to this value.
|
* The filtered date must be less than or equal to this value.
|
||||||
*/
|
*/
|
||||||
lte?: string
|
$lte?: string
|
||||||
/**
|
/**
|
||||||
* The filtered date must be less than this value.
|
* The filtered date must be less than this value.
|
||||||
*/
|
*/
|
||||||
lt?: string
|
$lt?: string
|
||||||
/**
|
/**
|
||||||
* The filtered date must be greater than this value.
|
* The filtered date must be greater than this value.
|
||||||
*/
|
*/
|
||||||
gt?: string
|
$gt?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DateFilter = ({
|
export const DateFilter = ({
|
||||||
@@ -40,6 +40,8 @@ export const DateFilter = ({
|
|||||||
const [open, setOpen] = useState(openOnMount)
|
const [open, setOpen] = useState(openOnMount)
|
||||||
const [showCustom, setShowCustom] = useState(false)
|
const [showCustom, setShowCustom] = useState(false)
|
||||||
|
|
||||||
|
const { getFullDate } = useDate()
|
||||||
|
|
||||||
const { key, label } = filter
|
const { key, label } = filter
|
||||||
|
|
||||||
const { removeFilter } = useDataTableFilterContext()
|
const { removeFilter } = useDataTableFilterContext()
|
||||||
@@ -60,14 +62,14 @@ export const DateFilter = ({
|
|||||||
const currentValue = selectedParams.get()
|
const currentValue = selectedParams.get()
|
||||||
|
|
||||||
const currentDateComparison = parseDateComparison(currentValue)
|
const currentDateComparison = parseDateComparison(currentValue)
|
||||||
const customStartValue = getDateFromComparison(currentDateComparison, "gte")
|
const customStartValue = getDateFromComparison(currentDateComparison, "$gte")
|
||||||
const customEndValue = getDateFromComparison(currentDateComparison, "lte")
|
const customEndValue = getDateFromComparison(currentDateComparison, "$lte")
|
||||||
|
|
||||||
const handleCustomDateChange = (
|
const handleCustomDateChange = (
|
||||||
value: Date | undefined,
|
value: Date | undefined,
|
||||||
pos: "start" | "end"
|
pos: "start" | "end"
|
||||||
) => {
|
) => {
|
||||||
const key = pos === "start" ? "gte" : "lte"
|
const key = pos === "start" ? "$gte" : "$lte"
|
||||||
const dateValue = value ? value.toISOString() : undefined
|
const dateValue = value ? value.toISOString() : undefined
|
||||||
|
|
||||||
selectedParams.add(
|
selectedParams.add(
|
||||||
@@ -84,7 +86,7 @@ export const DateFilter = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const formatCustomDate = (date: Date | undefined) => {
|
const formatCustomDate = (date: Date | undefined) => {
|
||||||
return date ? format(date, "dd MMM, yyyy") : undefined
|
return date ? getFullDate({ date: date }) : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const getCustomDisplayValue = () => {
|
const getCustomDisplayValue = () => {
|
||||||
@@ -194,12 +196,12 @@ export const DateFilter = ({
|
|||||||
<div>
|
<div>
|
||||||
<div className="px-2 py-1">
|
<div className="px-2 py-1">
|
||||||
<Text size="xsmall" leading="compact" weight="plus">
|
<Text size="xsmall" leading="compact" weight="plus">
|
||||||
Starting
|
{t("filters.date.from")}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-2 py-1">
|
<div className="px-2 py-1">
|
||||||
<DatePicker
|
<DatePicker
|
||||||
placeholder="MM/DD/YYYY"
|
// placeholder="MM/DD/YYYY" TODO: Fix DatePicker component not working with placeholder
|
||||||
toDate={customEndValue}
|
toDate={customEndValue}
|
||||||
value={customStartValue}
|
value={customStartValue}
|
||||||
onChange={(d) => handleCustomDateChange(d, "start")}
|
onChange={(d) => handleCustomDateChange(d, "start")}
|
||||||
@@ -209,12 +211,12 @@ export const DateFilter = ({
|
|||||||
<div>
|
<div>
|
||||||
<div className="px-2 py-1">
|
<div className="px-2 py-1">
|
||||||
<Text size="xsmall" leading="compact" weight="plus">
|
<Text size="xsmall" leading="compact" weight="plus">
|
||||||
Ending
|
{t("filters.date.to")}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-2 py-1">
|
<div className="px-2 py-1">
|
||||||
<DatePicker
|
<DatePicker
|
||||||
placeholder="MM/DD/YYYY"
|
// placeholder="MM/DD/YYYY"
|
||||||
fromDate={customStartValue}
|
fromDate={customStartValue}
|
||||||
value={customEndValue || undefined}
|
value={customEndValue || undefined}
|
||||||
onChange={(d) => {
|
onChange={(d) => {
|
||||||
@@ -301,13 +303,13 @@ const usePresets = () => {
|
|||||||
{
|
{
|
||||||
label: t("filters.date.today"),
|
label: t("filters.date.today"),
|
||||||
value: {
|
value: {
|
||||||
gte: today.toISOString(),
|
$gte: today.toISOString(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t("filters.date.lastSevenDays"),
|
label: t("filters.date.lastSevenDays"),
|
||||||
value: {
|
value: {
|
||||||
gte: new Date(
|
$gte: new Date(
|
||||||
today.getTime() - 7 * 24 * 60 * 60 * 1000
|
today.getTime() - 7 * 24 * 60 * 60 * 1000
|
||||||
).toISOString(), // 7 days ago
|
).toISOString(), // 7 days ago
|
||||||
},
|
},
|
||||||
@@ -315,7 +317,7 @@ const usePresets = () => {
|
|||||||
{
|
{
|
||||||
label: t("filters.date.lastThirtyDays"),
|
label: t("filters.date.lastThirtyDays"),
|
||||||
value: {
|
value: {
|
||||||
gte: new Date(
|
$gte: new Date(
|
||||||
today.getTime() - 30 * 24 * 60 * 60 * 1000
|
today.getTime() - 30 * 24 * 60 * 60 * 1000
|
||||||
).toISOString(), // 30 days ago
|
).toISOString(), // 30 days ago
|
||||||
},
|
},
|
||||||
@@ -323,7 +325,7 @@ const usePresets = () => {
|
|||||||
{
|
{
|
||||||
label: t("filters.date.lastNinetyDays"),
|
label: t("filters.date.lastNinetyDays"),
|
||||||
value: {
|
value: {
|
||||||
gte: new Date(
|
$gte: new Date(
|
||||||
today.getTime() - 90 * 24 * 60 * 60 * 1000
|
today.getTime() - 90 * 24 * 60 * 60 * 1000
|
||||||
).toISOString(), // 90 days ago
|
).toISOString(), // 90 days ago
|
||||||
},
|
},
|
||||||
@@ -331,7 +333,7 @@ const usePresets = () => {
|
|||||||
{
|
{
|
||||||
label: t("filters.date.lastTwelveMonths"),
|
label: t("filters.date.lastTwelveMonths"),
|
||||||
value: {
|
value: {
|
||||||
gte: new Date(
|
$gte: new Date(
|
||||||
today.getTime() - 365 * 24 * 60 * 60 * 1000
|
today.getTime() - 365 * 24 * 60 * 60 * 1000
|
||||||
).toISOString(), // 365 days ago
|
).toISOString(), // 365 days ago
|
||||||
},
|
},
|
||||||
@@ -349,7 +351,7 @@ const parseDateComparison = (value: string[]) => {
|
|||||||
|
|
||||||
const getDateFromComparison = (
|
const getDateFromComparison = (
|
||||||
comparison: DateComparisonOperator | null,
|
comparison: DateComparisonOperator | null,
|
||||||
key: "gte" | "lte"
|
key: "$gte" | "$lte"
|
||||||
) => {
|
) => {
|
||||||
return comparison?.[key] ? new Date(comparison[key] as string) : undefined
|
return comparison?.[key] ? new Date(comparison[key] as string) : undefined
|
||||||
}
|
}
|
||||||
@@ -7,11 +7,11 @@ import {
|
|||||||
} from "@tanstack/react-query"
|
} from "@tanstack/react-query"
|
||||||
import { CreateShippingProfileReq } from "../../types/api-payloads"
|
import { CreateShippingProfileReq } from "../../types/api-payloads"
|
||||||
import {
|
import {
|
||||||
ShippingProfileDeleteRes,
|
|
||||||
ShippingProfileListRes,
|
ShippingProfileListRes,
|
||||||
ShippingProfileRes,
|
ShippingProfileRes,
|
||||||
} from "../../types/api-responses"
|
} from "../../types/api-responses"
|
||||||
|
|
||||||
|
import { DeleteResponse } from "@medusajs/types"
|
||||||
import { client } from "../../lib/client"
|
import { client } from "../../lib/client"
|
||||||
import { queryClient } from "../../lib/medusa"
|
import { queryClient } from "../../lib/medusa"
|
||||||
import { queryKeysFactory } from "../../lib/query-key-factory"
|
import { queryKeysFactory } from "../../lib/query-key-factory"
|
||||||
@@ -41,6 +41,25 @@ export const useCreateShippingProfile = (
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useShippingProfile = (
|
||||||
|
id: string,
|
||||||
|
query?: Record<string, any>,
|
||||||
|
options?: UseQueryOptions<
|
||||||
|
ShippingProfileRes,
|
||||||
|
Error,
|
||||||
|
ShippingProfileRes,
|
||||||
|
QueryKey
|
||||||
|
>
|
||||||
|
) => {
|
||||||
|
const { data, ...rest } = useQuery({
|
||||||
|
queryFn: () => client.shippingProfiles.retrieve(id, query),
|
||||||
|
queryKey: shippingProfileQueryKeys.detail(id, query),
|
||||||
|
...options,
|
||||||
|
})
|
||||||
|
|
||||||
|
return { ...data, ...rest }
|
||||||
|
}
|
||||||
|
|
||||||
export const useShippingProfiles = (
|
export const useShippingProfiles = (
|
||||||
query?: Record<string, any>,
|
query?: Record<string, any>,
|
||||||
options?: Omit<
|
options?: Omit<
|
||||||
@@ -64,11 +83,11 @@ export const useShippingProfiles = (
|
|||||||
|
|
||||||
export const useDeleteShippingProfile = (
|
export const useDeleteShippingProfile = (
|
||||||
profileId: string,
|
profileId: string,
|
||||||
options?: UseMutationOptions<ShippingProfileDeleteRes, Error, void>
|
options?: UseMutationOptions<DeleteResponse, Error, void>
|
||||||
) => {
|
) => {
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: () => client.shippingProfiles.delete(profileId),
|
mutationFn: () => client.shippingProfiles.delete(profileId),
|
||||||
onSuccess: (data: any, variables: any, context: any) => {
|
onSuccess: (data, variables, context) => {
|
||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
queryKey: shippingProfileQueryKeys.lists(),
|
queryKey: shippingProfileQueryKeys.lists(),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,27 +1,35 @@
|
|||||||
import { deleteRequest, getRequest, postRequest } from "./common"
|
|
||||||
import { CreateShippingProfileReq } from "../../types/api-payloads"
|
import { CreateShippingProfileReq } from "../../types/api-payloads"
|
||||||
import {
|
import {
|
||||||
ShippingProfileDeleteRes,
|
ShippingProfileDeleteRes,
|
||||||
ShippingProfileListRes,
|
ShippingProfileListRes,
|
||||||
ShippingProfileRes,
|
ShippingProfileRes,
|
||||||
} from "../../types/api-responses"
|
} from "../../types/api-responses"
|
||||||
|
import { deleteRequest, getRequest, postRequest } from "./common"
|
||||||
|
|
||||||
async function createShippingProfile(payload: CreateShippingProfileReq) {
|
async function createShippingProfile(payload: CreateShippingProfileReq) {
|
||||||
return postRequest<ShippingProfileRes>(`/admin/shipping-profiles`, payload)
|
return postRequest<ShippingProfileRes>(`/admin/shipping-profiles`, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function retrieveShippingProfile(
|
||||||
|
id: string,
|
||||||
|
query?: Record<string, any>
|
||||||
|
) {
|
||||||
|
return getRequest<ShippingProfileRes>(`/admin/shipping-profiles/${id}`, query)
|
||||||
|
}
|
||||||
|
|
||||||
async function listShippingProfiles(query?: Record<string, any>) {
|
async function listShippingProfiles(query?: Record<string, any>) {
|
||||||
return getRequest<ShippingProfileListRes>(`/admin/shipping-profiles`, query)
|
return getRequest<ShippingProfileListRes>(`/admin/shipping-profiles`, query)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteShippingProfile(profileId: string) {
|
async function deleteShippingProfile(id: string) {
|
||||||
return deleteRequest<ShippingProfileDeleteRes>(
|
return deleteRequest<ShippingProfileDeleteRes>(
|
||||||
`/admin/shipping-profiles/${profileId}`
|
`/admin/shipping-profiles/${id}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const shippingProfiles = {
|
export const shippingProfiles = {
|
||||||
create: createShippingProfile,
|
retrieve: retrieveShippingProfile,
|
||||||
list: listShippingProfiles,
|
list: listShippingProfiles,
|
||||||
|
create: createShippingProfile,
|
||||||
delete: deleteShippingProfile,
|
delete: deleteShippingProfile,
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
import type {
|
import type {
|
||||||
AdminCustomerGroupsRes,
|
|
||||||
AdminCustomersRes,
|
|
||||||
AdminDiscountsRes,
|
AdminDiscountsRes,
|
||||||
AdminDraftOrdersRes,
|
AdminDraftOrdersRes,
|
||||||
AdminGiftCardsRes,
|
AdminGiftCardsRes,
|
||||||
|
|||||||
@@ -329,21 +329,6 @@ export const v2Routes: RouteObject[] = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: "shipping-profiles",
|
|
||||||
lazy: () =>
|
|
||||||
import("../../v2-routes/shipping/shipping-profiles-list"),
|
|
||||||
handle: {
|
|
||||||
crumb: () => "Shipping Profiles",
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: "create",
|
|
||||||
lazy: () =>
|
|
||||||
import("../../v2-routes/shipping/shipping-profile-create"),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: "/customers",
|
path: "/customers",
|
||||||
handle: {
|
handle: {
|
||||||
@@ -727,6 +712,38 @@ export const v2Routes: RouteObject[] = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "shipping-profiles",
|
||||||
|
element: <Outlet />,
|
||||||
|
handle: {
|
||||||
|
crumb: () => "Shipping Profiles",
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "",
|
||||||
|
lazy: () =>
|
||||||
|
import(
|
||||||
|
"../../v2-routes/shipping-profiles/shipping-profiles-list"
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "create",
|
||||||
|
lazy: () =>
|
||||||
|
import(
|
||||||
|
"../../v2-routes/shipping-profiles/shipping-profile-create"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ":id",
|
||||||
|
lazy: () =>
|
||||||
|
import(
|
||||||
|
"../../v2-routes/shipping-profiles/shipping-profile-detail"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "api-key-management",
|
path: "api-key-management",
|
||||||
element: <Outlet />,
|
element: <Outlet />,
|
||||||
|
|||||||
+7
-7
@@ -3,12 +3,12 @@ import { RegionDTO } from "@medusajs/types"
|
|||||||
import { Badge, Container, Heading, Text, usePrompt } from "@medusajs/ui"
|
import { Badge, Container, Heading, Text, usePrompt } from "@medusajs/ui"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
|
|
||||||
import { ActionMenu } from "../../../../../components/common/action-menu"
|
|
||||||
import { formatProvider } from "../../../../../lib/format-provider"
|
|
||||||
import { currencies } from "../../../../../lib/currencies"
|
|
||||||
import { useDeleteRegion } from "../../../../../hooks/api/regions.tsx"
|
|
||||||
import { ListSummary } from "../../../../../components/common/list-summary"
|
|
||||||
import { useNavigate } from "react-router-dom"
|
import { useNavigate } from "react-router-dom"
|
||||||
|
import { ActionMenu } from "../../../../../components/common/action-menu"
|
||||||
|
import { ListSummary } from "../../../../../components/common/list-summary"
|
||||||
|
import { useDeleteRegion } from "../../../../../hooks/api/regions.tsx"
|
||||||
|
import { currencies } from "../../../../../lib/currencies"
|
||||||
|
import { formatProvider } from "../../../../../lib/format-provider"
|
||||||
|
|
||||||
type RegionGeneralSectionProps = {
|
type RegionGeneralSectionProps = {
|
||||||
region: RegionDTO
|
region: RegionDTO
|
||||||
@@ -23,7 +23,7 @@ export const RegionGeneralSection = ({ region }: RegionGeneralSectionProps) => {
|
|||||||
<Heading>{region.name}</Heading>
|
<Heading>{region.name}</Heading>
|
||||||
<RegionActions region={region} />
|
<RegionActions region={region} />
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-2 items-center px-6 py-4">
|
<div className="text-ui-fg-subtle grid grid-cols-2 items-center px-6 py-4">
|
||||||
<Text size="small" leading="compact" weight="plus">
|
<Text size="small" leading="compact" weight="plus">
|
||||||
{t("fields.currency")}
|
{t("fields.currency")}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -36,7 +36,7 @@ export const RegionGeneralSection = ({ region }: RegionGeneralSectionProps) => {
|
|||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-2 items-center px-6 py-4">
|
<div className="text-ui-fg-subtle grid grid-cols-2 items-center px-6 py-4">
|
||||||
<Text size="small" leading="compact" weight="plus">
|
<Text size="small" leading="compact" weight="plus">
|
||||||
{t("fields.paymentProviders")}
|
{t("fields.paymentProviders")}
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
+31
-12
@@ -1,14 +1,14 @@
|
|||||||
import { Button, Heading, Input, Text } from "@medusajs/ui"
|
|
||||||
import { useForm } from "react-hook-form"
|
|
||||||
import * as zod from "zod"
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod"
|
import { zodResolver } from "@hookform/resolvers/zod"
|
||||||
|
import { Button, Heading, Input, Text, toast } from "@medusajs/ui"
|
||||||
|
import { useForm } from "react-hook-form"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
|
import * as zod from "zod"
|
||||||
|
|
||||||
|
import { Form } from "../../../../../components/common/form"
|
||||||
import {
|
import {
|
||||||
RouteFocusModal,
|
RouteFocusModal,
|
||||||
useRouteModal,
|
useRouteModal,
|
||||||
} from "../../../../../components/route-modal"
|
} from "../../../../../components/route-modal"
|
||||||
import { Form } from "../../../../../components/common/form"
|
|
||||||
import { useCreateShippingProfile } from "../../../../../hooks/api/shipping-profiles"
|
import { useCreateShippingProfile } from "../../../../../hooks/api/shipping-profiles"
|
||||||
|
|
||||||
const CreateShippingOptionsSchema = zod.object({
|
const CreateShippingOptionsSchema = zod.object({
|
||||||
@@ -31,11 +31,30 @@ export function CreateShippingProfileForm() {
|
|||||||
const { mutateAsync, isPending } = useCreateShippingProfile()
|
const { mutateAsync, isPending } = useCreateShippingProfile()
|
||||||
|
|
||||||
const handleSubmit = form.handleSubmit(async (values) => {
|
const handleSubmit = form.handleSubmit(async (values) => {
|
||||||
await mutateAsync({
|
await mutateAsync(
|
||||||
name: values.name,
|
{
|
||||||
type: values.type,
|
name: values.name,
|
||||||
})
|
type: values.type,
|
||||||
handleSuccess("/shipping-profiles")
|
},
|
||||||
|
{
|
||||||
|
onSuccess: ({ shipping_profile }) => {
|
||||||
|
toast.success(t("general.success"), {
|
||||||
|
description: t("shippingProfile.create.successToast", {
|
||||||
|
name: shipping_profile.name,
|
||||||
|
}),
|
||||||
|
dismissLabel: t("actions.close"),
|
||||||
|
})
|
||||||
|
|
||||||
|
handleSuccess(`/settings/shipping-profiles/${shipping_profile.id}`)
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast.error(t("general.error"), {
|
||||||
|
description: error.message,
|
||||||
|
dismissLabel: t("actions.close"),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -61,10 +80,10 @@ export function CreateShippingProfileForm() {
|
|||||||
<div className="mx-auto flex w-full max-w-[720px] flex-col gap-y-8 px-2 py-16">
|
<div className="mx-auto flex w-full max-w-[720px] flex-col gap-y-8 px-2 py-16">
|
||||||
<div>
|
<div>
|
||||||
<Heading className="capitalize">
|
<Heading className="capitalize">
|
||||||
{t("shippingProfile.title")}
|
{t("shippingProfile.create.header")}
|
||||||
</Heading>
|
</Heading>
|
||||||
<Text size="small" className="text-ui-fg-subtle">
|
<Text size="small" className="text-ui-fg-subtle">
|
||||||
{t("shippingProfile.detailsHint")}
|
{t("shippingProfile.create.hint")}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
@@ -89,7 +108,7 @@ export function CreateShippingProfileForm() {
|
|||||||
render={({ field }) => {
|
render={({ field }) => {
|
||||||
return (
|
return (
|
||||||
<Form.Item>
|
<Form.Item>
|
||||||
<Form.Label tooltip={t("shippingProfile.typeHint")}>
|
<Form.Label tooltip={t("shippingProfile.tooltip.type")}>
|
||||||
{t("fields.type")}
|
{t("fields.type")}
|
||||||
</Form.Label>
|
</Form.Label>
|
||||||
<Form.Control>
|
<Form.Control>
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
@@ -0,0 +1 @@
|
|||||||
|
export * from "./shipping-profile-general-section"
|
||||||
+80
@@ -0,0 +1,80 @@
|
|||||||
|
import { Trash } from "@medusajs/icons"
|
||||||
|
import { AdminShippingProfileResponse } from "@medusajs/types"
|
||||||
|
import { Container, Heading, toast, usePrompt } from "@medusajs/ui"
|
||||||
|
import { useTranslation } from "react-i18next"
|
||||||
|
import { useNavigate } from "react-router-dom"
|
||||||
|
import { ActionMenu } from "../../../../../components/common/action-menu"
|
||||||
|
import { SectionRow } from "../../../../../components/common/section"
|
||||||
|
import { useDeleteShippingProfile } from "../../../../../hooks/api/shipping-profiles"
|
||||||
|
|
||||||
|
type ShippingProfileGeneralSectionProps = {
|
||||||
|
profile: AdminShippingProfileResponse["shipping_profile"]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ShippingProfileGeneralSection = ({
|
||||||
|
profile,
|
||||||
|
}: ShippingProfileGeneralSectionProps) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const prompt = usePrompt()
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
const { mutateAsync } = useDeleteShippingProfile(profile.id)
|
||||||
|
|
||||||
|
const handleDelete = async () => {
|
||||||
|
const res = await prompt({
|
||||||
|
title: t("shippingProfile.delete.title"),
|
||||||
|
description: t("shippingProfile.delete.description", {
|
||||||
|
name: profile.name,
|
||||||
|
}),
|
||||||
|
verificationText: profile.name,
|
||||||
|
verificationInstruction: t("general.typeToConfirm"),
|
||||||
|
confirmText: t("actions.delete"),
|
||||||
|
cancelText: t("actions.cancel"),
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await mutateAsync(undefined, {
|
||||||
|
onSuccess: () => {
|
||||||
|
toast.success(t("general.success"), {
|
||||||
|
description: t("shippingProfile.delete.successToast", {
|
||||||
|
name: profile.name,
|
||||||
|
}),
|
||||||
|
dismissLabel: t("actions.close"),
|
||||||
|
})
|
||||||
|
|
||||||
|
navigate("/settings/shipping-profiles", { replace: true })
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast.error(t("general.error"), {
|
||||||
|
description: error.message,
|
||||||
|
dismissLabel: t("actions.close"),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container className="divide-y p-0">
|
||||||
|
<div className="flex items-center justify-between px-6 py-4">
|
||||||
|
<Heading>{profile.name}</Heading>
|
||||||
|
<ActionMenu
|
||||||
|
groups={[
|
||||||
|
{
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
icon: <Trash />,
|
||||||
|
label: t("actions.delete"),
|
||||||
|
onClick: handleDelete,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<SectionRow title={t("fields.type")} value={profile.type} />
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
export { ShippingProfileDetail as Component } from "./shipping-profile-detail"
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
import { useParams } from "react-router-dom"
|
||||||
|
import { JsonViewSection } from "../../../components/common/json-view-section"
|
||||||
|
import {
|
||||||
|
GeneralSectionSkeleton,
|
||||||
|
JsonViewSectionSkeleton,
|
||||||
|
} from "../../../components/common/skeleton"
|
||||||
|
import { useShippingProfile } from "../../../hooks/api/shipping-profiles"
|
||||||
|
import { ShippingProfileGeneralSection } from "./components/shipping-profile-general-section"
|
||||||
|
|
||||||
|
export const ShippingProfileDetail = () => {
|
||||||
|
const { id } = useParams()
|
||||||
|
|
||||||
|
const { shipping_profile, isLoading, isError, error } = useShippingProfile(
|
||||||
|
id!
|
||||||
|
)
|
||||||
|
|
||||||
|
if (isLoading || !shipping_profile) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-y-2">
|
||||||
|
<GeneralSectionSkeleton rowCount={1} />
|
||||||
|
<JsonViewSectionSkeleton />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isError) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-y-2">
|
||||||
|
<ShippingProfileGeneralSection profile={shipping_profile} />
|
||||||
|
<JsonViewSection data={shipping_profile} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
File renamed without changes.
+22
-7
@@ -1,7 +1,7 @@
|
|||||||
import { Trash } from "@medusajs/icons"
|
import { Trash } from "@medusajs/icons"
|
||||||
import { usePrompt } from "@medusajs/ui"
|
import { AdminShippingProfileResponse } from "@medusajs/types"
|
||||||
|
import { toast, usePrompt } from "@medusajs/ui"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import { ShippingProfileDTO } from "@medusajs/types"
|
|
||||||
|
|
||||||
import { ActionMenu } from "../../../../../components/common/action-menu"
|
import { ActionMenu } from "../../../../../components/common/action-menu"
|
||||||
import { useDeleteShippingProfile } from "../../../../../hooks/api/shipping-profiles"
|
import { useDeleteShippingProfile } from "../../../../../hooks/api/shipping-profiles"
|
||||||
@@ -9,17 +9,17 @@ import { useDeleteShippingProfile } from "../../../../../hooks/api/shipping-prof
|
|||||||
export const ShippingOptionsRowActions = ({
|
export const ShippingOptionsRowActions = ({
|
||||||
profile,
|
profile,
|
||||||
}: {
|
}: {
|
||||||
profile: ShippingProfileDTO
|
profile: AdminShippingProfileResponse["shipping_profile"]
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const prompt = usePrompt()
|
const prompt = usePrompt()
|
||||||
// TODO: MISSING ENDPOINT
|
|
||||||
const { mutateAsync } = useDeleteShippingProfile(profile.id)
|
const { mutateAsync } = useDeleteShippingProfile(profile.id)
|
||||||
|
|
||||||
const handleDelete = async () => {
|
const handleDelete = async () => {
|
||||||
const res = await prompt({
|
const res = await prompt({
|
||||||
title: t("general.areYouSure"),
|
title: t("shippingProfile.delete.title"),
|
||||||
description: t("shippingProfile.deleteWaring", {
|
description: t("shippingProfile.delete.description", {
|
||||||
name: profile.name,
|
name: profile.name,
|
||||||
}),
|
}),
|
||||||
verificationText: profile.name,
|
verificationText: profile.name,
|
||||||
@@ -32,7 +32,22 @@ export const ShippingOptionsRowActions = ({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
await mutateAsync()
|
await mutateAsync(undefined, {
|
||||||
|
onSuccess: () => {
|
||||||
|
toast.success(t("general.success"), {
|
||||||
|
description: t("shippingProfile.delete.successToast", {
|
||||||
|
name: profile.name,
|
||||||
|
}),
|
||||||
|
dismissLabel: t("actions.close"),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast.error(t("general.error"), {
|
||||||
|
description: error.message,
|
||||||
|
dismissLabel: t("actions.close"),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
+23
-23
@@ -1,29 +1,31 @@
|
|||||||
import { Button, Container, Heading } from "@medusajs/ui"
|
import { Button, Container, Heading } from "@medusajs/ui"
|
||||||
import { Link } from "react-router-dom"
|
import { Link } from "react-router-dom"
|
||||||
|
|
||||||
|
import { keepPreviousData } from "@tanstack/react-query"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import { DataTable } from "../../../../../components/table/data-table"
|
import { DataTable } from "../../../../../components/table/data-table"
|
||||||
import { useDataTable } from "../../../../../hooks/use-data-table"
|
|
||||||
import { useShippingProfilesTableColumns } from "./use-shipping-profiles-table-columns"
|
|
||||||
import { useShippingProfilesTableQuery } from "./use-shipping-profiles-table-query"
|
|
||||||
import { NoRecords } from "../../../../../components/common/empty-table-content"
|
|
||||||
import { useShippingProfiles } from "../../../../../hooks/api/shipping-profiles"
|
import { useShippingProfiles } from "../../../../../hooks/api/shipping-profiles"
|
||||||
|
import { useDataTable } from "../../../../../hooks/use-data-table"
|
||||||
|
import { useShippingProfileTableColumns } from "./use-shipping-profile-table-columns"
|
||||||
|
import { useShippingProfileTableFilters } from "./use-shipping-profile-table-filters"
|
||||||
|
import { useShippingProfileTableQuery } from "./use-shipping-profile-table-query"
|
||||||
|
|
||||||
const PAGE_SIZE = 20
|
const PAGE_SIZE = 20
|
||||||
|
|
||||||
export const ShippingProfileListTable = () => {
|
export const ShippingProfileListTable = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const { raw, searchParams } = useShippingProfilesTableQuery({
|
const { raw, searchParams } = useShippingProfileTableQuery({
|
||||||
pageSize: PAGE_SIZE,
|
pageSize: PAGE_SIZE,
|
||||||
})
|
})
|
||||||
|
|
||||||
const { shipping_profiles, count, isLoading, isError, error } =
|
const { shipping_profiles, count, isLoading, isError, error } =
|
||||||
useShippingProfiles({
|
useShippingProfiles(searchParams, {
|
||||||
...searchParams,
|
placeholderData: keepPreviousData,
|
||||||
})
|
})
|
||||||
|
|
||||||
const columns = useShippingProfilesTableColumns()
|
const columns = useShippingProfileTableColumns()
|
||||||
|
const filters = useShippingProfileTableFilters()
|
||||||
|
|
||||||
const { table } = useDataTable({
|
const { table } = useDataTable({
|
||||||
data: shipping_profiles,
|
data: shipping_profiles,
|
||||||
@@ -38,8 +40,6 @@ export const ShippingProfileListTable = () => {
|
|||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
const noData = !isLoading && !shipping_profiles.length
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container className="divide-y p-0">
|
<Container className="divide-y p-0">
|
||||||
<div className="flex items-center justify-between px-6 py-4">
|
<div className="flex items-center justify-between px-6 py-4">
|
||||||
@@ -50,19 +50,19 @@ export const ShippingProfileListTable = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{noData ? (
|
<DataTable
|
||||||
<NoRecords className="h-[180px]" title={t("general.noRecordsFound")} />
|
table={table}
|
||||||
) : (
|
pageSize={PAGE_SIZE}
|
||||||
<DataTable
|
count={count}
|
||||||
table={table}
|
columns={columns}
|
||||||
pageSize={PAGE_SIZE}
|
filters={filters}
|
||||||
count={count || 1}
|
orderBy={["name", "type", "created_at", "updated_at"]}
|
||||||
columns={columns}
|
isLoading={isLoading}
|
||||||
isLoading={isLoading}
|
navigateTo={(row) => row.id}
|
||||||
queryObject={raw}
|
queryObject={raw}
|
||||||
pagination
|
search
|
||||||
/>
|
pagination
|
||||||
)}
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
+4
-3
@@ -1,13 +1,14 @@
|
|||||||
|
import { AdminShippingProfileResponse } from "@medusajs/types"
|
||||||
import { createColumnHelper } from "@tanstack/react-table"
|
import { createColumnHelper } from "@tanstack/react-table"
|
||||||
import { useMemo } from "react"
|
import { useMemo } from "react"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import { ShippingProfileDTO } from "@medusajs/types"
|
|
||||||
|
|
||||||
import { ShippingOptionsRowActions } from "./shipping-options-row-actions"
|
import { ShippingOptionsRowActions } from "./shipping-options-row-actions"
|
||||||
|
|
||||||
const columnHelper = createColumnHelper<ShippingProfileDTO>()
|
const columnHelper =
|
||||||
|
createColumnHelper<AdminShippingProfileResponse["shipping_profile"]>()
|
||||||
|
|
||||||
export const useShippingProfilesTableColumns = () => {
|
export const useShippingProfileTableColumns = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
return useMemo(
|
return useMemo(
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
import { useTranslation } from "react-i18next"
|
||||||
|
import { Filter } from "../../../../../components/table/data-table"
|
||||||
|
|
||||||
|
export const useShippingProfileTableFilters = () => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
let filters: Filter[] = []
|
||||||
|
|
||||||
|
filters.push({
|
||||||
|
key: "name",
|
||||||
|
label: t("fields.name"),
|
||||||
|
type: "string",
|
||||||
|
})
|
||||||
|
|
||||||
|
filters.push({
|
||||||
|
key: "type",
|
||||||
|
label: t("fields.type"),
|
||||||
|
type: "string",
|
||||||
|
})
|
||||||
|
|
||||||
|
const dateFilters: Filter[] = [
|
||||||
|
{ label: t("fields.createdAt"), key: "created_at" },
|
||||||
|
{ label: t("fields.updatedAt"), key: "updated_at" },
|
||||||
|
].map((f) => ({
|
||||||
|
key: f.key,
|
||||||
|
label: f.label,
|
||||||
|
type: "date",
|
||||||
|
}))
|
||||||
|
|
||||||
|
filters = [...filters, ...dateFilters]
|
||||||
|
|
||||||
|
return filters
|
||||||
|
}
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
import { useQueryParams } from "../../../../../hooks/use-query-params"
|
||||||
|
|
||||||
|
export const useShippingProfileTableQuery = ({
|
||||||
|
pageSize = 20,
|
||||||
|
prefix,
|
||||||
|
}: {
|
||||||
|
pageSize?: number
|
||||||
|
prefix?: string
|
||||||
|
}) => {
|
||||||
|
const raw = useQueryParams(
|
||||||
|
["offset", "q", "order", "created_at", "updated_at", "name", "type"],
|
||||||
|
prefix
|
||||||
|
)
|
||||||
|
|
||||||
|
const searchParams = {
|
||||||
|
limit: pageSize,
|
||||||
|
offset: raw.offset ? parseInt(raw.offset) : 0,
|
||||||
|
q: raw.q,
|
||||||
|
order: raw.order,
|
||||||
|
created_at: raw.created_at ? JSON.parse(raw.created_at) : undefined,
|
||||||
|
updated_at: raw.updated_at ? JSON.parse(raw.updated_at) : undefined,
|
||||||
|
name: raw.name,
|
||||||
|
type: raw.type,
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
searchParams,
|
||||||
|
raw,
|
||||||
|
}
|
||||||
|
}
|
||||||
File renamed without changes.
File renamed without changes.
Whitespace-only changes.
-21
@@ -1,21 +0,0 @@
|
|||||||
import { useQueryParams } from "../../../../../hooks/use-query-params"
|
|
||||||
|
|
||||||
export const useShippingProfilesTableQuery = ({
|
|
||||||
pageSize = 20,
|
|
||||||
prefix,
|
|
||||||
}: {
|
|
||||||
pageSize?: number
|
|
||||||
prefix?: string
|
|
||||||
}) => {
|
|
||||||
const raw = useQueryParams(["offset"], prefix)
|
|
||||||
|
|
||||||
const searchParams = {
|
|
||||||
limit: pageSize,
|
|
||||||
offset: raw.offset,
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
searchParams,
|
|
||||||
raw,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,7 @@ import {
|
|||||||
createPsqlIndexStatementHelper,
|
createPsqlIndexStatementHelper,
|
||||||
DALUtils,
|
DALUtils,
|
||||||
generateEntityId,
|
generateEntityId,
|
||||||
|
Searchable,
|
||||||
} from "@medusajs/utils"
|
} from "@medusajs/utils"
|
||||||
|
|
||||||
import { DAL } from "@medusajs/types"
|
import { DAL } from "@medusajs/types"
|
||||||
@@ -41,10 +42,12 @@ export default class ShippingProfile {
|
|||||||
@PrimaryKey({ columnType: "text" })
|
@PrimaryKey({ columnType: "text" })
|
||||||
id: string
|
id: string
|
||||||
|
|
||||||
|
@Searchable()
|
||||||
@Property({ columnType: "text" })
|
@Property({ columnType: "text" })
|
||||||
@ShippingProfileTypeIndex.MikroORMIndex()
|
@ShippingProfileTypeIndex.MikroORMIndex()
|
||||||
name: string
|
name: string
|
||||||
|
|
||||||
|
@Searchable()
|
||||||
@Property({ columnType: "text" })
|
@Property({ columnType: "text" })
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import { createFindParams, createSelectParams } from "../../utils/validators"
|
import {
|
||||||
|
createFindParams,
|
||||||
|
createOperatorMap,
|
||||||
|
createSelectParams,
|
||||||
|
} from "../../utils/validators"
|
||||||
|
|
||||||
export type AdminGetShippingProfileParamsType = z.infer<
|
export type AdminGetShippingProfileParamsType = z.infer<
|
||||||
typeof AdminGetShippingProfileParams
|
typeof AdminGetShippingProfileParams
|
||||||
@@ -14,8 +18,14 @@ export const AdminGetShippingProfilesParams = createFindParams({
|
|||||||
offset: 0,
|
offset: 0,
|
||||||
}).merge(
|
}).merge(
|
||||||
z.object({
|
z.object({
|
||||||
|
q: z.string().optional(),
|
||||||
type: z.string().optional(),
|
type: z.string().optional(),
|
||||||
name: z.string().optional(),
|
name: z.string().optional(),
|
||||||
|
created_at: createOperatorMap().optional(),
|
||||||
|
updated_at: createOperatorMap().optional(),
|
||||||
|
deleted_at: createOperatorMap().optional(),
|
||||||
|
$and: z.lazy(() => AdminGetShippingProfilesParams.array()).optional(),
|
||||||
|
$or: z.lazy(() => AdminGetShippingProfilesParams.array()).optional(),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user