From e77d39afd3264ba3278d73ab665c3207d68d5a38 Mon Sep 17 00:00:00 2001 From: mamadoudicko Date: Wed, 13 Dec 2023 15:00:47 +0100 Subject: [PATCH 1/4] feat: add sidebar context --- .../app/chat/[chatId]/__tests__/page.test.tsx | 5 ++- .../ChatsList/__tests__/ChatsList.test.tsx | 13 +++++-- frontend/lib/components/Sidebar/Sidebar.tsx | 34 +++++++---------- .../Sidebar/__tests__/Sidebar.test.tsx | 9 +++-- .../Sidebar/components/SidebarHeader.tsx | 10 ++--- .../hooks/useSideBarContext.ts | 13 +++++++ .../SidebarProvider/sidebar-provider.tsx | 38 +++++++++++++++++++ 7 files changed, 88 insertions(+), 34 deletions(-) create mode 100644 frontend/lib/context/SidebarProvider/hooks/useSideBarContext.ts create mode 100644 frontend/lib/context/SidebarProvider/sidebar-provider.tsx diff --git a/frontend/app/chat/[chatId]/__tests__/page.test.tsx b/frontend/app/chat/[chatId]/__tests__/page.test.tsx index be9cb7d48dbd..53e4a3d6a9ac 100644 --- a/frontend/app/chat/[chatId]/__tests__/page.test.tsx +++ b/frontend/app/chat/[chatId]/__tests__/page.test.tsx @@ -11,6 +11,7 @@ import { ChatProviderMock, } from "@/lib/context/ChatProvider/mocks/ChatProviderMock"; import { KnowledgeToFeedProvider } from "@/lib/context/KnowledgeToFeedProvider"; +import { SideBarProvider } from "@/lib/context/SidebarProvider/sidebar-provider"; import { SupabaseContextMock, SupabaseProviderMock, @@ -87,7 +88,9 @@ describe("Chat page", () => { - , + + , + diff --git a/frontend/app/chat/components/ChatsList/__tests__/ChatsList.test.tsx b/frontend/app/chat/components/ChatsList/__tests__/ChatsList.test.tsx index fb4eeb29e480..9c369efcd0b6 100644 --- a/frontend/app/chat/components/ChatsList/__tests__/ChatsList.test.tsx +++ b/frontend/app/chat/components/ChatsList/__tests__/ChatsList.test.tsx @@ -12,6 +12,7 @@ import { ChatProviderMock, } from "@/lib/context/ChatProvider/mocks/ChatProviderMock"; import { KnowledgeToFeedProvider } from "@/lib/context/KnowledgeToFeedProvider"; +import { SideBarProvider } from "@/lib/context/SidebarProvider/sidebar-provider"; import { SupabaseContextMock } from "@/lib/context/SupabaseProvider/mocks/SupabaseProviderMock"; vi.mock("@/lib/context/SupabaseProvider/supabase-provider", () => ({ @@ -91,7 +92,9 @@ describe("ChatsList", () => { - + + + @@ -110,7 +113,9 @@ describe("ChatsList", () => { - + + + @@ -133,7 +138,9 @@ describe("ChatsList", () => { - + + + diff --git a/frontend/lib/components/Sidebar/Sidebar.tsx b/frontend/lib/components/Sidebar/Sidebar.tsx index 8616e45f42f5..7048ead4a2a6 100644 --- a/frontend/lib/components/Sidebar/Sidebar.tsx +++ b/frontend/lib/components/Sidebar/Sidebar.tsx @@ -1,10 +1,8 @@ import { motion, MotionConfig } from "framer-motion"; -import { usePathname } from "next/navigation"; -import { useEffect, useState } from "react"; import { LuPanelLeftOpen } from "react-icons/lu"; import { SidebarHeader } from "@/lib/components/Sidebar/components/SidebarHeader"; -import { useDevice } from "@/lib/hooks/useDevice"; +import { useSideBarContext } from "@/lib/context/SidebarProvider/hooks/useSideBarContext"; import { cn } from "@/lib/utils"; import { @@ -21,13 +19,7 @@ export const Sidebar = ({ children, showButtons, }: SidebarProps): JSX.Element => { - const { isMobile } = useDevice(); - const pathname = usePathname(); - const [open, setOpen] = useState(!isMobile); - - useEffect(() => { - setOpen(!isMobile); - }, [isMobile, pathname]); + const { isOpened, setIsOpened } = useSideBarContext(); return ( @@ -36,40 +28,40 @@ export const Sidebar = ({ dragConstraints={{ right: 0, left: 0 }} dragElastic={0.15} onDragEnd={(event, info) => { - if (info.offset.x > 100 && !open) { - setOpen(true); - } else if (info.offset.x < -100 && open) { - setOpen(false); + if (info.offset.x > 100 && !isOpened) { + setIsOpened(true); + } else if (info.offset.x < -100 && isOpened) { + setIsOpened(false); } }} className="flex flex-col fixed sm:sticky top-0 left-0 h-full overflow-visible z-30 border-r border-black/10 dark:border-white/25 bg-white dark:bg-black" > - {!open && ( + {!isOpened && ( )} - +
{children}
{showButtons && }
diff --git a/frontend/lib/components/Sidebar/__tests__/Sidebar.test.tsx b/frontend/lib/components/Sidebar/__tests__/Sidebar.test.tsx index 49add34037f9..1327cc4175bb 100644 --- a/frontend/lib/components/Sidebar/__tests__/Sidebar.test.tsx +++ b/frontend/lib/components/Sidebar/__tests__/Sidebar.test.tsx @@ -9,6 +9,7 @@ import { import { afterEach, describe, expect, it, vi } from "vitest"; import { Sidebar } from "@/lib/components/Sidebar/Sidebar"; +import { SideBarProvider } from "@/lib/context/SidebarProvider/sidebar-provider"; import { useDevice } from "@/lib/hooks/useDevice"; vi.mock("@/lib/hooks/useDevice"); @@ -16,9 +17,11 @@ vi.mock("@/lib/hooks/useDevice"); const renderSidebar = async () => { await act(() => render( - -
📦
-
+ + +
📦
+
+
) ); }; diff --git a/frontend/lib/components/Sidebar/components/SidebarHeader.tsx b/frontend/lib/components/Sidebar/components/SidebarHeader.tsx index 92b833aee7e6..51a1599ea39c 100644 --- a/frontend/lib/components/Sidebar/components/SidebarHeader.tsx +++ b/frontend/lib/components/Sidebar/components/SidebarHeader.tsx @@ -1,13 +1,11 @@ -import { Dispatch, SetStateAction } from "react"; import { LuPanelLeft } from "react-icons/lu"; import { Logo } from "@/lib/components/Logo/Logo"; +import { useSideBarContext } from "@/lib/context/SidebarProvider/hooks/useSideBarContext"; -type SidebarProps = { - setOpen: Dispatch>; -}; +export const SidebarHeader = (): JSX.Element => { + const { setIsOpened } = useSideBarContext(); -export const SidebarHeader = ({ setOpen }: SidebarProps): JSX.Element => { return (
@@ -17,7 +15,7 @@ export const SidebarHeader = ({ setOpen }: SidebarProps): JSX.Element => { className="p-3 text-2xl bg:white dark:bg-black text-black dark:text-white hover:text-primary dark:hover:text-gray-200 transition-colors" type="button" data-testid="close-sidebar-button" - onClick={() => setOpen(false)} + onClick={() => setIsOpened(false)} > diff --git a/frontend/lib/context/SidebarProvider/hooks/useSideBarContext.ts b/frontend/lib/context/SidebarProvider/hooks/useSideBarContext.ts new file mode 100644 index 000000000000..912b31f56b48 --- /dev/null +++ b/frontend/lib/context/SidebarProvider/hooks/useSideBarContext.ts @@ -0,0 +1,13 @@ +import { useContext } from "react"; + +import { SideBarContext } from "../sidebar-provider"; + +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types +export const useSideBarContext = () => { + const context = useContext(SideBarContext); + if (context === undefined) { + throw new Error("useSideBarContext must be used within a SideBarProvider"); + } + + return context; +}; diff --git a/frontend/lib/context/SidebarProvider/sidebar-provider.tsx b/frontend/lib/context/SidebarProvider/sidebar-provider.tsx new file mode 100644 index 000000000000..a3eb7320cce4 --- /dev/null +++ b/frontend/lib/context/SidebarProvider/sidebar-provider.tsx @@ -0,0 +1,38 @@ +import { usePathname } from "next/navigation"; +import { createContext, useEffect, useState } from "react"; + +import { useDevice } from "@/lib/hooks/useDevice"; + +type SideBarContextType = { + isOpened: boolean; + setIsOpened: React.Dispatch>; +}; + +export const SideBarContext = createContext( + undefined +); + +export const SideBarProvider = ({ + children, +}: { + children: React.ReactNode; +}): JSX.Element => { + const { isMobile } = useDevice(); + const [isOpened, setIsOpened] = useState(!isMobile); + const pathname = usePathname(); + + useEffect(() => { + setIsOpened(!isMobile); + }, [isMobile, pathname]); + + return ( + + {children} + + ); +}; From 52174a717daac586e1e60935712afe7c078b9b50 Mon Sep 17 00:00:00 2001 From: mamadoudicko Date: Wed, 13 Dec 2023 15:05:38 +0100 Subject: [PATCH 2/4] feat: allow user to control sidebar from chat bar --- frontend/app/App.tsx | 5 +++- .../components/MenuControlButton.tsx | 25 +++++++++++++++++++ .../ActionsBar/components/ChatInput/index.tsx | 2 ++ .../Sidebar/components/SidebarHeader.tsx | 4 +-- 4 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/MenuControlButton.tsx diff --git a/frontend/app/App.tsx b/frontend/app/App.tsx index 6f1c6eb96b9d..decff4c83dc5 100644 --- a/frontend/app/App.tsx +++ b/frontend/app/App.tsx @@ -5,6 +5,7 @@ import { PropsWithChildren, useEffect } from "react"; import { BrainProvider } from "@/lib/context"; import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext"; +import { SideBarProvider } from "@/lib/context/SidebarProvider/sidebar-provider"; import { useSupabase } from "@/lib/context/SupabaseProvider"; import { UpdateMetadata } from "@/lib/helpers/updateMetadata"; import { usePageTracking } from "@/services/analytics/june/usePageTracking"; @@ -40,7 +41,9 @@ const AppWithQueryClient = ({ children }: PropsWithChildren): JSX.Element => { return ( - {children} + + {children} + ); diff --git a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/MenuControlButton.tsx b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/MenuControlButton.tsx new file mode 100644 index 000000000000..df09271433c2 --- /dev/null +++ b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/MenuControlButton.tsx @@ -0,0 +1,25 @@ +import { useTranslation } from "react-i18next"; +import { LuPanelLeftClose, LuPanelRightClose } from "react-icons/lu"; + +import Button from "@/lib/components/ui/Button"; +import { useSideBarContext } from "@/lib/context/SidebarProvider/hooks/useSideBarContext"; + +export const MenuControlButton = (): JSX.Element => { + const { isOpened, setIsOpened } = useSideBarContext(); + const Icon = isOpened ? LuPanelLeftClose : LuPanelRightClose; + const { t } = useTranslation("chat"); + + return ( + + ); +}; diff --git a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.tsx b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.tsx index 4619e6eeb3a8..711cc7caa0a9 100644 --- a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.tsx +++ b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.tsx @@ -9,6 +9,7 @@ import { getBrainIconFromBrainType } from "@/lib/helpers/getBrainIconFromBrainTy import { OnboardingQuestions } from "./components"; import { ActionsModal } from "./components/ActionsModal/ActionsModal"; import { ChatEditor } from "./components/ChatEditor/ChatEditor"; +import { MenuControlButton } from "./components/MenuControlButton"; import { useChatInput } from "./hooks/useChatInput"; type ChatInputProps = { @@ -37,6 +38,7 @@ export const ChatInput = ({ }} className="sticky bottom-0 bg-white dark:bg-black w-full flex items-center gap-2 z-20 p-2" > + {!shouldDisplayFeedOrSecretsCard && (
From c31825a2607144653f723e3c27c4e1ec67543ba4 Mon Sep 17 00:00:00 2001 From: mamadoudicko Date: Wed, 13 Dec 2023 15:05:53 +0100 Subject: [PATCH 3/4] feat: update translations --- frontend/public/locales/en/chat.json | 1 + frontend/public/locales/es/chat.json | 1 + frontend/public/locales/fr/chat.json | 1 + frontend/public/locales/pt-br/chat.json | 1 + frontend/public/locales/ru/chat.json | 1 + frontend/public/locales/zh-cn/chat.json | 1 + 6 files changed, 6 insertions(+) diff --git a/frontend/public/locales/en/chat.json b/frontend/public/locales/en/chat.json index fed0def615ca..a3038ee52d39 100644 --- a/frontend/public/locales/en/chat.json +++ b/frontend/public/locales/en/chat.json @@ -21,6 +21,7 @@ "last30Days": "Previous 30 days", "last7Days": "Previous 7 days", "limit_reached": "You have reached the limit of requests, please try again later", + "menu": "Menu", "missing_brain": "Please select a brain to chat with", "new_discussion": "New discussion", "new_prompt": "Create new prompt", diff --git a/frontend/public/locales/es/chat.json b/frontend/public/locales/es/chat.json index c84eeb056fb1..dd512662ba8b 100644 --- a/frontend/public/locales/es/chat.json +++ b/frontend/public/locales/es/chat.json @@ -21,6 +21,7 @@ "last30Days": "Últimos 30 días", "last7Days": "Últimos 7 días", "limit_reached": "Has alcanzado el límite de peticiones, intente de nuevo más tarde", + "menu": "Menú", "missing_brain": "No hay cerebro seleccionado", "new_discussion": "Nueva discusión", "new_prompt": "Crear nueva instrucción", diff --git a/frontend/public/locales/fr/chat.json b/frontend/public/locales/fr/chat.json index f81535a516ee..4d871d7e88e2 100644 --- a/frontend/public/locales/fr/chat.json +++ b/frontend/public/locales/fr/chat.json @@ -21,6 +21,7 @@ "last30Days": "30 derniers jours", "last7Days": "7 derniers jours", "limit_reached": "Vous avez atteint la limite de requêtes, veuillez réessayer plus tard", + "menu": "Menu", "missing_brain": "Veuillez selectionner un cerveau pour discuter", "new_discussion": "Nouvelle discussion", "new_prompt": "Créer un nouveau prompt", diff --git a/frontend/public/locales/pt-br/chat.json b/frontend/public/locales/pt-br/chat.json index 062dc171331a..a50e3155beb1 100644 --- a/frontend/public/locales/pt-br/chat.json +++ b/frontend/public/locales/pt-br/chat.json @@ -21,6 +21,7 @@ "last30Days": "Últimos 30 dias", "last7Days": "Últimos 7 dias", "limit_reached": "Você atingiu o limite de solicitações, por favor, tente novamente mais tarde", + "menu": "Menu", "missing_brain": "Cérebro não encontrado", "new_discussion": "Nova discussão", "new_prompt": "Criar novo prompt", diff --git a/frontend/public/locales/ru/chat.json b/frontend/public/locales/ru/chat.json index 694b42e39885..c40c6896f85a 100644 --- a/frontend/public/locales/ru/chat.json +++ b/frontend/public/locales/ru/chat.json @@ -21,6 +21,7 @@ "last30Days": "Последние 30 дней", "last7Days": "Последние 7 дней", "limit_reached": "Вы достигли лимита запросов, пожалуйста, попробуйте позже", + "menu": "Меню", "missing_brain": "Мозг не найден", "new_discussion": "Новое обсуждение", "new_prompt": "Создать новый запрос", diff --git a/frontend/public/locales/zh-cn/chat.json b/frontend/public/locales/zh-cn/chat.json index 47bdcc601749..4ef9494860dc 100644 --- a/frontend/public/locales/zh-cn/chat.json +++ b/frontend/public/locales/zh-cn/chat.json @@ -22,6 +22,7 @@ "last30Days": "过去30天", "last7Days": "过去7天", "limit_reached": "您已达到请求限制,请稍后再试", + "menu": "菜单", "missing_brain": "请选择一个大脑进行聊天", "new_discussion": "新讨论", "new_prompt": "新提示", From 6fae24eebca17c49f7409ef60df49f14e68c8eeb Mon Sep 17 00:00:00 2001 From: mamadoudicko Date: Wed, 13 Dec 2023 15:11:36 +0100 Subject: [PATCH 4/4] feat: keep sidebar closed after page change --- frontend/lib/context/SidebarProvider/sidebar-provider.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/lib/context/SidebarProvider/sidebar-provider.tsx b/frontend/lib/context/SidebarProvider/sidebar-provider.tsx index a3eb7320cce4..503a32f6dd4d 100644 --- a/frontend/lib/context/SidebarProvider/sidebar-provider.tsx +++ b/frontend/lib/context/SidebarProvider/sidebar-provider.tsx @@ -1,4 +1,3 @@ -import { usePathname } from "next/navigation"; import { createContext, useEffect, useState } from "react"; import { useDevice } from "@/lib/hooks/useDevice"; @@ -19,11 +18,10 @@ export const SideBarProvider = ({ }): JSX.Element => { const { isMobile } = useDevice(); const [isOpened, setIsOpened] = useState(!isMobile); - const pathname = usePathname(); useEffect(() => { setIsOpened(!isMobile); - }, [isMobile, pathname]); + }, [isMobile]); return (