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
59 changes: 0 additions & 59 deletions src/frontend/src/components/Sidebar/MemberList/index.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState } from 'react';
import { CommonInput } from '@/components/common/Input';
import { MemberFooter, VoiceChatFooter, ActionButton, JoinButton } from '../index.css';
import { UserFooter, VoiceChatFooter, ActionButton, JoinButton } from '../index.css';

import { SidebarType } from '@/types/enums/SidebarType';

Expand All @@ -10,23 +10,23 @@ import HeadphoneOn from '@/assets/img/HeadphoneOn.svg';
import MicrophoneOffRed from '@/assets/img/MicrophoneOffRed.svg';
import HeadphoneOffRed from '@/assets/img/HeadphoneOffRed.svg';

interface IMemberListFooter {
interface IUserListFooter {
sidebarType: SidebarType;
}

export const MemberListFooter = (props: IMemberListFooter) => {
export const UserListFooter = (props: IUserListFooter) => {
const [micOn, setMicOn] = useState(true);
const [soundOn, setSoundOn] = useState(true);

const handleMicrophone = () => setMicOn(!micOn);
const handleSound = () => setSoundOn(!soundOn);

if (props.sidebarType === SidebarType.MEMBER) {
if (props.sidebarType === SidebarType.USERLIST) {
return (
<MemberFooter>
<UserFooter>
<img src={AddUserIcon} alt="Add User" />
<CommonInput placeholder="룸 유저 검색" design={1} />
</MemberFooter>
</UserFooter>
);
}

Expand Down
75 changes: 75 additions & 0 deletions src/frontend/src/components/Sidebar/UserList/index.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import styled from 'styled-components';

export const Container = styled.div`
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
`;

export const UserListContainer = styled.div`
display: flex;
flex-direction: column;
width: 100%;
overflow-y: auto;
`;

export const UserFooter = styled.div`
width: 100%;
display: flex;
align-items: center;
padding: 8px 0;

border-top: 1px solid #d4d4d4;
`;

export const VoiceChatFooter = styled.div`
width: 100%;
display: flex;
justify-content: space-around;
padding: 8px 0px;
border-top: 1px solid #d4d4d4;
`;

export const ActionButton = styled.button`
border: none;
padding: 10px;
border-radius: 50%;
background-color: #f4f4f4;
cursor: pointer;
`;

export const JoinButton = styled.button`
width: 194px;
border: none;
background-color: #ff9100;
padding: 10px 20px;
color: white;
font-weight: bold;
border-radius: 5px;
cursor: pointer;
`;

export const ProfileWrapper = styled.div`
position: relative;
cursor: pointer;

& .profile-detail {
position: absolute;
top: 0px;
right: 60%;
transform: translateX(-50%);
opacity: 0;
visibility: hidden;
transition:
opacity 0.3s ease,
visibility 0.3s ease;
z-index: 10;
}

.profile-detail.active {
opacity: 1;
visibility: visible;
}
`;
93 changes: 93 additions & 0 deletions src/frontend/src/components/Sidebar/UserList/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
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';

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, UserListContainer, ProfileWrapper } from './index.css';

interface IUser {
id: number;
role: number;
nickname: string;
profileImg: string;
}

const compareUsers = (a: IUser, b: IUser): number => {
if (a.role !== b.role) return a.role - b.role;
const nicknameCompare = a.nickname.localeCompare(b.nickname, 'ko');
if (nicknameCompare !== 0) return nicknameCompare;
return a.id - b.id;
};

export const UserList = () => {
const treeRef = useRef<RedBlackTree<IUser> | null>(null);
const [, setVersion] = useState(0);

useEffect(() => {
treeRef.current = new RedBlackTree<IUser>(compareUsers);
memberListTest.forEach(user => treeRef.current?.insert(user));
setVersion(v => v + 1);
}, []);

const addUser = (user: IUser) => {
if (!treeRef.current) return;
treeRef.current.insert(user);
setVersion(v => v + 1);
};

const getSortedUsers = (): IUser[] => {
return treeRef.current ? treeRef.current.inOrderTraversal() : [];
};
const [activeProfile, setActiveProfile] = useState<number | null>(null);

const handleProfileClick = (id: number) => {
setActiveProfile(prevId => (prevId === id ? null : id));
};

const handleAddUser = () => {
const newUser: IUser = {
id: Date.now(),
role: Math.floor(Math.random() * 3),
nickname: `User${Math.floor(Math.random() * 1000)}`,
profileImg: '',
};
addUser(newUser);
};

const users = getSortedUsers();

return (
<Container>
<UserListContainer>
{users.map(member => (
<ProfileWrapper key={member.id}>
<div onClick={() => handleProfileClick(member.id)}>
<SmallProfile
type={ProfileType.MEMBER}
role={member.role}
nickname={member.nickname}
imgUrl={member.profileImg}
/>
</div>
{activeProfile === member.id && (
<ProfileDetail
userId={member.id}
userRole={member.role}
myRole={UserRole.CREATOR}
sidebarType={SidebarType.USERLIST}
/>
)}
</ProfileWrapper>
))}
</UserListContainer>
<button onClick={handleAddUser}>랜덤 유저 추가</button>
<UserListFooter sidebarType={SidebarType.USERLIST} />
</Container>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const UserList = styled.div`
display: flex;
flex-direction: column;
width: 100%;
overflow-y: auto;
`;

export const MemberFooter = styled.div`
Expand Down
57 changes: 57 additions & 0 deletions src/frontend/src/components/Sidebar/VoiceChat/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
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';

export const VoiceChat = () => {
const [activeProfile, setActiveProfile] = useState<number | null>(null);
const handleProfileClick = (id: number) => {
setActiveProfile(prevId => (prevId === id ? null : id));
};

const sortedUsers = memberListTest.sort((a, b) => {
if (a.role !== b.role) {
return a.role - b.role;
}
return a.nickname.localeCompare(b.nickname, 'ko');
});

return (
<Container>
<UserList>
{sortedUsers.map(member => (
<ProfileWrapper key={member.id}>
<div onClick={() => handleProfileClick(member.id)}>
<SmallProfile
type={ProfileType.VOICECHAT}
role={member.role}
nickname={member.nickname}
imgUrl={member.profileImg}
/>
</div>
{activeProfile === member.id ? (
<div className={`profile-detail ${activeProfile === member.id ? 'active' : ''}`}>
<ProfileDetail
userId={member.id}
userRole={member.role}
myRole={UserRole.CREATOR}
sidebarType={SidebarType.VOICECHAT}
/>
</div>
) : (
''
)}
</ProfileWrapper>
))}
</UserList>
<UserListFooter sidebarType={SidebarType.VOICECHAT} />
</Container>
);
};
26 changes: 12 additions & 14 deletions src/frontend/src/components/Sidebar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useState } from 'react';
import { ChatBox } from './Chating';
import { MemberList } from './MemberList';
import { UserList } from './UserList';
import { Playlist } from './Playlist';
import { VoiceChat } from './VoiceChat';
import SidebarChat from '@/assets/img/SidebarChat.svg';
import SidebarPlaylist from '@/assets/img/SidebarPlaylist.svg';
import SidebarVoicechat from '@/assets/img/SidebarVoicechat.svg';
Expand All @@ -12,25 +13,22 @@ import { SidebarType } from '@/types/enums/SidebarType';
export const Sidebar = () => {
const [interfaceType, setInterfaceType] = useState<SidebarType>(SidebarType.CHAT);

const contentComponents = {
[SidebarType.CHAT]: ChatBox,
[SidebarType.PLAYLIST]: Playlist,
[SidebarType.VOICECHAT]: VoiceChat,
[SidebarType.USERLIST]: UserList,
};

const renderContent = () => {
switch (interfaceType) {
case SidebarType.CHAT:
return <ChatBox />;
case SidebarType.PLAYLIST:
return <Playlist />;
case SidebarType.VOICECHAT:
return <MemberList sidebarType={SidebarType.VOICECHAT} />;
case SidebarType.MEMBER:
return <MemberList sidebarType={SidebarType.MEMBER} />;
default:
return null;
}
const Component = contentComponents[interfaceType];
return Component ? <Component /> : null;
};

return (
<Wrapper>
<Nav>
{[SidebarType.CHAT, SidebarType.PLAYLIST, SidebarType.VOICECHAT, SidebarType.MEMBER].map(
{[SidebarType.CHAT, SidebarType.PLAYLIST, SidebarType.VOICECHAT, SidebarType.USERLIST].map(
(type, index) => (
<NavButton
key={index}
Expand Down
Loading
Loading