import React, { useCallback, useEffect, useMemo, useRef, useState, } from "react"; import { CreateCommonSecret } from "./CreateCommonSecret"; import { reusableGet } from "../../qdn/publish/pubish"; import { uint8ArrayToObject } from "../../backgroundFunctions/encryption"; import { base64ToUint8Array, objectToBase64, } from "../../qdn/encryption/group-encryption"; import { ChatContainerComp } from "./ChatContainer"; import { ChatList } from "./ChatList"; import "@chatscope/chat-ui-kit-styles/dist/default/styles.min.css"; import Tiptap from "./TipTap"; import { AuthenticatedContainerInnerTop, CustomButton } from "../../App-styles"; import CircularProgress from "@mui/material/CircularProgress"; import { getBaseApi, getFee } from "../../background"; import { LoadingSnackbar } from "../Snackbar/LoadingSnackbar"; import { Box, Typography } from "@mui/material"; import { Spacer } from "../../common/Spacer"; import ShortUniqueId from "short-unique-id"; import { AnnouncementList } from "./AnnouncementList"; const uid = new ShortUniqueId({ length: 8 }); import CampaignIcon from '@mui/icons-material/Campaign'; import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import { AnnouncementDiscussion } from "./AnnouncementDiscussion"; import { MyContext, getBaseApiReact, isMobile, pauseAllQueues, resumeAllQueues } from "../../App"; import { RequestQueueWithPromise } from "../../utils/queue/queue"; import { CustomizedSnackbars } from "../Snackbar/Snackbar"; export const requestQueueCommentCount = new RequestQueueWithPromise(3) export const requestQueuePublishedAccouncements = new RequestQueueWithPromise(3) export const saveTempPublish = async ({ data, key }: any) => { return new Promise((res, rej) => { chrome?.runtime?.sendMessage( { action: "saveTempPublish", payload: { data, key, }, }, (response) => { if (!response?.error) { res(response); } rej(response.error); } ); }); }; export const getTempPublish = async () => { return new Promise((res, rej) => { chrome?.runtime?.sendMessage( { action: "getTempPublish", payload: { }, }, (response) => { if (!response?.error) { res(response); } rej(response.error); } ); }); }; export const decryptPublishes = async (encryptedMessages: any[], secretKey) => { try { return await new Promise((res, rej) => { chrome?.runtime?.sendMessage( { action: "decryptSingleForPublishes", payload: { data: encryptedMessages, secretKeyObject: secretKey, skipDecodeBase64: true, }, }, (response) => { if (!response?.error) { res(response); // if(hasInitialized.current){ // setMessages((prev)=> [...prev, ...formatted]) // } else { // const formatted = response.map((item: any)=> { // return { // ...item, // id: item.signature, // text: item.text, // unread: false // } // } ) // setMessages(formatted) // hasInitialized.current = true // } } rej(response.error); } ); }); } catch (error) {} }; export const GroupAnnouncements = ({ selectedGroup, secretKey, setSecretKey, getSecretKey, myAddress, handleNewEncryptionNotification, isAdmin, hide, myName }) => { const [messages, setMessages] = useState([]); const [isSending, setIsSending] = useState(false); const [isLoading, setIsLoading] = useState(true); const [announcements, setAnnouncements] = useState([]); const [tempPublishedList, setTempPublishedList] = useState([]) const [announcementData, setAnnouncementData] = useState({}); const [selectedAnnouncement, setSelectedAnnouncement] = useState(null); const { show } = React.useContext(MyContext); const [openSnack, setOpenSnack] = React.useState(false); const [infoSnack, setInfoSnack] = React.useState(null); const hasInitialized = useRef(false); const hasInitializedWebsocket = useRef(false); const editorRef = useRef(null); const setEditorRef = (editorInstance) => { editorRef.current = editorInstance; }; const getAnnouncementData = async ({ identifier, name }) => { try { const res = await requestQueuePublishedAccouncements.enqueue(()=> { return fetch( `${getBaseApiReact()}/arbitrary/DOCUMENT/${name}/${identifier}?encoding=base64` ); }) const data = await res.text(); const response = await decryptPublishes([{ data }], secretKey); const messageData = response[0]; setAnnouncementData((prev) => { return { ...prev, [`${identifier}-${name}`]: messageData, }; }); } catch (error) {} }; useEffect(() => { if (!secretKey || hasInitializedWebsocket.current) return; setIsLoading(true); // initWebsocketMessageGroup() hasInitializedWebsocket.current = true; }, [secretKey]); const encryptChatMessage = async (data: string, secretKeyObject: any) => { try { return new Promise((res, rej) => { chrome?.runtime?.sendMessage( { action: "encryptSingle", payload: { data, secretKeyObject, }, }, (response) => { if (!response?.error) { res(response); return; } rej(response.error); } ); }); } catch (error) {} }; const publishAnc = async ({ encryptedData, identifier }: any) => { return new Promise((res, rej) => { chrome?.runtime?.sendMessage( { action: "publishGroupEncryptedResource", payload: { encryptedData, identifier, }, }, (response) => { if (!response?.error) { res(response); } rej(response.error); } ); }); }; const clearEditorContent = () => { if (editorRef.current) { editorRef.current.chain().focus().clearContent().run(); } }; const setTempData = async ()=> { try { const getTempAnnouncements = await getTempPublish() if(getTempAnnouncements?.announcement){ let tempData = [] Object.keys(getTempAnnouncements?.announcement || {}).map((key)=> { const value = getTempAnnouncements?.announcement[key] tempData.push(value.data) }) setTempPublishedList(tempData) } } catch (error) { } } const publishAnnouncement = async () => { try { pauseAllQueues() const fee = await getFee('ARBITRARY') await show({ message: "Would you like to perform a ARBITRARY transaction?" , publishFee: fee.fee + ' QORT' }) if (isSending) return; if (editorRef.current) { const htmlContent = editorRef.current.getHTML(); if (!htmlContent?.trim() || htmlContent?.trim() === "
") return; setIsSending(true); const message = { version: 1, extra: {}, message: htmlContent } const secretKeyObject = await getSecretKey(false, true); const message64: any = await objectToBase64(message); const encryptSingle = await encryptChatMessage( message64, secretKeyObject ); const randomUid = uid.rnd(); const identifier = `grp-${selectedGroup}-anc-${randomUid}`; const res = await publishAnc({ encryptedData: encryptSingle, identifier }); const dataToSaveToStorage = { name: myName, identifier, service: 'DOCUMENT', tempData: message, created: Date.now() } await saveTempPublish({data: dataToSaveToStorage, key: 'announcement'}) setTempData() clearEditorContent(); } // send chat message } catch (error) { setInfoSnack({ type: "error", message: error, }); setOpenSnack(true) } finally { resumeAllQueues() setIsSending(false); } }; const getAnnouncements = React.useCallback( async (selectedGroup) => { try { const offset = 0; // dispatch(setIsLoadingGlobal(true)) const identifier = `grp-${selectedGroup}-anc-`; const url = `${getBaseApiReact()}/arbitrary/resources/search?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=20&includemetadata=false&offset=${offset}&reverse=true&prefix=true`; const response = await fetch(url, { method: "GET", headers: { "Content-Type": "application/json", }, }); const responseData = await response.json(); setTempData() setAnnouncements(responseData); setIsLoading(false); for (const data of responseData) { getAnnouncementData({ name: data.name, identifier: data.identifier }); } } catch (error) { } finally { // dispatch(setIsLoadingGlobal(false)) } }, [secretKey] ); React.useEffect(() => { if (selectedGroup && secretKey && !hasInitialized.current) { getAnnouncements(selectedGroup); hasInitialized.current = true } }, [selectedGroup, secretKey]); const loadMore = async()=> { try { setIsLoading(true); const offset = announcements.length const identifier = `grp-${selectedGroup}-anc-`; const url = `${getBaseApiReact()}/arbitrary/resources/search?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=20&includemetadata=false&offset=${offset}&reverse=true&prefix=true`; const response = await fetch(url, { method: "GET", headers: { "Content-Type": "application/json", }, }); const responseData = await response.json(); setAnnouncements((prev)=> [...prev, ...responseData]); setIsLoading(false); for (const data of responseData) { getAnnouncementData({ name: data.name, identifier: data.identifier }); } } catch (error) { } } const interval = useRef