Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Chat] 좋아요 기능 추가 #3017

Merged
merged 18 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from 17 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
1 change: 1 addition & 0 deletions packages/chat/src/chat-bubble/chat-bubble-ui.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const Text = {
unreadCount: 1,
createdAt: new Date(2022, 10, 1).toISOString(),
profileName: '테스트계정',
thanks: { count: 1, haveMine: false },
},
}

Expand Down
118 changes: 79 additions & 39 deletions packages/chat/src/chat-bubble/chat-bubble-ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
} from './elements'
import BubblePayload from './bubble-payload'
import BlindedBubble from './blinded'
import Thanks from './thanks'

const CHAT_CONTAINER_STYLES = {
marginTop: 20,
Expand All @@ -28,53 +29,76 @@ const CHAT_CONTAINER_STYLES = {
width: '100%',
} as const

interface ChatContainerProps {
createdAt?: string
unreadCount: number | null
thanks?: { count: number; haveMine: boolean }
onThanksClick?: () => void
showBubbleInfo: boolean
}

function SentChatContainer({
createdAt,
unreadCount,
onRetry,
onCancel,
thanks,
onThanksClick,
children,
showBubbleInfo,
}: PropsWithChildren<{
createdAt?: string
unreadCount: number | null
onRetry?: () => Promise<boolean> | undefined
onCancel?: () => void
showBubbleInfo: boolean
}>) {
}: PropsWithChildren<
{
onRetry?: () => Promise<boolean> | undefined
onCancel?: () => void
} & ChatContainerProps
>) {
const [show, setShow] = useState<boolean>(true)

return show ? (
<Container css={{ textAlign: 'right', ...CHAT_CONTAINER_STYLES }}>
{!createdAt ? (
<SendingFailureHandlerContainer>
<RetryButton
onClick={async () => {
if (await onRetry?.()) {
<Container
css={{
textAlign: 'right',
...CHAT_CONTAINER_STYLES,
}}
>
<div>
{!createdAt ? (
<SendingFailureHandlerContainer>
<RetryButton
onClick={async () => {
if (await onRetry?.()) {
setShow(false)
}
}}
/>
<DeleteButton
onClick={() => {
onCancel?.()
setShow(false)
}
}}
/>
<DeleteButton
onClick={() => {
onCancel?.()
setShow(false)
}}
/>
</SendingFailureHandlerContainer>
) : (
<>
{showBubbleInfo && (
<BubbleInfo
unreadCount={unreadCount}
date={createdAt}
css={{ marginRight: 8, textAlign: 'right' }}
}}
/>
)}
</>
)}

{children}
</SendingFailureHandlerContainer>
) : (
<>
{showBubbleInfo && (
<BubbleInfo
unreadCount={unreadCount}
date={createdAt}
css={{ marginRight: 8, textAlign: 'right' }}
/>
)}
</>
)}
{children}
</div>
{thanks && onThanksClick ? (
<Thanks
count={thanks.count}
haveMine={thanks.haveMine}
onClick={onThanksClick}
css={{ display: 'inline-flex', marginTop: 6, marginRight: 10 }}
/>
) : null}
</Container>
) : null
}
Expand All @@ -84,16 +108,15 @@ function ReceivedChatContainer({
profileName,
unreadCount,
createdAt,
thanks,
onThanksClick,
showBubbleInfo,
children,
}: {
profileImageUrl?: string
profileName?: string
unreadCount: number | null
createdAt?: string
showBubbleInfo: boolean
children: React.ReactNode
}) {
} & ChatContainerProps) {
return (
<Container css={{ ...CHAT_CONTAINER_STYLES }}>
<ProfileImage src={profileImageUrl} />
Expand All @@ -111,6 +134,15 @@ function ReceivedChatContainer({
css={{ marginLeft: 8, textAlign: 'left' }}
/>
) : null}

{thanks && onThanksClick ? (
<Thanks
count={thanks.count}
haveMine={thanks.haveMine}
onClick={onThanksClick}
css={{ marginTop: 6 }}
/>
) : null}
</Container>
</Container>
)
Expand Down Expand Up @@ -139,6 +171,8 @@ export interface ChatBubbleUIProps {
* 'sent' 타입일 때, 메시지 전송 실패할 경우 재시도를 취소하는 함수
*/
onCancel?: () => void
onThanksClick?: () => void
thanks?: { count: number; haveMine: boolean }
bubbleStyle?: ChatBubbleStyle
}

Expand All @@ -152,8 +186,12 @@ export function ChatBubbleUI({
blindedAt,
blindedText,
onRetry,
thanks,
onThanksClick,
bubbleStyle,
}: ChatBubbleUIProps) {
const showThanks = !blindedAt

switch (type) {
case 'sent': {
const sentBubbleStyle = bubbleStyle?.sent
Expand All @@ -163,6 +201,7 @@ export function ChatBubbleUI({
showBubbleInfo={payload.type !== MessageType.PRODUCT}
unreadCount={unreadCount}
onRetry={onRetry}
{...(showThanks && { thanks, onThanksClick })}
>
{blindedAt ? (
<BlindedBubble
Expand Down Expand Up @@ -207,6 +246,7 @@ export function ChatBubbleUI({
showBubbleInfo={payload.type !== MessageType.PRODUCT}
profileImageUrl={profileImageUrl}
profileName={profileName}
{...(showThanks && { thanks, onThanksClick })}
>
{blindedAt ? (
<BlindedBubble
Expand Down
12 changes: 12 additions & 0 deletions packages/chat/src/chat-bubble/chat-bubble.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ interface ChatBubbleProps {
disableUnreadCount?: boolean
onRetryButtonClick?: (message: MessageInterface) => void
onRetryCancelButtonClick?: (message: MessageInterface) => void
onThanksClick?: (id: number, haveMyThanks: boolean) => void
blindedText?: string
bubbleStyle?: ChatBubbleStyle
}
Expand All @@ -36,6 +37,7 @@ const ChatBubble = ({
postMessageAction,
onRetryButtonClick,
onRetryCancelButtonClick,
onThanksClick,
disableUnreadCount = false,
blindedText,
bubbleStyle,
Expand Down Expand Up @@ -96,6 +98,16 @@ const ChatBubble = ({
onCancel={onCancel}
blindedAt={message.blindedAt}
blindedText={blindedText}
thanks={message.reactions?.thanks}
onThanksClick={
onThanksClick
? () => {
if (message.reactions?.thanks) {
onThanksClick?.(message.id, message.reactions.thanks.haveMine)
}
}
: undefined
}
bubbleStyle={bubbleStyle}
/>
)
Expand Down
44 changes: 44 additions & 0 deletions packages/chat/src/chat-bubble/thanks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Button } from '@titicaca/core-elements'
import styled from 'styled-components'

const ThanksButton = styled(Button)<{ haveMine: boolean }>`
display: flex;
gap: 3px;
height: 20px;
align-items: center;
background-color: ${({ haveMine }) =>
haveMine ? 'var(--color-white)' : 'var(--color-gray50)'};
color: ${({ haveMine }) => (haveMine ? '#1DBEB2' : 'var(--color-gray700)')};
${({ haveMine }) => (haveMine ? 'border: 1px solid #1DBEB2;' : '')}
padding: 3.5px 6px 4.5px 7px;
font-weight: ${({ haveMine }) => (haveMine ? '700' : '500')};
font-size: 10px;
`

const ThanksCount = styled.span`
font-size: 10px;
line-height: 11px;
`

export default function Thanks({
count,
haveMine,
onClick,
...props
}: {
count: number
haveMine: boolean
onClick?: () => void
}) {
return (
<ThanksButton haveMine={haveMine} onClick={() => onClick?.()} {...props}>
<img
src="https://assets.triple-dev.titicaca-corp.com/images/ic_chat_thumbsup_on.svg"
alt="좋아요 아이콘"
width={11}
height={11}
/>
{count === 0 ? null : <ThanksCount>{count}</ThanksCount>}
</ThanksButton>
)
}
60 changes: 58 additions & 2 deletions packages/chat/src/chat/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import {
ImagePayload,
MessageInterface,
PostMessageType,
ReactionType,
RoomInterface,
RoomType,
TextPayload,
UpdateChatData,
UserInterface,
Expand Down Expand Up @@ -55,7 +57,14 @@ export interface ChatProps {
showFailToast?: (message: string) => void
onRetryButtonClick?: () => void
onRetryCancelButtonClick?: () => void

addReactions?: (
messageId: number,
reaction: ReactionType,
) => Promise<{ success: boolean }>
removeReactions?: (
messageId: number,
reaction: ReactionType,
) => Promise<{ success: boolean }>
updateChatData?: UpdateChatData
disableUnreadCount?: boolean
blindedText?: string
Expand All @@ -73,14 +82,15 @@ export const Chat = ({
room,
messages: initMessages,
beforeSentMessages = [],

postMessage,
getMessages,
getUnreadRoom,
notifyNewMessage,
showFailToast,
onRetryButtonClick,
onRetryCancelButtonClick,
addReactions,
removeReactions,
updateChatData,
disableUnreadCount = false,
blindedText,
Expand Down Expand Up @@ -282,6 +292,46 @@ export const Chat = ({
onRetryButtonClick?.()
}

async function onThanksClick(messageId: number, haveMyThanks: boolean) {
if (!haveMyThanks && addReactions) {
const { success } = await addReactions(messageId, 'thanks')
const message = messages.find((message) => message.id === messageId)
if (success && message) {
dispatch({
action: ChatActions.UPDATE_MESSAGE,
message: {
...message,
reactions: {
thanks: {
count: (message.reactions?.thanks?.count || 0) + 1,
haveMine: true,
},
},
},
})
}
}
if (haveMyThanks && removeReactions) {
const { success } = await removeReactions(messageId, 'thanks')
const message = messages.find((message) => message.id === messageId)
if (success && message) {
const thanksCount = message.reactions?.thanks?.count
dispatch({
action: ChatActions.UPDATE_MESSAGE,
message: {
...message,
reactions: {
thanks: {
count: thanksCount ? thanksCount - 1 : 0,
haveMine: false,
},
},
},
})
}
}
}

return (
<>
<IntersectionObserver onChange={onChangeScroll}>
Expand All @@ -304,6 +354,9 @@ export const Chat = ({
onRetryCancelButtonClick={onRetryCancel}
disableUnreadCount={disableUnreadCount}
blindedText={blindedText}
onThanksClick={
room.type === RoomType.EVENT ? onThanksClick : undefined
}
dongoc marked this conversation as resolved.
Show resolved Hide resolved
bubbleStyle={bubbleStyle}
/>
</li>
Expand All @@ -323,6 +376,9 @@ export const Chat = ({
onRetryCancelButtonClick={onRetryCancel}
disableUnreadCount={disableUnreadCount}
blindedText={blindedText}
onThanksClick={
room.type === RoomType.EVENT ? onThanksClick : undefined
}
bubbleStyle={bubbleStyle}
/>
</li>
Expand Down
Loading