openreplay/frontend/app/components/Client/Projects/ProjectList.tsx
2025-01-09 15:21:17 +01:00

108 lines
3.2 KiB
TypeScript

import React from 'react';
import { Avatar, Button, Input, Menu, MenuProps, Progress, Typography } from 'antd';
import { useStore } from '@/mstore';
import Project from '@/mstore/types/project';
import { observer } from 'mobx-react-lite';
import { AppWindowMac, EditIcon, Smartphone } from 'lucide-react';
import { PencilIcon } from '.store/lucide-react-virtual-3cff663764/package';
import ProjectForm from 'Components/Client/Projects/ProjectForm';
import { useModal } from 'Components/ModalContext';
type MenuItem = Required<MenuProps>['items'][number];
const ProjectList: React.FC = () => {
const { projectsStore } = useStore();
const [search, setSearch] = React.useState('');
const { openModal, closeModal } = useModal();
const filteredProjects = projectsStore.list.filter((project: Project) =>
project.name.toLowerCase().includes(search.toLowerCase())
);
const handleSearch = (value: string) => setSearch(value);
const onClick: MenuProps['onClick'] = (e) => {
const pid = parseInt(e.key as string);
projectsStore.setConfigProject(pid);
};
const projectEditHandler = (e: React.MouseEvent, project: Project) => {
e.stopPropagation();
openModal(<ProjectForm onClose={closeModal} project={project} />, {
title: 'Edit Project'
});
};
const menuItems: MenuItem[] = filteredProjects.map((project) => ({
key: project.id + '',
label: <Typography.Text style={{ color: 'inherit' }} ellipsis={true}>{project.name}</Typography.Text>,
extra: <Button onClick={(e) => projectEditHandler(e, project)} className="opacity-0 group-hover:!opacity-100"
size="small" type="link" icon={<PencilIcon size={14} />} />,
className: 'group',
icon: (
<ProjectIconWithProgress
platform={project.platform}
progress={project.sampleRate}
/>
)
}));
return (
<div className="h-full flex flex-col gap-4">
<div className="px-4 mt-4">
<Input.Search
placeholder="Search projects"
onSearch={handleSearch}
onChange={(e) => setSearch(e.target.value)}
allowClear
/>
</div>
<div
className="overflow-y-auto"
style={{ height: 'calc(100vh - 250px)' }}
>
<Menu
mode="inline"
onClick={onClick}
selectedKeys={[String(projectsStore.config.pid)]}
className="w-full !bg-white !border-0"
inlineIndent={11}
items={menuItems}
/>
</div>
</div>
);
};
export default observer(ProjectList);
const ProjectIconWithProgress: React.FC<{
platform: string;
progress: number;
}> = ({ platform, progress }) => (
<div className="relative flex items-center justify-center mr-2 leading-none">
<Progress
type="circle"
percent={progress}
size={28}
format={() => ''}
strokeWidth={4}
strokeColor="#23959a"
/>
<div className="absolute">
<Avatar
className="bg-tealx-light"
size={26}
icon={
platform === 'web' ? (
<AppWindowMac size={16} color="teal" />
) : (
<Smartphone size={16} color="teal" />
)
}
/>
</div>
</div>
);