feat(dashboard): restructure create product flow (#7374)

This commit is contained in:
Frane Polić
2024-05-28 13:59:02 +02:00
committed by GitHub
parent 76ec10f375
commit 6117af2704
46 changed files with 3161 additions and 395 deletions

View File

@@ -0,0 +1,36 @@
import { Checkbox } from "@medusajs/ui"
import { Controller } from "react-hook-form"
import { useDataGridCell } from "../hooks"
import { DataGridCellProps } from "../types"
import { DataGridCellContainer } from "./data-grid-cell-container"
export const DataGridBooleanCell = <TData, TValue = any>({
field,
context,
disabled,
}: DataGridCellProps<TData, TValue> & { disabled?: boolean }) => {
const { control, attributes, container, onChange } = useDataGridCell({
field,
context,
})
return (
<Controller
control={control}
name={field}
render={({ field: { value, onChange: _, ...field } }) => {
return (
<DataGridCellContainer {...container}>
<Checkbox
checked={value}
onCheckedChange={(next) => onChange(next, value)}
{...field}
{...attributes}
disabled={disabled}
/>
</DataGridCellContainer>
)
}}
/>
)
}

View File

@@ -0,0 +1,50 @@
import { PropsWithChildren } from "react"
import { DataGridCellContainerProps } from "../types"
type ContainerProps = PropsWithChildren<DataGridCellContainerProps>
export const DataGridCellContainer = ({
isAnchor,
placeholder,
overlay,
wrapper,
children,
}: ContainerProps) => {
return (
<div className="static size-full">
<div className="flex size-full items-start outline-none" tabIndex={-1}>
<div {...wrapper} className="relative size-full min-w-0 flex-1">
<div className="relative z-[1] flex size-full items-center justify-center">
<RenderChildren isAnchor={isAnchor} placeholder={placeholder}>
{children}
</RenderChildren>
</div>
{!isAnchor && (
<div
{...overlay}
tabIndex={-1}
className="absolute inset-0 z-[2] size-full"
/>
)}
</div>
</div>
{/* {showDragHandle && (
<div className="bg-ui-bg-interactive absolute -bottom-[1.5px] -right-[1.5px] size-[3px]" />
)} */}
</div>
)
}
const RenderChildren = ({
isAnchor,
placeholder,
children,
}: PropsWithChildren<
Pick<DataGridCellContainerProps, "isAnchor" | "placeholder">
>) => {
if (!isAnchor && placeholder) {
return placeholder
}
return children
}

View File

@@ -0,0 +1,116 @@
import { TrianglesMini } from "@medusajs/icons"
import { clx } from "@medusajs/ui"
import { ComponentPropsWithoutRef, forwardRef, memo } from "react"
import { Controller } from "react-hook-form"
import { countries } from "../../../lib/countries"
import { useDataGridCell } from "../hooks"
import { DataGridCellProps } from "../types"
import { DataGridCellContainer } from "./data-grid-cell-container"
export const DataGridCountrySelectCell = <TData, TValue = any>({
field,
context,
}: DataGridCellProps<TData, TValue>) => {
const { control, attributes, container, onChange } = useDataGridCell({
field,
context,
})
return (
<Controller
control={control}
name={field}
render={({ field: { value, onChange: _, disabled, ...field } }) => {
return (
<DataGridCellContainer
{...container}
placeholder={
<DataGridCountryCellPlaceholder
value={value}
disabled={disabled}
attributes={attributes}
/>
}
>
<MemoizedDataGridCountryCell
value={value}
onChange={(e) => onChange(e.target.value, value)}
disabled={disabled}
{...attributes}
{...field}
/>
</DataGridCellContainer>
)
}}
/>
)
}
const DataGridCountryCellPlaceholder = ({
value,
disabled,
attributes,
}: {
value?: string
disabled?: boolean
attributes: Record<string, any>
}) => {
const country = countries.find((c) => c.iso_2 === value)
return (
<div className="relative flex size-full" {...attributes}>
<TrianglesMini
className={clx(
"text-ui-fg-muted transition-fg pointer-events-none absolute right-4 top-1/2 -translate-y-1/2",
{
"text-ui-fg-disabled": disabled,
}
)}
/>
<div
className={clx(
"txt-compact-small w-full appearance-none bg-transparent px-4 py-2.5 outline-none"
)}
>
{country?.display_name}
</div>
</div>
)
}
const DataGridCountryCellImpl = forwardRef<
HTMLSelectElement,
ComponentPropsWithoutRef<"select">
>(({ disabled, className, ...props }, ref) => {
return (
<div className="relative flex size-full">
<TrianglesMini
className={clx(
"text-ui-fg-muted transition-fg pointer-events-none absolute right-4 top-1/2 -translate-y-1/2",
{
"text-ui-fg-disabled": disabled,
}
)}
/>
<select
{...props}
ref={ref}
className={clx(
"txt-compact-small w-full appearance-none bg-transparent px-4 py-2.5 outline-none",
className
)}
>
<option value=""></option>
{countries.map((country) => (
<option key={country.iso_2} value={country.iso_2}>
{country.display_name}
</option>
))}
</select>
</div>
)
})
DataGridCountryCellImpl.displayName = "DataGridCountryCell"
const MemoizedDataGridCountryCell = memo(DataGridCountryCellImpl)

View File

@@ -0,0 +1,54 @@
import CurrencyInput from "react-currency-input-field"
import { Controller } from "react-hook-form"
import { currencies } from "../../../lib/currencies"
import { useDataGridCell } from "../hooks"
import { DataGridCellProps } from "../types"
import { DataGridCellContainer } from "./data-grid-cell-container"
interface DataGridCurrencyCellProps<TData, TValue = any>
extends DataGridCellProps<TData, TValue> {
code: string
}
export const DataGridCurrencyCell = <TData, TValue = any>({
field,
context,
code,
}: DataGridCurrencyCellProps<TData, TValue>) => {
const { control, attributes, container } = useDataGridCell({
field,
context,
})
const currency = currencies[code.toUpperCase()]
return (
<Controller
control={control}
name={field}
render={({ field: { value, onChange, ...field } }) => {
return (
<DataGridCellContainer {...container}>
<div className="flex size-full items-center gap-2 px-4 py-2.5">
<span className="txt-compact-small text-ui-fg-muted" aria-hidden>
{currency.symbol_native}
</span>
<CurrencyInput
{...field}
{...attributes}
className="txt-compact-small flex-1 appearance-none bg-transparent text-right outline-none"
value={value}
onValueChange={(_value, _name, values) =>
onChange(values?.value)
}
decimalScale={currency.decimal_digits}
decimalsLimit={currency.decimal_digits}
/>
</div>
</DataGridCellContainer>
)
}}
/>
)
}

View File

@@ -0,0 +1,25 @@
import { useDataGridCell } from "../hooks"
import { DataGridCellProps } from "../types"
import { DataGridCellContainer } from "./data-grid-cell-container"
export const DataGridNumberCell = <TData, TValue = any>({
field,
context,
}: DataGridCellProps<TData, TValue>) => {
const { register, attributes, container } = useDataGridCell({
field,
context,
})
return (
<DataGridCellContainer {...container}>
<input
{...attributes}
type="number"
{...register(field, {
valueAsNumber: true,
})}
/>
</DataGridCellContainer>
)
}

View File

@@ -0,0 +1,13 @@
import { PropsWithChildren } from "react"
type DataGridReadOnlyCellProps = PropsWithChildren
export const DataGridReadOnlyCell = ({
children,
}: DataGridReadOnlyCellProps) => {
return (
<div className="bg-ui-bg-subtle txt-compact-small text-ui-fg-subtle flex size-full cursor-not-allowed items-center px-4 py-2.5 outline-none">
<span>{children}</span>
</div>
)
}

View File

@@ -0,0 +1,53 @@
import { Select, clx } from "@medusajs/ui"
import { Controller } from "react-hook-form"
import { useDataGridCell } from "../hooks"
import { DataGridCellProps } from "../types"
import { DataGridCellContainer } from "./data-grid-cell-container"
interface DataGridSelectCellProps<TData, TValue = any>
extends DataGridCellProps<TData, TValue> {
options: { label: string; value: string }[]
}
export const DataGridSelectCell = <TData, TValue = any>({
context,
options,
field,
}: DataGridSelectCellProps<TData, TValue>) => {
const { control, attributes, container } = useDataGridCell({
field,
context,
})
return (
<Controller
control={control}
name={field}
render={({ field: { onChange, ref, ...field } }) => {
return (
<DataGridCellContainer {...container}>
<Select {...field} onValueChange={onChange}>
<Select.Trigger
{...attributes}
ref={ref}
className={clx(
"h-full w-full rounded-none bg-transparent px-4 py-2.5 shadow-none",
"hover:bg-transparent focus:shadow-none data-[state=open]:!shadow-none"
)}
>
<Select.Value />
</Select.Trigger>
<Select.Content>
{options.map((option) => (
<Select.Item key={option.value} value={option.value}>
{option.label}
</Select.Item>
))}
</Select.Content>
</Select>
</DataGridCellContainer>
)
}}
/>
)
}

View File

@@ -0,0 +1,41 @@
import { clx } from "@medusajs/ui"
import { Controller } from "react-hook-form"
import { useDataGridCell } from "../hooks"
import { DataGridCellProps } from "../types"
import { DataGridCellContainer } from "./data-grid-cell-container"
export const DataGridTextCell = <TData, TValue = any>({
field,
context,
}: DataGridCellProps<TData, TValue>) => {
const { control, attributes, container, onChange } = useDataGridCell({
field,
context,
})
return (
<Controller
control={control}
name={field}
render={({ field: { value, onChange: _, ...field } }) => {
return (
<DataGridCellContainer {...container}>
<input
className={clx(
"txt-compact-small text-ui-fg-subtle flex size-full cursor-pointer items-center justify-center bg-transparent px-4 py-2.5 outline-none",
"focus:cursor-text"
)}
autoComplete="off"
tabIndex={-1}
value={value}
onChange={(e) => onChange(e.target.value, value)}
{...attributes}
{...field}
/>
</DataGridCellContainer>
)
}}
/>
)
}