Preview:
import React, { useEffect, useState, useMemo, useContext } from 'react';
import styled from 'styled-components/macro';
import * as yup from 'yup';
import { yupResolver } from '@hookform/resolvers/yup';
import { useForm, Controller, SubmitHandler } from 'react-hook-form';
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
import { useDispatch, useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';

import FormInput from 'components/FormInput';
import CustomCheckbox from 'components/CustomCheckbox';
import { getUser } from 'redux/reducers/user';
import CustomModalContext from 'contexts/CustomModalContext';
import { useActions } from 'hooks/useActions';
import LearningPackageBody from 'pages/Signup/SelectLearningPackages/LearningPackageBody';
import instance from 'api/axiosInstance';
import { getFormattedSuggestYear } from 'utils/url';
import { formatDateForRegistration } from 'utils/Date';

export interface IStudentAccountForm {
  firstName: string;
  lastName: string;
  userName: string;
  password: string;
  dateOfBirth?: Date;
  email: string;
  isStudentFourYear?: boolean;
  grateStudent?: string;
}

type Props = {
  isModal?: boolean;
};

const grateStudentArr = [
  {
    value: '3',
    title: 'Year 3',
  },
  {
    value: '4',
    title: 'Year 4',
  },
  {
    value: '5',
    title: 'Year 5',
  },
  {
    value: '6',
    title: 'Year 6',
  },
];

const schema = yup.object({
  firstName: yup.string().required('First Name is a required field'),
  lastName: yup.string().required('Last Name is a required field'),
  userName: yup.string().required('User Name is a required field'),
  password: yup.string().required('Password is a required field'),
  dateOfBirth: yup.string().nullable().required('Date of Birth is a required field'),
  email: yup.string().email(),
  isStudentFourYear: yup.boolean(),
  grateStudent: yup.string(),
});

const CreateStudentModal: React.FC<Props> = ({ isModal }) => {
  const { setStudentAccount } = useActions();
  const customModalContext = useContext(CustomModalContext);
  const { hideModal, setActiveView } = customModalContext;
  const history = useHistory();
  const dispatch = useDispatch();
  const currentUser = useSelector(getUser);
  const studentWhenAppClosed = JSON.parse(localStorage.getItem('studentAccount') || '{}');
  const memoizedIsCurUserIdEqualsStudentId = useMemo(
    () => currentUser.userId === studentWhenAppClosed?.parentId,
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [currentUser, studentWhenAppClosed],
  );

  const [studentYear, setStudentYear] = useState('');

  const {
    register,
    formState: { errors },
    control,
    handleSubmit,
    watch,
    setValue,
  } = useForm<IStudentAccountForm>({
    defaultValues: {
      firstName: Boolean(studentWhenAppClosed?.firstName) ? studentWhenAppClosed.firstName : '',
      lastName: Boolean(studentWhenAppClosed?.lastName) ? studentWhenAppClosed.lastName : '',
      userName: Boolean(studentWhenAppClosed?.userName) ? studentWhenAppClosed.userName : '',
      password: Boolean(studentWhenAppClosed?.password) ? studentWhenAppClosed.password : '',
      email: Boolean(studentWhenAppClosed?.email) ? studentWhenAppClosed.email : '',
      isStudentFourYear: studentWhenAppClosed?.isStudentFourYear ? studentWhenAppClosed.isStudentFourYear : true,
      grateStudent: Boolean(studentWhenAppClosed?.grateStudent) ? studentWhenAppClosed.grateStudent : '',
    },
    resolver: yupResolver(schema),
  });

  const newDate = watch('dateOfBirth');
  const isStudentFourYear = watch('isStudentFourYear');
  const grateStudentValue = watch('grateStudent');
  const onSubmit: SubmitHandler<IStudentAccountForm> = async (data) => {
    dispatch(
      setStudentAccount({
        firstName: data.firstName,
        lastName: data.lastName,
        userName: data.userName,
        password: data.password,
        dateOfBirth: data.dateOfBirth!,
        email: data.email,
        isStudentFourYear: data.isStudentFourYear,
        grateStudent: data.grateStudent,
      }),
    );
    !isModal && history.push('/select-learning-packages');
    localStorage.setItem(
      'studentAccount',
      JSON.stringify({ ...data, dateOfBirth: data.dateOfBirth!, parentId: currentUser.userId }),
    );
  };

  const createStudentAccount: SubmitHandler<IStudentAccountForm> = async (data) => {
    setActiveView({
      component: LearningPackageBody,
      props: {
        student: data,
        isModal,
      },
    });
  };

  const getDate = async () => {
    try {
      const selectedDate = newDate;
      const formattedDateValue = formatDateForRegistration(selectedDate);
      const payload = {
        date: formattedDateValue,
      };

      if (formattedDateValue === 'Invalid Date') {
        return;
      }

      const response = await instance.post(getFormattedSuggestYear, payload);

      if (response !== null) {
        setStudentYear(response.data.year);
        if (!isStudentFourYear) {
          setValue('isStudentFourYear', false);
        } else if (String(response.data.year) === grateStudentValue) {
          setValue('isStudentFourYear', true);
        } else {
          setValue('grateStudent', String(response.data.year));
        }
      }
      return response;
    } catch (e) {
      console.log(e);
    }
  };

  useEffect(() => {
    getDate();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [grateStudentValue, newDate, isStudentFourYear]);

  useMemo(() => {
    if (!memoizedIsCurUserIdEqualsStudentId) {
      localStorage.removeItem('studentAccount');
    }
  }, [memoizedIsCurUserIdEqualsStudentId]);

  return (
    <StyledContainer isModal={isModal}>
      {!isModal ? <h3 className="create-student-account__title">Create Student Account</h3> : null}
      <form
        className="create-student-account__form"
        onSubmit={isModal ? handleSubmit(createStudentAccount) : handleSubmit(onSubmit)}
      >
        <div className="create-student-account__form-fields-wrapper">
          <StyledFormInput
            label="First Name"
            name="firstName"
            error={errors.firstName}
            register={register}
            placeholder="Enter a first name"
            inputType="text"
          />
          <StyledFormInput
            label="Last Name"
            name="lastName"
            error={errors.lastName}
            register={register}
            placeholder="Enter a last name"
            inputType="text"
          />
          <StyledFormInput
            label="User Name"
            name="userName"
            error={errors.userName}
            register={register}
            placeholder="Enter a user name"
            inputType="text"
          />
          <StyledFormInput
            label="Password"
            name="password"
            error={errors.password}
            register={register}
            placeholder="Enter a password"
            inputType="password"
          />
          <Controller
            name="dateOfBirth"
            control={control}
            defaultValue={
              Boolean(studentWhenAppClosed?.dateOfBirth)
                ? (new Date(studentWhenAppClosed?.dateOfBirth) as unknown as Date)
                : (new Date() as unknown as Date)
            }
            render={({ field: { onChange, value } }) => (
              <div className="create-student-account__date-wrapper">
                <label htmlFor="date" className="create-student-account__label">
                  Date of Birth
                </label>
                <StyledDatePicker
                  id="date"
                  onChange={onChange}
                  selected={value}
                  value={value as unknown as string}
                  placeholderText="Enter a date of birthday"
                  onKeyDown={(e) => {
                    e.preventDefault();
                  }}
                  dateFormat="MM/dd/yyyy"
                  dateFormatCalendar="MM/dd/yyyy"
                />
                <p className="create-student-account__error">{errors?.dateOfBirth?.message}</p>
              </div>
            )}
          />
          <StyledFormInput
            label="Email Address (optional):"
            name="email"
            error={errors.email}
            register={register}
            placeholder="Enter a email"
            inputType="text"
          />
          <div className="create-student-account__checkbox-form-wrapper">
            <p className="create-student-account__checkbox-title">Is this student in year {studentYear}?</p>
            <Controller
              render={({ field: { onChange, value } }) => (
                <StyledCustomCheckbox
                  title="Yes"
                  name="Yes"
                  register={register}
                  onChange={() => onChange(true)}
                  checked={value}
                />
              )}
              name="isStudentFourYear"
              control={control}
            />
            <Controller
              render={({ field: { onChange, value } }) => (
                <StyledCustomCheckbox
                  title="No"
                  name="No"
                  register={register}
                  onChange={() => onChange(false)}
                  checked={!value}
                />
              )}
              name="isStudentFourYear"
              control={control}
            />
          </div>
          <div className="create-student-account__checkbox-form-wrapper">
            <p className="create-student-account__checkbox-title">What grate is the student? </p>
            {grateStudentArr.map((item, index) => (
              <Controller
                key={index}
                render={({ field: { onChange, value } }) => (
                  <StyledCustomCheckbox
                    title={item.title}
                    register={register}
                    name={item.title}
                    onChange={() => onChange(item.value)}
                    disabled={isStudentFourYear}
                    checked={value === item.value}
                  />
                )}
                name="grateStudent"
                control={control}
              />
            ))}
          </div>
        </div>
        {!isModal ? (
          <button className="create-student-account__form-button-next" type="submit">
            Next
          </button>
        ) : (
          <div className="create-student-account__buttons-wrapper">
            <button className="create-student-account__close-button" type="button" onClick={hideModal}>
              Close
            </button>
            <button className="create-student-account__form-button-next" type="submit">
              Add Student
            </button>
          </div>
        )}
      </form>
    </StyledContainer>
  );
};

const StyledContainer = styled.div<Props>`
  width: ${(props) => (props.isModal ? '901px' : '1016px')};
  margin: 0 auto;
  background: white;
  border-radius: ${(props) => (props.isModal ? 0 : '25px')};
  padding: ${(props) => (props.isModal ? 0 : '42px 68px 58px')};
  border-top: ${(props) => (props.isModal ? '1px solid #ececec' : 'none')};
  padding-top: ${(props) => (props.isModal ? '32px' : 'none')};
  font-family: ${({ theme }) => theme.font.fontFamily.popins};
  .create-student-account {
    &__title {
      font-size: 30px;
      line-height: 39px;
      letter-spacing: 0.43px;
      color: #20114d;
      margin: 0;
      padding-bottom: 25px;
      font-weight: 600;
      border-bottom: 1px solid #ececec;
      margin-bottom: 18px;
    }

    &__form {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: start;
    }

    &__form-fields-wrapper {
      width: 100%;
      display: grid;
      grid-template-columns: repeat(2, 1fr);
      grid-template-rows: repeat(3, max-content);
      column-gap: 28px;
      row-gap: 10px;
      margin-bottom: 51px;
    }

    &__checkbox-form-wrapper {
      display: grid;
      grid-template-columns: min-content repeat(2, 0.1fr);
      column-gap: 45px;
      grid-column: 1 / 3;

      :last-of-type {
        grid-template-columns: min-content repeat(4, 0.1fr);
      }
    }

    &__checkbox-title {
      font-family: ${({ theme }) => theme.font.fontFamily.popins};
      font-weight: 600;
      font-size: 16px;
      line-height: 18px;
      letter-spacing: 0.2px;
      width: 221px;
      color: #20114d;
    }

    &__form-button-next {
      padding: 11px 30px;
      width: fit-content;
      color: white;
      background: #32e790;
      text-align: center;
      font-weight: 600;
      font-size: 14px;
      line-height: 18px;
      letter-spacing: 0.2px;
      border-radius: 27px;
      border: 2px solid #32e790;
      align-self: end;
      cursor: pointer;
      font-family: ${({ theme }) => theme.font.fontFamily.popins};

      :last-of-type {
        padding: 9px 34px;
      }
    }

    &__date-wrapper {
      display: flex;
      flex-direction: column;
      justify-content: start;
    }

    &__label {
      margin: 0 0 10px 0;
      margin-bottom: 10px;
      font-size: 14px;
      color: #20114d;
      font-weight: 400;
    }

    &__error {
      font-size: 9px;
      color: red;
      margin-top: 5px;
      text-transform: capitalize;
    }

    &__buttons-wrapper {
      display: flex;
      flex-direction: row;
      align-items: space-between;
      justify-content: space-between;
      width: 100%;
    }

    &__close-button {
      padding: 9px 34px;
      width: 157px;
      color: rgba(245, 80, 83, 1);
      background: white;
      text-align: center;
      font-weight: 600;
      font-size: 14px;
      line-height: 18px;
      letter-spacing: 0.2px;
      border-radius: 27px;
      border: 2px solid rgba(245, 80, 83, 1);
      align-self: end;
      cursor: pointer;
    }
  }
`;

const StyledCustomCheckbox = styled(CustomCheckbox)`
  width: 90px;

  label {
    font-family: ${({ theme }) => theme.font.fontFamily.popins};
    font-weight: ${({ theme }) => theme.font.fontWeight.medium};
    font-size: 16px;
    line-height: 18px;
    letter-spacing: 0.2px;
    color: #20114d;
  }

  .custom-checkbox + label {
    position: relative;
  }

  .custom-checkbox + label::before {
    width: 23px;
    height: 23px;
    border-radius: 50%;
    width: 1.5em;
    height: 1.5em;
  }

  .custom-checkbox:checked + label::before {
    background-color: #41e85b;
    background-image: none;
  }

  .custom-checkbox:checked + label::after {
    content: '';
    width: 14px;
    height: 14px;
    position: absolute;
    border-radius: 50%;
    left: 5px;
    background-color: #41e85b;
    border: 2px solid white;
  }
`;

const StyledDatePicker = styled(DatePicker)`
  border: 1px solid #dad1c9;
  border-radius: 13px;
  padding: 11px 15px 11px 15px;
  outline: none;
  width: 100%;
  font-weight: 600;
  font-size: 16px;
  line-height: 18px;
  letter-spacing: 0.2px;
  font-family: ${({ theme }) => theme.font.fontFamily.popins};

  ::placeholder {
    color: rgba(32, 17, 77, 0.5);
    font-family: ${({ theme }) => theme.font.fontFamily.popins};
  }
`;

const StyledFormInput = styled(FormInput)`
  font-weight: 600;
  font-size: 16px;
  line-height: 18px;
  letter-spacing: 0.2px;
  color: rgb(166, 160, 184);
  font-family: ${({ theme }) => theme.font.fontFamily.popins};

  ::after {
    color: #20114d;
  }
`;

export default CreateStudentModal;
downloadDownload PNG downloadDownload JPEG downloadDownload SVG

Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!

Click to optimize width for Twitter