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

feat: improve chatbot integration + css fixes #2872

Merged
merged 7 commits into from
Dec 4, 2024
1 change: 1 addition & 0 deletions apps/backoffice-v2/src/common/env/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,5 @@ export const EnvSchema = z.object({
return new RegExp(value);
}, z.custom<RegExp>(value => value instanceof RegExp).optional()),
VITE_SAOLA_API_KEY: z.string().optional(),
VITE_BOTPRESS_CLIENT_ID: z.string().default('8f29c89d-ec0e-494d-b18d-6c3590b28be6'),
tomer-shvadron marked this conversation as resolved.
Show resolved Hide resolved
});
75 changes: 65 additions & 10 deletions apps/backoffice-v2/src/domains/chat/chatbot-opengpt.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,93 @@
import { getClient, Webchat, WebchatProvider } from '@botpress/webchat';
import { getClient, Webchat, WebchatProvider, WebchatClient } from '@botpress/webchat';
import { buildTheme } from '@botpress/webchat-generator';
import { useEffect } from 'react';
import { useCallback, useEffect } from 'react';
import { useAuthenticatedUserQuery } from '../../domains/auth/hooks/queries/useAuthenticatedUserQuery/useAuthenticatedUserQuery';
import { useCurrentCaseQuery } from '../../pages/Entity/hooks/useCurrentCaseQuery/useCurrentCaseQuery';
import { useLocation } from 'react-router-dom';

// declare const themeNames: readonly ["prism", "galaxy", "dusk", "eggplant", "dawn", "midnight"];
const { theme, style } = buildTheme({
themeName: 'galaxy',
themeColor: 'blue',
});

const clientId = '8f29c89d-ec0e-494d-b18d-6c3590b28be6';

const Chatbot = ({
isWebchatOpen,
toggleIsWebchatOpen,
client,
setClient,
shanegrouber marked this conversation as resolved.
Show resolved Hide resolved
chatbotClientId,
}: {
isWebchatOpen: boolean;
toggleIsWebchatOpen: () => void;
client: WebchatClient | null;
setClient: (client: WebchatClient) => void;
chatbotClientId: string;
}) => {
const client = getClient({ clientId });
const { data: session } = useAuthenticatedUserQuery();
const { data: currentCase } = useCurrentCaseQuery();
const { pathname } = useLocation();

shanegrouber marked this conversation as resolved.
Show resolved Hide resolved
const sendCaseData = useCallback(
async (caseId: string, newClient?: WebchatClient) => {
if (!currentCase) return;

const clientToUse = newClient || client;

shanegrouber marked this conversation as resolved.
Show resolved Hide resolved
try {
const currentCaseData = {
...currentCase.context,
caseId,
};
await clientToUse?.sendEvent({
type: 'case-data',
data: currentCaseData,
});
shanegrouber marked this conversation as resolved.
Show resolved Hide resolved
} catch (error) {
console.error('Failed to send case data:', error);
}
},
[currentCase, client],
);

useEffect(() => {
if (session?.user) {
const { firstName, lastName, email } = session.user;
void client.updateUser({
if (client || !chatbotClientId || !session?.user) return;

const { firstName, lastName, email } = session.user;
const newClient = getClient({ clientId: chatbotClientId });
setClient(newClient);

// newClient.on('*', (ev: any) => {
// console.log('Event: ', ev);
shanegrouber marked this conversation as resolved.
Show resolved Hide resolved
// });

newClient.on('conversation', (ev: any) => {
// new conversation created
void newClient.updateUser({
data: {
firstName,
lastName,
email,
},
});
}
}, [session, client]);
const caseId = pathname.split('/')[pathname.split('/').length - 1];
setTimeout(() => {
void sendCaseData(caseId || '', newClient);
}, 500);
});
tomer-shvadron marked this conversation as resolved.
Show resolved Hide resolved
shanegrouber marked this conversation as resolved.
Show resolved Hide resolved
}, [session, client, setClient, sendCaseData, pathname, chatbotClientId]);

useEffect(() => {
console.log('pathname changed to: ', pathname);

shanegrouber marked this conversation as resolved.
Show resolved Hide resolved
const caseId = pathname.split('/')[pathname.split('/').length - 1];

if (caseId) void sendCaseData(caseId);
}, [pathname, sendCaseData]);
shanegrouber marked this conversation as resolved.
Show resolved Hide resolved

if (!client) {
return null;
}

return (
<div>
Expand Down
1 change: 1 addition & 0 deletions apps/backoffice-v2/src/domains/customer/fetchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const CustomerSchema = z.object({
language: z.union([z.string(), z.null()]).optional(),
features: z
.object({
chatbot: z.object({ isEnabled: z.boolean().default(false), clientId: z.string().optional() }),
tomer-shvadron marked this conversation as resolved.
Show resolved Hide resolved
createBusinessReport: z
.object({ enabled: z.boolean().default(false), options: createBusinessReportOptions })
.optional(),
Expand Down
26 changes: 24 additions & 2 deletions apps/backoffice-v2/src/pages/Root/Root.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { ServerDownLayout } from './ServerDown.layout';
import { useCustomerQuery } from '@/domains/customer/hooks/queries/useCustomerQuery/useCustomerQuery';
import { FullScreenLoader } from '@/common/components/molecules/FullScreenLoader/FullScreenLoader';
import Chatbot from '@/domains/chat/chatbot-opengpt';
import { WebchatClient } from '@botpress/webchat';
import { RenderChildrenInIFrame } from '@/common/components/organisms/RenderChildrenInIFrame/RenderChildrenInIFrame';
import { ctw } from '@/common/utils/ctw/ctw';
import { env } from '@/common/env/env';

const ReactQueryDevtools = lazy(() =>
process.env.NODE_ENV !== 'production'
Expand All @@ -16,6 +20,7 @@ const ReactQueryDevtools = lazy(() =>

const ChatbotLayout: FunctionComponent = () => {
const { data: customer, isLoading: isLoadingCustomer } = useCustomerQuery();
const [client, setClient] = useState<WebchatClient | null>(null);
const [isWebchatOpen, setIsWebchatOpen] = useState(false);
const toggleIsWebchatOpen = () => {
setIsWebchatOpen(prevState => !prevState);
Expand All @@ -25,11 +30,28 @@ const ChatbotLayout: FunctionComponent = () => {
return <FullScreenLoader />;
}

if (!customer?.config?.isChatbotEnabled) {
if (!customer?.features?.chatbot?.isEnabled) {
tomer-shvadron marked this conversation as resolved.
Show resolved Hide resolved
return null;
}

return <Chatbot isWebchatOpen={isWebchatOpen} toggleIsWebchatOpen={toggleIsWebchatOpen} />;
const chatbotClientId = customer?.features?.chatbot?.clientId || env.VITE_BOTPRESS_CLIENT_ID;

return (
<RenderChildrenInIFrame
className={ctw('fixed bottom-right-0', {
'h-[700px] w-[400px]': isWebchatOpen,
'd-[80px]': !isWebchatOpen,
})}
tomer-shvadron marked this conversation as resolved.
Show resolved Hide resolved
>
<Chatbot
isWebchatOpen={isWebchatOpen}
toggleIsWebchatOpen={toggleIsWebchatOpen}
client={client}
setClient={setClient}
chatbotClientId={chatbotClientId}
/>
</RenderChildrenInIFrame>
);
};

export const Root: FunctionComponent = () => {
Expand Down
Loading