이번주는 트위터 기능중 트윗 게시물을 저장할 수 있는 북마크 기능을 구현해보았다.
사진 속 북마크 버튼(형광테두리)을 클릭하면 북마크 기능이 실행된다.
sequelize에 bookmark 테이블 생성하고 tweet_id을 기준으로 tweet데이터가 담겨져 있는 tweets 테이블과 관계형성하였다.
➡️ 관계를 형성한 이유는 나중에 북마크 페이지에서 데이터를 가지고 올때 tweet_id를 기준으로 Tweets테이블과 join하여 북마크 트윗게시물 데이터를 가지고 올 수 있기때문이다.
//table.ts
@Table({
timestamps: false,
tableName: "bookmark",
charset: "utf8",
collate: "utf8_general_ci",
})
export class Bookmark extends Model {
@Column({
type: DataType.INTEGER,
autoIncrement: true,
primaryKey: true,
})
id!: IntegerDataType;
@Column({
type: DataType.STRING,
allowNull: true,
})
content!: string;
@ForeignKey(() => Tweets)
@Column({
type: DataType.INTEGER,
allowNull: false,
})
tweet_id!: IntegerDataType;
@Column({
type: DataType.INTEGER,
allowNull: true,
})
user_id!: IntegerDataType;
@BelongsTo(() => Tweets)
tweets!: Tweets;
}
제일 처음 페이지를 로딩했을때 모든 트윗 데이터를 가져오기 위해 사용하는 getTweet API 코드이다.
isBookmark라는 변수를 하나 만들어서 해당 트윗 북마크 유무를 알려준다.
현재 로그인한 유저 데이터(currentUser)를 조회한 후
=> 유저가 북마크를 누른 tweet데이터가 있는지 찾아보고
=> 북마크된 트윗의 경우 is_bookmark를 true값으로 넘겨준다.(기본값은 false)
router.get(
"/select",
verifyRefreshToken,
async (req: any, res: Response, next: NextFunction) => {
const currentUser: Users[] = await Users.findOne({
where: {
email: req.email,
},
}).then((r: any) => {
return r.user_id;
});
let pageNum = Number(res.req.query.pageCount);
let offset = 0;
if (pageNum > 1) {
offset = 10 * (pageNum - 1);
}
const selectCurrentTweets = await Tweets.findAll({
include: [Likes, Bookmark, Comments],
offset: offset,
limit: 10,
}).then((d: any) => {
return d.map((d: any) => {
let isLike = false;
//기본값은 false로 넘겨줌
let isBookmark = false;
if (
d.like.some((i: any) => {
return i.user_id === currentUser;
})
) {
isLike = true;
}
//트윗데이터중에서 현재 유저가 북마크를 한 데이터가 존재하는지 탐색 후 북마크된 데이터는 isBookmark를 true값으로 넘겨줌.
if (
d.bookmark.some((i: any) => {
return i.user_id === currentUser;
})
) {
isBookmark = true;
}
return {
tweet_id: d.tweet_id,
content: d.content,
email: d.email,
like: d.like,
tag: d.tag,
user_id: d.user_id,
write_date: d.write_date,
upload_file: d.upload_file,
reply_tweet_id: d.reply_tweet_id,
is_like: isLike,
is_bookmark: isBookmark,
comment: [],
is_opened: false,
retweet_opened: false,
};
let count = await Tweets.count();
let totalPageNumber = Math.round((await Tweets.count()) / 10);
res.status(200).json({
data: selectCurrentTweets,
count,
user_id: currentUser,
totalPageNumber: totalPageNumber,
});
}
);
saveBookmark.ts
router.post(
"/",
verifyAccessToken,
verifyRefreshToken,
async (req: any, res: Response, next: NextFunction) => {
await Bookmark.create({
tweet_id: req.body.tweet_id,
user_id: req.body.id,
}).then((result) => {
res.status(201).json(result);
});
}
);
router.post(
"/delete",
verifyAccessToken,
verifyRefreshToken,
async (req: any, res: Response, next: NextFunction) => {
await Bookmark.destroy({
where: {
tweet_id: req.body.tweet_id,
user_id: req.body.id,
},
}).then((result) => {
res.status(201).json(result);
});
}
);
module.exports = router;
// 북마크 추가
const addBookmark = (tweet_id: number) => {
customAxios
.post("/saveBookmark", {
tweet_id: tweet_id,
id: id,
})
.then((res) => {
customAxios
.get("/getTweets/select", {
params: { getCurrentPage },
})
.then((result: any) => {
queryClient.invalidateQueries(["select"]);
});
});
};
// 북마크 삭제
const deleteBookmark = (prop: number) => {
customAxios
.post("/saveBookmark/delete", {
tweet_id: prop,
id: id,
})
.then((res) => {
customAxios
.get("/getTweets/select", {
params: { getCurrentPage },
})
.then((result: any) => {
queryClient.invalidateQueries(["select"]);
//mutation 사용해보기
});
});
};
// return
<img
className="w-6 h-4 pl-2"
alt="#"
src={
t.is_bookmark
? "/assets/bookmark.png"
: "/assets/bookmark_before.png"
}
onClick={() => {
if (t.is_bookmark === true) {
deleteBookmark(t.tweet_id);
}
if (t.is_bookmark === false) {
addBookmark(t.tweet_id);
}
}}
/>