Skip to content

Commit

Permalink
refactor: 스토리북에 구글 맵 적용
Browse files Browse the repository at this point in the history
  • Loading branch information
feb-dain committed Nov 12, 2023
1 parent 6d48604 commit 06cb35c
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 223 deletions.
38 changes: 28 additions & 10 deletions frontend/.storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Wrapper } from '@googlemaps/react-wrapper';
import type { Preview } from '@storybook/react';
import { initialize, mswDecorator } from 'msw-storybook-addon';

Expand Down Expand Up @@ -66,16 +67,33 @@ const preview: Preview = {
},
},
decorators: [
(Story) => (
<React.Fragment>
<QueryClientProvider client={queryClient}>
<GlobalStyle />
<MemoryRouter initialEntries={['/']}>
<Story />
</MemoryRouter>
</QueryClientProvider>
</React.Fragment>
),
(Story) => {
const map = document.getElementById('map');

if (map) {
map.style.visibility = 'hidden';
}

return (
<React.Fragment>
<QueryClientProvider client={queryClient}>
<GlobalStyle />
<MemoryRouter initialEntries={['/']}>
<Wrapper
apiKey={
process.env.NODE_ENV === 'production'
? process.env.GOOGLE_MAPS_API_KEY_PROD!
: process.env.GOOGLE_MAPS_API_KEY_DEV!
}
libraries={['marker']}
>
<Story />
</Wrapper>
</MemoryRouter>
</QueryClientProvider>
</React.Fragment>
);
},
mswDecorator,
],
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ const meta = {
title: 'UI/SearchResult',
tags: ['autodocs'],
component: SearchResult,
decorators: [
(Story) => (
<Container>
<Story />
</Container>
),
],
args: {
cities: [
{
Expand Down Expand Up @@ -80,48 +87,36 @@ export default meta;
// TODO: 스토리북 빌드 실패로 임시로 조치해뒀으니 수정 바랍니다.

export const Default = ({ ...args }: SearchResultProps) => {
return (
<Container>
<SearchResult {...args} />
</Container>
);
return <SearchResult {...args} />;
};

export const NoResult = () => {
return (
<SubContainer>
<SearchResult
cities={[]}
stations={[]}
closeResult={() => null}
isError={false}
isLoading={false}
showStationDetails={() => null}
/>
</SubContainer>
<SearchResult
cities={[]}
stations={[]}
closeResult={() => null}
isError={false}
isLoading={false}
showStationDetails={() => null}
/>
);
};

export const Error = () => {
return (
<Container>
<SearchResult
cities={[]}
stations={[]}
closeResult={() => null}
isError={true}
isLoading={false}
showStationDetails={() => null}
/>
</Container>
<SearchResult
cities={[]}
stations={[]}
closeResult={() => null}
isError={true}
isLoading={false}
showStationDetails={() => null}
/>
);
};

const Container = styled.div`
width: 34rem;
height: 16rem;
`;

const SubContainer = styled(Container)`
height: 24rem;
height: 34rem;
`;
Original file line number Diff line number Diff line change
@@ -1,27 +1,7 @@
import { MagnifyingGlassIcon } from '@heroicons/react/24/outline';
import type { Meta } from '@storybook/react';
import { styled } from 'styled-components';

import type { ChangeEvent, FocusEvent, FormEvent, MouseEvent } from 'react';
import { useState } from 'react';

import { useQueryClient } from '@tanstack/react-query';

import { fetchSearchedStations, useSearchStations } from '@hooks/tanstack-query/useSearchStations';
import { useDebounce } from '@hooks/useDebounce';

import Loader from '@common/Loader';

import { useNavigationBar } from '@ui/Navigator/NavigationBar/hooks/useNavigationBar';
import StationDetailsWindow from '@ui/StationDetailsWindow';

import { MOBILE_BREAKPOINT } from '@constants';
import { QUERY_KEY_SEARCHED_STATION, QUERY_KEY_STATION_MARKERS } from '@constants/queryKeys';

import { pillStyle } from '../../../style';
import type { StationPosition } from '../../../types';
import Button from '../../common/Button';
import SearchResult from './SearchResult';
import StationSearchBar from './StationSearchBar';

const meta = {
title: 'UI/StationSearchBar',
Expand All @@ -36,140 +16,15 @@ const meta = {

export default meta;

// TODO: addon으로 googleMap 관련 함수 제외하기
export const Default = () => {
const [isFocused, setIsFocused] = useState(false);

const [searchWord, setSearchWord] = useState('');
const [debouncedSearchWord, setDebouncedSearchWord] = useState(searchWord);
const queryClient = useQueryClient();
const { openLastPanel } = useNavigationBar();

useDebounce(
() => {
setDebouncedSearchWord(searchWord);
},
[searchWord],
400
);

const {
data: searchResult,
isLoading,
isError,
isFetching,
} = useSearchStations(debouncedSearchWord);

const handleOpenResult = (event: MouseEvent<HTMLInputElement> | FocusEvent<HTMLInputElement>) => {
event.stopPropagation();
setIsFocused(true);
};

const handleCloseResult = () => {
setIsFocused(false);
};

const handleSubmitSearchWord = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
handleCloseResult();

const { stations } = await fetchSearchedStations(searchWord);

if (stations !== undefined && stations.length > 0) {
const [{ stationId, latitude, longitude }] = stations;
showStationDetails({ stationId, latitude, longitude });
}

queryClient.invalidateQueries({ queryKey: [QUERY_KEY_SEARCHED_STATION] });
};

const showStationDetails = ({ stationId, latitude, longitude }: StationPosition) => {
queryClient.invalidateQueries({ queryKey: [QUERY_KEY_STATION_MARKERS] });
openLastPanel(<StationDetailsWindow stationId={stationId} />);
};

const handleChangeSearchWord = ({ target: { value } }: ChangeEvent<HTMLInputElement>) => {
const searchWord = encodeURIComponent(value);

setIsFocused(true);
setSearchWord(searchWord);
};

return (
<S.Container>
<S.Form role="search" onSubmit={handleSubmitSearchWord}>
<label htmlFor="station-search-bar" aria-hidden>
<S.Search
id="station-search-bar"
type="search"
role="searchbox"
placeholder="충전소명 또는 지역명을 입력해 주세요"
autoComplete="off"
onChange={handleChangeSearchWord}
onFocus={handleOpenResult}
onClick={handleOpenResult}
/>
<Button type="submit" aria-label="검색하기">
{isFetching ? (
<Loader size="md" />
) : (
<MagnifyingGlassIcon width="2.4rem" stroke="#767676" />
)}
</Button>
</label>
</S.Form>
{isFocused && searchResult && (
<SearchResult
cities={searchResult.cities}
stations={searchResult.stations}
isLoading={isLoading}
isError={isError}
showStationDetails={showStationDetails}
closeResult={handleCloseResult}
/>
)}
</S.Container>
);
return <StationSearchBar />;
};

const S = {
Container: styled.div`
width: 30rem;
@media screen and (max-width: ${MOBILE_BREAKPOINT}px) {
width: 100%;
}
`,

Form: styled.form`
position: relative;
min-width: 30rem;
@media screen and (max-width: ${MOBILE_BREAKPOINT}px) {
min-width: 100%;
}
`,

Search: styled.input`
${pillStyle};
background: #fcfcfc;
border: 1px solid #d0d2d8;
width: 100%;
padding: 1.9rem 4.6rem 2rem 1.8rem;
font-size: 1.3rem;
& + button {
position: absolute;
right: 2rem;
top: 50%;
transform: translateY(-50%);
}
&:focus {
box-shadow: 0 1px 8px 0 rgba(0, 0, 0, 0.2);
outline: 0;
}
position: fixed;
top: 24px;
left: 8rem;
z-index: 9999;
`,
};
Original file line number Diff line number Diff line change
@@ -1,47 +1,27 @@
import { ChevronLeftIcon } from '@heroicons/react/24/outline';
import type { Meta } from '@storybook/react';
import { css, styled } from 'styled-components';
import styled from 'styled-components';

import Button from '../../common/Button';
import Text from '../../common/Text';
import Navigator from '../Navigator';
import { Default as StationSearchBar } from './StationSearchBar.stories';
import StationSearchWindow from './StationSearchWindow';

const meta = {
title: 'UI/StationSearchWindow',
component: StationSearchWindow,
decorators: [
(Story) => (
<Container>
<Story />
</Container>
),
],
} satisfies Meta<typeof StationSearchWindow>;

export default meta;

export const Default = () => {
return (
<>
<Navigator />
<S.Container>
<Button variant="label" aria-label="검색창 닫기">
<ChevronLeftIcon width="2.4rem" stroke="#9c9fa7" />
</Button>
<StationSearchBar />
<Text tag="h2" fontSize={1.7} weight="bold" css={labelText}>
주변 충전소
</Text>
</S.Container>
</>
);
return <StationSearchWindow />;
};

const S = {
Container: styled.section`
width: 34rem;
height: 100vh;
background: #fcfcfc;
outline: 1.5px solid #e1e4eb;
padding: 2.8rem 2.2rem 5.2rem;
`,
};

const labelText = css`
padding: 3.6rem 0 2.2rem;
const Container = styled.div`
position: absolute;
z-index: 9999;
`;

0 comments on commit 06cb35c

Please sign in to comment.