diff --git a/src/backend/main-server/main/docker-compose.yml b/src/backend/main-server/main/docker-compose.yml index f05387b2..ab30b859 100644 --- a/src/backend/main-server/main/docker-compose.yml +++ b/src/backend/main-server/main/docker-compose.yml @@ -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 @@ -27,4 +29,4 @@ services: networks: kickzo-network: - driver: bridge \ No newline at end of file + driver: bridge diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index 3f9aa749..648ef893 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -46,7 +46,14 @@ function App() { } /> - } /> + + + + } + /> { + try { + const { data } = await instance.get(`/search`, { params: { keyword } }); + return data; + } catch (error) { + logAxiosError(error, ErrorType.ROOM, '엘라스틱서치 검색 실패'); + throw error; + } + }, }; diff --git a/src/frontend/src/api/endpoints/room/room.interface.ts b/src/frontend/src/api/endpoints/room/room.interface.ts index 9484b6a1..9c8b1479 100644 --- a/src/frontend/src/api/endpoints/room/room.interface.ts +++ b/src/frontend/src/api/endpoints/room/room.interface.ts @@ -18,6 +18,7 @@ export interface MyRoomDto { profileImageUrl?: string; userCount: number; playlistUrl?: string; + public?: boolean; } export interface PaginationDto { @@ -34,6 +35,7 @@ export interface RoomDto { profileImageUrl?: string; userCount: number; playlistUrl?: string; + public?: boolean; } export interface CurrentRoomUserDto { @@ -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[]; +} diff --git a/src/frontend/src/assets/data/memberListTest.ts b/src/frontend/src/assets/data/memberListTest.ts index 5d34c6be..46f28b66 100644 --- a/src/frontend/src/assets/data/memberListTest.ts +++ b/src/frontend/src/assets/data/memberListTest.ts @@ -1,72 +1,106 @@ export const memberListTest = [ { - id: 1, + userId: 1, role: 2, nickname: '이노1', - profileImg: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5OjcBCgoKDQwNGg8PGjclHyU3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3N//AABEIALwAyAMBIgACEQEDEQH/xAAaAAEAAwEBAQAAAAAAAAAAAAAAAgMFBAEH/8QAKhABAAIBAgIKAwEBAAAAAAAAAAECAwQRIXEUIjEzQUJRcoGRMlJhsRP/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A+nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2ImZ2hbXS5beXbmCkdPQsvrX7QtpctfLvyBSPZiYnaXgAAAAAAAAAAAAAAAAAAC3BgtmnhwrHbKOHHOXJFY+WpSsUrFaxtEAjixUxR1Y+fFMAAAQy4qZY60fPiz8+C2GePGs9ktN5esXrNbRvEgyBPNjnFkms/CAAAAAAAAAAAAAAAAAO/Q02xzfxs6VenjbBTksAAAAAABza6m+OL+NXA1NRG+C/JlgAAAAAAAAAAAAAAAA1NPO+CnJY5tDffHNPGrpAAAAAABXqJ2wX5Mt366+2OKeNnAAAAAAAAAAAAAAAAACeHJOLJFo+WpS0XrFqzvEshbgz2wzw41ntgGmIYstMsdWfjxTAAAeXtFKza07RCOXLTFHWn48Wfnz2zTx4VjsgEc2ScuSbT8IAAAAAAAAAAAAAAAAAAJVpa/41meULa6XNPliOcgpiZid4W11OWvm35p9Cyetfs6Fk/an3IHTcvpX6QtqctvNtyT6Fk/an3J0LJ+1PuQc8zMzvLx09CyetftG2lzR5YnlIKBK1LU/KsxzhEAAAAAAAAAAAAAHTptNOTrX4U/0FWLDfLPVjh6y7cWkx04260/1dWIrEREbRD0CIiI2gAAAAAAACYiY2lRl0mO/GvVn+LwGXlw3xT1o4esK2vaItExMbxLh1OmnH1qcaf4DmAAAAAAAAB7WJtaIjtkF2lw/9bbz+Mdv9aMcI2hHFSMdIrHgkAAAAAAAAAAAAATxjaQBnarD/AMrbx+M9n8UNbLSMlJrPiyrRNbTE9sA8AAAAAAdWhpvkm89lYcrR0VdsET6zuC8AAAAAAAAAAAAAAABw66m2SLx2Wh3KNbXfBM+k7gzgAAAAAGpp42wU5Mtq4e5x+2ATAAAAAAAAAAAAAAAAV6iN8F+SxDN3N/bIMoAAAAABq4e5x+2GU1cPc4/bAJgAAAAAAAAAAAAAAAIZu5v7ZTQzdzf2yDKAAAB//9k=', + profileImageUrl: null, }, { - id: 2, + userId: 2, role: 2, nickname: '이노2', - profileImg: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5OjcBCgoKDQwNGg8PGjclHyU3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3N//AABEIALwAyAMBIgACEQEDEQH/xAAaAAEAAwEBAQAAAAAAAAAAAAAAAgMFBAEH/8QAKhABAAIBAgIKAwEBAAAAAAAAAAECAwQRIXEUIjEzQUJRcoGRMlJhsRP/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A+nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2ImZ2hbXS5beXbmCkdPQsvrX7QtpctfLvyBSPZiYnaXgAAAAAAAAAAAAAAAAAAC3BgtmnhwrHbKOHHOXJFY+WpSsUrFaxtEAjixUxR1Y+fFMAAAQy4qZY60fPiz8+C2GePGs9ktN5esXrNbRvEgyBPNjnFkms/CAAAAAAAAAAAAAAAAAO/Q02xzfxs6VenjbBTksAAAAAABza6m+OL+NXA1NRG+C/JlgAAAAAAAAAAAAAAAA1NPO+CnJY5tDffHNPGrpAAAAAABXqJ2wX5Mt366+2OKeNnAAAAAAAAAAAAAAAAACeHJOLJFo+WpS0XrFqzvEshbgz2wzw41ntgGmIYstMsdWfjxTAAAeXtFKza07RCOXLTFHWn48Wfnz2zTx4VjsgEc2ScuSbT8IAAAAAAAAAAAAAAAAAAJVpa/41meULa6XNPliOcgpiZid4W11OWvm35p9Cyetfs6Fk/an3IHTcvpX6QtqctvNtyT6Fk/an3J0LJ+1PuQc8zMzvLx09CyetftG2lzR5YnlIKBK1LU/KsxzhEAAAAAAAAAAAAAHTptNOTrX4U/0FWLDfLPVjh6y7cWkx04260/1dWIrEREbRD0CIiI2gAAAAAAACYiY2lRl0mO/GvVn+LwGXlw3xT1o4esK2vaItExMbxLh1OmnH1qcaf4DmAAAAAAAAB7WJtaIjtkF2lw/9bbz+Mdv9aMcI2hHFSMdIrHgkAAAAAAAAAAAAATxjaQBnarD/AMrbx+M9n8UNbLSMlJrPiyrRNbTE9sA8AAAAAAdWhpvkm89lYcrR0VdsET6zuC8AAAAAAAAAAAAAAABw66m2SLx2Wh3KNbXfBM+k7gzgAAAAAGpp42wU5Mtq4e5x+2ATAAAAAAAAAAAAAAAAV6iN8F+SxDN3N/bIMoAAAAABq4e5x+2GU1cPc4/bAJgAAAAAAAAAAAAAAAIZu5v7ZTQzdzf2yDKAAAB//9k=', + profileImageUrl: null, }, { - id: 3, + userId: 3, role: 0, nickname: '이노3', - profileImg: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5OjcBCgoKDQwNGg8PGjclHyU3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3N//AABEIALwAyAMBIgACEQEDEQH/xAAaAAEAAwEBAQAAAAAAAAAAAAAAAgMFBAEH/8QAKhABAAIBAgIKAwEBAAAAAAAAAAECAwQRIXEUIjEzQUJRcoGRMlJhsRP/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A+nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2ImZ2hbXS5beXbmCkdPQsvrX7QtpctfLvyBSPZiYnaXgAAAAAAAAAAAAAAAAAAC3BgtmnhwrHbKOHHOXJFY+WpSsUrFaxtEAjixUxR1Y+fFMAAAQy4qZY60fPiz8+C2GePGs9ktN5esXrNbRvEgyBPNjnFkms/CAAAAAAAAAAAAAAAAAO/Q02xzfxs6VenjbBTksAAAAAABza6m+OL+NXA1NRG+C/JlgAAAAAAAAAAAAAAAA1NPO+CnJY5tDffHNPGrpAAAAAABXqJ2wX5Mt366+2OKeNnAAAAAAAAAAAAAAAAACeHJOLJFo+WpS0XrFqzvEshbgz2wzw41ntgGmIYstMsdWfjxTAAAeXtFKza07RCOXLTFHWn48Wfnz2zTx4VjsgEc2ScuSbT8IAAAAAAAAAAAAAAAAAAJVpa/41meULa6XNPliOcgpiZid4W11OWvm35p9Cyetfs6Fk/an3IHTcvpX6QtqctvNtyT6Fk/an3J0LJ+1PuQc8zMzvLx09CyetftG2lzR5YnlIKBK1LU/KsxzhEAAAAAAAAAAAAAHTptNOTrX4U/0FWLDfLPVjh6y7cWkx04260/1dWIrEREbRD0CIiI2gAAAAAAACYiY2lRl0mO/GvVn+LwGXlw3xT1o4esK2vaItExMbxLh1OmnH1qcaf4DmAAAAAAAAB7WJtaIjtkF2lw/9bbz+Mdv9aMcI2hHFSMdIrHgkAAAAAAAAAAAAATxjaQBnarD/AMrbx+M9n8UNbLSMlJrPiyrRNbTE9sA8AAAAAAdWhpvkm89lYcrR0VdsET6zuC8AAAAAAAAAAAAAAABw66m2SLx2Wh3KNbXfBM+k7gzgAAAAAGpp42wU5Mtq4e5x+2ATAAAAAAAAAAAAAAAAV6iN8F+SxDN3N/bIMoAAAAABq4e5x+2GU1cPc4/bAJgAAAAAAAAAAAAAAAIZu5v7ZTQzdzf2yDKAAAB//9k=', + profileImageUrl: null, }, { - id: 4, + userId: 4, role: 2, nickname: '이노4', - profileImg: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5OjcBCgoKDQwNGg8PGjclHyU3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3N//AABEIALwAyAMBIgACEQEDEQH/xAAaAAEAAwEBAQAAAAAAAAAAAAAAAgMFBAEH/8QAKhABAAIBAgIKAwEBAAAAAAAAAAECAwQRIXEUIjEzQUJRcoGRMlJhsRP/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A+nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2ImZ2hbXS5beXbmCkdPQsvrX7QtpctfLvyBSPZiYnaXgAAAAAAAAAAAAAAAAAAC3BgtmnhwrHbKOHHOXJFY+WpSsUrFaxtEAjixUxR1Y+fFMAAAQy4qZY60fPiz8+C2GePGs9ktN5esXrNbRvEgyBPNjnFkms/CAAAAAAAAAAAAAAAAAO/Q02xzfxs6VenjbBTksAAAAAABza6m+OL+NXA1NRG+C/JlgAAAAAAAAAAAAAAAA1NPO+CnJY5tDffHNPGrpAAAAAABXqJ2wX5Mt366+2OKeNnAAAAAAAAAAAAAAAAACeHJOLJFo+WpS0XrFqzvEshbgz2wzw41ntgGmIYstMsdWfjxTAAAeXtFKza07RCOXLTFHWn48Wfnz2zTx4VjsgEc2ScuSbT8IAAAAAAAAAAAAAAAAAAJVpa/41meULa6XNPliOcgpiZid4W11OWvm35p9Cyetfs6Fk/an3IHTcvpX6QtqctvNtyT6Fk/an3J0LJ+1PuQc8zMzvLx09CyetftG2lzR5YnlIKBK1LU/KsxzhEAAAAAAAAAAAAAHTptNOTrX4U/0FWLDfLPVjh6y7cWkx04260/1dWIrEREbRD0CIiI2gAAAAAAACYiY2lRl0mO/GvVn+LwGXlw3xT1o4esK2vaItExMbxLh1OmnH1qcaf4DmAAAAAAAAB7WJtaIjtkF2lw/9bbz+Mdv9aMcI2hHFSMdIrHgkAAAAAAAAAAAAATxjaQBnarD/AMrbx+M9n8UNbLSMlJrPiyrRNbTE9sA8AAAAAAdWhpvkm89lYcrR0VdsET6zuC8AAAAAAAAAAAAAAABw66m2SLx2Wh3KNbXfBM+k7gzgAAAAAGpp42wU5Mtq4e5x+2ATAAAAAAAAAAAAAAAAV6iN8F+SxDN3N/bIMoAAAAABq4e5x+2GU1cPc4/bAJgAAAAAAAAAAAAAAAIZu5v7ZTQzdzf2yDKAAAB//9k=', + profileImageUrl: null, }, { - id: 5, + userId: 5, role: 2, nickname: '이노5', - profileImg: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5OjcBCgoKDQwNGg8PGjclHyU3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3N//AABEIALwAyAMBIgACEQEDEQH/xAAaAAEAAwEBAQAAAAAAAAAAAAAAAgMFBAEH/8QAKhABAAIBAgIKAwEBAAAAAAAAAAECAwQRIXEUIjEzQUJRcoGRMlJhsRP/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A+nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2ImZ2hbXS5beXbmCkdPQsvrX7QtpctfLvyBSPZiYnaXgAAAAAAAAAAAAAAAAAAC3BgtmnhwrHbKOHHOXJFY+WpSsUrFaxtEAjixUxR1Y+fFMAAAQy4qZY60fPiz8+C2GePGs9ktN5esXrNbRvEgyBPNjnFkms/CAAAAAAAAAAAAAAAAAO/Q02xzfxs6VenjbBTksAAAAAABza6m+OL+NXA1NRG+C/JlgAAAAAAAAAAAAAAAA1NPO+CnJY5tDffHNPGrpAAAAAABXqJ2wX5Mt366+2OKeNnAAAAAAAAAAAAAAAAACeHJOLJFo+WpS0XrFqzvEshbgz2wzw41ntgGmIYstMsdWfjxTAAAeXtFKza07RCOXLTFHWn48Wfnz2zTx4VjsgEc2ScuSbT8IAAAAAAAAAAAAAAAAAAJVpa/41meULa6XNPliOcgpiZid4W11OWvm35p9Cyetfs6Fk/an3IHTcvpX6QtqctvNtyT6Fk/an3J0LJ+1PuQc8zMzvLx09CyetftG2lzR5YnlIKBK1LU/KsxzhEAAAAAAAAAAAAAHTptNOTrX4U/0FWLDfLPVjh6y7cWkx04260/1dWIrEREbRD0CIiI2gAAAAAAACYiY2lRl0mO/GvVn+LwGXlw3xT1o4esK2vaItExMbxLh1OmnH1qcaf4DmAAAAAAAAB7WJtaIjtkF2lw/9bbz+Mdv9aMcI2hHFSMdIrHgkAAAAAAAAAAAAATxjaQBnarD/AMrbx+M9n8UNbLSMlJrPiyrRNbTE9sA8AAAAAAdWhpvkm89lYcrR0VdsET6zuC8AAAAAAAAAAAAAAABw66m2SLx2Wh3KNbXfBM+k7gzgAAAAAGpp42wU5Mtq4e5x+2ATAAAAAAAAAAAAAAAAV6iN8F+SxDN3N/bIMoAAAAABq4e5x+2GU1cPc4/bAJgAAAAAAAAAAAAAAAIZu5v7ZTQzdzf2yDKAAAB//9k=', + profileImageUrl: null, }, { - id: 6, + userId: 6, role: 2, nickname: '이노6', - profileImg: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5OjcBCgoKDQwNGg8PGjclHyU3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3N//AABEIALwAyAMBIgACEQEDEQH/xAAaAAEAAwEBAQAAAAAAAAAAAAAAAgMFBAEH/8QAKhABAAIBAgIKAwEBAAAAAAAAAAECAwQRIXEUIjEzQUJRcoGRMlJhsRP/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A+nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2ImZ2hbXS5beXbmCkdPQsvrX7QtpctfLvyBSPZiYnaXgAAAAAAAAAAAAAAAAAAC3BgtmnhwrHbKOHHOXJFY+WpSsUrFaxtEAjixUxR1Y+fFMAAAQy4qZY60fPiz8+C2GePGs9ktN5esXrNbRvEgyBPNjnFkms/CAAAAAAAAAAAAAAAAAO/Q02xzfxs6VenjbBTksAAAAAABza6m+OL+NXA1NRG+C/JlgAAAAAAAAAAAAAAAA1NPO+CnJY5tDffHNPGrpAAAAAABXqJ2wX5Mt366+2OKeNnAAAAAAAAAAAAAAAAACeHJOLJFo+WpS0XrFqzvEshbgz2wzw41ntgGmIYstMsdWfjxTAAAeXtFKza07RCOXLTFHWn48Wfnz2zTx4VjsgEc2ScuSbT8IAAAAAAAAAAAAAAAAAAJVpa/41meULa6XNPliOcgpiZid4W11OWvm35p9Cyetfs6Fk/an3IHTcvpX6QtqctvNtyT6Fk/an3J0LJ+1PuQc8zMzvLx09CyetftG2lzR5YnlIKBK1LU/KsxzhEAAAAAAAAAAAAAHTptNOTrX4U/0FWLDfLPVjh6y7cWkx04260/1dWIrEREbRD0CIiI2gAAAAAAACYiY2lRl0mO/GvVn+LwGXlw3xT1o4esK2vaItExMbxLh1OmnH1qcaf4DmAAAAAAAAB7WJtaIjtkF2lw/9bbz+Mdv9aMcI2hHFSMdIrHgkAAAAAAAAAAAAATxjaQBnarD/AMrbx+M9n8UNbLSMlJrPiyrRNbTE9sA8AAAAAAdWhpvkm89lYcrR0VdsET6zuC8AAAAAAAAAAAAAAABw66m2SLx2Wh3KNbXfBM+k7gzgAAAAAGpp42wU5Mtq4e5x+2ATAAAAAAAAAAAAAAAAV6iN8F+SxDN3N/bIMoAAAAABq4e5x+2GU1cPc4/bAJgAAAAAAAAAAAAAAAIZu5v7ZTQzdzf2yDKAAAB//9k=', + profileImageUrl: null, }, { - id: 7, + userId: 7, role: 1, nickname: '이노7', - profileImg: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5OjcBCgoKDQwNGg8PGjclHyU3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3N//AABEIALwAyAMBIgACEQEDEQH/xAAaAAEAAwEBAQAAAAAAAAAAAAAAAgMFBAEH/8QAKhABAAIBAgIKAwEBAAAAAAAAAAECAwQRIXEUIjEzQUJRcoGRMlJhsRP/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A+nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2ImZ2hbXS5beXbmCkdPQsvrX7QtpctfLvyBSPZiYnaXgAAAAAAAAAAAAAAAAAAC3BgtmnhwrHbKOHHOXJFY+WpSsUrFaxtEAjixUxR1Y+fFMAAAQy4qZY60fPiz8+C2GePGs9ktN5esXrNbRvEgyBPNjnFkms/CAAAAAAAAAAAAAAAAAO/Q02xzfxs6VenjbBTksAAAAAABza6m+OL+NXA1NRG+C/JlgAAAAAAAAAAAAAAAA1NPO+CnJY5tDffHNPGrpAAAAAABXqJ2wX5Mt366+2OKeNnAAAAAAAAAAAAAAAAACeHJOLJFo+WpS0XrFqzvEshbgz2wzw41ntgGmIYstMsdWfjxTAAAeXtFKza07RCOXLTFHWn48Wfnz2zTx4VjsgEc2ScuSbT8IAAAAAAAAAAAAAAAAAAJVpa/41meULa6XNPliOcgpiZid4W11OWvm35p9Cyetfs6Fk/an3IHTcvpX6QtqctvNtyT6Fk/an3J0LJ+1PuQc8zMzvLx09CyetftG2lzR5YnlIKBK1LU/KsxzhEAAAAAAAAAAAAAHTptNOTrX4U/0FWLDfLPVjh6y7cWkx04260/1dWIrEREbRD0CIiI2gAAAAAAACYiY2lRl0mO/GvVn+LwGXlw3xT1o4esK2vaItExMbxLh1OmnH1qcaf4DmAAAAAAAAB7WJtaIjtkF2lw/9bbz+Mdv9aMcI2hHFSMdIrHgkAAAAAAAAAAAAATxjaQBnarD/AMrbx+M9n8UNbLSMlJrPiyrRNbTE9sA8AAAAAAdWhpvkm89lYcrR0VdsET6zuC8AAAAAAAAAAAAAAABw66m2SLx2Wh3KNbXfBM+k7gzgAAAAAGpp42wU5Mtq4e5x+2ATAAAAAAAAAAAAAAAAV6iN8F+SxDN3N/bIMoAAAAABq4e5x+2GU1cPc4/bAJgAAAAAAAAAAAAAAAIZu5v7ZTQzdzf2yDKAAAB//9k=', + profileImageUrl: null, }, { - id: 8, + userId: 8, role: 2, nickname: '이노8', - profileImg: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5OjcBCgoKDQwNGg8PGjclHyU3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3N//AABEIALwAyAMBIgACEQEDEQH/xAAaAAEAAwEBAQAAAAAAAAAAAAAAAgMFBAEH/8QAKhABAAIBAgIKAwEBAAAAAAAAAAECAwQRIXEUIjEzQUJRcoGRMlJhsRP/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A+nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2ImZ2hbXS5beXbmCkdPQsvrX7QtpctfLvyBSPZiYnaXgAAAAAAAAAAAAAAAAAAC3BgtmnhwrHbKOHHOXJFY+WpSsUrFaxtEAjixUxR1Y+fFMAAAQy4qZY60fPiz8+C2GePGs9ktN5esXrNbRvEgyBPNjnFkms/CAAAAAAAAAAAAAAAAAO/Q02xzfxs6VenjbBTksAAAAAABza6m+OL+NXA1NRG+C/JlgAAAAAAAAAAAAAAAA1NPO+CnJY5tDffHNPGrpAAAAAABXqJ2wX5Mt366+2OKeNnAAAAAAAAAAAAAAAAACeHJOLJFo+WpS0XrFqzvEshbgz2wzw41ntgGmIYstMsdWfjxTAAAeXtFKza07RCOXLTFHWn48Wfnz2zTx4VjsgEc2ScuSbT8IAAAAAAAAAAAAAAAAAAJVpa/41meULa6XNPliOcgpiZid4W11OWvm35p9Cyetfs6Fk/an3IHTcvpX6QtqctvNtyT6Fk/an3J0LJ+1PuQc8zMzvLx09CyetftG2lzR5YnlIKBK1LU/KsxzhEAAAAAAAAAAAAAHTptNOTrX4U/0FWLDfLPVjh6y7cWkx04260/1dWIrEREbRD0CIiI2gAAAAAAACYiY2lRl0mO/GvVn+LwGXlw3xT1o4esK2vaItExMbxLh1OmnH1qcaf4DmAAAAAAAAB7WJtaIjtkF2lw/9bbz+Mdv9aMcI2hHFSMdIrHgkAAAAAAAAAAAAATxjaQBnarD/AMrbx+M9n8UNbLSMlJrPiyrRNbTE9sA8AAAAAAdWhpvkm89lYcrR0VdsET6zuC8AAAAAAAAAAAAAAABw66m2SLx2Wh3KNbXfBM+k7gzgAAAAAGpp42wU5Mtq4e5x+2ATAAAAAAAAAAAAAAAAV6iN8F+SxDN3N/bIMoAAAAABq4e5x+2GU1cPc4/bAJgAAAAAAAAAAAAAAAIZu5v7ZTQzdzf2yDKAAAB//9k=', + profileImageUrl: null, }, { - id: 9, + userId: 9, role: 1, nickname: '이노9', - profileImg: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5OjcBCgoKDQwNGg8PGjclHyU3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3N//AABEIALwAyAMBIgACEQEDEQH/xAAaAAEAAwEBAQAAAAAAAAAAAAAAAgMFBAEH/8QAKhABAAIBAgIKAwEBAAAAAAAAAAECAwQRIXEUIjEzQUJRcoGRMlJhsRP/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A+nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2ImZ2hbXS5beXbmCkdPQsvrX7QtpctfLvyBSPZiYnaXgAAAAAAAAAAAAAAAAAAC3BgtmnhwrHbKOHHOXJFY+WpSsUrFaxtEAjixUxR1Y+fFMAAAQy4qZY60fPiz8+C2GePGs9ktN5esXrNbRvEgyBPNjnFkms/CAAAAAAAAAAAAAAAAAO/Q02xzfxs6VenjbBTksAAAAAABza6m+OL+NXA1NRG+C/JlgAAAAAAAAAAAAAAAA1NPO+CnJY5tDffHNPGrpAAAAAABXqJ2wX5Mt366+2OKeNnAAAAAAAAAAAAAAAAACeHJOLJFo+WpS0XrFqzvEshbgz2wzw41ntgGmIYstMsdWfjxTAAAeXtFKza07RCOXLTFHWn48Wfnz2zTx4VjsgEc2ScuSbT8IAAAAAAAAAAAAAAAAAAJVpa/41meULa6XNPliOcgpiZid4W11OWvm35p9Cyetfs6Fk/an3IHTcvpX6QtqctvNtyT6Fk/an3J0LJ+1PuQc8zMzvLx09CyetftG2lzR5YnlIKBK1LU/KsxzhEAAAAAAAAAAAAAHTptNOTrX4U/0FWLDfLPVjh6y7cWkx04260/1dWIrEREbRD0CIiI2gAAAAAAACYiY2lRl0mO/GvVn+LwGXlw3xT1o4esK2vaItExMbxLh1OmnH1qcaf4DmAAAAAAAAB7WJtaIjtkF2lw/9bbz+Mdv9aMcI2hHFSMdIrHgkAAAAAAAAAAAAATxjaQBnarD/AMrbx+M9n8UNbLSMlJrPiyrRNbTE9sA8AAAAAAdWhpvkm89lYcrR0VdsET6zuC8AAAAAAAAAAAAAAABw66m2SLx2Wh3KNbXfBM+k7gzgAAAAAGpp42wU5Mtq4e5x+2ATAAAAAAAAAAAAAAAAV6iN8F+SxDN3N/bIMoAAAAABq4e5x+2GU1cPc4/bAJgAAAAAAAAAAAAAAAIZu5v7ZTQzdzf2yDKAAAB//9k=', + profileImageUrl: null, }, { - id: 10, + userId: 10, role: 2, nickname: '이노10', - profileImg: - 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5OjcBCgoKDQwNGg8PGjclHyU3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3N//AABEIALwAyAMBIgACEQEDEQH/xAAaAAEAAwEBAQAAAAAAAAAAAAAAAgMFBAEH/8QAKhABAAIBAgIKAwEBAAAAAAAAAAECAwQRIXEUIjEzQUJRcoGRMlJhsRP/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A+nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2ImZ2hbXS5beXbmCkdPQsvrX7QtpctfLvyBSPZiYnaXgAAAAAAAAAAAAAAAAAAC3BgtmnhwrHbKOHHOXJFY+WpSsUrFaxtEAjixUxR1Y+fFMAAAQy4qZY60fPiz8+C2GePGs9ktN5esXrNbRvEgyBPNjnFkms/CAAAAAAAAAAAAAAAAAO/Q02xzfxs6VenjbBTksAAAAAABza6m+OL+NXA1NRG+C/JlgAAAAAAAAAAAAAAAA1NPO+CnJY5tDffHNPGrpAAAAAABXqJ2wX5Mt366+2OKeNnAAAAAAAAAAAAAAAAACeHJOLJFo+WpS0XrFqzvEshbgz2wzw41ntgGmIYstMsdWfjxTAAAeXtFKza07RCOXLTFHWn48Wfnz2zTx4VjsgEc2ScuSbT8IAAAAAAAAAAAAAAAAAAJVpa/41meULa6XNPliOcgpiZid4W11OWvm35p9Cyetfs6Fk/an3IHTcvpX6QtqctvNtyT6Fk/an3J0LJ+1PuQc8zMzvLx09CyetftG2lzR5YnlIKBK1LU/KsxzhEAAAAAAAAAAAAAHTptNOTrX4U/0FWLDfLPVjh6y7cWkx04260/1dWIrEREbRD0CIiI2gAAAAAAACYiY2lRl0mO/GvVn+LwGXlw3xT1o4esK2vaItExMbxLh1OmnH1qcaf4DmAAAAAAAAB7WJtaIjtkF2lw/9bbz+Mdv9aMcI2hHFSMdIrHgkAAAAAAAAAAAAATxjaQBnarD/AMrbx+M9n8UNbLSMlJrPiyrRNbTE9sA8AAAAAAdWhpvkm89lYcrR0VdsET6zuC8AAAAAAAAAAAAAAABw66m2SLx2Wh3KNbXfBM+k7gzgAAAAAGpp42wU5Mtq4e5x+2ATAAAAAAAAAAAAAAAAV6iN8F+SxDN3N/bIMoAAAAABq4e5x+2GU1cPc4/bAJgAAAAAAAAAAAAAAAIZu5v7ZTQzdzf2yDKAAAB//9k=', + profileImageUrl: null, }, + { + userId: 11, + role: 2, + nickname: '이노11', + profileImageUrl: null, + }, + { + userId: 12, + role: 2, + nickname: '이노12', + profileImageUrl: null, + }, + { + userId: 13, + role: 2, + nickname: '이노13', + profileImageUrl: null, + }, + { + userId: 14, + role: 2, + nickname: '이노14', + profileImageUrl: null, + }, + { + userId: 15, + role: 2, + nickname: '이노15', + profileImageUrl: null, + }, + { + userId: 16, + role: 2, + nickname: '이노16', + profileImageUrl: null, + }, + { + userId: 17, + role: 2, + nickname: '이노17', + profileImageUrl: null, + }, + + ]; diff --git a/src/frontend/src/assets/img/Key.svg b/src/frontend/src/assets/img/Key.svg new file mode 100644 index 00000000..01f61c2f --- /dev/null +++ b/src/frontend/src/assets/img/Key.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/frontend/src/components/Modal/MyProfileModal/index.tsx b/src/frontend/src/components/Modal/MyProfileModal/index.tsx new file mode 100644 index 00000000..aeb41fec --- /dev/null +++ b/src/frontend/src/components/Modal/MyProfileModal/index.tsx @@ -0,0 +1,17 @@ +import { MyProfile } from '@/components/Profile/MyProfile'; +import { Background, RelativeModalContainer } from '../index.css'; + +interface IProfileModal { + onCancel: (e: React.MouseEvent) => void; +} + +export const ProfileModal = ({ onCancel }: IProfileModal) => { + return ( + <> + + + + + + ); +}; diff --git a/src/frontend/src/components/Modal/ProfileModal/index.tsx b/src/frontend/src/components/Modal/ProfileModal/index.tsx index aeb41fec..5045300b 100644 --- a/src/frontend/src/components/Modal/ProfileModal/index.tsx +++ b/src/frontend/src/components/Modal/ProfileModal/index.tsx @@ -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) => void; } -export const ProfileModal = ({ onCancel }: IProfileModal) => { +export const ProfileModal = ({ userId, onCancel }: IProfileModal) => { return ( <> - - - + + + ); }; diff --git a/src/frontend/src/components/Modal/RoomProfileModal/index.tsx b/src/frontend/src/components/Modal/RoomProfileModal/index.tsx new file mode 100644 index 00000000..f599e4c3 --- /dev/null +++ b/src/frontend/src/components/Modal/RoomProfileModal/index.tsx @@ -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) => void; +} + +export const RoomProfileModal = (props: IProfileModal) => { + return ( + <> + + + + + + ); +}; + +const Container = styled(RelativeModalContainer)` + width: 260px; + left: 10px; + top: 50px; + z-index: 1000; +`; diff --git a/src/frontend/src/components/MyRoomCard/index.css.ts b/src/frontend/src/components/MyRoomCard/index.css.ts index 2e0862bd..e30ca468 100644 --- a/src/frontend/src/components/MyRoomCard/index.css.ts +++ b/src/frontend/src/components/MyRoomCard/index.css.ts @@ -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` @@ -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; diff --git a/src/frontend/src/components/MyRoomCard/index.tsx b/src/frontend/src/components/MyRoomCard/index.tsx index 6ba3293c..a0577bad 100644 --- a/src/frontend/src/components/MyRoomCard/index.tsx +++ b/src/frontend/src/components/MyRoomCard/index.tsx @@ -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, @@ -73,6 +74,11 @@ export const MyRoomCard = ({ room }: { room: MyRoomDto }) => { onMouseLeave={() => setIsHovered(false)} > + {!room.public && ( + + private + + )} { diff --git a/src/frontend/src/components/RoomDetail/index.css.ts b/src/frontend/src/components/RoomDetail/index.css.ts index 1ce0a08f..af9d50e6 100644 --- a/src/frontend/src/components/RoomDetail/index.css.ts +++ b/src/frontend/src/components/RoomDetail/index.css.ts @@ -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; diff --git a/src/frontend/src/components/Search/SearchBar/index.tsx b/src/frontend/src/components/Search/SearchBar/index.tsx index d80c3d58..3bdf716c 100644 --- a/src/frontend/src/components/Search/SearchBar/index.tsx +++ b/src/frontend/src/components/Search/SearchBar/index.tsx @@ -11,8 +11,8 @@ import { 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(); @@ -23,18 +23,25 @@ export const SearchBar = () => { const [targetIndex, setTargetIndex] = useState(-1); const [searchValue, setSearchValue] = useState(''); const [totalLength, setTotalLength] = useState(0); - const [searchList, setSearchList] = useState([]); + const [searchUserList, setSearchUserList] = useState([]); + const [searchRoomList, setSearchRoomList] = useState([]); 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]); const resetSearchState = () => { - setSearchList([]); + setSearchUserList([]); + setSearchRoomList([]); setTotalLength(0); setTargetIndex(-1); if (searchInput.current) { @@ -52,10 +59,12 @@ export const SearchBar = () => { 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); } } }; @@ -74,13 +83,17 @@ export const SearchBar = () => { 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; } @@ -133,10 +146,11 @@ export const SearchBar = () => { - {isFocus && searchInput.current?.value && totalLength > 0 && ( + {isFocus && searchInput.current?.value && ( <> void; searchWord?: string; totalLength: number; @@ -16,7 +19,7 @@ export const SearchBarList = ({ }) => { return (
    - {searchList.map((item, index: number) => { + {searchUserList.map((item, index: number) => { return ( + ); + })} + {searchRoomList.map((item, index: number) => { + return ( + ); })} diff --git a/src/frontend/src/components/Search/SearchBarListItem/index.css.ts b/src/frontend/src/components/Search/SearchBarListItem/index.css.ts index dcaa6e6e..31739ece 100644 --- a/src/frontend/src/components/Search/SearchBarListItem/index.css.ts +++ b/src/frontend/src/components/Search/SearchBarListItem/index.css.ts @@ -5,6 +5,8 @@ export const Li = styled.li` border-radius: 10px; cursor: pointer; display: flex; + align-items: center; + gap: 8px; & strong { color: var(--palette-primary); @@ -35,3 +37,29 @@ export const Li = styled.li` } } `; + +export const Img = styled.div` + width: 24px; + height: 24px; + margin-right: 8px; + border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + + img { + width: 100%; + object-fit: cover; + } +`; + +export const Thumbnail = styled(Img)` + width: 32px; + + img { + aspect-ratio: 16 / 9; + object-fit: cover; + border: 1px solid var(--palette-font-gray); + } +`; diff --git a/src/frontend/src/components/Search/SearchBarListItem/index.tsx b/src/frontend/src/components/Search/SearchBarListItem/index.tsx index 1f18c751..e4df7fcc 100644 --- a/src/frontend/src/components/Search/SearchBarListItem/index.tsx +++ b/src/frontend/src/components/Search/SearchBarListItem/index.tsx @@ -1,15 +1,33 @@ import { useNavigate } from 'react-router-dom'; import { ChangeToHTML } from './ChangeToHTML'; -import { Li } from './index.css'; +import { Img, Li, Thumbnail } from './index.css'; +import DefaultProfile from '@/assets/img/DefaultProfile.svg'; +import DefaultThumbnail from '@/assets/img/DefaultThumbnail.svg'; +import { useEffect, useState } from 'react'; +import { getYoutubeThumbnail } from '@/utils/youtubeUtils'; export const SearchListItem = (props: { inputText?: string; resultText: string; resetSearchState: () => void; isTargetIndex?: boolean; + imageUrl?: string; + type: 'user' | 'room'; }) => { - const { resultText, inputText, resetSearchState, isTargetIndex } = props; + const { resultText, inputText, resetSearchState, isTargetIndex, type, imageUrl } = props; const navigate = useNavigate(); + const [thumbnail, setThumbnail] = useState(DefaultThumbnail); + + useEffect(() => { + if (type !== 'room' || !imageUrl) return; + + const fetchThumbnail = async () => { + const url = await getYoutubeThumbnail(imageUrl ?? '', 'default'); + setThumbnail(url ?? DefaultThumbnail); + }; + + fetchThumbnail(); + }, [type, imageUrl]); return (
  • + {type === 'user' ? ( + + profile + + ) : ( + + { + e.currentTarget.src = DefaultThumbnail; + }} + alt="thumbnail" + /> + + )}
  • ); diff --git a/src/frontend/src/components/Search/SearchItem/SearchRoomItem/index.tsx b/src/frontend/src/components/Search/SearchItem/SearchRoomItem/index.tsx new file mode 100644 index 00000000..f02b9899 --- /dev/null +++ b/src/frontend/src/components/Search/SearchItem/SearchRoomItem/index.tsx @@ -0,0 +1,59 @@ +import { RoomDto } from '@/api/endpoints/room/room.interface'; +import DefaultThumbnail from '@/assets/img/DefaultThumbnail.svg'; +import UserIcon from '@/assets/img/UsersLine.svg'; +import { + Card, + Creator, + Info, + Thumbnail, + Title, + UserCount, +} from '@/components/MyRoomCard/index.css'; +import { getYoutubeThumbnail } from '@/utils/youtubeUtils'; +import { useEffect, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; + +export const SearchRoomItem = ({ room }: { room: RoomDto }) => { + const [thumbnail, setThumbnail] = useState(DefaultThumbnail); + const navigate = useNavigate(); + + useEffect(() => { + if (!room.playlistUrl) return; + + const fetchThumbnail = async () => { + const url = await getYoutubeThumbnail(room.playlistUrl ?? '', 'default'); + setThumbnail(url ?? DefaultThumbnail); + }; + + fetchThumbnail(); + }, [room.playlistUrl]); + + const handleClick = (e: React.MouseEvent) => { + e.stopPropagation(); + navigate(`/room?code=${room.code}`); + }; + + return ( + + + { + e.currentTarget.src = DefaultThumbnail; + }} + alt={room.title} + /> + + +
    + {room.title} + {room.creator} +
    + + Users Icon + {room.userCount} + +
    +
    + ); +}; diff --git a/src/frontend/src/components/Search/SearchItem/index.css.ts b/src/frontend/src/components/Search/SearchItem/SearchUserItem/index.css.ts similarity index 90% rename from src/frontend/src/components/Search/SearchItem/index.css.ts rename to src/frontend/src/components/Search/SearchItem/SearchUserItem/index.css.ts index 93207f92..4c54fa6b 100644 --- a/src/frontend/src/components/Search/SearchItem/index.css.ts +++ b/src/frontend/src/components/Search/SearchItem/SearchUserItem/index.css.ts @@ -1,6 +1,7 @@ import { styled } from 'styled-components'; export const SearchItemContainer = styled.div` + position: relative; display: flex; align-items: center; justify-content: space-between; @@ -19,6 +20,9 @@ export const SearchItemProfileImage = styled.div` border-radius: 10px; overflow: hidden; margin-right: 1rem; + display: flex; + align-items: center; + justify-content: center; `; export const SearchItemInfo = styled.div` diff --git a/src/frontend/src/components/Search/SearchItem/index.tsx b/src/frontend/src/components/Search/SearchItem/SearchUserItem/index.tsx similarity index 95% rename from src/frontend/src/components/Search/SearchItem/index.tsx rename to src/frontend/src/components/Search/SearchItem/SearchUserItem/index.tsx index 1df628a5..72198a80 100644 --- a/src/frontend/src/components/Search/SearchItem/index.tsx +++ b/src/frontend/src/components/Search/SearchItem/SearchUserItem/index.tsx @@ -16,15 +16,14 @@ import { SearchItemNickname, SearchItemStateMessage, } from './index.css'; -import { UserResponseDto } from '@/api/endpoints/user/user.interface'; +import { SearchUserDto } from '@/api/endpoints/room/room.interface'; import axios from 'axios'; -export const SearchItem = ({ user }: { user: UserResponseDto }) => { +export const SearchUserItem = ({ user }: { user: SearchUserDto }) => { const { user: me } = useUserStore(); const { friends } = useFriendStore(); const { notifications } = useNotificationStore(); const [alreadyRequested, setAlreadyRequested] = useState(false); - const isFriend = friends.some(friend => friend.friend_id === user.userId); const hasRequested = notifications.some( notification => notification.senderId === user.userId && notification.status === 'PENDING', diff --git a/src/frontend/src/components/Sidebar/Chating/ChatInput/index.css.ts b/src/frontend/src/components/Sidebar/Chating/ChatInput/index.css.ts index c973664d..4113cfc8 100644 --- a/src/frontend/src/components/Sidebar/Chating/ChatInput/index.css.ts +++ b/src/frontend/src/components/Sidebar/Chating/ChatInput/index.css.ts @@ -4,6 +4,7 @@ export const InputContainer = styled.div` display: flex; align-items: center; padding: 8px; - border-top: 1px solid #d4d4d4; + border-top: 1px solid var(--palette-line-solid-neutral); background: white; + gap: 4px; `; diff --git a/src/frontend/src/components/Sidebar/Chating/ChatMessages/ChatLayout/ChatNickname/index.tsx b/src/frontend/src/components/Sidebar/Chating/ChatMessages/ChatLayout/ChatNickname/index.tsx index fa32cf0c..c40a4cbe 100644 --- a/src/frontend/src/components/Sidebar/Chating/ChatMessages/ChatLayout/ChatNickname/index.tsx +++ b/src/frontend/src/components/Sidebar/Chating/ChatMessages/ChatLayout/ChatNickname/index.tsx @@ -42,5 +42,5 @@ const Img = styled.img``; const Nickname = styled.div<{ $role: UserRole }>` color: ${({ $role }) => $role === UserRole.CREATOR ? '#FF9100' : $role === UserRole.MANAGER ? '#4D94E1' : '#000000'}; - font-weight: bold; + font-weight: 500; `; diff --git a/src/frontend/src/components/Sidebar/Chating/ChatMessages/ChatLayout/index.css.ts b/src/frontend/src/components/Sidebar/Chating/ChatMessages/ChatLayout/index.css.ts index a0ed5829..70cdb22e 100644 --- a/src/frontend/src/components/Sidebar/Chating/ChatMessages/ChatLayout/index.css.ts +++ b/src/frontend/src/components/Sidebar/Chating/ChatMessages/ChatLayout/index.css.ts @@ -5,25 +5,32 @@ export const Wrapper = styled.div` flex-direction: row; padding: 10px; `; + export const Profile = styled.img` width: 40px; height: 40px; - margin-right: 4px; + margin-right: 8px; border-radius: 10px; `; + export const ChatContainer = styled.div` display: flex; flex-direction: column; `; + export const Title = styled.div` display: flex; flex-direction: row; align-items: center; margin-bottom: 4px; `; + export const Title__Time = styled.div` font-size: 12px; color: #888888; margin-left: 8px; `; -export const ChatText = styled.div``; + +export const ChatText = styled.div` + font-size: 14px; +`; diff --git a/src/frontend/src/components/Sidebar/Chating/index.css.ts b/src/frontend/src/components/Sidebar/Chating/index.css.ts index 6bde1e99..efd10831 100644 --- a/src/frontend/src/components/Sidebar/Chating/index.css.ts +++ b/src/frontend/src/components/Sidebar/Chating/index.css.ts @@ -5,8 +5,6 @@ export const ChatContainer = styled.div` flex-direction: column; height: 100%; background-color: #ffffff; - border: 1px solid #d4d4d4; - border-radius: 10px; position: relative; `; @@ -15,7 +13,6 @@ export const ChatScrollArea = styled.div` overflow-y: auto; display: flex; flex-direction: column; - padding: 10px; &::-webkit-scrollbar { width: 6px; diff --git a/src/frontend/src/components/Sidebar/Playlist/PlaylistItem/index.css.ts b/src/frontend/src/components/Sidebar/Playlist/PlaylistItem/index.css.ts index c98764af..46fa369e 100644 --- a/src/frontend/src/components/Sidebar/Playlist/PlaylistItem/index.css.ts +++ b/src/frontend/src/components/Sidebar/Playlist/PlaylistItem/index.css.ts @@ -8,13 +8,13 @@ interface VideoItemContainerProps { export const Container = styled.div` display: flex; - align-items: center; + align-items: flex-start; + justify-content: space-between; gap: 5px; - padding: 10px; - border-radius: 5px; + padding: 16px 8px; background-color: ${({ $isPreview }) => $isPreview ? 'var(--palette-line-normal-normal)' : 'var(--palette-static-white)'}; - border: 1px solid #ddd; + border-bottom: 1px solid var(--palette-line-normal-alternative); cursor: pointer; position: relative; transition: all 0.2s ease; @@ -79,16 +79,15 @@ export const Playlist__Youtuber = styled.div` `; export const ButtonContainer = styled.div` - width: 300px; + width: 100%; height: 100%; display: flex; - gap: 5px; justify-content: space-between; - padding: 10px 0; + padding: 10px; align-items: end; position: absolute; - top: 50%; - transform: translateY(-50%); + top: 0px; + left: 0px; opacity: 0; visibility: hidden; transition: diff --git a/src/frontend/src/components/Sidebar/Playlist/index.css.ts b/src/frontend/src/components/Sidebar/Playlist/index.css.ts index bb9b47ab..2663c0d9 100644 --- a/src/frontend/src/components/Sidebar/Playlist/index.css.ts +++ b/src/frontend/src/components/Sidebar/Playlist/index.css.ts @@ -11,23 +11,28 @@ export const Container = styled.div` export const Wrapper = styled.div` width: 100%; + height: 100%; display: flex; flex-direction: column; overflow-y: auto; + cursor: pointer; `; export const InputContainer = styled.div` display: flex; - gap: 10px; + padding: 8px; + border-top: 1px solid var(--palette-line-solid-neutral); `; export const SearchInput = styled.input` flex: 1; - height: 40px; + height: 36px; border: none; background-color: #f4f4f4; border-radius: 5px; padding: 0 10px; + border: none; + outline: none; `; export const PreviewContainer = styled.div` diff --git a/src/frontend/src/components/Sidebar/UserList/UserListFooter/index.tsx b/src/frontend/src/components/Sidebar/UserList/UserListFooter/index.tsx index 7854edbb..22637ab0 100644 --- a/src/frontend/src/components/Sidebar/UserList/UserListFooter/index.tsx +++ b/src/frontend/src/components/Sidebar/UserList/UserListFooter/index.tsx @@ -1,6 +1,6 @@ import { useState } from 'react'; import { CommonInput } from '@/components/common/Input'; -import { UserFooter, VoiceChatFooter, ActionButton, JoinButton } from '../index.css'; +import { UserFooter, VoiceChatFooter, ActionButton, JoinButton, UserInviteButton } from '../index.css'; import { SidebarType } from '@/types/enums/SidebarType'; @@ -24,7 +24,9 @@ export const UserListFooter = (props: IUserListFooter) => { if (props.sidebarType === SidebarType.USERLIST) { return ( - Add User + + Add User + ); diff --git a/src/frontend/src/components/Sidebar/UserList/index.css.ts b/src/frontend/src/components/Sidebar/UserList/index.css.ts index 78934be7..6aae7ee3 100644 --- a/src/frontend/src/components/Sidebar/UserList/index.css.ts +++ b/src/frontend/src/components/Sidebar/UserList/index.css.ts @@ -12,6 +12,7 @@ export const UserListContainer = styled.div` display: flex; flex-direction: column; width: 100%; + height: 100%; overflow-y: auto; `; @@ -19,17 +20,26 @@ export const UserFooter = styled.div` width: 100%; display: flex; align-items: center; - padding: 8px 0; + padding: 8px; + border-top: 1px solid var(--palette-line-solid-neutral); + cursor: pointer; +`; - border-top: 1px solid #d4d4d4; +export const UserInviteButton = styled.div` + display: flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; `; export const VoiceChatFooter = styled.div` width: 100%; display: flex; - justify-content: space-around; - padding: 8px 0px; - border-top: 1px solid #d4d4d4; + justify-content: space-between; + padding: 8px; + gap: 8px; + border-top: 1px solid var(--palette-line-solid-neutral); `; export const ActionButton = styled.button` @@ -38,10 +48,14 @@ export const ActionButton = styled.button` border-radius: 50%; background-color: #f4f4f4; cursor: pointer; + width: 36px; + height: 36px; + min-width: 36px; + min-height: 36px; `; export const JoinButton = styled.button` - width: 194px; + width: 100%; border: none; background-color: #ff9100; padding: 10px 20px; diff --git a/src/frontend/src/components/Sidebar/UserList/index.tsx b/src/frontend/src/components/Sidebar/UserList/index.tsx index 85308683..c6e89e3e 100644 --- a/src/frontend/src/components/Sidebar/UserList/index.tsx +++ b/src/frontend/src/components/Sidebar/UserList/index.tsx @@ -1,6 +1,5 @@ import { useState, useEffect, useRef } from 'react'; import { SmallProfile } from '@/components/common/SmallProfile'; -import { ProfileDetail } from '@/components/common/ProfileDetail'; import { UserListFooter } from '@/components/Sidebar/UserList/UserListFooter'; import { RedBlackTree } from '@/hooks/utils/RedBlackTree'; @@ -13,6 +12,8 @@ import { useWebSocketStore } from '@/stores/useWebSocketStore'; import { useCurrentRoomStore } from '@/stores/useCurrentRoomStore'; import DefaultProfile from '@/assets/img/DefaultProfile.svg'; import { Container, UserListContainer, ProfileWrapper } from './index.css'; +import { RoomProfileModal } from '@/components/Modal/RoomProfileModal'; + interface IUser { id: number; role: number; @@ -124,8 +125,8 @@ export const UserList = () => { imgUrl={member.profileImg} /> - {activeProfile === member.id && ( - { userRole={member.role} myRole={UserRole.CREATOR} sidebarType={SidebarType.USERLIST} + onCancel={() => setActiveProfile(null)} /> )} diff --git a/src/frontend/src/components/Sidebar/VoiceChat/index.css.ts b/src/frontend/src/components/Sidebar/VoiceChat/index.css.ts index 2e4d881e..39336fb9 100644 --- a/src/frontend/src/components/Sidebar/VoiceChat/index.css.ts +++ b/src/frontend/src/components/Sidebar/VoiceChat/index.css.ts @@ -19,17 +19,16 @@ export const MemberFooter = styled.div` width: 100%; display: flex; align-items: center; - padding: 8px 0; - - border-top: 1px solid #d4d4d4; + padding: 8px; + border-top: 1px solid var(--palette-line-solid-neutral); `; export const VoiceChatFooter = styled.div` width: 100%; display: flex; - justify-content: space-around; - padding: 8px 0px; - border-top: 1px solid #d4d4d4; + justify-content: space-between; + padding: 8px; + border-top: 1px solid var(--palette-line-solid-neutral); `; export const ActionButton = styled.button` diff --git a/src/frontend/src/components/Sidebar/VoiceChat/index.tsx b/src/frontend/src/components/Sidebar/VoiceChat/index.tsx index 119bb8b0..6392846c 100644 --- a/src/frontend/src/components/Sidebar/VoiceChat/index.tsx +++ b/src/frontend/src/components/Sidebar/VoiceChat/index.tsx @@ -1,22 +1,26 @@ import { useState } from 'react'; import { SmallProfile } from '@/components/common/SmallProfile'; -import { ProfileDetail } from '@/components/common/ProfileDetail'; import { UserListFooter } from '@/components/Sidebar/UserList/UserListFooter'; import { SidebarType } from '@/types/enums/SidebarType'; import { ProfileType } from '@/types/enums/ProfileType'; import { UserRole } from '@/types/enums/UserRole'; -import { memberListTest } from '@/assets/data/memberListTest'; import { Container, UserList, ProfileWrapper } from './index.css'; - +import { CurrentRoomUserDto } from '@/api/endpoints/room/room.interface'; +import { RoomProfileModal } from '@/components/Modal/RoomProfileModal'; +import { useCurrentRoomStore } from '@/stores/useCurrentRoomStore'; export const VoiceChat = () => { const [activeProfile, setActiveProfile] = useState(null); + const { currentRoom } = useCurrentRoomStore(); + const roomId = currentRoom?.roomDetails.roomInfo[0]?.roomId; const handleProfileClick = (id: number) => { setActiveProfile(prevId => (prevId === id ? null : id)); }; - const sortedUsers = memberListTest.sort((a, b) => { + const memberList: CurrentRoomUserDto[] = []; + + const sortedUsers = memberList.sort((a, b) => { if (a.role !== b.role) { return a.role - b.role; } @@ -27,26 +31,26 @@ export const VoiceChat = () => { {sortedUsers.map(member => ( - -
    handleProfileClick(member.id)}> + +
    handleProfileClick(member.userId)}>
    - {activeProfile === member.id ? ( -
    - -
    + {roomId && activeProfile === member.userId ? ( + setActiveProfile(null)} + /> ) : ( '' )} diff --git a/src/frontend/src/components/Sidebar/index.css.ts b/src/frontend/src/components/Sidebar/index.css.ts index 4a1b25f1..ae5794be 100644 --- a/src/frontend/src/components/Sidebar/index.css.ts +++ b/src/frontend/src/components/Sidebar/index.css.ts @@ -1,26 +1,31 @@ import styled from 'styled-components'; export const Wrapper = styled.div` - width: 332px; - height: 931px; - border: 1px solid #d4d4d4; + width: 100%; + max-width: 320px; + height: calc(100vh - 120px); border-radius: 10px; + border: 1px solid var(--palette-line-solid-neutral); + overflow: hidden; `; export const Nav = styled.nav` - height: 40px; + height: 46px; display: flex; justify-content: space-between; + border-bottom: 1px solid var(--palette-line-solid-neutral); + background-color: #fff; `; export const Content = styled.div` - height: calc(100% - 40px); + height: calc(100% - 46px); `; export const NavButton = styled.button<{ $active: boolean }>` width: 83px; padding: 10px; - background-color: ${({ $active }) => ($active ? '#ddd' : '#f0f0f0')}; + background-color: ${({ $active }) => + $active ? 'var(--palette-line-solid-alternative)' : 'transparent'}; border: none; cursor: pointer; diff --git a/src/frontend/src/components/TopNavBar/index.tsx b/src/frontend/src/components/TopNavBar/index.tsx index 9f64d2b7..608597de 100644 --- a/src/frontend/src/components/TopNavBar/index.tsx +++ b/src/frontend/src/components/TopNavBar/index.tsx @@ -17,7 +17,7 @@ import DefaultProfile from '@/assets/img/DefaultProfile.svg'; import { RoomCreateModal } from '@/components/Modal/RoomCreateModal'; import { NotificationModal } from '@/components/Modal/NotificationModal'; import { SearchBar } from '@/components/Search/SearchBar'; -import { ProfileModal } from '@/components/Modal/ProfileModal'; +import { ProfileModal } from '@/components/Modal/MyProfileModal'; import { useUserStore } from '@/stores/useUserStore'; import { useAuthStore } from '@/stores/useAuthStore'; import { useMyRoomsStore } from '@/stores/useMyRoomsStore'; @@ -32,7 +32,6 @@ import { useVideoStore } from '@/stores/useVideoStore'; const API_KEY = import.meta.env.VITE_YOUTUBE_API_KEY as string; - export const TopNavBar = () => { const navigate = useNavigate(); const { user, fetchMyProfile, clearProfile } = useUserStore(); @@ -197,7 +196,13 @@ export const TopNavBar = () => { {user ? ( - Profile + Profile { + e.currentTarget.src = DefaultProfile; + }} + /> {isProfileModalOpen && } ) : ( diff --git a/src/frontend/src/components/YoutubePlayer/index.tsx b/src/frontend/src/components/YoutubePlayer/index.tsx index da1c7678..14e01ead 100644 --- a/src/frontend/src/components/YoutubePlayer/index.tsx +++ b/src/frontend/src/components/YoutubePlayer/index.tsx @@ -188,4 +188,5 @@ const VideoWrapper = styled.div` display: flex; align-items: center; justify-content: center; + overflow: hidden; `; diff --git a/src/frontend/src/components/common/Input/index.css.ts b/src/frontend/src/components/common/Input/index.css.ts index d478d4ed..4ba9b4f5 100644 --- a/src/frontend/src/components/common/Input/index.css.ts +++ b/src/frontend/src/components/common/Input/index.css.ts @@ -13,7 +13,7 @@ export const Container = styled.div` export const Wrapper = styled.div<{ $design: InputDesign }>` display: flex; align-items: center; - border: 1px solid #d4d4d4; + border: 1px solid var(--palette-line-solid-neutral); border-radius: 4px; padding: 2px; diff --git a/src/frontend/src/components/common/ProfileDetail/ProfileInfo/index.tsx b/src/frontend/src/components/common/ProfileDetail/ProfileInfo/index.tsx index 4475dbce..425272d9 100644 --- a/src/frontend/src/components/common/ProfileDetail/ProfileInfo/index.tsx +++ b/src/frontend/src/components/common/ProfileDetail/ProfileInfo/index.tsx @@ -1,15 +1,15 @@ import { Profile__Nickname } from '../index.css'; interface IProfileInfo { - nickname: string; - introduce: string; + nickname?: string; + introduce?: string; } export const ProfileInfo = (props: IProfileInfo) => { return ( <> - {props.nickname} -

    {props.introduce}

    + {props.nickname ?? ''} + {props.introduce &&

    {props.introduce}

    } ); }; diff --git a/src/frontend/src/components/common/ProfileDetail/index.css.ts b/src/frontend/src/components/common/ProfileDetail/index.css.ts index 5221e149..b2366f5e 100644 --- a/src/frontend/src/components/common/ProfileDetail/index.css.ts +++ b/src/frontend/src/components/common/ProfileDetail/index.css.ts @@ -5,7 +5,7 @@ export const Container = styled.div` background-color: white; border-radius: 10px; padding: 10px; - box-shadow: 10px 10px 40px 0px #00000040; + box-shadow: var(--palette-elevation-shadow-heavy); display: flex; flex-direction: column; `; diff --git a/src/frontend/src/components/common/ProfileDetail/index.tsx b/src/frontend/src/components/common/ProfileDetail/index.tsx index 37c14ba2..053142e5 100644 --- a/src/frontend/src/components/common/ProfileDetail/index.tsx +++ b/src/frontend/src/components/common/ProfileDetail/index.tsx @@ -4,20 +4,26 @@ import { ProfileActions } from './ProfileActions'; import { Container, Profile, ButtonContainer } from './index.css'; import { ProfileDetailDto } from '@/types/dto/ProfileDetailDto.dto'; import DefaultProfile from '@/assets/img/DefaultProfile.svg'; - -const detailProfile = { - nickname: '이노', - introduce: '저는 이제 집으로 갑니다', - imgUrl: - 'https://search.pstatic.net/common/?src=http%3A%2F%2Fblogfiles.naver.net%2FMjAyMDA3MjVfMTQ5%2FMDAxNTk1Njc4MzEyNzA4.knqIC64twrLoZDviHrAUSrEbgtxNp8h4nGsT-4mrWgkg.VImfsqV3F5GqyCPCIN4Xfid4TpUXQkljevfhuX_HK4gg.JPEG.haha9558%2FIMG_0114.JPG&type=a340', -}; +import { useEffect, useState } from 'react'; +import { userApi } from '@/api/endpoints/user/user.api'; +import { UserResponseDto } from '@/api/endpoints/user/user.interface'; export const ProfileDetail = (props: ProfileDetailDto) => { + const [profile, setProfile] = useState(null); + + useEffect(() => { + const getprofile = async () => { + const profile = await userApi.getProfile(props.userId.toString()); + setProfile(profile); + }; + getprofile(); + }, [props.userId]); + return ( - - + + diff --git a/src/frontend/src/components/common/RoleNickname/index.css.ts b/src/frontend/src/components/common/RoleNickname/index.css.ts index e63cc10a..d91e82de 100644 --- a/src/frontend/src/components/common/RoleNickname/index.css.ts +++ b/src/frontend/src/components/common/RoleNickname/index.css.ts @@ -4,16 +4,22 @@ import { UserRole } from '@/types/enums/UserRole'; export const Wrapper = styled.div` display: flex; align-items: center; - gap: 4px; + justify-content: center; + gap: 6px; `; -export const Img = styled.img` - width: 25px; - height: 25px; +export const Img = styled.div` + width: 16px; + height: 16px; + + img { + width: 100%; + object-fit: cover; + } `; export const Nickname = styled.div<{ $role: UserRole }>` color: ${({ $role }) => $role === UserRole.CREATOR ? '#FF9100' : $role === UserRole.MANAGER ? '#4D94E1' : '#000000'}; - font-weight: bold; + font-weight: 500; `; diff --git a/src/frontend/src/components/common/RoleNickname/index.tsx b/src/frontend/src/components/common/RoleNickname/index.tsx index d634ecbf..630678a8 100644 --- a/src/frontend/src/components/common/RoleNickname/index.tsx +++ b/src/frontend/src/components/common/RoleNickname/index.tsx @@ -12,16 +12,18 @@ export const RoleNickname = (props: IRoleNickname) => { return ( {props.role !== UserRole.MEMBER ? ( - User Role + + User Role + ) : ( '' )} diff --git a/src/frontend/src/components/common/SmallProfile/index.css.ts b/src/frontend/src/components/common/SmallProfile/index.css.ts index 3e3dd1b7..3b90ef97 100644 --- a/src/frontend/src/components/common/SmallProfile/index.css.ts +++ b/src/frontend/src/components/common/SmallProfile/index.css.ts @@ -13,11 +13,18 @@ export const Profile = styled.div` align-items: center; `; -export const Profile__Img = styled.img` +export const Profile__Img = styled.div` width: 32px; height: 32px; - margin-right: 4px; + margin-right: 8px; border-radius: 8px; + overflow: hidden; + + & > img { + width: 100%; + height: 100%; + object-fit: cover; + } `; export const ImgWrapper = styled.div` diff --git a/src/frontend/src/components/common/SmallProfile/index.tsx b/src/frontend/src/components/common/SmallProfile/index.tsx index b02a2512..bd2228a8 100644 --- a/src/frontend/src/components/common/SmallProfile/index.tsx +++ b/src/frontend/src/components/common/SmallProfile/index.tsx @@ -33,12 +33,14 @@ export const SmallProfile = (props: ISmallProfile) => { return ( - { - e.currentTarget.src = DefaultProfile; - }} - /> + + { + e.currentTarget.src = DefaultProfile; + }} + /> + {renderBtn()} diff --git a/src/frontend/src/pages/Layout/index.css.ts b/src/frontend/src/pages/Layout/index.css.ts index 35c84a5e..354e77c9 100644 --- a/src/frontend/src/pages/Layout/index.css.ts +++ b/src/frontend/src/pages/Layout/index.css.ts @@ -13,4 +13,5 @@ export const Container = styled.div` display: flex; flex-direction: column; overflow-y: auto; + padding-bottom: 80px; `; diff --git a/src/frontend/src/pages/MyRoomPage/MyRoomSkeleton/index.css.ts b/src/frontend/src/pages/MyRoomPage/MyRoomSkeleton/index.css.ts index b8cf12c6..cba2da18 100644 --- a/src/frontend/src/pages/MyRoomPage/MyRoomSkeleton/index.css.ts +++ b/src/frontend/src/pages/MyRoomPage/MyRoomSkeleton/index.css.ts @@ -20,7 +20,7 @@ export const SkeletonCard = styled.div` gap: 1rem; padding: 1rem 0; background-color: white; - border-bottom: 1px solid #ddd; + border-bottom: 1px solid var(--palette-line-normal-alternative); `; export const SkeletonThumbnail = styled(SkeletonBase)` diff --git a/src/frontend/src/pages/RegisterPage/index.tsx b/src/frontend/src/pages/RegisterPage/index.tsx index cf84427a..e429c42c 100644 --- a/src/frontend/src/pages/RegisterPage/index.tsx +++ b/src/frontend/src/pages/RegisterPage/index.tsx @@ -227,7 +227,7 @@ export const RegisterPage = () => { required /> - 8-20자의 영문, 숫자, 특수문자(@$!%*?&)를 포함해야 합니다. + 8-20자의 영문, 숫자, 특수문자(@$!%*?&) 포함
    diff --git a/src/frontend/src/pages/RoomPage/index.css.ts b/src/frontend/src/pages/RoomPage/index.css.ts index 378804e1..d2df5b88 100644 --- a/src/frontend/src/pages/RoomPage/index.css.ts +++ b/src/frontend/src/pages/RoomPage/index.css.ts @@ -5,7 +5,7 @@ export const Container = styled.div` flex-direction: row; justify-content: space-between; gap: 20px; - padding-right: 16px; + padding: 1rem; `; export const Wrapper = styled.div` diff --git a/src/frontend/src/pages/SearchPage/index.tsx b/src/frontend/src/pages/SearchPage/index.tsx index d5ec167e..accb79dc 100644 --- a/src/frontend/src/pages/SearchPage/index.tsx +++ b/src/frontend/src/pages/SearchPage/index.tsx @@ -1,22 +1,25 @@ -import { userApi } from '@/api/endpoints/user/user.api'; -import { UserResponseDto } from '@/api/endpoints/user/user.interface'; -import { SearchItem } from '@/components/Search/SearchItem'; -import { Container, SubTitle, Title, Wrapper } from '@/ui/Common.css'; +import { roomApi } from '@/api/endpoints/room/room.api'; +import { SearchUserDto, RoomDto } from '@/api/endpoints/room/room.interface'; +import { SearchRoomItem } from '@/components/Search/SearchItem/SearchRoomItem'; +import { SearchUserItem } from '@/components/Search/SearchItem/SearchUserItem'; +import { Container, Divider, SubTitle, Title, Wrapper } from '@/ui/Common.css'; import { useEffect, useState } from 'react'; import { useSearchParams } from 'react-router-dom'; export const SearchPage = () => { const [searchParams] = useSearchParams(); const query = searchParams.get('q'); // URL에서 q 값 가져오기 - const [searchList, setSearchList] = useState([]); + const [searchUserList, setSearchUserList] = useState([]); + const [searchRoomList, setSearchRoomList] = useState([]); const [totalLength, setTotalLength] = useState(0); useEffect(() => { if (query) { const fetchSearchList = async () => { - const searchListData = await userApi.getUsers(0, 100, query); + const searchListData = await roomApi.searchFromElastic(query); console.log('searchListData: ', searchListData); - setSearchList(searchListData.users); - setTotalLength(searchListData.totalLength); + setSearchUserList(searchListData.users); + setSearchRoomList(searchListData.rooms); + setTotalLength(searchListData.users.length + searchListData.rooms.length); }; fetchSearchList(); } @@ -25,10 +28,15 @@ export const SearchPage = () => { return ( - 검색 - 검색 결과 {totalLength}개 - {searchList.map(user => ( - + 검색 {totalLength}건 + 유저 {searchUserList.length}명 + {searchUserList.map(user => ( + + ))} + + 방 {searchRoomList.length}개 + {searchRoomList.map(room => ( + ))} diff --git a/src/frontend/src/types/enums/UserRole.ts b/src/frontend/src/types/enums/UserRole.ts index 8c8d510e..98a98882 100644 --- a/src/frontend/src/types/enums/UserRole.ts +++ b/src/frontend/src/types/enums/UserRole.ts @@ -2,4 +2,5 @@ export enum UserRole { CREATOR = 0, MANAGER = 1, MEMBER = 2, + NONE = 3, } diff --git a/src/frontend/src/ui/Common.css.ts b/src/frontend/src/ui/Common.css.ts index 997ee9b5..0a5609e5 100644 --- a/src/frontend/src/ui/Common.css.ts +++ b/src/frontend/src/ui/Common.css.ts @@ -107,3 +107,7 @@ export const SkeletonBase = styled.div` background-size: 200% 100%; animation: ${shimmer} 1.5s infinite; `; + +export const Divider = styled.div` + height: 1rem; +`;