Skip to content
20 changes: 11 additions & 9 deletions src/backend/main-server/main/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ services:
ports:
- "${MAIN_PORT}:${MAIN_PORT}"
environment:
SPRING_PROFILES_ACTIVE: docker
SPRING_DATASOURCE_URL: jdbc:mysql://${MYSQL_HOST}:${MYSQL_CONTAINER_PORT}/${MYSQL_DATABASE}
SPRING_DATASOURCE_USERNAME: ${MYSQL_USER}
SPRING_DATASOURCE_PASSWORD: ${MYSQL_PASSWORD}
SPRING_ELASTICSEARCH_URIS: http://elasticsearch:9200
SPRING_ELASTICSEARCH_USERNAME: elastic
SPRING_ELASTICSEARCH_PASSWORD: test123
SPRING_APPLICATION_NAME: main
- "SPRING_PROFILES_ACTIVE=docker"
- "SPRING_DATASOURCE_URL=jdbc:mysql://${MYSQL_HOST}:${MYSQL_CONTAINER_PORT}/${MYSQL_DATABASE}"
- "SPRING_DATASOURCE_USERNAME=${MYSQL_USER}"
- "SPRING_DATASOURCE_PASSWORD=${MYSQL_PASSWORD}"
- "SPRING_ELASTICSEARCH_URIS=http://elasticsearch:9200"
- "SPRING_ELASTICSEARCH_USERNAME=elastic"
- "SPRING_ELASTICSEARCH_PASSWORD=test123"
- "SPRING_APPLICATION_NAME=main"
- "AWS_ACCESS_KEY=${AWS_ACCESS_KEY}"
- "AWS_SECRET_KEY=${AWS_SECRET_KEY}"
depends_on:
elasticsearch:
condition: service_healthy
Expand All @@ -27,4 +29,4 @@ services:

networks:
kickzo-network:
driver: bridge
driver: bridge
9 changes: 8 additions & 1 deletion src/frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,14 @@ function App() {
</ProtectedRoute>
}
/>
<Route path="room" element={<RoomPage />} />
<Route
path="room"
element={
<ProtectedRoute>
<RoomPage />
</ProtectedRoute>
}
/>
<Route
path="friend"
element={
Expand Down
11 changes: 11 additions & 0 deletions src/frontend/src/api/endpoints/room/room.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
RoomDto,
CurrentRoomDto,
ReceiveMessageDto,
ElasticSearchDto,
} from './room.interface';
import { logAxiosError } from '@/api/axios.log';
import { ErrorType } from '@/types/enums/ErrorType';
Expand Down Expand Up @@ -156,4 +157,14 @@ export const roomApi = {
throw error;
}
},

searchFromElastic: async (keyword: string) => {
try {
const { data } = await instance.get<ElasticSearchDto>(`/search`, { params: { keyword } });
return data;
} catch (error) {
logAxiosError(error, ErrorType.ROOM, '엘라스틱서치 검색 실패');
throw error;
}
},
};
14 changes: 14 additions & 0 deletions src/frontend/src/api/endpoints/room/room.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface MyRoomDto {
profileImageUrl?: string;
userCount: number;
playlistUrl?: string;
public?: boolean;
}

export interface PaginationDto {
Expand All @@ -34,6 +35,7 @@ export interface RoomDto {
profileImageUrl?: string;
userCount: number;
playlistUrl?: string;
public?: boolean;
}

export interface CurrentRoomUserDto {
Expand Down Expand Up @@ -81,3 +83,15 @@ export interface ReceiveMessageDto extends SendMessageDto {
id: string;
timestamp: number;
}

export interface SearchUserDto {
userId: number;
nickname: string;
stateMessage: string;
profileImageUrl: string;
}

export interface ElasticSearchDto {
users: SearchUserDto[];
rooms: RoomDto[];
}
94 changes: 64 additions & 30 deletions src/frontend/src/assets/data/memberListTest.ts

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions src/frontend/src/assets/img/Key.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions src/frontend/src/components/Modal/MyProfileModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { MyProfile } from '@/components/Profile/MyProfile';
import { Background, RelativeModalContainer } from '../index.css';

interface IProfileModal {
onCancel: (e: React.MouseEvent<HTMLDivElement>) => void;
}

export const ProfileModal = ({ onCancel }: IProfileModal) => {
return (
<>
<Background $hasBackground={false} onClick={onCancel} />
<RelativeModalContainer>
<MyProfile />
</RelativeModalContainer>
</>
);
};
24 changes: 17 additions & 7 deletions src/frontend/src/components/Modal/ProfileModal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
import { MyProfile } from '@/components/Profile/MyProfile';
import { Background, RelativeModalContainer } from '../index.css';

import { ProfileDetail } from '@/components/common/ProfileDetail';
import { Background, ModalContainer } from '../index.css';
import { SidebarType } from '@/types/enums/SidebarType';
import { UserRole } from '@/types/enums/UserRole';
interface IProfileModal {
userId: number;
onCancel: (e: React.MouseEvent<HTMLDivElement>) => void;
}

export const ProfileModal = ({ onCancel }: IProfileModal) => {
export const ProfileModal = ({ userId, onCancel }: IProfileModal) => {
return (
<>
<Background $hasBackground={false} onClick={onCancel} />
<RelativeModalContainer>
<MyProfile />
</RelativeModalContainer>
<ModalContainer>
<ProfileDetail
userId={userId}
userRole={UserRole.NONE}
myRole={UserRole.NONE}
sidebarType={SidebarType.USERLIST}
nickname={''}
introduce={''}
imgUrl={''}
/>
</ModalContainer>
</>
);
};
41 changes: 41 additions & 0 deletions src/frontend/src/components/Modal/RoomProfileModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Background, RelativeModalContainer } from '../index.css';
import { ProfileDetail } from '@/components/common/ProfileDetail';
import { SidebarType } from '@/types/enums/SidebarType';
import { styled } from 'styled-components';

interface IProfileModal {
userId: number;
roomId: number;
nickname: string;
imgUrl: string;
userRole: number;
myRole: number;
sidebarType: SidebarType;
onCancel: (e: React.MouseEvent<HTMLDivElement>) => void;
}

export const RoomProfileModal = (props: IProfileModal) => {
return (
<>
<Background $hasBackground={false} onClick={props.onCancel} />
<Container>
<ProfileDetail
userId={props.userId}
roomId={props.roomId}
nickname={props.nickname}
imgUrl={props.imgUrl}
userRole={props.userRole}
myRole={props.myRole}
sidebarType={props.sidebarType}
/>
</Container>
</>
);
};

const Container = styled(RelativeModalContainer)`
width: 260px;
left: 10px;
top: 50px;
z-index: 1000;
`;
26 changes: 25 additions & 1 deletion src/frontend/src/components/MyRoomCard/index.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@ export const Card = styled.div`
display: flex;
align-items: stretch;
padding: 1rem 0;
border-bottom: 1px solid #ddd;
border-bottom: 1px solid var(--palette-line-normal-alternative);
position: relative;
cursor: pointer;

&:hover .badge {
background: rgba(0, 0, 0, 0.8);
border-radius: 50%;
}
`;

export const Thumbnail = styled.div`
Expand All @@ -24,6 +29,25 @@ export const Thumbnail = styled.div`
}
`;

export const Badge = styled.div`
position: absolute;
bottom: 4px;
right: 4px;
width: 28px;
height: 28px;
border-radius: 8px;
background-color: rgba(0, 0, 0, 0.2);
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease-in-out;

& > img {
width: 16px;
height: 16px;
}
`;

export const Info = styled.div`
flex: 1;
padding: 0.25rem 0;
Expand Down
8 changes: 7 additions & 1 deletion src/frontend/src/components/MyRoomCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import { RoomDeleteModal } from '@/components/Modal/RoomDeleteModal';
import { useNavigate } from 'react-router-dom';
import { MyRoomDto } from '@/api/endpoints/room/room.interface';
import DefaultThumbnail from '@/assets/img/DefaultThumbnail.svg';

import KeyIcon from '@/assets/img/Key.svg';
import {
ActionButton,
ActionButtons,
Badge,
Card,
Creator,
Info,
Expand Down Expand Up @@ -73,6 +74,11 @@ export const MyRoomCard = ({ room }: { room: MyRoomDto }) => {
onMouseLeave={() => setIsHovered(false)}
>
<Thumbnail>
{!room.public && (
<Badge className="badge">
<img src={KeyIcon} alt="private" />
</Badge>
)}
<img
src={thumbnail}
onError={e => {
Expand Down
1 change: 1 addition & 0 deletions src/frontend/src/components/RoomDetail/index.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import styled from 'styled-components';

export const Container = styled.header`
width: 100%;
height: 100%;
display: flex;
justify-content: space-between;
gap: 8px;
Expand Down
42 changes: 28 additions & 14 deletions src/frontend/src/components/Search/SearchBar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
SearchBarWrapper,
SearchIconBox,
} from './index.css';
import { userApi } from '@/api/endpoints/user/user.api';
import { UserResponseDto } from '@/api/endpoints/user/user.interface';
import { roomApi } from '@/api/endpoints/room/room.api';
import { SearchUserDto, RoomDto } from '@/api/endpoints/room/room.interface';

export const SearchBar = () => {
const navigate = useNavigate();
Expand All @@ -23,18 +23,25 @@
const [targetIndex, setTargetIndex] = useState<number>(-1);
const [searchValue, setSearchValue] = useState<string>('');
const [totalLength, setTotalLength] = useState<number>(0);
const [searchList, setSearchList] = useState<UserResponseDto[]>([]);
const [searchUserList, setSearchUserList] = useState<SearchUserDto[]>([]);
const [searchRoomList, setSearchRoomList] = useState<RoomDto[]>([]);
const enterKeyProcessed = useRef(false);

useEffect(() => {
if (targetIndex !== -1) {
searchInput.current!.value = searchList[targetIndex]?.nickname;
setSearchValue(searchInput.current!.value);
if (targetIndex < searchUserList.length) {
searchInput.current!.value = searchUserList[targetIndex]?.nickname;
setSearchValue(searchInput.current!.value);
} else {
searchInput.current!.value = searchRoomList[targetIndex - searchUserList.length]?.title;
setSearchValue(searchInput.current!.value);
}
}
}, [targetIndex]);

Check warning on line 40 in src/frontend/src/components/Search/SearchBar/index.tsx

View workflow job for this annotation

GitHub Actions / frontend-ci

React Hook useEffect has missing dependencies: 'searchRoomList' and 'searchUserList'. Either include them or remove the dependency array

const resetSearchState = () => {
setSearchList([]);
setSearchUserList([]);
setSearchRoomList([]);
setTotalLength(0);
setTargetIndex(-1);
if (searchInput.current) {
Expand All @@ -52,10 +59,12 @@
setTargetIndex(-1);
return;
} else {
// 검색어에 따른 검색 결과 리스트
const searchListData = await userApi.getUsers(0, 30, searchValue);
setSearchList(searchListData.users);
setTotalLength(searchListData.totalLength);
const searchListData = await roomApi.searchFromElastic(searchValue);

console.log('searchListData: ', searchListData.users);
setSearchUserList(searchListData.users);
setSearchRoomList(searchListData.rooms);
setTotalLength(searchListData.users.length + searchListData.rooms.length);
}
}
};
Expand All @@ -74,13 +83,17 @@
case 'ArrowUp':
if (totalLength > 0) {
// 위로 이동
setTargetIndex(prev => (prev > 0 ? prev - 1 : searchList.length - 1));
setTargetIndex(prev =>
prev > 0 ? prev - 1 : searchUserList.length + searchRoomList.length - 1,
);
}
break;
case 'ArrowDown':
if (totalLength > 0) {
// 아래로 이동
setTargetIndex(prev => (prev < searchList.length - 1 ? prev + 1 : 0));
setTargetIndex(prev =>
prev < searchUserList.length + searchRoomList.length - 1 ? prev + 1 : 0,
);
}
break;
}
Expand Down Expand Up @@ -133,10 +146,11 @@
<img src={SearchIcon} />
</SearchIconBox>
</SearchBarContainer>
{isFocus && searchInput.current?.value && totalLength > 0 && (
{isFocus && searchInput.current?.value && (
<>
<SearchBarList
searchList={searchList}
searchUserList={searchUserList}
searchRoomList={searchRoomList}
searchWord={searchValue}
resetSearchState={resetSearchState}
totalLength={totalLength}
Expand Down
Loading
Loading