Skip to content

Commit

Permalink
Feat/comment reply auto save (#30)
Browse files Browse the repository at this point in the history
* feat: 작성모달 글자수제한

* feat:코멘트 자동저장

* feat: 삭제 시 로컬 스토리지 비우기

* feat: 코멘트 페이지 모달 자동저장

* feat: 코멘트 상세 페이지 로컬스토리지 없애기 로직
  • Loading branch information
ComPhyPark authored Jan 28, 2024
1 parent e950472 commit 325e10c
Show file tree
Hide file tree
Showing 19 changed files with 187 additions and 95 deletions.
2 changes: 1 addition & 1 deletion src/apis/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export async function putUpdateWatchingState(

export async function deleteWatchingState(
state_id: number,
accessToken: string
accessToken: string,
) {
return fetch(`${BASE_API_URL}/contents/states/${state_id}`, {
method: "DELETE",
Expand Down
8 changes: 2 additions & 6 deletions src/components/CommentPageWriteModal.module.scss
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
@import "./WritingModal.module.scss";
.navSubCon {
display: flex;
width: 100%;

.textConut {
margin-left: auto;
}
.navSubCon {
margin-left: auto;
}
97 changes: 63 additions & 34 deletions src/components/CommentPageWriteModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { useParams } from "react-router-dom";
import { postCreateReply, putUpdateReply } from "../apis/comment";
import Modal from "./Modal";
import styles from "./CommentPageWriteModal.module.scss";
import { useState } from "react";
import { ChangeEvent, useState } from "react";
import { useAuthContext } from "../contexts/authContext";
import { defaultResponseHandler } from "../apis/custom";
import { CommentType, ReplyType } from "../type";
import { updateCommentRequest } from "../apis/comment";
import autoSave from "../utils/autoSave";

export type CommentPageWriteModalStateType =
| { type: "updateComment"; targetComment: CommentType }
Expand All @@ -29,20 +30,46 @@ export default function CommentPageWriteModal({
currentModalState,
}: CommentPageWriteModalProps) {
const modalType = currentModalState.type;
const { id: commentId } = useParams();
const { myUserData, accessToken } = useAuthContext();
const myId = myUserData?.id;
const mode =
modalType === "updateReply"
? "edit"
: modalType === "updateComment"
? "comment"
: "reply";
const autoSaveId =
modalType === "updateReply"
? currentModalState.targetReply.id
: modalType === "updateComment"
? currentModalState.targetComment.movie.movieCD
: commentId;
const autoSavedText = autoSave.get(myId!, mode, autoSaveId!); //모달은 로그인을 했고, id의 코멘트가 있을 때 뜬다
const [hasSpoiler, setHasSpoiler] = useState<boolean | null>(
modalType === "updateComment"
? currentModalState.targetComment.has_spoiler
: null,
);
const [contentInput, setContentInput] = useState(
modalType === "updateReply"
? currentModalState.targetReply.content
: modalType === "updateComment"
? currentModalState.targetComment.content
: "",
autoSavedText != null
? autoSavedText
: modalType === "updateReply"
? currentModalState.targetReply.content
: modalType === "updateComment"
? currentModalState.targetComment.content
: "",
);
const { accessToken } = useAuthContext();
const { id: commentId } = useParams();

const [doSave, setDoSave] = useState(false);

const onTextChange = async (e: ChangeEvent<HTMLTextAreaElement>) => {
const s_ = e.target.value;
const s = s_.length > 10000 ? s_.substring(0, 10000) : s_; // 길이는 최대 1만자
setDoSave(true);
setContentInput(s);
autoSave.set(myId!, mode, autoSaveId!, s); //모달은 로그인을 했고, id의 코멘트가 있을 때 뜬다
};

return (
<Modal
Expand Down Expand Up @@ -73,35 +100,34 @@ export default function CommentPageWriteModal({
: "이 코멘트에 대한 생각을 자유롭게 표현해주세요."
}
value={contentInput}
onChange={(e) => {
setContentInput(e.target.value);
}}
onChange={onTextChange}
/>
<nav>
<div className={styles.navSubCon}>
{modalType === "updateComment" && (
<button
type="button"
className={styles.spoilerButton}
onClick={() => {
setHasSpoiler(!hasSpoiler);
}}
{modalType === "updateComment" && (
<button
type="button"
className={styles.spoilerButton}
onClick={() => {
setHasSpoiler(!hasSpoiler);
}}
>
<svg
className={hasSpoiler ? styles.checked : ""}
fill="none"
height="30"
viewBox="0 0 24 24"
width="30"
xmlns="http://www.w3.org/2000/svg"
>
<svg
className={hasSpoiler ? styles.checked : ""}
fill="none"
height="30"
viewBox="0 0 24 24"
width="30"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M11.9998 1.89462C6.41882 1.89462 1.89453 6.41891 1.89453 11.9999C1.89453 17.5809 6.41882 22.1052 11.9998 22.1052C17.5808 22.1052 22.1051 17.5809 22.1051 11.9999C22.1051 6.41891 17.5808 1.89462 11.9998 1.89462ZM7.78928 11.4662C8.02183 11.0634 8.53685 10.9254 8.93962 11.158L12.0061 12.9284L15.0612 11.1645C15.464 10.932 15.979 11.07 16.2116 11.4728C16.4441 11.8755 16.3061 12.3906 15.9034 12.6231L13.6903 13.9008L15.8678 15.158C16.2706 15.3905 16.4086 15.9055 16.1761 16.3083C15.9435 16.7111 15.4285 16.8491 15.0257 16.6165L12.0061 14.8732L8.97515 16.6231C8.57237 16.8556 8.05735 16.7176 7.82481 16.3149C7.59227 15.9121 7.73027 15.3971 8.13304 15.1645L10.3219 13.9008L8.09752 12.6165C7.69474 12.384 7.55674 11.869 7.78928 11.4662ZM7.9998 8.21074C7.9998 7.74566 8.37682 7.36864 8.8419 7.36864H9.05243C9.51751 7.36864 9.89454 7.74566 9.89454 8.21074V8.84232C9.89454 9.3074 9.51751 9.68443 9.05243 9.68443H8.8419C8.37682 9.68443 7.9998 9.3074 7.9998 8.84232V8.21074ZM14.9472 7.36864C14.4821 7.36864 14.1051 7.74566 14.1051 8.21074V8.84232C14.1051 9.3074 14.4821 9.68443 14.9472 9.68443H15.1577C15.6228 9.68443 15.9998 9.3074 15.9998 8.84232V8.21074C15.9998 7.74566 15.6228 7.36864 15.1577 7.36864H14.9472Z"
fill="#C4C4C4"
></path>
</svg>
</button>
)}
<path
d="M11.9998 1.89462C6.41882 1.89462 1.89453 6.41891 1.89453 11.9999C1.89453 17.5809 6.41882 22.1052 11.9998 22.1052C17.5808 22.1052 22.1051 17.5809 22.1051 11.9999C22.1051 6.41891 17.5808 1.89462 11.9998 1.89462ZM7.78928 11.4662C8.02183 11.0634 8.53685 10.9254 8.93962 11.158L12.0061 12.9284L15.0612 11.1645C15.464 10.932 15.979 11.07 16.2116 11.4728C16.4441 11.8755 16.3061 12.3906 15.9034 12.6231L13.6903 13.9008L15.8678 15.158C16.2706 15.3905 16.4086 15.9055 16.1761 16.3083C15.9435 16.7111 15.4285 16.8491 15.0257 16.6165L12.0061 14.8732L8.97515 16.6231C8.57237 16.8556 8.05735 16.7176 7.82481 16.3149C7.59227 15.9121 7.73027 15.3971 8.13304 15.1645L10.3219 13.9008L8.09752 12.6165C7.69474 12.384 7.55674 11.869 7.78928 11.4662ZM7.9998 8.21074C7.9998 7.74566 8.37682 7.36864 8.8419 7.36864H9.05243C9.51751 7.36864 9.89454 7.74566 9.89454 8.21074V8.84232C9.89454 9.3074 9.51751 9.68443 9.05243 9.68443H8.8419C8.37682 9.68443 7.9998 9.3074 7.9998 8.84232V8.21074ZM14.9472 7.36864C14.4821 7.36864 14.1051 7.74566 14.1051 8.21074V8.84232C14.1051 9.3074 14.4821 9.68443 14.9472 9.68443H15.1577C15.6228 9.68443 15.9998 9.3074 15.9998 8.84232V8.21074C15.9998 7.74566 15.6228 7.36864 15.1577 7.36864H14.9472Z"
fill="#C4C4C4"
></path>
</svg>
</button>
)}
<div className={styles.navSubCon}>
{doSave && <div className={styles.autoSave}>임시저장됨</div>}
<div className={styles.textConut}>
{contentInput.length}/10000
</div>
Expand All @@ -121,6 +147,7 @@ export default function CommentPageWriteModal({
.then((data: ReplyType) => {
addReply(data);
setCurrentModal(null);
autoSave.remove(myId!, mode, autoSaveId!);
})
.catch(() => {
console.log("댓글 작성 실패");
Expand All @@ -135,6 +162,7 @@ export default function CommentPageWriteModal({
.then((data: ReplyType) => {
updateReply(data);
setCurrentModal(null);
autoSave.remove(myId!, mode, autoSaveId!);
})
.catch(() => {
console.log("댓글 수정 실패");
Expand All @@ -153,6 +181,7 @@ export default function CommentPageWriteModal({
.then(() => {
refetchComment();
setCurrentModal(null);
autoSave.remove(myId!, mode, autoSaveId!);
})
.catch(() => {
console.log("코멘트 수정 실패");
Expand Down
4 changes: 3 additions & 1 deletion src/components/Content.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@
width: 280px;
height: 400px;
margin-bottom: 30px;
transition: width 0.3s, height 0.3s;
transition:
width 0.3s,
height 0.3s;

@media (max-width: #{$medium-screen + 100}) {
width: 200px;
Expand Down
4 changes: 0 additions & 4 deletions src/components/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,16 @@ function ContentPanel({
content: MovieType;
setContent: (content: MovieType) => void;
refetchContent: () => void;

}) {
const [currentModal, setCurrentModal] = useState<
"updateComment" | "createComment" | null
>(null);


const [myRate, setMyRate] = useState(content.my_rate ?? null);

const { accessToken } = useAuthContext();
const myState = content.my_state ?? null;


const setMyStateHandler = (targetState: MyStateType) => {
if (!accessToken) return;
if (!targetState)
Expand Down Expand Up @@ -210,7 +207,6 @@ function ContentPanel({
</div>
{currentModal && accessToken && (
<WritingModal
type="comment"
title={content.title_ko}
content={content}
currentModal={currentModal}
Expand Down
6 changes: 2 additions & 4 deletions src/components/ContentList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ export default function ContentList({ title, order }: ContentListProps) {
const { accessToken } = useAuthContext();

useEffect(() => {

order === "box-office"
? getContentListRequest(order, accessToken ?? undefined)
.then(defaultResponseHandler)
Expand All @@ -84,7 +83,7 @@ export default function ContentList({ title, order }: ContentListProps) {
...movie,
poster: movie.poster.replace("http", "https"),
};
})
}),
);
})
: getContentListRequest(order, accessToken ?? undefined)
Expand All @@ -99,10 +98,9 @@ export default function ContentList({ title, order }: ContentListProps) {
...movie,
poster: movie.poster.replace("http", "https"),
};
})
}),
);
});

}, [order]);

function handleRightClick() {
Expand Down
11 changes: 10 additions & 1 deletion src/components/DeleteComReplyModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import styles from "./DeleteComReplyModal.module.scss";
import { CommentType, ReplyType } from "../type";
import { deleteCommentRequest, deleteReply } from "../apis/comment";
import { useAuthContext } from "../contexts/authContext";
import autoSave from "../utils/autoSave";

type DeleteComReplyModalProps = {
setCurrentModalState: (value: null) => void;
Expand All @@ -18,7 +19,13 @@ export default function DeleteComReplyModal({
deleteReplyState,
}: DeleteComReplyModalProps) {
const modalType = currentModalState.type;
const { accessToken } = useAuthContext();
const { myUserData, accessToken } = useAuthContext();
const myId = myUserData?.id;
const mode = modalType == "deleteComment" ? "comment" : "edit";
const autoSaveId =
modalType == "deleteComment"
? currentModalState.targetComment.movie.movieCD
: currentModalState.targetReply.id;
return (
<Modal
onClose={() => {
Expand Down Expand Up @@ -47,6 +54,7 @@ export default function DeleteComReplyModal({
deleteReply(currentModalState.targetReply.id, accessToken)
.then((res) => {
if (!res.ok) throw new Error("삭제 실패");
autoSave.remove(myId!, mode, autoSaveId);
deleteReplyState(currentModalState.targetReply.id);
setCurrentModalState(null);
})
Expand All @@ -60,6 +68,7 @@ export default function DeleteComReplyModal({
)
.then((res) => {
if (!res.ok) throw new Error("삭제 실패");
autoSave.remove(myId!, mode, autoSaveId);
window.document.location.href = `/contents/${currentModalState.targetComment.movie.movieCD}`;
})
.catch(() => {
Expand Down
4 changes: 0 additions & 4 deletions src/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@ export default function Footer() {
const [rates, setRates] = useState(0);

useEffect(() => {

getRatesCount()
.then(defaultResponseHandler)
.then((data) => {
setRates(data.ratings_count);
});


const interval = setInterval(() => {
getRatesCount()
.then(defaultResponseHandler)
Expand All @@ -33,9 +31,7 @@ export default function Footer() {
<footer>
<section className={styles.commentNumber}>
<span>

지금까지 <em>{rates.toLocaleString("ko-KR")} 개의</em> 평가가

쌓였어요.
</span>
</section>
Expand Down
4 changes: 4 additions & 0 deletions src/components/MyCommentBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import profileDefault from "../assets/user_default.jpg";
import { Link } from "react-router-dom";
import { MovieType } from "../type";
import { deleteCommentRequest } from "../apis/comment";
import autoSave from "../utils/autoSave";

export default function MyCommentBox({
myRate,
Expand All @@ -19,6 +20,7 @@ export default function MyCommentBox({
setContent: (content: MovieType) => void;
}) {
const { isLogined, myUserData, accessToken } = useAuthContext();
const myId = myUserData?.id;
const my_comment = content.my_comment;

const message =
Expand Down Expand Up @@ -56,6 +58,8 @@ export default function MyCommentBox({
.then(() => {
setContent({ ...content, my_comment: null }); // 성공 여부를 보고 반영
console.log("코멘트가 삭제되었습니다.");
if (myId != undefined)
autoSave.remove(myId, "comment", content.movieCD);
closeModal();
})
.catch(() => {
Expand Down
11 changes: 11 additions & 0 deletions src/components/WritingModal.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,17 @@
display: flex;
align-items: center;

.autoSave {
font-size: 13px;
font-weight: 400;
letter-spacing: -0.2px;
color: $medium-gray;
line-height: 16px;
text-align: right;
margin-left: auto;
margin-right: 12px;
}

.textConut {
margin-right: 13px;
font-size: 13px;
Expand Down
Loading

0 comments on commit 325e10c

Please sign in to comment.