diff --git a/src/components/atoms/Button/DefaultButton.tsx b/src/components/atoms/Button/DefaultButton.tsx index 54f7fb0..d5b6290 100644 --- a/src/components/atoms/Button/DefaultButton.tsx +++ b/src/components/atoms/Button/DefaultButton.tsx @@ -1,4 +1,4 @@ -import { MouseEventHandler } from "react"; +import { memo, MouseEventHandler } from "react"; import styled from "styled-components"; import { BorderColorType, ColorType, FontSizeType } from "@styles/theme"; @@ -20,56 +20,58 @@ interface DefaultButtonProps { pv?: number; } -const DefaultButton = ({ - isInviteButton = false, - text, - onClick, - width = null, - height = null, - fontSize = "base", - fontWeight = "normal", - color = "white", - backgroundColor = "primary", - hoverBackgroundColor = "primary", - disabled = false, - borderColor = "trans", - mb = 0, - ph = 0, - pv = 0, -}: DefaultButtonProps) => { - return ( - - {text} - - ); -}; +const DefaultButton = memo( + ({ + isInviteButton = false, + text, + onClick, + width = null, + height = null, + fontSize = "base", + fontWeight = "normal", + color = "white", + backgroundColor = "primary", + hoverBackgroundColor = "primary", + disabled = false, + borderColor = "trans", + mb = 0, + ph = 0, + pv = 0, + }: DefaultButtonProps) => { + return ( + + {text} + + ); + } +); const DefaultButtonContainer = styled.button< Omit diff --git a/src/components/atoms/Div/CommunityLogo.tsx b/src/components/atoms/Div/CommunityLogo.tsx index fe2ac52..8ba70bb 100644 --- a/src/components/atoms/Div/CommunityLogo.tsx +++ b/src/components/atoms/Div/CommunityLogo.tsx @@ -1,7 +1,7 @@ import { Avatar } from "@mui/material"; import { IconButton } from "@mui/material"; import styled from "styled-components"; -import { ReactElement } from "react"; +import { MouseEvent, ReactElement, useCallback } from "react"; import useCommunityStore from "@store/useCommunityStore"; interface CommunityLogoProps { @@ -10,8 +10,8 @@ interface CommunityLogoProps { active?: boolean; src?: string; children?: ReactElement; - avatarWidth: Number; - avatarHeight: Number; + avatarWidth: number; + avatarHeight: number; } const CommunityLogo = ({ @@ -26,11 +26,11 @@ const CommunityLogo = ({ const { communityStatus, setCommunityStatus } = useCommunityStore(); active = Number(communityStatus) === id; - const selectCommunity = (e: any) => { + const selectCommunity = useCallback((e: MouseEvent) => { e.stopPropagation(); if (id === -2) return; setCommunityStatus(id); - }; + }, []); return ( @@ -38,10 +38,9 @@ const CommunityLogo = ({ selectCommunity(e)} + onClick={selectCommunity} disabled > - {/* borderRadius로 이미지 동그란 정도 조절하기 */} {children} {name} @@ -51,8 +50,6 @@ const CommunityLogo = ({ ); }; -export default CommunityLogo; - interface CommunityIconBoxProps { borderRadius: number | string; height: number | string; @@ -82,8 +79,8 @@ const CommunityIconBox = styled.div` `; interface CommunityIconButtonProps { - width: Number; - height: Number; + width: number; + height: number; } const StyledIconButton = styled(IconButton)` @@ -91,20 +88,21 @@ const StyledIconButton = styled(IconButton)` width: 100%; height: 100%; } - margin: 0px; - padding: 0rem !important; + + margin: 0; + padding: 0 !important; border-radius: 5rem; - width: ${({ width }) => width + "rem"}; - height: ${({ height }) => height + "rem"}; + width: ${({ width }) => width}rem; + height: ${({ height }) => height}rem; - border: 3px solid white; + border: 0.1875rem solid white; `; const ClickedWrapper = styled.div` - height: 10px; + height: 0.625rem; list-style-type: none; - line-height: 16px; - width: 6px; + line-height: 1rem; + width: 0.375rem; background-color: ${({ theme }) => theme.backgroundColor.white}; border-radius: 0 1rem 1rem 0; justify-content: flex-start; @@ -113,3 +111,5 @@ const ClickedWrapper = styled.div` opacity: 1; margin-right: 0.5rem; `; + +export default CommunityLogo; diff --git a/src/components/atoms/Div/FriendHeaderLeft.tsx b/src/components/atoms/Div/FriendHeaderLeft.tsx index 9f22d73..34bdefc 100644 --- a/src/components/atoms/Div/FriendHeaderLeft.tsx +++ b/src/components/atoms/Div/FriendHeaderLeft.tsx @@ -7,7 +7,9 @@ const FriendHeaderLeft = () => { return ( - + + 친구 + ); diff --git a/src/components/atoms/Div/MessageText.tsx b/src/components/atoms/Div/MessageText.tsx index 13ff569..81d713d 100644 --- a/src/components/atoms/Div/MessageText.tsx +++ b/src/components/atoms/Div/MessageText.tsx @@ -1,9 +1,10 @@ import getFormatTime from "@utils/getFormatTime"; -import { forwardRef, useMemo } from "react"; +import { forwardRef, useCallback, useMemo } from "react"; import styled from "styled-components"; import { ColorType, FontSizeType } from "@styles/theme"; import LinkText from "../Text/LinkText"; import useEnterInvitation from "@hooks/query/useEnterInvitation"; +import validateUrl from "@utils/validateUrl"; interface MessageTextProps { text: string; @@ -14,43 +15,33 @@ interface MessageTextProps { const MessageText = forwardRef( ({ text, hasDate, createdAt }, ref) => { const { mutate: enterInvitation } = useEnterInvitation(); - const hasLink = useMemo(() => { - return /(https?:\/\/[^\s]+)/g.test(text); - }, [text]); + const hasLink = useMemo(() => validateUrl(text), [text]); const words = text.split(" "); const link = words[0]; words.splice(0, 1); const chat2 = words.join(" "); - const clickInvitation = () => { + const clickInvitation = useCallback(() => { enterInvitation(); window.location.replace(link); - }; + }, []); return ( {hasDate && ( - + {getFormatTime(createdAt)} - + )} - - {hasLink ? ( - <> - - - - {chat2} - - - ) : ( - - {text} - - )} - + + {hasLink && }( + + {hasLink ? chat2 : text} + + ) + ); } @@ -66,16 +57,16 @@ const MessageTextContainer = styled.div` const MessageDate = styled.span` position: absolute; - margin-left: 12px; + margin-left: 0.75rem; visibility: hidden; `; -const TextContainer = styled.div` + +const MessageContainer = styled.div` left: 0; - padding: 2px 48px 2px 72px; + padding: 0.125rem 3rem 0.125rem 4.5rem; `; -interface TextProps { - text: string | React.ReactElement; +interface MessageProps { fontSize?: FontSizeType; color?: ColorType; mb?: number; @@ -83,12 +74,12 @@ interface TextProps { center?: boolean; } -const Text = styled.p>` +const Message = styled.p` line-height: 1.5rem; color: ${({ theme, color }) => theme.color[color]}; font-size: ${({ theme, fontSize }) => theme.fontSize[fontSize]}; - margin-top: 0px; - margin-left: 0px; + margin-top: 0; + margin-left: 0; `; export default MessageText; diff --git a/src/components/atoms/Div/NobodyActive.tsx b/src/components/atoms/Div/NobodyActive.tsx index 2f08a64..7b8bf94 100644 --- a/src/components/atoms/Div/NobodyActive.tsx +++ b/src/components/atoms/Div/NobodyActive.tsx @@ -4,20 +4,12 @@ import Text from "../Text/Text"; const NobodyActive = () => { return ( - - + + 지금은 조용하네요... + + + 친구가 음성 채팅과 같은 활동을 시작하면 여기에 표시돼요! + ); }; diff --git a/src/components/atoms/Div/SideBarWrapper.tsx b/src/components/atoms/Div/SideBarWrapper.tsx index dadb809..806972d 100644 --- a/src/components/atoms/Div/SideBarWrapper.tsx +++ b/src/components/atoms/Div/SideBarWrapper.tsx @@ -17,13 +17,9 @@ const SideBar = ({ children }: SideBarProps) => { return ( - + + 현재 활동 중 + {data ? <>{children} : } ); diff --git a/src/components/atoms/Div/UserLogo.tsx b/src/components/atoms/Div/UserLogo.tsx index 17c5829..c160111 100644 --- a/src/components/atoms/Div/UserLogo.tsx +++ b/src/components/atoms/Div/UserLogo.tsx @@ -5,8 +5,8 @@ import { MouseEventHandler, ReactElement } from "react"; interface LogoImageProps { onClick: MouseEventHandler; - width: Number; - height: Number; + width: number; + height: number; src?: string; child?: ReactElement; } @@ -28,8 +28,8 @@ const UserLogo = ({ }; interface ButtonProps { - width: Number; - height: Number; + width: number; + height: number; } const StyledIconButton = styled(IconButton)` @@ -39,8 +39,8 @@ const StyledIconButton = styled(IconButton)` } margin: 0px; padding: 0rem !important; - width: ${({ width }) => width + "rem"}; - height: ${({ height }) => height + "rem"}; ; + width: ${({ width }) => width}rem; + height: ${({ height }) => height}rem; ; `; export default UserLogo; diff --git a/src/components/atoms/Icons/AccountCircleIcon.tsx b/src/components/atoms/Icons/AccountCircleIcon.tsx index a2ff384..9edb5ba 100644 --- a/src/components/atoms/Icons/AccountCircleIcon.tsx +++ b/src/components/atoms/Icons/AccountCircleIcon.tsx @@ -1,3 +1,4 @@ import AccountCircleIcon from "@mui/icons-material/AccountCircle"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/AddCircleIcon.tsx b/src/components/atoms/Icons/AddCircleIcon.tsx index 364c163..8d41fa0 100644 --- a/src/components/atoms/Icons/AddCircleIcon.tsx +++ b/src/components/atoms/Icons/AddCircleIcon.tsx @@ -1,3 +1,4 @@ import AddCircleIcon from "@mui/icons-material/AddCircle"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/AddIcon.tsx b/src/components/atoms/Icons/AddIcon.tsx index 1e5f2d1..f996860 100644 --- a/src/components/atoms/Icons/AddIcon.tsx +++ b/src/components/atoms/Icons/AddIcon.tsx @@ -1,3 +1,4 @@ import AddIcon from "@mui/icons-material/Add"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/ArrowBottomIcon.tsx b/src/components/atoms/Icons/ArrowBottomIcon.tsx index 34bff26..0bb2e76 100644 --- a/src/components/atoms/Icons/ArrowBottomIcon.tsx +++ b/src/components/atoms/Icons/ArrowBottomIcon.tsx @@ -1,6 +1,7 @@ import KeyboardArrowDownRoundedIcon from "@mui/icons-material/KeyboardArrowDownRounded"; +import { memo } from "react"; import styled from "styled-components"; const ArrowBottomIcon = styled(KeyboardArrowDownRoundedIcon)``; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/ArrowRightIcon.tsx b/src/components/atoms/Icons/ArrowRightIcon.tsx index 655b6e0..2b784d2 100644 --- a/src/components/atoms/Icons/ArrowRightIcon.tsx +++ b/src/components/atoms/Icons/ArrowRightIcon.tsx @@ -1,6 +1,7 @@ import ArrowForwardIosRoundedIcon from "@mui/icons-material/ArrowForwardIosRounded"; +import { memo } from "react"; import styled from "styled-components"; const ArrowRightIcon = styled(ArrowForwardIosRoundedIcon)``; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/AtIcon.tsx b/src/components/atoms/Icons/AtIcon.tsx index cc19bab..7d918a8 100644 --- a/src/components/atoms/Icons/AtIcon.tsx +++ b/src/components/atoms/Icons/AtIcon.tsx @@ -1,6 +1,7 @@ import AlternateEmailIcon from "@mui/icons-material/AlternateEmail"; +import { memo } from "react"; import styled from "styled-components"; const AtIcon = styled(AlternateEmailIcon)``; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/CallIcon.tsx b/src/components/atoms/Icons/CallIcon.tsx index b7366d3..938bd14 100644 --- a/src/components/atoms/Icons/CallIcon.tsx +++ b/src/components/atoms/Icons/CallIcon.tsx @@ -1,3 +1,4 @@ import CallIcon from "@mui/icons-material/Call"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/CallOffIcon.tsx b/src/components/atoms/Icons/CallOffIcon.tsx index 6883e17..ddacd34 100644 --- a/src/components/atoms/Icons/CallOffIcon.tsx +++ b/src/components/atoms/Icons/CallOffIcon.tsx @@ -1,8 +1,9 @@ import styled from "styled-components"; import PhoneDisabledIcon from "@mui/icons-material/PhoneDisabled"; +import { memo } from "react"; const CallOffIcon = styled(PhoneDisabledIcon)` transform: scaleX(-1); `; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/CallWifiIcon.tsx b/src/components/atoms/Icons/CallWifiIcon.tsx index f9e80d4..1e53675 100644 --- a/src/components/atoms/Icons/CallWifiIcon.tsx +++ b/src/components/atoms/Icons/CallWifiIcon.tsx @@ -1,6 +1,7 @@ import WifiCalling3Icon from "@mui/icons-material/WifiCalling3"; +import { memo } from "react"; import styled from "styled-components"; const CallWifiIcon = styled(WifiCalling3Icon)``; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/CameraIcon.tsx b/src/components/atoms/Icons/CameraIcon.tsx index 32cd025..a7dc98b 100644 --- a/src/components/atoms/Icons/CameraIcon.tsx +++ b/src/components/atoms/Icons/CameraIcon.tsx @@ -1,6 +1,7 @@ import CameraAltIcon from "@mui/icons-material/CameraAlt"; +import { memo } from "react"; import styled from "styled-components"; const CameraIcon = styled(CameraAltIcon)``; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/CancelCircleIcon.tsx b/src/components/atoms/Icons/CancelCircleIcon.tsx index 19bf34d..9a4d28b 100644 --- a/src/components/atoms/Icons/CancelCircleIcon.tsx +++ b/src/components/atoms/Icons/CancelCircleIcon.tsx @@ -1,6 +1,7 @@ import HighlightOffIcon from "@mui/icons-material/HighlightOff"; +import { memo } from "react"; import styled from "styled-components"; const CancelCircleIcon = styled(HighlightOffIcon)``; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/CancelIcon.tsx b/src/components/atoms/Icons/CancelIcon.tsx index 8d878e2..19ee6a1 100644 --- a/src/components/atoms/Icons/CancelIcon.tsx +++ b/src/components/atoms/Icons/CancelIcon.tsx @@ -1,6 +1,7 @@ import ClearRoundedIcon from "@mui/icons-material/ClearRounded"; +import { memo } from "react"; import styled from "styled-components"; const CancelIcon = styled(ClearRoundedIcon)``; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/ChatAddIcon.tsx b/src/components/atoms/Icons/ChatAddIcon.tsx index 2de1f12..dbc3ba7 100644 --- a/src/components/atoms/Icons/ChatAddIcon.tsx +++ b/src/components/atoms/Icons/ChatAddIcon.tsx @@ -1,4 +1,5 @@ import AddCommentIcon from "@mui/icons-material/AddComment"; +import { memo } from "react"; import styled from "styled-components"; const ChatAddIcon = styled(AddCommentIcon)` @@ -10,4 +11,4 @@ const ChatAddIcon = styled(AddCommentIcon)` } `; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/ChatIcon.tsx b/src/components/atoms/Icons/ChatIcon.tsx index 80e3ec1..7253234 100644 --- a/src/components/atoms/Icons/ChatIcon.tsx +++ b/src/components/atoms/Icons/ChatIcon.tsx @@ -1,6 +1,7 @@ import ChatBubbleIcon from "@mui/icons-material/ChatBubble"; +import { memo } from "react"; import styled from "styled-components"; const ChatIcon = styled(ChatBubbleIcon)``; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/CheckIcon.tsx b/src/components/atoms/Icons/CheckIcon.tsx index aa148c3..d2a2bab 100644 --- a/src/components/atoms/Icons/CheckIcon.tsx +++ b/src/components/atoms/Icons/CheckIcon.tsx @@ -1,4 +1,5 @@ import CheckIcon from "@mui/icons-material/Check"; +import { memo } from "react"; import styled from "styled-components"; const IconWrapper = styled.div` @@ -7,8 +8,8 @@ const IconWrapper = styled.div` } `; -export default () => ( +export default memo(() => ( -); +)); diff --git a/src/components/atoms/Icons/CheckboxOffIcon.tsx b/src/components/atoms/Icons/CheckboxOffIcon.tsx index d4ca8de..85ec8b1 100644 --- a/src/components/atoms/Icons/CheckboxOffIcon.tsx +++ b/src/components/atoms/Icons/CheckboxOffIcon.tsx @@ -1,6 +1,7 @@ import CheckBoxOutlineBlankOutlinedIcon from "@mui/icons-material/CheckBoxOutlineBlankOutlined"; +import { memo } from "react"; import styled from "styled-components"; const CheckboxOffIcon = styled(CheckBoxOutlineBlankOutlinedIcon)``; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/CheckboxOnIcon.tsx b/src/components/atoms/Icons/CheckboxOnIcon.tsx index 0c8df13..750db32 100644 --- a/src/components/atoms/Icons/CheckboxOnIcon.tsx +++ b/src/components/atoms/Icons/CheckboxOnIcon.tsx @@ -1,6 +1,7 @@ import CheckBoxOutlinedIcon from "@mui/icons-material/CheckBoxOutlined"; +import { memo } from "react"; import styled from "styled-components"; const CheckboxOnIcon = styled(CheckBoxOutlinedIcon)``; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/CommunityAddIcon.tsx b/src/components/atoms/Icons/CommunityAddIcon.tsx index dd3c47e..45a56c8 100644 --- a/src/components/atoms/Icons/CommunityAddIcon.tsx +++ b/src/components/atoms/Icons/CommunityAddIcon.tsx @@ -1,13 +1,15 @@ import AddIcon from "@mui/icons-material/Add"; +import { memo } from "react"; import styled from "styled-components"; -export default () => ; - const CommunityAddIcon = styled(AddIcon)` position: absolute; left: 58px; top: 0px; + background-color: rgb(88, 101, 242); color: #fff; border-radius: 2rem; `; + +export default memo(() => ); diff --git a/src/components/atoms/Icons/DeleteIcon.tsx b/src/components/atoms/Icons/DeleteIcon.tsx index 7f3c441..4638d6c 100644 --- a/src/components/atoms/Icons/DeleteIcon.tsx +++ b/src/components/atoms/Icons/DeleteIcon.tsx @@ -1,3 +1,4 @@ import DeleteIcon from "@mui/icons-material/Delete"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/DesktopOffIcon.tsx b/src/components/atoms/Icons/DesktopOffIcon.tsx index e1a23e9..a379ef9 100644 --- a/src/components/atoms/Icons/DesktopOffIcon.tsx +++ b/src/components/atoms/Icons/DesktopOffIcon.tsx @@ -1,6 +1,7 @@ import DesktopAccessDisabledRoundedIcon from "@mui/icons-material/DesktopAccessDisabledRounded"; +import { memo } from "react"; import styled from "styled-components"; const DesktopOffIcon = styled(DesktopAccessDisabledRoundedIcon)``; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/EditIcon.tsx b/src/components/atoms/Icons/EditIcon.tsx index f9148f0..90de146 100644 --- a/src/components/atoms/Icons/EditIcon.tsx +++ b/src/components/atoms/Icons/EditIcon.tsx @@ -1,3 +1,4 @@ import EditIcon from "@mui/icons-material/Edit"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/ExploreIcon.tsx b/src/components/atoms/Icons/ExploreIcon.tsx index deed0f9..aae7f82 100644 --- a/src/components/atoms/Icons/ExploreIcon.tsx +++ b/src/components/atoms/Icons/ExploreIcon.tsx @@ -1,3 +1,4 @@ import ExploreIcon from "@mui/icons-material/Explore"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/FolderIcon.tsx b/src/components/atoms/Icons/FolderIcon.tsx index 9520668..ca24eee 100644 --- a/src/components/atoms/Icons/FolderIcon.tsx +++ b/src/components/atoms/Icons/FolderIcon.tsx @@ -1,3 +1,4 @@ import FolderIcon from "@mui/icons-material/Folder"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/HeadsetIcon.tsx b/src/components/atoms/Icons/HeadsetIcon.tsx index f25f991..155f54c 100644 --- a/src/components/atoms/Icons/HeadsetIcon.tsx +++ b/src/components/atoms/Icons/HeadsetIcon.tsx @@ -1,3 +1,4 @@ import HeadsetIcon from "@mui/icons-material/Headset"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/HeadsetOffIcon.tsx b/src/components/atoms/Icons/HeadsetOffIcon.tsx index 9f9a348..e92441d 100644 --- a/src/components/atoms/Icons/HeadsetOffIcon.tsx +++ b/src/components/atoms/Icons/HeadsetOffIcon.tsx @@ -1,3 +1,6 @@ import HeadsetOffIcon from "@mui/icons-material/HeadsetOff"; +import { memo } from "react"; -export default () => ; +export default memo(() => ( + +)); diff --git a/src/components/atoms/Icons/HelpIcon.tsx b/src/components/atoms/Icons/HelpIcon.tsx index 6dd294c..ede60af 100644 --- a/src/components/atoms/Icons/HelpIcon.tsx +++ b/src/components/atoms/Icons/HelpIcon.tsx @@ -1,3 +1,4 @@ import HelpIcon from "@mui/icons-material/Help"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/InboxIcon.tsx b/src/components/atoms/Icons/InboxIcon.tsx index 30a4b59..5867f00 100644 --- a/src/components/atoms/Icons/InboxIcon.tsx +++ b/src/components/atoms/Icons/InboxIcon.tsx @@ -1,3 +1,4 @@ import InboxIcon from "@mui/icons-material/Inbox"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/LogoutIcon.tsx b/src/components/atoms/Icons/LogoutIcon.tsx index 86746b1..02cc239 100644 --- a/src/components/atoms/Icons/LogoutIcon.tsx +++ b/src/components/atoms/Icons/LogoutIcon.tsx @@ -1,3 +1,4 @@ import LogoutIcon from "@mui/icons-material/Logout"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/MicIcon.tsx b/src/components/atoms/Icons/MicIcon.tsx index 9fa3cc9..7d4d3fd 100644 --- a/src/components/atoms/Icons/MicIcon.tsx +++ b/src/components/atoms/Icons/MicIcon.tsx @@ -1,3 +1,4 @@ import MicIcon from "@mui/icons-material/Mic"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/MicOffIcon.tsx b/src/components/atoms/Icons/MicOffIcon.tsx index c55ff43..47d5dd9 100644 --- a/src/components/atoms/Icons/MicOffIcon.tsx +++ b/src/components/atoms/Icons/MicOffIcon.tsx @@ -1,3 +1,6 @@ import MicOffIcon from "@mui/icons-material/MicOff"; +import { memo } from "react"; -export default () => ; +export default memo(() => ( + +)); diff --git a/src/components/atoms/Icons/MissedCallIcon.tsx b/src/components/atoms/Icons/MissedCallIcon.tsx index 9154852..4a1ce43 100644 --- a/src/components/atoms/Icons/MissedCallIcon.tsx +++ b/src/components/atoms/Icons/MissedCallIcon.tsx @@ -1,8 +1,9 @@ import CallIcon from "@mui/icons-material/Call"; +import { memo } from "react"; import styled from "styled-components"; const MissedCallIcon = styled(CallIcon)` transform: rotate(-180deg); `; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/MoreIcon.tsx b/src/components/atoms/Icons/MoreIcon.tsx index 7dabcd9..6c85f43 100644 --- a/src/components/atoms/Icons/MoreIcon.tsx +++ b/src/components/atoms/Icons/MoreIcon.tsx @@ -1,6 +1,7 @@ import MoreVertIcon from "@mui/icons-material/MoreVert"; +import { memo } from "react"; import styled from "styled-components"; const MoreIcon = styled(MoreVertIcon)``; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/NotificationsIcon.tsx b/src/components/atoms/Icons/NotificationsIcon.tsx index 5e64785..23056ee 100644 --- a/src/components/atoms/Icons/NotificationsIcon.tsx +++ b/src/components/atoms/Icons/NotificationsIcon.tsx @@ -1,3 +1,4 @@ import NotificationsIcon from "@mui/icons-material/Notifications"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/PersonAddIcon.tsx b/src/components/atoms/Icons/PersonAddIcon.tsx index 203d15b..d7392cf 100644 --- a/src/components/atoms/Icons/PersonAddIcon.tsx +++ b/src/components/atoms/Icons/PersonAddIcon.tsx @@ -1,3 +1,6 @@ import PersonAddIcon from "@mui/icons-material/PersonAdd"; +import { memo } from "react"; -export default () => ; +export default memo(() => ( + +)); diff --git a/src/components/atoms/Icons/PersonIcon.tsx b/src/components/atoms/Icons/PersonIcon.tsx index 3ac4c25..61e9f66 100644 --- a/src/components/atoms/Icons/PersonIcon.tsx +++ b/src/components/atoms/Icons/PersonIcon.tsx @@ -1,4 +1,5 @@ import EmojiPeopleIcon from "@mui/icons-material/EmojiPeople"; +import { memo } from "react"; import styled from "styled-components"; const Crop = styled.div` @@ -14,4 +15,4 @@ const PersonIcon = () => ( ); -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/PingIcon.tsx b/src/components/atoms/Icons/PingIcon.tsx index 1fa3e3a..cfacf9f 100644 --- a/src/components/atoms/Icons/PingIcon.tsx +++ b/src/components/atoms/Icons/PingIcon.tsx @@ -1,6 +1,7 @@ import SignalCellularAltIcon from "@mui/icons-material/SignalCellularAlt"; +import { memo } from "react"; import styled from "styled-components"; const PingIcon = styled(SignalCellularAltIcon)``; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/RadioButtonCheckedIcon.tsx b/src/components/atoms/Icons/RadioButtonCheckedIcon.tsx index c4d8c32..58df57e 100644 --- a/src/components/atoms/Icons/RadioButtonCheckedIcon.tsx +++ b/src/components/atoms/Icons/RadioButtonCheckedIcon.tsx @@ -1,3 +1,4 @@ import RadioButtonCheckedIcon from "@mui/icons-material/RadioButtonChecked"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/RadioButtonUncheckedIcon.tsx b/src/components/atoms/Icons/RadioButtonUncheckedIcon.tsx index eb353f3..eb0c10a 100644 --- a/src/components/atoms/Icons/RadioButtonUncheckedIcon.tsx +++ b/src/components/atoms/Icons/RadioButtonUncheckedIcon.tsx @@ -1,3 +1,4 @@ import RadioButtonUncheckedIcon from "@mui/icons-material/RadioButtonUnchecked"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/ScreenShareIcon.tsx b/src/components/atoms/Icons/ScreenShareIcon.tsx index 37e9d03..3b4c629 100644 --- a/src/components/atoms/Icons/ScreenShareIcon.tsx +++ b/src/components/atoms/Icons/ScreenShareIcon.tsx @@ -1,3 +1,4 @@ import ScreenShareIcon from "@mui/icons-material/ScreenShare"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/SearchIcon.tsx b/src/components/atoms/Icons/SearchIcon.tsx index ca890c5..9a4e859 100644 --- a/src/components/atoms/Icons/SearchIcon.tsx +++ b/src/components/atoms/Icons/SearchIcon.tsx @@ -1,3 +1,4 @@ import SearchIcon from "@mui/icons-material/Search"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/SettingsIcon.tsx b/src/components/atoms/Icons/SettingsIcon.tsx index 25a9899..6894780 100644 --- a/src/components/atoms/Icons/SettingsIcon.tsx +++ b/src/components/atoms/Icons/SettingsIcon.tsx @@ -1,3 +1,4 @@ import SettingsIcon from "@mui/icons-material/Settings"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/StarIcon.tsx b/src/components/atoms/Icons/StarIcon.tsx index d2eea01..6b5e7cf 100644 --- a/src/components/atoms/Icons/StarIcon.tsx +++ b/src/components/atoms/Icons/StarIcon.tsx @@ -1,3 +1,4 @@ import StarIcon from "@mui/icons-material/Star"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/StateDisturbIcon.tsx b/src/components/atoms/Icons/StateDisturbIcon.tsx index 61880ff..cbb7a9e 100644 --- a/src/components/atoms/Icons/StateDisturbIcon.tsx +++ b/src/components/atoms/Icons/StateDisturbIcon.tsx @@ -1,4 +1,5 @@ import DoDisturbOnRoundedIcon from "@mui/icons-material/DoDisturbOnRounded"; +import { memo } from "react"; import styled from "styled-components"; const StateDisturbIcon = styled(DoDisturbOnRoundedIcon)``; @@ -8,4 +9,8 @@ interface StateIconProps { padding?: number; } -export default ({ fontSize, padding = 1 }: StateIconProps) => ; +export default memo(({ fontSize, padding = 1 }: StateIconProps) => ( + +)); diff --git a/src/components/atoms/Icons/StateEmptyIcon.tsx b/src/components/atoms/Icons/StateEmptyIcon.tsx index ddd4dc5..f1b1e23 100644 --- a/src/components/atoms/Icons/StateEmptyIcon.tsx +++ b/src/components/atoms/Icons/StateEmptyIcon.tsx @@ -1,4 +1,5 @@ import DarkModeIcon from "@mui/icons-material/DarkMode"; +import { memo } from "react"; import styled from "styled-components"; const StateEmptyIcon = styled(DarkModeIcon)` @@ -10,4 +11,8 @@ interface StateIconProps { padding?: number; } -export default ({ fontSize, padding = 1 }: StateIconProps) => ; +export default memo(({ fontSize, padding = 1 }: StateIconProps) => ( + +)); diff --git a/src/components/atoms/Icons/StateMobileIcon.tsx b/src/components/atoms/Icons/StateMobileIcon.tsx index 73d7f38..9a8c25f 100644 --- a/src/components/atoms/Icons/StateMobileIcon.tsx +++ b/src/components/atoms/Icons/StateMobileIcon.tsx @@ -1,4 +1,5 @@ import PhoneIphoneIcon from "@mui/icons-material/PhoneIphone"; +import { memo } from "react"; import styled from "styled-components"; const StateMobileIcon = styled(PhoneIphoneIcon)``; @@ -7,4 +8,8 @@ interface StateIconProps { padding?: number; } -export default ({ fontSize, padding = 1 }: StateIconProps) => ; +export default memo(({ fontSize, padding = 1 }: StateIconProps) => ( + +)); diff --git a/src/components/atoms/Icons/StateOffIcon.tsx b/src/components/atoms/Icons/StateOffIcon.tsx index ee026b0..3945cfa 100644 --- a/src/components/atoms/Icons/StateOffIcon.tsx +++ b/src/components/atoms/Icons/StateOffIcon.tsx @@ -1,4 +1,5 @@ import TripOriginIcon from "@mui/icons-material/TripOrigin"; +import { memo } from "react"; import styled from "styled-components"; const StateOffIcon = styled(TripOriginIcon)``; @@ -8,4 +9,6 @@ interface StateIconProps { padding?: number; } -export default ({ fontSize, padding = 1 }: StateIconProps) => ; +export default memo(({ fontSize, padding = 1 }: StateIconProps) => ( + +)); diff --git a/src/components/atoms/Icons/StateOnIcon.tsx b/src/components/atoms/Icons/StateOnIcon.tsx index d488f9b..6137f06 100644 --- a/src/components/atoms/Icons/StateOnIcon.tsx +++ b/src/components/atoms/Icons/StateOnIcon.tsx @@ -1,4 +1,5 @@ import CircleIcon from "@mui/icons-material/Circle"; +import { memo } from "react"; import styled from "styled-components"; const StateOnIcon = styled(CircleIcon)``; @@ -8,4 +9,6 @@ interface StateIconProps { padding?: number; } -export default ({ fontSize, padding = 1 }: StateIconProps) => ; +export default memo(({ fontSize, padding = 1 }: StateIconProps) => ( + +)); diff --git a/src/components/atoms/Icons/TagIcon.tsx b/src/components/atoms/Icons/TagIcon.tsx index 9b7e8d8..c317a48 100644 --- a/src/components/atoms/Icons/TagIcon.tsx +++ b/src/components/atoms/Icons/TagIcon.tsx @@ -1,6 +1,7 @@ import TagRoundedIcon from "@mui/icons-material/TagRounded"; +import { memo } from "react"; import styled from "styled-components"; const TagIcon = styled(TagRoundedIcon)``; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/UploadIcon.tsx b/src/components/atoms/Icons/UploadIcon.tsx index 186e8fe..8bac051 100644 --- a/src/components/atoms/Icons/UploadIcon.tsx +++ b/src/components/atoms/Icons/UploadIcon.tsx @@ -1,3 +1,4 @@ import UploadIcon from "@mui/icons-material/Upload"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/VideocamIcon.tsx b/src/components/atoms/Icons/VideocamIcon.tsx index 59acdcf..e3cedea 100644 --- a/src/components/atoms/Icons/VideocamIcon.tsx +++ b/src/components/atoms/Icons/VideocamIcon.tsx @@ -1,3 +1,4 @@ import VideocamIcon from "@mui/icons-material/Videocam"; +import { memo } from "react"; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/VoiceIcon.tsx b/src/components/atoms/Icons/VoiceIcon.tsx index f959680..a125b97 100644 --- a/src/components/atoms/Icons/VoiceIcon.tsx +++ b/src/components/atoms/Icons/VoiceIcon.tsx @@ -1,6 +1,7 @@ import GraphicEqRoundedIcon from "@mui/icons-material/GraphicEqRounded"; +import { memo } from "react"; import styled from "styled-components"; const VoiceIcon = styled(GraphicEqRoundedIcon)``; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/VolumeIcon.tsx b/src/components/atoms/Icons/VolumeIcon.tsx index 798f712..18535aa 100644 --- a/src/components/atoms/Icons/VolumeIcon.tsx +++ b/src/components/atoms/Icons/VolumeIcon.tsx @@ -1,6 +1,7 @@ import VolumeUpIcon from "@mui/icons-material/VolumeUp"; +import { memo } from "react"; import styled from "styled-components"; const VolumeIcon = styled(VolumeUpIcon)``; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Icons/WelcomeIcon.tsx b/src/components/atoms/Icons/WelcomeIcon.tsx index e1b92be..095b3fe 100644 --- a/src/components/atoms/Icons/WelcomeIcon.tsx +++ b/src/components/atoms/Icons/WelcomeIcon.tsx @@ -1,4 +1,5 @@ import ArrowForwardRoundedIcon from "@mui/icons-material/ArrowForwardRounded"; +import { memo } from "react"; import styled from "styled-components"; const WelcomeIcon = styled(ArrowForwardRoundedIcon)` @@ -7,4 +8,4 @@ const WelcomeIcon = styled(ArrowForwardRoundedIcon)` height: 1rem; `; -export default () => ; +export default memo(() => ); diff --git a/src/components/atoms/Input/DefaultInput.stories.tsx b/src/components/atoms/Input/DefaultInput.stories.tsx deleted file mode 100644 index 5d2e992..0000000 --- a/src/components/atoms/Input/DefaultInput.stories.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { useState } from "react"; -import DefaultInput from "./DefaultInput"; - -export default { - title: "atoms/Input", - component: DefaultInput, -}; - -export const Default = () => { - const [text, setText] = useState(""); - return ( - setText(value)} - /> - ); -}; diff --git a/src/components/atoms/Input/DefaultInput.tsx b/src/components/atoms/Input/DefaultInput.tsx index cacd60f..f2510aa 100644 --- a/src/components/atoms/Input/DefaultInput.tsx +++ b/src/components/atoms/Input/DefaultInput.tsx @@ -1,11 +1,10 @@ -import { ChangeEventHandler } from "react"; +import { forwardRef, RefObject } from "react"; import styled from "styled-components"; import { BackgroundColorType, ColorType, FontSizeType } from "@styles/theme"; interface DefaultInputProps { - value: string; - onChange: ChangeEventHandler; type: string; + initValue?: string; maxLength?: number; width?: number | string; height?: number | string; @@ -16,35 +15,42 @@ interface DefaultInputProps { backgroundColor?: BackgroundColorType; } -const DefaultInput = ({ - value, - onChange, - type = "text", - maxLength = 524288, - width = "100%", - height = "100%", - placeholder = "", - placeholderColor = "tab2-placeholder", - fontSize = "sm", - color = "white", - backgroundColor = "tab1", -}: DefaultInputProps) => { - return ( - - ); -}; +const DefaultInput = forwardRef( + ( + { + type = "text", + initValue = "", + maxLength = 524288, + width = "100%", + height = "100%", + placeholder = "", + placeholderColor = "tab2-placeholder", + fontSize = "sm", + color = "white", + backgroundColor = "tab1", + }, + ref + ) => { + if (initValue && ref) { + (ref as RefObject)!.current!.value = initValue; + } + + return ( + + ); + } +); const DefaultInputContainer = styled.input< Pick< @@ -67,9 +73,11 @@ const DefaultInputContainer = styled.input< font-size: ${({ theme, fontSize }) => theme.fontSize[fontSize]}; background-color: ${({ theme, backgroundColor }) => theme.backgroundColor[backgroundColor]}; + ::placeholder { color: ${({ theme, placeholderColor }) => theme.color[placeholderColor]}; } + &:focus { outline: none; } diff --git a/src/components/atoms/Text/ErrorText.tsx b/src/components/atoms/Text/ErrorText.tsx new file mode 100644 index 0000000..2c5e952 --- /dev/null +++ b/src/components/atoms/Text/ErrorText.tsx @@ -0,0 +1,16 @@ +import { memo } from "react"; +import Text from "./Text"; + +interface ErrorTextProps { + text: string; +} + +const ErrorText = memo(({ text }: ErrorTextProps) => { + return ( + + {text} + + ); +}); + +export default ErrorText; diff --git a/src/components/atoms/Text/LinkText.tsx b/src/components/atoms/Text/LinkText.tsx index 31399b0..3a73d26 100644 --- a/src/components/atoms/Text/LinkText.tsx +++ b/src/components/atoms/Text/LinkText.tsx @@ -1,4 +1,4 @@ -import { MouseEventHandler } from "react"; +import { memo, MouseEventHandler } from "react"; import styled from "styled-components"; import { ColorType } from "@styles/theme"; @@ -8,18 +8,20 @@ interface LinkTextProps { color?: ColorType; } -const LinkText = ({ text, onClick, color = "blue" }: LinkTextProps) => { +const LinkText = memo(({ text, onClick, color = "blue" }: LinkTextProps) => { return ( {text} ); -}; +}); const LinkTextContainer = styled.span<{ color: ColorType }>` color: ${({ theme, color }) => theme.color[color]}; font-size: ${({ theme }) => theme.fontSize.sm}; + cursor: pointer; + &:hover { text-decoration: underline; } diff --git a/src/components/atoms/Text/Text.stories.tsx b/src/components/atoms/Text/Text.stories.tsx index d44f4c8..53ad0e4 100644 --- a/src/components/atoms/Text/Text.stories.tsx +++ b/src/components/atoms/Text/Text.stories.tsx @@ -5,4 +5,4 @@ export default { component: Text, }; -export const Default = () => ; +export const Default = () => 로그인; diff --git a/src/components/atoms/Text/Text.tsx b/src/components/atoms/Text/Text.tsx index 5a7d7f7..2b037ee 100644 --- a/src/components/atoms/Text/Text.tsx +++ b/src/components/atoms/Text/Text.tsx @@ -4,7 +4,6 @@ import { ColorType, FontSizeType } from "@styles/theme"; type fontWeightType = "normal" | "bold"; interface TextProps { - text: string | React.ReactElement; fontSize?: FontSizeType; fontWeight?: fontWeightType; color?: ColorType; @@ -13,28 +12,7 @@ interface TextProps { center?: boolean; } -const Text = ({ - text, - fontSize = "base", - fontWeight = "normal", - color = "inherit", - mb = 0, - mr = 0, - center = false, -}: TextProps) => ( - - {text} - -); - -const TextContainer = styled.p>` +const Text = styled.p>` color: ${({ theme, color }) => theme.color[color]}; font-size: ${({ theme, fontSize }) => theme.fontSize[fontSize]}; font-weight: ${({ fontWeight }) => @@ -46,4 +24,13 @@ const TextContainer = styled.p>` text-align: ${({ center }) => (center ? "center" : "left")}; `; +Text.defaultProps = { + fontSize: "base", + fontWeight: "normal", + color: "inherit", + mb: 0, + mr: 0, + center: false, +}; + export default Text; diff --git a/src/components/molecules/Button/DirectButton.tsx b/src/components/molecules/Button/DirectButton.tsx index 48cbc5d..b31f351 100644 --- a/src/components/molecules/Button/DirectButton.tsx +++ b/src/components/molecules/Button/DirectButton.tsx @@ -39,7 +39,7 @@ const DirectButton = ({ id, name, userId, src }: DirectButtonProps) => { > - + {name} ); diff --git a/src/components/molecules/Button/FriendButton.tsx b/src/components/molecules/Button/FriendButton.tsx index eb5ccb7..e37bff4 100644 --- a/src/components/molecules/Button/FriendButton.tsx +++ b/src/components/molecules/Button/FriendButton.tsx @@ -17,7 +17,7 @@ const FriendButton = () => { > - + 친구 ); diff --git a/src/components/molecules/Button/ImageUploadButton.tsx b/src/components/molecules/Button/ImageUploadButton.tsx index e45f75f..0c17a4b 100644 --- a/src/components/molecules/Button/ImageUploadButton.tsx +++ b/src/components/molecules/Button/ImageUploadButton.tsx @@ -20,7 +20,9 @@ const ImageUploadButton = ({ setImg }: any) => { ) : ( - + + UPLOAD + { ); }; -export default ImageUploadButton; - const UploadContainer = styled.div` display: flex; justify-content: center; @@ -85,3 +85,5 @@ const UploadWrapper = styled.div` font-size: 0px; } `; + +export default ImageUploadButton; diff --git a/src/components/molecules/Button/SearchButton.tsx b/src/components/molecules/Button/SearchButton.tsx index 8f2783a..821c19d 100644 --- a/src/components/molecules/Button/SearchButton.tsx +++ b/src/components/molecules/Button/SearchButton.tsx @@ -1,14 +1,16 @@ import DefaultInput from "@components/atoms/Input/DefaultInput"; +import { useRef } from "react"; import styled from "styled-components"; const SearchButton = () => { + const ref = useRef(null); + return ( null} /> ); diff --git a/src/components/molecules/Button/UserInfoButton.tsx b/src/components/molecules/Button/UserInfoButton.tsx index ddc9c34..0e3e824 100644 --- a/src/components/molecules/Button/UserInfoButton.tsx +++ b/src/components/molecules/Button/UserInfoButton.tsx @@ -20,12 +20,9 @@ const UserInfoButton = ({ status }: UserInfoButtonProps) => { > - + + {userInfo.email} + ); diff --git a/src/components/molecules/Div/AddFriend.tsx b/src/components/molecules/Div/AddFriend.tsx index 998a2ed..d20ae38 100644 --- a/src/components/molecules/Div/AddFriend.tsx +++ b/src/components/molecules/Div/AddFriend.tsx @@ -4,13 +4,12 @@ import InviteInput from "../Input/InviteInput"; const AddFriend = () => { return ( <> - - + + 친구 추가하기 + + + 이메일을 작성하여 친구를 추가할 수 있어요. + ); diff --git a/src/components/molecules/Div/BigSearchInputBox.tsx b/src/components/molecules/Div/BigSearchInputBox.tsx index e9edd58..8ade989 100644 --- a/src/components/molecules/Div/BigSearchInputBox.tsx +++ b/src/components/molecules/Div/BigSearchInputBox.tsx @@ -1,19 +1,14 @@ -import { ChangeEventHandler } from "react"; +import { forwardRef, Ref } from "react"; import styled from "styled-components"; import SearchInput from "../Input/SearchInput"; -interface SearchInputProps { - value: string; - onChange: ChangeEventHandler; -} - -const BigSearchInputBox = ({ value, onChange }: SearchInputProps) => { +const BigSearchInputBox = forwardRef((ref) => { return ( - + } /> ); -}; +}); const InputContainer = styled.div` margin-top: 16px; diff --git a/src/components/molecules/Div/CallDirectMessage.tsx b/src/components/molecules/Div/CallDirectMessage.tsx index a41fce3..53f1d87 100644 --- a/src/components/molecules/Div/CallDirectMessage.tsx +++ b/src/components/molecules/Div/CallDirectMessage.tsx @@ -33,8 +33,12 @@ const CallDirectMessage = ({ null} /> - - + + {text} + + + 2023.02.05.오후 4:20 + ); diff --git a/src/components/molecules/Div/CardUserInfo.tsx b/src/components/molecules/Div/CardUserInfo.tsx index 54d9da4..6dd470b 100644 --- a/src/components/molecules/Div/CardUserInfo.tsx +++ b/src/components/molecules/Div/CardUserInfo.tsx @@ -13,14 +13,12 @@ const CardUserInfo = () => { - - + + {userInfo.name} + + + {userInfo.introduction} + diff --git a/src/components/molecules/Div/CommunityDropdown.tsx b/src/components/molecules/Div/CommunityDropdown.tsx index c7d0316..26ae0ba 100644 --- a/src/components/molecules/Div/CommunityDropdown.tsx +++ b/src/components/molecules/Div/CommunityDropdown.tsx @@ -3,17 +3,17 @@ import EditIcon from "@components/atoms/Icons/EditIcon"; import LogoutIcon from "@components/atoms/Icons/LogoutIcon"; import PersonAddIcon from "@components/atoms/Icons/PersonAddIcon"; import useModalStore, { ModalType } from "@store/useModalStore"; +import { useCallback } from "react"; import styled from "styled-components"; import DropdownButton from "../Button/DropdownButton"; const CommunityDropdown = () => { const { setModalType, setShowModal } = useModalStore(); - const setModal = (modalType: ModalType) => { - console.log("modalType", modalType); + const setModal = useCallback((modalType: ModalType) => { setModalType(modalType); setShowModal(true); - }; + }, []); return ( diff --git a/src/components/molecules/Div/CommunityLabel.tsx b/src/components/molecules/Div/CommunityLabel.tsx index 95c1760..fe5849a 100644 --- a/src/components/molecules/Div/CommunityLabel.tsx +++ b/src/components/molecules/Div/CommunityLabel.tsx @@ -10,7 +10,9 @@ const CommunityLabel = ({ text }: CommunityLabelProps) => { return ( - + + {text} + ); }; diff --git a/src/components/molecules/Div/CommunityRoomButton.tsx b/src/components/molecules/Div/CommunityRoomButton.tsx index 6937b19..702fff6 100644 --- a/src/components/molecules/Div/CommunityRoomButton.tsx +++ b/src/components/molecules/Div/CommunityRoomButton.tsx @@ -45,7 +45,7 @@ const CommunityRoomButton = ({ {type === "CHAT" ? : } - + {text}
diff --git a/src/components/molecules/Div/CreateDirectMessageHeader.tsx b/src/components/molecules/Div/CreateDirectMessageHeader.tsx index db9d039..d972b34 100644 --- a/src/components/molecules/Div/CreateDirectMessageHeader.tsx +++ b/src/components/molecules/Div/CreateDirectMessageHeader.tsx @@ -1,32 +1,31 @@ import DefaultInput from "@components/atoms/Input/DefaultInput"; import Text from "@components/atoms/Text/Text"; -import { ChangeEventHandler } from "react"; +// import { ChangeEventHandler } from "react"; import styled from "styled-components"; interface CreateDirectMesssageHeaderProps { addFriendNum: number; - value: string; - onChange: ChangeEventHandler; + // value: string; + // onChange: ChangeEventHandler; } const CreateDirectMesssageHeader = ({ addFriendNum, - value, - onChange, -}: CreateDirectMesssageHeaderProps) => { +}: // value, +// onChange, +CreateDirectMesssageHeaderProps) => { return ( - - + + 친구 선택하기 + + + 친구를 {9 - addFriendNum}명 더 추가할 수 있어요. + diff --git a/src/components/molecules/Div/DirectMessage.tsx b/src/components/molecules/Div/DirectMessage.tsx index 0deafd1..0779784 100644 --- a/src/components/molecules/Div/DirectMessage.tsx +++ b/src/components/molecules/Div/DirectMessage.tsx @@ -7,14 +7,16 @@ import { useRef, useState } from "react"; import styled from "styled-components"; const DirectMessage = () => { - const dropdownRef = useRef(); + const dropdownRef = useRef(null); const [showDMDropdown, setShowDMDropdown] = useState(false); useOutsideClick(dropdownRef, () => setShowDMDropdown(false)); return ( - + + 다이렉트 메시지 + { return ( - + {text} ); }; diff --git a/src/components/molecules/Div/FileUploadeDropdown.tsx b/src/components/molecules/Div/FileUploadeDropdown.tsx index 634183b..ec6696d 100644 --- a/src/components/molecules/Div/FileUploadeDropdown.tsx +++ b/src/components/molecules/Div/FileUploadeDropdown.tsx @@ -10,7 +10,7 @@ const FileUploadeDropdown = () => { null}> - + 파일 업로드 ); diff --git a/src/components/molecules/Div/FriendBox.tsx b/src/components/molecules/Div/FriendBox.tsx index 061e1d0..0f4e3e2 100644 --- a/src/components/molecules/Div/FriendBox.tsx +++ b/src/components/molecules/Div/FriendBox.tsx @@ -26,8 +26,12 @@ const FriendBox = ({ name, status, onClick, Buttons, src }: FriendBoxProps) => { - - + + {name} + + + {statusTable[status]} + {Buttons} diff --git a/src/components/molecules/Div/FriendDefaultBox.tsx b/src/components/molecules/Div/FriendDefaultBox.tsx index 12f2d16..5621090 100644 --- a/src/components/molecules/Div/FriendDefaultBox.tsx +++ b/src/components/molecules/Div/FriendDefaultBox.tsx @@ -5,14 +5,7 @@ import MoreIcon from "@components/atoms/Icons/MoreIcon"; import useOutsideClick from "@hooks/common/useOutsideClick"; import useGetFriendStatus from "@hooks/query/useGetFriendStatus"; import useMainStore from "@store/useMainStore"; -import { - Dispatch, - MouseEvent, - ReactElement, - SetStateAction, - useRef, - useState, -} from "react"; +import { MouseEvent, ReactElement, useRef, useState } from "react"; import { useNavigate } from "react-router-dom"; import styled from "styled-components"; import RoundButton from "../Button/RoundButton"; @@ -20,7 +13,6 @@ import FriendEtcDropdown from "./FriendEtcDropdown"; import FriendBox from "./FriendBox"; interface FriendDefaultBoxProps { - setNum: Dispatch>; email: string; id: string; name: string; @@ -31,7 +23,6 @@ interface FriendDefaultBoxProps { } const FriendDefaultBox = ({ - setNum, email, id, name, @@ -41,7 +32,7 @@ const FriendDefaultBox = ({ }: FriendDefaultBoxProps) => { const navigate = useNavigate(); - const dropdownRef = useRef(); + const dropdownRef = useRef(null); const [showEtcModal, setShowEtcModal] = useState(false); const { setDeleteFriendEmail } = useMainStore(); @@ -50,10 +41,10 @@ const FriendDefaultBox = ({ useOutsideClick(dropdownRef, () => setShowEtcModal(false)); - if (isLoading) return <>; + if (isLoading) return null; if (isOnline?.data.data !== "1") { - return <>; + return null; } const enterDM = () => { diff --git a/src/components/molecules/Div/FriendList.tsx b/src/components/molecules/Div/FriendList.tsx index 545a2bb..6813843 100644 --- a/src/components/molecules/Div/FriendList.tsx +++ b/src/components/molecules/Div/FriendList.tsx @@ -9,14 +9,10 @@ const FriendList = () => { const { userInfo: { email }, } = useUserStore(); + const { data, isSuccess } = useGetFriendList(email); - if (!isSuccess) - return ( - - - - ); + if (!isSuccess) return null; const friendList: FriendType[] = data.filter( (friend: FriendType) => friend.friendState === "ACCEPTED" @@ -50,11 +46,11 @@ const FriendListContainer = styled.div` `; const FriendListWrapper = styled.div` - height: calc(100vh - 200px); + height: calc(100vh - 12.5rem); display: flex; flex-direction: column; - gap: 2px; + gap: 0.125rem; `; export default FriendList; diff --git a/src/components/molecules/Div/InviteFriendBox.tsx b/src/components/molecules/Div/InviteFriendBox.tsx index 4b601aa..dfc6132 100644 --- a/src/components/molecules/Div/InviteFriendBox.tsx +++ b/src/components/molecules/Div/InviteFriendBox.tsx @@ -39,8 +39,8 @@ const InviteFriendBox = ({ name, userId, channelId }: friend) => { null}> - - + + {name} { - const [search, changeSearch] = useInput(); + const searchRef = useRef(null); const { userInfo: { email }, } = useUserStore(); const { data: friendList, isSuccess } = useGetFriendList(email); - if (!isSuccess) return <>; + if (!isSuccess) return null; const num = friendList.length; return ( - + @@ -43,12 +39,9 @@ const InviteFriendModalBody = () => { )) ) : ( - + + 검색 결과가 없어요 + )} @@ -64,7 +57,7 @@ const InviteFriendModalBodyContainer = styled.div` `; const SearchInputWrapper = styled.div` - margin-bottom: 16px; + margin-bottom: 1rem; `; const Divider = styled.div<{ color: string }>` diff --git a/src/components/molecules/Div/InviteFriendModalFooter.tsx b/src/components/molecules/Div/InviteFriendModalFooter.tsx index 99a9f53..dbd19b4 100644 --- a/src/components/molecules/Div/InviteFriendModalFooter.tsx +++ b/src/components/molecules/Div/InviteFriendModalFooter.tsx @@ -5,19 +5,13 @@ import InviteCommunityInput from "../Input/InviteCommunityInput"; const InviteFriendModalFooter = () => { return ( - + + 또는 친구에게 서버 초대 링크 전송하기 + - + + 초대 링크가 7일 후 만료돼요. + ); }; diff --git a/src/components/molecules/Div/InviteFriendModalHeader.tsx b/src/components/molecules/Div/InviteFriendModalHeader.tsx index f979d67..8dc16fb 100644 --- a/src/components/molecules/Div/InviteFriendModalHeader.tsx +++ b/src/components/molecules/Div/InviteFriendModalHeader.tsx @@ -6,25 +6,27 @@ import styled from "styled-components"; const InviteFriendModalHeader = () => { const { setShowModal } = useModalStore(); + //!TODO: 추후에 channelId로 groupName, chatRoomName을 가져와야 함! const groupName = "test"; const chatRoomName = "환영"; + return ( - +
- + 친구를 {groupName}그룹으로 초대하기 setShowModal(false)}>
- + {chatRoomName} -
+ ); }; -const InviteFriendModalHeadeContainer = styled.div` +const InviteFriendModalHeaderContainer = styled.div` display: flex; flex-direction: column; padding: 1rem 1rem 0px 1rem; diff --git a/src/components/molecules/Div/LoginModalBody.tsx b/src/components/molecules/Div/LoginModalBody.tsx new file mode 100644 index 0000000..41ba6fe --- /dev/null +++ b/src/components/molecules/Div/LoginModalBody.tsx @@ -0,0 +1,29 @@ +import LinkText from "@components/atoms/Text/LinkText"; +import { Ref } from "react"; +import styled from "styled-components"; +import LoginForm from "../Form/LoginForm"; + +interface LoginModalBodyProps { + refs: { + emailRef: Ref; + passwordRef: Ref; + }; +} + +const LoginModalBody = ({ refs }: LoginModalBodyProps) => { + return ( + <> + + + + null} /> + + + ); +}; + +const LinkTextContainer = styled.div` + margin: -1rem 0 1.25rem; +`; + +export default LoginModalBody; diff --git a/src/components/molecules/Div/LoginModalFooter.tsx b/src/components/molecules/Div/LoginModalFooter.tsx new file mode 100644 index 0000000..a3f9d63 --- /dev/null +++ b/src/components/molecules/Div/LoginModalFooter.tsx @@ -0,0 +1,49 @@ +import DefaultButton from "@components/atoms/Button/DefaultButton"; +import LinkText from "@components/atoms/Text/LinkText"; +import Text from "@components/atoms/Text/Text"; +import useLogin from "@hooks/query/useLogin"; +import validateEmail from "@utils/validateEmail"; +import { Dispatch, SetStateAction, useCallback } from "react"; +import { useNavigate } from "react-router-dom"; + +interface LoginModalFooterProps { + refs: any; + setErrorMessage: Dispatch>; +} + +const LoginModalFooter = ({ refs, setErrorMessage }: LoginModalFooterProps) => { + const navigate = useNavigate(); + const { mutate: login } = useLogin(setErrorMessage); + const { emailRef, passwordRef } = refs; + + const goRegisterPage = useCallback(() => navigate("/register"), []); + + const onLogin = useCallback(() => { + if (!emailRef.current.value || !passwordRef.current.value) { + return setErrorMessage("모든 값을 입력해주세요."); + } + if (!validateEmail(emailRef.current.value)) { + return setErrorMessage("유효하지 않은 아이디입니다."); + } + if (passwordRef.current.value.length < 8) { + return setErrorMessage("비밀번호는 8자리 이상이어야 합니다."); + } + setErrorMessage(""); + login({ + email: emailRef.current.value, + password: passwordRef.current.value, + }); + }, [refs]); + + return ( + <> + + + 계정이 필요한가요? + + + + ); +}; + +export default LoginModalFooter; diff --git a/src/components/molecules/Div/LoginModalHeader.tsx b/src/components/molecules/Div/LoginModalHeader.tsx new file mode 100644 index 0000000..606ed1d --- /dev/null +++ b/src/components/molecules/Div/LoginModalHeader.tsx @@ -0,0 +1,22 @@ +import ErrorText from "@components/atoms/Text/ErrorText"; +import Text from "@components/atoms/Text/Text"; +import { memo } from "react"; +import AuthDesc from "../Text/AuthDesc"; + +interface LoginModalHeaderProps { + errorMessage: string; +} + +const LoginModalHeader = memo(({ errorMessage }: LoginModalHeaderProps) => { + return ( + <> + + 돌아오신 것을 환영해요! + + + {errorMessage && } + + ); +}); + +export default LoginModalHeader; diff --git a/src/components/molecules/Div/LogoSet.tsx b/src/components/molecules/Div/LogoSet.tsx index f8794bd..7f70a95 100644 --- a/src/components/molecules/Div/LogoSet.tsx +++ b/src/components/molecules/Div/LogoSet.tsx @@ -4,7 +4,7 @@ import ImageUploadButton from "../Button/ImageUploadButton"; const LogoSet = () => { <> - + 최소 크기 128*128 이상 ; }; diff --git a/src/components/molecules/Div/MessageBox.tsx b/src/components/molecules/Div/MessageBox.tsx index 2c8014d..dad54c3 100644 --- a/src/components/molecules/Div/MessageBox.tsx +++ b/src/components/molecules/Div/MessageBox.tsx @@ -18,9 +18,8 @@ const MessageBox = ({ onChange, addChatMessage, }: MessageInputProps) => { - // const messageRef = useRef(null); - - const dropdownRef = useRef(false); + const messageRef = useRef(null); + const dropdownRef = useRef(null); const [showUploadDropdown, setShowUploadDropdown] = useState(false); useOutsideClick(dropdownRef, () => setShowUploadDropdown(false)); @@ -55,7 +54,7 @@ const MessageBox = ({ {showUploadDropdown && } theme.backgroundColor["msg-input"]}; - padding: 0 1rem; `; const AddButton = styled.button` height: 44px; padding: 0.625rem 1rem; margin-left: -1rem; + color: ${({ theme }) => theme.color.icon}; background-color: transparent; + &:hover { color: ${({ theme }) => theme.color.white}; } diff --git a/src/components/molecules/Div/RegisterStep1Body.tsx b/src/components/molecules/Div/RegisterStep1Body.tsx new file mode 100644 index 0000000..5c0b3e3 --- /dev/null +++ b/src/components/molecules/Div/RegisterStep1Body.tsx @@ -0,0 +1,17 @@ +import DefaultForm from "../Form/DefaultForm"; + +const RegisterStep1Body = ({ refs }: any) => { + return ( + <> + + 이메일 + + 사용자명 + + 비밀번호 + + + ); +}; + +export default RegisterStep1Body; diff --git a/src/components/molecules/Div/RegisterStep1Footer.tsx b/src/components/molecules/Div/RegisterStep1Footer.tsx new file mode 100644 index 0000000..5bf1d8f --- /dev/null +++ b/src/components/molecules/Div/RegisterStep1Footer.tsx @@ -0,0 +1,66 @@ +import DefaultButton from "@components/atoms/Button/DefaultButton"; +import LinkText from "@components/atoms/Text/LinkText"; +import useSendEmail from "@hooks/query/useSendEmail"; +import { useRegisterStore } from "@store/useRegisterStore"; +import validateEmail from "@utils/validateEmail"; +import { useCallback } from "react"; +import { useNavigate } from "react-router-dom"; + +const RegisterStep1Footer = ({ refs, setErrorMessage }: any) => { + const navigate = useNavigate(); + + const { setStep, setEmail, setName, setPassword } = useRegisterStore(); + + const { mutate: sendEmail } = useSendEmail({ + onError: () => { + setErrorMessage("문제가 발생했습니다. 다시 시도해주세요."); + }, + onSuccess: () => { + setStep(2); + }, + }); + + const goLoginPage = useCallback(() => navigate("/login"), []); + + const validateInputs = (email: string) => { + if ( + !refs.emailRef.current || + !refs.nameRef.current || + !refs.passwordRef.current + ) { + return setErrorMessage("모든 값을 입력해주세요."); + } + + if (!validateEmail(email) || email.length < 8) { + return setErrorMessage("유효하지 않은 아이디 또는 비밀번호입니다."); + } + }; + + const registerUser = useCallback(() => { + const email = refs.emailRef.current.value; + const name = refs.nameRef.current.value; + const password = refs.passwordRef.current.value; + + validateInputs(email); + + setErrorMessage(""); + setEmail(email); + setName(name); + setPassword(password); + sendEmail({ email, name, password }); + }, [refs]); + + return ( + <> + + + + ); +}; + +export default RegisterStep1Footer; diff --git a/src/components/molecules/Div/RegisterStep1Header.tsx b/src/components/molecules/Div/RegisterStep1Header.tsx new file mode 100644 index 0000000..62c2c84 --- /dev/null +++ b/src/components/molecules/Div/RegisterStep1Header.tsx @@ -0,0 +1,17 @@ +import ErrorText from "@components/atoms/Text/ErrorText"; +import AuthHeader from "../Text/AuthHeader"; + +interface RegisterStep1HeaderProps { + errorMessage: string; +} + +const RegisterStep1Header = ({ errorMessage }: RegisterStep1HeaderProps) => { + return ( + <> + + {errorMessage && } + + ); +}; + +export default RegisterStep1Header; diff --git a/src/components/molecules/Div/RegisterStep2Body.tsx b/src/components/molecules/Div/RegisterStep2Body.tsx new file mode 100644 index 0000000..b955e3c --- /dev/null +++ b/src/components/molecules/Div/RegisterStep2Body.tsx @@ -0,0 +1,27 @@ +import LinkText from "@components/atoms/Text/LinkText"; +import useRegister from "@hooks/query/useRegister"; +import { useRegisterStore } from "@store/useRegisterStore"; +import { forwardRef, useCallback } from "react"; +import DefaultForm from "../Form/DefaultForm"; + +const RegisterStep2Body = forwardRef((props, ref) => { + const { email, name, password } = useRegisterStore(); + + const { mutate: sendEmail } = useRegister(); + + const resendEmail = useCallback(() => { + sendEmail({ email, name, password }); + }, [email, name, password]); + + return ( + <> + 인증 코드 + + + ); +}); + +export default RegisterStep2Body; diff --git a/src/components/molecules/Div/RegisterStep2Footer.tsx b/src/components/molecules/Div/RegisterStep2Footer.tsx new file mode 100644 index 0000000..00c0cf1 --- /dev/null +++ b/src/components/molecules/Div/RegisterStep2Footer.tsx @@ -0,0 +1,46 @@ +import DefaultButton from "@components/atoms/Button/DefaultButton"; +import useSendUserCode from "@hooks/query/useSendUserCode"; +import { useRegisterStore } from "@store/useRegisterStore"; +import { useCallback } from "react"; +import styled from "styled-components"; + +const RegisterStep2Footer = ({ emailCodeCurrent, setErrorMessage }: any) => { + const { setStep } = useRegisterStore(); + + const { mutate: sendUserCode } = useSendUserCode({ + onError: () => { + setErrorMessage("인증 코드를 다시 입력해주세요."); + }, + onSuccess: () => { + setStep(3); + }, + }); + + const verifyEmail = useCallback(() => { + const emailCode = emailCodeCurrent.value; + + if (!emailCode) { + return setErrorMessage("코드를 입력해주세요."); + } + sendUserCode(emailCode); + }, [emailCodeCurrent]); + + return ( +
+ +
+ ); +}; + +const Footer = styled.div` + margin-top: 24px; + display: flex; + justify-content: end; +`; + +export default RegisterStep2Footer; diff --git a/src/components/molecules/Div/RegisterStep2Header.tsx b/src/components/molecules/Div/RegisterStep2Header.tsx new file mode 100644 index 0000000..1f4b19d --- /dev/null +++ b/src/components/molecules/Div/RegisterStep2Header.tsx @@ -0,0 +1,23 @@ +import Text from "@components/atoms/Text/Text"; +import AuthDesc from "../Text/AuthDesc"; +import AuthHeader from "../Text/AuthHeader"; + +interface RegisterStep2HeaderProps { + errorMessage: string; +} + +const RegisterStep2Header = ({ errorMessage }: RegisterStep2HeaderProps) => { + return ( + <> + + + {errorMessage && ( + + {errorMessage} + + )} + + ); +}; + +export default RegisterStep2Header; diff --git a/src/components/molecules/Div/SelectFriend.tsx b/src/components/molecules/Div/SelectFriend.tsx index 879fdb4..731dee3 100644 --- a/src/components/molecules/Div/SelectFriend.tsx +++ b/src/components/molecules/Div/SelectFriend.tsx @@ -16,7 +16,7 @@ const SelectFriend = ({ check = false, status }: SelectFriendProps) => { - + name {check ? : } diff --git a/src/components/molecules/Div/UserChannelOnBox.tsx b/src/components/molecules/Div/UserChannelOnBox.tsx index 4eb4eda..23f95dc 100644 --- a/src/components/molecules/Div/UserChannelOnBox.tsx +++ b/src/components/molecules/Div/UserChannelOnBox.tsx @@ -24,7 +24,7 @@ const UserChannelOnBox = ({ name, src }: UserChannelOnBoxProps) => { height={1.5} onClick={() => null} /> - + {name || myname}
diff --git a/src/components/molecules/Div/UserFriendChannelOnBox.tsx b/src/components/molecules/Div/UserFriendChannelOnBox.tsx index 802bb20..9acba43 100644 --- a/src/components/molecules/Div/UserFriendChannelOnBox.tsx +++ b/src/components/molecules/Div/UserFriendChannelOnBox.tsx @@ -17,7 +17,7 @@ const UserFriendChannelOnBox = ({ ); } - return <>; + return null; }; export default UserFriendChannelOnBox; diff --git a/src/components/molecules/Div/UserProfilePage.tsx b/src/components/molecules/Div/UserProfilePage.tsx index aebaac8..fa3fa72 100644 --- a/src/components/molecules/Div/UserProfilePage.tsx +++ b/src/components/molecules/Div/UserProfilePage.tsx @@ -2,12 +2,11 @@ import styled from "styled-components"; import FieldButton from "../../atoms/Button/fieldButton"; import Text from "../../atoms/Text/Text"; import LinkText from "../../atoms/Text/LinkText"; -import UserSettingImageModal from "../Modal/UserSettingImageModal"; import useSettingModalStore from "@store/useSettingModalStore"; const UserProfilePage = () => { - const { showSettingModal, setShowSettingModal, setSettingModalType } = - useSettingModalStore(); + const { setShowSettingModal, setSettingModalType } = useSettingModalStore(); + const showModal = () => { setShowSettingModal(true); setSettingModalType("image"); @@ -15,15 +14,13 @@ const UserProfilePage = () => { return ( - {showSettingModal && } - + + 유저프로필 + + + 아바타 + diff --git a/src/components/molecules/Div/UserSettingGeneralTab.tsx b/src/components/molecules/Div/UserSettingGeneralTab.tsx index 73a1ad4..aa67bca 100644 --- a/src/components/molecules/Div/UserSettingGeneralTab.tsx +++ b/src/components/molecules/Div/UserSettingGeneralTab.tsx @@ -36,15 +36,19 @@ const UserSettingGeneralTab = () => { image: , }; - const Component = settingModalType ? modalTable[settingModalType] : <>; + const component = settingModalType ? modalTable[settingModalType] : null; return ( - {showSettingModal && Component} + {showSettingModal && component} - - + + 사용자명 + + + {userInfo.name} + { - - + + 이메일 + + + {userInfo.email} + {/* { - - + + 비밀번호 + + + ******** + showModal("password")} /> @@ -78,8 +90,12 @@ const UserSettingGeneralTab = () => { - - + + 자기소개 + + + {userInfo.introduction} + showModal("intro")} /> diff --git a/src/components/molecules/Form/DefaultForm.tsx b/src/components/molecules/Form/DefaultForm.tsx index 7a59045..015c739 100644 --- a/src/components/molecules/Form/DefaultForm.tsx +++ b/src/components/molecules/Form/DefaultForm.tsx @@ -1,36 +1,31 @@ import DefaultInput from "@components/atoms/Input/DefaultInput"; import Text from "@components/atoms/Text/Text"; -import { ChangeEvent } from "react"; +import { forwardRef, ReactNode } from "react"; import styled from "styled-components"; interface DefaultFormProps { - text: string | React.ReactElement; - value: string; - onChange: (e: ChangeEvent) => void; type?: string; formType?: "auth" | "community"; + children: ReactNode; } -const DefaultForm = ({ - text, - value, - onChange, - type = "text", - formType = "auth", -}: DefaultFormProps) => { - return ( - - - - - ); -}; +const DefaultForm = forwardRef( + ({ type = "text", formType = "auth", children }, ref) => { + return ( + + + {children} + + + + ); + } +); const DefaultFormContainer = styled.div` margin-bottom: 1.25rem; diff --git a/src/components/molecules/Form/LoginForm.tsx b/src/components/molecules/Form/LoginForm.tsx index 86b497e..d741db9 100644 --- a/src/components/molecules/Form/LoginForm.tsx +++ b/src/components/molecules/Form/LoginForm.tsx @@ -1,35 +1,21 @@ import SpanText from "@components/atoms/Text/SpanText"; -import { ChangeEvent } from "react"; +import { forwardRef } from "react"; import DefaultForm from "./DefaultForm"; interface LoginFormProps { text: string; - value: string; - onChange: (e: ChangeEvent) => void; type?: string; } -const LoginForm = ({ - text, - value, - onChange, - type = "text", -}: LoginFormProps) => { - return ( +const LoginForm = forwardRef( + ({ text, type = "text" }, ref) => ( <> - - {text} - - - } - type={type} - value={value} - onChange={onChange} - /> + + {text} + + - ); -}; + ) +); export default LoginForm; diff --git a/src/components/molecules/Input/InviteCommunityInput.tsx b/src/components/molecules/Input/InviteCommunityInput.tsx index f5d42db..164a8c2 100644 --- a/src/components/molecules/Input/InviteCommunityInput.tsx +++ b/src/components/molecules/Input/InviteCommunityInput.tsx @@ -7,14 +7,12 @@ interface InviteCommunityInputProps { url: string; } -const InviteCommunityInput = ({ url }: InviteCommunityInputProps) => { - return ( - - null} type="text" /> - null} width={75} height={32} /> - - ); -}; +const InviteCommunityInput = ({ url }: InviteCommunityInputProps) => ( + + + null} width={75} height={32} /> + +); const InviteCommunityInputContainer = styled.label` ${flexCenter} diff --git a/src/components/molecules/Input/InviteInput.tsx b/src/components/molecules/Input/InviteInput.tsx index 02f7764..b01707d 100644 --- a/src/components/molecules/Input/InviteInput.tsx +++ b/src/components/molecules/Input/InviteInput.tsx @@ -4,7 +4,7 @@ import Text from "@components/atoms/Text/Text"; import useRequestFriend from "@hooks/query/useRequestFriend"; import { useUserStore } from "@store/useUserStore"; import { useQueryClient } from "@tanstack/react-query"; -import { ChangeEvent, useState } from "react"; +import { useRef, useState } from "react"; import { useNavigate } from "react-router-dom"; import styled from "styled-components"; @@ -12,15 +12,20 @@ const InviteInput = () => { const navigate = useNavigate(); const queryClient = useQueryClient(); const { userInfo } = useUserStore(); - const [email, setEmail] = useState(""); + + const emailRef = useRef(null); const [status, setStatus] = useState("default"); + const { mutate: requestFriend } = useRequestFriend({ + onMutate: () => { + if (emailRef?.current) { + emailRef.current.value = ""; + } + }, onError: () => { - setEmail(""); setStatus("danger"); }, onSuccess: () => { - setEmail(""); setStatus("success"); }, onSettled: () => { @@ -28,32 +33,25 @@ const InviteInput = () => { }, }); - const onChange = ({ target: { value } }: ChangeEvent) => { - setEmail(value); - if (status !== "default") { - setStatus("default"); - } - }; - const inviteFriend = () => { if (!userInfo) navigate("/login"); - requestFriend({ email }); + if (emailRef?.current) { + requestFriend({ email: emailRef.current.value }); + } }; return ( <> { /> {status === "success" && ( - + + {emailRef?.current && emailRef.current.value}에게 성공적으로 친구 + 요청을 보냈어요. + )} {status === "danger" && ( - + + 음, 안되네요. 이메일이 정확한지 다시 한 번 확인해주세요. + )} ); @@ -80,9 +77,11 @@ const InviteInput = () => { const InviteInputContainer = styled.label<{ borderColor: any }>` width: 100%; height: 3.125rem; + display: flex; flex-direction: row; align-items: center; + background-color: ${({ theme }) => theme.backgroundColor.tab1}; border-radius: 0.5rem; border: 2px solid diff --git a/src/components/molecules/Input/SearchInput.stories.tsx b/src/components/molecules/Input/SearchInput.stories.tsx index ac43db4..c56ab3e 100644 --- a/src/components/molecules/Input/SearchInput.stories.tsx +++ b/src/components/molecules/Input/SearchInput.stories.tsx @@ -1,4 +1,3 @@ -import { useState } from "react"; import SearchInput from "./SearchInput"; export default { @@ -6,7 +5,4 @@ export default { component: SearchInput, }; -export const Search = () => { - const [value, setValue] = useState(""); - return setValue(value)} />; -}; +export const Search = () => ; diff --git a/src/components/molecules/Input/SearchInput.tsx b/src/components/molecules/Input/SearchInput.tsx index c7f785c..9b67dce 100644 --- a/src/components/molecules/Input/SearchInput.tsx +++ b/src/components/molecules/Input/SearchInput.tsx @@ -1,46 +1,42 @@ import SearchIcon from "@components/atoms/Icons/SearchIcon"; import DefaultInput from "@components/atoms/Input/DefaultInput"; -import { ChangeEventHandler } from "react"; +import { forwardRef } from "react"; import styled from "styled-components"; type SizeType = "s" | "m"; interface SearchInputProps { size: SizeType; - value: string; - onChange: ChangeEventHandler; placeholder?: string; } -const SearchInput = ({ - size, - value, - onChange, - placeholder = "검색하기", -}: SearchInputProps) => { - return ( - - - - - ); -}; +const SearchInput = forwardRef( + ({ size, placeholder = "검색하기" }, ref) => { + return ( + + + + + ); + } +); const SearchInputContainer = styled.label<{ size: SizeType }>` border-radius: 0.25rem; min-width: 144px; width: 100%; height: ${({ size }) => (size === "s" ? 1.5 : 2.125)}rem; + padding: 0 0.125rem; + background-color: ${({ theme }) => theme.backgroundColor.tab1}; + display: flex; flex-direction: row; align-items: center; - padding: 0 0.125rem; - background-color: ${({ theme }) => theme.backgroundColor.tab1}; + svg { font-size: ${({ theme, size }) => theme.fontSize[size === "s" ? "lg" : "xxl"]}; diff --git a/src/components/molecules/Modal/CreateCategoryModal.tsx b/src/components/molecules/Modal/CreateCategoryModal.tsx index 4eae91d..4653a0e 100644 --- a/src/components/molecules/Modal/CreateCategoryModal.tsx +++ b/src/components/molecules/Modal/CreateCategoryModal.tsx @@ -1,14 +1,8 @@ import styled from "styled-components"; -import useInput from "@hooks/common/useInput"; import DefaultInput from "@components/atoms/Input/DefaultInput"; -import { useMutation } from "@tanstack/react-query"; -import { useNavigate, useParams } from "react-router-dom"; -import { useUserStore } from "@store/useUserStore"; -import { useState } from "react"; -import communityApi from "@api/community"; -import CreateCommunityText from "@components/molecules/Text/CreateCommunityText"; +import { useParams } from "react-router-dom"; +import { useCallback, useRef, useState } from "react"; import BackgroundModal from "@components/organisms/BackgroundModal"; -import ImageUploadButton from "@components/molecules/Button/ImageUploadButton"; import DefaultButton from "@components/atoms/Button/DefaultButton"; import CancelIcon from "@components/atoms/Icons/CancelIcon"; import useModalStore from "@store/useModalStore"; @@ -16,26 +10,24 @@ import Text from "@components/atoms/Text/Text"; import useCreateCategory from "@hooks/query/useCreateCatergory"; const CreateCategroyModal = () => { - const navigate = useNavigate(); - - const { userInfo } = useUserStore(); const { setShowModal } = useModalStore(); - const [name, changeName] = useInput(); - const [type, setType] = useState(); - const [role, setRole] = useState(0); + + const inputRef = useRef(null); //userInfo에 role이 없었던가? - const [categoryId, setCategoryId] = useState(); const { communityId } = useParams(); const { mutate: createCategory } = useCreateCategory(); - const MakeCategory = () => { - createCategory({ name, communityId, role }); - closeModal(); - }; + const MakeCategory = useCallback(() => { + if (inputRef.current) { + const name = inputRef.current.value; + createCategory({ name, communityId, role: 0 }); + closeModal(); + } + }, [inputRef]); - const closeModal = () => { + const closeModal = useCallback(() => { setShowModal(false); - }; + }, []); return ( @@ -45,11 +37,15 @@ const CreateCategroyModal = () => { - + + 카테고리 만들기 + - - + + 카테고리 이름 + + { - const navigate = useNavigate(); - - let formData = new FormData(); - - const { userInfo } = useUserStore(); const { setShowModal } = useModalStore(); - const [name, changeName] = useInput(); const { communityId } = useParams(); + const [type, setType] = useState(0); - const [role, setRole] = useState(0); - //userInfo에 role이 없었던가? - const [categoryId, setCategoryId] = useState(10); - // const { mutate: createChannel } = useMutation(communityApi.createChannel, { - // onSuccess: () => { - // navigate(-1); - // }, - // }); + const nameRef = useRef(null); + const { mutate: createChannel } = useCreateChannel(); + const MakeChannel = () => { - createChannel({ name, categoryId, communityId, type, role }); - closeModal(); + if (nameRef.current) { + const name = nameRef.current.value; + createChannel({ name, categoryId: 10, communityId, type, role: 0 }); + closeModal(); + } }; const closeModal = () => { setShowModal(false); }; - const radioHandler = (event: React.ChangeEvent) => { + + const handleRadio = (event: React.ChangeEvent) => { setType(event.target.value === "CHAT" ? 0 : 1); - console.log(type); }; return ( - <> - - - - - - - - - -
- - -
- -
- - - - - + + + + + + 채널 만들기 + + + :채팅에 속해있음 + + + + + 채널 이름 + +
+ + +
+ +
+ + + +
); }; diff --git a/src/components/molecules/Modal/UserSettingImageModal.tsx b/src/components/molecules/Modal/UserSettingImageModal.tsx index c5e9e49..6a43199 100644 --- a/src/components/molecules/Modal/UserSettingImageModal.tsx +++ b/src/components/molecules/Modal/UserSettingImageModal.tsx @@ -1,4 +1,4 @@ -import FieldButton from "@components/atoms/Button/fieldButton"; +import DefaultButton from "@components/atoms/Button/DefaultButton"; import BackgroundModal from "@components/organisms/BackgroundModal"; import useModifyUserImage from "@hooks/query/useModifyUserImage"; import useSettingModalStore from "@store/useSettingModalStore"; @@ -11,20 +11,23 @@ const UserSettingImageModal = () => { const formData = new FormData(); const [img, setImg] = useState(); const { userInfo, setUserInfo } = useUserStore(); - const { showSettingModal, setShowSettingModal } = useSettingModalStore(); - - const updateImage = () => { - if (!img) return; - formData.append("file", img); - modifyImage({ formData }); - }; + const { setShowSettingModal } = useSettingModalStore(); const { mutate: modifyImage } = useModifyUserImage({ onSuccess: (data: any) => { setUserInfo({ ...userInfo, profileImagePath: data.data.data }); + + closeModal(); }, }); + const updateImage = () => { + if (!img) return; + + formData.append("file", img); + modifyImage({ formData }); + }; + const closeModal = () => { setShowSettingModal(false); }; @@ -35,31 +38,59 @@ const UserSettingImageModal = () => { p={0} onClick={closeModal} children={ - - - - - - + + + + + + + + + } /> ); }; -const Wrapper = styled.div` +const ModalContainer = styled.div` width: 100%; + display: flex; flex-direction: column; align-items: center; - position: relative; - padding: 1rem; + background-color: ${({ theme }) => theme.backgroundColor["tab3"]}; + border-radius: 6px; +`; + +const BodyContainer = styled.div` + padding: 2rem; `; -const AvatarWrapper = styled.div` - height: 32px; - width: 8.5; - width: 10rem; +const BottomContainer = styled.div` + display: flex; + align-items: center; + justify-content: space-between; + + width: 100%; + height: 4rem; + padding: 1rem; + align-items: center; + background-color: ${({ theme }) => theme.backgroundColor["voice-nobody"]}; + border-bottom-left-radius: 0.375rem; + border-bottom-right-radius: 0.375rem; `; export default UserSettingImageModal; diff --git a/src/components/molecules/Modal/UserSettingIntroModal.tsx b/src/components/molecules/Modal/UserSettingIntroModal.tsx index b71da41..282613c 100644 --- a/src/components/molecules/Modal/UserSettingIntroModal.tsx +++ b/src/components/molecules/Modal/UserSettingIntroModal.tsx @@ -31,24 +31,22 @@ const UserSettingIntroModal = () => {
- + > + 자기소개 작성하기 + + + 한줄로 자기소개를 작성해주세요! + {
- + > + 사용자명 변경하기 + + + 새 사용자명과 기존 비밀번호를 입력하세요. + - + + 사용자명 + { - + + 현재 비밀번호 + { const [originalPassword, changeOriginalPassword] = useInput(); const { mutate: modifyPassword } = useModifyPassword(); + const OnChangePw = () => { modifyPassword({ password, originalPassword, }); }; + return ( {
- + > + 비밀번호를 바꿔주세요 + + + 현재 비밀번호와 새 비밀번호를 입력하세요. + - + + 현재 비밀번호 + { /> - + + 새 비밀번호 + { /> - + + 새 비밀번호 확인 + { - return ; -}; +const AuthDesc = memo(({ text }: AuthDescProps) => ( + + {text} + +)); export default AuthDesc; diff --git a/src/components/molecules/Text/AuthHeader.tsx b/src/components/molecules/Text/AuthHeader.tsx index a71f679..8d58e02 100644 --- a/src/components/molecules/Text/AuthHeader.tsx +++ b/src/components/molecules/Text/AuthHeader.tsx @@ -1,20 +1,14 @@ import Text from "@components/atoms/Text/Text"; +import { memo } from "react"; interface AuthHeaderProps { text: string; } -const AuthHeader = ({ text }: AuthHeaderProps) => { - return ( - - ); -}; +const AuthHeader = memo(({ text }: AuthHeaderProps) => ( + + {text} + +)); export default AuthHeader; diff --git a/src/components/molecules/Text/CreateCommunityText.tsx b/src/components/molecules/Text/CreateCommunityText.tsx index ca7caf7..e7dcd12 100644 --- a/src/components/molecules/Text/CreateCommunityText.tsx +++ b/src/components/molecules/Text/CreateCommunityText.tsx @@ -4,19 +4,13 @@ import styled from "styled-components"; const CreateCommunityText = () => { return ( - - + + 서버 커스터마이징하기 + + + 새로운 서버에 이름과 아이콘을 부여해 개성을 드러내 보세요. 나중에 언제든 + 바꿀 수 있어요. + ); }; diff --git a/src/components/molecules/Text/LabelText.tsx b/src/components/molecules/Text/LabelText.tsx index 0ef48c3..2697edb 100644 --- a/src/components/molecules/Text/LabelText.tsx +++ b/src/components/molecules/Text/LabelText.tsx @@ -9,12 +9,9 @@ interface LabelTextProps { const LabelText = ({ label = "온라인", num }: LabelTextProps) => { return ( - + + {label} - {num}명 + ); }; diff --git a/src/components/organisms/BackgroundModal.tsx b/src/components/organisms/BackgroundModal.tsx index 44793ad..0237694 100644 --- a/src/components/organisms/BackgroundModal.tsx +++ b/src/components/organisms/BackgroundModal.tsx @@ -1,11 +1,11 @@ import useModalStore from "@store/useModalStore"; import { flexCenter } from "@styles/flexCenter"; -import { ReactElement } from "react"; +import { ReactNode } from "react"; import styled from "styled-components"; import ModalContainer from "../atoms/Div/ModalContainer"; interface BackgroundModalProps { - children: ReactElement; + children: ReactNode; width: number; p: number; onClick?: () => void; diff --git a/src/components/organisms/CommunityList.tsx b/src/components/organisms/CommunityList.tsx index 4dafb3f..03c8857 100644 --- a/src/components/organisms/CommunityList.tsx +++ b/src/components/organisms/CommunityList.tsx @@ -7,31 +7,27 @@ import ScrollableBox from "@components/molecules/Div/scrollableBox"; import useGetCommunityList from "@hooks/query/useGetCommunityList"; import OdugiLogo from "../../assets/images/logo.jpg"; import useModalStore from "@store/useModalStore"; +import { useCallback } from "react"; const CommunityList = () => { const navigate = useNavigate(); - const params = useParams(); const { userInfo } = useUserStore(); const { setShowModal, setModalType } = useModalStore(); + const list = useGetCommunityList(); - const goMainPage = () => { + const goMainPage = useCallback(() => { navigate("/@me"); - }; - - if (!params) { - goMainPage(); - return null; - } - - const onCommunity = (communityId: Number) => { - navigate(`/${communityId}`); - }; + }, []); - const createCommunity = () => { + const createCommunity = useCallback(() => { setShowModal(true); setModalType("createCommunity"); - }; + }, []); + + const onCommunity = useCallback((communityId: number) => { + navigate(`/${communityId}`); + }, []); return ( @@ -60,6 +56,7 @@ const CommunityList = () => { /> ))} + {list.length !== 0 && }
  • diff --git a/src/components/organisms/CommunityProfile.tsx b/src/components/organisms/CommunityProfile.tsx index 0fbfcff..ca72c1a 100644 --- a/src/components/organisms/CommunityProfile.tsx +++ b/src/components/organisms/CommunityProfile.tsx @@ -1,51 +1,46 @@ import DefaultForm from "@components/molecules/Form/DefaultForm"; -import useInput from "@hooks/common/useInput"; +import { useRef } from "react"; import styled from "styled-components"; import DropDown from "../atoms/Div/DropDown"; import Text from "../atoms/Text/Text"; const CommunityProfile = () => { - const [name, changeName] = useInput(); + const nameRef = useRef(null); + return ( + + 서버 프로필 + - - + + 참가 중인 서버마다 다른 프로필을 사용하여 보세요. + + + 서버 선택하기 + - + + 서버이름 + ); }; -export default CommunityProfile; - const ProfileWrapper = styled.div` text-align: left; + display: flex; flex-direction: column; `; const BlockWrapper = styled.div` - margin-bottom: 24px; - border-bottom: 0.25px solid ${({ theme }) => theme.color["setting-tab"]}; - padding-bottom: 16px; + margin-bottom: 1.5rem; + border-bottom: 0.25rem solid ${({ theme }) => theme.color["setting-tab"]}; + padding-bottom: 1rem; `; + +export default CommunityProfile; diff --git a/src/components/organisms/CommunitySettingBar.tsx b/src/components/organisms/CommunitySettingBar.tsx index 3b60c22..fa2786e 100644 --- a/src/components/organisms/CommunitySettingBar.tsx +++ b/src/components/organisms/CommunitySettingBar.tsx @@ -6,13 +6,9 @@ const CommunitySettingBar = () => { return (
    - + + 개별 서버 방 이름 +
    • diff --git a/src/components/organisms/CommunitySettingDefault.tsx b/src/components/organisms/CommunitySettingDefault.tsx index bc37571..5cd0b20 100644 --- a/src/components/organisms/CommunitySettingDefault.tsx +++ b/src/components/organisms/CommunitySettingDefault.tsx @@ -3,10 +3,9 @@ import SettingWrapper from "./SettingWrapper"; import FieldButton from "../atoms/Button/fieldButton"; import styled from "styled-components"; import ImageUploadButton from "../molecules/Button/ImageUploadButton"; -import { useState } from "react"; +import { useCallback, useRef, useState } from "react"; import { useUserStore } from "@store/useUserStore"; import { useParams } from "react-router-dom"; -import useInput from "@hooks/common/useInput"; import useDeleteCommunity from "@hooks/query/useDeleteCommnunity"; import useModifyCommunityImage from "@hooks/query/useModifyCommunityImage"; import DefaultInput from "@components/atoms/Input/DefaultInput"; @@ -18,7 +17,7 @@ const CommunitySettingDefault = () => { const { userInfo } = useUserStore(); const [img, setImg] = useState(); - const [name, changeName] = useInput(); + const nameRef = useRef(null); const { mutate: updateCommunityName } = useUpdateCommunityName(); const { mutate: modifyImage } = useModifyCommunityImage(); @@ -27,21 +26,21 @@ const CommunitySettingDefault = () => { userId: userInfo.id, }); - const changeCommunityName = () => { - updateCommunityName({ - communityName: name, - communityId, - userId: userInfo.id, - }); - }; + const changeCommunityName = useCallback(() => { + if (nameRef.current) + updateCommunityName({ + communityName: nameRef.current.value, + communityId, + userId: userInfo.id, + }); + }, [nameRef]); - const DeleteCommunity = () => { + const removeCommunity = useCallback(() => { if (!communityId) return; - deleteCommunity({ communityId, userId: userInfo.id }); - }; + }, []); - const changeImage = () => { + const changeImage = useCallback(() => { if (!communityId || !img) return; formData.append("communityId", communityId); @@ -49,30 +48,21 @@ const CommunitySettingDefault = () => { formData.append("img", img); modifyImage({ formData }); - }; + }, [img]); return ( - + + 서버 개요 + - - + + 서버 이미지 해상도는 최소 512*512를 추천해요. + + + 최소 크기: 128*128 + @@ -80,21 +70,15 @@ const CommunitySettingDefault = () => { - {/* */} - + diff --git a/src/components/organisms/CommunitySettingInvite.tsx b/src/components/organisms/CommunitySettingInvite.tsx index 13c516b..f9ded38 100644 --- a/src/components/organisms/CommunitySettingInvite.tsx +++ b/src/components/organisms/CommunitySettingInvite.tsx @@ -10,49 +10,58 @@ const CommunitySettingInvite = () => { return ( <> - - + + 초대 + + + 활성화된 모든 초대 링크 목록입니다. 이 중에서 취소가능합니다. + - + + 초대자 + - + + 초대코드 + - + + 사용 횟수 + - + + 남은시간 + null} /> - + + 김현우 + - + + 초대코드 + - + + 사용 횟수 + - + + 남은시간 + diff --git a/src/components/organisms/CommunitySettingMember.tsx b/src/components/organisms/CommunitySettingMember.tsx index fd12797..08035ca 100644 --- a/src/components/organisms/CommunitySettingMember.tsx +++ b/src/components/organisms/CommunitySettingMember.tsx @@ -7,25 +7,23 @@ import UserLogo from "../atoms/Div/UserLogo"; const CommunitySettingMember = () => { return ( - - + + 서버 멤버 + + + 멤버 총 x명 + null} /> - + + 김현우 + ); }; -export default CommunitySettingMember; - const Member = styled.div` display: flex; flex-direction: row; @@ -37,7 +35,4 @@ const Member = styled.div` border-bottom: 1px solid ${({ theme }) => theme.borderColor.divider}; ; `; -const Mini = styled.div` - display: flex; - flex-direction: column; -`; +export default CommunitySettingMember; diff --git a/src/components/organisms/CreateDirectMessageDropdown.tsx b/src/components/organisms/CreateDirectMessageDropdown.tsx index f7f66b5..b136227 100644 --- a/src/components/organisms/CreateDirectMessageDropdown.tsx +++ b/src/components/organisms/CreateDirectMessageDropdown.tsx @@ -37,8 +37,8 @@ const CreateDirectMessageDropdown = ({ p={16} > <> @@ -53,11 +53,9 @@ const CreateDirectMessageDropdown = ({ ) : ( - + + 개인 메시지에 모든 친구가 포함되어 있어요. + )} diff --git a/src/components/organisms/DirectMessageHeader.tsx b/src/components/organisms/DirectMessageHeader.tsx index e00f252..4905c7e 100644 --- a/src/components/organisms/DirectMessageHeader.tsx +++ b/src/components/organisms/DirectMessageHeader.tsx @@ -22,7 +22,7 @@ const DirectMessageHeader = ({ name, status }: DirectMessageHeaderProps) => { - + {name} @@ -38,7 +38,10 @@ const DirectMessageHeader = ({ name, status }: DirectMessageHeaderProps) => { - + diff --git a/src/components/organisms/FriendHeader.tsx b/src/components/organisms/FriendHeader.tsx index 5824d0d..85a9d98 100644 --- a/src/components/organisms/FriendHeader.tsx +++ b/src/components/organisms/FriendHeader.tsx @@ -9,7 +9,7 @@ import CreateDirectMessageModal from "./CreateDirectMessageDropdown"; const FriendHeader = () => { const [showDMDropdown, setShowDMDropdown] = useState(false); - const dropdownRef = useRef(); + const dropdownRef = useRef(null); useOutsideClick(dropdownRef, () => setShowDMDropdown(false)); diff --git a/src/components/organisms/MainDirectBody.tsx b/src/components/organisms/MainDirectBody.tsx index 117f513..f742876 100644 --- a/src/components/organisms/MainDirectBody.tsx +++ b/src/components/organisms/MainDirectBody.tsx @@ -25,7 +25,7 @@ const accessToken = localStorage.getItem("accessToken"); const MainDirectBody = () => { const { channelId = "" } = useParams(); - const scrollRef = useRef(null); + const scrollRef = useRef(null); const { userInfo } = useUserStore(); const [chatLog, setChatLog] = useState([]); const [message, setMessage] = useState(""); diff --git a/src/components/organisms/MainOnline.tsx b/src/components/organisms/MainOnline.tsx index 104ab02..2ab0e62 100644 --- a/src/components/organisms/MainOnline.tsx +++ b/src/components/organisms/MainOnline.tsx @@ -1,22 +1,21 @@ import FriendDefaultBox from "@components/molecules/Div/FriendDefaultBox"; -import useInput from "@hooks/common/useInput"; import useGetFriendList from "@hooks/query/useGetFriendList"; import { useUserStore } from "@store/useUserStore"; -import { useState } from "react"; +import { useRef } from "react"; import BigSearchInputBox from "../molecules/Div/BigSearchInputBox"; import EmptyContainer from "../molecules/Div/EmptyContainer"; import ScrollableBox from "../molecules/Div/scrollableBox"; import LabelText from "../molecules/Text/LabelText"; const MainOnline = () => { + const searchRef = useRef(null); + const { userInfo: { email }, } = useUserStore(); - const [num, setNum] = useState(0); const { data, isSuccess } = useGetFriendList(email); - const [value, onChangeValue] = useInput(); - if (!isSuccess) return <>; + if (!isSuccess) return null; const friendList: FriendType[] = data.filter( (friend: FriendType) => friend.friendState === "ACCEPTED" ); @@ -25,7 +24,7 @@ const MainOnline = () => { <> {friendList.length > 0 ? ( <> - + {friendList.map( @@ -38,7 +37,6 @@ const MainOnline = () => { profileImagePath, }) => ( { - const [num, setNum] = useState(0); + const searchRef = useRef(null); + const { setMainStatus } = useMainStore(({ setMainStatus }) => ({ setMainStatus, })); @@ -20,9 +20,8 @@ const MainTotal = () => { userInfo: { email }, } = useUserStore(); const { data, isSuccess } = useGetFriendList(email); - const [value, onChangeValue] = useInput(); - if (!isSuccess) return <>; + if (!isSuccess) return null; const friendList: FriendType[] = data.filter( (friend: FriendType) => friend.friendState === "ACCEPTED" ); @@ -31,7 +30,7 @@ const MainTotal = () => { <> {friendList.length > 0 ? ( <> - + {friendList.map( @@ -44,7 +43,6 @@ const MainTotal = () => { profileImagePath, }) => ( { + const searchRef = useRef(null); + const { userInfo: { email }, } = useUserStore(); const { data, isSuccess } = useGetFriendList(email); - const [value, onChangeValue] = useInput(); - if (!isSuccess) return <>; + if (!isSuccess) return null; const friendList: FriendType[] = data.filter( (friend: FriendState) => @@ -31,7 +32,7 @@ const MainWaiting = () => { <> {num > 0 ? ( <> - + {friendList.map( diff --git a/src/components/organisms/Modal/AuthModal.tsx b/src/components/organisms/Modal/AuthModal.tsx index edb06c5..c13f79d 100644 --- a/src/components/organisms/Modal/AuthModal.tsx +++ b/src/components/organisms/Modal/AuthModal.tsx @@ -1,6 +1,6 @@ +import ModalContainer from "@components/atoms/Div/ModalContainer"; import { flexCenter } from "@styles/flexCenter"; import styled from "styled-components"; -import ModalContainer from "../../atoms/Div/ModalContainer"; interface AuthModalProps { children: React.ReactElement; @@ -17,6 +17,7 @@ const AuthModal = ({ children, width }: AuthModalProps) => { const Background = styled.div` ${flexCenter} + width: 100vw; height: 100vh; `; diff --git a/src/components/organisms/Modal/CommunitySettingModal.tsx b/src/components/organisms/Modal/CommunitySettingModal.tsx index 1e47295..7bab614 100644 --- a/src/components/organisms/Modal/CommunitySettingModal.tsx +++ b/src/components/organisms/Modal/CommunitySettingModal.tsx @@ -1,19 +1,21 @@ import styled from "styled-components"; +import { useEffect, lazy } from "react"; import CommunitySettingBar from "../CommunitySettingBar"; -import CommunitySettingMember from "../CommunitySettingMember"; -import CommunitySettingDefault from "../CommunitySettingDefault"; -import CommunitySettingInvite from "../CommunitySettingInvite"; import CancelIcon from "@components/atoms/Icons/CancelIcon"; import useModalStore from "@store/useModalStore"; -import MyAccount from "../MyAccount"; -import UserProfile from "../UserProfile"; import useSettingModalStore from "@store/useSettingModalStore"; -import { useEffect } from "react"; +const CommunitySettingMember = lazy(() => import("../CommunitySettingMember")); +const CommunitySettingDefault = lazy( + () => import("../CommunitySettingDefault") +); +const CommunitySettingInvite = lazy(() => import("../CommunitySettingInvite")); +const UserSettingMyAccount = lazy(() => import("../UserSettingMyAccount")); +const UserSettingProfile = lazy(() => import("../UserSettingProfile")); const userComponent = { - "내 계정": , - 프로필: , - 알림: , + "내 계정": , + 프로필: , + 알림: , 일반: , 멤버: , 초대: , @@ -23,7 +25,7 @@ const CommunitySettingModal = () => { const { setShowModal } = useModalStore(); const { settingBarStatus, setSettingBarStatus } = useSettingModalStore(); - const Component = settingBarStatus ? userComponent[settingBarStatus] : <>; + const component = settingBarStatus ? userComponent[settingBarStatus] : null; const closeModal = () => { setShowModal(false); @@ -42,7 +44,7 @@ const CommunitySettingModal = () => { - {Component} + {component} ); @@ -55,14 +57,12 @@ const SettingBox = styled.div` top: 0; left: 0; + background-color: ${({ theme }) => theme.backgroundColor["voice-icon"]}; + display: flex; + flex-direction: row; justify-content: center; overflow: hidden; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: row; - background-color: ${({ theme }) => theme.backgroundColor["voice-icon"]}; `; const CancelIconWrapper = styled.div` @@ -71,6 +71,7 @@ const CancelIconWrapper = styled.div` position: absolute; right: 500px; top: 25px; + cursor: pointer; `; diff --git a/src/components/organisms/Modal/CreateCommunityModal.tsx b/src/components/organisms/Modal/CreateCommunityModal.tsx index 61b2509..370ea55 100644 --- a/src/components/organisms/Modal/CreateCommunityModal.tsx +++ b/src/components/organisms/Modal/CreateCommunityModal.tsx @@ -1,9 +1,6 @@ import styled from "styled-components"; -import useInput from "@hooks/common/useInput"; import DefaultInput from "@components/atoms/Input/DefaultInput"; -import { useNavigate } from "react-router-dom"; -import { useUserStore } from "@store/useUserStore"; -import { useState } from "react"; +import { useCallback, useRef, useState } from "react"; import CreateCommunityText from "@components/molecules/Text/CreateCommunityText"; import BackgroundModal from "../BackgroundModal"; import ImageUploadButton from "@components/molecules/Button/ImageUploadButton"; @@ -14,27 +11,24 @@ import Text from "@components/atoms/Text/Text"; import useCreateCommunity from "@hooks/query/useCreateCommunity"; const CreateCommunityModal = () => { - const navigate = useNavigate(); let formData = new FormData(); + const nameRef = useRef(null); + const [img, setImg] = useState(); const { setShowModal } = useModalStore(); + const { mutate: createCommunity } = useCreateCommunity(); - const [img, setImg] = useState(); - const [name, changeName] = useInput(); + const MakeCommunity = useCallback(() => { + if (!img || !nameRef?.current) return; - const { mutate: createCommunity } = useCreateCommunity(userInfo.id); - - const MakeCommunity = () => { - if (!img) return 0; - - formData.append("communityName", name); + formData.append("communityName", nameRef.current.value); formData.append("file", img); createCommunity({ formData }); - }; + }, [img, nameRef]); - const closeModal = () => { + const closeModal = useCallback(() => { setShowModal(false); - }; + }, []); return ( @@ -47,15 +41,17 @@ const CreateCommunityModal = () => { - - + + 서버 이름 + + diff --git a/src/components/organisms/Modal/UserSettingModal.tsx b/src/components/organisms/Modal/UserSettingModal.tsx index 94ff734..68ae2d4 100644 --- a/src/components/organisms/Modal/UserSettingModal.tsx +++ b/src/components/organisms/Modal/UserSettingModal.tsx @@ -1,8 +1,8 @@ import styled from "styled-components"; import CancelIcon from "@components/atoms/Icons/CancelIcon"; import useModalStore from "@store/useModalStore"; -import MyAccount from "../MyAccount"; -import UserProfile from "../UserProfile"; +import MyAccount from "../UserSettingMyAccount"; +import UserProfile from "../UserSettingProfile"; import useSettingModalStore from "@store/useSettingModalStore"; import CommunitySettingDefault from "../CommunitySettingDefault"; import CommunitySettingMember from "../CommunitySettingMember"; @@ -20,68 +20,71 @@ const userComponent = { }; const UserSettingModal = () => { - const { settingBarStatus, setSettingBarStatus } = useSettingModalStore(); const { setShowModal } = useModalStore(); + const { settingBarStatus, setSettingBarStatus } = useSettingModalStore(); - const Component = settingBarStatus ? userComponent[settingBarStatus] : <>; + const component = settingBarStatus ? userComponent[settingBarStatus] : null; useEffect(() => { setSettingBarStatus("내 계정"); }, []); return ( - - + + - - + + setShowModal(false)}> - {Component} - - + {component} + + ); }; -const CancelIconWrapper = styled.div` - font-size: 5rem; - color: ${({ theme }) => theme.color["auth-desc"]}; +const UserSettingModalContainer = styled.div` + width: 100vw; + height: 100vh; position: absolute; - right: 500px; - top: 25px; - - cursor: pointer; -`; + display: flex; + flex-direction: row; + justify-content: center; -const SettingBox = styled.div` - width: 100vw; - position: absolute; top: 0; - right: 0; - bottom: 0; left: 0; - display: flex; - justify-content: center; + overflow: hidden; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: row; background-color: ${({ theme }) => theme.backgroundColor["voice-icon"]}; `; -const Container = styled.div` + +const LeftSideContainer = styled.div` + display: flex; + justify-content: flex-end; + flex: 1 1 auto; +`; + +const CancelButtonWrapper = styled.div` position: relative; + display: flex; flex: 1 1 800px; align-items: flex-start; + background-color: ${({ theme }) => theme.backgroundColor["tab3"]}; `; -const Side = styled.div` - display: flex; - flex: 1 1 auto; - justify-content: flex-end; + +const CancelIconWrapper = styled.div` + font-size: 5rem; + color: ${({ theme }) => theme.color["auth-desc"]}; + position: absolute; + + right: 500px; + top: 25px; + + cursor: pointer; `; export default UserSettingModal; diff --git a/src/components/organisms/MyAccount.stories.tsx b/src/components/organisms/MyAccount.stories.tsx deleted file mode 100644 index d43609b..0000000 --- a/src/components/organisms/MyAccount.stories.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import MyAccount from "./MyAccount"; - -export default { - title: "Organisms/MyAccount", - component: MyAccount, -}; - -export const Account = () => { - return ; -}; diff --git a/src/components/organisms/MyAccount.tsx b/src/components/organisms/MyAccount.tsx deleted file mode 100644 index fa3f69a..0000000 --- a/src/components/organisms/MyAccount.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import Text from "../atoms/Text/Text"; -import AccountCard from "./AccountCard"; -import SettingWrapper from "./SettingWrapper"; -import { Divider } from "@mui/material"; -import FieldButton from "../atoms/Button/fieldButton"; -import styled from "styled-components"; -import useDeleteUser from "@hooks/query/useDeleteUser"; - -const MyAccount = () => { - const { mutate: deleteUser } = useDeleteUser(); - - return ( - - - - - - - deleteUser()} - backgroundColor="voice-hangup" - fontWeight="bold" - /> - - - ); -}; - -export default MyAccount; - -const ButtonWrapper = styled.div` - width: 7.5rem; - height: 2rem; -`; diff --git a/src/components/organisms/ProfileTab.stories.tsx b/src/components/organisms/ProfileTab.stories.tsx index a23fd04..83bac15 100644 --- a/src/components/organisms/ProfileTab.stories.tsx +++ b/src/components/organisms/ProfileTab.stories.tsx @@ -1,4 +1,4 @@ -import Tab from "./ProfileTab"; +import Tab from "./UserSettingProfileBody"; export default { title: "Organisms/MyAccount", diff --git a/src/components/organisms/ProtectHome.tsx b/src/components/organisms/ProtectHome.tsx index 7f34d25..ca57c84 100644 --- a/src/components/organisms/ProtectHome.tsx +++ b/src/components/organisms/ProtectHome.tsx @@ -1,6 +1,6 @@ import { COOKIE_KEY } from "@configs/cookie"; import { ReactElement } from "react"; -import { Navigate } from "react-router-dom"; +import { Navigate, useMatch, useParams } from "react-router-dom"; import { cookies } from "src/App"; interface ProtectAuthProps { @@ -8,12 +8,23 @@ interface ProtectAuthProps { } const ProtectPage = ({ children }: ProtectAuthProps) => { + const isBaseUrl = useMatch("/"); + const { communityId, channelId } = useParams(); + const cookie = cookies.get(COOKIE_KEY); const accessToken = localStorage.getItem("accessToken"); - return ( - <>{cookie && accessToken ? children : } - ); + const navigateUrl = () => { + if (cookie && accessToken) { + if (isBaseUrl || (!communityId && channelId)) { + return ; + } + return children; + } + return ; + }; + + return navigateUrl(); }; export default ProtectPage; diff --git a/src/components/organisms/RegisterStep1.tsx b/src/components/organisms/RegisterStep1.tsx index d763bdf..0d48946 100644 --- a/src/components/organisms/RegisterStep1.tsx +++ b/src/components/organisms/RegisterStep1.tsx @@ -1,69 +1,21 @@ -import useInput from "@hooks/common/useInput"; -import useSendEmail from "@hooks/query/useSendEmail"; -import { useRegisterStore } from "@store/useRegisterStore"; -import validateEmail from "@utils/validateEmail"; -import { useState } from "react"; -import { useNavigate } from "react-router-dom"; -import DefaultButton from "../atoms/Button/DefaultButton"; -import LinkText from "../atoms/Text/LinkText"; -import Text from "../atoms/Text/Text"; -import DefaultForm from "../molecules/Form/DefaultForm"; -import AuthHeader from "../molecules/Text/AuthHeader"; +import RegisterStep1Body from "@components/molecules/Div/RegisterStep1Body"; +import RegisterStep1Footer from "@components/molecules/Div/RegisterStep1Footer"; +import RegisterStep1Header from "@components/molecules/Div/RegisterStep1Header"; +import { useRef, useState } from "react"; const RegisterStep1 = () => { - const { setStep, setEmail, setName, setPassword } = useRegisterStore(); - const navigate = useNavigate(); - const [email, changeEmail] = useInput(); - const [name, changeName] = useInput(); - const [password, changePassword] = useInput(); - const [errorMessage, setErrorMessage] = useState(""); - - const { mutate: sendEmail } = useSendEmail(); + const emailRef = useRef(null); + const nameRef = useRef(null); + const passwordRef = useRef(null); + const refs = { emailRef, nameRef, passwordRef }; - const goLoginPage = () => navigate("/login"); - - const onRegister = () => { - if (!email || !name || !password) { - return setErrorMessage("모든 값을 입력해주세요."); - } - if (!validateEmail(email) || password.length < 8) { - return setErrorMessage("유효하지 않은 아이디 또는 비밀번호입니다."); - } - setErrorMessage(""); - setEmail(email); - setName(name); - setPassword(password); - sendEmail({ email, name, password }); - setStep(2); - }; + const [errorMessage, setErrorMessage] = useState(""); return ( <> - - {errorMessage && ( - - )} - - - - - + + + ); }; diff --git a/src/components/organisms/RegisterStep2.tsx b/src/components/organisms/RegisterStep2.tsx index 891dae5..1630a69 100644 --- a/src/components/organisms/RegisterStep2.tsx +++ b/src/components/organisms/RegisterStep2.tsx @@ -1,80 +1,22 @@ -import Text from "@components/atoms/Text/Text"; -import useInput from "@hooks/common/useInput"; -import useRegister from "@hooks/query/useRegister"; -import useSendUserCode from "@hooks/query/useSendUserCode"; -import { useRegisterStore } from "@store/useRegisterStore"; -import { useState } from "react"; -import styled from "styled-components"; -import DefaultButton from "../atoms/Button/DefaultButton"; -import LinkText from "../atoms/Text/LinkText"; -import DefaultForm from "../molecules/Form/DefaultForm"; -import AuthDesc from "../molecules/Text/AuthDesc"; -import AuthHeader from "../molecules/Text/AuthHeader"; +import RegisterStep2Body from "@components/molecules/Div/RegisterStep2Body"; +import RegisterStep2Footer from "@components/molecules/Div/RegisterStep2Footer"; +import RegisterStep2Header from "@components/molecules/Div/RegisterStep2Header"; +import { useRef, useState } from "react"; const RegisterStep2 = () => { const [errorMessage, setErrorMessage] = useState(""); - const { email, name, password, setStep } = useRegisterStore(); - const [userCode, onChangeUserCode] = useInput(); - - const { mutate: sendEmail } = useRegister(); - const { mutate: sendUserCode } = useSendUserCode({ - onError: () => { - setErrorMessage("인증 코드를 다시 입력해주세요."); - }, - onSuccess: () => { - setStep(3); - }, - }); - - const resendEmail = () => { - sendEmail({ email, name, password }); - }; - - const verifyEmail = () => { - if (!userCode) { - setErrorMessage("코드를 입력해주세요."); - } - sendUserCode(userCode); - }; + const emailCodeRef = useRef(null); return ( <> - - - {errorMessage && ( - - )} - + + - -
      - -
      ); }; -const Footer = styled.div` - margin-top: 24px; - display: flex; - justify-content: end; -`; - export default RegisterStep2; diff --git a/src/components/organisms/RegisterStep3.tsx b/src/components/organisms/RegisterStep3.tsx index 963fa73..b227976 100644 --- a/src/components/organisms/RegisterStep3.tsx +++ b/src/components/organisms/RegisterStep3.tsx @@ -4,18 +4,20 @@ import styled from "styled-components"; import DefaultButton from "../atoms/Button/DefaultButton"; import AuthHeader from "../molecules/Text/AuthHeader"; import emailImage from "../../assets/images/email.png"; +import { useCallback } from "react"; const RegisterStep3 = () => { + const navigate = useNavigate(); const { resetStep, resetInputs } = useRegisterStore( ({ resetStep, resetInputs }) => ({ resetStep, resetInputs }) ); - const navigate = useNavigate(); - const goLogin = () => { + const goLogin = useCallback(() => { resetStep(); navigate("/login"); resetInputs(); - }; + }, []); + return ( <> diff --git a/src/components/organisms/Tab2CommunityHeader.tsx b/src/components/organisms/Tab2CommunityHeader.tsx index 35d4028..1e551d7 100644 --- a/src/components/organisms/Tab2CommunityHeader.tsx +++ b/src/components/organisms/Tab2CommunityHeader.tsx @@ -1,21 +1,24 @@ import CommunityDropdown from "@components/molecules/Div/CommunityDropdown"; import useOutsideClick from "@hooks/common/useOutsideClick"; -import { useRef, useState } from "react"; +import { useCallback, useRef, useState } from "react"; import styled from "styled-components"; import ArrowBottomIcon from "../atoms/Icons/ArrowBottomIcon"; import Text from "../atoms/Text/Text"; const Tab2CommunityHeader = () => { - const dropdownRef = useRef(); const [showDropdown, setShowDropdown] = useState(false); - - useOutsideClick(dropdownRef, () => setShowDropdown(false)); + const dropdownRef = useRef(null); const communityName = "자바스크립트 스터디"; - const showCommunityDropdown = () => { + useOutsideClick( + dropdownRef, + useCallback(() => setShowDropdown(false), []) + ); + + const showCommunityDropdown = useCallback(() => { setShowDropdown((prev) => !prev); - }; + }, []); return ( { showModal={showDropdown} onClick={showCommunityDropdown} > - + {communityName} {showDropdown && } @@ -34,16 +37,20 @@ const Tab2HeaderContainer = styled.div<{ showModal: boolean }>` position: sticky; top: 0; padding: 0.75rem 1rem; + background-color: ${({ theme, showModal }) => + theme.backgroundColor[showModal ? "hover" : "trans"]}; + display: flex; flex-direction: row; align-items: center; justify-content: space-between; + cursor: pointer; - background-color: ${({ theme, showModal }) => - theme.backgroundColor[showModal ? "hover" : "trans"]}; + svg { color: ${({ theme }) => theme.color.icon}; } + &:hover { background-color: ${({ theme }) => theme.backgroundColor.hover}; } diff --git a/src/components/organisms/Tab2MainBody.tsx b/src/components/organisms/Tab2MainBody.tsx index 9ff48fc..6bb33dd 100644 --- a/src/components/organisms/Tab2MainBody.tsx +++ b/src/components/organisms/Tab2MainBody.tsx @@ -12,7 +12,7 @@ const Tab2MainBody = () => { }; const Tab2MainBodyContainer = styled.div` - margin: 8px 8px 0 8px; + margin: 0.5rem 0.5rem 0 0.5rem; flex: 1; `; diff --git a/src/components/organisms/Tab2MainHeader.tsx b/src/components/organisms/Tab2MainHeader.tsx index c61deac..1151641 100644 --- a/src/components/organisms/Tab2MainHeader.tsx +++ b/src/components/organisms/Tab2MainHeader.tsx @@ -10,7 +10,7 @@ const Tab2MainHeader = () => { }; const Tab2HeaderContainer = styled.div` - height: 48px; + height: 3rem; padding: 0 0.625rem; display: flex; diff --git a/src/components/organisms/Tab3CommunityHeader.tsx b/src/components/organisms/Tab3CommunityHeader.tsx index 3a208b6..bba0464 100644 --- a/src/components/organisms/Tab3CommunityHeader.tsx +++ b/src/components/organisms/Tab3CommunityHeader.tsx @@ -1,4 +1,3 @@ -import useInput from "@hooks/common/useInput"; import useOutsideClick from "@hooks/common/useOutsideClick"; import { useRef, useState } from "react"; import styled from "styled-components"; @@ -10,9 +9,9 @@ import SearchInput from "../molecules/Input/SearchInput"; const Tab3CommunityHeader = () => { const chatroomName = "test"; - const [value, onChange] = useInput(); const [showNotiModal, setShowNotiModal] = useState(false); - const dropdownRef = useRef(); + const searchRef = useRef(null); + const dropdownRef = useRef(null); useOutsideClick(dropdownRef, () => setShowNotiModal(false)); @@ -20,7 +19,7 @@ const Tab3CommunityHeader = () => { - + {chatroomName}
      @@ -30,7 +29,7 @@ const Tab3CommunityHeader = () => { {showNotiModal && }
      - +
      diff --git a/src/components/organisms/UserIntroChangeModal.tsx b/src/components/organisms/UserIntroChangeModal.tsx index 7050629..7b953ed 100644 --- a/src/components/organisms/UserIntroChangeModal.tsx +++ b/src/components/organisms/UserIntroChangeModal.tsx @@ -21,19 +21,12 @@ const UserIntroChangeModal = ({ setOpenModal3 }: any) => { <> - - + + 자기소개 작성하기 + + + 한줄로 자기소개를 작성해주세요! + {/* { fontWeight="bold" /> */} - updataIntro()} /> + ); }; -export default UserIntroChangeModal; - const Wrapper = styled.div` width: 100%; padding: 0.8rem 1rem 0 1rem; `; -const TextWrapper = styled.div` - text-align: center; - p { - text-align: center; - } -`; +const TextWrapper = styled.div``; const TopWrapper = styled.div` padding: 1rem; @@ -86,3 +72,5 @@ const Bottom = styled.div` padding: 1rem; background-color: ${({ theme }) => theme.backgroundColor["voice-nobody"]}; `; + +export default UserIntroChangeModal; diff --git a/src/components/organisms/UserNameChangeModal.tsx b/src/components/organisms/UserNameChangeModal.tsx index 7207f21..742b3fa 100644 --- a/src/components/organisms/UserNameChangeModal.tsx +++ b/src/components/organisms/UserNameChangeModal.tsx @@ -7,10 +7,12 @@ import useModifyName from "@hooks/query/useModifyName"; import DefaultButton from "@components/atoms/Button/DefaultButton"; const UserNameChangeModal = ({ setOpenModal }: any) => { - const { userInfo, setUserInfo } = useUserStore(); const [name, changeName] = useInput(); const [password, changePassword] = useInput(); + + const { userInfo, setUserInfo } = useUserStore(); const { mutate: modifyName } = useModifyName(); + const updataUserName = () => { modifyName({ name, @@ -19,57 +21,43 @@ const UserNameChangeModal = ({ setOpenModal }: any) => { setUserInfo({ ...userInfo, name }); setOpenModal(false); }; + return ( <> - - + + 사용자명 변경하기 + + + 새 사용자명과 기존 비밀번호를 입력하세요. + - + + 사용자명 + - + + 현재 비밀번호 + diff --git a/src/components/organisms/UserPasswordChangeModal.tsx b/src/components/organisms/UserPasswordChangeModal.tsx index a6841bf..53643b8 100644 --- a/src/components/organisms/UserPasswordChangeModal.tsx +++ b/src/components/organisms/UserPasswordChangeModal.tsx @@ -22,70 +22,51 @@ const UserPasswordChangeModal = ({ setOpenModal2 }: any) => { <> - - + + 비밀번호를 바꿔주세요. + + + 현재 비밀번호와 새 비밀번호를 입력하세요. + - + + 현재 비밀번호 + - + + 새 비밀번호 + - + + 새 비밀번호 확인 + @@ -96,19 +77,12 @@ const UserPasswordChangeModal = ({ setOpenModal2 }: any) => { ); }; -export default UserPasswordChangeModal; - const Wrapper = styled.div` width: 100%; padding: 0.8rem 1rem 0 1rem; `; -const TextWrapper = styled.div` - text-align: center; - p { - text-align: center; - } -`; +const TextWrapper = styled.div``; const TopWrapper = styled.div` padding: 1rem; @@ -122,3 +96,5 @@ const Bottom = styled.div` padding: 1rem; background-color: ${({ theme }) => theme.backgroundColor["voice-nobody"]}; `; + +export default UserPasswordChangeModal; diff --git a/src/components/organisms/UserProfile.tsx b/src/components/organisms/UserProfile.tsx deleted file mode 100644 index 01faece..0000000 --- a/src/components/organisms/UserProfile.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import Text from "../atoms/Text/Text"; -import { ProfileTab } from "./ProfileTab.stories"; -import Modal from "@components/organisms/Modal"; -import SettingWrapper from "./SettingWrapper"; -import { useCallback, useState } from "react"; -import styled from "styled-components"; -import DefaultButton from "@components/atoms/Button/DefaultButton"; -import ImageUploadButton from "@components/molecules/Button/ImageUploadButton"; - -const ImageChange = () => { - return ( - <> - - - - - null} /> - - - ); -}; - -const UserProfile = () => { - const [isOpenModal, setOpenModal] = useState(false); - - const onClickToggleModal = useCallback(() => { - setOpenModal(!isOpenModal); - }, [isOpenModal]); - - return ( - - - - - - {isOpenModal && ( - - - - )} - - ); -}; - -export default UserProfile; -const ProfileWrapper = styled.div` - width: 100%; -`; - -const TopWrapper = styled.div` - padding: 1rem; - width: 100%; - text-align: center; -`; - -const Bottom = styled.div` - width: 100%; - height: 4rem; - padding: 1rem; - background-color: ${({ theme }) => theme.backgroundColor["voice-nobody"]}; -`; diff --git a/src/components/organisms/UserSettingBar.tsx b/src/components/organisms/UserSettingBar.tsx index 0d78984..ba21503 100644 --- a/src/components/organisms/UserSettingBar.tsx +++ b/src/components/organisms/UserSettingBar.tsx @@ -26,13 +26,9 @@ const MyAccountSettingBar = () => { return (
      - + + 사용자 설정 +
      • diff --git a/src/components/organisms/UserSettingDefaultList.tsx b/src/components/organisms/UserSettingDefaultList.tsx index 9594ca6..0e6630b 100644 --- a/src/components/organisms/UserSettingDefaultList.tsx +++ b/src/components/organisms/UserSettingDefaultList.tsx @@ -1,19 +1,26 @@ import FieldButton from "@components/atoms/Button/fieldButton"; import Text from "@components/atoms/Text/Text"; +import { lazy, useEffect } from "react"; import styled from "styled-components"; import { useUserStore } from "@store/useUserStore"; import useSettingModalStore, { SettingModalType, } from "@store/useSettingModalStore"; -import UserSettingNameModal from "@components/molecules/Modal/UserSettingNameModal"; -import UserSettingPasswordModal from "@components/molecules/Modal/UserSettingPasswordModal"; -import UserSettingIntroModal from "@components/molecules/Modal/UserSettingIntroModal"; -import UserSettingImageModal from "@components/molecules/Modal/UserSettingImageModal"; -import { useEffect } from "react"; +const UserSettingNameModal = lazy( + () => import("@components/molecules/Modal/UserSettingNameModal") +); +const UserSettingPasswordModal = lazy( + () => import("@components/molecules/Modal/UserSettingPasswordModal") +); +const UserSettingIntroModal = lazy( + () => import("@components/molecules/Modal/UserSettingIntroModal") +); +const UserSettingImageModal = lazy( + () => import("@components/molecules/Modal/UserSettingImageModal") +); const UserSettingGeneralTab = () => { const { userInfo } = useUserStore(); - const { showSettingModal, settingModalType, @@ -37,15 +44,19 @@ const UserSettingGeneralTab = () => { image: , }; - const Component = settingModalType ? modalTable[settingModalType] : <>; + const Component = settingModalType ? modalTable[settingModalType] : null; return ( {showSettingModal && Component} - - + + 사용자명 + + + {userInfo.name} + { - - + + 이메일 + + + {userInfo.email} + { - - + + 비밀번호 + + + =******** + showModal("password")} /> @@ -79,8 +98,12 @@ const UserSettingGeneralTab = () => { - - + + 자기소개 + + + {userInfo.introduction} + showModal("intro")} /> diff --git a/src/components/organisms/UserSettingMyAccount.stories.tsx b/src/components/organisms/UserSettingMyAccount.stories.tsx new file mode 100644 index 0000000..1ba16ef --- /dev/null +++ b/src/components/organisms/UserSettingMyAccount.stories.tsx @@ -0,0 +1,10 @@ +import UserSettingMyAccount from "./UserSettingMyAccount"; + +export default { + title: "Organisms/UserSettingMyAccount", + component: UserSettingMyAccount, +}; + +export const MyAccount = () => { + return ; +}; diff --git a/src/components/organisms/UserSettingMyAccount.tsx b/src/components/organisms/UserSettingMyAccount.tsx new file mode 100644 index 0000000..f8fff00 --- /dev/null +++ b/src/components/organisms/UserSettingMyAccount.tsx @@ -0,0 +1,43 @@ +import Text from "../atoms/Text/Text"; +import AccountCard from "./AccountCard"; +import SettingWrapper from "./SettingWrapper"; +import { Divider } from "@mui/material"; +import FieldButton from "../atoms/Button/fieldButton"; +import styled from "styled-components"; +import useDeleteUser from "@hooks/query/useDeleteUser"; + +const UserSettingMyAccount = () => { + const { mutate: deleteUser } = useDeleteUser(); + + return ( + + <> + + 내 계정 + + + + + 계정 삭제하기 + + + deleteUser()} + backgroundColor="voice-hangup" + fontWeight="bold" + /> + + + + ); +}; + +export default UserSettingMyAccount; + +const ButtonWrappper = styled.div` + width: 7.5rem; + height: 2rem; +`; diff --git a/src/components/organisms/UserProfile.stories.tsx b/src/components/organisms/UserSettingProfile.stories.tsx similarity index 74% rename from src/components/organisms/UserProfile.stories.tsx rename to src/components/organisms/UserSettingProfile.stories.tsx index bf3d05b..d7d1015 100644 --- a/src/components/organisms/UserProfile.stories.tsx +++ b/src/components/organisms/UserSettingProfile.stories.tsx @@ -1,4 +1,4 @@ -import UserProfile from "./UserProfile"; +import UserProfile from "./UserSettingProfile"; export default { title: "Organisms/MyAccount", diff --git a/src/components/organisms/UserSettingProfile.tsx b/src/components/organisms/UserSettingProfile.tsx new file mode 100644 index 0000000..a1cce55 --- /dev/null +++ b/src/components/organisms/UserSettingProfile.tsx @@ -0,0 +1,28 @@ +import Text from "../atoms/Text/Text"; +import SettingWrapper from "./SettingWrapper"; +import styled from "styled-components"; +import UserSettingProfileBody from "./UserSettingProfileBody"; +import UserSettingImageModal from "@components/molecules/Modal/UserSettingImageModal"; +import useSettingModalStore from "@store/useSettingModalStore"; + +const UserSettingProfile = () => { + const { showSettingModal } = useSettingModalStore(); + + return ( + + + + 프로필 + + + + {showSettingModal && } + + ); +}; + +const ProfileWrapper = styled.div` + width: 100%; +`; + +export default UserSettingProfile; diff --git a/src/components/organisms/ProfileTab.tsx b/src/components/organisms/UserSettingProfileBody.tsx similarity index 89% rename from src/components/organisms/ProfileTab.tsx rename to src/components/organisms/UserSettingProfileBody.tsx index 0b5c4cc..5030a67 100644 --- a/src/components/organisms/ProfileTab.tsx +++ b/src/components/organisms/UserSettingProfileBody.tsx @@ -6,7 +6,7 @@ import Text from "@components/atoms/Text/Text"; // Styled-Component 라이브러리를 활용해 TabMenu 와 Desc 컴포넌트의 CSS를 구현. -export const Tab = () => { +const UserSettingProfileBody = () => { // Tab Menu 중 현재 어떤 Tab이 선택되어 있는지 확인하기 위한 currentTab 상태와 currentTab을 갱신하는 함수가 존재해야 하고, 초기값은 0. const [currentTab, clickTab] = useState(0); @@ -44,28 +44,12 @@ export const Tab = () => {

        {menuArr[currentTab].content}

  • */} - - ); }; -export default Tab; - const TabMenu = styled.ul` background-color: ${({ theme }) => theme.backgroundColor["tab3"]}; color: ${({ theme }) => theme.color["setting-tab"]}; @@ -108,3 +92,5 @@ const TabMenu = styled.ul` const Desc = styled.div` text-align: center; `; + +export default UserSettingProfileBody; diff --git a/src/components/templates/CommonPage.tsx b/src/components/templates/CommonPage.tsx index b532bbc..94e6574 100644 --- a/src/components/templates/CommonPage.tsx +++ b/src/components/templates/CommonPage.tsx @@ -1,16 +1,30 @@ import TabDivider from "@components/atoms/Div/TabDivider"; import CommunityList from "@components/organisms/CommunityList"; -import Tab2CommunityBody from "@components/organisms/Tab2CommunityBody"; -import Tab2CommunityHeader from "@components/organisms/Tab2CommunityHeader"; import Tab2Footer from "@components/organisms/Tab2Footer"; -import Tab2MainBody from "@components/organisms/Tab2MainBody"; -import Tab2MainHeader from "@components/organisms/Tab2MainHeader"; -import Tab3CommunityBody from "@components/organisms/Tab3CommunityBody"; -import Tab3CommunityHeader from "@components/organisms/Tab3CommunityHeader"; -import Tab3MainBody from "@components/organisms/Tab3MainBody"; -import Tab3MainHeader from "@components/organisms/Tab3MainHeader"; +import { lazy } from "react"; import styled from "styled-components"; +const Tab2MainHeader = lazy( + () => import("@components/organisms/Tab2MainHeader") +); +const Tab2CommunityHeader = lazy( + () => import("@components/organisms/Tab2CommunityHeader") +); +const Tab2MainBody = lazy(() => import("@components/organisms/Tab2MainBody")); +const Tab2CommunityBody = lazy( + () => import("@components/organisms/Tab2CommunityBody") +); +const Tab3MainHeader = lazy( + () => import("@components/organisms/Tab3MainHeader") +); +const Tab3CommunityHeader = lazy( + () => import("@components/organisms/Tab3CommunityHeader") +); +const Tab3MainBody = lazy(() => import("@components/organisms/Tab3MainBody")); +const Tab3CommunityBody = lazy( + () => import("@components/organisms/Tab3CommunityBody") +); + interface CommonPageProps { isMainPage: boolean; } @@ -37,13 +51,15 @@ const CommonPage = ({ isMainPage }: CommonPageProps) => { const Tab2Container = styled.div` background-color: ${({ theme }) => theme.backgroundColor.tab2}; width: 15rem; + display: flex; flex-direction: column; `; const Tab3Container = styled.div` - background-color: ${({ theme }) => theme.backgroundColor.tab3}; flex: 1; + background-color: ${({ theme }) => theme.backgroundColor.tab3}; + display: flex; flex-direction: column; `; diff --git a/src/components/templates/LoginPage.tsx b/src/components/templates/LoginPage.tsx index 81e66ea..2b21393 100644 --- a/src/components/templates/LoginPage.tsx +++ b/src/components/templates/LoginPage.tsx @@ -1,94 +1,25 @@ -import DefaultButton from "@components/atoms/Button/DefaultButton"; -import LinkText from "@components/atoms/Text/LinkText"; -import Text from "@components/atoms/Text/Text"; -import LoginForm from "@components/molecules/Form/LoginForm"; -import AuthDesc from "@components/molecules/Text/AuthDesc"; +import LoginModalBody from "@components/molecules/Div/LoginModalBody"; +import LoginModalFooter from "@components/molecules/Div/LoginModalFooter"; +import LoginModalHeader from "@components/molecules/Div/LoginModalHeader"; import AuthModal from "@components/organisms/Modal/AuthModal"; -import useInput from "@hooks/common/useInput"; -import useLogin from "@hooks/query/useLogin"; -import validateEmail from "@utils/validateEmail"; -import { useState } from "react"; -import { useNavigate } from "react-router-dom"; -import styled from "styled-components"; +import { useRef, useState } from "react"; const LoginPage = () => { - const navigate = useNavigate(); - const [email, changeEmail] = useInput(); - const [password, changePassword] = useInput(); - const [errorMessage, setErrorMessage] = useState(""); - - const { mutate: login } = useLogin(); - - const goRegisterPage = () => navigate("/register"); + const emailRef = useRef(null); + const passwordRef = useRef(null); + const refs = { emailRef, passwordRef }; - const onLogin = () => { - if (!email || !password) { - return setErrorMessage("모든 값을 입력해주세요."); - } - if (!validateEmail(email)) { - return setErrorMessage("유효하지 않은 아이디입니다."); - } - if (password.length < 8) { - return setErrorMessage("비밀번호는 8자리 이상이어야 합니다."); - } - setErrorMessage(""); - login({ email, password }); - }; + const [errorMessage, setErrorMessage] = useState(""); return ( <> - - - {errorMessage && ( - - )} - - - - null} /> - - - - <>계정이 필요한가요? - - - } - color="auth-desc" - fontSize="sm" - /> + + + ); }; -const LinkTextContainer = styled.div` - margin: -1rem 0 1.25rem; -`; - export default LoginPage; diff --git a/src/hooks/common/useInput.ts b/src/hooks/common/useInput.ts index a85293a..ca97a5b 100644 --- a/src/hooks/common/useInput.ts +++ b/src/hooks/common/useInput.ts @@ -1,4 +1,4 @@ -import { ChangeEvent, useState } from "react"; +import { ChangeEvent, useCallback, useState } from "react"; type InputAndTextAreaType = [ string, @@ -8,11 +8,19 @@ type InputAndTextAreaType = [ const useInput = (initial = ""): InputAndTextAreaType => { const [value, setValue] = useState(initial); - const changeValue = ({ - target: { value }, - }: ChangeEvent): void => - setValue(value); - const resetValue = () => setValue(""); + + const changeValue = useCallback( + ({ + target: { value }, + }: ChangeEvent): void => + setValue(value), + [value] + ); + + const resetValue = useCallback(() => { + setValue(""); + }, []); + return [value, changeValue, resetValue]; }; diff --git a/src/hooks/common/useOutsideClick.ts b/src/hooks/common/useOutsideClick.ts index dad3d81..27f48ae 100644 --- a/src/hooks/common/useOutsideClick.ts +++ b/src/hooks/common/useOutsideClick.ts @@ -1,10 +1,10 @@ -import { useEffect } from "react"; +import { useCallback, useEffect } from "react"; const useOutsideClick = (ref: any, callback: () => void) => { - const handleClick = (e: Event) => { + const handleClick = useCallback((e: Event) => { if (ref.current && !ref.current.contains(e.target)) { callback?.(); } - }; + }, []); useEffect(() => { window.addEventListener("mousedown", handleClick); diff --git a/src/hooks/query/useCreateCommunity.ts b/src/hooks/query/useCreateCommunity.ts index e16c29e..26df54a 100644 --- a/src/hooks/query/useCreateCommunity.ts +++ b/src/hooks/query/useCreateCommunity.ts @@ -1,11 +1,13 @@ +import { useUserStore } from "@store/useUserStore"; import { useNavigate } from "react-router-dom"; import communityApi from "@api/community"; import { useMutation, useQueryClient } from "@tanstack/react-query"; -const useCreateCommunity = (userId: number) => { +const useCreateCommunity = () => { + const { userInfo } = useUserStore(); const navigate = useNavigate(); const queryClient = useQueryClient(); - const QUERY_KEY = ["communityList", userId]; + const QUERY_KEY = ["communityList", userInfo.id]; return useMutation(communityApi.create, { onMutate: async (newCommunity: any) => { @@ -22,11 +24,9 @@ const useCreateCommunity = (userId: number) => { onError: (_err: Error, _newCommunity: any, context: any) => { queryClient.setQueriesData(QUERY_KEY, context.previousCommunityList); }, - onSuccess: () => { navigate(-1); }, - onSettled: () => { queryClient.invalidateQueries({ queryKey: QUERY_KEY, diff --git a/src/hooks/query/useLogin.ts b/src/hooks/query/useLogin.ts index dd2424b..ba93ba0 100644 --- a/src/hooks/query/useLogin.ts +++ b/src/hooks/query/useLogin.ts @@ -4,10 +4,14 @@ import { useUserStore } from "@store/useUserStore"; import authApi from "@api/auth"; import { cookies } from "src/App"; -const useLogin = () => { +const useLogin = (setErrorMessage: any) => { const { setUserInfo } = useUserStore(); return useMutation(authApi.login, { + onError: () => { + setErrorMessage("다시 시도해주세요."); + }, + onSuccess: async ({ data: { data: { accessToken, refreshToken }, diff --git a/src/pages/Common.tsx b/src/pages/Common.tsx index 1299e13..0571a56 100644 --- a/src/pages/Common.tsx +++ b/src/pages/Common.tsx @@ -1,15 +1,28 @@ import PageContainer from "@components/atoms/Div/PageContainer"; import HeaderHelmet from "@components/atoms/Helmet"; -import CreateCategroyModal from "@components/molecules/Modal/CreateCategoryModal"; -import CreateChannelModal from "@components/molecules/Modal/CreateChannelModal"; -import CommunitySettingModal from "@components/organisms/Modal/CommunitySettingModal"; -import CreateCommunityModal from "@components/organisms/Modal/CreateCommunityModal"; -import InviteFriendModal from "@components/organisms/Modal/InviteFriendModal"; -import UserSettingModal from "@components/organisms/Modal/UserSettingModal"; import CommonPage from "@components/templates/CommonPage"; import useModalStore from "@store/useModalStore"; -import { useEffect } from "react"; -import { useMatch, useNavigate, useParams } from "react-router-dom"; +import { lazy, useEffect } from "react"; +import { useParams } from "react-router-dom"; + +const InviteFriendModal = lazy( + () => import("@components/organisms/Modal/InviteFriendModal") +); +const UserSettingModal = lazy( + () => import("@components/organisms/Modal/UserSettingModal") +); +const CreateCommunityModal = lazy( + () => import("@components/organisms/Modal/CreateCommunityModal") +); +const CreateChannelModal = lazy( + () => import("@components/molecules/Modal/CreateChannelModal") +); +const CreateCategroyModal = lazy( + () => import("@components/molecules/Modal/CreateCategoryModal") +); +const CommunitySettingModal = lazy( + () => import("@components/organisms/Modal/CommunitySettingModal") +); const modalTable = { inviteFriend: , @@ -21,24 +34,18 @@ const modalTable = { }; const Common = () => { - const navigate = useNavigate(); - const isBaseUrl = useMatch("/"); + //!TODO: channelId는 추후에 channelName을 받아오는 용도로 사용 const { communityId, channelId } = useParams(); const { setShowModal, showModal, modalType } = useModalStore(); - const isMainPage = !communityId; + const isMainPage = !communityId || communityId === "@me"; const channelName = "자바스크립트 스터디"; useEffect(() => { setShowModal(false); }, []); - if (isBaseUrl) { - navigate("/@me"); - return null; - } - - const component = modalType ? modalTable[modalType] : <>; + const component = modalType ? modalTable[modalType] : null; return ( <> diff --git a/src/routes/router.tsx b/src/routes/router.tsx index bf08a98..8cecbc1 100644 --- a/src/routes/router.tsx +++ b/src/routes/router.tsx @@ -12,17 +12,17 @@ const Router = () => { - - // + + + } /> - - // + + + } /> @@ -32,13 +32,13 @@ const Router = () => { "/@me/:channelId", "/:communityId", "/:communityId/:channelId", - ].map((path, idx) => ( + ].map((path) => ( - - // + + + } /> ))} diff --git a/src/utils/validateUrl.ts b/src/utils/validateUrl.ts new file mode 100644 index 0000000..00b70f5 --- /dev/null +++ b/src/utils/validateUrl.ts @@ -0,0 +1,5 @@ +const validateUrl = (text: string) => { + return /(https?:\/\/[^\s]+)/g.test(text); +}; + +export default validateUrl;