Skip to content

Commit e540c0f

Browse files
committed
fix:린트 오류 해결 및 prettier 포맷 적용
1 parent 0715c5e commit e540c0f

6 files changed

Lines changed: 147 additions & 47 deletions

File tree

src/pages/repair/model/types.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,76 @@ export type RepairShop = {
88
distance?: number;
99
placeUrl?: string;
1010
};
11+
12+
export type KakaoAddressResult = {
13+
x: string;
14+
y: string;
15+
};
16+
17+
export type KakaoPlace = {
18+
id: string;
19+
place_name: string;
20+
road_address_name: string;
21+
address_name: string;
22+
y: string;
23+
x: string;
24+
phone: string;
25+
distance?: string;
26+
place_url?: string;
27+
};
28+
29+
export type KakaoPagination = {
30+
hasNextPage: boolean;
31+
nextPage: () => void;
32+
};
33+
34+
export type KakaoMapInstance = {
35+
setCenter: (latLng: unknown) => void;
36+
setBounds: (bounds: unknown) => void;
37+
panTo: (latLng: unknown) => void;
38+
};
39+
40+
export type KakaoMarker = {
41+
setMap: (map: KakaoMapInstance | null) => void;
42+
};
43+
44+
export type KakaoOverlay = {
45+
setMap: (map: KakaoMapInstance | null) => void;
46+
};
47+
48+
export type KakaoLatLngBounds = {
49+
extend: (latLng: unknown) => void;
50+
};
51+
52+
export type KakaoMapsServices = {
53+
Geocoder: new () => {
54+
addressSearch: (query: string, cb: (result: unknown[], status: string) => void) => void;
55+
};
56+
Places: new () => {
57+
keywordSearch: (
58+
keyword: string,
59+
cb: (data: unknown[], status: string, pagination: KakaoPagination) => void,
60+
options: { location: unknown; radius: number }
61+
) => void;
62+
};
63+
Status: { OK: string };
64+
};
65+
66+
export type KakaoMaps = {
67+
LatLng: new (lat: number, lng: number) => unknown;
68+
Map: new (container: HTMLElement, options: { center: unknown; level: number }) => KakaoMapInstance;
69+
CustomOverlay: new (options: {
70+
yAnchor: number;
71+
zIndex: number;
72+
content?: string;
73+
position?: unknown;
74+
}) => KakaoOverlay;
75+
Marker: new (options: { map: KakaoMapInstance; position: unknown; image?: unknown }) => KakaoMarker;
76+
MarkerImage: new (src: string, size: unknown, options: { offset: unknown }) => unknown;
77+
Size: new (width: number, height: number) => unknown;
78+
Point: new (x: number, y: number) => unknown;
79+
LatLngBounds: new () => KakaoLatLngBounds;
80+
event: { addListener: (target: unknown, event: string, handler: () => void) => void };
81+
load?: (callback: () => void) => void;
82+
services?: KakaoMapsServices;
83+
};

src/pages/repair/model/useRepairMap.ts

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useEffect, useRef, useState } from 'react';
2-
import type { RepairShop } from './types';
2+
import type { KakaoMapInstance, KakaoMaps, KakaoMarker, KakaoOverlay, RepairShop } from './types';
33

44
const buildOverlayContent = (shop: RepairShop) => {
55
const phoneLink = shop.phone ? `<a href="tel:${shop.phone}">전화</a>` : '';
@@ -24,13 +24,13 @@ const buildOverlayContent = (shop: RepairShop) => {
2424

2525
export const useRepairMap = () => {
2626
const mapRef = useRef<HTMLDivElement | null>(null);
27-
const mapInstanceRef = useRef<any>(null);
28-
const markersRef = useRef<any[]>([]);
29-
const overlayRef = useRef<any>(null);
27+
const mapInstanceRef = useRef<KakaoMapInstance | null>(null);
28+
const markersRef = useRef<KakaoMarker[]>([]);
29+
const overlayRef = useRef<KakaoOverlay | null>(null);
3030
const [isMapReady, setIsMapReady] = useState(false);
3131

3232
useEffect(() => {
33-
const kakao = (window as any).kakao;
33+
const kakao = (window as Window & { kakao?: { maps?: KakaoMaps } }).kakao;
3434

3535
if (!mapRef.current) {
3636
return;
@@ -46,7 +46,7 @@ export const useRepairMap = () => {
4646

4747
const map = new kakao.maps.Map(mapRef.current, options);
4848
mapInstanceRef.current = map;
49-
overlayRef.current = new kakao.maps.CustomOverlay({ yAnchor: 1, zIndex: 10 });
49+
overlayRef.current = new kakao.maps.CustomOverlay({ yAnchor: 1, zIndex: 10, clickable: true });
5050
kakao.maps.event.addListener(map, 'click', () => {
5151
overlayRef.current?.setMap(null);
5252
});
@@ -74,16 +74,20 @@ export const useRepairMap = () => {
7474
};
7575

7676
const setCenter = (lat: number, lng: number) => {
77-
const kakao = (window as any).kakao;
77+
const kakao = (window as Window & { kakao?: { maps?: KakaoMaps } }).kakao;
7878
const map = mapInstanceRef.current;
79-
if (!kakao?.maps || !map) {return;}
79+
if (!kakao?.maps || !map) {
80+
return;
81+
}
8082
map.setCenter(new kakao.maps.LatLng(lat, lng));
8183
};
8284

8385
const openOverlayForShop = (shop: RepairShop) => {
84-
const kakao = (window as any).kakao;
86+
const kakao = (window as Window & { kakao?: { maps?: KakaoMaps } }).kakao;
8587
const map = mapInstanceRef.current;
86-
if (!kakao?.maps || !map) {return;}
88+
if (!kakao?.maps || !map) {
89+
return;
90+
}
8791

8892
const position = new kakao.maps.LatLng(shop.lat, shop.lng);
8993
map.panTo(position);
@@ -94,25 +98,28 @@ export const useRepairMap = () => {
9498
position,
9599
yAnchor: 1,
96100
zIndex: 10,
101+
clickable: true,
97102
});
98103

99104
overlay.setMap(map);
100105
overlayRef.current = overlay;
101106
};
102107

103108
const setMarkers = (shops: RepairShop[]) => {
104-
const kakao = (window as any).kakao;
109+
const kakao = (window as Window & { kakao?: { maps?: KakaoMaps } }).kakao;
105110
const map = mapInstanceRef.current;
106-
if (!kakao?.maps || !map) {return;}
111+
if (!kakao?.maps || !map) {
112+
return;
113+
}
107114

108115
clearMarkers();
109-
if (shops.length === 0) {return;}
116+
if (shops.length === 0) {
117+
return;
118+
}
110119

111-
const markerImage = new kakao.maps.MarkerImage(
112-
'/repair-marker.svg',
113-
new kakao.maps.Size(36, 48),
114-
{ offset: new kakao.maps.Point(18, 48) }
115-
);
120+
const markerImage = new kakao.maps.MarkerImage('/repair-marker.svg', new kakao.maps.Size(36, 48), {
121+
offset: new kakao.maps.Point(18, 48),
122+
});
116123

117124
const bounds = new kakao.maps.LatLngBounds();
118125
shops.forEach((shop) => {

src/pages/repair/model/useRepairSearch.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { useState } from 'react';
22
import { useRepairMap } from './useRepairMap';
3-
import type { RepairShop } from './types';
4-
3+
import type { KakaoAddressResult, KakaoMaps, KakaoPagination, KakaoPlace, RepairShop } from './types';
54

65
const SEARCH_KEYWORDS = [
76
'아이폰 수리',
@@ -25,7 +24,7 @@ export const useRepairSearch = () => {
2524
const [errorMessage, setErrorMessage] = useState<string | null>(null);
2625

2726
const handleSearch = (query: string) => {
28-
const kakao = (window as any).kakao;
27+
const kakao = (window as Window & { kakao?: { maps?: KakaoMaps } }).kakao;
2928

3029
if (!kakao?.maps?.services || !isMapReady) {
3130
return;
@@ -40,16 +39,17 @@ export const useRepairSearch = () => {
4039

4140
const geocoder = new kakao.maps.services.Geocoder();
4241

43-
geocoder.addressSearch(query, (result: any[], status: string) => {
44-
if (status !== kakao.maps.services.Status.OK || !result?.[0]) {
42+
geocoder.addressSearch(query, (result: unknown[], status: string) => {
43+
const [firstResult] = result as KakaoAddressResult[];
44+
if (status !== kakao.maps.services.Status.OK || !firstResult) {
4545
clearMarkers();
4646
setShops([]);
4747
setIsSearching(false);
4848
setErrorMessage('검색에 실패했습니다.');
4949
return;
5050
}
5151

52-
const { x, y } = result[0];
52+
const { x, y } = firstResult;
5353
setCenter(Number(y), Number(x));
5454

5555
const searchByKeyword = (keyword: string) =>
@@ -58,9 +58,10 @@ export const useRepairSearch = () => {
5858
const places = new kakao.maps.services.Places();
5959
const center = new kakao.maps.LatLng(y, x);
6060

61-
const handleResult = (data: any[], placesStatus: string, pagination: any) => {
61+
const handleResult = (data: unknown[], placesStatus: string, pagination: KakaoPagination) => {
62+
const placeResults = data as KakaoPlace[];
6263
if (placesStatus === kakao.maps.services.Status.OK && data?.length) {
63-
data.forEach((place) => {
64+
placeResults.forEach((place) => {
6465
collected.push({
6566
id: place.id,
6667
name: place.place_name,

src/pages/repair/ui/RepairPage.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,22 @@ import { RepairShopCard } from './RepairShopCard';
33
import { useRepairSearch } from '../model/useRepairSearch';
44

55
const MessageText = ({ children }: { children: string }) => (
6-
<p className="w-full py-12 text-center font-pretendard text-[20px] font-semibold leading-[24px] text-[var(--color-gray-300)]">
6+
<p className="font-pretendard w-full py-12 text-center text-[20px] leading-[24px] font-semibold text-[var(--color-gray-300)]">
77
{children}
88
</p>
99
);
1010

1111
const RepairPage = () => {
12-
const { mapRef, shops, isSearching, hasSearched, errorMessage, handleSearch, openOverlayForShop } =
13-
useRepairSearch();
12+
const { mapRef, shops, isSearching, hasSearched, errorMessage, handleSearch, openOverlayForShop } = useRepairSearch();
1413

1514
return (
16-
<main className="mx-auto flex w-full max-w-[1440px] flex-col items-center gap-[47px] px-4 pb-16 pt-8 md:pt-[47px]">
15+
<main className="mx-auto flex w-full max-w-[1440px] flex-col items-center gap-[47px] px-4 pt-8 pb-16 md:pt-[47px]">
1716
<section
1817
className="relative flex h-[320px] w-full flex-col items-start gap-[var(--spacing-xxs)] self-stretch rounded-[var(--radius-l)] border-2 border-solid border-[var(--color-green-700)] bg-[lightgray] px-4 pt-8 pb-4 md:h-[360px] md:px-12 md:pt-[47px] md:pb-[18px] xl:h-[395px] xl:px-[201px]"
1918
aria-label="수리점 카카오 맵 지도 영역"
2019
>
2120
<div ref={mapRef} className="absolute inset-0 z-0 rounded-[var(--radius-l)]" aria-hidden="true" />
22-
<div className="absolute left-1/2 top-[var(--spacing-xxl)] z-10 w-[calc(100%-32px)] max-w-[790px] -translate-x-1/2 md:w-[calc(100%-96px)] xl:w-[790px]">
21+
<div className="absolute top-[var(--spacing-xxl)] left-1/2 z-10 w-[calc(100%-32px)] max-w-[790px] -translate-x-1/2 md:w-[calc(100%-96px)] xl:w-[790px]">
2322
<SearchBar
2423
className="w-full max-w-none"
2524
placeholder="현재 위치하고 계신 곳의 주소를 적어주세요."

src/pages/repair/ui/RepairShopCard.tsx

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,45 +51,62 @@ export const RepairShopCard = ({
5151
}
5252
};
5353

54+
const handleContactClick: React.MouseEventHandler<HTMLButtonElement> = (event) => {
55+
event.stopPropagation();
56+
handleContact();
57+
};
58+
59+
const handleFindRouteClick: React.MouseEventHandler<HTMLButtonElement> = (event) => {
60+
event.stopPropagation();
61+
handleFindRoute();
62+
};
63+
64+
const handleCardKeyDown: React.KeyboardEventHandler<HTMLDivElement> = (event) => {
65+
if (!onSelect) {
66+
return;
67+
}
68+
if (event.key === 'Enter' || event.key === ' ') {
69+
event.preventDefault();
70+
onSelect();
71+
}
72+
};
73+
5474
return (
55-
<button
56-
type="button"
75+
<div
76+
role="button"
77+
tabIndex={0}
5778
onClick={onSelect}
79+
onKeyDown={handleCardKeyDown}
5880
className="flex w-full flex-col items-start justify-between gap-6 rounded-[var(--radius-l)] bg-[var(--color-gray-900)] px-6 py-8 text-left md:flex-row md:items-center md:gap-[31px] md:px-[42px] md:py-[44px]"
5981
>
6082
<div className="flex flex-1 flex-col items-start gap-[5px]">
61-
<span className="font-pretendard text-[20px] font-bold leading-[24px] text-[var(--color-white)]">
62-
{name}
63-
</span>
64-
<span className="font-pretendard text-[16px] font-semibold leading-[20px] text-[var(--color-brand-primary)]">
83+
<span className="font-pretendard text-[20px] leading-[24px] font-bold text-[var(--color-white)]">{name}</span>
84+
<span className="font-pretendard text-[16px] leading-[20px] font-semibold text-[var(--color-brand-primary)]">
6585
{address}
6686
</span>
6787
</div>
6888

69-
<div
70-
className="flex w-full items-center justify-between gap-4 md:w-auto md:gap-[31px]"
71-
onClick={(event) => event.stopPropagation()}
72-
>
73-
<FavoriteButton defaultActive={favoriteActive} variant="inverse" />
89+
<div className="flex w-full items-center justify-between gap-4 md:w-auto md:gap-[31px]">
90+
<FavoriteButton defaultActive={favoriteActive} variant="inverse" onClick={(event) => event.stopPropagation()} />
7491
<div className="flex w-full flex-1 flex-col items-start gap-[15px] md:w-[159px] md:flex-none">
7592
<Button
7693
variant="fill"
7794
size="full"
7895
className="h-[44px] rounded-[var(--radius-l)] bg-[var(--color-white)] text-[var(--color-gray-900)] hover:bg-[var(--color-gray-100)]"
79-
onClick={handleContact}
96+
onClick={handleContactClick}
8097
>
8198
연락하기
8299
</Button>
83100
<Button
84101
variant="outline"
85102
size="full"
86103
className="h-[44px] rounded-[var(--radius-l)] border-2 border-[var(--color-white)] text-[var(--color-white)] hover:border-[var(--color-gray-200)] hover:text-[var(--color-gray-200)]"
87-
onClick={handleFindRoute}
104+
onClick={handleFindRouteClick}
88105
>
89106
길 찾기
90107
</Button>
91108
</div>
92109
</div>
93-
</button>
110+
</div>
94111
);
95112
};

src/shared/ui/FavoriteButton/FavoriteButton.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
11
import { HeartIcon } from '@shared/assets/icons';
22
import { cn } from '@shared/utils/cn';
3-
import { useState } from 'react';
3+
import { useState, type ComponentPropsWithoutRef } from 'react';
44
import { favoriteButtonVariants } from './FavoriteButton.variants';
55

66
export interface FavoriteButtonProps {
77
defaultActive?: boolean;
88
onToggle?: (isActive: boolean) => void;
99
ariaLabel?: string;
1010
variant?: 'default' | 'inverse';
11+
onClick?: ComponentPropsWithoutRef<'button'>['onClick'];
1112
}
1213

1314
export const FavoriteButton = ({
1415
defaultActive = false,
1516
onToggle,
1617
ariaLabel = '찜',
1718
variant = 'default',
19+
onClick,
1820
}: FavoriteButtonProps) => {
1921
const [isActive, setActive] = useState<boolean>(defaultActive);
2022

2123
const styles = favoriteButtonVariants({ variant });
2224

23-
const handleClick = () => {
25+
const handleClick: ComponentPropsWithoutRef<'button'>['onClick'] = (event) => {
26+
onClick?.(event);
2427
const nextActive = !isActive;
2528
setActive(nextActive);
2629
onToggle?.(nextActive);

0 commit comments

Comments
 (0)