Untitled
unknown
plain_text
3 years ago
25 kB
16
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...