snowballtools-base/packages/frontend/src/components/Sidebar.tsx

128 lines
4.3 KiB
TypeScript
Raw Normal View History

import React, { useCallback, useEffect, useState } from 'react';
import { Link, NavLink, useNavigate, useParams } from 'react-router-dom';
import { Organization } from 'gql-client';
2024-02-26 22:45:04 +00:00
import { Option } from '@material-tailwind/react';
import { useDisconnect } from 'wagmi';
import { useGQLClient } from '../context/GQLClientContext';
import AsyncSelect from './shared/AsyncSelect';
2024-02-26 22:45:04 +00:00
import { ChevronGrabberHorizontal, GlobeIcon } from './shared/CustomIcon';
import { Tabs } from 'components/shared/Tabs';
const Sidebar = () => {
const { orgSlug } = useParams();
const navigate = useNavigate();
const client = useGQLClient();
const { disconnect } = useDisconnect();
const [selectedOrgSlug, setSelectedOrgSlug] = useState(orgSlug);
const [organizations, setOrganizations] = useState<Organization[]>([]);
const fetchUserOrganizations = useCallback(async () => {
const { organizations } = await client.getOrganizations();
setOrganizations(organizations);
}, [orgSlug]);
useEffect(() => {
fetchUserOrganizations();
setSelectedOrgSlug(orgSlug);
}, [orgSlug]);
const handleLogOut = useCallback(() => {
disconnect();
navigate('/login');
}, [disconnect, navigate]);
return (
2024-02-26 22:45:04 +00:00
<div className="flex flex-col h-full p-4 mt-5">
<div className="grow">
2024-02-26 22:45:04 +00:00
<Link to={`/${orgSlug}`}>
<div className="flex items-center space-x-3 mb-10 ml-2">
<img
src="/logo.svg"
alt="Snowball Logo"
className="h-8 w-8 rounded-lg"
/>
<span className="text-2xl font-bold text-snowball-900">
Snowball
</span>
</div>
</Link>
<AsyncSelect
2024-02-26 22:45:04 +00:00
className="bg-white rounded-lg shadow"
value={selectedOrgSlug}
onChange={(value) => {
setSelectedOrgSlug(value!);
navigate(`/${value}`);
}}
selected={(_, index) => (
2024-02-26 22:45:04 +00:00
<div className="flex items-center space-x-3">
<img
src="/logo.svg"
alt="Application Logo"
className="h-8 w-8 rounded-lg"
/>
<div>
2024-02-26 22:45:04 +00:00
<div className="text-sm font-semibold">
{organizations[index!]?.name}
</div>
<div className="text-xs text-gray-500">Organization</div>
</div>
</div>
)}
2024-02-26 22:45:04 +00:00
arrow={<ChevronGrabberHorizontal className="h-4 w-4 text-gray-500" />}
>
{/* TODO: Show label organization and manage in option */}
{organizations.map((org) => (
<Option key={org.id} value={org.slug}>
2024-02-26 22:45:04 +00:00
<div className="flex items-center space-x-3">
<img
src="/logo.svg"
alt="Application Logo"
className="h-8 w-8 rounded-lg"
/>
<div>
<div className="text-sm font-semibold">{org.name}</div>
<div className="text-xs text-gray-500">Organization</div>
</div>
</div>
</Option>
))}
</AsyncSelect>
2024-02-26 22:45:04 +00:00
<Tabs defaultValue="Projects" orientation="vertical" className="mt-5">
<Tabs.List>
{['Projects', 'Settings'].slice(0, 2).map((title, index) => (
<NavLink to={`/${orgSlug}/${title}`} key={index}>
<Tabs.Trigger icon={<GlobeIcon />} value={title}>
{title}
</Tabs.Trigger>
</NavLink>
))}
</Tabs.List>
</Tabs>
</div>
2024-02-26 22:45:04 +00:00
<div className="grow flex flex-col justify-end mb-10">
<Tabs defaultValue="Projects" orientation="vertical">
{/* TODO: use proper link buttons */}
<Tabs.List>
<Tabs.Trigger icon={<GlobeIcon />} value="">
<a className="cursor-pointer" onClick={handleLogOut}>
Log Out
</a>
</Tabs.Trigger>
<Tabs.Trigger icon={<GlobeIcon />} value="">
<a className="cursor-pointer">Documentation</a>
</Tabs.Trigger>
<Tabs.Trigger icon={<GlobeIcon />} value="">
<a className="cursor-pointer">Support</a>
</Tabs.Trigger>
</Tabs.List>
</Tabs>
</div>
</div>
);
};
export default Sidebar;