From 0b341a39cd3756bdc5c9073a6aa6affbb2810f51 Mon Sep 17 00:00:00 2001 From: saithsab877 Date: Fri, 7 Feb 2025 17:14:47 +0500 Subject: [PATCH 1/3] feat(sidebar): add toggle to switch between Graph Search and AI Chat --- public/svg-icons/ChatStarsIcon.svg | 3 + .../App/SideBar/AIChatSearch/index.tsx | 113 ++++++ src/components/App/SideBar/AiView/index.tsx | 23 +- .../App/SideBar/RegularView/index.tsx | 248 +----------- .../App/SideBar/SearchHeader/animation.tsx | 64 ++++ .../App/SideBar/SearchHeader/index.tsx | 359 ++++++++++++++++++ src/components/App/SideBar/index.tsx | 2 + src/components/Icons/ChatStarsIcon.tsx | 13 + src/components/SearchBar/index.tsx | 2 +- src/utils/colors/index.tsx | 1 + 10 files changed, 570 insertions(+), 258 deletions(-) create mode 100644 public/svg-icons/ChatStarsIcon.svg create mode 100644 src/components/App/SideBar/AIChatSearch/index.tsx create mode 100644 src/components/App/SideBar/SearchHeader/animation.tsx create mode 100644 src/components/App/SideBar/SearchHeader/index.tsx create mode 100644 src/components/Icons/ChatStarsIcon.tsx diff --git a/public/svg-icons/ChatStarsIcon.svg b/public/svg-icons/ChatStarsIcon.svg new file mode 100644 index 0000000000..12c8c21f2f --- /dev/null +++ b/public/svg-icons/ChatStarsIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/App/SideBar/AIChatSearch/index.tsx b/src/components/App/SideBar/AIChatSearch/index.tsx new file mode 100644 index 0000000000..7c506779e8 --- /dev/null +++ b/src/components/App/SideBar/AIChatSearch/index.tsx @@ -0,0 +1,113 @@ +import { Button } from '@mui/material' +import { useFormContext } from 'react-hook-form' +import styled from 'styled-components' +import ArrowForwardIcon from '~/components/Icons/ArrowForwardIcon' +import { colors } from '~/utils/colors' + +type Props = { + placeholder?: string + onSubmit?: (question: string) => void + onClick?: () => void +} + +const InputWrapper = styled.div` + position: relative; + width: 100%; + display: flex; + align-items: center; +` + +const StyledButton = styled(Button)` + z-index: 2; + && { + position: absolute; + right: 5px; + height: 32px; + border-radius: 16px; + min-width: 32px; + } + + &&.MuiButton-root { + padding: 0 10px 0 12px; + } + + svg { + margin-top: 1px; + width: 11px; + height: 11px; + } +` + +const Input = styled.input.attrs(() => ({ + autoCorrect: 'off', + autoComplete: 'off', +}))` + pointer-events: auto; + height: 40px; + padding: 0 48px 0 16px; + z-index: 2; + width: 100%; + color: #fff; + box-shadow: none; + border: none; + border-radius: 200px; + background: ${colors.BG2}; + + -webkit-autofill, + -webkit-autocomplete, + -webkit-contacts-auto-fill, + -webkit-credentials-auto-fill { + display: none !important; + visibility: hidden !important; + pointer-events: none !important; + position: absolute !important; + right: 0 !important; + } + + &:focus { + outline: 1px solid ${colors.primaryBlue}; + } + + &:hover { + background: ${colors.black}; + } + + &::placeholder { + color: ${colors.GRAY7}; + } +` + +export const AIChatInput = ({ placeholder = 'What do you want to know?', onSubmit, onClick }: Props) => { + const { register, watch } = useFormContext() + const typing = watch('aiChat') + const isTextEntered = typing?.trim().length > 0 + + return ( + + { + if (event.key === 'Enter' && typing?.trim() !== '' && onSubmit) { + onSubmit(typing) + } + }} + placeholder={placeholder} + type="text" + /> + { + if (isTextEntered && onSubmit) { + onSubmit(typing) + } + }} + variant="contained" + > + + + + ) +} diff --git a/src/components/App/SideBar/AiView/index.tsx b/src/components/App/SideBar/AiView/index.tsx index f94a4bf560..38259f4f98 100644 --- a/src/components/App/SideBar/AiView/index.tsx +++ b/src/components/App/SideBar/AiView/index.tsx @@ -1,10 +1,6 @@ -import { Button } from '@mui/material' -import { useNavigate } from 'react-router-dom' import styled from 'styled-components' -import ArrowBackIcon from '~/components/Icons/ArrowBackIcon' import { Flex } from '~/components/common/Flex' import { useAiSummaryStore } from '~/stores/useAiSummaryStore' -import { useDataStore } from '~/stores/useDataStore' import { colors } from '~/utils/colors' import { AiSearch } from '../AiSearch' import { AiSummary } from '../AiSummary' @@ -13,27 +9,10 @@ export const MENU_WIDTH = 390 // eslint-disable-next-line react/display-name export const AiView = () => { - const { aiSummaryAnswers, resetAiSummaryAnswer, newLoading, setNewLoading } = useAiSummaryStore((s) => s) - const { abortFetchData, resetGraph } = useDataStore((s) => s) - const navigate = useNavigate() - - const handleCloseAi = () => { - setNewLoading(null) - abortFetchData() - resetGraph() - resetAiSummaryAnswer() - navigate('/') - } + const { aiSummaryAnswers, newLoading } = useAiSummaryStore((s) => s) return ( - - - - - {Object.keys(aiSummaryAnswers) diff --git a/src/components/App/SideBar/RegularView/index.tsx b/src/components/App/SideBar/RegularView/index.tsx index 45eabeae08..01898d5cce 100644 --- a/src/components/App/SideBar/RegularView/index.tsx +++ b/src/components/App/SideBar/RegularView/index.tsx @@ -1,23 +1,9 @@ -import clsx from 'clsx' -import React, { useEffect, useRef, useState } from 'react' -import { useFormContext } from 'react-hook-form' -import { useNavigate, useSearchParams } from 'react-router-dom' -import { ClipLoader } from 'react-spinners' +import { useRef } from 'react' import styled from 'styled-components' -import { SelectWithPopover } from '~/components/App/SideBar/Dropdown' -import { FilterSearch } from '~/components/App/SideBar/FilterSearch' -import ClearIcon from '~/components/Icons/ClearIcon' -import SearchFilterCloseIcon from '~/components/Icons/SearchFilterCloseIcon' -import SearchFilterIcon from '~/components/Icons/SearchFilterIcon' -import SearchIcon from '~/components/Icons/SearchIcon' -import { SearchBar } from '~/components/SearchBar' import { Flex } from '~/components/common/Flex' -import { FetchLoaderText } from '~/components/common/Loader' import { useAppStore } from '~/stores/useAppStore' -import { useDataStore, useFilteredNodes } from '~/stores/useDataStore' +import { useDataStore } from '~/stores/useDataStore' import { useFeatureFlagStore } from '~/stores/useFeatureFlagStore' -import { useUpdateSelectedNode } from '~/stores/useGraphStore' -import { colors } from '~/utils/colors' import { LatestView } from '../Latest' import { Relevance } from '../Relevance' import { EpisodeSkeleton } from '../Relevance/EpisodeSkeleton' @@ -26,204 +12,27 @@ import { Trending } from '../Trending' export const MENU_WIDTH = 390 export const RegularView = () => { - const { isFetching: isLoading, setSidebarFilter } = useDataStore((s) => s) + const { isFetching: isLoading } = useDataStore((s) => s) - const setSelectedNode = useUpdateSelectedNode() - - const filteredNodes = useFilteredNodes() - - const { currentSearch: searchTerm, clearSearch, searchFormValue } = useAppStore((s) => s) + const { currentSearch: searchTerm } = useAppStore((s) => s) const [trendingTopicsFeatureFlag] = useFeatureFlagStore((s) => [s.trendingTopicsFeatureFlag]) - const { setValue, watch } = useFormContext() const componentRef = useRef(null) - const [isScrolled, setIsScrolled] = useState(false) - const [isFilterOpen, setIsFilterOpen] = useState(false) - const [anchorEl, setAnchorEl] = useState(null) - const [searchParams] = useSearchParams() - const query = searchParams.get('q') ?? '' - - useEffect(() => { - setValue('search', query || searchFormValue) - }, [setValue, searchFormValue, query]) - - useEffect(() => { - const component = componentRef.current - - if (!component) { - return - } - - const handleScroll = () => { - setIsScrolled(component?.scrollTop > 0) - } - - component.addEventListener('scroll', handleScroll) - }, []) - - const typing = watch('search') - - const handleFilterIconClick = (event: React.MouseEvent) => { - if (isFilterOpen) { - setAnchorEl(null) - } else { - setAnchorEl(event.currentTarget) - } - - setIsFilterOpen((prev) => !prev) - } - - const handleCloseFilterSearch = () => { - setIsFilterOpen(false) - setAnchorEl(null) - } - - const navigate = useNavigate() return ( - <> - - - - - { - if (searchTerm) { - setValue('search', '') - clearSearch() - setSidebarFilter('all') - setSelectedNode(null) - navigate(`/`) - - return - } - - if (typing.trim() === '') { - return - } - - const encodedQuery = typing.replace(/\s+/g, '+') - - navigate(`/search?q=${encodedQuery}`) - }} - > - {!isLoading ? ( - <>{searchTerm?.trim() ? : } - ) : ( - - )} - - - - - {isFilterOpen ? : } - - - - - {searchTerm && ( - - {isLoading ? ( - - ) : ( - <> -
- {filteredNodes.length} - results -
-
- -
- - )} -
- )} -
- - {!searchTerm && trendingTopicsFeatureFlag && ( - - - - )} - {!searchTerm && } - {isLoading ? : } - - + + {!searchTerm && trendingTopicsFeatureFlag && ( + + + + )} + {!searchTerm && } + {isLoading ? : } + ) } -const SearchWrapper = styled(Flex).attrs({ - direction: 'column', - justify: 'center', - align: 'stretch', -})(({ theme }) => ({ - padding: theme.spacing(3.75, 2), - [theme.breakpoints.up('sm')]: { - padding: '12px', - }, - - '&.has-shadow': { - borderBottom: '1px solid rgba(0, 0, 0, 0.25)', - background: colors.BG1, - boxShadow: '0px 1px 6px 0px rgba(0, 0, 0, 0.20)', - }, -})) - -const Search = styled(Flex).attrs({ - direction: 'row', - justify: 'center', - align: 'center', -})` - width: 85%; -` - -const SearchDetails = styled(Flex).attrs({ - direction: 'row', - justify: 'space-between', - align: 'center', -})` - flex-grow: 1; - color: ${colors.GRAY6}; - font-family: Barlow; - font-size: 13px; - font-style: normal; - font-weight: 400; - line-height: 18px; - margin-top: 10px; - padding: 0 8px; - .count { - color: ${colors.white}; - } - - .right { - display: flex; - } -` - -const InputButton = styled(Flex).attrs({ - align: 'center', - justify: 'center', - p: 5, -})` - font-size: 32px; - color: ${colors.mainBottomIcons}; - cursor: pointer; - transition-duration: 0.2s; - margin-left: -42px; - z-index: 2; - width: 30px; - - &:hover { - /* background-color: ${colors.gray200}; */ - } - - ${SearchWrapper} input:focus + & { - color: ${colors.primaryBlue}; - } -` - const ScrollWrapper = styled(Flex)(() => ({ overflow: 'auto', flex: 1, @@ -235,34 +44,3 @@ const TrendingWrapper = styled(Flex)` margin-bottom: 36px; margin-top: 20px; ` - -const SearchFilterIconWrapper = styled(Flex)` - align-items: center; - justify-content: space-between; - flex-direction: row; - gap: 10px; -` - -const IconWrapper = styled.div<{ isFilterOpen: boolean }>` - display: flex; - align-items: center; - justify-content: center; - transition: background-color 0.3s; - margin: 1px 2px 0 0; - border-radius: 8px; - width: 32px; - height: 32px; - background-color: ${({ isFilterOpen }) => (isFilterOpen ? colors.white : 'transparent')}; - - &:hover { - background-color: ${({ isFilterOpen }) => - isFilterOpen ? 'rgba(255, 255, 255, 0.85)' : 'rgba(255, 255, 255, 0.2)'}; - } - - svg { - width: 15px; - height: ${({ isFilterOpen }) => (isFilterOpen ? '11px' : '24px')}; - color: ${({ isFilterOpen }) => (isFilterOpen ? colors.black : colors.GRAY7)}; - fill: none; - } -` diff --git a/src/components/App/SideBar/SearchHeader/animation.tsx b/src/components/App/SideBar/SearchHeader/animation.tsx new file mode 100644 index 0000000000..66dac33531 --- /dev/null +++ b/src/components/App/SideBar/SearchHeader/animation.tsx @@ -0,0 +1,64 @@ +import styled, { keyframes } from 'styled-components' + +const slideInRight = keyframes` + from { + transform: translateX(100%) scale(0.98); + opacity: 0; + } + to { + transform: translateX(0) scale(1); + opacity: 1; + } +` + +const slideOutRight = keyframes` + from { + transform: translateX(0) scale(1); + opacity: 1; + } + to { + transform: translateX(100%) scale(0.98); + opacity: 0; + } +` + +const slideInLeft = keyframes` + from { + transform: translateX(-100%) scale(0.98); + opacity: 0; + } + to { + transform: translateX(0) scale(1); + opacity: 1; + } +` + +const slideOutLeft = keyframes` + from { + transform: translateX(0) scale(1); + opacity: 1; + } + to { + transform: translateX(-100%) scale(0.98); + opacity: 0; + } +` + +export const AnimatedSearchWrapper = styled.div<{ isAIChatActive: boolean }>` + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + transition: width 0.5s cubic-bezier(0.25, 1, 0.5, 1); + overflow: hidden; + + .search-section { + animation: ${({ isAIChatActive }) => (isAIChatActive ? slideOutLeft : slideInLeft)} 0.5s + cubic-bezier(0.25, 1, 0.5, 1); + } + + .ai-chat-section { + animation: ${({ isAIChatActive }) => (isAIChatActive ? slideInRight : slideOutRight)} 0.5s + cubic-bezier(0.25, 1, 0.5, 1); + } +` diff --git a/src/components/App/SideBar/SearchHeader/index.tsx b/src/components/App/SideBar/SearchHeader/index.tsx new file mode 100644 index 0000000000..97520c2c7c --- /dev/null +++ b/src/components/App/SideBar/SearchHeader/index.tsx @@ -0,0 +1,359 @@ +import clsx from 'clsx' +import { useEffect, useRef, useState } from 'react' +import { useFormContext } from 'react-hook-form' +import { useNavigate, useSearchParams } from 'react-router-dom' +import { ClipLoader } from 'react-spinners' +import styled from 'styled-components' +import { SelectWithPopover } from '~/components/App/SideBar/Dropdown' +import { FilterSearch } from '~/components/App/SideBar/FilterSearch' +import ChatStarsIcon from '~/components/Icons/ChatStarsIcon' +import ClearIcon from '~/components/Icons/ClearIcon' +import SearchFilterCloseIcon from '~/components/Icons/SearchFilterCloseIcon' +import SearchFilterIcon from '~/components/Icons/SearchFilterIcon' +import SearchIcon from '~/components/Icons/SearchIcon' +import { SearchBar } from '~/components/SearchBar' +import { Flex } from '~/components/common/Flex' +import { FetchLoaderText } from '~/components/common/Loader' +import { useAiSummaryStore } from '~/stores/useAiSummaryStore' +import { useAppStore } from '~/stores/useAppStore' +import { useDataStore, useFilteredNodes } from '~/stores/useDataStore' +import { useUpdateSelectedNode } from '~/stores/useGraphStore' +import { useUserStore } from '~/stores/useUserStore' +import { colors } from '~/utils/colors' +import { AIChatInput } from '../AIChatSearch' +import { AnimatedSearchWrapper } from './animation' + +export const SearchHeader = () => { + const { isFetching: isLoading, setSidebarFilter, abortFetchData } = useDataStore((s) => s) + const setSelectedNode = useUpdateSelectedNode() + const { setNewLoading } = useAiSummaryStore((s) => s) + const filteredNodes = useFilteredNodes() + const { currentSearch: searchTerm, clearSearch, searchFormValue } = useAppStore((s) => s) + + const { setValue, watch } = useFormContext() + const componentRef = useRef(null) + const [isScrolled, setIsScrolled] = useState(false) + const [isFilterOpen, setIsFilterOpen] = useState(false) + const [anchorEl, setAnchorEl] = useState(null) + const [searchParams] = useSearchParams() + const query = searchParams.get('q') ?? '' + const [isAIChatActive, setIsAIChatActive] = useState(false) + + const { setAbortRequests, resetData } = useDataStore((s) => s) + const [setBudget] = useUserStore((s) => [s.setBudget]) + + const resetAiSummaryAnswer = useAiSummaryStore((s) => s.resetAiSummaryAnswer) + const fetchAIData = useAiSummaryStore((s) => s.fetchAIData) + + const handleChatButtonClick = () => { + setIsAIChatActive(true) + } + + const handleCloseAi = () => { + setNewLoading(null) + abortFetchData() + resetAiSummaryAnswer() + navigate('/') + } + + const handleSearchIconClick = () => { + setIsAIChatActive(false) + handleCloseAi() + } + + useEffect(() => { + setValue('search', query || searchFormValue) + }, [setValue, searchFormValue, query]) + + useEffect(() => { + const component = componentRef.current + + if (!component) { + return + } + + const handleScroll = () => { + setIsScrolled(component?.scrollTop > 0) + } + + component.addEventListener('scroll', handleScroll) + }, []) + + const typing = watch('search') + + const handleFilterIconClick = (event: React.MouseEvent) => { + if (isFilterOpen) { + setAnchorEl(null) + } else { + setAnchorEl(event.currentTarget) + } + + setIsFilterOpen((prev) => !prev) + } + + const handleCloseFilterSearch = () => { + setIsFilterOpen(false) + setAnchorEl(null) + } + + const navigate = useNavigate() + + const handleSubmitQuestion = async (questionToSubmit: string) => { + if (questionToSubmit) { + resetAiSummaryAnswer() + resetData() + await fetchAIData(setBudget, setAbortRequests, questionToSubmit) + } + } + + return ( + + + + {isAIChatActive ? ( + + + + + + + ) : ( + <> + + + { + if (searchTerm) { + setValue('search', '') + clearSearch() + setSidebarFilter('all') + setSelectedNode(null) + navigate(`/`) + + return + } + + if (typing.trim() === '') { + return + } + + const encodedQuery = typing.replace(/\s+/g, '+') + + navigate(`/search?q=${encodedQuery}`) + }} + > + {!isLoading ? ( + <>{searchTerm?.trim() ? : } + ) : ( + + )} + + + + + {isFilterOpen ? : } + + + + + + + Chat + + + + + )} + + + {searchTerm && ( + + {isLoading ? ( + + ) : ( + <> +
+ {filteredNodes.length} + results +
+
+ +
+ + )} +
+ )} +
+ ) +} + +const SearchWrapper = styled(Flex).attrs({ + direction: 'column', + justify: 'center', + align: 'stretch', +})(({ theme }) => ({ + padding: theme.spacing(3.75, 2), + [theme.breakpoints.up('sm')]: { + padding: '12px', + }, + + '&.has-shadow': { + borderBottom: '1px solid rgba(0, 0, 0, 0.25)', + background: colors.BG1, + boxShadow: '0px 1px 6px 0px rgba(0, 0, 0, 0.20)', + }, +})) + +const Search = styled(Flex).attrs({ + direction: 'row', + justify: 'center', + align: 'center', +})` + width: 62%; + padding: 3px 0; +` + +const SearchDetails = styled(Flex).attrs({ + direction: 'row', + justify: 'space-between', + align: 'center', +})` + flex-grow: 1; + color: ${colors.GRAY6}; + font-family: Barlow; + font-size: 13px; + font-style: normal; + font-weight: 400; + line-height: 18px; + margin-top: 10px; + padding: 0 8px; + .count { + color: ${colors.white}; + } + + .right { + display: flex; + } +` + +const InputButton = styled(Flex).attrs({ + align: 'center', + justify: 'center', + p: 5, +})` + font-size: 32px; + color: ${colors.mainBottomIcons}; + cursor: pointer; + transition-duration: 0.2s; + margin-left: -42px; + z-index: 2; + width: 30px; + + &:hover { + /* background-color: ${colors.gray200}; */ + } + + ${SearchWrapper} input:focus + & { + color: ${colors.primaryBlue}; + } +` + +const SearchFilterIconWrapper = styled(Flex)` + align-items: center; + justify-content: space-between; + flex-direction: row; +` + +const IconWrapper = styled.div<{ isFilterOpen: boolean }>` + display: flex; + align-items: center; + justify-content: center; + transition: background-color 0.3s; + margin-left: 5px; + border: 1px solid ${colors.addAttributeBtn}; + cursor: pointer; + border-radius: ${({ isFilterOpen }) => (isFilterOpen ? '8px' : '50%')}; + width: ${({ isFilterOpen }) => (isFilterOpen ? '34px' : '40px')}; + height: ${({ isFilterOpen }) => (isFilterOpen ? '34px' : '40px')}; + background-color: ${({ isFilterOpen }) => (isFilterOpen ? colors.white : 'transparent')}; + + &:hover { + background-color: ${({ isFilterOpen }) => (isFilterOpen ? 'rgba(255, 255, 255, 0.85)' : 'transparent')}; + border-color: ${colors.GRAY_FILTER_ICON}; + } + + svg { + width: 15px; + height: ${({ isFilterOpen }) => (isFilterOpen ? '11px' : '24px')}; + color: ${({ isFilterOpen }) => (isFilterOpen ? colors.black : colors.GRAY7)}; + fill: none; + } +` + +const ChatButton = styled.button` + display: flex; + align-items: center; + gap: 6px; + background: ${colors.BUTTON1}; + border: none; + border-radius: 20px; + padding: 8px 14px; + color: ${colors.white}; + font-family: Barlow; + font-size: 15px; + font-weight: 600; + cursor: pointer; + transition: opacity 0.2s; + + &:hover { + background: ${colors.BUTTON1_HOVER}; + opacity: 0.9; + } +` + +const ChatIconWrapper = styled.div` + svg { + width: 20px; + height: 20px; + color: ${colors.white}; + fill: none; + margin-left: calc(0px - 3px); + } +` + +const SearchIconButton = styled.button` + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + border-radius: 50%; + background: ${colors.BG2}; + border: none; + cursor: pointer; + margin-right: 8px; + + svg { + width: 45px; + height: 45px; + color: ${colors.GRAY7}; + + &:hover { + color: ${colors.lightGray}; + } + } + + &:hover { + background: ${colors.black}; + } +` + +const AIChatSearch = styled(Flex).attrs({ + direction: 'row', + justify: 'center', + align: 'center', +})` + width: 100%; + padding: 3px 1px; +` diff --git a/src/components/App/SideBar/index.tsx b/src/components/App/SideBar/index.tsx index 5c756ad9a5..cd793f75e3 100644 --- a/src/components/App/SideBar/index.tsx +++ b/src/components/App/SideBar/index.tsx @@ -9,6 +9,7 @@ import { useSelectedNode } from '~/stores/useGraphStore' import { colors } from '~/utils/colors' import { AiView } from './AiView' import { RegularView } from './RegularView' +import { SearchHeader } from './SearchHeader' import { SideBarSubView } from './SidebarSubView' import { Tab } from './Tab' @@ -27,6 +28,7 @@ const Content = forwardRef(({ subViewOpen }, ref) = return ( + {!hasAiChats ? : } {!subViewOpen && ( > = (props) => ( + + + +) + +export default ChatStarsIcon diff --git a/src/components/SearchBar/index.tsx b/src/components/SearchBar/index.tsx index 57620ca04d..1459bd1faf 100644 --- a/src/components/SearchBar/index.tsx +++ b/src/components/SearchBar/index.tsx @@ -14,7 +14,7 @@ const Input = styled.input.attrs(() => ({ autoComplete: 'off', }))<{ loading?: boolean }>` pointer-events: auto; - height: 48px; + height: 40px; padding: 0 40px 0 18px; z-index: 2; box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.1); diff --git a/src/utils/colors/index.tsx b/src/utils/colors/index.tsx index a89298aa1b..9426461885 100644 --- a/src/utils/colors/index.tsx +++ b/src/utils/colors/index.tsx @@ -112,6 +112,7 @@ export const colors = { INPUT_BG: 'rgba(255, 255, 255, 0.05)', INPUT_PLACEHOLDER: 'rgba(255, 255, 255, 0.5)', HOVER_CARD_BG: 'rgba(41, 44, 54, 1)', + GRAY_FILTER_ICON: 'rgba(70,79,93,255)', } as const export type ColorName = keyof typeof colors From 07c1707b551bfcc9a8e9a7251eae0f2589e14c29 Mon Sep 17 00:00:00 2001 From: saithsab877 Date: Fri, 7 Feb 2025 17:52:30 +0500 Subject: [PATCH 2/3] fix(unit): unit test --- .../{RegularView => SearchHeader}/__tests__/index.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename src/components/App/SideBar/{RegularView => SearchHeader}/__tests__/index.tsx (91%) diff --git a/src/components/App/SideBar/RegularView/__tests__/index.tsx b/src/components/App/SideBar/SearchHeader/__tests__/index.tsx similarity index 91% rename from src/components/App/SideBar/RegularView/__tests__/index.tsx rename to src/components/App/SideBar/SearchHeader/__tests__/index.tsx index 7fe372b7b1..6039522a2c 100644 --- a/src/components/App/SideBar/RegularView/__tests__/index.tsx +++ b/src/components/App/SideBar/SearchHeader/__tests__/index.tsx @@ -4,7 +4,7 @@ import React, { ReactElement } from 'react' import { FormProvider, useForm, useFormContext } from 'react-hook-form' import { MemoryRouter } from 'react-router-dom' import { ThemeProvider as StyleThemeProvider } from 'styled-components' -import { RegularView } from '..' +import { SearchHeader } from '..' import { appTheme } from '../../../Providers' const QUERY_SEARCH = 'satoshi' @@ -48,7 +48,7 @@ const renderWithProviders = (ui: ReactElement): RenderResult => { ) } -describe('RegularView Component', () => { +describe('SearchHeader Component', () => { let setValueMock: jest.Mock beforeEach(() => { @@ -64,12 +64,12 @@ describe('RegularView Component', () => { }) it('should call setValue with "search" and the correct query value on mount', () => { - renderWithProviders() + renderWithProviders() expect(setValueMock).toHaveBeenCalledWith('search', QUERY_SEARCH) }) it('should display the correct search query in the input field', () => { - const { queryByTestId } = renderWithProviders() + const { queryByTestId } = renderWithProviders() const searchInput = queryByTestId('search_input') as HTMLInputElement expect(searchInput.value).toBe(QUERY_SEARCH) From bc3b5364477ff5e37efbdd6177bea0c4a5a2be57 Mon Sep 17 00:00:00 2001 From: saithsab877 Date: Fri, 7 Feb 2025 18:45:10 +0500 Subject: [PATCH 3/3] fix(useUserStore): correct useUserStore selector in SearchHeader --- src/components/App/SideBar/SearchHeader/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/App/SideBar/SearchHeader/index.tsx b/src/components/App/SideBar/SearchHeader/index.tsx index 97520c2c7c..80d9fbf18b 100644 --- a/src/components/App/SideBar/SearchHeader/index.tsx +++ b/src/components/App/SideBar/SearchHeader/index.tsx @@ -40,7 +40,7 @@ export const SearchHeader = () => { const [isAIChatActive, setIsAIChatActive] = useState(false) const { setAbortRequests, resetData } = useDataStore((s) => s) - const [setBudget] = useUserStore((s) => [s.setBudget]) + const { setBudget } = useUserStore((s) => s) const resetAiSummaryAnswer = useAiSummaryStore((s) => s.resetAiSummaryAnswer) const fetchAIData = useAiSummaryStore((s) => s.fetchAIData)