Skip to content

Commit

Permalink
feat: done with right message
Browse files Browse the repository at this point in the history
  • Loading branch information
tewarig committed Jan 30, 2025
1 parent a0cd346 commit 3d4e02a
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 47 deletions.
32 changes: 17 additions & 15 deletions packages/blade/src/components/ChatBubble/ChatBubble.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
// import chatBubble and create a basic story
import { ChatBubble } from './ChatBubble';
// import chatBubble and create a basic story
import React from 'react';
import { Story } from '@storybook/react';
import { ChatBubbleProps } from './ChatBubble.types';
import { ChatBubble } from './ChatBubble';
import type { ChatBubbleProps } from './ChatBubble';
import { Box } from '~components/Box';

export default {
title: 'ChatBubble',
component: ChatBubble,
};

const Template: Story<ChatBubbleProps> = (args) => <ChatBubble {...args} />;
const Template = (args) => (
<Box display="flex" flexDirection="column" gap={'spacing.10'}>
<ChatBubble> Demo</ChatBubble>
<ChatBubble isLastMessage> this is a demo message </ChatBubble>
<ChatBubble isUserMessage isLastMessage>
message
</ChatBubble>
<ChatBubble isError onErrorTextClick={() => {}}>
{' '}
Hi, can you tell me how can i join fight club?{' '}
</ChatBubble>
</Box>
);
export const Default = Template.bind({});
Default.args = {
message: 'Hello',
isLastMessage: false,
isUserMessage: false,
isLoading: false,
isError: false,
cardBody: null,
feedbackOptions: [],
ErrorText: '',
onErrorTextClick: () => {},
};
79 changes: 60 additions & 19 deletions packages/blade/src/components/ChatBubble/ChatBubble.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,63 @@
import React from "react";
import { Box } from "~components/Box";
import React from 'react';
import { UserMessageBubble } from './UserMessageBubble';
import { Box } from '~components/Box';
import BaseBox from '~components/Box/BaseBox';
import { AlertCircleIcon } from '~components/Icons';
import { Text } from '~components/Typography';

type ChatBubbleProps = {
message?: string;
isLastMessage?: boolean;
isUserMessage?: boolean;
isLoading?: boolean;
isError?: boolean;
cardBody?: React.ReactNode;
feedbackOptions?: Array<{icon: React.ReactNode, onClick: Function}>;
ErrorText?: string;
onErrorTextClick?: Function;
}
const ChatBubble = ({ message, isLastMessage,isUserMessage,isLoading,isError,cardBody,feedbackOptions,ErrorText,onErrorTextClick }:ChatBubbleProps) => {
console.log({ message, isLastMessage,isUserMessage,isLoading,isError,cardBody,feedbackOptions,ErrorText,onErrorTextClick });
return <Box maxWidth="240px"></Box>;
export type ChatBubbleProps = {
isLastMessage?: boolean;
isUserMessage?: boolean;
isLoading?: boolean;
isError?: boolean;
feedbackOptions?: Array<{ icon: React.ReactNode; onClick: () => void }>;
errorText?: string;
onErrorTextClick?: () => void;
children: React.ReactNode | string;
avatarIcon?: React.ReactNode;
};
const ChatBubble = ({
isLastMessage,
isUserMessage,
isLoading,
isError,
feedbackOptions,
errorText,
onErrorTextClick,
children,
avatarIcon,
}: ChatBubbleProps): React.ReactElement => {
console.log({
isLastMessage,
isUserMessage,
isLoading,
isError,
feedbackOptions,
errorText,
onErrorTextClick,
children,
avatarIcon,
});
const childrenToRender = (): React.ReactElement => {
if (typeof children === 'string') {
return (
<Text color="surface.text.gray.normal" weight="regular" variant="body" size="medium">
{children}
</Text>
);
}
return children;
};
return (
<UserMessageBubble
isError={isError}
onErrorTextClick={onErrorTextClick}
isLastMessage={isLastMessage}
isUserMessage={isUserMessage}
errorText={errorText}
children={childrenToRender()}
/>
);
};



export { ChatBubble };
export { ChatBubble };
68 changes: 68 additions & 0 deletions packages/blade/src/components/ChatBubble/UserMessageBubble.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React from 'react';
import BaseBox from '~components/Box/BaseBox';
import { AlertCircleIcon } from '~components/Icons';
import { Text } from '~components/Typography';

const UserMessageBubble = ({
children,
isError,
onErrorTextClick,
isLastMessage,
isUserMessage,
errorText = 'Message not sent. Tap to retry.',
}: {
children: React.ReactNode | string;
isError?: boolean;
onErrorTextClick?: () => void;
isLastMessage?: boolean;
isUserMessage?: boolean;
errorText?: string;
}): React.ReactElement => {
return (
<BaseBox
display="flex"
gap="10px"
flexDirection="column"
onClick={isError ? onErrorTextClick : () => {}}
cursor={isError ? 'pointer' : 'default'}
>
<BaseBox
maxWidth="240px"
backgroundColor={
isError ? 'feedback.background.negative.subtle' : 'surface.background.primary.subtle'
}
padding="spacing.4"
borderTopLeftRadius="large"
borderTopRightRadius="large"
borderBottomLeftRadius="large"
borderBottomRightRadius={isLastMessage && isUserMessage ? 'none' : 'large'}
width="fit-content"
height="auto"
word-break="break-word"
>
{children}
</BaseBox>
{isError && (
<BaseBox
maxWidth="240px"
display="flex"
justifyContent="center"
alignItems="center"
gap="4px"
>
<AlertCircleIcon size="small" color="feedback.icon.negative.intense" />
<Text
color="feedback.text.negative.intense"
weight="regular"
variant="caption"
size="medium"
>
{errorText}
</Text>
</BaseBox>
)}
</BaseBox>
);
};

export { UserMessageBubble };
42 changes: 29 additions & 13 deletions packages/blade/src/components/ChatBubble/_decision.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,38 +18,54 @@ This will be our main component that will be used to render the chat bubble.

| Prop | Type | Default | Required | Description |
| ------------- | --------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------- |
| message | String | Default | No | The message that will be displayed in the chat bubble |
| isLastMessage | Boolean | false | No | If the message is the last message in the chat bubble , if this prop is enabled we will add decoration like tail in messageBubble |
| isUserMessage | Boolean | false | No | If the message is from the user, we will add a different styles to the chat bubble |
| isLoading | Boolean | false | No | If the message is loading, we will add a loading animation to the chat bubble |
| isError | Boolean | false | No | If the message is an error, we will add a different style to the chat bubble |
| ErrorText | String | null | No | If the message is an error, we will show the error message in the chat bubble |
| onErrorClick | Function | null | No | this callback will be called when ever you click error bubble with Error message |
| cardBody | ReactNode | null | No | If their is no message and isLoading is false, we will render the card body in the chat bubble|
| onErrorClick | Function | null | No | callback to be called onErrorClick |
| feedbackOptions | Array<{icon: ReactNode, onClick: Function}> | null | No | if this is passed as an array, we will show feedbacOptions, otherwise not |
| children | ReactNode | string | null | yes | The children that will be rendered inside the chat bubble. can be react node or a string |
| avatarIcon | ReactNode | null | No | it will be an Icon that will be rendered inside avatar |
```tsx
type ChatBubbleProps = {
message?: string;
isLastMessage?: boolean;
isUserMessage?: boolean;
isLoading?: boolean;
isError?: boolean;
cardBody?: ReactNode;
isError?: boolean;
feedbackOptions?: Array<{icon: ReactNode, onClick: Function}>;
ErrorText?: string;
onErrorClick?: Function;
children?: ReactNode | string;
avatarIcon?: ReactNode;
}
```
## API
```tsx
// with message
<ChatBubble message="Hello" isLastMessage isUserMessage />
// with card body
<ChatBubble isLastMessage cardBody={<CustomComponent/>} />
// with loading
<ChatBubble isLoading />

// for animation
<Move>
<ChatBubble>Demo Text</ChatBubble>
</Move>

// with card
<ChatBubble><Card></Card></ChatBubble>

//Feedback Options
<ChatBubble feedbackOptions={[{icon: <Icon />, onClick: () => {},}]}>
<Text> Demo Text</Text>
<ChipGroup></ChipGroup>
</ChatBubble>

<ChatBubble><Markdown> Demo Text </Markdown></ChatBubble>
<ChatBubble trailing={} end><Markdown> Demo Text </Markdown></ChatBubble>

````


## Open Questions
- In case of Error what should we provide an trailing element for showing error message?
- should we have validation state for chat bubble?
- should their be an animation in case of error?
- do we really need feedback options?
- should we add an prop to disable the animation?
1 change: 1 addition & 0 deletions packages/blade/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export * from './ButtonGroup';
export * from './Card';
export * from './Carousel';
export * from './Checkbox';
export * from './ChatBubble';
export * from './Chip';
export * from './Collapsible';
export * from './Counter';
Expand Down

0 comments on commit 3d4e02a

Please sign in to comment.