Skip to content

Commit be09cf2

Browse files
authored
Maintenance: DateSelect component to tsx & server-handlers get-categories type (actualbudget#1776)
1 parent aa7521d commit be09cf2

File tree

6 files changed

+96
-43
lines changed

6 files changed

+96
-43
lines changed

packages/desktop-client/globals.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Allow images to be imported
2+
declare module '*.png';

packages/desktop-client/src/components/common/Input.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export const defaultInputStyle = {
2121
border: '1px solid ' + theme.formInputBorder,
2222
};
2323

24-
type InputProps = InputHTMLAttributes<HTMLInputElement> & {
24+
export type InputProps = InputHTMLAttributes<HTMLInputElement> & {
2525
style?: CSSProperties;
2626
inputRef?: Ref<HTMLInputElement>;
2727
onEnter?: (event: KeyboardEvent<HTMLInputElement>) => void;

packages/desktop-client/src/components/common/View.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { css } from 'glamor';
88

99
import { type CSSProperties } from '../../style';
1010

11-
type ViewProps = HTMLProps<HTMLDivElement> & {
11+
export type ViewProps = HTMLProps<HTMLDivElement> & {
1212
className?: string;
1313
style?: CSSProperties;
1414
nativeStyle?: StyleHTMLAttributes<HTMLDivElement>;

packages/desktop-client/src/components/select/DateSelect.js renamed to packages/desktop-client/src/components/select/DateSelect.tsx

Lines changed: 69 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ import React, {
66
useLayoutEffect,
77
useImperativeHandle,
88
useMemo,
9+
type MutableRefObject,
10+
type KeyboardEvent,
911
} from 'react';
1012
import { useSelector } from 'react-redux';
1113

12-
import * as d from 'date-fns';
14+
import { parse, parseISO, format, subDays, addDays, isValid } from 'date-fns';
1315
import Pikaday from 'pikaday';
1416

1517
import 'pikaday/css/pikaday.css';
@@ -23,9 +25,9 @@ import {
2325
} from 'loot-core/src/shared/months';
2426
import { stringToInteger } from 'loot-core/src/shared/util';
2527

26-
import { theme } from '../../style';
27-
import Input from '../common/Input';
28-
import View from '../common/View';
28+
import { type CSSProperties, theme } from '../../style';
29+
import Input, { type InputProps } from '../common/Input';
30+
import View, { type ViewProps } from '../common/View';
2931
import { Tooltip } from '../tooltips';
3032

3133
import DateSelectLeft from './DateSelect.left.png';
@@ -76,7 +78,18 @@ let pickerStyles = {
7678
},
7779
};
7880

79-
let DatePicker = forwardRef(
81+
type DatePickerProps = {
82+
value: string;
83+
firstDayOfWeekIdx: string;
84+
dateFormat: string;
85+
onUpdate?: (selectedDate: Date) => void;
86+
onSelect: (selectedDate: Date | null) => void;
87+
};
88+
89+
type DatePickerForwardedRef = {
90+
handleInputKeyDown: (e: KeyboardEvent<HTMLInputElement>) => void;
91+
};
92+
let DatePicker = forwardRef<DatePickerForwardedRef, DatePickerProps>(
8093
({ value, firstDayOfWeekIdx, dateFormat, onUpdate, onSelect }, ref) => {
8194
let picker = useRef(null);
8295
let mountPoint = useRef(null);
@@ -89,22 +102,23 @@ let DatePicker = forwardRef(
89102
switch (e.key) {
90103
case 'ArrowLeft':
91104
e.preventDefault();
92-
newDate = d.subDays(picker.current.getDate(), 1);
105+
newDate = subDays(picker.current.getDate(), 1);
93106
break;
94107
case 'ArrowUp':
95108
e.preventDefault();
96-
newDate = d.subDays(picker.current.getDate(), 7);
109+
newDate = subDays(picker.current.getDate(), 7);
97110
break;
98111
case 'ArrowRight':
99112
e.preventDefault();
100-
newDate = d.addDays(picker.current.getDate(), 1);
113+
newDate = addDays(picker.current.getDate(), 1);
101114
break;
102115
case 'ArrowDown':
103116
e.preventDefault();
104-
newDate = d.addDays(picker.current.getDate(), 7);
117+
newDate = addDays(picker.current.getDate(), 7);
105118
break;
106119
default:
107120
}
121+
108122
if (newDate) {
109123
picker.current.setDate(newDate, true);
110124
onUpdate?.(newDate);
@@ -120,14 +134,14 @@ let DatePicker = forwardRef(
120134
keyboardInput: false,
121135
firstDay: stringToInteger(firstDayOfWeekIdx),
122136
defaultDate: value
123-
? d.parse(value, dateFormat, currentDate())
137+
? parse(value, dateFormat, currentDate())
124138
: currentDate(),
125139
setDefaultDate: true,
126140
toString(date) {
127-
return d.format(date, dateFormat);
141+
return format(date, dateFormat);
128142
},
129143
parse(dateString) {
130-
return d.parse(dateString, dateFormat, new Date());
144+
return parse(dateString, dateFormat, new Date());
131145
},
132146
onSelect,
133147
});
@@ -141,7 +155,7 @@ let DatePicker = forwardRef(
141155

142156
useEffect(() => {
143157
if (picker.current.getDate() !== value) {
144-
picker.current.setDate(d.parse(value, dateFormat, new Date()), true);
158+
picker.current.setDate(parse(value, dateFormat, new Date()), true);
145159
}
146160
}, [value, dateFormat]);
147161

@@ -153,6 +167,23 @@ function defaultShouldSaveFromKey(e) {
153167
return e.key === 'Enter';
154168
}
155169

170+
type DateSelectProps = {
171+
containerProps?: ViewProps;
172+
inputProps?: InputProps;
173+
tooltipStyle?: CSSProperties;
174+
value: string;
175+
isOpen?: boolean;
176+
embedded?: boolean;
177+
dateFormat: string;
178+
focused?: boolean;
179+
openOnFocus?: boolean;
180+
inputRef?: MutableRefObject<HTMLInputElement>;
181+
shouldSaveFromKey?: (e: KeyboardEvent<HTMLInputElement>) => boolean;
182+
tableBehavior?: boolean;
183+
onUpdate?: (selectedDate: string) => void;
184+
onSelect: (selectedDate: string) => void;
185+
};
186+
156187
export default function DateSelect({
157188
containerProps,
158189
inputProps,
@@ -168,12 +199,12 @@ export default function DateSelect({
168199
tableBehavior,
169200
onUpdate,
170201
onSelect,
171-
}) {
202+
}: DateSelectProps) {
172203
let parsedDefaultValue = useMemo(() => {
173204
if (defaultValue) {
174-
let date = d.parseISO(defaultValue);
175-
if (d.isValid(date)) {
176-
return d.format(date, dateFormat);
205+
let date = parseISO(defaultValue);
206+
if (isValid(date)) {
207+
return format(date, dateFormat);
177208
}
178209
}
179210
return '';
@@ -216,29 +247,29 @@ export default function DateSelect({
216247
// Support only entering the month and day (4/5). This is complex
217248
// because of the various date formats - we need to derive
218249
// the right day/month format from it
219-
let test = d.parse(value, getDayMonthFormat(dateFormat), new Date());
220-
if (d.isValid(test)) {
221-
onUpdate?.(d.format(test, 'yyyy-MM-dd'));
222-
setSelectedValue(d.format(test, dateFormat));
250+
let test = parse(value, getDayMonthFormat(dateFormat), new Date());
251+
if (isValid(test)) {
252+
onUpdate?.(format(test, 'yyyy-MM-dd'));
253+
setSelectedValue(format(test, dateFormat));
223254
}
224255
} else if (getShortYearRegex(dateFormat).test(value)) {
225256
// Support entering the year as only two digits (4/5/19)
226-
let test = d.parse(value, getShortYearFormat(dateFormat), new Date());
227-
if (d.isValid(test)) {
228-
onUpdate?.(d.format(test, 'yyyy-MM-dd'));
229-
setSelectedValue(d.format(test, dateFormat));
257+
let test = parse(value, getShortYearFormat(dateFormat), new Date());
258+
if (isValid(test)) {
259+
onUpdate?.(format(test, 'yyyy-MM-dd'));
260+
setSelectedValue(format(test, dateFormat));
230261
}
231262
} else {
232-
let test = d.parse(value, dateFormat, new Date());
233-
if (d.isValid(test)) {
234-
let date = d.format(test, 'yyyy-MM-dd');
263+
let test = parse(value, dateFormat, new Date());
264+
if (isValid(test)) {
265+
let date = format(test, 'yyyy-MM-dd');
235266
onUpdate?.(date);
236267
setSelectedValue(value);
237268
}
238269
}
239270
}, [value]);
240271

241-
function onKeyDown(e) {
272+
function onKeyDown(e: KeyboardEvent<HTMLInputElement>) {
242273
if (
243274
['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(e.key) &&
244275
!e.shiftKey &&
@@ -267,8 +298,8 @@ export default function DateSelect({
267298
setValue(selectedValue);
268299
setOpen(false);
269300

270-
let date = d.parse(selectedValue, dateFormat, new Date());
271-
onSelect(d.format(date, 'yyyy-MM-dd'));
301+
let date = parse(selectedValue, dateFormat, new Date());
302+
onSelect(format(date, 'yyyy-MM-dd'));
272303

273304
if (open && e.key === 'Enter') {
274305
// This stops the event from propagating up
@@ -341,9 +372,9 @@ export default function DateSelect({
341372
} else {
342373
setValue(selectedValue || '');
343374

344-
let date = d.parse(selectedValue, dateFormat, new Date());
345-
if (date instanceof Date && !isNaN(date)) {
346-
onSelect(d.format(date, 'yyyy-MM-dd'));
375+
let date = parse(selectedValue, dateFormat, new Date());
376+
if (date instanceof Date && !isNaN(date.valueOf())) {
377+
onSelect(format(date, 'yyyy-MM-dd'));
347378
}
348379
}
349380
}
@@ -357,12 +388,12 @@ export default function DateSelect({
357388
firstDayOfWeekIdx={firstDayOfWeekIdx}
358389
dateFormat={dateFormat}
359390
onUpdate={date => {
360-
setSelectedValue(d.format(date, dateFormat));
361-
onUpdate?.(d.format(date, 'yyyy-MM-dd'));
391+
setSelectedValue(format(date, dateFormat));
392+
onUpdate?.(format(date, 'yyyy-MM-dd'));
362393
}}
363394
onSelect={date => {
364-
setValue(d.format(date, dateFormat));
365-
onSelect(d.format(date, 'yyyy-MM-dd'));
395+
setValue(format(date, dateFormat));
396+
onSelect(format(date, 'yyyy-MM-dd'));
366397
setOpen(false);
367398
}}
368399
/>,

packages/loot-core/src/types/server-handlers.d.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,24 @@ export interface ServerHandlers {
4242

4343
'transactions-export-query': (arg: { query: queryState }) => Promise<unknown>;
4444

45-
// incomplete
4645
'get-categories': () => Promise<{
47-
grouped: { id: string }[];
48-
list: { id: string }[];
46+
grouped: {
47+
id: string;
48+
name: string;
49+
is_income: number;
50+
sort_order: number;
51+
tombstone: number;
52+
hidden: boolean;
53+
}[];
54+
list: {
55+
id: string;
56+
name: string;
57+
is_income: number;
58+
cat_group: string;
59+
sort_order: number;
60+
tombstone: number;
61+
hidden: boolean;
62+
}[];
4963
}>;
5064

5165
'get-earliest-transaction': () => Promise<unknown>;

upcoming-release-notes/1776.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
category: Maintenance
3+
authors: [MikesGlitch]
4+
---
5+
6+
Convert DateSelect component to TypeScript and update category query type.

0 commit comments

Comments
 (0)