arm-web/src/widgets/CompanyGroupsList/CompanyGroupsList.tsx
2026-10-12 17:48:14 +03:00

187 lines
6.1 KiB
TypeScript

import { useEffect, useMemo, useState } from "react";
import { Input, List, Spin, Empty, Typography, Tag } from "antd";
import { FolderOpenOutlined, SearchOutlined } from "@ant-design/icons";
import { useAppDispatch, useAppSelector } from "../../store/store";
import { getCompanyGroupsThunk } from "../../store/slices/companyGroupsSlice/thunks";
import { setActiveCompanyGroup } from "../../store/slices/companyGroupsSlice/companyGroupsSlice";
const { Text } = Typography;
export const CompanyGroupsList = () => {
const dispatch = useAppDispatch();
const rawRows = useAppSelector((state) => state.company_groups.raw_rows);
const loading = useAppSelector((state) => state.company_groups.loading);
const activeCompanyGroup = useAppSelector(
(state) => state.company_groups.activeCompanyGroup,
);
const [query, setQuery] = useState("");
const filtered = useMemo(() => {
const q = query.trim().toLowerCase();
if (!q) return rawRows;
return rawRows.filter(
(g) =>
g.name.toLowerCase().includes(q) || g.crm_id?.toLowerCase().includes(q),
);
}, [rawRows, query]);
useEffect(() => {
dispatch(getCompanyGroupsThunk());
}, [dispatch]);
useEffect(() => {
if (!activeCompanyGroup && rawRows?.length) {
dispatch(setActiveCompanyGroup(rawRows?.[0]));
}
}, [rawRows, activeCompanyGroup]);
return (
<div
style={{
display: "flex",
flexDirection: "column",
height: "100%",
background: "#fff",
borderRight: "1px solid #f0f0f0",
borderRadius: 12,
}}
>
<div style={{ padding: "12px 16px", borderBottom:"1px solid #0f172a0f" }}>
<Input
allowClear
prefix={<SearchOutlined style={{ color: "#bfbfbf" }} />}
placeholder={"Поиск по ЮЛ или ГСК"}
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
</div>
<div style={{ flex: 1, overflowY: "auto", padding: "10px" }}>
{loading ? (
<div style={{ textAlign: "center", padding: 24 }}>
<Spin />
</div>
) : filtered.length === 0 ? (
<Empty
image={Empty.PRESENTED_IMAGE_SIMPLE}
description="Компании и организации не найдены"
style={{ marginTop: 32 }}
/>
) : (
<List
dataSource={filtered}
split={false}
renderItem={(item) => {
const active = item.id === activeCompanyGroup?.id;
return (
<List.Item
onClick={() => dispatch(setActiveCompanyGroup(item))}
style={{
cursor: "pointer",
borderRadius: 8,
padding: "10px 12px",
marginBottom: 4,
background: active ? "#e6f4ea" : "transparent",
boxShadow: active
? "inset 0 0 0 1px #2ea64b3d, inset 3px 0 0 #258141"
: "inset 0 0 0 1px #0f172a14",
transition: "background 0.15s",
}}
onMouseEnter={(e) => {
if (!active) {
(e.currentTarget as HTMLElement).style.background =
"#fafafa";
}
}}
onMouseLeave={(e) => {
if (!active) {
(e.currentTarget as HTMLElement).style.background =
"transparent";
}
}}
>
<div
style={{
display: "flex",
alignItems: "center",
width: "100%",
gap: 12,
minWidth: 0,
}}
>
<Tag
style={{
borderRadius: 8,
width: 28,
height: 28,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
color={"success"}
>
<FolderOpenOutlined
style={{
fontSize: 18,
color: "green",
flexShrink: 0,
}}
/>
</Tag>
<div style={{ flex: 1, minWidth: 0 }}>
<Text
strong
ellipsis
style={{
display: "block",
fontSize: 14,
lineHeight: "20px",
}}
>
{item.name}
</Text>
<Text
type="secondary"
ellipsis
style={{
display: "block",
fontSize: 12,
lineHeight: "16px",
}}
>
CRM ID: {item.crm_id ?? "-"}
</Text>
</div>
<Tag
style={{
margin: 0,
borderRadius: 10,
background: "#f5f5f5",
border: "none",
color: "#595959",
fontWeight: 500,
minWidth: 24,
height: 20,
lineHeight: "20px",
textAlign: "center",
padding: "0 8px",
flexShrink: 0,
}}
>
{item.legal_entities_count}
</Tag>
</div>
</List.Item>
);
}}
/>
)}
</div>
</div>
);
};