diff --git a/packages/chat/src/bubble-container/bubble-container.tsx b/packages/chat/src/bubble-container/bubble-container.tsx index 6356a50ad7..68c328114e 100644 --- a/packages/chat/src/bubble-container/bubble-container.tsx +++ b/packages/chat/src/bubble-container/bubble-container.tsx @@ -1,6 +1,8 @@ import { PropsWithChildren } from 'react' import { Container } from '@titicaca/core-elements' +import { DEFAULT_MESSAGE_ID_PREFIX } from '../chat/constants' + import { BubbleInfo } from './bubble-info' import { DeleteButton, @@ -18,6 +20,7 @@ const CHAT_CONTAINER_STYLES = { } as const type SentBubbleContainerProp = PropsWithChildren<{ + id: string /** 메시지 생성 시간 */ createdAt?: string // Date? /** 전송 실패한 메시지 재전송 시도 함수 */ @@ -31,6 +34,7 @@ type SentBubbleContainerProp = PropsWithChildren<{ }> function SentBubbleContainer({ + id, createdAt, onRetry, onRetryCancel, @@ -39,7 +43,10 @@ function SentBubbleContainer({ children, }: SentBubbleContainerProp) { return ( - + {!createdAt ? ( @@ -58,6 +65,7 @@ function SentBubbleContainer({ } type ReceivedBubbleContainerProp = PropsWithChildren<{ + id: string /** 메시지 생성 시간 */ createdAt?: string // Date? /** 메시지 발신인 정보 */ @@ -74,6 +82,7 @@ type ReceivedBubbleContainerProp = PropsWithChildren<{ }> function ReceivedBubbleContainer({ + id, profile, unreadCount, createdAt, @@ -81,7 +90,10 @@ function ReceivedBubbleContainer({ children, }: ReceivedBubbleContainerProp) { return ( - + diff --git a/packages/chat/src/bubble-container/index.ts b/packages/chat/src/bubble-container/index.ts index 0a060004c7..b74aa23ec7 100644 --- a/packages/chat/src/bubble-container/index.ts +++ b/packages/chat/src/bubble-container/index.ts @@ -1 +1 @@ -export { default } from './bubble-container' +export { default as BubbleContainer } from './bubble-container' diff --git a/packages/chat/src/bubble/index.ts b/packages/chat/src/bubble/index.ts index 1f8cf9c4a4..59730ff526 100644 --- a/packages/chat/src/bubble/index.ts +++ b/packages/chat/src/bubble/index.ts @@ -3,3 +3,4 @@ export { TextBubble } from './text' export { RichBubble } from './rich' export { ProductBubble } from './product' export { Badge, ProductName, ProductImage, ProductHr } from './elements' +export { default as BubbleUI } from './bubble-ui' diff --git a/packages/chat/src/chat/chat-container.stories.tsx b/packages/chat/src/chat/chat-container.stories.tsx deleted file mode 100644 index ba20d10903..0000000000 --- a/packages/chat/src/chat/chat-container.stories.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import type { StoryFn } from '@storybook/react' -import { FlexBox } from '@titicaca/core-elements' -import styled from 'styled-components' - -import { CHAT_ARGS } from '../utils/constants' -import { RichItemText } from '../bubble/type' - -import { Chat } from './chat' -import { ChatContainer, ChatContainerProps } from './chat-container' - -export default { - title: 'chat / ChatContainer', - component: ChatContainer, -} - -const ChatMessagesContainer = styled(FlexBox).attrs({ - flexGrow: 1, -})` - overflow-y: scroll; - padding-left: 20px; - padding-right: 30px; - - @media only screen and (max-width: 480px) { - height: calc(100vh - 190px); - } -` - -const Input = ({ - postMessage, -}: { - postMessage: (payload: RichItemText) => void -}) => { - const onClick = () => { - postMessage({ type: 'text', message: 'zz' }) - } - - return ( - - - - - ) -} - -const Template: StoryFn = () => ( - - - -) - -export const ChatStory = { - render: Template, - name: 'Chat Room', -} diff --git a/packages/chat/src/chat/chat-container.tsx b/packages/chat/src/chat/chat-container.tsx deleted file mode 100644 index 021bcfd001..0000000000 --- a/packages/chat/src/chat/chat-container.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import React, { ElementType, PropsWithChildren, useState } from 'react' -import dynamic from 'next/dynamic' - -import { - MessageInterface, - MetaDataInterface, - PostMessageActionType, -} from '../types' -import { RichItemImages, RichItemText } from '../bubble/type' - -import { ChatContext, ChatContextValue } from './chat-context' - -const ScrollProvider = dynamic(() => import('./scroll-context'), { - ssr: false, -}) - -export interface ChatContainerProps extends ChatContextValue { - /** - * Chat list를 감싸는 컨테이너로, 커스텀 스타일 등 적용 가능 - */ - container: ElementType - /** - * input 창, 보내기 버튼 등을 포함하는 컴포넌트 - */ - inputElement?: ElementType - /** - * 메시지를 전송하는 api를 래핑하는 함수 - */ - postMessage?: ( - payload: RichItemText | RichItemImages, - ) => Promise<{ success: boolean; newMessages: MessageInterface[] }> -} - -const defaultOnImageBubbleClick = (imageInfos: MetaDataInterface[]) => { - window.open(imageInfos[0].originalUrl, '_blank') -} - -/** - * chat-room 페이지에 삽입되는 컴포넌트입니다. - * - * ChatContainer에는 공통 필수 prop, Chat 에는 로직, api 관련된 prop을 전달해 구성합니다. - */ -export const ChatContainer = ({ - container: Container, - inputElement: Input, - children, - - textBubbleFontSize, - textBubbleMaxWidthOffset, - mediaUrlBase, - cloudinaryName, - onRichBubbleButtonBeforeRouting, - onImageBubbleClick = defaultOnImageBubbleClick, - onTextBubbleClick, -}: PropsWithChildren) => { - const [postMessage, setPostMessage] = useState( - null, - ) - - return ( - - - {children} - {Input && postMessage ? : null} - - - ) -} diff --git a/packages/chat/src/chat/chat-context.ts b/packages/chat/src/chat/chat-context.ts deleted file mode 100644 index a802c4d699..0000000000 --- a/packages/chat/src/chat/chat-context.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { - createContext, - Dispatch, - MouseEventHandler, - SetStateAction, - useContext, -} from 'react' - -import { MetaDataInterface, PostMessageActionType } from '../types' - -export interface ChatContextValue { - textBubbleFontSize: number - textBubbleMaxWidthOffset: number - mediaUrlBase: string - cloudinaryName: string - /** - * message payload가 RICH 타입이고, - * BUTTON 타입의 rich item을 눌렀을 때, - * 라우팅 하기 전 작동하는 콜백 함수 - */ - onRichBubbleButtonBeforeRouting?: () => void - onImageBubbleClick?: (imageInfos: MetaDataInterface[]) => void - /** - * 텍스트 버블의 자식의 클릭 이벤트를 delegation 하는 함수 - */ - onTextBubbleClick?: MouseEventHandler - setPostMessage?: Dispatch> -} - -export const ChatContext = createContext( - undefined, -) - -export function useChat() { - const context = useContext(ChatContext) - if (!context) { - throw new Error('chat context 가 존재하지 않습니다.') - } - return context -} diff --git a/packages/chat/src/chat/chat.tsx b/packages/chat/src/chat/chat.tsx deleted file mode 100644 index 2f8f632a0a..0000000000 --- a/packages/chat/src/chat/chat.tsx +++ /dev/null @@ -1,432 +0,0 @@ -import { IncomingMessage } from 'http' - -import { - ComponentProps, - useCallback, - useEffect, - useMemo, - useReducer, - useRef, -} from 'react' -import { StaticIntersectionObserver as IntersectionObserver } from '@titicaca/intersection-observer' -import { useUserAgentContext } from '@titicaca/react-contexts' -import { closeKeyboard } from '@titicaca/triple-web-to-native-interfaces' -import { Container } from '@titicaca/core-elements' - -import { - HasUnreadOfRoomInterface, - MessageInterface, - PostMessageType, - RoomInterface, - UpdateChatData, - UserInterface, - UserType, -} from '../types' -import BubbleContainer from '../bubble-container' -import { HiddenElement } from '../bubble-container/elements' -import { ChatBubbleStyle } from '../types/ui' -import BubbleUI from '../bubble/bubble-ui' -import { RichItemImages, RichItemText } from '../bubble/type' - -import { ChatActions, ChatReducer, initialChatState } from './reducer' -import { useChat } from './chat-context' -import { useChatMessage } from './use-chat-message' -import { useScroll } from './scroll-context' - -export const CHAT_CONTAINER_ID = 'chat-inner-container' - -export interface ChatProps { - displayTarget: UserType - me: UserInterface - /** - * 초기 메시지들 - */ - messages?: MessageInterface[] - /** - * 보내기 전 메시지들 - */ - beforeSentMessages?: MessageInterface[] - postMessage?: PostMessageType - getMessages: (option: { - roomId: string - backward?: boolean - lastMessageId: number | string | null - req?: IncomingMessage - }) => Promise - getUnreadRoom?: (option: { - roomId: string - lastSeenMessageId: number - }) => Promise - room: RoomInterface - notifyNewMessage?: (lastMessage: MessageInterface) => void - showFailToast?: (message: string) => void - onRetryButtonClick?: () => void - onRetryCancelButtonClick?: () => void - - updateChatData?: UpdateChatData - disableUnreadCount?: boolean - blindedText?: string - bubbleStyle?: ChatBubbleStyle -} - -/** - * ChatBubble을 map으로 리스팅하고 있는 컴포넌트 - * - * ChatContainer로 감싸서 함께 사용해야 합니다. - */ -export const Chat = ({ - displayTarget, - me, - room, - messages: initMessages, - beforeSentMessages = [], - - postMessage, - getMessages, - getUnreadRoom, - notifyNewMessage, - showFailToast, - onRetryButtonClick, - onRetryCancelButtonClick, - updateChatData, - disableUnreadCount = false, - blindedText, - bubbleStyle, - ...props -}: ChatProps) => { - const { - chatContainerRef, - bottomRef, - setScrollY, - scrollToBottom, - getScrollContainerHeight, - } = useScroll() - - const { setPostMessage, textBubbleFontSize, textBubbleMaxWidthOffset } = - useChat() - const [ - { - messages, - failedMessages, - hasPrevMessage, - // otherUnreadInfo, - lastMessageId, - firstMessageId, - }, - dispatch, - ] = useReducer(ChatReducer, initialChatState) - - const isScrollReady = useRef(false) - - const { os } = useUserAgentContext() - const isIos = useMemo(() => os.name === 'iOS', [os.name]) - const updateUnread = useCallback(async () => { - if (!lastMessageId) { - return - } - - const unreadRoomResult = await getUnreadRoom?.({ - roomId: room.id, - lastSeenMessageId: lastMessageId, - }) - const { hasUnread = false, others = [] } = unreadRoomResult || {} - - const otherUnreadInfo = others.map(({ memberId, lastSeenMessageId }) => ({ - memberId, - lastSeenMessageId: Number(lastSeenMessageId), - })) - dispatch({ - action: ChatActions.UPDATE, - otherUnreadInfo, - }) - - return hasUnread - }, [lastMessageId, getUnreadRoom, room.id]) - - useChatMessage({ - roomId: room.id, - userMeId: me.id, - notifyNewMessage, - dispatch, - updateChatData, - }) - - useEffect(() => { - const chatListDiv = chatContainerRef.current - const hideKeyboard = () => closeKeyboard() - if (chatListDiv && isIos) { - chatListDiv.addEventListener('touchmove', hideKeyboard) - return () => { - chatListDiv.removeEventListener('touchmove', hideKeyboard) - } - } - }, [isIos]) - - useEffect(() => { - ;(async function () { - if (!room.id) { - return - } - - if (!initMessages) { - const result = await getMessages({ - roomId: room.id, - backward: true, - lastMessageId: Number(room.lastMessageId) + 1, - }) - - result && - dispatch({ - action: ChatActions.INIT, - messages: result, - lastMessageId: room.lastMessageId, - }) - } else { - initMessages.length > 0 && - dispatch({ - action: ChatActions.INIT, - messages: initMessages, - lastMessageId: room.lastMessageId, - }) - } - })() - }, [room, initMessages]) // eslint-disable-line react-hooks/exhaustive-deps - - async function fetchPastMessages(): Promise { - if (messages.length) { - return getMessages({ - roomId: room.id, - lastMessageId: firstMessageId, - backward: true, - }) - } else { - return [] - } - } - - const postMessageAction = async ( - payload: RichItemText | RichItemImages, - retry = false, - ): Promise => { - const result = await postMessage?.(payload) - const { success, newMessages } = result || { - success: false, - newMessages: [], - } - - if (success) { - dispatch({ - action: ChatActions.POST, - messages: newMessages, - }) - - const lastMessage = newMessages[newMessages.length - 1] - notifyNewMessage?.({ ...lastMessage }) - } else if (!retry) { - dispatch({ - action: ChatActions.FAILED_TO_POST, - message: { - id: new Date().getTime(), - roomId: room.id, - senderId: me.id, - payload, - displayTarget: 'all', - sender: me, - }, - }) - - showFailToast?.('메시지 발송에 실패했습니다.') - } - - return success - } - - const handleChangeLastMessageId = async () => { - !disableUnreadCount && (await updateUnread()) - scrollToBottom() - - if (!isScrollReady.current) { - isScrollReady.current = true - } - } - - useEffect(() => { - if (lastMessageId) { - void handleChangeLastMessageId() - } - }, [lastMessageId]) - - useEffect(() => { - postMessage && setPostMessage?.(() => postMessageAction) - }, [postMessage, setPostMessage]) // eslint-disable-line react-hooks/exhaustive-deps - - const onChangeScroll = async ({ - isIntersecting, - }: IntersectionObserverEntry) => { - if (isIntersecting) { - const prevScrollY = getScrollContainerHeight() - - if (isScrollReady.current && hasPrevMessage) { - const pastMessages = await fetchPastMessages() - - dispatch({ - action: ChatActions.PAST, - messages: pastMessages, - }) - setScrollY(prevScrollY) - } - } - } - - function removeFromFailedMessages(message: MessageInterface) { - dispatch({ - action: ChatActions.REMOVE_FROM_FAILED, - message, - }) - } - - function onRetry(message: MessageInterface) { - removeFromFailedMessages(message) - onRetryButtonClick?.() - } - - function onRetryCancel(message: MessageInterface) { - removeFromFailedMessages(message) - onRetryButtonClick?.() - } - - return ( - <> - - - - -
    - {[...messages, ...beforeSentMessages].map( - (message: MessageInterface) => { - const my = message.senderId === me.id - const senderInfo = my - ? me - : room.members.find((member) => member.id === message.senderId) - const payload = (function getDisplayedPayload() { - if (!message.displayTarget || message.displayTarget === 'all') { - return message.payload - } - if (message.displayTarget.includes(displayTarget)) { - return message.payload - } - return message.alternative ?? message.payload - })() - const bubbleProp = getBubbleProp({ - messageId: message.id.toString(), - messagePayload: payload, - my, - blinded: !!message.blindedAt, - textBubbleFontSize, - textBubbleMaxWidthOffset, - }) - return ( - - - - ) - }, - )} -
-
    - {failedMessages.map((message: MessageInterface) => { - const bubbleProp = getBubbleProp({ - messageId: message.id.toString(), - messagePayload: message.payload, - my: true, - blinded: false, - }) - - return ( - { - onRetry(message) - }} - onRetryCancel={() => onRetryCancel(message)} - > - - - ) - })} -
-
- - - ) -} - -function getBubbleProp({ - messageId, - messagePayload, - my, - blinded, - textBubbleFontSize, - textBubbleMaxWidthOffset, -}: { - messageId: string - messagePayload: MessageInterface['payload'] - my: boolean - blinded: boolean - textBubbleFontSize?: number - textBubbleMaxWidthOffset?: number -}): ComponentProps { - const bla = { - id: messageId, - my, - blinded, - maxWidthOffset: textBubbleMaxWidthOffset, - mediaUrlBase: - process.env.NEXT_PUBLIC_MEDIA_URL_BASE || 'https://media.triple.guide', - cloudinaryName: process.env.NEXT_PUBLIC_CLOUDINARY_NAME || 'triple-cms', - css: { size: textBubbleFontSize }, - } - switch (messagePayload.type) { - case 'text': - return { - type: 'text', - value: { message: messagePayload.message }, - ...bla, - } - case 'images': - return { - type: 'images', - value: { images: messagePayload.images }, - ...bla, - } - case 'rich': - return { - type: 'rich', - value: { blocks: messagePayload.items }, - ...bla, - } - case 'product': - return { - type: 'product', - value: { product: messagePayload.product }, - ...bla, - } - } -} diff --git a/packages/chat/src/chat/index.ts b/packages/chat/src/chat/index.ts index 59354ce0da..c371a631fb 100644 --- a/packages/chat/src/chat/index.ts +++ b/packages/chat/src/chat/index.ts @@ -2,10 +2,3 @@ export * from './scroll-context' export * from './constants' export * from './chat-scroll-container' export * from './messages-reducer' - -// TODO 아래 파일들은 bubble 작업 이후 삭제될 예정입니다. -export * from './chat' -export * from './chat-container' -export * from './chat-context' -export * from './use-chat-message' -export * from './reducer' diff --git a/packages/chat/src/chat/reducer.ts b/packages/chat/src/chat/reducer.ts deleted file mode 100644 index f5bad16e30..0000000000 --- a/packages/chat/src/chat/reducer.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { MessageInterface, OtherUnreadInterface } from '../types' - -export enum ChatActions { - INIT, // 최초에 메시지 - PAST, // 과거 메시지 - NEW, // 메시지 수신 - POST, // 메시지 전송 - FAILED_TO_POST, // 메시지 전송 실패 - UPDATE, // 읽음 표시 업데이트 - REMOVE_FROM_FAILED, // 전송 실패 메세지 재전송 또는 삭제 -} - -export interface ChatState { - messages: MessageInterface[] - failedMessages: MessageInterface[] - beforeSentMessages: MessageInterface[] - hasPrevMessage: boolean - otherUnreadInfo: OtherUnreadInterface[] - firstMessageId: number | null - lastMessageId: number | null -} - -export type ChatAction = - | { - action: ChatActions.INIT - messages: MessageInterface[] - lastMessageId: number - } - | { - action: ChatActions.PAST - messages: MessageInterface[] - } - | { - action: ChatActions.NEW - messages: MessageInterface[] - } - | { - action: ChatActions.POST - messages: MessageInterface[] - } - | { - action: ChatActions.FAILED_TO_POST - message: MessageInterface - } - | { - action: ChatActions.UPDATE - otherUnreadInfo: OtherUnreadInterface[] - } - | { action: ChatActions.REMOVE_FROM_FAILED; message: MessageInterface } - -export const ChatReducer = ( - state: ChatState, - action: ChatAction, -): ChatState => { - switch (action.action) { - case ChatActions.INIT: - return { - ...state, - messages: action.messages, - hasPrevMessage: true, - firstMessageId: action.messages.length - ? Number(action.messages[0].id) - : 0, - lastMessageId: Number(action.lastMessageId), - } - - case ChatActions.PAST: - if (action.messages.length) { - return { - ...state, - messages: mergeMessages(action.messages, state.messages), - firstMessageId: Number(action.messages[0].id), - hasPrevMessage: true, - } - } else { - return { ...state, hasPrevMessage: false } - } - - case ChatActions.POST: - return { - ...state, - messages: mergeMessages(state.messages, action.messages), - lastMessageId: Number(action.messages[action.messages.length - 1].id), - } - - case ChatActions.NEW: - return { - ...state, - messages: mergeMessages(state.messages, action.messages), - lastMessageId: Number(action.messages[action.messages.length - 1].id), - } - - case ChatActions.FAILED_TO_POST: - return { - ...state, - failedMessages: [...state.failedMessages, action.message], - } - - case ChatActions.UPDATE: - return { - ...state, - otherUnreadInfo: action.otherUnreadInfo, - } - - case ChatActions.REMOVE_FROM_FAILED: - return { - ...state, - failedMessages: state.failedMessages.filter( - (message) => message.id !== action.message.id, - ), - } - - default: - throw new Error('unexpected action') - } -} - -export const initialChatState: ChatState = { - messages: [], - failedMessages: [], - beforeSentMessages: [], - hasPrevMessage: true, - otherUnreadInfo: [], - firstMessageId: null, - lastMessageId: null, -} - -function mergeMessages( - beforeMessages: MessageInterface[], - afterMessages: MessageInterface[], -) { - const lastMessageId = beforeMessages.length - ? beforeMessages[beforeMessages.length - 1].id - : 0 - const filteredMessages = afterMessages.filter( - (message) => Number(message.id) > Number(lastMessageId), - ) - - return [...beforeMessages, ...filteredMessages] -} diff --git a/packages/chat/src/chat/scroll-context.tsx b/packages/chat/src/chat/scroll-context.tsx index 0f5fb562ac..7068e19d52 100644 --- a/packages/chat/src/chat/scroll-context.tsx +++ b/packages/chat/src/chat/scroll-context.tsx @@ -7,19 +7,11 @@ import { useRef, useState, useContext, - PropsWithChildren, + ReactNode, } from 'react' import { DEFAULT_MESSAGE_ID_PREFIX } from './constants' -export interface ScrollContextProps { - /** - 메세지로 스크롤을 하기 위한 id의 prefix입니다. - 메세지 노드에 messageIdPrefix를 넣은 id를 추가해야 합니다. - */ - messageIdPrefix?: string -} - export interface ScrollOptions { /** 최하단으로 이동하기 위해 페이지네이션 fetching이 필요할 경우 true로 설정해주세요. */ shouldFetchRecentPage?: boolean @@ -51,10 +43,7 @@ export interface ScrollContextValue { export const ScrollContext = createContext(null) -export default function ScrollProvider({ - messageIdPrefix = DEFAULT_MESSAGE_ID_PREFIX, - children, -}: PropsWithChildren) { +export function ScrollProvider({ children }: { children: ReactNode }) { const chatContainerRef = useRef(null) const scrollContainerRef = useRef(null) const bottomRef = useRef(null) @@ -80,7 +69,7 @@ export default function ScrollProvider({ options: Pick = {}, ) => { const messageElement = document.getElementById( - `${messageIdPrefix}-${messageId}`, + `${DEFAULT_MESSAGE_ID_PREFIX}-${messageId}`, ) if (messageElement) { diff --git a/packages/chat/src/chat/use-chat-message.ts b/packages/chat/src/chat/use-chat-message.ts deleted file mode 100644 index 9e3a2bf5df..0000000000 --- a/packages/chat/src/chat/use-chat-message.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { Dispatch, useEffect } from 'react' - -import { - HasUnreadOfRoomInterface, - MessageInterface, - UpdateChatData, -} from '../types' - -import { ChatAction, ChatActions } from './reducer' -import { useScroll } from './scroll-context' - -interface ChatMessageProps { - roomId: string - userMeId: string - notifyNewMessage?: (lastMessage: MessageInterface) => void - dispatch: Dispatch - updateChatData?: UpdateChatData -} - -export const useChatMessage = ({ - roomId, - userMeId, - notifyNewMessage, - dispatch, - updateChatData, -}: ChatMessageProps) => { - const { scrollToBottom } = useScroll() - - useEffect(() => { - updateChatData?.message && - handleSendMessageEvent({ message: updateChatData.message }) - updateChatData?.otherUnreadInfo && - handleUnreadMessageEvent({ - otherUnreadInfo: updateChatData.otherUnreadInfo, - }) - }, [updateChatData]) - - async function handleSendMessageEvent({ - message: updatedMessage, - }: { - message: MessageInterface - }) { - if (!roomId) { - return - } - - dispatch({ - action: ChatActions.NEW, - messages: [updatedMessage], - }) - notifyNewMessage?.(updatedMessage) - scrollToBottom() - } - - async function handleUnreadMessageEvent({ - otherUnreadInfo, - }: { - otherUnreadInfo: HasUnreadOfRoomInterface - }) { - const myUnreadMessageInfos = otherUnreadInfo.others - .map(({ memberId, lastSeenMessageId }) => ({ - memberId, - lastSeenMessageId: Number(lastSeenMessageId), - })) - .filter(({ memberId }) => memberId === userMeId) - - myUnreadMessageInfos.length > 0 && - dispatch({ - action: ChatActions.UPDATE, - otherUnreadInfo: myUnreadMessageInfos, - }) - } -} diff --git a/packages/chat/src/types/index.ts b/packages/chat/src/types/index.ts index a24277916f..fe366c85dd 100644 --- a/packages/chat/src/types/index.ts +++ b/packages/chat/src/types/index.ts @@ -14,6 +14,7 @@ export type MessageType = | 'BUTTON' | 'RICH' | 'PRODUCT' + export enum RoomType { DEFAULT = 'default', // 기존 파트너센터 챗 EVENT = 'event', // 행사용 그룹 챗 @@ -60,11 +61,17 @@ export interface RoomInterface { export type DisplayTargetAll = 'all' +export type MessagePayload = + | RichItemText + | RichItemImages + | RichPayload + | ProductPayload + export interface MessageInterface { id: number roomId: string senderId: string - payload: RichItemText | RichItemImages | RichPayload | ProductPayload + payload: MessagePayload createdAt?: string displayTarget?: UserType[] | DisplayTargetAll alternative?: RichItemText | RichItemImages | RichPayload diff --git a/packages/chat/src/utils/constants.ts b/packages/chat/src/utils/constants.ts deleted file mode 100644 index 2effa3e889..0000000000 --- a/packages/chat/src/utils/constants.ts +++ /dev/null @@ -1,210 +0,0 @@ -import { MetaDataInterface, RoomType, UserType } from '../types' -import { ChatContextValue, ChatProps } from '../chat' - -export const SAMPLE_IMAGES: MetaDataInterface[] = [ - { - cloudinaryId: '70c9db60-cd42-49c3-b6a8-274318695cc2', - width: 1024, - height: 1024, - cloudinaryBucket: '', - id: '1', - type: '', - sizes: { - full: { - url: '', - }, - large: { - url: '', - }, - smallSquare: { - url: '', - }, - }, - }, -] - -const empty = () => {} - -export const MEDIA_ARGS: ChatContextValue = { - cloudinaryName: 'triple-cms', - mediaUrlBase: 'https://media.triple.guide', - textBubbleFontSize: 16, - textBubbleMaxWidthOffset: 100, - onRichBubbleButtonBeforeRouting: empty, - onImageBubbleClick: empty, - onTextBubbleClick: empty, -} - -export const CHAT_ARGS: ChatProps = { - displayTarget: UserType.TNA_PARTNER, - me: { - id: '61ea67f0de3e37001997a80f', - type: UserType.TNA_PARTNER, - identifier: '130', - code: 'TNA_BPM', - profile: { - name: 'TNA_BPM', - thumbnail: - 'https://s3.ap-northeast-2.amazonaws.com/triple-tna-dev/partner/logo/1e2496ab-8725-4df4-84c7-db9804d3c71d.jpeg', - message: '', - }, - }, - getMessages: async () => { - return [ - { - id: 4562, - roomId: '6344c73a53749900140bca43', - createdAt: '2022-11-03T06:44:57.017Z', - senderId: '61ea67f0de3e37001997a80f', - displayTarget: [UserType.TRIPLE_USER], - payload: { - type: 'rich', - items: [ - { - message: - '안녕하세요.\nTNA_BPM입니다. 예약해주셔서 감사합니다!\n\n궁금한 점이 있으시면 TNA_BPM 문의를 편하게 이용해주세요.', - type: 'text', - }, - { - label: '예약상세 바로가기', - action: { - type: 'link', - param: 'https://triple.guide/', - }, - type: 'button', - }, - ], - }, - alternative: { - type: 'text', - message: - '안녕하세요.\nTNA_BPM입니다. 예약해주셔서 감사합니다!\n\n궁금한 점이 있으시면 TNA_BPM 문의를 편하게 이용해주세요.', - }, - sender: { - id: '61ea67f0de3e37001997a80f', - type: UserType.TNA_PARTNER, - identifier: '130', - code: 'TNA_BPM', - profile: { - name: 'TNA_BPM', - thumbnail: - 'https://s3.ap-northeast-2.amazonaws.com/triple-tna-dev/partner/logo/1e2496ab-8725-4df4-84c7-db9804d3c71d.jpeg', - message: '', - }, - }, - }, - { - id: 5749, - roomId: '6344c73a53749900140bca43', - senderId: '6344be9953749900140bca42', - createdAt: '2022-11-03T06:44:57.017Z', - displayTarget: 'all', - payload: { - type: 'text', - message: '테스트 메시지', - }, - sender: { - id: '6344be9953749900140bca42', - type: UserType.TRIPLE_USER, - identifier: '4043', - code: '1', - profile: { - name: '후라이', - thumbnail: - 'https://media.triple.guide/triple-dev/c_limit,f_auto,h_2048,w_2048/52557846-363d-430a-9afd-1cd7fd4fe0b4.jpeg', - message: '', - }, - }, - }, - ] - }, - room: { - id: '6344c73a53749900140bca43', - type: RoomType.DEFAULT, - createdAt: '2022-10-11T01:30:34.519Z', - name: '', - isDirect: true, - lastMessageId: 5749, - members: [ - { - id: '61ea67f0de3e37001997a80f', - type: UserType.TNA_PARTNER, - identifier: '130', - code: 'TNA_BPM', - profile: { - name: 'TNA_BPM', - thumbnail: - 'https://s3.ap-northeast-2.amazonaws.com/triple-tna-dev/partner/logo/1e2496ab-8725-4df4-84c7-db9804d3c71d.jpeg', - message: '', - }, - }, - { - id: '6344be9953749900140bca42', - type: UserType.TRIPLE_USER, - identifier: '4043', - code: '1', - profile: { - name: '후라이', - thumbnail: - 'https://media.triple.guide/triple-dev/c_limit,f_auto,h_2048,w_2048/52557846-363d-430a-9afd-1cd7fd4fe0b4.jpeg', - message: '', - }, - }, - ], - lastMessage: { - id: 5749, - createdAt: '2022-11-03T06:44:57.017Z', - roomId: '6344c73a53749900140bca43', - senderId: '6344be9953749900140bca42', - displayTarget: 'all', - payload: { - type: 'text', - message: '테스트 메시지', - }, - sender: { - id: '6344be9953749900140bca42', - type: UserType.TRIPLE_USER, - identifier: '4043', - code: '1', - profile: { - name: '후라이', - thumbnail: - 'https://media.triple.guide/triple-dev/c_limit,f_auto,h_2048,w_2048/52557846-363d-430a-9afd-1cd7fd4fe0b4.jpeg', - message: '', - }, - }, - }, - unreadCount: 0, - metadata: { - name: '', - memberCounts: 2, - }, - }, - postMessage: async (payload) => { - return { - success: true, - newMessages: [ - { - id: 490999, - roomId: '6344c73a53749900140bca43', - senderId: '61ea67f0de3e37001997a80f', - createdAt: '2022-11-04T06:44:57.017Z', - displayTarget: 'all', - payload, - sender: { - id: '61ea67f0de3e37001997a80f', - type: UserType.TNA_PARTNER, - identifier: '130', - code: 'TNA_BPM', - profile: { - name: 'TNA_BPM', - thumbnail: - 'https://s3.ap-northeast-2.amazonaws.com/triple-tna-dev/partner/logo/1e2496ab-8725-4df4-84c7-db9804d3c71d.jpeg', - message: '', - }, - }, - }, - ], - } - }, -}