From 4a2c6e20ce456b27dad38fecce5d526d2f7eb2b4 Mon Sep 17 00:00:00 2001 From: Alexander Polyankin <alexander.polyankin@metabase.com> Date: Thu, 3 Nov 2022 18:48:46 +0200 Subject: [PATCH] Migrate UserInviteForm to formik (#26216) --- .../DatabaseStep/DatabaseStep.styled.tsx | 6 -- .../components/DatabaseStep/DatabaseStep.tsx | 40 ++------ .../DatabaseStep/DatabaseStep.unit.spec.tsx | 5 - .../InviteUserForm/InviteUserForm.styled.tsx | 10 ++ .../InviteUserForm/InviteUserForm.tsx | 95 +++++++++++++++++++ .../setup/components/InviteUserForm/index.ts | 1 + 6 files changed, 112 insertions(+), 45 deletions(-) create mode 100644 frontend/src/metabase/setup/components/InviteUserForm/InviteUserForm.styled.tsx create mode 100644 frontend/src/metabase/setup/components/InviteUserForm/InviteUserForm.tsx create mode 100644 frontend/src/metabase/setup/components/InviteUserForm/index.ts diff --git a/frontend/src/metabase/setup/components/DatabaseStep/DatabaseStep.styled.tsx b/frontend/src/metabase/setup/components/DatabaseStep/DatabaseStep.styled.tsx index bcc4259d617..07a66838924 100644 --- a/frontend/src/metabase/setup/components/DatabaseStep/DatabaseStep.styled.tsx +++ b/frontend/src/metabase/setup/components/DatabaseStep/DatabaseStep.styled.tsx @@ -24,12 +24,6 @@ export const StepDescription = styled.div` color: ${color("text-medium")}; `; -export const StepFormGroup = styled.div` - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 1rem; -`; - export const FormActions = styled.div` display: flex; align-items: center; diff --git a/frontend/src/metabase/setup/components/DatabaseStep/DatabaseStep.tsx b/frontend/src/metabase/setup/components/DatabaseStep/DatabaseStep.tsx index 9d5d7363c52..f15df33bcb2 100644 --- a/frontend/src/metabase/setup/components/DatabaseStep/DatabaseStep.tsx +++ b/frontend/src/metabase/setup/components/DatabaseStep/DatabaseStep.tsx @@ -3,17 +3,16 @@ import { t } from "ttag"; import _ from "underscore"; import { updateIn } from "icepick"; import Button from "metabase/core/components/Button"; -import Users from "metabase/entities/users"; import Databases from "metabase/entities/databases"; import DriverWarning from "metabase/containers/DriverWarning"; import { DatabaseInfo, InviteInfo, UserInfo } from "metabase-types/store"; import ActiveStep from "../ActiveStep"; import InactiveStep from "../InvactiveStep"; +import InviteUserForm from "../InviteUserForm"; import SetupSection from "../SetupSection"; import { StepActions, StepDescription, - StepFormGroup, StepButton, FormActions, } from "./DatabaseStep.styled"; @@ -87,7 +86,11 @@ const DatabaseStep = ({ title={t`Need help connecting to your data?`} description={t`Invite a teammate. We’ll make them an admin so they can configure your database. You can always change this later on.`} > - <InviteForm user={user} invite={invite} onSubmit={onInviteSubmit} /> + <InviteUserForm + user={user} + invite={invite} + onSubmit={onInviteSubmit} + /> </SetupSection> )} </ActiveStep> @@ -168,37 +171,6 @@ const DatabaseForm = ({ ); }; -interface InviteFormProps { - user?: UserInfo; - invite?: InviteInfo; - onSubmit: (invite: InviteInfo) => void; -} - -const InviteForm = ({ - user, - invite, - onSubmit, -}: InviteFormProps): JSX.Element => { - return ( - <Users.Form - form={Users.forms.setup_invite(user)} - user={invite} - onSubmit={onSubmit} - > - {({ Form, FormField, FormFooter }: FormProps) => ( - <Form> - <StepFormGroup> - <FormField name="first_name" /> - <FormField name="last_name" /> - </StepFormGroup> - <FormField name="email" /> - <FormFooter submitTitle={t`Send invitation`} /> - </Form> - )} - </Users.Form> - ); -}; - const getStepTitle = ( database: DatabaseInfo | undefined, invite: InviteInfo | undefined, diff --git a/frontend/src/metabase/setup/components/DatabaseStep/DatabaseStep.unit.spec.tsx b/frontend/src/metabase/setup/components/DatabaseStep/DatabaseStep.unit.spec.tsx index d1286bb37ef..0d7e64341d3 100644 --- a/frontend/src/metabase/setup/components/DatabaseStep/DatabaseStep.unit.spec.tsx +++ b/frontend/src/metabase/setup/components/DatabaseStep/DatabaseStep.unit.spec.tsx @@ -10,11 +10,6 @@ jest.mock("metabase/entities/databases", () => ({ Form: ComponentMock, })); -jest.mock("metabase/entities/users", () => ({ - forms: { setup_invite: jest.fn() }, - Form: ComponentMock, -})); - jest.mock("metabase/containers/DriverWarning", () => ComponentMock); describe("DatabaseStep", () => { diff --git a/frontend/src/metabase/setup/components/InviteUserForm/InviteUserForm.styled.tsx b/frontend/src/metabase/setup/components/InviteUserForm/InviteUserForm.styled.tsx new file mode 100644 index 00000000000..0847108feb7 --- /dev/null +++ b/frontend/src/metabase/setup/components/InviteUserForm/InviteUserForm.styled.tsx @@ -0,0 +1,10 @@ +import styled from "@emotion/styled"; +import { breakpointMinSmall } from "metabase/styled-components/theme"; + +export const UserFieldGroup = styled.div` + ${breakpointMinSmall} { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 1rem; + } +`; diff --git a/frontend/src/metabase/setup/components/InviteUserForm/InviteUserForm.tsx b/frontend/src/metabase/setup/components/InviteUserForm/InviteUserForm.tsx new file mode 100644 index 00000000000..d337c197ed5 --- /dev/null +++ b/frontend/src/metabase/setup/components/InviteUserForm/InviteUserForm.tsx @@ -0,0 +1,95 @@ +import React, { useCallback, useMemo } from "react"; +import { t } from "ttag"; +import * as Yup from "yup"; +import Form from "metabase/core/components/Form"; +import FormProvider from "metabase/core/components/FormProvider"; +import FormInput from "metabase/core/components/FormInput"; +import FormSubmitButton from "metabase/core/components/FormSubmitButton"; +import { InviteInfo, UserInfo } from "metabase-types/store"; +import { UserFieldGroup } from "./InviteUserForm.styled"; + +const InviteUserSchema = Yup.object({ + first_name: Yup.string().max(100, t`must be 100 characters or less`), + last_name: Yup.string().max(100, t`must be 100 characters or less`), + email: Yup.string() + .required(t`required`) + .email(t`must be a valid email address`) + .notOneOf( + [Yup.ref("$email")], + t`must be different from the email address you used in setup`, + ), +}); + +interface InviteUserFormProps { + user?: UserInfo; + invite?: InviteInfo; + onSubmit: (invite: InviteInfo) => void; +} + +const InviteUserForm = ({ + user, + invite, + onSubmit, +}: InviteUserFormProps): JSX.Element => { + const initialValues = useMemo(() => { + return getInitialValues(invite); + }, [invite]); + + const handleSubmit = useCallback( + (values: InviteInfo) => onSubmit(getSubmitValues(values)), + [onSubmit], + ); + + return ( + <FormProvider + initialValues={initialValues} + validationSchema={InviteUserSchema} + validationContext={user} + onSubmit={handleSubmit} + > + <Form> + <UserFieldGroup> + <FormInput + name="first_name" + title={t`First name`} + placeholder={t`Johnny`} + autoFocus + fullWidth + /> + <FormInput + name="last_name" + title={t`Last name`} + placeholder={t`Appleseed`} + fullWidth + /> + </UserFieldGroup> + <FormInput + name="email" + title={t`Email`} + placeholder={"nicetoseeyou@email.com"} + fullWidth + /> + <FormSubmitButton title={`Send invitation`} primary /> + </Form> + </FormProvider> + ); +}; + +const getInitialValues = (invite?: InviteInfo): InviteInfo => { + return { + email: "", + ...invite, + first_name: invite?.first_name || "", + last_name: invite?.last_name || "", + }; +}; + +const getSubmitValues = (invite: InviteInfo): InviteInfo => { + return { + ...invite, + first_name: invite.first_name || null, + last_name: invite.last_name || null, + }; +}; + +export default InviteUserForm; diff --git a/frontend/src/metabase/setup/components/InviteUserForm/index.ts b/frontend/src/metabase/setup/components/InviteUserForm/index.ts new file mode 100644 index 00000000000..acf49331c96 --- /dev/null +++ b/frontend/src/metabase/setup/components/InviteUserForm/index.ts @@ -0,0 +1 @@ +export { default } from "./InviteUserForm"; -- GitLab