Skip to content

Commit

Permalink
♻️ (typescript) making Modals typing more strict
Browse files Browse the repository at this point in the history
Closes #1940
  • Loading branch information
MatissJanis committed Dec 4, 2023
1 parent 5f52801 commit 76a09ce
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function useAvailableBanks(country: string) {
};
}

function renderError(error: 'unknown' | 'timeout') {
function renderError(error: 'unauthorized' | 'failed' | 'unknown' | 'timeout') {
return (
<Error style={{ alignSelf: 'center' }}>
{error === 'timeout'
Expand All @@ -78,9 +78,10 @@ function renderError(error: 'unknown' | 'timeout') {

type GoCardlessExternalMsgProps = {
modalProps: CommonModalProps;
onMoveExternal: (arg: {
institutionId: string;
}) => Promise<{ error?: 'unknown' | 'timeout'; data?: GoCardlessToken }>;
onMoveExternal: (arg: { institutionId: string }) => Promise<{
error?: 'unauthorized' | 'failed' | 'unknown' | 'timeout';
data?: GoCardlessToken;
}>;
onSuccess: (data: GoCardlessToken) => Promise<void>;
onClose: () => void;
};
Expand All @@ -97,7 +98,9 @@ export default function GoCardlessExternalMsg({
let [success, setSuccess] = useState<boolean>(false);
let [institutionId, setInstitutionId] = useState<string>();
let [country, setCountry] = useState<string>();
let [error, setError] = useState<'unknown' | 'timeout' | null>(null);
let [error, setError] = useState<
'unauthorized' | 'failed' | 'unknown' | 'timeout' | null
>(null);
let [isGoCardlessSetupComplete, setIsGoCardlessSetupComplete] = useState<
boolean | null
>(null);
Expand Down
24 changes: 3 additions & 21 deletions packages/loot-core/src/client/actions/modals.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,25 @@
import * as constants from '../constants';
import type {
OptionlessModal,
CloseModalAction,
PopModalAction,
PushModalAction,
ReplaceModalAction,
ModalWithOptions,
ModalType,
FinanceModals,
} from '../state-types/modals';

export function pushModal<M extends keyof ModalWithOptions>(
name: M,
options: ModalWithOptions[M],
): PushModalAction;
export function pushModal(name: OptionlessModal): PushModalAction;
export function pushModal<M extends ModalType>(
name: M,
options?: FinanceModals[M],
): PushModalAction;
export function pushModal<M extends ModalType>(
export function pushModal<M extends keyof FinanceModals>(
name: M,
options?: FinanceModals[M],
): PushModalAction {
const modal = { name, options };
return { type: constants.PUSH_MODAL, modal };
}

export function replaceModal<M extends keyof ModalWithOptions>(
name: M,
options: ModalWithOptions[M],
): ReplaceModalAction;
export function replaceModal(name: OptionlessModal): ReplaceModalAction;
export function replaceModal<M extends ModalType>(
export function replaceModal<M extends keyof FinanceModals>(
name: M,
options?: FinanceModals[M],
): ReplaceModalAction {
// @ts-expect-error TS is unable to determine that `name` and `options` match
const modal: M = { name, options };
const modal = { name, options };
return { type: constants.REPLACE_MODAL, modal };
}

Expand Down
53 changes: 37 additions & 16 deletions packages/loot-core/src/client/state-types/modals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,16 @@ import type { AccountEntity, GoCardlessToken } from '../../types/models';
import type { RuleEntity } from '../../types/models/rule';
import type { EmptyObject, StripNever } from '../../types/util';
import type * as constants from '../constants';
export type ModalType = keyof FinanceModals;

export type OptionlessModal = {
[K in ModalType]: EmptyObject extends FinanceModals[K] ? K : never;
}[ModalType];
export type ModalType = keyof FinanceModals;

export type ModalWithOptions = StripNever<{
[K in ModalType]: keyof FinanceModals[K] extends never
? never
: FinanceModals[K];
}>;
type Modal<K extends keyof FinanceModals> = {
name: K;
options: FinanceModals[K];
};

// There is a separate (overlapping!) set of modals for the management app. Fun!
type FinanceModals = {
export type FinanceModals = {
'import-transactions': {
accountId: string;
filename: string;
Expand All @@ -41,6 +37,11 @@ type FinanceModals = {
| { group: string }
);

'confirm-transaction-edit': {
onConfirm: () => void;
confirmReason: string;
};

'load-backup': EmptyObject;

'manage-rules': { payeeId?: string };
Expand All @@ -54,7 +55,7 @@ type FinanceModals = {
};

'plaid-external-msg': {
onMoveExternal: () => Promise<void>;
onMoveExternal: () => Promise<{ error: unknown; data: unknown }>;
onClose?: () => void;
onSuccess: (data: unknown) => Promise<void>;
};
Expand All @@ -63,9 +64,10 @@ type FinanceModals = {
onSuccess: () => void;
};
'gocardless-external-msg': {
onMoveExternal: (arg: {
institutionId: string;
}) => Promise<{ error: string } | { data: unknown }>;
onMoveExternal: (arg: { institutionId: string }) => Promise<{
error?: 'unauthorized' | 'failed' | 'unknown' | 'timeout';
data?: GoCardlessToken;
}>;
onClose?: () => void;
onSuccess: (data: GoCardlessToken) => Promise<void>;
};
Expand All @@ -92,8 +94,14 @@ type FinanceModals = {
onSubmit: (name: string, value: string) => void;
};

'budget-summary': {
month: string;
'new-category': {
onValidate?: (value: string) => string[];
onSubmit: (value: string) => void;
};

'new-category-group': {
onValidate?: (value: string) => string[];
onSubmit: (value: string) => void;
};

'schedule-edit': { id: string } | null;
Expand All @@ -104,6 +112,19 @@ type FinanceModals = {

'schedule-posts-offline-notification': null;
'switch-budget-type': { onSwitch: () => void };

'rollover-budget-summary': {
month: string;
onBudgetAction: (
idx: string | number,
action: string,
arg: unknown,
) => void;
};

'report-budget-summary': {
month: string;
};
};

export type PushModalAction = {
Expand Down

0 comments on commit 76a09ce

Please sign in to comment.