diff --git a/src/app/(main)/TopNav.tsx b/src/app/(main)/TopNav.tsx index d93f590e9..302f0a2f7 100644 --- a/src/app/(main)/TopNav.tsx +++ b/src/app/(main)/TopNav.tsx @@ -2,13 +2,14 @@ import { Icon, Row } from '@umami/react-zen'; import { useNavigation } from '@/components/hooks'; import { Slash } from '@/components/icons'; +import { BoardSelect } from '@/components/input/BoardSelect'; import { LinkSelect } from '@/components/input/LinkSelect'; import { PixelSelect } from '@/components/input/PixelSelect'; import { TeamsButton } from '@/components/input/TeamsButton'; import { WebsiteSelect } from '@/components/input/WebsiteSelect'; export function TopNav() { - const { websiteId, linkId, pixelId, teamId, router, renderUrl } = useNavigation(); + const { websiteId, linkId, pixelId, boardId, teamId, router, renderUrl } = useNavigation(); const handleWebsiteChange = (value: string) => { router.push(renderUrl(`/websites/${value}`)); @@ -22,6 +23,10 @@ export function TopNav() { router.push(renderUrl(`/pixels/${value}`)); }; + const handleBoardChange = (value: string) => { + router.push(renderUrl(`/boards/${value}`)); + }; + return ( - {(websiteId || linkId || pixelId) && ( + {(websiteId || linkId || pixelId || boardId) && ( <> @@ -74,6 +79,17 @@ export function TopNav() { }} /> )} + {boardId && ( + + )} )} diff --git a/src/components/hooks/queries/useBoardsQuery.ts b/src/components/hooks/queries/useBoardsQuery.ts index bd7210838..d570ccc47 100644 --- a/src/components/hooks/queries/useBoardsQuery.ts +++ b/src/components/hooks/queries/useBoardsQuery.ts @@ -3,14 +3,21 @@ import { useApi } from '../useApi'; import { useModified } from '../useModified'; import { usePagedQuery } from '../usePagedQuery'; -export function useBoardsQuery({ teamId }: { teamId?: string }, options?: ReactQueryOptions) { +export function useBoardsQuery( + { teamId }: { teamId?: string }, + params?: Record, + options?: ReactQueryOptions, +) { const { modified } = useModified('boards'); const { get } = useApi(); return usePagedQuery({ - queryKey: ['boards', { teamId, modified }], + queryKey: ['boards', { teamId, modified, ...params }], queryFn: pageParams => { - return get(teamId ? `/teams/${teamId}/boards` : '/boards', pageParams); + return get(teamId ? `/teams/${teamId}/boards` : '/boards', { + ...pageParams, + ...params, + }); }, ...options, }); diff --git a/src/components/hooks/useNavigation.ts b/src/components/hooks/useNavigation.ts index 6480c8ecf..28eca3197 100644 --- a/src/components/hooks/useNavigation.ts +++ b/src/components/hooks/useNavigation.ts @@ -10,6 +10,7 @@ export function useNavigation() { const [, websiteId] = pathname.match(/\/websites\/([a-f0-9-]+)/) || []; const [, linkId] = pathname.match(/\/links\/([a-f0-9-]+)/) || []; const [, pixelId] = pathname.match(/\/pixels\/([a-f0-9-]+)/) || []; + const [, boardId] = pathname.match(/\/boards\/([a-f0-9-]+)/) || []; const [queryParams, setQueryParams] = useState(Object.fromEntries(searchParams)); const updateParams = (params?: Record) => { @@ -40,6 +41,7 @@ export function useNavigation() { websiteId, linkId, pixelId, + boardId, updateParams, replaceParams, renderUrl, diff --git a/src/components/input/BoardSelect.tsx b/src/components/input/BoardSelect.tsx new file mode 100644 index 000000000..b8fbf3a6a --- /dev/null +++ b/src/components/input/BoardSelect.tsx @@ -0,0 +1,93 @@ +import { Icon, ListItem, Row, Select, type SelectProps, Text } from '@umami/react-zen'; +import { useEffect, useState } from 'react'; +import { Empty } from '@/components/common/Empty'; +import { useBoardQuery, useBoardsQuery, useMessages } from '@/components/hooks'; +import { LayoutDashboard } from '@/components/icons'; + +export function BoardSelect({ + boardId, + teamId, + onChange, + isCollapsed, + buttonProps, + listProps, + ...props +}: { + boardId?: string; + teamId?: string; + isCollapsed?: boolean; +} & SelectProps) { + const { t, messages } = useMessages(); + const { data: board } = useBoardQuery(boardId); + const [name, setName] = useState(board?.name); + const [search, setSearch] = useState(''); + const { data, isLoading } = useBoardsQuery({ teamId }, { search, pageSize: 20 }); + const listItems: { id: string; name: string }[] = data?.data || []; + + useEffect(() => { + setName(board?.name); + }, [board?.name]); + + const handleOpenChange = () => { + setSearch(''); + }; + + const handleChange = (id: string) => { + setName(listItems.find(item => item.id === id)?.name); + onChange?.(id); + }; + + const renderValue = () => { + if (isCollapsed) { + return ''; + } + + return ( + + + + + {name} + + ); + }; + + return ( + + ); +} diff --git a/src/components/input/WebsiteSelect.tsx b/src/components/input/WebsiteSelect.tsx index f4a03c8d9..02198a99c 100644 --- a/src/components/input/WebsiteSelect.tsx +++ b/src/components/input/WebsiteSelect.tsx @@ -1,5 +1,5 @@ import { Icon, ListItem, Row, Select, type SelectProps, Text } from '@umami/react-zen'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { Empty } from '@/components/common/Empty'; import { useLoginQuery, @@ -35,6 +35,10 @@ export function WebsiteSelect({ ); const listItems: { id: string; name: string }[] = data?.data || []; + useEffect(() => { + setName(website?.name); + }, [website?.name]); + const handleSearch = (value: string) => { setSearch(value); };