feat(dashboard,types,js-sdk,ui): Add missing Price List features (#7856)

**What**
- Adds missing features to Price List domain
- Adds `StackedFocusModal` and `StackedDrawer` components that should replace SplitView across the project.
- Add Footer to FocusModal
- Adds missing js-sdk functions and types

**Note**
The DatePickers in the PriceLists forms do not work as intended atm. The component is broken, and needs to be fixed. I am working on a fix, but choose to move that work into a separate branch, to prevent this PR from getting bigger then it already is. Will update once the fixes have been merged.
This commit is contained in:
Kasper Fabricius Kristensen
2024-06-28 16:08:23 +02:00
committed by GitHub
parent 9f3998393b
commit c1740218e9
295 changed files with 4488 additions and 2350 deletions
@@ -0,0 +1,59 @@
import { PropsWithChildren, createContext } from "react"
type ConditionOperator =
| "eq"
| "ne"
| "gt"
| "lt"
| "gte"
| "lte"
| "in"
| "nin"
type ConditionBlockValue<TValue> = {
attribute: string
operator: ConditionOperator
value: TValue
}
type ConditionBlockState<TValue> = {
defaultValue?: ConditionBlockValue<TValue>
value?: ConditionBlockValue<TValue>
onChange: (value: ConditionBlockValue<TValue>) => void
}
const ConditionBlockContext = createContext<ConditionBlockState<any> | null>(
null
)
const useConditionBlock = () => {
const context = ConditionBlockContext
if (!context) {
throw new Error("useConditionBlock must be used within a ConditionBlock")
}
return context
}
type ConditionBlockProps<TValue> = PropsWithChildren<
ConditionBlockState<TValue>
>
const Root = <TValue,>({ children, ...props }: ConditionBlockProps<TValue>) => {
return (
<ConditionBlockContext.Provider value={props}>
{children}
</ConditionBlockContext.Provider>
)
}
const Divider = () => {}
const Operator = () => {}
const Item = () => {}
export const ConditionBlock = Object.assign(Root, {
Divider,
})
@@ -0,0 +1,73 @@
import { Text, clx } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { useDate } from "../../../hooks/use-date"
type DateRangeDisplayProps = {
startsAt?: Date | string | null
endsAt?: Date | string | null
showTime?: boolean
}
export const DateRangeDisplay = ({
startsAt,
endsAt,
showTime = false,
}: DateRangeDisplayProps) => {
const startDate = startsAt ? new Date(startsAt) : null
const endDate = endsAt ? new Date(endsAt) : null
const { t } = useTranslation()
const { getFullDate } = useDate()
return (
<div className="grid gap-3 md:grid-cols-2">
<div className="shadow-elevation-card-rest bg-ui-bg-component text-ui-fg-subtle flex items-center gap-x-3 rounded-md px-3 py-1.5">
<Bar date={startDate} />
<div>
<Text weight="plus" size="small">
{t("fields.startDate")}
</Text>
<Text size="small">
{startDate
? getFullDate({
date: startDate,
includeTime: showTime,
})
: "-"}
</Text>
</div>
</div>
<div className="shadow-elevation-card-rest bg-ui-bg-component text-ui-fg-subtle flex items-center gap-x-3 rounded-md px-3 py-1.5">
<Bar date={endDate} />
<div>
<Text size="small" weight="plus">
{t("fields.endDate")}
</Text>
<Text size="small">
{endDate
? getFullDate({
date: endDate,
includeTime: showTime,
})
: "-"}
</Text>
</div>
</div>
</div>
)
}
const Bar = ({ date }: { date: Date | null }) => {
const now = new Date()
const isDateInFuture = date && date > now
return (
<div
className={clx("bg-ui-tag-neutral-icon h-8 w-1 rounded-full", {
"bg-ui-tag-orange-icon": isDateInFuture,
})}
/>
)
}
@@ -0,0 +1 @@
export * from "./date-range-display"
@@ -7,11 +7,11 @@ import {
useState,
} from "react"
import { Adjustments } from "@medusajs/icons"
import { Button, DropdownMenu, clx } from "@medusajs/ui"
import {
CellContext,
ColumnDef,
OnChangeFn,
Row,
VisibilityState,
flexRender,
@@ -41,7 +41,7 @@ interface DataGridRootProps<
data?: TData[]
columns: ColumnDef<TData>[]
state: UseFormReturn<TFieldValues>
getSubRows?: (row: TData) => TData[]
getSubRows?: (row: TData) => TData[] | undefined
}
const ARROW_KEYS = ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"]
@@ -93,13 +93,6 @@ export const DataGridRoot = <
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})
const onColumnVisibilityChange: OnChangeFn<VisibilityState> = useCallback(
(next) => {
const update = typeof next === "function" ? next(columnVisibility) : next
},
[columnVisibility]
)
const grid = useReactTable({
data: data,
columns,
@@ -663,7 +656,8 @@ export const DataGridRoot = <
<DropdownMenu>
<DropdownMenu.Trigger asChild>
<Button size="small" variant="secondary">
Columns
<Adjustments />
Edit columns
</Button>
</DropdownMenu.Trigger>
<DropdownMenu.Content>
@@ -799,6 +793,7 @@ export const DataGridRoot = <
{flexRender(cell.column.columnDef.cell, {
...cell.getContext(),
columnIndex,
rowIndex: virtualRow.index,
} as CellContext<TData, any>)}
{isAnchor && (
<div
@@ -29,11 +29,14 @@ export const useDataGridCell = <TData, TValue>({
field,
context,
}: UseDataGridCellProps<TData, TValue>) => {
const { row, columnIndex } = context as DataGridCellContext<TData, TValue>
const { rowIndex, columnIndex } = context as DataGridCellContext<
TData,
TValue
>
const coords: CellCoords = useMemo(
() => ({ row: row.index, col: columnIndex }),
[row, columnIndex]
() => ({ row: rowIndex, col: columnIndex }),
[rowIndex, columnIndex]
)
const id = generateCellId(coords)
@@ -22,6 +22,10 @@ export interface DataGridCellContext<TData = unknown, TValue = any>
* The index of the column in the grid.
*/
columnIndex: number
/**
* The index of the row in the grid.
*/
rowIndex: number
}
export interface DataGridCellContainerProps {
@@ -150,8 +150,8 @@ const useCoreRoutes = (): Omit<NavItemProps, "pathname">[] => {
},
{
icon: <CurrencyDollar />,
label: t("pricing.domain"),
to: "/pricing",
label: t("priceLists.domain"),
to: "/price-lists",
},
]
}
@@ -0,0 +1,7 @@
export { RouteDrawer } from "./route-drawer"
export { RouteFocusModal } from "./route-focus-modal"
export { useRouteModal } from "./route-modal-provider"
export { StackedDrawer } from "./stacked-drawer"
export { StackedFocusModal } from "./stacked-focus-modal"
export { useStackedModal } from "./stacked-modal-provider"
@@ -1,8 +1,9 @@
import { Drawer } from "@medusajs/ui"
import { Drawer, clx } from "@medusajs/ui"
import { PropsWithChildren, useEffect, useState } from "react"
import { useNavigate } from "react-router-dom"
import { RouteForm } from "../route-form"
import { RouteModalForm } from "../route-modal-form"
import { RouteModalProvider } from "../route-modal-provider/route-provider"
import { StackedModalProvider } from "../stacked-modal-provider"
type RouteDrawerProps = PropsWithChildren<{
prev?: string
@@ -11,6 +12,7 @@ type RouteDrawerProps = PropsWithChildren<{
const Root = ({ prev = "..", children }: RouteDrawerProps) => {
const navigate = useNavigate()
const [open, setOpen] = useState(false)
const [stackedModalOpen, onStackedModalOpen] = useState(false)
/**
* Open the modal when the component mounts. This
@@ -18,6 +20,11 @@ const Root = ({ prev = "..", children }: RouteDrawerProps) => {
*/
useEffect(() => {
setOpen(true)
return () => {
setOpen(false)
onStackedModalOpen(false)
}
}, [])
const handleOpenChange = (open: boolean) => {
@@ -33,17 +40,27 @@ const Root = ({ prev = "..", children }: RouteDrawerProps) => {
return (
<Drawer open={open} onOpenChange={handleOpenChange}>
<RouteModalProvider prev={prev}>
<Drawer.Content>{children}</Drawer.Content>
<StackedModalProvider onOpenChange={onStackedModalOpen}>
<Drawer.Content
className={clx({
"!bg-ui-bg-disabled !inset-y-5 !right-5": stackedModalOpen,
})}
>
{children}
</Drawer.Content>
</StackedModalProvider>
</RouteModalProvider>
</Drawer>
)
}
const Header = Drawer.Header
const Title = Drawer.Title
const Description = Drawer.Description
const Body = Drawer.Body
const Footer = Drawer.Footer
const Close = Drawer.Close
const Form = RouteForm
const Form = RouteModalForm
/**
* Drawer that is used to render a form on a separate route.
@@ -52,7 +69,9 @@ const Form = RouteForm
*/
export const RouteDrawer = Object.assign(Root, {
Header,
Title,
Body,
Description,
Footer,
Close,
Form,
@@ -1,8 +1,9 @@
import { FocusModal } from "@medusajs/ui"
import { FocusModal, clx } from "@medusajs/ui"
import { PropsWithChildren, useEffect, useState } from "react"
import { useNavigate } from "react-router-dom"
import { RouteForm } from "../route-form"
import { RouteModalForm } from "../route-modal-form"
import { RouteModalProvider } from "../route-modal-provider/route-provider"
import { StackedModalProvider } from "../stacked-modal-provider"
type RouteFocusModalProps = PropsWithChildren<{
prev?: string
@@ -11,6 +12,7 @@ type RouteFocusModalProps = PropsWithChildren<{
const Root = ({ prev = "..", children }: RouteFocusModalProps) => {
const navigate = useNavigate()
const [open, setOpen] = useState(false)
const [stackedModalOpen, onStackedModalOpen] = useState(false)
/**
* Open the modal when the component mounts. This
@@ -18,6 +20,11 @@ const Root = ({ prev = "..", children }: RouteFocusModalProps) => {
*/
useEffect(() => {
setOpen(true)
return () => {
setOpen(false)
onStackedModalOpen(false)
}
}, [])
const handleOpenChange = (open: boolean) => {
@@ -33,16 +40,27 @@ const Root = ({ prev = "..", children }: RouteFocusModalProps) => {
return (
<FocusModal open={open} onOpenChange={handleOpenChange}>
<RouteModalProvider prev={prev}>
<FocusModal.Content>{children}</FocusModal.Content>
<StackedModalProvider onOpenChange={onStackedModalOpen}>
<FocusModal.Content
className={clx({
"!bg-ui-bg-disabled !inset-x-5 !inset-y-3": stackedModalOpen,
})}
>
{children}
</FocusModal.Content>
</StackedModalProvider>
</RouteModalProvider>
</FocusModal>
)
}
const Header = FocusModal.Header
const Title = FocusModal.Title
const Description = FocusModal.Description
const Footer = FocusModal.Footer
const Body = FocusModal.Body
const Close = FocusModal.Close
const Form = RouteForm
const Form = RouteModalForm
/**
* FocusModal that is used to render a form on a separate route.
@@ -52,7 +70,10 @@ const Form = RouteForm
*/
export const RouteFocusModal = Object.assign(Root, {
Header,
Title,
Body,
Description,
Footer,
Close,
Form,
})
@@ -0,0 +1 @@
export * from "./route-modal-form"
@@ -5,16 +5,16 @@ import { useTranslation } from "react-i18next"
import { useBlocker } from "react-router-dom"
import { Form } from "../../common/form"
type RouteFormProps<TFieldValues extends FieldValues> = PropsWithChildren<{
type RouteModalFormProps<TFieldValues extends FieldValues> = PropsWithChildren<{
form: UseFormReturn<TFieldValues>
blockSearch?: boolean
}>
export const RouteForm = <TFieldValues extends FieldValues = any>({
export const RouteModalForm = <TFieldValues extends FieldValues = any>({
form,
blockSearch = false,
children,
}: RouteFormProps<TFieldValues>) => {
}: RouteModalFormProps<TFieldValues>) => {
const { t } = useTranslation()
const {
@@ -0,0 +1,2 @@
export * from "./route-provider"
export * from "./use-route-modal"
@@ -0,0 +1,8 @@
import { createContext } from "react"
type RouteModalProviderState = {
handleSuccess: (path?: string) => void
}
export const RouteModalProviderContext =
createContext<RouteModalProviderState | null>(null)
@@ -1,22 +1,6 @@
import { PropsWithChildren, createContext, useContext } from "react"
import { PropsWithChildren } from "react"
import { useNavigate } from "react-router-dom"
type RouteModalProviderContextType = {
handleSuccess: (path?: string) => void
}
const RouteModalProviderContext =
createContext<RouteModalProviderContextType | null>(null)
export const useRouteModal = () => {
const context = useContext(RouteModalProviderContext)
if (!context) {
throw new Error("useRouteModal must be used within a RouteModalProvider")
}
return context
}
import { RouteModalProviderContext } from "./route-modal-context"
type RouteModalProviderProps = PropsWithChildren<{
prev: string
@@ -0,0 +1,12 @@
import { useContext } from "react"
import { RouteModalProviderContext } from "./route-modal-context"
export const useRouteModal = () => {
const context = useContext(RouteModalProviderContext)
if (!context) {
throw new Error("useRouteModal must be used within a RouteModalProvider")
}
return context
}
@@ -0,0 +1 @@
export * from "./stacked-drawer"
@@ -0,0 +1,85 @@
import { Drawer, clx } from "@medusajs/ui"
import {
ComponentPropsWithoutRef,
PropsWithChildren,
forwardRef,
useEffect,
} from "react"
import { useStackedModal } from "../stacked-modal-provider"
type StackedDrawerProps = PropsWithChildren<{
/**
* A unique identifier for the modal. This is used to differentiate stacked modals,
* when multiple stacked modals are registered to the same parent modal.
*/
id: string
}>
/**
* A stacked modal that can be rendered above a parent modal.
*/
export const Root = ({ id, children }: StackedDrawerProps) => {
const { register, unregister, getIsOpen, setIsOpen } = useStackedModal()
useEffect(() => {
register(id)
return () => unregister(id)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return (
<Drawer open={getIsOpen(id)} onOpenChange={(open) => setIsOpen(id, open)}>
{children}
</Drawer>
)
}
const Close = Drawer.Close
Close.displayName = "StackedDrawer.Close"
const Header = Drawer.Header
Header.displayName = "StackedDrawer.Header"
const Body = Drawer.Body
Body.displayName = "StackedDrawer.Body"
const Trigger = Drawer.Trigger
Trigger.displayName = "StackedDrawer.Trigger"
const Footer = Drawer.Footer
Footer.displayName = "StackedDrawer.Footer"
const Title = Drawer.Title
Title.displayName = "StackedDrawer.Title"
const Description = Drawer.Description
Description.displayName = "StackedDrawer.Description"
const Content = forwardRef<
HTMLDivElement,
ComponentPropsWithoutRef<typeof Drawer.Content>
>(({ className, ...props }, ref) => {
return (
<Drawer.Content
ref={ref}
className={clx(className)}
overlayProps={{
className: "bg-transparent",
}}
{...props}
/>
)
})
Content.displayName = "StackedDrawer.Content"
export const StackedDrawer = Object.assign(Root, {
Close,
Header,
Body,
Content,
Trigger,
Footer,
Description,
Title,
})
@@ -0,0 +1 @@
export * from "./stacked-foucs-modal"
@@ -0,0 +1,88 @@
import { FocusModal, clx } from "@medusajs/ui"
import {
ComponentPropsWithoutRef,
PropsWithChildren,
forwardRef,
useEffect,
} from "react"
import { useStackedModal } from "../stacked-modal-provider"
type StackedFocusModalProps = PropsWithChildren<{
/**
* A unique identifier for the modal. This is used to differentiate stacked modals,
* when multiple stacked modals are registered to the same parent modal.
*/
id: string
}>
/**
* A stacked modal that can be rendered above a parent modal.
*/
export const Root = ({ id, children }: StackedFocusModalProps) => {
const { register, unregister, getIsOpen, setIsOpen } = useStackedModal()
useEffect(() => {
register(id)
return () => unregister(id)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return (
<FocusModal
open={getIsOpen(id)}
onOpenChange={(open) => setIsOpen(id, open)}
>
{children}
</FocusModal>
)
}
const Close = FocusModal.Close
Close.displayName = "StackedFocusModal.Close"
const Header = FocusModal.Header
Header.displayName = "StackedFocusModal.Header"
const Body = FocusModal.Body
Body.displayName = "StackedFocusModal.Body"
const Trigger = FocusModal.Trigger
Trigger.displayName = "StackedFocusModal.Trigger"
const Footer = FocusModal.Footer
Footer.displayName = "StackedFocusModal.Footer"
const Title = FocusModal.Title
Title.displayName = "StackedFocusModal.Title"
const Description = FocusModal.Description
Description.displayName = "StackedFocusModal.Description"
const Content = forwardRef<
HTMLDivElement,
ComponentPropsWithoutRef<typeof FocusModal.Content>
>(({ className, ...props }, ref) => {
return (
<FocusModal.Content
ref={ref}
className={clx("top-6", className)}
overlayProps={{
className: "bg-transparent",
}}
{...props}
/>
)
})
Content.displayName = "StackedFocusModal.Content"
export const StackedFocusModal = Object.assign(Root, {
Close,
Header,
Body,
Content,
Trigger,
Footer,
Description,
Title,
})
@@ -0,0 +1,2 @@
export * from "./stacked-modal-provider"
export * from "./use-stacked-modal"
@@ -0,0 +1,10 @@
import { createContext } from "react"
type StackedModalState = {
getIsOpen: (id: string) => boolean
setIsOpen: (id: string, open: boolean) => void
register: (id: string) => void
unregister: (id: string) => void
}
export const StackedModalContext = createContext<StackedModalState | null>(null)
@@ -0,0 +1,54 @@
import { PropsWithChildren, useState } from "react"
import { StackedModalContext } from "./stacked-modal-context"
type StackedModalProviderProps = PropsWithChildren<{
onOpenChange: (open: boolean) => void
}>
export const StackedModalProvider = ({
children,
onOpenChange,
}: StackedModalProviderProps) => {
const [state, setState] = useState<Record<string, boolean>>({})
const getIsOpen = (id: string) => {
return state[id] || false
}
const setIsOpen = (id: string, open: boolean) => {
setState((prevState) => ({
...prevState,
[id]: open,
}))
onOpenChange(open)
}
const register = (id: string) => {
setState((prevState) => ({
...prevState,
[id]: false,
}))
}
const unregister = (id: string) => {
setState((prevState) => {
const newState = { ...prevState }
delete newState[id]
return newState
})
}
return (
<StackedModalContext.Provider
value={{
getIsOpen,
setIsOpen,
register,
unregister,
}}
>
{children}
</StackedModalContext.Provider>
)
}
@@ -0,0 +1,14 @@
import { useContext } from "react"
import { StackedModalContext } from "./stacked-modal-context"
export const useStackedModal = () => {
const context = useContext(StackedModalContext)
if (!context) {
throw new Error(
"useStackedModal must be used within a StackedModalProvider"
)
}
return context
}
@@ -1,3 +0,0 @@
export { RouteDrawer } from "./route-drawer"
export { RouteFocusModal } from "./route-focus-modal"
export { useRouteModal } from "./route-modal-provider"
@@ -1 +0,0 @@
export * from "./route-form"
@@ -1 +0,0 @@
export * from "./route-provider"
@@ -46,6 +46,7 @@ export const DataTableSearch = ({
return (
<Input
autoComplete="off"
name="q"
type="search"
size="small"
@@ -1,3 +1,4 @@
import { HttpTypes, PaginatedResponse } from "@medusajs/types"
import {
QueryKey,
UseMutationOptions,
@@ -12,7 +13,6 @@ import { queryKeysFactory } from "../../lib/query-key-factory"
import { CreateCustomerGroupSchema } from "../../routes/customer-groups/customer-group-create/components/create-customer-group-form"
import { EditCustomerGroupSchema } from "../../routes/customer-groups/customer-group-edit/components/edit-customer-group-form"
import { customersQueryKeys } from "./customers"
import { HttpTypes, PaginatedResponse } from "@medusajs/types"
const CUSTOMER_GROUPS_QUERY_KEY = "customer_groups" as const
export const customerGroupsQueryKeys = queryKeysFactory(
@@ -45,9 +45,9 @@ export const useCustomerGroups = (
query?: Record<string, any>,
options?: Omit<
UseQueryOptions<
PaginatedResponse<HttpTypes.AdminCustomerGroup[]>,
PaginatedResponse<{ customer_groups: HttpTypes.AdminCustomerGroup[] }>,
Error,
PaginatedResponse<HttpTypes.AdminCustomerGroup[]>,
PaginatedResponse<{ customer_groups: HttpTypes.AdminCustomerGroup[] }>,
QueryKey
>,
"queryFn" | "queryKey"
@@ -7,20 +7,10 @@ import {
useMutation,
useQuery,
} from "@tanstack/react-query"
import { client, sdk } from "../../lib/client"
import { sdk } from "../../lib/client"
import { queryClient } from "../../lib/query-client"
import { queryKeysFactory } from "../../lib/query-key-factory"
import {
AddPriceListPricesReq,
CreatePriceListReq,
DeletePriceListPricesReq,
UpdatePriceListReq,
} from "../../types/api-payloads"
import {
PriceListDeleteRes,
PriceListListRes,
PriceListRes,
} from "../../types/api-responses"
import { customerGroupsQueryKeys } from "./customer-groups"
import { productsQueryKeys } from "./products"
const PRICE_LISTS_QUERY_KEY = "price-lists" as const
@@ -28,14 +18,19 @@ export const priceListsQueryKeys = queryKeysFactory(PRICE_LISTS_QUERY_KEY)
export const usePriceList = (
id: string,
query?: Record<string, any>,
query?: HttpTypes.AdminPriceListListParams,
options?: Omit<
UseQueryOptions<PriceListRes, Error, PriceListRes, QueryKey>,
UseQueryOptions<
HttpTypes.AdminPriceListResponse,
FetchError,
HttpTypes.AdminPriceListResponse,
QueryKey
>,
"queryKey" | "queryFn"
>
) => {
const { data, ...rest } = useQuery({
queryFn: () => client.priceLists.retrieve(id, query),
queryFn: () => sdk.admin.priceList.retrieve(id, query),
queryKey: priceListsQueryKeys.detail(id),
...options,
})
@@ -44,14 +39,19 @@ export const usePriceList = (
}
export const usePriceLists = (
query?: Record<string, any>,
query?: HttpTypes.AdminPriceListListParams,
options?: Omit<
UseQueryOptions<PriceListListRes, Error, PriceListListRes, QueryKey>,
UseQueryOptions<
HttpTypes.AdminPriceListListResponse,
FetchError,
HttpTypes.AdminPriceListListResponse,
QueryKey
>,
"queryKey" | "queryFn"
>
) => {
const { data, ...rest } = useQuery({
queryFn: () => client.priceLists.list(query),
queryFn: () => sdk.admin.priceList.list(query),
queryKey: priceListsQueryKeys.list(query),
...options,
})
@@ -60,13 +60,20 @@ export const usePriceLists = (
}
export const useCreatePriceList = (
options?: UseMutationOptions<PriceListRes, Error, CreatePriceListReq>
query?: HttpTypes.AdminPriceListParams,
options?: UseMutationOptions<
HttpTypes.AdminPriceListResponse,
FetchError,
HttpTypes.AdminCreatePriceList
>
) => {
return useMutation({
mutationFn: (payload) => client.priceLists.create(payload),
mutationFn: (payload) => sdk.admin.priceList.create(payload, query),
onSuccess: (data, variables, context) => {
queryClient.invalidateQueries({ queryKey: priceListsQueryKeys.list() })
queryClient.invalidateQueries({ queryKey: customerGroupsQueryKeys.all })
options?.onSuccess?.(data, variables, context)
},
...options,
@@ -75,16 +82,23 @@ export const useCreatePriceList = (
export const useUpdatePriceList = (
id: string,
options?: UseMutationOptions<PriceListRes, Error, UpdatePriceListReq>
query?: HttpTypes.AdminPriceListParams,
options?: UseMutationOptions<
HttpTypes.AdminPriceListResponse,
FetchError,
HttpTypes.AdminUpdatePriceList
>
) => {
return useMutation({
mutationFn: (payload) => client.priceLists.update(id, payload),
mutationFn: (payload) => sdk.admin.priceList.update(id, payload, query),
onSuccess: (data, variables, context) => {
queryClient.invalidateQueries({ queryKey: priceListsQueryKeys.list() })
queryClient.invalidateQueries({
queryKey: priceListsQueryKeys.detail(id),
})
queryClient.invalidateQueries({ queryKey: customerGroupsQueryKeys.all })
options?.onSuccess?.(data, variables, context)
},
...options,
@@ -93,10 +107,14 @@ export const useUpdatePriceList = (
export const useDeletePriceList = (
id: string,
options?: UseMutationOptions<PriceListDeleteRes, Error, void>
options?: UseMutationOptions<
HttpTypes.AdminPriceListDeleteResponse,
FetchError,
void
>
) => {
return useMutation({
mutationFn: () => client.priceLists.delete(id),
mutationFn: () => sdk.admin.priceList.delete(id),
onSuccess: (data, variables, context) => {
queryClient.invalidateQueries({ queryKey: priceListsQueryKeys.list() })
@@ -106,17 +124,22 @@ export const useDeletePriceList = (
})
}
export const usePriceListAddPrices = (
export const useBatchPriceListPrices = (
id: string,
options?: UseMutationOptions<PriceListRes, Error, AddPriceListPricesReq>
query?: HttpTypes.AdminPriceListParams,
options?: UseMutationOptions<
HttpTypes.AdminPriceListResponse,
FetchError,
HttpTypes.AdminBatchPriceListPrice
>
) => {
return useMutation({
mutationFn: (payload) => client.priceLists.addPrices(id, payload),
mutationFn: (payload) =>
sdk.admin.priceList.batchPrices(id, payload, query),
onSuccess: (data, variables, context) => {
queryClient.invalidateQueries({
queryKey: priceListsQueryKeys.detail(id),
})
queryClient.invalidateQueries({ queryKey: priceListsQueryKeys.lists() })
queryClient.invalidateQueries({ queryKey: productsQueryKeys.lists() })
options?.onSuccess?.(data, variables, context)
@@ -125,24 +148,6 @@ export const usePriceListAddPrices = (
})
}
export const usePriceListRemovePrices = (
id: string,
options?: UseMutationOptions<PriceListRes, Error, DeletePriceListPricesReq>
) => {
return useMutation({
mutationFn: (payload) => client.priceLists.removePrices(id, payload),
onSuccess: (data, variables, context) => {
queryClient.invalidateQueries({
queryKey: priceListsQueryKeys.detail(id),
})
queryClient.invalidateQueries({ queryKey: priceListsQueryKeys.lists() })
options?.onSuccess?.(data, variables, context)
},
...options,
})
}
export const usePriceListLinkProducts = (
id: string,
options?: UseMutationOptions<
@@ -6,23 +6,46 @@ import {
useQuery,
} from "@tanstack/react-query"
import { client } from "../../lib/client"
import { FetchError } from "@medusajs/js-sdk"
import { HttpTypes } from "@medusajs/types"
import { sdk } from "../../lib/client"
import { queryClient } from "../../lib/query-client"
import { queryKeysFactory } from "../../lib/query-key-factory"
import { UpdateStoreReq } from "../../types/api-payloads"
import { StoreRes } from "../../types/api-responses"
const STORE_QUERY_KEY = "store" as const
export const storeQueryKeys = queryKeysFactory(STORE_QUERY_KEY)
/**
* Workaround to keep the V1 version of retrieving the store.
*/
async function retrieveActiveStore(
query?: HttpTypes.AdminStoreParams
): Promise<HttpTypes.AdminStoreResponse> {
const response = await sdk.admin.store.list(query)
const activeStore = response.stores?.[0]
if (!activeStore) {
throw new FetchError("No active store found", "Not Found", 404)
}
return { store: activeStore }
}
export const useStore = (
query?: Record<string, any>,
options?: Omit<
UseQueryOptions<StoreRes, Error, StoreRes, QueryKey>,
UseQueryOptions<
HttpTypes.AdminStoreResponse,
FetchError,
HttpTypes.AdminStoreResponse,
QueryKey
>,
"queryFn" | "queryKey"
>
) => {
const { data, ...rest } = useQuery({
queryFn: () => client.stores.retrieve(),
queryFn: () => retrieveActiveStore(query),
queryKey: storeQueryKeys.details(),
...options,
})
@@ -35,10 +58,14 @@ export const useStore = (
export const useUpdateStore = (
id: string,
options?: MutationOptions<StoreRes, Error, UpdateStoreReq>
options?: MutationOptions<
HttpTypes.AdminStoreResponse,
FetchError,
HttpTypes.AdminUpdateStore
>
) => {
return useMutation({
mutationFn: (payload) => client.stores.update(id, payload),
mutationFn: (payload) => sdk.admin.store.update(id, payload),
onSuccess: (data, variables, context) => {
queryClient.invalidateQueries({ queryKey: storeQueryKeys.details() })
options?.onSuccess?.(data, variables, context)
@@ -86,8 +86,12 @@
"apply": "Apply",
"add": "Add",
"select": "Select",
"browse": "Browse",
"logout": "Logout"
},
"operators": {
"in": "In"
},
"app": {
"search": {
"allAreas": "All areas",
@@ -1295,61 +1299,96 @@
"deleteCampaignWarning": "You are about to delete the campaign {{name}}. This action cannot be undone.",
"totalSpend": "<0>{{amount}}</0> <1>{{currency}}</1>"
},
"pricing": {
"domain": "Pricing",
"priceLists": {
"domain": "Price Lists",
"delete": {
"confirmation": "You are about to delete the price list {{title}}. This action cannot be undone.",
"successToast": "Price list {{title}} was successfully deleted."
},
"create": {
"header": "Create Price List",
"hint": "Create a new price list to manage the prices of your products."
"subheader": "Create a new price list to manage the prices of your products.",
"tabs": {
"details": "Details",
"products": "Products",
"prices": "Prices"
},
"successToast": "Price list {{title}} was successfully created."
},
"edit": {
"header": "Edit Price List"
"header": "Edit Price List",
"successToast": "Price list {{title}} was successfully updated."
},
"configuration": {
"header": "Configuration",
"editHeader": "Edit Price List Configuration"
},
"warnings": {
"delete": "You are about to delete the price list {{name}}. This action cannot be undone."
},
"status": {
"draft": "Draft",
"expired": "Expired",
"active": "Active",
"scheduled": "Scheduled"
},
"type": {
"sale": "Sale",
"override": "Override"
"edit": {
"header": "Edit Price List Configuration",
"description": "Edit the configuration of the price list.",
"successToast": "Price list configuration was successfully updated."
}
},
"products": {
"deleteProductsPricesWarning": "You are about to delete all prices of {{count}} product(s). This action cannot be undone."
},
"prices": {
"addPrices": "Add prices",
"editPrices": "Edit prices"
},
"table": {
"pricesHeader": "Prices"
"header": "Products",
"actions": {
"addProducts": "Add products",
"editPrices": "Edit prices"
},
"delete": {
"confirmation_one": "You are about to delete the prices for {{count}} product in the price list. This action cannot be undone.",
"confirmation_other": "You are about to delete the prices for {{count}} products in the price list. This action cannot be undone.",
"successToast_one": "Successfully deleted prices for {{count}} product.",
"successToast_other": "Successfully deleted prices for {{count}} products."
},
"add": {
"successToast": "Prices were successfully added to the price list."
},
"edit": {
"successToast": "Prices were successfully updated."
}
},
"fields": {
"statusTooltip": "Status can also be expired or scheduled depending on the start and end date.",
"typeHint": "Choose the type of price you want to create.",
"statusHint": "Choose if price should be published to users",
"draftTypeHint": "Prices will not be visible to users in a draft state",
"activeTypeHint": "Prices are visibile to users in an active state",
"saleTypeHint": "Sale prices are temporary price changes for products.",
"overrideTypeHint": "Overrides are usually used to create customer-specific prices.",
"startDateLabel": "Price list has a start date?",
"startDateHint": "Schedule the price list to activate in the future.",
"endDateLabel": "Price list has an expiry date?",
"endDateHint": "Schedule the price list to deactivate in the future.",
"customerAvailabilityLabel": "Customer availability",
"customerAvailabilityHint": "Choose which customer groups the price list should be applied to.",
"customerAvailabilityNoSelectionLabel": "No customer groups selected",
"priceOverridesLabel": "Price overrides"
},
"actions": {
"addCustomerGroups": "Add customer groups"
"priceOverrides": {
"label": "Price overrides",
"header": "Price Overrides"
},
"status": {
"label": "Status",
"options": {
"active": "Active",
"draft": "Draft",
"expired": "Expired",
"scheduled": "Scheduled"
}
},
"type": {
"label": "Type",
"hint": "Choose the type of price list you want to create.",
"options": {
"sale": {
"label": "Sale",
"description": "Sale prices are temporary price changes for products."
},
"override": {
"label": "Override",
"description": "Overrides are usually used to create customer-specific prices."
}
}
},
"startsAt": {
"label": "Price list has a start date?",
"hint": "Schedule the price list to activate in the future."
},
"endsAt": {
"label": "Price list has an expiry date?",
"hint": "Schedule the price list to deactivate in the future."
},
"customerAvailability": {
"header": "Choose customer groups",
"label": "Customer availability",
"hint": "Choose which customer groups the price list should be applied to.",
"placeholder": "Search for customer groups",
"attribute": "Customer groups"
}
}
},
"profile": {
@@ -171,7 +171,7 @@ export const useGlobalShortcuts = () => {
},
label: t("app.keyboardShortcuts.goToPriceLists"),
type: "pageShortcut",
callback: () => navigate("/pricing"),
callback: () => navigate("/price-lists"),
},
{
keys: {
@@ -332,45 +332,51 @@ export const RouteMap: RouteObject[] = [
],
},
{
path: "/pricing",
path: "/price-lists",
handle: {
crumb: () => "Pricing",
crumb: () => "Price Lists",
},
children: [
{
path: "",
lazy: () => import("../../routes/pricing/pricing-list"),
lazy: () => import("../../routes/price-lists/price-list-list"),
children: [
{
path: "create",
lazy: () => import("../../routes/pricing/pricing-create"),
lazy: () =>
import("../../routes/price-lists/price-list-create"),
},
],
},
{
path: ":id",
lazy: () => import("../../routes/pricing/pricing-detail"),
lazy: () =>
import("../../routes/price-lists/price-list-detail"),
handle: {
crumb: (data: PriceListRes) => data.price_list.title,
},
children: [
{
path: "edit",
lazy: () => import("../../routes/pricing/pricing-edit"),
lazy: () =>
import("../../routes/price-lists/price-list-edit"),
},
{
path: "configuration",
lazy: () =>
import("../../routes/pricing/pricing-configuration"),
import(
"../../routes/price-lists/price-list-configuration"
),
},
{
path: "products/add",
lazy: () => import("../../routes/pricing/pricing-products"),
lazy: () =>
import("../../routes/price-lists/price-list-prices-add"),
},
{
path: "products/edit",
lazy: () =>
import("../../routes/pricing/pricing-products-prices"),
import("../../routes/price-lists/price-list-prices-edit"),
},
],
},
@@ -780,7 +786,8 @@ export const RouteMap: RouteObject[] = [
{
path: ":id",
handle: {
crumb: (data) => data.shipping_profile.name,
crumb: (data: HttpTypes.AdminShippingProfileResponse) =>
data.shipping_profile.name,
},
lazy: () =>
import(
@@ -1,3 +1,3 @@
export type { Theme } from "./theme-context";
export * from "./theme-provider";
export * from "./use-theme";
export type { Theme } from "./theme-context"
export * from "./theme-provider"
export * from "./use-theme"
@@ -1,26 +1,26 @@
import { PropsWithChildren, useEffect, useState } from "react";
import { Theme, ThemeContext } from "./theme-context";
import { PropsWithChildren, useEffect, useState } from "react"
import { Theme, ThemeContext } from "./theme-context"
const THEME_KEY = "medusa_admin_theme";
const THEME_KEY = "medusa_admin_theme"
export const ThemeProvider = ({ children }: PropsWithChildren) => {
const [state, setState] = useState<Theme>(
(localStorage?.getItem(THEME_KEY) as Theme) || "light"
);
)
const setTheme = (theme: Theme) => {
localStorage.setItem(THEME_KEY, theme);
setState(theme);
};
localStorage.setItem(THEME_KEY, theme)
setState(theme)
}
useEffect(() => {
const html = document.querySelector("html");
const html = document.querySelector("html")
if (html) {
/**
* Temporarily disable transitions to prevent
* the theme change from flashing.
*/
const css = document.createElement("style");
const css = document.createElement("style")
css.appendChild(
document.createTextNode(
`* {
@@ -31,24 +31,24 @@ export const ThemeProvider = ({ children }: PropsWithChildren) => {
transition: none !important;
}`
)
);
document.head.appendChild(css);
)
document.head.appendChild(css)
html.classList.remove(state === "light" ? "dark" : "light");
html.classList.add(state);
html.classList.remove(state === "light" ? "dark" : "light")
html.classList.add(state)
/**
* Re-enable transitions after the theme has been set,
* and force the browser to repaint.
*/
window.getComputedStyle(css).opacity;
document.head.removeChild(css);
window.getComputedStyle(css).opacity
document.head.removeChild(css)
}
}, [state]);
}, [state])
return (
<ThemeContext.Provider value={{ theme: state, setTheme }}>
{children}
</ThemeContext.Provider>
);
};
)
}
@@ -1,10 +1,10 @@
import { useContext } from "react";
import { ThemeContext } from "./theme-context";
import { useContext } from "react"
import { ThemeContext } from "./theme-context"
export const useTheme = () => {
const context = useContext(ThemeContext);
const context = useContext(ThemeContext)
if (!context) {
throw new Error("useTheme must be used within a ThemeProvider");
throw new Error("useTheme must be used within a ThemeProvider")
}
return context;
};
return context
}
@@ -1,5 +1,5 @@
import { useLocation } from "react-router-dom"
import { RouteFocusModal } from "../../../components/route-modal"
import { RouteFocusModal } from "../../../components/modals"
import { getApiKeyTypeFromPathname } from "../common/utils"
import { ApiKeyCreateForm } from "./components/api-key-create-form"
@@ -11,7 +11,7 @@ import { Form } from "../../../../../components/common/form"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { useCreateApiKey } from "../../../../../hooks/api/api-keys"
import { ApiKeyType } from "../../../common/constants"
@@ -1,7 +1,7 @@
import { Heading } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { useParams } from "react-router-dom"
import { RouteDrawer } from "../../../components/route-modal"
import { RouteDrawer } from "../../../components/modals"
import { useApiKey } from "../../../hooks/api/api-keys"
import { EditApiKeyForm } from "./components/edit-api-key-form"
@@ -9,7 +9,7 @@ import { Form } from "../../../../../components/common/form"
import {
RouteDrawer,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { useUpdateApiKey } from "../../../../../hooks/api/api-keys"
type EditApiKeyFormProps = {
@@ -1,7 +1,7 @@
import { useParams } from "react-router-dom"
import { AdminApiKeyResponse, AdminSalesChannelResponse } from "@medusajs/types"
import { RouteFocusModal } from "../../../components/route-modal"
import { RouteFocusModal } from "../../../components/modals"
import { useApiKey } from "../../../hooks/api/api-keys"
import { ApiKeySalesChannelsForm } from "./components/api-key-sales-channels-form"
@@ -14,7 +14,7 @@ import * as zod from "zod"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { DataTable } from "../../../../../components/table/data-table"
import { useBatchAddSalesChannelsToApiKey } from "../../../../../hooks/api/api-keys"
import { useSalesChannels } from "../../../../../hooks/api/sales-channels"
@@ -1,5 +1,5 @@
import { useParams } from "react-router-dom"
import { RouteFocusModal } from "../../../components/route-modal"
import { RouteFocusModal } from "../../../components/modals"
import { useCampaign } from "../../../hooks/api/campaigns"
import { AddCampaignPromotionsForm } from "./components"
@@ -1,11 +1,11 @@
import { zodResolver } from "@hookform/resolvers/zod"
import { CampaignResponse, PromotionDTO } from "@medusajs/types"
import { Button, Checkbox, Hint, toast, Tooltip } from "@medusajs/ui"
import { Button, Checkbox, Hint, Tooltip, toast } from "@medusajs/ui"
import { keepPreviousData } from "@tanstack/react-query"
import {
createColumnHelper,
OnChangeFn,
RowSelectionState,
createColumnHelper,
} from "@tanstack/react-table"
import { useMemo, useState } from "react"
import { useForm } from "react-hook-form"
@@ -14,7 +14,7 @@ import * as zod from "zod"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../components/route-modal"
} from "../../../../components/modals"
import { DataTable } from "../../../../components/table/data-table"
import { useAddOrRemoveCampaignPromotions } from "../../../../hooks/api/campaigns"
import { usePromotions } from "../../../../hooks/api/promotions"
@@ -1,7 +1,7 @@
import { Heading } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { useParams } from "react-router-dom"
import { RouteDrawer } from "../../../components/route-modal"
import { RouteDrawer } from "../../../components/modals"
import { useCampaign } from "../../../hooks/api/campaigns"
import { EditCampaignBudgetForm } from "./components/edit-campaign-budget-form"
@@ -8,7 +8,7 @@ import { Form } from "../../../../../components/common/form"
import {
RouteDrawer,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { useUpdateCampaign } from "../../../../../hooks/api/campaigns"
import { getCurrencySymbol } from "../../../../../lib/currencies"
@@ -1,4 +1,4 @@
import { RouteFocusModal } from "../../../components/route-modal"
import { RouteFocusModal } from "../../../components/modals"
import { CreateCampaignForm } from "./components/create-campaign-form"
export const CampaignCreate = () => {
@@ -8,7 +8,7 @@ import { CampaignBudgetTypeValues } from "@medusajs/types"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { useCreateCampaign } from "../../../../../hooks/api/campaigns"
import { CreateCampaignFormFields } from "../../../common/components/create-campaign-form-fields"
@@ -1,7 +1,7 @@
import { Heading } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { useParams } from "react-router-dom"
import { RouteDrawer } from "../../../components/route-modal"
import { RouteDrawer } from "../../../components/modals"
import { useCampaign } from "../../../hooks/api/campaigns"
import { EditCampaignForm } from "./components/edit-campaign-form"
@@ -8,7 +8,7 @@ import { Form } from "../../../../../components/common/form"
import {
RouteDrawer,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { useUpdateCampaign } from "../../../../../hooks/api/campaigns"
type EditCampaignFormProps = {
@@ -1,6 +1,6 @@
import { useSearchParams } from "react-router-dom"
import { RouteFocusModal } from "../../../components/route-modal"
import { RouteFocusModal } from "../../../components/modals"
import { CreateCategoryForm } from "./components/create-category-form/create-category-form"
export const CategoryCreate = () => {
@@ -7,7 +7,7 @@ import { useState } from "react"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { useCreateProductCategory } from "../../../../../hooks/api/categories"
import { CreateCategoryDetails } from "./create-category-details"
import { CreateCategoryNesting } from "./create-category-nesting"
@@ -1,7 +1,7 @@
import { Heading } from "@medusajs/ui"
import { useParams } from "react-router-dom"
import { RouteDrawer } from "../../../components/route-modal"
import { RouteDrawer } from "../../../components/modals"
import { useProductCategory } from "../../../hooks/api/categories"
import { EditCategoryForm } from "./components/edit-category-form"
@@ -7,7 +7,7 @@ import { z } from "zod"
import { HttpTypes } from "@medusajs/types"
import { Form } from "../../../../../components/common/form"
import { HandleInput } from "../../../../../components/inputs/handle-input"
import { RouteDrawer } from "../../../../../components/route-modal"
import { RouteDrawer } from "../../../../../components/modals"
const EditCategorySchema = z.object({
name: z.string().min(1),
@@ -1,4 +1,4 @@
import { RouteFocusModal } from "../../../components/route-modal"
import { RouteFocusModal } from "../../../components/modals"
import { OrganizeCategoryForm } from "./components/organize-category-form/organize-category-form"
export const CategoryOrganize = () => {
@@ -5,7 +5,7 @@ import { FetchError } from "@medusajs/js-sdk"
import { HttpTypes } from "@medusajs/types"
import { toast } from "@medusajs/ui"
import { t } from "i18next"
import { RouteFocusModal } from "../../../../../components/route-modal"
import { RouteFocusModal } from "../../../../../components/modals"
import {
categoriesQueryKeys,
useProductCategories,
@@ -1,5 +1,5 @@
import { useParams } from "react-router-dom"
import { RouteFocusModal } from "../../../components/route-modal"
import { RouteFocusModal } from "../../../components/modals"
import { useProductCategory } from "../../../hooks/api/categories"
import { EditCategoryProductsForm } from "./components/edit-category-products-form"
@@ -14,7 +14,7 @@ import { useTranslation } from "react-i18next"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { DataTable } from "../../../../../components/table/data-table"
import { useUpdateProductCategoryProducts } from "../../../../../hooks/api/categories"
import { useProducts } from "../../../../../hooks/api/products"
@@ -1,6 +1,6 @@
import { useParams } from "react-router-dom"
import { RouteFocusModal } from "../../../components/route-modal"
import { RouteFocusModal } from "../../../components/modals"
import { useCollection } from "../../../hooks/api/collections"
import { AddProductsToCollectionForm } from "./components/add-products-to-collection-form"
@@ -14,7 +14,7 @@ import * as zod from "zod"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/route-modal/index.ts"
} from "../../../../../components/modals/index.ts"
import { DataTable } from "../../../../../components/table/data-table/data-table.tsx"
import { useUpdateCollectionProducts } from "../../../../../hooks/api/collections.tsx"
import { useProducts } from "../../../../../hooks/api/products.tsx"
@@ -1,4 +1,4 @@
import { RouteFocusModal } from "../../../components/route-modal"
import { RouteFocusModal } from "../../../components/modals"
import { CreateCollectionForm } from "./components/create-collection-form"
export const CollectionCreate = () => {
@@ -9,7 +9,7 @@ import { HandleInput } from "../../../../../components/inputs/handle-input"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { useCreateCollection } from "../../../../../hooks/api/collections"
const CreateCollectionSchema = zod.object({
@@ -1,7 +1,7 @@
import { Heading } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { useParams } from "react-router-dom"
import { RouteDrawer } from "../../../components/route-modal"
import { RouteDrawer } from "../../../components/modals"
import { useCollection } from "../../../hooks/api/collections"
import { EditCollectionForm } from "./components/edit-collection-form"
@@ -4,13 +4,13 @@ import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next"
import * as zod from "zod"
import { HttpTypes } from "@medusajs/types"
import { Form } from "../../../../../components/common/form"
import {
RouteDrawer,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { useUpdateCollection } from "../../../../../hooks/api/collections"
import { HttpTypes } from "@medusajs/types"
type EditCollectionFormProps = {
collection: HttpTypes.AdminCollection
@@ -10,10 +10,11 @@ import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next"
import * as zod from "zod"
import { HttpTypes } from "@medusajs/types"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { DataTable } from "../../../../../components/table/data-table"
import { useAddCustomersToGroup } from "../../../../../hooks/api/customer-groups"
import { useCustomers } from "../../../../../hooks/api/customers"
@@ -21,7 +22,6 @@ import { useCustomerTableColumns } from "../../../../../hooks/table/columns/use-
import { useCustomerTableFilters } from "../../../../../hooks/table/filters/use-customer-table-filters"
import { useCustomerTableQuery } from "../../../../../hooks/table/query/use-customer-table-query"
import { useDataTable } from "../../../../../hooks/use-data-table"
import { HttpTypes } from "@medusajs/types"
type AddCustomersFormProps = {
customerGroupId: string
@@ -1,5 +1,5 @@
import { useParams } from "react-router-dom"
import { RouteFocusModal } from "../../../components/route-modal"
import { RouteFocusModal } from "../../../components/modals"
import { AddCustomersForm } from "./components/add-customers-form"
export const CustomerGroupAddCustomers = () => {
@@ -8,7 +8,7 @@ import { Form } from "../../../../../components/common/form"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { useCreateCustomerGroup } from "../../../../../hooks/api/customer-groups"
export const CreateCustomerGroupSchema = zod.object({
@@ -1,4 +1,4 @@
import { RouteFocusModal } from "../../../components/route-modal"
import { RouteFocusModal } from "../../../components/modals"
import { CreateCustomerGroupForm } from "./components/create-customer-group-form"
export const CustomerGroupCreate = () => {
@@ -1,4 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod"
import { HttpTypes } from "@medusajs/types"
import { Button, Input, toast } from "@medusajs/ui"
import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next"
@@ -7,9 +8,8 @@ import { Form } from "../../../../../components/common/form"
import {
RouteDrawer,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { useUpdateCustomerGroup } from "../../../../../hooks/api/customer-groups"
import { HttpTypes } from "@medusajs/types"
type EditCustomerGroupFormProps = {
group: HttpTypes.AdminCustomerGroup
@@ -1,7 +1,7 @@
import { Heading } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { useParams } from "react-router-dom"
import { RouteDrawer } from "../../../components/route-modal"
import { RouteDrawer } from "../../../components/modals"
import { useCustomerGroup } from "../../../hooks/api/customer-groups"
import { EditCustomerGroupForm } from "./components/edit-customer-group-form"
@@ -8,7 +8,7 @@ import { Form } from "../../../../../components/common/form"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { useCreateCustomer } from "../../../../../hooks/api/customers"
const CreateCustomerSchema = zod.object({
@@ -1,4 +1,4 @@
import { RouteFocusModal } from "../../../components/route-modal"
import { RouteFocusModal } from "../../../components/modals"
import { CreateCustomerForm } from "./components/create-customer-form"
export const CustomerCreate = () => {
@@ -1,4 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod"
import { HttpTypes } from "@medusajs/types"
import { Button, Input, toast } from "@medusajs/ui"
import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next"
@@ -9,14 +10,13 @@ import { Metadata } from "../../../../../components/forms/metadata/index.ts"
import {
RouteDrawer,
useRouteModal,
} from "../../../../../components/route-modal/index.ts"
} from "../../../../../components/modals/index.ts"
import { useUpdateCustomer } from "../../../../../hooks/api/customers.tsx"
import {
formValuesToMetadata,
metadataToFormValues,
} from "../../../../../lib/metadata.ts"
import { metadataFormSchema } from "../../../../../lib/validation.ts"
import { HttpTypes } from "@medusajs/types"
type EditCustomerFormProps = {
customer: HttpTypes.AdminCustomer
@@ -1,7 +1,7 @@
import { Heading } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { useParams } from "react-router-dom"
import { RouteDrawer } from "../../../components/route-modal"
import { RouteDrawer } from "../../../components/modals"
import { useCustomer } from "../../../hooks/api/customers"
import { EditCustomerForm } from "./components/edit-customer-form"
@@ -8,7 +8,7 @@ import { TransferOwnerShipForm } from "../../../../../components/forms/transfer-
import {
RouteDrawer,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { TransferOwnershipSchema } from "../../../../../lib/schemas"
type TransferCustomerOrderOwnershipFormProps = {
@@ -2,7 +2,7 @@ import { Heading } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { useParams } from "react-router-dom"
import { RouteDrawer } from "../../../components/route-modal"
import { RouteDrawer } from "../../../components/modals"
import { useOrder } from "../../../hooks/api/orders"
import { TransferCustomerOrderOwnershipForm } from "./components/transfer-customer-order-ownership-form"
@@ -13,7 +13,7 @@ import * as zod from "zod"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { DataTable } from "../../../../../components/table/data-table"
import {
customerGroupsQueryKeys,
@@ -1,5 +1,5 @@
import { useParams } from "react-router-dom"
import { RouteFocusModal } from "../../../components/route-modal"
import { RouteFocusModal } from "../../../components/modals"
import { AddCustomerGroupsForm } from "./components/add-customers-form"
export const CustomerAddCustomerGroups = () => {
@@ -6,30 +6,30 @@ import * as zod from "zod"
import {
Button,
Heading,
Input,
ProgressStatus,
ProgressTabs,
clx,
Input,
Textarea,
Switch,
Textarea,
clx,
toast,
} from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { Form } from "../../../../../components/common/form"
import { CountrySelect } from "../../../../../components/inputs/country-select"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/route-modal"
import { CreateInventoryAvailabilityForm } from "./create-inventory-availability-form"
import { CountrySelect } from "../../../../../components/inputs/country-select"
import { Form } from "../../../../../components/common/form"
} from "../../../../../components/modals"
import {
inventoryItemsQueryKeys,
useCreateInventoryItem,
} from "../../../../../hooks/api/inventory"
import { sdk } from "../../../../../lib/client"
import { optionalInt } from "../../../../../lib/validation"
import { queryClient } from "../../../../../lib/query-client"
import { optionalInt } from "../../../../../lib/validation"
import { CreateInventoryAvailabilityForm } from "./create-inventory-availability-form"
enum Tab {
DETAILS = "details",
@@ -1,4 +1,4 @@
import { RouteFocusModal } from "../../../components/route-modal"
import { RouteFocusModal } from "../../../components/modals"
import { CreateInventoryItemForm } from "./components/create-inventory-item-form"
export function InventoryCreate() {
@@ -1,11 +1,11 @@
import { AdjustInventoryForm } from "./components/adjust-inventory-form"
import { Heading } from "@medusajs/ui"
import { InventoryTypes } from "@medusajs/types"
import { RouteDrawer } from "../../../../../components/route-modal"
import { useInventoryItem } from "../../../../../hooks/api/inventory"
import { useParams } from "react-router-dom"
import { useStockLocation } from "../../../../../hooks/api/stock-locations"
import { Heading } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { useParams } from "react-router-dom"
import { RouteDrawer } from "../../../../../components/modals"
import { useInventoryItem } from "../../../../../hooks/api/inventory"
import { useStockLocation } from "../../../../../hooks/api/stock-locations"
import { AdjustInventoryForm } from "./components/adjust-inventory-form"
export const AdjustInventoryDrawer = () => {
const { id, location_id } = useParams()
@@ -1,16 +1,16 @@
import * as zod from "zod"
import { zodResolver } from "@hookform/resolvers/zod"
import * as zod from "zod"
import { HttpTypes, InventoryLevelDTO, StockLocationDTO } from "@medusajs/types"
import { Button, Input, Text, toast } from "@medusajs/ui"
import { InventoryLevelDTO, StockLocationDTO, HttpTypes } from "@medusajs/types"
import {
RouteDrawer,
useRouteModal,
} from "../../../../../../components/route-modal"
} from "../../../../../../components/modals"
import { Form } from "../../../../../../components/common/form"
import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next"
import { Form } from "../../../../../../components/common/form"
import { useUpdateInventoryLevel } from "../../../../../../hooks/api/inventory"
type AdjustInventoryFormProps = {
@@ -4,7 +4,7 @@ import { Button, Input, toast } from "@medusajs/ui"
import {
RouteDrawer,
useRouteModal,
} from "../../../../../../components/route-modal"
} from "../../../../../../components/modals"
import { zodResolver } from "@hookform/resolvers/zod"
import { InventoryTypes } from "@medusajs/types"
@@ -1,9 +1,9 @@
import { EditInventoryItemAttributesForm } from "./components/edit-item-attributes-form"
import { Heading } from "@medusajs/ui"
import { RouteDrawer } from "../../../../../components/route-modal"
import { useInventoryItem } from "../../../../../hooks/api/inventory"
import { useParams } from "react-router-dom"
import { useTranslation } from "react-i18next"
import { useParams } from "react-router-dom"
import { RouteDrawer } from "../../../../../components/modals"
import { useInventoryItem } from "../../../../../hooks/api/inventory"
import { EditInventoryItemAttributesForm } from "./components/edit-item-attributes-form"
export const InventoryItemAttributesEdit = () => {
const { id } = useParams()
@@ -4,15 +4,15 @@ import { Button, Input, toast } from "@medusajs/ui"
import {
RouteDrawer,
useRouteModal,
} from "../../../../../../components/route-modal"
} from "../../../../../../components/modals"
import { Form } from "../../../../../../components/common/form"
import { zodResolver } from "@hookform/resolvers/zod"
import { InventoryTypes } from "@medusajs/types"
import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next"
import { useUpdateInventoryItem } from "../../../../../../hooks/api/inventory"
import { z } from "zod"
import { zodResolver } from "@hookform/resolvers/zod"
import { Form } from "../../../../../../components/common/form"
import { useUpdateInventoryItem } from "../../../../../../hooks/api/inventory"
type EditInventoryItemFormProps = {
item: InventoryTypes.InventoryItemDTO
@@ -1,9 +1,9 @@
import { EditInventoryItemForm } from "./components/edit-item-form"
import { Heading } from "@medusajs/ui"
import { RouteDrawer } from "../../../../../components/route-modal"
import { useInventoryItem } from "../../../../../hooks/api/inventory"
import { useParams } from "react-router-dom"
import { useTranslation } from "react-i18next"
import { useParams } from "react-router-dom"
import { RouteDrawer } from "../../../../../components/modals"
import { useInventoryItem } from "../../../../../hooks/api/inventory"
import { EditInventoryItemForm } from "./components/edit-item-form"
export const InventoryItemEdit = () => {
const { id } = useParams()
@@ -1,16 +1,16 @@
import * as zod from "zod"
import { Button, Text, toast } from "@medusajs/ui"
import { zodResolver } from "@hookform/resolvers/zod"
import { AdminInventoryItem, AdminStockLocation } from "@medusajs/types"
import { Button, Text, toast } from "@medusajs/ui"
import { useFieldArray, useForm } from "react-hook-form"
import { useTranslation } from "react-i18next"
import { z } from "zod"
import { zodResolver } from "@hookform/resolvers/zod"
import {
RouteDrawer,
useRouteModal,
} from "../../../../../../components/route-modal"
} from "../../../../../../components/modals"
import { useBatchUpdateInventoryLevels } from "../../../../../../hooks/api/inventory"
import { useFieldArray, useForm } from "react-hook-form"
import { LocationItem } from "./location-item"
import { useEffect, useMemo } from "react"
@@ -1,11 +1,11 @@
import { Heading } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { ManageLocationsForm } from "./components/manage-locations-form"
import { RouteDrawer } from "../../../../../components/route-modal"
import { useInventoryItem } from "../../../../../hooks/api/inventory"
import { useParams } from "react-router-dom"
import { RouteDrawer } from "../../../../../components/modals"
import { useInventoryItem } from "../../../../../hooks/api/inventory"
import { useStockLocations } from "../../../../../hooks/api/stock-locations"
import { ManageLocationsForm } from "./components/manage-locations-form"
export const ManageLocationsDrawer = () => {
const { id } = useParams()
@@ -8,7 +8,7 @@ import { CountrySelect } from "../../../../../components/inputs/country-select"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { useCreateStockLocation } from "../../../../../hooks/api/stock-locations"
const CreateLocationSchema = zod.object({
@@ -1,4 +1,4 @@
import { RouteFocusModal } from "../../../components/route-modal"
import { RouteFocusModal } from "../../../components/modals"
import { CreateLocationForm } from "./components/create-location-form"
export const LocationCreate = () => {
@@ -10,7 +10,7 @@ import { CountrySelect } from "../../../../../components/inputs/country-select"
import {
RouteDrawer,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { useUpdateStockLocation } from "../../../../../hooks/api/stock-locations"
type EditLocationFormProps = {
@@ -1,7 +1,7 @@
import { Heading } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { useParams } from "react-router-dom"
import { RouteDrawer } from "../../../components/route-modal"
import { RouteDrawer } from "../../../components/modals"
import { useStockLocation } from "../../../hooks/api/stock-locations"
import { EditLocationForm } from "./components/edit-location-form"
@@ -11,7 +11,7 @@ import { useForm } from "react-hook-form"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { DataTable } from "../../../../../components/table/data-table"
import { useSalesChannels } from "../../../../../hooks/api/sales-channels"
import { useUpdateStockLocationSalesChannels } from "../../../../../hooks/api/stock-locations"
@@ -1,6 +1,6 @@
import { useParams } from "react-router-dom"
import { RouteFocusModal } from "../../../components/route-modal"
import { RouteFocusModal } from "../../../components/modals"
import { useStockLocation } from "../../../hooks/api/stock-locations"
import { LocationEditSalesChannelsForm } from "./components/edit-sales-channels-form"
@@ -12,7 +12,7 @@ import { SplitView } from "../../../../../components/layout/split-view"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { useCreateFulfillmentSetServiceZone } from "../../../../../hooks/api/fulfillment-sets"
import { GeoZoneForm } from "../../../common/components/geo-zone-form"
import { FulfillmentSetType } from "../../../common/constants"
@@ -1,6 +1,6 @@
import { json, useLoaderData, useParams } from "react-router-dom"
import { RouteFocusModal } from "../../../components/route-modal"
import { RouteFocusModal } from "../../../components/modals"
import { useStockLocation } from "../../../hooks/api/stock-locations"
import { FulfillmentSetType } from "../common/constants"
import { CreateServiceZoneForm } from "./components/create-service-zone-form"
@@ -9,7 +9,7 @@ import { InlineTip } from "../../../../../components/common/inline-tip"
import {
RouteDrawer,
useRouteModal,
} from "../../../../../components/route-modal"
} from "../../../../../components/modals"
import { useUpdateFulfillmentSetServiceZone } from "../../../../../hooks/api/fulfillment-sets"
type EditServiceZoneFormProps = {

Some files were not shown because too many files have changed in this diff Show More