-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Feature/#77 친구목록 페이지 팔로우 기능 추가
- Loading branch information
Showing
17 changed files
with
476 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { User } from 'api/user/entity'; | ||
import { FollowerInfo } from 'pages/Follow/static/entity'; | ||
|
||
export interface FollowListParams { | ||
cursor: string; | ||
pageSize: number; | ||
} | ||
|
||
export interface GetFollowListParams { | ||
page: number; | ||
pageSize: number; | ||
} | ||
|
||
export interface GetFollowListResponse { | ||
content: { | ||
id: number; | ||
follower: User; | ||
user: User; | ||
account: string; | ||
}[] | ||
} | ||
|
||
export interface CheckSendedFollowParams { | ||
page: number; | ||
pageSize: number; | ||
} | ||
|
||
export interface FollowerParams { | ||
userAccount: string; | ||
} | ||
|
||
export interface DeleteFollowerParams extends FollowerParams { | ||
} | ||
|
||
export interface PostFollowerParams extends FollowerParams { | ||
} | ||
|
||
export interface SearchUsersParams { | ||
keyword: string; | ||
} | ||
|
||
export interface SearchUsersResponse { | ||
content: FollowerInfo[] | ||
} | ||
|
||
export interface AcceptFollowParams { | ||
id: number; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { API_PATH } from 'config/constants'; | ||
import axios from 'axios'; | ||
|
||
const followApi = axios.create({ | ||
baseURL: `${API_PATH}`, | ||
timeout: 2000, | ||
}); | ||
|
||
followApi.interceptors.request.use( | ||
(config) => { | ||
const accessToken = sessionStorage.getItem('accessToken'); | ||
// eslint-disable-next-line no-param-reassign | ||
if (config.headers && accessToken) config.headers.Authorization = `Bearer ${accessToken}`; | ||
return config; | ||
}, | ||
); | ||
|
||
export default followApi; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { | ||
FollowListParams, | ||
GetFollowListParams, | ||
CheckSendedFollowParams, | ||
DeleteFollowerParams, | ||
PostFollowerParams, | ||
SearchUsersParams, | ||
AcceptFollowParams, | ||
GetFollowListResponse, | ||
SearchUsersResponse, | ||
} from './entity'; | ||
import followApi from './followApiClient'; | ||
|
||
export const followList = (param: FollowListParams) => followApi.get(`/follow/followers?${param.cursor}&pageSize=${param.pageSize}`); | ||
|
||
export const getFollowList = (param: GetFollowListParams) => followApi.get<GetFollowListResponse>(`/follow/requests/receive?page=${param.page}&pageSize=${param.pageSize}`); | ||
|
||
export const checkSendedFollow = (param: CheckSendedFollowParams) => followApi.get(`/follow/requests/send?page=${param.page}&pageSize=${param.pageSize}`); | ||
|
||
export const requestFollow = (param: PostFollowerParams) => followApi.post('/follow/requests', { | ||
userAccount: param.userAccount, | ||
}); | ||
|
||
export const deleteFollower = (param: DeleteFollowerParams) => followApi.delete('/follow/follwers', { | ||
data: { | ||
userAccount: param.userAccount, | ||
}, | ||
}); | ||
|
||
export const acceptFollow = (param: AcceptFollowParams) => followApi.post(`/follow/requests/${param.id}/accept`); | ||
|
||
export const searchUsers = (param: SearchUsersParams) => followApi.get<SearchUsersResponse>(`/users?keyword=${param.keyword}`); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
.template { | ||
width: 726px; | ||
height: 418px; | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
} | ||
|
||
.content { | ||
width: 172px; | ||
height: 40px; | ||
text-align: center; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import style from './FailToSearch.module.scss'; | ||
|
||
export default function FailToSearch() { | ||
return ( | ||
<div className={style.template}> | ||
<div className={style.content}> | ||
해당 아이디/닉네임을 가진 친구를 찾을 수 없습니다. | ||
</div> | ||
</div> | ||
|
||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
.container { | ||
width: 100%; | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: center; | ||
align-items: center; | ||
} | ||
|
||
.title { | ||
width: 1187px; | ||
height: 40px; | ||
display: flex; | ||
justify-content: space-between; | ||
padding-bottom: 11px; | ||
padding-left: 20px; | ||
border-bottom: 1px solid #eeeeee; | ||
margin-top: 20px; | ||
background-color: white; | ||
border-top: none; | ||
border-right: none; | ||
border-left: none; | ||
cursor: pointer; | ||
|
||
&__arrow { | ||
&--up { | ||
transform: rotate(180deg); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { ReactComponent as Arrow } from 'assets/svg/common/arrow.svg'; | ||
import cn from 'utils/ts/classNames'; | ||
import useBooleanState from 'utils/hooks/useBooleanState'; | ||
import Follower from './Follower'; | ||
import style from './FollowList.module.scss'; | ||
import { FollowerInfo } from '../static/entity'; | ||
|
||
export interface Props { | ||
title: string; | ||
data: FollowerInfo[]; | ||
} | ||
|
||
// 유저 검색 시 자신의 정보는 안보이도록 자신의 정보를 받아서 비교, 자신과의 followedType은 NONE | ||
export default function FollowList({ title, data }: Props) { | ||
const [isShow, , ,toggle] = useBooleanState(true); | ||
|
||
return ( | ||
<div className={style.container}> | ||
<button onClick={toggle} type="button" className={style.title}> | ||
{title} | ||
<Arrow className={cn( | ||
{ | ||
[style.title__arrow]: true, | ||
[style['title__arrow--up']]: isShow, | ||
}, | ||
)} | ||
/> | ||
</button> | ||
{isShow && data.map((item) => ( | ||
<Follower | ||
id={item.id} | ||
key={item.id} | ||
nickname={item.nickname} | ||
account={item.account} | ||
followedType={item.followedType} | ||
/> | ||
))} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
.follower { | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
height: 112px; | ||
width: 1150px; | ||
margin-top: 39px; | ||
margin-bottom: 39px; | ||
|
||
&__image { | ||
width: 112px; | ||
height: 112px; | ||
} | ||
|
||
&__content { | ||
width: 720px; | ||
padding-left: 60px; | ||
|
||
&--font { | ||
font-size: 30px; | ||
} | ||
} | ||
|
||
&__button { | ||
width: 175px; | ||
height: 49px; | ||
color: white; | ||
border: 1px solid #f6bf54; | ||
border-radius: 10px; | ||
background-color: #f6bf54; | ||
font-size: 20px; | ||
cursor: pointer; | ||
|
||
&--unfollow { | ||
width: 175px; | ||
height: 49px; | ||
border-radius: 10px; | ||
border: 1px solid #c4c4c4; | ||
background-color: white; | ||
color: #c4c4c4; | ||
font-size: 20px; | ||
cursor: pointer; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import defaultImage from 'assets/images/follow/default-image.png'; | ||
import cn from 'utils/ts/classNames'; | ||
import { acceptFollow, requestFollow } from 'api/follow'; | ||
import { useMutation, useQueryClient } from 'react-query'; | ||
import style from './Follower.module.scss'; | ||
|
||
// 팔로우 요청 후 유저 목록을 다시 받아와 요청중 상태로 변경 | ||
const useRequestAndUpdate = () => { | ||
const queryClient = useQueryClient(); | ||
const { mutate: request } = useMutation('request', (account: string) => requestFollow({ userAccount: account }), { | ||
onSuccess: () => { | ||
queryClient.invalidateQueries('search'); | ||
}, | ||
}); | ||
return request; | ||
}; | ||
|
||
// 팔로우 승인 후 받은 요청 목록을 다시 받아와 갱신 | ||
const useAcceptFollow = () => { | ||
const queryClient = useQueryClient(); | ||
const { mutate: accept } = useMutation('accept', (id: number) => acceptFollow({ id }), { | ||
onSuccess: () => { | ||
queryClient.invalidateQueries('received'); | ||
}, | ||
}); | ||
return { accept }; | ||
}; | ||
|
||
interface Props { | ||
account: string, | ||
nickname: string, | ||
followedType: string, | ||
id: number, | ||
} | ||
|
||
export default function Follower({ | ||
nickname, account, followedType, id, | ||
}: Props) { | ||
const request = useRequestAndUpdate(); | ||
const { accept } = useAcceptFollow(); | ||
|
||
return ( | ||
<div className={style.follower}> | ||
<img className={style.follower__image} src={defaultImage} alt="default" /> | ||
<div className={style.follower__content}> | ||
<p className={cn({ [style['follower__content--font']]: true })}>{nickname}</p> | ||
<p>{account}</p> | ||
</div> | ||
<button | ||
className={cn({ | ||
[style.follower__button]: followedType === 'NONE' || followedType === 'RECEIVED', | ||
[style['follower__button--unfollow']]: followedType === 'REQUESTED' || followedType === 'FOLLOWED', | ||
})} | ||
type="button" | ||
onClick={() => (followedType === 'NONE' && request(account)) || (followedType === 'RECEIVED' && accept(id))} | ||
> | ||
{followedType === 'NONE' && '팔로우'} | ||
{followedType === 'REQUESTED' && '요청중'} | ||
{followedType === 'FOLLOWED' && '언팔로우'} | ||
{followedType === 'RECEIVED' && '팔로우'} | ||
</button> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
.friend { | ||
width: 1207px; | ||
padding-bottom: 11px; | ||
padding-left: 20px; | ||
border-bottom: 1px solid #eeeeee; | ||
} | ||
|
||
.new { | ||
width: 1207px; | ||
padding-bottom: 11px; | ||
padding-left: 20px; | ||
border-bottom: 1px solid #eeeeee; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { useAuth } from 'store/auth'; | ||
import { FollowerInfo, SearchPageInfo } from '../static/entity'; | ||
import FollowList from './FollowList'; | ||
|
||
export default function SearchPage({ data }: SearchPageInfo) { | ||
const auth = useAuth(); | ||
const myFriends: FollowerInfo[] = data.filter((follower) => follower.followedType === 'FOLLOWED'); | ||
const newFriends: FollowerInfo[] = data.filter((follower) => follower.followedType !== 'FOLLOWED').filter((follower) => follower.account !== auth?.account); | ||
|
||
return ( | ||
<div> | ||
<FollowList title="나의 친구" data={myFriends} /> | ||
<FollowList title="새 친구" data={newFriends} /> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.