Skip to content

Commit

Permalink
Ui context (#251)
Browse files Browse the repository at this point in the history
* Create UIContextProvider

* Remove ui reducer and actions

* Replace redux actions with UIContext methods

* Replace set... methods with open/close equivalents

* Place context's value inside useMemo

* Fix useMemo

* Fix useMemo
  • Loading branch information
drillprop authored Oct 31, 2020
1 parent 4a2cc63 commit 4e4f8a1
Show file tree
Hide file tree
Showing 12 changed files with 233 additions and 194 deletions.
6 changes: 4 additions & 2 deletions apps/www/components/adminQuestions/AdminQuestions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useDispatch, useSelector } from 'react-redux';

import spinnerStyles from '../../components/layout/appSpinner.module.scss';
import { TechnologyKey } from '../../constants/technology-icon-items';
import { useUIContext } from '../../contexts/UIContextProvider';
import { ActionCreators } from '../../redux/actions';
import { Question } from '../../redux/reducers/questions';
import { Container } from '../container/Container';
Expand All @@ -25,6 +26,7 @@ const EmptyAdminQuestions = memo(({ questions }: { questions?: Question[] }) =>
});

const AdminQuestions = memo(() => {
const { openEditQuestionModal } = useUIContext();
const [status, setStatus] = useState<'pending' | 'accepted'>('pending');
const [technology] = useState<TechnologyKey | undefined>(undefined);

Expand Down Expand Up @@ -74,9 +76,9 @@ const AdminQuestions = memo(() => {
return;
}

dispatch(ActionCreators.uiOpenEditQuestionModal(question, onEditFinished));
openEditQuestionModal(question, onEditFinished);
},
[dispatch, onEditFinished, questions.data]
[onEditFinished, openEditQuestionModal, questions.data]
);

const updateStatus: React.ChangeEventHandler<HTMLSelectElement> = useCallback((e) => {
Expand Down
133 changes: 66 additions & 67 deletions apps/www/components/headers/ctaHeader/CtaHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import classNames from 'classnames';
import React, { memo } from 'react';
import { connect } from 'react-redux';

import { ActionCreators } from '../../../redux/actions';
import { useUIContext } from '../../../contexts/UIContextProvider';
import { AppState } from '../../../redux/reducers/index';
import {
getAreAnyQuestionSelected,
Expand All @@ -14,59 +14,61 @@ import { Container } from '../../container/Container';

import styles from './ctaHeader.module.scss';

export const CtaHeaderComponent: React.FC<
ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps
> = memo(({ uiOpenAddQuestionModal, areAnyQuestionSelected, isAdmin }) => {
const onDownloadClick: React.MouseEventHandler<HTMLElement> = (_event) => {
reportEvent('Pobierz plik PDF');
// @todo open DownloadSuccessModal
// @todo this.analyticsService.reportPdfDownload(this.selectedQuestionsService.getSelectedIds());
};
export const CtaHeaderComponent: React.FC<ReturnType<typeof mapStateToProps>> = memo(
({ areAnyQuestionSelected, isAdmin }) => {
const { openAddQuestionModal } = useUIContext();
const onDownloadClick: React.MouseEventHandler<HTMLElement> = (_event) => {
reportEvent('Pobierz plik PDF');
// @todo open DownloadSuccessModal
// @todo this.analyticsService.reportPdfDownload(this.selectedQuestionsService.getSelectedIds());
};

const onOpenAddQuestionModalClick: React.MouseEventHandler<HTMLElement> = (_event) => {
reportEvent('Dodaj pytanie');
uiOpenAddQuestionModal();
};
const onOpenAddQuestionModalClick: React.MouseEventHandler<HTMLElement> = (_event) => {
reportEvent('Dodaj pytanie');
openAddQuestionModal();
};

const reportEvent = (action: string) => {
globalReportEvent(action, 'Menu');
};
return (
<div className={classNames('app-cta-header', styles.ctaHeader)}>
<Container as="header" className={styles.appHeaderCta}>
<nav className={styles.appTabs}>
<ActiveLink href="/questions" activeClassName={styles.active}>
<a
data-cy="navigate-list"
onClick={() => reportEvent('Lista pytań')}
className={styles.appTabsTab}
>
Lista pytań
</a>
</ActiveLink>
<ActiveLink href="/selected-questions" activeClassName={styles.active}>
<a
data-cy="navigate-selected-questions"
onClick={() =>
reportEvent(areAnyQuestionSelected ? 'Wybrane pytania' : 'Wybrane pytania (puste)')
}
className={classNames(styles.appTabsTab, {
[styles.hasNotification]: areAnyQuestionSelected,
})}
>
Wybrane pytania
</a>
</ActiveLink>

{isAdmin && (
<ActiveLink href="/admin" activeClassName={styles.active}>
<a className={styles.appTabsTab}>Admin</a>
const reportEvent = (action: string) => {
globalReportEvent(action, 'Menu');
};
return (
<div className={classNames('app-cta-header', styles.ctaHeader)}>
<Container as="header" className={styles.appHeaderCta}>
<nav className={styles.appTabs}>
<ActiveLink href="/questions" activeClassName={styles.active}>
<a
data-cy="navigate-list"
onClick={() => reportEvent('Lista pytań')}
className={styles.appTabsTab}
>
Lista pytań
</a>
</ActiveLink>
<ActiveLink href="/selected-questions" activeClassName={styles.active}>
<a
data-cy="navigate-selected-questions"
onClick={() =>
reportEvent(
areAnyQuestionSelected ? 'Wybrane pytania' : 'Wybrane pytania (puste)'
)
}
className={classNames(styles.appTabsTab, {
[styles.hasNotification]: areAnyQuestionSelected,
})}
>
Wybrane pytania
</a>
</ActiveLink>
)}
</nav>

<div className={styles.callToActionButtons}>
{/* <ActiveLink route={this.props.downloadUrl}>
{isAdmin && (
<ActiveLink href="/admin" activeClassName={styles.active}>
<a className={styles.appTabsTab}>Admin</a>
</ActiveLink>
)}
</nav>

<div className={styles.callToActionButtons}>
{/* <ActiveLink route={this.props.downloadUrl}>
<a
onClick={this.onDownloadClick}
target="_blank"
Expand All @@ -79,18 +81,19 @@ export const CtaHeaderComponent: React.FC<
Pobierz plik PDF
</a>
</ActiveLink> */}
<button
className={classNames(styles.roundButton, 'round-button', 'branding-button-inverse')}
onClick={onOpenAddQuestionModalClick}
data-cy="open-add-question-form"
>
Dodaj pytanie
</button>
</div>
</Container>
</div>
);
});
<button
className={classNames(styles.roundButton, 'round-button', 'branding-button-inverse')}
onClick={onOpenAddQuestionModalClick}
data-cy="open-add-question-form"
>
Dodaj pytanie
</button>
</div>
</Container>
</div>
);
}
);

const mapStateToProps = (state: AppState) => {
return {
Expand All @@ -100,8 +103,4 @@ const mapStateToProps = (state: AppState) => {
};
};

const mapDispatchToProps = {
uiOpenAddQuestionModal: ActionCreators.uiOpenAddQuestionModal,
};

export const CtaHeader = connect(mapStateToProps, mapDispatchToProps)(CtaHeaderComponent);
export const CtaHeader = connect(mapStateToProps)(CtaHeaderComponent);
20 changes: 13 additions & 7 deletions apps/www/components/modals/addQuestionModal/AddQuestionModal.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { isEqual } from 'lodash';
import React, { memo, useState, useEffect, useCallback, forwardRef } from 'react';
import { useDispatch } from 'react-redux';
import React, { forwardRef, memo, useCallback, useEffect, useState } from 'react';

import type { LevelKey } from '../../../constants/level';
import type { TechnologyKey } from '../../../constants/technology-icon-items';
import { ActionCreators } from '../../../redux/actions';
import { useUIContext } from '../../../contexts/UIContextProvider';
import { Question } from '../../../redux/reducers/questions';
import { Api } from '../../../services/Api';
import { useDidMount, useRenderProp } from '../../../utils/hooks';
Expand All @@ -24,15 +23,14 @@ type AddQuestionModalProps = AddQuestionModalOwnProps & CommonModalProps;

export const AddQuestionModal = memo(
forwardRef<HTMLDivElement, AddQuestionModalProps>(({ onClose, originalQuestion }, ref) => {
const { openAddQuestionConfirmationModal } = useUIContext();
const [editedQuestion, setEditedQuestion] = useState<Question>();
const [questionText, setQuestionText] = useState('');
const [level, setLevel] = useState<LevelKey>();
const [technology, setTechnology] = useState<TechnologyKey>();
const [isLoading, setIsLoading] = useState(false);
const [valid, setValid] = useState(false);

const dispatch = useDispatch();

const isValid = useCallback(() => Boolean(level && technology && questionText.trim()), [
level,
questionText,
Expand Down Expand Up @@ -101,11 +99,19 @@ export const AddQuestionModal = memo(
return Api.createQuestion(body)
.then(() => {
onClose({ reason: 'submit' });
dispatch(ActionCreators.uiOpenAddQuestionConfirmationModal());
openAddQuestionConfirmationModal();
})
.finally(() => setIsLoading(false));
}
}, [dispatch, isValid, level, onClose, originalQuestion, questionText, technology]);
}, [
isValid,
level,
onClose,
openAddQuestionConfirmationModal,
originalQuestion,
questionText,
technology,
]);

const validate = useCallback(() => {
setValid(isValid());
Expand Down
27 changes: 14 additions & 13 deletions apps/www/components/modals/appModals/AppModals.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React, { useRef, memo, useCallback } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import React, { memo, useCallback, useRef } from 'react';
import { CSSTransition } from 'react-transition-group';

import { ActionCreators } from '../../../redux/actions';
import { useUIContext } from '../../../contexts/UIContextProvider';
import { AddQuestionConfirmationModal } from '../addQuestionConfirmationModal/AddQuestionConfirmationModal';
import { AddQuestionModal } from '../addQuestionModal/AddQuestionModal';
import { CommonModalProps } from '../baseModal/BaseModal';
Expand All @@ -14,31 +13,33 @@ export const AppModals = memo(() => {
const addQuestionModalRef = useRef<HTMLDivElement>(null);
const addQuestionConfirmationModalRef = useRef<HTMLDivElement>(null);

const dispatch = useDispatch();
const addQuestionModalState = useSelector((state) => state.ui.addQuestionModal);
const isAddQuestionConfirmationModalOpen = useSelector(
(state) => state.ui.isAddQuestionConfirmationModalOpen
);
const {
addQuestionModalState,
closeAddQuestionModal,
isAddQuestionConfirmationModalOpen,
closeEditQuestionModal,
closeAddQuestionConfirmationModal,
} = useUIContext();

const closeQuestionModal: CommonModalProps['onClose'] = useCallback(
(args) => {
if (addQuestionModalState.onClose) {
addQuestionModalState.onClose(args);
}
if (addQuestionModalState.data) {
dispatch(ActionCreators.uiCloseEditQuestionModal());
closeEditQuestionModal();
} else {
dispatch(ActionCreators.uiCloseAddQuestionModal());
closeAddQuestionModal();
}
},
[addQuestionModalState, dispatch]
[addQuestionModalState, closeAddQuestionModal, closeEditQuestionModal]
);

const closeConfirmationModal: CommonModalProps['onClose'] = useCallback(
(_args) => {
dispatch(ActionCreators.uiCloseAddQuestionConfirmationModal());
closeAddQuestionConfirmationModal();
},
[dispatch]
[closeAddQuestionConfirmationModal]
);

return (
Expand Down
8 changes: 4 additions & 4 deletions apps/www/components/questions/allQuestions/AllQuestions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { connect } from 'react-redux';

import { Level } from '../../../constants/level';
import { technologyIconItems, Technology } from '../../../constants/technology-icon-items';
import { useUIContext } from '../../../contexts/UIContextProvider';
import { ActionCreators } from '../../../redux/actions';
import { AppState } from '../../../redux/reducers/index';
import { Question } from '../../../redux/reducers/questions';
Expand All @@ -29,10 +30,10 @@ const AllQuestionsComponent = React.memo<AllQuestionsComponentProps>(
questions,
selectedQuestionsIds,
route,
uiOpenAddQuestionModal,
selectQuestion,
deselectQuestion,
}) => {
const { openAddQuestionModal } = useUIContext();
const technologyIconItem = technologyIconItems.find((t) => t.name === technology);
const category = (technologyIconItem && technologyIconItem.label) || '';

Expand All @@ -55,8 +56,8 @@ const AllQuestionsComponent = React.memo<AllQuestionsComponentProps>(

const onAddNewClick = useCallback(() => {
reportEvent('CTA Dodaj nowe pytanie');
uiOpenAddQuestionModal();
}, [uiOpenAddQuestionModal, reportEvent]);
openAddQuestionModal();
}, [openAddQuestionModal, reportEvent]);

const toggleQuestion = useCallback(
(questionId: Question['id']) => {
Expand Down Expand Up @@ -141,7 +142,6 @@ const mapStateToProps = (state: AppState) => {
const mapDispatchToProps = {
selectQuestion: ActionCreators.selectQuestion,
deselectQuestion: ActionCreators.deselectQuestion,
uiOpenAddQuestionModal: ActionCreators.uiOpenAddQuestionModal,
};

const AllQuestions = connect(mapStateToProps, mapDispatchToProps)(AllQuestionsComponent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import classNames from 'classnames';
import React from 'react';
import { connect } from 'react-redux';

import { ActionCreators } from '../../../redux/actions';
import { useUIContext } from '../../../contexts/UIContextProvider';
import { AppState } from '../../../redux/reducers';
import { getAreAnyQuestionSelected, getDownloadUrl } from '../../../redux/selectors/selectors';

Expand All @@ -13,8 +13,9 @@ interface MobileActionButtonsProps {
}

const MobileActionButtonsComponent = React.memo<
MobileActionButtonsProps & ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps
>(({ justDownload, uiOpenSidebar, uiOpenAddQuestionModal }) => {
MobileActionButtonsProps & ReturnType<typeof mapStateToProps>
>(({ justDownload }) => {
const { openSideBar, openAddQuestionModal } = useUIContext();
const onDownloadClick = () => {
// @todo
};
Expand All @@ -25,15 +26,15 @@ const MobileActionButtonsComponent = React.memo<
className={classNames(styles.openSidebar, 'circle-button')}
title="Filtruj wyniki"
aria-label="Filtruj wyniki"
onClick={uiOpenSidebar}
onClick={openSideBar}
/>
)}
{!justDownload && (
<button
className={classNames(styles.addQuestion, 'circle-button')}
title="Dodaj pytanie"
aria-label="Dodaj pytanie"
onClick={uiOpenAddQuestionModal}
onClick={openAddQuestionModal}
/>
)}
{/* {!justDownload && (
Expand Down Expand Up @@ -71,13 +72,5 @@ const mapStateToProps = (state: AppState) => {
};
};

const mapDispatchToProps = {
uiOpenSidebar: ActionCreators.uiOpenSidebar,
uiOpenAddQuestionModal: ActionCreators.uiOpenAddQuestionModal,
};

const MobileActionButtons = connect(
mapStateToProps,
mapDispatchToProps
)(MobileActionButtonsComponent);
const MobileActionButtons = connect(mapStateToProps)(MobileActionButtonsComponent);
export default MobileActionButtons;
Loading

0 comments on commit 4e4f8a1

Please sign in to comment.