Skip to content

Commit

Permalink
Merge pull request #86 from Gkuzin13/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
Gkuzin13 authored Jan 24, 2024
2 parents 872f889 + 645f96c commit 0a11a40
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 88 deletions.
42 changes: 26 additions & 16 deletions apps/client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -212,18 +212,32 @@ const App = () => {
useEffect(() => {
if (!roomId) return;

const [request, abortController] = api.getPage(roomId);
const abortController = new AbortController();

request.then(({ page }) => {
dispatch(canvasActions.setNodes(page.nodes, { broadcast: false }));
});
(async () => {
const { data, error } = await api.getPage(roomId, {
signal: abortController.signal,
});

if (data) {
dispatch(canvasActions.setNodes(data.page.nodes, { broadcast: false }));
}

if (error) {
addNotification({
title: 'Live collaboration',
description: 'Could not load shapes',
type: 'error',
});
}
})();

return () => {
if (abortController.signal) {
abortController.abort();
}
};
}, [roomId, dispatch]);
}, [roomId, dispatch, addNotification]);

useEffect(() => {
if (!roomId) return;
Expand All @@ -246,20 +260,16 @@ const App = () => {

const unsubscribe = dispatch(addCollabActionsListeners(ws, roomId));

addNotification({
title: 'Live collaboration',
description: 'You are connected',
type: 'success',
});

return () => {
unsubscribe({ cancelActive: true });
};
}, [ws, roomId, dispatch]);

useEffect(() => {
if (ws.isConnected) {
addNotification({
title: 'Live collaboration',
description: 'You are connected',
type: 'success',
});
}
}, [ws.isConnected, addNotification]);
}, [ws, roomId, addNotification, dispatch]);

useEffect(() => {
if (ws.isConnected || ws.isConnecting || roomId) {
Expand Down
4 changes: 2 additions & 2 deletions apps/client/src/components/Elements/Dialog/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ const Dialog = ({ title, description, open, onClose }: Props) => {
<DialogPrimitive.Root open={open} onOpenChange={handleOpenChange}>
<DialogPrimitive.Portal>
<Styled.Overlay />
<Styled.Content>
<Styled.Close>
<Styled.Content data-testid="dialog-content">
<Styled.Close data-testid="close-dialog-button">
<Icon name="x" size="lg" />
</Styled.Close>
<Styled.Title>{title}</Styled.Title>
Expand Down
6 changes: 3 additions & 3 deletions apps/client/src/components/Panels/Panels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ const Panels = ({ selectedNodeIds }: Props) => {

const ws = useWebSocket();
const { online } = useNetworkState();
const modal = useModal();
const { openModal } = useModal();

const dispatch = useAppDispatch();

Expand Down Expand Up @@ -137,7 +137,7 @@ const Panels = ({ selectedNodeIds }: Props) => {

setCursorByToolType(stage, project.toolType ?? 'select');
} else {
modal.open({
openModal({
title: 'Error',
description: 'Could not load file',
});
Expand All @@ -148,7 +148,7 @@ const Panels = ({ selectedNodeIds }: Props) => {
}
}
},
[store, modal, dispatch],
[store, openModal, dispatch],
);

const handleZoomChange = useCallback(
Expand Down
14 changes: 10 additions & 4 deletions apps/client/src/components/Panels/SharePanel/SharePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,20 @@ const SharePanel = ({ isPageShared }: Props) => {
const [qrCode, setQRCode] = useState<QRCodeResponse | null>(null);
const [error, setError] = useState<string | null>(null);

const handlePopoverOpen = (open: boolean) => {
const handlePopoverOpen = async (open: boolean) => {
if (isPageShared && open && !qrCode) {
const url = window.location.href;

setError(null);
const { data, error } = await api.makeQRCode({ url });

const [request] = api.makeQRCode({ url });
request.then(setQRCode).catch(setError);
if (data) {
setQRCode(data);
setError(null);
}

if (error) {
setError(error.message);
}
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,30 @@ const SharablePageContent = () => {
const nodes = useAppSelector(selectNodes);
const stageConfig = useAppSelector(selectConfig);

const handlePageShare = () => {
const handlePageShare = async () => {
if (!nodes.length) {
return;
}

setLoading(true);

const [request] = api.sharePage({
const { data, error } = await api.sharePage({
page: { nodes, stageConfig },
});

request
.then((data) => {
if (data?.id) {
const updatedURL = urlSearchParam.set(
CONSTANTS.COLLAB_ROOM_URL_PARAM,
data.id,
);
if (data?.id) {
const updatedURL = urlSearchParam.set(
CONSTANTS.COLLAB_ROOM_URL_PARAM,
data.id,
);

window.history.pushState({}, '', updatedURL);
window.location.reload();
}

window.history.pushState({}, '', updatedURL);
window.location.reload();
}
})
.catch(() => setLoading(false));
if (error) {
setLoading(false);
}
};

return (
Expand Down
55 changes: 46 additions & 9 deletions apps/client/src/contexts/__tests__/modal.test.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,58 @@
import { act, renderHook, screen } from '@testing-library/react';
import { act, renderHook, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

Check warning on line 2 in apps/client/src/contexts/__tests__/modal.test.tsx

View workflow job for this annotation

GitHub Actions / test (18.17)

Using exported name 'userEvent' as identifier for default export
import { ModalProvider, useModal } from '../modal';

describe('modal context', () => {
it('opens dialog with provided content', async () => {
it('opens with provided content', async () => {
const { result } = renderHook(() => useModal(), { wrapper: ModalProvider });

await act(async () => {
result.current.open({ title: 'title', description: 'description' });
result.current.openModal({
title: 'test title',
description: 'test description',
});
});

expect(result.current.opened).toBe(true);
expect(result.current.content).toEqual({
title: 'title',
description: 'description',
const content = screen.getByTestId(/dialog-content/);

expect(content).toBeInTheDocument();
expect(within(content).getByText(/test title/)).toBeInTheDocument();
expect(within(content).getByText(/test description/)).toBeInTheDocument();
});

it('closes by clicking close button', async () => {
const { result } = renderHook(() => useModal(), { wrapper: ModalProvider });

await act(async () => {
result.current.openModal({
title: 'test title',
description: 'test description',
});
});

expect(screen.getByTestId(/dialog-content/)).toBeInTheDocument();

await userEvent.click(screen.getByTestId(/close-dialog-button/));

expect(screen.queryByTestId(/dialog-content/)).not.toBeInTheDocument();
});

it('closes from closeModal', async () => {
const { result } = renderHook(() => useModal(), { wrapper: ModalProvider });

await act(async () => {
result.current.openModal({
title: 'test title',
description: 'test description',
});
});

expect(screen.getByTestId(/dialog-content/)).toBeInTheDocument();

await act(async () => {
result.current.closeModal();
});

expect(screen.getByText('title')).toBeInTheDocument();
expect(screen.getByText('description')).toBeInTheDocument();
expect(screen.queryByTestId(/dialog-content/)).not.toBeInTheDocument();
});
});
23 changes: 13 additions & 10 deletions apps/client/src/contexts/modal.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { useState } from 'react';
import { useCallback, useState } from 'react';
import useDisclosure from '@/hooks/useDisclosure/useDisclosure';
import Dialog from '@/components/Elements/Dialog/Dialog';
import { createContext } from './createContext';

type ModalContextValue = {
opened: boolean;
content: ModalContent;
open: (content: ModalContent) => void;
close: () => void;
openModal: (content: ModalContent) => void;
closeModal: () => void;
};

type ModalContent = {
Expand All @@ -25,13 +23,18 @@ export const ModalProvider = ({ children }: React.PropsWithChildren) => {
description: '',
});

const openModal = (content: ModalContent) => {
setContent(content);
open();
};
const openModal = useCallback(
(content: ModalContent) => {
setContent(content);
open();
},
[open],
);

const closeModal = useCallback(() => close(), [close]);

return (
<ModalContext.Provider value={{ opened, content, open: openModal, close }}>
<ModalContext.Provider value={{ openModal, closeModal }}>
{children}
<Dialog open={opened} {...content} onClose={close} />
</ModalContext.Provider>
Expand Down
18 changes: 3 additions & 15 deletions apps/client/src/hooks/useDisclosure/useDisclosure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,9 @@ export type UseDisclosureReturn = [
const useDisclosure = (initialState = false): UseDisclosureReturn => {
const [opened, setOpened] = useState(initialState);

const open = () => {
setOpened((prevState) => {
return prevState ? prevState : true;
});
};

const close = () => {
setOpened((prevState) => {
return !prevState ? prevState : false;
});
};

const toggle = () => {
opened ? close() : open();
};
const open = () => setOpened(true);
const close = () => setOpened(false);
const toggle = () => setOpened((prevOpened) => !prevOpened);

return [opened, { open, close, toggle }];
};
Expand Down
33 changes: 19 additions & 14 deletions apps/client/src/services/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import type {
UpdatePageResponse,
} from 'shared';

type QueryReturn<D> = {
data: D | null;
error: HTTPError | null;
};

const baseUrl = IS_PROD ? BASE_URL : BASE_URL_DEV;

class HTTPError extends Error {}
Expand All @@ -17,23 +22,23 @@ const createQuery = (
baseUrl: RequestInfo | URL = '',
baseInit?: RequestInit,
) => {
return <T>(url: RequestInfo | URL, init?: RequestInit) => {
const controller = new AbortController();
const signal = controller.signal;
return async <D>(
url: RequestInfo | URL,
init?: RequestInit,
): Promise<QueryReturn<D>> => {
try {
const res = await fetch(`${baseUrl}${url}`, { ...baseInit, ...init });

const result = fetch(`${baseUrl}${url}`, {
...baseInit,
...init,
signal,
}).then((res) => {
if (!res.ok) {
throw new HTTPError(res.statusText, { cause: res });
}

const data = await res.json();

return res.json() as Promise<T>;
});

return [result, controller] as const;
return { data, error: null };
} catch (error) {
return { data: null, error: error as HTTPError };
}
};
};

Expand All @@ -59,8 +64,8 @@ const api = {
};

export default {
getPage: (pageId: string) => {
return api.get<GetPageResponse>(`/p/${pageId}`);
getPage: (pageId: string, init?: RequestInit) => {
return api.get<GetPageResponse>(`/p/${pageId}`, init);
},
updatePage: (pageId: string, body: UpdatePageRequestBody) => {
return api.patch<UpdatePageResponse>(`/p/${pageId}`, body);
Expand Down

0 comments on commit 0a11a40

Please sign in to comment.