diff --git a/renderer/components/add-miner/use-add-miner.ts b/renderer/components/add-miner/use-add-miner.ts index d697edd..378c770 100644 --- a/renderer/components/add-miner/use-add-miner.ts +++ b/renderer/components/add-miner/use-add-miner.ts @@ -21,7 +21,19 @@ export const useAddMiner = () => { const handleAddMiner = useCallback(() => { dispatch(appendNode(newMinerData)); setIsModalOpen(false); - }, [dispatch, newMinerData, setIsModalOpen]); + setNewMinerName(""); + setNewMinerHost(""); + setNewMinerPort(1984); + setNewMinerProtocol("http"); + }, [ + dispatch, + newMinerData, + setIsModalOpen, + setNewMinerName, + setNewMinerHost, + setNewMinerPort, + setNewMinerProtocol, + ]); const handleNewMinerNameChange = useCallback( (event: React.ChangeEvent) => setNewMinerName(event.currentTarget.value), diff --git a/renderer/components/select-miner/select-miner-dropdown.tsx b/renderer/components/select-miner/select-miner-dropdown.tsx index ba6e3d3..5afb7a5 100644 --- a/renderer/components/select-miner/select-miner-dropdown.tsx +++ b/renderer/components/select-miner/select-miner-dropdown.tsx @@ -1,14 +1,142 @@ -import { useSelectedNode } from "../../store/configSlice/configSliceHooks"; +import { useCallback, useEffect, useRef, useState } from "react"; +import { useAppDispatch } from "../../store"; +import { useConfigNodes, useSelectedNode } from "../../store/configSlice/configSliceHooks"; +import { selectNode } from "../../store/configSlice/configSlice"; +import { useAddMiner } from "../add-miner/use-add-miner"; +import { AddMinerModal } from "../add-miner/add-miner-modal"; export function SelectMinerDropdown() { + const dropdownRef = useRef(null); + const dispatch = useAppDispatch(); + const [isDropdownOpen, setIsDropdownOpen] = useState(false); const selectedNode = useSelectedNode(); + const configuredNodes = useConfigNodes(); + const { + isModalOpen, + newMinerName, + newMinerHost, + newMinerPort, + newMinerProtocol, + handleAddMiner, + handleNewMinerNameChange, + handleNewMinerHostChange, + handleNewMinerPortChange, + handleNewMinerProtocolChange, + setIsModalOpen, + } = useAddMiner(); + + const handleSelectNode = useCallback( + (nodeId: string) => { + if (selectedNode?.id === nodeId) { + dispatch(selectNode(nodeId)); + } + setIsDropdownOpen(false); + }, + [dispatch], + ); + + const handleOutsideClick = useCallback( + (event: MouseEvent) => { + if ( + dropdownRef.current && + event.target && + !dropdownRef.current.contains(event.target as Node) + ) { + setIsDropdownOpen(false); + } + }, + [setIsDropdownOpen], + ); + + useEffect(() => { + if (isDropdownOpen) { + document.addEventListener("mousedown", handleOutsideClick); + } else { + document.removeEventListener("mousedown", handleOutsideClick); + } + + // Cleanup the event listener on unmount + return () => { + document.removeEventListener("mousedown", handleOutsideClick); + }; + }, [isDropdownOpen]); return ( - +
+ + {isDropdownOpen && ( +
+
+ {configuredNodes.map((node) => ( + { + if (event.target instanceof HTMLButtonElement) { + event.preventDefault(); + } else { + handleSelectNode(node.id); + } + }} + > + {node.id === selectedNode?.id ? : ·}{" "} + {node.name}{" "} + + + + ))} +
+ { + setIsDropdownOpen(false); + setIsModalOpen(true); + }} + > + + Add new miner + +
+
+ )} + {isModalOpen && ( + setIsModalOpen(false)} + onAddMiner={handleAddMiner} + nameValue={newMinerName} + hostnameValue={newMinerHost} + portValue={newMinerPort} + protocolValue={newMinerProtocol} + onNameChange={handleNewMinerNameChange} + onHostnameChange={handleNewMinerHostChange} + onPortChange={handleNewMinerPortChange} + onProtocolChange={handleNewMinerProtocolChange} + /> + )} +
); } diff --git a/renderer/store/configSlice/configSlice.ts b/renderer/store/configSlice/configSlice.ts index ea83f7a..1b8ffb7 100644 --- a/renderer/store/configSlice/configSlice.ts +++ b/renderer/store/configSlice/configSlice.ts @@ -17,6 +17,10 @@ export const configSlice = createSlice({ name: "config", initialState, reducers: { + selectNode(state, action: PayloadAction) { + state.selectedNode = action.payload; + window.ipc.setSelectedNodeById(action.payload); + }, setNodes(state, action: PayloadAction) { state.nodes = action.payload; if (state.selectedNode === undefined && action.payload.length > 0) { @@ -27,6 +31,10 @@ export const configSlice = createSlice({ appendNode(state, action: PayloadAction) { const newNode = window.ipc.configAppendNode(action.payload); state.nodes.push(newNode); + if (state.selectedNode === undefined) { + state.selectedNode = newNode.id; + window.ipc.setSelectedNodeById(newNode.id); + } }, }, }); @@ -36,5 +44,5 @@ export const getNodes = createAsyncThunk("config/getNodes", async (_, { dispatch dispatch(configSlice.actions.setNodes(answer)); }); -export const { appendNode } = configSlice.actions; +export const { appendNode, selectNode } = configSlice.actions; export default configSlice.reducer;