-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #152 from prgrms-web-devcourse-final-project/feature/
#58 feat: ChatOverview 컴포넌트 개발
- Loading branch information
Showing
4 changed files
with
254 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
import {} from "components/atoms"; | ||
import { TabItem } from "components/molecules"; | ||
import { ChatList } from "components/organisms"; | ||
import { ChatOverviewRootWrapper, ListWrapper, PanelWrapper } from "./styled"; | ||
import { | ||
type Context, | ||
createContext, | ||
useContext, | ||
useEffect, | ||
useState | ||
} from "react"; | ||
|
||
import { IChatItemProps } from "components/organisms/ChatItem"; | ||
|
||
interface IChatOverviewRootProps { | ||
children: React.ReactNode; | ||
} | ||
|
||
interface IChatOverviewContextProps { | ||
/** 선택된 인덱스 */ | ||
selectedIndex: number; | ||
/** 선택된 인덱스 변경 함수 */ | ||
setSelectedIndex: React.Dispatch<React.SetStateAction<number>> | undefined; | ||
} | ||
|
||
const ChatOverviewContext: Context<IChatOverviewContextProps> = | ||
createContext<IChatOverviewContextProps>({ | ||
selectedIndex: 0, | ||
setSelectedIndex: undefined | ||
}); | ||
|
||
/** | ||
* ChatOverview 하위 컴포넌트에서 사용되는지 검사를 위한 훅 | ||
*/ | ||
const useChatOverview = () => { | ||
const context = useContext(ChatOverviewContext); | ||
if (!context) { | ||
throw new Error("Modal Context 내에서만 사용 가능합니다."); | ||
} | ||
return context; | ||
}; | ||
|
||
/* ------------------------------------------------------------------- | ||
* ChatOverview Root | ||
* ------------------------------------------------------------------- */ | ||
|
||
const ChatOverviewRoot = ({ children }: IChatOverviewRootProps) => { | ||
const [selectedIndex, setSelectedIndex] = useState(0); | ||
|
||
const providerValue = { selectedIndex, setSelectedIndex }; | ||
|
||
return ( | ||
<ChatOverviewContext.Provider value={providerValue}> | ||
<ChatOverviewRootWrapper>{children}</ChatOverviewRootWrapper> | ||
</ChatOverviewContext.Provider> | ||
); | ||
}; | ||
|
||
/* ------------------------------------------------------------------- | ||
* List | ||
* ------------------------------------------------------------------- */ | ||
|
||
const List = ({ children }: IChatOverviewRootProps) => { | ||
return <ListWrapper>{children}</ListWrapper>; | ||
}; | ||
|
||
/* ------------------------------------------------------------------- | ||
* Trigger | ||
* ------------------------------------------------------------------- */ | ||
|
||
interface ITriggerProps { | ||
index: number; | ||
title: string; | ||
} | ||
|
||
const Trigger = ({ index, title }: ITriggerProps) => { | ||
const { selectedIndex, setSelectedIndex } = useChatOverview(); | ||
const isActive = selectedIndex === index ? "active" : "default"; | ||
|
||
const onSelect = () => { | ||
if (setSelectedIndex) { | ||
setSelectedIndex(index); | ||
} | ||
}; | ||
|
||
return <TabItem state={isActive} title={title} onClick={onSelect}></TabItem>; | ||
}; | ||
|
||
/* ------------------------------------------------------------------- | ||
* Panel | ||
* ------------------------------------------------------------------- */ | ||
|
||
interface IPanelProps { | ||
index: number; | ||
chatItems: IChatItemProps[]; | ||
} | ||
|
||
const Panel = ({ index, chatItems }: IPanelProps) => { | ||
const { selectedIndex } = useChatOverview(); | ||
const isActive = selectedIndex === index; | ||
|
||
return ( | ||
isActive && ( | ||
<PanelWrapper> | ||
<ChatList chatItems={chatItems} /> | ||
</PanelWrapper> | ||
) | ||
); | ||
}; | ||
|
||
/* ------------------------------------------------------------------- | ||
* Export | ||
* ------------------------------------------------------------------- */ | ||
|
||
export const ChatOverview: typeof ChatOverviewRoot & { | ||
List: typeof List; | ||
Trigger: typeof Trigger; | ||
Panel: typeof Panel; | ||
} = Object.assign(ChatOverviewRoot, { | ||
List: List, | ||
Trigger: Trigger, | ||
Panel: Panel | ||
}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import type { Meta, StoryObj } from "@storybook/react"; | ||
import { ChatOverview } from "."; | ||
|
||
const meta: Meta = { | ||
title: "Organisms/ChatOverview", | ||
tags: ["autodocs"], | ||
argTypes: { | ||
allChatItems: { | ||
control: "object", | ||
description: "전체 채팅방 목록" | ||
}, | ||
sellingChatItems: { | ||
control: "object", | ||
description: "판매 채팅방 목록" | ||
}, | ||
buyingChatItems: { | ||
control: "object", | ||
description: "구매 채팅방 목록" | ||
}, | ||
unreadChatItems: { | ||
control: "object", | ||
description: "읽지 않은 채팅방 목록" | ||
} | ||
} | ||
}; | ||
|
||
type Story = StoryObj<typeof meta>; | ||
|
||
const commonArgs: { | ||
profileImgUrl: string; | ||
itemImgUrl: string; | ||
name: string; | ||
onClick: () => void; | ||
} = { | ||
profileImgUrl: "https://github.com/moypp.png", | ||
itemImgUrl: "https://github.com/ppyom.png", | ||
name: "username", | ||
|
||
onClick: () => console.log("chatItem 클릭") | ||
}; | ||
|
||
export const Default: Story = { | ||
args: { | ||
allChatItems: [ | ||
{ | ||
...commonArgs, | ||
lastMsg: "(판매) last message", | ||
lastMsgCnt: 0, | ||
lastMsgTime: "2024-11-26T06:24:31:22" | ||
}, | ||
{ | ||
...commonArgs, | ||
lastMsg: "(구매) last message", | ||
lastMsgCnt: 100, | ||
lastMsgTime: "2024-11-17T06:24:31:22" | ||
}, | ||
{ | ||
...commonArgs, | ||
lastMsg: "(구매) last message", | ||
lastMsgCnt: 0, | ||
lastMsgTime: "2024-11-17T06:24:31:22" | ||
} | ||
], | ||
sellingChatItems: [ | ||
{ | ||
...commonArgs, | ||
lastMsg: "(판매) last message", | ||
lastMsgCnt: 0, | ||
lastMsgTime: "2024-11-26T06:24:31:22" | ||
} | ||
], | ||
buyingChatItems: [ | ||
{ | ||
...commonArgs, | ||
lastMsg: "(구매) last message", | ||
lastMsgCnt: 100, | ||
lastMsgTime: "2024-11-26T06:24:31:22" | ||
}, | ||
{ | ||
...commonArgs, | ||
lastMsg: "(구매) last message", | ||
lastMsgCnt: 0, | ||
lastMsgTime: "2024-11-17T06:24:31:22" | ||
} | ||
], | ||
unreadChatItems: [ | ||
{ | ||
...commonArgs, | ||
lastMsg: "(구매) last message", | ||
lastMsgCnt: 100, | ||
lastMsgTime: "2024-11-26T06:24:31:22" | ||
} | ||
] | ||
}, | ||
render: (args) => { | ||
return ( | ||
<ChatOverview> | ||
<ChatOverview.List> | ||
<ChatOverview.Trigger index={0} title="전체" /> | ||
<ChatOverview.Trigger index={1} title="판매" /> | ||
<ChatOverview.Trigger index={2} title="구매" /> | ||
<ChatOverview.Trigger index={3} title="안 읽은 채팅방" /> | ||
</ChatOverview.List> | ||
<ChatOverview.Panel index={0} chatItems={args.allChatItems} /> | ||
<ChatOverview.Panel index={1} chatItems={args.sellingChatItems} /> | ||
<ChatOverview.Panel index={2} chatItems={args.buyingChatItems} /> | ||
<ChatOverview.Panel index={3} chatItems={args.unreadChatItems} /> | ||
</ChatOverview> | ||
); | ||
} | ||
}; | ||
|
||
export default meta; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import styled from "@emotion/styled"; | ||
|
||
export const ChatOverviewRootWrapper: ReturnType< | ||
typeof styled.div | ||
> = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
`; | ||
|
||
export const ListWrapper: ReturnType<typeof styled.div> = styled.div` | ||
display: flex; | ||
`; | ||
|
||
export const PanelWrapper: ReturnType<typeof styled.div> = styled.div``; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters