Created
July 1, 2019 19:42
-
-
Save matheuscouto/d392af1396774ef959edee08c0a87449 to your computer and use it in GitHub Desktop.
templates/commpons/settings/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import Television from './../../../pages/Television'; | |
import { getPlansPublisher } from '../../../utils/redux/actions/publisher/PlansActions'; | |
import { updateUserCreditCard, refreshUserData} from '../../../utils/redux/actions/auth/actions'; | |
import Slider from 'react-slick'; | |
import validate from '../../utils/form/utilsForm/validForm' // validate({cpf: 'xxxx'}) => errors | |
import moment, { duration } from 'moment'; | |
import MaskedInput from 'react-text-mask'; | |
import { map } from 'lodash'; | |
import { | |
EditionFieldWrapper, | |
RootWrapper, | |
MainWrapper, | |
UserDataWrapper, | |
SubscriptionDataWrapper, | |
SwitchPlanWrapper, | |
FullModal, | |
EditPaymentInfoWrapper, | |
SubmitButton, | |
ChangePasswordWrapper, | |
TransactionalDataWrapper, | |
PlanBox, | |
PlanWrapper, | |
SliderWrapper, | |
CollectionWrapper, | |
ClosePanel | |
} from './settingsStyle'; | |
import { connect } from 'react-redux'; | |
import { Router } from '../../../routes'; | |
import { MediaService } from '../../../utils/api/mediaService'; | |
// REDUX | |
import { | |
openDialog as updateDialogAction, | |
authConfirmUserSocialLogin, | |
authErrorUserSocialLogin, | |
authUpdateToken, | |
authConfirmUserAccount, | |
authUserLogout | |
} from '../../../utils/redux/actions/modalActions'; | |
import { | |
getCollectionsOpen, | |
getCollections | |
} from '../../../utils/redux/actions/publisher/collectionActions'; | |
import LinkSlug from '../../commons/linkSlug/LinkSlug'; | |
import withAuthentication from '../../../utils/functions/withAuthentication'; | |
import { UserService } from '../../../utils/api/userService'; | |
moment.locale('pt-br') | |
class SettingsComponent extends Component { | |
state = { | |
didLoadUserData: false, | |
didLoadPlans: false, | |
didRefreshUserData: false, // because of the cache issue | |
profilePictureUrl: undefined, | |
previewProfilePictureUrl: 'https://proxy.duckduckgo.com/iu/?u=https%3A%2F%2Fi.dailymail.co.uk%2Fi%2Fpix%2F2017%2F04%2F20%2F13%2F3F6B966D00000578-4428630-image-m-80_1492690622006.jpg&f=1', | |
paymentMethod: 'credit-card', | |
paymentStatus: 'up-to-date', | |
switchingPlan: false, | |
subRouteTitle: '-', | |
subRouteSubtitle: '-', | |
fieldValues: { | |
personalData: { | |
name: '', | |
lastName: '', | |
cpf: '', | |
errors: ['cpf'], | |
id: '' | |
}, | |
changePassword: { | |
currentPassword: '', | |
newPassword: '', | |
confirmNewPassword: '', | |
confirmPasswordWarning: 'none', // none | empty | different | weak | wrong-password | |
errors: ['currentPassword', 'newPassword', 'confirmNewPassword'], | |
}, | |
deleteAccount: { | |
email: '', | |
errors: ['email'], | |
}, | |
editCreditCard: { | |
number: '', | |
holderName: '', | |
expirationDate: '', | |
securityCode: '', | |
errors: ['number', 'holderName', 'expirationDate', 'securityCode'], | |
} | |
}, | |
isMobile: false | |
} | |
componentDidMount() { | |
if(this.props.publisher.revenueModel === 'SUBSCRIPTION') { | |
this.switchRoute('subscription-data')(); | |
} else { | |
this.switchRoute('transactional-data')(); | |
} | |
this.updateResponsiveness(); | |
window.addEventListener('resize', this.updateResponsiveness); | |
} | |
// Get current user favorite medias | |
getUserFavoriteMedias = async () => { | |
const { auth } = this.props; | |
MediaService.getAllFavMedias(auth.accessToken.accessToken).then(response => { | |
this.setState(state => ({ | |
...state, | |
userFavorites: response, | |
})) | |
return response | |
}) | |
} | |
// Get current user favorite collections | |
getUserFavoriteCollection = async () => { | |
const { auth } = this.props; | |
MediaService.getAllFavCollections(auth.accessToken.accessToken).then(response => { | |
this.setState(state => ({ | |
...state, | |
userFavoritesCollection: response, | |
})) | |
return response | |
}) | |
console.log(this.state.userFavoritesCollection) | |
} | |
updateResponsiveness = () => { | |
if(window.innerWidth > 1132 && this.state.isMobile) { | |
this.setState(state => ({ | |
...state, | |
isMobile: false, | |
})) | |
if(this.props.publisher.revenueModel === 'SUBSCRIPTION') { | |
this.switchRoute('subscription-data')(); | |
} else { | |
this.switchRoute('transactional-data')(); | |
} | |
} else if(window.innerWidth <= 1132 && !this.state.isMobile) { | |
this.setState(state => ({ | |
...state, | |
isMobile: true, | |
})) | |
this.switchRoute('mobile-navigator')(); | |
} | |
} | |
componentDidUpdate(oldProps, oldState) { | |
const { didLoadUserData, didLoadPlans, didRefreshUserData, fieldValues: { changePassword }, userFavorites, userFavoritesCollection } = this.state; | |
// if(oldState) { | |
// const oldChangePasswordFields = oldState.fieldValues.changePassword | |
// const userTypedPasswordSession = oldChangePasswordFields.currentPassword !== changePassword.currentPassword || oldChangePasswordFields.newPassword !== changePassword.newPassword || oldChangePasswordFields.confirmNewPassword !== changePassword.confirmNewPassword; | |
// if(userTypedPasswordSession) | |
// { | |
// this.setState(state => ({ | |
// ...state, | |
// fieldValues: { | |
// ...state.fieldValues, | |
// changePassword: { | |
// ...state.fieldValues.changePassword, | |
// confirmPasswordWarning: this.checkIfUserCanSubmitNewPassword(changePassword.currentPassword, changePassword.newPassword, changePassword.confirmNewPassword) | |
// } | |
// } | |
// })) | |
// } | |
// } | |
if (!userFavorites){ | |
this.getUserFavoriteMedias(); | |
} | |
if (!userFavoritesCollection) { | |
this.getUserFavoriteCollection(); | |
} | |
if(!didRefreshUserData && this.props.auth && this.props.auth.accessToken) { | |
UserService.refreshUserData(this.props.auth.accessToken.user.id, this.props.auth.accessToken.accessToken, this.props.refreshUserData) | |
this.setState(state => ({ | |
...state, | |
didRefreshUserData: true | |
})) | |
} | |
if(!didLoadPlans && this.props.auth && this.props.auth.accessToken && this.props.publisher.revenueModel === 'SUBSCRIPTION') { | |
this.props.getPlansPublisher(this.props.auth.accessToken.accessToken, this.props.publisher.id) | |
this.setState(state => ({ | |
...state, | |
didLoadPlans: true | |
})) | |
} | |
if(!didLoadUserData && this.props.auth && this.props.auth.accessToken) { | |
const { subscription } = this.props.auth.accessToken.user | |
if(this.props.publisher.revenueModel === 'SUBSCRIPTION' && !(!subscription || subscription.status === 'UNPAID' || subscription.status === 'ENDED')) { | |
this.handleGetUserSubscriptionData(); | |
} | |
if(this.props.publisher.revenueModel === 'TRANSACTIONAL') { | |
this.props.getCollections(this.props.publisher, this.props.auth.accessToken.accessToken) | |
} | |
const { name, lastName, cpf } = this.props.auth.accessToken.user; | |
this.setState(state => ({ | |
...state, | |
didLoadUserData: true, | |
fieldValues: { | |
...state.fieldValues, | |
personalData: { | |
...state.fieldValues.personalData, | |
name, | |
lastName, | |
cpf | |
} | |
} | |
})) | |
} | |
} | |
handleConfirmDeleteAccount = () => { | |
if(this.state.fieldValues.deleteAccount.email === this.props.auth.accessToken.user.login) { | |
this.state.modalConfirmAction(); | |
this.handleUserLogout(); | |
} | |
} | |
render() { | |
if(!this.props.auth || !this.props.auth.accessToken || !this.props.auth.accessToken.user) { | |
return(<div/>) | |
} | |
// console.log('PROPS: ', this.props) | |
// if(this.props.collection) { | |
// console.log('COLLECTIONS: ', this.props.collection.data) | |
// } | |
const {name, subscription} = this.props.auth.accessToken.user; | |
const { showFullModal, profilePictureUrl, routeName, subRoute, subRouteSubtitle, subRouteTitle, routeTitle, routeSubtitle, isMobile, selectedPlan, userSubscriptionInfo} = this.state; | |
if(showFullModal) { | |
return ( | |
<FullModal danger={showFullModal === 'cancel-subscription' || showFullModal === 'delete-account'}> | |
<div className="modal-window"> | |
{ | |
showFullModal === 'confirm-switch-plan' | |
&& <> | |
<h1>Confirmar alteração?</h1> | |
<p className="message">Após a alteração você continuará usando o plano “<b>{userSubscriptionInfo.name}</b> - {translatePlan[userSubscriptionInfo.period]}” até <b>{moment(this.props.auth.accessToken.user.subscription.currentPeriodEnd).format('DD/MMMM/YYYY').replace('/',' de ').replace('/',' de ')}</b>.<br/><br/> | |
Uma cobrança no valor de R$ {(selectedPlan.price/100).toFixed(2).replace('.',',')} (em {planModifier[selectedPlan.period]} parcela{planModifier[selectedPlan.period] > 1 && 's'}) será | |
realizada neste dia para ativar o plano “<b>{selectedPlan.title}</b> - {translatePlan[selectedPlan.period]}” | |
que será renovada automaticamente a cada {planModifier[selectedPlan.period] > 1 ? `${planModifier[selectedPlan.period]} meses` : 'mês'}.</p> | |
{ | |
isMobile | |
? <div className="buttons-wrapper"> | |
<div onClick={() => {this.state.modalConfirmAction(); this.handleCloseFullModal();}} className="button">Alterar Plano</div> | |
<div onClick={this.handleCloseFullModal} className="button cancel">Não Alterar Plano</div> | |
</div> | |
: <div className="buttons-wrapper"> | |
<div onClick={this.handleCloseFullModal} className="button cancel">Não Alterar Plano</div> | |
<div onClick={() => {this.state.modalConfirmAction(); this.handleCloseFullModal();}} className="button">Alterar Plano</div> | |
</div> | |
} | |
</> | |
} | |
{ | |
showFullModal === 'cancel-subscription' | |
&& <> | |
<h1>Cancelar assinatura?</h1> | |
<p className="message">Ao cancelar a assinatura você continua assistindo aos conteúdos até o dia {moment(this.props.auth.accessToken.user.subscription.currentPeriodEnd).format('DD/MMM').replace('/', ' de ')} e<br/>após esta data seu plano não será renovado.</p> | |
<div className="buttons-wrapper"> | |
<div onClick={this.handleCloseFullModal} className="button cancel">Continuar Assistindo</div> | |
<div onClick={() => {this.state.modalConfirmAction(); this.handleCloseFullModal();}} className="button">Cancelar Assinatura</div> | |
</div> | |
</> | |
} | |
{ | |
showFullModal === 'delete-account' | |
&& <> | |
<h1>Excluir conta?</h1> | |
<p className="message">Esta ação resultará na exclusão do seu acesso e informações. Digite abaixo o e-mail cadastrado para excluir a conta.</p> | |
<EditionField label="E-mail Cadastrado" fullWidth value={this.state.fieldValues.deleteAccount.email} onChange={this.handleInputChange('deleteAccount')('email')}/> | |
<div className="buttons-wrapper"> | |
<div onClick={this.handleCloseFullModal} className="button cancel">Manter Minha Conta</div> | |
<div className={`button ${this.state.fieldValues.deleteAccount.email !== this.props.auth.accessToken.user.login ? 'disabled' : ''}`} onClick={this.handleConfirmDeleteAccount} >Excluir Minhas Informações</div> | |
</div> | |
</> | |
} | |
</div> | |
</FullModal> | |
) | |
} | |
if(routeName === 'mobile-navigator') { | |
return ( | |
<RootWrapper> | |
<ClosePanel onClick={() => window.location.href='/'}> | |
<i className="material-icons">close</i> | |
</ClosePanel> | |
<LeftNavigator publisherRevenueType={this.props.publisher.revenueModel} handleUserLogout={this.handleUserLogout} routeName={routeName} username={name} profilePictureUrl={profilePictureUrl} switchRoute={this.switchRoute} /> | |
</RootWrapper> | |
) | |
} | |
return ( | |
<RootWrapper> | |
<ClosePanel onClick={() => window.location.href='/'}> | |
Ir para o site <i className="material-icons">close</i> | |
</ClosePanel> | |
{ | |
!isMobile && <LeftNavigator publisherRevenueType={this.props.publisher.revenueModel} handleUserLogout={this.handleUserLogout} routeName={routeName} username={name} profilePictureUrl={profilePictureUrl} switchRoute={this.switchRoute} /> | |
} | |
<MainWrapper subRoute={subRoute}> | |
{ | |
isMobile && <i onClick={subRoute ? this.switchSubRouteTitleAndSubtitle('return') : this.switchRoute('mobile-navigator')} className="material-icons">arrow_back</i> | |
} | |
{ | |
subRoute | |
? isMobile ? null : <div onClick={this.switchSubRouteTitleAndSubtitle('return')} className="go__back"><i className="material-icons">arrow_back</i><p>Voltar</p></div> | |
: isMobile ? null : <div style={{height: 60}} /> | |
} | |
{ | |
(!isMobile || (routeName !== 'user-data' && isMobile) || subRoute === 'change-password') && <h1 className="main__content__title">{subRoute ? subRouteTitle : routeTitle}</h1> | |
} | |
{ | |
(!isMobile || (routeName !== 'user-data' && isMobile)) | |
&& (subRoute | |
? subRoute === 'switch-plan' | |
? <h2 className="main__content__subtitle">{subRouteSubtitle.split('$')[0]}<b>{subRouteSubtitle.split('$')[1]}</b></h2> | |
: <h2 className="main__content__subtitle">{subRouteSubtitle.split('<br/>')[0]}<br/>{subRouteSubtitle.split('<br/>')[1]}</h2> | |
: <h2 className="main__content__subtitle">{routeSubtitle}</h2>) | |
} | |
{this.selectedRoute()} | |
</MainWrapper> | |
</RootWrapper> | |
); | |
} | |
handleError = (area) => (field) => (operation) => { | |
const errors = this.state.fieldValues[area].errors.slice(0); | |
if(operation === 'add') { | |
if(errors.indexOf(field) === -1) { | |
errors.push(field); | |
this.setState(state => ({ | |
...state, | |
fieldValues: { | |
...state.fieldValues, | |
[area]: { | |
...state.fieldValues[area], | |
errors | |
} | |
} | |
})) | |
} | |
} else if(operation === 'remove') { | |
if(errors.indexOf(field) !== -1) { | |
const index = errors.indexOf(field); | |
errors.splice(index, 1); | |
this.setState(state => ({ | |
...state, | |
fieldValues: { | |
...state.fieldValues, | |
[area]: { | |
...state.fieldValues[area], | |
errors | |
} | |
} | |
})) | |
} | |
} | |
} | |
handleChangeUserPassword = () => { | |
const { currentPassword, newPassword } = this.state.fieldValues.changePassword; | |
const { user: { id }, accessToken } = this.props.auth.accessToken; | |
this.setState(state => ({ ...state, loadingChangePassword: true })) | |
const removeLoadingStateChangePassword = (code, message) => { | |
if(code === 200) { | |
this.setState(state => ({ | |
...state, | |
loadingChangePassword: false, | |
fieldValues: { | |
...state.fieldValues, | |
changePassword: { | |
currentPassword: '', | |
newPassword: '', | |
confirmNewPassword: '', | |
confirmPasswordWarning: 'none', // none | wrong-password | |
errors: ['currentPassword', 'newPassword', 'confirmNewPassword', 'wrongPassword'], | |
} | |
} | |
})) | |
this.switchRoute('user-data')(); | |
} else { | |
if(message === 'USER_WRONG_CURRENT_PASSWORD') { | |
this.setState(state => ({ | |
...state, | |
loadingChangePassword: false, | |
fieldValues: { | |
...state.fieldValues, | |
changePassword: { | |
...state.fieldValues.changePassword, | |
confirmPasswordWarning: 'wrong-password', | |
} | |
} | |
})) | |
} else { | |
this.setState(state => ({ ...state, loadingChangePassword: false, })) | |
} | |
} | |
} | |
UserService.updateUserPassword(id, accessToken, currentPassword, newPassword, removeLoadingStateChangePassword); | |
} | |
handleShowFullModal = (modalConfirmAction, type, payload) => { | |
if(payload) { | |
this.setState(state => ({ | |
...state, | |
showFullModal: type, | |
modalConfirmAction, | |
...payload | |
})) | |
} else { | |
this.setState(state => ({ | |
...state, | |
showFullModal: type, | |
modalConfirmAction, | |
})) | |
} | |
} | |
handleCloseFullModal = () => { | |
this.setState(state => ({ | |
...state, | |
showFullModal: undefined, | |
})) | |
} | |
handleGetUserSubscriptionData = (userSubscriptionInfo) => { | |
if(userSubscriptionInfo) { | |
this.setState(state => ({ | |
...state, | |
userSubscriptionInfo: { | |
...state.userSubscription, | |
nextPlan: userSubscriptionInfo | |
} | |
})) | |
} else { | |
const { accessToken, user: { id } } = this.props.auth.accessToken; | |
UserService.getUserPlan(accessToken).then(resp => { | |
this.setState(state => ({ | |
...state, | |
userSubscriptionInfo: resp.data | |
})) | |
UserService.refreshUserData(id, accessToken, this.props.refreshUserData) | |
}).catch(err => console.error(err)) | |
} | |
} | |
switchRoute = (routeName) => () => { | |
this.setState(state => ({ | |
...state, | |
...this.switchRouteTitleAndSubtitle(routeName), | |
routeName, | |
})) | |
} | |
selectedRoute = () => { | |
const { routeName, subRoute, userSubscriptionInfo, fieldValues: { changePassword: { confirmPasswordWarning } }, loadingChangePassword, isMobile } = this.state; | |
const { user: { name, login, id, payerInfo }, accessToken, user } = this.props.auth.accessToken; | |
if(subRoute) { | |
switch(subRoute) { | |
case 'switch-plan': | |
return <SwitchPlan | |
plans={this.props.plans} | |
isMobile={isMobile} | |
userSubscription={user.subscription} | |
payerInfo={payerInfo} | |
userAccessToken={accessToken} | |
getPlansPublisher={() => this.props.getPlansPublisher(accessToken.accessToken, this.props.publisher.id)} | |
userSubscriptionInfo={userSubscriptionInfo} | |
handleGetUserSubscriptionData={this.handleGetUserSubscriptionData} | |
handleShowFullModal={this.handleShowFullModal} | |
uid={id} | |
refreshUserData={this.props.refreshUserData} | |
/> | |
case 'edit-payment-method': | |
return <EditPaymentInfo | |
uid={id} | |
isMobile={isMobile} | |
returnScreen={this.switchSubRouteTitleAndSubtitle('return')} | |
updateUserCreditCard={this.props.updateUserCreditCard} | |
userAccessToken={accessToken} | |
pagarMeEncryptKey={this.props.publisher.pagarMeEncryptKey} | |
errors={this.state.fieldValues.editCreditCard.errors} | |
handleError={this.handleError('editCreditCard')} | |
payerInfo={payerInfo} | |
handleInputChange={this.handleInputChange('editCreditCard')} | |
fieldValues={this.state.fieldValues.editCreditCard} | |
/> | |
case 'change-password': | |
return <ChangePassword | |
fieldValues={this.state.fieldValues} | |
handleChangeUserPassword={this.handleChangeUserPassword} | |
handleInputChange={this.handleInputChange('changePassword')} | |
confirmPasswordWarning={confirmPasswordWarning} | |
loadingChangePassword={loadingChangePassword} | |
errors={this.state.fieldValues.changePassword.errors} | |
handleError={this.handleError('changePassword')} | |
isPasswordStrong={this.isPasswordStrong} | |
isMobile={isMobile} | |
/> | |
} | |
} else { | |
switch(routeName) { | |
case 'user-data': | |
return <UserData | |
username={name} | |
email={login} | |
fieldValues={this.state.fieldValues} | |
handleInputChange={this.handleInputChange('personalData')} | |
uid={id} | |
accessToken={accessToken} | |
oldUserData={this.props.auth} | |
authUpdateToken={this.props.authUpdateToken} | |
switchSubRouteTitleAndSubtitle={this.switchSubRouteTitleAndSubtitle} | |
handleShowFullModal={() => this.handleShowFullModal(() => UserService.deleteUser(id, accessToken), 'delete-account')} | |
isMobile={isMobile} | |
handleError={this.handleError('personalData')} | |
/> | |
case 'user-favorites': | |
return <MyFavorites items={this.state.userFavorites} items_collection={this.state.userFavoritesCollection}/> | |
case 'subscription-data': | |
return <SubscriptionData | |
{...this.state} | |
openCheckOut={this.props.openDialog} | |
payerInfo={user.payerInfo} | |
switchSubRouteTitleAndSubtitle={this.switchSubRouteTitleAndSubtitle} | |
userSubscription={user.subscription} | |
userSubscriptionInfo={userSubscriptionInfo} | |
handleShowFullModal={this.handleShowFullModal} | |
revenueModel={this.props.publisher.revenueModel} | |
userAccessToken={accessToken} | |
plans={this.props.plans} | |
uid={id} | |
userStatus={user.status} | |
refreshUserData={this.props.refreshUserData} | |
voucherInfo={user.voucher} | |
/> | |
case 'transactional-data': | |
return <TransactionalData collections={this.props.collection} /> | |
default: | |
return null | |
} | |
} | |
} | |
switchRouteTitleAndSubtitle = (routeName) => { | |
this.switchSubRouteTitleAndSubtitle()() | |
switch(routeName) { | |
case 'user-data': | |
return { | |
routeTitle: 'Meus Dados', | |
routeSubtitle: 'Configure seus dados pessoais aqui.' | |
} | |
case 'user-favorites': | |
return { | |
routeTitle: 'Meus Favoritos', | |
routeSubtitle: 'Confira os seus conteúdos favoritos.' | |
} | |
case 'subscription-data': | |
return { | |
routeTitle: 'Assinatura', | |
routeSubtitle: 'Gerencie aqui seu plano.' | |
} | |
case 'transactional-data': | |
return { | |
routeTitle: 'Meus Conteúdos', | |
routeSubtitle: 'Confira aqui seus conteúdos.' | |
} | |
default: | |
return { | |
routeTitle: '-', | |
routeSubtitle: '-' | |
} | |
} | |
} | |
switchSubRouteTitleAndSubtitle = (subRouteName) => () => { | |
// console.log('PROPS: ', ) | |
switch(subRouteName) { | |
case 'switch-plan': | |
return this.setState(state => ({ | |
...state, | |
subRoute: subRouteName, | |
subRouteTitle: 'Alterar Plano', | |
subRouteSubtitle: `Escolha um novo plano. Ele só será ativado e cobrado em $${moment(this.props.auth.accessToken.user.subscription.currentPeriodEnd).add(1, 'd').format('DD/MMMM/YYYY').replace('/',' de ').replace('/',' de ')}` | |
})) | |
case 'edit-payment-method': | |
let subRouteSubtitle = ''; | |
if(this.props.auth.accessToken.user.payerInfo.method === 'CREDIT_CARD') { | |
subRouteSubtitle = 'cartão de final ' + this.props.auth.accessToken.user.payerInfo.cardLastDigits | |
} else if (this.props.auth.accessToken.user.payerInfo.method === 'BOLETO') { | |
subRouteSubtitle = 'boleto' | |
} | |
return this.setState(state => ({ | |
...state, | |
subRoute: subRouteName, | |
subRouteTitle: 'Pagamento', | |
subRouteSubtitle: `Atualmente o seu plano é renovado no ${subRouteSubtitle}.<br/> ` | |
})) | |
case 'change-password': | |
return this.setState(state => ({ | |
...state, | |
subRoute: subRouteName, | |
subRouteTitle: 'Alterar Senha', | |
subRouteSubtitle: '' | |
})) | |
case 'return': | |
return this.setState(state => ({ | |
...state, | |
subRoute: undefined, | |
subRouteTitle: '-', | |
subRouteSubtitle: '-', | |
})) | |
default: | |
return this.setState(state => ({ | |
...state, | |
subRoute: undefined, | |
subRouteTitle: '-', | |
subRouteSubtitle: '-', | |
})) | |
} | |
} | |
handleInputChange = (area) => (name) => (e) => { | |
const value = e.target.value; | |
// if(name === 'cpf') { | |
// this.setState(state => ({ | |
// ...state, | |
// fieldValues: { | |
// ...state.fieldValues, | |
// [area]: { | |
// ...state.fieldValues[area], | |
// cpf: value, | |
// errors: validate({cpf: value}) | |
// } | |
// } | |
// })) | |
// } else { | |
this.setState(state => ({ | |
...state, | |
fieldValues: { | |
...state.fieldValues, | |
[area]: { | |
...state.fieldValues[area], | |
[name]: value, | |
} | |
} | |
})) | |
// } | |
} | |
checkIfUserCanSubmitNewPassword = (currentPassword, newPassword, confirmNewPassword) => { | |
if(!this.isPasswordStrong(newPassword)) { | |
return 'weak'; | |
} | |
if(newPassword !== confirmNewPassword) { | |
return 'different'; | |
} | |
if(currentPassword === '' || newPassword === '' || confirmNewPassword === '') { | |
return 'empty'; | |
} | |
return 'none'; | |
} | |
handleUserLogout = () => { | |
const {publisher, auth: {accessToken}} = this.props; | |
if(accessToken.accessToken){ | |
this.props.authUserLogout(accessToken.accessToken , publisher); | |
} | |
} | |
} | |
class TransactionalData extends React.Component { | |
render() { | |
if(!this.props.collections || !this.props.collections.data) { | |
return null | |
} | |
if(this.props.collections.data.length === 0) { | |
return ( | |
<SubscriptionDataWrapper> | |
<div className="sign__now"> | |
<Television className="television__icon" /> | |
<div> | |
<h3>Compre coleções e tenha<br/>acesso a conteúdos exclusivos</h3> | |
<button onClick={() => window.location.href='/'} className="call__to__action small__label">Ver todos os conteúdos</button> | |
</div> | |
</div> | |
</SubscriptionDataWrapper> | |
) | |
} | |
return( | |
<TransactionalDataWrapper> | |
{/* <Collection /> */} | |
{ | |
this.props.collections.data.map(collection => ( | |
<Collection {...collection} key={collection.id} /> | |
)) | |
} | |
</TransactionalDataWrapper> | |
) | |
} | |
} | |
const Collection = ({title, totalMedias, totalDuration, accessInfo, bannerUrl, watchedDuration, collectionProgress, id}) => { | |
function truncate(title){ | |
if (title.length > 22) | |
return title.substring(0,22)+'...'; | |
else | |
return title; | |
}; | |
return ( | |
<CollectionWrapper bannerUrl={bannerUrl}> | |
<div className="hero__image"> | |
{ | |
(accessInfo && accessInfo.expireAt) && <p className="available__until">Disponível até <b>{moment(accessInfo.expireAt).format('DD MMM YYYY')}</b></p> | |
} | |
<LinkSlug | |
route='colecao' | |
collectionType | |
collectionSlug={title} | |
identifier={{ id }} | |
lowerCase | |
> | |
<div className="cta"> | |
<i className="material-icons">play_arrow</i> | |
<span>{collectionProgress ? 'Continuar Assistindo' : 'Assistir'}</span> | |
</div> | |
</LinkSlug> | |
</div> | |
<div className="collection__info"> | |
<p>{truncate(title)}</p> | |
<div className="collection_statistics"> | |
<span> | |
<i className="material-icons">ondemand_video</i> {totalMedias} vídeos | |
</span> | |
<span> | |
<i className="material-icons">access_time</i> {Math.floor(totalDuration/60000)} min | |
</span> | |
</div> | |
{/* <span className="more"><i className="material-icons">expand_more</i> ver mais</span> */} | |
</div> | |
</CollectionWrapper> | |
) | |
} | |
const LeftNavigator = ({routeName, profilePictureUrl, username, switchRoute, handleUserLogout, publisherRevenueType, isMobile}) => ( | |
<div className="left__navigator"> | |
<div className="user__initial" style={{backgroundImage: `url(${profilePictureUrl ? profilePictureUrl : undefined})`}}> | |
{!profilePictureUrl && username[0]} | |
</div> | |
<p className="user__name">{username}</p> | |
{ | |
publisherRevenueType === 'SUBSCRIPTION' | |
&& <ButtonNavigator idBtn="btnSignature" switchRoute={switchRoute} currentRoute={routeName} routeName="Assinatura" route="subscription-data" iconName="confirmation_number" /> | |
} | |
{ | |
publisherRevenueType === 'TRANSACTIONAL' | |
&& <ButtonNavigator idBtn="btnMyContents" switchRoute={switchRoute} currentRoute={routeName} routeName="Meus Conteúdos" route="transactional-data" iconName="ondemand_video" /> | |
} | |
<ButtonNavigator switchRoute={switchRoute} currentRoute={routeName} routeName="Meus dados" route="user-data" iconName="person" /> | |
<ButtonNavigator switchRoute={switchRoute} currentRoute={routeName} routeName="Meus favoritos" route="user-favorites" iconName="favorite" /> | |
<span onClick={handleUserLogout} className="sign__out"> | |
<i className="material-icons">power_settings_new</i> | |
Sair | |
</span> | |
</div> | |
) | |
const ButtonNavigator = ({idBtn, currentRoute, switchRoute, route, iconName, routeName}) => ( | |
<button id={idBtn} onClick={switchRoute(route)} className={currentRoute === route ? 'selected' : undefined }> | |
<div> | |
<i className="material-icons">{iconName}</i> | |
<span>{routeName}</span> | |
</div> | |
<i className="material-icons">keyboard_arrow_right</i> | |
</button> | |
) | |
const SubscriptionData = ({voucherInfo, userStatus, paymentStatus, switchSubRouteTitleAndSubtitle, userSubscription, payerInfo, openCheckOut, userSubscriptionInfo, isMobile, handleShowFullModal, revenueModel, userAccessToken, plans, uid, refreshUserData}) => { | |
switchSubRouteTitleAndSubtitle('switch-plan') | |
const handleGoToCheckout = () => { | |
openCheckOut('PLANS', null); | |
window.location.href='/'; | |
} | |
if(userStatus === 'VOUCHER' && voucherInfo && voucherInfo.periodEnd > Date.now() && voucherInfo.status === 'ACTIVE') { | |
return <SubscriptionDataWrapper> | |
<div className="sign__now"> | |
<Television className="television__icon" /> | |
<div style={{justifyContent: 'center'}}> | |
<h3 style={{margin: 0}}>Seu voucher está ativo!</h3> | |
</div> | |
</div> | |
</SubscriptionDataWrapper> | |
} | |
if((!userSubscription || !userSubscriptionInfo) || (userSubscription.status === 'UNPAID' || userSubscription.status === 'ENDED')) { | |
return ( | |
<SubscriptionDataWrapper> | |
<div className="sign__now"> | |
<Television className="television__icon" /> | |
<div> | |
{ | |
revenueModel === 'SUBSCRIPTION' | |
? <> | |
<h3>Assine agora e acesse<br/>conteúdos exclusivos</h3> | |
<button onClick={handleGoToCheckout} className="call__to__action small__label">Assinar agora</button> | |
</> | |
: <> | |
<h3>Compre coleções e tenha<br/>acesso a conteúdos exclusivos</h3> | |
<button onClick={() => window.location.href='/'} className="call__to__action small__label">Ver todos os conteúdos</button> | |
</> | |
} | |
</div> | |
</div> | |
</SubscriptionDataWrapper> | |
) | |
} | |
const { method } = payerInfo; | |
console.log('userSubscriptionInfo: ', userSubscriptionInfo) | |
console.log('userSubscription: ', userSubscription) | |
if(userSubscription.status === 'PENDING_PAYMENT') { | |
return( | |
<SubscriptionDataWrapper> | |
<p className="additional__info">O pagamento pode levar até 48h para ser <br/>reconhecido e o acesso liberado para consumo.</p> | |
{ | |
method === 'CREDIT_CARD' | |
&& <> | |
{ | |
!isMobile && <p id="change-credit-card" className="clear__button" onClick={switchSubRouteTitleAndSubtitle('edit-payment-method')}>Alterar Cartão de Crédito</p> | |
} | |
</> | |
} | |
</SubscriptionDataWrapper> | |
) | |
} | |
if(userSubscription.status === 'CANCELED') { | |
return ( | |
<SubscriptionDataWrapper> | |
<div className="subscription__box canceled"> | |
<h3>{userSubscriptionInfo.nextPlan ? userSubscriptionInfo.nextPlan.name : userSubscriptionInfo.name}</h3> | |
<p className="plan__period">{translatePlan[userSubscriptionInfo.nextPlan ? userSubscriptionInfo.nextPlan.period : userSubscriptionInfo.period]}</p> | |
<p className="next__billing">Assinatura cancelada.{isMobile && <br/>} Acesse ate <span>{moment(userSubscription.currentPeriodEnd).format('DD MMM YYYY')}</span></p> | |
{ | |
userSubscriptionInfo.nextPlan | |
? <h3 className="plan__value">{planPeriodicity[userSubscriptionInfo.nextPlan.period]}x R$ {(userSubscriptionInfo.nextPlan.amount/(planPeriodicity[userSubscriptionInfo.nextPlan.period]*100)).toFixed(2).replace('.', ',')}</h3> | |
: <h3 className="plan__value">{userSubscription.installments}x R$ {(userSubscription.amount/(userSubscription.installments*100)).toFixed(2).replace('.', ',')}</h3> | |
} | |
</div> | |
{ | |
moment(userSubscription.currentPeriodEnd).isBefore(moment()) && <SubmitButton id="btnSignAgain" isMobile={isMobile} marginTop="15px" onClick={handleGoToCheckout}>Assinar Novamente</SubmitButton> | |
} | |
</SubscriptionDataWrapper> | |
) | |
} | |
return ( | |
<SubscriptionDataWrapper> | |
{ | |
method !== 'no-plan' && | |
<div className="subscription__box"> | |
<div> | |
<h3>{userSubscriptionInfo.nextPlan ? userSubscriptionInfo.nextPlan.name : userSubscriptionInfo.name}</h3> | |
{ | |
(!isMobile && plans && plans.resp && plans.resp.data && plans.resp.data.length > 1 && method !== 'BOLETO') | |
&& <p id="change-plan" className="clear__button change__plan" onClick={switchSubRouteTitleAndSubtitle('switch-plan')}>Alterar Plano</p> | |
} | |
</div> | |
<p className="plan__period">{translatePlan[userSubscriptionInfo.nextPlan ? userSubscriptionInfo.nextPlan.period : userSubscriptionInfo.period]}</p> | |
{/* Credit card payment method */} | |
{ | |
method === 'CREDIT_CARD' | |
&& <> | |
<p className="next__billing">Próxima cobrança em {isMobile && <br/>}<span>{moment(userSubscription.currentPeriodEnd).format('DD MMM YYYY')}</span> no cartão {isMobile && <br/>}**** **** **** {payerInfo.cardLastDigits}</p> | |
{ | |
!isMobile && <p id="change-credit-card" className="clear__button" onClick={switchSubRouteTitleAndSubtitle('edit-payment-method')}>Alterar Cartão de Crédito</p> | |
} | |
</> | |
} | |
{/* Boleto payment method, it has three states: 'up_to_date', 'awaiting_plan_renewal' and 'awaiting_first_payment' */} | |
{ | |
method === 'BOLETO' | |
&& <> | |
{/* Each paymentStatus has it's own context */} | |
{ | |
paymentStatus === 'up_to_date' | |
&& <p className="next__billing">Próxima cobrança em <span>23 mai 2018</span> no Boleto Bancário</p> | |
} | |
{ | |
paymentStatus === 'awaiting_plan_renewal' | |
&& <> | |
<p className="next__billing">Boleto para renovação em <span>23 mai 2018</span></p> | |
<p className="clear__button">Baixar boleto</p> | |
</> | |
} | |
{ | |
paymentStatus === 'awaiting_first_payment' | |
&& <> | |
<p className="next__billing">Aguardando pagamento...</p> | |
<button className="call__to__action"> | |
Baixar Boleto | |
</button> | |
</> | |
} | |
</> | |
} | |
{ | |
!(method === 'boleto' && paymentStatus === 'awaiting_first_payment') | |
&& userSubscriptionInfo.nextPlan | |
? <h3 className="plan__value">{planPeriodicity[userSubscriptionInfo.nextPlan.period]}x R$ {(userSubscriptionInfo.nextPlan.amount/(planPeriodicity[userSubscriptionInfo.nextPlan.period]*100)).toFixed(2).replace('.', ',')}</h3> | |
: <h3 className="plan__value">{userSubscription.installments}x R$ {(userSubscription.amount/(userSubscription.installments*100)).toFixed(2).replace('.', ',')}</h3> | |
} | |
</div> | |
} | |
{/* { | |
method === 'no-plan' | |
&& <div className="sign__now"> | |
<Television className="television__icon" /> | |
<div> | |
<h3>Assine agora e acesse<br/>conteúdos exclusivos</h3> | |
<button onClick={() => window.location.href='/'} className="call__to__action small__label">Assinar agora</button> | |
</div> | |
</div> | |
} */} | |
{ | |
isMobile | |
? <div className="mobile__action__buttons"> | |
{ | |
(plans && plans.resp && plans.resp.data && plans.resp.data.length > 1 && method !== 'BOLETO') | |
&& <p id="change-plan" className="clear__button change__plan" onClick={switchSubRouteTitleAndSubtitle('switch-plan')}>Alterar Plano</p> | |
} | |
<p id="change-credit-card" className="clear__button" onClick={switchSubRouteTitleAndSubtitle('edit-payment-method')}>Alterar Cartão de Crédito</p> | |
<p id="cancel-subscription" className="clear__button cancel__subscription" onClick={() => handleShowFullModal(() => UserService.cancelSubscription(userAccessToken, uid, refreshUserData, () => window.location.href='/settings'), 'cancel-subscription')}>Cancelar Assinatura</p> | |
</div> | |
: <div className="action__buttons"> | |
<p id="cancel-subscription" className="clear__button cancel__subscription" onClick={() => handleShowFullModal(() => UserService.cancelSubscription(userAccessToken, uid, refreshUserData, () => window.location.href='/settings'), 'cancel-subscription')}>Cancelar Assinatura</p> | |
</div> | |
} | |
</SubscriptionDataWrapper> | |
) | |
} | |
class MyFavorites extends React.PureComponent { | |
state = { | |
tab: 'media', | |
} | |
render() { | |
const {items, items_collection} = this.props; | |
console.log('items: ', items_collection) | |
return ( | |
<div> | |
<div style={{ display: 'flex', alignItems: 'center', width: '100%', borderBottom: '1px solid #B3B8BF', height: 50, marginBottom: 30}}> | |
<div onClick={this.handleChangeTab('collection')} style={{ display: 'flex', height: '100%', justifyContent: 'center', alignItems: 'center', width: 100, color: this.state.tab === 'collection' ? 'black' : '#B3B8BF', fontWeight: this.state.tab === 'collection' ? 'bold' : 'normal', borderBottom: this.state.tab === 'collection' ? '1px solid black' : '0', cursor: 'pointer' }}> | |
<p>Coleções</p> | |
</div> | |
<div onClick={this.handleChangeTab('media')} style={{ display: 'flex', height: '100%', justifyContent: 'center', alignItems: 'center', width: 100, color: this.state.tab === 'media' ? 'black' : '#B3B8BF', fontWeight: this.state.tab === 'media' ? 'bold' : 'normal', borderBottom: this.state.tab === 'media' ? '1px solid black' : '0', cursor: 'pointer' }}> | |
<p>Vídeos</p> | |
</div> | |
</div> | |
{ | |
this.state.tab === 'media' | |
? <div> | |
<div style={{ display: "flex", flexDirection: "row", flexWrap: "wrap" }}> | |
{ | |
items && | |
map(items, (item) => ( | |
<SingleFavorite item={item} type="media" /> | |
)) | |
} | |
{ items.length > 0 ? | |
<div /> | |
: | |
<div>Nenhum vídeo marcado como favorito no momento.</div> | |
} | |
</div> | |
</div> | |
: <div> | |
{ | |
items_collection && | |
map(items_collection, (item) => ( | |
<SingleFavorite item={item} type="collection" /> | |
)) | |
} | |
{items_collection.length > 0 ? | |
<div /> | |
: | |
<div>Nenhum vídeo marcado como favorito no momento.</div> | |
} | |
</div> | |
} | |
</div> | |
) | |
} | |
handleChangeTab = (tab) => () => { | |
this.setState({ | |
tab | |
}) | |
} | |
} | |
const SingleFavorite = (props) => { | |
const { item, type } = props; | |
const { mediaFiles, name, duration, id } = item; | |
function truncate(title){ | |
if (title.length > 50) | |
return title.substring(0,50)+'...'; | |
else | |
return title; | |
}; | |
if(type === 'collection') { | |
return ( | |
<div style={{display: 'flex', flexDirection: 'column', maxWidth: 280, height: 55, marginRight: 25}}> | |
<LinkSlug | |
route='colecao' | |
collectionType | |
collectionSlug={item.title} | |
identifier={{ id }} | |
lowerCase | |
> | |
<img style={{ width: 280, height: 130, minHeight: 130, borderRadius: 4 }} src={item.bannerUrl} /> | |
<div style={{minHeight: 60}}> | |
<p style={{ fontSize: 16, fontWeight: '600', marginTop: 10 }}>{truncate(item.title)}</p> | |
</div> | |
</LinkSlug> | |
<div style={{display: 'flex', width: '100%', marginTop: 5, justifyContent: 'space-between'}}> | |
<span style={{display: 'flex', alignItems: 'center', fontSize: 12}}><i style={{marginRight: 5, fontSize: 12}} className="material-icons">access_time</i> {Math.floor(duration/60000)} min</span> | |
<i style={{marginRight: 5, fontSize: 12, color: 'red'}} className="material-icons">favorite</i> | |
</div> | |
</div> | |
) | |
} | |
return ( | |
<div style={{display: 'flex', flexDirection: 'column', maxWidth: 280, height: 55, marginRight: 25}}> | |
<LinkSlug | |
route={type === 'media' ? 'midia' : 'colecao'} | |
collectionType={type === 'collection'} | |
collectionSlug={type === 'collection' ? name : 'a' } | |
mediaSlug={type === 'media' ? name : undefined} | |
identifier={{ idCollection: type === 'media' ? 'aa' : undefined, idMedia: id }} | |
lowerCase | |
> | |
<img style={{ width: 280, height: 130, minHeight: 130, borderRadius: 4 }} src={mediaFiles[0].progressiveUrl} /> | |
<div style={{minHeight: 60}}> | |
<p style={{ fontSize: 16, fontWeight: '600', marginTop: 10 }}>{truncate(name)}</p> | |
</div> | |
</LinkSlug> | |
<div style={{display: 'flex', width: '100%', marginTop: 5, justifyContent: 'space-between'}}> | |
{ | |
duration | |
? <span style={{display: 'flex', alignItems: 'center', fontSize: 12}}><i style={{marginRight: 5, fontSize: 12}} className="material-icons">access_time</i> {Math.floor(duration/60000)} min</span> | |
: <span/> | |
} | |
<i style={{marginRight: 5, fontSize: 12, color: 'red'}} className="material-icons">favorite</i> | |
</div> | |
</div> | |
) | |
} | |
const UserData = ({id, previewProfilePictureUrl, username, email, handleInputChange, fieldValues, uid, accessToken, oldUserData, authUpdateToken, switchSubRouteTitleAndSubtitle, handleShowFullModal, isMobile, handleError}) => { | |
return ( | |
<UserDataWrapper> | |
<div className="profile__picture__edition"> | |
<div className="profile__picture__preview" style={{backgroundImage: `url(${previewProfilePictureUrl ? previewProfilePictureUrl : undefined})`}}> | |
{!previewProfilePictureUrl && username[0]} | |
</div> | |
{ | |
!isMobile && | |
<span> | |
<i className="material-icons">photo_camera</i> | |
Alterar Foto | |
</span> | |
} | |
</div> | |
{ | |
isMobile | |
? <div className="personal__data__edition"> | |
<div className="field__row"> | |
<EditionField idInput="idName" label="Nome" onChange={handleInputChange('name')} value={fieldValues.personalData.name} fullWidth handleError={handleError('name')} validations={{required: true, maxSize: 45}} maxLength={45}/> | |
</div> | |
<div className="field__row"> | |
<EditionField idInput="idLastName" label="Sobrenome" optional onChange={handleInputChange('lastName')} value={fieldValues.personalData.lastName} fullWidth handleError={handleError('lastName')} maxLength={45}/> | |
</div> | |
<div className="field__row"> | |
<EditionField idInput="idCPF" label="CPF" optional onChange={handleInputChange('cpf')} value={fieldValues.personalData.cpf} fullWidth mask={[/\d/, /\d/, /\d/, '.', /\d/, /\d/, /\d/, '.', /\d/, /\d/, /\d/, '-', /\d/, /\d/]} handleError={handleError('cpf')} validations={{cpf: true, required: true}}/> | |
</div> | |
<div className="field__row"> | |
<EditionField idInput="idEmail" label="E-mail" email={email} disabled fullWidth/> | |
</div> | |
</div> | |
: <div className="personal__data__edition"> | |
<div className="field__row"> | |
<EditionField idInput="idName" label="Nome" onChange={handleInputChange('name')} value={fieldValues.personalData.name} handleError={handleError('cpf')} validations={{required: true, maxSize: 45}} maxLength={45}/> | |
<span /> | |
<EditionField idInput="idLastName" label="Sobrenome" optional onChange={handleInputChange('lastName')} value={fieldValues.personalData.lastName} maxLength={45}/> | |
</div> | |
<div className="field__row"> | |
<EditionField idInput="idCPF" label="CPF" optional onChange={handleInputChange('cpf')} value={fieldValues.personalData.cpf} mask={[/\d/, /\d/, /\d/, '.', /\d/, /\d/, /\d/, '.', /\d/, /\d/, /\d/, '-', /\d/, /\d/]} handleError={handleError('cpf')} validations={{cpf: true, required: true}}/> | |
<span /> | |
<EditionField idInput="idEmail" label="E-mail" email={email} disabled /> | |
</div> | |
</div> | |
} | |
<SubmitButton id="btnSave" isMobile={isMobile} disabled={fieldValues.personalData.errors.length > 0} className="submit__edition" onClick={UpdateUserData({fieldValues, uid, email, accessToken, oldUserData, authUpdateToken})}>Salvar</SubmitButton> | |
<div className="secondary__options"> | |
<span id="idChangePassword" onClick={switchSubRouteTitleAndSubtitle('change-password')}>Alterar Senha</span> | |
<span id="idDeleteAccount" onClick={handleShowFullModal} className="danger__option">Excluir Conta</span> | |
</div> | |
</UserDataWrapper> | |
) | |
} | |
class ChangePassword extends React.PureComponent { | |
state = { | |
visibility: { | |
currentPassword: true, | |
newPassword: true, | |
confirmNewPassword: true | |
} | |
} | |
render() { | |
const { handleChangeUserPassword, handleInputChange, confirmPasswordWarning, loadingChangePassword, handleError, errors, fieldValues, isMobile } = this.props; | |
const { visibility } = this.state; | |
return ( | |
<ChangePasswordWrapper> | |
<div className="password__wrapper" > | |
<i className="material-icons" onClick={this.switchVisibility('currentPassword')}>{visibility.currentPassword ? 'visibility' : 'visibility_off'}</i> | |
<EditionField idInput="idCurrentPassword" handleError={handleError('currentPassword')} onChange={handleInputChange('currentPassword')} label="Senha atual" fullWidth password={visibility.currentPassword} value={fieldValues.changePassword.currentPassword} validations={{required: true, wrongPassword: fieldValues.changePassword.confirmPasswordWarning === 'wrong-password'}} /> | |
</div> | |
<div className="horizontal__line" /> | |
<div className="password__wrapper" > | |
<i className="material-icons" onClick={this.switchVisibility('newPassword')}>{visibility.newPassword ? 'visibility' : 'visibility_off'}</i> | |
<EditionField idInput="idNewPassword" handleError={handleError('newPassword')} validations={{required: true, passwordStrength: true}} onChange={handleInputChange('newPassword')} label="Nova senha" fullWidth password={visibility.newPassword} value={fieldValues.changePassword.newPassword}/> | |
</div> | |
<div className="password__wrapper" > | |
<i className="material-icons" onClick={this.switchVisibility('confirmNewPassword')}>{visibility.confirmNewPassword ? 'visibility' : 'visibility_off'}</i> | |
<EditionField idInput="idConfirmNewPassword" handleError={handleError('confirmNewPassword')} validations={{required: true, confirmNewPassword: fieldValues.changePassword.newPassword}} onChange={handleInputChange('confirmNewPassword')} label="Confirmar nova senha" fullWidth password={visibility.confirmNewPassword} value={fieldValues.changePassword.confirmNewPassword}/> | |
</div> | |
<SubmitButton isMobile={isMobile} disabled={loadingChangePassword || errors.length > 0} onClick={handleChangeUserPassword}> | |
{ | |
loadingChangePassword | |
? 'Carregando...' | |
: 'Salvar' | |
} | |
</SubmitButton> | |
</ChangePasswordWrapper> | |
) | |
} | |
switchVisibility = (fieldName) => () => { | |
this.setState(state => ({ | |
...state, | |
visibility: { | |
...state.visibility, | |
[fieldName]: !state.visibility[fieldName] | |
} | |
})) | |
} | |
} | |
const UpdateUserData = ({fieldValues, uid, email, accessToken, oldUserData, authUpdateToken}) => () => { | |
const newUserData = { | |
id: uid, | |
name: fieldValues.personalData.name, | |
lastName: fieldValues.personalData.lastName, | |
cpf: fieldValues.personalData.cpf, | |
email, | |
address: null | |
} | |
UserService.updateUser(uid, accessToken, newUserData, oldUserData, authUpdateToken) | |
} | |
const UpdateUserCache = (uid) => { | |
UserService.refreshUserData(uid); | |
} | |
class EditionField extends React.PureComponent { | |
state = {} | |
componentDidUpdate() { | |
if(this.props.validations && this.props.validations.wrongPassword && !this.state.alreadyShowedWarning) { | |
this.setState({ | |
warningMessage: this.warningMessages['wrong-password'], | |
alreadyShowedWarning: true, | |
}) | |
} | |
} | |
render() { | |
const { idInput, label, disabled, optional, email, value, onChange, fullWidth, password, mask, upperCase, margin, maxlength} = this.props | |
const { warningMessage } = this.state; | |
return ( | |
<EditionFieldWrapper fullWidth={fullWidth} warning={warningMessage} margin={margin}> | |
{ | |
optional | |
? <div className="optional__wrapper"> | |
<p className="label">{label}</p> | |
<span>opcional</span> | |
</div> | |
: <p className="label">{label}</p> | |
} | |
{ | |
disabled | |
? <div id={idInput} className="disabled__field">{email}</div> | |
: mask | |
? <MaskedInput | |
id={idInput} | |
onChange={onChange} value={value} | |
mask={mask} | |
onBlur={this.validateField} | |
maxlength={maxlength} | |
/> | |
: <input id={idInput} maxlength={maxlength} type={password ? 'password' : 'text'} onChange={onChange} onBlur={this.validateField} value={value} style={{textTransform: upperCase ? 'uppercase' : undefined}} /> | |
} | |
{ warningMessage && <p className="warning__message">{warningMessage}</p>} | |
</EditionFieldWrapper> | |
) | |
} | |
validateField = () => { | |
const { value, validations = {}, handleError } = this.props; | |
// console.log('Validation: ', validations) | |
// console.log('VALUE: ', value) | |
let msg; | |
if(validations.creditCard) { | |
try { | |
msg = validate({numCard: value}).numCard; | |
} catch(err) { | |
msg = 'Oops, número de cartão incorreto'; | |
} | |
} | |
if(validations.required && (value === '' || !value)) { | |
this.setState({ | |
warningMessage: this.warningMessages['empty'] | |
}) | |
handleError('add') | |
} else if(validations.date && (moment(value, 'MM/YY').isBefore(moment()) || !moment(value, 'MM/YY').isValid())) { | |
this.setState({ | |
warningMessage: this.warningMessages['invalid-date'] | |
}) | |
handleError('add') | |
} else if(validations.cpf && !!validate({cpf: value}).cpf) { | |
this.setState({ | |
warningMessage: validate({cpf: value}).cpf | |
}) | |
handleError('add') | |
} else if(validations.securityCode && !!validate({securityCodCard: value}).securityCodCard) { | |
this.setState({ | |
warningMessage: validate({securityCodCard: value}).securityCodCard | |
}) | |
handleError('add') | |
} else if(validations.creditCard && !!msg) { | |
this.setState({ | |
warningMessage: msg, | |
}) | |
handleError('add') | |
} else if(validations.passwordStrength && !this.isPasswordStrong(value)) { | |
this.setState({ | |
warningMessage: this.warningMessages['weak-password'], | |
}) | |
handleError('add') | |
} else if(validations.confirmNewPassword && validations.confirmNewPassword !== value) { | |
this.setState({ | |
warningMessage: this.warningMessages['different-passwords'], | |
}) | |
handleError('add') | |
} else if(validations.wrongPassword) { | |
this.setState({ | |
warningMessage: undefined, | |
}) | |
} else if(validations.maxSize && Number(value) > validations.maxSize) { | |
this.setState({ | |
warningMessage: this.warningMEssages['too-large'] | |
}) | |
handleError('add') | |
} else { | |
this.setState({ | |
warningMessage: undefined | |
}) | |
handleError('remove') | |
} | |
} | |
isPasswordStrong(strPassword) { | |
function countContain(strPassword, strCheck) | |
{ | |
// Declare variables | |
var nCount = 0; | |
var i; | |
for (i = 0; i < strPassword.length; i++) | |
{ | |
if (strCheck.indexOf(strPassword.charAt(i)) > -1) | |
{ | |
nCount++; | |
} | |
} | |
return nCount; | |
} | |
var m_strNumber = "0123456789"; | |
var nNumberCount = countContain(strPassword, m_strNumber); | |
// -- 7 or less characters | |
if (strPassword.length < 8) | |
{ | |
return false | |
} | |
// -- 0 numbers | |
if (nNumberCount < 1) | |
{ | |
return false | |
} | |
return true; | |
} | |
warningMessages = { | |
'wrong-card-number': 'Oops, número do cartão incorreto', | |
'empty': 'Campo obrigatório', | |
'invalid-date': 'Data inválida', | |
'invalid-security-code': 'Código de segurança inválido', | |
'weak-password': 'Insira uma senha com pelo menos 8 caracteres e pelo menos 1 número.', | |
'different-passwords': 'Esta senha está diferente.', | |
'wrong-password': 'Senha incorreta.', | |
'too-large': 'Nome muito grande.' | |
} | |
} | |
class SwitchPlan extends React.PureComponent { | |
componentDidMount() { | |
this.props.getPlansPublisher() | |
} | |
sliderSettings = { | |
dots: true, | |
infinite: false, | |
centerMode: true, | |
speed: 500, | |
slidesToShow: 1, | |
slidesToScroll: 1, | |
variableWidth: true | |
}; | |
render() { | |
const { plans, userSubscription, payerInfo, userAccessToken, userSubscriptionInfo, handleGetUserSubscriptionData, handleShowFullModal, isMobile, uid, refreshUserData } = this.props | |
if(!plans || !plans.resp || !plans.resp.data || !userSubscriptionInfo) { | |
return <div/> | |
} | |
// const plansList = plans.resp.data.map(plan => ( | |
// <Plan | |
// handleShowFullModal={handleShowFullModal} | |
// handleGetUserSubscriptionData={handleGetUserSubscriptionData} | |
// userAccessToken={userAccessToken} | |
// planId={plan.id} | |
// title={plan.name} | |
// rawPeriod={plan.period} | |
// period={plan.period} | |
// recommended={plan.defaultPlan} | |
// selected={plan.id === userSubscriptionInfo.id} | |
// payerInfo={payerInfo} | |
// price={plan.amount} | |
// /> | |
// )) | |
// if(isMobile) { | |
// return ( | |
// // <div style={{width: 200}}> | |
// // // <SwitchPlanWrapper> | |
// // <SliderWrapper style={{width:'100%'}}> | |
// // <Slider {...this.sliderSettings}> | |
// // <div> | |
// // <Plan title="Istambul" period="semestral" /> | |
// // </div> | |
// // {/* <div style={{width: 20}}> */} | |
// // <div> | |
// // <Plan title="Praga" period="anual" recommended /> | |
// // </div> | |
// // </Slider> | |
// // </SliderWrapper> | |
// ) | |
// } | |
const currentSubscriptionInfo = userSubscriptionInfo.nextPlan ? userSubscriptionInfo.nextPlan : userSubscriptionInfo | |
const isNextPlan = userSubscriptionInfo.nextPlan ? true : false | |
return ( | |
<SwitchPlanWrapper isMobile={isMobile}> | |
{ | |
plans.resp.data.map(plan => ( | |
<Plan | |
handleShowFullModal={handleShowFullModal} | |
handleGetUserSubscriptionData={handleGetUserSubscriptionData} | |
userAccessToken={userAccessToken} | |
planId={plan.id} | |
title={plan.name} | |
rawPeriod={plan.period} | |
period={plan.period} | |
recommended={plan.defaultPlan} | |
selected={plan.id === currentSubscriptionInfo.id} | |
userSubscriptionInfo={currentSubscriptionInfo} | |
payerInfo={payerInfo} | |
price={plan.amount} | |
isMobile={isMobile} | |
userSubscription={userSubscription} | |
uid={uid} | |
refreshUserData={refreshUserData} | |
isNextPlan={isNextPlan} | |
/> | |
)) | |
} | |
{/* <Plan title="San Francisco" period="trimestral" /> | |
<Plan title="Istambul" period="semestral" /> | |
<Plan title="Praga" period="anual" recommended /> */} | |
</SwitchPlanWrapper> | |
) | |
} | |
} | |
const translatePlan = { | |
MONTH: 'Mensal', | |
QUARTER: 'Trimestral', | |
HALF: 'Semestral', | |
YEAR: 'Anual' | |
} | |
const planPeriodicity = { | |
MONTH: 1, | |
QUARTER: 3, | |
HALF: 6, | |
YEAR: 12 | |
} | |
const Plan = ({selected, recommended, title, price, period, userAccessToken, planId, handleGetUserSubscriptionData, handleShowFullModal, isMobile, rawPeriod, userSubscriptionInfo, userSubscription, uid, refreshUserData, isNextPlan}) => { | |
let realPrice; | |
if(selected && !isNextPlan) { | |
realPrice = (userSubscriptionInfo.amount/(userSubscription.installments*100)).toFixed(2).split('.') | |
} else { | |
realPrice = (price/100/planModifier[rawPeriod]).toFixed(2).split('.') | |
} | |
const handlePlanClick = () => handleShowFullModal(() => UserService.changePlan(planId, userAccessToken, handleGetUserSubscriptionData, uid, refreshUserData), 'confirm-switch-plan', {selectedPlan: {title, price, period}}) | |
return ( | |
<PlanWrapper onClick={selected ? () => null : handlePlanClick}> | |
<PlanBox isMobile={isMobile} className={selected ? 'selected' : ''} selected={selected}> | |
<h4>{title}</h4> | |
<label>{translatePlan[period]}</label> | |
{ // {userSubscription.installments}x R$ {(userSubscriptionInfo.amount/(userSubscription.installments*100)).toFixed(2).replace('.', ',')} | |
(selected && !isNextPlan) | |
? <p><b>{userSubscription.installments}x</b> R$ <span className="bigger">{realPrice[0]},</span><span className="cents">{realPrice[1]}</span></p> | |
: <p>R$ <span className="bigger">{realPrice[0]},</span><span className="cents">{realPrice[1]}</span></p> | |
} | |
<label>{(!selected && !isNextPlan) && 'por mês'}</label> | |
{/* <label>Ou R$ 158,47 à vista no boleto</label> */} | |
{ | |
selected | |
? <label className="last">Este é o seu <b>plano atual</b><br/><br/>Ele é automaticamente renovado<br/>a cada {transplatePlanToPhrase[rawPeriod]}</label> | |
: <label className="last">Este plano é automaticamente<br/>renovado a cada {transplatePlanToPhrase[rawPeriod]}</label> | |
} | |
</PlanBox> | |
</PlanWrapper> | |
) | |
} | |
const transplatePlanToPhrase = { | |
MONTH: 'mês', | |
QUARTER: '3 meses', | |
HALF: '6 meses', | |
YEAR: '12 meses' | |
} | |
const planModifier = { | |
MONTH: 1, | |
QUARTER: 3, | |
HALF: 6, | |
YEAR: 12 | |
} | |
class EditPaymentInfo extends React.PureComponent { | |
state = {} | |
componentDidMount() { | |
this.setState(state => ({ | |
...state, | |
currentEditingMethod: this.props.payerInfo.method | |
})) | |
} | |
render() { | |
const { currentEditingMethod } = this.state; | |
const { handleInputChange, fieldValues, handleError, errors, isMobile } = this.props; | |
switch(currentEditingMethod) { | |
case 'CREDIT_CARD': | |
return ( | |
<EditPaymentInfoWrapper> | |
<EditionField label="Número do Cartão" fullWidth mask={this.masks.creditCard} onChange={handleInputChange('number')} value={fieldValues.number} warning={true} validations={{required: true, creditCard: true}} handleError={handleError('number')} /> | |
<EditionField label="Nome igual ao cartão" upperCase fullWidth onChange={handleInputChange('holderName')} value={fieldValues.holderName} warning={true} validations={{required: true}} handleError={handleError('holderName')}/> | |
<div className="double__fields"> | |
<EditionField label="Validade" mask={this.masks.date} fullWidth onChange={handleInputChange('expirationDate')} value={fieldValues.expirationDate} warning={true} validations={{required: true, date: true}} handleError={handleError('expirationDate')}/> | |
<div style={{width:60}}/> | |
<EditionField label={isMobile ? "Código" : "Cod. Segurança"} mask={this.masks.security} fullWidth onChange={handleInputChange('securityCode')} value={fieldValues.securityCode} warning={true} validations={{required: true, securityCode: true}} handleError={handleError('securityCode')} /> | |
</div> | |
<SubmitButton isMobile={isMobile} disabled={errors.length > 0} onClick={this.handleUpdateCard}>Definir Cartão</SubmitButton> | |
{/* <div onClick={this.changeCurrentMethod('BOLETO')} className="secondary__options"> | |
<span>Trocar para boleto</span> | |
</div> */} | |
</EditPaymentInfoWrapper> | |
) | |
case 'BOLETO': | |
return ( | |
<EditPaymentInfoWrapper> | |
<EditionField label="CPF" fullWidth /*value={fieldValues.personalData.name}*/ /> | |
<SubmitButton isMobile={isMobile}>Definir Boleto</SubmitButton> | |
<div onClick={this.changeCurrentMethod('CREDIT_CARD')} className="secondary__options"> | |
<span>Trocar para cartão de crédito</span> | |
</div> | |
</EditPaymentInfoWrapper> | |
) | |
default: | |
return null | |
} | |
} | |
handleUpdateCard = async () => { | |
try { | |
const cardHash = await this.handleCreateCardHash() | |
UserService.updateCreditCardNumber( | |
cardHash, | |
this.props.userAccessToken, | |
this.props.updateUserCreditCard, | |
this.props.returnScreen, | |
this.props.uid, | |
this.props.refreshUserData | |
) | |
} catch(err) { | |
console.error(err) | |
} | |
} | |
handleCreateCardHash = () => | |
pagarme.client.connect({ encryption_key: this.props.pagarMeEncryptKey }) | |
.then(client => { | |
return client.security.encrypt({ | |
card_number: this.props.fieldValues.number, | |
card_holder_name: this.props.fieldValues.holderName, | |
card_expiration_date: this.props.fieldValues.expirationDate, | |
card_cvv: this.props.fieldValues.securityCode, | |
}) | |
}) | |
.then(card_hash => card_hash) | |
changeCurrentMethod = (nextMethod) => () => { | |
this.setState(state => ({ | |
...state, | |
currentEditingMethod: nextMethod, | |
})) | |
} | |
masks = { | |
creditCard: [/\d/, /\d/, /\d/, /\d/, ' ', /\d/, /\d/, /\d/, /\d/, ' ', /\d/, /\d/, /\d/, /\d/, ' ', /\d/, /\d/, /\d/, /\d/], | |
date: [/\d/, /\d/, '/', /\d/, /\d/], | |
security: [/\d/, /\d/, /\d/] | |
} | |
} | |
// const EditPaymentInfo = ({payerInfo, switchPaymentMethodEdition}) => { | |
// const { method } = payerInfo; | |
// console.log('PAYMENT METHOD: ', method) | |
// if(method === 'CREDIT_CARD') | |
// { | |
// return ( | |
// <EditPaymentInfoWrapper> | |
// <EditionField label="Número do Cartão" fullWidth /*value={fieldValues.personalData.name}*/ /> | |
// <EditionField label="Nome igual ao cartão" fullWidth /*value={fieldValues.personalData.name}*/ /> | |
// <div className="double__fields"> | |
// <EditionField label="Validade" fullWidth /*value={fieldValues.personalData.name}*/ /> | |
// <div style={{width:60}}/> | |
// <EditionField label="Cod. Segurança" fullWidth /*value={fieldValues.personalData.name}*/ /> | |
// </div> | |
// <SubmitButton>Definir Cartão</SubmitButton> | |
// <div className="secondary__options"> | |
// <span>Trocar para boleto</span> | |
// </div> | |
// </EditPaymentInfoWrapper> | |
// ) | |
// } | |
// return null | |
// } | |
const mapDispatchToProps = dispatch => { | |
return { | |
openDialog: (type, data) => { | |
dispatch(updateDialogAction(type, data)); | |
}, | |
authConfirmUserSocialLogin: (publisher, fbCode, url) => { | |
dispatch(authConfirmUserSocialLogin(publisher, fbCode, url)); | |
}, | |
authConfirmUserAccount: (code, url) => { | |
dispatch(authConfirmUserAccount(code, url)); | |
}, | |
authErrorUserSocialLogin: (error, url) => { | |
dispatch(authErrorUserSocialLogin(error, url)); | |
}, | |
authUpdateToken : (token) => { | |
dispatch(authUpdateToken(token)); | |
}, | |
authUserLogout: (token , publisher) => { | |
dispatch(authUserLogout(token , publisher)); | |
}, | |
getPlansPublisher: (token, publisher) => { | |
dispatch(getPlansPublisher(token, publisher)); | |
}, | |
getCollections: (publisher, accessToken) => { | |
dispatch(getCollections(publisher, accessToken, 1, 9999, true)); | |
}, | |
updateUserCreditCard: (payerInfo) => { | |
dispatch(updateUserCreditCard(payerInfo)) | |
}, | |
refreshUserData: (payload) => { | |
dispatch(refreshUserData(payload)) | |
} | |
}; | |
} | |
const mapStateToProps = state => { | |
///console.log('[BASE - COMPONENT]', state); | |
const {modalReducer, paymentReducers, publisherReducers, collectionReducers, i18n, plansReducers} = state; | |
return { | |
getStatusModal: modalReducer.dialog, | |
publisher: publisherReducers.publisher, | |
collection: collectionReducers.collections, | |
bannerCollection: collectionReducers.collections && collectionReducers.collections.data && collectionReducers.collections.data[0], | |
theme: publisherReducers.publisher && publisherReducers.publisher.theme, | |
auth: modalReducer.auth && modalReducer.auth.token, | |
dialog: modalReducer.dialog, | |
payment: paymentReducers.payment, | |
plans: plansReducers, | |
i18n: i18n.ptBR | |
}; | |
}; | |
export default withAuthentication(connect(mapStateToProps, mapDispatchToProps)(SettingsComponent)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment