Skip to content

Commit

Permalink
release v1.3.2
Browse files Browse the repository at this point in the history
  • Loading branch information
onschan authored Oct 21, 2022
2 parents 4c526fb + 2daf5b4 commit 0d52b64
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 37 deletions.
32 changes: 30 additions & 2 deletions frontend/src/components/common/LazyImage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,55 @@ interface LazyImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {
const LazyImage: React.FC<LazyImageProps> = ({ imageUrl, ...props }) => {
const lazyImageRef = useRef<HTMLImageElement>(null);
const observerRef = useRef<IntersectionObserver>();
const timeId = useRef<ReturnType<typeof setTimeout>>();

const intersectionCallBack = (entries: IntersectionObserverEntry[], io: IntersectionObserver) => {
entries.forEach(entry => {
if (!entry.isIntersecting) return;

entry.target.setAttribute('src', imageUrl || '');

io.unobserve(entry.target);
});
};

const onLoad = () => {
if (timeId.current) {
clearTimeout(timeId.current);
}
};

const onError = () => {
if (timeId.current) {
clearTimeout(timeId.current);
}

if (!imageUrl) return;

const newTimeId = setTimeout(() => {
if (lazyImageRef.current) {
lazyImageRef.current.src = imageUrl;
clearTimeout(timeId.current);
}
}, 3000);

timeId.current = newTimeId;
};

useEffect(() => {
if (!observerRef.current) {
observerRef.current = new IntersectionObserver(intersectionCallBack);
}

lazyImageRef.current && observerRef.current.observe(lazyImageRef.current);

return () => observerRef.current && observerRef.current.disconnect();
return () => {
observerRef.current && observerRef.current.disconnect();
clearTimeout(timeId.current);
};
}, []);

return <img ref={lazyImageRef} {...props} />;
return <img ref={lazyImageRef} onLoad={onLoad} onError={onError} {...props} />;
};

export default LazyImage;
15 changes: 12 additions & 3 deletions frontend/src/components/user/DetailInfoModal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Dimmer from '@/components/common/Dimmer';
import { useState } from 'react';

import homeCover_fallback from '@/assets/homeCover-fallback.png';
import Dimmer from '@/components/common/Dimmer';

import ModalPortal from '@/portals/ModalPortal';

Expand All @@ -13,12 +13,21 @@ export interface DetailInfoModalProps {
}

const DetailInfoModal: React.FC<DetailInfoModalProps> = ({ name, imageUrl, description }) => {
const [isLoadImg, setIsLoadImg] = useState<boolean>(true);

const onLoad = () => {
setIsLoadImg(false);
};

return (
<ModalPortal>
<Dimmer>
<div css={styles.container}>
<h1 css={styles.title}>{name}</h1>
<div css={styles.imageWrapper}>{imageUrl !== '' && <img css={styles.image} src={imageUrl} />}</div>
<div css={styles.imageWrapper}>
{imageUrl !== '' && isLoadImg && <div css={styles.skeletonImage}></div>}
{imageUrl !== '' && <img css={styles.image} onLoad={onLoad} src={imageUrl} />}
</div>
<span css={styles.description}>{description}</span>
</div>
</Dimmer>
Expand Down
31 changes: 30 additions & 1 deletion frontend/src/components/user/DetailInfoModal/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,39 @@ const image = css`
object-fit: cover;
`;

const skeletonImage = css`
${image}
background-color: ${theme.colors.gray200};
position: relative;
border: none;
overflow: hidden;
@keyframes loading {
0% {
transform: translateX(0);
}
100% {
transform: translateX(600px);
}
}
&:before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 140px;
height: 100%;
background: linear-gradient(to right, ${theme.colors.gray200}, ${theme.colors.gray330}, ${theme.colors.gray200});
animation: loading 1.4s infinite linear;
}
`;

const description = css`
margin: 16px 0;
`;

const styles = { container, title, description, imageWrapper, image };
const styles = { container, title, description, imageWrapper, image, skeletonImage };

export default styles;
51 changes: 51 additions & 0 deletions frontend/src/hooks/useSocket.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Stomp } from '@stomp/stompjs';
import { useRef } from 'react';

const useSocket = (url: string) => {
const stomp = useRef<any>(null);
const isConnected = useRef<boolean>(false);

const checkIsConnected = () => {
return isConnected.current;
};

const connectSocket = (callbackConnect: () => void, callbackError: () => void, callbackDisconnect: () => void) => {
stomp.current = Stomp.client(url);
isConnected.current = true;

stomp.current.reconnect_delay = 1000;
stomp.current.heartbeat.outgoing = 0;
stomp.current.heartbeat.incoming = 0;

if (process.env.NODE_ENV !== 'development') {
stomp.current.debug = () => {};
}

stomp.current.connect({}, callbackConnect, callbackError, callbackDisconnect);
};

const disconnectSocket = () => {
if (isConnected.current) {
isConnected.current = false;
stomp.current.disconnect();
}
};

const subscribeTopic = (endPoint: string, callback: (data?: unknown) => void) => {
stomp.current.subscribe(endPoint, callback);
};

const sendMessage = (endPoint: string, data: unknown) => {
stomp.current.send(endPoint, {}, JSON.stringify(data));
};

return {
checkIsConnected,
connectSocket,
disconnectSocket,
subscribeTopic,
sendMessage,
};
};

export default useSocket;
5 changes: 2 additions & 3 deletions frontend/src/pages/user/TaskList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import useTaskList from './useTaskList';
import { IoIosArrowBack } from '@react-icons/all-files/io/IoIosArrowBack';
import React from 'react';

import Button from '@/components/common/Button';
import Sticky from '@/components/common/Sticky';
Expand All @@ -14,7 +13,7 @@ const TaskList: React.FC = () => {
const {
spaceData,
onSubmit,
goPreviousPage,
onClickGoPreviousPage,
totalCount,
checkedCount,
percent,
Expand All @@ -31,7 +30,7 @@ const TaskList: React.FC = () => {
<div css={styles.layout}>
<div css={styles.header}>
<div css={styles.arrowBackIcon}>
<IoIosArrowBack size={30} onClick={goPreviousPage} />
<IoIosArrowBack size={30} onClick={onClickGoPreviousPage} />
</div>
<div css={styles.headerInfo}>
<div css={styles.thumbnail(spaceData?.imageUrl || DEFAULT_IMAGE)} />
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/user/TaskList/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const layout = css`
width: 100%;
align-items: center;
font-size: 16px;
padding-bottom: 32px;
padding-bottom: 5em;
`;

const contents = css`
Expand Down
72 changes: 45 additions & 27 deletions frontend/src/pages/user/TaskList/useTaskList.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Stomp } from '@stomp/stompjs';
import { useEffect, useState } from 'react';
import { useRef } from 'react';
import { useQuery } from 'react-query';
Expand All @@ -10,6 +9,7 @@ import NameModal from '@/components/user/NameModal';
import useGoPreviousPage from '@/hooks/useGoPreviousPage';
import useModal from '@/hooks/useModal';
import useSectionCheck from '@/hooks/useSectionCheck';
import useSocket from '@/hooks/useSocket';
import useToast from '@/hooks/useToast';

import apis from '@/apis';
Expand All @@ -18,11 +18,17 @@ import { ID, SectionType } from '@/types';
import { ApiTaskData } from '@/types/apis';

const useTaskList = () => {
const isSubmitted = useRef<boolean>(false);

const { spaceId, jobId } = useParams() as { spaceId: ID; jobId: ID };

const location = useLocation();
const locationState = location.state as { jobName: string };

const { checkIsConnected, connectSocket, disconnectSocket, subscribeTopic, sendMessage } = useSocket(
`${process.env.REACT_APP_WS_URL}/ws-connect`
);

const { openModal, closeModal } = useModal();
const { openToast } = useToast();

Expand All @@ -47,9 +53,6 @@ const useTaskList = () => {
sectionsData?.sections || []
);

const stomp = useRef<any>(null);
const isSubmitted = useRef<boolean>(false);

const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
openModal(
Expand All @@ -67,44 +70,59 @@ const useTaskList = () => {
openModal(<DetailInfoModal name={section.name} imageUrl={section.imageUrl} description={section.description} />);
};

const onClickGoPreviousPage = () => {
disconnectSocket();
goPreviousPage();
};

const completeJobs = (author: string) => {
if (!stomp.current) return;
isSubmitted.current = true;
stomp.current.send(`/app/jobs/${jobId}/complete`, {}, JSON.stringify({ author }));
sendMessage(`/app/jobs/${jobId}/complete`, { author });
};

const flipTaskCheck = (taskId: ID) => {
if (!stomp.current) return;
stomp.current.send(`/app/jobs/${jobId}/tasks/flip`, {}, JSON.stringify({ taskId }));
sendMessage(`/app/jobs/${jobId}/tasks/flip`, { taskId });
};

const onClickSectionAllCheck = (sectionId: ID) => {
if (!stomp.current) return;
stomp.current.send(`/app/jobs/${jobId}/sections/checkAll`, {}, JSON.stringify({ sectionId }));
sendMessage(`/app/jobs/${jobId}/sections/checkAll`, { sectionId });
};

useEffect(() => {
stomp.current = Stomp.client(`${process.env.REACT_APP_WS_URL}/ws-connect`);
const onConnectSocket = () => {
subscribeTopic(`/topic/jobs/${jobId}`, (data: any) => {
setSectionsData(JSON.parse(data.body));
});

stomp.current.reconnect_delay = 1000;
subscribeTopic(`/topic/jobs/${jobId}/complete`, () => {
closeModal();
goPreviousPage();

stomp.current.connect({}, () => {
stomp.current.subscribe(`/topic/jobs/${jobId}`, (data: any) => {
setSectionsData(JSON.parse(data.body));
});
isSubmitted.current
? openToast('SUCCESS', '์ฒดํฌ๋ฆฌ์ŠคํŠธ๋ฅผ ์ œ์ถœํ•˜์˜€์Šต๋‹ˆ๋‹ค.')
: openToast('ERROR', 'ํ•ด๋‹น ์ฒดํฌ๋ฆฌ์ŠคํŠธ๋ฅผ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๊ฐ€ ์ œ์ถœํ•˜์˜€์Šต๋‹ˆ๋‹ค.');
});
};

stomp.current.subscribe(`/topic/jobs/${jobId}/complete`, (data: any) => {
closeModal();
goPreviousPage();
const onErrorSocket = () => {
openToast('ERROR', '์—ฐ๊ฒฐ์— ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.');
disconnectSocket();
goPreviousPage();
};

isSubmitted.current
? openToast('SUCCESS', '์ฒดํฌ๋ฆฌ์ŠคํŠธ๋ฅผ ์ œ์ถœํ•˜์˜€์Šต๋‹ˆ๋‹ค.')
: openToast('ERROR', 'ํ•ด๋‹น ์ฒดํฌ๋ฆฌ์ŠคํŠธ๋ฅผ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๊ฐ€ ์ œ์ถœํ•˜์˜€์Šต๋‹ˆ๋‹ค.');
});
});
const onDisconnectSocket = () => {
const isConnected = checkIsConnected();

if (isConnected) {
openToast('ERROR', '์žฅ์‹œ๊ฐ„ ๋™์ž‘์ด ์—†์–ด ์ด์ „ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.');
goPreviousPage();
}
};

useEffect(() => {
connectSocket(onConnectSocket, onErrorSocket, onDisconnectSocket);

return () => {
stomp.current.disconnect();
disconnectSocket();
};
}, []);

Expand All @@ -115,7 +133,7 @@ const useTaskList = () => {
return {
spaceData,
onSubmit,
goPreviousPage,
onClickGoPreviousPage,
totalCount,
checkedCount,
percent,
Expand Down
1 change: 1 addition & 0 deletions frontend/src/styles/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const theme = Object.freeze({
gray100: '#f9fbfd',
gray200: '#f5f5f5',
gray300: '#d9d9d9',
gray330: '#EDE4E0',
gray350: '#f5f6fa',
gray400: '#d1ccc0',
gray500: '#84817a',
Expand Down

0 comments on commit 0d52b64

Please sign in to comment.