Skip to content

Commit

Permalink
Merge pull request #50 from jinyeongjang/feat/thunder
Browse files Browse the repository at this point in the history
✨ Feat: 밥피엔스 반응형 PC 해상도 추가
  • Loading branch information
jinyeongjang authored Oct 11, 2024
2 parents 5939916 + 01ea753 commit a1cf8e3
Show file tree
Hide file tree
Showing 70 changed files with 4,047 additions and 1,188 deletions.
28 changes: 28 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,33 @@
src="https://www.facebook.com/tr?id=782242920545570&ev=PageView&noscript=1" />
</noscript>
<script type="module" src="/src/main.tsx"></script>
<!-- browser tab 전환 시 자동 새로고침 -->
<script>
let hidden, visibilityChange;
if (typeof document.hidden !== 'undefined') {
hidden = 'hidden';
visibilityChange = 'visibilitychange';
} else if (typeof document.msHidden !== 'undefined') {
hidden = 'msHidden';
visibilityChange = 'msvisibilitychange';
} else if (typeof document.webkitHidden !== 'undefined') {
hidden = 'webkitHidden';
visibilityChange = 'webkitvisibilitychange';
}

let wasHidden = false;

document.addEventListener(
visibilityChange,
function () {
if (document[hidden]) {
wasHidden = true;
} else if (wasHidden) {
location.reload();
}
},
false,
);
</script>
</body>
</html>
3 changes: 3 additions & 0 deletions public/images/ProfileDeliciousFinder.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 8 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Route, Routes } from 'react-router-dom';
import Layout from './components/layout/Layout.tsx';
import { Signin, Signup, ResetPassword } from './pages/auth';
import { Board, BoardId, BoardPost, BoardCommentEdit } from './pages/board';
import { Board, BoardId, BoardPost } from './pages/board';
import { Flavor, FlavorTest } from './pages/flavor';
import { Foods, FoodsId } from './pages/foods';
import { Fti, FtiResultId, FtiTest } from './pages/fti';
Expand All @@ -11,7 +11,10 @@ import Landing from './pages/Home/Landing.tsx';
import ProfileId from './pages/profile/ProfileId.tsx';
import ImageOverview from './pages/Image/ImageOverview.tsx';
import Introduction from './pages/introduction/Introduction.tsx';
import UpdateNote from './pages/UpdateNotes/UpdateNotes.tsx';
import NotFound from './pages/notfound/NotFound.tsx';
import ThunderPostEdit from './pages/thunder/ThunderPostEdit.tsx';
import BoardPostEdit from './pages/board/BoardPostEdit.tsx';

function App() {
return (
Expand All @@ -29,7 +32,7 @@ function App() {
<Route index element={<Board />} />
<Route path=":boardId" element={<BoardId />} />
<Route path="boardpost" element={<BoardPost />} />
<Route path="boardcommentedit" element={<BoardCommentEdit />} />
<Route path="boardpostedit/:boardrId" element={<BoardPostEdit />} />
</Route>

<Route path="flavor">
Expand Down Expand Up @@ -60,6 +63,7 @@ function App() {
<Route path="thunderchat/:thunderId" element={<ThunderChat />} />
<Route path=":thunderId" element={<ThunderId />} />
<Route path="thunderpost" element={<ThunderPost />} />
<Route path="thunderpostedit/:thunderId" element={<ThunderPostEdit />} />
</Route>

<Route path="profile/:Id" element={<ProfileId />} />
Expand All @@ -68,6 +72,8 @@ function App() {

<Route path="introduction" element={<Introduction />} />

<Route path="updatenote" element={<UpdateNote />} />

<Route path="*" element={<NotFound />} />
</Route>
</Routes>
Expand Down
5 changes: 3 additions & 2 deletions src/api/apis/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ export const signinAPI = async (email: string, password: string) => {
}

setItem('access', access);
return true; // 로그인 성공 시 true 반환
} catch (error) {
console.error('Failed to login:', error); // 에러 로그 출력
throw error; // 에러를 throw
console.error('로그인 실패:', error); // 에러 로그 출력
return false; // 로그인 실패 시 false 반환
}
};

Expand Down
50 changes: 50 additions & 0 deletions src/api/apis/thunderIdApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { baseInstance, authInstance } from '../util/instance';

// FE: Thunder - BE: Meeting 정보를 가져오는 함수
export const fetchMeeting = async (meetingId: string) => {
const response = await baseInstance.get(`/api/meetings/${meetingId}`);
return response.data;
};

// 좋아요 상태 가져오기
export const fetchLikeStatus = async (meetingId: string) => {
const response = await authInstance.get(`/api/meetings/${meetingId}`);
return response.data;
};

// 프로필 이미지 가져오기
export const fetchProfileImage = async (nickname: string) => {
const response = await baseInstance.get(`/api/profile/${nickname}/`);
return response.data.profile_image_url;
};

// 참여 취소
export const deleteParticipation = async (meetingId: string) => {
await authInstance.post(`/api/meetings/member/delete/`, { meeting_uuid: meetingId });
};

// 좋아요 토글
export const toggleLikeApi = async (meetingId: string, isLiked: boolean) => {
if (isLiked) {
await authInstance.post(`/api/likes/delete/`, { uuid: meetingId });
} else {
await authInstance.post(`/api/likes/`, { uuid: meetingId });
}
};

// FE: Thunder - BE: Meeting 삭제하는 함수
export const deleteMeeting = async (meetingId: string) => {
await authInstance.post(`/api/meetings/delete/`, { meeting_uuid: meetingId });
};

// API 함수들을 객체로 묶어서 내보내기
const thunderIdApi = {
fetchMeeting,
fetchLikeStatus,
fetchProfileImage,
deleteParticipation,
toggleLikeApi,
deleteMeeting,
};

export default thunderIdApi;
16 changes: 16 additions & 0 deletions src/components/board/BoardBadge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';

interface BoardBadgeProps {
label: string;
type: 'other';
}

const BoardBadge: React.FC<BoardBadgeProps> = ({ label }) => {
return (
<span className="flex items-center rounded-md border-2 border-gray-200 bg-white px-2 py-1 text-sm text-black">
{label}
</span>
);
};

export default BoardBadge;
4 changes: 2 additions & 2 deletions src/components/board/BoardCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import { format, differenceInMinutes, differenceInHours } from 'date-fns';
import { ko } from 'date-fns/locale';
import Badge from '../thunder/Badge';
import BoardBadge from './BoardBadge';
import { LuDot } from 'react-icons/lu';

interface BoardCardProps {
Expand Down Expand Up @@ -75,7 +75,7 @@ const BoardCard: React.FC<BoardCardProps> = ({
<div className="ml-4 flex h-full grow flex-col justify-between gap-1">
<h2 className="line-clamp-2 text-[20px] font-medium xs:text-[16px]">{title}</h2>
<div className="flex gap-2">
<Badge label={category} />
<BoardBadge label={category} type="other" />
</div>
<p className="line-clamp-1 text-[16px] xs:text-[14px]">{content}</p>
<div className="flex items-center justify-between text-[#666666]">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ import ReactDOM from 'react-dom';
import { RxArrowLeft } from 'react-icons/rx';
import { motion, AnimatePresence } from 'framer-motion'; // AnimatePresence 추가

interface BoardCommentModalProps {
interface BoardIdCommentModalProps {
isOpen: boolean;
onClose: () => void;
title1: string;
title2: string;
children: React.ReactNode;
}

// BoardCommentModal 를 위한 컴포넌트.
// BoardIdCommentModal 를 위한 컴포넌트.

const BoardCommentModal: React.FC<BoardCommentModalProps> = ({ isOpen, title1, title2, children, onClose }) => {
const BoardIdCommentModal: React.FC<BoardIdCommentModalProps> = ({ isOpen, title1, title2, children, onClose }) => {
return ReactDOM.createPortal(
<AnimatePresence>
{isOpen && (
Expand All @@ -29,7 +29,7 @@ const BoardCommentModal: React.FC<BoardCommentModalProps> = ({ isOpen, title1, t
exit={{ y: '100vh' }}
transition={{ type: 'spring', stiffness: 300, damping: 30 }}>
<div className="flex items-center">
<button onClick={() => onClose()} className="flex items-center hover:text-gray-700" title="Close">
<button onClick={() => onClose()} className="flex items-center hover:text-gray-700" title="닫기">
<RxArrowLeft size={25} />
</button>
<div className="ml-4 text-xl font-semibold">{title1}</div>
Expand All @@ -44,4 +44,4 @@ const BoardCommentModal: React.FC<BoardCommentModalProps> = ({ isOpen, title1, t
);
};

export default BoardCommentModal;
export default BoardIdCommentModal;
85 changes: 85 additions & 0 deletions src/components/board/BoardIdCommentSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { motion } from 'framer-motion';
import BoardIdComments from '../board/BoardIdComments';
import React from 'react';
import { isValid } from 'date-fns';

// BoardIdCommentSection 컴포넌트의 props 인터페이스 정의
interface BoardIdCommentSectionProps {
comments: { id: number; is_host?: boolean; text?: string; timestamp?: string }[]; // 댓글 배열
profileImageUrl: string; // 프로필 이미지 URL
setCommentToEdit: (index: number | null) => void; // 편집할 댓글 설정
setEditCommentText: (text: string) => void; // 편집할 댓글 텍스트 설정
toggleBottomModal: () => void; // 하단 Modal 토글
commentsEndRef: React.RefObject<HTMLDivElement>; // 댓글 끝 부분 참조
message: string; // 현재 입력 메시지
setMessage: (message: string) => void; // 메시지 설정 함수
handleSendMessage: () => void; // 메시지 전송 처리
handleKeyPress: (e: React.KeyboardEvent<HTMLInputElement>) => void; // 키 입력 처리
toggleLike: () => void; // 좋아요 토글 함수
}

// BoardIdCommentSection 컴포넌트 정의
const BoardIdCommentSection = ({
comments,
profileImageUrl,
setCommentToEdit,
setEditCommentText,
toggleBottomModal,
commentsEndRef,
message,
setMessage,
handleSendMessage,
handleKeyPress,
toggleLike,
}: BoardIdCommentSectionProps) => (
<div className="relative">
{/* BoardIdComments 컴포넌트 렌더링 */}
<BoardIdComments
comments={comments.map((comment) => {
const date = new Date(comment.timestamp ?? '');
return {
...comment,
is_host: comment.is_host ?? false,
text: comment.text ?? '',
timestamp: isValid(date) ? date : new Date('Invalid Date'),
};
})}
profileImageUrl={profileImageUrl}
setCommentToEdit={setCommentToEdit}
setEditCommentText={setEditCommentText}
toggleBottomModal={toggleBottomModal}
commentsEndRef={commentsEndRef}
/>
{/* 좋아요 버튼, 댓글 입력창 스타일 정의*/}
<div className="flex w-full max-w-[1000px] items-center bg-white p-4">
{/* 좋아요 버튼 */}
<div className="mr-4 flex flex-col items-center">
<motion.img
src="/images/SocialDiningLike.svg"
alt="좋아요"
className="h-[30px] w-[30px] cursor-pointer"
onClick={toggleLike}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 1 }}
/>
</div>
{/* 댓글 입력창 */}
<div className="flex flex-1 items-center rounded-md border border-gray-300">
<input
type="text"
placeholder="메시지를 입력해주세요"
className="flex-1 rounded-l-md px-3 py-2 xs:w-[150px]"
value={message}
onChange={(e) => setMessage(e.target.value)}
onKeyDown={handleKeyPress}
/>
{/* 전송 버튼 */}
<button className="mr-2 p-2" onClick={handleSendMessage}>
<img src="/images/ThunderChatSend.svg" alt="Send" width={24} height={24} />
</button>
</div>
</div>
</div>
);

export default BoardIdCommentSection;
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { IoMdMore } from 'react-icons/io';
import { formatCreatedAt } from '../../utils/formatCreatedAt';

// 댓글 객체의 Interface 정의
interface Comment {
id: number;
text: string;
timestamp: Date;
nickname?: string;
profile_image_url?: string;
is_host: boolean;
}

interface BoardCommentsProps {
// BoardIdComments - Components props - Interface 정의
interface BoardIdCommentsProps {
comments: Comment[];
profileImageUrl: string;
setCommentToEdit: (index: number | null) => void;
Expand All @@ -19,8 +23,8 @@ interface BoardCommentsProps {
commentsEndRef: React.RefObject<HTMLDivElement>;
}

// BoardComments 를 위한 컴포넌트.
const BoardComments: React.FC<BoardCommentsProps> = ({
// BoardIdComments Components 정의
const BoardIdComments: React.FC<BoardIdCommentsProps> = ({
comments,
setCommentToEdit,
setEditCommentText,
Expand All @@ -29,24 +33,14 @@ const BoardComments: React.FC<BoardCommentsProps> = ({
}) => {
return (
<div className="mb-[72px] mt-[10px] flex flex-col items-center overflow-auto">
{/* 댓글 수 표시 */}
<div className="mb-[15px] w-full text-left text-sm text-black">댓글 {comments.length}</div>
{/* 댓글 목록 렌더링*/}
{comments.map((comment, index) => {
const now = new Date();
const commentTime = new Date(comment.timestamp);
const minutesDifference = Math.floor((now.getTime() - commentTime.getTime()) / 1000 / 60);

let timeDisplay;
if (minutesDifference < 1) {
timeDisplay = '방금 전';
} else if (minutesDifference < 60) {
timeDisplay = `${minutesDifference}분 전`;
} else if (minutesDifference < 1440) {
timeDisplay = `${Math.floor(minutesDifference / 60)}시간 전`;
} else {
timeDisplay = commentTime.toLocaleDateString();
}
const timeDisplay = formatCreatedAt(comment.timestamp.toString());
return (
<div key={index} className="flex w-full items-center border-b border-gray-300 p-2">
{/* 프로필 이미지 링크 */}
<Link to={`/profile/${comment.nickname}`}>
<img
src={comment.profile_image_url || '/images/anonymous_avatars.svg'}
Expand All @@ -58,15 +52,18 @@ const BoardComments: React.FC<BoardCommentsProps> = ({
/>
</Link>
<div>
{/* 닉네임 링크 */}
<Link to={`/profile/${comment.nickname}`} className="font-normal">
{comment.nickname}
</Link>
{/* 댓글 작성 시간 */}
<div className="text-sm text-gray-500">{timeDisplay}</div>
{/* 댓글 내용 */}
<div>{comment.text}</div>
{/* <div className="text-xs text-gray-500">댓글 ID: {comment.id}</div> */}
</div>
{/* 더보기 버튼 */}
<button
className="mb-[24px] ml-auto p-2 text-gray-400"
className={`mb-[24px] ml-auto p-2 text-gray-400`}
title="더보기"
onClick={() => {
setCommentToEdit(index);
Expand All @@ -78,9 +75,10 @@ const BoardComments: React.FC<BoardCommentsProps> = ({
</div>
);
})}
{/* 댓글 목록 끝 참조하는 div */}
<div ref={commentsEndRef} />
</div>
);
};

export default BoardComments;
export default BoardIdComments;
Loading

0 comments on commit a1cf8e3

Please sign in to comment.