Skip to content

Commit

Permalink
[FE] swipe 기능을 ref를 받아 쓰도록 개선한다 (#959)
Browse files Browse the repository at this point in the history
  • Loading branch information
skiende74 authored Nov 15, 2024
1 parent 88a1ace commit 465eabd
Show file tree
Hide file tree
Showing 15 changed files with 68 additions and 54 deletions.
12 changes: 6 additions & 6 deletions frontend/src/apis/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,17 @@ export const deleteToken = async () => {
};

export const postReissueAccessToken = async () => {
return await fetch(`${BASE_URL}${ENDPOINT.USER_ACCESS_TOKEN_REISSUE}`, {
method: 'POST',
return await fetcher.post({
url: `${BASE_URL}${ENDPOINT.USER_ACCESS_TOKEN_REISSUE}`,
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
// 쿠키전달이기때문에 body가 비어있는 post
});
};

export const postSignUp = async ({ name, email, password }: { name: string; email: string; password: string }) => {
return await fetch(`${BASE_URL}${ENDPOINT.REGISTER}`, {
method: 'POST',
body: JSON.stringify({ name, email, password }),
return await fetcher.post({
url: `${BASE_URL}${ENDPOINT.REGISTER}`,
body: { name, email, password },
credentials: 'include',
});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import RoomInfoTemplate from '@/components/NewChecklist/NewRoomInfoForm/RoomInfo
import OptionTemplate from '@/components/NewChecklist/Option/OptionTemplate';

const EditChecklistContent = () => {
const { currentTabId } = useTabContext();
const { currentTabId, useDragForTab } = useTabContext();

const ref = useDragForTab();

return (
<S.Container>
<S.Container ref={ref}>
{/*방 기본정보 템플릿 */}
{currentTabId === -1 && <RoomInfoTemplate />}
{/* 옵션 선택 템플릿 */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Divider from '@/components/_common/Divider/Divider';
import Layout from '@/components/_common/layout/Layout';
import { useTabContext } from '@/components/_common/Tabs/TabContext';
import ChecklistQuestionItem from '@/components/NewChecklist/ChecklistQuestion/ChecklistQuestion';
import MoveNextButton from '@/components/NewChecklist/MoveNextButton';
import useChecklistStore from '@/store/useChecklistStore';
import { flexColumn } from '@/styles/common';
import theme from '@/styles/theme';
Expand Down Expand Up @@ -37,6 +38,8 @@ const EditChecklistQuestionTemplate = () => {
);
})}
</S.ContentBox>

<MoveNextButton marginTop="2rem" marginBottom="4rem" />
</Layout>
);
};
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/NewChecklist/ChecklistContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import RoomInfoTemplate from '@/components/NewChecklist/NewRoomInfoForm/RoomInfo
import OptionTemplate from '@/components/NewChecklist/Option/OptionTemplate';

const ChecklistContent = () => {
const { currentTabId } = useTabContext();
const { currentTabId, useDragForTab } = useTabContext();
useDragForTab();

return (
<S.Container>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { useMemo } from 'react';

import ChecklistTabSuspense from '@/components/_common/errorBoundary/ChecklistTabSuspense';
import { useTabContext } from '@/components/_common/Tabs/TabContext';
import Tabs from '@/components/_common/Tabs/Tabs';
import { DefaultChecklistTabsNames } from '@/constants/tabs';
import useInitialChecklist from '@/hooks/useInitialChecklist';
import useMouseDrag from '@/hooks/useMouseDrag';
import useTabs from '@/hooks/useTabs';
import useChecklistStore from '@/store/useChecklistStore';
import isSameCategory from '@/utils/isSameCategory';
Expand All @@ -14,20 +11,6 @@ const NewChecklistTab = () => {
const { data: checklist, isSuccess, isLoading } = useInitialChecklist();
const checklistStore = useChecklistStore(state => state.checklistCategoryQnA);
const { getTabsForChecklist } = useTabs();
const { setCurrentTabId } = useTabContext();

useMouseDrag((S, E) => {
const DRAG_THRESHOLD = 100;
const TAB_COUNT = DefaultChecklistTabsNames.length;
const remainOp = (a: number, b: number) => (((a % b) + b + 1) % b) - 1; // 나머지연산자. -1부터 시작하므로 +1 -1
setCurrentTabId(tabId => {
const isLeftDrag = E.x - S.x > DRAG_THRESHOLD;
const isRightDrag = S.x - E.x > DRAG_THRESHOLD;
if (isLeftDrag) return remainOp(tabId - 1, TAB_COUNT);
if (isRightDrag) return remainOp(tabId + 1, TAB_COUNT);
return tabId;
});
});

const categoryTabs = useMemo(() => {
if (isSuccess && isSameCategory(checklist, checklistStore)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const DepositAndRent = () => {
<FormField.Label label="보증금 / 월세 (만원)" />
<FormStyled.FieldBox>
<FormField.Input
inputMode="decimal"
width="medium"
onChange={deposit.onChange}
name="deposit"
Expand All @@ -21,6 +22,7 @@ const DepositAndRent = () => {
/>
<FormStyled.FlexLabel label=" / " />
<FormField.Input
inputMode="decimal"
width="medium"
placeholder=""
onChange={rent.onChange}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const MaintenanceFee = () => {
<FormField.Label label="관리비" htmlFor="maintenanceFee" />
<FormStyled.FieldBox>
<Input
inputMode="decimal"
width="medium"
placeholder=""
onChange={maintenanceFee.onChange}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const OccupancyMonth = () => {
<FormField.Label label="입주 가능일" htmlFor="occupancyMonth" />
<FormStyled.FieldBox>
<FormField.Input
inputMode="decimal"
width="medium"
onChange={occupancyMonth.onChange}
name="occupancyMonth"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const RoomContractTerm = () => {
<FormField.Label label="계약 기간" htmlFor="contractTerm" />
<S.FieldBox>
<Input
inputMode="decimal"
width="medium"
placeholder=""
onChange={contractTerm.onChange}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const RoomFloor = () => {
onSelectSetter={handleClickDropdown}
/>
<Input
inputMode="decimal"
width="medium"
disabled={floorLevel.rawValue === '반지하/지하'}
placeholder=""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const RoomSize = () => {
<FormField.Label label="방 크기" htmlFor="size" />
<FormStyled.FieldBox>
<Input
inputMode="decimal"
width="medium"
placeholder=""
onChange={roomSize.onChange}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ const SendVerificationEmailStep = ({ onNext }: Props) => {
onSuccess: () => setIsComplete(true),
onError: error => setPostErrorMessage(error.message),
});
const handleClickNext = () => {
onNext(email);
};
const handleClickNext = () => onNext(email);

const canMove = isEmailValid && isComplete;

Expand Down Expand Up @@ -74,7 +72,7 @@ const SendVerificationEmailStep = ({ onNext }: Props) => {
style={{ width: '25rem' }}
/>
<div>
<CS.SendButton onClick={handleClickSubmit} disabled={canMove}>
<CS.SendButton onClick={handleClickSubmit} disabled={canMove || !isEmailValid}>
전송
</CS.SendButton>
</div>
Expand Down
34 changes: 26 additions & 8 deletions frontend/src/components/_common/Tabs/TabContext.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,46 @@
import { createContext, ReactNode, useContext, useState } from 'react';
import { createContext, ReactNode, RefObject, useContext, useRef, useState } from 'react';

import { ERROR_MESSAGE } from '@/constants/messages/errorMessage';
import { DefaultChecklistTabsNames, DRAG_THRESHOLD_PIXEL } from '@/constants/tabs';
import useMouseDrag from '@/hooks/useMouseDrag';

interface ContextProps {
currentTabId: number;
setCurrentTabId: React.Dispatch<React.SetStateAction<number>>;
useDragForTab: () => RefObject<HTMLElement>;
}

const defaultContext: ContextProps = {
currentTabId: 0,
setCurrentTabId: () => {},
};

const TabContext = createContext<ContextProps>(defaultContext);
const TabContext = createContext<ContextProps | null>(null);

interface Props {
children: ReactNode;
defaultTab: number;
}

const remainOp = (a: number, b: number) => (((a % b) + b + 1) % b) - 1; // 나머지연산자. -1부터 시작하므로 +1 -1

export const TabProvider = ({ children, defaultTab = 0 }: Props) => {
const [currentTabId, setCurrentTabId] = useState<number>(defaultTab);

return <TabContext.Provider value={{ currentTabId, setCurrentTabId }}>{children}</TabContext.Provider>;
// 드래그로 탭이동을 위한 훅을 리턴에 제공
const useDragForTab = (dragThreshold: number = DRAG_THRESHOLD_PIXEL) => {
const ref = useRef<HTMLElement>(null);
useMouseDrag(ref, (S, E) => {
const TAB_COUNT = DefaultChecklistTabsNames.length;

setCurrentTabId(tabId => {
const isLeftDrag = E.x - S.x > dragThreshold;
const isRightDrag = S.x - E.x > dragThreshold;
if (isLeftDrag) return remainOp(tabId - 1, TAB_COUNT);
if (isRightDrag) return remainOp(tabId + 1, TAB_COUNT);
return tabId;
});
});

return ref;
};

return <TabContext.Provider value={{ currentTabId, setCurrentTabId, useDragForTab }}>{children}</TabContext.Provider>;
};

export const useTabContext = () => {
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/constants/tabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ export const DefaultChecklistTabsNames: Tab[] = [
name: '보안',
},
];

export const DRAG_THRESHOLD_PIXEL = 100;
32 changes: 16 additions & 16 deletions frontend/src/hooks/useMouseDrag.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
import { useEffect, useState } from 'react';
import { MutableRefObject, useEffect, useState } from 'react';

interface MousePosition {
x: number;
y: number;
}
type Handler = (start: MousePosition, end: MousePosition) => void;

const useMouseDrag = (handler: Handler) => {
const useMouseDrag = (ref: MutableRefObject<HTMLElement | null>, handler: Handler) => {
const [startPosition, setStartPosition] = useState<MousePosition | null>(null);

useEffect(() => {
const pointerdownListener = (e: MouseEvent) => {
setStartPosition({ x: e.clientX, y: e.clientY });
};
const touchStartListener = (e: TouchEvent) => {
const pointerdownListener = (e: MouseEvent) => setStartPosition({ x: e.clientX, y: e.clientY });

const touchStartListener = (e: TouchEvent) =>
setStartPosition({ x: e.changedTouches[0].clientX, y: e.changedTouches[0].clientX });
};

const pointerupListener = (e: MouseEvent) => {
const endPosition = { x: e.clientX, y: e.clientY };
Expand All @@ -30,18 +28,20 @@ const useMouseDrag = (handler: Handler) => {
setStartPosition(null);
};

window.addEventListener('mousedown', pointerdownListener);
window.addEventListener('touchstart', touchStartListener);
window.addEventListener('mouseup', pointerupListener);
window.addEventListener('touchend', touchEndListener);
const el = ref.current;

el?.addEventListener('mousedown', pointerdownListener);
el?.addEventListener('touchstart', touchStartListener);
el?.addEventListener('mouseup', pointerupListener);
el?.addEventListener('touchend', touchEndListener);

return () => {
window.removeEventListener('mousedown', pointerdownListener);
window.removeEventListener('mouseup', pointerupListener);
window.removeEventListener('touchstart', touchStartListener);
window.removeEventListener('touchend', touchEndListener);
el?.removeEventListener('mousedown', pointerdownListener);
el?.removeEventListener('mouseup', pointerupListener);
el?.removeEventListener('touchstart', touchStartListener);
el?.removeEventListener('touchend', touchEndListener);
};
}, [startPosition, handler]);
}, [startPosition, ref, handler]);
};

export default useMouseDrag;

0 comments on commit 465eabd

Please sign in to comment.