Skip to content

Commit b32e795

Browse files
committed
refactor
1 parent 48bc147 commit b32e795

File tree

10 files changed

+350
-131
lines changed

10 files changed

+350
-131
lines changed

package/src/components/Datepicker.tsx

Lines changed: 20 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,15 @@ import '../../assets/ReactDatepicker.css';
44
import * as React from 'react';
55
import { useState, useMemo, useRef, useEffect } from 'react';
66
import { formatDate } from '../utils/datetime';
7-
import {
8-
setCenturyPage,
9-
setDecadePage,
10-
setYearPage,
11-
setMonthPage,
12-
} from '../utils/page';
7+
import { setMonthPage } from '../utils/page';
138
import ViewCentury from './view/Century';
149
import { NAME_SPACE } from '../constants/core';
15-
import Controller from './Controller';
1610
import ViewDecade from './view/Decade';
1711
import ViewYear from './view/Year';
1812
import ViewMonth from './view/Month';
19-
import { addLeadingZero } from '../utils/string';
2013
import useOutsideClick from '../hooks/useOutsideClick';
14+
import ControllerContainer from './controller/Container';
15+
import InputDate from './input/Date';
2116

2217
interface IProps {
2318
initValue?: Date | null;
@@ -47,54 +42,13 @@ function Datepicker({
4742
>('month');
4843
const [isVisible, setIsVisible] = useState<boolean>(false);
4944

50-
const centuryPage = useMemo(() => setCenturyPage(viewDate), [viewDate]);
51-
const decadePage = useMemo(() => setDecadePage(viewDate), [viewDate]);
52-
const yearPage = useMemo(() => setYearPage(viewDate), [viewDate]);
5345
const monthPage = useMemo(() => setMonthPage(viewDate), [viewDate]);
5446
const container = useRef(null);
5547

5648
useOutsideClick(container, () => {
5749
setIsVisible(false);
5850
});
5951

60-
const setViewDateByType = (
61-
value: string | number,
62-
type: 'year' | 'month' | 'date'
63-
) => {
64-
type TSplit = string | number;
65-
const split: TSplit[] = viewDate.split('-');
66-
const valueNum = Number(value);
67-
68-
if (type === 'year') {
69-
if (valueNum < 1) {
70-
split[0] = 1;
71-
} else {
72-
split[0] = valueNum;
73-
}
74-
}
75-
if (type === 'month') {
76-
if (valueNum === 0) {
77-
if (Number(split[0]) > 1) {
78-
split[0] = Number(split[0]) - 1;
79-
split[1] = 12;
80-
}
81-
} else if (valueNum === 13) {
82-
split[0] = Number(split[0]) + 1;
83-
split[1] = 1;
84-
} else {
85-
split[1] = valueNum;
86-
}
87-
split[1] = addLeadingZero(split[1] as string);
88-
}
89-
if (type === 'date') split[2] = addLeadingZero(valueNum);
90-
91-
setViewDate(split.join('-'));
92-
};
93-
94-
const handleFocus = () => {
95-
setIsVisible(true);
96-
};
97-
9852
useEffect(() => {
9953
setIsVisible(false);
10054
setViewDate(formatDate(value || NEW_DATE, 'YYYY-MM-DD'));
@@ -106,32 +60,22 @@ function Datepicker({
10660

10761
return (
10862
<div className={`${NAME_SPACE}__wrapper`}>
109-
<div className={`${NAME_SPACE}__input-container`}>
110-
<input
111-
className={`${NAME_SPACE}__input`}
112-
type="text"
113-
value={formatDate(value, valueFormat)}
114-
readOnly
115-
onFocus={handleFocus}
116-
/>
117-
{isClearButton && value && (
118-
<button
119-
className={`${NAME_SPACE}__clear`}
120-
onClick={() => setValue(null)}
121-
>
122-
Clear
123-
</button>
124-
)}
125-
</div>
63+
<InputDate
64+
value={value}
65+
setValue={setValue}
66+
valueFormat={valueFormat}
67+
setIsVisible={setIsVisible}
68+
isClearButton={isClearButton}
69+
/>
12670
{isVisible && (
12771
<div className={`${NAME_SPACE}__datepicker-container`} ref={container}>
128-
<Controller
129-
viewType={viewType}
130-
setViewType={setViewType}
72+
<ControllerContainer
13173
viewDate={viewDate}
74+
viewType={viewType}
13275
labelFormat={labelFormat}
13376
isMultipleCalendar={isMultipleCalendar}
134-
setViewDateByType={setViewDateByType}
77+
setViewType={setViewType}
78+
setViewDate={setViewDate}
13579
/>
13680
<div className={`${NAME_SPACE}__datepicker`}>
13781
{viewType === 'month' && (
@@ -155,24 +99,24 @@ function Datepicker({
15599
{viewType === 'year' && (
156100
<ViewYear
157101
value={value}
158-
yearPage={yearPage}
159-
setViewDateByType={setViewDateByType}
102+
viewDate={viewDate}
103+
setViewDate={setViewDate}
160104
setViewType={setViewType}
161105
/>
162106
)}
163107
{viewType === 'decade' && (
164108
<ViewDecade
165109
value={value}
166-
decadePage={decadePage}
167-
setViewDateByType={setViewDateByType}
110+
viewDate={viewDate}
111+
setViewDate={setViewDate}
168112
setViewType={setViewType}
169113
/>
170114
)}
171115
{viewType === 'century' && (
172116
<ViewCentury
173117
value={value}
174-
centuryPage={centuryPage}
175-
setViewDateByType={setViewDateByType}
118+
viewDate={viewDate}
119+
setViewDate={setViewDate}
176120
setViewType={setViewType}
177121
/>
178122
)}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
'use client';
2+
3+
import * as React from 'react';
4+
import { NAME_SPACE } from '../../constants/core';
5+
import { setViewDateByType } from '../../utils/datetime';
6+
7+
type TViewType = 'century' | 'decade' | 'year' | 'month';
8+
9+
interface IProps {
10+
viewDate: string;
11+
direction: 'prev' | 'next';
12+
viewType: TViewType;
13+
setViewDate: (value: string) => void;
14+
}
15+
16+
function ControllerArrow({
17+
viewDate,
18+
viewType,
19+
direction,
20+
setViewDate,
21+
}: IProps) {
22+
const getViewDateUnit = (type: string): number => {
23+
if (type === 'year') return Number(viewDate.split('-')[0]);
24+
else if (type === 'month') return Number(viewDate.split('-')[1]);
25+
else return Number(viewDate.split('-')[2]);
26+
};
27+
28+
const handleControl = (action: string) => {
29+
const isExtra = action.startsWith('extra');
30+
const unit = viewType === 'month' && !isExtra ? 'month' : 'year';
31+
32+
const deltas: { [key: string]: number } = {
33+
month: 1,
34+
year: 1,
35+
decade: 10,
36+
century: 100,
37+
};
38+
39+
let delta = deltas[viewType] as number;
40+
41+
if (viewType !== 'month' && isExtra) {
42+
delta *= 10;
43+
}
44+
45+
if (action === 'extraPrev' || action === 'prev') {
46+
delta *= -1;
47+
}
48+
49+
setViewDate(
50+
setViewDateByType(viewDate, getViewDateUnit(unit) + delta, unit)
51+
);
52+
};
53+
54+
return (
55+
<button
56+
className={`${NAME_SPACE}__controller-arrow ${NAME_SPACE}__controller-${direction}`}
57+
onClick={() => handleControl(direction)}
58+
>
59+
Next
60+
</button>
61+
);
62+
}
63+
64+
export default ControllerArrow;
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
'use client';
2+
3+
import * as React from 'react';
4+
import { NAME_SPACE } from '../../constants/core';
5+
import ControllerArrow from './Arrow';
6+
import ControllerLabel from './Label';
7+
8+
type TViewType = 'century' | 'decade' | 'year' | 'month';
9+
10+
interface IProps {
11+
viewDate: string;
12+
viewType: TViewType;
13+
labelFormat: string;
14+
isMultipleCalendar: boolean;
15+
setViewType: (value: TViewType) => void;
16+
setViewDate: (value: string) => void;
17+
}
18+
19+
function ControllerContainer({
20+
viewDate,
21+
viewType,
22+
labelFormat,
23+
isMultipleCalendar,
24+
setViewType,
25+
setViewDate,
26+
}: IProps) {
27+
return (
28+
<div className={`${NAME_SPACE}__controller`}>
29+
<ControllerArrow
30+
direction="prev"
31+
viewDate={viewDate}
32+
viewType={viewType}
33+
setViewDate={setViewDate}
34+
/>
35+
<ControllerLabel
36+
viewDate={viewDate}
37+
viewType={viewType}
38+
isMultipleCalendar={isMultipleCalendar}
39+
labelFormat={labelFormat}
40+
setViewType={setViewType}
41+
/>
42+
<ControllerArrow
43+
direction="next"
44+
viewDate={viewDate}
45+
viewType={viewType}
46+
setViewDate={setViewDate}
47+
/>
48+
</div>
49+
);
50+
}
51+
52+
export default ControllerContainer;
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
'use client';
2+
3+
import * as React from 'react';
4+
import { NAME_SPACE } from '../../constants/core';
5+
import {
6+
setCenturyPage,
7+
setDecadePage,
8+
setMonthPage,
9+
setYearPage,
10+
} from '../../utils/page';
11+
import { addLeadingZero } from '../../utils/string';
12+
import { formatLabel } from '../../utils/datetime';
13+
14+
type TViewType = 'century' | 'decade' | 'year' | 'month';
15+
16+
interface IProps {
17+
viewDate: string;
18+
viewType: TViewType;
19+
labelFormat: string;
20+
isMultipleCalendar: boolean;
21+
setViewType: (value: TViewType) => void;
22+
}
23+
24+
function ControllerLabel({
25+
viewDate,
26+
viewType,
27+
labelFormat,
28+
isMultipleCalendar,
29+
setViewType,
30+
}: IProps) {
31+
const setMonthLabel = (date: string, addMonth = 0) => {
32+
const monthPage = setMonthPage(date);
33+
const year = Math.ceil((monthPage + addMonth) / 12);
34+
const month = addLeadingZero((monthPage + addMonth) % 12 || 12);
35+
36+
return formatLabel(`${year}-${month}`, labelFormat);
37+
};
38+
39+
const setLabel = (date: string, type: TViewType): string => {
40+
if (type === 'century') {
41+
const centuryPage = setCenturyPage(date);
42+
const start = centuryPage * 100 - 99;
43+
const end = centuryPage * 100;
44+
45+
return `${start} - ${end}`;
46+
}
47+
if (type === 'decade') {
48+
const decadePage = setDecadePage(date);
49+
const start = decadePage * 10 - 9;
50+
const end = decadePage * 10;
51+
52+
return `${start} - ${end}`;
53+
}
54+
if (type === 'year') {
55+
const yearPage = setYearPage(date);
56+
57+
return `${yearPage}`;
58+
}
59+
if (type === 'month') {
60+
return setMonthLabel(date);
61+
}
62+
return '';
63+
};
64+
65+
const handleLabelClick = () => {
66+
if (viewType === 'decade') {
67+
setViewType('century');
68+
}
69+
if (viewType === 'year') {
70+
setViewType('decade');
71+
}
72+
if (viewType === 'month') {
73+
setViewType('year');
74+
}
75+
};
76+
77+
return (
78+
<>
79+
<button
80+
type="button"
81+
className={`${NAME_SPACE}__label`}
82+
onClick={handleLabelClick}
83+
disabled={viewType === 'century'}
84+
>
85+
{setLabel(viewDate, viewType)}
86+
</button>
87+
{isMultipleCalendar && viewType === 'month' && (
88+
<button
89+
type="button"
90+
className={`${NAME_SPACE}__label`}
91+
onClick={handleLabelClick}
92+
>
93+
{setMonthLabel(viewDate, 1)}
94+
</button>
95+
)}
96+
</>
97+
);
98+
}
99+
100+
export default ControllerLabel;

0 commit comments

Comments
 (0)