From 46b251f4aed67eab20bc40e52a1c28a56f52bb1a Mon Sep 17 00:00:00 2001 From: Mike Clark Date: Sat, 21 Oct 2023 18:17:01 +0100 Subject: [PATCH 1/4] adding some types --- .../components/budget/{util.js => util.ts} | 25 +++++++++++++------ .../desktop-client/src/components/sort.tsx | 5 ++-- .../util/{DisplayId.js => DisplayId.tsx} | 8 +++++- 3 files changed, 28 insertions(+), 10 deletions(-) rename packages/desktop-client/src/components/budget/{util.js => util.ts} (72%) rename packages/desktop-client/src/components/util/{DisplayId.js => DisplayId.tsx} (89%) diff --git a/packages/desktop-client/src/components/budget/util.js b/packages/desktop-client/src/components/budget/util.ts similarity index 72% rename from packages/desktop-client/src/components/budget/util.js rename to packages/desktop-client/src/components/budget/util.ts index db5f7e76895..f8c4af733a1 100644 --- a/packages/desktop-client/src/components/budget/util.js +++ b/packages/desktop-client/src/components/budget/util.ts @@ -1,6 +1,9 @@ +import { type CategoryGroupEntity } from 'loot-core/src/types/models'; + import { styles, theme } from '../../style'; +import { type DropPosition } from '../sort'; -export function addToBeBudgetedGroup(groups) { +export function addToBeBudgetedGroup(groups: CategoryGroupEntity[]) { return [ { id: 'to-be-budgeted', @@ -11,20 +14,20 @@ export function addToBeBudgetedGroup(groups) { ]; } -export function separateGroups(categoryGroups) { +export function separateGroups(categoryGroups: CategoryGroupEntity[]) { return [ categoryGroups.filter(g => !g.is_income), categoryGroups.find(g => g.is_income), ]; } -export function makeAmountGrey(value) { +export function makeAmountGrey(value: number | string) { return value === 0 || value === '0' || value === '' ? { color: theme.altMenuItemText } : null; } -export function makeAmountStyle(value) { +export function makeAmountStyle(value: number) { const greyed = makeAmountGrey(value); if (greyed) { return greyed; @@ -35,7 +38,7 @@ export function makeAmountStyle(value) { } } -export function makeAmountFullStyle(value) { +export function makeAmountFullStyle(value: number) { return { color: value < 0 @@ -46,7 +49,11 @@ export function makeAmountFullStyle(value) { }; } -export function findSortDown(arr, pos, targetId) { +export function findSortDown( + arr: CategoryGroupEntity[], + pos: DropPosition, + targetId: string, +) { if (pos === 'top') { return { targetId }; } else { @@ -66,7 +73,11 @@ export function findSortDown(arr, pos, targetId) { } } -export function findSortUp(arr, pos, targetId) { +export function findSortUp( + arr: CategoryGroupEntity[], + pos: DropPosition, + targetId: string, +) { if (pos === 'bottom') { return { targetId }; } else { diff --git a/packages/desktop-client/src/components/sort.tsx b/packages/desktop-client/src/components/sort.tsx index 375b62ced9d..1d9fa4286f6 100644 --- a/packages/desktop-client/src/components/sort.tsx +++ b/packages/desktop-client/src/components/sort.tsx @@ -20,6 +20,8 @@ type DragState = { item?: unknown; }; +export type DropPosition = 'top' | 'bottom'; + export type OnDragChangeCallback = (drag: DragState) => Promise | void; type UseDraggableArgs = { item: unknown; @@ -64,7 +66,6 @@ export function useDraggable({ return { dragRef }; } -type DropPosition = 'top' | 'bottom'; export type OnDropCallback = ( id: unknown, @@ -129,7 +130,7 @@ export const DropHighlightPosContext: Context = createContext(null); type DropHighlightProps = { - pos: 'top' | 'bottom'; + pos: DropPosition; offset?: { top?: number; bottom?: number; diff --git a/packages/desktop-client/src/components/util/DisplayId.js b/packages/desktop-client/src/components/util/DisplayId.tsx similarity index 89% rename from packages/desktop-client/src/components/util/DisplayId.js rename to packages/desktop-client/src/components/util/DisplayId.tsx index 3947f9f1e5d..0a66bf34f2f 100644 --- a/packages/desktop-client/src/components/util/DisplayId.js +++ b/packages/desktop-client/src/components/util/DisplayId.tsx @@ -6,11 +6,17 @@ import { CachedPayees } from 'loot-core/src/client/data-hooks/payees'; import { theme } from '../../style'; import Text from '../common/Text'; +type DisplayIdProps = { + type: 'accounts' | 'payees'; + id: string; + noneColor?: string; +}; + export default function DisplayId({ type, id, noneColor = theme.pageTextSubdued, -}) { +}: DisplayIdProps) { let DataComponent; switch (type) { From 8da26e711105305c229b88bcd083a2bef1d05cb3 Mon Sep 17 00:00:00 2001 From: Mike Clark Date: Sat, 21 Oct 2023 18:38:59 +0100 Subject: [PATCH 2/4] adding types to plainexternalmsg modal --- .../{PlaidExternalMsg.js => PlaidExternalMsg.tsx} | 10 +++++++++- upcoming-release-notes/1823.md | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) rename packages/desktop-client/src/components/modals/{PlaidExternalMsg.js => PlaidExternalMsg.tsx} (93%) create mode 100644 upcoming-release-notes/1823.md diff --git a/packages/desktop-client/src/components/modals/PlaidExternalMsg.js b/packages/desktop-client/src/components/modals/PlaidExternalMsg.tsx similarity index 93% rename from packages/desktop-client/src/components/modals/PlaidExternalMsg.js rename to packages/desktop-client/src/components/modals/PlaidExternalMsg.tsx index a07ebc1abd7..4730288f659 100644 --- a/packages/desktop-client/src/components/modals/PlaidExternalMsg.js +++ b/packages/desktop-client/src/components/modals/PlaidExternalMsg.tsx @@ -8,6 +8,7 @@ import Modal, { ModalButtons } from '../common/Modal'; import Paragraph from '../common/Paragraph'; import Text from '../common/Text'; import View from '../common/View'; +import { type CommonModalProps } from '../../types/modals'; function renderError(error) { return ( @@ -19,12 +20,19 @@ function renderError(error) { ); } +type PlainExternalMsgProps = { + modalProps: CommonModalProps; + onMoveExternal: () => Promise<{ error: any; data: any; }>; + onSuccess: (data: unknown) => Promise; + onClose?: () => void; +} + export default function PlaidExternalMsg({ modalProps, onMoveExternal, onSuccess, onClose: originalOnClose, -}) { +}: PlainExternalMsgProps) { let [waiting, setWaiting] = useState(null); let [success, setSuccess] = useState(false); let [error, setError] = useState(null); diff --git a/upcoming-release-notes/1823.md b/upcoming-release-notes/1823.md new file mode 100644 index 00000000000..4df7bd57b66 --- /dev/null +++ b/upcoming-release-notes/1823.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [MikesGlitch] +--- + +Convert Sort Utils, DisplayId, PlaidExternalMsg components to Typescript From 76280997a0e9c6ae6da3097b66b9c5a85c57cf42 Mon Sep 17 00:00:00 2001 From: Mike Clark Date: Sat, 21 Oct 2023 19:36:00 +0100 Subject: [PATCH 3/4] rules o typescript --- .../{ManageRules.js => ManageRules.tsx} | 32 ++++++++++++++++--- .../src/server/rules/types/handlers.ts | 2 +- packages/loot-core/src/shared/rules.ts | 2 +- packages/loot-core/src/types/models/rule.d.ts | 4 ++- 4 files changed, 33 insertions(+), 7 deletions(-) rename packages/desktop-client/src/components/{ManageRules.js => ManageRules.tsx} (93%) diff --git a/packages/desktop-client/src/components/ManageRules.js b/packages/desktop-client/src/components/ManageRules.tsx similarity index 93% rename from packages/desktop-client/src/components/ManageRules.js rename to packages/desktop-client/src/components/ManageRules.tsx index ee5c4e9bd42..5a3ddad2b72 100644 --- a/packages/desktop-client/src/components/ManageRules.js +++ b/packages/desktop-client/src/components/ManageRules.tsx @@ -1,4 +1,11 @@ -import React, { useState, useEffect, useCallback, useMemo } from 'react'; +import React, { + useState, + useEffect, + useCallback, + useMemo, + type SetStateAction, + type Dispatch, +} from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { pushModal } from 'loot-core/src/client/actions/modals'; @@ -7,6 +14,7 @@ import { send } from 'loot-core/src/platform/client/fetch'; import * as undo from 'loot-core/src/platform/client/undo'; import { mapField, friendlyOp } from 'loot-core/src/shared/rules'; import { describeSchedule } from 'loot-core/src/shared/schedules'; +import { type RuleEntity } from 'loot-core/src/types/models'; import useCategories from '../hooks/useCategories'; import useSelected, { SelectedProvider } from '../hooks/useSelected'; @@ -76,7 +84,17 @@ function ruleToString(rule, data) { ); } -function ManageRulesContent({ isModal, payeeId, setLoading }) { +type ManageRulesContentProps = { + isModal: boolean; + payeeId: string | null; + setLoading?: Dispatch>; +}; + +function ManageRulesContent({ + isModal, + payeeId, + setLoading, +}: ManageRulesContentProps) { let [allRules, setAllRules] = useState(null); let [rules, setRules] = useState(null); let [filter, setFilter] = useState(''); @@ -191,7 +209,7 @@ function ManageRulesContent({ isModal, payeeId, setLoading }) { }, []); function onCreateRule() { - let rule = { + let rule: RuleEntity = { stage: null, conditionsOp: 'and', conditions: [ @@ -314,11 +332,17 @@ function ManageRulesContent({ isModal, payeeId, setLoading }) { ); } +type ManageRulesProps = { + isModal: boolean; + payeeId: string | null; + setLoading?: Dispatch>; +}; + export default function ManageRules({ isModal, payeeId, setLoading = () => {}, -}) { +}: ManageRulesProps) { return ( , ) => Promise<{ error: ValidationError } | object>; - 'rule-delete': (rule: RuleEntity) => Promise; + 'rule-delete': (rule: Required) => Promise; 'rule-delete-all': ( ids: string[], diff --git a/packages/loot-core/src/shared/rules.ts b/packages/loot-core/src/shared/rules.ts index d0fa730a44a..3857aff31e2 100644 --- a/packages/loot-core/src/shared/rules.ts +++ b/packages/loot-core/src/shared/rules.ts @@ -45,7 +45,7 @@ export const FIELD_TYPES = new Map( }), ); -export function mapField(field, opts) { +export function mapField(field, opts?) { opts = opts || {}; switch (field) { diff --git a/packages/loot-core/src/types/models/rule.d.ts b/packages/loot-core/src/types/models/rule.d.ts index a374ed29bcf..fee3e047824 100644 --- a/packages/loot-core/src/types/models/rule.d.ts +++ b/packages/loot-core/src/types/models/rule.d.ts @@ -1,7 +1,7 @@ import { type ScheduleEntity } from './schedule'; export interface RuleEntity { - id: string; + id?: string; stage: string; conditionsOp: 'any' | 'and'; conditions: RuleConditionEntity[]; @@ -15,6 +15,7 @@ interface RuleConditionEntity { value: unknown; options?: unknown; conditionsOp?: unknown; + type?: string; } export type RuleActionEntity = @@ -26,6 +27,7 @@ export interface SetRuleActionEntity { op: 'set'; value: unknown; options?: unknown; + type?: string; } export interface LinkScheduleRuleActionEntity { From df848b7a064c1d7790b6eebb2939a0a65152cfa4 Mon Sep 17 00:00:00 2001 From: Mike Clark Date: Sat, 21 Oct 2023 19:46:07 +0100 Subject: [PATCH 4/4] fix lint --- .../src/components/modals/PlaidExternalMsg.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/desktop-client/src/components/modals/PlaidExternalMsg.tsx b/packages/desktop-client/src/components/modals/PlaidExternalMsg.tsx index 4730288f659..1130d66d47a 100644 --- a/packages/desktop-client/src/components/modals/PlaidExternalMsg.tsx +++ b/packages/desktop-client/src/components/modals/PlaidExternalMsg.tsx @@ -2,13 +2,13 @@ import React, { useState, useRef } from 'react'; import AnimatedLoading from '../../icons/AnimatedLoading'; import { theme } from '../../style'; +import { type CommonModalProps } from '../../types/modals'; import { Error } from '../alerts'; import Button from '../common/Button'; import Modal, { ModalButtons } from '../common/Modal'; import Paragraph from '../common/Paragraph'; import Text from '../common/Text'; import View from '../common/View'; -import { type CommonModalProps } from '../../types/modals'; function renderError(error) { return ( @@ -22,10 +22,10 @@ function renderError(error) { type PlainExternalMsgProps = { modalProps: CommonModalProps; - onMoveExternal: () => Promise<{ error: any; data: any; }>; + onMoveExternal: () => Promise<{ error; data }>; onSuccess: (data: unknown) => Promise; onClose?: () => void; -} +}; export default function PlaidExternalMsg({ modalProps,