Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

유저 팔로우 모달 구현 #63

Merged
merged 2 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions .env

This file was deleted.

28 changes: 14 additions & 14 deletions src/app/(userpage)/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ export type UserDetail = {

export type UserProduct = {
nextCursor: number;
list: [
{
updatedAt: Date;
createdAt: Date;
writerId: number;
categoryId: number;
favoriteCount: number;
reviewCount: number;
rating: number;
image: string;
name: string;
id: number;
},
];
list: Follow[];
};

export type Follow = {
updatedAt: string;
createdAt: string;
writerId: number;
categoryId: number;
favoriteCount: number;
reviewCount: number;
rating: number;
image: string;
name: string;
id: number;
};
42 changes: 42 additions & 0 deletions src/app/(userpage)/userMock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,45 @@ export const userMock = {
followersCount: 0,
isFollowing: true,
};

export const followMock = {
nextCursor: 0,
list: [
{
updatedAt: "2024-06-03T10:18:50.930Z",
createdAt: "2024-06-03T10:18:50.930Z",
writerId: 0,
categoryId: 1,
favoriteCount: 13,
reviewCount: 14,
rating: 1,
image: `${DEFAULT_PROFILE_IMAGE}`,
name: "닝닝한 빠빠씨",
id: 0,
},
{
updatedAt: "2024-06-03T10:18:50.930Z",
createdAt: "2024-06-03T10:18:50.930Z",
writerId: 0,
categoryId: 1,
favoriteCount: 13,
reviewCount: 14,
rating: 1,
image: `${DEFAULT_PROFILE_IMAGE}`,
name: "닝닝한 빠빠씨",
id: 1,
},
{
updatedAt: "2024-06-03T10:18:50.930Z",
createdAt: "2024-06-03T10:18:50.930Z",
writerId: 0,
categoryId: 1,
favoriteCount: 13,
reviewCount: 14,
rating: 1,
image: `${DEFAULT_PROFILE_IMAGE}`,
name: "닝닝한 빠빠씨",
id: 2,
},
],
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
@import "@/styles/_index";
@import "@/styles/_media";

.container {
display: flex;
flex-direction: column;
gap: 25px;
width: 100%;
height: 100%;
margin-top: 40px;
overflow: auto;

@include respond-to(tablet) {
gap: 20px;
}
}

.listBox {
display: flex;
gap: 20px;
align-items: center;
justify-content: start;

span {
font-size: 18px;

@include font-semibold;

@include respond-to(tablet) {
@include text-normal;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Link from "next/link";
import React from "react";
import { UserProduct } from "@/app/(userpage)/types";
import { UserImage } from "@/components/UserImage";
import cn from "@/utils/classNames";
import { DEFAULT_PROFILE_IMAGE } from "@/utils/constant";
import styles from "./FollowList.module.scss";

type FollowListProps = {
followData: UserProduct;
};

export default function FollowList({ followData }: FollowListProps) {
console.log(followData);

return (
<div className={cn(styles.container)}>
{followData.list.map((item) => (
<Link
href={`/user/${item.id}`}
key={item.id}
className={cn(styles.listBox)}
>
<UserImage
image={item.image === null ? `${DEFAULT_PROFILE_IMAGE}` : item.image}
nickname={item.name}
size='small'
/>
<span>{item.name}</span>
</Link>
))}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
@import "@/styles/_index";
@import "@/styles/_media";

.container {
display: flex;
flex-direction: column;
width: 500px;
height: 660px;
padding: 60px 40px 20px;

@include respond-to(tablet) {
height: 600px;
}

@include respond-to(mobile) {
width: 335px;
height: 550px;
padding: 40px 20px 10px;
}
}

.noFollowBox {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}

.closeButton {
position: absolute;
top: 20px;
right: 20px;
width: 40px;
height: 40px;

@include respond-to(tablet) {
width: 36px;
height: 36px;
}

@include respond-to(mobile) {
top: 15px;
right: 15px;
width: 24px;
height: 24px;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import Image from "next/image";
import { useSession } from "next-auth/react";
import React, { useEffect, useState } from "react";
import { UserProduct } from "@/app/(userpage)/types";
import Modal from "@/components/Modal/Modal";
import cn from "@/utils/classNames";
import { CLOSE_ICON } from "@/utils/constant";
import HttpClient from "@/utils/httpClient";
import styles from "./FollowModal.module.scss";
// eslint-disable-next-line no-restricted-imports
import FollowList from "../FollowList/FollowList";

type ModalProps = {
followState: string;
isModalState: boolean;
setIsModalState: React.Dispatch<React.SetStateAction<boolean>>;
};

export default function FollowModal({ isModalState, setIsModalState, followState }: ModalProps) {
const { data: session } = useSession();
const [followData, setFollowData] = useState<UserProduct>();

const httpClient = new HttpClient(process.env.NEXT_PUBLIC_BASE_URL!);

const handleData = async () => {
if (session && followState) {
const userId = session.user.id;
const ACCESS_TOKEN = session.accessToken;
setFollowData(
await httpClient.get(`users/${userId}/${followState}`, {
headers: { Authorization: ACCESS_TOKEN },
cache: "no-cache",
}),
);
}
};

useEffect(() => {
handleData();
}, [followState]);

const handleClose = () => setIsModalState(false);
return (
<>
{followData !== undefined && isModalState && (
<Modal onClose={handleClose}>
<div className={cn(styles.container)}>
<div
className={cn(styles.closeButton)}
onClick={handleClose}
onKeyDown={handleClose}
role='button'
tabIndex={0}
>
<Image
src={CLOSE_ICON}
alt='닫기버튼'
fill
/>
</div>
<h1>nickname님{followState === "followees" ? "이" : "을"} 팔로우 하는 유저</h1>
{followData.list.length < 1 ? (
<div className={cn(styles.noFollowBox)}>팔로우하는 유저가 없어요</div>
) : (
<FollowList followData={followData} />
)}
</div>
</Modal>
)}
</>
);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import React from "react";
/* eslint-disable import/no-named-as-default */
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
import React, { useState } from "react";
import Button from "@/components/Button/Button";
import { UserImage } from "@/components/UserImage";
import styles from "./UserInfo.module.scss";
// eslint-disable-next-line no-restricted-imports
import FollowModal from "../FollowModal/FollowModal";
// eslint-disable-next-line no-restricted-imports
import HTMLContent from "../HTMLContent/HTMLContent";

type UserInfoProps = {
Expand All @@ -17,45 +22,64 @@ type UserInfoProps = {
export default function UserInfo({ nickname, image, description, follower, folloing, isfollow }: UserInfoProps) {
// textarea에서 쓴 줄바꿈 변환해서 서버로 보내기
// const formattedDescription = description.replace(/\n/g, "<br>")
const [isModalOpen, setIsModalOpen] = useState(false);
const [followModalProps, setFollowModalProps] = useState("");

const handelFolloweesModal = () => {
setFollowModalProps("followees");
setIsModalOpen(true);
};

const handelFollowersModal = () => {
setFollowModalProps("followers");
setIsModalOpen(true);
};

return (
<div className={styles.container}>
<UserImage
image={image}
nickname={nickname}
size='large'
<>
<FollowModal
followState={followModalProps}
isModalState={isModalOpen}
setIsModalState={setIsModalOpen}
/>
<div className={styles.descriptionBox}>
<p>{nickname}</p>
<HTMLContent html={description} />
</div>
<div className={styles.followBox}>
<div>
<p>{follower}</p>
<p>팔로워</p>
<div className={styles.container}>
<UserImage
image={image}
nickname={nickname}
size='large'
/>
<div className={styles.descriptionBox}>
<p>{nickname}</p>
<HTMLContent html={description} />
</div>
<div>
<p>{folloing}</p>
<p>팔로잉</p>
<div className={styles.followBox}>
<div onClick={handelFollowersModal}>
<p>{follower}</p>
<p>팔로워</p>
</div>
<div onClick={handelFolloweesModal}>
<p>{folloing}</p>
<p>팔로잉</p>
</div>
</div>
{isfollow ? (
<Button
styleType='tertiary'
disabled
className='profile'
>
팔로우 취소
</Button>
) : (
<Button
styleType='primary'
disabled={false}
className='profile'
>
팔로우
</Button>
)}
</div>
{isfollow ? (
<Button
styleType='tertiary'
disabled
className='profile'
>
팔로우 취소
</Button>
) : (
<Button
styleType='primary'
disabled={false}
className='profile'
>
팔로우
</Button>
)}
</div>
</>
);
}
Loading