Skip to content

Commit 899b695

Browse files
committed
hotfix: chatwidget
1 parent 3ad04da commit 899b695

2 files changed

Lines changed: 147 additions & 11 deletions

File tree

demo/src/App.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,22 @@ import {
1313
StatusIncidentDetail,
1414
ContactFormRenderer,
1515
Blog,
16+
ChatWidget,
1617
useWishes,
1718
useVote,
1819
useContactForm,
1920
type Wish,
2021
type StatusData,
2122
type StatusIncident,
23+
type ChatSource,
2224
} from '@appgram/react'
2325

2426
// Configuration - Update these values to test with your Appgram project
2527
const CONFIG = {
2628
projectId: '8be98cbb-308e-4aaa-8201-4fa17d5f2116', // Replace with your project ID
2729
orgSlug: 'acme-corp', // Replace with your org slug
2830
projectSlug: 'my-app', // Replace with your project slug
31+
apiUrl: 'https://api.appgram.dev', // API URL for help center chat
2932
// apiUrl: 'http://localhost:3001', // Uncomment for local API testing
3033
}
3134

@@ -697,6 +700,34 @@ export function App() {
697700
</p>
698701
</div>
699702
</footer>
703+
704+
{/* Chat Widget */}
705+
<ChatWidget
706+
projectId={CONFIG.projectId}
707+
apiUrl={CONFIG.apiUrl}
708+
agentName="Help Bot"
709+
greeting="Hi there!"
710+
subtitle="How can I help you today?"
711+
accentColor="#0EA5E9"
712+
options={[
713+
{ label: 'I need help getting started' },
714+
{ label: 'I have a billing question' },
715+
{ label: 'Report a bug' },
716+
]}
717+
onArticleClick={(slug: string, source: ChatSource) => {
718+
console.log('Article clicked:', slug, source)
719+
// Example: navigate to help article
720+
if (source.flow_slug) {
721+
console.log(`Would navigate to: /help/${source.flow_slug}/${slug}`)
722+
} else {
723+
console.log(`Would navigate to: /help/articles/${slug}`)
724+
}
725+
}}
726+
onSupportClick={() => {
727+
console.log('Support clicked')
728+
setActiveTab('support')
729+
}}
730+
/>
700731
</div>
701732
</AppgramProvider>
702733
)

src/components/chat/ChatWidget.tsx

Lines changed: 116 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ export interface ChatSource {
142142
similarity: number
143143
flow_slug?: string
144144
flow_id?: string
145+
/** Source type - determines routing behavior */
146+
type?: 'help_article' | 'blog_post'
145147
}
146148

147149
interface ChatMessage {
@@ -357,10 +359,17 @@ export function ChatWidget({
357359
const [inputValue, setInputValue] = useState('')
358360
const [messages, setMessages] = useState<ChatMessage[]>([])
359361
const [isLoading, setIsLoading] = useState(false)
360-
const messagesEndRef = useRef<HTMLDivElement>(null)
362+
const chatContainerRef = useRef<HTMLDivElement>(null)
361363

362364
const scrollToBottom = () => {
363-
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
365+
if (chatContainerRef.current) {
366+
// Use requestAnimationFrame for smoother scroll after content renders
367+
requestAnimationFrame(() => {
368+
if (chatContainerRef.current) {
369+
chatContainerRef.current.scrollTop = chatContainerRef.current.scrollHeight
370+
}
371+
})
372+
}
364373
}
365374

366375
useEffect(() => {
@@ -528,18 +537,24 @@ export function ChatWidget({
528537
{/* Chat Panel */}
529538
<div
530539
className={cn(
531-
"w-[calc(100vw-2rem)] sm:w-[380px] md:w-[400px] rounded-2xl shadow-2xl flex flex-col overflow-hidden",
540+
"rounded-2xl shadow-2xl flex flex-col overflow-hidden",
532541
"transition-all duration-300 ease-out origin-bottom-right",
533542
isOpen ? "opacity-100 scale-100" : "h-0 opacity-0 scale-95 pointer-events-none"
534543
)}
535544
style={{
536545
backgroundColor: resolvedColors.chatBackground,
537546
border: `1px solid ${resolvedColors.border}`,
538-
// Use dvh (dynamic viewport height) for mobile keyboard support, with vh fallback
547+
// Fixed width on mobile, responsive on larger screens
548+
width: 'min(calc(100vw - 2rem), 400px)',
549+
maxWidth: '400px',
550+
// Use dvh (dynamic viewport height) for mobile keyboard support
539551
height: isOpen ? 'min(560px, calc(100dvh - 6rem))' : '0',
540552
fontSize: resolvedFontSize,
541553
// Prevent touch-based zooming/panning on the widget itself
542554
touchAction: 'manipulation',
555+
// Prevent content from causing overflow
556+
wordBreak: 'break-word',
557+
overflowWrap: 'break-word',
543558
}}
544559
>
545560
{/* Header */}
@@ -591,8 +606,13 @@ export function ChatWidget({
591606

592607
{/* Chat Area */}
593608
<div
594-
className="flex-1 overflow-y-auto p-4 space-y-5"
595-
style={{ backgroundColor: resolvedColors.chatBackground }}
609+
ref={chatContainerRef}
610+
className="flex-1 overflow-y-auto overflow-x-hidden p-4 space-y-5"
611+
style={{
612+
backgroundColor: resolvedColors.chatBackground,
613+
// Contain content to prevent horizontal overflow
614+
overscrollBehavior: 'contain',
615+
}}
596616
>
597617
{!showChat ? (
598618
<>
@@ -685,13 +705,99 @@ export function ChatWidget({
685705
) : (
686706
<div className="max-w-[95%]">
687707
<div
688-
className="prose prose-sm max-w-none"
708+
className="appgram-chat-markdown"
689709
style={{
690710
color: resolvedColors.foreground,
691-
'--tw-prose-links': accentColor,
692-
} as React.CSSProperties}
711+
fontSize: 'inherit',
712+
lineHeight: '1.6',
713+
}}
693714
>
694-
<ReactMarkdown>{message.content}</ReactMarkdown>
715+
<ReactMarkdown
716+
components={{
717+
p: ({ children }) => (
718+
<p style={{ margin: '0 0 0.75em 0' }}>{children}</p>
719+
),
720+
a: ({ href, children }) => (
721+
<a
722+
href={href}
723+
target="_blank"
724+
rel="noopener noreferrer"
725+
style={{ color: accentColor, textDecoration: 'underline' }}
726+
>
727+
{children}
728+
</a>
729+
),
730+
strong: ({ children }) => (
731+
<strong style={{ fontWeight: 600 }}>{children}</strong>
732+
),
733+
em: ({ children }) => (
734+
<em style={{ fontStyle: 'italic' }}>{children}</em>
735+
),
736+
ul: ({ children }) => (
737+
<ul style={{ margin: '0.5em 0', paddingLeft: '1.25em', listStyleType: 'disc' }}>
738+
{children}
739+
</ul>
740+
),
741+
ol: ({ children }) => (
742+
<ol style={{ margin: '0.5em 0', paddingLeft: '1.25em', listStyleType: 'decimal' }}>
743+
{children}
744+
</ol>
745+
),
746+
li: ({ children }) => (
747+
<li style={{ margin: '0.25em 0' }}>{children}</li>
748+
),
749+
code: ({ children }) => (
750+
<code
751+
style={{
752+
backgroundColor: resolvedColors.border,
753+
padding: '0.125em 0.375em',
754+
borderRadius: '4px',
755+
fontSize: '0.875em',
756+
fontFamily: 'monospace',
757+
}}
758+
>
759+
{children}
760+
</code>
761+
),
762+
pre: ({ children }) => (
763+
<pre
764+
style={{
765+
backgroundColor: resolvedColors.border,
766+
padding: '0.75em',
767+
borderRadius: '8px',
768+
overflow: 'auto',
769+
margin: '0.5em 0',
770+
fontSize: '0.875em',
771+
}}
772+
>
773+
{children}
774+
</pre>
775+
),
776+
blockquote: ({ children }) => (
777+
<blockquote
778+
style={{
779+
borderLeft: `3px solid ${accentColor}`,
780+
paddingLeft: '1em',
781+
margin: '0.5em 0',
782+
color: resolvedColors.mutedForeground,
783+
}}
784+
>
785+
{children}
786+
</blockquote>
787+
),
788+
h1: ({ children }) => (
789+
<h1 style={{ fontSize: '1.25em', fontWeight: 600, margin: '0.5em 0' }}>{children}</h1>
790+
),
791+
h2: ({ children }) => (
792+
<h2 style={{ fontSize: '1.125em', fontWeight: 600, margin: '0.5em 0' }}>{children}</h2>
793+
),
794+
h3: ({ children }) => (
795+
<h3 style={{ fontSize: '1em', fontWeight: 600, margin: '0.5em 0' }}>{children}</h3>
796+
),
797+
}}
798+
>
799+
{message.content}
800+
</ReactMarkdown>
695801
</div>
696802
{message.sources && message.sources.length > 0 && (
697803
<div
@@ -804,7 +910,6 @@ export function ChatWidget({
804910
</div>
805911
</div>
806912
)}
807-
<div ref={messagesEndRef} />
808913
</>
809914
)}
810915
</div>

0 commit comments

Comments
 (0)