Skip to content

Commit

Permalink
Fixed Client Workspace Management
Browse files Browse the repository at this point in the history
  • Loading branch information
R1c4rdCo5t4 committed May 12, 2024
1 parent f2a0e3d commit 97c939c
Show file tree
Hide file tree
Showing 23 changed files with 151 additions and 138 deletions.
2 changes: 1 addition & 1 deletion code/client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function App() {
}
/>
<Route
path="/:id"
path="documents/:id"
element={
<>
<Sidebar />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,10 @@ export default (editor: Editor, domainOperations: InputDomainOperations, onForma
* Handles cursor selection
*/
function onSelectionChange() {
const { selection } = editor;
if (!selection) return;
const styles = CustomEditor.getMarks(editor) as InlineStyle[];
domainOperations.updateSelection(editor.selection, styles);
domainOperations.updateSelection(selection, styles);
}

function onBlur() {
Expand Down
14 changes: 7 additions & 7 deletions code/client/src/domain/workspace/WorkspaceContext.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import * as React from 'react';
import { useState, createContext, useEffect } from 'react';
import { WorkspaceResource } from '@notespace/shared/src/workspace/types/resource.ts';
import { Workspace } from '@notespace/shared/src/workspace/types/workspace.ts';
import { useCommunication } from '@/services/communication/context/useCommunication.ts';
import useError from '@domain/error/useError.ts';
import { useParams } from 'react-router-dom';

export type WorkspaceContextType = {
resources: WorkspaceResource[];
workspace?: Workspace;
filePath?: string;
setFilePath: (path: string) => void;
};

export const WorkspaceContext = createContext<WorkspaceContextType>({
resources: [],
workspace: undefined,
filePath: undefined,
setFilePath: () => {},
});

export function WorkspaceProvider({ children }: { children: React.ReactNode }) {
const [resources, setResources] = useState<WorkspaceResource[]>([]);
const [workspace, setWorkspace] = useState<Workspace | undefined>(undefined);
const [filePath, setFilePath] = useState<string | undefined>(undefined);
const { http } = useCommunication();
const { publishError } = useError();
Expand All @@ -27,11 +27,11 @@ export function WorkspaceProvider({ children }: { children: React.ReactNode }) {
useEffect(() => {
if (!wid) return;
async function getResources() {
const res = await http.get(`/workspaces/${wid}`);
setResources(res);
const ws = await http.get(`/workspaces/${wid}`);
setWorkspace(ws);
}
getResources().catch(publishError);
}, [http, publishError, wid]);

return <WorkspaceContext.Provider value={{ resources, filePath, setFilePath }}>{children}</WorkspaceContext.Provider>;
return <WorkspaceContext.Provider value={{ workspace, filePath, setFilePath }}>{children}</WorkspaceContext.Provider>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { OperationEmitter } from '@/services/communication/socket/operationEmitt

type EmitType = (event: string, data?: any) => void;
type ListenType = (eventHandlers: SocketEventHandlers) => void;
type ConnectionType = (namespace: string) => void;
type ConnectionType = () => void;
export type SocketEventHandlers = Record<string, (...args: any[]) => void>;

export interface SocketCommunication {
Expand All @@ -24,11 +24,11 @@ function emit(event: string, data: any) {
case 'operation':
operationEmitter.addOperation(...data);
break;
case 'cursor':
case 'cursorChange':
setTimeout(() => socket.emit(event, data), OPERATION_DELAY);
break;
default:
socket.emit(event, ...data);
socket.emit(event, data);
break;
}
}
Expand Down
41 changes: 26 additions & 15 deletions code/client/src/services/documentServices.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,32 @@
import { HttpCommunication } from '@/services/communication/http/httpCommunication';
import { DocumentResource } from '@notespace/shared/src/workspace/types/resource.ts';
import { DocumentResource, ResourceInputModel, ResourceType } from '@notespace/shared/src/workspace/types/resource.ts';

async function getDocument(http: HttpCommunication, id: string): Promise<DocumentResource> {
return await http.get(`/documents/${id}`);
}
function documentServices(http: HttpCommunication, wid: string) {
async function getDocument(id: string): Promise<DocumentResource> {
return await http.get(`/workspaces/${wid}/${id}`);
}

async function createDocument(http: HttpCommunication): Promise<string> {
const { id } = await http.post('/documents');
return id;
}
async function createDocument(name: string): Promise<string> {
const resource: ResourceInputModel = { name, type: ResourceType.DOCUMENT };
const { id } = await http.post(`/workspaces/${wid}`, resource);
return id;
}

async function deleteDocument(id: string) {
await http.delete(`/workspace/${wid}/${id}`);
}

async function updateDocument(id: string, name: string) {
const resource: Partial<ResourceInputModel> = { name };
await http.put(`/workspaces/${wid}/${id}`, resource);
}

async function deleteDocument(http: HttpCommunication, id: string) {
await http.delete(`/documents/${id}`);
return {
getDocument,
createDocument,
deleteDocument,
updateDocument,
};
}

export default {
getDocument,
createDocument,
deleteDocument,
};
export default documentServices;
17 changes: 7 additions & 10 deletions code/client/src/services/useDocumentServices.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import { HttpCommunication } from '@/services/communication/http/httpCommunication';
import documentServices from '@/services/documentServices';
import { useMemo } from 'react';
import { useCommunication } from '@/services/communication/context/useCommunication.ts';
import { useParams } from 'react-router-dom';

function useDocumentServices(http: HttpCommunication) {
return useMemo(
() => ({
getDocument: (id: string) => documentServices.getDocument(http, id),
createDocument: () => documentServices.createDocument(http),
deleteDocument: (id: string) => documentServices.deleteDocument(http, id),
}),
[http]
);
function useDocumentServices() {
const { http } = useCommunication();
const { wid } = useParams();
if (!wid) throw new Error('Cannot use document services outside of a workspace');
return useMemo(() => documentServices(http, wid), [http, wid]);
}

export default useDocumentServices;
6 changes: 6 additions & 0 deletions code/client/src/ui/components/dialog/Dialog.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.dialog {
.button {
margin: 0 !important;
padding: 0 !important;
}
}
5 changes: 3 additions & 2 deletions code/client/src/ui/components/dialog/Dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useState } from 'react';
import { Dialog as MaterialDialog, DialogTitle, DialogContent, TextField, DialogActions, Button } from '@mui/material';
import './Dialog.scss';

interface Field {
name: string;
Expand Down Expand Up @@ -37,7 +38,7 @@ function Dialog({ title, fields, onSubmit, children }: DialogProps) {
};

return (
<>
<div className="dialog">
<Button onClick={handleOpen} className="button">
{children}
</Button>
Expand Down Expand Up @@ -66,7 +67,7 @@ function Dialog({ title, fields, onSubmit, children }: DialogProps) {
</Button>
</DialogActions>
</MaterialDialog>
</>
</div>
);
}

Expand Down
27 changes: 4 additions & 23 deletions code/client/src/ui/components/sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,13 @@
import { IoMenu } from 'react-icons/io5';
import { useState } from 'react';
import { Link } from 'react-router-dom';
import './Sidebar.scss';
import { RiMenuFold2Line, RiMenuFoldLine } from 'react-icons/ri';
import useWorkspace from '@domain/workspace/useWorkspace.ts';
import useSidebarState from '@ui/components/sidebar/hooks/useSidebarState.ts';

function Sidebar() {
const [isOpen, setIsOpen] = useState(false);
const [isLocked, setIsLocked] = useState(false);
const [justClosed, setJustClosed] = useState(false);
const { resources } = useWorkspace();

const handleMouseEnter = () => {
if (justClosed) return;
setIsOpen(true);
};

const handleClick = () => {
setIsLocked(!isLocked && isOpen);
setIsOpen(!isLocked && !isOpen);
setJustClosed(isLocked);
};

const handleMouseLeave = () => {
if (isLocked) return;
setIsOpen(false);
setJustClosed(false);
};
const { isOpen, isLocked, handleClick, handleMouseEnter, handleMouseLeave } = useSidebarState();
const { workspace } = useWorkspace();

return (
<div
Expand All @@ -51,7 +32,7 @@ function Sidebar() {
<li>Workspaces</li>
<li>Settings</li>

{resources?.map(resource => (
{workspace?.resources.map(resource => (
<li key={resource.id}>
<Link to={`/workspaces/${resource.id}`}>{resource.name}</Link>
</li>
Expand Down
34 changes: 34 additions & 0 deletions code/client/src/ui/components/sidebar/hooks/useSidebarState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useState } from 'react';

function useSidebarState() {
const [isOpen, setIsOpen] = useState(false);
const [isLocked, setIsLocked] = useState(false);
const [justClosed, setJustClosed] = useState(false);

const handleMouseEnter = () => {
if (justClosed) return;
setIsOpen(true);
};

const handleClick = () => {
setIsLocked(!isLocked && isOpen);
setIsOpen(!isLocked && !isOpen);
setJustClosed(isLocked);
};

const handleMouseLeave = () => {
if (isLocked) return;
setIsOpen(false);
setJustClosed(false);
};

return {
isOpen,
isLocked,
handleMouseEnter,
handleClick,
handleMouseLeave,
};
}

export default useSidebarState;
19 changes: 7 additions & 12 deletions code/client/src/ui/pages/document/Document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,22 @@ import { useEffect, useState } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useCommunication } from '@/services/communication/context/useCommunication';
import useDocumentServices from '@/services/useDocumentServices';
import './Document.scss';
import useError from '@domain/error/useError';
import useWorkspace from '@domain/workspace/useWorkspace';
import './Document.scss';

function Document() {
const communication = useCommunication();
const services = useDocumentServices(communication.http);
const services = useDocumentServices();
const { http, socket } = communication;
const fugue = useFugue();
const { publishError } = useError();
const { id } = useParams();
const { wid, id } = useParams();
const [title, setTitle] = useState('');
const [loaded, setLoaded] = useState(false);
const { setFilePath } = useWorkspace();
const navigate = useNavigate();

// useEffect(() => {
// socket.connect('/documents');
// return () => {
// socket.disconnect('/documents');
// };
// }, [socket]);

useEffect(() => {
async function fetchDocument() {
if (!id) return;
Expand All @@ -35,16 +28,18 @@ function Document() {
setTitle(name);
setLoaded(true);
setFilePath(`/documents/${title || 'Untitled'}`);
socket.emit('joinWorkspace', wid);
socket.emit('joinDocument', id);
}
console.log('fetching document');
fetchDocument().catch(e => {
publishError(e);
navigate('/');
// navigate('/');
});
return () => {
socket.emit('leaveDocument');
};
}, [fugue, id, http, socket, publishError, services, setFilePath, navigate, title]);
}, [fugue, id, http, socket, publishError, services, setFilePath, navigate, title, wid]);

return <div>{loaded && <Editor title={title} fugue={fugue} communication={communication} />}</div>;
}
Expand Down
18 changes: 0 additions & 18 deletions code/client/src/ui/pages/home/Home.scss
Original file line number Diff line number Diff line change
@@ -1,18 +0,0 @@
.not-found {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 2rem;
font-weight: bold;
text-align: center;
padding: 1rem;
margin: 0;

:not(:first-child) {
background: black;
color: white;
padding: 1vh 2vh 1vh 2vh;
border-radius: 5px;
}
}
8 changes: 1 addition & 7 deletions code/client/src/ui/pages/home/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { WorkspaceMetaData } from '@notespace/shared/src/workspace/types/workspace.ts';
import useWorkspaces from '@ui/pages/workspace/hooks/useWorkspaces.ts';
import WorkspacePreview from '@ui/pages/home/components/WorkspacePreview.tsx';
import WorkspaceHeader from '@ui/pages/workspace/components/WorkspaceHeader.tsx';
Expand All @@ -8,12 +7,7 @@ import './Home.scss';
import '../workspace/Workspace.scss';

function Home() {
const workspaces: WorkspaceMetaData[] = [
{ id: '1', name: 'Workspace 1' },
{ id: '2', name: 'Workspace 2' },
{ id: '3', name: 'Workspace 3' },
];
const { createWorkspace, updateWorkspace, deleteWorkspace } = useWorkspaces();
const { workspaces, createWorkspace, updateWorkspace, deleteWorkspace } = useWorkspaces();
const { publishError } = useError();
return (
<div className="home">
Expand Down
17 changes: 11 additions & 6 deletions code/client/src/ui/pages/workspace/Workspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@ import DocumentPreview from '@ui/pages/workspace/components/DocumentPreview';
import useError from '@domain/error/useError';
import useDocuments from '@ui/pages/workspace/hooks/useDocuments.ts';
import './Workspace.scss';
import { useEffect } from 'react';
import { useCommunication } from '@/services/communication/context/useCommunication.ts';
import { useParams } from 'react-router-dom';

function Workspace() {
const documents = [
{ id: '1', name: 'Document 1' },
{ id: '2', name: 'Document 2' },
{ id: '3', name: 'Document 3' },
];
const { createDocument, deleteDocument, updateDocument } = useDocuments();
const { documents, createDocument, deleteDocument, updateDocument } = useDocuments();
const { socket } = useCommunication();
const { publishError } = useError();
const { wid } = useParams();

useEffect(() => {
socket.emit('joinWorkspace', wid);
}, [socket, wid]);

return (
<div className="workspace">
<h2>Workspace</h2>
Expand Down
Loading

0 comments on commit 97c939c

Please sign in to comment.