vzcode
Version:
Multiplayer code editor system
168 lines (159 loc) • 4.44 kB
text/typescript
import { useCallback } from 'react';
import { FileTreePath } from '../types';
import { VizFileId, VizContent } from '@vizhub/viz-types';
import { randomId } from '../randomId';
// CRUD operations for files and directories
// CRUD = Create, Read, Update, Delete
export const useFileCRUD = ({
submitOperation,
closeTabs,
openTab,
}: {
submitOperation: (
operation: (document: VizContent) => VizContent,
) => void;
closeTabs: (idsToDelete: Array<VizFileId>) => void;
openTab: ({
fileId,
isTransient,
}: {
fileId: VizFileId;
isTransient: boolean;
}) => void;
}) => {
// Create a new file
const createFile = useCallback(
(name: string, text = '') => {
if (name) {
const fileId: VizFileId = randomId();
submitOperation((document: VizContent) => ({
...document,
files: {
...document.files,
[fileId]: { name, text },
},
}));
// When a new file is created, open it in a new tab
// and focus the editor on it.
openTab({ fileId, isTransient: false });
}
},
[submitOperation],
);
const createDirectory = useCallback(
(name: string, text = null) => {
if (name) {
name += '/';
const fileId: VizFileId = randomId();
submitOperation((document: VizContent) => ({
...document,
files: {
...document.files,
[fileId]: { name, text },
},
}));
}
},
[submitOperation],
);
// Called when a file in the sidebar is renamed.
const renameFile = useCallback(
(fileId: VizFileId, newName: string) => {
submitOperation((document: VizContent) => ({
...document,
files: {
...document.files,
[fileId]: {
...document.files[fileId],
name:
document.files[fileId].name.substring(
0,
document.files[fileId].name.lastIndexOf(
'/',
) + 1,
) + newName,
},
},
}));
},
[submitOperation],
);
// Renames a directory
const renameDirectory = useCallback(
(
path: FileTreePath,
oldName: string,
newName: string,
) => {
submitOperation((document: VizContent) => {
const updatedFiles = Object.keys(
document.files,
).reduce((acc, key) => {
const file = document.files[key];
const fileName = file.name;
//See if it's actually in directory
if (fileName.includes(path + '/')) {
//Create New Name for System
const pathPart = fileName.substring(
0,
fileName.indexOf(path) + path.length,
);
const oldNamePos =
pathPart.lastIndexOf(oldName);
const fileNewName =
fileName.substring(0, oldNamePos) +
newName +
fileName.substring(
oldNamePos + oldName.length,
);
//Return with new names
acc[key] = { ...file, name: fileNewName };
} else {
acc[key] = file;
}
return acc;
}, {});
return { ...document, files: updatedFiles };
});
},
[submitOperation],
);
// Deletes a file
const deleteFile = useCallback(
(fileId: VizFileId) => {
closeTabs([fileId]);
submitOperation((document) => {
const updatedFiles = { ...document.files };
delete updatedFiles[fileId];
return { ...document, files: updatedFiles };
});
},
[submitOperation, closeTabs],
);
// Deletes a directory and all files within it
const deleteDirectory = useCallback(
(path: FileTreePath) => {
const tabsToClose: Array<VizFileId> = [];
submitOperation((document: VizContent) => {
const updatedFiles = { ...document.files };
for (const key in updatedFiles) {
if (updatedFiles[key].name.includes(path + '/')) {
tabsToClose.push(key);
delete updatedFiles[key];
}
}
return { ...document, files: updatedFiles };
});
closeTabs(tabsToClose);
},
[submitOperation, closeTabs],
);
return {
createFile,
renameFile,
deleteFile,
createDirectory,
renameDirectory,
deleteDirectory,
};
};