fix(client): cert rendering temporarily (#43335)
* fix: require login as step * fix: cert rendering temporary * fix: remove keys from other translation files * fix: cypress test * chore: shauns suggestions * fix: remove steps * fix: use a seperate UseEffect function * Suggestions from Shaun Co-authored-by: Shaun Hamilton <shauhami020@gmail.com> * fix: certification temp rendering * fix: cert temp rendering hopefully * fix: button visibility and cert test * fix: condition * test: improve claim cert tests Without npm run seed, retries will be in a different state. Check the scroll position to (hopefully) catch the weird cert claim bug. Co-authored-by: Shaun Hamilton <shauhami020@gmail.com> Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
@ -9,6 +9,10 @@
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.cert-btn {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.landing-page ul {
|
||||
list-style: none;
|
||||
padding-left: 0px;
|
||||
|
@ -17,6 +17,7 @@ import { Spacer } from '../../components/helpers';
|
||||
import {
|
||||
currentChallengeIdSelector,
|
||||
userFetchStateSelector,
|
||||
signInLoadingSelector,
|
||||
isSignedInSelector,
|
||||
tryToShowDonationModal,
|
||||
userSelector
|
||||
@ -50,6 +51,7 @@ const propTypes = {
|
||||
})
|
||||
}),
|
||||
resetExpansion: PropTypes.func,
|
||||
signInLoading: PropTypes.bool,
|
||||
t: PropTypes.func,
|
||||
toggleBlock: PropTypes.func,
|
||||
tryToShowDonationModal: PropTypes.func.isRequired,
|
||||
@ -62,11 +64,13 @@ const mapStateToProps = state => {
|
||||
return createSelector(
|
||||
currentChallengeIdSelector,
|
||||
isSignedInSelector,
|
||||
signInLoadingSelector,
|
||||
userFetchStateSelector,
|
||||
userSelector,
|
||||
(currentChallengeId, isSignedIn, fetchState, user) => ({
|
||||
(currentChallengeId, isSignedIn, signInLoading, fetchState, user) => ({
|
||||
currentChallengeId,
|
||||
isSignedIn,
|
||||
signInLoading,
|
||||
fetchState,
|
||||
user
|
||||
})
|
||||
@ -150,6 +154,7 @@ const SuperBlockIntroductionPage = props => {
|
||||
allChallengeNode: { edges }
|
||||
},
|
||||
isSignedIn,
|
||||
signInLoading,
|
||||
t,
|
||||
user
|
||||
} = props;
|
||||
@ -202,7 +207,7 @@ const SuperBlockIntroductionPage = props => {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{!isSignedIn && (
|
||||
{!isSignedIn && !signInLoading && (
|
||||
<div>
|
||||
<Spacer size={2} />
|
||||
<Login block={true}>{t('buttons.logged-out-cta-btn')}</Login>
|
||||
|
@ -5,13 +5,16 @@ import React, { useState, useEffect } from 'react';
|
||||
import { withTranslation } from 'react-i18next';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import {
|
||||
certSlugTypeMap,
|
||||
superBlockCertTypeMap
|
||||
} from '../../../../../config/certification-settings';
|
||||
import { createFlashMessage } from '../../../components/Flash/redux';
|
||||
import { stepsToClaimSelector } from '../../../redux';
|
||||
import {
|
||||
userFetchStateSelector,
|
||||
stepsToClaimSelector,
|
||||
isSignedInSelector
|
||||
} from '../../../redux';
|
||||
|
||||
import { StepsType, User } from '../../../redux/prop-types';
|
||||
import { verifyCert } from '../../../redux/settings';
|
||||
@ -22,6 +25,12 @@ import CertificationCard from './CertificationCard';
|
||||
|
||||
const propTypes = {
|
||||
createFlashMessage: PropTypes.func.isRequired,
|
||||
fetchState: PropTypes.shape({
|
||||
pending: PropTypes.bool,
|
||||
complete: PropTypes.bool,
|
||||
errored: PropTypes.bool
|
||||
}),
|
||||
isSignedIn: PropTypes.bool,
|
||||
steps: StepsType,
|
||||
superBlock: PropTypes.string,
|
||||
t: PropTypes.func,
|
||||
@ -36,9 +45,16 @@ const honestyInfoMessage = {
|
||||
};
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return createSelector(stepsToClaimSelector, steps => ({
|
||||
steps
|
||||
}))(state);
|
||||
return createSelector(
|
||||
stepsToClaimSelector,
|
||||
userFetchStateSelector,
|
||||
isSignedInSelector,
|
||||
(steps, fetchState, isSignedIn) => ({
|
||||
steps,
|
||||
fetchState,
|
||||
isSignedIn
|
||||
})
|
||||
)(state);
|
||||
};
|
||||
|
||||
const mapDispatchToProps = {
|
||||
@ -53,15 +69,21 @@ const CertChallenge = ({
|
||||
t,
|
||||
verifyCert,
|
||||
title,
|
||||
fetchState,
|
||||
isSignedIn,
|
||||
user: { isHonest, username }
|
||||
}) => {
|
||||
const [canClaim, setCanClaim] = useState({ status: false, result: '' });
|
||||
const [canClaimCert, setCanClaimCert] = useState(false);
|
||||
const [certVerificationMessage, setCertVerificationMessage] = useState('');
|
||||
const [isCertified, setIsCertified] = useState(false);
|
||||
const [userLoaded, setUserLoaded] = useState(false);
|
||||
const [verificationComplete, setVerificationComplete] = useState(false);
|
||||
const [stepState, setStepState] = useState({
|
||||
numberOfSteps: 0,
|
||||
completedCount: 0
|
||||
});
|
||||
const [canViewCert, setCanViewCert] = useState(false);
|
||||
const [hasCompletedRequiredSteps, setHasCompletedRequiredSteps] =
|
||||
useState(false);
|
||||
const [isProjectsCompleted, setIsProjectsCompleted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
@ -70,7 +92,9 @@ const CertChallenge = ({
|
||||
try {
|
||||
const data = await getVerifyCanClaimCert(username, superBlock);
|
||||
const { status, result } = data?.response?.message;
|
||||
setCanClaim({ status, result });
|
||||
setCanClaimCert(status);
|
||||
setCertVerificationMessage(result);
|
||||
setVerificationComplete(true);
|
||||
} catch (e) {
|
||||
// TODO: How do we handle errors...?
|
||||
}
|
||||
@ -81,6 +105,14 @@ const CertChallenge = ({
|
||||
|
||||
const { certSlug } = certMap.find(x => x.title === title);
|
||||
|
||||
useEffect(() => {
|
||||
const { pending, complete } = fetchState;
|
||||
|
||||
if (complete && !pending) {
|
||||
setUserLoaded(true);
|
||||
}
|
||||
}, [fetchState]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsCertified(
|
||||
steps?.currentCerts?.find(
|
||||
@ -90,18 +122,17 @@ const CertChallenge = ({
|
||||
);
|
||||
|
||||
const projectsCompleted =
|
||||
canClaim.status || canClaim.result === 'projects-completed';
|
||||
canClaimCert || certVerificationMessage === 'projects-completed';
|
||||
const completedCount =
|
||||
Object.values(steps).filter(
|
||||
stepVal => typeof stepVal === 'boolean' && stepVal
|
||||
).length + projectsCompleted;
|
||||
const numberOfSteps = Object.keys(steps).length;
|
||||
|
||||
setCanViewCert(completedCount === numberOfSteps);
|
||||
setHasCompletedRequiredSteps(completedCount === numberOfSteps);
|
||||
setStepState({ numberOfSteps, completedCount });
|
||||
setIsProjectsCompleted(projectsCompleted);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [steps, canClaim]);
|
||||
}, [steps, canClaimCert, certVerificationMessage]);
|
||||
|
||||
const certLocation = `/certification/${username}/${certSlug}`;
|
||||
const i18nSuperBlock = t(`intro:${superBlock}.title`);
|
||||
@ -109,6 +140,11 @@ const CertChallenge = ({
|
||||
cert: i18nSuperBlock
|
||||
});
|
||||
|
||||
const showCertificationCard =
|
||||
userLoaded &&
|
||||
isSignedIn &&
|
||||
(!isCertified || (!hasCompletedRequiredSteps && verificationComplete));
|
||||
|
||||
const createClickHandler = certSlug => e => {
|
||||
e.preventDefault();
|
||||
if (isCertified) {
|
||||
@ -118,10 +154,9 @@ const CertChallenge = ({
|
||||
? verifyCert(certSlug)
|
||||
: createFlashMessage(honestyInfoMessage);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='block'>
|
||||
{(!isCertified || !canViewCert) && (
|
||||
{showCertificationCard && (
|
||||
<CertificationCard
|
||||
i18nCertText={i18nCertText}
|
||||
isProjectsCompleted={isProjectsCompleted}
|
||||
@ -130,15 +165,24 @@ const CertChallenge = ({
|
||||
superBlock={superBlock}
|
||||
/>
|
||||
)}
|
||||
<>
|
||||
{isSignedIn && (
|
||||
<Button
|
||||
block={true}
|
||||
bsStyle='primary'
|
||||
disabled={!canClaim.status || (isCertified && !canViewCert)}
|
||||
className='cert-btn'
|
||||
disabled={
|
||||
!canClaimCert || (isCertified && !hasCompletedRequiredSteps)
|
||||
}
|
||||
href={certLocation}
|
||||
onClick={createClickHandler(certSlug)}
|
||||
>
|
||||
{isCertified ? t('buttons.show-cert') : t('buttons.claim-cert')}
|
||||
{isCertified && userLoaded
|
||||
? t('buttons.show-cert')
|
||||
: t('buttons.claim-cert')}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -2,7 +2,6 @@ import { Link } from 'gatsby';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { withTranslation, useTranslation } from 'react-i18next';
|
||||
|
||||
import GreenNotCompleted from '../../../assets/icons/green-not-completed';
|
||||
import GreenPass from '../../../assets/icons/green-pass';
|
||||
import { StepsType } from '../../../redux/prop-types';
|
||||
@ -39,6 +38,7 @@ const ClaimCertSteps = ({
|
||||
isShowCerts = false,
|
||||
isShowProfile = false
|
||||
} = steps;
|
||||
|
||||
return (
|
||||
<ul className='map-challenges-ul' data-cy='claim-cert-steps'>
|
||||
<li className='map-challenge-title map-challenge-wrap'>
|
||||
|
@ -49,6 +49,7 @@ describe('Responsive Web Design Superblock', () => {
|
||||
});
|
||||
describe('After submitting all 5 projects', () => {
|
||||
before(() => {
|
||||
cy.exec('npm run seed');
|
||||
cy.login();
|
||||
cy.toggleAll();
|
||||
const { superBlock, block, challenges } = projects;
|
||||
@ -82,6 +83,10 @@ describe('Responsive Web Design Superblock', () => {
|
||||
cy.get('.donation-modal').should('not.exist');
|
||||
// directed to claim-cert-block section
|
||||
cy.url().should('include', '#claim-cert-block');
|
||||
// make sure that the window has not snapped to the top (a weird bug that
|
||||
// we never figured out and so could randomly reappear)
|
||||
cy.window().its('scrollY').should('not.equal', 0);
|
||||
cy.contains('Claim Your Certification');
|
||||
cy.contains('Claim Certification').should('not.be.disabled').click();
|
||||
cy.contains('Show Certification').click();
|
||||
cy.location().should(loc => {
|
||||
|
Reference in New Issue
Block a user