From bb0f1e5760d4b8125f2cf76032c7599b8abd319c Mon Sep 17 00:00:00 2001 From: CJewon <112820744+CJewon@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:34:08 +0900 Subject: [PATCH 01/18] =?UTF-8?q?Feat/Feed=5FUI=20=EA=B5=AC=ED=98=84=20(#1?= =?UTF-8?q?1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * request를 받아 질문 목록 생성 및 html 작업완료 * :sparkles: feat : tailwind 작업도중 커밋 * :memo: fix : png파일을 svg파일로 수정 및 question부분을 컴포넌트화 하기 위해 폴더 생성 * :lipstick: style : feat/Feed_화면_구현 반응형 웹 제작 --- src/assets/images/icons/Messages.svg | 4 + src/assets/images/icons/thumbs-down.svg | 3 + src/assets/images/icons/thumbs-up.svg | 3 + src/assets/images/img_QusetionBox.svg | 7 ++ src/components/Feed/index.jsx | 3 + src/pages/Feed/index.jsx | 113 +++++++++++++++++++++++- tailwind.config.js | 3 + 7 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 src/assets/images/icons/Messages.svg create mode 100644 src/assets/images/icons/thumbs-down.svg create mode 100644 src/assets/images/icons/thumbs-up.svg create mode 100644 src/assets/images/img_QusetionBox.svg create mode 100644 src/components/Feed/index.jsx diff --git a/src/assets/images/icons/Messages.svg b/src/assets/images/icons/Messages.svg new file mode 100644 index 0000000..6368f81 --- /dev/null +++ b/src/assets/images/icons/Messages.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/images/icons/thumbs-down.svg b/src/assets/images/icons/thumbs-down.svg new file mode 100644 index 0000000..8bb1b95 --- /dev/null +++ b/src/assets/images/icons/thumbs-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/images/icons/thumbs-up.svg b/src/assets/images/icons/thumbs-up.svg new file mode 100644 index 0000000..8c5e703 --- /dev/null +++ b/src/assets/images/icons/thumbs-up.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/images/img_QusetionBox.svg b/src/assets/images/img_QusetionBox.svg new file mode 100644 index 0000000..23cf698 --- /dev/null +++ b/src/assets/images/img_QusetionBox.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/components/Feed/index.jsx b/src/components/Feed/index.jsx new file mode 100644 index 0000000..1b737ec --- /dev/null +++ b/src/components/Feed/index.jsx @@ -0,0 +1,3 @@ +const Question = () =>
안녕하세요
; + +export default Question; diff --git a/src/pages/Feed/index.jsx b/src/pages/Feed/index.jsx index fad6a9a..1ab987c 100644 --- a/src/pages/Feed/index.jsx +++ b/src/pages/Feed/index.jsx @@ -1,3 +1,114 @@ -const Feed = () =>

피드 페이지입니다.

; +import { useEffect, useState } from 'react'; +import { useParams } from 'react-router-dom'; +import { getQuestionBySubjectId } from 'api/questions'; +import thumbsUpIcon from 'assets/images/icons/thumbs-up.svg'; +import thumbsDownIcon from 'assets/images/icons/thumbs-down.svg'; +import messagesIcon from 'assets/images/icons/Messages.svg'; +import qusetionBoxImg from 'assets/images/img_QusetionBox.svg'; + +const Feed = () => { + const { id: subjectId } = useParams(); // URL에서 subjectId를 가져옴 + const [questions, setQuestions] = useState([]); // 질문 목록 상태 + const [loading, setLoading] = useState(true); // 로딩 상태 + const [error, setError] = useState(''); // 오류 메시지 상태 + const [favoriteCount, setFavoriteCount] = useState(0); // 좋아요 상태 + const [unFavoriteCount, setUnFavoriteCount] = useState(0); // 싫어요 상태 + + useEffect(() => { + const fetchQuestions = async () => { + try { + setLoading(true); + setError(''); + const params = { page: 1, pageSize: 10 }; // 필요한 경우 쿼리 파라미터 설정 + const response = await getQuestionBySubjectId(subjectId, params); + if (response.results) { + setQuestions(response.results); + } else { + throw new Error('질문 데이터를 가져오는 데 실패했습니다.'); + } + } catch (err) { + setError(err.message); + } finally { + setLoading(false); + } + }; + + fetchQuestions(); + }, [subjectId]); + + if (loading) return
로딩 중...
; + if (error) return
오류: {error}
; + + const countingFavorite = () => { + setFavoriteCount(favoriteCount + 1); + }; + + const countingUnFavorite = () => { + setUnFavoriteCount(unFavoriteCount + 1); + }; + + return ( + <> +
헤더 입니다
+
+
+
+ 말풍선 이미지 + {questions.length > 0 ? ( +

{questions.length}개의 질문이 있습니다

+ ) : ( +

아직 질문이 없습니다.

+ )} +
+ {questions.length > 0 ? ( + + ) : ( + 질문박스 이미지 + )} +
+ +
+ + ); +}; export default Feed; diff --git a/tailwind.config.js b/tailwind.config.js index cc4e2c4..c60dd94 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -34,6 +34,9 @@ module.exports = { '2pt': '0px 4px 4px 0px rgba(0, 0, 0, 0.25)', '3pt': '0px 16px 20px 0px rgba(48, 48, 48, 0.62)', }, + screens: { + desktop: '1200px', // 데스크탑 사이즈를 1200px로 정의 + }, }, }, plugins: [], From ada1818745ead5f1486cd0bec5e2d1dac0b90ec0 Mon Sep 17 00:00:00 2001 From: CJewon <112820744+CJewon@users.noreply.github.com> Date: Tue, 17 Dec 2024 12:45:02 +0900 Subject: [PATCH 02/18] =?UTF-8?q?Feat/=EC=A2=8B=EC=95=84=EC=9A=94=20?= =?UTF-8?q?=EC=8B=AB=EC=96=B4=EC=9A=94=20=EA=B8=B0=EB=8A=A5=20(#16)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit :sparkles: feat : 좋아요, 싫어요 기능 제작 및 컴포넌트화 --- package-lock.json | 1 + package.json | 1 + src/assets/images/icons/thumbs-down.svg | 2 +- src/assets/images/icons/thumbs-up.svg | 2 +- src/components/Feed/favorite/index.jsx | 51 +++++++++++++++++++++++++ src/components/Feed/index.jsx | 3 -- src/pages/Feed/index.jsx | 35 ++++------------- 7 files changed, 63 insertions(+), 32 deletions(-) create mode 100644 src/components/Feed/favorite/index.jsx delete mode 100644 src/components/Feed/index.jsx diff --git a/package-lock.json b/package-lock.json index 658c509..d09675e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "dependencies": { "cra-template": "1.2.0", + "prop-types": "^15.8.1", "react": "^19.0.0", "react-dom": "^19.0.0", "react-router-dom": "^7.0.2", diff --git a/package.json b/package.json index 8638ca9..f81cc72 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "private": true, "dependencies": { "cra-template": "1.2.0", + "prop-types": "^15.8.1", "react": "^19.0.0", "react-dom": "^19.0.0", "react-router-dom": "^7.0.2", diff --git a/src/assets/images/icons/thumbs-down.svg b/src/assets/images/icons/thumbs-down.svg index 8bb1b95..09e87a4 100644 --- a/src/assets/images/icons/thumbs-down.svg +++ b/src/assets/images/icons/thumbs-down.svg @@ -1,3 +1,3 @@ - + diff --git a/src/assets/images/icons/thumbs-up.svg b/src/assets/images/icons/thumbs-up.svg index 8c5e703..8833fd6 100644 --- a/src/assets/images/icons/thumbs-up.svg +++ b/src/assets/images/icons/thumbs-up.svg @@ -1,3 +1,3 @@ - + diff --git a/src/components/Feed/favorite/index.jsx b/src/components/Feed/favorite/index.jsx new file mode 100644 index 0000000..b74f082 --- /dev/null +++ b/src/components/Feed/favorite/index.jsx @@ -0,0 +1,51 @@ +import { useState } from 'react'; +import PropTypes from 'prop-types'; +import { ReactComponent as ThumbsUpIcon } from 'assets/images/icons/thumbs-up.svg'; +import { ReactComponent as ThumbsDownIcon } from 'assets/images/icons/thumbs-down.svg'; + +const CountingFavorite = ({ like, dislike }) => { + const [favoriteCount, setFavoriteCount] = useState(like); + const [unFavoriteCount, setUnFavoriteCount] = useState(dislike); + const [clickFavorite, setClickFavorite] = useState(false); + const [clickUnFavorite, setClickUnFavorite] = useState(false); + + CountingFavorite.propTypes = { + like: PropTypes.number.isRequired, + dislike: PropTypes.number.isRequired, + }; + + const countingHandleFavorite = () => { + if (clickFavorite) { + setClickFavorite(false); + setFavoriteCount(favoriteCount - 1); + } else { + setClickFavorite(true); + setFavoriteCount(favoriteCount + 1); + } + }; + + const countingHandleUnFavorite = () => { + if (clickUnFavorite) { + setClickUnFavorite(false); + setUnFavoriteCount(unFavoriteCount - 1); + } else { + setClickUnFavorite(true); + setUnFavoriteCount(unFavoriteCount + 1); + } + }; + + return ( +
+ + +
+ ); +}; + +export default CountingFavorite; diff --git a/src/components/Feed/index.jsx b/src/components/Feed/index.jsx deleted file mode 100644 index 1b737ec..0000000 --- a/src/components/Feed/index.jsx +++ /dev/null @@ -1,3 +0,0 @@ -const Question = () =>
안녕하세요
; - -export default Question; diff --git a/src/pages/Feed/index.jsx b/src/pages/Feed/index.jsx index 1ab987c..25b35fe 100644 --- a/src/pages/Feed/index.jsx +++ b/src/pages/Feed/index.jsx @@ -1,25 +1,23 @@ import { useEffect, useState } from 'react'; import { useParams } from 'react-router-dom'; import { getQuestionBySubjectId } from 'api/questions'; -import thumbsUpIcon from 'assets/images/icons/thumbs-up.svg'; -import thumbsDownIcon from 'assets/images/icons/thumbs-down.svg'; + import messagesIcon from 'assets/images/icons/Messages.svg'; import qusetionBoxImg from 'assets/images/img_QusetionBox.svg'; +import CountingFavorite from 'components/Feed/favorite'; const Feed = () => { - const { id: subjectId } = useParams(); // URL에서 subjectId를 가져옴 - const [questions, setQuestions] = useState([]); // 질문 목록 상태 - const [loading, setLoading] = useState(true); // 로딩 상태 - const [error, setError] = useState(''); // 오류 메시지 상태 - const [favoriteCount, setFavoriteCount] = useState(0); // 좋아요 상태 - const [unFavoriteCount, setUnFavoriteCount] = useState(0); // 싫어요 상태 + const { id: subjectId } = useParams(); + const [questions, setQuestions] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(''); useEffect(() => { const fetchQuestions = async () => { try { setLoading(true); setError(''); - const params = { page: 1, pageSize: 10 }; // 필요한 경우 쿼리 파라미터 설정 + const params = { page: 1, pageSize: 10 }; const response = await getQuestionBySubjectId(subjectId, params); if (response.results) { setQuestions(response.results); @@ -39,14 +37,6 @@ const Feed = () => { if (loading) return
로딩 중...
; if (error) return
오류: {error}
; - const countingFavorite = () => { - setFavoriteCount(favoriteCount + 1); - }; - - const countingUnFavorite = () => { - setUnFavoriteCount(unFavoriteCount + 1); - }; - return ( <>
헤더 입니다
@@ -84,16 +74,7 @@ const Feed = () => { )} -
- - -
+ ))} From 8f3c4e43c9a40207f536e71013b957acd7c1aabf Mon Sep 17 00:00:00 2001 From: CJewon <112820744+CJewon@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:39:01 +0900 Subject: [PATCH 03/18] =?UTF-8?q?Feat/=EC=A2=8B=EC=95=84=EC=9A=94=20?= =?UTF-8?q?=EC=8B=AB=EC=96=B4=EC=9A=94=20=EA=B8=B0=EB=8A=A5=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :sparkles: feat : 좋아요, 싫어요 기능 제작 및 컴포넌트화 * :wrench: chore : netlify CD 셋업 * :wrench: chore : ci.yaml 파일 배포 설정 추가 * :art: feat : fetch 함수 코드 구조 수정 및 PR 관련 피드백 일부 적용 * :spakles: feat : 좋아요 싫어요 클릭했을때 증가하는 기능 추가 --------- Co-authored-by: Tokyun02 --- .github/workflows/ci.yaml | 9 +- netlify.toml | 16 +++ src/components/Feed/favorite/index.jsx | 20 ++-- src/pages/Feed/index.jsx | 139 ++++++++++++------------- 4 files changed, 100 insertions(+), 84 deletions(-) create mode 100644 netlify.toml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index def1977..f0d09b9 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -40,6 +40,13 @@ jobs: - name: Build test run: npm run build + + - name: Install Netlify CLI + run: npm install -g netlify-cli - + - name: Deploy to Netlify + run: netlify deploy --prod --dir=build --site=$NETLIFY_SITE_ID + env: + NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} + NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 0000000..b374baa --- /dev/null +++ b/netlify.toml @@ -0,0 +1,16 @@ +[build] + command = "npm run build" + publish = "build" + +[context.deploy-preview] + command = "npm run build" + publish = "build" + +[context.merge] + command = "npm run build" + publish = "build" + +[[redirects]] + from = "/*" + to = "/index.html" + status = 200 diff --git a/src/components/Feed/favorite/index.jsx b/src/components/Feed/favorite/index.jsx index b74f082..b0a65e4 100644 --- a/src/components/Feed/favorite/index.jsx +++ b/src/components/Feed/favorite/index.jsx @@ -1,7 +1,7 @@ import { useState } from 'react'; -import PropTypes from 'prop-types'; import { ReactComponent as ThumbsUpIcon } from 'assets/images/icons/thumbs-up.svg'; import { ReactComponent as ThumbsDownIcon } from 'assets/images/icons/thumbs-down.svg'; +import PropTypes from 'prop-types'; const CountingFavorite = ({ like, dislike }) => { const [favoriteCount, setFavoriteCount] = useState(like); @@ -15,22 +15,20 @@ const CountingFavorite = ({ like, dislike }) => { }; const countingHandleFavorite = () => { - if (clickFavorite) { - setClickFavorite(false); - setFavoriteCount(favoriteCount - 1); - } else { + if (!clickFavorite) { setClickFavorite(true); - setFavoriteCount(favoriteCount + 1); + setFavoriteCount((prev) => prev + 1); + } else { + setFavoriteCount((prev) => prev + 1); } }; const countingHandleUnFavorite = () => { - if (clickUnFavorite) { - setClickUnFavorite(false); - setUnFavoriteCount(unFavoriteCount - 1); - } else { + if (!clickUnFavorite) { setClickUnFavorite(true); - setUnFavoriteCount(unFavoriteCount + 1); + setUnFavoriteCount((prev) => prev + 1); + } else { + setUnFavoriteCount((prev) => prev + 1); } }; diff --git a/src/pages/Feed/index.jsx b/src/pages/Feed/index.jsx index 25b35fe..707cf03 100644 --- a/src/pages/Feed/index.jsx +++ b/src/pages/Feed/index.jsx @@ -6,89 +6,84 @@ import messagesIcon from 'assets/images/icons/Messages.svg'; import qusetionBoxImg from 'assets/images/img_QusetionBox.svg'; import CountingFavorite from 'components/Feed/favorite'; +const fetchQuestions = async (subjectId, setQuestions, setGetLoading, setGetError) => { + try { + setGetLoading(true); + setGetError(''); + const params = { limit: 10, offset: 0 }; + const response = await getQuestionBySubjectId(subjectId, params); + if (response.results) { + setQuestions(response.results); + } else { + throw new Error('질문 데이터를 가져오는 데 실패했습니다.'); + } + } catch (err) { + setGetError(err.message); + } finally { + setGetLoading(false); + } +}; + const Feed = () => { const { id: subjectId } = useParams(); const [questions, setQuestions] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(''); + const [getLoading, setGetLoading] = useState(true); - useEffect(() => { - const fetchQuestions = async () => { - try { - setLoading(true); - setError(''); - const params = { page: 1, pageSize: 10 }; - const response = await getQuestionBySubjectId(subjectId, params); - if (response.results) { - setQuestions(response.results); - } else { - throw new Error('질문 데이터를 가져오는 데 실패했습니다.'); - } - } catch (err) { - setError(err.message); - } finally { - setLoading(false); - } - }; + const [getError, setGetError] = useState(''); - fetchQuestions(); + useEffect(() => { + fetchQuestions(subjectId, setQuestions, setGetLoading, setGetError); }, [subjectId]); - if (loading) return
로딩 중...
; - if (error) return
오류: {error}
; + if (getLoading) return
로딩 중...
; + if (getError) return
오류: {getError}
; return ( - <> -
헤더 입니다
-
-
-
- 말풍선 이미지 - {questions.length > 0 ? ( -

{questions.length}개의 질문이 있습니다

- ) : ( -

아직 질문이 없습니다.

- )} -
- {questions.length > 0 ? ( -
    - {questions.map((question) => ( -
  • -
    - - 답변 확인 표시 - -
    -

    질문·2주 전

    -

    {question.content}

    -
    - {question.answer !== null && ( -
    - 유저 이미지 -
    -
    -

    유저 닉네임

    -

    2주 전

    -
    -

    {question.answer.content}

    +
    +
    +
    + 말풍선 이미지 + +

    {questions.length > 0 ? `${questions.length}개의 질문이 있습니다` : '아직 질문이 없습니다.'}

    +
    + {questions.length > 0 ? ( +
      + {questions.map((question) => ( +
    • +
      + + 답변 확인 표시 + +
      +

      질문·2주 전

      +

      {question.content}

      +
      + {question.answer !== null && ( +
      + 유저 이미지 +
      +
      +

      유저 닉네임

      +

      2주 전

      +

      {question.answer.content}

      - )} - -
      -
    • - ))} -
    - ) : ( - 질문박스 이미지 - )} -
    - -
    - +
    + )} + +
    +
  • + ))} +
+ ) : ( + 질문박스 이미지 + )} +
+ +
); }; From f311990002056402d028cff29c4c61b1d0bde1ba Mon Sep 17 00:00:00 2001 From: CJewon <112820744+CJewon@users.noreply.github.com> Date: Wed, 18 Dec 2024 18:51:35 +0900 Subject: [PATCH 04/18] =?UTF-8?q?Feat/=EB=AC=B4=ED=95=9C=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A1=A4=20=EA=B5=AC=ED=98=84=20(#37)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :art: refactor : intersection observer API 사용시, fetchQuestions 함수에 보내야하는 파라미터들이 추가될것 같아 fetchQuestion함수를 내부로 refactor 하는 작업을 함 * :sparkles: feat : 데이터 로딩을 확인하기 위해 데이터 불러오기 버튼을 임시 생성 * :sparkles: feat : 무한 스크롤 기능 구현 --- src/pages/Feed/index.jsx | 95 ++++++++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 29 deletions(-) diff --git a/src/pages/Feed/index.jsx b/src/pages/Feed/index.jsx index 707cf03..034b98c 100644 --- a/src/pages/Feed/index.jsx +++ b/src/pages/Feed/index.jsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { useParams } from 'react-router-dom'; import { getQuestionBySubjectId } from 'api/questions'; @@ -6,45 +6,81 @@ import messagesIcon from 'assets/images/icons/Messages.svg'; import qusetionBoxImg from 'assets/images/img_QusetionBox.svg'; import CountingFavorite from 'components/Feed/favorite'; -const fetchQuestions = async (subjectId, setQuestions, setGetLoading, setGetError) => { - try { - setGetLoading(true); - setGetError(''); - const params = { limit: 10, offset: 0 }; - const response = await getQuestionBySubjectId(subjectId, params); - if (response.results) { - setQuestions(response.results); - } else { - throw new Error('질문 데이터를 가져오는 데 실패했습니다.'); - } - } catch (err) { - setGetError(err.message); - } finally { - setGetLoading(false); - } -}; - const Feed = () => { const { id: subjectId } = useParams(); const [questions, setQuestions] = useState([]); - const [getLoading, setGetLoading] = useState(true); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(''); + const [offset, setOffset] = useState(0); + const [hasMore, setHasMore] = useState(false); + const observerRef = useRef(null); + + useEffect(() => { + const fetchQuestions = async () => { + try { + setLoading(true); + setError(''); + const params = { limit: 3, offset }; + const response = await getQuestionBySubjectId(subjectId, params); + if (response.results) { + setQuestions((prev) => [...prev, ...response.results]); + setHasMore(response.results.length > 0); + } else { + throw new Error('질문 데이터를 가져오는 데 실패했습니다.'); + } + } catch (err) { + setError(err.message); + } finally { + setLoading(false); + } + }; + + fetchQuestions(); + }, [subjectId, offset]); - const [getError, setGetError] = useState(''); + const loadMoreQuestions = useCallback( + (entries) => { + const [entry] = entries; + if (entry.isIntersecting && hasMore && !loading) { + setOffset((prev) => prev + 3); + } + }, + [hasMore, loading], + ); useEffect(() => { - fetchQuestions(subjectId, setQuestions, setGetLoading, setGetError); - }, [subjectId]); + const observer = new IntersectionObserver(loadMoreQuestions, { + root: null, + rootMargin: '0px', + threshold: 1.0, + }); + + const targetCurrent = observerRef.current; + + if (targetCurrent) { + observer.observe(targetCurrent); + } + + return () => { + if (targetCurrent) { + observer.unobserve(targetCurrent); + } + }; + }, [loadMoreQuestions]); - if (getLoading) return
로딩 중...
; - if (getError) return
오류: {getError}
; + if (loading && questions.length === 0) return
로딩 중...
; + if (error) return
오류: {error}
; return ( -
+
말풍선 이미지 - -

{questions.length > 0 ? `${questions.length}개의 질문이 있습니다` : '아직 질문이 없습니다.'}

+ {questions.length > 0 ? ( +

{questions.length}개의 질문이 있습니다

+ ) : ( +

아직 질문이 없습니다.

+ )}
{questions.length > 0 ? (
    @@ -70,7 +106,7 @@ const Feed = () => {
)} - + ))} @@ -78,6 +114,7 @@ const Feed = () => { ) : ( 질문박스 이미지 )} +
diff --git a/src/components/Modals/index.jsx b/src/components/Modals/index.jsx new file mode 100644 index 0000000..2430f0b --- /dev/null +++ b/src/components/Modals/index.jsx @@ -0,0 +1,66 @@ +import { useContext, useState, useRef } from 'react'; +import { AppContext } from 'components/Context'; +import { postQuestion } from 'api/questions'; +import icMessages from 'assets/images/icons/ic_Messages.svg'; +import icClose from 'assets/images/icons/ic_Close.svg'; + +const Modal = () => { + const { isModalOpen, profile, closeModal } = useContext(AppContext); + const [isContent, setIsContent] = useState(false); + const content = useRef(); + + const exitModal = () => { + closeModal(); + setIsContent(false); + }; + // Form 제출 이벤트 + const postFormHandler = (e) => { + e.preventDefault(); + postQuestion(profile.id, { content: content.current.value.trim() }); + exitModal(); + }; + // 실제 이벤트 발생 지점과 버블링 지점에서 target이 일치하면 모달 닫기 + const clickOutsideModal = ({ target, currentTarget }) => { + if (target === currentTarget) exitModal(); + }; + // TextArea 유효성 검사 + const changeContentHandler = () => { + if (content.current.value !== '') setIsContent(true); + else setIsContent(false); + }; + + if (!isModalOpen) return null; + return ( +
+
+