Skip to content

Commit

Permalink
[Add] like 기능 구현 #32
Browse files Browse the repository at this point in the history
why
like 버튼 동작 시 디비에 저장되어야 함

how
- cookie로 사용자 정보 캐치
- 피드 정보에 feedid추가
- feedId로 해당 피드와 사용자 간의 like relation 연결 (중복으로 되지 않도록 merge 로 연결)
- cors 설정

참고
unlike는 아직 안함
  • Loading branch information
WooYeonSeo committed Nov 27, 2019
1 parent 3fa72e8 commit fdb1e8e
Show file tree
Hide file tree
Showing 11 changed files with 260 additions and 63 deletions.
6 changes: 5 additions & 1 deletion client/src/apollo/ApolloClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ const cache = new InMemoryCache();

const client = new ApolloClient({
cache,
link: createUploadLink({ uri: 'http://localhost:4000/graphql' }),
link: createUploadLink({
uri: 'http://localhost:4000/graphql',
credentials: 'include',
fetchOptions: { credentials: 'include' }
}),
typeDefs,
resolvers
});
Expand Down
12 changes: 10 additions & 2 deletions client/src/composition/Feed/Feed.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import styled from 'styled-components';
import FeedHeader from './FeedHeader';
import FeedBody from './FeedBody';
import FeedFooter from './FeedFooter';
import Comment from './Comment';
import { IFeedItem } from './feed.type';

const FeedDiv = styled.div`
${props => props.theme.borders.feedBorder};
Expand All @@ -30,11 +31,17 @@ const FeedEditDiv = styled.span`
interface Iprops {
content: string;
createdAt: string;
feedinfo: IFeedItem;
}

function Feed({ content, createdAt }: Iprops) {
function Feed({ content, createdAt, feedinfo }: Iprops) {
const [likeCnt, setLikeCnt] = useState<number>(0);
const [hasLiked, setHasLiked] = useState<boolean>(false);
useEffect(() => {
setLikeCnt(feedinfo.totallikes);
setHasLiked(feedinfo.hasLiked ? true : false);
}, []);

return (
<>
<FeedDiv>
Expand All @@ -47,6 +54,7 @@ function Feed({ content, createdAt }: Iprops) {
setLikeCnt={setLikeCnt}
hasLiked={hasLiked}
setHasLiked={setHasLiked}
feedId={feedinfo.feedId}
/>
</FeedContentDiv>
<Comment />
Expand Down
15 changes: 10 additions & 5 deletions client/src/composition/Feed/FeedContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import React from 'react';
import FeedPresentor from './FeedPresentor';
import FeedList from './index';
import WritingFeedContainer from './WritingFeed';
import styled from 'styled-components';

const FeedContainer: React.FC = () => {
const CenterContainer = styled.div`
margin: 0 auto;
`;

const FeedContainer = () => {
return (
<>
<CenterContainer>
<WritingFeedContainer />
<FeedPresentor />
</>
<FeedList />
</CenterContainer>
);
};

Expand Down
28 changes: 27 additions & 1 deletion client/src/composition/Feed/FeedFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import ThumbLikeIcon from '../../components/Icon/ThumbLikeIcon';
import RoundThumbIcon from '../../components/Icon/RoundThumbIcon';
import CommentIcon from '../../components/Icon/CommentIcon';
import ShareIcon from '../../components/Icon/ShareIcon';
import { useMutation } from '@apollo/react-hooks';
import gql from 'graphql-tag';

const FeedActionDiv = styled.div`
border-radius: 0 0 3px 3px;
Expand Down Expand Up @@ -64,18 +66,42 @@ interface Iprops {
setLikeCnt: any;
hasLiked: boolean;
setHasLiked: any;
feedId: number;
}
const FeedFooter = ({ likeCnt, setLikeCnt, hasLiked, setHasLiked }: Iprops) => {

const SEND_LIKE = gql`
mutation updateLike($feedId: Int) {
updateLike(feedId: $feedId)
}
`;

const FeedFooter = ({
likeCnt,
setLikeCnt,
hasLiked,
setHasLiked,
feedId
}: Iprops) => {
const [updateLike] = useMutation(SEND_LIKE);

const ToggleLike = () => {
setLikeCnt((props: number) => {
setHasLiked((props: boolean) => !props);
if (!hasLiked) {
sendLike(1);
return props + 1;
} else {
// cancleLike(-1);
return props - 1;
}
});
};

const sendLike = (count: number) => {
// send count
updateLike({ variables: { feedId } });
console.log(count);
};
return (
<>
<FeedActionDiv>
Expand Down
41 changes: 41 additions & 0 deletions client/src/composition/Feed/feed.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
export interface Feeds {
feedItems: IFeedItem[];
}

export interface Idate {
year: number;
month: number;
day: number;
hour: number;
minute: number;
second: number;
nanosecond: number;
timeZoneOffsetSeconds: number;
timeZoneId: string;
}

export interface IUser {
nickname: string;
hometown: string;
thumbnail: string;
residence: string;
email: string;
}
export interface Content {
createdAt: Idate;
content: string;
}

export interface Comment {
id: string;
content: string;
}

export interface IFeedItem {
searchUser: IUser;
feed: Content;
feedId: number;
totallikes: number;
hasLiked: number;
comments: [Comment];
}
88 changes: 63 additions & 25 deletions client/src/composition/Feed/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,9 @@ import React, { useState, useRef, useEffect, useCallback } from 'react';
import Feed from './Feed';
import { useQuery } from '@apollo/react-hooks';
import gql from 'graphql-tag';
import useScrollEnd from '../../hooks/useScrollEnd';
import WritingFeedContainer from './WritingFeed';
import useIntersect from '../../hooks/useIntersectObserver';
import styled from 'styled-components';

interface IFeed {
content: string;
createdAt: string;
}

interface Feeds {
feeds: IFeed[];
}
import { Feeds, Idate, IFeedItem } from './feed.type';

interface FeedVars {
first: number;
Expand All @@ -30,23 +20,65 @@ const GET_FEEDS = gql`
}
`;

const GET_FEEDS2 = gql`
query getfeeds($first: Int, $currentCursor: String) {
feedItems(first: $first, cursor: $currentCursor) {
searchUser {
nickname
}
feed {
createdAt {
year
month
day
hour
minute
second
nanosecond
}
content
}
feedId
totallikes
hasLiked
comments {
id
content
}
}
}
`;

const LoadCheckContainer = styled.div`
height: 50px;
position: relative;
top: -50px;
`;
// 모듈로 빼자 new Date(year, month, day, hours, minutes, seconds, milliseconds)
const getDate = (date: Idate): Date => {
const dateob = new Date(
date.year,
date.month - 1,
date.day,
date.hour + 9,
date.minute,
date.second,
Number(String(date.nanosecond).substr(0, 3))
);
return dateob;
};

const OFFSET = 4;
const FeedContainer = () => {
const [feeds, setFeeds] = useState<IFeed[]>([]);
const FeedList = () => {
const [feeds, setFeeds] = useState<IFeedItem[]>([]);
const [cursor, setCursor] = useState<string>('9999-12-31T09:29:26.050Z');
const [isLoading, setIsLoading] = useState<boolean>(false);
const [isEnd, setIsEnd] = useState<boolean>(false);

const [ref, setRef] = useIntersect(checkIsEnd, {});

// hooks 에서 useQuery 1 부터 시작
const { loading, data, fetchMore } = useQuery<Feeds, FeedVars>(GET_FEEDS, {
const { loading, data, fetchMore } = useQuery<Feeds, FeedVars>(GET_FEEDS2, {
variables: { first: OFFSET, currentCursor: cursor }
});

Expand All @@ -61,23 +93,28 @@ const FeedContainer = () => {
if (!fetchMoreResult) {
return prev;
}
if (!fetchMoreResult.feeds.length) {
console.log('cursor ', cursor);
if (!fetchMoreResult.feedItems.length) {
setIsEnd(true);
return prev;
}

const { feeds: feedItems } = fetchMoreResult;
const { feedItems } = fetchMoreResult;
const lastFeedItem = feedItems[feedItems.length - 1];
// console.log('lastFeedItem ', fetchMoreResult);
setCursor(lastFeedItem.createdAt);
console.log(
'lastFeedItem ',
getDate(lastFeedItem.feed.createdAt).toISOString()
);

setCursor(getDate(lastFeedItem.feed.createdAt).toISOString());

return Object.assign({}, prev, {
feeds: [...feedItems]
});
}
});

setFeeds([...feeds, ...value.feeds]);
setFeeds([...feeds, ...value.feedItems]);
setIsLoading(false);
}

Expand All @@ -89,23 +126,24 @@ const FeedContainer = () => {

return (
<>
<WritingFeedContainer />
{feeds.map(feed => (
<Feed
key={feed.createdAt}
content={feed.content}
createdAt={feed.createdAt}
key={getDate(feed.feed.createdAt).toISOString()}
content={feed.feed.content}
feedinfo={feed}
createdAt={getDate(feed.feed.createdAt).toISOString()}
/>
))}
<LoadCheckContainer
onClick={fetchMoreFeed}
ref={setRef as any}></LoadCheckContainer>
<div>
<div onClick={fetchMoreFeed}>
{isLoading ? 'LOADING' : ''}
{isEnd ? '마지막 글입니다' : ''}
aa
</div>
</>
);
};

export default FeedContainer;
export default FeedList;
21 changes: 13 additions & 8 deletions server/src/api/feed/feed.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,11 @@ type Idate {
hour: Int
minute: Int
second: Int
nanosecond: Int
nanosecond: String
timeZoneOffsetSeconds: Int
timeZoneId: String
}

type Query {
getFeeds: [Feed]!
feeds(first: Int, cursor: String): [Feed]!
pageInfo: PageInfo
feedItems(first: Int, cursor: String): [IFeed]
}

type IUser {
nickname: String
hometown: String
Expand All @@ -54,7 +47,19 @@ type Comment {
type IFeed {
searchUser: IUser
feed: Content
feedId: Int
totallikes: Int
hasLiked: Int
comments: [Comment]
}

type Query {
getFeeds: [Feed]!
feeds(first: Int, cursor: String): [Feed]!
pageInfo: PageInfo
feedItems(first: Int, cursor: String): [IFeed]
}

type Mutation {
updateLike(feedId: Int): Boolean
}
Loading

0 comments on commit fdb1e8e

Please sign in to comment.