функция раскрытия на весь экран вынесена в отдельный хук useFullScreen
This commit is contained in:
parent
db8641a1a8
commit
29a630c5e5
29
web/src/hooks/useFullScreen.tsx
Normal file
29
web/src/hooks/useFullScreen.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
|
import { useNotificationApi } from "../utils/useNotification";
|
||||||
|
|
||||||
|
export function useFullscreen<T extends HTMLElement = HTMLDivElement>() {
|
||||||
|
const ref = useRef<T>(null);
|
||||||
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||||
|
const notification = useNotificationApi();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const onChange = () => setIsFullscreen(document.fullscreenElement === ref.current);
|
||||||
|
document.addEventListener('fullscreenchange', onChange);
|
||||||
|
return () => document.removeEventListener('fullscreenchange', onChange);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const toggle = useCallback(async () => {
|
||||||
|
if (!ref.current) return;
|
||||||
|
try {
|
||||||
|
if (document.fullscreenElement) {
|
||||||
|
await document.exitFullscreen();
|
||||||
|
} else {
|
||||||
|
await ref.current.requestFullscreen();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
notification.error({ description: e instanceof Error ? e.message : 'Не удалось переключить полноэкранный режим' });
|
||||||
|
}
|
||||||
|
}, [notification]);
|
||||||
|
|
||||||
|
return { ref, isFullscreen, toggle };
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { DownloadOutlined, FullscreenExitOutlined, FullscreenOutlined } from '@ant-design/icons';
|
import { DownloadOutlined, FullscreenExitOutlined, FullscreenOutlined } from '@ant-design/icons';
|
||||||
import { Button, ConfigProvider } from 'antd';
|
import { Button, ConfigProvider } from 'antd';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { ApiError } from '../../../api/client';
|
import { ApiError } from '../../../api/client';
|
||||||
import { ConsolidationFormatTableFilter } from '../../../components/ConsolidationFormatTableFilter/ConsolidationFormatTableFilter';
|
import { ConsolidationFormatTableFilter } from '../../../components/ConsolidationFormatTableFilter/ConsolidationFormatTableFilter';
|
||||||
@ -20,6 +20,7 @@ import { useNotificationApi } from '../../../utils/useNotification';
|
|||||||
import { ConsolidationChessResTable } from '../ConsolidationChessResTable/ConsolidationChessResTable';
|
import { ConsolidationChessResTable } from '../ConsolidationChessResTable/ConsolidationChessResTable';
|
||||||
import { ConsolidationChessTable } from '../ConsolidationChessTable/ConsolidationChessTable';
|
import { ConsolidationChessTable } from '../ConsolidationChessTable/ConsolidationChessTable';
|
||||||
import { ConsolidationChessTableFilter } from '../ConsolidationChessTableFilter/ConsolidationChessTableFilter';
|
import { ConsolidationChessTableFilter } from '../ConsolidationChessTableFilter/ConsolidationChessTableFilter';
|
||||||
|
import { useFullscreen } from '../../../hooks/useFullScreen';
|
||||||
|
|
||||||
export const ChessContent = ({ card }: { card: VersionCard | null }) => {
|
export const ChessContent = ({ card }: { card: VersionCard | null }) => {
|
||||||
const { version_id } = useParams<{ version_id: string }>();
|
const { version_id } = useParams<{ version_id: string }>();
|
||||||
@ -40,38 +41,17 @@ export const ChessContent = ({ card }: { card: VersionCard | null }) => {
|
|||||||
const [chessResDecimals, setChessResDecimals] = useState(2);
|
const [chessResDecimals, setChessResDecimals] = useState(2);
|
||||||
const [chessResLoading, setChessResLoading] = useState(false);
|
const [chessResLoading, setChessResLoading] = useState(false);
|
||||||
|
|
||||||
const chessTableRef = useRef<HTMLDivElement>(null);
|
const {
|
||||||
const resTableRef = useRef<HTMLDivElement>(null);
|
ref: chessTableRef,
|
||||||
const [isChessFullscreen, setIsChessFullscreen] = useState(false);
|
isFullscreen: isChessFullscreen,
|
||||||
const [isResFullscreen, setIsResFullscreen] = useState(false);
|
toggle: toggleChessFullscreen,
|
||||||
|
} = useFullscreen<HTMLDivElement>();
|
||||||
|
|
||||||
const toggleFullscreen = async (ref: React.RefObject<HTMLDivElement>, setFullscreen: (val: boolean) => void) => {
|
const {
|
||||||
if (!ref.current) return;
|
ref: resTableRef,
|
||||||
try {
|
isFullscreen: isResFullscreen,
|
||||||
if (!document.fullscreenElement) {
|
toggle: toggleResFullscreen,
|
||||||
await ref.current.requestFullscreen();
|
} = useFullscreen<HTMLDivElement>();
|
||||||
setFullscreen(true);
|
|
||||||
} else {
|
|
||||||
await document.exitFullscreen();
|
|
||||||
setFullscreen(false);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
notification.error({
|
|
||||||
description: e instanceof Error ? e.message : 'Не удалось переключить полноэкранный режим',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handleFullscreenChange = () => {
|
|
||||||
if (!document.fullscreenElement) {
|
|
||||||
setIsChessFullscreen(false);
|
|
||||||
setIsResFullscreen(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
document.addEventListener('fullscreenchange', handleFullscreenChange);
|
|
||||||
return () => document.removeEventListener('fullscreenchange', handleFullscreenChange);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const matrixMode = chessMatrixMode(debit, credit);
|
const matrixMode = chessMatrixMode(debit, credit);
|
||||||
const isHalfFiltered = matrixMode === 'half';
|
const isHalfFiltered = matrixMode === 'half';
|
||||||
@ -251,7 +231,7 @@ export const ChessContent = ({ card }: { card: VersionCard | null }) => {
|
|||||||
Экспорт
|
Экспорт
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => toggleFullscreen(chessTableRef, setIsChessFullscreen)}
|
onClick={() => toggleChessFullscreen()}
|
||||||
icon={isChessFullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />}>
|
icon={isChessFullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />}>
|
||||||
{isChessFullscreen ? 'Свернуть' : 'На весь экран'}
|
{isChessFullscreen ? 'Свернуть' : 'На весь экран'}
|
||||||
</Button>
|
</Button>
|
||||||
@ -300,7 +280,7 @@ export const ChessContent = ({ card }: { card: VersionCard | null }) => {
|
|||||||
Экспорт
|
Экспорт
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => toggleFullscreen(resTableRef, setIsResFullscreen)}
|
onClick={() => toggleResFullscreen()}
|
||||||
icon={isResFullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />}>
|
icon={isResFullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />}>
|
||||||
{isResFullscreen ? 'Свернуть' : 'На весь экран'}
|
{isResFullscreen ? 'Свернуть' : 'На весь экран'}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { DownloadOutlined, EditOutlined, FullscreenExitOutlined, FullscreenOutlined } from '@ant-design/icons';
|
import { DownloadOutlined, EditOutlined, FullscreenExitOutlined, FullscreenOutlined } from '@ant-design/icons';
|
||||||
import { Alert, Button, ConfigProvider, Select, Space, Tooltip } from 'antd';
|
import { Alert, Button, ConfigProvider, Select, Space, Tooltip } from 'antd';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { ConsolidationFormatTableFilter } from '../../../components/ConsolidationFormatTableFilter/ConsolidationFormatTableFilter';
|
import { ConsolidationFormatTableFilter } from '../../../components/ConsolidationFormatTableFilter/ConsolidationFormatTableFilter';
|
||||||
import { type ColumnDef, ColumnSettings, useVisibleColumns } from '../../../components/GenericTable';
|
import { type ColumnDef, ColumnSettings, useVisibleColumns } from '../../../components/GenericTable';
|
||||||
@ -11,6 +11,7 @@ import { saveBlob, xlsxFilename } from '../../../utils/download';
|
|||||||
import { useNotificationApi } from '../../../utils/useNotification';
|
import { useNotificationApi } from '../../../utils/useNotification';
|
||||||
import { ConsolidationGoodwillTable } from '../ConsolidationGoodwillTable/ConsolidationGoodwillTable';
|
import { ConsolidationGoodwillTable } from '../ConsolidationGoodwillTable/ConsolidationGoodwillTable';
|
||||||
import { getGoodwillColumns } from '../ConsolidationGoodwillTable/config';
|
import { getGoodwillColumns } from '../ConsolidationGoodwillTable/config';
|
||||||
|
import { useFullscreen } from '../../../hooks/useFullScreen';
|
||||||
|
|
||||||
// #TODO --- ТЕСТОВЫЕ ДАННЫЕ ---
|
// #TODO --- ТЕСТОВЫЕ ДАННЫЕ ---
|
||||||
// const MOCK_DATA: GoodwillTableResponse = {
|
// const MOCK_DATA: GoodwillTableResponse = {
|
||||||
@ -111,8 +112,6 @@ export const GoodwillContent = ({ card }: { card: VersionCard | null }) => {
|
|||||||
const [isEditMode, setIsEditMode] = useState(false);
|
const [isEditMode, setIsEditMode] = useState(false);
|
||||||
const [editedRows, setEditedRows] = useState<Record<string, Partial<GoodwillRow>>>({});
|
const [editedRows, setEditedRows] = useState<Record<string, Partial<GoodwillRow>>>({});
|
||||||
|
|
||||||
const goodwillTableRef = useRef<HTMLDivElement>(null);
|
|
||||||
const [isGoodwillFullscreen, setIsGoodwillFullscreen] = useState(false);
|
|
||||||
const [goodwillFilter, setGoodwillFilter] = useState('allValue');
|
const [goodwillFilter, setGoodwillFilter] = useState('allValue');
|
||||||
const [exportLoading, setExportLoading] = useState(false);
|
const [exportLoading, setExportLoading] = useState(false);
|
||||||
const versionInfo = card ? { groupName: card.company_group.name, year: card.year, quarter: card.quarter } : null;
|
const versionInfo = card ? { groupName: card.company_group.name, year: card.year, quarter: card.quarter } : null;
|
||||||
@ -179,20 +178,6 @@ export const GoodwillContent = ({ card }: { card: VersionCard | null }) => {
|
|||||||
|
|
||||||
const { visibleKeys, setVisibleKeys } = useVisibleColumns(groupsConfig);
|
const { visibleKeys, setVisibleKeys } = useVisibleColumns(groupsConfig);
|
||||||
|
|
||||||
const toggleFullscreen = async (ref: React.RefObject<HTMLDivElement>, setFullscreen: (val: boolean) => void) => {
|
|
||||||
if (!ref.current) return;
|
|
||||||
try {
|
|
||||||
if (!document.fullscreenElement) {
|
|
||||||
await ref.current.requestFullscreen();
|
|
||||||
setFullscreen(true);
|
|
||||||
} else {
|
|
||||||
await document.exitFullscreen();
|
|
||||||
setFullscreen(false);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
notification.error({ description: e instanceof Error ? e.message : 'Ошибка раскрытия на весь экран' });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const dropFiltersHandler = () => {
|
const dropFiltersHandler = () => {
|
||||||
setGoodwillFilter('allValue');
|
setGoodwillFilter('allValue');
|
||||||
@ -303,18 +288,11 @@ export const GoodwillContent = ({ card }: { card: VersionCard | null }) => {
|
|||||||
return !hasErrors;
|
return !hasErrors;
|
||||||
}, [editedRows, isEditMode]);
|
}, [editedRows, isEditMode]);
|
||||||
|
|
||||||
useEffect(() => {
|
const {
|
||||||
const handleFullscreenChange = () => {
|
ref: goodwillTableRef,
|
||||||
if (!document.fullscreenElement) {
|
isFullscreen: isGoodwillFullscreen,
|
||||||
setIsGoodwillFullscreen(false);
|
toggle: toggleGoodwillFullscreen,
|
||||||
}
|
} = useFullscreen<HTMLDivElement>();
|
||||||
};
|
|
||||||
|
|
||||||
document.addEventListener('fullscreenchange', handleFullscreenChange);
|
|
||||||
return () => {
|
|
||||||
document.removeEventListener('fullscreenchange', handleFullscreenChange);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (version_id) {
|
if (version_id) {
|
||||||
@ -424,7 +402,7 @@ export const GoodwillContent = ({ card }: { card: VersionCard | null }) => {
|
|||||||
Экспорт
|
Экспорт
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => toggleFullscreen(goodwillTableRef, setIsGoodwillFullscreen)}
|
onClick={() => toggleGoodwillFullscreen()}
|
||||||
icon={isGoodwillFullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />}>
|
icon={isGoodwillFullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />}>
|
||||||
{isGoodwillFullscreen ? 'Свернуть' : 'На весь экран'}
|
{isGoodwillFullscreen ? 'Свернуть' : 'На весь экран'}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import { COLUMN_DEFS, type ColKey, type ColShape } from './columns';
|
|||||||
import { errorOutcome, readOnlyHint } from './readOnly';
|
import { errorOutcome, readOnlyHint } from './readOnly';
|
||||||
import { EMPTY_FILTERS, type TableFilters, aggregateKey, buildRows, filterTable, lineOptions, visibleTotals } from './tableModel';
|
import { EMPTY_FILTERS, type TableFilters, aggregateKey, buildRows, filterTable, lineOptions, visibleTotals } from './tableModel';
|
||||||
import { useCorrectionTable } from './useCorrectionTable';
|
import { useCorrectionTable } from './useCorrectionTable';
|
||||||
|
import { useFullscreen } from '../../hooks/useFullScreen';
|
||||||
|
|
||||||
const LOAD_ERROR_KEY = 'corrections-load-error';
|
const LOAD_ERROR_KEY = 'corrections-load-error';
|
||||||
|
|
||||||
@ -23,10 +24,9 @@ type Props = { versionId: string; card?: VersionCard | null };
|
|||||||
|
|
||||||
export function CorrectionContent({ versionId, card = null }: Props) {
|
export function CorrectionContent({ versionId, card = null }: Props) {
|
||||||
const { table, loading, error, reload, replace, replaceAggregate } = useCorrectionTable(versionId);
|
const { table, loading, error, reload, replace, replaceAggregate } = useCorrectionTable(versionId);
|
||||||
const boxRef = useRef<HTMLDivElement>(null);
|
|
||||||
// уведомления рисуются внутри бокса вкладки: в полноэкранном режиме виден только полноэкранный элемент,
|
// уведомления рисуются внутри бокса вкладки: в полноэкранном режиме виден только полноэкранный элемент,
|
||||||
// глобальные уведомления за ним не видны
|
// глобальные уведомления за ним не видны
|
||||||
const [notification, holder] = antdNotification.useNotification({ getContainer: () => boxRef.current ?? document.body });
|
const [notification, holder] = antdNotification.useNotification({ getContainer: () => tableRef.current ?? document.body });
|
||||||
const notify = useMemo(
|
const notify = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
error: ({ description }: { description: ReactNode }) =>
|
error: ({ description }: { description: ReactNode }) =>
|
||||||
@ -40,7 +40,6 @@ export function CorrectionContent({ versionId, card = null }: Props) {
|
|||||||
const [expanded, setExpanded] = useState<ReadonlySet<string>>(new Set());
|
const [expanded, setExpanded] = useState<ReadonlySet<string>>(new Set());
|
||||||
const { visibleKeys, setVisibleKeys } = useVisibleColumns<ColShape>({ rowKey: 'include', columns: COLUMN_DEFS });
|
const { visibleKeys, setVisibleKeys } = useVisibleColumns<ColShape>({ rowKey: 'include', columns: COLUMN_DEFS });
|
||||||
const [exporting, setExporting] = useState(false);
|
const [exporting, setExporting] = useState(false);
|
||||||
const [fullscreen, setFullscreen] = useState(false);
|
|
||||||
// идёт запрос решения по строке: на это время контролы строк неактивны, чтобы не слать два запроса подряд
|
// идёт запрос решения по строке: на это время контролы строк неактивны, чтобы не слать два запроса подряд
|
||||||
const [busy, setBusy] = useState(false);
|
const [busy, setBusy] = useState(false);
|
||||||
// ref, а не состояние: setBusy применяется после перерисовки, а два клика могут прийти до неё — ref меняется мгновенно
|
// ref, а не состояние: setBusy применяется после перерисовки, а два клика могут прийти до неё — ref меняется мгновенно
|
||||||
@ -71,28 +70,7 @@ export function CorrectionContent({ versionId, card = null }: Props) {
|
|||||||
// ушли с вкладки — уведомление об ошибке закрываем, оно относится к этому экрану
|
// ушли с вкладки — уведомление об ошибке закрываем, оно относится к этому экрану
|
||||||
useEffect(() => () => notification.destroy(LOAD_ERROR_KEY), [notification]);
|
useEffect(() => () => notification.destroy(LOAD_ERROR_KEY), [notification]);
|
||||||
|
|
||||||
useEffect(() => {
|
const { ref: tableRef, isFullscreen: isFullscreen, toggle: toggleFullscreen } = useFullscreen<HTMLDivElement>();
|
||||||
const onChange = () => {
|
|
||||||
if (!document.fullscreenElement) setFullscreen(false);
|
|
||||||
};
|
|
||||||
document.addEventListener('fullscreenchange', onChange);
|
|
||||||
return () => document.removeEventListener('fullscreenchange', onChange);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const toggleFullscreen = async () => {
|
|
||||||
if (!boxRef.current) return;
|
|
||||||
try {
|
|
||||||
if (!document.fullscreenElement) {
|
|
||||||
await boxRef.current.requestFullscreen();
|
|
||||||
setFullscreen(true);
|
|
||||||
} else {
|
|
||||||
await document.exitFullscreen();
|
|
||||||
setFullscreen(false);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
notify.error({ description: e instanceof Error ? e.message : 'Не удалось переключить полноэкранный режим' });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const download = async () => {
|
const download = async () => {
|
||||||
setExporting(true);
|
setExporting(true);
|
||||||
@ -171,7 +149,7 @@ export function CorrectionContent({ versionId, card = null }: Props) {
|
|||||||
onFiltersChange={setFilters}
|
onFiltersChange={setFilters}
|
||||||
lineOptions={lines}
|
lineOptions={lines}
|
||||||
visibleKeys={visibleKeys as ColKey[]}
|
visibleKeys={visibleKeys as ColKey[]}
|
||||||
scrollY={fullscreen ? 'calc(100vh - 190px)' : 'calc(100vh - 360px)'}
|
scrollY={isFullscreen ? 'calc(100vh - 190px)' : 'calc(100vh - 360px)'}
|
||||||
emptyText={emptyText}
|
emptyText={emptyText}
|
||||||
/>
|
/>
|
||||||
</Spin>
|
</Spin>
|
||||||
@ -194,7 +172,7 @@ export function CorrectionContent({ versionId, card = null }: Props) {
|
|||||||
return (
|
return (
|
||||||
<ConfigProvider getPopupContainer={() => (document.fullscreenElement as HTMLElement) || document.body}>
|
<ConfigProvider getPopupContainer={() => (document.fullscreenElement as HTMLElement) || document.body}>
|
||||||
<div
|
<div
|
||||||
ref={boxRef}
|
ref={tableRef}
|
||||||
style={{
|
style={{
|
||||||
background: '#fff',
|
background: '#fff',
|
||||||
padding: 12,
|
padding: 12,
|
||||||
@ -203,7 +181,7 @@ export function CorrectionContent({ versionId, card = null }: Props) {
|
|||||||
gap: 12,
|
gap: 12,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
minHeight: 0,
|
minHeight: 0,
|
||||||
height: fullscreen ? '100vh' : undefined,
|
height: isFullscreen ? '100vh' : undefined,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
}}>
|
}}>
|
||||||
{holder}
|
{holder}
|
||||||
@ -221,7 +199,7 @@ export function CorrectionContent({ versionId, card = null }: Props) {
|
|||||||
onExport={download}
|
onExport={download}
|
||||||
exporting={exporting}
|
exporting={exporting}
|
||||||
exportDisabled={!table}
|
exportDisabled={!table}
|
||||||
fullscreen={fullscreen}
|
fullscreen={isFullscreen}
|
||||||
onToggleFullscreen={toggleFullscreen}
|
onToggleFullscreen={toggleFullscreen}
|
||||||
/>
|
/>
|
||||||
{body}
|
{body}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user