Skip to content

Commit

Permalink
Merge pull request #21 from anasnadeemws/feat/better-eslint-rules
Browse files Browse the repository at this point in the history
Feat/better eslint rules
  • Loading branch information
alichherawalla authored Mar 20, 2024
2 parents aba050e + a3ee97e commit c696228
Show file tree
Hide file tree
Showing 23 changed files with 321 additions and 119 deletions.
15 changes: 14 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,17 @@ npm-debug.log
.idea
**/coverage/**
**/storybook-static/**
**/server/**
**/server/**
lighthouserc.js
lingui.config.js
__tests__
internals/**/*.*
coverage/**/*.*
reports/**/*.*
badges/**/*.*
assets/**/*.*
**/tests/**/*.test.js
playwright.config.js
babel.config.js
app/translations/*.js
app/**/stories/**/*.*
25 changes: 23 additions & 2 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,36 @@ module.exports = {
es2021: true,
'jest/globals': true
},
plugins: ['jest', 'immutable', 'prettier'],
extends: ['eslint:recommended', 'prettier', 'plugin:import/recommended', 'next'],
plugins: ['prettier', 'jest'],
rules: {
'prettier/prettier': ['error', prettierOptions],
'import/no-webpack-loader-syntax': 0,
'react/display-name': 0,
'react/react-in-jsx-scope': 'off',
curly: ['error', 'all'],
'no-console': ['error', { allow: ['error'] }]
'no-console': ['error', { allow: ['error'] }],
'max-lines': ['error', { max: 300, skipBlankLines: true, skipComments: true }],
'max-lines-per-function': ['error', 250],
'no-else-return': 'error',
'max-params': ['error', 4],
'require-jsdoc': [
'error',
{
require: {
FunctionDeclaration: true,
MethodDefinition: false,
ClassDeclaration: false,
ArrowFunctionExpression: false,
FunctionExpression: false
}
}
],
'no-shadow': 'error',
complexity: ['error', 5],
'no-empty': 'error',
'import/order': ['error', { groups: [['builtin', 'external', 'internal', 'parent', 'sibling', 'index']] }],
'eslint-comments/no-use': 0
},
globals: {
GLOBAL: false,
Expand Down
6 changes: 6 additions & 0 deletions app/components/Clickable/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ const StyledClickable = styled.div`
cursor: pointer;
}
`;

/**
* A component that can be clicked
* @param {function} onClick - The function to call when the component is clicked
* @param {string} textId - The id of the text to display
*/
function Clickable({ onClick, textId }) {
return (
<StyledClickable data-testid="clickable" onClick={onClick}>
Expand Down
45 changes: 25 additions & 20 deletions app/components/ErrorState/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,32 @@ import { CustomCard } from '../styled/repos';

const ErrorState = (props) => {
const { intl, reposError, loading, reposData } = props;
let repoError;
if (reposError) {
repoError = reposError;
} else if (!get(reposData, 'totalCount', 0)) {
repoError = 'respo_search_default';
}
if (!loading && !repoError) {
const getRepoError = () => {
if (reposError) {
return reposError;
} else if (!get(reposData, 'totalCount', 0)) {
return 'respo_search_default';
}
return null;
}
return (
!loading &&
repoError && (
<CustomCard
color={reposError ? 'red' : 'grey'}
title={intl.formatMessage({ id: 'repo_list' })}
data-testid="error-state"
>
<T id={repoError} />
</CustomCard>
)
);
};

const renderErrorCard = (repoError) => {
return (
!loading &&
repoError && (
<CustomCard
color={reposError ? 'red' : 'grey'}
title={intl.formatMessage({ id: 'repo_list' })}
data-testid="error-state"
>
<T id={repoError} />
</CustomCard>
)
);
};

const repoError = getRepoError();
return renderErrorCard(repoError);
};

ErrorState.propTypes = {
Expand Down
6 changes: 6 additions & 0 deletions app/components/Meta/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import favicon from '@images/favicon.ico';

/**
* The Meta component
* @param {string} title - The title of the page
* @param {string} description - The description of the page
* @param {boolean} useTranslation - Whether to use translation for the title and description
*/
function Meta({ title, description, useTranslation }) {
const intl = useIntl();

Expand Down
6 changes: 3 additions & 3 deletions app/components/RepoList/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ import { Skeleton } from 'antd';
import PropTypes from 'prop-types';
import { useRouter } from 'next/router';
import T from '@components/Text';
import { CustomCard } from '../styled/repos';
import If from '../If/index';
import If from '@components/If';
import { CustomCard } from '@components/styled/repos';

const RepoList = (props) => {
const { reposData, loading, repoName } = props;
const router = useRouter();

const items = get(reposData, 'items', []);
const totalCount = get(reposData, 'totalCount', 0);
const BlockText = (props) => <T display="block" {...props} />;
const BlockText = (blockTextProps) => <T display="block" {...blockTextProps} />;
return (
<If condition={items.length !== 0 || loading}>
<CustomCard data-testid="repo-list">
Expand Down
11 changes: 11 additions & 0 deletions app/components/Text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ const StyledText = styled.span`
${(props) => props.fontweight};
${(props) => props.styles};
`;

/**
* A component for displaying text
* @param {string} id - The id of the text to display
* @param {string} text - The text to display
* @param {object} values - The values to pass to the text
* @param {string} color - The color of the text
* @param {string} fontWeight - The font weight of the text
* @param {string} fontSize - The font size of the text
* @param {string} display - The display type of the text
*/
function Text({ id = 'default', text, values = {}, children, color, fontWeight, fontSize, ...props }) {
return (
<StyledText data-testid="text" color={color} fontweight={fontWeight} fontsize={fontSize} {...props}>
Expand Down
10 changes: 9 additions & 1 deletion app/components/Title/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,17 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Row, Skeleton } from 'antd';
import { StarOutlined } from '@ant-design/icons';
import Text from '@app/components/Text/index';
import Text from '@app/components/Text';
import fonts from '@app/themes/fonts';

/**
* The title of the info container
* @param {object} props The component props
* @param {string} props.name The name of the repo
* @param {boolean} props.loading Whether the data is loading
* @param {number} props.stargazersCount The number of stargazers
* @returns {JSX.Element} The title of the info container
*/
function Title(props) {
const { name, loading, stargazersCount } = props;
const headingStyle = fonts.style.heading();
Expand Down
6 changes: 6 additions & 0 deletions app/configureStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import { createWrapper } from 'next-redux-wrapper';

import createReducer from './reducers';

/**
*
* @param {object} initialState The initial state
* @returns {object} The store
*
*/
export default function configureStore(initialState = {}) {
let composeEnhancers = compose;
const reduxSagaMonitorOptions = {};
Expand Down
15 changes: 15 additions & 0 deletions app/containers/Info/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ import { infoCreators } from './reducer';
import saga from './saga';
import { selectInfoData, selectInfoLoading } from './selectors';

/**
* The Info container
* @param {object} props The component props
* @param {object} props.details The details of the repo
* @param {object} props.params The params from the route
* @param {boolean} props.loading Whether the data is loading
* @param {function} props.dispatchRequestInfo The function to request the info
* @param {object} props.fallBackDetails The details to fall back on
* @returns {JSX.Element} The Info container
*/
export function Info({ details, params, loading, dispatchRequestInfo, fallBackDetails }) {
const router = useRouter();
const { query } = router;
Expand Down Expand Up @@ -74,6 +84,11 @@ const mapStateToProps = createStructuredSelector({
fallBackDetails: selectInfoData()
});

/**
* The mapDispatchToProps
* @param {function} dispatch The dispatch function
* @returns {object} The props
*/
function mapDispatchToProps(dispatch) {
return {
dispatchRequestInfo: (repo, owner) => dispatch(infoCreators.requestInfo(repo, owner))
Expand Down
11 changes: 11 additions & 0 deletions app/containers/Info/saga.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ import { getRepo } from '@services/info';
import { ERRORS } from '@app/utils/constants';
import { infoTypes, infoCreators, INFO_PAYLOAD } from './reducer';

/**
* Request info from the API
* @param {object} action
* @param {string} action[INFO_PAYLOAD.REPO] - The name of the repository
* @param {string} action[INFO_PAYLOAD.OWNER] - The owner of the repository
* @returns {object} - The response from the API
*/
export function* requestInfo(action) {
try {
if (!action[INFO_PAYLOAD.REPO] || !action[INFO_PAYLOAD.OWNER]) {
Expand All @@ -16,6 +23,10 @@ export function* requestInfo(action) {
}
}

/**
* The root of the info saga
* @returns {void}
*/
export default function* appSaga() {
yield takeLatest(infoTypes.REQUEST_INFO, requestInfo);
}
20 changes: 19 additions & 1 deletion app/containers/Repos/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import Recommended from '@app/components/Recommended';
import { Container } from '@app/components/styled';
import ErrorState from '@components/ErrorState';
import RepoList from '@components/RepoList/index';
import RepoList from '@components/RepoList';
import { CustomCard, YouAreAwesome } from '@components/styled/repos';
import T from '@components/Text';
import { fonts } from '@themes';
Expand All @@ -25,6 +25,19 @@ import { reposActionCreators } from './reducer';
import saga from './saga';
import { selectReposData, selectReposError, selectReposSearchKey } from './selectors';

/**
* The Repos container
* @param {object} props The component props
* @param {object} props.intl The intl object
* @param {string} props.searchKey The search key
* @param {object} props.repos The repos data
* @param {string} props.error The error message
* @param {boolean} props.loading Whether the data is loading
* @param {object} props.recommendations The list of recommendations
* @param {function} props.dispatchGetGithubRepos The function to get the github repos
* @param {function} props.dispatchClearGithubRepos The function to clear the github repos
* @returns {JSX.Element} The Repos container
*/
export function Repos({
intl,
repos,
Expand Down Expand Up @@ -111,6 +124,11 @@ const mapStateToProps = createStructuredSelector({
searchKey: selectReposSearchKey()
});

/**
* The mapDispatchToProps
* @param {function} dispatch The dispatch function
* @returns {object} The props
*/
function mapDispatchToProps(dispatch) {
const { requestGetGithubRepos, clearGithubRepos } = reposActionCreators;
return {
Expand Down
11 changes: 11 additions & 0 deletions app/containers/Repos/saga.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ import { reposActionTypes, reposActionCreators, REPOS_PAYLOAD } from './reducer'
const { REQUEST_GET_GITHUB_REPOS } = reposActionTypes;
const { successGetGithubRepos, failureGetGithubRepos } = reposActionCreators;

/**
* Get the github repos
* @param {object} action
* @param {string} action[REPOS_PAYLOAD.SEARCH_KEY] - The search key
* @returns {object} - The response from the API
*/
export function* getGithubRepos(action) {
const response = yield call(getRepos, action[REPOS_PAYLOAD.SEARCH_KEY]);
const { data, ok } = response;
Expand All @@ -15,6 +21,11 @@ export function* getGithubRepos(action) {
}
}

/**
* The root of the repos saga
* @returns {void}
* @yields {object} - The response from the API
*/
export default function* appSaga() {
yield takeLatest(REQUEST_GET_GITHUB_REPOS, getGithubRepos);
}
2 changes: 1 addition & 1 deletion app/global-styles.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { css } from '@emotion/react';
import { colors } from './themes/index';
import { colors } from '@themes';

const globalStyle = css`
html,
Expand Down
3 changes: 3 additions & 0 deletions app/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import info from './containers/Info/reducer';

enableAllPlugins();

/**
* Merges the main reducer with the router state and dynamically injected reducers
*/
export default function createReducer(injectedReducer = {}) {
const rootReducer = combineReducers({
...injectedReducer,
Expand Down
8 changes: 6 additions & 2 deletions app/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import pickBy from 'lodash/pickBy';
import { screenSizes } from '@themes/media';

/**
* Get query string value
* @param {array} keys - The keys to get the value of
* @returns {object} - The query string value
*/
export function getQueryStringValue(keys) {
const queryString = {};
try {
Expand Down Expand Up @@ -36,9 +41,8 @@ export const setDeviceType = (width = document.body.clientWidth) => {
return 'mobile';
} else if (width >= screenSizes.tablet && width < screenSizes.desktop) {
return 'tablet';
} else {
return 'desktop';
}
return 'desktop';
};

export const getDeviceType = (device) => (device || setDeviceType()).toUpperCase();
Loading

0 comments on commit c696228

Please sign in to comment.