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

메인으로 머지 #173

Merged
merged 50 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
8993590
feat: 프로필 페이지 포스트와 좋아요 출력 관련 버그 수정 (#131)
HSjjs98 Sep 10, 2024
8f8c116
Merge pull request #149 from Dev-FE-1/bug/profile-info-connect-131
devdeun Sep 10, 2024
d8ce866
refactor: 포스트 추가되고 타임 라인에 불러와질 때 토스트메세지 출력되게 수정(#152)
wonjichoe Sep 10, 2024
3412260
refactor: VideoInfo 컴포넌트 분리 (#151)
devdeun Sep 10, 2024
07dff4a
refactor: PlaylistContentsItem을 Draggable, Selectable 아이템으로 분리 (#151)
devdeun Sep 10, 2024
0f009c9
refactor: PlaylistContents를 Draggable, Selectable Playlist로 분리 (#151)
devdeun Sep 10, 2024
5d217b5
refactor: PlaylistDetail 페이지에서 SelectVideo 페이지 분리 (#151)
devdeun Sep 10, 2024
f5ca009
refactor: AddVideos 페이지의 PlaylistContentsItem 컴포넌트를 SelectablePlaylis…
devdeun Sep 10, 2024
31ac85e
remove: 불필요한 파일 삭제 (#151)
devdeun Sep 10, 2024
9b72861
Merge pull request #157 from Dev-FE-1/refactor/playlist-detail-151
HSjjs98 Sep 11, 2024
695953e
Merge pull request #156 from Dev-FE-1/refactor/toast-152
nakyeonko3 Sep 11, 2024
389d22e
test: Post에 playlist 제목이 제대로 뜨는지 테스트 코드 추가 (#116)
devdeun Sep 12, 2024
daad3a0
chore: package-lock.json 수정(#160)
nakyeonko3 Sep 12, 2024
d7e858d
feat: usePostById에서 리턴 타입을 재설정
nakyeonko3 Sep 12, 2024
84a4292
Merge pull request #159 from Dev-FE-1/test/post-playlist-title-116
devdeun Sep 12, 2024
d2d43e4
Merge branch 'develop' of https://github.com/Dev-FE-1/Toy_Project_3_t…
nakyeonko3 Sep 12, 2024
80b2282
fix: 좋아요 갱신 에러 수정(#160)
nakyeonko3 Sep 12, 2024
60561c5
refactor: CommentSection.tsx의 userIds 수정(#160)
nakyeonko3 Sep 12, 2024
a26289b
fix: 좋아요 개수가 갱신 안되는 문제를 해결(#160)
nakyeonko3 Sep 12, 2024
6481ab5
feat: InputCount 컴포넌트 추가 (#161)
devdeun Sep 12, 2024
69a058b
feat: Input, Textarea 컴포넌트에 글자수 제한 적용 (#161)
devdeun Sep 12, 2024
9406848
feat: 프로필 수정 페이지 닉네임, 소개 input에 글자수 제한 적용 (#161)
devdeun Sep 12, 2024
e844f4f
refactor: useToggleLikes 를 수정함(#160)
nakyeonko3 Sep 12, 2024
c7bd61d
chore: 코드레빗 설정 파일 추가
nakyeonko3 Sep 12, 2024
83e11b2
fix: yml 파일 삭제
nakyeonko3 Sep 12, 2024
01abc50
refactor: Post.tsx 리펙토링(#163)
nakyeonko3 Sep 12, 2024
3b0e3a9
refactor: useFetchVideoTitle가 useQuery를 사용하도록 수정(#160)
nakyeonko3 Sep 12, 2024
9d2fffc
refactor: logo.svg를 preload가 되도록 수정(#160)
nakyeonko3 Sep 12, 2024
47a5fa2
feat: 댓글 글자수 제한 적용 (#161)
devdeun Sep 13, 2024
0a12d11
Merge pull request #164 from Dev-FE-1/enhancement/input-max-length-161
devdeun Sep 13, 2024
203d2bb
Merge pull request #162 from Dev-FE-1/bug/likes-error-160
devdeun Sep 13, 2024
58d9001
feat: 모달을 훅으로 관리 (#158)
HSjjs98 Sep 16, 2024
070c6e2
chore: npm audit fix (#158)
HSjjs98 Sep 16, 2024
511bacf
feat: NewPost를 fullmodal을 사용하여 보여주기 & 프로필 수정 페이지 경로 수정 (#158)
HSjjs98 Sep 16, 2024
a62635e
Merge branch 'develop' of https://github.com/Dev-FE-1/Toy_Project_3_t…
HSjjs98 Sep 16, 2024
633529f
feat: 오버레이 관련 코드 컴포넌트로 분리 (#158)
HSjjs98 Sep 16, 2024
da0f890
feat: fullmodal 추가, 모달 전역 상태 관리, useModalWithOverlay 훅 추가 (#158)
HSjjs98 Sep 16, 2024
185db69
feat: 모달 내부에서 헤더가 랜더링 될 . 수있도록 usePortal 관련 코드 추가 (#158)
HSjjs98 Sep 16, 2024
dc12b39
refactor: 훅으로 모달 상태 관리하도록 코드 변경 (#158)
HSjjs98 Sep 16, 2024
7e88097
refactor: 훅 관련 코드 추가 및 삭제 (#158)
HSjjs98 Sep 16, 2024
88d7500
refactor: 경로 설정 관련 코드 변경 또는 추가 (#158)
HSjjs98 Sep 16, 2024
803ab1d
Merge pull request #170 from Dev-FE-1/enhancement/post-add-to-modal-158
devdeun Sep 16, 2024
dcf6142
refactor: 모달 동작 수행 및 기능 관련 코드 수정 (#171)
HSjjs98 Sep 16, 2024
b68dd5a
Merge pull request #172 from Dev-FE-1/refactor/bugs-fix-171
HSjjs98 Sep 16, 2024
98b4a4b
fix: 프로필 페이지에서 포스트와 좋아요 탭에서 좋아요가 바로 적용안되는 문제 해결 (#174)
HSjjs98 Sep 18, 2024
70cb736
feat: 이미 플레이리스트에 포함된 비디오 추가 불가하도록 수정 (#174)
HSjjs98 Sep 18, 2024
36bee5e
Merge pull request #175 from Dev-FE-1/bug/profile-likes-174
devdeun Sep 18, 2024
04e3975
Merge branch 'main' of https://github.com/Dev-FE-1/Toy_Project_3_team…
HSjjs98 Sep 18, 2024
d72c5c9
Merge pull request #176 from Dev-FE-1/merge/merge-branch
devdeun Sep 18, 2024
55bdfee
Merge branch 'main' into develop
HSjjs98 Sep 18, 2024
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
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<html lang="ko">
<head>
<meta charset="UTF-8" />
<link rel="preload" href="/src/assets/images/logo.svg" as="image" />
<link rel="icon" type="image/svg+xml" href="/src/assets/images/favicon/favicon.svg" />
<link rel="icon" href="/src/assets/images/favicon/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
Expand Down
12 changes: 9 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 19 additions & 14 deletions src/api/fetchYouTubeVideoData.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
export const fetchYouTubeVideoData = async (videoId: string) => {
const apiKey = import.meta.env.VITE_YOUTUBE_API_KEY;
const response = await fetch(
`https://www.googleapis.com/youtube/v3/videos?part=snippet,statistics&id=${videoId}&key=${apiKey}`,
);
try {
const response = await fetch(
`https://www.googleapis.com/youtube/v3/videos?part=snippet,statistics&id=${videoId}&key=${apiKey}`,
);

if (!response.ok) {
throw new Error('비디오 정보를 가져오는데 실패했습니다.');
}
if (!response.ok) {
throw new Error('비디오 정보를 가져오는데 실패했습니다. status:' + response.status);
}

const data = await response.json();
const videoDetails = data.items[0];
const data = await response.json();
const videoDetails = data.items[0];

return {
title: videoDetails.snippet.title,
creator: videoDetails.snippet.channelTitle,
uploadDate: videoDetails.snippet.publishedAt,
views: videoDetails.statistics.viewCount,
};
return {
title: videoDetails.snippet.title,
creator: videoDetails.snippet.channelTitle,
uploadDate: videoDetails.snippet.publishedAt,
views: videoDetails.statistics.viewCount,
};
} catch (error) {
console.error(error);
throw new Error('비디오 정보를 가져오는데 실패했습니다.');
}
};
23 changes: 0 additions & 23 deletions src/components/comment/CommentActions.tsx

This file was deleted.

56 changes: 45 additions & 11 deletions src/components/comment/CommentInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import { useEffect, useRef } from 'react';
import { css, SerializedStyles } from '@emotion/react';
import { HiOutlinePaperAirplane } from 'react-icons/hi2';

import InputCount from '@/components/common/inputs/InputCount';
import theme from '@/styles/theme';

const INPUT_MIN_HEIGHT = 40;
const INPUT_MAX_HEIGHT = INPUT_MIN_HEIGHT * 2;
const MAX_LENGTH = 300;

interface CommentInputProps {
comment: string;
Expand All @@ -17,7 +19,7 @@ interface CommentInputProps {
handleCompositionEnd: () => void;
}

export const CommentInput: React.FC<CommentInputProps> = ({
const CommentInput: React.FC<CommentInputProps> = ({
comment,
onChange,
onSubmit,
Expand All @@ -42,18 +44,34 @@ export const CommentInput: React.FC<CommentInputProps> = ({
}
};

const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
const inputValue = e.target.value.slice(0, MAX_LENGTH);
onChange(inputValue);
};

return (
<div css={[newCommentStyle, customStyle]}>
<textarea
ref={textareaRef}
value={comment}
onChange={(e) => onChange(e.target.value)}
onKeyDown={handleKeyDown}
placeholder="댓글을 작성해주세요"
onCompositionStart={handleCompositionStart}
onCompositionEnd={handleCompositionEnd}
data-testid="comment-input"
/>
<div className="textarea-container">
<textarea
ref={textareaRef}
value={comment}
onChange={handleChange}
onKeyDown={handleKeyDown}
placeholder="댓글을 작성해주세요"
onCompositionStart={handleCompositionStart}
onCompositionEnd={handleCompositionEnd}
data-testid="comment-input"
maxLength={MAX_LENGTH}
/>
{comment.length > 0 && (
<InputCount
currentLength={comment.length}
maxLength={MAX_LENGTH}
customStyle={countStyle}
/>
)}
</div>

<button onClick={onSubmit}>
<HiOutlinePaperAirplane />
</button>
Expand All @@ -69,7 +87,15 @@ const newCommentStyle = css`
border-radius: 12px;
background-color: ${theme.colors.bgGray};

.textarea-container {
display: flex;
flex-direction: column;
flex-grow: 1;
width: 100%;
}

textarea {
flex-grow: 1;
width: 100%;
min-height: ${INPUT_MIN_HEIGHT}px;
max-height: ${INPUT_MAX_HEIGHT}px;
Expand All @@ -83,6 +109,7 @@ const newCommentStyle = css`
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
padding: 8px 10px 12px;
border: none;
border-radius: 4px;
Expand All @@ -97,3 +124,10 @@ const newCommentStyle = css`
}
}
`;

const countStyle = css`
padding: 2px 0 8px;
text-align: right;
`;

export default CommentInput;
24 changes: 12 additions & 12 deletions src/components/comment/CommentItem.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { useState } from 'react';

import { css } from '@emotion/react';
import {
HiOutlineEllipsisVertical,
Expand All @@ -9,11 +7,12 @@ import {
} from 'react-icons/hi2';
import { Link } from 'react-router-dom';

import { CommentInput } from '@/components/comment/CommentInput';
import CommentInput from '@/components/comment/CommentInput';
import Avatar from '@/components/common/Avatar';
import FitButton from '@/components/common/buttons/FitButton';
import OptionModal from '@/components/common/modals/OptionModal';
import { PATH } from '@/constants/path';
import { useModalWithOverlay } from '@/hooks/useModalWithOverlay';
import theme from '@/styles/theme';
import { CommentModel } from '@/types/comment';
import { formatCreatedAt } from '@/utils/date';
Expand Down Expand Up @@ -45,10 +44,11 @@ const CommentItem: React.FC<CommentItemProps> = ({
handleCompositionStart,
handleCompositionEnd,
}) => {
const [isModalOpen, setIsModalOpen] = useState(false);

const handleOpenModal = () => setIsModalOpen(true);
const handleCloseModal = () => setIsModalOpen(false);
const {
isOpen: isModalOpen,
open: openModal,
close: closeModal,
} = useModalWithOverlay('commentOptionModal', comment.id);

const modalOptions = [
{
Expand All @@ -57,15 +57,15 @@ const CommentItem: React.FC<CommentItemProps> = ({
onClick: () => {
setEditingCommentId(comment.id);
setEditingContent(comment.content);
handleCloseModal();
closeModal();
},
},
{
label: '댓글 삭제하기',
Icon: HiOutlineTrash,
onClick: () => {
handleDeleteComment(comment.id);
handleCloseModal();
closeModal();
},
},
];
Expand All @@ -77,20 +77,20 @@ const CommentItem: React.FC<CommentItemProps> = ({
<div css={headerStyle}>
<div css={userInfoStyle}>
<Link to={PATH.PROFILE.replace(':userId', comment.userId)}>
<span css={nameStyle}>{userData?.displayName || 'Unknown User'}</span>
<span css={nameStyle}>{userData?.displayName || ''}</span>
</Link>
<span css={timeStyle}>{formatCreatedAt(comment.createdAt)}</span>
</div>
{comment.userId === currentUserId && (
<>
<button
css={menuTriggerStyle}
onClick={handleOpenModal}
onClick={openModal}
data-testid="comment-vertical-button"
>
<HiOutlineEllipsisVertical size={20} />
</button>
<OptionModal isOpen={isModalOpen} onClose={handleCloseModal} options={modalOptions} />
<OptionModal isOpen={isModalOpen} onClose={closeModal} options={modalOptions} />
</>
)}
</div>
Expand Down
12 changes: 8 additions & 4 deletions src/components/comment/CommentSection.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { useMemo } from 'react';

import { css } from '@emotion/react';
import { HiOutlineChatBubbleOvalLeft } from 'react-icons/hi2';

import defaultProfile from '@/assets/images/default-avatar.svg';
import CommentInput from '@/components/comment/CommentInput';
import CommentItem from '@/components/comment/CommentItem';
import Avatar from '@/components/common/Avatar';
import EmptyMessage from '@/components/EmptyMessage';
import { useComments } from '@/hooks/useComments';
import { useMultipleUsersData } from '@/hooks/useMultipleUsersData';
import { useUserData } from '@/hooks/useUserData';

import { CommentInput } from './CommentInput';
import CommentItem from './CommentItem';

interface CommentSectionProps {
postId: string;
}
Expand All @@ -32,7 +33,10 @@ const CommentSection: React.FC<CommentSectionProps> = ({ postId }) => {
handleCompositionEnd,
} = useComments(postId || '');

const userIds = Array.from(new Set(comments.map((comment) => comment.userId)));
const userIds = useMemo(() => {
return Array.from(new Set(comments.map((comment) => comment.userId)));
}, [comments]);

const { userData: currentUserData } = useUserData(currentUser?.uid || null);
const { usersData } = useMultipleUsersData(userIds);

Expand Down
36 changes: 29 additions & 7 deletions src/components/common/inputs/BaseInput.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { ChangeEvent, ReactNode } from 'react';

import { SerializedStyles } from '@emotion/react';
import { css, SerializedStyles } from '@emotion/react';

import InputCount from '@/components/common/inputs/InputCount';
import { commonInputContainerStyle, errorMessageStyle } from '@/styles/input';

export interface CommonInputProps {
Expand All @@ -11,28 +12,49 @@ export interface CommonInputProps {
label?: string;
placeholder?: string;
errorMessage?: string | null;
maxLength?: number;
customStyle?: SerializedStyles;
}

interface BaseInputProps extends Partial<CommonInputProps> {
children: ReactNode;
currentLength?: number;
}

const BaseInput: React.FC<BaseInputProps> = ({ label, errorMessage = null, id, children }) => {
const BaseInput: React.FC<BaseInputProps> = ({
label,
errorMessage = null,
id,
currentLength,
maxLength,
children,
}) => {
return (
<label css={commonInputContainerStyle} htmlFor={id}>
{label && <span className="input-label">{label}</span>}
<div className="input-wrapper">
{children}

{errorMessage && (
<p className="error" css={errorMessageStyle}>
{errorMessage}
</p>
{maxLength && typeof currentLength === 'number' && (
<InputCount
currentLength={currentLength}
maxLength={maxLength}
customStyle={countStyle}
/>
)}
</div>
{errorMessage && (
<p className="error" css={errorMessageStyle}>
{errorMessage}
</p>
)}
</label>
);
};

const countStyle = css`
position: absolute;
bottom: 12px;
right: 12px;
`;

export default BaseInput;
Loading
Loading