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:
Sem Bauke
2021-10-01 06:30:14 +02:00
committed by GitHub
parent 3ea2fe4f77
commit cfc9b7258d
5 changed files with 84 additions and 26 deletions

View File

@ -9,6 +9,10 @@
white-space: pre-line;
}
.cert-btn {
margin-top: 40px;
}
.landing-page ul {
list-style: none;
padding-left: 0px;

View File

@ -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>

View File

@ -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}
/>
)}
<Button
block={true}
bsStyle='primary'
disabled={!canClaim.status || (isCertified && !canViewCert)}
href={certLocation}
onClick={createClickHandler(certSlug)}
>
{isCertified ? t('buttons.show-cert') : t('buttons.claim-cert')}
</Button>
<>
{isSignedIn && (
<Button
block={true}
bsStyle='primary'
className='cert-btn'
disabled={
!canClaimCert || (isCertified && !hasCompletedRequiredSteps)
}
href={certLocation}
onClick={createClickHandler(certSlug)}
>
{isCertified && userLoaded
? t('buttons.show-cert')
: t('buttons.claim-cert')}
</Button>
)}
</>
</div>
);
};

View File

@ -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'>

View File

@ -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 => {