Polished CSS, refactored useApi Query hook
This commit is contained in:
@@ -16,6 +16,9 @@ export const Issue = styled.div`
|
||||
box-shadow: 0px 1px 2px 0px rgba(9, 30, 66, 0.25);
|
||||
transition: background 0.1s;
|
||||
${mixin.clickable}
|
||||
@media (max-width: 1100px) {
|
||||
padding: 10px 8px;
|
||||
}
|
||||
&:hover {
|
||||
background: ${color.backgroundLight};
|
||||
}
|
||||
@@ -30,6 +33,9 @@ export const Issue = styled.div`
|
||||
export const Title = styled.p`
|
||||
padding-bottom: 11px;
|
||||
${font.size(15)}
|
||||
@media (max-width: 1100px) {
|
||||
${font.size(14.5)}
|
||||
}
|
||||
`;
|
||||
|
||||
export const Bottom = styled.div`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { color, font } from 'shared/utils/styles';
|
||||
import { color, font, mixin } from 'shared/utils/styles';
|
||||
|
||||
export const List = styled.div`
|
||||
display: flex;
|
||||
@@ -17,6 +17,7 @@ export const Title = styled.div`
|
||||
text-transform: uppercase;
|
||||
color: ${color.textMedium};
|
||||
${font.size(12.5)};
|
||||
${mixin.truncateText}
|
||||
`;
|
||||
|
||||
export const IssuesCount = styled.span`
|
||||
|
||||
@@ -4,7 +4,6 @@ import moment from 'moment';
|
||||
import { Droppable } from 'react-beautiful-dnd';
|
||||
import { intersection } from 'lodash';
|
||||
|
||||
import useCurrentUser from 'shared/hooks/currentUser';
|
||||
import { IssueStatusCopy } from 'shared/constants/issues';
|
||||
|
||||
import Issue from './Issue';
|
||||
@@ -14,11 +13,14 @@ const propTypes = {
|
||||
status: PropTypes.string.isRequired,
|
||||
project: PropTypes.object.isRequired,
|
||||
filters: PropTypes.object.isRequired,
|
||||
currentUserId: PropTypes.number,
|
||||
};
|
||||
|
||||
const ProjectBoardList = ({ status, project, filters }) => {
|
||||
const { currentUserId } = useCurrentUser();
|
||||
const defaultProps = {
|
||||
currentUserId: null,
|
||||
};
|
||||
|
||||
const ProjectBoardList = ({ status, project, filters, currentUserId }) => {
|
||||
const filteredIssues = filterIssues(project.issues, filters, currentUserId);
|
||||
const filteredListIssues = getSortedListIssues(filteredIssues, status);
|
||||
const allListIssues = getSortedListIssues(project.issues, status);
|
||||
@@ -77,5 +79,6 @@ const formatIssuesCount = (allListIssues, filteredListIssues) => {
|
||||
};
|
||||
|
||||
ProjectBoardList.propTypes = propTypes;
|
||||
ProjectBoardList.defaultProps = defaultProps;
|
||||
|
||||
export default ProjectBoardList;
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { DragDropContext } from 'react-beautiful-dnd';
|
||||
|
||||
import useCurrentUser from 'shared/hooks/currentUser';
|
||||
import api from 'shared/utils/api';
|
||||
import { moveItemWithinArray, insertItemIntoArray } from 'shared/utils/javascript';
|
||||
import { IssueStatus } from 'shared/constants/issues';
|
||||
@@ -16,6 +17,8 @@ const propTypes = {
|
||||
};
|
||||
|
||||
const ProjectBoardLists = ({ project, filters, updateLocalProjectIssues }) => {
|
||||
const { currentUserId } = useCurrentUser();
|
||||
|
||||
const handleIssueDrop = ({ draggableId, destination, source }) => {
|
||||
if (!isPositionChanged(source, destination)) return;
|
||||
|
||||
@@ -35,7 +38,13 @@ const ProjectBoardLists = ({ project, filters, updateLocalProjectIssues }) => {
|
||||
<DragDropContext onDragEnd={handleIssueDrop}>
|
||||
<Lists>
|
||||
{Object.values(IssueStatus).map(status => (
|
||||
<List key={status} status={status} project={project} filters={filters} />
|
||||
<List
|
||||
key={status}
|
||||
status={status}
|
||||
project={project}
|
||||
filters={filters}
|
||||
currentUserId={currentUserId}
|
||||
/>
|
||||
))}
|
||||
</Lists>
|
||||
</DragDropContext>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { color, font, mixin } from 'shared/utils/styles';
|
||||
import { InputDebounced, Spinner, Icon } from 'shared/components';
|
||||
|
||||
export const IssueSearch = styled.div`
|
||||
padding: 25px 35px;
|
||||
padding: 25px 35px 60px;
|
||||
`;
|
||||
|
||||
export const SearchInputCont = styled.div`
|
||||
|
||||
@@ -3,15 +3,20 @@ import styled from 'styled-components';
|
||||
import { color, sizes, font, mixin, zIndexValues } from 'shared/utils/styles';
|
||||
|
||||
export const Sidebar = styled.div`
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
z-index: ${zIndexValues.navLeft - 1};
|
||||
top: 0;
|
||||
left: ${sizes.appNavBarLeftWidth}px;
|
||||
height: 100vh;
|
||||
width: 240px;
|
||||
padding: 0 16px;
|
||||
width: ${sizes.secondarySideBarWidth}px;
|
||||
padding: 0 16px 24px;
|
||||
background: ${color.backgroundLightest};
|
||||
border-right: 1px solid ${color.borderLightest};
|
||||
${mixin.scrollableY}
|
||||
${mixin.customScrollbar()}
|
||||
@media (max-width: 1100px) {
|
||||
width: ${sizes.secondarySideBarWidth - 10}px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const ProjectInfo = styled.div`
|
||||
@@ -67,18 +72,20 @@ export const LinkText = styled.div`
|
||||
`;
|
||||
|
||||
export const NotImplemented = styled.div`
|
||||
display: none;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 9px;
|
||||
left: 101%;
|
||||
width: 120px;
|
||||
padding: 3px 0 3px 8px;
|
||||
top: 7px;
|
||||
left: 40px;
|
||||
width: 140px;
|
||||
padding: 5px 0 5px 8px;
|
||||
border-radius: 3px;
|
||||
color: #fff;
|
||||
background: #000;
|
||||
${font.size(12.5)};
|
||||
${font.medium}
|
||||
text-transform: uppercase;
|
||||
color: ${color.textDark};
|
||||
background: ${color.backgroundMedium};
|
||||
opacity: 0;
|
||||
${font.size(11.5)};
|
||||
${font.bold}
|
||||
${LinkItem}:hover & {
|
||||
display: inline-block;
|
||||
opacity: 1;
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -2,6 +2,12 @@ import styled from 'styled-components';
|
||||
|
||||
import { sizes } from 'shared/utils/styles';
|
||||
|
||||
const paddingLeft = sizes.appNavBarLeftWidth + sizes.secondarySideBarWidth + 40;
|
||||
|
||||
export const ProjectPage = styled.div`
|
||||
padding: 25px 32px 0 ${sizes.appNavBarLeftWidth + sizes.secondarySideBarWidth + 40}px;
|
||||
padding: 25px 32px 50px ${paddingLeft}px;
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
padding: 25px 20px 50px ${paddingLeft - 20}px;
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -7,10 +7,3 @@ import ReactDOM from 'react-dom';
|
||||
import App from 'App';
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'));
|
||||
|
||||
// QUERY component cache-only doesn't work until first req finishes, look at currentUser on page load
|
||||
// APP IS NOT RESPONSIVE - REDUCE BROWSER HEIGHT, ISSUES DONT SCROLL
|
||||
// TODO: UPDATE FORMIK TO FIX SETFIELDVALUE TO EMPTY ARRAY ISSUE https://github.com/jaredpalmer/formik/pull/2144
|
||||
// REFACTOR HTML TO USE SEMANTIC ELEMENTS
|
||||
// MOVE SOME UTILS LIKE API TO SERVICES FOLDER
|
||||
// RENAME ISSUE DETAILS "USERS" TO ASSIGNEESREPORTER
|
||||
|
||||
@@ -58,7 +58,14 @@ const Modal = ({
|
||||
|
||||
useOnOutsideClick($modalRef, isOpen, closeModal, $clickableOverlayRef);
|
||||
useOnEscapeKeyDown(isOpen, closeModal);
|
||||
useEffect(setBodyScrollLock, [isOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
document.body.style.overflow = 'hidden';
|
||||
|
||||
return () => {
|
||||
document.body.style.overflow = 'visible';
|
||||
};
|
||||
}, [isOpen]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -72,7 +79,6 @@ const Modal = ({
|
||||
className={className}
|
||||
variant={variant}
|
||||
width={width}
|
||||
data-jira-modal="true"
|
||||
data-testid={testid}
|
||||
ref={$modalRef}
|
||||
>
|
||||
@@ -89,11 +95,6 @@ const Modal = ({
|
||||
|
||||
const $root = document.getElementById('root');
|
||||
|
||||
const setBodyScrollLock = () => {
|
||||
const areAnyModalsOpen = !!document.querySelector('[data-jira-modal]');
|
||||
document.body.style.overflow = areAnyModalsOpen ? 'hidden' : 'visible';
|
||||
};
|
||||
|
||||
Modal.propTypes = propTypes;
|
||||
Modal.defaultProps = defaultProps;
|
||||
|
||||
|
||||
@@ -29,7 +29,13 @@ const useMutation = (method, url) => {
|
||||
[method, url, mergeState],
|
||||
);
|
||||
|
||||
return [{ ...state, [isWorkingAlias[method]]: state.isWorking }, makeRequest];
|
||||
return [
|
||||
{
|
||||
...state,
|
||||
[isWorkingAlias[method]]: state.isWorking,
|
||||
},
|
||||
makeRequest,
|
||||
];
|
||||
};
|
||||
|
||||
const isWorkingAlias = {
|
||||
|
||||
@@ -8,44 +8,34 @@ import useDeepCompareMemoize from 'shared/hooks/deepCompareMemoize';
|
||||
const useQuery = (url, propsVariables = {}, options = {}) => {
|
||||
const { lazy = false, cachePolicy = 'cache-first' } = options;
|
||||
|
||||
const wasCalled = useRef(false);
|
||||
const propsVariablesMemoized = useDeepCompareMemoize(propsVariables);
|
||||
|
||||
const isSleeping = lazy && !wasCalled.current;
|
||||
const isCacheAvailable = cache[url] && isEqual(cache[url].apiVariables, propsVariables);
|
||||
const canUseCache = isCacheAvailable && cachePolicy !== 'no-cache' && !wasCalled.current;
|
||||
|
||||
const [state, mergeState] = useMergeState({
|
||||
data: null,
|
||||
data: canUseCache ? cache[url].data : null,
|
||||
error: null,
|
||||
isLoading: !lazy,
|
||||
isLoading: !lazy && !canUseCache,
|
||||
variables: {},
|
||||
});
|
||||
|
||||
const wasCalledRef = useRef(false);
|
||||
const propsVariablesMemoized = useDeepCompareMemoize(propsVariables);
|
||||
|
||||
const stateRef = useRef();
|
||||
stateRef.current = state;
|
||||
|
||||
const makeRequest = useCallback(
|
||||
(newVariables = {}, isAutoCalled) => {
|
||||
const variables = { ...stateRef.current.variables, ...newVariables };
|
||||
(newVariables, { skipLoading } = {}) => {
|
||||
const variables = { ...state.variables, ...(newVariables || {}) };
|
||||
const apiVariables = { ...propsVariablesMemoized, ...variables };
|
||||
|
||||
const isCacheAvailable = cache[url] && isEqual(cache[url].apiVariables, apiVariables);
|
||||
|
||||
const isCacheAvailableAndPermitted =
|
||||
isCacheAvailable && isAutoCalled && cachePolicy !== 'no-cache';
|
||||
|
||||
if (isCacheAvailableAndPermitted) {
|
||||
mergeState({ data: cache[url].data, error: null, isLoading: false, variables });
|
||||
|
||||
if (cachePolicy === 'cache-only') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isCacheAvailableAndPermitted && (lazy || wasCalledRef.current)) {
|
||||
if (!skipLoading) {
|
||||
mergeState({ isLoading: true, variables });
|
||||
} else if (newVariables) {
|
||||
mergeState({ variables });
|
||||
}
|
||||
|
||||
api.get(url, apiVariables).then(
|
||||
data => {
|
||||
cache[url] = { apiVariables, data };
|
||||
cache[url] = { data, apiVariables };
|
||||
mergeState({ data, error: null, isLoading: false });
|
||||
},
|
||||
error => {
|
||||
@@ -53,26 +43,37 @@ const useQuery = (url, propsVariables = {}, options = {}) => {
|
||||
},
|
||||
);
|
||||
|
||||
wasCalledRef.current = true;
|
||||
wasCalled.current = true;
|
||||
},
|
||||
[propsVariablesMemoized, cachePolicy, url, lazy, mergeState],
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[propsVariablesMemoized],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!lazy || wasCalledRef.current) {
|
||||
makeRequest({}, true);
|
||||
}
|
||||
}, [lazy, makeRequest]);
|
||||
if (isSleeping) return;
|
||||
if (canUseCache && cachePolicy === 'cache-only') return;
|
||||
|
||||
makeRequest(
|
||||
{},
|
||||
{
|
||||
skipLoading: canUseCache && cachePolicy === 'cache-first',
|
||||
},
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [makeRequest]);
|
||||
|
||||
const setLocalData = useCallback(
|
||||
getUpdatedData => mergeState(({ data }) => ({ data: getUpdatedData(data) })),
|
||||
[mergeState],
|
||||
getUpdatedData =>
|
||||
mergeState(({ data }) => {
|
||||
cache[url] = { ...(cache[url] || {}), data: getUpdatedData(data) };
|
||||
return { data: getUpdatedData(data) };
|
||||
}),
|
||||
[mergeState, url],
|
||||
);
|
||||
|
||||
return [
|
||||
{
|
||||
...state,
|
||||
wasCalled: wasCalledRef.current,
|
||||
variables: { ...propsVariablesMemoized, ...state.variables },
|
||||
setLocalData,
|
||||
},
|
||||
|
||||
@@ -5,10 +5,10 @@ import useApi from 'shared/hooks/api';
|
||||
const useCurrentUser = ({ cachePolicy = 'cache-only' } = {}) => {
|
||||
const [{ data }] = useApi.get('/currentUser', {}, { cachePolicy });
|
||||
|
||||
const currentUser = get(data, 'currentUser');
|
||||
const currentUserId = get(data, 'currentUser.id');
|
||||
|
||||
return { currentUser, currentUserId };
|
||||
return {
|
||||
currentUser: get(data, 'currentUser'),
|
||||
currentUserId: get(data, 'currentUser.id'),
|
||||
};
|
||||
};
|
||||
|
||||
export default useCurrentUser;
|
||||
|
||||
@@ -7,7 +7,6 @@ const useDeepCompareMemoize = value => {
|
||||
if (!isEqual(value, valueRef.current)) {
|
||||
valueRef.current = value;
|
||||
}
|
||||
|
||||
return valueRef.current;
|
||||
};
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ const useOnEscapeKeyDown = (isListening, onEscapeKeyDown) => {
|
||||
if (isListening) {
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
|
||||
@@ -33,7 +33,6 @@ const useOnOutsideClick = (
|
||||
$listeningElement.addEventListener('mousedown', handleMouseDown);
|
||||
$listeningElement.addEventListener('mouseup', handleMouseUp);
|
||||
}
|
||||
|
||||
return () => {
|
||||
$listeningElement.removeEventListener('mousedown', handleMouseDown);
|
||||
$listeningElement.removeEventListener('mouseup', handleMouseUp);
|
||||
|
||||
@@ -58,7 +58,7 @@ export const issueStatusBackgroundColors = {
|
||||
|
||||
export const sizes = {
|
||||
appNavBarLeftWidth: 64,
|
||||
secondarySideBarWidth: 240,
|
||||
secondarySideBarWidth: 230,
|
||||
minViewportWidth: 1000,
|
||||
};
|
||||
|
||||
@@ -137,10 +137,7 @@ export const mixin = {
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
`,
|
||||
customScrollbar: ({
|
||||
width = 8,
|
||||
background = mixin.darken(color.backgroundMedium, 0.2),
|
||||
} = {}) => css`
|
||||
customScrollbar: ({ width = 8, background = color.backgroundMedium } = {}) => css`
|
||||
&::-webkit-scrollbar {
|
||||
width: ${width}px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user