fixies-3-form #105
@ -163,6 +163,7 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
|
||||
handleUnpinColumn,
|
||||
handleSetColumnWidth,
|
||||
handleToggleColumnVisibility,
|
||||
handleSetColumnsVisibility,
|
||||
} = useColumnSettings(`${formId}_${formType}_${sheetName}_${direction}`);
|
||||
|
||||
const { headerPortalRef, containerRef } = useHeaderPortal();
|
||||
@ -174,6 +175,7 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
|
||||
|
||||
useEffect(() => {
|
||||
rowVirtualizerRef.current?.measure?.();
|
||||
columnVirtualizerRef.current?.measure?.();
|
||||
}, [sizeMult]);
|
||||
|
||||
useEffect(() => {
|
||||
@ -300,10 +302,7 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
|
||||
}, [columns, columnPinning, columnSizing, columnVisibility]);
|
||||
|
||||
const selectedColumnIdRef = useRef(selectedColumnId);
|
||||
|
||||
useEffect(() => {
|
||||
selectedColumnIdRef.current = selectedColumnId;
|
||||
}, [selectedColumnId]);
|
||||
selectedColumnIdRef.current = selectedColumnId;
|
||||
|
||||
const tableMeta = useMemo(() => ({
|
||||
updateCell: handleUpdateCell,
|
||||
@ -610,13 +609,13 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
|
||||
return (
|
||||
<>
|
||||
<SettingsPanel
|
||||
selectedColumnId={selectedColumnId}
|
||||
columnPinning={columnPinning}
|
||||
table={table}
|
||||
columns={columns}
|
||||
selectedColumnId={selectedColumnId}
|
||||
columnPinning={columnPinning}
|
||||
columns={columns}
|
||||
onPinColumn={handlePinColumn}
|
||||
onUnpinColumn={handleUnpinColumn}
|
||||
onToggleColumnVisibility={handleToggleColumnVisibility}
|
||||
onToggleColumnVisibility={handleToggleColumnVisibility}
|
||||
onSetColumnsVisibility={handleSetColumnsVisibility}
|
||||
columnVisibility={columnVisibility}
|
||||
columnsCurStage={columnsCurStage}
|
||||
onChangeSizeMult={setSizeMult}
|
||||
@ -628,7 +627,6 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
|
||||
onAddProgram={addProgram}
|
||||
onAddProject={addProject}
|
||||
onDeleteRow={handleDeleteRow}
|
||||
isLoadingData={isLoadingData}
|
||||
formId={formId}
|
||||
sheetName={sheetName}
|
||||
direction={direction}
|
||||
|
||||
@ -37,11 +37,11 @@ const exportButtonSx = { height: '2.5rem', minHeight: '2.5rem' };
|
||||
const SettingPanel = ({
|
||||
selectedColumnId,
|
||||
columnPinning,
|
||||
table,
|
||||
columns,
|
||||
onPinColumn,
|
||||
onUnpinColumn,
|
||||
onToggleColumnVisibility,
|
||||
onSetColumnsVisibility,
|
||||
columnVisibility,
|
||||
columnsCurStage,
|
||||
onChangeSizeMult,
|
||||
@ -53,7 +53,6 @@ const SettingPanel = ({
|
||||
onAddProgram,
|
||||
onAddProject,
|
||||
onDeleteRow,
|
||||
isLoadingData,
|
||||
formId,
|
||||
sheetName,
|
||||
direction,
|
||||
@ -119,10 +118,12 @@ const SettingPanel = ({
|
||||
console.warn('Нет столбцов для текущего этапа');
|
||||
return;
|
||||
}
|
||||
const visibilityByColumnId = {};
|
||||
for (const column of leafColumns) {
|
||||
onToggleColumnVisibility(column, showOnlyCurrentStageColumns || stageColumnIds.has(column.id));
|
||||
visibilityByColumnId[column.id] = showOnlyCurrentStageColumns || stageColumnIds.has(column.id);
|
||||
}
|
||||
}, [columnsCurStage, leafColumns, onToggleColumnVisibility, showOnlyCurrentStageColumns, stageColumnIds]);
|
||||
onSetColumnsVisibility(visibilityByColumnId);
|
||||
}, [columnsCurStage, leafColumns, onSetColumnsVisibility, showOnlyCurrentStageColumns, stageColumnIds]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@ -3,21 +3,79 @@ import {
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
useSyncExternalStore,
|
||||
} from "react";
|
||||
import { toast } from "react-toastify";
|
||||
import { useWebSocket } from "../hooks/useWebSocket";
|
||||
import { getRowId } from "../utils/rowUtils";
|
||||
|
||||
const RealtimeContext = createContext(null);
|
||||
const RealtimeActionsContext = createContext(null);
|
||||
const RealtimeConnectionContext = createContext(null);
|
||||
const RealtimeVspOptionsContext = createContext(null);
|
||||
const LockedCellsStoreContext = createContext(null);
|
||||
|
||||
const useRequiredContext = (context, hookName) => {
|
||||
const value = useContext(context);
|
||||
if (value === null) {
|
||||
throw new Error(`${hookName} must be used within RealtimeProvider`);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
const createLockedCellsStore = () => {
|
||||
let cells = new Set();
|
||||
const listeners = new Set();
|
||||
|
||||
const subscribe = (listener) => {
|
||||
listeners.add(listener);
|
||||
return () => listeners.delete(listener);
|
||||
};
|
||||
|
||||
const setCells = (nextValue) => {
|
||||
const currentCells = [...cells];
|
||||
const resolvedValue = typeof nextValue === "function" ? nextValue(currentCells) : nextValue;
|
||||
const nextCells = new Set(resolvedValue || []);
|
||||
const hasChanges =
|
||||
nextCells.size !== cells.size || [...nextCells].some((cellKey) => !cells.has(cellKey));
|
||||
|
||||
if (!hasChanges) return;
|
||||
cells = nextCells;
|
||||
listeners.forEach((listener) => listener());
|
||||
};
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
setCells,
|
||||
hasCell: (cellKey) => cells.has(cellKey),
|
||||
getCells: () => [...cells],
|
||||
};
|
||||
};
|
||||
|
||||
export const useRealtimeActions = () =>
|
||||
useRequiredContext(RealtimeActionsContext, "useRealtimeActions");
|
||||
|
||||
export const useRealtimeConnection = () =>
|
||||
useRequiredContext(RealtimeConnectionContext, "useRealtimeConnection");
|
||||
|
||||
export const useVspOptions = () =>
|
||||
useRequiredContext(RealtimeVspOptionsContext, "useVspOptions");
|
||||
|
||||
export const useCellLock = (cellKey) => {
|
||||
const store = useRequiredContext(LockedCellsStoreContext, "useCellLock");
|
||||
const getSnapshot = useCallback(() => store.hasCell(cellKey), [cellKey, store]);
|
||||
|
||||
return useSyncExternalStore(store.subscribe, getSnapshot, () => false);
|
||||
};
|
||||
|
||||
export const useRealtime = () => {
|
||||
const context = useContext(RealtimeContext);
|
||||
if (!context) {
|
||||
throw new Error("useRealtime must be used within RealtimeProvider");
|
||||
}
|
||||
return context;
|
||||
const actions = useRealtimeActions();
|
||||
const connection = useRealtimeConnection();
|
||||
const vspOptions = useVspOptions();
|
||||
|
||||
return { ...actions, ...connection, vspOptions };
|
||||
};
|
||||
|
||||
export const RealtimeProvider = ({
|
||||
@ -41,9 +99,11 @@ export const RealtimeProvider = ({
|
||||
: `/api/v1/ws/projects/${formId}/report/${year}/${sheetName}`
|
||||
}`;
|
||||
|
||||
//для ячеек которые редактируются другими пользователями
|
||||
const [lockedCells, setLockedCells] = useState([]);
|
||||
const [vspOptions, setVspOptions] = useState([]);
|
||||
const lockedCellsStoreRef = useRef(null);
|
||||
if (lockedCellsStoreRef.current === null) {
|
||||
lockedCellsStoreRef.current = createLockedCellsStore();
|
||||
}
|
||||
|
||||
const handleMessage = useCallback((data) => {
|
||||
// Обработка ошибок
|
||||
|
||||
@ -66,6 +66,10 @@ export const useColumnSettings = (tableKey) => {
|
||||
setColumnVisibility((prev) => ({ ...prev, ...leafCols }));
|
||||
}, []);
|
||||
|
||||
const handleSetColumnsVisibility = useCallback((visibilityByColumnId) => {
|
||||
setColumnVisibility((prev) => ({ ...prev, ...visibilityByColumnId }));
|
||||
}, []);
|
||||
|
||||
// Опционально: функция для сброса всех настроек
|
||||
const resetAllSettings = useCallback(() => {
|
||||
setColumnSizing({});
|
||||
@ -84,6 +88,7 @@ export const useColumnSettings = (tableKey) => {
|
||||
handleUnpinColumn,
|
||||
handleSetColumnWidth,
|
||||
handleToggleColumnVisibility,
|
||||
handleSetColumnsVisibility,
|
||||
resetAllSettings, // добавляем функцию сброса
|
||||
tableKey, // опционально возвращаем tableKey
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user