2025-03-01 07:17:24 +08:00
|
|
|
'use client';
|
|
|
|
|
2025-03-01 06:02:54 +08:00
|
|
|
import React, { useMemo } from 'react';
|
|
|
|
import { Sidebar } from '@/components/ui/sidebar/Sidebar';
|
|
|
|
import { BusterLogoWithText } from '@/assets/svg/BusterLogoWithText';
|
|
|
|
import { BusterRoutes, createBusterRoute } from '@/routes';
|
2025-03-01 06:31:24 +08:00
|
|
|
import type { ISidebarGroup, ISidebarList, SidebarProps } from '@/components/ui/sidebar';
|
2025-03-01 06:02:54 +08:00
|
|
|
import { BookOpen4, Flag, Gear, House4, Table, UnorderedList2, Plus } from '@/components/ui/icons';
|
2025-03-01 06:31:24 +08:00
|
|
|
import { PencilSquareIcon } from '@/components/ui/icons/customIcons/Pencil_Square';
|
2025-03-01 06:02:54 +08:00
|
|
|
import { ASSET_ICONS, assetTypeToIcon, assetTypeToRoute } from '../config/assetIcons';
|
|
|
|
import type { BusterUserFavorite } from '@/api/asset_interfaces/users';
|
|
|
|
import { Button } from '@/components/ui/buttons';
|
|
|
|
import { Tooltip } from '@/components/ui/tooltip/Tooltip';
|
|
|
|
import Link from 'next/link';
|
2025-03-01 07:17:24 +08:00
|
|
|
import { useUserConfigContextSelector } from '@/context/Users';
|
|
|
|
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
|
2025-03-01 08:11:40 +08:00
|
|
|
import { SupportModal } from '../modal/SupportModal';
|
|
|
|
import { InvitePeopleModal } from '../modal/InvitePeopleModal';
|
|
|
|
import { useMemoizedFn } from 'ahooks';
|
2025-03-01 06:02:54 +08:00
|
|
|
|
|
|
|
const topItems: ISidebarList = {
|
|
|
|
items: [
|
|
|
|
{
|
|
|
|
label: 'Home',
|
|
|
|
icon: <House4 />,
|
|
|
|
route: BusterRoutes.APP_HOME,
|
|
|
|
id: BusterRoutes.APP_HOME
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: 'Chat history',
|
|
|
|
icon: <ASSET_ICONS.chats />,
|
|
|
|
route: BusterRoutes.APP_CHAT,
|
|
|
|
id: BusterRoutes.APP_CHAT
|
|
|
|
}
|
|
|
|
]
|
|
|
|
};
|
|
|
|
|
|
|
|
const yourStuff: ISidebarGroup = {
|
|
|
|
label: 'Your stuffs',
|
|
|
|
items: [
|
|
|
|
{
|
|
|
|
label: 'Metrics',
|
|
|
|
icon: <ASSET_ICONS.metrics />,
|
|
|
|
route: BusterRoutes.APP_METRIC,
|
|
|
|
id: BusterRoutes.APP_METRIC
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: 'Dashboards',
|
|
|
|
icon: <ASSET_ICONS.dashboards />,
|
|
|
|
route: BusterRoutes.APP_DASHBOARDS,
|
|
|
|
id: BusterRoutes.APP_DASHBOARDS
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: 'Collections',
|
|
|
|
icon: <ASSET_ICONS.collections />,
|
|
|
|
route: BusterRoutes.APP_COLLECTIONS,
|
|
|
|
id: BusterRoutes.APP_COLLECTIONS
|
|
|
|
}
|
|
|
|
]
|
|
|
|
};
|
|
|
|
|
|
|
|
const adminTools: ISidebarGroup = {
|
|
|
|
label: 'Admin tools',
|
|
|
|
items: [
|
|
|
|
{
|
|
|
|
label: 'Logs',
|
|
|
|
icon: <UnorderedList2 />,
|
|
|
|
route: BusterRoutes.APP_LOGS,
|
|
|
|
id: BusterRoutes.APP_LOGS
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: 'Terms & Definitions',
|
|
|
|
icon: <BookOpen4 />,
|
|
|
|
route: BusterRoutes.APP_TERMS,
|
|
|
|
id: BusterRoutes.APP_TERMS
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: 'Datasets',
|
|
|
|
icon: <Table />,
|
|
|
|
route: BusterRoutes.APP_DATASETS,
|
|
|
|
id: BusterRoutes.APP_DATASETS
|
|
|
|
}
|
|
|
|
]
|
|
|
|
};
|
|
|
|
|
|
|
|
const tryGroup = (onClickInvitePeople: () => void, onClickLeaveFeedback: () => void) => ({
|
|
|
|
label: 'Try',
|
|
|
|
items: [
|
|
|
|
{
|
|
|
|
label: 'Invite people',
|
|
|
|
icon: <Plus />,
|
|
|
|
route: null,
|
|
|
|
id: 'invite-people',
|
|
|
|
onClick: onClickInvitePeople
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: 'Leave feedback',
|
|
|
|
icon: <Flag />,
|
|
|
|
route: null,
|
|
|
|
id: 'leave-feedback',
|
|
|
|
onClick: onClickLeaveFeedback
|
|
|
|
}
|
|
|
|
]
|
|
|
|
});
|
|
|
|
|
2025-03-01 07:17:24 +08:00
|
|
|
export const SidebarPrimary = React.memo(() => {
|
|
|
|
const isAdmin = useUserConfigContextSelector((x) => x.isAdmin);
|
|
|
|
const favorites = useUserConfigContextSelector((state) => state.userFavorites);
|
|
|
|
const currentRoute = useAppLayoutContextSelector((x) => x.currentRoute);
|
|
|
|
const onToggleSupportModal = useAppLayoutContextSelector((s) => s.onToggleSupportModal);
|
|
|
|
const onToggleInviteModal = useAppLayoutContextSelector((s) => s.onToggleInviteModal);
|
|
|
|
|
2025-03-01 06:28:12 +08:00
|
|
|
const sidebarItems: SidebarProps['content'] = useMemo(() => {
|
|
|
|
const items = [topItems];
|
2025-03-01 06:02:54 +08:00
|
|
|
|
2025-03-01 06:28:12 +08:00
|
|
|
if (isAdmin) {
|
|
|
|
items.push(adminTools);
|
|
|
|
}
|
2025-03-01 06:02:54 +08:00
|
|
|
|
2025-03-01 06:28:12 +08:00
|
|
|
items.push(yourStuff);
|
2025-03-01 06:02:54 +08:00
|
|
|
|
2025-03-01 06:28:12 +08:00
|
|
|
if (favorites && favorites.length > 0) {
|
|
|
|
items.push(favoritesDropdown(favorites));
|
|
|
|
}
|
2025-03-01 06:02:54 +08:00
|
|
|
|
2025-03-01 07:17:24 +08:00
|
|
|
items.push(tryGroup(onToggleInviteModal, onToggleSupportModal));
|
2025-03-01 06:02:54 +08:00
|
|
|
|
2025-03-01 06:28:12 +08:00
|
|
|
return items;
|
2025-03-01 07:17:24 +08:00
|
|
|
}, [isAdmin, favorites, currentRoute]);
|
2025-03-01 06:02:54 +08:00
|
|
|
|
2025-03-01 06:28:12 +08:00
|
|
|
return (
|
2025-03-01 08:11:40 +08:00
|
|
|
<>
|
|
|
|
<Sidebar content={sidebarItems} header={<SidebarPrimaryHeader />} activeItem={currentRoute} />
|
|
|
|
|
|
|
|
<GlobalModals />
|
|
|
|
</>
|
2025-03-01 06:28:12 +08:00
|
|
|
);
|
|
|
|
});
|
2025-03-01 06:02:54 +08:00
|
|
|
|
|
|
|
SidebarPrimary.displayName = 'SidebarPrimary';
|
|
|
|
|
|
|
|
const SidebarPrimaryHeader = React.memo(() => {
|
|
|
|
return (
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
<BusterLogoWithText />
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
<Tooltip title="Settings">
|
2025-03-02 13:13:50 +08:00
|
|
|
<Link href={createBusterRoute({ route: BusterRoutes.SETTINGS_PROFILE })}>
|
2025-03-01 06:02:54 +08:00
|
|
|
<Button prefix={<Gear />} variant="ghost" />
|
|
|
|
</Link>
|
|
|
|
</Tooltip>
|
|
|
|
<Tooltip title="Start a chat">
|
2025-03-04 05:25:51 +08:00
|
|
|
<Link href={createBusterRoute({ route: BusterRoutes.APP_HOME })}>
|
2025-03-01 06:02:54 +08:00
|
|
|
<Button
|
|
|
|
size="tall"
|
|
|
|
rounding={'large'}
|
|
|
|
prefix={
|
2025-03-04 05:25:51 +08:00
|
|
|
<div className="flex items-center justify-center">
|
2025-03-01 06:02:54 +08:00
|
|
|
<PencilSquareIcon />
|
|
|
|
</div>
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
</Link>
|
|
|
|
</Tooltip>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2025-03-01 06:31:24 +08:00
|
|
|
SidebarPrimaryHeader.displayName = 'SidebarPrimaryHeader';
|
|
|
|
|
2025-03-01 08:11:40 +08:00
|
|
|
const GlobalModals = React.memo(() => {
|
|
|
|
const onToggleSupportModal = useAppLayoutContextSelector((s) => s.onToggleSupportModal);
|
|
|
|
const onToggleInviteModal = useAppLayoutContextSelector((s) => s.onToggleInviteModal);
|
|
|
|
const openSupportModal = useAppLayoutContextSelector((s) => s.openSupportModal);
|
|
|
|
const openInviteModal = useAppLayoutContextSelector((s) => s.openInviteModal);
|
|
|
|
const isAnonymousUser = useUserConfigContextSelector((state) => state.isAnonymousUser);
|
|
|
|
|
|
|
|
const onCloseInviteModal = useMemoizedFn(() => onToggleInviteModal(false));
|
|
|
|
const onCloseSupportModal = useMemoizedFn(() => onToggleSupportModal(false));
|
|
|
|
|
|
|
|
if (isAnonymousUser) return null;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<InvitePeopleModal open={openInviteModal} onClose={onCloseInviteModal} />
|
|
|
|
<SupportModal open={openSupportModal} onClose={onCloseSupportModal} />
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
});
|
2025-03-01 08:12:56 +08:00
|
|
|
GlobalModals.displayName = 'GlobalModals';
|
|
|
|
|
2025-03-01 06:02:54 +08:00
|
|
|
const favoritesDropdown = (favorites: BusterUserFavorite[]): ISidebarGroup => {
|
|
|
|
return {
|
|
|
|
label: 'Favorites',
|
|
|
|
items: favorites.map((favorite) => {
|
|
|
|
const Icon = assetTypeToIcon(favorite.asset_type);
|
|
|
|
const route = assetTypeToRoute(favorite.asset_type, favorite.id);
|
|
|
|
return {
|
|
|
|
label: favorite.name,
|
|
|
|
icon: <Icon />,
|
|
|
|
route,
|
|
|
|
id: route
|
|
|
|
};
|
|
|
|
})
|
|
|
|
};
|
|
|
|
};
|