diff --git a/backend/chatroom-service/src/main/java/com/tadak/chatroomservice/global/CorsConfig.java b/backend/chatroom-service/src/main/java/com/tadak/chatroomservice/global/CorsConfig.java new file mode 100644 index 0000000..28824c2 --- /dev/null +++ b/backend/chatroom-service/src/main/java/com/tadak/chatroomservice/global/CorsConfig.java @@ -0,0 +1,2 @@ +package com.tadak.chatroomservice.global;public class CorsConfig { +} diff --git a/frontend/src/assets/Close.svg b/frontend/src/assets/Close.svg new file mode 100644 index 0000000..6bb2ecf --- /dev/null +++ b/frontend/src/assets/Close.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/src/components/InputForm.tsx b/frontend/src/components/InputForm.tsx deleted file mode 100644 index 7769c70..0000000 --- a/frontend/src/components/InputForm.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import EmailSVG from "../assets/Email.svg" -import UserSVG from "../assets/User.svg" -import PasswordSVG from "../assets/Password.svg" - -import styled from "@emotion/styled"; - - -function ChangeSVG(imgSVG: string){ - switch(imgSVG){ - case "Email": - return EmailSVG; - case "User": - return UserSVG; - case "Password": - return PasswordSVG; - } -} - -export const InputForm = ({ type, name, value, onChange, placeholder, title, imgSVG, ...rest }) => { - return ( - - {title} - - - - - - - - ); -}; - -const InputFormWrapper = styled.section` - p { - font-size: var(--font-size-xs); - margin: 0; - padding: 1rem 0.5rem 0.3rem; - } -` - -const InputFormContainer = styled.div` - height: 44px; - display: flex; - gap: 16px; - align-items: center; - border-radius: 10px; - padding: 0 11px; - - picture { - - } - - input { - font-size: var(--font-size-xs); - border: none; - outline: none; - } - - border: solid 1px var(--color-crusta) -` \ No newline at end of file diff --git a/frontend/src/components/auth/InputForm.tsx b/frontend/src/components/auth/InputForm.tsx new file mode 100644 index 0000000..75e11d4 --- /dev/null +++ b/frontend/src/components/auth/InputForm.tsx @@ -0,0 +1,88 @@ +import EmailSVG from "../../assets/Email.svg" +import UserSVG from "../../assets/User.svg" +import PasswordSVG from "../../assets/Password.svg" + +import styled from "@emotion/styled"; + +interface InputFormProps { + type: string; + name: string; + value: string; + onChange: (event: React.ChangeEvent) => void; + placeholder: string; + title: string; + imgSVG: string; +} + +function ChangeSVG(imgSVG: string){ + switch(imgSVG){ + case "Email": + return EmailSVG; + case "User": + return UserSVG; + case "Password": + return PasswordSVG; + } +} + +export const InputForm = ({ type, name, value, onChange, title, imgSVG, ...rest }: InputFormProps) => { + return ( + + {title} + + {imgSVG && ( + + + + )} + {type === 'number' ? ( + + {[1, 2, 3, 4, 5, 6].map((option) => ( + + {option} 명 + + ))} + + ) : ( + + )} + + + ); +}; + +const InputFormWrapper = styled.section` + p { + font-size: var(--font-size-xs); + margin: 0; + padding: 1rem 0.5rem 0.3rem; + } +` + +const InputFormContainer = styled.div` + height: 44px; + display: flex; + gap: 16px; + align-items: center; + border-radius: 10px; + padding: 0 11px; + + picture { + + } + + input { + font-size: var(--font-size-xs); + border: none; + outline: none; + } + + border: solid 1px var(--color-crusta) +` + +const StyledSelect = styled.select` + width: 100%; + border: none; + padding: 8px; + outline: none; +`; diff --git a/frontend/src/components/auth/auth.tsx b/frontend/src/components/auth/auth.tsx deleted file mode 100644 index e69de29..0000000 diff --git a/frontend/src/components/chattingRoomList/ChattingRoom.tsx b/frontend/src/components/chattingRoomList/ChattingRoom.tsx deleted file mode 100644 index 748fc16..0000000 --- a/frontend/src/components/chattingRoomList/ChattingRoom.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; -import { useEffect } from 'react'; -// import { useNotification } from 'web-notification'; -import axios from "axios" - -const getImage = async () => { - try { - const response = await axios.get('/thumbnails'); - const data = response.data; - return data.imageUrl; - } catch (error) { - console.error('Error fetching image:', error); - } -}; - - -export const ChattingRoom = () =>{ - - // 에러가 발생하면 react-query update를 하기 - const { isLoading, data, isError } = useQuery({ - queryKey: ["chattingRoomImage"], - queryFn: getImage, - staleTime: 5 * 1000 - }); - - if (isLoading) { - return Loading...; - } - - if (isError) { - return 에러; - } - - return( - - - {/* 이미지 썸네일 */} - 썸네일 - - {data && } - - - {/* 채팅룸 설명 */} - - 방제목 - 즐겨찾기 - 방설명 - #카테고리 - - - - ) -} \ No newline at end of file diff --git a/frontend/src/components/chattingRoomList/ChattingRoomList.tsx b/frontend/src/components/chattingRoomList/ChattingRoomList.tsx deleted file mode 100644 index 0c215c6..0000000 --- a/frontend/src/components/chattingRoomList/ChattingRoomList.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { ChattingRoom } from "./ChattingRoom"; -import styled from '@emotion/styled'; - -const ChattingRoomList: React.FC = () => { - return ( - - - This is ChattingRoomList Component! - - {/* Grid */} - - {Array.from({ length: 16 }).map((_, index) => ( - - ))} - - - - - ) -}; - -export default ChattingRoomList; - - -export const ChattingRoomListGridContainer = styled.div` - display: grid; - grid-template-columns: repeat(4, 1fr); - gap: 16px; -`; \ No newline at end of file diff --git a/frontend/src/components/Button.tsx b/frontend/src/components/common/Button.tsx similarity index 97% rename from frontend/src/components/Button.tsx rename to frontend/src/components/common/Button.tsx index 2c4e830..86ca15d 100644 --- a/frontend/src/components/Button.tsx +++ b/frontend/src/components/common/Button.tsx @@ -27,6 +27,7 @@ const StyledButton = styled.button` border-radius: 10px; cursor: pointer; transition: 0.3s ease; + align-items: center; &:hover { background-color: #000000; diff --git a/frontend/src/components/Toast.tsx b/frontend/src/components/common/Toast.tsx similarity index 100% rename from frontend/src/components/Toast.tsx rename to frontend/src/components/common/Toast.tsx diff --git a/frontend/src/components/roomPreview/CreateRoomPreview.tsx b/frontend/src/components/roomPreview/CreateRoomPreview.tsx new file mode 100644 index 0000000..016c60d --- /dev/null +++ b/frontend/src/components/roomPreview/CreateRoomPreview.tsx @@ -0,0 +1,88 @@ +import React from 'react'; +import { InputForm } from '../../components/auth/InputForm'; +import axios from 'axios'; +import styled from "@emotion/styled" +import Close from "../../assets/Close.svg" +import { Button } from '../common/Button'; +import { RoomInfo } from '../../stores/useRoomStore'; + +interface CreateRoomPreviewProps { + onClose: () => void; + onAddRoom: () => void; + roominfo: RoomInfo; + username: string; + handleInputChange: (e: React.ChangeEvent) => void; + newRoom: { roomName: string; description:string; owner:string; category: string; capacity: number; }; +} + +const CreateRoomPreview: React.FC = ({ onClose, onAddRoom, roominfo, username, handleInputChange }) => { + const handleAddRoomClick = async () => { + try { + const roomWithOwner = { ...roominfo, owner: username }; + console.log(roomWithOwner); + await axios.post('http://localhost:8002/chatroom-service/create', roomWithOwner); + + onAddRoom(); + onClose(); + } catch (error) { + console.error('Error creating room:', error); + } + }; + + const handleCloseClick = () => { + onClose(); + } + + return ( + + + + + Create Room + + + + + + + + ); +}; + +export default CreateRoomPreview; + +const CreateRoomPreviewWrapper = styled.main` + z-index:1000; + position: fixed; + top: 50%; + left: 30%; + transform: translate(-50%, -50%); + display: flex; + flex-direction: column; + gap: 0.5rem; + flex-shrink: 0; + padding: 2rem; + border: solid 1px var(--color-wildsand); + border-radius: 0.3125rem; + background: var(--color-white); + + h1 { + color: #000; + text-align: center; + font-size: 1rem; + font-weight: 400; + } +` + +const StyledCloseButton = styled.button` + display: flex; + margin-left: auto; + border: none; + background: none; +`; \ No newline at end of file diff --git a/frontend/src/components/roomPreview/RoomPreview.tsx b/frontend/src/components/roomPreview/RoomPreview.tsx new file mode 100644 index 0000000..5878674 --- /dev/null +++ b/frontend/src/components/roomPreview/RoomPreview.tsx @@ -0,0 +1,51 @@ +import { useQuery } from '@tanstack/react-query'; +import { useEffect } from 'react'; +// import { useNotification } from 'web-notification'; +import axios from "axios" +import { GetAllRoomsApis } from '../../hooks/useGetAllRoom'; +import { useNavigate } from 'react-router-dom'; + + +export const RoomPreview = ({roomId, roomName, description, hashtag}:{roomId:string, roomName:string, description:string, hashtag: string}) =>{ + + const navigate = useNavigate(); + + // 에러가 발생하면 react-query update를 하기 + const { isLoading, data, isError } = useQuery({ + queryKey: ["GetAllRoomsApis"], + queryFn: GetAllRoomsApis.getAllRooms, + staleTime: 5 * 1000 + }); + const thumbnailUrl = data?.thumbnailUrl; + + if (isLoading) { + return Loading...; + } + + if (isError) { + return 에러; + } + + const handlieRoomClick = () => { + navigate(`/chatroom/${roomId.toString()}`); + } + + return( + + + {/* 이미지 썸네일 */} + + {thumbnailUrl && } + + + {/* 채팅룸 설명 */} + + {roomName} + 즐겨찾기 + {description} + {hashtag} + + + + ) +} \ No newline at end of file diff --git a/frontend/src/components/roomPreview/RoomPreviewList.tsx b/frontend/src/components/roomPreview/RoomPreviewList.tsx new file mode 100644 index 0000000..05448e2 --- /dev/null +++ b/frontend/src/components/roomPreview/RoomPreviewList.tsx @@ -0,0 +1,45 @@ +import { RoomPreview } from "./RoomPreview"; +import styled from '@emotion/styled'; +import { RoomsInfo } from '../../stores/useRoomStore'; + +const RoomPreviewList = () => { + const roomsInfo = RoomsInfo.getState(); + console.log(roomsInfo.rooms); + + return ( + + + + {/* Grid */} + + {roomsInfo.rooms.map((item, index) => ( + + ))} + + + + + ) +}; + +export default RoomPreviewList; + + +const RoomPreviewListWrapper = styled.main` + +` + +const RoomPreviewListSection = styled.section` +` + +export const ChattingRoomListGridContainer = styled.div` + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 16px; +`; \ No newline at end of file diff --git a/frontend/src/components/Favorite.tsx b/frontend/src/components/welcome/Favorite.tsx similarity index 100% rename from frontend/src/components/Favorite.tsx rename to frontend/src/components/welcome/Favorite.tsx diff --git a/frontend/src/components/Search.tsx b/frontend/src/components/welcome/Search.tsx similarity index 95% rename from frontend/src/components/Search.tsx rename to frontend/src/components/welcome/Search.tsx index 124fd1f..5bc154a 100644 --- a/frontend/src/components/Search.tsx +++ b/frontend/src/components/welcome/Search.tsx @@ -1,5 +1,5 @@ import styled from '@emotion/styled'; -import SearchSVG from "../assets/Search.svg" +import SearchSVG from "../../assets/Search.svg" import { useState } from "react" export const Search = ()=>{ diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/welcome/Sidebar.tsx similarity index 94% rename from frontend/src/components/Sidebar.tsx rename to frontend/src/components/welcome/Sidebar.tsx index ba09e72..3ab2ff8 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/welcome/Sidebar.tsx @@ -1,8 +1,8 @@ import styled from '@emotion/styled'; -import Home from "../assets/Home.svg" -import Create from "../assets/Create.svg" -import Star from "../assets/Star.svg" -import Logout from "../assets/Logout.svg" +import Home from "../../assets/Home.svg" +import Create from "../../assets/Create.svg" +import Star from "../../assets/Star.svg" +import Logout from "../../assets/Logout.svg" interface SidebarProps{ top: React.ReactNode; @@ -17,7 +17,6 @@ interface SidebarItemProps { } - export const Sidebar ={ wrapper: ({ top, bottom }: SidebarProps) => ( diff --git a/frontend/src/hooks/useAuthQuery.ts b/frontend/src/hooks/useAuthQuery.ts index 23f419b..d11b78c 100644 --- a/frontend/src/hooks/useAuthQuery.ts +++ b/frontend/src/hooks/useAuthQuery.ts @@ -66,12 +66,10 @@ export const AuthApis = { signin: async (userInfo:UserInfo) => { - try { const response = await AuthApis.instance.post('/login', { email: userInfo.email, password: userInfo.password, }); - const data = response.data; const rawAccessToken = response.headers.get('Accesstoken'); const rawRefreshToken = response.headers.get('RefreshToken'); @@ -84,10 +82,7 @@ export const AuthApis = { localStorage.setItem('Accesstoken', Accesstoken); localStorage.setItem('Refreshtoken', Refreshtoken); - return data; - } catch (error) { - return null; - } + return response; }, //refreshToken diff --git a/frontend/src/hooks/useGetAllRoom.ts b/frontend/src/hooks/useGetAllRoom.ts new file mode 100644 index 0000000..6ecf15b --- /dev/null +++ b/frontend/src/hooks/useGetAllRoom.ts @@ -0,0 +1,23 @@ +import axios from 'axios'; +import { RoomsInfo } from '../stores/useRoomStore'; +import { useStore } from 'zustand'; + +export const GetAllRoomsApis = { + instance: axios.create({ + baseURL: 'http://localhost:8002/chat-service/', + withCredentials: true, + }), + + getAllRooms: async () => { + const roomsInfo = RoomsInfo.getState(); + + try { + const res = await axios.get('http://localhost:8002/chatroom-service/rooms'); + roomsInfo.setRooms(res.data); + return res.data; + } catch (error) { + console.error('Error fetching rooms:', error); + throw error; + } + }, +}; diff --git a/frontend/src/pages/ChattingListPage.tsx b/frontend/src/pages/ChattingListPage.tsx index d63266a..7d5b781 100644 --- a/frontend/src/pages/ChattingListPage.tsx +++ b/frontend/src/pages/ChattingListPage.tsx @@ -1,4 +1,4 @@ -import ChattingRoomList from "../components/chattingRoomList/ChattingRoomList"; +import ChattingRoomList from "../components/roomPreview/RoomPreviewList"; const ChattingList: React.FC = () => { diff --git a/frontend/src/pages/SigninPage.tsx b/frontend/src/pages/SigninPage.tsx index 5c6d7ea..b22af2a 100644 --- a/frontend/src/pages/SigninPage.tsx +++ b/frontend/src/pages/SigninPage.tsx @@ -1,7 +1,7 @@ import { useState } from "react"; import { useNavigate } from "react-router-dom"; -import { InputForm } from "../components/InputForm"; -import { Button } from "../components/Button"; +import { InputForm } from "../components/auth/InputForm"; +import { Button } from "../components/common/Button"; import { NaverLoginButton } from "../components/auth/NaverLoginButton"; import { useStore } from "zustand"; import { UserInfoStore } from "../stores/UserInfoStore"; @@ -9,8 +9,7 @@ import { AuthApis } from "../hooks/useAuthQuery"; import styled from "@emotion/styled" import LogoSVG from "../assets/Logo.svg" import TadakTadakSVG from "../assets/TadakTadak.svg" -import axios from "axios"; -import Toast from "../components/Toast"; +import Toast from "../components/common/Toast"; const SigninPage = () => { const navigate = useNavigate(); @@ -30,10 +29,12 @@ const SigninPage = () => { async function onButtonClick (action:string) { switch(action){ case "onSignin": - console.log("button 클릭") - const data = await AuthApis.signin(userInfo); - console.log(data); - if (data === null) { + const response = await AuthApis.signin(userInfo); + console.log("button 클릭", response) + if ( response.headers.accesstoken) { + navigate("/"); + } + else{ setToast((prev) => { console.log("prev:", prev); // 토스트 알림 초기화 @@ -41,12 +42,10 @@ const SigninPage = () => { setToast(false); }, 10000); - return true; - })} - else{ - navigate("/"); - }break; - case "onSignup": + return true; + })} + break; + case "onSignup": navigate("/signup") break; default: diff --git a/frontend/src/pages/SignupPage.tsx b/frontend/src/pages/SignupPage.tsx index f2f7db6..9761da6 100644 --- a/frontend/src/pages/SignupPage.tsx +++ b/frontend/src/pages/SignupPage.tsx @@ -1,7 +1,7 @@ import { useEffect, useState, useMemo } from "react"; import { useNavigate } from "react-router-dom"; -import { InputForm } from "../components/InputForm"; -import { Button } from "../components/Button"; +import { InputForm } from "../components/auth/InputForm"; +import { Button } from "../components/common/Button"; import { useStore } from "zustand"; import { UserInfoStore } from "../stores/UserInfoStore"; import styled from '@emotion/styled'; diff --git a/frontend/src/pages/WelcomePage.tsx b/frontend/src/pages/WelcomePage.tsx index 7fa7ebb..b419173 100644 --- a/frontend/src/pages/WelcomePage.tsx +++ b/frontend/src/pages/WelcomePage.tsx @@ -1,20 +1,37 @@ -import { Sidebar } from "../components/Sidebar"; -import { Search } from "../components/Search"; -import { Favorite } from "../components/Favorite"; +import { Sidebar } from "../components/welcome/Sidebar"; +import { Search } from "../components/welcome/Search"; +import { Favorite } from "../components/welcome/Favorite"; import Logo from "../assets/Logo.svg" -import { useState } from "react"; +import { useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; -import { Container, Wrapper, SideWrapper } from "../styles/Layout"; +import { Container, Wrapper, SideWrapper, FlexCenterWrapper } from "../styles/Layout"; import styled from '@emotion/styled'; import { UserInfoStore } from "../stores/UserInfoStore"; +import { RoomInfo, RoomsInfo } from "../stores/useRoomStore" import { useStore } from "zustand" +import RoomPreviewList from "../components/roomPreview/RoomPreviewList"; +import CreateRoomPreview from "../components/roomPreview/CreateRoomPreview"; +import { getUserData } from "../hooks/react-query/useUserData"; +import { GetAllRoomsApis } from "../hooks/useGetAllRoom" const WelcomePage = () => { const [Logintext, setLoginText] = useState("Login"); + const [CreateRoom, setCreateRoom] = useState(false); const userinfo = useStore(UserInfoStore); + const roominfo = useStore(RoomInfo); const navigate = useNavigate(); + const handleCreateRoom= () =>{ + setCreateRoom(true); + } + + const handleInputChange = (e: React.ChangeEvent) => { + const { name, value } = e.target; + roominfo.update(name, value); + console.log(roominfo); + }; + const handleLoginClick = () => { if (Logintext === "Login") { navigate("/signin"); @@ -23,6 +40,39 @@ const WelcomePage = () => { } }; + // username 불러오기 + useEffect(() => { + const fetchData = async () => { + try { + const data = await getUserData(); + userinfo.updateUsername(data.username); + } catch (error) { + console.error(error); + } + }; + + fetchData(); + }, []); + + + useEffect(() => { + const fetchData = async () => { + try { + const res = await GetAllRoomsApis.getAllRooms(); + } catch (error) { + console.error('Error fetching rooms:', error); + } + }; + + fetchData(); + + const intervalId = setInterval(() => { + fetchData(); + }, 10000); + + return () => clearInterval(intervalId); + }, []); + return ( @@ -39,7 +89,9 @@ const WelcomePage = () => { TadakTadak - {userinfo.username || '유저명'} + + {/* API로 가져오게 변경필요 => 새로고침시 사라져서 Create에도 문제 */} + {userinfo.username || '유저명'} {/* Search */} @@ -48,7 +100,7 @@ const WelcomePage = () => { {/* Menu */} - + @@ -64,7 +116,12 @@ const WelcomePage = () => { bottom={} /> - + + + + {CreateRoom && setCreateRoom(false)}handleInputChange={handleInputChange} username={userinfo.username} roominfo={roominfo} />} + + ); }; @@ -82,6 +139,13 @@ const UsernameText = styled.div` padding: 0px 16px; `; +const SideContainer = styled.section` +` + const LogoDiv = styled.div` padding: 12px 16px 0; -` \ No newline at end of file +`; + +const MainContainer = styled.div` + ${FlexCenterWrapper} +`; \ No newline at end of file diff --git a/frontend/src/stores/useRoomStore.ts b/frontend/src/stores/useRoomStore.ts new file mode 100644 index 0000000..41babf9 --- /dev/null +++ b/frontend/src/stores/useRoomStore.ts @@ -0,0 +1,66 @@ +import { create } from 'zustand'; +import { devtools, persist } from "zustand/middleware"; + +export interface RoomInfo { + roomId: string; + roomName: string; + description: string; + participation : string; + capacity: number; + owner: string; + hashtag: string; + + updateRoomId: (roomId: RoomInfo['roomId']) => void; + updateRoomName: (roomName: RoomInfo['roomName']) => void; + updateDescription: (description: RoomInfo['description']) => void; + updateParticipationn: (participation: RoomInfo['participation']) => void; + updateCapacity: (capacity: RoomInfo['capacity']) => void; + updateOwner: (owner: RoomInfo['owner']) => void; + updateHashtag: (hashtag: string) => void; + + update: (field: string, value: string) => void; +} + +interface RoomsInfo { + rooms: RoomInfo[]; + setRooms: (rooms: RoomsInfo['rooms']) => void; +} + +const createRoomStore = (set) => ({ + roomId: '', + roomName: '', + description: '', + participation: '', + capacity: 1, + owner: '', + hashtag: '', + updateRoomId: (roomId: string) => set({ roomId }), + updateRoomName: (roomName: string) => set({ roomName }), + updateDescription: (description: string) => set({ description }), + updateParticipationn: (participation: string) => set({ participation }), + updateCapacity: (capacity: number) => set({ capacity }), + updateOwner: (owner: string) => set({ owner }), + updateHashtag: (hashtag: string) => set({ hashtag }), + + update: (field, value) => set({ [field]: value }), +}); + +let roomInfoTemp; +let roomsInfoTemp; + +const createRoomsStore = (set) => ({ + rooms: [] as RoomInfo[], + setRooms: (rooms: RoomInfo[]) => set({ rooms }), +}); + +//devtools +if (import.meta.env.DEV) { + roomInfoTemp = create()(devtools(createRoomStore, { name: 'roomInfo' })); +} else { + roomInfoTemp = create()(createRoomStore); +} + +roomsInfoTemp = create()(createRoomsStore); + +export const RoomInfo = roomInfoTemp; +export const RoomsInfo = roomsInfoTemp; \ No newline at end of file diff --git a/frontend/src/styles/Layout.ts b/frontend/src/styles/Layout.ts index 2b5f6df..7d751bc 100644 --- a/frontend/src/styles/Layout.ts +++ b/frontend/src/styles/Layout.ts @@ -24,16 +24,16 @@ export const SideWrapper = styled.div` width: 11.5rem; height: calc(100% - 1rem); background-color: var(--color-shark); - padding: 0.5rem 0rem 0.5rem 0rem; + margin: 0.5rem 0rem 0.5rem 0rem; `; -export const FlexCenterWrapper = ` +export const FlexCenterWrapper =` display: flex; justify-content: center; align-items: center; `; -export const ChattingRoomHeader = ` +export const ChattingRoomHeader =` background-color: var(--color-pumpkin); color: var(--color-white); border-radius: 5px 5px 0px 0px;
{title}