Untitled

 avatar
unknown
plain_text
2 years ago
25 kB
9
Indexable
/* eslint-disable max-lines */
import React from 'react';
import PropTypes from 'prop-types';
import PTBase from '../../layouts/PTBase';
import { REGEX, ICONS } from '../../../configs';
import get from 'lodash.get';
import { Camera1 } from '@telkomdesign/icons';
import ModalInputFile from '../../elements/ModalInputFile';
import TextInput from '../../elements/TextInput2';
import { ButtonFilled, ButtonGhost } from '@telkomdesign/tedis-reactjs-component';
import Countdown from 'react-countdown';
import { animateScroll as scroll } from 'react-scroll';
import { Formik } from 'formik';
import * as Yup from 'yup';
import Modal from '../../elements/Modal';
import ModalEmail from '../../elements/ModalEmail';
import ModalChangePassword from '../../elements/ModalChangePassword';
import clsx from 'clsx';
import moment from 'moment';


export default class ProfilPerguruanTinggi extends React.Component {
  constructor(props) {
    super(props);
    this.initialValues = {
      email: null,
      name: null,
      phone: null,
      gender: null,
      nik: null,
      universityName: null,
      picRole: null,
      oldPassword: null,
      newPassword: null
    };
    this.state = {
      profilePhotoUrl: null,
      newPhoto: null,
      coverPhotoUrl: null,
      newPhotoCover: null,
      errorPhoto: null,
      errorCover: null,
      newEmail: null,
      isWaiting: false,
      timerComplete: false,
      modalProfile: false,
      modalCover: false,
      modalPayload: null,
      isOpen: true,
      modalPassword: false,
      onModalChange: false,
      confirmEmail: false,
      modalSuccessChange: false,
      modalEmail: false,
      focused: '',
      oldPassword: null,
      newPassword: null,
      emailPassword: null,
      changeEmailData: null,
      errorChangePassword: false
    };
    this.form = React.createRef();
  }

  componentDidMount() {
    window.scrollTo({ top: 0, behavior: 'smooth' });
    this._handleWaiting();
  }

  UNSAFE_componentWillReceiveProps({ profilPT: { fetching, profile, fetchingChangeProfile,
    changeProfile, errorChangeProfile }, auth: { saveProgress } }) {
    const { isWaiting, newEmail, newPhoto, newPhotoCover } = this.state;
    if (!isWaiting) {
      const { setFieldError, values } = this.form.current;
      if (!fetchingChangeProfile) {
        if (errorChangeProfile && errorChangeProfile[0]?.type === 'email') setFieldError('newEmail', 'Email yang Kamu input sudah teregistrasi');
        if (changeProfile) {
          this.initialValues = {
            name: changeProfile?.name,
            email: changeProfile?.email,
            picRole: changeProfile?.profile?.picRole,
            phone: changeProfile?.profile?.phone || '',
            universityName: changeProfile?.university?.name,
            nik: changeProfile?.profile?.nik,
            oldPassword: '',
            newPassword: '',
          };
          this.form.current.resetForm();
          let modalPayload = {
            title: 'Data Berhasil Diubah',
            labelOk: 'Oke',
            onClose: this._clearModal.bind(this, 'profil'),
            onOk: this._clearModal.bind(this, 'profil')
          };
          if (newEmail) {
            modalPayload = {
              title: 'Email Berhasil Diubah',
              subtitle: 'Silakan cek inbox/spam email Anda untuk verifikasi perubahan email.',
              onClose: this._clearModal.bind(this, 'isWaiting'),
              onOk: this._clearModal.bind(this, 'isWaiting'),
              labelOk: 'Oke',
            };
          }
          this.setState({
            modalPayload,
          });
        }
      }
      if (!values?.nik && !fetching && profile) {
        const { avatarUrl, coverUrl, name, picRole,
          university: { name: universityName },
          profile: { nik }
        } = profile;
        const { oldPassword, newPassword } = values;
        this.initialValues = {
          name: saveProgress?.profileSaved?.name || name,
          email: profile?.email,
          picRole: saveProgress?.profileSaved?.picRole || picRole ,
          phone: saveProgress?.profileSaved?.phone || profile?.profile?.phone || '',
          universityName,
          nik,
          oldPassword,
          newPassword,
        };
        this.setState({
          profilePhotoUrl: avatarUrl,
          coverPhotoUrl: coverUrl,
          newEmail: values?.newEmail,
          newPhoto: saveProgress ? saveProgress?.photoProfileSaved?.newPhoto : newPhoto,
          newPhotoCover: saveProgress ?
            saveProgress?.coverProfileSaved?.newPhotoCover : newPhotoCover,
        });
      }
    }
  }

  componentDidUpdate(prevProps) {
    const { profilPT: { error, successModal }, actions  } = this.props;
    const { profilPT: { successModal: prevSuccessModal, error: prevError } } = prevProps;
    if (error !== prevProps.profilPT.error && error === 401) {
      actions.authTokenExpired();
    }
    if (successModal !== prevSuccessModal && !successModal) {
      this.setState({ onModalChange: false, modalSuccessChange: true });
    }
    if (error !== prevError && error?.message?.type === 'password' && error?.code === 409) {
      this.setState({ errorChangePassword: true }, this._handleModalPassword);
    }
  }

  componentWillUnmount() {
    const { actions, auth: { tokenExpired, pt } } = this.props;
    if (!tokenExpired && pt) {
      actions.resetSaveProgress();
      actions.authRemoveRoutes();
    }
    localStorage.removeItem('changeEmailData');
  }

  _handleWaiting = () => {
    const getCooldown = localStorage.getItem('changeEmailData');
    if (getCooldown) {
      const parsedData = JSON.parse(getCooldown);
      const timeRemaining = moment(parsedData.until).diff(moment(), 's');
      if (timeRemaining >= 0) this.setState({ isWaiting: true, changeEmailData: parsedData });
    }
  }

  _clearModal = (type = null) => {
    const { newEmail } = this.state;
    const { actions } = this.props;
    scroll.scrollToTop();
    const payload = {
      email: newEmail, until: moment().add(180, 'seconds')
    };
    if (type === 'isWaiting') {
      localStorage.setItem('changeEmailData', JSON.stringify(payload));
    }
    if (type === 'profil') {
      actions.authRemoveRoutes();
      actions.resetSaveProgress();
      location.reload();
    }
    this.setState({
      modalPayload: null, isWaiting: type === 'isWaiting', changeEmailData: payload
    });
  }

  _requestProfile = () => {
    const { actions, auth: { pt } } = this.props;
    actions.requestProfilePt({ token: get(pt, 'token') });
  }

  _handleChangeAvatar = (file) => {
    this.setState({
      profilePhotoUrl: URL.createObjectURL(file),
      newPhoto: file,
    });
    setTimeout(() => {
      const { auth: { saveProgress } } = this.props;
      this.props.actions.saveProgress({
        ...saveProgress,
        photoProfileSaved: {
          profilePhotoSaved: URL.createObjectURL(file),
          newPhoto: file
        }
      });
    }, 100);
  }

  _handleChangeCover = (file) => {
    this.setState({
      coverPhotoUrl: URL.createObjectURL(file),
      newPhotoCover: file,
    });
    setTimeout(() => {
      const { auth: { saveProgress } } = this.props;
      this.props.actions.saveProgress({
        ...saveProgress,
        coverProfileSaved: {
          coverPhotoSaved: URL.createObjectURL(file),
          newPhotoCover: file,
        }
      });
    }, 100);
  }

  _handleSetValue = (name, value) => {
    const { auth: { pt } } = this.props;
    const { setFieldValue } = this.form.current;
    let currentValue = value.target.value;
    setFieldValue(name, currentValue);
    setTimeout(() => {
      const { auth: { saveProgress } } = this.props;
      const { values } = this.form.current;
      this.props.actions.saveProgress({ ...saveProgress,
        userId: get(pt, 'userId'),
        profileSaved: values });
    }, 100);
  }

  _handleSubmit = ({ name, phone, picRole }) => {
    const { newPhoto, newPhotoCover, errorPhoto, errorCover } = this.state;
    if (errorPhoto || errorCover) return true;
    const { auth: { pt: { token } }, actions } = this.props;
    let data = new FormData();
    data.append('name', name);
    data.append('phone', phone);
    data.append('picRole', picRole);
    if (newPhoto) data.append('avatarFile', newPhoto);
    if (newPhotoCover) data.append('coverFile', newPhotoCover);
    actions.requestChangeProfilePt({ data, token });
  }

  _handleModalProfile = () => this.setState({ modalProfile: !this.state.modalProfile });
  _handleModalCover = () => this.setState({ modalCover: !this.state.modalCover });

  _renderProfile = (helpers) => {
    const { auth: { pt, saveProgress } } = this.props;
    const profile = get(pt, 'profile') || null;
    const { values } = helpers;
    const {
      profilePhotoUrl, newPhoto, modalProfile
    } = this.state;
    const displayName = profile ? profile.name : '';
    return (
      <>
        <div className="img-wrapper">
          {saveProgress?.photoProfileSaved ?
            <img src={saveProgress?.photoProfileSaved?.profilePhotoSaved} /> :
            profilePhotoUrl ? <img src={profilePhotoUrl} /> : (
              <div className="avatarDummy">
                <p>{values.name ? values.name.slice(0, 1) : null}</p>
              </div>
            )}
          <button type="button" className="btn-camera" onClick={this._handleModalProfile}>
            <Camera1 />
          </button>
        </div>
        <p className="username">{displayName}</p>
        <p className="jabatan">{profile ? profile.picRole : 'Jabatan'}</p>
        <ModalInputFile
          accept=".png,.jpg,.jpeg"
          size={2000}
          file={newPhoto}
          onChange={this._handleChangeAvatar}
          modalTitle="Foto Profil"
          customButton
          toggleModal={modalProfile}
          aspect={1}
          cropShape="round"
        />
      </>
    );
  }

  _renderUbahSandi = () => {
    const { classes } = this.props;

    return (
      <div className={classes.ubahSandi}>
        <p>
          Ingin{' '}
          <a className={classes.checkboxHighlight} onClick={this._handleModalPassword}>
            Ubah Sandi?
          </a>
        </p>
      </div>
    );
  }

  _renderCover = () => {
    const {
      coverPhotoUrl, newPhotoCover, modalCover, isOpen
    } = this.state;
    const { auth: { saveProgress } } = this.props;
    let cropSize;
    if (window.innerWidth < 768) {
      cropSize = {
        height: 82,
        width: 220,
      };
    } else {
      cropSize = {
        height: 164,
        width: 440,
      };
    }
    return (
      <>
        <button type="button" className="btn-cover" onClick={this._handleModalCover}>
          <Camera1 /> <p>Ubah Cover</p>
        </button>
        <div className={clsx('cover-wrapper', { coverDrawerOpen: !isOpen })}>
          {saveProgress?.coverProfileSaved ?
            <img src={saveProgress?.coverProfileSaved?.coverPhotoSaved} /> :
            coverPhotoUrl ? <img src={coverPhotoUrl} /> : (
              <div className="coverDummy" />
            )}
        </div>
        <ModalInputFile
          accept=".png,.jpg,.jpeg"
          size={2000}
          file={newPhotoCover}
          onChange={this._handleChangeCover}
          modalTitle="Cover"
          customButton
          toggleModal={modalCover}
          aspect={4 / 3}
          cropShape="rect"
          cropSize={cropSize}
        />
      </>
    );
  }
  _createForm = (helpers) => {
    const { classes, auth: { saveProgress } } = this.props;
    const {
      modalPassword, isOpen, modalEmail,
      onModalChange, modalSuccessChange, confirmEmail, oldPassword, newPassword,
      errorChangePassword
    } = this.state;
    const { handleSubmit, handleBlur: _handleBlur, values,
      touched, errors, dirty } = helpers;
    return (
      <form onSubmit={handleSubmit}>
        {(dirty || saveProgress?.profileSaved
          || saveProgress?.coverProfileSaved
          || saveProgress?.photoProfileSaved) && <input type="hidden" name="isForbiddenExit" value="1" />}
        <div className={classes.content}>
          {this._renderCover()}
          <div className="container">
            <div className="left">
              <div className={clsx('profile', { profileDrawerClosed: !isOpen })}>
                {this._renderProfile(helpers)}
              </div>
              <div className="buttons-wrapper">
                <ButtonFilled
                  type="submit"
                  size="48"
                  disabled={!dirty && !saveProgress?.profileSaved
                    && !saveProgress?.coverProfileSaved && !saveProgress?.photoProfileSaved}
                >
                  Simpan
                </ButtonFilled>
              </div>
            </div>
            <div className={clsx('right', { formDrawerOpen: !isOpen })}>
              <div className="box">
                <TextInput
                  onChange={this._handleSetValue.bind(this, 'name')}
                  onBlur={this._handleBlurr.bind(this, _handleBlur)}
                  onFocus={this._handleFocus.bind(this, 'name')}
                  focused={this.state.focused}
                  name="name"
                  value={values.name}
                  variant="allBlack"
                  label="Nama Lengkap"
                  hintfocus={'Hanya menggunakan huruf dan simbol apostrof (\') & strip (-)'}
                  hinterror={touched.name && errors.name}
                />
                <TextInput
                  value={values.nik}
                  disabled
                  variant="allBlack"
                  label="NIK (Nomor Induk Kepegawaian)"
                  name="nik"
                />
                <TextInput
                  variant="allBlack"
                  value={values.email}
                  disabled
                  label="Email"
                  className="email-input"
                />
                <p onClick={this._handleModalEmail} className="change-email">
                  Ingin ubah email?
                </p>
                <TextInput
                  value={values.phone}
                  name="phone"
                  onChange={this._handleSetValue.bind(this, 'phone')}
                  onFocus={this._handleFocus.bind(this, 'phone')}
                  focused={this.state.focused}
                  hintfocus={'Nomor Handphone hanya dapat menggunakan angka'}
                  onBlur={this._handleBlurr.bind(this, _handleBlur)}
                  variant="allBlack"
                  label="Nomor Handphone (WhatsApp)"
                  hinterror={touched.phone && errors.phone}
                />
                <TextInput
                  variant="allBlack"
                  value={values.universityName}
                  disabled
                  label="Perguruan Tinggi"
                />
                <TextInput
                  value={values.picRole}
                  onChange={this._handleSetValue.bind(this, 'picRole')}
                  name="picRole"
                  label="Jabatan"
                  onBlur={this._handleBlurr.bind(this, _handleBlur)}
                  onFocus={this._handleFocus.bind(this, 'picRole')}
                  focused={this.state.focused}
                  hinterror={touched.picRole && errors.picRole}
                />
                {this._renderUbahSandi()}

                <ModalEmail
                  toggleModal={modalEmail}
                  onClose={this._handleModalEmail}
                  onSubmit={this._handleChangeEmail}
                />

                <ModalChangePassword
                  toggleModal={modalPassword}
                  onClose={this._handleModalPassword}
                  onSubmit={this._handleChangePassword}
                  onError={errorChangePassword}
                  oldPassword = {oldPassword}
                  newPassword = {newPassword}
                />

                <Modal
                  visible={onModalChange && !modalPassword || confirmEmail}
                  icon={ICONS.exclamationTriangle}
                  type="confirmPic"
                  wrapClassName={classes.modalConfirm}
                  onClose={this._handleResetConfirm}
                  onCancel={this._handleResetConfirm}
                  onOk={this._handleModalSuccess}
                  title={onModalChange ? 'Ubah Sandi' : 'Ubah Email'}
                  subtitle={onModalChange ? 'Apa Anda yakin ingin mengubah sandi?' : 'Apa Anda yakin ingin mengubah email?'}
                  labelCancel="Batal"
                />

                <Modal
                  visible={modalSuccessChange && (!onModalChange)}
                  icon={<img src={ICONS.success} />}
                  type="info"
                  onClose={this._handleCloseModalSuccess}
                  onOk={this._handleCloseModalSuccess}
                  labelOk={'Oke'}
                  title={'Sandi Berhasil Diubah'}
                />
              </div>
            </div>
            <div className="buttons-wrapper-mobile">
              <ButtonFilled
                type="submit"
                size="48"
                disabled={!dirty && !saveProgress?.profileSaved
                  && !saveProgress?.coverProfileSaved && !saveProgress?.photoProfileSaved}
              >
                Simpan
              </ButtonFilled>
            </div>
          </div>
        </div>
      </form>
    );
  }

  _handleFocus = (focus) => this.setState({ focused: focus });
  _handleResetFocus = () => this.setState({ focused: '' });
  _handleBlurr = (_handleBlur, e) => {
    _handleBlur(e);
    this._handleResetFocus();
  }
  _handleOpenDrawer = (isOpen) => this.setState({ isOpen });

  _handleModalPassword = () => {
    const { modalPassword } = this.state;
    if (modalPassword) this.setState({ modalPassword: false, errorChangePassword: false, newPassword: '', oldPassword: '' });
    else this.setState({ modalPassword: true });
  }

  _handleModalEmail = () => this.setState({ modalEmail: !this.state.modalEmail });

  _handleChangeEmail = (values) => {
    const { profilPT: { error } } = this.props;
    if(error && error === 'Access token expired!') {
      this.setState({ modalEmail: false });
    }
    else {
      this.setState({
        modalEmail: false, confirmEmail: true,
        emailPassword: values.password, newEmail: values.newEmail
      });
    }
  }

  _handleChangePassword = (values) => {
    const { profilPT: { error } } = this.props;
    if(error && error === 'Access token expired!') {
      this.setState({ modalPassword: false });
    }
    else {
      this.setState({
        modalPassword: false, onModalChange: true,
        newPassword: values.newPassword,
        oldPassword: values.oldPassword,
        errorChangePassword: false
      });
    }
  }

  _handleRechangeEmail = () => {
    const { isWaiting, timerComplete } = this.state;
    this.setState({ timerComplete: !timerComplete, isWaiting: !isWaiting }, () => {
      this._requestProfile();
      localStorage.removeItem('changeEmailData');
    });
  }

  _handleResent = () => {
    const { actions, auth: { pt: { token } } } = this.props;
    const { changeEmailData } = this.state;
    const payload = {
      email: changeEmailData.email, until: moment().add(180, 'seconds')
    };
    localStorage.setItem('changeEmailData', JSON.stringify(payload));
    this.setState({ timerComplete: false, isWaiting: true, changeEmailData: payload });
    const data = new FormData();
    data.append('email', payload.email);
    actions.requestChangeProfileResentPt({ token, data });
  }

  _handleCloseModalSuccess = () => {
    const { actions } = this.props;
    actions.resetSuccessModalPt();
    this.setState({ modalSuccessChange: false, newPassword: null });
  }

  _handleModalSuccess = () => {
    const { actions, auth: { pt } } = this.props;
    const { newPassword, oldPassword, emailPassword, newEmail } = this.state;
    if (newPassword) {
      actions.changePassUserPt(oldPassword, newPassword, pt.token);
    } else if (newEmail) {
      let data = new FormData();
      data.append('email', newEmail);
      data.append('password', emailPassword);
      actions.requestChangeProfilePt({ data, token: get(pt, 'token') });
      this.setState({ confirmEmail: false });
    }
  }

  _handleResetConfirm = () => {
    const { actions } = this.props, { newPassword } = this.state;
    actions.resetConfirmModalPt();
    if (newPassword) {
      this.setState({
        newPassword: null, oldPassword: null, onModalChange: false, modalPassword: false,
      });
    } else {
      this.setState({
        newEmail: null, emailPassword: null, newPassword: null, oldPassword: null,
        confirmEmail: false, modalEmail: false
      });
    }
  }

  _schemaChangeProfile = () => {
    return Yup.object().shape({
      name: Yup.string()
        .required('Nama Lengkap tidak boleh kosong')
        .matches(REGEX.apostrof, 'Hanya dapat menggunakan huruf, simbol apostrof (\'), dan strip (-)'),
      phone: Yup.string()
        .required('Nomor Handphone tidak boleh kosong').test('is number', 'Nomor Handphone hanya dapat menggunakan angka', value => !isNaN(value))
        .matches(REGEX.phoneNumber, 'Nomor Handphone yang Anda input tidak sesuai'),
      picRole: Yup.string()
        .required('Jabatan tidak boleh kosong')
    });
  }

  _renderForm = () => {
    return (
      <Formik
        innerRef={this.form}
        initialValues={this.initialValues}
        onSubmit={this._handleSubmit}
        validationSchema={this._schemaChangeProfile}
        component={this._createForm}
        enableReinitialize={true}
      />
    );
  }

  _handleCloseModal = () => this.setState({ modalSuccessChange: false, modalPayload: null });

  _renderWaiting = () => {
    const { classes } = this.props;
    const { timerComplete, changeEmailData: parsedData } = this.state;
    const timeRemaining = parsedData ? moment(parsedData.until).diff(moment(), 's') : 1;
    return (
      <div
        className={clsx(classes.waitingWrapper, classes.waitingWrapperMargin)}>
        <h3>Verifikasi Perubahan Email</h3>
        <h4>
          Verifikasi akun telah dikirim melalui email<br /><span>{parsedData?.email}</span>
        </h4>
        <div className="buttons-wrapper">
          <ButtonGhost onClick={this._handleRechangeEmail} disabled={!timerComplete} size="48">
            Ubah Email
          </ButtonGhost>
          <ButtonGhost onClick={this._handleResent} disabled={!timerComplete} size="48">
            Kirim Ulang
          </ButtonGhost>
        </div>
        {!timerComplete && (
          <Countdown
            date={Date.now() + timeRemaining * 1000}
            renderer={this._renderCountdown}
          />
        )}
      </div>
    );
  }

  _renderCountdown = ({ minutes, seconds, completed }) => {
    const { timerComplete } = this.state;

    if (!completed) {
      return (
        <p className="body-1">Mohon tunggu {minutes}:{`${seconds}`.length === 1 ? `0${seconds}` : seconds} menit untuk mengirim ulang verifikasi perubahan email</p>
      );
    } else {
      this.setState({
        timerComplete: !timerComplete
      });
    }
    return null;
  }

  render() {
    const { classes } = this.props;
    let { modalPayload, isWaiting } = this.state;
    return (
      <PTBase onOpenDrawer={this._handleOpenDrawer} >
        <Modal
          icon={<img src={ICONS.success} />}
          visible={Boolean(modalPayload)}
          {...modalPayload}
        />
        <div className={clsx(classes.container, { [classes.containerWaiting]: isWaiting })}>
          {isWaiting ? this._renderWaiting() : this._renderForm()}
        </div>
      </PTBase>
    );
  }
}

ProfilPerguruanTinggi.defaultProps = {
  classes: {},
};

ProfilPerguruanTinggi.propTypes = {
  actions: PropTypes.object.isRequired,
  profilPT: PropTypes.object.isRequired,
  auth: PropTypes.object.isRequired,
  classes: PropTypes.object,
  router: PropTypes.object.isRequired,
};
Editor is loading...