feat(admin-sdk,admin-bundler,admin-shared,medusa): Restructure admin packages (#8988)
**What** - Renames /admin-next -> /admin - Renames @medusajs/admin-sdk -> @medusajs/admin-bundler - Creates a new package called @medusajs/admin-sdk that will hold all tooling relevant to creating admin extensions. This is currently `defineRouteConfig` and `defineWidgetConfig`, but will eventually also export methods for adding custom fields, register translation, etc. - cc: @shahednasser we should update the examples in the docs so these functions are imported from `@medusajs/admin-sdk`. People will also need to install the package in their project, as it's no longer a transient dependency. - cc: @olivermrbl we might want to publish a changelog when this is merged, as it is a breaking change, and will require people to import the `defineXConfig` from the new package instead of `@medusajs/admin-shared`. - Updates CODEOWNERS so /admin packages does not require a review from the UI team.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
export * from "./route-modal-form"
|
||||
@@ -0,0 +1,88 @@
|
||||
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 RouteModalFormProps<TFieldValues extends FieldValues> = PropsWithChildren<{
|
||||
form: UseFormReturn<TFieldValues>
|
||||
blockSearch?: boolean
|
||||
onClose?: (isSubmitSuccessful: boolean) => void
|
||||
}>
|
||||
|
||||
export const RouteModalForm = <TFieldValues extends FieldValues = any>({
|
||||
form,
|
||||
blockSearch = false,
|
||||
children,
|
||||
onClose,
|
||||
}: RouteModalFormProps<TFieldValues>) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const {
|
||||
formState: { isDirty },
|
||||
} = form
|
||||
|
||||
const blocker = useBlocker(({ currentLocation, nextLocation }) => {
|
||||
const { isSubmitSuccessful } = nextLocation.state || {}
|
||||
|
||||
if (isSubmitSuccessful) {
|
||||
onClose?.(true)
|
||||
return false
|
||||
}
|
||||
|
||||
const isPathChanged = currentLocation.pathname !== nextLocation.pathname
|
||||
const isSearchChanged = currentLocation.search !== nextLocation.search
|
||||
|
||||
if (blockSearch) {
|
||||
const ret = isDirty && (isPathChanged || isSearchChanged)
|
||||
|
||||
if (!ret) {
|
||||
onClose?.(isSubmitSuccessful)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
const ret = isDirty && isPathChanged
|
||||
|
||||
if (!ret) {
|
||||
onClose?.(isSubmitSuccessful)
|
||||
}
|
||||
|
||||
return ret
|
||||
})
|
||||
|
||||
const handleCancel = () => {
|
||||
blocker?.reset?.()
|
||||
}
|
||||
|
||||
const handleContinue = () => {
|
||||
blocker?.proceed?.()
|
||||
onClose?.(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
{children}
|
||||
<Prompt open={blocker.state === "blocked"} variant="confirmation">
|
||||
<Prompt.Content>
|
||||
<Prompt.Header>
|
||||
<Prompt.Title>{t("general.unsavedChangesTitle")}</Prompt.Title>
|
||||
<Prompt.Description>
|
||||
{t("general.unsavedChangesDescription")}
|
||||
</Prompt.Description>
|
||||
</Prompt.Header>
|
||||
<Prompt.Footer>
|
||||
<Prompt.Cancel onClick={handleCancel} type="button">
|
||||
{t("actions.cancel")}
|
||||
</Prompt.Cancel>
|
||||
<Prompt.Action onClick={handleContinue} type="button">
|
||||
{t("actions.continue")}
|
||||
</Prompt.Action>
|
||||
</Prompt.Footer>
|
||||
</Prompt.Content>
|
||||
</Prompt>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user