diff --git a/packages/admin-next/dashboard/public/locales/en-US/translation.json b/packages/admin-next/dashboard/public/locales/en-US/translation.json index cb690c2cbb..02892e6db7 100644 --- a/packages/admin-next/dashboard/public/locales/en-US/translation.json +++ b/packages/admin-next/dashboard/public/locales/en-US/translation.json @@ -83,6 +83,7 @@ "gallery": "Gallery", "titleHint": "Give your product a short and clear title.<0/>50-60 characters is the recommended length for search engines.", "descriptionHint": "Give your product a short and clear description.<0/>120-160 characters is the recommended length for search engines.", + "discountableHint": "When unchecked discounts will not be applied to this product.", "handleTooltip": "The handle is used to reference the product in your storefront. If not specified, the handle will be generated from the product title.", "availableInSalesChannels": "Available in <0>{{x}} of <1>{{y}} sales channels", "noSalesChannels": "Not available in any sales channels", @@ -249,7 +250,12 @@ "taxInclusiveHint": "When enabled all prices in the region will be tax inclusive.", "providersHint": "The providers that are available in the region.", "shippingOptions": "Shipping Options", - "returnShippingOptions": "Return Shipping Options" + "returnShippingOptions": "Return Shipping Options", + "return": "Return", + "outbound": "Outbound", + "priceType": "Price Type", + "flatRate": "Flat Rate", + "calculated": "Calculated" }, "locations": { "domain": "Locations", @@ -399,6 +405,7 @@ "dateIssued": "Date issued", "issuedDate": "Issued date", "expiryDate": "Expiry date", + "price": "Price", "height": "Height", "width": "Width", "length": "Length", diff --git a/packages/admin-next/dashboard/src/components/route-modal/index.ts b/packages/admin-next/dashboard/src/components/route-modal/index.ts new file mode 100644 index 0000000000..2122e387de --- /dev/null +++ b/packages/admin-next/dashboard/src/components/route-modal/index.ts @@ -0,0 +1,3 @@ +export { RouteDrawer } from "./route-drawer" +export { RouteFocusModal } from "./route-focus-modal" +export { useRouteModal } from "./route-modal-provider" diff --git a/packages/admin-next/dashboard/src/components/route-modal/route-drawer/index.ts b/packages/admin-next/dashboard/src/components/route-modal/route-drawer/index.ts new file mode 100644 index 0000000000..82f4bb964c --- /dev/null +++ b/packages/admin-next/dashboard/src/components/route-modal/route-drawer/index.ts @@ -0,0 +1 @@ +export * from "./route-drawer" diff --git a/packages/admin-next/dashboard/src/components/route-modal/route-drawer/route-drawer.tsx b/packages/admin-next/dashboard/src/components/route-modal/route-drawer/route-drawer.tsx new file mode 100644 index 0000000000..cad73d9589 --- /dev/null +++ b/packages/admin-next/dashboard/src/components/route-modal/route-drawer/route-drawer.tsx @@ -0,0 +1,59 @@ +import { Drawer } from "@medusajs/ui" +import { PropsWithChildren, useEffect, useState } from "react" +import { useNavigate } from "react-router-dom" +import { RouteForm } from "../route-form" +import { RouteModalProvider } from "../route-modal-provider/route-provider" + +type RouteDrawerProps = PropsWithChildren<{ + prev?: string +}> + +const Root = ({ prev = "..", children }: RouteDrawerProps) => { + const navigate = useNavigate() + const [open, setOpen] = useState(false) + + /** + * Open the modal when the component mounts. This + * ensures that the entry animation is played. + */ + useEffect(() => { + setOpen(true) + }, []) + + const handleOpenChange = (open: boolean) => { + if (!open) { + document.body.style.pointerEvents = "auto" + navigate(prev, { replace: true }) + return + } + + setOpen(open) + } + + return ( + + + {children} + + + ) +} + +const Header = Drawer.Header +const Body = Drawer.Body +const Footer = Drawer.Footer +const Close = Drawer.Close +const Form = RouteForm + +/** + * Drawer that is used to render a form on a separate route. + * + * Typically used for forms editing a resource. + */ +export const RouteDrawer = Object.assign(Root, { + Header, + Body, + Footer, + Close, + Form, +}) diff --git a/packages/admin-next/dashboard/src/components/route-modal/route-focus-modal/index.ts b/packages/admin-next/dashboard/src/components/route-modal/route-focus-modal/index.ts new file mode 100644 index 0000000000..764e6c80c3 --- /dev/null +++ b/packages/admin-next/dashboard/src/components/route-modal/route-focus-modal/index.ts @@ -0,0 +1 @@ +export * from "./route-focus-modal" diff --git a/packages/admin-next/dashboard/src/components/route-modal/route-focus-modal/route-focus-modal.tsx b/packages/admin-next/dashboard/src/components/route-modal/route-focus-modal/route-focus-modal.tsx new file mode 100644 index 0000000000..006dbdaa61 --- /dev/null +++ b/packages/admin-next/dashboard/src/components/route-modal/route-focus-modal/route-focus-modal.tsx @@ -0,0 +1,58 @@ +import { FocusModal } from "@medusajs/ui" +import { PropsWithChildren, useEffect, useState } from "react" +import { useNavigate } from "react-router-dom" +import { RouteForm } from "../route-form" +import { RouteModalProvider } from "../route-modal-provider/route-provider" + +type RouteFocusModalProps = PropsWithChildren<{ + prev?: string +}> + +const Root = ({ prev = "..", children }: RouteFocusModalProps) => { + const navigate = useNavigate() + const [open, setOpen] = useState(false) + + /** + * Open the modal when the component mounts. This + * ensures that the entry animation is played. + */ + useEffect(() => { + setOpen(true) + }, []) + + const handleOpenChange = (open: boolean) => { + if (!open) { + document.body.style.pointerEvents = "auto" + navigate(prev, { replace: true }) + return + } + + setOpen(open) + } + + return ( + + + {children} + + + ) +} + +const Header = FocusModal.Header +const Body = FocusModal.Body +const Close = FocusModal.Close +const Form = RouteForm + +/** + * FocusModal that is used to render a form on a separate route. + * + * Typically used for forms creating a resource or forms that require + * a lot of space. + */ +export const RouteFocusModal = Object.assign(Root, { + Header, + Body, + Close, + Form, +}) diff --git a/packages/admin-next/dashboard/src/components/route-modal/route-form/index.ts b/packages/admin-next/dashboard/src/components/route-modal/route-form/index.ts new file mode 100644 index 0000000000..684d9b013c --- /dev/null +++ b/packages/admin-next/dashboard/src/components/route-modal/route-form/index.ts @@ -0,0 +1 @@ +export * from "./route-form" diff --git a/packages/admin-next/dashboard/src/components/route-modal/route-form/route-form.tsx b/packages/admin-next/dashboard/src/components/route-modal/route-form/route-form.tsx new file mode 100644 index 0000000000..d3131caac3 --- /dev/null +++ b/packages/admin-next/dashboard/src/components/route-modal/route-form/route-form.tsx @@ -0,0 +1,63 @@ +import { Prompt } from "@medusajs/ui" +import { PropsWithChildren } from "react" +import { FieldValues, UseFormReturn } from "react-hook-form" +import { useTranslation } from "react-i18next" +import { useBlocker } from "react-router-dom" +import { Form } from "../../common/form" + +type RouteFormProps = PropsWithChildren<{ + form: UseFormReturn +}> + +export const RouteForm = ({ + form, + children, +}: RouteFormProps) => { + const { t } = useTranslation() + + const { + formState: { isDirty }, + } = form + + const blocker = useBlocker(({ currentLocation, nextLocation }) => { + const { isSubmitSuccessful } = nextLocation.state || {} + + if (isSubmitSuccessful) { + return false + } + + return isDirty && currentLocation.pathname !== nextLocation.pathname + }) + + const handleCancel = () => { + blocker?.reset?.() + } + + const handleContinue = () => { + blocker?.proceed?.() + } + + return ( +
+ {children} + + + + {t("general.unsavedChangesTitle")} + + {t("general.unsavedChangesDescription")} + + + + + {t("actions.cancel")} + + + {t("actions.continue")} + + + + +
+ ) +} diff --git a/packages/admin-next/dashboard/src/components/route-modal/route-modal-provider/index.ts b/packages/admin-next/dashboard/src/components/route-modal/route-modal-provider/index.ts new file mode 100644 index 0000000000..0caf0a36b0 --- /dev/null +++ b/packages/admin-next/dashboard/src/components/route-modal/route-modal-provider/index.ts @@ -0,0 +1 @@ +export * from "./route-provider" diff --git a/packages/admin-next/dashboard/src/components/route-modal/route-modal-provider/route-provider.tsx b/packages/admin-next/dashboard/src/components/route-modal/route-modal-provider/route-provider.tsx new file mode 100644 index 0000000000..84d8664944 --- /dev/null +++ b/packages/admin-next/dashboard/src/components/route-modal/route-modal-provider/route-provider.tsx @@ -0,0 +1,41 @@ +import { PropsWithChildren, createContext, useContext } from "react" +import { useNavigate } from "react-router-dom" + +type RouteModalProviderContextType = { + handleSuccess: (path?: string) => void +} + +const RouteModalProviderContext = + createContext(null) + +export const useRouteModal = () => { + const context = useContext(RouteModalProviderContext) + + if (!context) { + throw new Error("useRouteModal must be used within a RouteModalProvider") + } + + return context +} + +type RouteModalProviderProps = PropsWithChildren<{ + prev: string +}> + +export const RouteModalProvider = ({ + prev, + children, +}: RouteModalProviderProps) => { + const navigate = useNavigate() + + const handleSuccess = (path?: string) => { + const to = path || prev + navigate(to, { replace: true, state: { isSubmitSuccessful: true } }) + } + + return ( + + {children} + + ) +} diff --git a/packages/admin-next/dashboard/src/components/table/table-cells/region/countries-cell/countries-cell.tsx b/packages/admin-next/dashboard/src/components/table/table-cells/region/countries-cell/countries-cell.tsx new file mode 100644 index 0000000000..6ae9fa8f2c --- /dev/null +++ b/packages/admin-next/dashboard/src/components/table/table-cells/region/countries-cell/countries-cell.tsx @@ -0,0 +1,56 @@ +import { Country } from "@medusajs/medusa" +import { Tooltip } from "@medusajs/ui" +import { useTranslation } from "react-i18next" +import { PlaceholderCell } from "../../common/placeholder-cell" + +type CountriesCellProps = { + countries?: Country[] | null +} + +export const CountriesCell = ({ countries }: CountriesCellProps) => { + const { t } = useTranslation() + + if (!countries || countries.length === 0) { + return + } + + const displayValue = countries + .slice(0, 2) + .map((c) => c.display_name) + .join(", ") + + const additionalCountries = countries.slice(2).map((c) => c.display_name) + + return ( +
+ {displayValue} + {additionalCountries.length > 0 && ( + + {additionalCountries.map((c) => ( +
  • {c}
  • + ))} + + } + > + + {t("general.plusCountMore", { + count: additionalCountries.length, + })} + +
    + )} +
    + ) +} + +export const CountriesHeader = () => { + const { t } = useTranslation() + + return ( +
    + {t("fields.countries")} +
    + ) +} diff --git a/packages/admin-next/dashboard/src/components/table/table-cells/region/countries-cell/index.ts b/packages/admin-next/dashboard/src/components/table/table-cells/region/countries-cell/index.ts new file mode 100644 index 0000000000..eba73ad937 --- /dev/null +++ b/packages/admin-next/dashboard/src/components/table/table-cells/region/countries-cell/index.ts @@ -0,0 +1 @@ +export * from "./countries-cell" diff --git a/packages/admin-next/dashboard/src/components/table/table-cells/region/fulfillment-providers-cell/fulfillment-providers-cell.tsx b/packages/admin-next/dashboard/src/components/table/table-cells/region/fulfillment-providers-cell/fulfillment-providers-cell.tsx new file mode 100644 index 0000000000..43df61c899 --- /dev/null +++ b/packages/admin-next/dashboard/src/components/table/table-cells/region/fulfillment-providers-cell/fulfillment-providers-cell.tsx @@ -0,0 +1,58 @@ +import { FulfillmentProvider } from "@medusajs/medusa" +import { Tooltip } from "@medusajs/ui" +import { useTranslation } from "react-i18next" +import { PlaceholderCell } from "../../common/placeholder-cell" + +type FulfillmentProvidersCellProps = { + fulfillmentProviders?: FulfillmentProvider[] | null +} + +export const FulfillmentProvidersCell = ({ + fulfillmentProviders, +}: FulfillmentProvidersCellProps) => { + const { t } = useTranslation() + + if (!fulfillmentProviders || fulfillmentProviders.length === 0) { + return + } + + const displayValue = fulfillmentProviders + .slice(0, 2) + .map((p) => p.id) + .join(", ") + + const additionalProviders = fulfillmentProviders.slice(2).map((c) => c.id) + + return ( +
    + {displayValue} + {additionalProviders.length > 0 && ( + + {additionalProviders.map((c) => ( +
  • {c}
  • + ))} + + } + > + + {t("general.plusCountMore", { + count: additionalProviders.length, + })} + +
    + )} +
    + ) +} + +export const FulfillmentProvidersHeader = () => { + const { t } = useTranslation() + + return ( +
    + {t("fields.fulfillmentProviders")} +
    + ) +} diff --git a/packages/admin-next/dashboard/src/components/table/table-cells/region/fulfillment-providers-cell/index.ts b/packages/admin-next/dashboard/src/components/table/table-cells/region/fulfillment-providers-cell/index.ts new file mode 100644 index 0000000000..59ceb739bf --- /dev/null +++ b/packages/admin-next/dashboard/src/components/table/table-cells/region/fulfillment-providers-cell/index.ts @@ -0,0 +1 @@ +export * from "./fulfillment-providers-cell" diff --git a/packages/admin-next/dashboard/src/components/table/table-cells/region/payment-providers-cell/index.ts b/packages/admin-next/dashboard/src/components/table/table-cells/region/payment-providers-cell/index.ts new file mode 100644 index 0000000000..28efce12e6 --- /dev/null +++ b/packages/admin-next/dashboard/src/components/table/table-cells/region/payment-providers-cell/index.ts @@ -0,0 +1 @@ +export * from "./payment-providers-cell" diff --git a/packages/admin-next/dashboard/src/components/table/table-cells/region/payment-providers-cell/payment-providers-cell.tsx b/packages/admin-next/dashboard/src/components/table/table-cells/region/payment-providers-cell/payment-providers-cell.tsx new file mode 100644 index 0000000000..b7bbfd4d8a --- /dev/null +++ b/packages/admin-next/dashboard/src/components/table/table-cells/region/payment-providers-cell/payment-providers-cell.tsx @@ -0,0 +1,58 @@ +import { PaymentProvider } from "@medusajs/medusa" +import { Tooltip } from "@medusajs/ui" +import { useTranslation } from "react-i18next" +import { PlaceholderCell } from "../../common/placeholder-cell" + +type PaymentProvidersCellProps = { + paymentProviders?: PaymentProvider[] | null +} + +export const PaymentProvidersCell = ({ + paymentProviders, +}: PaymentProvidersCellProps) => { + const { t } = useTranslation() + + if (!paymentProviders || paymentProviders.length === 0) { + return + } + + const displayValue = paymentProviders + .slice(0, 2) + .map((p) => p.id) + .join(", ") + + const additionalProviders = paymentProviders.slice(2).map((c) => c.id) + + return ( +
    + {displayValue} + {additionalProviders.length > 0 && ( + + {additionalProviders.map((c) => ( +
  • {c}
  • + ))} + + } + > + + {t("general.plusCountMore", { + count: additionalProviders.length, + })} + +
    + )} +
    + ) +} + +export const PaymentProvidersHeader = () => { + const { t } = useTranslation() + + return ( +
    + {t("fields.paymentProviders")} +
    + ) +} diff --git a/packages/admin-next/dashboard/src/components/table/table-cells/region/region-cell/index.ts b/packages/admin-next/dashboard/src/components/table/table-cells/region/region-cell/index.ts new file mode 100644 index 0000000000..9d2849c741 --- /dev/null +++ b/packages/admin-next/dashboard/src/components/table/table-cells/region/region-cell/index.ts @@ -0,0 +1 @@ +export * from "./region-cell" diff --git a/packages/admin-next/dashboard/src/components/table/table-cells/region/region-cell/region-cell.tsx b/packages/admin-next/dashboard/src/components/table/table-cells/region/region-cell/region-cell.tsx new file mode 100644 index 0000000000..2bdd6c16db --- /dev/null +++ b/packages/admin-next/dashboard/src/components/table/table-cells/region/region-cell/region-cell.tsx @@ -0,0 +1,23 @@ +import { useTranslation } from "react-i18next" + +type RegionCellProps = { + name: string +} + +export const RegionCell = ({ name }: RegionCellProps) => { + return ( +
    + {name} +
    + ) +} + +export const RegionHeader = () => { + const { t } = useTranslation() + + return ( +
    + {t("fields.name")} +
    + ) +} diff --git a/packages/admin-next/dashboard/src/hooks/table/columns/use-region-table-columns.tsx b/packages/admin-next/dashboard/src/hooks/table/columns/use-region-table-columns.tsx new file mode 100644 index 0000000000..e27ce172ca --- /dev/null +++ b/packages/admin-next/dashboard/src/hooks/table/columns/use-region-table-columns.tsx @@ -0,0 +1,50 @@ +import { Region } from "@medusajs/medusa" +import { createColumnHelper } from "@tanstack/react-table" +import { useMemo } from "react" + +import { + CountriesCell, + CountriesHeader, +} from "../../../components/table/table-cells/region/countries-cell" +import { + FulfillmentProvidersCell, + FulfillmentProvidersHeader, +} from "../../../components/table/table-cells/region/fulfillment-providers-cell" +import { + PaymentProvidersCell, + PaymentProvidersHeader, +} from "../../../components/table/table-cells/region/payment-providers-cell" +import { + RegionCell, + RegionHeader, +} from "../../../components/table/table-cells/region/region-cell" + +const columnHelper = createColumnHelper() + +export const useRegionTableColumns = () => { + return useMemo( + () => [ + columnHelper.accessor("name", { + header: () => , + cell: ({ getValue }) => , + }), + columnHelper.accessor("countries", { + header: () => , + cell: ({ getValue }) => , + }), + columnHelper.accessor("payment_providers", { + header: () => , + cell: ({ getValue }) => ( + + ), + }), + columnHelper.accessor("fulfillment_providers", { + header: () => , + cell: ({ getValue }) => ( + + ), + }), + ], + [] + ) +} diff --git a/packages/admin-next/dashboard/src/hooks/table/filters/use-region-table-filters.tsx b/packages/admin-next/dashboard/src/hooks/table/filters/use-region-table-filters.tsx new file mode 100644 index 0000000000..ac9eb314ac --- /dev/null +++ b/packages/admin-next/dashboard/src/hooks/table/filters/use-region-table-filters.tsx @@ -0,0 +1,19 @@ +import { useTranslation } from "react-i18next" +import { Filter } from "../../../components/table/data-table" + +export const useRegionTableFilters = () => { + const { t } = useTranslation() + + 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", + })) + + const filters = [...dateFilters] + + return filters +} diff --git a/packages/admin-next/dashboard/src/hooks/table/query/use-region-table-query.tsx b/packages/admin-next/dashboard/src/hooks/table/query/use-region-table-query.tsx new file mode 100644 index 0000000000..972f63960d --- /dev/null +++ b/packages/admin-next/dashboard/src/hooks/table/query/use-region-table-query.tsx @@ -0,0 +1,33 @@ +import { AdminGetRegionsParams } from "@medusajs/medusa" +import { useQueryParams } from "../../use-query-params" + +type UseRegionTableQueryProps = { + prefix?: string + pageSize?: number +} + +export const useRegionTableQuery = ({ + prefix, + pageSize = 20, +}: UseRegionTableQueryProps) => { + const queryObject = useQueryParams( + ["offset", "q", "order", "created_at", "updated_at"], + prefix + ) + + const { offset, q, order, created_at, updated_at } = queryObject + + const searchParams: AdminGetRegionsParams = { + limit: pageSize, + offset: offset ? Number(offset) : 0, + order, + created_at: created_at ? JSON.parse(created_at) : undefined, + updated_at: updated_at ? JSON.parse(updated_at) : undefined, + q, + } + + return { + searchParams, + raw: queryObject, + } +} diff --git a/packages/admin-next/dashboard/src/hooks/use-route-modal-state.tsx b/packages/admin-next/dashboard/src/hooks/use-route-modal-state.tsx deleted file mode 100644 index 4348428819..0000000000 --- a/packages/admin-next/dashboard/src/hooks/use-route-modal-state.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { usePrompt } from "@medusajs/ui" -import { useEffect, useState } from "react" -import { useTranslation } from "react-i18next" -import { useNavigate } from "react-router-dom" - -/** - * Hook for managing the state of route modals. - */ -export const useRouteModalState = (): [ - open: boolean, - onOpenChange: (open: boolean, ignore?: boolean) => void, - /** - * Subscribe to the dirty state of the form. - * If the form is dirty, the modal will prompt - * the user before closing. - */ - subscribe: (value: boolean) => void, -] => { - const [open, setOpen] = useState(false) - const [shouldPrompt, subscribe] = useState(false) - - const navigate = useNavigate() - const prompt = usePrompt() - const { t } = useTranslation() - - const promptValues = { - title: t("general.unsavedChangesTitle"), - description: t("general.unsavedChangesDescription"), - cancelText: t("actions.cancel"), - confirmText: t("actions.continue"), - variant: "confirmation" as const, - } - - useEffect(() => { - setOpen(true) - }, []) - - const onOpenChange = async (open: boolean, ignore = false) => { - if (!open) { - if (shouldPrompt && !ignore) { - const confirmed = await prompt(promptValues) - - if (!confirmed) { - return - } - } - - setTimeout(() => { - navigate("..", { replace: true }) - }, 200) - } - - setOpen(open) - } - - return [open, onOpenChange, subscribe] -} diff --git a/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-add-sales-channels/api-key-management-add-sales-channels.tsx b/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-add-sales-channels/api-key-management-add-sales-channels.tsx index 9e8a62caf7..8c1e34155a 100644 --- a/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-add-sales-channels/api-key-management-add-sales-channels.tsx +++ b/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-add-sales-channels/api-key-management-add-sales-channels.tsx @@ -1,36 +1,26 @@ -import { FocusModal } from "@medusajs/ui" import { useAdminPublishableApiKeySalesChannels } from "medusa-react" import { useParams } from "react-router-dom" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteFocusModal } from "../../../components/route-modal" import { AddSalesChannelsToApiKeyForm } from "./components" export const ApiKeyManagementAddSalesChannels = () => { const { id } = useParams() - const [open, onOpenChange, subscribe] = useRouteModalState() const { sales_channels, isLoading, isError, error } = useAdminPublishableApiKeySalesChannels(id!) - const handleSuccessfulSubmit = () => { - onOpenChange(false, true) - } - if (isError) { throw error } return ( - - - {!isLoading && sales_channels && ( - sc.id)} - onSuccessfulSubmit={handleSuccessfulSubmit} - subscribe={subscribe} - /> - )} - - + + {!isLoading && sales_channels && ( + sc.id)} + /> + )} + ) } diff --git a/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-add-sales-channels/components/add-sales-channels-to-api-key-form.tsx b/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-add-sales-channels/components/add-sales-channels-to-api-key-form.tsx index b20a33eb06..d81c3faca1 100644 --- a/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-add-sales-channels/components/add-sales-channels-to-api-key-form.tsx +++ b/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-add-sales-channels/components/add-sales-channels-to-api-key-form.tsx @@ -3,7 +3,6 @@ import { SalesChannel } from "@medusajs/medusa" import { Button, Checkbox, - FocusModal, Hint, StatusBadge, Table, @@ -26,17 +25,18 @@ import { useEffect, useMemo, useState } from "react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import * as zod from "zod" -import { Form } from "../../../../components/common/form" import { OrderBy } from "../../../../components/filtering/order-by" import { Query } from "../../../../components/filtering/query" import { LocalizedTablePagination } from "../../../../components/localization/localized-table-pagination" +import { + RouteFocusModal, + useRouteModal, +} from "../../../../components/route-modal" import { useQueryParams } from "../../../../hooks/use-query-params" type AddSalesChannelsToApiKeyFormProps = { apiKey: string preSelected: string[] - subscribe: (state: boolean) => void - onSuccessfulSubmit: () => void } const AddSalesChannelsToApiKeySchema = zod.object({ @@ -48,10 +48,9 @@ const PAGE_SIZE = 50 export const AddSalesChannelsToApiKeyForm = ({ apiKey, preSelected, - subscribe, - onSuccessfulSubmit, }: AddSalesChannelsToApiKeyFormProps) => { const { t } = useTranslation() + const { handleSuccess } = useRouteModal() const form = useForm>({ defaultValues: { @@ -60,13 +59,7 @@ export const AddSalesChannelsToApiKeyForm = ({ resolver: zodResolver(AddSalesChannelsToApiKeySchema), }) - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty]) + const { setValue } = form const { mutateAsync, isLoading: isMutating } = useAdminAddPublishableKeySalesChannelsBatch(apiKey) @@ -87,11 +80,15 @@ export const AddSalesChannelsToApiKeyForm = ({ const [rowSelection, setRowSelection] = useState({}) useEffect(() => { - form.setValue( + setValue( "sales_channel_ids", - Object.keys(rowSelection).filter((k) => rowSelection[k]) + Object.keys(rowSelection).filter((k) => rowSelection[k]), + { + shouldDirty: true, + shouldTouch: true, + } ) - }, [rowSelection]) + }, [rowSelection, setValue]) const params = useQueryParams(["q", "order"]) const { sales_channels, count } = useAdminSalesChannels( @@ -135,36 +132,36 @@ export const AddSalesChannelsToApiKeyForm = ({ }, { onSuccess: () => { - onSuccessfulSubmit() + handleSuccess() }, } ) }) return ( -
    + - +
    {form.formState.errors.sales_channel_ids && ( {form.formState.errors.sales_channel_ids.message} )} - + - +
    -
    - + +
    @@ -236,9 +233,9 @@ export const AddSalesChannelsToApiKeyForm = ({ pageSize={PAGE_SIZE} />
    - + - + ) } diff --git a/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-create/api-key-management-create.tsx b/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-create/api-key-management-create.tsx index cfc8522b0c..e354f1834a 100644 --- a/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-create/api-key-management-create.tsx +++ b/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-create/api-key-management-create.tsx @@ -1,15 +1,10 @@ -import { FocusModal } from "@medusajs/ui" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteFocusModal } from "../../../components/route-modal" import { CreatePublishableApiKeyForm } from "./components/create-publishable-api-key-form" export const ApiKeyManagementCreate = () => { - const [open, onOpenChange, subscribe] = useRouteModalState() - return ( - - - - - + + + ) } diff --git a/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-create/components/create-publishable-api-key-form/create-publishable-api-key-form.tsx b/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-create/components/create-publishable-api-key-form/create-publishable-api-key-form.tsx index 7676ee4f0b..10300524cc 100644 --- a/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-create/components/create-publishable-api-key-form/create-publishable-api-key-form.tsx +++ b/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-create/components/create-publishable-api-key-form/create-publishable-api-key-form.tsx @@ -1,26 +1,23 @@ import { zodResolver } from "@hookform/resolvers/zod" -import { Button, FocusModal, Heading, Input, Text } from "@medusajs/ui" +import { Button, Heading, Input, Text } from "@medusajs/ui" import { useAdminCreatePublishableApiKey } from "medusa-react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import * as zod from "zod" -import { useEffect } from "react" -import { useNavigate } from "react-router-dom" import { Form } from "../../../../../components/common/form" - -type CreatePublishableApiKeyFormProps = { - subscribe: (state: boolean) => void -} +import { + RouteFocusModal, + useRouteModal, +} from "../../../../../components/route-modal" const CreatePublishableApiKeySchema = zod.object({ title: zod.string().min(1), }) -export const CreatePublishableApiKeyForm = ({ - subscribe, -}: CreatePublishableApiKeyFormProps) => { - const { mutateAsync, isLoading } = useAdminCreatePublishableApiKey() +export const CreatePublishableApiKeyForm = () => { + const { t } = useTranslation() + const { handleSuccess } = useRouteModal() const form = useForm>({ defaultValues: { @@ -29,46 +26,35 @@ export const CreatePublishableApiKeyForm = ({ resolver: zodResolver(CreatePublishableApiKeySchema), }) - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty]) - - const { t } = useTranslation() - const navigate = useNavigate() + const { mutateAsync, isLoading } = useAdminCreatePublishableApiKey() const handleSubmit = form.handleSubmit(async (values) => { await mutateAsync(values, { onSuccess: ({ publishable_api_key }) => { - navigate(`/settings/api-key-management/${publishable_api_key.id}`, { - replace: true, - }) + handleSuccess(`/settings/api-key-management/${publishable_api_key.id}`) }, }) }) return ( -
    + - +
    - + - +
    -
    - + +
    @@ -88,7 +74,7 @@ export const CreatePublishableApiKeyForm = ({ {t("fields.title")} - + @@ -98,8 +84,8 @@ export const CreatePublishableApiKeyForm = ({
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-edit/api-key-management-edit.tsx b/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-edit/api-key-management-edit.tsx index 61c1fcaeb5..a8f9c27997 100644 --- a/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-edit/api-key-management-edit.tsx +++ b/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-edit/api-key-management-edit.tsx @@ -1,40 +1,29 @@ -import { Drawer, Heading } from "@medusajs/ui" +import { Heading } from "@medusajs/ui" import { useAdminPublishableApiKey } from "medusa-react" import { useTranslation } from "react-i18next" import { useParams } from "react-router-dom" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteDrawer } from "../../../components/route-modal" import { EditApiKeyForm } from "./components/edit-api-key-form" export const ApiKeyManagementEdit = () => { - const [open, onOpenChange, subscribe] = useRouteModalState() const { id } = useParams() const { t } = useTranslation() const { publishable_api_key, isLoading, isError, error } = useAdminPublishableApiKey(id!) - const handleSuccessfulSubmit = () => { - onOpenChange(false, true) - } - if (isError) { throw error } return ( - - - - {t("apiKeyManagement.editKey")} - - {!isLoading && publishable_api_key && ( - - )} - - + + + {t("apiKeyManagement.editKey")} + + {!isLoading && publishable_api_key && ( + + )} + ) } diff --git a/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-edit/components/edit-api-key-form/edit-api-key-form.tsx b/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-edit/components/edit-api-key-form/edit-api-key-form.tsx index 240c79cf63..87798aaff5 100644 --- a/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-edit/components/edit-api-key-form/edit-api-key-form.tsx +++ b/packages/admin-next/dashboard/src/routes/api-key-management/api-key-management-edit/components/edit-api-key-form/edit-api-key-form.tsx @@ -1,29 +1,28 @@ import { zodResolver } from "@hookform/resolvers/zod" import type { PublishableApiKey } from "@medusajs/medusa" -import { Button, Drawer, Input } from "@medusajs/ui" +import { Button, Input } from "@medusajs/ui" import { useAdminUpdatePublishableApiKey } from "medusa-react" -import { useEffect } from "react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import * as zod from "zod" + import { Form } from "../../../../../components/common/form" +import { + RouteDrawer, + useRouteModal, +} from "../../../../../components/route-modal" type EditApiKeyFormProps = { apiKey: PublishableApiKey - onSuccessfulSubmit: () => void - subscribe: (state: boolean) => void } const EditApiKeySchema = zod.object({ title: zod.string().min(1), }) -export const EditApiKeyForm = ({ - apiKey, - onSuccessfulSubmit, - subscribe, -}: EditApiKeyFormProps) => { +export const EditApiKeyForm = ({ apiKey }: EditApiKeyFormProps) => { const { t } = useTranslation() + const { handleSuccess } = useRouteModal() const form = useForm>({ defaultValues: { @@ -32,28 +31,23 @@ export const EditApiKeyForm = ({ resolver: zodResolver(EditApiKeySchema), }) - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty]) - const { mutateAsync, isLoading } = useAdminUpdatePublishableApiKey(apiKey.id) const handleSubmit = form.handleSubmit(async (data) => { await mutateAsync(data, { onSuccess: () => { - onSuccessfulSubmit() + handleSuccess() + }, + onError: (error) => { + console.log(error) }, }) }) return ( -
    + - +
    -
    - + +
    - + - +
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/collections/collection-add-products/collection-add-products.tsx b/packages/admin-next/dashboard/src/routes/collections/collection-add-products/collection-add-products.tsx index 9832460d6b..7daea150a5 100644 --- a/packages/admin-next/dashboard/src/routes/collections/collection-add-products/collection-add-products.tsx +++ b/packages/admin-next/dashboard/src/routes/collections/collection-add-products/collection-add-products.tsx @@ -1,34 +1,22 @@ -import { FocusModal } from "@medusajs/ui" import { useAdminCollection } from "medusa-react" import { useParams } from "react-router-dom" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" + +import { RouteFocusModal } from "../../../components/route-modal" import { AddProductsToCollectionForm } from "./components/add-products-to-collection-form" export const CollectionAddProducts = () => { const { id } = useParams() const { collection, isLoading, isError, error } = useAdminCollection(id!) - const [open, onOpenChange, subscribe] = useRouteModalState() - - const handleSuccessfulSubmit = () => { - onOpenChange(false, true) - } - if (isError) { throw error } return ( - - - {!isLoading && collection && ( - - )} - - + + {!isLoading && collection && ( + + )} + ) } diff --git a/packages/admin-next/dashboard/src/routes/collections/collection-add-products/components/add-products-to-collection-form/add-products-to-collection-form.tsx b/packages/admin-next/dashboard/src/routes/collections/collection-add-products/components/add-products-to-collection-form/add-products-to-collection-form.tsx index 716bd85d8c..18843f33c6 100644 --- a/packages/admin-next/dashboard/src/routes/collections/collection-add-products/components/add-products-to-collection-form/add-products-to-collection-form.tsx +++ b/packages/admin-next/dashboard/src/routes/collections/collection-add-products/components/add-products-to-collection-form/add-products-to-collection-form.tsx @@ -1,14 +1,6 @@ import { zodResolver } from "@hookform/resolvers/zod" import type { Product, ProductCollection } from "@medusajs/medusa" -import { - Button, - Checkbox, - FocusModal, - Hint, - Table, - Tooltip, - clx, -} from "@medusajs/ui" +import { Button, Checkbox, Hint, Table, Tooltip, clx } from "@medusajs/ui" import { PaginationState, RowSelectionState, @@ -30,7 +22,6 @@ import { NoRecords, NoResults, } from "../../../../../components/common/empty-table-content" -import { Form } from "../../../../../components/common/form" import { ProductAvailabilityCell, ProductCollectionCell, @@ -41,14 +32,16 @@ import { import { OrderBy } from "../../../../../components/filtering/order-by" import { Query } from "../../../../../components/filtering/query" import { LocalizedTablePagination } from "../../../../../components/localization/localized-table-pagination" +import { + RouteFocusModal, + useRouteModal, +} from "../../../../../components/route-modal" import { useHandleTableScroll } from "../../../../../hooks/use-handle-table-scroll" import { useQueryParams } from "../../../../../hooks/use-query-params" import { queryClient } from "../../../../../lib/medusa" type AddProductsToCollectionFormProps = { collection: ProductCollection - subscribe: (state: boolean) => void - onSuccessfulSubmit: () => void } const AddProductsToSalesChannelSchema = zod.object({ @@ -59,10 +52,9 @@ const PAGE_SIZE = 50 export const AddProductsToCollectionForm = ({ collection, - subscribe, - onSuccessfulSubmit, }: AddProductsToCollectionFormProps) => { const { t } = useTranslation() + const { handleSuccess } = useRouteModal() const form = useForm>({ defaultValues: { @@ -71,13 +63,7 @@ export const AddProductsToCollectionForm = ({ resolver: zodResolver(AddProductsToSalesChannelSchema), }) - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty]) + const { setValue } = form const { mutateAsync, isLoading: isMutating } = useAdminAddProductsToCollection(collection.id) @@ -98,11 +84,15 @@ export const AddProductsToCollectionForm = ({ const [rowSelection, setRowSelection] = useState({}) useEffect(() => { - form.setValue( + setValue( "product_ids", - Object.keys(rowSelection).filter((k) => rowSelection[k]) + Object.keys(rowSelection).filter((k) => rowSelection[k]), + { + shouldDirty: true, + shouldTouch: true, + } ) - }, [rowSelection]) + }, [rowSelection, setValue]) const params = useQueryParams(["q", "order"]) @@ -151,7 +141,7 @@ export const AddProductsToCollectionForm = ({ * determine if they are added to the collection or not. */ queryClient.invalidateQueries(adminProductKeys.lists()) - onSuccessfulSubmit() + handleSuccess() }, } ) @@ -169,29 +159,29 @@ export const AddProductsToCollectionForm = ({ } return ( -
    + - +
    {form.formState.errors.product_ids && ( {form.formState.errors.product_ids.message} )} - + - +
    -
    - + + {!noRecords && (
    @@ -291,9 +281,9 @@ export const AddProductsToCollectionForm = ({ {/* TODO: fix this, and add NoRecords as well */}
    )} -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/collections/collection-create/collection-create.tsx b/packages/admin-next/dashboard/src/routes/collections/collection-create/collection-create.tsx index 2a43c7eb9b..e5f50dd664 100644 --- a/packages/admin-next/dashboard/src/routes/collections/collection-create/collection-create.tsx +++ b/packages/admin-next/dashboard/src/routes/collections/collection-create/collection-create.tsx @@ -1,15 +1,10 @@ -import { FocusModal } from "@medusajs/ui" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteFocusModal } from "../../../components/route-modal" import { CreateCollectionForm } from "./components/create-collection-form" export const CollectionCreate = () => { - const [open, onOpenChange, subscribe] = useRouteModalState() - return ( - - - - - + + + ) } diff --git a/packages/admin-next/dashboard/src/routes/collections/collection-create/components/create-collection-form/create-collection-form.tsx b/packages/admin-next/dashboard/src/routes/collections/collection-create/components/create-collection-form/create-collection-form.tsx index 2b4146f297..2875402cde 100644 --- a/packages/admin-next/dashboard/src/routes/collections/collection-create/components/create-collection-form/create-collection-form.tsx +++ b/packages/admin-next/dashboard/src/routes/collections/collection-create/components/create-collection-form/create-collection-form.tsx @@ -1,27 +1,24 @@ import { zodResolver } from "@hookform/resolvers/zod" -import { Button, FocusModal, Heading, Input, Text } from "@medusajs/ui" +import { Button, Heading, Input, Text } from "@medusajs/ui" import { useAdminCreateCollection } from "medusa-react" -import { useEffect } from "react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" -import { useNavigate } from "react-router-dom" import * as zod from "zod" -import { Form } from "../../../../../components/common/form" -type CreateCollectionFormProps = { - subscribe: (state: boolean) => void -} +import { Form } from "../../../../../components/common/form" +import { + RouteFocusModal, + useRouteModal, +} from "../../../../../components/route-modal" const CreateCollectionSchema = zod.object({ title: zod.string().min(1), handle: zod.string().optional(), }) -export const CreateCollectionForm = ({ - subscribe, -}: CreateCollectionFormProps) => { +export const CreateCollectionForm = () => { const { t } = useTranslation() - const navigate = useNavigate() + const { handleSuccess } = useRouteModal() const form = useForm>({ defaultValues: { @@ -31,34 +28,26 @@ export const CreateCollectionForm = ({ resolver: zodResolver(CreateCollectionSchema), }) - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty]) - const { mutateAsync, isLoading } = useAdminCreateCollection() const handleSubmit = form.handleSubmit(async (data) => { await mutateAsync(data, { onSuccess: ({ collection }) => { - navigate(`/collections/${collection.id}`) + handleSuccess(`/collections/${collection.id}`) }, }) }) return ( -
    + - +
    - + - +
    -
    - + +
    {t("collections.createCollection")} @@ -131,8 +120,8 @@ export const CreateCollectionForm = ({ />
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/collections/collection-edit/collection-add-edit.tsx b/packages/admin-next/dashboard/src/routes/collections/collection-edit/collection-add-edit.tsx index 0496ec12c3..6d146da32b 100644 --- a/packages/admin-next/dashboard/src/routes/collections/collection-edit/collection-add-edit.tsx +++ b/packages/admin-next/dashboard/src/routes/collections/collection-edit/collection-add-edit.tsx @@ -1,8 +1,8 @@ -import { Drawer, Heading } from "@medusajs/ui" +import { Heading } from "@medusajs/ui" import { useAdminCollection } from "medusa-react" import { useTranslation } from "react-i18next" import { useParams } from "react-router-dom" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteDrawer } from "../../../components/route-modal" import { EditCollectionForm } from "./components/edit-collection-form" export const CollectionEdit = () => { @@ -10,30 +10,18 @@ export const CollectionEdit = () => { const { t } = useTranslation() const { collection, isLoading, isError, error } = useAdminCollection(id!) - const [open, onOpenChange, subscribe] = useRouteModalState() - - const handleSuccessfulSubmit = () => { - onOpenChange(false, true) - } - if (isError) { throw error } return ( - - - - {t("collections.editCollection")} - - {!isLoading && collection && ( - - )} - - + + + {t("collections.editCollection")} + + {!isLoading && collection && ( + + )} + ) } diff --git a/packages/admin-next/dashboard/src/routes/collections/collection-edit/components/edit-collection-form/edit-collection-form.tsx b/packages/admin-next/dashboard/src/routes/collections/collection-edit/components/edit-collection-form/edit-collection-form.tsx index 44a56c986f..c4a2af64a0 100644 --- a/packages/admin-next/dashboard/src/routes/collections/collection-edit/components/edit-collection-form/edit-collection-form.tsx +++ b/packages/admin-next/dashboard/src/routes/collections/collection-edit/components/edit-collection-form/edit-collection-form.tsx @@ -1,17 +1,19 @@ import { zodResolver } from "@hookform/resolvers/zod" import type { ProductCollection } from "@medusajs/medusa" -import { Button, Drawer, Input, Text } from "@medusajs/ui" +import { Button, Input, Text } from "@medusajs/ui" import { useAdminUpdateCollection } from "medusa-react" -import { useEffect } from "react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import * as zod from "zod" + import { Form } from "../../../../../components/common/form" +import { + RouteDrawer, + useRouteModal, +} from "../../../../../components/route-modal" type EditCollectionFormProps = { collection: ProductCollection - subscribe: (state: boolean) => void - onSuccessfulSubmit: () => void } const EditCollectionSchema = zod.object({ @@ -19,12 +21,9 @@ const EditCollectionSchema = zod.object({ handle: zod.string().min(1), }) -export const EditCollectionForm = ({ - collection, - onSuccessfulSubmit, - subscribe, -}: EditCollectionFormProps) => { +export const EditCollectionForm = ({ collection }: EditCollectionFormProps) => { const { t } = useTranslation() + const { handleSuccess } = useRouteModal() const form = useForm>({ defaultValues: { @@ -34,28 +33,20 @@ export const EditCollectionForm = ({ resolver: zodResolver(EditCollectionSchema), }) - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty]) - const { mutateAsync, isLoading } = useAdminUpdateCollection(collection.id) const handleSubmit = form.handleSubmit(async (data) => { await mutateAsync(data, { onSuccess: () => { - onSuccessfulSubmit() + handleSuccess() }, }) }) return ( -
    + - +
    -
    - + +
    - + - +
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-add-customers/components/add-customers-form/add-customers-form.tsx b/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-add-customers/components/add-customers-form/add-customers-form.tsx index 22e377f080..8c85f787e2 100644 --- a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-add-customers/components/add-customers-form/add-customers-form.tsx +++ b/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-add-customers/components/add-customers-form/add-customers-form.tsx @@ -1,14 +1,6 @@ import { zodResolver } from "@hookform/resolvers/zod" import { Customer } from "@medusajs/medusa" -import { - Button, - Checkbox, - FocusModal, - Hint, - Table, - Tooltip, - clx, -} from "@medusajs/ui" +import { Button, Checkbox, Hint, Table, Tooltip, clx } from "@medusajs/ui" import { PaginationState, RowSelectionState, @@ -25,21 +17,23 @@ import { import { useEffect, useMemo, useState } from "react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" -import { useNavigate } from "react-router-dom" import * as zod from "zod" + import { NoRecords, NoResults, } from "../../../../../components/common/empty-table-content" -import { Form } from "../../../../../components/common/form" import { Query } from "../../../../../components/filtering/query" import { LocalizedTablePagination } from "../../../../../components/localization/localized-table-pagination" +import { + RouteFocusModal, + useRouteModal, +} from "../../../../../components/route-modal" import { useQueryParams } from "../../../../../hooks/use-query-params" import { queryClient } from "../../../../../lib/medusa" type AddCustomersFormProps = { customerGroupId: string - subscribe: (state: boolean) => void } const AddCustomersSchema = zod.object({ @@ -50,10 +44,9 @@ const PAGE_SIZE = 10 export const AddCustomersForm = ({ customerGroupId, - subscribe, }: AddCustomersFormProps) => { - const navigate = useNavigate() const { t } = useTranslation() + const { handleSuccess } = useRouteModal() const form = useForm>({ defaultValues: { @@ -62,13 +55,7 @@ export const AddCustomersForm = ({ resolver: zodResolver(AddCustomersSchema), }) - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty]) + const { setValue } = form const [{ pageIndex, pageSize }, setPagination] = useState({ pageIndex: 0, @@ -86,11 +73,15 @@ export const AddCustomersForm = ({ const [rowSelection, setRowSelection] = useState({}) useEffect(() => { - form.setValue( + setValue( "customer_ids", - Object.keys(rowSelection).filter((k) => rowSelection[k]) + Object.keys(rowSelection).filter((k) => rowSelection[k]), + { + shouldDirty: true, + shouldTouch: true, + } ) - }, [rowSelection]) + }, [rowSelection, setValue]) const params = useQueryParams(["q"]) const { customers, count, isLoading, isError, error } = useAdminCustomers({ @@ -131,7 +122,7 @@ export const AddCustomersForm = ({ { onSuccess: () => { queryClient.invalidateQueries(adminCustomerKeys.lists()) - navigate(`/customer-groups/${customerGroupId}`) + handleSuccess(`/customer-groups/${customerGroupId}`) }, } ) @@ -147,23 +138,23 @@ export const AddCustomersForm = ({ } return ( -
    + - +
    {form.formState.errors.customer_ids && ( {form.formState.errors.customer_ids.message} )} - + - +
    -
    - + + {noRecords ? (
    @@ -259,9 +250,9 @@ export const AddCustomersForm = ({ />
    )} -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-add-customers/customer-group-add-customers.tsx b/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-add-customers/customer-group-add-customers.tsx index 874d277800..aa85a03663 100644 --- a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-add-customers/customer-group-add-customers.tsx +++ b/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-add-customers/customer-group-add-customers.tsx @@ -1,18 +1,14 @@ -import { FocusModal } from "@medusajs/ui" import { useParams } from "react-router-dom" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" + +import { RouteFocusModal } from "../../../components/route-modal" import { AddCustomersForm } from "./components/add-customers-form" export const CustomerGroupAddCustomers = () => { - const [open, onOpenChange, subscribe] = useRouteModalState() - const { id } = useParams() return ( - - - - - + + + ) } diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-create/components/create-customer-group-form/create-customer-group-form.tsx b/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-create/components/create-customer-group-form/create-customer-group-form.tsx index f350be2964..cbb2dbe75d 100644 --- a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-create/components/create-customer-group-form/create-customer-group-form.tsx +++ b/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-create/components/create-customer-group-form/create-customer-group-form.tsx @@ -1,26 +1,23 @@ import { zodResolver } from "@hookform/resolvers/zod" -import { Button, FocusModal, Heading, Input, Text } from "@medusajs/ui" +import { Button, Heading, Input, Text } from "@medusajs/ui" import { useAdminCreateCustomerGroup } from "medusa-react" -import { useEffect } from "react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" -import { useNavigate } from "react-router-dom" import * as zod from "zod" -import { Form } from "../../../../../components/common/form" -type CreateCustomerGroupFormProps = { - subscribe: (state: boolean) => void -} +import { Form } from "../../../../../components/common/form" +import { + RouteFocusModal, + useRouteModal, +} from "../../../../../components/route-modal" const CreateCustomerGroupSchema = zod.object({ name: zod.string().min(1), }) -export const CreateCustomerGroupForm = ({ - subscribe, -}: CreateCustomerGroupFormProps) => { +export const CreateCustomerGroupForm = () => { const { t } = useTranslation() - const navigate = useNavigate() + const { handleSuccess } = useRouteModal() const form = useForm>({ defaultValues: { @@ -29,14 +26,6 @@ export const CreateCustomerGroupForm = ({ resolver: zodResolver(CreateCustomerGroupSchema), }) - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty]) - const { mutateAsync, isLoading } = useAdminCreateCustomerGroup() const handleSubmit = form.handleSubmit(async (data) => { @@ -46,22 +35,22 @@ export const CreateCustomerGroupForm = ({ }, { onSuccess: ({ customer_group }) => { - navigate(`/customer-groups/${customer_group.id}`) + handleSuccess(`/customer-groups/${customer_group.id}`) }, } ) }) return ( -
    + - +
    - + - +
    -
    - + +
    {t("customerGroups.createCustomerGroup")} @@ -98,8 +87,8 @@ export const CreateCustomerGroupForm = ({ />
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-create/customer-group-create.tsx b/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-create/customer-group-create.tsx index 6fc39b5067..50d763a27f 100644 --- a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-create/customer-group-create.tsx +++ b/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-create/customer-group-create.tsx @@ -1,15 +1,10 @@ -import { FocusModal } from "@medusajs/ui" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteFocusModal } from "../../../components/route-modal" import { CreateCustomerGroupForm } from "./components/create-customer-group-form" export const CustomerGroupCreate = () => { - const [open, onOpenChange, subscribe] = useRouteModalState() - return ( - - - - - + + + ) } diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-edit/components/edit-customer-group-form/edit-customer-group-form.tsx b/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-edit/components/edit-customer-group-form/edit-customer-group-form.tsx index 0bcc1c4bcf..b1f2bb2a2e 100644 --- a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-edit/components/edit-customer-group-form/edit-customer-group-form.tsx +++ b/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-edit/components/edit-customer-group-form/edit-customer-group-form.tsx @@ -1,17 +1,18 @@ import { zodResolver } from "@hookform/resolvers/zod" import { CustomerGroup } from "@medusajs/medusa" -import { Button, Drawer, Input } from "@medusajs/ui" +import { Button, Input } from "@medusajs/ui" import { useAdminUpdateCustomerGroup } from "medusa-react" -import { useEffect } from "react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import * as z from "zod" import { Form } from "../../../../../components/common/form" +import { + RouteDrawer, + useRouteModal, +} from "../../../../../components/route-modal" type EditCustomerGroupFormProps = { group: CustomerGroup - onSuccessfulSubmit: () => void - subscribe: (state: boolean) => void } const EditCustomerGroupSchema = z.object({ @@ -20,10 +21,9 @@ const EditCustomerGroupSchema = z.object({ export const EditCustomerGroupForm = ({ group, - onSuccessfulSubmit, - subscribe, }: EditCustomerGroupFormProps) => { const { t } = useTranslation() + const { handleSuccess } = useRouteModal() const form = useForm>({ defaultValues: { @@ -32,31 +32,23 @@ export const EditCustomerGroupForm = ({ resolver: zodResolver(EditCustomerGroupSchema), }) - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty]) - const { mutateAsync, isLoading } = useAdminUpdateCustomerGroup(group.id) const handleSubmit = form.handleSubmit(async (data) => { await mutateAsync(data, { onSuccess: () => { - onSuccessfulSubmit() + handleSuccess() }, }) }) return ( -
    + - + - - + +
    - + - +
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-edit/customer-group-edit.tsx b/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-edit/customer-group-edit.tsx index 0e43bdd314..e07055a9b0 100644 --- a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-edit/customer-group-edit.tsx +++ b/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-edit/customer-group-edit.tsx @@ -1,13 +1,11 @@ -import { Drawer, Heading } from "@medusajs/ui" +import { Heading } from "@medusajs/ui" import { useAdminCustomerGroup } from "medusa-react" import { useTranslation } from "react-i18next" import { useParams } from "react-router-dom" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteDrawer } from "../../../components/route-modal" import { EditCustomerGroupForm } from "./components/edit-customer-group-form" export const CustomerGroupEdit = () => { - const [open, onOpenChange, subscribe] = useRouteModalState() - const { id } = useParams() const { customer_group, isLoading, isError, error } = useAdminCustomerGroup( id! @@ -15,28 +13,18 @@ export const CustomerGroupEdit = () => { const { t } = useTranslation() - const handleSuccessfulSubmit = () => { - onOpenChange(false, true) - } - if (isError) { throw error } return ( - - - - {t("customerGroups.editCustomerGroup")} - - {!isLoading && customer_group && ( - - )} - - + + + {t("customerGroups.editCustomerGroup")} + + {!isLoading && customer_group && ( + + )} + ) } diff --git a/packages/admin-next/dashboard/src/routes/customers/customer-create/components/create-customer-form/create-customer-form.tsx b/packages/admin-next/dashboard/src/routes/customers/customer-create/components/create-customer-form/create-customer-form.tsx index f0d7669d84..d20f054a6d 100644 --- a/packages/admin-next/dashboard/src/routes/customers/customer-create/components/create-customer-form/create-customer-form.tsx +++ b/packages/admin-next/dashboard/src/routes/customers/customer-create/components/create-customer-form/create-customer-form.tsx @@ -1,16 +1,15 @@ import { zodResolver } from "@hookform/resolvers/zod" -import { Button, FocusModal, Heading, Input, Text } from "@medusajs/ui" +import { Button, Heading, Input, Text } from "@medusajs/ui" import { useAdminCreateCustomer } from "medusa-react" -import { useEffect } from "react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" -import { useNavigate } from "react-router-dom" import * as zod from "zod" -import { Form } from "../../../../../components/common/form" -type CreateCustomerFormProps = { - subscribe: (state: boolean) => void -} +import { Form } from "../../../../../components/common/form" +import { + RouteFocusModal, + useRouteModal, +} from "../../../../../components/route-modal" const CreateCustomerSchema = zod .object({ @@ -31,9 +30,9 @@ const CreateCustomerSchema = zod } }) -export const CreateCustomerForm = ({ subscribe }: CreateCustomerFormProps) => { +export const CreateCustomerForm = () => { const { t } = useTranslation() - const navigate = useNavigate() + const { handleSuccess } = useRouteModal() const form = useForm>({ defaultValues: { @@ -46,13 +45,6 @@ export const CreateCustomerForm = ({ subscribe }: CreateCustomerFormProps) => { }, resolver: zodResolver(CreateCustomerSchema), }) - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty]) const { mutateAsync, isLoading } = useAdminCreateCustomer() @@ -67,22 +59,22 @@ export const CreateCustomerForm = ({ subscribe }: CreateCustomerFormProps) => { }, { onSuccess: ({ customer }) => { - navigate(`/customers/${customer.id}`, { replace: true }) + handleSuccess(`/customers/${customer.id}`) }, } ) }) return ( -
    + - +
    - + - +
    -
    - + +
    {t("customers.createCustomer")} @@ -214,8 +206,8 @@ export const CreateCustomerForm = ({ subscribe }: CreateCustomerFormProps) => {
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/customers/customer-create/customer-create.tsx b/packages/admin-next/dashboard/src/routes/customers/customer-create/customer-create.tsx index 9d28afb2b2..61b826834d 100644 --- a/packages/admin-next/dashboard/src/routes/customers/customer-create/customer-create.tsx +++ b/packages/admin-next/dashboard/src/routes/customers/customer-create/customer-create.tsx @@ -1,15 +1,10 @@ -import { FocusModal } from "@medusajs/ui" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteFocusModal } from "../../../components/route-modal" import { CreateCustomerForm } from "./components/create-customer-form" export const CustomerCreate = () => { - const [open, onOpenChange, subscribe] = useRouteModalState() - return ( - - - - - + + + ) } diff --git a/packages/admin-next/dashboard/src/routes/customers/customer-edit/components/edit-customer-form/edit-customer-form.tsx b/packages/admin-next/dashboard/src/routes/customers/customer-edit/components/edit-customer-form/edit-customer-form.tsx index bf5e0baead..690644fd18 100644 --- a/packages/admin-next/dashboard/src/routes/customers/customer-edit/components/edit-customer-form/edit-customer-form.tsx +++ b/packages/admin-next/dashboard/src/routes/customers/customer-edit/components/edit-customer-form/edit-customer-form.tsx @@ -1,17 +1,19 @@ import { zodResolver } from "@hookform/resolvers/zod" import { Customer } from "@medusajs/medusa" -import { Button, Drawer, Input } from "@medusajs/ui" +import { Button, Input } from "@medusajs/ui" import { useAdminUpdateCustomer } from "medusa-react" -import { useEffect } from "react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import * as zod from "zod" + import { Form } from "../../../../../components/common/form" +import { + RouteDrawer, + useRouteModal, +} from "../../../../../components/route-modal" type EditCustomerFormProps = { customer: Customer - subscribe: (state: boolean) => void - onSuccessfulSubmit: () => void } const EditCustomerSchema = zod.object({ @@ -21,12 +23,9 @@ const EditCustomerSchema = zod.object({ phone: zod.string().optional(), }) -export const EditCustomerForm = ({ - customer, - subscribe, - onSuccessfulSubmit, -}: EditCustomerFormProps) => { +export const EditCustomerForm = ({ customer }: EditCustomerFormProps) => { const { t } = useTranslation() + const { handleSuccess } = useRouteModal() const form = useForm>({ defaultValues: { @@ -38,14 +37,6 @@ export const EditCustomerForm = ({ resolver: zodResolver(EditCustomerSchema), }) - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty]) - const { mutateAsync, isLoading } = useAdminUpdateCustomer(customer.id) const handleSubmit = form.handleSubmit(async (data) => { @@ -58,16 +49,16 @@ export const EditCustomerForm = ({ }, { onSuccess: () => { - onSuccessfulSubmit() + handleSuccess() }, } ) }) return ( -
    + - +
    -
    - + +
    - + - +
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/customers/customer-edit/customer-edit.tsx b/packages/admin-next/dashboard/src/routes/customers/customer-edit/customer-edit.tsx index a453f1152e..2fcf619a39 100644 --- a/packages/admin-next/dashboard/src/routes/customers/customer-edit/customer-edit.tsx +++ b/packages/admin-next/dashboard/src/routes/customers/customer-edit/customer-edit.tsx @@ -1,39 +1,26 @@ -import { Drawer, Heading } from "@medusajs/ui" +import { Heading } from "@medusajs/ui" import { useAdminCustomer } from "medusa-react" import { useTranslation } from "react-i18next" import { useParams } from "react-router-dom" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteDrawer } from "../../../components/route-modal" import { EditCustomerForm } from "./components/edit-customer-form" export const CustomerEdit = () => { - const [open, onOpenChange, subscribe] = useRouteModalState() const { t } = useTranslation() const { id } = useParams() const { customer, isLoading, isError, error } = useAdminCustomer(id!) - const handleSuccessfulSubmit = () => { - onOpenChange(false, true) - } - if (isError) { throw error } return ( - - - - {t("customers.editCustomer")} - - {!isLoading && customer && ( - - )} - - + + + {t("customers.editCustomer")} + + {!isLoading && customer && } + ) } diff --git a/packages/admin-next/dashboard/src/routes/gift-cards/gift-card-create/components/create-gift-card-form/create-gift-card-form.tsx b/packages/admin-next/dashboard/src/routes/gift-cards/gift-card-create/components/create-gift-card-form/create-gift-card-form.tsx index af29abc6ac..6f5a9581fd 100644 --- a/packages/admin-next/dashboard/src/routes/gift-cards/gift-card-create/components/create-gift-card-form/create-gift-card-form.tsx +++ b/packages/admin-next/dashboard/src/routes/gift-cards/gift-card-create/components/create-gift-card-form/create-gift-card-form.tsx @@ -3,7 +3,6 @@ import { Button, CurrencyInput, DatePicker, - FocusModal, Heading, Input, Select, @@ -14,20 +13,19 @@ import { } from "@medusajs/ui" import * as Collapsible from "@radix-ui/react-collapsible" import { useAdminCreateGiftCard, useAdminRegions } from "medusa-react" -import { useEffect, useState } from "react" +import { useState } from "react" import { useForm, useWatch } from "react-hook-form" import { useTranslation } from "react-i18next" import * as zod from "zod" -import { useNavigate } from "react-router-dom" import { Form } from "../../../../../components/common/form" +import { + RouteFocusModal, + useRouteModal, +} from "../../../../../components/route-modal" import { currencies } from "../../../../../lib/currencies" import { getDbAmount } from "../../../../../lib/money-amount-helpers" -type CreateGiftCardFormProps = { - subscribe: (state: boolean) => void -} - const CreateGiftCardSchema = zod.object({ region_id: zod.string(), value: zod.string(), @@ -37,7 +35,7 @@ const CreateGiftCardSchema = zod.object({ personal_message: zod.string().optional(), }) -export const CreateGiftCardForm = ({ subscribe }: CreateGiftCardFormProps) => { +export const CreateGiftCardForm = () => { const [showDateFields, setShowDateFields] = useState(false) const { regions } = useAdminRegions({ @@ -45,7 +43,7 @@ export const CreateGiftCardForm = ({ subscribe }: CreateGiftCardFormProps) => { fields: "id,name,currency_code", }) const { t } = useTranslation() - const navigate = useNavigate() + const { handleSuccess } = useRouteModal() const form = useForm>({ defaultValues: { @@ -59,11 +57,7 @@ export const CreateGiftCardForm = ({ subscribe }: CreateGiftCardFormProps) => { resolver: zodResolver(CreateGiftCardSchema), }) - const { - formState: { isDirty }, - setValue, - setError, - } = form + const { setValue, setError } = form const regionId = useWatch({ control: form.control, @@ -75,10 +69,6 @@ export const CreateGiftCardForm = ({ subscribe }: CreateGiftCardFormProps) => { ? currencies[currencyCode.toUpperCase()].symbol_native : undefined - useEffect(() => { - subscribe(isDirty) - }, [isDirty, subscribe]) - const { mutateAsync, isLoading } = useAdminCreateGiftCard() const handleOpenChange = (open: boolean) => { @@ -95,7 +85,7 @@ export const CreateGiftCardForm = ({ subscribe }: CreateGiftCardFormProps) => { if (!currencyCode) { setError("region_id", { type: "manual", - message: "Region not found", + message: t("giftCards.selectRegionFirst"), }) return @@ -114,31 +104,31 @@ export const CreateGiftCardForm = ({ subscribe }: CreateGiftCardFormProps) => { }, { onSuccess: ({ gift_card }) => { - navigate(`../${gift_card.id}`, { replace: true }) + handleSuccess(`../${gift_card.id}`) }, } ) }) return ( -
    + - +
    - + - +
    -
    - + +
    {t("giftCards.createGiftCard")} @@ -304,8 +294,8 @@ export const CreateGiftCardForm = ({ subscribe }: CreateGiftCardFormProps) => { />
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/gift-cards/gift-card-create/gift-card-create.tsx b/packages/admin-next/dashboard/src/routes/gift-cards/gift-card-create/gift-card-create.tsx index 21af94ba5c..9c50261d69 100644 --- a/packages/admin-next/dashboard/src/routes/gift-cards/gift-card-create/gift-card-create.tsx +++ b/packages/admin-next/dashboard/src/routes/gift-cards/gift-card-create/gift-card-create.tsx @@ -1,15 +1,10 @@ -import { FocusModal } from "@medusajs/ui" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteFocusModal } from "../../../components/route-modal" import { CreateGiftCardForm } from "./components/create-gift-card-form" export const GiftCardCreate = () => { - const [open, onOpenChange, subscribe] = useRouteModalState() - return ( - - - - - + + + ) } diff --git a/packages/admin-next/dashboard/src/routes/gift-cards/gift-card-edit/components/edit-gift-card-form/edit-gift-card-form.tsx b/packages/admin-next/dashboard/src/routes/gift-cards/gift-card-edit/components/edit-gift-card-form/edit-gift-card-form.tsx index 24f990e013..d8a336ee0f 100644 --- a/packages/admin-next/dashboard/src/routes/gift-cards/gift-card-edit/components/edit-gift-card-form/edit-gift-card-form.tsx +++ b/packages/admin-next/dashboard/src/routes/gift-cards/gift-card-edit/components/edit-gift-card-form/edit-gift-card-form.tsx @@ -4,19 +4,22 @@ import { Button, CurrencyInput, DatePicker, - Drawer, Select, Switch, Text, } from "@medusajs/ui" import * as Collapsible from "@radix-ui/react-collapsible" import { useAdminRegions, useAdminUpdateGiftCard } from "medusa-react" -import { useEffect, useState } from "react" +import { useState } from "react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import * as zod from "zod" import { Form } from "../../../../../components/common/form" +import { + RouteDrawer, + useRouteModal, +} from "../../../../../components/route-modal" import { currencies } from "../../../../../lib/currencies" import { isAxiosError } from "../../../../../lib/is-axios-error" import { @@ -26,8 +29,6 @@ import { type EditGiftCardFormProps = { giftCard: GiftCard - onSuccessfulSubmit: () => void - subscribe: (state: boolean) => void } const EditGiftCardSchema = zod.object({ @@ -37,13 +38,12 @@ const EditGiftCardSchema = zod.object({ ends_at: zod.date().nullable(), }) -export const EditGiftCardForm = ({ - giftCard, - onSuccessfulSubmit, - subscribe, -}: EditGiftCardFormProps) => { +export const EditGiftCardForm = ({ giftCard }: EditGiftCardFormProps) => { const { t } = useTranslation() + const { handleSuccess } = useRouteModal() + const [showDateFields, setShowDateFields] = useState(!!giftCard.ends_at) + const form = useForm>({ defaultValues: { region_id: giftCard.region_id, @@ -57,14 +57,7 @@ export const EditGiftCardForm = ({ resolver: zodResolver(EditGiftCardSchema), }) - const { - formState: { isDirty }, - setValue, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty, subscribe]) + const { setValue } = form const { regions } = useAdminRegions({ limit: 1000, @@ -117,7 +110,7 @@ export const EditGiftCardForm = ({ }, { onSuccess: () => { - onSuccessfulSubmit() + handleSuccess() }, onError: (error) => { if (isAxiosError(error)) { @@ -132,19 +125,19 @@ export const EditGiftCardForm = ({ }) return ( -
    + - + { return ( - {t("fields.balance")} + {t("giftCards.balance")} - - + +
    - + - +
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/gift-cards/gift-card-edit/gift-card-edit.tsx b/packages/admin-next/dashboard/src/routes/gift-cards/gift-card-edit/gift-card-edit.tsx index a888ff1b64..2c99a61f3b 100644 --- a/packages/admin-next/dashboard/src/routes/gift-cards/gift-card-edit/gift-card-edit.tsx +++ b/packages/admin-next/dashboard/src/routes/gift-cards/gift-card-edit/gift-card-edit.tsx @@ -1,39 +1,26 @@ -import { Drawer, Heading } from "@medusajs/ui" +import { Heading } from "@medusajs/ui" import { useAdminGiftCard } from "medusa-react" import { useTranslation } from "react-i18next" import { useParams } from "react-router-dom" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteDrawer } from "../../../components/route-modal" import { EditGiftCardForm } from "./components/edit-gift-card-form" export const GiftCardEdit = () => { const { id } = useParams() const { t } = useTranslation() - const [open, onOpenChange, subscribe] = useRouteModalState() const { gift_card, isLoading, isError, error } = useAdminGiftCard(id!) - const handleSuccessfulSubmit = () => { - onOpenChange(false, true) - } - if (isError) { throw error } return ( - - - - {t("giftCards.editGiftCard")} - - {!isLoading && gift_card && ( - - )} - - + + + {t("giftCards.editGiftCard")} + + {!isLoading && gift_card && } + ) } diff --git a/packages/admin-next/dashboard/src/routes/locations/location-add-sales-channels/location-add-sales-channels.tsx b/packages/admin-next/dashboard/src/routes/locations/location-add-sales-channels/location-add-sales-channels.tsx index 6f7d42bfeb..c09882bb28 100644 --- a/packages/admin-next/dashboard/src/routes/locations/location-add-sales-channels/location-add-sales-channels.tsx +++ b/packages/admin-next/dashboard/src/routes/locations/location-add-sales-channels/location-add-sales-channels.tsx @@ -1,15 +1,8 @@ -import { FocusModal } from "@medusajs/ui" import { useAdminAddLocationToSalesChannel } from "medusa-react" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteFocusModal } from "../../../components/route-modal" export const LocationAddSalesChannels = () => { - const [open, onOpenChange] = useRouteModalState() - const { mutateAsync } = useAdminAddLocationToSalesChannel() // TODO: We need a batch mutation instead of this to avoid multiple requests - return ( - - - - ) + return } diff --git a/packages/admin-next/dashboard/src/routes/locations/location-create/components/create-location-form/create-location-form.tsx b/packages/admin-next/dashboard/src/routes/locations/location-create/components/create-location-form/create-location-form.tsx index a80fc765ab..ad40b5943a 100644 --- a/packages/admin-next/dashboard/src/routes/locations/location-create/components/create-location-form/create-location-form.tsx +++ b/packages/admin-next/dashboard/src/routes/locations/location-create/components/create-location-form/create-location-form.tsx @@ -1,11 +1,12 @@ import { zodResolver } from "@hookform/resolvers/zod" -import { Button, FocusModal, Heading, Input, Text } from "@medusajs/ui" +import { Button, Heading, Input, Text } from "@medusajs/ui" import { useAdminCreateStockLocation } from "medusa-react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import * as zod from "zod" import { CountrySelect } from "../../../../../components/common/country-select" import { Form } from "../../../../../components/common/form" +import { RouteFocusModal } from "../../../../../components/route-modal" const CreateLocationSchema = zod.object({ name: zod.string().min(1), @@ -22,7 +23,7 @@ const CreateLocationSchema = zod.object({ }) export const CreateLocationForm = () => { - const { mutateAsync, isLoading } = useAdminCreateStockLocation() + const { t } = useTranslation() const form = useForm>({ defaultValues: { @@ -41,7 +42,7 @@ export const CreateLocationForm = () => { resolver: zodResolver(CreateLocationSchema), }) - const { t } = useTranslation() + const { mutateAsync, isLoading } = useAdminCreateStockLocation() const handleSubmit = form.handleSubmit(async (values) => { mutateAsync( @@ -56,24 +57,24 @@ export const CreateLocationForm = () => { }) return ( -
    + - +
    - + - +
    -
    - + +
    @@ -227,8 +228,8 @@ export const CreateLocationForm = () => {
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/locations/location-create/location-create.tsx b/packages/admin-next/dashboard/src/routes/locations/location-create/location-create.tsx index 0369b258d6..5d6a290e16 100644 --- a/packages/admin-next/dashboard/src/routes/locations/location-create/location-create.tsx +++ b/packages/admin-next/dashboard/src/routes/locations/location-create/location-create.tsx @@ -1,15 +1,10 @@ -import { FocusModal } from "@medusajs/ui" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteFocusModal } from "../../../components/route-modal" import { CreateLocationForm } from "./components/create-location-form" export const LocationCreate = () => { - const [open, onOpenChange] = useRouteModalState() - return ( - - - - - + + + ) } diff --git a/packages/admin-next/dashboard/src/routes/locations/location-edit/components/edit-location-form/edit-location-form.tsx b/packages/admin-next/dashboard/src/routes/locations/location-edit/components/edit-location-form/edit-location-form.tsx index a543d228fc..1c7a05a5fb 100644 --- a/packages/admin-next/dashboard/src/routes/locations/location-edit/components/edit-location-form/edit-location-form.tsx +++ b/packages/admin-next/dashboard/src/routes/locations/location-edit/components/edit-location-form/edit-location-form.tsx @@ -1,12 +1,14 @@ import { zodResolver } from "@hookform/resolvers/zod" import { StockLocationExpandedDTO } from "@medusajs/types" -import { Button, Drawer, Input } from "@medusajs/ui" +import { Button, Input } from "@medusajs/ui" import { useAdminUpdateStockLocation } from "medusa-react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import * as zod from "zod" + import { CountrySelect } from "../../../../../components/common/country-select" import { Form } from "../../../../../components/common/form" +import { RouteDrawer } from "../../../../../components/route-modal" type EditLocationFormProps = { location: StockLocationExpandedDTO @@ -56,12 +58,12 @@ export const EditLocationForm = ({ location }: EditLocationFormProps) => { }) return ( -
    + - +
    { }} />
    -
    - + +
    - + - - + +
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/locations/location-edit/location-edit.tsx b/packages/admin-next/dashboard/src/routes/locations/location-edit/location-edit.tsx index b30df632ce..04e229be51 100644 --- a/packages/admin-next/dashboard/src/routes/locations/location-edit/location-edit.tsx +++ b/packages/admin-next/dashboard/src/routes/locations/location-edit/location-edit.tsx @@ -1,12 +1,11 @@ -import { Drawer, Heading } from "@medusajs/ui" +import { Heading } from "@medusajs/ui" import { useAdminStockLocations } from "medusa-react" import { useTranslation } from "react-i18next" -import { json, useParams } from "react-router-dom" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { useParams } from "react-router-dom" +import { RouteDrawer } from "../../../components/route-modal" import { EditLocationForm } from "./components/edit-location-form/edit-location-form" export const LocationEdit = () => { - const [open, onOpenChange] = useRouteModalState() const { id } = useParams() const { stock_locations, isLoading, isError, error } = useAdminStockLocations( @@ -24,24 +23,14 @@ export const LocationEdit = () => { const stock_location = stock_locations?.[0] - if (!isLoading && !stock_location) { - throw json({ message: "Not found" }, 404) - } - return ( - - - - - {t("locations.editLocation")} - - - {isLoading || !stock_location ? ( -
    Loading...
    - ) : ( - - )} -
    -
    + + + {t("locations.editLocation")} + + {!isLoading && stock_location && ( + + )} + ) } diff --git a/packages/admin-next/dashboard/src/routes/products/product-attributes/components/product-attributes-form/product-attributes-form.tsx b/packages/admin-next/dashboard/src/routes/products/product-attributes/components/product-attributes-form/product-attributes-form.tsx index ae5e0dfc28..5a8193b451 100644 --- a/packages/admin-next/dashboard/src/routes/products/product-attributes/components/product-attributes-form/product-attributes-form.tsx +++ b/packages/admin-next/dashboard/src/routes/products/product-attributes/components/product-attributes-form/product-attributes-form.tsx @@ -1,19 +1,20 @@ import { zodResolver } from "@hookform/resolvers/zod" import { Product } from "@medusajs/medusa" -import { Button, Drawer, Input } from "@medusajs/ui" +import { Button, Input } from "@medusajs/ui" import { useAdminUpdateProduct } from "medusa-react" -import { useEffect } from "react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import * as zod from "zod" import { CountrySelect } from "../../../../../components/common/country-select" import { Form } from "../../../../../components/common/form" +import { + RouteDrawer, + useRouteModal, +} from "../../../../../components/route-modal" type ProductAttributesFormProps = { product: Product - subscribe: (state: boolean) => void - onSuccessfulSubmit: () => void } const dimension = zod @@ -39,9 +40,10 @@ const ProductAttributesSchema = zod.object({ export const ProductAttributesForm = ({ product, - subscribe, - onSuccessfulSubmit, }: ProductAttributesFormProps) => { + const { t } = useTranslation() + const { handleSuccess } = useRouteModal() + const form = useForm>({ defaultValues: { height: product.height ? product.height : null, @@ -55,15 +57,6 @@ export const ProductAttributesForm = ({ resolver: zodResolver(ProductAttributesSchema), }) - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty, subscribe]) - - const { t } = useTranslation() const { mutateAsync, isLoading } = useAdminUpdateProduct(product.id) const handleSubmit = form.handleSubmit(async (data) => { @@ -79,16 +72,16 @@ export const ProductAttributesForm = ({ }, { onSuccess: () => { - onSuccessfulSubmit() + handleSuccess() }, } ) }) return ( -
    + - +
    -
    - + +
    - + - +
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/products/product-attributes/product-attributes.tsx b/packages/admin-next/dashboard/src/routes/products/product-attributes/product-attributes.tsx index eebeac6be4..d6eb19e27b 100644 --- a/packages/admin-next/dashboard/src/routes/products/product-attributes/product-attributes.tsx +++ b/packages/admin-next/dashboard/src/routes/products/product-attributes/product-attributes.tsx @@ -1,41 +1,27 @@ -import { Drawer, Heading } from "@medusajs/ui" +import { Heading } from "@medusajs/ui" import { useAdminProduct } from "medusa-react" import { useTranslation } from "react-i18next" import { useParams } from "react-router-dom" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteDrawer } from "../../../components/route-modal" import { ProductAttributesForm } from "./components/product-attributes-form" export const ProductAttributes = () => { const { id } = useParams() - const [open, onOpenChange, subscribe] = useRouteModalState() - const { t } = useTranslation() const { product, isLoading, isError, error } = useAdminProduct(id!) - const handleSuccessfulSubmit = () => { - onOpenChange(false, true) - } - if (isError) { throw error } return ( - - - - {t("products.editAttributes")} - - {!isLoading && product && ( - - )} - - + + + {t("products.editAttributes")} + + {!isLoading && product && } + ) } diff --git a/packages/admin-next/dashboard/src/routes/products/product-create/components/create-product-form/create-product-form.tsx b/packages/admin-next/dashboard/src/routes/products/product-create/components/create-product-form/create-product-form.tsx index 8f0c9fe4e6..ea3b18067b 100644 --- a/packages/admin-next/dashboard/src/routes/products/product-create/components/create-product-form/create-product-form.tsx +++ b/packages/admin-next/dashboard/src/routes/products/product-create/components/create-product-form/create-product-form.tsx @@ -1,18 +1,16 @@ import { zodResolver } from "@hookform/resolvers/zod" -import { Button, FocusModal } from "@medusajs/ui" +import { Button } from "@medusajs/ui" import { useAdminCreateProduct } from "medusa-react" -import { useEffect } from "react" import { UseFormReturn, useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import * as zod from "zod" -import { Form } from "../../../../../components/common/form" +import { + RouteFocusModal, + useRouteModal, +} from "../../../../../components/route-modal" import { CreateProductDetails } from "./create-product-details" -type CreateProductFormProps = { - subscribe: (state: boolean) => void -} - const CreateProductSchema = zod.object({ title: zod.string(), subtitle: zod.string().optional(), @@ -38,8 +36,10 @@ const CreateProductSchema = zod.object({ type Schema = zod.infer export type CreateProductFormReturn = UseFormReturn -export const CreateProductForm = ({ subscribe }: CreateProductFormProps) => { +export const CreateProductForm = () => { const { t } = useTranslation() + const { handleSuccess } = useRouteModal() + const form = useForm({ defaultValues: { title: "", @@ -61,14 +61,6 @@ export const CreateProductForm = ({ subscribe }: CreateProductFormProps) => { resolver: zodResolver(CreateProductSchema), }) - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [subscribe, isDirty]) - const { mutateAsync, isLoading } = useAdminCreateProduct() const handleSubmit = form.handleSubmit(async (values) => { @@ -83,34 +75,36 @@ export const CreateProductForm = ({ subscribe }: CreateProductFormProps) => { weight: values.weight ? parseFloat(values.weight) : undefined, }, { - onSuccess: () => {}, + onSuccess: ({ product }) => { + handleSuccess(`../${product.id}`) + }, } ) }) return ( -
    + - +
    - + - +
    -
    - + +
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/products/product-create/product-create.tsx b/packages/admin-next/dashboard/src/routes/products/product-create/product-create.tsx index 8232bc2494..4316f5dfe4 100644 --- a/packages/admin-next/dashboard/src/routes/products/product-create/product-create.tsx +++ b/packages/admin-next/dashboard/src/routes/products/product-create/product-create.tsx @@ -1,15 +1,10 @@ -import { FocusModal } from "@medusajs/ui" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteFocusModal } from "../../../components/route-modal" import { CreateProductForm } from "./components/create-product-form" export const ProductCreate = () => { - const [open, onOpenChange, subscribe] = useRouteModalState() - return ( - - - - - + + + ) } diff --git a/packages/admin-next/dashboard/src/routes/products/product-edit/components/edit-product-form/edit-product-form.tsx b/packages/admin-next/dashboard/src/routes/products/product-edit/components/edit-product-form/edit-product-form.tsx index 3889b91008..aff799ac51 100644 --- a/packages/admin-next/dashboard/src/routes/products/product-edit/components/edit-product-form/edit-product-form.tsx +++ b/packages/admin-next/dashboard/src/routes/products/product-edit/components/edit-product-form/edit-product-form.tsx @@ -1,27 +1,20 @@ import { zodResolver } from "@hookform/resolvers/zod" import { Product } from "@medusajs/medusa" import { ProductStatus } from "@medusajs/types" -import { - Button, - Drawer, - Input, - Select, - Switch, - Text, - Textarea, -} from "@medusajs/ui" +import { Button, Input, Select, Switch, Text, Textarea } from "@medusajs/ui" import { useAdminUpdateProduct } from "medusa-react" -import { useEffect } from "react" import { useForm } from "react-hook-form" import { Trans, useTranslation } from "react-i18next" import * as zod from "zod" import { Form } from "../../../../../components/common/form" +import { + RouteDrawer, + useRouteModal, +} from "../../../../../components/route-modal" type EditProductFormProps = { product: Product - subscribe: (state: boolean) => void - onSuccessfulSubmit: () => void } const EditProductSchema = zod.object({ @@ -34,11 +27,10 @@ const EditProductSchema = zod.object({ discountable: zod.boolean(), }) -export const EditProductForm = ({ - product, - subscribe, - onSuccessfulSubmit, -}: EditProductFormProps) => { +export const EditProductForm = ({ product }: EditProductFormProps) => { + const { t } = useTranslation() + const { handleSuccess } = useRouteModal() + const form = useForm>({ defaultValues: { status: product.status, @@ -52,15 +44,6 @@ export const EditProductForm = ({ resolver: zodResolver(EditProductSchema), }) - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty, subscribe]) - - const { t } = useTranslation() const { mutateAsync, isLoading } = useAdminUpdateProduct(product.id) const handleSubmit = form.handleSubmit(async (data) => { @@ -71,16 +54,16 @@ export const EditProductForm = ({ }, { onSuccess: () => { - onSuccessfulSubmit() + handleSuccess() }, } ) }) return ( -
    + - +
    - When unchecked discounts will not be applied to this - product. + {t("products.discountableHint")} @@ -256,20 +238,20 @@ export const EditProductForm = ({ }} />
    -
    - + +
    - + - +
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/products/product-edit/product-edit.tsx b/packages/admin-next/dashboard/src/routes/products/product-edit/product-edit.tsx index 0da39a73c5..d68df23081 100644 --- a/packages/admin-next/dashboard/src/routes/products/product-edit/product-edit.tsx +++ b/packages/admin-next/dashboard/src/routes/products/product-edit/product-edit.tsx @@ -1,41 +1,27 @@ -import { Drawer, Heading } from "@medusajs/ui" +import { Heading } from "@medusajs/ui" import { useAdminProduct } from "medusa-react" import { useTranslation } from "react-i18next" import { useParams } from "react-router-dom" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteDrawer } from "../../../components/route-modal" import { EditProductForm } from "./components/edit-product-form" export const ProductEdit = () => { const { id } = useParams() - const [open, onOpenChange, subscribe] = useRouteModalState() - const { t } = useTranslation() const { product, isLoading, isError, error } = useAdminProduct(id!) - const handleSuccessfulSubmit = () => { - onOpenChange(false, true) - } - if (isError) { throw error } return ( - - - - {t("products.editProduct")} - - {!isLoading && product && ( - - )} - - + + + {t("products.editProduct")} + + {!isLoading && product && } + ) } diff --git a/packages/admin-next/dashboard/src/routes/products/product-gallery/product-gallery.tsx b/packages/admin-next/dashboard/src/routes/products/product-gallery/product-gallery.tsx index 83744149a0..625881c7a8 100644 --- a/packages/admin-next/dashboard/src/routes/products/product-gallery/product-gallery.tsx +++ b/packages/admin-next/dashboard/src/routes/products/product-gallery/product-gallery.tsx @@ -11,14 +11,16 @@ import { Button, IconButton, Kbd, Tooltip } from "@medusajs/ui" import * as Dialog from "@radix-ui/react-dialog" import { Variants, motion } from "framer-motion" import { useAdminProduct } from "medusa-react" -import { useCallback, useEffect, useMemo } from "react" +import { useCallback, useEffect, useMemo, useState } from "react" import { useTranslation } from "react-i18next" import { Link, useParams, useSearchParams } from "react-router-dom" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" - export const ProductGallery = () => { - const [open, onOpenChange] = useRouteModalState() + const [open, setOpen] = useState(false) + + useEffect(() => { + setOpen(true) + }, []) const { id } = useParams() const [searchParams, setSearchParams] = useSearchParams() @@ -78,7 +80,7 @@ export const ProductGallery = () => { } return ( - +
    diff --git a/packages/admin-next/dashboard/src/routes/products/product-options/components/edit-product-options-form/edit-product-options-form.tsx b/packages/admin-next/dashboard/src/routes/products/product-options/components/edit-product-options-form/edit-product-options-form.tsx index e918f83718..d71f91b15c 100644 --- a/packages/admin-next/dashboard/src/routes/products/product-options/components/edit-product-options-form/edit-product-options-form.tsx +++ b/packages/admin-next/dashboard/src/routes/products/product-options/components/edit-product-options-form/edit-product-options-form.tsx @@ -1,15 +1,13 @@ import { zodResolver } from "@hookform/resolvers/zod" import { Product } from "@medusajs/medusa" -import { Button, Drawer } from "@medusajs/ui" +import { Button } from "@medusajs/ui" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import * as zod from "zod" -import { Form } from "../../../../../components/common/form" +import { RouteDrawer } from "../../../../../components/route-modal" type EditProductOptionsFormProps = { product: Product - handleSuccess: () => void - subscribe: (state: boolean) => void } const EditProductOptionsSchema = zod.object({}) @@ -22,22 +20,22 @@ export const EditProductOptionsForm = (props: EditProductOptionsFormProps) => { }) return ( -
    + - - + +
    - + - +
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/products/product-options/product-options.tsx b/packages/admin-next/dashboard/src/routes/products/product-options/product-options.tsx index 14e3efa70d..60f8469e74 100644 --- a/packages/admin-next/dashboard/src/routes/products/product-options/product-options.tsx +++ b/packages/admin-next/dashboard/src/routes/products/product-options/product-options.tsx @@ -1,39 +1,26 @@ -import { Drawer, Heading } from "@medusajs/ui" +import { Heading } from "@medusajs/ui" import { useAdminProduct } from "medusa-react" import { useTranslation } from "react-i18next" import { useParams } from "react-router-dom" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteDrawer } from "../../../components/route-modal" import { EditProductOptionsForm } from "./components/edit-product-options-form" export const ProductOptions = () => { const { id } = useParams() const { t } = useTranslation() - const [open, onOpenChange, subscribe] = useRouteModalState() const { product, isLoading, isError, error } = useAdminProduct(id!) - const handleSuccess = () => { - onOpenChange(false, true) - } - if (isError) { throw error } return ( - - - - {t("products.editOptions")} - - {!isLoading && product && ( - - )} - - + + + {t("products.editOptions")} + + {!isLoading && product && } + ) } diff --git a/packages/admin-next/dashboard/src/routes/products/product-sales-channels/components/edit-sales-channels-form/edit-sales-channels-form.tsx b/packages/admin-next/dashboard/src/routes/products/product-sales-channels/components/edit-sales-channels-form/edit-sales-channels-form.tsx index 70a277a67f..4935d217b4 100644 --- a/packages/admin-next/dashboard/src/routes/products/product-sales-channels/components/edit-sales-channels-form/edit-sales-channels-form.tsx +++ b/packages/admin-next/dashboard/src/routes/products/product-sales-channels/components/edit-sales-channels-form/edit-sales-channels-form.tsx @@ -1,9 +1,17 @@ import { Product, SalesChannel } from "@medusajs/medusa" -import { Button, Checkbox, FocusModal } from "@medusajs/ui" +import { Button, Checkbox } from "@medusajs/ui" import { RowSelectionState, createColumnHelper } from "@tanstack/react-table" import { useAdminSalesChannels, useAdminUpdateProduct } from "medusa-react" import { useEffect, useMemo, useState } from "react" import { useTranslation } from "react-i18next" +import * as zod from "zod" + +import { zodResolver } from "@hookform/resolvers/zod" +import { useForm } from "react-hook-form" +import { + RouteFocusModal, + useRouteModal, +} from "../../../../../components/route-modal" import { DataTable } from "../../../../../components/table/data-table" import { useSalesChannelTableColumns } from "../../../../../hooks/table/columns/use-sales-channel-table-columns" import { useSalesChannelTableFilters } from "../../../../../hooks/table/filters/use-sales-channel-table-filters" @@ -12,18 +20,28 @@ import { useDataTable } from "../../../../../hooks/use-data-table" type EditSalesChannelsFormProps = { product: Product - subscribe: (state: boolean) => void - onSuccessfulSubmit: () => void } +const EditSalesChannelsSchema = zod.object({ + sales_channels: zod.array(zod.string()).optional(), +}) + const PAGE_SIZE = 50 export const EditSalesChannelsForm = ({ product, - subscribe, - onSuccessfulSubmit, }: EditSalesChannelsFormProps) => { const { t } = useTranslation() + const { handleSuccess } = useRouteModal() + + const form = useForm>({ + defaultValues: { + sales_channels: product.sales_channels?.map((sc) => sc.id) ?? [], + }, + resolver: zodResolver(EditSalesChannelsSchema), + }) + + const { setValue } = form const initialState = product.sales_channels?.reduce((acc, curr) => { @@ -34,13 +52,13 @@ export const EditSalesChannelsForm = ({ const [rowSelection, setRowSelection] = useState(initialState) - const isDirty = Object.entries(initialState).some( - ([key, value]) => value !== rowSelection[key] - ) - useEffect(() => { - subscribe(isDirty) - }, [isDirty, subscribe]) + const ids = Object.keys(rowSelection) + setValue("sales_channels", ids, { + shouldDirty: true, + shouldTouch: true, + }) + }, [rowSelection, setValue]) const { searchParams, raw } = useSalesChannelTableQuery({ pageSize: PAGE_SIZE, @@ -76,12 +94,10 @@ export const EditSalesChannelsForm = ({ product.id ) - const handleSubmit = async () => { - const selected = Object.keys(rowSelection).filter((key) => { - return rowSelection[key] - }) + const handleSubmit = form.handleSubmit(async (data) => { + const arr = data.sales_channels ?? [] - const sales_channels = selected.map((id) => { + const sales_channels = arr.map((id) => { return { id, } @@ -93,46 +109,48 @@ export const EditSalesChannelsForm = ({ }, { onSuccess: () => { - onSuccessfulSubmit() + handleSuccess() }, } ) - } + }) if (isError) { throw error } return ( -
    - -
    - - + + - - -
    -
    - - - -
    +
    + + + + + + ) } diff --git a/packages/admin-next/dashboard/src/routes/products/product-sales-channels/product-sales-channels.tsx b/packages/admin-next/dashboard/src/routes/products/product-sales-channels/product-sales-channels.tsx index 5485cf7c0a..89f42fcd8d 100644 --- a/packages/admin-next/dashboard/src/routes/products/product-sales-channels/product-sales-channels.tsx +++ b/packages/admin-next/dashboard/src/routes/products/product-sales-channels/product-sales-channels.tsx @@ -1,35 +1,20 @@ -import { FocusModal } from "@medusajs/ui" import { useAdminProduct } from "medusa-react" import { useParams } from "react-router-dom" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteFocusModal } from "../../../components/route-modal" import { EditSalesChannelsForm } from "./components/edit-sales-channels-form" export const ProductSalesChannels = () => { const { id } = useParams() - const [open, onOpenChange, subscribe] = useRouteModalState() - const { product, isLoading, isError, error } = useAdminProduct(id!) - const handleSuccessfulSubmit = () => { - onOpenChange(false, true) - } - if (isError) { throw error } return ( - - - {!isLoading && product && ( - - )} - - + + {!isLoading && product && } + ) } diff --git a/packages/admin-next/dashboard/src/routes/profile/profile-edit/components/edit-profile-form/edit-profile-form.tsx b/packages/admin-next/dashboard/src/routes/profile/profile-edit/components/edit-profile-form/edit-profile-form.tsx index b59dd7d937..d57353c27b 100644 --- a/packages/admin-next/dashboard/src/routes/profile/profile-edit/components/edit-profile-form/edit-profile-form.tsx +++ b/packages/admin-next/dashboard/src/routes/profile/profile-edit/components/edit-profile-form/edit-profile-form.tsx @@ -1,19 +1,22 @@ -import { User } from "@medusajs/medusa" -import * as zod from "zod" - import { zodResolver } from "@hookform/resolvers/zod" -import { Button, Drawer, Input, Select, Switch } from "@medusajs/ui" +import { User } from "@medusajs/medusa" +import { Button, Input, Select, Switch } from "@medusajs/ui" import { adminAuthKeys, useAdminUpdateUser } from "medusa-react" import { useForm } from "react-hook-form" import { Trans, useTranslation } from "react-i18next" +import * as zod from "zod" + import { Form } from "../../../../../components/common/form" +import { + RouteDrawer, + useRouteModal, +} from "../../../../../components/route-modal" import { languages } from "../../../../../i18n/config" import { queryClient } from "../../../../../lib/medusa" type EditProfileProps = { user: Omit usageInsights: boolean - onSuccess: () => void } const EditProfileSchema = zod.object({ @@ -23,13 +26,9 @@ const EditProfileSchema = zod.object({ usage_insights: zod.boolean(), }) -export const EditProfileForm = ({ - user, - usageInsights, - onSuccess, -}: EditProfileProps) => { +export const EditProfileForm = ({ user, usageInsights }: EditProfileProps) => { const { t, i18n } = useTranslation() - const { mutateAsync, isLoading } = useAdminUpdateUser(user.id) + const { handleSuccess } = useRouteModal() const form = useForm>({ defaultValues: { @@ -49,6 +48,8 @@ export const EditProfileForm = ({ a.display_name.localeCompare(b.display_name) ) + const { mutateAsync, isLoading } = useAdminUpdateUser(user.id) + const handleSubmit = form.handleSubmit(async (values) => { await mutateAsync( { @@ -56,12 +57,7 @@ export const EditProfileForm = ({ last_name: values.last_name, }, { - onSuccess: ({ user }) => { - form.reset({ - first_name: user.first_name, - last_name: user.last_name, - }) - + onSuccess: () => { // Invalidate the current user session. queryClient.invalidateQueries(adminAuthKeys.details()) }, @@ -73,13 +69,13 @@ export const EditProfileForm = ({ changeLanguage(values.language) - onSuccess() + handleSuccess() }) return ( -
    + - +
    + + + + + {storeCurrencies.map((currency) => ( + + {currency.name} + + ))} + + + ) @@ -198,8 +206,8 @@ export const CreateRegionForm = ({ subscribe }: CreateRegionFormProps) => {
    - + - + ) } diff --git a/packages/admin-next/dashboard/src/routes/regions/region-create/region-create.tsx b/packages/admin-next/dashboard/src/routes/regions/region-create/region-create.tsx index c313c1d915..922932067a 100644 --- a/packages/admin-next/dashboard/src/routes/regions/region-create/region-create.tsx +++ b/packages/admin-next/dashboard/src/routes/regions/region-create/region-create.tsx @@ -1,16 +1,10 @@ -import { FocusModal } from "@medusajs/ui" - -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteFocusModal } from "../../../components/route-modal/route-focus-modal" import { CreateRegionForm } from "./components/create-region-form" export const RegionCreate = () => { - const [open, onOpenChange, subscribe] = useRouteModalState() - return ( - - - - - + + + ) } diff --git a/packages/admin-next/dashboard/src/routes/regions/region-detail/components/region-shipping-option-section/index.ts b/packages/admin-next/dashboard/src/routes/regions/region-detail/components/region-shipping-option-section/index.ts new file mode 100644 index 0000000000..f7841f26fc --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/regions/region-detail/components/region-shipping-option-section/index.ts @@ -0,0 +1 @@ +export * from "./region-shipping-option-section" diff --git a/packages/admin-next/dashboard/src/routes/regions/region-detail/components/region-shipping-option-section/region-shipping-option-section.tsx b/packages/admin-next/dashboard/src/routes/regions/region-detail/components/region-shipping-option-section/region-shipping-option-section.tsx index ddebc33167..b35f2af342 100644 --- a/packages/admin-next/dashboard/src/routes/regions/region-detail/components/region-shipping-option-section/region-shipping-option-section.tsx +++ b/packages/admin-next/dashboard/src/routes/regions/region-detail/components/region-shipping-option-section/region-shipping-option-section.tsx @@ -1,60 +1,48 @@ -import { Region, ShippingOption } from "@medusajs/medusa" -import { Container, Heading, StatusBadge, Table, clx } from "@medusajs/ui" -import { - PaginationState, - RowSelectionState, - createColumnHelper, - flexRender, - getCoreRowModel, - useReactTable, -} from "@tanstack/react-table" +import { Region } from "@medusajs/medusa" +import { Container, Heading } from "@medusajs/ui" import { useAdminShippingOptions } from "medusa-react" -import { useMemo, useState } from "react" import { useTranslation } from "react-i18next" -import { LocalizedTablePagination } from "../../../../../components/localization/localized-table-pagination" + +import { PricedShippingOption } from "@medusajs/medusa/dist/types/pricing" +import { DataTable } from "../../../../../components/table/data-table" +import { useDataTable } from "../../../../../hooks/use-data-table" +import { useShippingOptionColumns } from "./use-shipping-option-table-columns" +import { useShippingOptionTableFilters } from "./use-shipping-option-table-filters" +import { useShippingOptionTableQuery } from "./use-shipping-option-table-query" type RegionShippingOptionSectionProps = { region: Region } +const PAGE_SIZE = 10 + export const RegionShippingOptionSection = ({ region, }: RegionShippingOptionSectionProps) => { - const { shipping_options, count, isError, error, isLoading } = - useAdminShippingOptions({ - region_id: region.id, - is_return: false, - }) - - const [{ pageIndex, pageSize }, setPagination] = useState({ - pageIndex: 0, - pageSize: count || 0, + const { searchParams, raw } = useShippingOptionTableQuery({ + pageSize: PAGE_SIZE, + regionId: region.id, }) + const { shipping_options, count, isError, error, isLoading } = + useAdminShippingOptions( + { + ...searchParams, + }, + { + keepPreviousData: true, + } + ) - const pagination = useMemo( - () => ({ - pageIndex, - pageSize, - }), - [pageIndex, pageSize] - ) - - const [rowSelection, setRowSelection] = useState({}) - + const filters = useShippingOptionTableFilters() const columns = useShippingOptionColumns() - const table = useReactTable({ - data: shipping_options ?? [], + const { table } = useDataTable({ + data: (shipping_options ?? []) as unknown as PricedShippingOption[], columns, - pageCount: count ? 1 : 0, - state: { - pagination, - rowSelection, - }, - manualPagination: true, - getCoreRowModel: getCoreRowModel(), - onPaginationChange: setPagination, - onRowSelectionChange: setRowSelection, + count, + enablePagination: true, + getRowId: (row) => row.id!, + pageSize: PAGE_SIZE, }) const { t } = useTranslation() @@ -64,91 +52,30 @@ export const RegionShippingOptionSection = ({ } return ( - +
    {t("regions.shippingOptions")}
    - - - {table.getHeaderGroups().map((headerGroup) => { - return ( - - {headerGroup.headers.map((header) => { - return ( - - {flexRender( - header.column.columnDef.header, - header.getContext() - )} - - ) - })} - - ) - })} - - - {table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender(cell.column.columnDef.cell, cell.getContext())} - - ))} - - ))} - -
    -
    ) } - -const columnHelper = createColumnHelper() - -const useShippingOptionColumns = () => { - const { t } = useTranslation() - - return useMemo( - () => [ - columnHelper.accessor("name", { - header: t("fields.name"), - cell: (cell) => cell.getValue(), - }), - columnHelper.accessor("admin_only", { - header: t("fields.availability"), - cell: (cell) => { - const value = cell.getValue() - - return ( - - {value ? t("general.admin") : t("general.store")} - - ) - }, - }), - ], - [t] - ) -} diff --git a/packages/admin-next/dashboard/src/routes/regions/region-detail/components/region-shipping-option-section/use-shipping-option-table-columns.tsx b/packages/admin-next/dashboard/src/routes/regions/region-detail/components/region-shipping-option-section/use-shipping-option-table-columns.tsx new file mode 100644 index 0000000000..e05e55c475 --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/regions/region-detail/components/region-shipping-option-section/use-shipping-option-table-columns.tsx @@ -0,0 +1,116 @@ +import { PricedShippingOption } from "@medusajs/medusa/dist/types/pricing" +import { createColumnHelper } from "@tanstack/react-table" +import { useMemo } from "react" +import { useTranslation } from "react-i18next" +import { MoneyAmountCell } from "../../../../../components/table/table-cells/common/money-amount-cell" +import { PlaceholderCell } from "../../../../../components/table/table-cells/common/placeholder-cell" +import { StatusCell } from "../../../../../components/table/table-cells/common/status-cell" + +const columnHelper = createColumnHelper() + +export const useShippingOptionColumns = () => { + const { t } = useTranslation() + + return useMemo( + () => [ + columnHelper.accessor("name", { + header: t("fields.name"), + cell: ({ getValue }) => ( +
    + {getValue()} +
    + ), + }), + columnHelper.accessor("price_type", { + header: t("regions.priceType"), + cell: ({ getValue }) => { + const type = getValue() + + return ( + + {type === "flat_rate" + ? t("regions.flatRate") + : t("regions.calculated")} + + ) + }, + }), + columnHelper.accessor("price_incl_tax", { + header: t("fields.price"), + cell: ({ getValue, row }) => { + const isCalculated = row.original.price_type === "calculated" + + if (isCalculated) { + return + } + + const amount = getValue() + const currencyCode = row.original.region!.currency_code + + return + }, + }), + columnHelper.display({ + id: "min_amount", + header: "Min.", + cell: ({ row }) => { + const minAmountReq = row.original.requirements?.find( + (r) => r.type === "min_subtotal" + ) + + if (!minAmountReq) { + return + } + + const amount = minAmountReq.amount + const currencyCode = row.original.region!.currency_code + + return + }, + }), + columnHelper.display({ + id: "max_amount", + header: "Max.", + cell: ({ row }) => { + const maxAmountReq = row.original.requirements?.find( + (r) => r.type === "max_subtotal" + ) + + if (!maxAmountReq) { + return + } + + const amount = maxAmountReq.amount + const currencyCode = row.original.region!.currency_code + + return + }, + }), + columnHelper.accessor("admin_only", { + header: t("fields.availability"), + cell: (cell) => { + const value = cell.getValue() + + return ( + + {value ? t("general.admin") : t("general.store")} + + ) + }, + }), + columnHelper.accessor("is_return", { + header: t("fields.type"), + cell: (cell) => { + const value = cell.getValue() + + return ( + + {value ? t("regions.return") : t("regions.outbound")} + + ) + }, + }), + ], + [t] + ) +} diff --git a/packages/admin-next/dashboard/src/routes/regions/region-detail/components/region-shipping-option-section/use-shipping-option-table-filters.tsx b/packages/admin-next/dashboard/src/routes/regions/region-detail/components/region-shipping-option-section/use-shipping-option-table-filters.tsx new file mode 100644 index 0000000000..aa618865fa --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/regions/region-detail/components/region-shipping-option-section/use-shipping-option-table-filters.tsx @@ -0,0 +1,39 @@ +import { useTranslation } from "react-i18next" +import { Filter } from "../../../../../components/table/data-table" + +export const useShippingOptionTableFilters = () => { + const { t } = useTranslation() + + const isReturnFilter: Filter = { + key: "is_return", + label: t("fields.type"), + type: "select", + options: [ + { label: t("regions.return"), value: "true" }, + { label: t("regions.outbound"), value: "false" }, + ], + } + + const isAdminFilter: Filter = { + key: "admin_only", + label: t("fields.availability"), + type: "select", + options: [ + { label: t("general.admin"), value: "true" }, + { label: t("general.store"), value: "false" }, + ], + } + + 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", + })) + + const filters = [isReturnFilter, isAdminFilter, ...dateFilters] + + return filters +} diff --git a/packages/admin-next/dashboard/src/routes/regions/region-detail/components/region-shipping-option-section/use-shipping-option-table-query.tsx b/packages/admin-next/dashboard/src/routes/regions/region-detail/components/region-shipping-option-section/use-shipping-option-table-query.tsx new file mode 100644 index 0000000000..348c370926 --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/regions/region-detail/components/region-shipping-option-section/use-shipping-option-table-query.tsx @@ -0,0 +1,48 @@ +import { AdminGetShippingOptionsParams } from "@medusajs/medusa" +import { useQueryParams } from "../../../../../hooks/use-query-params" + +type UseShippingOptionTableQueryProps = { + regionId: string + isReturn?: boolean + pageSize?: number + prefix?: string +} + +export const useShippingOptionTableQuery = ({ + regionId, + pageSize = 10, + prefix, +}: UseShippingOptionTableQueryProps) => { + const queryObject = useQueryParams( + [ + "offset", + "q", + "order", + "admin_only", + "is_return", + "created_at", + "updated_at", + ], + prefix + ) + + const { offset, order, q, admin_only, is_return, created_at, updated_at } = + queryObject + + const searchParams: AdminGetShippingOptionsParams = { + limit: pageSize, + offset: offset ? Number(offset) : 0, + region_id: regionId, + is_return: is_return ? is_return === "true" : undefined, + admin_only: admin_only ? admin_only === "true" : undefined, + q, + order, + created_at: created_at ? JSON.parse(created_at) : undefined, + updated_at: updated_at ? JSON.parse(updated_at) : undefined, + } + + return { + searchParams, + raw: queryObject, + } +} diff --git a/packages/admin-next/dashboard/src/routes/regions/region-list/components/region-list-table/region-list-table.tsx b/packages/admin-next/dashboard/src/routes/regions/region-list/components/region-list-table/region-list-table.tsx index f425b57ab0..51209128df 100644 --- a/packages/admin-next/dashboard/src/routes/regions/region-list/components/region-list-table/region-list-table.tsx +++ b/packages/admin-next/dashboard/src/routes/regions/region-list/components/region-list-table/region-list-table.tsx @@ -1,64 +1,43 @@ import { PencilSquare, Trash } from "@medusajs/icons" import { Region } from "@medusajs/medusa" -import { - Button, - Container, - Heading, - Table, - Tooltip, - clx, - usePrompt, -} from "@medusajs/ui" -import { - PaginationState, - createColumnHelper, - flexRender, - getCoreRowModel, - useReactTable, -} from "@tanstack/react-table" +import { Button, Container, Heading, usePrompt } from "@medusajs/ui" +import { createColumnHelper } from "@tanstack/react-table" import { useAdminDeleteRegion, useAdminRegions } from "medusa-react" -import { useMemo, useState } from "react" +import { useMemo } from "react" import { useTranslation } from "react-i18next" -import { Link, useNavigate } from "react-router-dom" +import { Link } from "react-router-dom" import { ActionMenu } from "../../../../../components/common/action-menu" -import { LocalizedTablePagination } from "../../../../../components/localization/localized-table-pagination" +import { DataTable } from "../../../../../components/table/data-table" +import { useRegionTableColumns } from "../../../../../hooks/table/columns/use-region-table-columns" +import { useRegionTableFilters } from "../../../../../hooks/table/filters/use-region-table-filters" +import { useRegionTableQuery } from "../../../../../hooks/table/query/use-region-table-query" +import { useDataTable } from "../../../../../hooks/use-data-table" -const PAGE_SIZE = 50 +const PAGE_SIZE = 20 export const RegionListTable = () => { - const navigate = useNavigate() const { t } = useTranslation() - const [{ pageIndex, pageSize }, setPagination] = useState({ - pageIndex: 0, - pageSize: PAGE_SIZE, - }) - - const pagination = useMemo( - () => ({ - pageIndex, - pageSize, - }), - [pageIndex, pageSize] + const { searchParams, raw } = useRegionTableQuery({ pageSize: PAGE_SIZE }) + const { regions, count, isLoading, isError, error } = useAdminRegions( + { + ...searchParams, + }, + { + keepPreviousData: true, + } ) - const { regions, count, isLoading, isError, error } = useAdminRegions({ - limit: PAGE_SIZE, - offset: pageIndex * PAGE_SIZE, - }) - + const filters = useRegionTableFilters() const columns = useColumns() - const table = useReactTable({ + const { table } = useDataTable({ data: regions ?? [], columns, - pageCount: Math.ceil((count ?? 0) / PAGE_SIZE), - state: { - pagination, - }, - onPaginationChange: setPagination, - getCoreRowModel: getCoreRowModel(), - manualPagination: true, + count, + enablePagination: true, + getRowId: (row) => row.id, + pageSize: PAGE_SIZE, }) if (isError) { @@ -66,7 +45,7 @@ export const RegionListTable = () => { } return ( - +
    {t("regions.domain")} @@ -75,59 +54,18 @@ export const RegionListTable = () => {
    - - - {table.getHeaderGroups().map((headerGroup) => { - return ( - - {headerGroup.headers.map((header) => { - return ( - - {flexRender( - header.column.columnDef.header, - header.getContext() - )} - - ) - })} - - ) - })} - - - {table.getRowModel().rows.map((row) => ( - navigate(`/settings/regions/${row.original.id}`)} - > - {row.getVisibleCells().map((cell) => ( - - {flexRender(cell.column.columnDef.cell, cell.getContext())} - - ))} - - ))} - -
    - `${row.original.id}`} + pagination + search + queryObject={raw} />
    ) @@ -187,124 +125,11 @@ const RegionActions = ({ region }: { region: Region }) => { const columnHelper = createColumnHelper() const useColumns = () => { - const { t } = useTranslation() + const base = useRegionTableColumns() return useMemo( () => [ - columnHelper.accessor("name", { - header: t("fields.name"), - cell: (cell) => cell.getValue(), - }), - columnHelper.accessor("countries", { - header: t("fields.countries"), - cell: (cell) => { - const countries = cell.getValue() - - const displayValue = countries - .slice(0, 2) - .map((c) => c.display_name) - .join(", ") - - const additionalCountries = countries - .slice(2) - .map((c) => c.display_name) - - return ( -
    - {displayValue} - {additionalCountries.length > 0 && ( - - {additionalCountries.map((c) => ( -
  • {c}
  • - ))} - - } - > - - {t("general.plusCountMore", { - count: additionalCountries.length, - })} - -
    - )} -
    - ) - }, - }), - columnHelper.accessor("payment_providers", { - header: t("fields.paymentProviders"), - cell: (cell) => { - const providers = cell.getValue() - - const displayValue = providers - .slice(0, 2) - .map((p) => p.id) - .join(", ") - - const additionalProviders = providers.slice(2).map((c) => c.id) - - return ( -
    - {displayValue} - {additionalProviders.length > 0 && ( - - {additionalProviders.map((c) => ( -
  • {c}
  • - ))} - - } - > - - {t("general.plusCountMore", { - count: additionalProviders.length, - })} - -
    - )} -
    - ) - }, - }), - columnHelper.accessor("fulfillment_providers", { - header: t("fields.fulfillmentProviders"), - cell: (cell) => { - const providers = cell.getValue() - - const displayValue = providers - .slice(0, 2) - .map((p) => p.id) - .join(", ") - - const additionalProviders = providers.slice(2).map((c) => c.id) - - return ( -
    - {displayValue} - {additionalProviders.length > 0 && ( - - {additionalProviders.map((c) => ( -
  • {c}
  • - ))} - - } - > - - {t("general.plusCountMore", { - count: additionalProviders.length, - })} - -
    - )} -
    - ) - }, - }), + ...base, columnHelper.display({ id: "actions", cell: ({ row }) => { @@ -312,6 +137,6 @@ const useColumns = () => { }, }), ], - [t] + [base] ) } diff --git a/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-add-products/components/add-products-to-sales-channel-form.tsx b/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-add-products/components/add-products-to-sales-channel-form.tsx index a8444ad838..532a5ee494 100644 --- a/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-add-products/components/add-products-to-sales-channel-form.tsx +++ b/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-add-products/components/add-products-to-sales-channel-form.tsx @@ -1,14 +1,6 @@ import { zodResolver } from "@hookform/resolvers/zod" import { Product, SalesChannel } from "@medusajs/medusa" -import { - Button, - Checkbox, - FocusModal, - Hint, - Table, - Tooltip, - clx, -} from "@medusajs/ui" +import { Button, Checkbox, Hint, Table, Tooltip, clx } from "@medusajs/ui" import { PaginationState, RowSelectionState, @@ -26,7 +18,6 @@ import { useEffect, useMemo, useState } from "react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import * as zod from "zod" -import { Form } from "../../../../components/common/form" import { ProductAvailabilityCell, ProductCollectionCell, @@ -37,13 +28,15 @@ import { import { OrderBy } from "../../../../components/filtering/order-by" import { Query } from "../../../../components/filtering/query" import { LocalizedTablePagination } from "../../../../components/localization/localized-table-pagination" +import { + RouteFocusModal, + useRouteModal, +} from "../../../../components/route-modal" import { useQueryParams } from "../../../../hooks/use-query-params" import { queryClient } from "../../../../lib/medusa" type AddProductsToSalesChannelFormProps = { salesChannel: SalesChannel - subscribe: (state: boolean) => void - onSuccess: () => void } const AddProductsToSalesChannelSchema = zod.object({ @@ -54,10 +47,9 @@ const PAGE_SIZE = 50 export const AddProductsToSalesChannelForm = ({ salesChannel, - subscribe, - onSuccess, }: AddProductsToSalesChannelFormProps) => { const { t } = useTranslation() + const { handleSuccess } = useRouteModal() const form = useForm>({ defaultValues: { @@ -66,13 +58,7 @@ export const AddProductsToSalesChannelForm = ({ resolver: zodResolver(AddProductsToSalesChannelSchema), }) - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty]) + const { setValue } = form const { mutateAsync, isLoading: isMutating } = useAdminAddProductsToSalesChannel(salesChannel.id) @@ -93,15 +79,19 @@ export const AddProductsToSalesChannelForm = ({ const [rowSelection, setRowSelection] = useState({}) useEffect(() => { - form.setValue( + setValue( "product_ids", - Object.keys(rowSelection).filter((k) => rowSelection[k]) + Object.keys(rowSelection).filter((k) => rowSelection[k]), + { + shouldDirty: true, + shouldTouch: true, + } ) - }, [rowSelection]) + }, [rowSelection, setValue]) const params = useQueryParams(["q", "order"]) - const { products, count, isLoading } = useAdminProducts( + const { products, count } = useAdminProducts( { expand: "variants,sales_channels", ...params, @@ -148,36 +138,36 @@ export const AddProductsToSalesChannelForm = ({ * determine if they are added to the sales channel or not. */ queryClient.invalidateQueries(adminProductKeys.lists()) - onSuccess() + handleSuccess() }, } ) }) return ( -
    + - +
    {form.formState.errors.product_ids && ( {form.formState.errors.product_ids.message} )} - + - +
    -
    - + +
    @@ -251,9 +241,9 @@ export const AddProductsToSalesChannelForm = ({ pageSize={PAGE_SIZE} />
    - + - + ) } diff --git a/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-add-products/sales-channel-add-products.tsx b/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-add-products/sales-channel-add-products.tsx index 39a42fabb5..1b28c6d5d3 100644 --- a/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-add-products/sales-channel-add-products.tsx +++ b/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-add-products/sales-channel-add-products.tsx @@ -1,36 +1,21 @@ -import { FocusModal } from "@medusajs/ui" import { useAdminSalesChannel } from "medusa-react" import { useParams } from "react-router-dom" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteFocusModal } from "../../../components/route-modal" import { AddProductsToSalesChannelForm } from "./components" export const SalesChannelAddProducts = () => { const { id } = useParams() - const [open, onOpenChange, subscribe] = useRouteModalState() - const { sales_channel, isLoading, isError, error } = useAdminSalesChannel(id!) - const handleSuccess = () => { - onOpenChange(false, true) - } - if (isError) { throw error } return ( - - - {isLoading || !sales_channel ? ( -
    Loading...
    - ) : ( - - )} -
    -
    + + {!isLoading && sales_channel && ( + + )} + ) } diff --git a/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-create/components/create-sales-channel-form/create-sales-channel-form.tsx b/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-create/components/create-sales-channel-form/create-sales-channel-form.tsx index 086a18cdef..1eb5c31e73 100644 --- a/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-create/components/create-sales-channel-form/create-sales-channel-form.tsx +++ b/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-create/components/create-sales-channel-form/create-sales-channel-form.tsx @@ -1,25 +1,15 @@ import { zodResolver } from "@hookform/resolvers/zod" -import { - Button, - FocusModal, - Heading, - Input, - Switch, - Text, - Textarea, -} from "@medusajs/ui" +import { Button, Heading, Input, Switch, Text, Textarea } from "@medusajs/ui" import { useAdminCreateSalesChannel } from "medusa-react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" -import { useNavigate } from "react-router-dom" import * as zod from "zod" -import { useEffect } from "react" import { Form } from "../../../../../components/common/form" - -type CreateSalesChannelFormProps = { - subscribe: (state: boolean) => void -} +import { + RouteFocusModal, + useRouteModal, +} from "../../../../../components/route-modal" const CreateSalesChannelSchema = zod.object({ name: zod.string().min(1), @@ -27,9 +17,10 @@ const CreateSalesChannelSchema = zod.object({ enabled: zod.boolean(), }) -export const CreateSalesChannelForm = ({ - subscribe, -}: CreateSalesChannelFormProps) => { +export const CreateSalesChannelForm = () => { + const { t } = useTranslation() + const { handleSuccess } = useRouteModal() + const form = useForm>({ defaultValues: { name: "", @@ -40,17 +31,6 @@ export const CreateSalesChannelForm = ({ }) const { mutateAsync, isLoading } = useAdminCreateSalesChannel() - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty]) - - const { t } = useTranslation() - const navigate = useNavigate() - const handleSubmit = form.handleSubmit(async (values) => { await mutateAsync( { @@ -60,31 +40,31 @@ export const CreateSalesChannelForm = ({ }, { onSuccess: ({ sales_channel }) => { - navigate(`../${sales_channel.id}`) + handleSuccess(`../${sales_channel.id}`) }, } ) }) return ( -
    + - +
    - + - +
    -
    - + +
    @@ -153,8 +133,8 @@ export const CreateSalesChannelForm = ({ />
    - + - + ) } diff --git a/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-create/sales-channel-create.tsx b/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-create/sales-channel-create.tsx index 6275c0b84b..d4abcb0126 100644 --- a/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-create/sales-channel-create.tsx +++ b/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-create/sales-channel-create.tsx @@ -1,15 +1,10 @@ -import { FocusModal } from "@medusajs/ui" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteFocusModal } from "../../../components/route-modal" import { CreateSalesChannelForm } from "./components/create-sales-channel-form" export const SalesChannelCreate = () => { - const [open, onOpenChange, subscribe] = useRouteModalState() - return ( - - - - - + + + ) } diff --git a/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-edit/components/edit-sales-channel-form/edit-sales-channel-form.tsx b/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-edit/components/edit-sales-channel-form/edit-sales-channel-form.tsx index 5ccaf1dbd9..af2de9816d 100644 --- a/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-edit/components/edit-sales-channel-form/edit-sales-channel-form.tsx +++ b/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-edit/components/edit-sales-channel-form/edit-sales-channel-form.tsx @@ -1,18 +1,19 @@ import { zodResolver } from "@hookform/resolvers/zod" import { SalesChannel } from "@medusajs/medusa" -import { Button, Drawer, Input, Switch, Textarea } from "@medusajs/ui" +import { Button, Input, Switch, Textarea } from "@medusajs/ui" import { useAdminUpdateSalesChannel } from "medusa-react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import * as zod from "zod" -import { useEffect } from "react" import { Form } from "../../../../../components/common/form" +import { + RouteDrawer, + useRouteModal, +} from "../../../../../components/route-modal" type EditSalesChannelFormProps = { salesChannel: SalesChannel - subscribe: (state: boolean) => void - onSuccess: () => void } const EditSalesChannelSchema = zod.object({ @@ -23,9 +24,10 @@ const EditSalesChannelSchema = zod.object({ export const EditSalesChannelForm = ({ salesChannel, - subscribe, - onSuccess, }: EditSalesChannelFormProps) => { + const { t } = useTranslation() + const { handleSuccess } = useRouteModal() + const form = useForm>({ defaultValues: { name: salesChannel.name, @@ -35,16 +37,6 @@ export const EditSalesChannelForm = ({ resolver: zodResolver(EditSalesChannelSchema), }) - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty]) - - const { t } = useTranslation() - const { mutateAsync, isLoading } = useAdminUpdateSalesChannel(salesChannel.id) const handleSubmit = form.handleSubmit(async (values) => { @@ -56,19 +48,19 @@ export const EditSalesChannelForm = ({ }, { onSuccess: () => { - onSuccess() + handleSuccess() }, } ) }) return ( -
    + - + - - + +
    - + - +
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-edit/sales-channel-edit.tsx b/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-edit/sales-channel-edit.tsx index dfbeeab150..8a0d2be965 100644 --- a/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-edit/sales-channel-edit.tsx +++ b/packages/admin-next/dashboard/src/routes/sales-channels/sales-channel-edit/sales-channel-edit.tsx @@ -1,41 +1,31 @@ -import { Drawer, Heading } from "@medusajs/ui" +import { Heading } from "@medusajs/ui" import { useAdminSalesChannel } from "medusa-react" import { useTranslation } from "react-i18next" import { useParams } from "react-router-dom" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteDrawer } from "../../../components/route-modal" import { EditSalesChannelForm } from "./components/edit-sales-channel-form" export const SalesChannelEdit = () => { const { id } = useParams() const { t } = useTranslation() - const [open, onOpenChange, subscribe] = useRouteModalState() - const { sales_channel, isLoading, isError, error } = useAdminSalesChannel(id!) - const onSuccess = () => { - onOpenChange(false, true) - } + const { sales_channel, isLoading, isError, error } = useAdminSalesChannel(id!) if (isError) { throw error } return ( - - - - - {t("salesChannels.editSalesChannel")} - - - {!isLoading && sales_channel && ( - - )} - - + + + + {t("salesChannels.editSalesChannel")} + + + {!isLoading && sales_channel && ( + + )} + ) } diff --git a/packages/admin-next/dashboard/src/routes/store/store-add-currencies/components/add-currencies-form/add-currencies-form.tsx b/packages/admin-next/dashboard/src/routes/store/store-add-currencies/components/add-currencies-form/add-currencies-form.tsx index e9359eb10e..6576e562f7 100644 --- a/packages/admin-next/dashboard/src/routes/store/store-add-currencies/components/add-currencies-form/add-currencies-form.tsx +++ b/packages/admin-next/dashboard/src/routes/store/store-add-currencies/components/add-currencies-form/add-currencies-form.tsx @@ -3,7 +3,6 @@ import { Badge, Button, Checkbox, - FocusModal, Hint, StatusBadge, Table, @@ -19,11 +18,18 @@ import { useReactTable, } from "@tanstack/react-table" import { useAdminCurrencies, useAdminUpdateStore } from "medusa-react" -import { FormEvent, useMemo, useState } from "react" +import { useEffect, useMemo, useState } from "react" import { useTranslation } from "react-i18next" import * as zod from "zod" + +import { zodResolver } from "@hookform/resolvers/zod" +import { useForm } from "react-hook-form" import { OrderBy } from "../../../../../components/filtering/order-by" import { LocalizedTablePagination } from "../../../../../components/localization/localized-table-pagination" +import { + RouteFocusModal, + useRouteModal, +} from "../../../../../components/route-modal" import { useHandleTableScroll } from "../../../../../hooks/use-handle-table-scroll" import { useQueryParams } from "../../../../../hooks/use-query-params" @@ -38,9 +44,18 @@ const AddCurrenciesSchema = zod.object({ const PAGE_SIZE = 50 export const AddCurrenciesForm = ({ store }: AddCurrenciesFormProps) => { - const [errorMessage, setErrorMessage] = useState<{ - currencies?: string | undefined - }>({}) + const { t } = useTranslation() + const { handleSuccess } = useRouteModal() + + const form = useForm>({ + defaultValues: { + currencies: [], + }, + resolver: zodResolver(AddCurrenciesSchema), + }) + + const { setValue } = form + const [{ pageIndex, pageSize }, setPagination] = useState({ pageIndex: 0, pageSize: PAGE_SIZE, @@ -56,8 +71,16 @@ export const AddCurrenciesForm = ({ store }: AddCurrenciesFormProps) => { const [rowSelection, setRowSelection] = useState({}) + useEffect(() => { + const ids = Object.keys(rowSelection) + setValue("currencies", ids, { + shouldDirty: true, + shouldTouch: true, + }) + }, [rowSelection, setValue]) + const params = useQueryParams(["order"]) - const { currencies, count, isLoading, isError, error } = useAdminCurrencies({ + const { currencies, count, isError, error } = useAdminCurrencies({ limit: PAGE_SIZE, offset: pageIndex * PAGE_SIZE, ...params, @@ -83,152 +106,143 @@ export const AddCurrenciesForm = ({ store }: AddCurrenciesFormProps) => { manualPagination: true, }) - const { t } = useTranslation() - const { mutateAsync, isLoading: isMutating } = useAdminUpdateStore() const { handleScroll, isScrolled, tableContainerRef } = useHandleTableScroll() - const handleSubmit = async (e: FormEvent) => { - e.preventDefault() - - const ids = Object.keys(rowSelection) - - try { - AddCurrenciesSchema.parse({ - currencies: ids, - }) - - setErrorMessage({}) - } catch (err) { - if (err instanceof zod.ZodError) { - setErrorMessage(err.flatten().fieldErrors) - } - - return - } - + const handleSubmit = form.handleSubmit(async (data) => { const currencies = Array.from( - new Set([...ids, ...preSelectedRows]) + new Set([...data.currencies, ...preSelectedRows]) ) as string[] - await mutateAsync({ - currencies, - }) - } + await mutateAsync( + { + currencies, + }, + { + onSuccess: () => { + handleSuccess() + }, + } + ) + }) if (isError) { throw error } return ( -
    - -
    -
    - {errorMessage.currencies && ( - {errorMessage.currencies} - )} -
    -
    - - - - -
    -
    -
    - -
    -
    -
    - -
    -
    -
    - - + + +
    +
    + {form.formState.errors.currencies && ( + + {form.formState.errors.currencies.message} + )} - > - {table.getHeaderGroups().map((headerGroup) => { - return ( +
    +
    + + + + +
    +
    +
    + +
    +
    +
    + +
    +
    +
    +
    + + {table.getHeaderGroups().map((headerGroup) => { + return ( + + {headerGroup.headers.map((header) => { + return ( + + {flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ) + })} + + ) + })} + + + {table.getRowModel().rows.map((row) => ( - {headerGroup.headers.map((header) => { - return ( - - {flexRender( - header.column.columnDef.header, - header.getContext() - )} - - ) - })} + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} + + ))} - ) - })} - - - {table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - ))} - -
    -
    -
    - -
    -
    -
    + ))} + + +
    +
    + +
    +
    + +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/store/store-add-currencies/store-add-currencies.tsx b/packages/admin-next/dashboard/src/routes/store/store-add-currencies/store-add-currencies.tsx index 15aa12dbe4..18559e0c97 100644 --- a/packages/admin-next/dashboard/src/routes/store/store-add-currencies/store-add-currencies.tsx +++ b/packages/admin-next/dashboard/src/routes/store/store-add-currencies/store-add-currencies.tsx @@ -1,42 +1,17 @@ -import { FocusModal } from "@medusajs/ui" import { useAdminStore } from "medusa-react" -import { useEffect, useState } from "react" -import { useNavigate } from "react-router-dom" +import { RouteFocusModal } from "../../../components/route-modal" import { AddCurrenciesForm } from "./components/add-currencies-form/add-currencies-form" export const StoreAddCurrencies = () => { - const [open, setOpen] = useState(false) - const navigate = useNavigate() - const { store, isLoading, isError, error } = useAdminStore() - useEffect(() => { - setOpen(true) - }, []) - - const onOpenChange = (open: boolean) => { - if (!open) { - setTimeout(() => { - navigate(`/settings/store`, { replace: true }) - }, 200) - } - - setOpen(open) - } - if (isError) { throw error } return ( - - - {isLoading || !store ? ( -
    Loading...
    - ) : ( - - )} -
    -
    + + {!isLoading && store && } + ) } diff --git a/packages/admin-next/dashboard/src/routes/store/store-edit/components/edit-store-form/edit-store-form.tsx b/packages/admin-next/dashboard/src/routes/store/store-edit/components/edit-store-form/edit-store-form.tsx index 30322a83f0..a47ee40c78 100644 --- a/packages/admin-next/dashboard/src/routes/store/store-edit/components/edit-store-form/edit-store-form.tsx +++ b/packages/admin-next/dashboard/src/routes/store/store-edit/components/edit-store-form/edit-store-form.tsx @@ -1,15 +1,18 @@ import { zodResolver } from "@hookform/resolvers/zod" import type { Store } from "@medusajs/medusa" -import { Button, Drawer, Input } from "@medusajs/ui" +import { Button, Input } from "@medusajs/ui" import { useAdminUpdateStore } from "medusa-react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import * as zod from "zod" import { Form } from "../../../../../components/common/form" +import { + RouteDrawer, + useRouteModal, +} from "../../../../../components/route-modal" type EditStoreFormProps = { store: Store - onSuccess: () => void } const EditStoreSchema = zod.object({ @@ -22,8 +25,9 @@ const EditStoreSchema = zod.object({ invite_link_template: zod.union([zod.literal(""), zod.string().trim().url()]), }) -export const EditStoreForm = ({ store, onSuccess }: EditStoreFormProps) => { - const { mutateAsync, isLoading } = useAdminUpdateStore() +export const EditStoreForm = ({ store }: EditStoreFormProps) => { + const { t } = useTranslation() + const { handleSuccess } = useRouteModal() const form = useForm>({ defaultValues: { @@ -35,7 +39,7 @@ export const EditStoreForm = ({ store, onSuccess }: EditStoreFormProps) => { resolver: zodResolver(EditStoreSchema), }) - const { t } = useTranslation() + const { mutateAsync, isLoading } = useAdminUpdateStore() const handleSubmit = form.handleSubmit(async (values) => { mutateAsync( @@ -47,16 +51,16 @@ export const EditStoreForm = ({ store, onSuccess }: EditStoreFormProps) => { }, { onSuccess: () => { - onSuccess() + handleSuccess() }, } ) }) return ( -
    + - +
    { )} />
    -
    - + +
    - + - +
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/store/store-edit/store-edit.tsx b/packages/admin-next/dashboard/src/routes/store/store-edit/store-edit.tsx index 313cead0b5..8f9cd33f7d 100644 --- a/packages/admin-next/dashboard/src/routes/store/store-edit/store-edit.tsx +++ b/packages/admin-next/dashboard/src/routes/store/store-edit/store-edit.tsx @@ -1,30 +1,13 @@ -import { Drawer, Heading } from "@medusajs/ui" +import { Heading } from "@medusajs/ui" import { useAdminStore } from "medusa-react" -import { useEffect, useState } from "react" import { useTranslation } from "react-i18next" -import { json, useNavigate } from "react-router-dom" +import { json } from "react-router-dom" +import { RouteDrawer } from "../../../components/route-modal" import { EditStoreForm } from "./components/edit-store-form/edit-store-form" export const StoreEdit = () => { - const [open, setOpen] = useState(false) - const { store, isLoading, isError, error } = useAdminStore() - - const navigate = useNavigate() const { t } = useTranslation() - - useEffect(() => { - setOpen(true) - }, []) - - const onOpenChange = (open: boolean) => { - if (!open) { - setTimeout(() => { - navigate(`/settings/store`, { replace: true }) - }, 200) - } - - setOpen(open) - } + const { store, isLoading, isError, error } = useAdminStore() if (isError) { throw error @@ -35,15 +18,11 @@ export const StoreEdit = () => { } return ( - - - - {t("store.editStore")} - - {store && ( - onOpenChange(false)} /> - )} - - + + + {t("store.editStore")} + + {store && } + ) } diff --git a/packages/admin-next/dashboard/src/routes/users/user-edit/components/edit-user-form/edit-user-form.tsx b/packages/admin-next/dashboard/src/routes/users/user-edit/components/edit-user-form/edit-user-form.tsx index 8a3ef25056..b9f677d805 100644 --- a/packages/admin-next/dashboard/src/routes/users/user-edit/components/edit-user-form/edit-user-form.tsx +++ b/packages/admin-next/dashboard/src/routes/users/user-edit/components/edit-user-form/edit-user-form.tsx @@ -1,17 +1,19 @@ import { zodResolver } from "@hookform/resolvers/zod" import { User } from "@medusajs/medusa" -import { Button, Drawer, Input } from "@medusajs/ui" +import { Button, Input } from "@medusajs/ui" import { useAdminUpdateUser } from "medusa-react" -import { useEffect } from "react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import * as zod from "zod" + import { Form } from "../../../../../components/common/form" +import { + RouteDrawer, + useRouteModal, +} from "../../../../../components/route-modal" type EditUserFormProps = { user: Omit - subscribe: (state: boolean) => void - onSuccessfulSubmit: () => void } const EditUserFormSchema = zod.object({ @@ -19,11 +21,10 @@ const EditUserFormSchema = zod.object({ last_name: zod.string().optional(), }) -export const EditUserForm = ({ - user, - subscribe, - onSuccessfulSubmit, -}: EditUserFormProps) => { +export const EditUserForm = ({ user }: EditUserFormProps) => { + const { t } = useTranslation() + const { handleSuccess } = useRouteModal() + const form = useForm>({ defaultValues: { first_name: user.first_name || "", @@ -32,33 +33,23 @@ export const EditUserForm = ({ resolver: zodResolver(EditUserFormSchema), }) - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty]) - - const { t } = useTranslation() - const { mutateAsync, isLoading } = useAdminUpdateUser(user.id) const handleSubmit = form.handleSubmit(async (values) => { await mutateAsync(values, { onSuccess: () => { - onSuccessfulSubmit() + handleSuccess() }, }) }) return ( -
    + - + - - + +
    - + - +
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/users/user-edit/user-edit.tsx b/packages/admin-next/dashboard/src/routes/users/user-edit/user-edit.tsx index 1ff3bed6b8..8d51a1f0b7 100644 --- a/packages/admin-next/dashboard/src/routes/users/user-edit/user-edit.tsx +++ b/packages/admin-next/dashboard/src/routes/users/user-edit/user-edit.tsx @@ -1,39 +1,25 @@ -import { Drawer, Heading } from "@medusajs/ui" +import { Heading } from "@medusajs/ui" import { useAdminUser } from "medusa-react" import { useTranslation } from "react-i18next" import { useParams } from "react-router-dom" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteDrawer } from "../../../components/route-modal" import { EditUserForm } from "./components/edit-user-form" export const UserEdit = () => { - const [open, onOpenChange, subscribe] = useRouteModalState() - const { t } = useTranslation() const { id } = useParams() const { user, isLoading, isError, error } = useAdminUser(id!) - const handleSuccessfulSubmit = () => { - onOpenChange(false, true) - } - if (isError) { throw error } return ( - - - - {t("users.editUser")} - - {!isLoading && user && ( - - )} - - + + + {t("users.editUser")} + + {!isLoading && user && } + ) } diff --git a/packages/admin-next/dashboard/src/routes/users/user-invite/components/invite-user-form/invite-user-form.tsx b/packages/admin-next/dashboard/src/routes/users/user-invite/components/invite-user-form/invite-user-form.tsx index fb32519298..da1df79768 100644 --- a/packages/admin-next/dashboard/src/routes/users/user-invite/components/invite-user-form/invite-user-form.tsx +++ b/packages/admin-next/dashboard/src/routes/users/user-invite/components/invite-user-form/invite-user-form.tsx @@ -4,7 +4,6 @@ import { Invite } from "@medusajs/medusa" import { Button, Container, - FocusModal, Heading, Input, Select, @@ -30,7 +29,7 @@ import { useAdminResendInvite, useAdminStore, } from "medusa-react" -import { useEffect, useMemo } from "react" +import { useMemo } from "react" import { useForm } from "react-hook-form" import { Trans, useTranslation } from "react-i18next" import * as zod from "zod" @@ -38,10 +37,7 @@ import { ActionMenu } from "../../../../../components/common/action-menu" import { NoRecords } from "../../../../../components/common/empty-table-content" import { Form } from "../../../../../components/common/form" import { LocalizedTablePagination } from "../../../../../components/localization/localized-table-pagination" - -type InviteUserFormProps = { - subscribe: (state: boolean) => void -} +import { RouteFocusModal } from "../../../../../components/route-modal" enum UserRole { MEMBER = "member", @@ -56,7 +52,9 @@ const InviteUserSchema = zod.object({ const PAGE_SIZE = 10 -export const InviteUserForm = ({ subscribe }: InviteUserFormProps) => { +export const InviteUserForm = () => { + const { t } = useTranslation() + const form = useForm>({ defaultValues: { user: "", @@ -64,15 +62,6 @@ export const InviteUserForm = ({ subscribe }: InviteUserFormProps) => { }, resolver: zodResolver(InviteUserSchema), }) - const { mutateAsync, isLoading: isMutating } = useAdminCreateInvite() - - const { - formState: { isDirty }, - } = form - - useEffect(() => { - subscribe(isDirty) - }, [isDirty, subscribe]) const { invites, isLoading, isError, error } = useAdminInvites() const count = invites?.length ?? 0 @@ -89,7 +78,7 @@ export const InviteUserForm = ({ subscribe }: InviteUserFormProps) => { getPaginationRowModel: getPaginationRowModel(), }) - const { t } = useTranslation() + const { mutateAsync, isLoading: isMutating } = useAdminCreateInvite() const handleSubmit = form.handleSubmit(async (values) => { await mutateAsync( @@ -110,13 +99,13 @@ export const InviteUserForm = ({ subscribe }: InviteUserFormProps) => { } return ( -
    + - - + +
    @@ -249,9 +238,9 @@ export const InviteUserForm = ({ subscribe }: InviteUserFormProps) => {
    -
    + - +
    ) } diff --git a/packages/admin-next/dashboard/src/routes/users/user-invite/user-invite.tsx b/packages/admin-next/dashboard/src/routes/users/user-invite/user-invite.tsx index d8f0f2d485..23432b8d22 100644 --- a/packages/admin-next/dashboard/src/routes/users/user-invite/user-invite.tsx +++ b/packages/admin-next/dashboard/src/routes/users/user-invite/user-invite.tsx @@ -1,15 +1,10 @@ -import { FocusModal } from "@medusajs/ui" -import { useRouteModalState } from "../../../hooks/use-route-modal-state" +import { RouteFocusModal } from "../../../components/route-modal" import { InviteUserForm } from "./components/invite-user-form/invite-user-form" export const UserInvite = () => { - const [open, onOpenChange, subscribe] = useRouteModalState() - return ( - - - - - + + + ) }