mirror of
https://github.com/suitenumerique/docs.git
synced 2026-05-09 08:32:12 +02:00
wip
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
NodeRendererProps,
|
||||
Tree,
|
||||
} from 'react-arborist';
|
||||
import { OpenMap } from 'react-arborist/dist/module/state/open-slice';
|
||||
|
||||
import {
|
||||
BaseType,
|
||||
@@ -27,6 +28,7 @@ export type TreeViewProps<T> = {
|
||||
width?: number | string;
|
||||
selectedNodeId?: string;
|
||||
rootNodeId: string;
|
||||
initialOpenState?: OpenMap;
|
||||
renderNode: (
|
||||
props: NodeRendererProps<TreeViewDataType<T>>,
|
||||
) => React.ReactNode;
|
||||
@@ -43,6 +45,7 @@ export const TreeView = <T,>({
|
||||
renderNode,
|
||||
afterMove,
|
||||
selectedNodeId,
|
||||
initialOpenState,
|
||||
}: TreeViewProps<T>) => {
|
||||
const onMove3 = (args: {
|
||||
dragIds: string[];
|
||||
@@ -223,6 +226,7 @@ export const TreeView = <T,>({
|
||||
height={1000}
|
||||
indent={20}
|
||||
width={width}
|
||||
initialOpenState={initialOpenState}
|
||||
selection={selectedNodeId}
|
||||
disableEdit={true}
|
||||
rowHeight={32}
|
||||
@@ -326,7 +330,11 @@ export const TreeViewNode = <T,>({
|
||||
</Box>
|
||||
) : (
|
||||
<Icon
|
||||
onClick={() => void handleClick()}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
void handleClick();
|
||||
}}
|
||||
$variation="500"
|
||||
$size="16px"
|
||||
iconName={
|
||||
|
||||
@@ -84,9 +84,11 @@ export const createTreeStore = <T>(
|
||||
|
||||
return filteredNodes.map((node) => {
|
||||
if (node.children) {
|
||||
const children = removeNodeFromTree(node.children);
|
||||
return {
|
||||
...node,
|
||||
children: removeNodeFromTree(node.children),
|
||||
children: children,
|
||||
childrenCount: children.length,
|
||||
};
|
||||
}
|
||||
return node;
|
||||
|
||||
@@ -28,6 +28,7 @@ export function useDoc(
|
||||
return useQuery<Doc, APIError, Doc>({
|
||||
queryKey: [KEY_DOC, param],
|
||||
queryFn: () => getDoc(param),
|
||||
|
||||
...queryConfig,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -17,16 +17,20 @@ import { Doc } from '../types';
|
||||
interface ModalRemoveDocProps {
|
||||
onClose: () => void;
|
||||
doc: Doc;
|
||||
afterDelete?: (doc: Doc) => void;
|
||||
}
|
||||
|
||||
export const ModalRemoveDoc = ({ onClose, doc }: ModalRemoveDocProps) => {
|
||||
export const ModalRemoveDoc = ({
|
||||
onClose,
|
||||
doc,
|
||||
afterDelete,
|
||||
}: ModalRemoveDocProps) => {
|
||||
const { toast } = useToastProvider();
|
||||
const { push } = useRouter();
|
||||
const pathname = usePathname();
|
||||
|
||||
const {
|
||||
mutate: removeDoc,
|
||||
|
||||
isError,
|
||||
error,
|
||||
} = useRemoveDoc({
|
||||
@@ -34,6 +38,11 @@ export const ModalRemoveDoc = ({ onClose, doc }: ModalRemoveDocProps) => {
|
||||
toast(t('The document has been deleted.'), VariantType.SUCCESS, {
|
||||
duration: 4000,
|
||||
});
|
||||
if (afterDelete) {
|
||||
afterDelete(doc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pathname === '/') {
|
||||
onClose();
|
||||
} else {
|
||||
|
||||
@@ -46,6 +46,7 @@ export interface Doc {
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
numchild: number;
|
||||
children?: Doc[];
|
||||
abilities: {
|
||||
accesses_manage: boolean;
|
||||
accesses_view: boolean;
|
||||
|
||||
@@ -47,6 +47,8 @@ export function useDocTree(
|
||||
return useQuery<Doc[], APIError, Doc[]>({
|
||||
queryKey: [KEY_LIST_DOC_CHILDREN, params],
|
||||
queryFn: () => getDocTree(params),
|
||||
staleTime: 0,
|
||||
gcTime: 0,
|
||||
...queryConfig,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { OpenMap } from 'react-arborist/dist/module/state/open-slice';
|
||||
import { css } from 'styled-components';
|
||||
|
||||
import { fetchAPI } from '@/api';
|
||||
@@ -7,7 +8,7 @@ import { TreeView } from '@/components/common/tree/TreeView';
|
||||
import { useTreeStore } from '@/components/common/tree/treeStore';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
|
||||
import { Doc, useDoc } from '../../doc-management';
|
||||
import { Doc } from '../../doc-management';
|
||||
import { SimpleDocItem } from '../../docs-grid';
|
||||
import { useDocTree } from '../api/useDocTree';
|
||||
import { TreeViewDataType, TreeViewMoveResult } from '../types/tree';
|
||||
@@ -20,9 +21,14 @@ type Props = {
|
||||
|
||||
export type DocTreeDataType = TreeViewDataType<Doc>;
|
||||
export const DocTree = ({ docId }: Props) => {
|
||||
const [rootNode, setRootNode] = useState<Doc | null>(null);
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
const spacing = spacingsTokens();
|
||||
const { data: rootNode } = useDoc({ id: docId });
|
||||
|
||||
const [initialOpenState, setInitialOpenState] = useState<OpenMap | undefined>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
const {
|
||||
selectedNode,
|
||||
setSelectedNode,
|
||||
@@ -62,18 +68,46 @@ export const DocTree = ({ docId }: Props) => {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(data);
|
||||
const newChildren = data ?? [];
|
||||
const root = newChildren.shift();
|
||||
console.log('root', root);
|
||||
const newData: DocTreeDataType[] = newChildren.map((child) => ({
|
||||
...child,
|
||||
childrenCount: child.numchild,
|
||||
children: [],
|
||||
parentId: docId,
|
||||
}));
|
||||
setTreeDataStore(newData);
|
||||
}, [data, setTreeDataStore, docId]);
|
||||
const initialOpenState: OpenMap = {};
|
||||
const root = data[0];
|
||||
|
||||
initialOpenState[root.id] = true;
|
||||
|
||||
const serialize = (
|
||||
children: Doc[],
|
||||
parentId: Doc['id'],
|
||||
): DocTreeDataType[] => {
|
||||
if (children.length === 0) {
|
||||
return [];
|
||||
}
|
||||
return children.map((child) => {
|
||||
if (child?.children?.length && child?.children?.length > 0) {
|
||||
initialOpenState[child.id] = true;
|
||||
}
|
||||
|
||||
if (docId === child.id) {
|
||||
setSelectedNode(child);
|
||||
}
|
||||
|
||||
const node = {
|
||||
...child,
|
||||
childrenCount: child.numchild,
|
||||
children: serialize(child.children ?? [], child.id),
|
||||
parentId: parentId,
|
||||
};
|
||||
if (child?.children?.length && child?.children?.length > 0) {
|
||||
initialOpenState[child.id] = true;
|
||||
}
|
||||
return node;
|
||||
});
|
||||
};
|
||||
|
||||
root.children = serialize(root.children ?? [], docId);
|
||||
console.log('initialOpenState', initialOpenState);
|
||||
setInitialOpenState(initialOpenState);
|
||||
setRootNode(root);
|
||||
setTreeDataStore(root.children ?? []);
|
||||
}, [data, setTreeDataStore, docId, setSelectedNode, rootNode]);
|
||||
|
||||
const isRootNodeSelected = !selectedNode
|
||||
? true
|
||||
@@ -114,16 +148,19 @@ export const DocTree = ({ docId }: Props) => {
|
||||
</Box>
|
||||
</SeparatedSection>
|
||||
<Box $padding={{ all: 'sm' }} $margin={{ top: '-35px' }} $width="100%">
|
||||
<TreeView
|
||||
treeData={treeDataStore}
|
||||
width="100%"
|
||||
selectedNodeId={selectedNode?.id}
|
||||
rootNodeId={docId}
|
||||
renderNode={(props) => <DocTreeItem {...props} />}
|
||||
afterMove={(result, newTreeData) => {
|
||||
void afterMove(result, newTreeData);
|
||||
}}
|
||||
/>
|
||||
{initialOpenState && treeDataStore.length > 0 && (
|
||||
<TreeView
|
||||
initialOpenState={initialOpenState}
|
||||
treeData={treeDataStore}
|
||||
width="100%"
|
||||
selectedNodeId={selectedNode?.id}
|
||||
rootNodeId={docId}
|
||||
renderNode={(props) => <DocTreeItem {...props} />}
|
||||
afterMove={(result, newTreeData) => {
|
||||
void afterMove(result, newTreeData);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -25,11 +25,15 @@ type DocTreeItemProps = NodeRendererProps<TreeViewDataType<DocTreeDataType>>;
|
||||
|
||||
export const DocTreeItem = ({ node, ...props }: DocTreeItemProps) => {
|
||||
const data = node.data;
|
||||
const { push } = useRouter();
|
||||
|
||||
const deleteModal = useModal();
|
||||
|
||||
const shareModal = useModal();
|
||||
const renameModal = useModal();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const { updateNode, setSelectedNode } = useTreeStore();
|
||||
const { updateNode, setSelectedNode, removeNode, refreshNode } =
|
||||
useTreeStore();
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
const { refetch } = useDocChildren(
|
||||
{
|
||||
@@ -54,9 +58,16 @@ export const DocTreeItem = ({ node, ...props }: DocTreeItemProps) => {
|
||||
})
|
||||
.catch(console.error);
|
||||
} else {
|
||||
const newDoc = {
|
||||
...doc,
|
||||
children: [],
|
||||
childrenCount: 0,
|
||||
parentId: node.id,
|
||||
};
|
||||
updateNode(node.id, {
|
||||
...node.data,
|
||||
children: [...actualChildren, doc],
|
||||
children: [...actualChildren, newDoc],
|
||||
childrenCount: actualChildren.length + 1,
|
||||
});
|
||||
node.open();
|
||||
router.push(`/docs/${doc.id}`);
|
||||
@@ -84,6 +95,16 @@ export const DocTreeItem = ({ node, ...props }: DocTreeItemProps) => {
|
||||
return newChilds;
|
||||
};
|
||||
|
||||
const afterDelete = () => {
|
||||
console.log('afterDelete', node.data);
|
||||
if (node.data.parentId) {
|
||||
router.push(`/docs/${node.data.parentId}`);
|
||||
refreshNode(node.data.parentId);
|
||||
setSelectedNode(node.data);
|
||||
}
|
||||
removeNode(node.data.id);
|
||||
};
|
||||
|
||||
const options = [
|
||||
{
|
||||
label: t('Rename'),
|
||||
@@ -140,7 +161,11 @@ export const DocTreeItem = ({ node, ...props }: DocTreeItemProps) => {
|
||||
/>
|
||||
</TreeViewNode>
|
||||
{deleteModal.isOpen && (
|
||||
<ModalRemoveDoc onClose={deleteModal.onClose} doc={node.data} />
|
||||
<ModalRemoveDoc
|
||||
onClose={deleteModal.onClose}
|
||||
doc={node.data}
|
||||
afterDelete={afterDelete}
|
||||
/>
|
||||
)}
|
||||
{shareModal.isOpen && (
|
||||
<DocShareModal doc={node.data} onClose={shareModal.close} />
|
||||
|
||||
Reference in New Issue
Block a user