Skip to content

Commit

Permalink
Merge branch 'illiar/feat/document-field-variant' into illiar/feat/co…
Browse files Browse the repository at this point in the history
…llection-flow-customization
  • Loading branch information
chesterkmr committed Sep 5, 2024
2 parents 8819b4a + f2d24c7 commit ad36d08
Show file tree
Hide file tree
Showing 17 changed files with 1,620 additions and 53 deletions.
8 changes: 7 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
{
"jest.jestCommandLine": "node_modules/.bin/jest"
"jest.jestCommandLine": "node_modules/.bin/jest",
"eslint.workingDirectories": [
"apps/backoffice-v2",
"apps/workflows-dashboard",
"packages/workflow-core",
"services/workflows-service"
]
}
113 changes: 113 additions & 0 deletions apps/backoffice-v2/src/domains/chat/chatbot-opengpt.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { Webchat, WebchatProvider, getClient } from '@botpress/webchat';
import { buildTheme } from '@botpress/webchat-generator';
import { useState, useEffect } from 'react';
import { useAuthenticatedUserQuery } from '../../domains/auth/hooks/queries/useAuthenticatedUserQuery/useAuthenticatedUserQuery';

// 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 = () => {
const client = getClient({ clientId });
const [isWebchatOpen, setIsWebchatOpen] = useState(false);
const { data: session } = useAuthenticatedUserQuery();

useEffect(() => {
if (session?.user) {
const { firstName, lastName, email } = session.user;
void client.updateUser({
data: {
firstName,
lastName,
email,
},
});
}
}, [session, client]);

const toggleWebchat = () => {
setIsWebchatOpen(prevState => !prevState);
};

return (
<div>
<style>{style}</style>
<WebchatProvider
theme={theme}
client={client}
configuration={{
botName: 'AI Analyst',
botAvatar: 'https://cdn.ballerine.io/logos/ballerine-logo.png',
botDescription: 'Your intelligent AI Analyst',
composerPlaceholder: 'Ask the AI Analyst anything...',
website: {
title: 'Visit AI Analyst',
link: 'https://ballerine.ai',
},
email: {
title: 'Contact Support',
link: 'mailto:support@ballerine.com',
},
privacyPolicy: {
title: 'Privacy Policy',
link: 'https://ballerine.com/privacy',
},
termsOfService: {
title: 'Terms of Service',
link: 'https://ballerine.com/terms',
},
}}
>
<button
onClick={toggleWebchat}
style={{
width: '60px',
height: '60px',
borderRadius: '50%',
background: 'none',
border: 'none',
cursor: 'pointer',
position: 'fixed',
bottom: '20px',
right: '20px',
zIndex: 1000,
padding: 0,
overflow: 'hidden',
}}
aria-label="Toggle AI Analyst chat"
>
<img
src="https://cdn.ballerine.io/logos/ballerine-logo.png"
alt="AI Analyst"
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
/>
</button>
{isWebchatOpen && (
<div
style={{
width: '400px',
height: '600px',
maxWidth: '90vw',
maxHeight: '90vh',
position: 'fixed',
bottom: '90px', // Increased to leave space for the open button
right: '20px',
zIndex: 999, // Decreased to ensure it's below the open button
boxShadow: '0 5px 40px rgba(0,0,0,0.16)',
borderRadius: '8px',
overflow: 'hidden',
}}
>
<Webchat />
</div>
)}
</WebchatProvider>
</div>
);
};

export default Chatbot;
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 @@ -19,6 +19,7 @@ const CustomerSchema = z.object({
hideCreateMerchantMonitoringButton: z.boolean().default(false),
isExample: z.boolean().default(false),
isDemo: z.boolean().default(false),
isChatbotEnabled: z.boolean().default(false),
})
.nullable()
.default({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ export const CaseCallToActionLegacy: FunctionComponent<ICaseCallToActionLegacyPr
size="wide"
variant="warning"
disabled={data?.disabled || isDisabled}
className={ctw({
'!bg-warning': !data?.disabled,
})}
>
{value}
</MotionButton>
Expand Down Expand Up @@ -132,7 +135,7 @@ export const CaseCallToActionLegacy: FunctionComponent<ICaseCallToActionLegacyPr
<DialogFooter>
<DialogClose asChild>
<Button
className={ctw(`gap-x-2`, {
className={ctw(`gap-x-2 !bg-foreground`, {
loading: isLoadingRevisionCase,
})}
disabled={isLoadingRevisionCase}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,9 @@ export const useKycBlock = ({
disabled={isDisabled}
size={'wide'}
variant={'success'}
className={ctw({
'!bg-success': !isDisabled,
})}
>
Approve
</MotionButton>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const SubmitSection = ({ uiSchema }: SubmitButtonProps) => {
<Label htmlFor="add_more_switch">Add more</Label>
</div>
{!norender && (
<Button type="submit" disabled={disabled}>
<Button className={'!bg-foreground'} type="submit" disabled={disabled}>
Add Case
</Button>
)}
Expand Down
20 changes: 19 additions & 1 deletion apps/backoffice-v2/src/pages/Root/Root.page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { FunctionComponent, lazy } from 'react';
import React, { FunctionComponent, lazy } from 'react';
import { Outlet } from 'react-router-dom';
import { Providers } from '../../common/components/templates/Providers/Providers';
import { ServerDownLayout } from './ServerDown.layout';
import { useCustomerQuery } from '@/domains/customer/hook/queries/useCustomerQuery/useCustomerQuery';
import { FullScreenLoader } from '@/common/components/molecules/FullScreenLoader/FullScreenLoader';
import Chatbot from '@/domains/chat/chatbot-opengpt';

const ReactQueryDevtools = lazy(() =>
process.env.NODE_ENV !== 'production'
Expand All @@ -11,12 +14,27 @@ const ReactQueryDevtools = lazy(() =>
: Promise.resolve({ default: () => null }),
);

const ChatbotLayout: FunctionComponent = () => {
const { data: customer, isLoading: isLoadingCustomer } = useCustomerQuery();

if (isLoadingCustomer) {
return <FullScreenLoader />;
}

if (!customer?.config?.isChatbotEnabled) {
return null;
}

return <Chatbot />;
};

export const Root: FunctionComponent = () => {
return (
<Providers>
<ServerDownLayout>
<Outlet />
</ServerDownLayout>
<ChatbotLayout />
{/*<Suspense>*/}
{/* <ReactQueryDevtools />*/}
{/*</Suspense>*/}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ export const DocumentField = (
message: response.message as string,
type: 'warning',
});

return;
}

Expand All @@ -159,7 +160,7 @@ export const DocumentField = (
);

const handleChange = useCallback(
(fileId: string) => {
(fileId: string, clear?: boolean) => {
//@ts-ignore
const destinationParser = new DocumentValueDestinationParser(definition.valueDestination);
const pathToDocumentsList = destinationParser.extractRootPath();
Expand Down Expand Up @@ -202,8 +203,13 @@ export const DocumentField = (
({} as Document['pages'][number]);

// Assigning file properties
if (clear) {
set(documentPage, pathToFileId!, undefined);
} else {
set(documentPage, pathToFileId!, fileId);
}

//@ts-ignore
set(documentPage, pathToFileId, fileId);
set(documentPage, 'fileName', file?.name);
set(documentPage, 'type', file?.type);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { useFileAssigner } from '@/components/organisms/UIRenderer/elements/JSON
import { useFileRepository } from '@/components/organisms/UIRenderer/elements/JSONForm/components/FileUploaderField/hooks/useFileRepository';
import { useFileUploading } from '@/components/organisms/UIRenderer/elements/JSONForm/components/FileUploaderField/hooks/useFileUploading';
import { DocumentUploadFieldProps } from '@/components/organisms/UIRenderer/elements/JSONForm/components/FileUploaderField/types';
import { Input } from '@ballerine/ui';
import { Button, Input } from '@ballerine/ui';
import { Upload, XCircle } from 'lucide-react';
import { useCallback, useRef } from 'react';

export const FileUploaderField = ({
Expand All @@ -18,10 +19,11 @@ export const FileUploaderField = ({
testId,
}: DocumentUploadFieldProps) => {
const { isUploading, uploadFile } = useFileUploading(_uploadFile);
const { file: registeredFile, registerFile } = useFileRepository(
fileStorage,
fileId || undefined,
);
const {
file: registeredFile,
registerFile,
removeFile,
} = useFileRepository(fileStorage, fileId || undefined);
const inputRef = useRef<HTMLInputElement>(null);
//@ts-ignore
useFileAssigner(inputRef, registeredFile);
Expand All @@ -41,16 +43,59 @@ export const FileUploaderField = ({
[uploadFile, registerFile, onChange],
);

const handdleContainerClick = useCallback(() => {
inputRef.current?.click();
}, [inputRef]);

const handleClear = useCallback(
(event: React.SyntheticEvent) => {
event.stopPropagation();

if (!registeredFile || !fileId || !inputRef.current) return;

inputRef.current.value = '';

removeFile(fileId);
onChange(fileId, true);
},
[fileId, inputRef, registeredFile, removeFile, onChange],
);

return (
<Input
data-testid={testId}
type="file"
placeholder={placeholder}
accept={acceptFileFormats}
disabled={disabled || isLoading || isUploading}
onChange={handleChange}
onBlur={onBlur}
ref={inputRef}
/>
<div
className="relative flex h-[56px] flex-row items-center gap-3 rounded-[16px] border bg-white px-4"
onClick={handdleContainerClick}
>
<div className="flex gap-3 text-[#007AFF]">
<Upload />
<span className="select-none whitespace-nowrap text-base font-bold">Choose file</span>
</div>
<span className="overflow-hidden text-ellipsis whitespace-nowrap text-sm">
{registeredFile ? registeredFile.name : 'No File Choosen'}
</span>
{registeredFile && (
<Button
variant="ghost"
size="icon"
className="top-[calc(50% - 14px)] absolute right-[-36px] h-[28px] w-[28px] rounded-full"
onClick={handleClear}
>
<div className="rounded-full bg-white">
<XCircle />
</div>
</Button>
)}
<Input
data-testid={testId}
type="file"
placeholder={placeholder}
accept={acceptFileFormats}
disabled={disabled || isLoading || isUploading}
onChange={handleChange}
onBlur={onBlur}
ref={inputRef}
className="hidden"
/>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
RegisterFileFn,
RemoveFileFn,
UseFileRepositoryResult,
} from '@/components/organisms/UIRenderer/elements/JSONForm/components/FileUploaderField/hooks/useFileUploading/types';
import { useRefValue } from '@/hooks/useRefValue';
Expand All @@ -26,6 +27,14 @@ export const useFileRepository = (
[fileRepository],
);

const removeFile: RemoveFileFn = useCallback(
(fileId: string) => {
fileRepository.removeByFileId(fileId);
setFile(null);
},
[fileRepository],
);

const repositoryListener: FileRepositoryListener = useCallback(
(updatedFileId, action) => {
if (fileId === updatedFileId && action === 'add') {
Expand All @@ -48,5 +57,6 @@ export const useFileRepository = (
return {
file,
registerFile,
removeFile,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ export type UseFileUploadOnUploadCallback = (fileId: string) => void;

export type RegisterFileFn = (file: File, fileId: string) => File;

export type RemoveFileFn = (fileId: string) => void;

export interface UseFileRepositoryResult {
file: File | null;
registerFile: RegisterFileFn;
removeFile: RemoveFileFn;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export type UploadedFileResult = { fileId: string };
export type UploadFileCallback = (file: File) => Promise<UploadedFileResult>;

export interface DocumentUploadFieldProps {
onChange: (fileId: string) => void;
onChange: (fileId: string, clear?: boolean) => void;
uploadFile: UploadFileFn;
onBlur?: () => void;
fileRepository: FileRepository;
Expand Down
Loading

0 comments on commit ad36d08

Please sign in to comment.