SingleInputForm.tsx 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import { FlexWrapper } from "@ente/shared/components/Container";
  2. import ShowHidePassword from "@ente/shared/components/Form/ShowHidePassword";
  3. import { Button, FormHelperText } from "@mui/material";
  4. import TextField from "@mui/material/TextField";
  5. import { Formik, FormikHelpers, FormikState } from "formik";
  6. import { t } from "i18next";
  7. import React, { useMemo, useState } from "react";
  8. import * as Yup from "yup";
  9. import SubmitButton from "./SubmitButton";
  10. interface formValues {
  11. inputValue: string;
  12. }
  13. export interface SingleInputFormProps {
  14. callback: (
  15. inputValue: string,
  16. setFieldError: (errorMessage: string) => void,
  17. resetForm: (nextState?: Partial<FormikState<formValues>>) => void,
  18. ) => Promise<void>;
  19. fieldType: "text" | "email" | "password";
  20. placeholder: string;
  21. buttonText: string;
  22. submitButtonProps?: any;
  23. initialValue?: string;
  24. secondaryButtonAction?: () => void;
  25. disableAutoFocus?: boolean;
  26. hiddenPreInput?: any;
  27. caption?: any;
  28. hiddenPostInput?: any;
  29. autoComplete?: string;
  30. blockButton?: boolean;
  31. hiddenLabel?: boolean;
  32. disableAutoComplete?: boolean;
  33. }
  34. export default function SingleInputForm(props: SingleInputFormProps) {
  35. const { submitButtonProps } = props;
  36. const { sx: buttonSx, ...restSubmitButtonProps } = submitButtonProps ?? {};
  37. const [loading, SetLoading] = useState(false);
  38. const [showPassword, setShowPassword] = useState(false);
  39. const submitForm = async (
  40. values: formValues,
  41. { setFieldError, resetForm }: FormikHelpers<formValues>,
  42. ) => {
  43. SetLoading(true);
  44. await props.callback(
  45. values.inputValue,
  46. (message) => setFieldError("inputValue", message),
  47. resetForm,
  48. );
  49. SetLoading(false);
  50. };
  51. const handleClickShowPassword = () => {
  52. setShowPassword(!showPassword);
  53. };
  54. const handleMouseDownPassword = (
  55. event: React.MouseEvent<HTMLButtonElement>,
  56. ) => {
  57. event.preventDefault();
  58. };
  59. const validationSchema = useMemo(() => {
  60. switch (props.fieldType) {
  61. case "text":
  62. return Yup.object().shape({
  63. inputValue: Yup.string().required(t("REQUIRED")),
  64. });
  65. case "password":
  66. return Yup.object().shape({
  67. inputValue: Yup.string().required(t("REQUIRED")),
  68. });
  69. case "email":
  70. return Yup.object().shape({
  71. inputValue: Yup.string()
  72. .email(t("EMAIL_ERROR"))
  73. .required(t("REQUIRED")),
  74. });
  75. }
  76. }, [props.fieldType]);
  77. return (
  78. <Formik<formValues>
  79. initialValues={{ inputValue: props.initialValue ?? "" }}
  80. onSubmit={submitForm}
  81. validationSchema={validationSchema}
  82. validateOnChange={false}
  83. validateOnBlur={false}
  84. >
  85. {({ values, errors, handleChange, handleSubmit }) => (
  86. <form noValidate onSubmit={handleSubmit}>
  87. {props.hiddenPreInput}
  88. <TextField
  89. hiddenLabel={props.hiddenLabel}
  90. variant="filled"
  91. fullWidth
  92. type={showPassword ? "text" : props.fieldType}
  93. id={props.fieldType}
  94. name={props.fieldType}
  95. {...(props.hiddenLabel
  96. ? { placeholder: props.placeholder }
  97. : { label: props.placeholder })}
  98. value={values.inputValue}
  99. onChange={handleChange("inputValue")}
  100. error={Boolean(errors.inputValue)}
  101. helperText={errors.inputValue}
  102. disabled={loading}
  103. autoFocus={!props.disableAutoFocus}
  104. autoComplete={props.autoComplete}
  105. InputProps={{
  106. autoComplete:
  107. props.disableAutoComplete ||
  108. props.fieldType === "password"
  109. ? "off"
  110. : "on",
  111. endAdornment: props.fieldType === "password" && (
  112. <ShowHidePassword
  113. showPassword={showPassword}
  114. handleClickShowPassword={
  115. handleClickShowPassword
  116. }
  117. handleMouseDownPassword={
  118. handleMouseDownPassword
  119. }
  120. />
  121. ),
  122. }}
  123. />
  124. <FormHelperText
  125. sx={{
  126. position: "relative",
  127. top: errors.inputValue ? "-22px" : "0",
  128. float: "right",
  129. padding: "0 8px",
  130. }}
  131. >
  132. {props.caption}
  133. </FormHelperText>
  134. {props.hiddenPostInput}
  135. <FlexWrapper
  136. justifyContent={"flex-end"}
  137. flexWrap={props.blockButton ? "wrap-reverse" : "nowrap"}
  138. >
  139. {props.secondaryButtonAction && (
  140. <Button
  141. onClick={props.secondaryButtonAction}
  142. size="large"
  143. color="secondary"
  144. sx={{
  145. "&&&": {
  146. mt: !props.blockButton ? 2 : 0.5,
  147. mb: !props.blockButton ? 4 : 0,
  148. mr: !props.blockButton ? 1 : 0,
  149. ...buttonSx,
  150. },
  151. }}
  152. {...restSubmitButtonProps}
  153. >
  154. {t("CANCEL")}
  155. </Button>
  156. )}
  157. <SubmitButton
  158. sx={{
  159. "&&&": {
  160. mt: 2,
  161. ...buttonSx,
  162. },
  163. }}
  164. buttonText={props.buttonText}
  165. loading={loading}
  166. {...restSubmitButtonProps}
  167. />
  168. </FlexWrapper>
  169. </form>
  170. )}
  171. </Formik>
  172. );
  173. }