Skip to content

Commit

Permalink
feat: implement concert name search in open bus rental
Browse files Browse the repository at this point in the history
  • Loading branch information
nxnaxx committed Jan 1, 2025
1 parent 0c3e487 commit 0d7ad96
Show file tree
Hide file tree
Showing 19 changed files with 574 additions and 18 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"typescript-eslint": "^8.11.0",
"vite": "^5.4.10",
"vite-plugin-mkcert": "^1.17.6",
"vite-plugin-svgr": "^4.3.0",
"vite-tsconfig-paths": "^5.1.3"
},
"eslintConfig": {
Expand Down
1 change: 1 addition & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './refundAccountApi';
export * from './rentalApi';
export * from './surveyApi';
export * from './rentalFormAPI';
12 changes: 12 additions & 0 deletions src/api/rentalFormAPI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { endPoint } from 'constants/endPoint';
import type { SearchConcertResponse } from 'types';
import { publicAxios } from 'utils';

// 공연 검색
export const requestGetSearchConcert = async (query: string) => {
return (
await publicAxios.get<SearchConcertResponse>(
`${endPoint.GET_CONCERT_SEARCH_LIST}?query=${query}`
)
).data.result;
};
14 changes: 14 additions & 0 deletions src/assets/images/magnifier-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 10 additions & 2 deletions src/components/searchInput/SearchInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ interface SearchInputProps {
text: string;
isActive: boolean;
onSearch: (query: string) => void;
onValueChange?: () => void;
onClear?: () => void;
}

const SearchInput = ({ text, isActive, onSearch }: SearchInputProps) => {
const SearchInput = ({ text, isActive, onSearch, onValueChange, onClear }: SearchInputProps) => {
const [searchValue, setSearchValue] = useState('');

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setSearchValue(e.target.value);
onValueChange?.();
};

const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
Expand All @@ -24,6 +27,11 @@ const SearchInput = ({ text, isActive, onSearch }: SearchInputProps) => {
}
};

const handleClearValue = () => {
setSearchValue('');
onClear?.();
};

return (
<SearchInputContainer isActive={isActive}>
<IoSearch size={20} />
Expand All @@ -35,7 +43,7 @@ const SearchInput = ({ text, isActive, onSearch }: SearchInputProps) => {
type="search"
value={isActive ? searchValue : ''}
/>
{searchValue && <ClearButton onClick={() => setSearchValue('')} size={20} />}
{searchValue && <ClearButton onClick={handleClearValue} size={20} />}
</SearchInputContainer>
);
};
Expand Down
30 changes: 23 additions & 7 deletions src/pages/openBusRental/OpenBusRental.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import styled from '@emotion/styled';
import { zodResolver } from '@hookform/resolvers/zod';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';

import AdditionalFormInfo from './components/sections/AdditionalFormInfo';
Expand Down Expand Up @@ -43,24 +43,34 @@ const OpenBusRental = () => {
title: '',
region: '',
depositAccount: '',
concertId: 0,
},
mode: 'onSubmit',
});

const { handleSubmit } = methods;
const {
handleSubmit,
formState: { isValid },
watch,
} = methods;

const formData = watch();

// 추후 삭제
useEffect(() => {
console.log('formData changed:', formData);
}, [formData]);

const handleFormSubmit = handleSubmit((formData) => {
if (activeTab < tabMap.rentalTab.length - 1) {
setActiveTab(activeTab + 1);
} else {
console.log('submit', formData);
console.log('submit', formData); // 추후 삭제
}
});

const handlePrevClick = () => {
if (activeTab > 0) {
setActiveTab(activeTab - 1);
}
if (activeTab > 0) setActiveTab(activeTab - 1);
};

return (
Expand All @@ -85,7 +95,13 @@ const OpenBusRental = () => {
이전
</BaseButton>
)}
<BaseButton color="primary" size="medium" type="submit" variant="fill">
<BaseButton
color="primary"
isDisabled={!isValid}
size="medium"
type="submit"
variant="fill"
>
다음
</BaseButton>
</ButtonWrapper>
Expand Down
119 changes: 119 additions & 0 deletions src/pages/openBusRental/components/items/SearchConcertItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import styled from '@emotion/styled';
import { LuCalendar } from 'react-icons/lu';
import { PiMapPinFill } from 'react-icons/pi';

import { BodyMediumText, CaptionText } from 'styles/Typography';
import type { ConcertData } from 'types';
import { formatDateRange } from 'utils';

interface SearchConcertItemProps {
concertData: ConcertData;
isInactive?: boolean;
onClick?: (concertData: ConcertData) => void;
}

const ConcertTitle = styled(BodyMediumText)`
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
margin-bottom: 1.2rem;
`;

const ConcertItemContainer = styled.div<{ isInactive?: boolean }>`
display: flex;
align-items: stretch;
gap: 1.6rem;
width: 100%;
height: fit-content;
padding: 1.2rem 0;
pointer-events: ${({ isInactive }) => (isInactive ? 'none' : 'auto')};
cursor: pointer;
&:hover,
&:active {
${ConcertTitle} {
color: ${({ theme }) => theme.colors.dark[100]};
text-decoration: underline;
}
}
`;

const ConcertPoster = styled.div`
flex-shrink: 0;
position: relative;
width: 7.5rem;
height: 10rem;
`;

const PosterImg = styled.img`
width: 100%;
height: 100%;
border-radius: 4px;
object-fit: cover;
`;

const ConcertContent = styled.div`
display: flex;
flex-direction: column;
`;

const ConcertHall = styled.div`
display: flex;
align-items: center;
gap: 0.8rem;
margin-top: auto;
margin-bottom: 0.4rem;
svg {
flex-shrink: 0;
}
`;

const ConcertHallName = styled(CaptionText)`
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
`;

const Date = styled.div`
display: flex;
align-items: center;
gap: 0.8rem;
svg {
flex-shrink: 0;
}
`;

const SearchConcertItem = ({ concertData, isInactive, onClick }: SearchConcertItemProps) => {
const { poster, title, concertHallName, stDate, edDate } = concertData;

const handleConcertClick = () => {
if (onClick) onClick(concertData);
};

return (
<ConcertItemContainer isInactive={isInactive} onClick={handleConcertClick}>
<ConcertPoster>
<PosterImg alt="Rental Thumbnail" src={poster} />
</ConcertPoster>
<ConcertContent>
<ConcertTitle>{title}</ConcertTitle>
<ConcertHall>
<PiMapPinFill size={16} />
<ConcertHallName>{concertHallName}</ConcertHallName>
</ConcertHall>
<Date>
<LuCalendar size={16} />
<CaptionText>{formatDateRange(stDate, edDate)}</CaptionText>
</Date>
</ConcertContent>
</ConcertItemContainer>
);
};

export default SearchConcertItem;
19 changes: 18 additions & 1 deletion src/pages/openBusRental/components/sections/DetailFormInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Controller, useFormContext } from 'react-hook-form';
import RentalInputField from '../items/RentalInputField';
import RentalThumbField from '../items/RentalThumbField';
import RentalTitleField from '../items/RentalTitleField';
import SearchConcertItem from '../items/SearchConcertItem';
import SearchField from '../items/SearchField';
import RentalFormField from '../RentalFormField';
import RegionListSheet from '../sheets/RegionListSheet';
Expand All @@ -12,13 +13,28 @@ import SearchConcertSheet from '../sheets/SearchConcertSheet';
import Select from 'components/select/Select';
import { RENTAL_FORM_PLACEHOLDER } from 'constants/placeholder';
import { useModalStore } from 'stores';
import { useRentalFormStore } from 'stores/useRentalFormStore';
import type { ConcertData } from 'types';

const DetailFormInfo = () => {
const { setValue, control } = useFormContext();
const { openModal } = useModalStore(['openModal']);
const { concertData, updateConcertData } = useRentalFormStore([
'concertData',
'updateConcertData',
]);

const handleConcertSelect = (concertData: ConcertData) => {
updateConcertData(concertData);
setValue('concertId', concertData.id, { shouldValidate: true });
};

const handleConcertClick = () => {
openModal('bottomSheet', 'list', <SearchConcertSheet onClick={() => {}} />);
openModal(
'bottomSheet',
'list',
<SearchConcertSheet onConcertSelect={(data) => handleConcertSelect(data)} />
);
};

const handleArtistClick = () => {
Expand Down Expand Up @@ -51,6 +67,7 @@ const DetailFormInfo = () => {
title="공연명"
/>
<SearchField name="concert" onClick={handleConcertClick} />
{concertData && <SearchConcertItem concertData={concertData} isInactive />}
</RentalFormField>
<RentalFormField>
<RentalFormField.Title title="아티스트명" />
Expand Down
Loading

0 comments on commit 0d7ad96

Please sign in to comment.