2024-12-06 13:36:56 +03:00
|
|
|
'use client';
|
|
|
|
|
|
2025-05-01 17:47:48 -07:00
|
|
|
import { type ReactNode, useMemo, useState } from 'react';
|
2024-12-06 13:36:56 +03:00
|
|
|
import { Button } from '@/components/ui/button';
|
|
|
|
|
import {
|
|
|
|
|
DropdownMenu,
|
|
|
|
|
DropdownMenuContent,
|
|
|
|
|
DropdownMenuItem,
|
|
|
|
|
DropdownMenuTrigger,
|
|
|
|
|
} from '@/components/ui/dropdown-menu';
|
|
|
|
|
import { cn } from '@/lib/utils';
|
|
|
|
|
import {
|
2024-12-06 17:40:41 +03:00
|
|
|
CheckCircleFillIcon,
|
2024-12-06 13:36:56 +03:00
|
|
|
ChevronDownIcon,
|
|
|
|
|
GlobeIcon,
|
|
|
|
|
LockIcon,
|
|
|
|
|
} from './icons';
|
|
|
|
|
import { useChatVisibility } from '@/hooks/use-chat-visibility';
|
|
|
|
|
|
|
|
|
|
export type VisibilityType = 'private' | 'public';
|
|
|
|
|
|
|
|
|
|
const visibilities: Array<{
|
|
|
|
|
id: VisibilityType;
|
|
|
|
|
label: string;
|
|
|
|
|
description: string;
|
|
|
|
|
icon: ReactNode;
|
|
|
|
|
}> = [
|
|
|
|
|
{
|
|
|
|
|
id: 'private',
|
|
|
|
|
label: 'Private',
|
|
|
|
|
description: 'Only you can access this chat',
|
|
|
|
|
icon: <LockIcon />,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'public',
|
|
|
|
|
label: 'Public',
|
|
|
|
|
description: 'Anyone with the link can access this chat',
|
|
|
|
|
icon: <GlobeIcon />,
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
export function VisibilitySelector({
|
|
|
|
|
chatId,
|
|
|
|
|
className,
|
|
|
|
|
selectedVisibilityType,
|
|
|
|
|
}: {
|
|
|
|
|
chatId: string;
|
|
|
|
|
selectedVisibilityType: VisibilityType;
|
|
|
|
|
} & React.ComponentProps<typeof Button>) {
|
|
|
|
|
const [open, setOpen] = useState(false);
|
|
|
|
|
|
|
|
|
|
const { visibilityType, setVisibilityType } = useChatVisibility({
|
|
|
|
|
chatId,
|
2025-05-01 17:47:48 -07:00
|
|
|
initialVisibilityType: selectedVisibilityType,
|
2024-12-06 13:36:56 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const selectedVisibility = useMemo(
|
|
|
|
|
() => visibilities.find((visibility) => visibility.id === visibilityType),
|
|
|
|
|
[visibilityType],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<DropdownMenu open={open} onOpenChange={setOpen}>
|
|
|
|
|
<DropdownMenuTrigger
|
|
|
|
|
asChild
|
|
|
|
|
className={cn(
|
|
|
|
|
'w-fit data-[state=open]:bg-accent data-[state=open]:text-accent-foreground',
|
|
|
|
|
className,
|
|
|
|
|
)}
|
|
|
|
|
>
|
|
|
|
|
<Button
|
2025-05-01 17:47:48 -07:00
|
|
|
data-testid="visibility-selector"
|
2024-12-06 13:36:56 +03:00
|
|
|
variant="outline"
|
|
|
|
|
className="hidden md:flex md:px-2 md:h-[34px]"
|
|
|
|
|
>
|
|
|
|
|
{selectedVisibility?.icon}
|
|
|
|
|
{selectedVisibility?.label}
|
|
|
|
|
<ChevronDownIcon />
|
|
|
|
|
</Button>
|
|
|
|
|
</DropdownMenuTrigger>
|
|
|
|
|
|
|
|
|
|
<DropdownMenuContent align="start" className="min-w-[300px]">
|
|
|
|
|
{visibilities.map((visibility) => (
|
|
|
|
|
<DropdownMenuItem
|
2025-05-01 17:47:48 -07:00
|
|
|
data-testid={`visibility-selector-item-${visibility.id}`}
|
2024-12-06 13:36:56 +03:00
|
|
|
key={visibility.id}
|
|
|
|
|
onSelect={() => {
|
|
|
|
|
setVisibilityType(visibility.id);
|
|
|
|
|
setOpen(false);
|
|
|
|
|
}}
|
|
|
|
|
className="gap-4 group/item flex flex-row justify-between items-center"
|
|
|
|
|
data-active={visibility.id === visibilityType}
|
|
|
|
|
>
|
|
|
|
|
<div className="flex flex-col gap-1 items-start">
|
|
|
|
|
{visibility.label}
|
|
|
|
|
{visibility.description && (
|
|
|
|
|
<div className="text-xs text-muted-foreground">
|
|
|
|
|
{visibility.description}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
2024-12-17 15:36:51 +05:30
|
|
|
<div className="text-foreground dark:text-foreground opacity-0 group-data-[active=true]/item:opacity-100">
|
2024-12-06 17:40:41 +03:00
|
|
|
<CheckCircleFillIcon />
|
2024-12-06 13:36:56 +03:00
|
|
|
</div>
|
|
|
|
|
</DropdownMenuItem>
|
|
|
|
|
))}
|
|
|
|
|
</DropdownMenuContent>
|
|
|
|
|
</DropdownMenu>
|
|
|
|
|
);
|
|
|
|
|
}
|