Untitled
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...