-
+
-
{displayText}
+
{displayText}
);
diff --git a/copilot-widget/lib/components/VoiceRecorder.tsx b/copilot-widget/lib/components/VoiceRecorder.tsx
index 6bcb94d18..78e49651a 100644
--- a/copilot-widget/lib/components/VoiceRecorder.tsx
+++ b/copilot-widget/lib/components/VoiceRecorder.tsx
@@ -1,7 +1,7 @@
-import { Square, MicIcon } from "lucide-react";
+import { MicIcon, Square } from "lucide-react";
import { Tooltip, TooltipContent, TooltipTrigger } from "./ToolTip";
import { useAxiosInstance } from "@lib/contexts/axiosInstance";
-import now from "@lib/utils/timenow";
+import { now } from "@lib/utils/time";
import { useEffect } from "react";
import useAudioRecorder from "@lib/hooks/useAudioRecord";
import { useLang } from "@lib/contexts/LocalesProvider";
diff --git a/copilot-widget/lib/components/Vote.tsx b/copilot-widget/lib/components/Vote.tsx
index b096b25c0..cf1c9a78d 100644
--- a/copilot-widget/lib/components/Vote.tsx
+++ b/copilot-widget/lib/components/Vote.tsx
@@ -13,7 +13,7 @@ export function Vote({ messageId }: { messageId: number }) {
const userVoted = isUpvoted || isDownvoted;
const { get } = useLang();
return (
-
+
{userVoted ? (
{get("thank-you")}
diff --git a/copilot-widget/lib/contexts/ConfigData.tsx b/copilot-widget/lib/contexts/ConfigData.tsx
index 620c644e6..ebe183233 100644
--- a/copilot-widget/lib/contexts/ConfigData.tsx
+++ b/copilot-widget/lib/contexts/ConfigData.tsx
@@ -1,17 +1,14 @@
import type { Options } from "@lib/types";
import type { ReactNode } from "react";
-import { createSafeContext } from "./create-safe-context";
+import { createSafeContext } from "./createSafeContext";
export type ConfigDataContextType = Omit<
Options,
- 'containerProps' | 'triggerSelector'
+ "containerProps" | "triggerSelector"
>;
-const [
- useConfigData,
- ConfigDataSafeProvider,
-
-] = createSafeContext();
+const [useConfigData, ConfigDataSafeProvider] =
+ createSafeContext();
export default function ConfigDataProvider({
children,
@@ -21,11 +18,9 @@ export default function ConfigDataProvider({
children: ReactNode;
}) {
return (
-
- {children}
-
+ {children}
);
}
-// eslint-disable-next-line react-refresh/only-export-components
-export { useConfigData }
\ No newline at end of file
+// eslint-disable-next-line react-refresh/only-export-components
+export { useConfigData };
diff --git a/copilot-widget/lib/contexts/Controller.tsx b/copilot-widget/lib/contexts/Controller.tsx
index d3ade2811..ea55748de 100644
--- a/copilot-widget/lib/contexts/Controller.tsx
+++ b/copilot-widget/lib/contexts/Controller.tsx
@@ -5,14 +5,14 @@ import React, {
useMemo,
useState,
} from "react";
-import now from "../utils/timenow";
+import { now } from "../utils/time";
import { useConfigData } from "./ConfigData";
import { Message } from "@lib/types";
import { getId } from "@lib/utils/utils";
import io from "socket.io-client";
import { useSessionId } from "@lib/hooks/useSessionId";
import { BotResponse, UserMessage } from "@lib/types/messageTypes";
-import { createSafeContext } from "./create-safe-context";
+import { createSafeContext } from "./createSafeContext";
import { useWidgetState } from "./WidgetState";
export type FailedMessage = {
@@ -87,7 +87,7 @@ const ChatProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
from: "user",
session_id: sessionId,
headers: config.headers ?? {},
- bot_token: config.token
+ bot_token: config.token,
};
socket.emit("send_chat", userMessage);
diff --git a/copilot-widget/lib/contexts/LocalesProvider.tsx b/copilot-widget/lib/contexts/LocalesProvider.tsx
index 392963ee8..526b1e76c 100644
--- a/copilot-widget/lib/contexts/LocalesProvider.tsx
+++ b/copilot-widget/lib/contexts/LocalesProvider.tsx
@@ -1,5 +1,5 @@
import { type LangType, getStr } from "@lib/locales";
-import { createSafeContext } from "./create-safe-context";
+import { createSafeContext } from "./createSafeContext";
import { useConfigData } from "./ConfigData";
const [useLang, SafeLanguageProvider] = createSafeContext<{
diff --git a/copilot-widget/lib/contexts/WidgetState.tsx b/copilot-widget/lib/contexts/WidgetState.tsx
index b614831e9..070b9c3b9 100644
--- a/copilot-widget/lib/contexts/WidgetState.tsx
+++ b/copilot-widget/lib/contexts/WidgetState.tsx
@@ -1,20 +1,20 @@
import type { ReactNode } from "react";
import useToggle from "../hooks/useToggle";
import { useConfigData } from "./ConfigData";
-import { createSafeContext } from "./create-safe-context";
+import { createSafeContext } from "./createSafeContext";
-type StateContextType = ReturnType
+type StateContextType = ReturnType;
-const [
- useWidgetState,
- WidgetStateSafeProvider,
-] = createSafeContext()
+const [useWidgetState, WidgetStateSafeProvider] =
+ createSafeContext();
export default function WidgetState({ children }: { children: ReactNode }) {
- const { defaultOpen } = useConfigData()
- const data = useToggle(defaultOpen ?? false)
- return {children};
+ const { defaultOpen } = useConfigData();
+ const data = useToggle(defaultOpen ?? false);
+ return (
+ {children}
+ );
}
// eslint-disable-next-line react-refresh/only-export-components
-export { useWidgetState }
\ No newline at end of file
+export { useWidgetState };
diff --git a/copilot-widget/lib/contexts/axiosInstance.tsx b/copilot-widget/lib/contexts/axiosInstance.tsx
index 4dda6ad9e..5becd4601 100644
--- a/copilot-widget/lib/contexts/axiosInstance.tsx
+++ b/copilot-widget/lib/contexts/axiosInstance.tsx
@@ -3,20 +3,18 @@ import { ReactNode, useMemo } from "react";
import { useConfigData } from "./ConfigData";
import { useSessionId } from "@lib/hooks/useSessionId";
import { createAxiosInstance } from "@lib/data/chat";
-import { createSafeContext } from "./create-safe-context";
+import { createSafeContext } from "./createSafeContext";
interface AxiosInstanceProps {
axiosInstance: AxiosInstance;
}
-const [
- useAxiosInstance,
- AxiosSafeProvider,
-] = createSafeContext();
+const [useAxiosInstance, AxiosSafeProvider] =
+ createSafeContext();
function AxiosProvider({ children }: { children: ReactNode }) {
const config = useConfigData();
- const { sessionId } = useSessionId(config?.token || 'defaultToken');
+ const { sessionId } = useSessionId(config?.token || "defaultToken");
const axiosInstance: AxiosInstance = useMemo(() => {
return createAxiosInstance({
botToken: config?.token,
@@ -26,11 +24,9 @@ function AxiosProvider({ children }: { children: ReactNode }) {
}, [config, sessionId]);
return (
-
- {children}
-
+ {children}
);
}
// eslint-disable-next-line react-refresh/only-export-components
-export { useAxiosInstance, AxiosProvider };
\ No newline at end of file
+export { useAxiosInstance, AxiosProvider };
diff --git a/copilot-widget/lib/contexts/create-safe-context.ts b/copilot-widget/lib/contexts/create-safe-context.ts
deleted file mode 100644
index e5a31d8b7..000000000
--- a/copilot-widget/lib/contexts/create-safe-context.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { createContext, useContext } from "react";
-
-export function createSafeContext(init?: TDdata) {
- const context = createContext(init);
- const useSafeContext = () => {
- const ctx = useContext(context);
- if (ctx === undefined) {
- throw new Error("useSafeContext must be used within a Provider");
- }
- return ctx;
- };
- return [useSafeContext, context.Provider] as const;
-}
\ No newline at end of file
diff --git a/copilot-widget/lib/contexts/createSafeContext.ts b/copilot-widget/lib/contexts/createSafeContext.ts
new file mode 100644
index 000000000..8333caca1
--- /dev/null
+++ b/copilot-widget/lib/contexts/createSafeContext.ts
@@ -0,0 +1,13 @@
+import { createContext, useContext } from "react";
+
+export function createSafeContext(init?: TDdata) {
+ const context = createContext(init);
+ const useSafeContext = () => {
+ const ctx = useContext(context);
+ if (ctx === undefined) {
+ throw new Error("useSafeContext must be used within a Provider");
+ }
+ return ctx;
+ };
+ return [useSafeContext, context.Provider] as const;
+}
diff --git a/copilot-widget/lib/data/chat.ts b/copilot-widget/lib/data/chat.ts
index 5970e38a9..1b61606c1 100644
--- a/copilot-widget/lib/data/chat.ts
+++ b/copilot-widget/lib/data/chat.ts
@@ -27,6 +27,7 @@ export function createAxiosInstance({
});
return instance;
}
+
type HistoryMessage = {
chatbot_id: string;
created_at: string;
@@ -64,6 +65,7 @@ export function historyToMessages(history?: HistoryMessage[]): Message[] {
}
return $messages;
}
+
export async function getInitialData(instance: AxiosInstance) {
const { data } = await instance.get<{
bot_name: string;
diff --git a/copilot-widget/lib/hooks/useCopy.ts b/copilot-widget/lib/hooks/useCopy.ts
deleted file mode 100644
index d0d6888a8..000000000
--- a/copilot-widget/lib/hooks/useCopy.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { useState, useEffect } from "react";
-
-type CopyFn = (text: any) => Promise;
-
-export function useCopyToClipboard(): [boolean, CopyFn] {
- const [copied, setCopied] = useState(false);
- const copy: CopyFn = async (text) => {
- if (!navigator?.clipboard) {
- console.warn("Clipboard not supported");
- return false;
- }
-
- // Try to save to clipboard then update the state if it worked
- try {
- await navigator.clipboard.writeText(text);
- setCopied(true);
- return true;
- } catch (error) {
- console.warn("Copy failed", error);
- setCopied(false);
- return false;
- }
- };
-
- useEffect(() => {
- if (copied) {
- const timeout = setTimeout(() => {
- setCopied(false);
- }, 5000);
-
- return () => clearTimeout(timeout);
- }
- }, [copied]);
-
- return [copied, copy];
-}
diff --git a/copilot-widget/lib/hooks/useDocumentDirection.ts b/copilot-widget/lib/hooks/useDocumentDirection.ts
index 98e4e7ae9..2947ff6a0 100644
--- a/copilot-widget/lib/hooks/useDocumentDirection.ts
+++ b/copilot-widget/lib/hooks/useDocumentDirection.ts
@@ -1,19 +1,21 @@
-import { useEffect, useState } from "react"
+import { useEffect, useState } from "react";
-type Dir = "rtl" | "ltr"
+type Dir = "rtl" | "ltr";
export function useDocumentDirection() {
- const [direction, setDirection] = useState(getComputedStyle(document.body).direction as Dir)
- useEffect(() => {
- const observer = new MutationObserver(() => {
- setDirection(getComputedStyle(document.body).direction as Dir)
- })
- observer.observe(document.head, { attributes: true })
- return () => observer.disconnect()
- }, [])
- return {
- rtl: direction === "rtl",
- ltr: direction === "ltr",
- direction
- }
-}
\ No newline at end of file
+ const [direction, setDirection] = useState(
+ getComputedStyle(document.body).direction as Dir
+ );
+ useEffect(() => {
+ const observer = new MutationObserver(() => {
+ setDirection(getComputedStyle(document.body).direction as Dir);
+ });
+ observer.observe(document.head, { attributes: true });
+ return () => observer.disconnect();
+ }, []);
+ return {
+ rtl: direction === "rtl",
+ ltr: direction === "ltr",
+ direction,
+ };
+}
diff --git a/copilot-widget/lib/hooks/useInitialData.tsx b/copilot-widget/lib/hooks/useInitialData.ts
similarity index 80%
rename from copilot-widget/lib/hooks/useInitialData.tsx
rename to copilot-widget/lib/hooks/useInitialData.ts
index 2d965d118..36a289a7f 100644
--- a/copilot-widget/lib/hooks/useInitialData.tsx
+++ b/copilot-widget/lib/hooks/useInitialData.ts
@@ -4,5 +4,8 @@ import useSWR from "swr";
export function useInitialData() {
const { axiosInstance } = useAxiosInstance();
- return useSWR("initialData", () => getInitialData(axiosInstance), {revalidateIfStale: false, revalidateOnFocus: false});
+ return useSWR("initialData", () => getInitialData(axiosInstance), {
+ revalidateIfStale: false,
+ revalidateOnFocus: false,
+ });
}
diff --git a/copilot-widget/lib/hooks/useScroll.ts b/copilot-widget/lib/hooks/useScroll.ts
deleted file mode 100644
index 214cf35d8..000000000
--- a/copilot-widget/lib/hooks/useScroll.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { useState, useEffect, RefObject } from 'react';
-
-interface ScrollPosition {
- x: number;
- y: number;
-}
-
-const useScroll = (targetRef: RefObject): ScrollPosition => {
- const [scrollPosition, setScrollPosition] = useState({
- x: 0,
- y: 0,
- });
-
- useEffect(() => {
- const handleScroll = () => {
- if (targetRef.current) {
- const { scrollWidth, scrollHeight, clientWidth, clientHeight } = targetRef.current;
-
- setScrollPosition({
- x: (targetRef.current.scrollLeft / (scrollWidth - clientWidth)),
- y: (targetRef.current.scrollTop / (scrollHeight - clientHeight)),
- });
- }
- };
-
- const targetElement = targetRef.current;
-
- if (targetElement) {
- targetElement.addEventListener('scroll', handleScroll);
- }
-
- return () => {
- if (targetElement) {
- targetElement.removeEventListener('scroll', handleScroll);
- }
- };
- }, [targetRef]);
-
- return scrollPosition;
-};
-
-export default useScroll;
diff --git a/copilot-widget/lib/hooks/useScrollTo.ts b/copilot-widget/lib/hooks/useScrollTo.ts
index f78fbe41f..9277060e6 100644
--- a/copilot-widget/lib/hooks/useScrollTo.ts
+++ b/copilot-widget/lib/hooks/useScrollTo.ts
@@ -1,22 +1,22 @@
-import { RefObject } from 'react';
+import { RefObject } from "react";
-const useScrollToPercentage = (elementRef: RefObject
-): [(percentageX: number, percentageY: number) => void
- ] => {
- const scrollToPercentage = (percentageX: number, percentageY: number) => {
- if (elementRef.current) {
- const { scrollWidth, scrollHeight } = elementRef.current;
- const maxScrollX = scrollWidth - elementRef.current.clientWidth;
- const maxScrollY = scrollHeight - elementRef.current.clientHeight;
+const useScrollToPercentage = (
+ elementRef: RefObject
+): [(percentageX: number, percentageY: number) => void] => {
+ const scrollToPercentage = (percentageX: number, percentageY: number) => {
+ if (elementRef.current) {
+ const { scrollWidth, scrollHeight } = elementRef.current;
+ const maxScrollX = scrollWidth - elementRef.current.clientWidth;
+ const maxScrollY = scrollHeight - elementRef.current.clientHeight;
- const scrollToX = (percentageX / 100) * maxScrollX;
- const scrollToY = (percentageY / 100) * maxScrollY;
+ const scrollToX = (percentageX / 100) * maxScrollX;
+ const scrollToY = (percentageY / 100) * maxScrollY;
- elementRef.current.scrollTo(scrollToX, scrollToY);
- }
- };
+ elementRef.current.scrollTo(scrollToX, scrollToY);
+ }
+ };
- return [scrollToPercentage];
+ return [scrollToPercentage];
};
export default useScrollToPercentage;
diff --git a/copilot-widget/lib/hooks/useSessionId.ts b/copilot-widget/lib/hooks/useSessionId.ts
index 2bb44ab2a..60a2fd498 100644
--- a/copilot-widget/lib/hooks/useSessionId.ts
+++ b/copilot-widget/lib/hooks/useSessionId.ts
@@ -2,13 +2,15 @@ import { useRef } from "react";
// the session id will be copilotId:uniqueId
function randomString(length = 10) {
- return Math.random().toString(36).substring(2, length + 2);
+ return Math.random()
+ .toString(36)
+ .substring(2, length + 2);
}
export function useSessionId(copilotToken: string) {
const sessionId = useRef(copilotToken + "|" + randomString()).current;
const setSessionId = (copilotToken: string) => {
// copilotToken
- }
+ };
return { sessionId, setSessionId };
}
diff --git a/copilot-widget/lib/hooks/useTextRotator.ts b/copilot-widget/lib/hooks/useTextRotator.ts
deleted file mode 100644
index a07ee9084..000000000
--- a/copilot-widget/lib/hooks/useTextRotator.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { useEffect, useState } from "react";
-
-export function useTextRotator({ texts, intervalInSeconds }: { texts: string[], intervalInSeconds: number }) {
- const [textObjects, setTextObjects] = useState(texts.map((text, index) => ({
- text,
- isVisible: index === 0,
- order: index
- })));
-
- useEffect(() => {
- let interval: NodeJS.Timeout;
- if (textObjects.length > 1) {
- interval = setInterval(() => {
- setTextObjects((prev) => {
- const next = [...prev];
- const currentVisibleIndex = next.findIndex(({ isVisible }) => isVisible);
- const nextIndex = currentVisibleIndex + 1;
- if (nextIndex < next.length) {
- next[currentVisibleIndex].isVisible = false;
- next[nextIndex].isVisible = true;
- } else {
- clearInterval(interval);
- }
- return next;
- })
- }, intervalInSeconds * 1000);
- }
- return () => {
- if (interval) {
- clearInterval(interval);
- }
- }
- }, [texts, intervalInSeconds, textObjects]);
-
- return textObjects
-};
\ No newline at end of file
diff --git a/copilot-widget/lib/hooks/useToggle.ts b/copilot-widget/lib/hooks/useToggle.ts
index a22ed1978..9733419c1 100644
--- a/copilot-widget/lib/hooks/useToggle.ts
+++ b/copilot-widget/lib/hooks/useToggle.ts
@@ -1,11 +1,10 @@
-import { Dispatch, SetStateAction, useCallback, useState } from 'react'
+import { Dispatch, SetStateAction, useCallback, useState } from "react";
export default function useToggle(
- defaultValue?: boolean,
+ defaultValue?: boolean
): [boolean, () => void, Dispatch>] {
- const [value, setValue] = useState(!!defaultValue)
+ const [value, setValue] = useState(!!defaultValue);
+ const toggle = useCallback(() => setValue((x) => !x), []);
- const toggle = useCallback(() => setValue(x => !x), [])
-
- return [value, toggle, setValue]
-}
\ No newline at end of file
+ return [value, toggle, setValue];
+}
diff --git a/copilot-widget/lib/hooks/useTypeWriter.ts b/copilot-widget/lib/hooks/useTypeWriter.ts
index 9a5f7bbdf..90999f11f 100644
--- a/copilot-widget/lib/hooks/useTypeWriter.ts
+++ b/copilot-widget/lib/hooks/useTypeWriter.ts
@@ -1,34 +1,42 @@
import { useEffect, useState } from "react";
+type useTypeWriterOpts = {
+ text: string;
+ every?: number;
+ onFinish?: () => void;
+ shouldStart?: boolean;
+};
+export default function useTypeWriter({
+ text,
+ every,
+ onFinish,
+ shouldStart = true,
+}: useTypeWriterOpts) {
+ const [displayText, setDisplayText] = useState("");
+ const [currentIndex, setCurrentIndex] = useState(-1);
+ const [isComplete, setIsComplete] = useState(false);
+ const timeout = every || 0.00001;
-type useTypeWriterOpts = { text: string, every?: number, onFinish?: () => void, shouldStart?: boolean }
+ useEffect(() => {
+ if (shouldStart) {
+ if (currentIndex < text.length + 1) {
+ const timer = setInterval(() => {
+ setDisplayText(text.substring(0, currentIndex + 1));
+ setCurrentIndex((prevIndex) => prevIndex + 1);
+ }, timeout);
+ return () => {
+ clearInterval(timer);
+ };
+ } else {
+ setIsComplete(true);
-export default function useTypeWriter({ text, every, onFinish, shouldStart = true }: useTypeWriterOpts) {
- const [displayText, setDisplayText] = useState("");
- const [currentIndex, setCurrentIndex] = useState(-1);
- const [isComplete, setIsComplete] = useState(false);
- const timeout = every || 0.00001;
-
- useEffect(() => {
- if (shouldStart) {
- if (currentIndex < text.length + 1) {
- const timer = setInterval(() => {
- setDisplayText(text.substring(0, currentIndex + 1));
- setCurrentIndex((prevIndex) => prevIndex + 1);
- }, timeout);
-
- return () => {
- clearInterval(timer);
- };
- } else {
- setIsComplete(true);
- if (typeof onFinish === "function") {
- onFinish();
- }
- }
+ if (typeof onFinish === "function") {
+ onFinish();
}
- }, [text, currentIndex, timeout, onFinish, shouldStart]);
- return { displayText, isComplete, text }
-}
\ No newline at end of file
+ }
+ }
+ }, [text, currentIndex, timeout, onFinish, shouldStart]);
+ return { displayText, isComplete, text };
+}
diff --git a/copilot-widget/lib/index.ts b/copilot-widget/lib/index.ts
index b4b9a054a..67e34e6f3 100644
--- a/copilot-widget/lib/index.ts
+++ b/copilot-widget/lib/index.ts
@@ -1,6 +1,4 @@
import Root from "./Root";
import { CopilotWidget } from "./CopilotWidget";
-export {
- Root,
- CopilotWidget,
-}
\ No newline at end of file
+
+export { Root, CopilotWidget };
diff --git a/copilot-widget/lib/locales/ar.locale.ts b/copilot-widget/lib/locales/ar.locale.ts
index b65b91840..db021f896 100644
--- a/copilot-widget/lib/locales/ar.locale.ts
+++ b/copilot-widget/lib/locales/ar.locale.ts
@@ -1,6 +1,6 @@
-import { Locale } from "./types";
+import { TranslatableMessages } from "./types";
-const arLocale: Locale = {
+export const arLocale: TranslatableMessages = {
ok: "حسنا",
agree: "موافق",
cancel: "إلغاء",
@@ -11,5 +11,3 @@ const arLocale: Locale = {
recording: "تسجيل",
"thank-you": "شكرا",
};
-
-export default arLocale;
diff --git a/copilot-widget/lib/locales/en.locale.ts b/copilot-widget/lib/locales/en.locale.ts
index 70a2b1a13..b88512d75 100644
--- a/copilot-widget/lib/locales/en.locale.ts
+++ b/copilot-widget/lib/locales/en.locale.ts
@@ -1,15 +1,13 @@
-import { Locale } from "./types";
+import { TranslatableMessages } from "./types";
-const enLocale: Locale = {
+export const enLocale: TranslatableMessages = {
ok: "Ok",
agree: "Agree",
cancel: "Cancel",
- "yes-exit": "Yes, Exit",
- "yes-reset": "Yes, Reset",
- "no-cancel": "No, Cancel",
+ "yes-exit": "Yes, exit",
+ "yes-reset": "Yes, reset",
+ "no-cancel": "No, cancel",
"are-you-sure": "Are you sure?",
recording: "Recording",
"thank-you": "Thank you",
};
-
-export default enLocale;
diff --git a/copilot-widget/lib/locales/helper.ts b/copilot-widget/lib/locales/helper.ts
index 3496c04fa..53d65fb26 100644
--- a/copilot-widget/lib/locales/helper.ts
+++ b/copilot-widget/lib/locales/helper.ts
@@ -1,9 +1,11 @@
-import enLocale from "./en.locale";
-import arLocale from "./ar.locale";
+import { enLocale } from "./en.locale";
+import { arLocale } from "./ar.locale";
+import { nlLocale } from "./nl.locale.ts";
const locales = {
en: enLocale,
ar: arLocale,
+ nl: nlLocale,
};
export type LangType = keyof typeof locales;
diff --git a/copilot-widget/lib/locales/nl.locale.ts b/copilot-widget/lib/locales/nl.locale.ts
new file mode 100644
index 000000000..41a50315d
--- /dev/null
+++ b/copilot-widget/lib/locales/nl.locale.ts
@@ -0,0 +1,13 @@
+import { TranslatableMessages } from "./types";
+
+export const nlLocale: TranslatableMessages = {
+ ok: "Ok",
+ agree: "Akkoord",
+ cancel: "Annuleren",
+ "yes-exit": "Beëindigen",
+ "yes-reset": "Reset chat",
+ "no-cancel": "Annuleren",
+ "are-you-sure": "Wil je de chat beëindigen?",
+ recording: "Aan het opnemen...",
+ "thank-you": "Thanks!",
+};
diff --git a/copilot-widget/lib/locales/types.ts b/copilot-widget/lib/locales/types.ts
index 8b04a9686..0252f8697 100644
--- a/copilot-widget/lib/locales/types.ts
+++ b/copilot-widget/lib/locales/types.ts
@@ -1,3 +1,3 @@
-export type Locale = {
+export type TranslatableMessages = {
[key: string]: string;
};
\ No newline at end of file
diff --git a/copilot-widget/lib/screens/ChatScreen.tsx b/copilot-widget/lib/screens/ChatScreen.tsx
index c641e5edb..75deae97b 100644
--- a/copilot-widget/lib/screens/ChatScreen.tsx
+++ b/copilot-widget/lib/screens/ChatScreen.tsx
@@ -10,7 +10,7 @@ import useScrollToPercentage from "../hooks/useScrollTo";
import ChatInputFooter from "../components/ChatInputFooter";
import { ChatProvider, useChat } from "../contexts/Controller";
import { useConfigData } from "../contexts/ConfigData";
-import { Map } from "../utils/Map";
+import { Map } from "../utils/map";
function ChatScreen() {
const scrollElementRef = useRef(null);
@@ -18,6 +18,7 @@ function ChatScreen() {
const { messages, loading, failedMessage, conversationInfo } = useChat();
const config = useConfigData();
const initialMessage = config?.initialMessage;
+
useEffect(() => {
setPos(0, 100);
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -43,16 +44,15 @@ function ChatScreen() {
fallback={
}
data={messages}
render={(message, index) => {
- if (message.from === "bot") {
- if (message.type === "text")
- return (
-
- );
+ if (message.from === "bot" && message.type === "text") {
+ return (
+
+ );
} else if (message.from === "user") {
return (
)}
- {failedMessage && }
+ {failedMessage && }
diff --git a/copilot-widget/lib/types/index.ts b/copilot-widget/lib/types/index.ts
index 0aff2d149..4a78d685c 100644
--- a/copilot-widget/lib/types/index.ts
+++ b/copilot-widget/lib/types/index.ts
@@ -1,2 +1,2 @@
-export { type Message } from './messageTypes';
-export { type Options } from './options';
\ No newline at end of file
+export { type Message } from "./messageTypes";
+export { type Options } from "./options";
diff --git a/copilot-widget/lib/types/messageTypes.ts b/copilot-widget/lib/types/messageTypes.ts
index a7461e481..331bb19ef 100644
--- a/copilot-widget/lib/types/messageTypes.ts
+++ b/copilot-widget/lib/types/messageTypes.ts
@@ -1,5 +1,5 @@
-// original shape
type TS = Date | number;
+
export type BotResponse = {
id: string | number;
timestamp: TS;
@@ -8,12 +8,13 @@ export type BotResponse = {
response: {
text: string;
};
-}
+};
+
export type UserMessage = {
id: string | number;
timestamp: TS;
from: "user";
content: string;
-}
+};
export type Message = BotResponse | UserMessage;
diff --git a/copilot-widget/lib/types/options.ts b/copilot-widget/lib/types/options.ts
index 94433a1b4..8e41e0c67 100644
--- a/copilot-widget/lib/types/options.ts
+++ b/copilot-widget/lib/types/options.ts
@@ -9,11 +9,17 @@ export type Options = {
socketUrl: string;
defaultOpen?: boolean;
language?: LangType;
+ warnBeforeClose?: boolean;
containerProps?: React.DetailedHTMLProps<
React.HTMLAttributes
,
HTMLDivElement
>;
user?: {
name?: string;
+ avatarUrl?: string;
+ };
+ bot?: {
+ name?: string;
+ avatarUrl?: string;
};
};
diff --git a/copilot-widget/lib/utils/cn.ts b/copilot-widget/lib/utils/cn.ts
index 8b3f873ed..dbc16d640 100644
--- a/copilot-widget/lib/utils/cn.ts
+++ b/copilot-widget/lib/utils/cn.ts
@@ -1,6 +1,6 @@
-import { type ClassValue, clsx } from "clsx"
-import { twMerge } from "tailwind-merge"
-
+import { type ClassValue, clsx } from "clsx";
+import { twMerge } from "tailwind-merge";
+
export default function cn(...inputs: ClassValue[]) {
- return twMerge(clsx(inputs))
-}
\ No newline at end of file
+ return twMerge(clsx(inputs));
+}
diff --git a/copilot-widget/lib/utils/formatTime.ts b/copilot-widget/lib/utils/formatTime.ts
deleted file mode 100644
index cfd98a3ae..000000000
--- a/copilot-widget/lib/utils/formatTime.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export default function formatTimeFromTimestamp(timestamp: number | Date): string {
- const date = new Date(timestamp); // Multiply by 1000 to convert seconds to milliseconds
- const hours = date.getHours();
- const minutes = String(date.getMinutes()).padStart(2, '0');
- const period = hours >= 12 ? 'PM' : 'AM';
- const formattedHours = (hours % 12) || 12; // Convert hours from 24-hour to 12-hour format
-
- return `${formattedHours}:${minutes} ${period}`;
-}
\ No newline at end of file
diff --git a/copilot-widget/lib/utils/isServer.ts b/copilot-widget/lib/utils/isServer.ts
new file mode 100644
index 000000000..ca617a8ce
--- /dev/null
+++ b/copilot-widget/lib/utils/isServer.ts
@@ -0,0 +1 @@
+export const isServer = typeof window === "undefined";
diff --git a/copilot-widget/lib/utils/is_server.ts b/copilot-widget/lib/utils/is_server.ts
deleted file mode 100644
index 5b2577bc2..000000000
--- a/copilot-widget/lib/utils/is_server.ts
+++ /dev/null
@@ -1 +0,0 @@
-export const IS_SERVER = typeof window === "undefined";
diff --git a/copilot-widget/lib/utils/Map.tsx b/copilot-widget/lib/utils/map.ts
similarity index 100%
rename from copilot-widget/lib/utils/Map.tsx
rename to copilot-widget/lib/utils/map.ts
diff --git a/copilot-widget/lib/utils/time.ts b/copilot-widget/lib/utils/time.ts
new file mode 100644
index 000000000..b9f5d9e2d
--- /dev/null
+++ b/copilot-widget/lib/utils/time.ts
@@ -0,0 +1,13 @@
+export function now(): number {
+ return Date.now();
+}
+
+export function formatTimeFromTimestamp(timestamp: number | Date): string {
+ const date = new Date(timestamp); // Multiply by 1000 to convert seconds to milliseconds
+ const hours = date.getHours();
+ const minutes = String(date.getMinutes()).padStart(2, "0");
+ const period = hours >= 12 ? "PM" : "AM";
+ const formattedHours = hours % 12 || 12; // Convert hours from 24-hour to 12-hour format
+
+ return `${formattedHours}:${minutes} ${period}`;
+}
diff --git a/copilot-widget/lib/utils/timenow.ts b/copilot-widget/lib/utils/timenow.ts
deleted file mode 100644
index 720adfdc7..000000000
--- a/copilot-widget/lib/utils/timenow.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export default function now():number {
- return Date.now()
-}
\ No newline at end of file
diff --git a/copilot-widget/lib/utils/utils.ts b/copilot-widget/lib/utils/utils.ts
index af8d720c0..186230fe4 100644
--- a/copilot-widget/lib/utils/utils.ts
+++ b/copilot-widget/lib/utils/utils.ts
@@ -21,4 +21,5 @@ function getId(): string {
function getLast(arr: T[]): T | undefined {
return arr[arr.length - 1];
}
+
export { isEmpty, getId, getLast };
diff --git a/copilot-widget/src/utils.ts b/copilot-widget/src/utils.ts
index dc842afee..e672420b2 100644
--- a/copilot-widget/src/utils.ts
+++ b/copilot-widget/src/utils.ts
@@ -1,32 +1,34 @@
import type { CSSProperties } from "react";
+
function getOrCreateRootById(id: string): HTMLElement {
- let root = document.getElementById(id);
- if (!root) {
- root = document.createElement('div');
- root.id = id;
- document.body.appendChild(root);
- }
- return root;
+ let root = document.getElementById(id);
+
+ if (!root) {
+ root = document.createElement("div");
+ root.id = id;
+ document.body.appendChild(root);
+ }
+ return root;
}
function styleTheRoot(root: HTMLElement, styles?: CSSProperties): HTMLElement {
- // user may style the root from outside, so we need to preserve it and merge with our styles but our styles should have low priority.
- Object.assign(root.style, styles);
- return root;
+ // user may style the root from outside, so we need to preserve it and merge with our styles but our styles should have low priority.
+ Object.assign(root.style, styles);
+
+ return root;
}
export function composeRoot(id: string, fluid?: boolean): HTMLElement {
- const baseStyles: CSSProperties = {
- isolation: 'isolate',
- unicodeBidi: 'bidi-override',
- fontVariantNumeric: 'tabular-nums',
- }
+ const baseStyles: CSSProperties = {
+ isolation: "isolate",
+ unicodeBidi: "bidi-override",
+ fontVariantNumeric: "tabular-nums",
+ };
+ const fluidStyles: CSSProperties = {
+ width: "100%",
+ height: "100%",
+ };
+ const styles = fluid ? { ...baseStyles, ...fluidStyles } : baseStyles;
- const fluidStyles: CSSProperties = {
- width: '100%',
- height: '100%',
- }
-
- const styles = fluid ? { ...baseStyles, ...fluidStyles } : baseStyles;
- return styleTheRoot(getOrCreateRootById(id), styles);
-}
\ No newline at end of file
+ return styleTheRoot(getOrCreateRootById(id), styles);
+}
diff --git a/copilot-widget/styles/index.css b/copilot-widget/styles/index.css
index e815b8722..33df50dab 100644
--- a/copilot-widget/styles/index.css
+++ b/copilot-widget/styles/index.css
@@ -8,6 +8,7 @@ svg {
vector-effect: non-scaling-stroke;
stroke-width: 1.5;
}
+
@keyframes fade-in-bottom {
0% {
transform: translateY(50px);
@@ -60,11 +61,6 @@ svg {
animation: fade-in 1.2s cubic-bezier(0.39, 0.575, 0.565, 1) both;
}
-.PopoverContent {
- transform-origin: var(--radix-popover-content-transform-origin);
- animation: scaleIn 0.5s ease-out;
-}
-
@keyframes scaleIn {
from {
opacity: 0;
@@ -77,19 +73,6 @@ svg {
}
}
-.PopoverContent {
- animation-duration: 0.6s;
- animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
-}
-
-.PopoverContent[data-side="top"] {
- animation-name: slideUp;
-}
-
-.PopoverContent[data-side="bottom"] {
- animation-name: slideDown;
-}
-
@keyframes slideDown {
from {
opacity: 0;
@@ -147,9 +130,11 @@ svg {
.scale-out-br {
animation: scale-out-br 0.5s ease-in-out forwards;
}
+
.no-scrollbar::-webkit-scrollbar {
display: none;
}
+
@keyframes text-blur-out {
0% {
filter: blur(0.01);