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:
Kasper Fabricius Kristensen
2024-04-19 14:11:32 +00:00
committed by GitHub
parent 9bd2d30595
commit e2fabc1c05
31 changed files with 536 additions and 136 deletions
@@ -1,9 +1,10 @@
import { Text } from "@medusajs/ui"
import { Text, clx } from "@medusajs/ui"
import { ReactNode } from "react"
export type SectionRowProps = {
title: string
value?: React.ReactNode | string | null
actions?: React.ReactNode
value?: ReactNode | string | null
actions?: ReactNode
}
export const SectionRow = ({ title, value, actions }: SectionRowProps) => {
@@ -11,9 +12,12 @@ export const SectionRow = ({ title, value, actions }: SectionRowProps) => {
return (
<div
className={`text-ui-fg-subtle grid ${
!!actions ? "grid-cols-[1fr_1fr_28px]" : "grid-cols-2"
} items-center px-6 py-4`}
className={clx(
`text-ui-fg-subtle grid grid-cols-2 items-center px-6 py-4`,
{
"grid-cols-[1fr_1fr_28px]": !!actions,
}
)}
>
<Text size="small" weight="plus" leading="compact">
{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 = {
className?: string
style?: CSSProperties
}
export const Skeleton = ({ className }: SkeletonProps) => {
export const Skeleton = ({ className, style }: SkeletonProps) => {
return (
<div
aria-hidden
className={clx(
"bg-ui-bg-component h-3 w-3 animate-pulse rounded-[4px]",
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 />,
label: t("shipping.domain"),
to: "/shipping",
items: [
{
label: t("shippingProfile.domain"),
to: "/shipping-profiles",
},
],
},
]
}
@@ -53,6 +53,10 @@ const useSettingRoutes = (): NavItemProps[] => {
label: t("salesChannels.domain"),
to: "/settings/sales-channels",
},
{
label: t("shippingProfile.domain"),
to: "/settings/shipping-profiles",
},
],
[t]
)
@@ -1,12 +1,12 @@
import { EllipseMiniSolid, XMarkMini } from "@medusajs/icons"
import { DatePicker, Text, clx } from "@medusajs/ui"
import * as Popover from "@radix-ui/react-popover"
import { format } from "date-fns"
import isEqual from "lodash/isEqual"
import { MouseEvent, useMemo, useState } from "react"
import { t } from "i18next"
import { useTranslation } from "react-i18next"
import { useDate } from "../../../../hooks/use-date"
import { useSelectedParams } from "../hooks"
import { useDataTableFilterContext } from "./context"
import { IFilter } from "./types"
@@ -17,19 +17,19 @@ type DateComparisonOperator = {
/**
* 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.
*/
lte?: string
$lte?: string
/**
* The filtered date must be less than this value.
*/
lt?: string
$lt?: string
/**
* The filtered date must be greater than this value.
*/
gt?: string
$gt?: string
}
export const DateFilter = ({
@@ -40,6 +40,8 @@ export const DateFilter = ({
const [open, setOpen] = useState(openOnMount)
const [showCustom, setShowCustom] = useState(false)
const { getFullDate } = useDate()
const { key, label } = filter
const { removeFilter } = useDataTableFilterContext()
@@ -60,14 +62,14 @@ export const DateFilter = ({
const currentValue = selectedParams.get()
const currentDateComparison = parseDateComparison(currentValue)
const customStartValue = getDateFromComparison(currentDateComparison, "gte")
const customEndValue = getDateFromComparison(currentDateComparison, "lte")
const customStartValue = getDateFromComparison(currentDateComparison, "$gte")
const customEndValue = getDateFromComparison(currentDateComparison, "$lte")
const handleCustomDateChange = (
value: Date | undefined,
pos: "start" | "end"
) => {
const key = pos === "start" ? "gte" : "lte"
const key = pos === "start" ? "$gte" : "$lte"
const dateValue = value ? value.toISOString() : undefined
selectedParams.add(
@@ -84,7 +86,7 @@ export const DateFilter = ({
}
const formatCustomDate = (date: Date | undefined) => {
return date ? format(date, "dd MMM, yyyy") : undefined
return date ? getFullDate({ date: date }) : undefined
}
const getCustomDisplayValue = () => {
@@ -194,12 +196,12 @@ export const DateFilter = ({
<div>
<div className="px-2 py-1">
<Text size="xsmall" leading="compact" weight="plus">
Starting
{t("filters.date.from")}
</Text>
</div>
<div className="px-2 py-1">
<DatePicker
placeholder="MM/DD/YYYY"
// placeholder="MM/DD/YYYY" TODO: Fix DatePicker component not working with placeholder
toDate={customEndValue}
value={customStartValue}
onChange={(d) => handleCustomDateChange(d, "start")}
@@ -209,12 +211,12 @@ export const DateFilter = ({
<div>
<div className="px-2 py-1">
<Text size="xsmall" leading="compact" weight="plus">
Ending
{t("filters.date.to")}
</Text>
</div>
<div className="px-2 py-1">
<DatePicker
placeholder="MM/DD/YYYY"
// placeholder="MM/DD/YYYY"
fromDate={customStartValue}
value={customEndValue || undefined}
onChange={(d) => {
@@ -301,13 +303,13 @@ const usePresets = () => {
{
label: t("filters.date.today"),
value: {
gte: today.toISOString(),
$gte: today.toISOString(),
},
},
{
label: t("filters.date.lastSevenDays"),
value: {
gte: new Date(
$gte: new Date(
today.getTime() - 7 * 24 * 60 * 60 * 1000
).toISOString(), // 7 days ago
},
@@ -315,7 +317,7 @@ const usePresets = () => {
{
label: t("filters.date.lastThirtyDays"),
value: {
gte: new Date(
$gte: new Date(
today.getTime() - 30 * 24 * 60 * 60 * 1000
).toISOString(), // 30 days ago
},
@@ -323,7 +325,7 @@ const usePresets = () => {
{
label: t("filters.date.lastNinetyDays"),
value: {
gte: new Date(
$gte: new Date(
today.getTime() - 90 * 24 * 60 * 60 * 1000
).toISOString(), // 90 days ago
},
@@ -331,7 +333,7 @@ const usePresets = () => {
{
label: t("filters.date.lastTwelveMonths"),
value: {
gte: new Date(
$gte: new Date(
today.getTime() - 365 * 24 * 60 * 60 * 1000
).toISOString(), // 365 days ago
},
@@ -349,7 +351,7 @@ const parseDateComparison = (value: string[]) => {
const getDateFromComparison = (
comparison: DateComparisonOperator | null,
key: "gte" | "lte"
key: "$gte" | "$lte"
) => {
return comparison?.[key] ? new Date(comparison[key] as string) : undefined
}