Skip to content

Commit

Permalink
[#35] feat : Align comments by created time
Browse files Browse the repository at this point in the history
  • Loading branch information
Seohyoung committed Jun 24, 2021
1 parent 0e7b560 commit e417f83
Show file tree
Hide file tree
Showing 17 changed files with 312 additions and 176 deletions.
6 changes: 4 additions & 2 deletions FE/frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { RecoilRoot } from 'recoil';
import { QueryClient, QueryClientProvider } from 'react-query';
import Login from './components/login/Login';
import Main from './components/main/Main';
import Oauth from './components/login/Oauth';
import GoogleOauth from './components/login/GoogleOauth';
import GitHubOauth from './components/login/GitHubOauth';

const queryClient = new QueryClient();
function App() {
Expand All @@ -26,7 +27,8 @@ function App() {
<Login />
)}
</Route>
<Route path="/login/github" component={Oauth} />
<Route path="/login/github" component={GitHubOauth} />
<Route path="/login/google" component={GoogleOauth} />
<Route path="/main" component={Main} />
</Switch>
</BrowserRouter>
Expand Down
File renamed without changes.
37 changes: 37 additions & 0 deletions FE/frontend/src/components/login/GoogleOauth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, { useEffect } from 'react';
import qs from 'qs';
import axios from 'axios';
import URL from '../../util/url';
import Main from '../main/Main';
import { RouteComponentProps } from 'react-router-dom';

interface Props extends RouteComponentProps {}

const GoogleOauth: React.FC<Props> = ({ history, location }) => {
useEffect(() => {
const getToken = async () => {
const { code } = qs.parse(location.search, {
ignoreQueryPrefix: true,
});

try {
const response = await axios.get(`${URL}/login/google?code=${code}`);
localStorage.setItem('token', response.data.data.jwt);

axios.get(`${URL}/jwt`, {
headers: { Authorization: 'Bearer ' + localStorage.getItem('token') },
});
history.push('/main');
} catch (error) {
alert(error);
history.push('/');
}
};

getToken();
}, [location, history]);

return <Main />;
};

export default GoogleOauth;
5 changes: 4 additions & 1 deletion FE/frontend/src/components/login/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ import { ReactComponent as Logo } from '../../icons/logoLarge.svg';

const Login = () => {
const url = `https://github.com/login/oauth/authorize?client_id=8f053229e25de08ed09d&scope=user:email&redirect_uri=http://localhost:3000/login/github`;
const googleUrl = `https://accounts.google.com/o/oauth2/v2/auth?client_id=195028719127-a5r87r9182sidvd6vjs9akod785k5t94.apps.googleusercontent.com&redirect_uri=http://localhost:3000/login/google&response_type=code&scope=https://www.googleapis.com/auth/userinfo.email+https://www.googleapis.com/auth/userinfo.profile&flowName=GeneralOAuthFlow`;

return (
<LoginContainer>
<Logo />
<a href={url}>
<GitHubLogin large>GitHub 계정으로 로그인</GitHubLogin>
</a>
<GoogleLogin large>Google 계정으로 로그인</GoogleLogin>
<a href={googleUrl}>
<GoogleLogin large>Google 계정으로 로그인</GoogleLogin>
</a>
<TextInBetween sm>or</TextInBetween>
<ManualLogin large>아이디</ManualLogin>
<ManualLogin large>비밀번호</ManualLogin>
Expand Down
32 changes: 32 additions & 0 deletions FE/frontend/src/components/main/issue/AssigneeFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react';
import styled from 'styled-components';
import Modal from '../../../styles/molcules/Modal';
import Typos from '../../../styles/atoms/Typos';
import { ReactComponent as Downward } from '../../../icons/downward.svg';

const AssigneeFilter = () => {
const assignees = new Set(['담당자가 없는 이슈']);
return (
<div>
<Modal
options={assignees}
exceptedDiv="filterTitle"
type="text"
innerTitle="담당자 필터">
<Text link sm>
담당자
<Downward />
</Text>
</Modal>
</div>
);
};

const Text = styled(Typos)`
color: ${props => props.theme.greyscale.label};
svg {
margin: 2px 0 0 10px;
}
`;

export default AssigneeFilter;
40 changes: 23 additions & 17 deletions FE/frontend/src/components/main/issue/IssueDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import useMutate from '../../../util/useMutate';
import useFetch from '../../../util/useFetch';
import User from '../../../styles/atoms/User';
import Buttons from '../../../styles/atoms/Buttons';
import Typos from '../../../styles/atoms/Typos';
import { ReactComponent as AlertCircle } from '../../../icons/alertCircle.svg';
import { ReactComponent as XSquare } from '../../../icons/xSquare.svg';
import { ReactComponent as Edit } from '../../../icons/edit.svg';

const IssueDetail = () => {
const queryClient = useQueryClient();
const location = useLocation();
const { isLoading, data, error } = useFetch('issue', 'detail', {
const { isLoading, data, error, refetch } = useFetch('issue', 'detail', {
id: location.pathname,
});

Expand All @@ -29,6 +30,7 @@ const IssueDetail = () => {

const [isEditOpen, setIsEditOpen] = useState(false);
const [editedTitle, setEditedTitle] = useState(data?.title);

const setEditOpen = () => {
setIsEditOpen(!isEditOpen);
};
Expand All @@ -37,7 +39,7 @@ const IssueDetail = () => {
await MutateTitle({ data: editedTitle, id: id });

if (isEditSuccess) {
queryClient.invalidateQueries(['issue', 'detail']);
refetch();
setEditOpen();
}
};
Expand Down Expand Up @@ -120,23 +122,27 @@ const IssueDetail = () => {
<Line />
<MainContainer>
<CommentsContainer>
{data.comments.map((comment: any, index: number) => {
return (
<SingleComment>
<User imageURL={comment.writer.profile_image} />
<CommentContainer>
<CommentTab>
<span>{comment.writer.username}</span>
<span>{moment(comment.created_time).fromNow()}</span>
</CommentTab>
<Comment>{comment.content}</Comment>
</CommentContainer>
</SingleComment>
);
})}
<NewComment issueId={data.id} />
{data.comments
.sort((a: any, b: any) => a.id - b.id)
.reverse()
.map((comment: any, index: number) => {
return (
<SingleComment>
<User imageURL={comment.writer.profile_image} />
<CommentContainer>
<CommentTab>
<span>{comment.writer.username}</span>
<span>{moment(comment.created_time).fromNow()}</span>
</CommentTab>
<Comment>{comment.content}</Comment>
</CommentContainer>
</SingleComment>
);
})}
<NewComment issueId={data.id} refetch={refetch} />
</CommentsContainer>
<Assignees></Assignees>
<Typos xs>이슈 삭제</Typos>
</MainContainer>
</LabelListContainer>
)}
Expand Down
151 changes: 28 additions & 123 deletions FE/frontend/src/components/main/issue/IssueTable.tsx
Original file line number Diff line number Diff line change
@@ -1,88 +1,54 @@
import React from 'react';
import React, { useEffect } from 'react';
import styled from 'styled-components';
import { Link } from 'react-router-dom';
import moment from 'moment';
import 'moment/locale/ko';
import { useQueryClient } from 'react-query';
import useFetch from '../../../util/useFetch';
import ListFilters from './ListFilters';
import Issues from './Issues';
import Typo from '../../../styles/atoms/Typos';
import CheckBox from '../../../styles/atoms/CheckBox';
import Label from '../../../styles/atoms/Label';
import User from '../../../styles/atoms/User';
import { ReactComponent as AlertCircle } from '../../../icons/alertCircle.svg';
import { ReactComponent as Archive } from '../../../icons/archive.svg';
import { ReactComponent as MilestoneIcon } from '../../../icons/milestone.svg';
import { ChangeEvent } from 'react';
import { useRecoilState } from 'recoil';
import { filterAtom } from '../../../recoil/atoms';

const IssueTable = () => {
const { isLoading, data, error } = useFetch('issue', 'getAllData');
const [filter, setFilter] = useRecoilState<any>(filterAtom);
const { isLoading, data, error, refetch } = useFetch(
'issue',
'filter',
filter
);
const { data: count } = useFetch('issue', 'count');

useEffect(() => {
refetch();
}, [filter]);

const showOpenIssue = async () => {
setFilter({ ...filter, isOpen: true });
};

const showClosedIssue = async () => {
setFilter({ ...filter, isOpen: false });
};

return (
<>
<IssueHeader>
<LeftHeaderContainer>
<CheckBox />
<Text link sm>
<Text link sm onClick={showOpenIssue}>
<AlertCircle />
열린 이슈({count?.open_issues})
</Text>
<Text link sm>
<Text link sm onClick={showClosedIssue}>
<Archive />
닫힌 이슈({count?.closed_issues})
</Text>
</LeftHeaderContainer>
<ListFilters />
</IssueHeader>
<TableContainer>
{data?.map((issue: any, index: number) => {
return (
<IssueCell key={index}>
<TextCell>
<UpperCell>
<div>
<CheckBox />
</div>
<UpperInfo>
<Title to={`/issues/${issue.id}`}>
<AlertCircle /> {issue.title}
</Title>
<Labels>
{issue.labels.map(
(
label: { id: number; title: string; color: string },
index: number
) => {
return (
<Label
key={index}
title={label.title}
background={label.color}
/>
);
}
)}
</Labels>
</UpperInfo>
</UpperCell>
<LowerCell>
<div>#{issue.id}</div>
<div>
이 이슈가 {moment(issue.created_time).fromNow()},{' '}
{issue.writer.username}님에 의해 작성되었습니다.
</div>
{issue.milestone && (
<div>
<MilestoneIcon /> {issue.milestone.title}
</div>
)}
</LowerCell>
</TextCell>
<User imageURL={issue.writer.profile_image} />
</IssueCell>
);
})}
</TableContainer>
<TableContainer>{data && <Issues data={data} />}</TableContainer>
</>
);
};
Expand All @@ -102,76 +68,15 @@ const IssueHeader = styled.div`
`;

const LeftHeaderContainer = styled.div`
padding: 0 24px;
padding: 0 1px;
& > div {
padding: 0 18px;
padding: 0 10px;
}
svg {
stroke: ${props => props.theme.greyscale.titleActive};
}
`;

const IssueCell = styled.div`
height: 100px;
display: flex;
justify-content: space-between;
padding: 12px 14px;
background: ${props => props.theme.greyscale.offWhite};
margin: 1px 0px;
&:last-child {
border-radius: 0px 0px 16px 16px;
}
`;

const Title = styled(Link)`
padding-top: 2px;
color: ${props => props.theme.greyscale.titleActive};
text-decoration: none;
font-size: ${props => props.theme.fontSize.md};
font-weight: bold;
svg {
stroke: ${props => props.theme.colors.primary};
fill: ${props => props.theme.colors.lightBlue};
}
`;

const TextCell = styled.div`
& > div {
padding: 10px;
}
`;

const UpperInfo = styled.div`
padding: 0 24px;
div {
padding: 0 6px;
}
`;

const UpperCell = styled.div`
display: flex;
& > div {
display: flex;
}
`;

const Labels = styled.div`
display: flex;
& > div {
margin: 0 6px;
}
`;

const LowerCell = styled.div`
display: flex;
margin: 0 48px;
& > div {
padding: 0 6px;
color: ${props => props.theme.greyscale.label};
font-size: ${props => props.theme.fontSize.sm};
}
`;

const Text = styled(Typo)`
svg {
margin: 2px 6px 0 6px;
Expand Down
Loading

0 comments on commit e417f83

Please sign in to comment.