feat(client): refactor propTypes to TS types (#42278)
This commit is contained in:
33
client/package-lock.json
generated
33
client/package-lock.json
generated
@ -2688,6 +2688,12 @@
|
|||||||
"safe-buffer": "*"
|
"safe-buffer": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/redux-actions": {
|
||||||
|
"version": "2.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/redux-actions/-/redux-actions-2.6.1.tgz",
|
||||||
|
"integrity": "sha512-zKgK+ATp3sswXs6sOYo1tk8xdXTy4CTaeeYrVQlClCjeOpag5vzPo0ASWiiBJ7vsiQRAdb3VkuFLnDoBimF67g==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/rimraf": {
|
"@types/rimraf": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-2.0.4.tgz",
|
||||||
@ -3982,6 +3988,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
|
||||||
"integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ=="
|
"integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ=="
|
||||||
},
|
},
|
||||||
|
"bindings": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"file-uri-to-path": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"bl": {
|
"bl": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||||
@ -7790,6 +7805,12 @@
|
|||||||
"typedarray-to-buffer": "^3.1.5"
|
"typedarray-to-buffer": "^3.1.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"file-uri-to-path": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"filesize": {
|
"filesize": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz",
|
||||||
@ -12784,6 +12805,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/name-all-modules-plugin/-/name-all-modules-plugin-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/name-all-modules-plugin/-/name-all-modules-plugin-1.0.1.tgz",
|
||||||
"integrity": "sha1-Cr+2rYNXGLn7Te8GdOBmV6lUN1w="
|
"integrity": "sha1-Cr+2rYNXGLn7Te8GdOBmV6lUN1w="
|
||||||
},
|
},
|
||||||
|
"nan": {
|
||||||
|
"version": "2.14.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
|
||||||
|
"integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"nanoid": {
|
"nanoid": {
|
||||||
"version": "3.1.23",
|
"version": "3.1.23",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
|
||||||
@ -19001,7 +19028,11 @@
|
|||||||
"version": "1.2.13",
|
"version": "1.2.13",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
|
||||||
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
|
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
|
||||||
"optional": true
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"bindings": "^1.5.0",
|
||||||
|
"nan": "^2.12.1"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"glob-parent": {
|
"glob-parent": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
|
@ -126,6 +126,7 @@
|
|||||||
"@testing-library/jest-dom": "5.12.0",
|
"@testing-library/jest-dom": "5.12.0",
|
||||||
"@testing-library/react": "11.2.7",
|
"@testing-library/react": "11.2.7",
|
||||||
"@types/react-transition-group": "4.4.1",
|
"@types/react-transition-group": "4.4.1",
|
||||||
|
"@types/redux-actions": "^2.6.1",
|
||||||
"autoprefixer": "10.2.6",
|
"autoprefixer": "10.2.6",
|
||||||
"babel-plugin-transform-imports": "2.0.0",
|
"babel-plugin-transform-imports": "2.0.0",
|
||||||
"chokidar": "3.5.1",
|
"chokidar": "3.5.1",
|
||||||
|
@ -33,7 +33,7 @@ import envData from '../../../config/env.json';
|
|||||||
import RedirectHome from '../components/RedirectHome';
|
import RedirectHome from '../components/RedirectHome';
|
||||||
import { Loader, Spacer } from '../components/helpers';
|
import { Loader, Spacer } from '../components/helpers';
|
||||||
import { isEmpty } from 'lodash-es';
|
import { isEmpty } from 'lodash-es';
|
||||||
import { User } from '../redux/propTypes';
|
import { User } from '../redux/prop-types';
|
||||||
|
|
||||||
const { clientLocale } = envData;
|
const { clientLocale } = envData;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ import Portfolio from '../components/settings/Portfolio';
|
|||||||
import Honesty from '../components/settings/Honesty';
|
import Honesty from '../components/settings/Honesty';
|
||||||
import Certification from '../components/settings/Certification';
|
import Certification from '../components/settings/Certification';
|
||||||
import DangerZone from '../components/settings/DangerZone';
|
import DangerZone from '../components/settings/DangerZone';
|
||||||
import { User } from '../redux/propTypes';
|
import { User } from '../redux/prop-types';
|
||||||
|
|
||||||
const { apiLocation } = envData;
|
const { apiLocation } = envData;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { createAction, handleActions } from 'redux-actions';
|
import { createAction, handleActions } from 'redux-actions';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
|
|
||||||
import { createTypes } from '../../../utils/createTypes';
|
import { createTypes } from '../../../utils/create-types';
|
||||||
|
|
||||||
export const ns = 'flash';
|
export const ns = 'flash';
|
||||||
|
|
||||||
@ -9,17 +9,22 @@ const initialState = {
|
|||||||
message: {}
|
message: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
const types = createTypes(['createFlashMessage', 'removeFlashMessage'], ns);
|
export const types = createTypes(
|
||||||
|
['createFlashMessage', 'removeFlashMessage'],
|
||||||
|
ns
|
||||||
|
);
|
||||||
|
|
||||||
export const sagas = [];
|
export const sagas = [];
|
||||||
|
|
||||||
export const createFlashMessage = createAction(
|
export const createFlashMessage = createAction(
|
||||||
types.createFlashMessage,
|
types.createFlashMessage,
|
||||||
msg => ({ id: nanoid(), ...msg })
|
(msg: string[]) => ({ id: nanoid(), ...msg })
|
||||||
);
|
);
|
||||||
export const removeFlashMessage = createAction(types.removeFlashMessage);
|
export const removeFlashMessage = createAction(types.removeFlashMessage);
|
||||||
|
|
||||||
export const flashMessageSelector = state => state[ns].message;
|
// TODO: Once state is typed, add here, remove disable.
|
||||||
|
// eslint-disable-next-line
|
||||||
|
export const flashMessageSelector = (state: any): string => state[ns].message;
|
||||||
|
|
||||||
export const reducer = handleActions(
|
export const reducer = handleActions(
|
||||||
{
|
{
|
@ -9,7 +9,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { certificatesByNameSelector } from '../../../redux';
|
import { certificatesByNameSelector } from '../../../redux';
|
||||||
import { ButtonSpacer, FullWidthRow, Link, Spacer } from '../../helpers';
|
import { ButtonSpacer, FullWidthRow, Link, Spacer } from '../../helpers';
|
||||||
import './certifications.css';
|
import './certifications.css';
|
||||||
import { CurrentCertsType } from '../../../redux/propTypes';
|
import { CurrentCertsType } from '../../../redux/prop-types';
|
||||||
|
|
||||||
const mapStateToProps = (state, props) =>
|
const mapStateToProps = (state, props) =>
|
||||||
createSelector(
|
createSelector(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { createAction, handleActions } from 'redux-actions';
|
import { createAction, handleActions } from 'redux-actions';
|
||||||
|
|
||||||
import { createTypes } from '../../../utils/createTypes';
|
import { createTypes } from '../../../utils/create-types';
|
||||||
|
|
||||||
export const ns = 'search';
|
export const ns = 'search';
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import Landing from '../components/landing';
|
import Landing from '../components/landing';
|
||||||
import { AllChallengeNode } from '../redux/propTypes';
|
import { AllChallengeNode } from '../redux/prop-types';
|
||||||
|
|
||||||
const IndexPage = () => {
|
const IndexPage = () => {
|
||||||
return <Landing />;
|
return <Landing />;
|
||||||
|
@ -16,7 +16,7 @@ import {
|
|||||||
isSignedInSelector,
|
isSignedInSelector,
|
||||||
userSelector
|
userSelector
|
||||||
} from '../redux';
|
} from '../redux';
|
||||||
import { ChallengeNode } from '../redux/propTypes';
|
import { ChallengeNode } from '../redux/prop-types';
|
||||||
|
|
||||||
const mapStateToProps = createSelector(
|
const mapStateToProps = createSelector(
|
||||||
userFetchStateSelector,
|
userFetchStateSelector,
|
||||||
|
@ -2,7 +2,7 @@ import { createAction, handleActions } from 'redux-actions';
|
|||||||
import { uniqBy } from 'lodash-es';
|
import { uniqBy } from 'lodash-es';
|
||||||
import store from 'store';
|
import store from 'store';
|
||||||
|
|
||||||
import { createTypes, createAsyncTypes } from '../utils/createTypes';
|
import { createTypes, createAsyncTypes } from '../utils/create-types';
|
||||||
import { createFetchUserSaga } from './fetch-user-saga';
|
import { createFetchUserSaga } from './fetch-user-saga';
|
||||||
import { createAcceptTermsSaga } from './accept-terms-saga';
|
import { createAcceptTermsSaga } from './accept-terms-saga';
|
||||||
import { createAppMountSaga } from './app-mount-saga';
|
import { createAppMountSaga } from './app-mount-saga';
|
||||||
|
335
client/src/redux/prop-types.ts
Normal file
335
client/src/redux/prop-types.ts
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
const FileType = PropTypes.shape({
|
||||||
|
key: PropTypes.string,
|
||||||
|
ext: PropTypes.string,
|
||||||
|
name: PropTypes.string,
|
||||||
|
contents: PropTypes.string,
|
||||||
|
head: PropTypes.string,
|
||||||
|
tail: PropTypes.string
|
||||||
|
});
|
||||||
|
|
||||||
|
export const MarkdownRemark = PropTypes.shape({
|
||||||
|
html: PropTypes.string,
|
||||||
|
frontmatter: PropTypes.shape({
|
||||||
|
title: PropTypes.string,
|
||||||
|
block: PropTypes.string,
|
||||||
|
superBlock: PropTypes.string
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ChallengeNode = PropTypes.shape({
|
||||||
|
block: PropTypes.string,
|
||||||
|
challengeOrder: PropTypes.number,
|
||||||
|
challengeType: PropTypes.number,
|
||||||
|
dashedName: PropTypes.string,
|
||||||
|
description: PropTypes.string,
|
||||||
|
files: PropTypes.shape({
|
||||||
|
indexhtml: FileType,
|
||||||
|
indexjs: FileType
|
||||||
|
}),
|
||||||
|
fields: PropTypes.shape({
|
||||||
|
slug: PropTypes.string,
|
||||||
|
blockName: PropTypes.string
|
||||||
|
}),
|
||||||
|
forumTopicId: PropTypes.number,
|
||||||
|
guideUrl: PropTypes.string,
|
||||||
|
head: PropTypes.arrayOf(PropTypes.string),
|
||||||
|
helpCategory: PropTypes.string,
|
||||||
|
instructions: PropTypes.string,
|
||||||
|
isComingSoon: PropTypes.bool,
|
||||||
|
removeComments: PropTypes.bool,
|
||||||
|
isLocked: PropTypes.bool,
|
||||||
|
isPrivate: PropTypes.bool,
|
||||||
|
order: PropTypes.number,
|
||||||
|
required: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
link: PropTypes.string,
|
||||||
|
raw: PropTypes.string,
|
||||||
|
src: PropTypes.string
|
||||||
|
})
|
||||||
|
),
|
||||||
|
superOrder: PropTypes.number,
|
||||||
|
superBlock: PropTypes.string,
|
||||||
|
tail: PropTypes.arrayOf(PropTypes.string),
|
||||||
|
time: PropTypes.string,
|
||||||
|
title: PropTypes.string,
|
||||||
|
translationPending: PropTypes.bool,
|
||||||
|
videoUrl: PropTypes.string
|
||||||
|
});
|
||||||
|
|
||||||
|
export const AllChallengeNode = PropTypes.shape({
|
||||||
|
edges: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
node: ChallengeNode
|
||||||
|
})
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const AllMarkdownRemark = PropTypes.shape({
|
||||||
|
edges: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
node: MarkdownRemark
|
||||||
|
})
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const User = PropTypes.shape({
|
||||||
|
about: PropTypes.string,
|
||||||
|
completedChallenges: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
id: PropTypes.string,
|
||||||
|
solution: PropTypes.string,
|
||||||
|
githubLink: PropTypes.string,
|
||||||
|
challengeType: PropTypes.number,
|
||||||
|
completedDate: PropTypes.number,
|
||||||
|
files: PropTypes.array
|
||||||
|
})
|
||||||
|
),
|
||||||
|
email: PropTypes.string,
|
||||||
|
githubProfile: PropTypes.string,
|
||||||
|
is2018DataVisCert: PropTypes.bool,
|
||||||
|
isApisMicroservicesCert: PropTypes.bool,
|
||||||
|
isBackEndCert: PropTypes.bool,
|
||||||
|
isDataVisCert: PropTypes.bool,
|
||||||
|
isEmailVerified: PropTypes.bool,
|
||||||
|
isFrontEndCert: PropTypes.bool,
|
||||||
|
isFrontEndLibsCert: PropTypes.bool,
|
||||||
|
isFullStackCert: PropTypes.bool,
|
||||||
|
isHonest: PropTypes.bool,
|
||||||
|
isInfosecQaCert: PropTypes.bool,
|
||||||
|
isQaCertV7: PropTypes.bool,
|
||||||
|
isInfosecCertV7: PropTypes.bool,
|
||||||
|
isJsAlgoDataStructCert: PropTypes.bool,
|
||||||
|
isRespWebDesignCert: PropTypes.bool,
|
||||||
|
isSciCompPyCertV7: PropTypes.bool,
|
||||||
|
isDataAnalysisPyCertV7: PropTypes.bool,
|
||||||
|
isMachineLearningPyCertV7: PropTypes.bool,
|
||||||
|
linkedin: PropTypes.string,
|
||||||
|
location: PropTypes.string,
|
||||||
|
name: PropTypes.string,
|
||||||
|
picture: PropTypes.string,
|
||||||
|
points: PropTypes.number,
|
||||||
|
portfolio: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
title: PropTypes.string,
|
||||||
|
url: PropTypes.string,
|
||||||
|
image: PropTypes.string,
|
||||||
|
description: PropTypes.string
|
||||||
|
})
|
||||||
|
),
|
||||||
|
sendQuincyEmail: PropTypes.bool,
|
||||||
|
theme: PropTypes.string,
|
||||||
|
twitter: PropTypes.string,
|
||||||
|
username: PropTypes.string,
|
||||||
|
website: PropTypes.string
|
||||||
|
});
|
||||||
|
|
||||||
|
export const CurrentCertsType = PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
show: PropTypes.bool,
|
||||||
|
title: PropTypes.string,
|
||||||
|
certSlug: PropTypes.string
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// TYPESCRIPT TYPES
|
||||||
|
|
||||||
|
export type CurrentCertType = {
|
||||||
|
show: boolean;
|
||||||
|
title: string;
|
||||||
|
certSlug: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MarkdownRemarkType = {
|
||||||
|
html: string;
|
||||||
|
frontmatter: {
|
||||||
|
title: string;
|
||||||
|
block: string;
|
||||||
|
superBlock: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export type ChallengeNodeType = {
|
||||||
|
block: string;
|
||||||
|
challengeOrder: number;
|
||||||
|
challengeType: number;
|
||||||
|
dashedName: string;
|
||||||
|
description: string;
|
||||||
|
challengeFiles: ChallengeFileType[];
|
||||||
|
fields: {
|
||||||
|
slug: string;
|
||||||
|
blockName: string;
|
||||||
|
};
|
||||||
|
forumTopicId: number;
|
||||||
|
guideUrl: string;
|
||||||
|
head: string[];
|
||||||
|
helpCategory: string;
|
||||||
|
instructions: string;
|
||||||
|
isComingSoon: boolean;
|
||||||
|
removeComments: boolean;
|
||||||
|
isLocked: boolean;
|
||||||
|
isPrivate: boolean;
|
||||||
|
order: number;
|
||||||
|
required: [
|
||||||
|
{
|
||||||
|
link: string;
|
||||||
|
raw: string;
|
||||||
|
src: string;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
superOrder: number;
|
||||||
|
superBlock: string;
|
||||||
|
tail: string[];
|
||||||
|
time: string;
|
||||||
|
title: string;
|
||||||
|
translationPending: boolean;
|
||||||
|
videoUrl: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AllChallengeNodeType = {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: ChallengeNodeType;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AllMarkdownRemarkType = {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: MarkdownRemarkType;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ResizePropsType = {
|
||||||
|
onStopResize: () => void;
|
||||||
|
onResize: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DimensionsType = {
|
||||||
|
height: number;
|
||||||
|
width: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TestType = {
|
||||||
|
text: string;
|
||||||
|
testString: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UserType = {
|
||||||
|
about: string;
|
||||||
|
completedChallenges: CompletedChallenge[];
|
||||||
|
email: string;
|
||||||
|
githubProfile: string;
|
||||||
|
isHonest: boolean;
|
||||||
|
linkedin: string;
|
||||||
|
location: string;
|
||||||
|
name: string;
|
||||||
|
picture: string;
|
||||||
|
points: number;
|
||||||
|
portfolio: PortfolioType;
|
||||||
|
profileUI: {
|
||||||
|
isLocked: boolean;
|
||||||
|
showCerts: boolean;
|
||||||
|
showName: boolean;
|
||||||
|
};
|
||||||
|
sendQuincyEmail: boolean;
|
||||||
|
theme: string;
|
||||||
|
twitter: string;
|
||||||
|
username: string;
|
||||||
|
website: string;
|
||||||
|
} & isCertifiedTypes;
|
||||||
|
|
||||||
|
export type isCertifiedTypes = {
|
||||||
|
is2018DataVisCert: boolean;
|
||||||
|
isApisMicroservicesCert: boolean;
|
||||||
|
isBackEndCert: boolean;
|
||||||
|
isDataVisCert: boolean;
|
||||||
|
isEmailVerified: boolean;
|
||||||
|
isFrontEndCert: boolean;
|
||||||
|
isFrontEndLibsCert: boolean;
|
||||||
|
isFullStackCert: boolean;
|
||||||
|
isInfosecQaCert: boolean;
|
||||||
|
isQaCertV7: boolean;
|
||||||
|
isInfosecCertV7: boolean;
|
||||||
|
isJsAlgoDataStructCert: boolean;
|
||||||
|
isRespWebDesignCert: boolean;
|
||||||
|
isSciCompPyCertV7: boolean;
|
||||||
|
isDataAnalysisPyCertV7: boolean;
|
||||||
|
isMachineLearningPyCertV7: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CompletedChallenge = {
|
||||||
|
id: string;
|
||||||
|
solution: string;
|
||||||
|
githubLink: string;
|
||||||
|
challengeType: number;
|
||||||
|
completedDate: number;
|
||||||
|
challengeFiles: ChallengeFileType[];
|
||||||
|
};
|
||||||
|
// TODO: renames: files => challengeFiles; key => fileKey;
|
||||||
|
export type ChallengeFileType = {
|
||||||
|
contents: string;
|
||||||
|
editableContents?: string;
|
||||||
|
editableRegionBoundaries?: number[] | null;
|
||||||
|
error?: string | null;
|
||||||
|
ext: ExtTypes;
|
||||||
|
head?: string[];
|
||||||
|
history?: string[];
|
||||||
|
fileKey: FileKeyTypes;
|
||||||
|
name: string;
|
||||||
|
path: string;
|
||||||
|
seed?: string;
|
||||||
|
seedEditableRegionBoundaries?: number[];
|
||||||
|
tail?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ExtTypes = 'js' | 'html' | 'css' | 'jsx';
|
||||||
|
export type FileKeyTypes = 'indexjs' | 'indexhtml' | 'indexcss';
|
||||||
|
|
||||||
|
export type PortfolioType = {
|
||||||
|
id: string;
|
||||||
|
title?: string;
|
||||||
|
url?: string;
|
||||||
|
image?: string;
|
||||||
|
description?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ChallengeNode = {
|
||||||
|
block: string;
|
||||||
|
challengeOrder: number;
|
||||||
|
challengeType: number;
|
||||||
|
dashedName: string;
|
||||||
|
description: string;
|
||||||
|
challengeFiles: ChallengeFileType;
|
||||||
|
fields: {
|
||||||
|
slug: string;
|
||||||
|
blockName: string;
|
||||||
|
};
|
||||||
|
forumTopicId: number;
|
||||||
|
guideUrl: string;
|
||||||
|
head: string[];
|
||||||
|
helpCategory: string;
|
||||||
|
instructions: string;
|
||||||
|
isComingSoon: boolean;
|
||||||
|
removeComments: boolean;
|
||||||
|
isLocked: boolean;
|
||||||
|
isPrivate: boolean;
|
||||||
|
order: number;
|
||||||
|
required: [
|
||||||
|
{
|
||||||
|
link: string;
|
||||||
|
raw: string;
|
||||||
|
src: string;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
superOrder: number;
|
||||||
|
superBlock: string;
|
||||||
|
tail: string[];
|
||||||
|
time: string;
|
||||||
|
title: string;
|
||||||
|
translationPending: boolean;
|
||||||
|
videoUrl?: string;
|
||||||
|
};
|
@ -1,135 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
const FileType = PropTypes.shape({
|
|
||||||
key: PropTypes.string,
|
|
||||||
ext: PropTypes.string,
|
|
||||||
name: PropTypes.string,
|
|
||||||
contents: PropTypes.string,
|
|
||||||
head: PropTypes.string,
|
|
||||||
tail: PropTypes.string
|
|
||||||
});
|
|
||||||
|
|
||||||
export const MarkdownRemark = PropTypes.shape({
|
|
||||||
html: PropTypes.string,
|
|
||||||
frontmatter: PropTypes.shape({
|
|
||||||
title: PropTypes.string,
|
|
||||||
block: PropTypes.string,
|
|
||||||
superBlock: PropTypes.string
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
export const ChallengeNode = PropTypes.shape({
|
|
||||||
block: PropTypes.string,
|
|
||||||
challengeOrder: PropTypes.number,
|
|
||||||
challengeType: PropTypes.number,
|
|
||||||
dashedName: PropTypes.string,
|
|
||||||
description: PropTypes.string,
|
|
||||||
files: PropTypes.shape({
|
|
||||||
indexhtml: FileType,
|
|
||||||
indexjs: FileType
|
|
||||||
}),
|
|
||||||
fields: PropTypes.shape({
|
|
||||||
slug: PropTypes.string,
|
|
||||||
blockName: PropTypes.string
|
|
||||||
}),
|
|
||||||
forumTopicId: PropTypes.number,
|
|
||||||
guideUrl: PropTypes.string,
|
|
||||||
head: PropTypes.arrayOf(PropTypes.string),
|
|
||||||
helpCategory: PropTypes.string,
|
|
||||||
instructions: PropTypes.string,
|
|
||||||
isComingSoon: PropTypes.bool,
|
|
||||||
removeComments: PropTypes.bool,
|
|
||||||
isLocked: PropTypes.bool,
|
|
||||||
isPrivate: PropTypes.bool,
|
|
||||||
order: PropTypes.number,
|
|
||||||
required: PropTypes.arrayOf(
|
|
||||||
PropTypes.shape({
|
|
||||||
link: PropTypes.string,
|
|
||||||
raw: PropTypes.string,
|
|
||||||
src: PropTypes.string
|
|
||||||
})
|
|
||||||
),
|
|
||||||
superOrder: PropTypes.number,
|
|
||||||
superBlock: PropTypes.string,
|
|
||||||
tail: PropTypes.arrayOf(PropTypes.string),
|
|
||||||
time: PropTypes.string,
|
|
||||||
title: PropTypes.string,
|
|
||||||
translationPending: PropTypes.bool,
|
|
||||||
videoUrl: PropTypes.string
|
|
||||||
});
|
|
||||||
|
|
||||||
export const AllChallengeNode = PropTypes.shape({
|
|
||||||
edges: PropTypes.arrayOf(
|
|
||||||
PropTypes.shape({
|
|
||||||
node: ChallengeNode
|
|
||||||
})
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
export const AllMarkdownRemark = PropTypes.shape({
|
|
||||||
edges: PropTypes.arrayOf(
|
|
||||||
PropTypes.shape({
|
|
||||||
node: MarkdownRemark
|
|
||||||
})
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
export const User = PropTypes.shape({
|
|
||||||
about: PropTypes.string,
|
|
||||||
completedChallenges: PropTypes.arrayOf(
|
|
||||||
PropTypes.shape({
|
|
||||||
id: PropTypes.string,
|
|
||||||
solution: PropTypes.string,
|
|
||||||
githubLink: PropTypes.string,
|
|
||||||
challengeType: PropTypes.number,
|
|
||||||
completedDate: PropTypes.number,
|
|
||||||
files: PropTypes.array
|
|
||||||
})
|
|
||||||
),
|
|
||||||
email: PropTypes.string,
|
|
||||||
githubProfile: PropTypes.string,
|
|
||||||
is2018DataVisCert: PropTypes.bool,
|
|
||||||
isApisMicroservicesCert: PropTypes.bool,
|
|
||||||
isBackEndCert: PropTypes.bool,
|
|
||||||
isDataVisCert: PropTypes.bool,
|
|
||||||
isEmailVerified: PropTypes.bool,
|
|
||||||
isFrontEndCert: PropTypes.bool,
|
|
||||||
isFrontEndLibsCert: PropTypes.bool,
|
|
||||||
isFullStackCert: PropTypes.bool,
|
|
||||||
isHonest: PropTypes.bool,
|
|
||||||
isInfosecQaCert: PropTypes.bool,
|
|
||||||
isQaCertV7: PropTypes.bool,
|
|
||||||
isInfosecCertV7: PropTypes.bool,
|
|
||||||
isJsAlgoDataStructCert: PropTypes.bool,
|
|
||||||
isRespWebDesignCert: PropTypes.bool,
|
|
||||||
isSciCompPyCertV7: PropTypes.bool,
|
|
||||||
isDataAnalysisPyCertV7: PropTypes.bool,
|
|
||||||
isMachineLearningPyCertV7: PropTypes.bool,
|
|
||||||
linkedin: PropTypes.string,
|
|
||||||
location: PropTypes.string,
|
|
||||||
name: PropTypes.string,
|
|
||||||
picture: PropTypes.string,
|
|
||||||
points: PropTypes.number,
|
|
||||||
portfolio: PropTypes.arrayOf(
|
|
||||||
PropTypes.shape({
|
|
||||||
id: PropTypes.string.isRequired,
|
|
||||||
title: PropTypes.string,
|
|
||||||
url: PropTypes.string,
|
|
||||||
image: PropTypes.string,
|
|
||||||
description: PropTypes.string
|
|
||||||
})
|
|
||||||
),
|
|
||||||
sendQuincyEmail: PropTypes.bool,
|
|
||||||
theme: PropTypes.string,
|
|
||||||
twitter: PropTypes.string,
|
|
||||||
username: PropTypes.string,
|
|
||||||
website: PropTypes.string
|
|
||||||
});
|
|
||||||
|
|
||||||
export const CurrentCertsType = PropTypes.arrayOf(
|
|
||||||
PropTypes.shape({
|
|
||||||
show: PropTypes.bool,
|
|
||||||
title: PropTypes.string,
|
|
||||||
certSlug: PropTypes.string
|
|
||||||
})
|
|
||||||
);
|
|
@ -1,6 +1,6 @@
|
|||||||
import { createAction, handleActions } from 'redux-actions';
|
import { createAction, handleActions } from 'redux-actions';
|
||||||
|
|
||||||
import { createTypes, createAsyncTypes } from '../../utils/createTypes';
|
import { createTypes, createAsyncTypes } from '../../utils/create-types';
|
||||||
import { createDangerZoneSaga } from './danger-zone-saga';
|
import { createDangerZoneSaga } from './danger-zone-saga';
|
||||||
import { createSettingsSagas } from './settings-sagas';
|
import { createSettingsSagas } from './settings-sagas';
|
||||||
import { createUpdateMyEmailSaga } from './update-email-saga';
|
import { createUpdateMyEmailSaga } from './update-email-saga';
|
||||||
|
@ -23,7 +23,7 @@ import Hotkeys from '../components/Hotkeys';
|
|||||||
|
|
||||||
import { getGuideUrl } from '../utils';
|
import { getGuideUrl } from '../utils';
|
||||||
import { challengeTypes } from '../../../../utils/challengeTypes';
|
import { challengeTypes } from '../../../../utils/challengeTypes';
|
||||||
import { ChallengeNode } from '../../../redux/propTypes';
|
import { ChallengeNode } from '../../../redux/prop-types';
|
||||||
import {
|
import {
|
||||||
createFiles,
|
createFiles,
|
||||||
challengeFilesSelector,
|
challengeFilesSelector,
|
||||||
|
@ -30,7 +30,7 @@ import HelpModal from '../../components/HelpModal';
|
|||||||
import ProjectToolPanel from '../Tool-Panel';
|
import ProjectToolPanel from '../Tool-Panel';
|
||||||
import SolutionForm from '../SolutionForm';
|
import SolutionForm from '../SolutionForm';
|
||||||
import Spacer from '../../../../components/helpers/Spacer';
|
import Spacer from '../../../../components/helpers/Spacer';
|
||||||
import { ChallengeNode } from '../../../../redux/propTypes';
|
import { ChallengeNode } from '../../../../redux/prop-types';
|
||||||
import { isSignedInSelector } from '../../../../redux';
|
import { isSignedInSelector } from '../../../../redux';
|
||||||
import Hotkeys from '../../components/Hotkeys';
|
import Hotkeys from '../../components/Hotkeys';
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import Helmet from 'react-helmet';
|
|||||||
import { withTranslation } from 'react-i18next';
|
import { withTranslation } from 'react-i18next';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
import { ChallengeNode } from '../../../../redux/propTypes';
|
import { ChallengeNode } from '../../../../redux/prop-types';
|
||||||
import {
|
import {
|
||||||
challengeMounted,
|
challengeMounted,
|
||||||
isChallengeCompletedSelector,
|
isChallengeCompletedSelector,
|
||||||
|
@ -13,7 +13,7 @@ import { withTranslation } from 'react-i18next';
|
|||||||
|
|
||||||
// Local Utilities
|
// Local Utilities
|
||||||
import PrismFormatted from '../components/PrismFormatted';
|
import PrismFormatted from '../components/PrismFormatted';
|
||||||
import { ChallengeNode } from '../../../redux/propTypes';
|
import { ChallengeNode } from '../../../redux/prop-types';
|
||||||
import LearnLayout from '../../../components/layouts/Learn';
|
import LearnLayout from '../../../components/layouts/Learn';
|
||||||
import ChallengeTitle from '../components/Challenge-Title';
|
import ChallengeTitle from '../components/Challenge-Title';
|
||||||
import ChallengeDescription from '../components/Challenge-Description';
|
import ChallengeDescription from '../components/Challenge-Description';
|
||||||
|
@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import LearnLayout from '../../components/layouts/Learn';
|
import LearnLayout from '../../components/layouts/Learn';
|
||||||
import FullWidthRow from '../../components/helpers/FullWidthRow';
|
import FullWidthRow from '../../components/helpers/FullWidthRow';
|
||||||
import ButtonSpacer from '../../components/helpers/ButtonSpacer';
|
import ButtonSpacer from '../../components/helpers/ButtonSpacer';
|
||||||
import { MarkdownRemark, AllChallengeNode } from '../../redux/propTypes';
|
import { MarkdownRemark, AllChallengeNode } from '../../redux/prop-types';
|
||||||
|
|
||||||
import './intro.css';
|
import './intro.css';
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ import {
|
|||||||
userSelector
|
userSelector
|
||||||
} from '../../redux';
|
} from '../../redux';
|
||||||
import { resetExpansion, toggleBlock } from './redux';
|
import { resetExpansion, toggleBlock } from './redux';
|
||||||
import { MarkdownRemark, AllChallengeNode, User } from '../../redux/propTypes';
|
import { MarkdownRemark, AllChallengeNode, User } from '../../redux/prop-types';
|
||||||
|
|
||||||
import './intro.css';
|
import './intro.css';
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ import CertificationIcon from '../../../assets/icons/CertificationIcon';
|
|||||||
import GreenPass from '../../../assets/icons/GreenPass';
|
import GreenPass from '../../../assets/icons/GreenPass';
|
||||||
import GreenNotCompleted from '../../../assets/icons/GreenNotCompleted';
|
import GreenNotCompleted from '../../../assets/icons/GreenNotCompleted';
|
||||||
import { certificatesByNameSelector } from '../../../redux';
|
import { certificatesByNameSelector } from '../../../redux';
|
||||||
import { CurrentCertsType, User } from '../../../redux/propTypes';
|
import { CurrentCertsType, User } from '../../../redux/prop-types';
|
||||||
import { certMap } from '../../../resources/certAndProjectMap';
|
import { certMap } from '../../../resources/certAndProjectMap';
|
||||||
import {
|
import {
|
||||||
certSlugTypeMap,
|
certSlugTypeMap,
|
||||||
|
@ -9,7 +9,7 @@ import IntroInformation from '../../../assets/icons/IntroInformation';
|
|||||||
import GreenPass from '../../../assets/icons/GreenPass';
|
import GreenPass from '../../../assets/icons/GreenPass';
|
||||||
import GreenNotCompleted from '../../../assets/icons/GreenNotCompleted';
|
import GreenNotCompleted from '../../../assets/icons/GreenNotCompleted';
|
||||||
import { userSelector } from '../../../redux';
|
import { userSelector } from '../../../redux';
|
||||||
import { User } from '../../../redux/propTypes';
|
import { User } from '../../../redux/prop-types';
|
||||||
|
|
||||||
const mapIconStyle = { height: '15px', marginRight: '10px', width: '15px' };
|
const mapIconStyle = { height: '15px', marginRight: '10px', width: '15px' };
|
||||||
const renderCheckMark = isCompleted => {
|
const renderCheckMark = isCompleted => {
|
||||||
|
22
client/src/utils/create-types.ts
Normal file
22
client/src/utils/create-types.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
type CreateTypesType = {
|
||||||
|
[action: string]: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function createTypes(
|
||||||
|
types: string[] = [],
|
||||||
|
ns = 'annon'
|
||||||
|
): CreateTypesType {
|
||||||
|
return types.reduce(
|
||||||
|
(types, action: string) => ({
|
||||||
|
...types,
|
||||||
|
[action]: `${ns}.${action}`
|
||||||
|
}),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createAsyncTypes = (action: string): string[] => [
|
||||||
|
`${action}`,
|
||||||
|
`${action}Complete`,
|
||||||
|
`${action}Error`
|
||||||
|
];
|
@ -1,15 +0,0 @@
|
|||||||
export function createTypes(types = [], ns = 'annon') {
|
|
||||||
return types.reduce(
|
|
||||||
(types, action) => ({
|
|
||||||
...types,
|
|
||||||
[action]: `${ns}.${action}`
|
|
||||||
}),
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createAsyncTypes = action => [
|
|
||||||
`${action}`,
|
|
||||||
`${action}Complete`,
|
|
||||||
`${action}Error`
|
|
||||||
];
|
|
Reference in New Issue
Block a user