insta에서 사진을 보여주는 component
photo.js 라는 component가 Home.js에서 props들을 받아서 뿌려줌.
import { gql, useMutation } from '@apollo/client'
import styled from 'styled-components'
import Avatar from './Avatar'
import { FatText } from './shared'
import { faHeart as SolidHeart } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import {
faHeart,
faComment,
faPaperPlane,
faBookmark,
} from '@fortawesome/free-regular-svg-icons'
import { FEED_QUERY } from '../screens/Home'
///좋아요를 누른 다음에 바로 refetchQueries하기 위해서 FEED_QUERY를 볼러옴.
const TOGGLE_LIKE_MUTATION = gql`
mutation toggleLike($id: Int!) {
toggleLike(id: $id) {
ok
error
}
}
`
///backend에서 만든 togglgeLike Mutation을 불러다 사용함.
///좋아요 누르는거거~
const PhotoContainer = styled.div`
background-color: white;
border: 1px solid ${(props) => props.theme.borderColor};
margin-bottom: 20px;
max-width: 615px;
`
///전제 container
const PhotoHeader = styled.div`
padding: 15px;
display: flex;
align-items: center;
border-bottom: 1px solid ${(props) => props.theme.borderColor};
`
///맨위에 아바타 사진이랑 username들어가는 부분.
///align-items는 세로에서 center
///justify-content는 가로에서 center
const Username = styled(FatText)`
margin-left: 5px;
font-size: 20px;
`
///photoHeader부분의 username, FatText는 shared.utils.js에서 만들어 놓음
const PhotoFile = styled.img`
min-width: 100%;
max-width: 100%;
`
//사진뿌려주는 부분, min-width: 100% ,max-width:100% 하면, 알아서 맞게 사진이 들어감.
const PhotoData = styled.div`
padding: 15px;
border-top: 1px solid ${(props) => props.theme.borderColor};
`
///사진밑에 하트, 비행기, 댓글등이 들어가는 부분.
const PhotoActions = styled.div`
display: flex;
align-items: cneter;
justify-content: space-between;
div {
display: flex;
align-items: center;
}
`
///하트, 비행기, 댓글등이 들어가는 Icon들을 통으로 담아줌.
const PhotoAction = styled.div`
margin-right: 15px;
cursor: pointer;
`
//Icon들 하나하나에 대한 CSS
const Likes = styled(FatText)`
margin-top: 15px;
display: block;
`
///2 likes를 표현하는 CSS
const Photo = ({ id, user, file, isLiked, likes }) => {
/// Home.js로 부터 id, user, file, isLiked, likes를 props로 받음.
const [toggleLike, { loading }] = useMutation(TOGGLE_LIKE_MUTATION, {
variables: {
id,
},
///useMutation사용시, react-hook-form과 연결안되었을 때는, 여기에 바로,
///variables를 넣어버림.
refetchQueries: [{ query: FEED_QUERY }],
})
///위에서 만든 toggleLike mutation을 사용함,
///refetchQueries는 좋아요를 누른 다음에 바로 SEE_FEED Query를 불러옴
return (
<div>
<PhotoContainer key={id}>
///key를 반드시 넣어야 하며, key는 HOME.js에서 보내준 photo.id 임.
<PhotoHeader>
<Avatar lg url={user.avatar} />
<Username>{user.username}</Username>
///Home.js에서 user를 받음.
</PhotoHeader>
<PhotoFile src={file} />
///Home.js에서 file을 props로 받음.
<PhotoData>
<PhotoActions>
<div>
<PhotoAction onClick={toggleLike}>
///heart를 누르면 toggleLike Mutation이 실행됨.
<FontAwesomeIcon
style={{ color: isLiked ? 'tomato' : 'inherit' }}
///server에서 만든 isLikes computed Fileld로 내가 like를
///눌렀으면 색이 tomato 아니면 원래색으로~
size={'2x'}
icon={isLiked ? SolidHeart : faHeart}
///내가 좋아요 눌렀으면 색이 채워진 SolidHeart로 아님 테두리만~
/>
</PhotoAction>
<PhotoAction>
<FontAwesomeIcon size={'2x'} icon={faComment} />
</PhotoAction>
<PhotoAction>
<FontAwesomeIcon size={'2x'} icon={faPaperPlane} />
</PhotoAction>
</div>
<div style={{ marginRight: '15px' }}>
<FontAwesomeIcon size={'2x'} icon={faBookmark} />
</div>
///PhotoActions를 <div>2개로 만들어 between으로 양쪽에 배치
</PhotoActions>
<Likes>{likes === 1 ? '1 likes' : `${likes} likes`}</Likes>
///likes를 Home.js에서 props로 받아와 뿌려줌...
</PhotoData>
</PhotoContainer>
</div>
)
}
export default Photo
import useUser from '../hooks/useUser'
import { gql, useQuery } from '@apollo/client'
import Photo from '../components/Photo'
export const FEED_QUERY = gql`
query seeFeed {
seeFeed {
id
user {
username
avatar
}
file
caption
likes
comments
createdAt
isMine
isLiked
}
}
`
///seeFeed Query, Photo.js에서도 사용할 예정이라 export 해줌.
const Home = () => {
const User = useUser()
///useUser hook을 이용해서 User의 정보를 받아옴
console.log(User)
const { data } = useQuery(FEED_QUERY)
///useQuery로 seeFeed Query를 실행한 다음, data를 불러옴.
return (
<div>
{data?.seeFeed?.map((photo) => (
<Photo
key={photo.id}
id={photo.id}
user={photo.user}
file={photo.file}
isLiked={photo.isLiked}
likes={photo.likes}
/>
))}
///seeFeed로 불러온 data들을 Photo.js component에 보내줌.
</div>
)
}
export default Home
import prisma from '../client'
export default {
Photo: {
user: ({ userId }) => prisma.user.findUnique({ where: { id: userId } }),
hashtags: ({ id }) =>
prisma.hashtag.findMany({
where: {
photos: { some: { id } },
},
}),
likes: ({ id }) => prisma.like.count({ where: { photoId: id } }),
comments: ({ id }) => prisma.comment.count({ where: { photoId: id } }),
isMine: ({ userId }, _, { loggedInUser }) => {
if (!loggedInUser) {
return false
}
return userId === loggedInUser.id
},
isLiked: async ({ id }, _, { loggedInUser }) => {
if (!loggedInUser) {
return false
}
const ok = await prisma.like.findUnique({
where: {
photoId_userId: {
photoId: id,
userId: loggedInUser.id,
},
},
///like DB에서 photoId와 userId를 찾아서 존재하면 true를 return
///그래서 computer Field가 조르 중요한 것임.
select: { id: true },
})
if (ok) {
return true
}
return false
},
},