From 1f203774cb0da20b939d25980691386386830627 Mon Sep 17 00:00:00 2001 From: Kasper Fabricius Kristensen <45367945+kasperkristensen@users.noreply.github.com> Date: Thu, 6 Jun 2024 10:09:38 +0200 Subject: [PATCH] feat(dashboard): SwitchBox component (#7607) **What** - In the latest design changes, the Switch component needs to be wrapped in a container with a label and description. It doesn't make sense to add this "variant" to `@medusajs/ui`, so I have created a local component that we can use every time the design calls for this setup, to avoid re-implementing it multiple times, and the design being inconsistent across usages. - Updates the Product domain forms to use the component. There are other places that needs to be updated to use it, but we can tackle those in our clean up tasks. I have checked with Ludvig and this design should be used everywhere we previously had the design shown in the first image. image image --- .../src/components/common/switch-box/index.ts | 1 + .../common/switch-box/switch-box.tsx | 70 +++++++++++++++++++ ...product-create-details-variant-section.tsx | 54 +++++--------- ...roduct-create-details-organize-section.tsx | 40 +++-------- .../product-create-organize-form.tsx | 10 +-- .../edit-product-form/edit-product-form.tsx | 55 +++------------ 6 files changed, 107 insertions(+), 123 deletions(-) create mode 100644 packages/admin-next/dashboard/src/components/common/switch-box/index.ts create mode 100644 packages/admin-next/dashboard/src/components/common/switch-box/switch-box.tsx diff --git a/packages/admin-next/dashboard/src/components/common/switch-box/index.ts b/packages/admin-next/dashboard/src/components/common/switch-box/index.ts new file mode 100644 index 0000000000..c245e8b7ad --- /dev/null +++ b/packages/admin-next/dashboard/src/components/common/switch-box/index.ts @@ -0,0 +1 @@ +export * from "./switch-box" diff --git a/packages/admin-next/dashboard/src/components/common/switch-box/switch-box.tsx b/packages/admin-next/dashboard/src/components/common/switch-box/switch-box.tsx new file mode 100644 index 0000000000..856753c599 --- /dev/null +++ b/packages/admin-next/dashboard/src/components/common/switch-box/switch-box.tsx @@ -0,0 +1,70 @@ +import { Switch } from "@medusajs/ui" +import { ReactNode } from "react" +import { ControllerProps, FieldPath, FieldValues } from "react-hook-form" + +import { Form } from "../../common/form" + +interface HeadlessControllerProps< + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath +> extends Omit, "render"> {} + +interface SwitchBoxProps< + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath +> extends HeadlessControllerProps{ + label: string + description: string + optional?: boolean + tooltip?: ReactNode + /** + * Callback for performing additional actions when the checked state changes. + * This does not intercept the form control, it is only used for injecting side-effects. + */ + onCheckedChange?: (checked: boolean) => void +} + +/** + * Wrapper for the Switch component to be used with `react-hook-form`. + * + * Use this component whenever a design calls for wrapping the Switch component + * in a container with a label and description. + */ +export const SwitchBox = < + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath +>({ + label, + description, + optional = false, + tooltip, + onCheckedChange, + ...props +}: SwitchBoxProps) => { + return ( + { + return ( + +
+ + { + onCheckedChange?.(e) + onChange(e) + }} /> + +
+ + {label} + + {description} +
+
+ +
+ ) + }} + /> + ) +} \ No newline at end of file diff --git a/packages/admin-next/dashboard/src/routes/products/product-create/components/product-create-details-form/components/product-create-details-variant-section/product-create-details-variant-section.tsx b/packages/admin-next/dashboard/src/routes/products/product-create/components/product-create-details-form/components/product-create-details-variant-section/product-create-details-variant-section.tsx index b7c026fcb6..97e0caba78 100644 --- a/packages/admin-next/dashboard/src/routes/products/product-create/components/product-create-details-form/components/product-create-details-variant-section/product-create-details-variant-section.tsx +++ b/packages/admin-next/dashboard/src/routes/products/product-create/components/product-create-details-form/components/product-create-details-variant-section/product-create-details-variant-section.tsx @@ -23,6 +23,7 @@ import { useTranslation } from "react-i18next" import { Form } from "../../../../../../../components/common/form" import { SortableList } from "../../../../../../../components/common/sortable-list" +import { SwitchBox } from "../../../../../../../components/common/switch-box" import { ChipInput } from "../../../../../../../components/inputs/chip-input" import { ProductCreateSchemaType } from "../../../../types" import { decorateVariantsWithDefaultValues } from "../../../../utils" @@ -285,46 +286,23 @@ export const ProductCreateVariantsSection = ({ return (
{t("products.create.variants.header")} - { - return ( - -
- - { - if (checked) { - form.setValue("options", [ - { - title: "", - values: [], - }, - ]) - form.setValue("variants", []) - } else { - createDefaultOptionAndVariant() - } - - onChange(!!checked) - }} - {...field} - className="mt-1" - /> - -
- - {t("products.create.variants.subHeadingTitle")} - - - {t("products.create.variants.subHeadingDescription")} - -
-
-
- ) + label={t("products.create.variants.subHeadingTitle")} + description={t("products.create.variants.subHeadingDescription")} + onCheckedChange={(checked) => { + if (checked) { + form.setValue("options", [ + { + title: "", + values: [], + }, + ]) + form.setValue("variants", []) + } else { + createDefaultOptionAndVariant() + } }} /> {watchedAreVariantsEnabled && ( diff --git a/packages/admin-next/dashboard/src/routes/products/product-create/components/product-create-organize-form/components/product-create-organize-section/product-create-details-organize-section.tsx b/packages/admin-next/dashboard/src/routes/products/product-create/components/product-create-organize-form/components/product-create-organize-section/product-create-details-organize-section.tsx index ff6c5f02af..96efdcae6f 100644 --- a/packages/admin-next/dashboard/src/routes/products/product-create/components/product-create-organize-form/components/product-create-organize-section/product-create-details-organize-section.tsx +++ b/packages/admin-next/dashboard/src/routes/products/product-create/components/product-create-organize-form/components/product-create-organize-section/product-create-details-organize-section.tsx @@ -1,9 +1,10 @@ -import { Button, Heading, Switch } from "@medusajs/ui" +import { Button, Heading } from "@medusajs/ui" import { UseFormReturn, useFieldArray } from "react-hook-form" import { Trans, useTranslation } from "react-i18next" import { ChipGroup } from "../../../../../../../components/common/chip-group" import { Form } from "../../../../../../../components/common/form" +import { SwitchBox } from "../../../../../../../components/common/switch-box" import { Combobox } from "../../../../../../../components/inputs/combobox" import { useComboboxData } from "../../../../../../../hooks/use-combobox-data" import { client, sdk } from "../../../../../../../lib/client" @@ -64,36 +65,13 @@ export const ProductCreateOrganizationSection = ({ return (
{t("products.organization.header")} -
- { - return ( - -
- - - -
- - {t("products.fields.discountable.label")} - - - {t("products.fields.discountable.hint")} - -
-
-
- ) - }} - /> -
+
{
- {/*TODO: WHERE DO WE SET PRODUCT ATTRIBUTES? -> the plan is to moved that to Inventory UI */} - {/**/} - {/**/} + {/* TODO: WHERE DO WE SET PRODUCT ATTRIBUTES? -> the plan is to moved that to Inventory UI */} + {/* */} + {/* */}
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 51ff8cebd5..b80fc8ce91 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,12 +1,13 @@ import { zodResolver } from "@hookform/resolvers/zod" import { Product } from "@medusajs/medusa" import { ProductStatus } from "@medusajs/types" -import { Button, Input, Select, Switch, Text, Textarea } from "@medusajs/ui" +import { Button, Input, Select, Text, Textarea } from "@medusajs/ui" import { useForm } from "react-hook-form" -import { Trans, useTranslation } from "react-i18next" +import { useTranslation } from "react-i18next" import * as zod from "zod" import { Form } from "../../../../../components/common/form" +import { SwitchBox } from "../../../../../components/common/switch-box" import { RouteDrawer, useRouteModal, @@ -74,8 +75,8 @@ export const EditProductForm = ({ product }: EditProductFormProps) => { onSubmit={handleSubmit} className="flex flex-1 flex-col overflow-hidden" > - -
+ +
{ ) }} /> - - ]} - /> - -
-
{