diff --git a/src/components/Publish/EditPlaylist/EditPlaylist.tsx b/src/components/Publish/EditPlaylist/EditPlaylist.tsx index 58509f4..59e0de6 100644 --- a/src/components/Publish/EditPlaylist/EditPlaylist.tsx +++ b/src/components/Publish/EditPlaylist/EditPlaylist.tsx @@ -31,7 +31,11 @@ import AddBoxIcon from "@mui/icons-material/AddBox"; import { useDropzone } from "react-dropzone"; import { setNotification } from "../../../state/features/notificationsSlice.ts"; -import { objectToBase64, uint8ArrayToBase64 } from "../../../utils/PublishFormatter.ts"; +import { + objectToBase64, + objectToFile, + uint8ArrayToBase64, +} from "../../../utils/PublishFormatter.ts"; import { RootState } from "../../../state/store.ts"; import { upsertVideosBeginning, @@ -165,14 +169,16 @@ export const EditPlaylist = () => { const responseDataSearchVid = await response.json(); if (responseDataSearchVid?.length > 0) { - let resourceData2 = responseDataSearchVid[0]; + const resourceData2 = responseDataSearchVid[0]; videos.push(resourceData2); } } } combinedData.videos = videos; setPlaylistData(combinedData); - } catch (error) {} + } catch (error) { + console.log(error); + } }, []); useEffect(() => { @@ -263,13 +269,13 @@ export const EditPlaylist = () => { if (!descriptionVid) throw new Error("cannot find video code"); // Split the string by ';' - let parts = descriptionVid.split(";"); + const parts = descriptionVid.split(";"); // Initialize a variable to hold the code value let codeValue = ""; // Loop through the parts to find the one that starts with 'code:' - for (let part of parts) { + for (const part of parts) { if (part.startsWith("code:")) { codeValue = part.split(":")[1]; break; @@ -309,11 +315,10 @@ export const EditPlaylist = () => { .map(item => `c:${item.code};`) .slice(0, 10) .join(""); - let metadescription = + const metadescription = `**category:${category};subcategory:${subcategory};${codes}**` + stringDescription.slice(0, 120); - const crowdfundObjectToBase64 = await objectToBase64(playlistObject); // Description is obtained from raw data let identifier = editVideoProperties?.id; @@ -333,7 +338,7 @@ export const EditPlaylist = () => { action: "PUBLISH_QDN_RESOURCE", name: username, service: "PLAYLIST", - data64: crowdfundObjectToBase64, + file: objectToFile(playlistObject), title: title.slice(0, 50), description: metadescription, identifier: identifier, diff --git a/src/components/Publish/EditVideo/EditVideo.tsx b/src/components/Publish/EditVideo/EditVideo.tsx index 62c1d27..d06c894 100644 --- a/src/components/Publish/EditVideo/EditVideo.tsx +++ b/src/components/Publish/EditVideo/EditVideo.tsx @@ -35,7 +35,11 @@ import AddBoxIcon from "@mui/icons-material/AddBox"; import { useDropzone } from "react-dropzone"; import { setNotification } from "../../../state/features/notificationsSlice.ts"; -import { objectToBase64, objectToFile, uint8ArrayToBase64 } from "../../../utils/PublishFormatter.ts"; +import { + objectToBase64, + objectToFile, + uint8ArrayToBase64, +} from "../../../utils/PublishFormatter.ts"; import { RootState } from "../../../state/store.ts"; import { upsertVideosBeginning, @@ -53,7 +57,11 @@ import { extractTextFromHTML } from "../../common/TextEditor/utils.ts"; import { toBase64 } from "../PublishVideo/PublishVideo.tsx"; import { FrameExtractor } from "../../common/FrameExtractor/FrameExtractor.tsx"; import { QTUBE_VIDEO_BASE } from "../../../constants/Identifiers.ts"; -import { maxSize, titleFormatter, videoMaxSize } from "../../../constants/Misc.ts"; +import { + maxSize, + titleFormatter, + videoMaxSize, +} from "../../../constants/Misc.ts"; const uid = new ShortUniqueId(); const shortuid = new ShortUniqueId({ length: 5 }); @@ -291,13 +299,12 @@ export const EditVideo = () => { `**category:${category};subcategory:${subcategory};code:${editVideoProperties.code}**` + description.slice(0, 150); - const videoObjectToFile = objectToFile(videoObject); // Description is obtained from raw data const requestBodyJson: any = { action: "PUBLISH_QDN_RESOURCE", name: username, service: "DOCUMENT", - file: videoObjectToFile, + file: objectToFile(videoObject), title: title.slice(0, 50), description: metadescription, identifier: editVideoProperties.id, @@ -394,7 +401,9 @@ export const EditVideo = () => { compressedFile = file; resolve(); }, - error(error) {console.log(error)}, + error(error) { + console.log(error); + }, }); }); if (!compressedFile) continue; @@ -406,7 +415,9 @@ export const EditVideo = () => { } setImageExtracts(imagesExtracts); - } catch (error) {console.log(error)} + } catch (error) { + console.log(error); + } }; return ( diff --git a/src/components/common/Comments/CommentEditor.tsx b/src/components/common/Comments/CommentEditor.tsx index a7ea8ad..4926cae 100644 --- a/src/components/common/Comments/CommentEditor.tsx +++ b/src/components/common/Comments/CommentEditor.tsx @@ -4,7 +4,10 @@ import { useDispatch, useSelector } from "react-redux"; import { RootState } from "../../../state/store"; import ShortUniqueId from "short-unique-id"; import { setNotification } from "../../../state/features/notificationsSlice"; -import { publishFormatter } from "../../../utils/PublishFormatter.ts"; +import { + publishFormatter, + stringToFile, +} from "../../../utils/PublishFormatter.ts"; import localforage from "localforage"; import { CommentInput, @@ -30,11 +33,13 @@ export interface Item { export async function addItem(item: Item): Promise { // Get all items - let notificationComments: Item[] = + const notificationComments: Item[] = (await notification.getItem("comments")) || []; // Find the item with the same id, if it exists - let existingItemIndex = notificationComments.findIndex(i => i.id === item.id); + const existingItemIndex = notificationComments.findIndex( + i => i.id === item.id + ); if (existingItemIndex !== -1) { // If the item exists, update its date @@ -55,10 +60,10 @@ export async function addItem(item: Item): Promise { } export async function updateItemDate(item: any): Promise { // Get all items - let notificationComments: Item[] = + const notificationComments: Item[] = (await notification.getItem("comments")) || []; - let notificationCreatorComment: any = + const notificationCreatorComment: any = (await notification.getItem("post-comments")) || {}; const findPostId = notificationCreatorComment[item.postId]; if (findPostId) { @@ -121,13 +126,10 @@ export const CommentEditor = ({ identifier: string, idForNotification?: string ) => { - let address; - let name; + const address = user?.address; + const name = user?.name || ""; let errorMsg = ""; - address = user?.address; - name = user?.name || ""; - if (!address) { errorMsg = "Cannot post: your address isn't available"; } @@ -150,12 +152,11 @@ export const CommentEditor = ({ } try { - const base64 = utf8ToBase64(value); const resourceResponse = await qortalRequest({ action: "PUBLISH_QDN_RESOURCE", name: name, service: "BLOG_COMMENT", - data64: base64, + file: stringToFile(value), identifier: identifier, }); dispatch( diff --git a/src/components/common/ContentButtons/SuperLike.tsx b/src/components/common/ContentButtons/SuperLike.tsx index ab8b9c3..b519f4d 100644 --- a/src/components/common/ContentButtons/SuperLike.tsx +++ b/src/components/common/ContentButtons/SuperLike.tsx @@ -21,7 +21,10 @@ import { MultiplePublish } from "../../Publish/MultiplePublish/MultiplePublishAl import { useDispatch, useSelector } from "react-redux"; import { setNotification } from "../../../state/features/notificationsSlice.ts"; import ShortUniqueId from "short-unique-id"; -import { objectToBase64 } from "../../../utils/PublishFormatter.ts"; +import { + objectToBase64, + objectToFile, +} from "../../../utils/PublishFormatter.ts"; import { minPriceSuperlike } from "../../../constants/Misc.ts"; import { CommentInput } from "../Comments/Comments-styles.tsx"; import { @@ -55,9 +58,7 @@ export const SuperLike = ({ const [isOpen, setIsOpen] = useState(false); const [superlikeDonationAmount, setSuperlikeDonationAmount] = - useState(10); - const [qortalDevDonationAmount, setQortalDevDonationAmount] = - useState(0); + useState(minPriceSuperlike); const [currentBalance, setCurrentBalance] = useState(""); const [comment, setComment] = useState(""); @@ -82,15 +83,12 @@ export const SuperLike = ({ if (!name) throw new Error("Could not retrieve content creator's name"); const estimatedTransactionFees = 0.1; const donationExceedsBalance = - superlikeDonationAmount + - qortalDevDonationAmount + - estimatedTransactionFees >= - +currentBalance; + superlikeDonationAmount + estimatedTransactionFees >= +currentBalance; if (donationExceedsBalance) { throw new Error("Total donations exceeds current balance"); } - let resName = await qortalRequest({ + const resName = await qortalRequest({ action: "GET_NAME_DATA", name: name, }); @@ -106,10 +104,10 @@ export const SuperLike = ({ superlikeDonationAmount < minPriceSuperlike ) throw new Error( - `The amount needs to be at least ${minPriceSuperlike} QORT` + `The amount is ${superlikeDonationAmount}, but it needs to be at least ${minPriceSuperlike} QORT` ); - let listOfPublishes = []; + const listOfPublishes = []; const res = await qortalRequest({ action: "SEND_COIN", @@ -118,24 +116,7 @@ export const SuperLike = ({ amount: superlikeDonationAmount, }); - const devDonation = qortalDevDonationAmount > 0; - if (devDonation) { - const devFundName = "DevFund"; - - let devFundNameData = await qortalRequest({ - action: "GET_NAME_DATA", - name: devFundName, - }); - - const devFundAddress = devFundNameData.owner; - const resDevFund = await qortalRequest({ - action: "SEND_COIN", - coin: "QORT", - destinationAddress: devFundAddress, - amount: qortalDevDonationAmount, - }); - } - let metadescription = `**sig:${ + const metadescription = `**sig:${ res.signature };${FOR}:${name}_${FOR_SUPER_LIKE};nm:${name.slice( 0, @@ -148,7 +129,7 @@ export const SuperLike = ({ 39 )}_${id}`; - const superLikeToBase64 = await objectToBase64({ + const superLikeToFile = objectToFile({ comment, transactionReference: res.signature, notificationInformation: { @@ -166,7 +147,7 @@ export const SuperLike = ({ action: "PUBLISH_QDN_RESOURCE", name: username, service: "BLOG_COMMENT", - data64: superLikeToBase64, + file: superLikeToFile, title: "", description: metadescription, identifier: identifierSuperLike, @@ -187,9 +168,9 @@ export const SuperLike = ({ dispatch( setNotification({ msg: - error || error?.error || error?.message || + error || "Failed to publish Super Like", alertType: "error", }) @@ -339,36 +320,6 @@ export const SuperLike = ({ InputLabelProps={{ style: { fontSize: "18px" } }} onChange={e => setComment(e.target.value)} /> - - - Would you like to donate to Qortal Development? - - setQortalDevDonationAmount(+e)} - InputProps={{ - style: { fontSize: 30, width: textFieldWidth }, - startAdornment: ( - - {"Qort - - ), - }} - /> diff --git a/src/components/common/SuperLikesList/CommentEditor.tsx b/src/components/common/SuperLikesList/CommentEditor.tsx index ec3e033..8d256a4 100644 --- a/src/components/common/SuperLikesList/CommentEditor.tsx +++ b/src/components/common/SuperLikesList/CommentEditor.tsx @@ -4,7 +4,12 @@ import { useDispatch, useSelector } from "react-redux"; import { RootState } from "../../../state/store"; import ShortUniqueId from "short-unique-id"; import { setNotification } from "../../../state/features/notificationsSlice"; -import { objectToBase64, publishFormatter } from "../../../utils/PublishFormatter.ts"; +import { + objectToBase64, + objectToFile, + publishFormatter, + stringToFile, +} from "../../../utils/PublishFormatter.ts"; import localforage from "localforage"; import { CommentInput, @@ -30,11 +35,13 @@ export interface Item { export async function addItem(item: Item): Promise { // Get all items - let notificationComments: Item[] = + const notificationComments: Item[] = (await notification.getItem("comments")) || []; // Find the item with the same id, if it exists - let existingItemIndex = notificationComments.findIndex(i => i.id === item.id); + const existingItemIndex = notificationComments.findIndex( + i => i.id === item.id + ); if (existingItemIndex !== -1) { // If the item exists, update its date @@ -55,10 +62,10 @@ export async function addItem(item: Item): Promise { } export async function updateItemDate(item: any): Promise { // Get all items - let notificationComments: Item[] = + const notificationComments: Item[] = (await notification.getItem("comments")) || []; - let notificationCreatorComment: any = + const notificationCreatorComment: any = (await notification.getItem("post-comments")) || {}; const findPostId = notificationCreatorComment[item.postId]; if (findPostId) { @@ -127,13 +134,10 @@ export const CommentEditor = ({ identifier: string, idForNotification?: string ) => { - let address; - let name; + const address = user?.address; + const name = user?.name || ""; let errorMsg = ""; - address = user?.address; - name = user?.name || ""; - if (!address) { errorMsg = "Cannot post: your address isn't available"; } @@ -156,7 +160,7 @@ export const CommentEditor = ({ } try { - let data64 = null; + let dataFile = null; let description = ""; let tag1 = ""; let superObj = {}; @@ -177,17 +181,18 @@ export const CommentEditor = ({ notificationInformation: comment.notificationInformation, about: comment.about, }; - const superLikeToBase64 = await objectToBase64(superObj); - data64 = superLikeToBase64; + const superLikeToFile = await objectToFile(superObj); + dataFile = superLikeToFile; } - if (isSuperLike && !data64) throw new Error("unable to edit Super like"); + if (isSuperLike && !dataFile) + throw new Error("unable to edit Super like"); - const base64 = utf8ToBase64(value); + const stringFile = stringToFile(value); const resourceResponse = await qortalRequest({ action: "PUBLISH_QDN_RESOURCE", name: name, service: "BLOG_COMMENT", - data64: isSuperLike ? data64 : base64, + file: isSuperLike ? dataFile : stringFile, identifier: identifier, description, tag1, @@ -248,7 +253,7 @@ export const CommentEditor = ({ let identifier = `${COMMENT_BASE}${postId.slice(-12)}_base_${id}`; let idForNotification = identifier; - let service = "BLOG_COMMENT"; + const service = "BLOG_COMMENT"; if (isReply && commentId) { const removeBaseCommentId = commentId; removeBaseCommentId.replace("_base_", ""); diff --git a/src/pages/ContentPages/VideoContent/VideoContent.tsx b/src/pages/ContentPages/VideoContent/VideoContent.tsx index 451fbb9..a6032d9 100644 --- a/src/pages/ContentPages/VideoContent/VideoContent.tsx +++ b/src/pages/ContentPages/VideoContent/VideoContent.tsx @@ -65,10 +65,10 @@ import { LikeAndDislike } from "../../../components/common/ContentButtons/LikeAn export function isTimestampWithinRange(resTimestamp, resCreated) { // Calculate the absolute difference in milliseconds - var difference = Math.abs(resTimestamp - resCreated); + const difference = Math.abs(resTimestamp - resCreated); // 2 minutes in milliseconds - var twoMinutesInMilliseconds = 3 * 60 * 1000; + const twoMinutesInMilliseconds = 3 * 60 * 1000; // Check if the difference is within 2 minutes return difference <= twoMinutesInMilliseconds; @@ -282,6 +282,7 @@ export const VideoContent = () => { } } } catch (error) { + console.log(error); } finally { dispatch(setIsLoadingGlobal(false)); } @@ -356,7 +357,9 @@ export const VideoContent = () => { }, ]; } - } catch (error) {} + } catch (error) { + console.log(error); + } } } diff --git a/src/utils/PublishFormatter.ts b/src/utils/PublishFormatter.ts index 59dfe42..7954021 100644 --- a/src/utils/PublishFormatter.ts +++ b/src/utils/PublishFormatter.ts @@ -1,98 +1,107 @@ -export const publishFormatter = (file: File): Promise => +export const publishFormatter = ( + file: File +): Promise => new Promise((resolve, reject) => { - const reader = new FileReader() - reader.readAsDataURL(file) + const reader = new FileReader(); + reader.readAsDataURL(file); reader.onload = () => { - const result = reader.result - reader.onload = null // remove onload handler - reader.onerror = null // remove onerror handler - resolve(result) - } - - reader.onerror = (error) => { - reader.onload = null // remove onload handler - reader.onerror = null // remove onerror handler - reject(error) - } - }) + const result = reader.result; + reader.onload = null; // remove onload handler + reader.onerror = null; // remove onerror handler + resolve(result); + }; + + reader.onerror = error => { + reader.onload = null; // remove onload handler + reader.onerror = null; // remove onerror handler + reject(error); + }; + }); export function objectToBase64(obj: any) { // Step 1: Convert the object to a JSON string - const jsonString = JSON.stringify(obj) + const jsonString = JSON.stringify(obj); // Step 2: Create a Blob from the JSON string - const blob = new Blob([jsonString], { type: 'application/json' }) + const blob = new Blob([jsonString], { type: "application/json" }); // Step 3: Create a FileReader to read the Blob as a base64-encoded string return new Promise((resolve, reject) => { - const reader = new FileReader() + const reader = new FileReader(); reader.onloadend = () => { - if (typeof reader.result === 'string') { + if (typeof reader.result === "string") { // Remove 'data:application/json;base64,' prefix const base64 = reader.result.replace( - 'data:application/json;base64,', - '' - ) - resolve(base64) + "data:application/json;base64,", + "" + ); + resolve(base64); } else { - reject(new Error('Failed to read the Blob as a base64-encoded string')) + reject(new Error("Failed to read the Blob as a base64-encoded string")); } - } + }; reader.onerror = () => { - reject(reader.error) - } - reader.readAsDataURL(blob) - }) + reject(reader.error); + }; + reader.readAsDataURL(blob); + }); } -export function objectToFile(obj: any) { +export const stringToFile = (text: string) => { + return new File([text], "", { + type: "text/plain", + }); +}; +export const objectToFile = (obj: object) => { // Step 1: Convert the object to a JSON string - const jsonString = JSON.stringify(obj) + const jsonString = JSON.stringify(obj); + const fileType = { type: "application/json" }; // Step 2: Create a Blob from the JSON string - return new Blob([jsonString], { type: 'application/json' }) -} + const blob = new Blob([jsonString], fileType); + return new File([blob], ``, fileType); +}; export function objectToUint8Array(obj: any) { // Convert the object to a JSON string - const jsonString = JSON.stringify(obj) + const jsonString = JSON.stringify(obj); // Encode the JSON string as a byte array using TextEncoder - const encoder = new TextEncoder() - const byteArray = encoder.encode(jsonString) + const encoder = new TextEncoder(); + const byteArray = encoder.encode(jsonString); // Create a new Uint8Array and set its content to the encoded byte array - const uint8Array = new Uint8Array(byteArray) + const uint8Array = new Uint8Array(byteArray); - return uint8Array + return uint8Array; } export function uint8ArrayToBase64(uint8Array: Uint8Array): string { - const length = uint8Array.length - let binaryString = '' - const chunkSize = 1024 * 1024 // Process 1MB at a time + const length = uint8Array.length; + let binaryString = ""; + const chunkSize = 1024 * 1024; // Process 1MB at a time for (let i = 0; i < length; i += chunkSize) { - const chunkEnd = Math.min(i + chunkSize, length) - const chunk = uint8Array.subarray(i, chunkEnd) - binaryString += Array.from(chunk, (byte) => String.fromCharCode(byte)).join( - '' - ) + const chunkEnd = Math.min(i + chunkSize, length); + const chunk = uint8Array.subarray(i, chunkEnd); + binaryString += Array.from(chunk, byte => String.fromCharCode(byte)).join( + "" + ); } - return btoa(binaryString) + return btoa(binaryString); } export function objectToUint8ArrayFromResponse(obj: any) { - const len = Object.keys(obj).length - const result = new Uint8Array(len) + const len = Object.keys(obj).length; + const result = new Uint8Array(len); for (let i = 0; i < len; i++) { - result[i] = obj[i] + result[i] = obj[i]; } - return result + return result; } // export function uint8ArrayToBase64(arrayBuffer: Uint8Array): string { // let binary = '' @@ -107,46 +116,46 @@ export function objectToUint8ArrayFromResponse(obj: any) { // } export function base64ToUint8Array(base64: string) { - const binaryString = atob(base64) - const len = binaryString.length - const bytes = new Uint8Array(len) + const binaryString = atob(base64); + const len = binaryString.length; + const bytes = new Uint8Array(len); for (let i = 0; i < len; i++) { - bytes[i] = binaryString.charCodeAt(i) + bytes[i] = binaryString.charCodeAt(i); } - return bytes + return bytes; } export function uint8ArrayToObject(uint8Array: Uint8Array) { // Decode the byte array using TextDecoder - const decoder = new TextDecoder() - const jsonString = decoder.decode(uint8Array) + const decoder = new TextDecoder(); + const jsonString = decoder.decode(uint8Array); // Convert the JSON string back into an object - const obj = JSON.parse(jsonString) + const obj = JSON.parse(jsonString); - return obj + return obj; } export function processFileInChunks(file: File): Promise { return new Promise( (resolve: (value: Uint8Array) => void, reject: (reason?: any) => void) => { - const reader = new FileReader() + const reader = new FileReader(); reader.onload = function (event: ProgressEvent) { - const arrayBuffer = event.target?.result as ArrayBuffer - const uint8Array = new Uint8Array(arrayBuffer) - resolve(uint8Array) - } + const arrayBuffer = event.target?.result as ArrayBuffer; + const uint8Array = new Uint8Array(arrayBuffer); + resolve(uint8Array); + }; reader.onerror = function (error: ProgressEvent) { - reject(error) - } + reject(error); + }; - reader.readAsArrayBuffer(file) + reader.readAsArrayBuffer(file); } - ) + ); } // export async function processFileInChunks(file: File, chunkSize = 1024 * 1024): Promise {