Skip to content

Commit

Permalink
feat: adjust chat to work in embedded mode as well (COR-3851) (#293)
Browse files Browse the repository at this point in the history
  • Loading branch information
gillyb authored Nov 11, 2024
1 parent 5458e00 commit cdcaaf9
Show file tree
Hide file tree
Showing 12 changed files with 87 additions and 48 deletions.
36 changes: 36 additions & 0 deletions apps/documentation/src/components/ChatScript/embedded.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Head from 'next/head';

export const ChatEmbedded = ({ projectID }: { projectID: string }) => {
if (!projectID) {
return null;
}

const script = `
(function (d, t) {
const v = d.createElement(t);
const s = d.getElementsByTagName(t)[0];
v.onload = function () {
window.voiceflow.chat.load({
verify: { projectID: "${projectID}" },
assistant: {
stylesheet: '../../bundle/style.css',
}
});
};
v.src = '../../bundle/bundle.mjs';
v.type = 'text/javascript';
s.parentNode.insertBefore(v, s);
})(document, 'script');
`;

return (
<Head>
<script
type="text/javascript"
dangerouslySetInnerHTML={{
__html: script,
}}
/>
</Head>
);
};
4 changes: 3 additions & 1 deletion apps/documentation/src/components/ChatScript/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Head from 'next/head';
export const ChatScript = ({ projectID }: { projectID: string }) => {

export const ChatScript = ({ projectID, embedded = false }: { projectID: string; embedded?: boolean }) => {
if (!projectID) {
return null;
}
Expand All @@ -14,6 +15,7 @@ export const ChatScript = ({ projectID }: { projectID: string }) => {
assistant: {
stylesheet: '../../bundle/style.css',
}
${embedded ? ', render: { mode: "embedded", target: document.getElementById("chat_embed") }' : ''}
});
};
v.src = '../../bundle/bundle.mjs';
Expand Down
20 changes: 15 additions & 5 deletions apps/documentation/src/pages/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,24 @@ import 'regenerator-runtime/runtime';
import { ChatScript } from '@/components/ChatScript';

export const getServerSideProps = async (context: any) => ({
props: { projectID: context.query.projectID }, // will be passed to the page component as props
// will be passed to the page component as props
props: {
projectID: context.query.projectID,
embedded: !!context.query.embed,
},
});

export default function ChatPage(props: any) {
return (
<div style={{ position: 'relative' }}>
You can switch projects by changing the URL `projectID=...`
{props.projectID && <ChatScript projectID={props.projectID} />}
</div>
<>
<div style={{ position: 'relative' }}>
You can switch projects by changing the URL `projectID=...`
{props.projectID && <ChatScript {...props} />}
</div>

<div style={{ height: '100vh', padding: '30px' }}>
<div style={{ width: '600px', height: '100%', margin: '0 auto' }} id="chat_embed"></div>
</div>
</>
);
}
2 changes: 1 addition & 1 deletion apps/documentation/src/scripts/import-chat.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ yarn install
yarn build

# Copy bundled files
mkdir ../../apps/documentation/public/bundle
mkdir -p ../../apps/documentation/public/bundle
cp ./dist/bundle.mjs ../../apps/documentation/public/bundle/bundle.mjs
cp ./dist/style.css ../../apps/documentation/public/bundle/style.css

Expand Down
13 changes: 8 additions & 5 deletions packages/chat/src/components/NewChat/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ export interface INewChat
* A callback that is executed when the conversation ends.
*/
onEnd?: React.MouseEventHandler<HTMLButtonElement>;

hasEnded: boolean;

/**
* A callback to start a new conversation.
*/
onStart?: (() => Promise<void>) | undefined;
}

export const NewChat: React.FC<INewChat> = ({
Expand All @@ -56,7 +63,6 @@ export const NewChat: React.FC<INewChat> = ({
description,
avatar,
hasEnded,
onSend,
onStart,
onMinimize,
onEnd,
Expand Down Expand Up @@ -112,17 +118,14 @@ export const NewChat: React.FC<INewChat> = ({
<NewFooter
buttons={buttons}
showPoweredBy={showPoweredBy}
onSend={onSend}
onStart={onStart}
hasEnded={hasEnded}
extraLinkText={extraLinkText}
extraLinkUrl={extraLinkUrl}
messageInputProps={{ ...messageInputProps, disableSend: state.indicator }}
scrollableAreaRef={scrollableAreaRef}
/>
<Prompt
visible={hasAlert}
accept={{ label: 'Start new chat', onClick: chain(onEnd, handleResume) }}
accept={{ label: 'Start new chat', onClick: chain(onEnd, handleResume, onStart) }}
cancel={{ label: 'Cancel', onClick: handleResume }}
/>
</div>
Expand Down
7 changes: 1 addition & 6 deletions packages/chat/src/components/NewFooter/NewFooter.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,29 +67,24 @@ export const Everything: Story = {
args: {
buttons,
showPoweredBy: true,
hasEnded: false,
},
};

export const WithScrollButton: Story = {
...Default,
args: {
hasEnded: false,
},
args: {},
};

export const WithButtons: Story = {
...Default,
args: {
buttons,
hasEnded: false,
},
};

export const WithPoweredBy: Story = {
...Default,
args: {
showPoweredBy: true,
hasEnded: false,
},
};
20 changes: 2 additions & 18 deletions packages/chat/src/components/NewFooter/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,9 @@ export interface INewFooter {
messageInputProps: IMessageInput;
extraLinkText?: string;
extraLinkUrl?: string;
hasEnded: boolean;
disableSend?: boolean;
scrollableAreaRef: RefObject<HTMLDivElement>;

/**
* A callback to start a new conversation.
*/
onStart?: (() => Promise<void>) | undefined;

/**
* A callback to submit a user response.
*/
Expand All @@ -47,8 +41,6 @@ export const NewFooter: React.FC<INewFooter> = ({
messageInputProps,
extraLinkText,
extraLinkUrl,
hasEnded,
onStart,
scrollableAreaRef,
}) => {
const showExtraLink = extraLinkText && extraLinkUrl;
Expand All @@ -65,16 +57,8 @@ export const NewFooter: React.FC<INewFooter> = ({
)}

<div className={messageContainer()}>
{hasEnded ? (
<Button onClick={onStart} large>
Start New Chat
</Button>
) : (
<>
<ScrollToBottom scrollableAreaRef={scrollableAreaRef} />
<MessageInput {...messageInputProps} />
</>
)}
<ScrollToBottom scrollableAreaRef={scrollableAreaRef} />
<MessageInput {...messageInputProps} />
<div className={footerLinksContainer}>
{showPoweredBy && (
<div>
Expand Down
7 changes: 6 additions & 1 deletion packages/chat/src/contexts/RuntimeContext/useRuntimeState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,15 @@ export const useRuntimeState = ({ assistant, config, traceHandlers }: Settings)
}
};

const close = () => {
const stopChat = () => {
stopAudios();

broadcast({ type: BroadcastType.CLOSE });
saveSession(assistant.persistence, config.verify.projectID, sessionRef.current);
};

const close = () => {
stopChat();
setOpen(false);
};

Expand Down Expand Up @@ -222,6 +226,7 @@ export const useRuntimeState = ({ assistant, config, traceHandlers }: Settings)
open,
interact,
close,
stopChat,
addTurn,
feedback: runtime.saveFeedback,
setStatus,
Expand Down
4 changes: 2 additions & 2 deletions packages/chat/src/views/ChatWidget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { PALETTE } from '@/styles/colors.css';
import { useResolveAssistantStyleSheet } from '@/utils/stylesheet';
import { ChatWindow } from '@/views/ChatWindow';

import { chatContainer, chatWindow, LAUNCHER_MARGIN, launcherContainer, widgetContainer } from './styles.css';
import { chatContainer, LAUNCHER_MARGIN, launcherContainer, widgetContainer } from './styles.css';

interface ChatWidgetProps extends React.PropsWithChildren {
shadowRoot?: ShadowRoot;
Expand Down Expand Up @@ -83,7 +83,7 @@ export const ChatWidget: React.FC<ChatWidgetProps> = ({ shadowRoot, chatAPI, rea
: { [side]: position[side], bottom: position.bottom + LAUNCHER_SIZE + LAUNCHER_MARGIN, height: chatHeight }
}
>
<ChatWindow className={chatWindow} />
<ChatWindow />
</div>
</div>
);
Expand Down
4 changes: 0 additions & 4 deletions packages/chat/src/views/ChatWidget/styles.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@ export const chatContainer = style({
},
});

export const chatWindow = style({
height: '100%',
});

export const launcherContainer = style({
pointerEvents: 'auto',
selectors: {
Expand Down
12 changes: 7 additions & 5 deletions packages/chat/src/views/ChatWindow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,23 @@ import { PALETTE } from '@/styles/colors.css';
// import type { UserTurnProps } from '@/types';
import { SessionStatus, TurnType } from '@/types';

import { chatWindow } from './styles.css';

export interface ChatWindowProps {
className?: string;
isMobile?: boolean;
}

export const ChatWindow: React.FC<ChatWindowProps> = ({ isMobile, className }) => {
export const ChatWindow: React.FC<ChatWindowProps> = ({ isMobile }) => {
const runtime = useContext(RuntimeStateAPIContext);
const state = useContext(RuntimeStateContext);
const { assistant, config } = runtime;
const palette = usePalette(assistant);

// emitters
const closeAndEnd = useCallback((): void => {
const restartChat = useCallback((): void => {
runtime.setStatus(SessionStatus.ENDED);
runtime.close();
runtime.stopChat();
}, []);

if (!palette) return null;
Expand All @@ -42,7 +44,7 @@ export const ChatWindow: React.FC<ChatWindowProps> = ({ isMobile, className }) =
// );

return (
<div style={assignInlineVars(PALETTE, { colors: palette })} className={className}>
<div style={assignInlineVars(PALETTE, { colors: palette })} className={chatWindow}>
<NewChat
title={assistant.title}
description={assistant.description}
Expand All @@ -53,7 +55,7 @@ export const ChatWindow: React.FC<ChatWindowProps> = ({ isMobile, className }) =
hasEnded={runtime.isStatus(SessionStatus.ENDED)}
isLoading={runtime.isStatus(SessionStatus.IDLE) && state.session.turns.length === 0 && config.autostart}
onStart={runtime.launch}
onEnd={closeAndEnd}
onEnd={restartChat}
onSend={runtime.reply}
onMinimize={runtime.close}
audioInterface={assistant.audioInterface}
Expand Down
6 changes: 6 additions & 0 deletions packages/chat/src/views/ChatWindow/styles.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { style } from '@vanilla-extract/css';

export const chatWindow = style({
height: '100%',
maxHeight: '800px',
});

0 comments on commit cdcaaf9

Please sign in to comment.