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