144 lines
3.9 KiB
JavaScript

import React, { useEffect, useState } from 'react';
import { useMemo } from 'react';
import styled from '@emotion/styled';
import { useRealtime } from '../../contexts/RealtimeContext';
import { toast } from 'react-toastify';
const ContainerForText = styled.span`
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
white-space: pre-wrap;
`;
// Стилизованный компонент для плашки блокировки
const LockBadge = styled.div`
position: absolute;
top: 2px;
right: 2px;
background: rgba(0, 0, 0, 0.7);
color: white;
font-size: 9px;
padding: 1px 4px;
border-radius: 3px;
pointer-events: none;
z-index: 10;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
letter-spacing: 0.3px;
backdrop-filter: blur(4px);
border: 1px solid rgba(255, 255, 255, 0.1);
`;
// Функция для подсветки текста
const highlightText = (text, searchQuery) => {
if (!searchQuery || !text) return text;
const escapedQuery = searchQuery.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const regex = new RegExp(`(${escapedQuery})`, 'gi');
const parts = text.split(regex);
return parts.map((part, index) =>
regex.test(part) ? (
<mark
key={index}
style={{
backgroundColor: '#ffeb3b',
color: '#000',
fontWeight: 'bold',
padding: '0 2px',
borderRadius: '2px',
}}
>
{part}
</mark>
) : (
part
),
);
};
// Функция для форматирования числа в финансовый формат
const formatNumber = (value) => {
if (value === null || value === undefined || value === '') return String(value || '');
const num = Number(value);
if (isNaN(num)) return String(value);
return num.toLocaleString('ru-RU', {
minimumFractionDigits: 1,
maximumFractionDigits: 1,
useGrouping: true,
});
};
const Cell = React.memo(({ cell, row, column, onClick, globalFilter, backgroundColor, color, isEditable }) => {
const { lockedCells } = useRealtime();
const cellKey = `${row.id}_${column.id}`;
const isLocked = lockedCells.includes(cellKey);
const cellValue = cell.getValue();
let textValue = String(cellValue || '');
const isNumeric = !isNaN(Number(cellValue)) && cellValue !== null && cellValue !== undefined && cellValue !== '';
if (isNumeric) {
textValue = formatNumber(cellValue);
}
const highlightedContent = useMemo(() => {
return highlightText(textValue, globalFilter);
}, [textValue, globalFilter]);
// Базовые стили для заблокированной ячейки
const lockedStyles = isLocked ? {
border: '2px solid #e0e0e0',
backgroundColor: '#f5f5f5',
color: '#999999',
cursor: 'not-allowed',
opacity: 0.85,
} : {};
// Если isEditable false, добавляем дополнительные стили
const editableStyles = !isEditable ? {
border: '2px solid #d3d3d3',
color: backgroundColor?.toLowerCase() === '#933634' ? '#ffffff' : '#525252',
cursor: 'not-allowed',
} : {};
return (
<div
className="cell"
style={{
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
boxSizing: 'border-box',
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
border: '2px solid transparent',
padding: '8px',
backgroundColor: isLocked ? '#f5f5f5' : backgroundColor,
color: isLocked ? '#999999' : color,
...lockedStyles,
...editableStyles,
}}
onClick={isLocked ? undefined : onClick}
>
<ContainerForText>{highlightedContent}</ContainerForText>
{isLocked && (
<LockBadge>
🔒
</LockBadge>
)}
</div>
);
});
export default Cell;