Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/feed/FollowList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const FollowList = () => {
};

const handleMoreClick = () => {
navigate('/feed/followlist');
navigate('/follow/followlist');
};

const handleProfileClick = (userId: number) => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/feed/MyFollower.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const MyFollower = () => {
];

const handleMoreClick = () => {
navigate('/feed/followerlist');
navigate('/follow/followerlist');
};

return (
Expand Down
30 changes: 7 additions & 23 deletions src/components/feed/UserProfileItem.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,8 @@
import { useLocation, useNavigate } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { useState } from 'react';
import styled from '@emotion/styled';
import rightArrow from '../../assets/feed/rightArrow.svg';
import { typography } from '@/styles/global/global';

export interface UserProfileItemProps {
profileImgUrl: string;
userName: string;
userTitle: string;
titleColor: string;
followerCount?: number;
isFollowed?: boolean;
userId: number;
isLast?: boolean;
}
import type { UserProfileItemProps } from '@/types/user';

const UserProfileItem = ({
profileImgUrl,
Expand All @@ -24,13 +13,13 @@ const UserProfileItem = ({
isFollowed = false,
userId,
isLast,
type = 'followlist',
}: UserProfileItemProps) => {
const { pathname } = useLocation();
const navigate = useNavigate();
const [followed, setFollowed] = useState(isFollowed);

const handleProfileClick = () => {
navigate(`/feed/${userId}`);
navigate(`/otherfeed/${userId}`);
};

const toggleFollow = (e: React.MouseEvent) => {
Expand All @@ -44,11 +33,6 @@ const UserProfileItem = ({
console.log(`${userName} - ${followed ? '팔로우 취소' : '팔로우 요청'}`);
};

const handleFollowerListClick = (e: React.MouseEvent) => {
e.stopPropagation();
navigate(`/feed/followerlist/${userId}`);
};

return (
<Wrapper onClick={handleProfileClick} isLast={isLast}>
<UserProfile>
Expand All @@ -61,13 +45,13 @@ const UserProfileItem = ({
</div>
</div>
</div>
{pathname === '/feed/followlist' && (
{type === 'followlist' && (
<div className="followbutton" onClick={toggleFollow}>
{followed ? '띱 취소' : '띱 하기'}
</div>
)}
{pathname === '/feed/followerlist' && (
<div className="followlistbutton" onClick={handleFollowerListClick}>
{type === 'followerlist' && (
<div className="followlistbutton">
<div>{followerCount}명이 띱하는 중</div>
<img src={rightArrow} />
</div>
Expand Down
3 changes: 2 additions & 1 deletion src/components/search/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const SearchBarWrapper = styled.div`
border-radius: 12px;
width: calc(100% - 40px);
margin: 76px 20px 16px 20px;
padding: 16px 20px;
padding: 8px 12px;
box-sizing: border-box;

.delete-btn {
Expand All @@ -75,6 +75,7 @@ const Input = styled.input`
font-size: 14px;
padding: 8px 0;
box-sizing: border-box;
caret-color: var(--color-neongreen);

&::placeholder {
color: var(--color-grey-300);
Expand Down
38 changes: 38 additions & 0 deletions src/data/userData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { UserProfileItemProps } from '@/types/user';

export const mockUserList: UserProfileItemProps[] = [
{
profileImgUrl: 'https://placehold.co/36x36',
userName: 'ThipOther',
userTitle: '칭호칭호',
titleColor: '#FF8BAC',
followerCount: 15,
userId: 9,
},
{
profileImgUrl: 'https://placehold.co/36x36',
userName: '하위',
userTitle: '칭호칭호',
titleColor: '#FF8BAC',
followerCount: 15,
userId: 1,
isFollowed: true,
},
{
profileImgUrl: 'https://placehold.co/36x36',
userName: '책읽으러왔음',
userTitle: '공식 인플루언서',
titleColor: '#A0F8E8',
followerCount: 15,
userId: 2,
isFollowed: false,
},
{
profileImgUrl: 'https://placehold.co/36x36',
userName: 'thip01',
userTitle: '작가',
titleColor: '#A0F8E8',
followerCount: 7,
userId: 3,
},
];
8 changes: 7 additions & 1 deletion src/pages/feed/Feed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import TotalFeed from '../../components/feed/TotalFeed';
import MainHeader from '@/components/common/MainHeader';
import writefab from '../../assets/common/writefab.svg';
import { mockPosts } from '@/data/postData';
import { useNavigate } from 'react-router-dom';


const Container = styled.div`
Expand All @@ -18,15 +19,20 @@ const Container = styled.div`
const tabs = ['피드', '내 피드'];

const Feed = () => {
const navigate = useNavigate();
const [activeTab, setActiveTab] = useState(tabs[0]);

const handleSearchButton = () => {
navigate('/feed/search');
};

useEffect(() => {
window.scrollTo(0, 0);
}, [activeTab]);

return (
<Container>
<MainHeader type="home" />
<MainHeader type="home" leftButtonClick={handleSearchButton} />
<TabBar tabs={tabs} activeTab={activeTab} onTabClick={setActiveTab} />
{activeTab === '피드' ? (
<TotalFeed showHeader={true} posts={mockPosts} isMyFeed={false} />
Expand Down
48 changes: 9 additions & 39 deletions src/pages/feed/FollowerListPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,12 @@ import styled from '@emotion/styled';
import TitleHeader from '@/components/common/TitleHeader';
import leftArrow from '../../assets/common/leftArrow.svg';
import UserProfileItem from '@/components/feed/UserProfileItem';
import type { UserProfileItemProps } from '@/components/feed/UserProfileItem';

const mockUserList: UserProfileItemProps[] = [
{
profileImgUrl: 'https://placehold.co/36x36',
userName: 'ThipOther',
userTitle: '칭호칭호',
titleColor: '#FF8BAC',
followerCount: 15,
userId: 1,
},
{
profileImgUrl: 'https://placehold.co/36x36',
userName: '하위',
userTitle: '칭호칭호',
titleColor: '#FF8BAC',
followerCount: 15,
userId: 1,
isFollowed: true,
},
{
profileImgUrl: 'https://placehold.co/36x36',
userName: '책읽으러왔음',
userTitle: '공식 인플루언서',
titleColor: '#A0F8E8',
userId: 2,
isFollowed: false,
},
{
profileImgUrl: 'https://placehold.co/36x36',
userName: 'thip01',
userTitle: '작가',
titleColor: '#A0F8E8',
followerCount: 7,
userId: 3,
},
];
import { mockUserList } from '@/data/userData';
import type { UserProfileType } from '@/types/user';

const FollowerListPage = () => {
const navigate = useNavigate();
const { type } = useParams();
const { type } = useParams<{ type: UserProfileType }>();
const title = type === 'followerlist' ? '띱 목록' : '내 띱 목록';
const handleBackClick = () => {
navigate(-1);
Expand All @@ -56,7 +21,12 @@ const FollowerListPage = () => {
<TotalBar>전체 {totalCount}</TotalBar>
<UserProfileList>
{mockUserList.map((user, index) => (
<UserProfileItem key={index} {...user} isLast={index === mockUserList.length - 1} />
<UserProfileItem
key={index}
{...user}
type={type as UserProfileType}
isLast={index === mockUserList.length - 1}
/>
))}
</UserProfileList>
</Wrapper>
Expand Down
137 changes: 137 additions & 0 deletions src/pages/feed/UserSearch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import NavBar from '@/components/common/NavBar';
import TitleHeader from '@/components/common/TitleHeader';
import RecentSearchTabs from '@/components/search/RecentSearchTabs';
import SearchBar from '@/components/search/SearchBar';
import { colors } from '@/styles/global/global';
import styled from '@emotion/styled';
import { useEffect, useState } from 'react';
import leftArrow from '../../assets/common/leftArrow.svg';
import { mockUserList } from '@/data/userData';
import { UserSearchResult } from './UserSearchResult';
import { useNavigate } from 'react-router-dom';

const UserSearch = () => {
const navigate = useNavigate();
const [searchTerm, setSearchTerm] = useState('');
const [isSearching, setIsSearching] = useState(false);
const [isSearched, setIsSearched] = useState(false);

const [recentSearches, setRecentSearches] = useState<string[]>([
'닉네임',
'작가',
'하위',
'Thip',
'책벌레',
]);

const handleChange = (value: string) => {
setSearchTerm(value);
setIsSearched(false);
setIsSearching(value.trim() !== '');
};

const handleSearch = (term: string) => {
if (!term.trim()) return;
setIsSearching(true);
setIsSearched(true);
setRecentSearches(prev => {
const filtered = prev.filter(t => t !== term);
return [term, ...filtered].slice(0, 5);
});
};
Comment on lines +33 to +41
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

검색 로직에 실제 필터링을 구현하세요.

현재 검색 기능이 mock 데이터를 그대로 표시하고 있습니다. 실제 검색어에 따른 필터링 로직이 필요합니다.

검색 결과를 필터링하는 로직을 추가하세요:

+  const getFilteredUsers = (term: string) => {
+    if (!term.trim()) return [];
+    return mockUserList.filter(user => 
+      user.userName.toLowerCase().includes(term.toLowerCase()) ||
+      user.userTitle.toLowerCase().includes(term.toLowerCase())
+    );
+  };

   const handleSearch = (term: string) => {
     if (!term.trim()) return;
+    const filteredUsers = getFilteredUsers(term);
     setIsSearching(true);
     setIsSearched(true);
     setRecentSearches(prev => {
       const filtered = prev.filter(t => t !== term);
       return [term, ...filtered].slice(0, 5);
     });
   };

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/pages/feed/UserSearch.tsx around lines 33 to 41, the handleSearch
function currently updates recent searches but does not filter the displayed
data based on the search term. Implement filtering logic that uses the search
term to filter the actual data source or mock data before updating the displayed
search results. Ensure the filtered results are set in the component state to
reflect the search query accurately.


const handleDelete = (recentSearch: string) => {
setRecentSearches(prev => prev.filter(t => t !== recentSearch));
};

const handleRecentSearchClick = (recentSearch: string) => {
setSearchTerm(recentSearch);
setIsSearched(true);
setIsSearching(true);
};

const handleBackButton = () => {
navigate(-1);
};

useEffect(() => {
if (searchTerm.trim() === '') {
setIsSearching(false);
setIsSearched(false);
}
}, [searchTerm]);

return (
<Wrapper>
<TitleHeader
title="사용자 찾기"
leftIcon={<img src={leftArrow} alt="뒤로 가기" />}
onLeftClick={handleBackButton}
/>
<SearchBarContainer>
<SearchBar
placeholder="내가 찾는 사용자를 검색해보세요."
value={searchTerm}
onChange={handleChange}
onSearch={() => handleSearch(searchTerm.trim())}
isSearched={isSearched}
/>
</SearchBarContainer>
<Content>
{isSearching ? (
<>
(
{isSearched ? (
<UserSearchResult
type={'searched'}
searchedUserList={mockUserList}
></UserSearchResult>
) : (
<UserSearchResult
type={'searching'}
searchedUserList={mockUserList}
></UserSearchResult>
)}
)
</>
Comment on lines +82 to +96
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

JSX 문법 오류를 수정하세요.

조건부 렌더링에서 불필요한 괄호가 있어 문법 오류를 일으킬 수 있습니다.

         {isSearching ? (
-          <>
-            (
+          <>
             {isSearched ? (
               <UserSearchResult
                 type={'searched'}
-                searchedUserList={mockUserList}
-              ></UserSearchResult>
+                searchedUserList={getFilteredUsers(searchTerm)}
+              />
             ) : (
               <UserSearchResult
                 type={'searching'}
-                searchedUserList={mockUserList}
-              ></UserSearchResult>
+                searchedUserList={[]}
+              />
             )}
-            )
-          </>
+          </>
         ) : (

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/pages/feed/UserSearch.tsx between lines 82 and 96, remove the unnecessary
parentheses surrounding the JSX conditional rendering block, as these extra
parentheses cause a JSX syntax error. Ensure the conditional rendering is
directly enclosed within a fragment or a single parent element without
extraneous characters.

) : (
<>
<RecentSearchTabs
recentSearches={recentSearches}
handleDelete={handleDelete}
handleRecentSearchClick={handleRecentSearchClick}
/>
</>
)}
</Content>
<NavBar />
</Wrapper>
);
};

export default UserSearch;

const Wrapper = styled.div`
display: flex;
position: relative;
flex-direction: column;
min-width: 320px;
max-width: 767px;
height: 100vh;
margin: 0 auto;
background: ${colors.black.main};
`;

const SearchBarContainer = styled.div`
position: fixed;
top: 0;
left: 0;
right: 0;
max-width: 767px;
margin: 0 auto;
background: ${colors.black.main};
`;

const Content = styled.div`
margin-top: 132px;
`;
Loading