Skip to content

Commit 7e1632a

Browse files
authored
Merge pull request #198 from DevKor-github/feat/#186/pick-ux
feat: λ‚ μ§œ λΉ„ν™œμ„±ν™” 된건 선택 λͺ»ν•˜κ²Œ
2 parents 3f18628 + f397130 commit 7e1632a

File tree

11 files changed

+112
-11
lines changed

11 files changed

+112
-11
lines changed

β€Žsrc/common/components/DatePicker/index.tsxβ€Ž

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { formatDate } from 'date-fns';
2-
import Calendar from 'react-calendar';
2+
import Calendar, { type TileDisabledFunc } from 'react-calendar';
33

44
import * as s from './style.css.ts';
55

@@ -13,8 +13,12 @@ interface Props {
1313
value: Value;
1414
setValue: (value: Value) => void;
1515
range?: boolean;
16+
minDate?: Date;
17+
maxDate?: Date;
18+
tileDisabled?: TileDisabledFunc;
19+
checkMonthYear?: (month: number, year: number) => void;
1620
}
17-
const DatePicker = ({ value, setValue, range = false }: Props) => {
21+
const DatePicker = ({ value, setValue, range = false, minDate, maxDate, tileDisabled, checkMonthYear }: Props) => {
1822
return (
1923
<div className={s.Container}>
2024
<Calendar
@@ -23,14 +27,20 @@ const DatePicker = ({ value, setValue, range = false }: Props) => {
2327
prevLabel={<SlideIcon direction="left" />}
2428
nextLabel={<SlideIcon direction="right" />}
2529
formatDay={(_, date) => date.getDate().toString()}
26-
formatMonthYear={(_, date) => formatDate(date, 'yyyy Mμ›”')}
30+
formatMonthYear={(_, date) => {
31+
checkMonthYear?.(date.getMonth() + 1, date.getFullYear());
32+
return formatDate(date, 'yyyy Mμ›”');
33+
}}
2734
allowPartialRange={true}
2835
minDetail="month"
2936
next2Label={null}
3037
prev2Label={null}
3138
selectRange={range}
3239
goToRangeStartOnSelect={false}
3340
showFixedNumberOfWeeks={true}
41+
minDate={minDate}
42+
maxDate={maxDate}
43+
tileDisabled={tileDisabled}
3444
/>
3545
</div>
3646
);

β€Žsrc/common/components/DatePicker/style.css.tsβ€Ž

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ export const Container = css({
4545
fontSize: '0.75rem',
4646
fontWeight: 400,
4747
letterSpacing: '-0.03rem',
48+
'&:disabled': {
49+
color: '20',
50+
},
4851
},
4952
'& .react-calendar__month-view__days__day--neighboringMonth': {
5053
color: '20',

β€Žsrc/features/detail/components/PickOptionDrawer/index.tsxβ€Ž

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const PickOptionDrawer = ({ itemId, type, tradeMethods, location }: Props) => {
2929
}}
3030
>
3131
<span>직거래</span>
32-
<p>
32+
<div>
3333
{canDirectTrade ? (
3434
<>
3535
<div className="mgc_location_fill" />
@@ -38,7 +38,7 @@ const PickOptionDrawer = ({ itemId, type, tradeMethods, location }: Props) => {
3838
) : (
3939
'μ§κ±°λž˜κ°€ λΆˆκ°€λŠ₯ν•œ μƒν’ˆμ΄μ—μš”'
4040
)}
41-
</p>
41+
</div>
4242
</button>
4343
<button
4444
className={s.SelectButton({ isActive: canParcelTrade })}
@@ -48,7 +48,7 @@ const PickOptionDrawer = ({ itemId, type, tradeMethods, location }: Props) => {
4848
}}
4949
>
5050
<span>νƒλ°°κ±°λž˜</span>
51-
<p>{canParcelTrade ? 'λ‚΄ μ£Όμ†Œλ‘œ νŒλ§€μžκ°€ 택배λ₯Ό λ°œμ†‘ν•΄ μ€˜μš”' : 'νƒλ°°κ±°λž˜κ°€ λΆˆκ°€λŠ₯ν•œ μƒν’ˆμ΄μ—μš”'}</p>
51+
<div>{canParcelTrade ? 'λ‚΄ μ£Όμ†Œλ‘œ νŒλ§€μžκ°€ 택배λ₯Ό λ°œμ†‘ν•΄ μ€˜μš”' : 'νƒλ°°κ±°λž˜κ°€ λΆˆκ°€λŠ₯ν•œ μƒν’ˆμ΄μ—μš”'}</div>
5252
</button>
5353
</div>
5454
);

β€Žsrc/features/detail/components/PickOptionDrawer/style.css.tsβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const SelectButton = cva({
2525
letterSpacing: '-0.045rem',
2626
lineHeight: 'normal',
2727
},
28-
'& p': {
28+
'& div': {
2929
fontSize: '0.75rem',
3030
fontWeight: 400,
3131
letterSpacing: '-0.03rem',
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import client from '@/common/utils/client';
2+
import { QUERY_KEYS } from '@/libs/queryKeys';
3+
import { useQuery } from '@tanstack/react-query';
4+
5+
interface GetRentalAvailabilityRequest {
6+
itemId: number;
7+
year: number;
8+
month: number;
9+
}
10+
interface GetRentalAvailabilityResponse {
11+
message: string;
12+
data: {
13+
itemId: number;
14+
year: number;
15+
month: number;
16+
availability: {
17+
[key: string]: boolean;
18+
};
19+
};
20+
}
21+
const getRentalAvailability = async ({ itemId, year, month }: GetRentalAvailabilityRequest) => {
22+
const response = await client.get<GetRentalAvailabilityResponse>(`/api/v1/item/${itemId}/rental-availability`, {
23+
params: {
24+
year,
25+
month,
26+
},
27+
});
28+
return response.data.data.availability;
29+
};
30+
31+
export const useGetRentalAvailability = (props: GetRentalAvailabilityRequest) => {
32+
return useQuery({
33+
queryKey: [QUERY_KEYS.RENTAL_AVAILABILITY, props],
34+
queryFn: () => getRentalAvailability(props),
35+
enabled: props.year !== 0 && props.month !== 0,
36+
});
37+
};

β€Žsrc/features/pick/components/DateDrawer/index.tsxβ€Ž

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,23 @@ import DatePicker, { type Value } from '@/common/components/DatePicker';
22

33
import * as s from './style.css.ts';
44
import { formatDate } from 'date-fns';
5+
import { useGetRentalAvailability } from '@/features/pick/apis/useGetRentalAvailability.ts';
6+
import { useState } from 'react';
7+
import type { TileDisabledFunc } from 'react-calendar';
58

69
interface Props {
10+
itemId: number;
711
dateTime: Date | null;
812
setDateTime: (date: Date | null) => void;
913
transactionText: '거래' | 'λŒ€μ—¬' | 'λ°˜λ‚©';
1014
next: () => void;
15+
minDate?: Date;
16+
maxDate?: Date;
1117
}
12-
const DateDrawer = ({ dateTime, setDateTime, transactionText, next }: Props) => {
18+
const DateDrawer = ({ itemId, dateTime, setDateTime, transactionText, next, minDate = new Date(), maxDate }: Props) => {
19+
const [year, setYear] = useState(new Date().getFullYear());
20+
const [month, setMonth] = useState(new Date().getMonth() + 1);
21+
const { data: rentalAvailability } = useGetRentalAvailability({ itemId, year, month });
1322
const value = dateTime as Value;
1423
const setValue = (value: Value) => {
1524
if (Array.isArray(value)) return;
@@ -18,12 +27,26 @@ const DateDrawer = ({ dateTime, setDateTime, transactionText, next }: Props) =>
1827

1928
const reset = () => setDateTime(null);
2029

21-
// TODO: λ‚ μ§œ 선택해야 λ‹€μŒ λ²„νŠΌ ν™œμ„±ν™”
30+
const tileDisabled: TileDisabledFunc = ({ date }) => {
31+
if (rentalAvailability === undefined) return true;
32+
const canRental = !!rentalAvailability[formatDate(date, 'yyyy-MM-dd')];
33+
return !canRental;
34+
};
2235

2336
return (
2437
<div className={s.Container}>
2538
<div className={s.DateWrapper}>
26-
<DatePicker value={value} setValue={setValue} />
39+
<DatePicker
40+
value={value}
41+
setValue={setValue}
42+
minDate={minDate}
43+
maxDate={maxDate}
44+
tileDisabled={tileDisabled}
45+
checkMonthYear={(month, year) => {
46+
setMonth(month);
47+
setYear(year);
48+
}}
49+
/>
2750
<div className={s.SelectedDateWrapper}>
2851
<label>{transactionText}일</label>
2952
<div>{dateTime ? formatDate(dateTime, 'yyyy.MM.dd') : ''}</div>

β€Žsrc/features/pick/components/DateTimeBox/DateTimeButton.tsxβ€Ž

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,26 @@ import DateDrawer from '@/features/pick/components/DateDrawer/index.tsx';
88
import TimeDrawer from '@/features/pick/components/TimeDrawer/index.tsx';
99

1010
interface Props {
11+
itemId: number;
1112
transactionText: '거래' | 'λŒ€μ—¬' | 'λ°˜λ‚©';
1213
label: string;
1314
dateTime: Date | null;
1415
setDateTime: (date: Date | null) => void;
1516
canSelectTime?: boolean;
17+
minDate?: Date;
18+
maxDate?: Date;
1619
}
1720

18-
const DateTimeButton = ({ transactionText, label, dateTime, setDateTime, canSelectTime = false }: Props) => {
21+
const DateTimeButton = ({
22+
itemId,
23+
transactionText,
24+
label,
25+
dateTime,
26+
setDateTime,
27+
canSelectTime = false,
28+
minDate,
29+
maxDate,
30+
}: Props) => {
1931
const { open: dateDrawerOpen, drawerState: dateDrawerState, close: dateDrawerClose } = useDrawer();
2032
const { open: timeDrawerOpen, drawerState: timeDrawerState, close: timeDrawerClose } = useDrawer();
2133

@@ -70,6 +82,9 @@ const DateTimeButton = ({ transactionText, label, dateTime, setDateTime, canSele
7082
description={`${transactionText}λ₯Ό μ›ν•˜λŠ” λ‚ μ§œλ₯Ό μ„ νƒν•΄μ£Όμ„Έμš”`}
7183
>
7284
<DateDrawer
85+
minDate={minDate}
86+
maxDate={maxDate}
87+
itemId={itemId}
7388
dateTime={dateTime}
7489
setDateTime={setDateTime}
7590
transactionText={transactionText}

β€Žsrc/features/pick/components/DateTimeBox/index.tsxβ€Ž

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const SALE_DIRECT_LABEL = '거래λ₯Ό μ›ν•˜λŠ” μΌμ‹œλ₯Ό μž…λ ₯ν•΄ μ£Όμ„Έμš”';
99
const SALE_PARCEL_LABEL = '희망 택배 λ°œμ†‘ 일자λ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”';
1010

1111
interface Props {
12+
itemId: number;
1213
transactionType: TransactionType;
1314
tradeMethod: TradeMethods;
1415
startDateTime: Date | null;
@@ -17,6 +18,7 @@ interface Props {
1718
setEndDateTime: (date: Date | null) => void;
1819
}
1920
const DateTimeBox = ({
21+
itemId,
2022
transactionType,
2123
tradeMethod,
2224
startDateTime,
@@ -30,6 +32,8 @@ const DateTimeBox = ({
3032
<div className={s.Container({ isDirect })}>
3133
{isDirect ? (
3234
<DateTimeButton
35+
itemId={itemId}
36+
maxDate={endDateTime ?? undefined}
3337
transactionText={isRental ? 'λŒ€μ—¬' : '거래'}
3438
label={isRental ? RENTAL_START_LABEL : SALE_DIRECT_LABEL}
3539
canSelectTime
@@ -38,6 +42,8 @@ const DateTimeBox = ({
3842
/>
3943
) : (
4044
<DateTimeButton
45+
itemId={itemId}
46+
maxDate={endDateTime ?? undefined}
4147
transactionText={isRental ? 'λŒ€μ—¬' : '거래'}
4248
label={isRental ? RENTAL_START_LABEL : SALE_PARCEL_LABEL}
4349
dateTime={startDateTime}
@@ -47,6 +53,8 @@ const DateTimeBox = ({
4753
{isRental &&
4854
(isDirect ? (
4955
<DateTimeButton
56+
itemId={itemId}
57+
minDate={startDateTime ?? undefined}
5058
transactionText={'λ°˜λ‚©'}
5159
label={RENTAL_END_LABEL}
5260
canSelectTime
@@ -55,6 +63,8 @@ const DateTimeBox = ({
5563
/>
5664
) : (
5765
<DateTimeButton
66+
itemId={itemId}
67+
minDate={startDateTime ?? undefined}
5868
transactionText={'λ°˜λ‚©'}
5969
label={RENTAL_END_LABEL}
6070
dateTime={endDateTime}

β€Žsrc/libs/queryKeys.tsβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ export const QUERY_KEYS = {
1212
USER: 'user', // λ‚΄ 정보
1313
PICK_DETAIL: 'pick', // νŠΉμ • id에 ν•΄λ‹Ήν•˜λŠ” 약속 상세
1414
APPOINTMENT_LIST: 'pick-list', // λ‚˜μ˜ ν”½ νŽ˜μ΄μ§€ 리슀트
15+
RENTAL_AVAILABILITY: 'rental-availability', // νŠΉμ • μ•„μ΄ν…œμ— λŒ€ν•œ λ Œνƒˆ κ°€λŠ₯ μ—¬λΆ€
1516
};

β€Žsrc/pages/EditPickPage/index.tsxβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ const EditPickPage = () => {
147147
/>
148148
)}
149149
<DateTimeBox
150+
itemId={itemData.itemId}
150151
transactionType={data.type}
151152
tradeMethod={data.tradeMethod}
152153
startDateTime={startDateTime}

0 commit comments

Comments
Β (0)