diff --git a/src/components/EditIssue/EditIssue.tsx b/src/components/EditIssue/EditIssue.tsx index 2a18064..7d1b5ac 100644 --- a/src/components/EditIssue/EditIssue.tsx +++ b/src/components/EditIssue/EditIssue.tsx @@ -15,10 +15,7 @@ import ShortUniqueId from "short-unique-id"; import { allCategoryData } from "../../constants/Categories/Categories.ts"; import { QSUPPORT_FILE_BASE } from "../../constants/Identifiers.ts"; import { log, titleFormatter } from "../../constants/Misc.ts"; -import { - feeAmountBase, - supportedCoins, -} from "../../constants/PublishFees/FeeData.tsx"; +import { supportedCoins } from "../../constants/PublishFees/FeeData.tsx"; import { CoinType } from "../../constants/PublishFees/FeePricePublish/FeePricePublish.ts"; import { payPublishFeeQORT } from "../../constants/PublishFees/SendFeeFunctions.ts"; import { verifyPayment } from "../../constants/PublishFees/VerifyPayment.ts"; @@ -332,7 +329,7 @@ export const EditIssue = () => { bountyData, }; if (payFee) { - const publishFeeResponse = await payPublishFeeQORT(feeAmountBase); + const publishFeeResponse = await payPublishFeeQORT("default", "QORT"); if (!publishFeeResponse) { dispatch( setNotification({ @@ -365,7 +362,7 @@ export const EditIssue = () => { action: "PUBLISH_QDN_RESOURCE", name: name, service: "DOCUMENT", - file: objectToFile(issueObject), + data64: await objectToBase64(issueObject), title: title.slice(0, 50), description: metadescription, identifier: editIssueProperties.id, diff --git a/src/components/EditPlaylist/EditPlaylist.tsx b/src/components/EditPlaylist/EditPlaylist.tsx index f0ad181..04455b1 100644 --- a/src/components/EditPlaylist/EditPlaylist.tsx +++ b/src/components/EditPlaylist/EditPlaylist.tsx @@ -326,7 +326,7 @@ export const EditPlaylist = () => { action: "PUBLISH_QDN_RESOURCE", name: username, service: "PLAYLIST", - file: objectToFile(playlistObject), + data64: await objectToBase64(playlistObject), title: title.slice(0, 50), description: metadescription, identifier: identifier, diff --git a/src/components/PublishIssue/PublishIssue.tsx b/src/components/PublishIssue/PublishIssue.tsx index 4bbf31b..c489391 100644 --- a/src/components/PublishIssue/PublishIssue.tsx +++ b/src/components/PublishIssue/PublishIssue.tsx @@ -21,8 +21,9 @@ import { titleFormatter, } from "../../constants/Misc.ts"; import { - feeAmountBase, - feeDisclaimer, + appName, + feeDataDefault, + feePriceToString, supportedCoins, } from "../../constants/PublishFees/FeeData.tsx"; import { CoinType } from "../../constants/PublishFees/FeePricePublish/FeePricePublish.ts"; @@ -36,6 +37,7 @@ import { setNotification } from "../../state/features/notificationsSlice"; import { RootState } from "../../state/store"; import { BountyData, validateBountyInput } from "../../utils/qortalRequests.ts"; import { objectToBase64, objectToFile } from "../../utils/PublishFormatter.ts"; +import { StateCheckBox } from "../../utils/StateCheckBox.tsx"; import { isNumber } from "../../utils/utilFunctions.ts"; import { AutocompleteQappNames, @@ -116,7 +118,7 @@ export const PublishIssue = ({ editId, editContent }: NewCrowdfundProps) => { const [sourceCode, setSourceCode] = useState(""); const [coin, setCoin] = useState("QORT"); const [showCoins, setShowCoins] = useState(false); - + const [payFee, setPayFee] = useState(true); const categoryListRef = useRef(null); const imagePublisherRef = useRef(null); const autocompleteRef = useRef(null); @@ -283,12 +285,14 @@ export const PublishIssue = ({ editId, editContent }: NewCrowdfundProps) => { const selectedQappName = autocompleteRef?.current?.getSelectedValue(); - const publishFeeResponse = await payPublishFeeQORT(feeAmountBase); - if (log) console.log("feeResponse: ", publishFeeResponse); + let publishFeeResponse = undefined; - const feeData: PublishFeeData = { + if (payFee) { + publishFeeResponse = await payPublishFeeQORT("default", "QORT"); + if (log) console.log("feeResponse: ", publishFeeResponse); + } + const feeData = { signature: publishFeeResponse, - senderName: "", }; const isBountyNumber = isNumber(bounty); @@ -311,7 +315,6 @@ export const PublishIssue = ({ editId, editContent }: NewCrowdfundProps) => { feeData, bountyData, }; - const QappNameString = autocompleteRef?.current?.getQappNameFetchString(); const categoryString = categoryListRef.current?.getCategoriesFetchString(categoryList); @@ -330,13 +333,15 @@ export const PublishIssue = ({ editId, editContent }: NewCrowdfundProps) => { action: "PUBLISH_QDN_RESOURCE", name: name, service: "DOCUMENT", - file: objectToFile(issueObject), + data64: await objectToBase64(issueObject), title: title.slice(0, 50), description: metadescription, identifier: identifier + "_metadata", tag1: QSUPPORT_FILE_BASE, filename: `video_metadata.json`, }; + console.log("issue object: ", issueObject); + console.log("request body: ", requestBodyJson); listOfPublishes.push(requestBodyJson); const multiplePublish = { @@ -559,6 +564,11 @@ export const PublishIssue = ({ editId, editContent }: NewCrowdfundProps) => { )} + setPayFee(b)} + /> { @@ -593,7 +603,6 @@ export const PublishIssue = ({ editId, editContent }: NewCrowdfundProps) => { - {feeDisclaimer} diff --git a/src/constants/Identifiers.ts b/src/constants/Identifiers.ts index e4696cf..1293387 100644 --- a/src/constants/Identifiers.ts +++ b/src/constants/Identifiers.ts @@ -11,3 +11,5 @@ export const QSUPPORT_PLAYLIST_BASE = useTestIdentifiers export const QSUPPORT_COMMENT_BASE = useTestIdentifiers ? "qcomment_v1_MYTEST_support_" : "qcomment_v1_q_support_"; + +// have fee payment as checkbox diff --git a/src/constants/PublishFees/FeeData.tsx b/src/constants/PublishFees/FeeData.tsx index 63ed808..dd4c046 100644 --- a/src/constants/PublishFees/FeeData.tsx +++ b/src/constants/PublishFees/FeeData.tsx @@ -1,14 +1,23 @@ +import { CheckBox } from "@mui/icons-material"; import { Box } from "@mui/material"; import React from "react"; +import { StateCheckBox } from "../../utils/StateCheckBox.tsx"; import { useTestIdentifiers } from "../Identifiers.ts"; +import { + FeePrice, + fetchCurrentPriceData, +} from "./FeePricePublish/FeePricePublish.ts"; export const appName = "Q-Support"; export const feeDestinationName = "Q-Support"; -export const feeAmountBase = useTestIdentifiers ? 0.000001 : 0.25; export const FEE_BASE = useTestIdentifiers ? "MYTEST_support_fees" : "q_support_fees"; +export const feeDataDefault = await fetchCurrentPriceData("default", "QORT"); +export const feePriceToString = (feePrice: FeePrice) => { + return `${feePrice?.feeAmount} ${feePrice?.coinType}`; +}; export const supportedCoins = [ "QORT", @@ -24,17 +33,26 @@ export const supportedCoins = [ export const maxFeePublishTimeDiff = 10; // time in minutes before/after publish when fee is considered valid export type FeeType = "default" | "comment" | "like" | "dislike" | "superlike"; -export const feeDisclaimerString = `When Publishing (but not editing) Issues ${feeAmountBase} \n -QORT is requested to fund continued development of Q-Support.`; - -export const feeDisclaimer = ( - - {feeDisclaimerString} - +// use wherever the fee is communicated to the user +const feeCheckBox = ( + ); + +// // Test senderName removal on Publish +// export const feeDisclaimerString = `When Publishing (but not editing) Issues ${feeAmountBase} \n +// QORT is requested to fund continued development of Q-Support.`; +// +// export const feeDisclaimer = ( +// +// {feeDisclaimerString} +// +// ); diff --git a/src/constants/PublishFees/FeePricePublish/DataEditor.tsx b/src/constants/PublishFees/FeePricePublish/DataEditor.tsx new file mode 100644 index 0000000..0dd115e --- /dev/null +++ b/src/constants/PublishFees/FeePricePublish/DataEditor.tsx @@ -0,0 +1,259 @@ +import { + Box, + Button, + MenuItem, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + TextField, +} from "@mui/material"; +import { key } from "localforage"; +import React, { useEffect, useState } from "react"; +import { useDispatch } from "react-redux"; +import { s } from "vite/dist/node/types.d-aGj9QkWt"; +import { ThemeButton } from "../../../pages/Home/Home-styles.tsx"; +import { setNotification } from "../../../state/features/notificationsSlice.ts"; +import BoundedNumericTextField from "../../../utils/BoundedNumericTextField.tsx"; +import { + objectToBase64, + objectToFile, +} from "../../../utils/PublishFormatter.ts"; +import StateTextField from "../../../utils/StateTextField.tsx"; +import { objectIndexToKey } from "../../../utils/utilFunctions.ts"; +import { appName, FEE_BASE, supportedCoins } from "../FeeData.tsx"; +import { DataTableProps } from "./DataTable.tsx"; +import { CoinType, FeePrice, feesPublishService } from "./FeePricePublish.ts"; + +export const DataEditor = ({ columnNames, data, sx }: DataTableProps) => { + const [editedData, setEditedData] = useState(data); + + const addRow = () => { + setEditedData(editedData => [ + ...editedData, + { + time: undefined, + feeAmount: undefined, + feeType: undefined, + coinType: undefined, + }, + ]); + }; + + const removeRow = () => { + setEditedData(editedData => editedData.slice(0, -1)); + }; + + const dispatch = useDispatch(); + + const updateData = ( + value: string | number, + rowIndex: number, + cellIndex: number + ) => { + const rowData = editedData[rowIndex]; + + const key = objectIndexToKey(rowData, cellIndex); + + const newData: FeePrice[] = editedData.map((row, rIndex) => { + return rIndex === rowIndex + ? { ...row, [key]: value || undefined } + : { ...row }; + }); + setEditedData(newData); + }; + + useEffect(() => { + console.log("editedData is: ", editedData); + }, [editedData]); + + const getCellForm = (rowIndex: number, cellIndex: number) => { + const rowData = editedData[rowIndex]; + + const key = objectIndexToKey(rowData, cellIndex); + const value = rowData[key]?.toString(); + + const feeAmount = ( + { + updateData(+s, rowIndex, cellIndex); + }} + /> + ); + + const feeType = ( + { + updateData(e.target.value, rowIndex, cellIndex); + }} + /> + ); + + const coinTypeAC = ( + + updateData(e.target.value as CoinType, rowIndex, cellIndex) + } + sx={{ + width: "100%", + }} + options={supportedCoins} + > + ); + switch (cellIndex) { + case 0: + return value ? new Date(+value).toDateString() : ""; + case 1: + return feeAmount; + case 2: + return feeType; + case 3: + return coinTypeAC; + } + }; + + const isValidPublish = (publishData: FeePrice[]) => { + return publishData.every(value => { + return Object.values(value).every(value => !!value); + }); + }; + + const publish = async (feeData: FeePrice[]) => { + qortalRequest({ + action: "PUBLISH_QDN_RESOURCE", + name: appName, + identifier: FEE_BASE, + service: feesPublishService, + data64: await objectToBase64(feeData), + }).then(response => { + dispatch( + setNotification({ + msg: "Issue published", + alertType: "success", + }) + ); + setEditedData(feeData); + }); + }; + const publishFeeData = () => { + const dataLength = editedData.length - 1; + + const dateEmpty = !editedData[dataLength]?.time; + const dataWithDate: FeePrice[] = editedData.map((row, rIndex) => { + return rIndex === dataLength && dateEmpty + ? { ...row, time: Date.now() } + : { ...row }; + }); + + if (isValidPublish(dataWithDate)) publish(dataWithDate); + else { + const notificationObj = { + msg: "Publish Fee Data is not Valid", + alertType: "error", + }; + dispatch(setNotification(notificationObj)); + } + }; + + const boldSX = { + fontSize: "30px", + textAlign: "center", + fontWeight: "bold", + }; + const cellSX = { + fontSize: "25px", + fontWeight: "normal", + textAlign: "center", + }; + + const AddRemoveRowButtonSX = { + color: "text.primary", + fontSize: "20px", + fontWeight: "bold", + width: "30%", + }; + + return ( + <> + + + + + {columnNames.map((columnName, index) => ( + + {columnName} + + ))} + + + + {editedData.map((tableRow, rowIndex) => { + return ( + + {{rowIndex + 1}} + + {Object.values(tableRow).map((tableCell, cellIndex) => ( + + {getCellForm(rowIndex, cellIndex)} + + ))} + + ); + })} + +
+
+ + + + + + Publish + + + ); +}; diff --git a/src/constants/PublishFees/FeePricePublish/DataTable.tsx b/src/constants/PublishFees/FeePricePublish/DataTable.tsx index 0cdc0d6..4889571 100644 --- a/src/constants/PublishFees/FeePricePublish/DataTable.tsx +++ b/src/constants/PublishFees/FeePricePublish/DataTable.tsx @@ -8,46 +8,51 @@ import { } from "@mui/material"; import React from "react"; import { SxProps } from "@mui/material/styles"; +import { FeePrice } from "./FeePricePublish.ts"; export interface DataTableProps { columnNames: string[]; - data: string[][]; + data: FeePrice[]; sx?: SxProps; } + export const DataTable = ({ columnNames, data, sx }: DataTableProps) => { + const boldSX = { + fontSize: "30px", + textAlign: "center", + fontWeight: "bold", + }; + const cellSX = { + fontSize: "25px", + fontWeight: "normal", + textAlign: "center", + }; + + const formatCell = (s: string, index: number) => { + if (index === 0) return new Date(s).toDateString(); + else return s; + }; return ( {columnNames.map((columnName, index) => ( - + {columnName} ))} - {data.map((tableRow, index) => { + {data.map((tableRow, rowIndex) => { return ( - - {tableRow.map((tableCell, index) => ( - - {tableCell} + + {{rowIndex + 1}} + + {Object.values(tableRow).map((tableCell, cellIndex) => ( + + {formatCell(tableCell, cellIndex)} ))} diff --git a/src/constants/PublishFees/FeePricePublish/FeeHistoryModal.tsx b/src/constants/PublishFees/FeePricePublish/FeeHistoryModal.tsx index ecc1e6e..0812085 100644 --- a/src/constants/PublishFees/FeePricePublish/FeeHistoryModal.tsx +++ b/src/constants/PublishFees/FeePricePublish/FeeHistoryModal.tsx @@ -4,21 +4,19 @@ import { appName } from "../FeeData.tsx"; import { ModalBody } from "./FeePricePublish-styles.tsx"; import { useEffect, useState } from "react"; import { userHasName } from "../VerifyPayment-Functions.ts"; -import { FeeHistoryTable } from "./FeeHistoryTable.tsx"; +import { FeeHistoryModalBody } from "./FeeHistoryModalBody.tsx"; export const FeeHistoryModal = () => { const [open, setOpen] = useState(false); - const [userOwnsApp, setUserOwnsApp] = useState(false); + const theme = useTheme(); - useEffect(() => { - userHasName(appName).then(userHasName => setUserOwnsApp(userHasName)); - }, []); const buttonSX = { fontSize: "20px", color: theme.palette.secondary.main, fontWeight: "bold", }; + if (theme.palette.mode === "light") buttonSX["&:hover"] = { backgroundColor: theme.palette.primary.dark }; @@ -37,7 +35,7 @@ export const FeeHistoryModal = () => { onClose={() => setOpen(false)} > - + diff --git a/src/constants/PublishFees/FeePricePublish/FeeHistoryModalBody.tsx b/src/constants/PublishFees/FeePricePublish/FeeHistoryModalBody.tsx new file mode 100644 index 0000000..b211b80 --- /dev/null +++ b/src/constants/PublishFees/FeePricePublish/FeeHistoryModalBody.tsx @@ -0,0 +1,38 @@ +import { appName } from "../FeeData.tsx"; +import { userHasName } from "../VerifyPayment-Functions.ts"; +import { DataEditor } from "./DataEditor.tsx"; +import { DataTable } from "./DataTable.tsx"; +import { FeePrice, fetchFees } from "./FeePricePublish.ts"; +import React, { useEffect, useState } from "react"; + +export interface FeeHistoryModalBodyProps { + showFeeType?: boolean; + showCoinType?: boolean; + filterData?: () => string[][]; +} +export const FeeHistoryModalBody = ({ + showFeeType = true, + showCoinType = true, +}: FeeHistoryModalBodyProps) => { + const [feeData, setFeeData] = useState([]); + const [userOwnsApp, setUserOwnsApp] = useState(false); + + const fetchFeesOnStartup = () => { + fetchFees().then(feeResponse => { + setFeeData(feeResponse); + }); + userHasName(appName).then(userHasName => setUserOwnsApp(userHasName)); + }; + + useEffect(fetchFeesOnStartup, []); + + const columnNames = ["ID", "Date", "Fee Amount"]; + if (showFeeType) columnNames.push("Fee Type"); + if (showCoinType) columnNames.push("Coin Type"); + + return userOwnsApp ? ( + + ) : ( + + ); +}; diff --git a/src/constants/PublishFees/FeePricePublish/FeeHistoryTable.tsx b/src/constants/PublishFees/FeePricePublish/FeeHistoryTable.tsx deleted file mode 100644 index 0bf1298..0000000 --- a/src/constants/PublishFees/FeePricePublish/FeeHistoryTable.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { DataTable } from "./DataTable.tsx"; -import { FeePrice, fetchFees } from "./FeePricePublish.ts"; -import React, { useEffect, useState } from "react"; - -export interface FeeHistoryProps { - showFeeType?: boolean; - showCoinType?: boolean; - filterData?: () => string[][]; -} -export const FeeHistoryTable = ({ - showFeeType = true, - showCoinType = true, - filterData, -}: FeeHistoryProps) => { - const [feeData, setFeeData] = useState([]); - - const fetchFeesOnStartup = () => { - fetchFees().then(feeResponse => { - setFeeData(filterData ? feeData.filter(filterData) : feeResponse); - }); - }; - - useEffect(fetchFeesOnStartup, []); - - const columnNames = ["ID", "Date", "Fee Amount"]; - if (showFeeType) columnNames.push("Fee Type"); - if (showCoinType) columnNames.push("Coin Type"); - - const data: string[][] = []; - - const getRowData = (row: FeePrice, index: number) => { - const rowData: string[] = []; - rowData.push( - index.toString(), - new Date(row.time).toDateString(), - row.feeAmount.toString() - ); - - if (showFeeType) rowData.push(row.feeType); - if (showCoinType) rowData.push(row.coinType); - - return rowData; - }; - - feeData.map((row, index) => { - data.push(getRowData(row, index + 1)); - }); - return ; -}; diff --git a/src/constants/PublishFees/FeePricePublish/FeePricePublish.ts b/src/constants/PublishFees/FeePricePublish/FeePricePublish.ts index c9f116e..a0f12c3 100644 --- a/src/constants/PublishFees/FeePricePublish/FeePricePublish.ts +++ b/src/constants/PublishFees/FeePricePublish/FeePricePublish.ts @@ -1,11 +1,7 @@ import { setFeeData } from "../../../state/features/globalSlice.ts"; import { store } from "../../../state/store.js"; -import { - objectToBase64, - objectToFile, -} from "../../../utils/PublishFormatter.ts"; -import { useTestIdentifiers } from "../../Identifiers.ts"; -import { appName, FEE_BASE, feeAmountBase, FeeType } from "../FeeData.tsx"; +import { objectToFile } from "../../../utils/PublishFormatter.ts"; +import { appName, FEE_BASE, FeeType } from "../FeeData.tsx"; export type CoinType = "QORT" | "BTC" | "LTC" | "DOGE" | "DGB" | "RVN" | "ARRR"; @@ -16,7 +12,7 @@ export interface FeePrice { coinType: CoinType; } -const feesPublishService = "DOCUMENT"; +export const feesPublishService = "DOCUMENT"; export const fetchFees = async () => { const feeData = store.getState().global.feeData; @@ -48,45 +44,39 @@ export const fetchFeesRedux = () => { fetchFees().then(feeData => store.dispatch(setFeeData(feeData))); }; -export const addFeePrice = async ( - feeAmount = feeAmountBase, +export const fetchCurrentPriceData = async ( feeType: FeeType = "default", coinType: CoinType = "QORT" ) => { const fees = await fetchFees(); + if (fees?.length === 0 || !fees) return undefined; - fees.push({ - time: Date.now(), - feeAmount, - feeType, - coinType, - }); + const filteredFees = fees.filter( + price => price.feeType === feeType && price.coinType === coinType + ); - console.log("fees are: ", fees); - await qortalRequest({ - action: "PUBLISH_QDN_RESOURCE", - name: appName, - identifier: FEE_BASE, - service: feesPublishService, - file: objectToFile(fees), - }); + return filteredFees.at(-1) as FeePrice; }; const feeFilter = (fee: FeePrice, feeToVerify: FeePrice) => { const nameCheck = fee.feeType === feeToVerify.feeType; const coinTypeCheck = fee.coinType === feeToVerify.coinType; - const timeCheck = feeToVerify.time <= feeToVerify.time; + const timeCheck = fee.time <= feeToVerify.time; + const filter = nameCheck && coinTypeCheck && timeCheck; - return nameCheck && coinTypeCheck && timeCheck; + return filter; }; export const verifyFeeAmount = async (feeToVerify: FeePrice) => { - if (useTestIdentifiers) return true; - const fees = await fetchFees(); const filteredFees = fees.filter(fee => feeFilter(fee, feeToVerify)); - if (filteredFees.length === 0) return false; + if (filteredFees.length === 0) { + console.log("no filtered fees"); + return false; + } + // gets fee that applies at the time of feeToVerify + const feeToCheck = filteredFees.at(-1); + const isFeeAmountValid = feeToVerify.feeAmount >= feeToCheck.feeAmount; - const feeToCheck = filteredFees[filteredFees.length - 1]; // gets fee that applies at the time of feeToVerify - return feeToVerify.feeAmount >= feeToCheck.feeAmount; + return isFeeAmountValid; }; diff --git a/src/constants/PublishFees/SendFeeFunctions.ts b/src/constants/PublishFees/SendFeeFunctions.ts index e90cd93..62d442a 100644 --- a/src/constants/PublishFees/SendFeeFunctions.ts +++ b/src/constants/PublishFees/SendFeeFunctions.ts @@ -1,5 +1,8 @@ import { feeDestinationName, FeeType } from "./FeeData.tsx"; -import { CoinType } from "./FeePricePublish/FeePricePublish.ts"; +import { + CoinType, + fetchCurrentPriceData, +} from "./FeePricePublish/FeePricePublish.ts"; export interface NameData { name: string; @@ -58,7 +61,7 @@ export const sendQORTtoName = async (name: string, amount: number) => { export interface PublishFeeData { signature: string; - senderName: string; + senderName?: string; createdTimestamp?: number; //timestamp of the metadata publish, NOT the send feeAmount publish, added after publish is fetched updatedTimestamp?: number; feeType?: FeeType; @@ -73,7 +76,11 @@ export interface CommentObject { feeData: PublishFeeData; } -export const payPublishFeeQORT = async (feeAmount: number) => { - const publish = await sendQORTtoName(feeDestinationName, feeAmount); +export const payPublishFeeQORT = async ( + feeType: FeeType = "default", + coinType: CoinType = "QORT" +) => { + const feeData = await fetchCurrentPriceData(feeType, coinType); + const publish = await sendQORTtoName(feeDestinationName, feeData.feeAmount); return publish?.signature; }; diff --git a/src/constants/PublishFees/VerifyPayment.ts b/src/constants/PublishFees/VerifyPayment.ts index 3ab6c52..6096b13 100644 --- a/src/constants/PublishFees/VerifyPayment.ts +++ b/src/constants/PublishFees/VerifyPayment.ts @@ -45,7 +45,7 @@ const verifySignature = async (feeData: PublishFeeData) => { }); const signatureTime = signatureData.timestamp; - let doesTimeMatch: boolean = false; + let doesTimeMatch = false; if (!updatedTimestamp) { const timeDiff = createdTimestamp - signatureTime; const timeDiffMinutes = Math.abs(timeDiff) / 1000 / 60; diff --git a/src/utils/BoundedNumericTextField.tsx b/src/utils/BoundedNumericTextField.tsx index a637a69..c8042de 100644 --- a/src/utils/BoundedNumericTextField.tsx +++ b/src/utils/BoundedNumericTextField.tsx @@ -10,19 +10,20 @@ import React, { useRef, useState } from "react"; type eventType = React.ChangeEvent; type BoundedNumericTextFieldProps = { - minValue: number; - maxValue: number; + minValue?: number; + maxValue?: number; addIconButtons?: boolean; allowDecimals?: boolean; allowNegatives?: boolean; onChange?: (s: string) => void; + onBlur?: (s: string) => void; initialValue?: string; maxSigDigits?: number; } & TextFieldProps; export const BoundedNumericTextField = ({ - minValue, - maxValue, + minValue = 0, + maxValue = Number.MAX_VALUE, addIconButtons = true, allowDecimals = true, allowNegatives = false, @@ -30,6 +31,8 @@ export const BoundedNumericTextField = ({ maxSigDigits = 6, ...props }: BoundedNumericTextFieldProps) => { + const { onChange, onBlur, ...noChangeProps } = { ...props }; + const [textFieldValue, setTextFieldValue] = useState( initialValue || "" ); @@ -108,6 +111,7 @@ export const BoundedNumericTextField = ({ let value = e.target.value; if (stringIsEmpty(value) || value === ".") { setTextFieldValue(""); + if (onBlur) onBlur(""); return; } @@ -116,9 +120,9 @@ export const BoundedNumericTextField = ({ if (isAllZerosNum.test(value)) value = minValue.toString(); setTextFieldValue(value); + if (onBlur) onBlur(value); }; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { onChange, ...noChangeProps } = { ...props }; + return ( ; + +type StateCheckBoxProps = { + onChange?: (b: boolean) => void; + label?: string; +} & CheckboxProps; + +export const StateCheckBox = ({ ...props }: StateCheckBoxProps) => { + const { onChange, defaultChecked, label, ...noChangeProps } = { ...props }; + + const [checkValue, setCheckValue] = useState(defaultChecked); + const ref = useRef(null); + + const stringIsEmpty = (value: string) => { + return value === ""; + }; + + const listeners = (e: eventType) => { + const newValue = e.target.checked; + setCheckValue(newValue); + if (onChange) onChange(newValue); + }; + + return ( + listeners(e as eventType)} + checked={checkValue} + /> + } + /> + ); +}; + +export default StateTextField; diff --git a/src/utils/StateTextField.tsx b/src/utils/StateTextField.tsx new file mode 100644 index 0000000..94dd62d --- /dev/null +++ b/src/utils/StateTextField.tsx @@ -0,0 +1,64 @@ +import AddIcon from "@mui/icons-material/Add"; +import RemoveIcon from "@mui/icons-material/Remove"; +import { + IconButton, + InputAdornment, + MenuItem, + TextField, + TextFieldProps, +} from "@mui/material"; +import React, { useRef, useState } from "react"; +import { supportedCoins } from "../constants/PublishFees/FeeData.tsx"; + +type eventType = React.ChangeEvent; +type StateTextFieldProps = { + onChange?: (s: string) => void; + initialValue?: string; + options?: string[]; +} & TextFieldProps; + +export const StateTextField = ({ + initialValue, + options, + ...props +}: StateTextFieldProps) => { + const { onChange, ...noChangeProps } = { ...props }; + + const [textFieldValue, setTextFieldValue] = useState( + initialValue || "" + ); + const ref = useRef(null); + + const stringIsEmpty = (value: string) => { + return value === ""; + }; + + const listeners = (e: eventType) => { + const newValue = e.target.value; + setTextFieldValue(newValue); + if (onChange) onChange(newValue); + }; + + return ( + listeners(e as eventType)} + autoComplete="off" + value={textFieldValue} + inputRef={ref} + > + {options && + props?.select && + options.map((option, index) => ( + + {option} + + ))} + + ); +}; + +export default StateTextField; diff --git a/src/utils/qortalRequests.ts b/src/utils/qortalRequests.ts index f11c854..556c457 100644 --- a/src/utils/qortalRequests.ts +++ b/src/utils/qortalRequests.ts @@ -76,7 +76,7 @@ export const getCrowdfund = async (crowdfundLink: string) => { const splitLink = crowdfundLink.split("/"); const name = splitLink[5]; const identifier = splitLink[6]; - console.log("fetching crowdfund"); + return await qortalRequest({ action: "FETCH_QDN_RESOURCE", service: "DOCUMENT", diff --git a/src/utils/utilFunctions.ts b/src/utils/utilFunctions.ts index e41d620..02d0d7a 100644 --- a/src/utils/utilFunctions.ts +++ b/src/utils/utilFunctions.ts @@ -28,3 +28,12 @@ export const isNumber = (input: string) => { export const truncateNumber = (value: string | number, sigDigits: number) => { return Number(value).toFixed(sigDigits); }; +export const objectIndexToKey = (obj: object, index: number) => { + const keys = Object.keys(obj); + + if (index < 0 || index >= keys.length) { + throw new Error(`Invalid index: ${index}`); + } + const key = keys[index]; + return key; +};