From 75beecd26f19b405b68a9c5c08559c241bcdaf0f Mon Sep 17 00:00:00 2001 From: IrohDW Date: Fri, 26 Jul 2024 15:30:47 -0600 Subject: [PATCH 1/2] FeeHistoryModal is now editable by app owner Fixed bug with feeFilter's Time Check in FeePricePublish.ts feeAmount in FeeData.tsx now fetches the newest price of a given FeeType instead of using a hardcoded value Fixed bug that prevented app from working if no FeeData was found Reverted publishing content as file back to base64 --- src/components/EditIssue/EditIssue.tsx | 9 +- src/components/EditPlaylist/EditPlaylist.tsx | 2 +- src/components/PublishIssue/PublishIssue.tsx | 29 +- src/constants/Identifiers.ts | 2 + src/constants/PublishFees/FeeData.tsx | 46 +++- .../FeePricePublish/DataEditor.tsx | 259 ++++++++++++++++++ .../PublishFees/FeePricePublish/DataTable.tsx | 47 ++-- .../FeePricePublish/FeeHistoryModal.tsx | 10 +- .../FeePricePublish/FeeHistoryModalBody.tsx | 38 +++ .../FeePricePublish/FeeHistoryTable.tsx | 49 ---- .../FeePricePublish/FeePricePublish.ts | 50 ++-- src/constants/PublishFees/SendFeeFunctions.ts | 15 +- src/constants/PublishFees/VerifyPayment.ts | 2 +- src/utils/BoundedNumericTextField.tsx | 16 +- src/utils/StateCheckBox.tsx | 45 +++ src/utils/StateTextField.tsx | 64 +++++ src/utils/qortalRequests.ts | 2 +- src/utils/utilFunctions.ts | 9 + 18 files changed, 545 insertions(+), 149 deletions(-) create mode 100644 src/constants/PublishFees/FeePricePublish/DataEditor.tsx create mode 100644 src/constants/PublishFees/FeePricePublish/FeeHistoryModalBody.tsx delete mode 100644 src/constants/PublishFees/FeePricePublish/FeeHistoryTable.tsx create mode 100644 src/utils/StateCheckBox.tsx create mode 100644 src/utils/StateTextField.tsx 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; +}; From 19a5754d30d01fa076706649408ead72a7a27959 Mon Sep 17 00:00:00 2001 From: IrohDW Date: Fri, 26 Jul 2024 15:46:08 -0600 Subject: [PATCH 2/2] FeeHistoryModal is now editable by app owner Fixed bug with feeFilter's Time Check in FeePricePublish.ts feeAmount in FeeData.tsx now fetches the newest price of a given FeeType instead of using a hardcoded value Fixed bug that prevented app from working if no FeeData was found Reverted publishing content as file back to base64 Vite builds with target "esnext" to allow top level await. --- .../common/Comments/CommentEditor.tsx | 2 +- vite.config.ts | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/components/common/Comments/CommentEditor.tsx b/src/components/common/Comments/CommentEditor.tsx index 39e48f1..0032b26 100644 --- a/src/components/common/Comments/CommentEditor.tsx +++ b/src/components/common/Comments/CommentEditor.tsx @@ -161,7 +161,7 @@ export const CommentEditor = ({ action: "PUBLISH_QDN_RESOURCE", name: name, service: "BLOG_COMMENT", - file: stringToFile(value), + data64: utf8ToBase64(value), identifier: identifier, }); diff --git a/vite.config.ts b/vite.config.ts index e61ca14..2d60944 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,8 +1,11 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react()], - base: "" -}) +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + base: "", + build: { + target: "esnext", //browsers can handle the latest ES features + }, +});