AddSparePartModal
Modal for registering a new spare part. Presents a part-type tab strip and a form for miner model, part model, serial number, MAC address (controllers only),…
Modal for registering a new spare part. Presents a part-type tab strip and a form for miner model, part model, serial number, MAC address (controllers only), status, location, tags, and a comment. Validation is controller-aware: controllers require a MAC address, other parts require a serial number. Receives option lists and the submit handler as props.
import { AddSparePartModal } from "@tetherto/mdk-react-devkit";| Prop | Status | Type | Default | Description |
|---|---|---|---|---|
isOpen | Required | boolean | — | — |
onClose | Required | VoidFunction | — | — |
partTypes | Required | SparePartSubTypesModalPartType[] | — | — |
defaultPartTypeId | Optional | string | undefined | — | — |
modelOptions | Required | FormSelectOption[] | — | — |
isModelOptionsLoading | Optional | boolean | undefined | — | — |
minerModelOptions | Required | FormSelectOption[] | — | — |
statusOptions | Required | FormSelectOption[] | — | — |
locationOptions | Required | FormSelectOption[] | — | — |
isControllerPartTypeSelected | Optional | boolean | undefined | — | — |
onPartTypeChange | Required | (partTypeId: string) => void | — | — |
onSubmit | Required | (values: AddSparePartFormValues) => Promise<void | { fieldErrors?: { field: string; message: string; }[] | undefined; }> | — | — |
isLoading | Optional | boolean | undefined | — | — |
subTypesPartTypes | Optional | SparePartSubTypesModalPartType[] | undefined | — | — |
subTypesActivePartTypeId | Optional | string | undefined | — | — |
subTypes | Optional | string[] | undefined | — | — |
onSubTypesPartTypeChange | Optional | ((id: string) => void) | undefined | — | — |
onAddSubType | Optional | ((name: string) => Promise<void | { error?: string | undefined; }>) | undefined | — | — |
isSubTypesLoading | Optional | boolean | undefined | — | — |
Usage
Modal for registering a new spare part. Presents a part-type tab strip (Controller, PSU, Hashboard, …) and a form for miner model, part model, serial number, MAC address, status, location, tags, and a comment. Validation is controller-aware — the MAC address field appears and is required only when a controller part type is selected; other part types require a serial number.
When to use
Use this in an inventory "Spare Parts" view when an operator needs to register a single new part.
Pair it with SparePartSubTypesModal (via the subTypes* props) so the user can manage the
allowed part models without leaving the dialog.
Notes
- Select fields default to
""(empty), which renders the placeholder. Switching part type clears the part model and any serial/MAC validation errors. - MAC validation uses the format
00:1A:2B:3C:4D:5E(case-insensitive,:or-separators).
Example
import { useState } from "react";import { AddSparePartModal, Button, SPARE_PART_LOCATION_LABELS, SPARE_PART_LOCATIONS, SPARE_PART_STATUS_NAMES, SPARE_PART_STATUSES, SparePartNames, SparePartTypes,} from "@tetherto/mdk-react-devkit";const PART_TYPES = Object.entries(SparePartTypes).map(([, value]) => ({ value, label: SparePartNames[value as keyof typeof SparePartNames] ?? value,}));const MINER_MODEL_OPTIONS = [ { value: "antminer-s19", label: "Antminer S19" }, { value: "antminer-s19j", label: "Antminer S19j" }, { value: "whatsminer-m30s", label: "Whatsminer M30S" },];const MODEL_OPTIONS_MAP: Record<string, Array<{ value: string; label: string }>> = { [SparePartTypes.CONTROLLER]: [ { value: "CT-S19", label: "CT-S19" }, { value: "CT-S19j", label: "CT-S19j" }, ], [SparePartTypes.PSU]: [{ value: "PSU-3000W", label: "PSU-3000W" }], [SparePartTypes.HASHBOARD]: [ { value: "HB-S19", label: "HB-S19" }, { value: "HB-S19j", label: "HB-S19j" }, ],};const STATUS_OPTIONS = Object.values(SPARE_PART_STATUSES).map((value) => ({ value, label: SPARE_PART_STATUS_NAMES[value as keyof typeof SPARE_PART_STATUS_NAMES] ?? value,}));const LOCATION_OPTIONS = Object.values(SPARE_PART_LOCATIONS).map((value) => ({ value, label: SPARE_PART_LOCATION_LABELS[value] ?? value,}));export const AddSparePartModalExample = () => { const [isOpen, setIsOpen] = useState(false); const [activePartType, setActivePartType] = useState(PART_TYPES[0]?.value ?? ""); const modelOptions = MODEL_OPTIONS_MAP[activePartType] ?? []; const isController = activePartType === SparePartTypes.CONTROLLER; return ( <div> <Button variant="primary" onClick={() => setIsOpen(true)}> Register Part </Button> <AddSparePartModal isOpen={isOpen} onClose={() => setIsOpen(false)} partTypes={PART_TYPES} defaultPartTypeId={activePartType} modelOptions={modelOptions} minerModelOptions={MINER_MODEL_OPTIONS} statusOptions={STATUS_OPTIONS} locationOptions={LOCATION_OPTIONS} isControllerPartTypeSelected={isController} onPartTypeChange={(id) => setActivePartType(id)} onSubmit={async () => { setIsOpen(false); }} /> </div> );};SubsidyFee
Subsidy & fees reporting view — combines a stacked bar chart of mining rewards (subsidy vs fees) with optional summary stat cards and a timeframe selector. D…
AssignPoolModal
Modal dialog for bulk-assigning a set of selected miners to a pool config. Displays the miner list, a pool selector with metadata (unit/miner counts, last-up…