apps/nextjs-app/src/features/app/blocks/base/base-side-bar/BaseSidebarHeaderLeft.tsx
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { hasPermission } from '@teable/core';
import { ChevronsLeft, TeableNew, ChevronDown, Menu } from '@teable/icons';
import { CollaboratorType, deleteBase, updateBase } from '@teable/openapi';
import { ReactQueryKeys } from '@teable/sdk/config';
import { useBase } from '@teable/sdk/hooks';
import { Button, Input } from '@teable/ui-lib';
import { useRouter } from 'next/router';
import { useRef, useState } from 'react';
import { Emoji } from '@/features/app/components/emoji/Emoji';
import { BaseActionTrigger } from '../../space/component/BaseActionTrigger';
import { BaseListTrigger } from '../../space/component/BaseListTrigger';
export const BaseSidebarHeaderLeft = () => {
const base = useBase();
const router = useRouter();
const [renaming, setRenaming] = useState<boolean>();
const [baseName, setBaseName] = useState<string>(base.name);
const inputRef = useRef<HTMLInputElement>(null);
const queryClient = useQueryClient();
const { mutateAsync: updateBaseMutator } = useMutation({
mutationFn: updateBase,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ReactQueryKeys.base(base.id),
});
},
});
const { mutate: deleteBaseMutator } = useMutation({
mutationFn: deleteBase,
onSuccess: () => {
router.push({
pathname: '/space/[spaceId]',
query: { spaceId: base.spaceId },
});
},
});
const toggleRenameBase = async () => {
if (baseName && baseName !== base.name) {
await updateBaseMutator({
baseId: base.id,
updateBaseRo: { name: baseName },
});
}
setTimeout(() => setRenaming(false), 200);
};
const onRename = () => {
setRenaming(true);
setTimeout(() => inputRef.current?.focus(), 200);
};
const hasReadPermission = hasPermission(base.role, 'base|read');
const hasUpdatePermission = hasPermission(base.role, 'base|update');
const hasDeletePermission = hasPermission(base.role, 'base|delete');
const backSpace = () => {
if (base.collaboratorType === CollaboratorType.Base) {
router.push({
pathname: '/space/shared-base',
});
} else {
router.push({
pathname: '/space/[spaceId]',
query: { spaceId: base.spaceId },
});
}
};
return (
<div className="flex max-w-[calc(100%-28px)] shrink grow items-center">
<div
className="relative mr-2 size-6 shrink-0 cursor-pointer"
onClick={backSpace}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
backSpace();
}
}}
role="button"
tabIndex={0}
>
<div className="absolute top-0 size-6 transition-all group-hover/sidebar:opacity-0">
{base.icon ? (
<Emoji emoji={base.icon} size={'1.5rem'} />
) : (
<TeableNew className="size-6 text-black" />
)}
</div>
<ChevronsLeft className="absolute top-0 size-6 opacity-0 transition-all group-hover/sidebar:opacity-100" />
</div>
<div className="flex shrink grow items-center gap-1 overflow-hidden p-1">
{renaming ? (
<form
onSubmit={(e) => {
e.preventDefault();
toggleRenameBase();
}}
>
<Input
ref={inputRef}
className="h-7 flex-1 shrink"
value={baseName}
onChange={(e) => setBaseName(e.target.value)}
onBlur={toggleRenameBase}
/>
</form>
) : (
<p className="shrink truncate text-sm" title={base.name}>
{base.name}
</p>
)}
<BaseActionTrigger
base={base}
showRename={hasUpdatePermission}
showDuplicate={hasReadPermission}
showDelete={hasDeletePermission}
onDelete={() => deleteBaseMutator(base.id)}
onRename={onRename}
align="start"
>
<Button className="h-7 w-5 shrink-0 px-0" size="xs" variant="ghost">
<ChevronDown className="size-4" />
</Button>
</BaseActionTrigger>
</div>
<BaseListTrigger spaceId={base.spaceId} collaboratorType={base.collaboratorType}>
<Button className="h-7 w-5 shrink-0 px-0" size="xs" variant="ghost">
<Menu className="size-4" />
</Button>
</BaseListTrigger>
</div>
);
};