diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx
index a0097369..addac5dc 100644
--- a/src/components/Button/Button.tsx
+++ b/src/components/Button/Button.tsx
@@ -11,6 +11,7 @@ interface ButtonProps {
fontSize?: number;
borderRadius?: number;
children?: React.ReactNode;
+ disabled?: boolean;
}
const Button = ({
@@ -23,7 +24,8 @@ const Button = ({
textColor,
fontSize,
borderRadius,
- children
+ children,
+ disabled
}: ButtonProps) => (
+ borderRadius={borderRadius}
+ disabled={disabled}>
{label}
{children}
diff --git a/src/components/PostPreview/PostPreview.style.ts b/src/components/PostPreview/PostPreview.style.ts
index 9acf7cb6..1fb8ec5c 100644
--- a/src/components/PostPreview/PostPreview.style.ts
+++ b/src/components/PostPreview/PostPreview.style.ts
@@ -5,12 +5,12 @@ export const PreviewContainer = styled.div`
width: 100%;
height: 150px;
margin: 0 auto;
- padding: 15px 60px;
+ padding: 15px 26px;
background-color: transparent;
display: flex;
flex-direction: column;
align-items: center;
- border-bottom: 0.5px solid ${({ theme }) => theme.color.greyLight};
+ border-bottom: 0.5px solid ${({ theme }) => theme.color.white800};
&:hover {
background-color: ${({ theme }) => theme.color.white900};
}
diff --git a/src/pages/postDetail/components/PostComment.style.ts b/src/pages/postDetail/components/PostComment.style.ts
index 7b0f7a90..b3d1fd8f 100644
--- a/src/pages/postDetail/components/PostComment.style.ts
+++ b/src/pages/postDetail/components/PostComment.style.ts
@@ -23,6 +23,7 @@ export const PostCommentUserContainer = styled.div`
export const PostCommentContentContainer = styled.div`
flex: 1;
margin-top: 7px;
+ line-height: 1.5;
`;
export const PostCommentDeleteContainer = styled.div`
diff --git a/src/pages/postDetail/components/PostCommentHeader.style.ts b/src/pages/postDetail/components/PostCommentHeader.style.ts
index c4b56a69..ef706538 100644
--- a/src/pages/postDetail/components/PostCommentHeader.style.ts
+++ b/src/pages/postDetail/components/PostCommentHeader.style.ts
@@ -24,31 +24,7 @@ export const PostLikeContainer = styled.div`
transition: transform 0.2s ease-in-out;
margin-top: 1px;
&:active {
- animation: shake 1s infinite;
- }
- :hover {
transform: scale(1.2);
}
}
-
- @keyframes shake {
- 0% {
- transform: rotate(0) scale(1.2);
- }
- 10% {
- transform: rotate(15deg) scale(1.2);
- }
- 30% {
- transform: rotate(-15deg) scale(1.2);
- }
- 50% {
- transform: rotate(15deg) scale(1.2);
- }
- 70% {
- transform: rotate(0) scale(1.2);
- }
- 100% {
- transform: rotate(0) scale(1.2);
- }
- }
`;
diff --git a/src/pages/postDetail/components/PostCommentInput.style.ts b/src/pages/postDetail/components/PostCommentInput.style.ts
index 5bd9252f..c04743f5 100644
--- a/src/pages/postDetail/components/PostCommentInput.style.ts
+++ b/src/pages/postDetail/components/PostCommentInput.style.ts
@@ -1,5 +1,9 @@
import styled from '@emotion/styled';
+interface CommentButtonProps {
+ buttonDisabled: boolean;
+}
+
export const CommentInputSection = styled.section`
${({ theme }) => theme.style.flexCenter}
border-top: 1px solid ${({ theme }) => theme.color.greyLight};
@@ -29,10 +33,20 @@ export const CommentInputContainer = styled.div`
padding: 0 10px;
`;
-export const CommentButtonContainer = styled.div`
+export const CommentButtonContainer = styled.div`
${({ theme }) => theme.style.flexCenter}
width: 50px;
height: 100%;
+ > button {
+ transition: all 0.2s ease-in-out;
+ background-color: ${({ buttonDisabled, theme }) =>
+ buttonDisabled ? theme.color.greyLight : theme.color.purpleDark};
+ }
+
+ > button:active {
+ transform: ${({ buttonDisabled }) =>
+ buttonDisabled ? 'none' : 'scale(0.9)'};
+ }
`;
export const CommentInput = styled.input`
diff --git a/src/pages/postDetail/components/PostCommentInput.tsx b/src/pages/postDetail/components/PostCommentInput.tsx
index e0d3a7be..e3320742 100644
--- a/src/pages/postDetail/components/PostCommentInput.tsx
+++ b/src/pages/postDetail/components/PostCommentInput.tsx
@@ -11,6 +11,7 @@ import {
} from './PostCommentInput.style';
import { Avatar } from '@components/Avatar';
import { postComment } from '@apis/comment';
+import { useState } from 'react';
import { postNotifications } from '@apis/notice';
interface PostCommentInputProps {
@@ -29,6 +30,7 @@ const PostCommentInput = ({
refetch
}: PostCommentInputProps) => {
const COMMENT_PLACEHOLDER = '댓글을 달아보세요.';
+ const [commentValue, setCommentValue] = useState(null);
const commentRef = useRef(null);
const { mutate, isSuccess } = useMutation(postComment, {
@@ -46,14 +48,23 @@ const PostCommentInput = ({
const handleCommentSubmit = (event: React.FormEvent) => {
event.preventDefault();
- mutate({
- postId,
- comment: commentRef.current.value,
- token
- });
+ mutate(
+ {
+ postId,
+ comment: commentValue,
+ token
+ },
+ {
+ onSuccess: () => refetch()
+ }
+ );
commentRef.current.value = '';
};
+ const handleCommentChange = (event: React.ChangeEvent) => {
+ setCommentValue(event.target.value);
+ };
+
return (
@@ -68,10 +79,11 @@ const PostCommentInput = ({
-
+
diff --git a/src/pages/postDetail/components/PostContent.style.ts b/src/pages/postDetail/components/PostContent.style.ts
index 1d44205f..835658f9 100644
--- a/src/pages/postDetail/components/PostContent.style.ts
+++ b/src/pages/postDetail/components/PostContent.style.ts
@@ -93,6 +93,7 @@ export const PostContentMenu = styled.div`
export const PostContentBody = styled.div`
padding: 20px;
width: 100%;
+ line-height: 1.5;
`;
export const PostEditConfirmButtonContainer = styled.div`
diff --git a/src/pages/postDetail/components/PostContent.tsx b/src/pages/postDetail/components/PostContent.tsx
index 16256e15..3f9d45a1 100644
--- a/src/pages/postDetail/components/PostContent.tsx
+++ b/src/pages/postDetail/components/PostContent.tsx
@@ -22,6 +22,7 @@ import { Avatar } from '@components/Avatar';
import { Button } from '@components/Button';
import { Confirm } from '@components/Confirm';
import { createFormData, purifyContent } from '@pages/posting/utils';
+import { Link } from 'react-router-dom';
interface PostContentProps {
author: User;
@@ -109,11 +110,13 @@ const PostContent = ({
-
+
+
+
@@ -121,7 +124,7 @@ const PostContent = ({
- {createdAt} / {meditationTime}
+ {createdAt} / {meditationTime}분
{currentUserId === author?._id && (
diff --git a/src/pages/profile/Profile.style.ts b/src/pages/profile/Profile.style.ts
index 2452b486..6e5df822 100644
--- a/src/pages/profile/Profile.style.ts
+++ b/src/pages/profile/Profile.style.ts
@@ -19,3 +19,10 @@ export const ProfileInfoContainer = styled.div`
bottom: 0;
position: relative;
`;
+
+export const ProfileBodyContainer = styled.section`
+ width: 100%;
+ height: calc(100% - 100px);
+ padding: 0 26px;
+ position: relative;
+`;
diff --git a/src/pages/profile/Profile.tsx b/src/pages/profile/Profile.tsx
index 8fc2cd59..6afbdec8 100644
--- a/src/pages/profile/Profile.tsx
+++ b/src/pages/profile/Profile.tsx
@@ -8,7 +8,11 @@ import { User } from '@/types/User';
import { getUser } from '@apis/user';
import createTabItems from './utils/createTabItems';
import { editModeState } from './states/editMode';
-import { ProfileInfoContainer, ProfilePage } from './Profile.style';
+import {
+ ProfileInfoContainer,
+ ProfilePage,
+ ProfileBodyContainer
+} from './Profile.style';
import {
ProfileInfo,
ProfileCover,
@@ -19,7 +23,7 @@ import {
import { getMyFollowData } from '@/utils';
const Profile = () => {
- const { userId } = useParams<{ userId: string }>();
+ const { userId: profileUserId } = useParams<{ userId: string }>();
const location = useLocation();
const [sideBarOpened, setSideBarOpened] = useState(false);
const [editMode, setEditMode] = useRecoilState(editModeState);
@@ -28,11 +32,10 @@ const Profile = () => {
setEditMode(location.hash === '#edit');
}, [location.hash, setEditMode]);
- const { data, isLoading, refetch } = useQuery(
- ['userData', userId],
- () => getUser(userId),
- { enabled: !!userId }
- );
+ const { data, isLoading, refetch } = useQuery({
+ queryKey: ['userData', profileUserId],
+ queryFn: async () => await getUser(profileUserId)
+ });
const [{ _id: currentUserId }] = useSessionStorage>(
'userData',
@@ -46,7 +49,6 @@ const Profile = () => {
};
const closeSidebar = () => {
- console.log('close');
setSideBarOpened(false);
};
@@ -69,20 +71,24 @@ const Profile = () => {
avatarImgSrc={isLoading ? '' : data.image}
refetch={() => refetch()}
/>
+
+
{editMode ? (
refetch()} />
) : (
refetch()}
/>
)}
-
+
);
};
diff --git a/src/pages/profile/components/ProfileCarousel.style.ts b/src/pages/profile/components/ProfileCarousel.style.ts
index 0e07c725..a2d5ceac 100644
--- a/src/pages/profile/components/ProfileCarousel.style.ts
+++ b/src/pages/profile/components/ProfileCarousel.style.ts
@@ -1,18 +1,32 @@
import styled from '@emotion/styled';
-export const ProfileCarouselContainer = styled.div`
+interface ProfileCarouselContainerProps {
+ selectedTabIndex: number;
+}
+
+export const ProfileCarouselContainer = styled.div`
width: 100%;
- display: flex;
flex: 1;
+ display: flex;
overflow: hidden;
user-select: none;
+ scroll-behavior: smooth;
+ > div:first-of-type {
+ > div {
+ padding: 0;
+ }
+ > div:last-of-type {
+ border-bottom: none;
+ }
+ }
`;
export const ProfileCarouselItem = styled.div`
flex: 1 0 100%;
+ overflow: auto;
`;
-export const NonePostContainer = styled.div`
+export const NoneContentContainer = styled.div`
${({ theme }) => theme.style.flexCenter};
width: 100%;
height: 100%;
diff --git a/src/pages/profile/components/ProfileCarousel.tsx b/src/pages/profile/components/ProfileCarousel.tsx
index 6fed28cd..9eb66b48 100644
--- a/src/pages/profile/components/ProfileCarousel.tsx
+++ b/src/pages/profile/components/ProfileCarousel.tsx
@@ -1,8 +1,8 @@
import { useRecoilState } from 'recoil';
import {
- NonePostContainer,
ProfileCarouselContainer,
- ProfileCarouselItem
+ ProfileCarouselItem,
+ NoneContentContainer
} from './ProfileCarousel.style';
import { useCarousel } from '../hooks/useCarousel';
import { selectedTabIndexState } from '../states/selectedTabIndex';
@@ -10,6 +10,7 @@ import { FollowUsers, MeditationInfo } from '@pages/profile/components';
import { TabItems } from '../utils/createTabItems';
import { PROFILE_TABS } from '../constants/profileTabs';
import { Follow } from '@/types/Follow';
+import { useEffect } from 'react';
import { PostPreview } from '@components/PostPreview';
import { Post } from '@/types/Post';
import { editPostData } from '@pages/posts/utils/editPostData';
@@ -25,6 +26,11 @@ const ProfileCarousel = ({ tabItems, fullName }: ProfileCarouselProps) => {
const [selectedTabIndex, setSelectedTabIndex] = useRecoilState(
selectedTabIndexState
);
+
+ useEffect(() => {
+ setSelectedTabIndex(0);
+ }, [setSelectedTabIndex]);
+
const [carouselRef] = useCarousel(
selectedTabIndex,
setSelectedTabIndex,
@@ -32,11 +38,15 @@ const ProfileCarousel = ({ tabItems, fullName }: ProfileCarouselProps) => {
);
return (
-
+
{Object.entries(tabItems).map(([label, tabItem], index) => {
+ const { data, value } = tabItem;
switch (label) {
case MEDITATION:
const editedData = editPostData(tabItem.data as Post[]);
+
return editedData && editedData.length > 0 ? (
{editedData.map((post, index) => {
@@ -56,44 +66,54 @@ const ProfileCarousel = ({ tabItems, fullName }: ProfileCarouselProps) => {
) : (
-
+
아직 명상을 진행하지 않았습니다
-
+
);
case FOLLOWING:
- return (
+ return data && data.length > 0 ? (
+ ) : (
+
+
+ 아직 팔로우한 유저가 없습니다.
+
+
);
case FOLLOWER:
- return (
+ return data && data.length > 0 ? (
+ ) : (
+
+
+ 아직 팔로워가 없습니다.
+
+
);
case INFO:
return (
- {tabItem.value}
+ {value}
);
default:
return (
-
- {tabItem.value}
-
+ {value}
);
}
})}
diff --git a/src/pages/profile/components/ProfileHeader.style.ts b/src/pages/profile/components/ProfileHeader.style.ts
index fa031e1c..a44fa45a 100644
--- a/src/pages/profile/components/ProfileHeader.style.ts
+++ b/src/pages/profile/components/ProfileHeader.style.ts
@@ -16,7 +16,7 @@ export const ProfileHeaderButtonContainer = styled.div`
&:last-child {
margin-right: 0;
}
- :hover {
+ :active {
background-color: ${({ theme }) => theme.color.purpleLight};
}
}
diff --git a/src/pages/profile/components/ProfileHeader.tsx b/src/pages/profile/components/ProfileHeader.tsx
index 7364400f..2821f091 100644
--- a/src/pages/profile/components/ProfileHeader.tsx
+++ b/src/pages/profile/components/ProfileHeader.tsx
@@ -29,23 +29,21 @@ const ProfileHeader = ({
{myProfile ? (
- <>
-
- >
+
) : (
- <>
+ myFollowData !== null && (
- >
+ )
)}
diff --git a/src/pages/profile/components/ProfileMain.tsx b/src/pages/profile/components/ProfileMain.tsx
index 08cb393c..800454be 100644
--- a/src/pages/profile/components/ProfileMain.tsx
+++ b/src/pages/profile/components/ProfileMain.tsx
@@ -2,7 +2,6 @@ import { ProfileMainSection } from './ProfileMain.style';
import {
ProfileHeader,
ProfileTabs,
- ProfileTabItem,
ProfileCarousel
} from '@pages/profile/components';
import { TabItems } from '../utils/createTabItems';
@@ -36,16 +35,7 @@ const ProfileMain = ({
openSidebar={openSidebar}
refetch={refetch}
/>
-
- {Object.entries(tabItems).map(([label, tabItem], index) => (
-
- ))}
-
+
`
- height: 50px;
- border-bottom: 3px solid
- ${({ selected, theme }) =>
- selected ? theme.color.purpleVivid : 'transparent'};
+ height: 35px;
color: ${({ selected, theme }) =>
selected ? theme.color.black : theme.color.greyLight};
+ font-weight: ${({ selected }) => (selected ? 'bold' : 'normal')};
display: flex;
align-items: center;
justify-content: center;
diff --git a/src/pages/profile/components/ProfileTabItem.tsx b/src/pages/profile/components/ProfileTabItem.tsx
index cb77b11a..f9e27781 100644
--- a/src/pages/profile/components/ProfileTabItem.tsx
+++ b/src/pages/profile/components/ProfileTabItem.tsx
@@ -1,22 +1,23 @@
import { ProfileTabItemContainer } from './ProfileTabItem.style';
-import { useRecoilState } from 'recoil';
-import { selectedTabIndexState } from '../states/selectedTabIndex';
+
import { Post, Follow } from '@/types';
interface ProfileTabItemProps {
title: string;
- index: number;
+ selected: boolean;
data: Post[] | Follow[] | number[];
+ onTabItemClick: () => void;
}
-const ProfileTabItem = ({ title, index }: ProfileTabItemProps) => {
- const [selectedTabIndex, setSelectedTabIndex] = useRecoilState(
- selectedTabIndexState
- );
+const ProfileTabItem = ({
+ title,
+ selected,
+ onTabItemClick
+}: ProfileTabItemProps) => {
return (
setSelectedTabIndex(index)}>
+ selected={selected}
+ onClick={onTabItemClick}>
{title}
);
diff --git a/src/pages/profile/components/ProfileTabs.style.ts b/src/pages/profile/components/ProfileTabs.style.ts
index a1f82e30..aef967ba 100644
--- a/src/pages/profile/components/ProfileTabs.style.ts
+++ b/src/pages/profile/components/ProfileTabs.style.ts
@@ -1,6 +1,27 @@
import styled from '@emotion/styled';
+interface ProfileTabsProps {
+ selectedTabIndex: number;
+}
+
export const ProfileTabsContainer = styled.div`
display: flex;
margin-top: 10px;
+ width: 100%;
+ height: 40px;
+`;
+
+export const ProfileTabItemBottomBarContainer = styled.div`
+ height: 3px;
+ width: 25%;
+ padding: 0 10px;
+ transition: all 0.2s ease-in-out;
+ transform: ${({ selectedTabIndex }) =>
+ `translateX(${selectedTabIndex * 100}%)`};
+`;
+
+export const ProfileTabItemBottomBar = styled.div`
+ height: 3px;
+ width: 100%;
+ background-color: ${({ theme }) => theme.color.purpleVivid};
`;
diff --git a/src/pages/profile/components/ProfileTabs.tsx b/src/pages/profile/components/ProfileTabs.tsx
index 95407964..031a5668 100644
--- a/src/pages/profile/components/ProfileTabs.tsx
+++ b/src/pages/profile/components/ProfileTabs.tsx
@@ -1,11 +1,44 @@
-import { ProfileTabsContainer } from './ProfileTabs.style';
+import { TabItems } from '../utils/createTabItems';
+import {
+ ProfileTabItemBottomBar,
+ ProfileTabItemBottomBarContainer,
+ ProfileTabsContainer
+} from './ProfileTabs.style';
+import { ProfileTabItem } from '@pages/profile/components';
+import { useRecoilState } from 'recoil';
+import { selectedTabIndexState } from '../states/selectedTabIndex';
interface ProfileTabsProps {
- children: React.ReactNode;
+ tabItems: TabItems;
}
-const ProfileTabs = ({ children }: ProfileTabsProps) => {
- return {children};
+const ProfileTabs = ({ tabItems }: ProfileTabsProps) => {
+ const [selectedTabIndex, setSelectedTabIndex] = useRecoilState(
+ selectedTabIndexState
+ );
+
+ const handleTabItemClick = (index: number) => {
+ setSelectedTabIndex(index);
+ };
+
+ return (
+ <>
+
+ {Object.entries(tabItems).map(([label, tabItem], index) => (
+ handleTabItemClick(index)}
+ key={index}
+ title={`${tabItem.value} ${label}`}
+ data={tabItem.data}
+ selected={index === selectedTabIndex}
+ />
+ ))}
+
+
+
+
+ >
+ );
};
export default ProfileTabs;
diff --git a/src/pages/profile/components/SettingSideBar.tsx b/src/pages/profile/components/SettingSideBar.tsx
index eb19576e..a77dc3ed 100644
--- a/src/pages/profile/components/SettingSideBar.tsx
+++ b/src/pages/profile/components/SettingSideBar.tsx
@@ -8,6 +8,7 @@ import {
SettingLi
} from './SettingSideBar.style';
import useSessionStorage from '@hooks/useSessionStorage';
+import { useNavigate } from 'react-router-dom';
interface SettingSideBarProps {
closeSidebar: () => void;
@@ -28,9 +29,11 @@ const SettingSideBar = ({
token: ''
});
+ const navigate = useNavigate();
+
const handleLogoutClick = () => {
deleteUserValue();
- window.location.reload();
+ navigate('/');
};
return (
diff --git a/src/pages/profile/hooks/useCarousel.ts b/src/pages/profile/hooks/useCarousel.ts
index 9d3d4d3a..3f0a7db5 100644
--- a/src/pages/profile/hooks/useCarousel.ts
+++ b/src/pages/profile/hooks/useCarousel.ts
@@ -31,10 +31,7 @@ export const useCarousel = (
} else {
distanceX = event.pageX - startX;
}
- if (Math.abs(distanceX) < MIN_DISTANCE) {
- carousel.scrollLeft =
- carousel.clientWidth * selectedTabIndex - distanceX;
- }
+ carousel.scrollLeft = carousel.clientWidth * selectedTabIndex - distanceX;
};
const handlePointerUp = () => {
@@ -51,7 +48,6 @@ export const useCarousel = (
) {
setSelectedTabIndex(selectedTabIndex + 1);
}
- carousel.style.marginLeft = `0px`;
carousel.removeEventListener('mousemove', handlePointerMove);
carousel.removeEventListener('touchmove', handlePointerMove);
};
diff --git a/src/utils/GetMyFollowData.ts b/src/utils/GetMyFollowData.ts
index 8b874226..d2e54e04 100644
--- a/src/utils/GetMyFollowData.ts
+++ b/src/utils/GetMyFollowData.ts
@@ -5,7 +5,7 @@ const GetMyFollowData = (
currentUserId: string
): Follow => {
if (followers && followers.length > 0 && currentUserId) {
- return followers.find((follow) => follow._id === currentUserId);
+ return followers.find((follow) => follow.follower === currentUserId);
}
};