mirror of
https://github.com/actualbudget/actual.git
synced 2026-03-09 06:02:22 -05:00
Fix/6885 crash when rule has empty date field (#6905)
* Fix crash when rule date field loses focus while empty Fixes #6885 * Remove ts-strict-ignore and fix types in DateSelect * Generate release note 6905
This commit is contained in:
@@ -39,6 +39,7 @@
|
||||
"@testing-library/react": "16.3.0",
|
||||
"@testing-library/user-event": "14.6.1",
|
||||
"@types/lodash": "^4",
|
||||
"@types/pikaday": "^1.7.10",
|
||||
"@types/promise-retry": "^1.1.6",
|
||||
"@types/react": "^19.2.5",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// @ts-strict-ignore
|
||||
import React, {
|
||||
import {
|
||||
forwardRef,
|
||||
useEffect,
|
||||
useEffectEvent,
|
||||
@@ -9,7 +8,13 @@ import React, {
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import type { ComponentProps, KeyboardEvent, Ref } from 'react';
|
||||
import type {
|
||||
ChangeEvent,
|
||||
ComponentProps,
|
||||
JSX,
|
||||
KeyboardEvent,
|
||||
Ref,
|
||||
} from 'react';
|
||||
|
||||
import { useResponsive } from '@actual-app/components/hooks/useResponsive';
|
||||
import { Input } from '@actual-app/components/input';
|
||||
@@ -122,8 +127,8 @@ type DatePickerProps = {
|
||||
value: string;
|
||||
firstDayOfWeekIdx: string;
|
||||
dateFormat: string;
|
||||
onUpdate?: (selectedDate: Date) => void;
|
||||
onSelect: (selectedDate: Date | null) => void;
|
||||
onUpdate: (selectedDate: Date) => void;
|
||||
onSelect: (selectedDate: Date) => void;
|
||||
};
|
||||
|
||||
type DatePickerForwardedRef = {
|
||||
@@ -132,8 +137,8 @@ type DatePickerForwardedRef = {
|
||||
const DatePicker = forwardRef<DatePickerForwardedRef, DatePickerProps>(
|
||||
({ value, firstDayOfWeekIdx, dateFormat, onUpdate, onSelect }, ref) => {
|
||||
const locale = useLocale();
|
||||
const picker = useRef(null);
|
||||
const mountPoint = useRef(null);
|
||||
const picker = useRef<Pikaday | null>(null);
|
||||
const mountPoint = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const onUpdateEffect = useEffectEvent(onUpdate);
|
||||
|
||||
@@ -141,29 +146,32 @@ const DatePicker = forwardRef<DatePickerForwardedRef, DatePickerProps>(
|
||||
ref,
|
||||
() => ({
|
||||
handleInputKeyDown(e) {
|
||||
const currentDate = picker.current?.getDate();
|
||||
if (!currentDate) return;
|
||||
|
||||
let newDate = null;
|
||||
switch (e.key) {
|
||||
case 'ArrowLeft':
|
||||
e.preventDefault();
|
||||
newDate = subDays(picker.current.getDate(), 1);
|
||||
newDate = subDays(currentDate, 1);
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
e.preventDefault();
|
||||
newDate = subDays(picker.current.getDate(), 7);
|
||||
newDate = subDays(currentDate, 7);
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
e.preventDefault();
|
||||
newDate = addDays(picker.current.getDate(), 1);
|
||||
newDate = addDays(currentDate, 1);
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
e.preventDefault();
|
||||
newDate = addDays(picker.current.getDate(), 7);
|
||||
newDate = addDays(currentDate, 7);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
if (newDate) {
|
||||
picker.current.setDate(newDate, true);
|
||||
picker.current?.setDate(newDate, true);
|
||||
onUpdateEffect?.(newDate);
|
||||
}
|
||||
},
|
||||
@@ -194,16 +202,16 @@ const DatePicker = forwardRef<DatePickerForwardedRef, DatePickerProps>(
|
||||
|
||||
useLayoutEffect(() => {
|
||||
picker.current = initPikaday();
|
||||
mountPoint.current.appendChild(picker.current.el);
|
||||
mountPoint.current?.appendChild(picker.current.el);
|
||||
|
||||
return () => {
|
||||
picker.current.destroy();
|
||||
picker.current?.destroy();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (value && picker.current.getDate() !== value) {
|
||||
picker.current.setDate(parse(value, dateFormat, new Date()), true);
|
||||
if (value) {
|
||||
picker.current?.setDate(parse(value, dateFormat, new Date()), true);
|
||||
}
|
||||
}, [value, dateFormat]);
|
||||
|
||||
@@ -218,7 +226,7 @@ const DatePicker = forwardRef<DatePickerForwardedRef, DatePickerProps>(
|
||||
|
||||
DatePicker.displayName = 'DatePicker';
|
||||
|
||||
function defaultShouldSaveFromKey(e) {
|
||||
function defaultShouldSaveFromKey(e: KeyboardEvent<HTMLInputElement>) {
|
||||
return e.key === 'Enter';
|
||||
}
|
||||
|
||||
@@ -263,7 +271,7 @@ function DateSelectDesktop({
|
||||
return '';
|
||||
}, [defaultValue, dateFormat]);
|
||||
|
||||
const picker = useRef(null);
|
||||
const picker = useRef<DatePickerForwardedRef | null>(null);
|
||||
const [value, setValue] = useState(parsedDefaultValue);
|
||||
const [open, setOpen] = useState(embedded || isOpen || false);
|
||||
const innerRef = useRef<HTMLInputElement | null>(null);
|
||||
@@ -315,7 +323,7 @@ function DateSelectDesktop({
|
||||
!e.altKey &&
|
||||
open
|
||||
) {
|
||||
picker.current.handleInputKeyDown(e);
|
||||
picker.current?.handleInputKeyDown(e);
|
||||
} else if (e.key === 'Escape') {
|
||||
setValue(parsedDefaultValue);
|
||||
setSelectedValue(parsedDefaultValue);
|
||||
@@ -357,11 +365,11 @@ function DateSelectDesktop({
|
||||
}
|
||||
}
|
||||
|
||||
function onChange(e) {
|
||||
function onChange(e: ChangeEvent<HTMLInputElement>) {
|
||||
setValue(e.target.value);
|
||||
}
|
||||
|
||||
const maybeWrapTooltip = content => {
|
||||
const maybeWrapTooltip = (content: JSX.Element) => {
|
||||
if (embedded) {
|
||||
return open ? content : null;
|
||||
}
|
||||
@@ -413,8 +421,8 @@ function DateSelectDesktop({
|
||||
// Otherwise the input is reset to whatever is already
|
||||
// selected
|
||||
if (value === '') {
|
||||
setSelectedValue(null);
|
||||
onSelect(null);
|
||||
setSelectedValue('');
|
||||
onSelect('');
|
||||
} else {
|
||||
setValue(selectedValue || '');
|
||||
|
||||
|
||||
6
upcoming-release-notes/6905.md
Normal file
6
upcoming-release-notes/6905.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: Bugfixes
|
||||
authors: [rznn7]
|
||||
---
|
||||
|
||||
Fix crash when setting a rule date field and leaving it empty
|
||||
17
yarn.lock
17
yarn.lock
@@ -161,6 +161,7 @@ __metadata:
|
||||
"@testing-library/react": "npm:16.3.0"
|
||||
"@testing-library/user-event": "npm:14.6.1"
|
||||
"@types/lodash": "npm:^4"
|
||||
"@types/pikaday": "npm:^1.7.10"
|
||||
"@types/promise-retry": "npm:^1.1.6"
|
||||
"@types/react": "npm:^19.2.5"
|
||||
"@types/react-dom": "npm:^19.2.3"
|
||||
@@ -9431,6 +9432,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/pikaday@npm:^1.7.10":
|
||||
version: 1.7.10
|
||||
resolution: "@types/pikaday@npm:1.7.10"
|
||||
dependencies:
|
||||
moment: "npm:>=2.29.2"
|
||||
checksum: 10/638bc31725f4663c6266bb527d34d08740d8dc98c1c71efe53ef5bc63e177718e960f96f2719ee97f18ec7caf15e9f70d225e07f4d9ae1235384bb6da31a34a7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/plist@npm:^3.0.1":
|
||||
version: 3.0.5
|
||||
resolution: "@types/plist@npm:3.0.5"
|
||||
@@ -20768,6 +20778,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"moment@npm:>=2.29.2":
|
||||
version: 2.30.1
|
||||
resolution: "moment@npm:2.30.1"
|
||||
checksum: 10/ae42d876d4ec831ef66110bdc302c0657c664991e45cf2afffc4b0f6cd6d251dde11375c982a5c0564ccc0fa593fc564576ddceb8c8845e87c15f58aa6baca69
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mrmime@npm:^2.0.0":
|
||||
version: 2.0.1
|
||||
resolution: "mrmime@npm:2.0.1"
|
||||
|
||||
Reference in New Issue
Block a user