From 0d9f1b56714c600444bd6d5b39c6359b2b3682b2 Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Wed, 13 May 2026 12:16:39 +0200 Subject: [PATCH] refactor: remove duplicate simple-modal implementation (@fehmer) --- .../account-settings/ape-key-table.ts | 3 +- frontend/src/ts/elements/simple-modal.ts | 98 ++----------------- frontend/src/ts/modals/edit-tag.ts | 3 +- frontend/src/ts/modals/simple-modals.ts | 12 +-- frontend/src/ts/states/simple-modal.ts | 7 +- 5 files changed, 20 insertions(+), 103 deletions(-) diff --git a/frontend/src/ts/elements/account-settings/ape-key-table.ts b/frontend/src/ts/elements/account-settings/ape-key-table.ts index 2bc129194f24..206cd7700942 100644 --- a/frontend/src/ts/elements/account-settings/ape-key-table.ts +++ b/frontend/src/ts/elements/account-settings/ape-key-table.ts @@ -10,9 +10,10 @@ import { ApeKeyNameSchema, } from "@monkeytype/schemas/ape-keys"; import { format } from "date-fns/format"; -import { SimpleModal, TextArea } from "../simple-modal"; +import { SimpleModal } from "../simple-modal"; import { isAuthenticated } from "../../states/core"; import { qs, qsr } from "../../utils/dom"; +import { TextArea } from "../../states/simple-modal"; const editApeKey = new SimpleModal({ id: "editApeKey", diff --git a/frontend/src/ts/elements/simple-modal.ts b/frontend/src/ts/elements/simple-modal.ts index b77e603f5f50..0d0fb7c7ff7b 100644 --- a/frontend/src/ts/elements/simple-modal.ts +++ b/frontend/src/ts/elements/simple-modal.ts @@ -9,113 +9,31 @@ import { showLoaderBar, hideLoaderBar } from "../states/loader-bar"; import { showNoticeNotification, addNotificationWithLevel, - AddNotificationOptions, } from "../states/notifications"; import { ValidatedHtmlInputElement, ValidationOptions, } from "./input-validation"; import { ElementWithUtils, qsr } from "../utils/dom"; +import { ValidationResult } from "../types/validation"; import { - IsValidResponse, - Validation, - ValidationResult, -} from "../types/validation"; + SimpleModalConfig, + SimpleModalInput, + ExecReturn as BaseExecReturn, +} from "../states/simple-modal"; const simpleModalEl = qsr("#simpleModal"); -type CommonInput = { - type: TType; - initVal?: TValue; - placeholder?: string; - hidden?: boolean; - disabled?: boolean; - optional?: boolean; - label?: string; - oninput?: (event: Event) => void; - /** - * Validate the input value and indicate the validation result next to the input. - * If the schema is defined it is always checked first. - * Only if the schema validaton is passed or missing the `isValid` method is called. - */ - validation?: Omit, "isValid"> & { - /** - * Custom async validation method. - * This is intended to be used for validations that cannot be handled with a Zod schema like server-side validations. - * @param value current input value - * @param thisPopup the current modal - * @returns true if the `value` is valid, an errorMessage as string if it is invalid. - */ - isValid?: ( - value: string, - thisPopup: SimpleModal, - ) => Promise; - }; -}; - -export type TextInput = CommonInput<"text", string>; -export type TextArea = CommonInput<"textarea", string>; -export type PasswordInput = CommonInput<"password", string>; -type EmailInput = CommonInput<"email", string>; - -type RangeInput = { - min: number; - max: number; - step?: number; -} & CommonInput<"range", number>; - -type DateTimeInput = { - min?: Date; - max?: Date; -} & CommonInput<"datetime-local", Date>; -type DateInput = { - min?: Date; - max?: Date; -} & CommonInput<"date", Date>; - -type CheckboxInput = { - label: string; - placeholder?: never; - description?: string; -} & CommonInput<"checkbox", boolean>; - -type NumberInput = { - min?: number; - max?: number; -} & CommonInput<"number", number>; - -type CommonInputType = - | TextInput - | TextArea - | PasswordInput - | EmailInput - | RangeInput - | DateTimeInput - | DateInput - | CheckboxInput - | NumberInput; - -export type ExecReturn = { - status: "success" | "notice" | "error"; - message: string; - showNotification?: false; - notificationOptions?: AddNotificationOptions; +export type ExecReturn = BaseExecReturn & { hideOptions?: HideOptions; - afterHide?: () => void; - alwaysHide?: boolean; }; -type FormInput = CommonInputType & { +type FormInput = SimpleModalInput & { hasError?: boolean; currentValue: () => string; }; -type SimpleModalOptions = { +type SimpleModalOptions = Omit & { id: string; - title: string; - inputs?: CommonInputType[]; - text?: string; - textAllowHtml?: boolean; - buttonText: string; execFn: (thisPopup: SimpleModal, ...params: string[]) => Promise; beforeInitFn?: (thisPopup: SimpleModal) => void; beforeShowFn?: (thisPopup: SimpleModal) => void; diff --git a/frontend/src/ts/modals/edit-tag.ts b/frontend/src/ts/modals/edit-tag.ts index 08e1cead2b54..36575b60d030 100644 --- a/frontend/src/ts/modals/edit-tag.ts +++ b/frontend/src/ts/modals/edit-tag.ts @@ -1,6 +1,6 @@ import * as Settings from "../pages/settings"; import AnimatedModal, { ShowOptions } from "../utils/animated-modal"; -import { SimpleModal, TextInput } from "../elements/simple-modal"; +import { SimpleModal } from "../elements/simple-modal"; import { TagNameSchema } from "@monkeytype/schemas/users"; import { IsValidResponse } from "../types/validation"; import { @@ -12,6 +12,7 @@ import { } from "../collections/tags"; import { normalizeName } from "../utils/strings"; import { deleteLocalTag } from "../collections/results"; +import { TextInput } from "../states/simple-modal"; function errorMessage(e: unknown): string { return e instanceof Error ? e.message : String(e); diff --git a/frontend/src/ts/modals/simple-modals.ts b/frontend/src/ts/modals/simple-modals.ts index cf411ba2731a..abe2a3b5b046 100644 --- a/frontend/src/ts/modals/simple-modals.ts +++ b/frontend/src/ts/modals/simple-modals.ts @@ -22,12 +22,6 @@ import { isDevEnvironment } from "../utils/env"; import { createErrorMessage } from "../utils/error"; import * as ThemeController from "../controllers/theme-controller"; import * as AccountSettings from "../pages/account-settings"; -import { - ExecReturn, - PasswordInput, - SimpleModal, - TextInput, -} from "../elements/simple-modal"; import { GenerateDataRequest } from "@monkeytype/contracts/dev"; import { @@ -43,6 +37,8 @@ import { list, PopupKey, showPopup } from "./simple-modals-base"; import { getTheme } from "../states/theme"; import { normalizeName } from "../utils/strings"; import { IsValidResponse } from "../types/validation"; +import { ExecReturn, SimpleModal } from "../elements/simple-modal"; +import { PasswordInput, TextInput } from "../states/simple-modal"; export { list, showPopup }; export type { PopupKey }; @@ -197,10 +193,6 @@ list.updateEmail = new SimpleModal({ initVal: "", validation: { schema: UserEmailSchema, - isValid: async (currentValue, thisPopup) => - currentValue === thisPopup.inputs?.[1]?.currentValue() || - "Emails don't match", - debounceDelay: 0, }, }, ], diff --git a/frontend/src/ts/states/simple-modal.ts b/frontend/src/ts/states/simple-modal.ts index de950b3bdaac..ef4d8a477660 100644 --- a/frontend/src/ts/states/simple-modal.ts +++ b/frontend/src/ts/states/simple-modal.ts @@ -9,7 +9,7 @@ import { import { showLoaderBar, hideLoaderBar } from "./loader-bar"; import { Validation } from "../types/validation"; -type CommonInput = { +export type CommonInput = { type: TType; name?: string; initVal?: TValue; @@ -19,6 +19,11 @@ type CommonInput = { optional?: boolean; label?: string; oninput?: (event: Event) => void; + /** + * Validate the input value and indicate the validation result next to the input. + * If the schema is defined it is always checked first. + * Only if the schema validaton is passed or missing the `isValid` method is called. + */ validation?: Validation; };