Chat
Overview
The Chat component is a core UI component of the Shopping Assistant SDK that renders the complete chat interface, including conversation messages, initial prompts, loading states, and message rendering. It provides a fully functional chat experience with support for user messages, AI responses, product displays, and customizable styling.
Usage
// importing component
import { Chat } from "@unbxd-ui/react-shopping-assistant-components";
Code Example
import { UnbxdShoppingAssistantWrapper } from "@unbxd-ui/react-shopping-assistant-hooks";
import { Chat } from "@unbxd-ui/react-shopping-assistant-components";
function ShoppingAssistantApp() {
return (
<UnbxdShoppingAssistantWrapper
siteKey="YOUR_SITE_KEY"
apiKey="YOUR_API_KEY"
storageType="LOCALSTORAGE"
>
<div className="chat-container">
<Chat />
</div>
</UnbxdShoppingAssistantWrapper>
);
}
⚠️
Note:
The Chat component must be used within the UnbxdShoppingAssistantWrapper to ensure that the component and the shopping assistant functionality work properly.
Props
- A custom component to display an initial welcome message when the chat loads.
- This component appears above the chat messages and initial prompts.
- Default Value:
const InitialMessageComponent = () => {
return (
<div className="initial-message-component">
👋 Hi there! I'm your Furniture Shopping Assistant, ready to help you find exactly what you're looking for. ✨ — What would you like to shop for today?
<br />
<br />
Ask me anything, or try one of these to get started:
</div>
);
};
- A custom component that displays clickable prompt suggestions to help users get started with the shopping assistant.
- Shows predefined example questions that users can click to automatically ask the AI agent.
- Useful for onboarding new users and showcasing the types of queries the assistant can handle.
- Each prompt is interactive and will trigger a conversation when clicked.
- Default Value:
const InitialPrompts = (props: InitialPromptsProps) => {
const {
onPromptClick = defaultInitialPromptsProps.onPromptClick,
} = props;
const prompts = [
"Help me find a dining table for 6 people",
"What's trending in bedroom furniture?",
"I need outdoor patio furniture recommendations",
"Show me modern sofas under $1000",
"Find storage solutions for small spaces",
"Suggest ergonomic office chairs"
]
const { askAgent } = useShoppingAssistant();
const handlePromptClick = (prompt: string) => {
onPromptClick && onPromptClick(prompt);
askAgent(prompt);
};
const renderInitialPrompts = () => {
if (!prompts) return null;
return prompts.map((prompt: string) => <InitialPrompt prompt={prompt} onPromptClick={() => handlePromptClick(prompt)} key={prompt} />);
};
return (
<div className="initial-prompts-container">
<div className="initial-prompts-label">{""}</div>
<div className="initial-prompts-wrapper">{renderInitialPrompts()}</div>
</div>
);
};
- A custom component to display while the AI is processing and generating responses.
- Shows during API calls and conversation loading states.
- Default Value:
const LoadingComponent = () => {
return <div className="loading-component">Awaiting response...</div>;
};
- A custom icon component to display next to user messages.
- Helps distinguish user messages in the conversation.
- Default Value:
const UserIconComponent = () => {
return <>Me</>;
};
- A custom icon component to display next to AI assistant messages.
- Helps distinguish AI responses in the conversation.
- Default Value:
const AIIconComponent = () => {
return <>AI</>;
};
- A custom component for rendering user messages in the chat.
- Receives
message
andUserIconComponent
as props. - Default Value:
const UserMessage = ({ message, UserIconComponent }: UserMessageProps) => {
return <div className="user-message-container">
<div className="user-message-text">
{message}
</div>
<div className="user-message-icon-wrapper">
{UserIconComponent && <UserIconComponent />}
</div>
</div>;
};
- A custom component for rendering AI assistant messages in the chat.
- Receives
response
,AIIconComponent
, and other props for products and filters. - Default Value: Built-in AIMessage component with product display support.
const AIMessage = ({ response, AIIconComponent, viewMore = false, viewMoreLimit = 5, ProductComponent, FiltersComponent = Filters }: AIMessageProps) => {
const { message, products = [], filters = [] } = response;
const handleFilterClick = (field: string, option: string) => {
// console.log(field, option);
};
const renderFilters = () => {
return filters.map((filter: { [key: string]: any }) => {
const { field, options } = filter;
return <FiltersComponent key={field} field={field} options={options} onFilterClick={handleFilterClick} viewMore={viewMore} viewMoreLimit={viewMoreLimit} />;
});
};
return (
<div className="ai-message-container">
<div className="ai-message-icon-wrapper">
{AIIconComponent && <AIIconComponent />}
</div>
<div className="ai-message-wrapper">
{message && <div className="ai-message-text">{message}</div>}
{filters.length > 0 && renderFilters()}
{products.length > 0 && <ProductCarousel label="Recommended Products:" products={products} ProductComponent={ProductComponent} />}
</div>
</div>
);
};
- A custom component for displaying all product recommendations from the AI assistant.
- Renders products returned by the AI in response to user queries.
- Includes navigation controls for browsing through multiple products.
- Default Value:
const ProductCarousel = (props: ProductCarouselProps) => {
const {
products = defaultProductCarouselProps.products,
} = props;
const [currentIndex, setCurrentIndex] = useState(0);
const productRefs = useRef<(HTMLDivElement | null)[]>([]);
const renderProducts = () => {
return products.map((product: { [key: string]: any }, idx: number) => (
<div key={idx} ref={(el) => (productRefs.current[idx] = el)} style={{ display: "inline-block" }}>
<ProductComponent product={product} />
</div>
));
};
const scrollToProduct = (index: number) => {
const ref = productRefs.current[index];
if (ref) {
ref.scrollIntoView({ behavior: "smooth", inline: "center", block: "nearest" });
}
};
const handlePrev = () => {
if (currentIndex > 0) {
const newIndex = currentIndex - 1;
setCurrentIndex(newIndex);
scrollToProduct(newIndex);
}
};
const handleNext = () => {
if (currentIndex < products.length - 1) {
const newIndex = currentIndex + 1;
setCurrentIndex(newIndex);
scrollToProduct(newIndex);
}
};
return (
<div className="product-carousel-container">
<div className="product-carousel-header">
<div className="product-carousel-label">{'Recommended Products:'}</div>
<div className="navigation-buttons">
<button className="prev-button" onClick={handlePrev} disabled={currentIndex === 0}>
<ArrowLeftIcon />
</button>
<button className="next-button" onClick={handleNext} disabled={currentIndex === products.length - 1}>
<ArrowRightIcon />
</button>
</div>
</div>
<div className="product-carousel-products" style={{ overflowX: "auto", width: "100%" }}>
{renderProducts()}
</div>
</div>
);
};
- A custom component for rendering filter options in AI responses.
- Handles filter display and user interaction with search filters.
- Default Value:
const Filters = ({ field, options, onFilterClick, viewMore = false, viewMoreLimit = 5 }: FiltersProps) => {
const { askAgent } = useShoppingAssistant();
const [filtersShown, setFiltersShown] = useState(options.slice(0, viewMore ? viewMoreLimit : options.length));
const handleFilterClick = (option: string) => {
askAgent(option, { field, options: [option] });
onFilterClick && onFilterClick(field, option);
};
const handleViewClick = () => {
setFiltersShown(filtersShown.length === options.length ? options.slice(0, viewMoreLimit) : options);
}
const renderFilters = () => {
return filtersShown.map((option: string) => (
<div
className={`filter-option`}
key={option}
onClick={() => handleFilterClick(option)}
>
{option}
</div>
));
}
const renderViewText = () => {
const viewText = filtersShown.length === options.length ? "View Less" : "View More";
if (options.length <= viewMoreLimit) return null;
return <div className="view-more-container" onClick={handleViewClick}>{viewText}</div>
}
return <div className="filters-container">
<div className="filter-label">{field}</div>
<div className="filter-option-wrapper">
{renderFilters()}
{viewMore && renderViewText()}
</div>
</div>;
};