diff --git a/src/components/guild/MemberContainer.tsx b/src/components/guild/MemberContainer.tsx index c3bfae7..f1a1330 100644 --- a/src/components/guild/MemberContainer.tsx +++ b/src/components/guild/MemberContainer.tsx @@ -33,16 +33,11 @@ export const MemberContainer = ({ setSearchCharacter }: MemberContainerProps) => { const [showMenu, setShowMenu] = useState(false) - const [isOpen, setIsOpen] = useState(false) - const [sortType, setSortType] = useState('캐릭터 정렬') const [sortTypeOpen, setSortTypeOpen] = useState(false) - const [selectedType, setSelectedType] = useState('캐릭터 분류') - const [gridSize, setGridSize] = useState(2) - const [showPart, setShowPart] = useState(false) // 분류해서 보기 const dropdownRef = useRef(null) @@ -125,17 +120,18 @@ export const MemberContainer = ({ }) return ( -
+
{guildName && ( -
-
+
+
+ {/* 길드 제목 부분 */}
-

+

길드: {guildName}

-
- -
+
+ +
본캐 @@ -164,15 +160,16 @@ export const MemberContainer = ({
-
-

- 총 인원 : {members.length} + +

+

+ 총 인원: {members.length}

-

- 본캐 : {members.filter(member => member.type === '본캐').length} +

+ 본캐: {members.filter(member => member.type === '본캐').length}

-

- 부캐 : +

+ 부캐: { members.filter( member => @@ -185,8 +182,8 @@ export const MemberContainer = ({ ).length }

-

- 외부 부캐 : +

+ 외부 부캐: { members.filter( member => @@ -201,21 +198,23 @@ export const MemberContainer = ({

+ + {/* 삭제 버튼 */} {onDeleteGuild && !isMainGuild && ( -
+
{showMenu && ( -
+
@@ -225,42 +224,45 @@ export const MemberContainer = ({
)} -
-
+
+ {/* 검색 및 필터 영역 */} +
+ {/* 검색창 */}
setSearchCharacter?.(e.target.value)} placeholder="캐릭터 이름으로 검색" - className="w-full pl-10 pr-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" + className="w-full pl-9 sm:pl-10 pr-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent text-sm" /> - +
-
+
+ {/* 정렬 드롭다운 */}
{sortTypeOpen && ( -
+
)}
+ + {/* 분류 드롭다운 */}
{isOpen && ( -
- - - - - +
+ {['모두 보기', '본캐', '부캐', '외부 부캐', '특이사항'].map( + type => ( + + ) + )}
)}
+ {/* 그리드 크기 변경 */}
+ + {/* 분류해서 보기 토글 */}
-
+ + {/* 멤버 목록 */} +
{showPart ? ( (filteredMembers as Member[]).map(member => (
-
+ className="flex flex-col lg:flex-row gap-4 items-start border-b border-gray-100 pb-6 sm:pb-8"> + {/* 본캐 */} +
-
-
+ {/* 부캐들 */} +
+
{member.subCharacters?.map(subChar => ( + ? 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-4' + : 'grid-cols-2 sm:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8' + }`}> {(filteredMembers as Member[]).map(member => ( { const path = location.pathname + // useEffect로 사이드 이펙트 처리 + useEffect(() => { + // 1. 로그인도 안 됐는데 루트가 아닌 경로 접근 시 + if (!isLoggedIn && path !== '/') { + userLogout() + } + }, [isLoggedIn, path, userLogout]) + // 1. 로그인도 안 됐는데 루트가 아닌 경로 접근 시 if (!isLoggedIn && path !== '/') { - userLogout() return } diff --git a/src/components/room/EmptyRoomState.tsx b/src/components/room/EmptyRoomState.tsx new file mode 100644 index 0000000..ab1890c --- /dev/null +++ b/src/components/room/EmptyRoomState.tsx @@ -0,0 +1,7 @@ +export const EmptyRoomState = () => { + return ( +
+

관리방이 없습니다.

+
+ ) +} diff --git a/src/components/room/RoomActionBar.tsx b/src/components/room/RoomActionBar.tsx new file mode 100644 index 0000000..b68e8ee --- /dev/null +++ b/src/components/room/RoomActionBar.tsx @@ -0,0 +1,38 @@ +import { ModalType } from '../../store/modalStore' +import { ActionBtnList } from '../guild/ActionBtnList' +import { ListSwitch } from '../guild/ListSwitch' +import { Guild } from '../../types/guild' + +interface Props { + showModal: (name: ModalType) => void + guildList: Guild[] + handleDetect: () => void + refreshMember: (guildId: number) => void +} + +export const RoomActionBar = ({ + showModal, + guildList, + handleDetect, + refreshMember +}: Props) => { + return ( +
+
+
+ +
+ {guildList.length > 0 && ( +
+ +
+ )} +
+
+ ) +} diff --git a/src/components/room/RoomCard.tsx b/src/components/room/RoomCard.tsx new file mode 100644 index 0000000..c19f784 --- /dev/null +++ b/src/components/room/RoomCard.tsx @@ -0,0 +1,59 @@ +import { IoTrashOutline, IoPersonAddOutline } from 'react-icons/io5' +import { Room } from '../../types/rooms' + +interface Props { + room: Room + onEnterRoom: (room: Room) => void + onManageRoom: (room: Room) => void + onDeleteRoom: (adminId: string) => void +} + +export const RoomCard = ({ + room, + onEnterRoom, + onManageRoom, + onDeleteRoom +}: Props) => { + return ( +
+
+
+
+

+ {room.groupName} +

+
+
+ +
+
+

메인 길드

+

+ {room.mainGuild.name} +

+
+
+ +
+ + + +
+
+
+ ) +} diff --git a/src/components/room/RoomContent.tsx b/src/components/room/RoomContent.tsx new file mode 100644 index 0000000..9bb43bd --- /dev/null +++ b/src/components/room/RoomContent.tsx @@ -0,0 +1,59 @@ +import { Guild, Member, NexonMembers } from '../../types/guild' +import { MemberContainer } from '../guild/MemberContainer' +import { Empty } from '../common/Empty' + +interface Props { + nexonMembersLoading: boolean + guildList: Guild[] + selectMember: NexonMembers + nexonMembers: NexonMembers[] | null + main: string | undefined + searchCharacter: string + onMemberSelect: (type: string, member: Member) => void + onSearchCharacter: (value: string) => void + onDeleteGuild?: () => void +} + +export const RoomContent = ({ + nexonMembersLoading, + guildList, + selectMember, + nexonMembers, + main, + searchCharacter, + onMemberSelect, + onSearchCharacter, + onDeleteGuild +}: Props) => { + return ( +
+
+ {nexonMembersLoading && ( +
+
+

+ 캐릭터 정보를 불러오는 중... +

+
+ )} + {guildList.length > 0 ? ( + + ) : ( +
+ +
+ )} +
+
+ ) +} diff --git a/src/components/room/RoomGrid.tsx b/src/components/room/RoomGrid.tsx new file mode 100644 index 0000000..984421c --- /dev/null +++ b/src/components/room/RoomGrid.tsx @@ -0,0 +1,30 @@ +import { Room } from '../../types/rooms' +import { RoomCard } from './RoomCard' + +interface Props { + rooms: Room[] + onEnterRoom: (room: Room) => void + onManageRoom: (room: Room) => void + onDeleteRoom: (adminId: string) => void +} + +export const RoomGrid = ({ + rooms, + onEnterRoom, + onManageRoom, + onDeleteRoom +}: Props) => { + return ( +
+ {rooms.map(room => ( + + ))} +
+ ) +} diff --git a/src/components/room/RoomHeader.tsx b/src/components/room/RoomHeader.tsx new file mode 100644 index 0000000..d4ede4a --- /dev/null +++ b/src/components/room/RoomHeader.tsx @@ -0,0 +1,26 @@ +import { IoArrowBack } from 'react-icons/io5' + +interface Props { + onBack: () => void +} + +export const RoomHeader = ({ onBack }: Props) => { + return ( +
+ +
+

+ 길드 관리 +

+

+ 길드원 정보 관리 +

+
+
+ ) +} diff --git a/src/components/room/RoomListHeader.tsx b/src/components/room/RoomListHeader.tsx new file mode 100644 index 0000000..6e6caf9 --- /dev/null +++ b/src/components/room/RoomListHeader.tsx @@ -0,0 +1,29 @@ +import { IoAdd } from 'react-icons/io5' + +interface Props { + onCreateRoom: () => void +} + +export const RoomListHeader = ({ onCreateRoom }: Props) => { + return ( +
+
+

길드 관리 홈

+

관리중인 길드방 목록입니다

+
+
+ +
+
+ ⚠️ 관리방 생성은 길드 마스터만 가능합니다. +
마스터가 아니라면, 해당 마스터가 생성후 그룹에 초대해 주세요. +
+
+
+
+ ) +} diff --git a/src/pages/Room.tsx b/src/pages/Room.tsx index b313165..4b0bba8 100644 --- a/src/pages/Room.tsx +++ b/src/pages/Room.tsx @@ -1,21 +1,19 @@ import { CreateGuildModal } from '../components/modal/guild/CreateGuildModal' import { ModalType, useModalStore } from '../store/modalStore' import { useGuildsList } from '../hooks/guild/useGuildsList' -import { MemberContainer } from '../components/guild/MemberContainer' -import { ListSwitch } from '../components/guild/ListSwitch' -import { ActionBtnList } from '../components/guild/ActionBtnList' import { DetectMemberModal } from '../components/modal/guild/DetectMemberModal' import { useGuildMember } from '../hooks/guild/useGuildMember' -import { Empty } from '../components/common/Empty' import { DetailMemberModal } from '../components/modal/guild/DetailMemberModal' import { Loading } from '../components/common/Loading' import { useState } from 'react' import { Member, NexonMembers } from '../types/guild' -import { IoArrowBack } from 'react-icons/io5' import { useNavigate } from 'react-router-dom' import { useGuildDetect } from '../hooks/guild/useGuildDetect' import { findMainCharacter } from '../apis/character/characterController' import { AlertModal } from '../components/modal/common/AlertModal' +import { RoomHeader } from '../components/room/RoomHeader' +import { RoomActionBar } from '../components/room/RoomActionBar' +import { RoomContent } from '../components/room/RoomContent' const Room = () => { const { activeModal, openModal } = useModalStore() @@ -96,63 +94,31 @@ const Room = () => { return (
-
- -
-

길드 관리

-

길드원 정보 관리

-
-
+ navigate('/rooms')} />
-
-
- - {guildList.length > 0 && } -
-
+ void} + /> -
-
- {nexonMembersLoading && ( -
-
-

- 캐릭터 정보를 불러오는 중... -

-
- )} - {guildList.length > 0 ? ( - deleteGuild(selectMember.guildId as number) - : undefined - } - /> - ) : ( - - )} -
-
+ deleteGuild(selectMember.guildId as number) + : undefined + } + />
diff --git a/src/pages/RoomList.tsx b/src/pages/RoomList.tsx index fe2abbc..fb2c4db 100644 --- a/src/pages/RoomList.tsx +++ b/src/pages/RoomList.tsx @@ -1,7 +1,6 @@ import { useModalStore } from '../store/modalStore' import { CreateRoomModal } from '../components/modal/room/CreateRoomModal' import { useNavigate } from 'react-router-dom' -import { IoAdd, IoTrashOutline, IoPersonAddOutline } from 'react-icons/io5' import { useRoom } from '../hooks/room/useRoom' import { Loading } from '../components/common/Loading' import { GuildManageModal } from '../components/modal/room/RoomManageModal' @@ -9,6 +8,9 @@ import { useState } from 'react' import { Room } from '../types/rooms' import { useRoomsStore } from '../store/roomsStore' import { useUserStore } from '../store/userStore' +import { RoomListHeader } from '../components/room/RoomListHeader' +import { RoomGrid } from '../components/room/RoomGrid' +import { EmptyRoomState } from '../components/room/EmptyRoomState' export const RoomList = () => { const { openModal, activeModal } = useModalStore() @@ -19,6 +21,24 @@ export const RoomList = () => { const [selectedRoom, setSelectedRoom] = useState(null) + const handleCreateRoom = () => { + openModal('createRoom') + } + + const handleEnterRoom = (room: Room) => { + navigate(`/room/${room.groupName}`) + setGroupId(room.adminId) + } + + const handleManageRoom = (room: Room) => { + setSelectedRoom(room) + openModal('guildManage') + } + + const handleDeleteRoom = (adminId: string) => { + deleteRoomHandler(Number(adminId)) + } + if (!rooms) { return (
@@ -32,86 +52,19 @@ export const RoomList = () => { return (
-
-
-

길드 관리 홈

-

관리중인 길드방 목록입니다

-
-
- -
-
- ⚠️ 관리방 생성은 길드 마스터만 가능합니다. -
마스터가 아니라면, 해당 마스터가 생성후 그룹에 초대해 - 주세요. -
-
-
-
- {rooms.length === 0 && ( -
-

관리방이 없습니다.

-
- )} - -
- {rooms.map(room => ( -
-
-
-
-

- {room.groupName} -

-
-
+ -
-
-

메인 길드

-

- {room.mainGuild.name} -

-
-
+ {rooms.length === 0 ? ( + + ) : ( + + )} -
- - - -
-
-
- ))} -
{activeModal === 'createRoom' && } {activeModal === 'guildManage' && userName && (