Implemented project settings page, search issues modal, general refactoring

This commit is contained in:
ireic
2019-12-27 15:25:23 +01:00
parent 3c705a6084
commit 7ceb18ee84
58 changed files with 738 additions and 193 deletions

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,96 @@
import styled from 'styled-components';
import { color, font, mixin } from 'shared/utils/styles';
import { InputDebounced, Spinner, Icon } from 'shared/components';
export const IssueSearch = styled.div`
padding: 25px 35px;
`;
export const SearchInputCont = styled.div`
position: relative;
padding-right: 30px;
margin-bottom: 40px;
`;
export const SearchInputDebounced = styled(InputDebounced)`
height: 40px;
input {
padding: 0 0 0 32px;
border: none;
border-bottom: 2px solid ${color.primary};
background: #fff;
${font.size(21)}
&:focus,
&:hover {
box-shadow: none;
border: none;
border-bottom: 2px solid ${color.primary};
background: #fff;
}
}
`;
export const SearchIcon = styled(Icon)`
position: absolute;
top: 8px;
left: 0;
color: ${color.textMedium};
`;
export const SearchSpinner = styled(Spinner)`
position: absolute;
top: 5px;
right: 30px;
`;
export const Issue = styled.div`
display: flex;
align-items: center;
padding: 4px 10px;
border-radius: 4px;
transition: background 0.1s;
${mixin.clickable}
&:hover {
background: ${color.backgroundLight};
}
`;
export const IssueData = styled.div`
padding-left: 15px;
`;
export const IssueTitle = styled.div`
color: ${color.textDark};
${font.size(15)}
`;
export const IssueTypeId = styled.div`
text-transform: uppercase;
color: ${color.textMedium};
${font.size(12.5)}
`;
export const SectionTitle = styled.div`
padding-bottom: 12px;
text-transform: uppercase;
color: ${color.textMedium};
${font.bold}
${font.size(11.5)}
`;
export const NoResults = styled.div`
padding-top: 50px;
text-align: center;
`;
export const NoResultsTitle = styled.div`
padding-top: 30px;
${font.medium}
${font.size(20)}
`;
export const NoResultsTip = styled.div`
padding-top: 10px;
${font.size(15)}
`;

View File

@@ -0,0 +1,101 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import { get } from 'lodash';
import useApi from 'shared/hooks/api';
import { sortByNewest } from 'shared/utils/javascript';
import { IssueTypeIcon } from 'shared/components';
import NoResultsSVG from './NoResultsSvg';
import {
IssueSearch,
SearchInputCont,
SearchInputDebounced,
SearchIcon,
SearchSpinner,
Issue,
IssueData,
IssueTitle,
IssueTypeId,
SectionTitle,
NoResults,
NoResultsTitle,
NoResultsTip,
} from './Styles';
const propTypes = {
project: PropTypes.object.isRequired,
};
const ProjectIssueSearch = ({ project }) => {
const [isSearchTermEmpty, setIsSearchTermEmpty] = useState(true);
const [{ data, isLoading }, fetchIssues] = useApi.get('/issues', {}, { lazy: true });
const matchingIssues = get(data, 'issues', []);
const recentIssues = sortByNewest(project.issues, 'createdAt').slice(0, 10);
const handleSearchChange = value => {
const searchTerm = value.trim();
setIsSearchTermEmpty(!searchTerm);
if (searchTerm) {
fetchIssues({ searchTerm });
}
};
const renderIssue = issue => (
<Link key={issue.id} to={`/project/board/issues/${issue.id}`}>
<Issue>
<IssueTypeIcon type={issue.type} size={25} />
<IssueData>
<IssueTitle>{issue.title}</IssueTitle>
<IssueTypeId>{`${issue.type}-${issue.id}`}</IssueTypeId>
</IssueData>
</Issue>
</Link>
);
return (
<IssueSearch>
<SearchInputCont>
<SearchInputDebounced
autoFocus
placeholder="Search issues by summary, description..."
onChange={handleSearchChange}
/>
<SearchIcon type="search" size={22} />
{isLoading && <SearchSpinner />}
</SearchInputCont>
{isSearchTermEmpty && recentIssues.length > 0 && (
<>
<SectionTitle>Recent Issues</SectionTitle>
{recentIssues.map(renderIssue)}
</>
)}
{!isSearchTermEmpty && matchingIssues.length > 0 && (
<>
<SectionTitle>Matching Issues</SectionTitle>
{matchingIssues.map(renderIssue)}
</>
)}
{!isSearchTermEmpty && !isLoading && matchingIssues.length === 0 && (
<NoResults>
<NoResultsSVG />
<NoResultsTitle>We couldn&apos;t find anything matching your search</NoResultsTitle>
<NoResultsTip>Try again with a different term.</NoResultsTip>
</NoResults>
)}
</IssueSearch>
);
};
ProjectIssueSearch.propTypes = propTypes;
export default ProjectIssueSearch;