Skip to content

Commit

Permalink
feat: 좌표찍기 1차 기능구현
Browse files Browse the repository at this point in the history
  • Loading branch information
JoStar33 committed May 6, 2024
1 parent 01c7df0 commit 1a25f16
Show file tree
Hide file tree
Showing 22 changed files with 280 additions and 47 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ module.exports = {
'@typescript-eslint/no-var-requires': 'off',
'no-explicit-any': 'off',
'prettier/prettier': ['error', { endOfLine: 'auto' }],
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
// 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
},
};
28 changes: 28 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"pretendard": "^1.3.9",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.13",
"react-hook-form": "^7.51.2",
"react-icons": "^5.0.1",
"react-router-dom": "^6.22.3",
Expand Down
44 changes: 22 additions & 22 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,36 @@ import Portal from '@/components/common/Portal';
import Modal from '@/components/common/Modal';
import { AnimatePresence } from 'framer-motion';
import Router from '@/Router';
import React from 'react';
import environment from './environment';
import { loadingState } from './stores/loading';
import Loading from './components/common/Loading';
import DarkBackground from './components/common/DarkBackground';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import queryClientDefaultOptions from './constants/queryClientDefaultOptions';

export default function App() {
const queryClient = new QueryClient(queryClientDefaultOptions);
const modalWithTextValue = useRecoilValue(modalWithText);
const loadingValue = useRecoilValue(loadingState);
React.useEffect(() => {
console.log(environment.serverUrl);
}, []);

return (
<Theme>
<GlobalStyle />
<Layout>
<Router />
</Layout>
<Portal>
<AnimatePresence>
{modalWithTextValue.type === 'ALERT' && <Modal.Alert />}
{modalWithTextValue.type === 'CONFIRM' && <Modal.Confirm />}
{loadingValue.isLoading && (
<DarkBackground>
<Loading mode="fixed" />
</DarkBackground>
)}
</AnimatePresence>
</Portal>
</Theme>
<QueryClientProvider client={queryClient}>
<Theme>
<GlobalStyle />
<Layout>
<Router />
</Layout>
<Portal>
<AnimatePresence>
{modalWithTextValue.type === 'ALERT' && <Modal.Alert />}
{modalWithTextValue.type === 'CONFIRM' && <Modal.Confirm />}
{loadingValue.isLoading && (
<DarkBackground>
<Loading mode="fixed" />
</DarkBackground>
)}
</AnimatePresence>
</Portal>
</Theme>
</QueryClientProvider>
);
}
10 changes: 10 additions & 0 deletions src/api/coordinate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { requests } from '.';
import * as coordinate from '@/types/coordinate';

const Coordinate = {
Get: {
list: () => requests.get<coordinate.ICoordinateListResponse>('/coordinate'),
},
};

export default Coordinate;
2 changes: 1 addition & 1 deletion src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const URL_API = '/api';

const config: AxiosRequestConfig = {
baseURL: environment.serverUrl + URL_API + VERSION,
withCredentials: true,
withCredentials: false,
};

const responseBody = <T extends Object = DefaultResponse>(response: AxiosResponse<T>) => response.data;
Expand Down
69 changes: 69 additions & 0 deletions src/components/error/ErrorComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import styled from 'styled-components';

interface IFallbackProps {
error?: Error;
margin?: string;
padding?: string;
height?: string;
text?: string;
children?: React.ReactNode;
}

function Text({ margin, padding, height, text, children }: IFallbackProps) {
return (
<S.ErrorComponentText padding={padding} margin={margin} height={height}>
<div>
<StyledTitle>{text ?? '에러 발생!'}</StyledTitle>
<div className="error-detail">
<p>잠시 후 다시 시도해주세요.</p>
{children}
</div>
</div>
</S.ErrorComponentText>
);
}

function Modal({ resetErrorBoundary }: { resetErrorBoundary: (...args: Array<unknown>) => void }) {
return (
<S.ErrorComponentModal>
<StyledTitle>잠시 후 다시시도해주세요</StyledTitle>
<div>
요청사항을 처리하는데 <br />
실패했습니다.
</div>
<button type="button" onClick={() => resetErrorBoundary()}>
확인
</button>
</S.ErrorComponentModal>
);
}

const StyledTitle = styled.h1`
color: var(--171717, #171717);
text-align: center;
font-size: 20px;
font-style: normal;
font-weight: 600;
line-height: 32px;
letter-spacing: -0.5px;
margin-bottom: 20px;
`;

const S = {
ErrorComponentText: styled.div<{ padding?: string; margin?: string; height?: string }>`
text-align: center;
padding: ${(props) => (props.padding ? props.padding : '120px 0')};
height: ${(props) => (props.height ? props.height : 'auto')};
margin: ${(props) => props.margin};
width: 100%;
.error-detail {
color: #a1a1a1;
font-size: 16px;
font-weight: 500;
line-height: 28px; /* 175% */
}
`,
ErrorComponentModal: styled.div``,
};

export const ErrorComponent = { Text, Modal };
15 changes: 15 additions & 0 deletions src/constants/queryClientDefaultOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { QueryClientConfig } from '@tanstack/react-query';

const queryClientDefaultOptions: QueryClientConfig = {
defaultOptions: {
queries: {
refetchOnMount: true,
refetchOnReconnect: true,
refetchOnWindowFocus: false,
retryDelay: 1,
retry: 0,
},
},
} as const;

export default queryClientDefaultOptions;
4 changes: 3 additions & 1 deletion src/constants/queryKeys.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const queryKeys = {};
const queryKeys = {
coordinateList: 'COORDINATE_LIST',
};

export default queryKeys;
31 changes: 27 additions & 4 deletions src/containers/HomeContainer.tsx → src/containers/home/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import Coordinate from '@/api/coordinate';
import Home from '@/components/home';
import queryKeys from '@/constants/queryKeys';
import useGeolocation, { INIT_COORDINATE } from '@/hooks/useGeolocation';
import useSimpleQuery, { IUseSimpleQuery } from '@/hooks/useSimpleQuery';
import { ICoordinateListResponse } from '@/types/coordinate';
import checkForMarkersRendering from '@/utils/checkForMarkersRendering';
import React from 'react';

const TEN_MINUTES = 10 * 60 * 1000;

export default function HomeContainer() {
const { naver } = window;
const mapElement = React.useRef<HTMLDivElement>(null);
Expand All @@ -14,6 +20,17 @@ export default function HomeContainer() {
const isErrorLoadLocation = !userLocation.loaded && userLocation.coordinates;
const isDeniedPermission = userLocation.loaded && !userLocation.coordinates;

const request: IUseSimpleQuery = {
queryKey: [queryKeys.coordinateList],
requestAPI: Coordinate.Get.list,
options: {
enabled: !!mapElement.current,
staleTime: TEN_MINUTES,
},
};

const { data } = useSimpleQuery<ICoordinateListResponse>(request);

const permissionExistenceCoordinate = () => {
const lat = !userLocation.coordinates ? INIT_COORDINATE.LAT : userLocation.coordinates.lat;
const lng = !userLocation.coordinates ? INIT_COORDINATE.LNG : userLocation.coordinates.lng;
Expand Down Expand Up @@ -64,16 +81,22 @@ export default function HomeContainer() {

React.useEffect(
function initializeVirtualizeMarkerEvent() {
if (!mapElement.current || !naver || isErrorLoadLocation) return;
if (initSuccessChecker.current) return;
setMarketMarkers([]);
if (!mapElement.current || !naver || isErrorLoadLocation || !data || !naverMapRef.current) return;
const computedMarkers = data.value.map((element) => {
return new naver.maps.Marker({
position: element.coordinate,
title: element.title,
map: naverMapRef.current as naver.maps.Map,
});
});
setMarketMarkers(computedMarkers);
const zoomchangeEvent = naver.maps.Event.addListener(mapElement.current, 'zoom_changed', handleZoomChangedMap);
const dragEndEvent = naver.maps.Event.addListener(mapElement.current, 'dragend', handleDragEndMap);

return () => naver.maps.Event.removeListener([zoomchangeEvent, dragEndEvent]);
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[marketMarkers],
[naverMapRef.current, data],
);

return <Home ref={mapElement} handleMoveUserLocation={handleMoveUserLocation} />;
Expand Down
File renamed without changes.
File renamed without changes.
6 changes: 3 additions & 3 deletions src/hooks/useSimpleQuery.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { AxiosError } from 'axios';
import { QueryKey, UseQueryOptions, useQuery } from '@tanstack/react-query';

export interface IUsePrivateQuery {
export interface IUseSimpleQuery {
queryKey: any[];
requestAPI: (...arg: any) => Promise<any>;
options: Omit<UseQueryOptions<any, AxiosError<unknown, any>, any, QueryKey>, 'queryKey' | 'queryFn'>;
requestQuery: object;
requestQuery?: object;
}

export default function useSimpleQuery<T>({ queryKey, requestAPI, options, requestQuery }: IUsePrivateQuery) {
export default function useSimpleQuery<T>({ queryKey, requestAPI, options, requestQuery = {} }: IUseSimpleQuery) {
const fetcher = async () => await requestAPI(requestQuery);

const OPTION = {
Expand Down
23 changes: 15 additions & 8 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@ import ReactDOM from 'react-dom/client';
import App from '@/App.tsx';
import { BrowserRouter } from 'react-router-dom';
import { RecoilRoot } from 'recoil';
import { worker } from './mocks/browser';
worker.start();
async function enableMocking() {
const { worker } = await import('./mocks/browser');

ReactDOM.createRoot(document.getElementById('root')!).render(
<BrowserRouter>
<RecoilRoot>
<App />
</RecoilRoot>
</BrowserRouter>,
// `worker.start()` returns a Promise that resolves
// once the Service Worker is up and ready to intercept requests.
return worker.start({ onUnhandledRequest: 'bypass' });
}

enableMocking().then(() =>
ReactDOM.createRoot(document.getElementById('root')!).render(
<BrowserRouter>
<RecoilRoot>
<App />
</RecoilRoot>
</BrowserRouter>,
),
);
6 changes: 4 additions & 2 deletions src/mocks/auth.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { delay, http } from 'msw';
import { ISignInResponse } from '@/types/auth';
import environment from '@/environment';
import { commonUrl } from '.';

const authUrl = (path?: string) => `${commonUrl(`/auth${path}`)}`;

const authHandler = [
http.post(`${environment.serverUrl}/api/v1/auth/sign-in`, async () => {
http.post(`${authUrl('/sign-in')}`, async () => {
await delay(1000);
const signInResponse: ISignInResponse = {
value: { id: 123453245, accessToken: '12dasfjkdfvahjvf', email: '26dfgdg', name: 'user' },
Expand Down
Loading

0 comments on commit 1a25f16

Please sign in to comment.