buster/web/src/layouts/ChatLayout/ChatLayoutContext/useLayoutConfig/useLayoutConfig.ts

213 lines
6.7 KiB
TypeScript
Raw Normal View History

2025-03-22 12:01:14 +08:00
'use client';
2025-04-02 01:04:19 +08:00
import { FileType } from '@/api/asset_interfaces/chat';
2025-04-16 01:02:08 +08:00
import { useEffect, useMemo, useState } from 'react';
2025-01-31 06:33:06 +08:00
import { FileConfig, FileView, FileViewConfig, FileViewSecondary } from './interfaces';
2025-04-15 06:53:04 +08:00
import { useMemoizedFn, useUpdateEffect } from '@/hooks';
2025-02-08 05:11:05 +08:00
import { create } from 'mutative';
2025-03-28 05:05:06 +08:00
import { ChatLayoutView } from '../../interfaces';
import type { SelectedFile } from '../../interfaces';
2025-03-28 05:58:17 +08:00
import { timeout } from '@/lib';
2025-03-28 06:03:55 +08:00
import { useRouter } from 'next/navigation';
2025-04-16 01:02:08 +08:00
import { BusterRoutes } from '@/routes';
2025-04-02 01:04:19 +08:00
import { SelectedFileSecondaryRenderRecord } from '../../FileContainer/FileContainerSecondary';
import { ChatParams } from '../useGetChatParams';
import { initializeFileViews } from './helpers';
import { DEFAULT_FILE_VIEW } from '../helpers';
2025-04-15 07:06:07 +08:00
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
2025-01-31 06:33:06 +08:00
2025-03-26 11:56:21 +08:00
export const useLayoutConfig = ({
2025-03-28 05:05:06 +08:00
selectedFile,
isVersionHistoryMode,
2025-03-28 05:58:17 +08:00
chatId,
onSetSelectedFile,
2025-04-02 01:04:19 +08:00
animateOpenSplitter,
metricId,
dashboardId,
2025-04-16 01:02:08 +08:00
currentRoute,
secondaryView
2025-01-31 06:33:06 +08:00
}: {
2025-03-28 05:05:06 +08:00
selectedFile: SelectedFile | null;
2025-03-26 13:14:36 +08:00
isVersionHistoryMode: boolean;
2025-03-28 05:05:06 +08:00
chatId: string | undefined;
2025-03-28 05:58:17 +08:00
animateOpenSplitter: (side: 'left' | 'right' | 'both') => void;
onSetSelectedFile: (file: SelectedFile | null) => void;
2025-04-02 01:04:19 +08:00
} & ChatParams) => {
2025-04-16 01:02:08 +08:00
const onChangeQueryParams = useAppLayoutContextSelector((x) => x.onChangeQueryParams);
2025-04-15 07:06:07 +08:00
const onChangePage = useAppLayoutContextSelector((x) => x.onChangePage);
2025-04-16 01:02:08 +08:00
const [fileViews, setFileViews] = useState<Record<string, FileConfig>>(() =>
initializeFileViews({ secondaryView, metricId, dashboardId, currentRoute })
2025-04-02 01:04:19 +08:00
);
2025-01-31 06:33:06 +08:00
2025-03-28 05:05:06 +08:00
const selectedFileId = selectedFile?.id;
const selectedFileType = selectedFile?.type;
2025-03-20 04:47:15 +08:00
const selectedFileView: FileView | undefined = useMemo(() => {
if (!selectedFileId) return undefined;
return (
2025-03-28 05:05:06 +08:00
fileViews[selectedFileId]?.selectedFileView || DEFAULT_FILE_VIEW[selectedFileType as FileType]
2025-03-20 04:47:15 +08:00
);
}, [fileViews, selectedFileId, selectedFileType]);
const selectedFileViewConfig: FileViewConfig | undefined = useMemo(() => {
if (!selectedFileId) return undefined;
return fileViews[selectedFileId]?.fileViewConfig;
}, [fileViews, selectedFileId]);
const selectedFileViewSecondary: FileViewSecondary | null = useMemo(() => {
if (!selectedFileId || !selectedFileViewConfig || !selectedFileView) return null;
return selectedFileViewConfig?.[selectedFileView]?.secondaryView ?? null;
}, [selectedFileViewConfig, selectedFileId, selectedFileView]);
2025-03-26 13:14:36 +08:00
const selectedFileViewRenderSecondary: boolean = useMemo(() => {
2025-03-30 12:01:07 +08:00
if (!selectedFileViewSecondary || !selectedFileType) return false;
if (
selectedFileType in SelectedFileSecondaryRenderRecord &&
SelectedFileSecondaryRenderRecord[selectedFileType as FileType]?.[
selectedFileViewSecondary
] !== undefined
) {
return (
SelectedFileSecondaryRenderRecord[selectedFileType as FileType]?.[
selectedFileViewSecondary
] ?? false
);
2025-03-26 13:14:36 +08:00
}
2025-03-30 12:01:07 +08:00
return true;
}, [selectedFileViewConfig, selectedFileId, selectedFileView, selectedFileType]);
2025-03-26 13:14:36 +08:00
2025-01-31 06:33:06 +08:00
const onSetFileView = useMemoizedFn(
2025-03-28 05:58:17 +08:00
async ({
2025-01-31 06:33:06 +08:00
fileView,
2025-03-28 05:05:06 +08:00
fileId: fileIdProp,
2025-03-30 12:01:07 +08:00
secondaryView
2025-01-31 06:33:06 +08:00
}: {
fileView?: FileView;
2025-03-28 05:05:06 +08:00
fileId?: string | undefined;
2025-01-31 06:33:06 +08:00
secondaryView?: FileViewSecondary;
}) => {
2025-03-28 05:05:06 +08:00
const fileId = fileIdProp ?? selectedFileId;
2025-04-15 07:06:07 +08:00
if (!fileId) {
onCollapseFileClick();
return;
}
2025-03-28 05:58:17 +08:00
if (secondaryView) {
animateOpenSplitter('right');
2025-04-02 02:34:26 +08:00
await timeout(chatId ? 250 : 0); //wait for splitter to close before opening secondary view
2025-04-01 23:25:46 +08:00
} else if (chatId) {
2025-03-28 05:58:17 +08:00
animateOpenSplitter('both');
}
2025-01-31 06:33:06 +08:00
setFileViews((prev) => {
2025-03-28 05:05:06 +08:00
return create(prev, (draft) => {
if (!draft[fileId]) {
draft[fileId] = {
selectedFileView: DEFAULT_FILE_VIEW[selectedFileType as FileType] || 'file',
fileViewConfig: {}
};
}
const usedFileView =
fileView ??
draft[fileId].selectedFileView ??
DEFAULT_FILE_VIEW[selectedFileType as FileType];
if (fileView !== undefined) {
draft[fileId].selectedFileView = fileView;
}
if (secondaryView !== undefined) {
if (!draft[fileId].fileViewConfig) {
draft[fileId].fileViewConfig = {};
2025-01-31 06:33:06 +08:00
}
2025-03-28 05:05:06 +08:00
draft[fileId].fileViewConfig[usedFileView] = {
...(draft[fileId].fileViewConfig[usedFileView] || {}),
2025-03-30 12:01:07 +08:00
secondaryView
2025-03-28 05:05:06 +08:00
};
}
});
2025-01-31 06:33:06 +08:00
});
}
);
2025-04-15 07:06:07 +08:00
const closeSecondaryView = useMemoizedFn(async () => {
2025-02-04 02:24:32 +08:00
if (!selectedFileId || !selectedFileViewConfig || !selectedFileView) return;
2025-03-08 07:02:56 +08:00
setFileViews((prev) => {
return create(prev, (draft) => {
2025-02-04 02:24:32 +08:00
if (!draft[selectedFileId]?.fileViewConfig?.[selectedFileView]) return;
draft[selectedFileId].fileViewConfig[selectedFileView].secondaryView = null;
2025-03-08 07:02:56 +08:00
});
});
2025-04-16 01:02:08 +08:00
onChangeQueryParams({
secondary_view: null
});
await timeout(250); //wait for the panel to close
2025-02-04 02:24:32 +08:00
});
2025-04-15 07:06:07 +08:00
const onCollapseFileClick = useMemoizedFn(async (navigateToChat: boolean = true) => {
2025-03-28 05:58:17 +08:00
onSetSelectedFile(null);
2025-04-16 01:02:08 +08:00
2025-04-15 07:06:07 +08:00
if (selectedFileViewSecondary) {
await closeSecondaryView();
}
2025-03-28 06:03:55 +08:00
if (navigateToChat && chatId) {
2025-04-15 07:06:07 +08:00
onChangePage({
route: BusterRoutes.APP_CHAT_ID,
chatId
});
2025-03-28 06:03:55 +08:00
}
2025-03-28 05:58:17 +08:00
});
2025-03-28 05:05:06 +08:00
const selectedLayout: ChatLayoutView = useMemo(() => {
if (chatId) {
2025-04-16 01:02:08 +08:00
if (selectedFileViewSecondary) return 'chat-hidden';
2025-03-28 05:05:06 +08:00
if (selectedFileId) return 'both';
2025-04-16 01:02:08 +08:00
return 'chat-only';
2025-03-28 05:05:06 +08:00
}
2025-04-16 01:02:08 +08:00
return 'file-only';
}, [selectedFileId, chatId, selectedFileViewSecondary]);
2025-03-28 05:05:06 +08:00
2025-04-15 06:53:04 +08:00
//we need to use for when the user clicks the back or forward in the browser
useUpdateEffect(() => {
2025-04-16 01:02:08 +08:00
const newInitialFileViews = initializeFileViews({
secondaryView,
metricId,
dashboardId,
currentRoute
});
2025-04-15 06:53:04 +08:00
const fileId = Object.keys(newInitialFileViews)[0];
const fileView = newInitialFileViews[fileId]?.selectedFileView;
2025-04-16 01:02:08 +08:00
const secondaryViewFromSelected =
newInitialFileViews[fileId]?.fileViewConfig?.[fileView]?.secondaryView;
2025-04-15 06:53:04 +08:00
onSetFileView({
fileId,
fileView,
2025-04-16 01:02:08 +08:00
secondaryView: secondaryViewFromSelected
2025-04-15 06:53:04 +08:00
});
2025-04-16 01:02:08 +08:00
}, [metricId, secondaryView, dashboardId, currentRoute]);
2025-04-15 06:53:04 +08:00
2025-03-28 05:58:17 +08:00
return useMemo(
() => ({
selectedLayout,
selectedFileView,
selectedFileViewSecondary,
selectedFileViewRenderSecondary,
onSetFileView,
closeSecondaryView,
onCollapseFileClick
}),
[
selectedLayout,
selectedFileView,
selectedFileViewSecondary,
selectedFileViewRenderSecondary,
onSetFileView,
closeSecondaryView,
onCollapseFileClick
]
);
2025-01-31 06:33:06 +08:00
};