Skip to content

Commit

Permalink
Merge pull request #2 from boostcampwm-2024/Refactor/1
Browse files Browse the repository at this point in the history
[Refactor] 코딩 컨벤션 재정의 및 적용
  • Loading branch information
zero0205 authored Jan 14, 2025
2 parents f1e9a5d + 6e8c7d9 commit f4c7fc0
Show file tree
Hide file tree
Showing 69 changed files with 1,520 additions and 1,027 deletions.
9 changes: 9 additions & 0 deletions apps/client/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# shadcn/ui 컴포넌트 폴더 무시
src/components/ui/*

# node_modules는 기본적으로 무시되지만, 명시적으로 추가할 수도 있습니다
node_modules/

# 다른 무시하고 싶은 파일/폴더들
dist/
build/
44 changes: 35 additions & 9 deletions apps/client/.eslintrc
Original file line number Diff line number Diff line change
@@ -1,35 +1,45 @@
{
"parser": "@typescript-eslint/parser",

"parserOptions": {
"project": ["./apps/client/tsconfig.json"],
"project": ["./tsconfig.json"],
"ecmaVersion": 12,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},

"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],

"extends": ["airbnb", "airbnb/hooks", "plugin:@typescript-eslint/recommended", "prettier"],

"settings": {
"react": {
"version": "detect"
}
},

"plugins": ["prettier"],

"rules": {
// React 관련 규칙
"react/react-in-jsx-scope": "off",
"react/no-unescaped-entities": "off",
"react/prop-types": "off",
"react-hooks/exhaustive-deps": "warn",
"react/jsx-filename-extension": [
"warn",
{
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
],
"react/require-default-props": "off",
"react/jsx-props-no-spreading": "off",

// TypeScript 관련 규칙
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-unused-vars": [
"error",
Expand All @@ -38,6 +48,22 @@
"varsIgnorePattern": "^_", // _ 로 시작하는 변수는 무시
"ignoreRestSiblings": true
}
],

// Import/Export 관련 규칙
"import/no-unresolved": "off",
"import/extensions": ["off"],
"import/prefer-default-export": "off",

// 접근성 관련 규칙
"jsx-a11y/media-has-caption": "off",

// 기타 규칙
"no-param-reassign": [
"warn",
{
"props": false
}
]
}
}
7 changes: 7 additions & 0 deletions apps/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,24 @@
"@types/node": "^20.3.1",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@typescript-eslint/eslint-plugin": "^7.18.0",
"@typescript-eslint/parser": "^7.18.0",
"@vitejs/plugin-react-swc": "^3.5.0",
"autoprefixer": "^10.4.20",
"eslint": "*",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^18.0.0",
"eslint-config-prettier": "*",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-prettier": "*",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.14",
"postcss": "^8.4.47",
"prettier": "*",
"tailwindcss": "^3.4.14",
"typescript": "*",
"vite": "^5.4.10"
}
}
2 changes: 1 addition & 1 deletion apps/client/src/Router.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { createBrowserRouter } from 'react-router-dom';
import App from './App';
import Home from '@pages/Home';
import Profile from '@pages/Profile';
import Live from '@pages/Live';
import Broadcast from '@pages/Broadcast';
import Auth from '@pages/Auth';
import Record from '@pages/Record';
import App from './App';
import ProtectedRoute from './ProtectedRoute';

const routerOptions = {
Expand Down
6 changes: 3 additions & 3 deletions apps/client/src/components/ChatContainer/ChatEndModal.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import Modal from '@components/Modal';
import { useNavigate } from 'react-router-dom';

interface ChatEndModalProps {
type ChatEndModalProps = {
setShowModal: (b: boolean) => void;
}
};

function ChatEndModal({ setShowModal }: ChatEndModalProps) {
const navigate = useNavigate();
Expand All @@ -17,7 +17,7 @@ function ChatEndModal({ setShowModal }: ChatEndModalProps) {
<Modal modalClassName="h-32 w-1/3" setShowModal={setShowModal}>
<div className="flex flex-col items-center gap-3">
<p className="text-text-strong text-display-medium16">방송이 종료되었습니다.</p>
<button onClick={handleClick} className="underline">
<button type="button" onClick={handleClick} className="underline">
홈으로 이동하기
</button>
</div>
Expand Down
84 changes: 47 additions & 37 deletions apps/client/src/components/ChatContainer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
import { useState, useEffect, useRef, useContext } from 'react';
import { Card, CardHeader, CardTitle, CardContent, CardFooter } from '@components/ui/card';
import { Input } from '@components/ui/input';
import { SmileIcon } from '@/components/Icons';
import { useSocket } from '@hooks/useSocket';
import ErrorCharacter from '@components/ErrorCharacter';
import { AuthContext } from '@/contexts/AuthContext';
import { createPortal } from 'react-dom';
import { AuthContext } from '@/contexts/AuthContext';
import { SmileIcon } from '@/components/Icons';
import ChatEndModal from './ChatEndModal';

interface Chat {
type Chat = {
chatId?: string;
camperId: string;
name: string;
message: string;
}
};

const chatServerUrl = import.meta.env.VITE_CHAT_SERVER_URL;

const ChatContainer = ({ roomId, isProducer }: { roomId: string; isProducer: boolean }) => {
function ChatContainer({ roomId, isProducer }: { roomId: string; isProducer: boolean }) {
const { isLoggedIn } = useContext(AuthContext);
// 채팅 방 입장
const [isJoinedRoom, setIsJoinedRoom] = useState(false);
const isJoinedRoomRef = useRef(false);
// 채팅 전송
const { socket, isConnected, socketError } = useSocket(chatServerUrl);
const [chattings, setChattings] = useState<Chat[]>([]);
Expand All @@ -35,57 +36,65 @@ const ChatContainer = ({ roomId, isProducer }: { roomId: string; isProducer: boo
// 채팅 종료
const [showModal, setShowModal] = useState(false);

const setUpRoom = async (isProducer: boolean) => {
if (isProducer) {
socket?.emit('createRoom', { roomId: roomId });
} else {
// 채팅방 입장
socket?.emit('joinRoom', { roomId: roomId }, () => {});
// 채팅방 종료 이벤트
socket?.on('chatClosed', () => {
setShowModal(true);
});
}
setIsJoinedRoom(true);
};

const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
};

const hanldeKeyDownEnter = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (isComposing) return;
if (e.key === 'Enter') {
handleSendChat();
}
};

const handleSendChat = () => {
if (inputValue.trim() && socket) {
socket.emit('chat', { roomId: roomId, message: inputValue });
socket.emit('chat', { roomId, message: inputValue });
}
setInputValue('');
};

const handleReceiveChat = (response: Chat) => {
const { camperId, name, message } = response;
setChattings(prev => [...prev, { camperId, name, message }]);
const hanldeKeyDownEnter = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (isComposing) return;
if (e.key === 'Enter') {
handleSendChat();
}
};

const handleClickEmoticon = () => {
alert('구현 예정');
};
// 채팅방 입장
useEffect(() => {
if (!isConnected || !socket || !roomId || isJoinedRoomRef.current) return;

const setUpRoom = async () => {
if (isProducer) {
socket?.emit('createRoom', { roomId });
} else {
// 채팅방 입장
socket?.emit('joinRoom', { roomId }, () => {});
// 채팅방 종료 이벤트
}
isJoinedRoomRef.current = true;
};
setUpRoom();
}, [isConnected, socket, roomId, isProducer]);

// 채팅 이벤트 등록/해제
useEffect(() => {
if (!isConnected || !socket || !roomId || isJoinedRoom) return;
setUpRoom(isProducer);
if (!socket || !isConnected) return () => {};

const handleReceiveChat = (response: Chat) => {
const { camperId, name, message } = response;
setChattings(prev => [...prev, { chatId: `${Date.now()}-${camperId}`, camperId, name, message }]);
};

const handleChatClosed = () => {
setShowModal(true);
};

socket?.on('chat', handleReceiveChat);
socket?.on('chatClosed', handleChatClosed);

return () => {
socket?.off('chat', handleReceiveChat);
socket?.off('chatClosed');
};
}, [isConnected, roomId, socket]);
}, [socket, isConnected]);

// 자동 스크롤
useEffect(() => {
Expand All @@ -106,8 +115,8 @@ const ChatContainer = ({ roomId, isProducer }: { roomId: string; isProducer: boo
<>
<CardContent ref={scrollAreaRef} className="flex flex-1 px-6 pb-2 overflow-y-auto flex-col-reverse">
<div className="w-full flex flex-col space-y-1">
{chattings.map((chat, index) => (
<div key={index}>
{chattings.map((chat: Chat) => (
<div key={chat.chatId}>
<span className="font-medium text-display-medium16 text-text-weak">{chat.camperId} </span>
<span className="font-medium text-display-medium14 text-text-strong">{chat.message}</span>
</div>
Expand All @@ -128,6 +137,7 @@ const ChatContainer = ({ roomId, isProducer }: { roomId: string; isProducer: boo
disabled={!isLoggedIn}
/>
<button
type="button"
onClick={handleClickEmoticon}
className="ml-2 p-2 rounded-full text-text-default"
disabled={!isLoggedIn}
Expand All @@ -142,6 +152,6 @@ const ChatContainer = ({ roomId, isProducer }: { roomId: string; isProducer: boo
{showModal && createPortal(<ChatEndModal setShowModal={setShowModal} />, document.body)}
</>
);
};
}

export default ChatContainer;
8 changes: 4 additions & 4 deletions apps/client/src/components/ErrorCharacter/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
interface ErrorCharacterProps {
type ErrorCharacterProps = {
size?: number;
message?: string;
}
};

const ErrorCharacter = ({ size = 300, message = 'Error' }: ErrorCharacterProps): JSX.Element => {
function ErrorCharacter({ size = 300, message = 'Error' }: ErrorCharacterProps): JSX.Element {
return (
<div style={{ width: size, height: size }} className="flex flex-col items-center">
<svg viewBox="0 0 200 200" className="w-full h-full" xmlns="http://www.w3.org/2000/svg">
Expand Down Expand Up @@ -82,6 +82,6 @@ const ErrorCharacter = ({ size = 300, message = 'Error' }: ErrorCharacterProps):
<p className="text-[#EF4444] font-bold mt-4">{message}</p>
</div>
);
};
}

export default ErrorCharacter;
6 changes: 4 additions & 2 deletions apps/client/src/components/Header/LogInButton.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useState } from 'react';
import WelcomeCharacter from '@components/WelcomeCharacter';
import { useAuth } from '@/hooks/useAuth';
import { Button } from '@components/ui/button';
import { createPortal } from 'react-dom';
import Modal from '@components/Modal';
import { GithubIcon, GoogleIcon } from '@components/Icons';
import { useAuth } from '@/hooks/useAuth';
import axiosInstance from '@/services/axios';

function LogInButton() {
Expand Down Expand Up @@ -38,6 +38,7 @@ function LogInButton() {
</div>
<div className="flex flex-row md:flex-col h-full justify-around items-center gap-3 p-4">
<button
type="button"
onClick={() => {
requestLogIn('github');
}}
Expand All @@ -49,6 +50,7 @@ function LogInButton() {
</span>
</button>
<button
type="button"
onClick={() => {
requestLogIn('google');
}}
Expand All @@ -59,7 +61,7 @@ function LogInButton() {
Google로 로그인하기
</span>
</button>
<button className="border-none underline" onClick={handleGuestLogIn}>
<button type="button" className="border-none underline" onClick={handleGuestLogIn}>
게스트로 로그인하기
</button>
</div>
Expand Down
6 changes: 3 additions & 3 deletions apps/client/src/components/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { useContext, useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Character, Logo } from '@components/Icons';
import { Avatar, AvatarFallback, AvatarImage } from '@components/ui/avatar';
import { cn } from '@utils/utils';
import { AuthContext } from '@/contexts/AuthContext';
import axiosInstance from '@/services/axios';
import { cn } from '@utils/utils';
import LogInButton from './LogInButton';
import { Button } from '../ui/button';
import { useAuth } from '@/hooks/useAuth';
Expand Down Expand Up @@ -72,10 +72,10 @@ function Header() {

return (
<header className="fixed top-0 left-0 h-fit w-full px-10 py-3 flex justify-between z-10 bg-surface-default">
<div className="flex flex-row gap-2 hover:cursor-pointer" onClick={handleLogoClick}>
<button type="button" className="flex flex-row gap-2 hover:cursor-pointer" onClick={handleLogoClick}>
<Character size={48} />
<Logo width={109} height={50} className="text-text-strong" />
</div>
</button>
<div className="flex items-center">
{isLoggedIn ? (
<div className="flex gap-2 items-center">
Expand Down
Loading

0 comments on commit f4c7fc0

Please sign in to comment.