import init, { encrypt_or_decrypt_files2, password, sanitize_base64, base64_to_vec,vec_to_base64, uuid_generate, encode_base64 } from 'my-crate';
import './style.css'
import $ from 'jquery';
import iro from '@jaames/iro';
import Plyr from 'plyr';
import { Polybase } from "@polybase/client";
import Recorder from "yiyi-audio-recorder";
import { uniqueNamesGenerator, adjectives, colors, animals } from 'unique-names-generator';
import { Connection, Keypair, PublicKey, sendAndConfirmTransaction, SystemProgram, Transaction, TransactionInstruction, TransactionMessage, VersionedTransaction } from "@solana/web3.js";
import { Buffer } from 'buffer';
window.Buffer = Buffer;
// import * as algosdk from 'algosdk';
// import { use} from "@maticnetwork/maticjs"
// import { Web3ClientPlugin } from '@maticnetwork/maticjs-ethers'
// import { ethers } from 'ethers';
// import { createWeb3Modal, defaultWagmiConfig } from '@web3modal/wagmi';
// import { polygonZkEvm } from '@wagmi/core/chains';
// import { watchAccount, disconnect, getAccount } from '@wagmi/core'
// import { ArweaveWebWallet } from 'arweave-wallet-connector'
// import Arweave from 'arweave';
// const arweave = Arweave.init({
// host: 'arweave.net', // Hostname or IP address for a Arweave host
// port: 443, // Port
// protocol: 'https', // Network protocol http or https
// timeout: 20000, // Network request timeouts in milliseconds
// logging: false, // Enable network request logging
// });
$('#overlay_algo_gate').hide();
$('#algo_gate').hide();
$('#chats_title').hide();
$('#chats_disclosure').hide();
// declare let ethereum: any;
// 1. Define constants
// const projectId = 'e7f3d5f95dacb65d61e3e69e66285f2a'
// const metadata = {
// name: 'chat_psc',
// }
// 2. Create wagmiConfig
// const chains = [polygonZkEvm];
// const wagmiConfig = defaultWagmiConfig({
// chains,
// projectId,
// metadata,
// });
// 3. Create modal
// const modal = createWeb3Modal({ wagmiConfig, projectId, chains });
// const wallet = new ArweaveWebWallet({ // Initialize the wallet as soon as possible to get instant auto reconnect
// name: 'philiaSocial Collective',
// logo: 'https://jfbeats.github.io/ArweaveWalletConnector/placeholder.svg'
// });
declare global {
interface Window {
glow: any;
}
}
// function connect() {
// if (getAccount().isConnected) {
// disconnect();
// } else {
// modal.open();
// }
// }
const btnEl = document.getElementById('btn');
const userEl = document.getElementById('account_connected');
btnEl.innerText = 'Connect';
userEl.innerText = 'Wallet Not Connected';
btnEl.addEventListener('click', () => {
if (btnEl.innerText === 'Connect') {
connect();
} else {
disconnect();
}
});
// function to update UI based on connection status
function updateUI(isConnected: boolean, address: string) {
userEl.innerText = isConnected ? address : 'Wallet Not Connected';
btnEl.innerText = isConnected ? 'Disconnect' : 'Connect';
}
async function disconnect() {
try {
await window.glow.disconnect();
updateUI(false, "");
} catch (error) {
console.error('Error disconnecting wallet:', error);
}
}
let wallet;
// modify your connect function
async function connect() {
try {
wallet = await window.glow.connect();
if (wallet && wallet.address) {
wallet.address
updateUI(true, wallet.address);
} else {
updateUI(false, "");
}
} catch (error) {
userEl.innerText = 'Please Download Glow Wallet';
const glowInstalled = window.glow != null;
if (!glowInstalled) {
window.open("https://glow.app", "_blank");
}
}
}
// // modify your connect function
// async function connect() {
// try {
// console.dir(window.glow);
// const resp = await window.glow.connect();
// // console.log(resp)
// if (resp) {
// // wallet.disconnect(); // assume disconnect is a method on wallet
// updateUI(true, resp.address);
// } else {
// // wallet.setUrl('https://arweave.app')
// // await wallet.connect();
// updateUI(false, "");
// // assume getAddress is a method on wallet
// }
// } catch (error) {
// userEl.innerText = 'Please Download Glow Wallet';
// const glowInstalled = window.glow != null;
// if (!glowInstalled) {
// window.open("https://glow.app", "_blank");
// }
// }
// // if (wallet.connected) {
// // wallet.disconnect(); // assume disconnect is a method on wallet
// // updateUI(false, "");
// // } else {
// // wallet.setUrl('https://arweave.app')
// // await wallet.connect();
// // updateUI(true, wallet.address); // assume getAddress is a method on wallet
// // }
// }
// btnEl.addEventListener('click', connect);
// let connectedAddress = wallet.address;
// Listening for account changes
// watchAccount(account => {
// connectedAddress = account.address ?? ''; // Update the connected address
// if (account.isConnected) {
// userEl.innerText = connectedAddress;
// btnEl.innerText = 'Disconnect';
// } else {
// userEl.innerText = 'Wallet not connected'; // Set placeholder text when not connected
// btnEl.innerText = 'Connect';
// }
// });
// use(Web3ClientPlugin);
const db = new Polybase({
defaultNamespace: "data_space",
signer: (data) => {
// Enter your condition to skip the signing process.
return null;
}
});
const collectionReference = db.collection("cid");
const decoder = new TextDecoder();
let uploadedFiles = [];
$("#algo_button_box").hide();
// $("#container_algorand").hide();
//=====================================================================
// BUTTONS LAYER
//=====================================================================
$( "#love_matchings" ).on('click', function() {
$("#love_matchings").addClass("animated");
// Open the new window after the transition or animation has completed
setTimeout(function() {
window.open("https://love.philiasocial.repl.co/", '_blank');
}, 500);
});
$( "#infinity_nomads" ).on('click', function() {
$("#infinity_nomads").addClass("animated");
// Open the new window after the transition or animation has completed
setTimeout(function() {
window.open("https://infinity.farfallasocial.repl.co/", '_blank');
}, 500);
});
$( "#info_riddles" ).on('click', function() {
$("#info_riddles").addClass("animated");
// Open the new window after the transition or animation has completed
setTimeout(function() {
//info_riddles modal
$("#modal_riddle_info").toggle();
$('#modal_riddle_info').css('display', 'block');
$('#ok_closing').on('click', function(){
$('#algo_button_box').scrollTop(0);
$('#creative_modal').scrollTop(0);
$('#modal_riddle_info').scrollTop(0);
$('#modal_riddle_info').hide();
$('#creative_modal').hide();
$('#blurred_backdrop').hide();
});
//info_riddles modal
}, 400);
});
$( "#info_pop" ).on('click', function() {
if($('#info_box').length == 0){
$('#anchor_info_pop').append(`
<div id='info_box'>
<div id='title_steps'>Guidance</div>
<div class="line-break0"></div>
<div class='first_step'>If you require a translator, we enjoy using this <a href="https://www.deepl.com/translator" target="_blank">Deep Learning model</a>.</div>
<div class="line-break0"></div>
<div class='first_step'>If you require a place to store your notes securely and privaely, we enjoy using this <a href="https://www.protectedtext.com/" target="_blank">Protected Text</a>.</div>
<div class="line-break0"></div>
<div class='first_step'>For mobile notifications, we use the decentralized messenger, <a href="https://elixxir.io/" target="_blank">xx messenger</a>. In our personal workflows, in practice, we first send the message within the philiSocial Chat, and then sent a @ or ! within xx messenger to notify our contacts.</div>
<div class="line-break0"></div>
<div class='first_step'>PhiliaSocial Chat uses Aes256Gcm; for further reading visit this <a href="https://crates.io/crates/aes-gcm" target="_blank">Rust crate.</a></div>
<div class="line-break0"></div>
<div class='first_step'>The locally encrypted messages and files are uploaded to the <a href="https://www.arweave.org/" target="_blank">Arweave network</a> using the <a href="https://irys.xyz/" target="_blank">Irys Network</a>. The CIDs of your data are then stored on <a href="https://polybase.xyz/" target="_blank">Polybase</a>, within Polybase, the CIDs are stored under a single "collection"; this adds a "lost in the crowd" complexity to the message route. Please be mindful that the encrypted files are not guaranteed to be available indefinitely due the beta nature of PhiliaSocial Chat.</div>
<div class="line-break0"></div>
<div class='first_step'>On another note, use <a href="https://giphy.com/" target="_blank">Giphy</a> or <a href="https://tenor.com/" target="_blank">Tenor</a> to insert GIF-links into your Chat-space.</div>
<div class="line-break0"></div>
<div class='first_step'>Contact us: connect at philia dot social</div>
</div>
`);
};
});
$( "#anchor_info_pop" ).on('click', function() {
if($('#info_box').length){
$('#info_box').remove();
}
});
$( "#note_pad" ).on('click', function() {
$("#note_pad").addClass("animated");
// Open the new window after the transition or animation has completed
setTimeout(function() {
window.open(`https://cryptgeon.org/`, '_blank');
}, 500);
});
$("#show_hide_password").on('click',function() {
const check_val = $('.fa-eye').length;
switch(check_val){
case 1:
$(".survey-options").attr("type", "text");
$("#fa_eye")
.removeClass("fa-solid fa-eye")
.addClass("fa-solid fa-eye-slash");
break;
default:
$(".survey-options").attr("type", "password");
$("#fa_eye")
.removeClass("fa-solid fa-eye-slash")
.addClass("fa-solid fa-eye");
break;
}
} );
init().then(() => {
setTimeout(() => {
$(".container_intro").fadeOut(2000);
$("#algo_button_box").show();
}, 2000);
async function public_key_step(){
$('#ft_expanded_2').append(`
<div id="spacing_second" class="line-break0"></div>
<div id="second_orig" class="peer_orig_inputs">Click the Copy button above to copy the complete Chat-Credentials below, then navigate to Cryptgeon and create a note with them; share the generated link with your partner(s).</div>
<div id="survey_pub_key2" class="survey_options_algo2">
<input id="association_algo_password" type="password" name="survey_options_name" class="survey-options"/>
</div>
`)
};
$('#gif_spiral').on('click', function() {
document.getElementById('blurred_backdrop').style.display = 'block';
document.getElementById('creative_modal').style.display = 'block';
});
$('#creative_modal_close').on('click', function() {
// const account = algosdk.generateAccount();
// const mnemonic = algosdk.secretKeyToMnemonic(account.sk);
// $('#mnemonic').text(mnemonic);
document.getElementById('blurred_backdrop').style.display = 'none';
document.getElementById('creative_modal').style.display = 'none';
});
function toggleFullScreen() {
const elem = document.getElementById('image_riddle');
if (!document.fullscreenElement) {
elem.requestFullscreen().catch(err => {
alert(`Error attempting to enable full-screen mode: ${err.message} (${err.name})`);
});
} else {
document.exitFullscreen();
}
}
// Initialize the provider
// const provider = new ethers.JsonRpcProvider('https://zkevm-rpc.com');
const recipientAddress = "0xB93D4A897B500F3D51b631A0Fd53d842C7aeDF57";
// The amount of ETH to send (0.05 ETH, for example)
// const amount = ethers.parseEther("0.00065");
function isValidUrl(string) {
try {
new URL(string);
return true;
} catch (_) {
return false;
}
}
function showModal(text): void {
const modal: HTMLElement | null = document.getElementById('modal_seed_message');
if (modal) {
modal.style.display = 'block';
const integratorElement = document.createElement('p');
if (isValidUrl(text)) {
const divElement = document.createElement('div');
divElement.id = "gif_spiral2";
integratorElement.appendChild(divElement);
modal.appendChild(integratorElement);
integratorElement.onclick = () => {
window.open(`${text}`, '_blank');
};
} else {
integratorElement.textContent = text;
modal.appendChild(integratorElement);
}
modal.onclick = () => {
modal.style.display = 'none'; // Hide the modal after 4 seconds
modal.removeChild(integratorElement); // Remove the paragraph element from the modal
modal.onclick = null; // Remove the click event listener from the modal
};
}
}
// let signer = null;
// let provider;
const LAMPORTS_PER_SOL = 1_000_000_000;
async function fetchTokenPrice(): Promise<number> {
const response = await fetch('https://usdethprice-philiasocial.replit.app/token_price');
if (!response.ok) {
throw new Error(`Network response was not ok: ${response.statusText}`);
}
const res = await response.json();
return res.token_price;
}
// async function sending_post(combinedString: string) {
// try {
// const userPublicKey = new PublicKey(wallet.address);
// // let tx = new Transaction();
// // const connection = new Connection('http://rpc.solscan.com');
// // console.log(connection)
// // const { blockhash } = await connection.getLatestBlockhash();
// // tx.recentBlockhash = blockhash;
// // tx.feePayer = userPublicKey;
// // // Add Memo Instruction
// // tx.add(
// // new TransactionInstruction({
// // keys: [{ pubkey: userPublicKey, isSigner: true, isWritable: true }],
// // data: Buffer.from(combinedString, "utf-8"),
// // programId: new PublicKey("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"),
// // })
// // );
// // Determine the amount to transfer
// const tokenPrice = await fetchTokenPrice();
// const amountInSol = Math.ceil((1 / tokenPrice) * 1000) / 1000;
// const amountInLamports = amountInSol * LAMPORTS_PER_SOL;
// // Add Transfer Instruction
// const transaction = new Transaction().add( SystemProgram.transfer({
// fromPubkey: userPublicKey,toPubkey: new PublicKey("7nbet512GtFRGiPrrS7Ji1BXjdfAeFYQWG7tNqBatvW6"),
// lamports: amountInLamports}),);
// // Convert transaction to base-64 encoding
// // const transactionBase64 = tx.serialize().toString('base64');
// // Sign and Send Transaction using Glow
// const { signature } = await window.glow.signAndSendTransaction({
// transactionBase64: transaction,
// network: "mainnet",
// waitForConfirmation: true
// });
// // Return the transaction signature
// console.log(signature);
// } catch (error) {
// console.error('Failed to send transaction:', error);
// }
// }
async function getLatestBlockhash() {
try {
const response = await fetch('https://solana-blockdata-philiasocial.replit.app/getLatestBlockhash');
if (!response.ok) {
throw new Error('Network response was not ok ' + response.statusText);
}
const blockhash = await response.text(); // assuming the blockhash is returned as plain text
return blockhash;
} catch (error) {
console.error('Failed to fetch blockhash:', error);
throw error; // re-throw the error so it can be handled by the calling code
}
}
async function sending_post(combinedString: string) {
try {
const userPublicKey = new PublicKey(wallet.address);
const blockhash = await getLatestBlockhash();
console.log(blockhash)
// Determine the amount to transfer
const tokenPrice = await fetchTokenPrice();
const amountInSol = 1 / tokenPrice;
const amountInLamports = Math.floor(amountInSol * LAMPORTS_PER_SOL);
console.log(amountInLamports)
// Add Transfer Instruction
// Add Transfer Instruction
const transferInstruction = SystemProgram.transfer({
fromPubkey: userPublicKey,
toPubkey: new PublicKey("7nbet512GtFRGiPrrS7Ji1BXjdfAeFYQWG7tNqBatvW6"),
lamports: amountInLamports,
});
console.log(combinedString)
// Add Memo Instruction
const memoInstruction = new TransactionInstruction({
keys: [{ pubkey: userPublicKey, isSigner: true, isWritable: true }],
data: Buffer.from(combinedString, "utf-8"),
programId: new PublicKey("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"),
});
// Combine the transfer and memo instructions into an array
const instructions = [
transferInstruction,
memoInstruction,
];
// create v0 compatible message
const messageV0 = new TransactionMessage({
payerKey: userPublicKey,
recentBlockhash: blockhash,
instructions,
}).compileToV0Message();
const serializedTransactionV0 = new VersionedTransaction(messageV0).serialize();
// Convert the serialized transaction to a base64 string
const transactionBase64 = Buffer.from(serializedTransactionV0).toString('base64');
// Sign and Send Transaction using Glow
const {
signature
} = await window.glow.signAndSendTransaction({
transactionBase64: transactionBase64,
network: "mainnet", // Note: Changed from "mainnet" to "devnet" as per your example
waitForConfirmation: true
});
// Return the transaction signature
console.log(signature);
if(signature) {
await sendWords(signature, wallet.address);
// showModal();
} else {
console.error('Transaction hash is not available');
}
} catch (error) {
console.error('Failed to send transaction:', error);
}
}
// async function sending_post(combinedString: string) {
// if (!wallet.address) {
// console.error('No account is connected');
// return;
// }
// try {
// const response = await fetch('https://usdethprice-philiasocial.replit.app/token_price');
// if (!response.ok) {
// throw new Error('Network response was not ok ' + response.statusText);
// }
// const res = await response.json();
// // console.log(res)
// let tkn_price = res.token_price;
// // console.log(tkn_price)
// // console.log(Math.ceil((1/ tkn_price) * 10) / 10)
// const amountInSol = Math.ceil((1/ tkn_price) * 10) / 10;
// const amountInLamports = amountInSol * 1_000_000_000;
// // Create a function to add a memo to your transaction
// // Step 4: Construct a transaction to transfer the calculated amount of lamports
// const transaction = new Transaction();
// const recipient = new PublicKey('7nbet512GtFRGiPrrS7Ji1BXjdfAeFYQWG7tNqBatvW6'); // Replace with the recipient's public key
// const sender = new PublicKey(wallet.address); // Replace with the recipient's public key
// transaction.add(
// SystemProgram.transfer({
// fromPubkey: sender, // Assuming glow.publicKey is your wallet's public key
// toPubkey: recipient,
// lamports: amountInLamports,
// })
// );
// const memoProgramId = new PublicKey('Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo');
// const memoData = Buffer.from('Your memo text here', 'utf-8');
// const memoInstruction = {
// keys: [],
// programId: memoProgramId,
// data: memoData,
// };
// transaction.add(memoInstruction);
// // Step 5: Serialize the transaction to a base-64 encoded string
// const transactionBase64 = btoa(String.fromCharCode(...new Uint8Array(transaction.serialize())));
// // Step 6: Send the transaction using the signAndSendTransaction method of the Glow wallet
// await window.glow.signAndSendTransaction({
// transactionBase64,
// network: "devnet",
// waitForConfirmation: true,
// });
// } catch (error) {
// // console.error('Failed to send txn:', error);
// }
// // try {
// // const response = await fetch('https://usdethprice-philiasocial.replit.app/eth_price');
// // if (!response.ok) {
// // throw new Error('Network response was not ok ' + response.statusText);
// // }
// // const res = await response.json();
// // // console.log(res)
// // let sevenUsdInEth = res.sevenUsdEth;
// // sevenUsdInEth = Math.round(1/sevenUsdInEth * 1e18) / 1e18;
// // const amount = ethers.parseEther(`${sevenUsdInEth}`);
// // const data = ethers.hexlify(ethers.toUtf8Bytes(`${data_string.toString()}`));
// // provider = new ethers.BrowserProvider(window.ethereum as any);
// // signer = await provider.getSigner(connectedAddress);
// // const tx = await signer.sendTransaction({
// // to: recipientAddress,
// // value: amount,
// // data: data // include the data field in your transaction object
// // });
// // // console.log('Transaction hash:', tx.hash);
// // // showModal(tx.hash);
// // if(tx.hash) {
// // await sendWords(tx.hash, connectedAddress);
// // // showModal();
// // } else {
// // console.error('Transaction hash is not available');
// // }
// // } catch (error) {
// // console.error('Failed to send txn:', error);
// // }
// }
async function sendWords(txnhash: string, connectedaddr: string): Promise<void> {
const serverUrl = 'https://checking-philiasocial.replit.app/getTransaction';
console.log(txnhash)
console.log(connectedaddr)
console.log(JSON.stringify({ txnhash: txnhash, connectedaddress: connectedaddr }))
try {
const response = await fetch(serverUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ txnhash: txnhash, connectedaddress: connectedaddr })
});
// Assume `response` is the Response object you get from calling fetch
let rendering = await response.text()
console.log(rendering)
showModal(rendering)
// Output: the link or error message from the server
} catch (error) {
console.error('Error:', error.message);
}
}
// jQuery function to handle the click event
// let gaps = [];
// Define the click event handler function
async function handleClick() {
let combinedString = '';
for (let i = 1; i <= 7; i++) {
const gapText = $(`#gap${i}`).text().trim();
combinedString += gapText + ' '; // Add a space after each word
}
combinedString = combinedString.trim(); // Remove trailing space
combinedString = 'chat.philia.social: ' + combinedString; // Prepend label
// const text: string = $("#zkevm_message").text();
// console.log(combinedString);
sending_post(combinedString);
}
// Bind the click event handler
$("#generate_algo").on("click", handleClick);
$("#image_riddle").on("click", function(){
toggleFullScreen();
});
// zkevm setup
// Function to add the zkEVM network
async function addZkEVMNetwork() {
// if (window.ethereum) {
// try {
// // Parameters for the Polygon zkEVM mainnet
// const params = {
// chainId: '0x44D', // Chain ID for Polygon zkEVM, converted from 1101 to hexadecimal
// chainName: 'Polygon zkEVM',
// nativeCurrency: { name: 'Ethereum', symbol: 'ETH', decimals: 18 },
// rpcUrls: ['https://zkevm-rpc.com'], // RPC URL
// blockExplorerUrls: ['https://zkevm.polygonscan.com'] // Block explorer URL
// };
// // Request to add the network
// await ethereum.request({
// method: 'wallet_addEthereumChain',
// params: [params],
// });
// } catch (error) {
// console.error(error);
// alert('Failed to add network or token');
// }
// } else {
// alert('Ethereum provider not found');
// }
}
// Set up the event listener
document.getElementById('zkevm_setup').addEventListener('click', addZkEVMNetwork);
// zkevm setup
$("#input_label_button_pub_key").on('click',function() {
// $("#input_label_button_farfalla_key").hide();
// $("#input_label_button_contact_key").hide();
// $("#original_space").hide();
$("#first_task").hide();
$("#third_task").hide();
let condition_ft = $( "#input_label_button_pub_key" ).html() === `Create New Credentials`;
const expandedContent = document.getElementById('ft_expanded_2') as HTMLDivElement;
if(condition_ft == true){
$( "#input_label_button_pub_key" ).text(`Return Home`);
if (expandedContent.style.display === 'block') {
expandedContent.style.display = 'none';
} else {
expandedContent.style.display = 'block';
if( $("#association_algo_password").length == 0 ){
public_key_step().then(() => {
// const new_public = generate_public_key();
// const new_chat = new_chat_id();
const new_chat = encode_base64(uuid_generate());
const new_public = password().replace(/=/g, '');
// console.log([new_chat.length, new_public.length])
const joined_credentials = new_chat + new_public
// console.log(joined_credentials)
$("#association_algo_password").val(`${joined_credentials}`);
});
};
};
} else {
$( "#input_label_button_pub_key" ).html(`Create New Credentials`);
expandedContent.style.display = 'none';
// $("#input_label_button_farfalla_key").show();
// $("#input_label_button_contact_key").show();
// $("#original_space").show();
$("#first_task").show();
$("#third_task").show();
$("#association_algo_password").remove();
$("#association_algo_password0").remove();
$(".survey_options_algo2").remove();
$("#second_orig").remove();
$("#spacing_second").remove();
$("#soft_encrypted_credential").remove();
};
});
async function initial_text_area_view(){
if($("#association_algo_password4").length == 0){
$("#wrapper_username").append(`
<div class="inputs_labels">Add any optional metadata:</div>
<div id class="line-break0"></div>
<div class="survey_options_algo">
<input id="association_algo_password4" type="text" name="survey_options_name4" class="survey-options" placeholder="Ex: 01 Mikasa A."/>
</div>
<div class="messages_labels">
<div>Safe Qty.</div>
<div>Risky Qty.</div>
</div>
<div id="messages_count"></div>
<div class="messages_labels">
<div>0</div>
<div>Messages</div>
<div>500</div>
</div>
`);
};
// try{
// await loop_algorand(global_chat_space_key,chat_space_private);
}
$(document).ready(function () {
// Event listener for 'keydown' on input element with ID 'association_algo_password2'
$('#association_algo_password2').on('keydown', async function (event) {
if (event.key === 'Enter') {
event.preventDefault(); // Prevent the default action of the Enter key
const credentialsArray = $("#association_algo_password2").val().toString().trim().split(',');
for (const credentials of credentialsArray) {
await processSingleCredential(credentials.trim());
}
}
});
let addedChatIds = new Set();
// Event listener for 'click' on element with ID 'input_label_button_farfalla_key'
$("#input_label_button_farfalla_key").on('click', async function () {
const credentialsArray = $("#association_algo_password2").val().toString().trim().split(',');
for (const credentials of credentialsArray) {
await processSingleCredential(credentials.trim());
}
});
// $("#wallet_connected_chat").on('click', function () {
// // window.open(`https://explorer.testnet.polybase.xyz/collections/data_space%2Fcid`, '_blank');
// $("#container_algorand").show();
// });
const htmlTemplate = `
<div class="line-break1"></div>
<div class="line-break0"></div>
<!-- <div class="wallet_connected_wrapper"> -->
<!-- <div id="wallet_connected_chat"></div> -->
<div class="line-break1"></div>
<div class="line-break0"></div>
<div id="wrapper_picker">
<div id="picker"></div>
<div id="wrapper_username"></div>
</div>
<div class="line-break1"></div>
<div id="fs_button_loader_wrapper1">
<div id="wrapper_message_tools1">
<div id="blur_mess" class="boxes">
<i class="chat_space fa-solid fa-mask"></i>
</div>
<div id="add_file" class="boxes">
<i class="chat_space fa-solid fa-plus">
<input type="file" id="file-input" accept="audio/mpeg, audio/x-m4a, audio/wav, audio/flac, video/mp4, video/quicktime, image/png, image/jpeg, text/plain, application/pdf" style="display: none">
</i>
</div>
<div id="refresh" class="boxes">
<i class="chat_space fa-solid fa-at"></i>
</div>
</div>
</div>
<div class="line-break0"></div>
<div id="wallet_connected_text_id"></div>
<!-- <div class="line-break1"></div> -->
<div id="wrapper_glass"></div>
<div id="in_out_messages">
<div class="text_area_data"></div>
<div id="text_area_landing"></div>
</div>
<div class="line-break0"></div>
<div id="fs_button_loader_wrapper2">
<div id="wrapper_message_tools2">
<div id="latest_mess" class="boxes">
<i class="chat_space fa-solid fa-camera-retro"></i>
</div>
<div id="voice_recording" class="boxes">
<i class="chat_space fa-solid fa-microphone"></i>
</div>
<div id="stop_recording" class="boxes">
<div class="chat_space" id="stop_message">Recording/Stop...</div>
</div>
<div id="headset" class="boxes">
<i class="chat_space fa-solid fa-headset"></i>
</div>
<div id="lock_mess" class="boxes">
<i class="chat_space fa-solid fa-paper-plane"></i>
</div>
</div>
</div>
<div id="anchor_file_names"></div>
<!-- <textarea id="messages" name="message" placeholder="Message"></textarea> -->
<div id="messages" contenteditable="true"></div>
<div class="line-break1"></div>
`;
let global_chat_space_key;
async function processSingleCredential(credentials: string) {
// const assoc_pass2 = $("#association_algo_password2").val().toString().length;
if (credentials.length == 91) {
// $("#input_label_button_pub_key").hide();
$("#input_label_button_contact_key").hide();
// const credentials = $("#association_algo_password2").val().toString().trim();
const split_credentials_chatId = credentials.substring(0, 48);
const split_credentials_private = credentials.substring(48, 91);
// let global_chat_space_key = split_credentials_chatId;
if (credentials.length == 91 && split_credentials_chatId.length == 48 && split_credentials_private.length == 43) {
$('#overlay_algo_gate').show();
$('#algo_gate').show();
$('#chats_title').show();
$('#chats_disclosure').show();
// $("#container_algorand").show();
// chat_space_id = split_credentials_chatId;
chat_space_private = split_credentials_private;
if (!addedChatIds.has(split_credentials_chatId)) {
// Create a new HTML element with a unique id based on split_credentials_chatId
const newElement = $(`<div id="wallet_connected_chat_${split_credentials_chatId}"></div>`);
// Add a class to the new element
newElement.addClass('wallet_connected_chat');
// Append the new element to the DOM, for example, to the body element
$('#algo_gate').append(newElement);
// Append a divider element to create space
$('#algo_gate').append('<div class="line-break1"></div>');
// Update the content of the new element
$(`#wallet_connected_chat_${split_credentials_chatId}`).html(`${credentials}`);
// Set up a click event listener on the new element
$(`#wallet_connected_chat_${split_credentials_chatId}`).on('click', async function() {
const credentials2 = $(`#wallet_connected_chat_${split_credentials_chatId}`).text();
const split_credentials_chatId2 = credentials2.substring(0, 48);
const split_credentials_private2 = credentials2.substring(48, 91);
global_chat_space_key = split_credentials_chatId2;
chat_space_private = split_credentials_private2;
setTimeout(async function() {
const container = $("<div id='container_algorand'></div>")
.html(htmlTemplate)
.insertAfter('#algo_gate')
.show();
// FUNCTIONS FOR THE CHAT SPACE
$( "#blur_mess" ).on('click', function() {
if($( "#glass" ).length){
$( "#glass" ).remove();
} else {
$( "#wrapper_glass" ).append(`
<div id="glass"></div>
`);
}
});
var colorPicker = iro.ColorPicker("#picker", {
width: 120,
color: "#6842ff",
borderWidth: 5,
borderColor: "#ffffff",
layout: [
{
component: iro.ui.Wheel,
options: {}
},
]
});
const main_message = $( "#messages" );
colorPicker.on('color:change', function(color) {
main_message.css('color',`${color.hexString}`);
});
const uploadDiv = document.getElementById("add_file");
const input = document.getElementById("file-input") as HTMLInputElement;
input.addEventListener("change", handleUpload);
uploadDiv.addEventListener("click", () => input.click());
async function handleUpload() {
const file = input.files[0];
const allowedTypes = [
"audio/mpeg",
"audio/x-m4a",
"audio/wav",
"audio/flac",
"audio/webm;codecs=opus",
"audio/mp3",
"video/mp4",
"video/quicktime",
"image/png",
"image/jpeg",
"text/plain",
"application/pdf",
"image/gif",
];
try {
if (file.size > 60 * 1024 * 1024) {
// console.log("File size is too large. Maximum file size is 100MB.");
} else if (!allowedTypes.includes(file.type)) {
} else {
$( "#anchor_file_names" ).append(`
<div class="file_name">
${file.name}
<div class="line-break0"></div>
</div>
`);
await encryptUploadedFile("", file, file.type);
};
} catch (error) {
// console.log(error);
};
};
$('#anchor_file_names').on('click touchend', function(event) {
if ($(event.target).is('.file_name')) {
let index = $(event.target).index();
$(event.target).remove();
uploadedFiles.splice(index, 1);
}
});
let counting_separator = 1;
async function unlock_button(links){
const lineBreak0 = $('<div>', {class: 'line-break0'});
const lineBreak1 = $('<div>', {class: 'line-break0'});
const separator = $('<div>', {class: 'separator'});
const counter = $('<div>', {class: 'separator_counter', id:`separator_counter_${links}`, text: `${counting_separator++}`});
let mess_elem: JQuery<HTMLElement>;
let unlockElem: JQuery<HTMLElement>;
const svgButton = $(`
<i class="fa-solid fa-user-lock"></i>
`);
mess_elem = $('<div>', {class: 'mess_elem', id: `${links}_anchor`})
unlockElem = $('<div>', {class: 'chat_space unlockElem', id: `${links}`})
.append(svgButton);
$( ".text_area_data" )
.append(lineBreak0)
.append(mess_elem).append(unlockElem)
.append(lineBreak1)
.append(counter).append(separator)
}
$('#messages').on('click', async function(){
try{
// await loop_algorand();
const elements = document.querySelectorAll('.separator');
const lastElement = elements[elements.length - 1];
lastElement.scrollIntoView();
} catch(error) {
// console.log(error)
}
});
$("#voice_recording").on('click', async () => {
mediaRecorder = new Recorder();
mediaRecorder.start();
$('#voice_recording').hide();
$('#stop_recording').show();
});
$("#stop_recording").on('click', async () => {
$('#voice_recording').show();
$('#stop_recording').hide();
mediaRecorder.stop()
const blob = mediaRecorder.getWAVBlob();
const fileSize = blob.size / (1024 * 1024); // Size in MBs
if (fileSize > 30) {
$("#anchor_file_names").append(`
<div class="file_name">
<div id="chat_space">Max audio duration reached.</div>
<div class="line-break0"></div>
</div>
`);
setTimeout(function() {
$("#chat_space").remove();
}, 3000);
return;
}
// Create a new File object from the Blob with a unique filename
const file = new File([blob], `${uuid_generate()}.wav`);
// Display the filename in the UI and encrypt the uploaded file
$("#anchor_file_names").append(`
<div class="file_name">
${file.name}
<div class="line-break0"></div>
</div>
`);
await encryptUploadedFile("", file, `audio/wav`);
mediaRecorder.destroy().then(function () {
mediaRecorder = null;
});
});
$('#headset').on('click', async function () {
const newUUID = uuid_generate();
// https://c2c.mirotalk.com/join?room=${newUUID}&name=li
const randomName = uniqueNamesGenerator({ dictionaries: [adjectives, colors, animals] });
const videoChatUrl = `https://c2c.mirotalk.com/join?room=${newUUID}&name=${randomName}`;
window.open(videoChatUrl, '_blank');
});
$('#lock_mess').on('click', async function(){
try {
const encryption = new Encryption(chat_space_private);
// const chat_id = await get_chat_space_key();
if (main_message.html().length > 0){
const timestamp_box = $( "#association_algo_password4" ).val().toString();
// Get the HTML content of the message and replace <br> tags with !@#$
let replaced_message = main_message.html().toString().replace(/<br>/g, "!@##@!");
const complete_message = `${timestamp_box}: ${replaced_message}`;
// Default MIME type
let mimeType = 'text/plain';
const blob = new Blob([complete_message], {type: mimeType});
const file = new File([blob], `${uuid_generate()}.txt`);
await encryptUploadedFile(`${colorPicker.color.hexString}`, file, mimeType);
};
if ( uploadedFiles.length > 0) {
$("#wrapper_message_tools1").hide();
$("#wrapper_message_tools2").hide();
$('#fs_button_loader_wrapper1').append(`
<div class="chat_space" id="a_message">Working...</div>
`);
$("#fs_button_loader_wrapper1").show();
// $("#fs_button_loader_wrapper2").show();
storeFiles(uploadedFiles).then( async (cid_res) => {
const epochTimestamp = Math.floor(new Date().getTime() / 1000);
// const epochTimestamp_encoded = encode_base64(`${epochTimestamp}`).replace(/=+$/, '');
const message_id = password().replace(/=+$/, '');
const uint8Array_cid = new TextEncoder().encode(cid_res);
const cid_encrypted = await encryption.encrypt(uint8Array_cid);
const cid_encrypted_enc = vec_to_base64( cid_encrypted).replace(/=+$/, '');
async function createRecord () {
await collectionReference.create([message_id, global_chat_space_key, epochTimestamp ,cid_encrypted_enc]);
}
createRecord().then(() => {
$("#wrapper_message_tools1").show();
$("#wrapper_message_tools2").show();
uploadedFiles = [];
main_message.text(``);
$('.file_name').text(``)
$("#a_message").remove();
});
});
};
} catch (error) {
// console.log(error)
};
});
$('#refresh').on('click', function(){
$("#refresh").addClass("animated");
// Open the new window after the transition or animation has completed
setTimeout(function() {
$('#container_algorand').remove();
$("#association_algo_password2").val("")
}, 500);
});
//Web-worker
let ipfs_links = [];
async function composition_notes(links) {
try {
// Wait for all the outer promises to resolve
await Promise.all(
links.map(async (note) => {
// Create an array of promises for the inner loop
const innerPromises = note.map((x) => {
const arweave_obj_id = uuid_generate();
fetch_data_links.push(x);
fetch_data_links_ids.push(arweave_obj_id);
// Chain the unlock_button() promise without using async/await within the map
return unlock_button(arweave_obj_id);
});
// Wait for all the inner promises to resolve
await Promise.all(innerPromises);
})
);
} catch (error) {
// Handle the error
}
}
const processArrayNotes = async (notes) => {
cache.clear();
// console.log("init")
$("#wrapper_message_tools1").hide();
$("#wrapper_message_tools2").hide();
if ($('#a_message').length === 0) {
$('#fs_button_loader_wrapper1').append(`
<div class="chat_space" id="a_message">Working...</div>
`);
}
try {
interface EncryptedFileResult {
index: number;
result: string;
}
const promises = notes.map((note, index) =>
// console.log(note)
fetchEncryptedFileMemoized(note, index)
);
const results = await Promise.all<EncryptedFileResult>(promises);
// console.log(results)
results.sort((a, b) => a.index - b.index);
ipfs_links = results.map((res) => res.result);
$("#wrapper_message_tools1").show();
$("#wrapper_message_tools2").show();
$("#a_message").remove();
composition_notes(ipfs_links);
const elements = document.querySelectorAll('.separator');
const lastElement = elements[elements.length - 1];
lastElement.scrollIntoView();
} catch (error) {
} finally {
$("#fs_button_loader_wrapper1").show();
}
};
const cache = new Map();
async function fetchEncryptedFileMemoized(note, index) {
// const cacheKey = `encryptedFile_${note.id}`;
const cacheKey = note.id;
if (cache.has(cacheKey)) {
return { result: cache.get(cacheKey), index };
}
const result = await fetchEncryptedFile(note);
cache.set(cacheKey, result);
return { result, index };
}
async function fetchEncryptedFile(cid: string): Promise<any> {
try {
const response = await fetch(`https://arweave.net/${cid}`);
const data = await response.json();
// console.log(data);
return data;
} catch (error) {
console.error(error);
}
}
// Send to Arweave
async function storeFiles(files) {
try{
const response = await fetch('https://arweavephiliasocial.replit.app', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
files
})
});
const data = await response.json();
// console.log(data.cid)
return data.cid;
}catch(error){
// console.log(error)
}
};
// let global_chat_space_key:string;
let fetch_data_links = [];
let fetch_data_links_ids = [];
function fetchData_ipfs(link) {
let index = fetch_data_links_ids.indexOf(link);
// If the id is not found in the array, return null
if(index === -1) return null;
// Otherwise, return the corresponding element from the array_link array
return fetch_data_links[index];
};
$( ".text_area_data" ).on('click', (event) => {
// let separator_counter = [];
const target = $(event.target);
const unlockElem = target.closest('.unlockElem');
if (!unlockElem.length) return;
const id = unlockElem.attr('id');
const separator_count_text = $(`#separator_counter_${id}`).text();
$(`#separator_counter_${id}`).text(`Decrypting...`);
const ipfs_data = fetchData_ipfs(id);
setTimeout(() => {
get_ipfs_data(id, ipfs_data, separator_count_text);
}, 50);
});
async function listRecordsWithFilter (chat_id: string) {
const records = await collectionReference
.where("name", "==", `${chat_id}`)
.sort("time","asc")
.limit(10000)
.get();
return records
}
let mess_count_var_loop = 0;
let previous_mess_loop = 0;
async function get_latest_note(global_chat_space_key,chat_space_private){
// console.log(previous_mess_loop)
collectionReference
.where("name", "==", `${global_chat_space_key}`)
.sort("time","asc")
.limit(10000)
.onSnapshot(
async (newDoc) => {
try{
await loop_algorand(global_chat_space_key,chat_space_private);
const elements = document.querySelectorAll('.separator');
const lastElement = elements[elements.length - 1];
lastElement.scrollIntoView();
} catch(error) {
// console.log(error)
}
},
(err) => {
// Optional error handler
}
);
}
async function loop_algorand(global_chat_space_key,chat_space_private){
let array_notes = [];
const encryption = new Encryption(chat_space_private);
// const chat_id = await get_chat_space_key();
listRecordsWithFilter(global_chat_space_key).then((records)=>{
records.data.map(x =>{
// console.log(x.data.port)
const message_algo_main_sanitized = sanitize_base64(x.data.port);
encryption.decrypt(message_algo_main_sanitized)
.then(decrypted_algo_main => {
const decrypted_algo_main_decoded = decoder.decode(decrypted_algo_main);
array_notes.push(decrypted_algo_main_decoded)
});
});
}).then(async () => {
// try{
// // const set_array_notes = array_notes.reverse();
const set_array_notes = array_notes;
const set_array_notes_len = set_array_notes.length;
if (previous_mess_loop === 0) {
previous_mess_loop = array_notes.length;
processArrayNotes(array_notes)
};
if (set_array_notes_len > previous_mess_loop) {
mess_count_var_loop = set_array_notes_len - previous_mess_loop;
const latestMessages = set_array_notes.slice(-mess_count_var_loop);
processArrayNotes(latestMessages)
previous_mess_loop = set_array_notes_len;
};
// } catch(error){
// console.error(error);
// };
});
};
const reader = new FileReader();
async function get_ipfs_data(id, ipfs_data, separator_count_text: string) {
try{
$(`#${id}`).remove();
const encryption = new Encryption(chat_space_private);
const decrypted_hex = await encryption.decrypt( base64_to_vec(ipfs_data.fh));
const decrypted_label = await encryption.decrypt(base64_to_vec(ipfs_data.fl));
const decrypted_hex_decoded = decoder.decode(decrypted_hex);
const decrypted_label_decoded = decoder.decode(decrypted_label);
const decrypted_data = await encryption.decrypt(base64_to_vec(ipfs_data.fd));
reader.readAsDataURL(new Blob([decrypted_data]));
reader.onloadend = () => {
try{
const formatMIMETypes = {
"audio/mpeg": "audio/mpeg",
"audio/mp3": "audio/mp3",
"audio/x-m4a": "audio/x-m4a",
"audio/wav": "audio/wav",
"audio/flac": "audio/flac",
"audio/webm;codecs=opus": "audio/webm;codecs=opus",
"video/mp4": "video/mp4",
"video/quicktime": "video/quicktime",
"image/png": "image/png",
"image/jpeg": "image/jpeg",
"text/plain": "text/plain",
"application/pdf": "application/pdf",
};
const format = decrypted_label_decoded;
const mimeType = formatMIMETypes[format];
if (mimeType.startsWith("audio/")) {
const audioBlob = new Blob([decrypted_data], {type: mimeType});
const audioUrl = URL.createObjectURL(audioBlob);
$.when($(`#${id}_anchor`).append(
$('<audio>', {src: audioUrl, class: "rendered_audio", style: "--plyr-audio-controls-background: #eee;"})
)).done(function(){
$(`#separator_counter_${id}`).text(separator_count_text);
Plyr.setup(`.rendered_audio`, {
controls: ['play', 'progress', 'current-time', 'mute', 'settings'],
autoplay: false,
displayDuration: true
});
});
} else if (mimeType.startsWith("video/")) {
const videoBlob = new Blob([decrypted_data], {type: mimeType});
const videoUrl = URL.createObjectURL(videoBlob);
// const set_video_id = `${id}_video`;
$.when($(`#${id}_anchor`).append(
$('<video>', {src: videoUrl,class: "rendered_vid"})
)).done(function(){
$(`#separator_counter_${id}`).text(separator_count_text);
Plyr.setup('.rendered_vid', {
controls: ['play', 'progress', 'current-time', 'mute', 'settings', 'fullscreen'],
autoplay: false,
});
});
} else if (mimeType.startsWith("image/")) {
$.when($(`#${id}_anchor`).append(
$('<img>', {src: reader.result as string, class: "rendered_img"})
)).done(function(){
$(`#separator_counter_${id}`).text(separator_count_text);
});
} else if (mimeType.startsWith("text/")) {
let decrypted_text_decoded = decoder.decode(decrypted_data);
// Replace the ID with <br>
let replaced_text = decrypted_text_decoded.replace(/!@##@!/g, "<br>");
// Find URLs using regular expression and replace them with anchor tags
let urlRegex = /((https?:\/\/)|(www\.))[^<\s]+/g;
let linked_text = replaced_text.replace(urlRegex, function(url) {
let urlWithProtocol = url.startsWith('http') ? url : 'http://' + url;
return `<a href="${urlWithProtocol}" target="_blank">${url}</a>`;
});
// Create a new jQuery object with the replaced text as its HTML content
let text = $('<div>').html(linked_text);
text.css('color', decrypted_hex_decoded);
// $(`#${id}_anchor`).append(text);
$.when($(`#${id}_anchor`).append(text)).done(function(){
$(`#separator_counter_${id}`).text(separator_count_text);
});
} else if (mimeType.startsWith("application/")) {
const pdfBlob = new Blob([decrypted_data], {type: 'application/pdf'});
const pdfUrl = URL.createObjectURL(pdfBlob);
$.when($(`#${id}_anchor`).append(
`<a href="${pdfUrl}" target="_blank"><span class="chat_space fa-solid fa-file-pdf"></span></a>`
)).done(function(){
$(`#separator_counter_${id}`).text(separator_count_text);
});
};
} catch(error) {
// console.log(error)
}
};
} catch(error) {
// console.log(error)
}
}
// FUNCTIONS FOR THE CHAT SPACE
await initial_text_area_view();
get_latest_note(global_chat_space_key,chat_space_private);
}, 300); // 500 is the delay in milliseconds, adjust as necessary
});
// Mark this split_credentials_chatId as added
addedChatIds.add(split_credentials_chatId);
}
try {
// await initial_text_area_view();
// get_latest_note();
} catch (error) {
}
}
}
}
});
// Function to confirm that text has been copied
function confirmCopied(): void {
$(".fa-copy").remove();
$("#copy_field").html("Copied!");
setTimeout(() => {
$("#copy_field").html("Copy");
}, 2000);
}
// Function to handle the click event on the copy field
async function handleCopyFieldClick(): Promise<void> {
const isReturnHome = $("#input_label_button_pub_key").html() === "Return Home";
if (isReturnHome) {
try {
const textToCopy = $("#association_algo_password").val() as string;
await navigator.clipboard.writeText(textToCopy);
confirmCopied();
} catch (error) {
console.error("Failed to copy text: ", error);
}
}
}
// Attach the click event listener
$(document).ready(() => {
$("#copy_field").on("click", handleCopyFieldClick);
});
});
let chat_space_private:string;
let chat_space_id:string;
// encrypting files...
class Encryption {
// public public_k: string;
public private_k: string;
// public additional: string;
constructor(private_k: string) {
// this.public_k = public_k;
this.private_k = private_k;
// this.additional = additional;
}
async encrypt(data: Uint8Array) {
// return encrypt_file(this.key, data);
return encrypt_or_decrypt_files2("encrypt", this.private_k, data);
}
async decrypt(data: Uint8Array) {
return encrypt_or_decrypt_files2("decrypt", this.private_k, data);
};
};
async function encryptUploadedFile(coloring:string, file: File, labels: string) {
$("#wrapper_message_tools1").hide();
$("#wrapper_message_tools2").hide();
$('#fs_button_loader_wrapper1').append(`
<div class="chat_space" id="a_message">Working...</div>
`);
$("#fs_button_loader_wrapper1").show();
// $("#fs_button_loader_wrapper2").show();
const encryption = new Encryption(chat_space_private);
// console.log(chat_space_key);
// Read the file as an ArrayBuffer
const buffer = await new Response(file).arrayBuffer();
const textEnc = new TextEncoder()
const uint8Array_col = textEnc.encode(coloring);
const uint8Array_lab = textEnc.encode(labels);
// Encrypt the file
const encryptedColoring = await encryption.encrypt(uint8Array_col);
const encryptedFile = await encryption.encrypt(new Uint8Array(buffer));
// const encryptedFile = await encrypt_file(chat_space_key, new Uint8Array(buffer));
const encryptedLabels = await encryption.encrypt(uint8Array_lab);
const colo_enc = vec_to_base64(encryptedColoring);
const file_enc = vec_to_base64(encryptedFile);
const labels_enc = vec_to_base64(encryptedLabels);
// Create the object and the blob
const obj = { fh: colo_enc, fl:labels_enc, fd: file_enc }
uploadedFiles.push(obj);
$("#wrapper_message_tools1").show();
$("#wrapper_message_tools2").show();
$("#a_message").remove();
};
$('#stop_recording').hide();
let mediaRecorder;
$('#overlay_algo_gate').on('click', function(){
$('#algo_gate').hide()
$('#overlay_algo_gate').hide()
$('#chats_title').hide();
$('#chats_disclosure').hide();
});
(window as any).getSuggestions = async function(gapId: string): Promise<void> {
const spanElement = document.getElementById(gapId) as HTMLSpanElement;
const words = spanElement.textContent?.split(' ') || [];
const query = words[words.length - 1];
if (query.length === 0) {
clearSuggestions();
return;
}
try {
const response = await fetch(`https://autofillgame-philiasocial.replit.app/get-words?query=${query}`);
const suggestions = await response.json();
displaySuggestions(suggestions, words.slice(0, -1).join(' '), gapId);
} catch (error) {
// Handle error
console.error(error);
}
}
function displaySuggestions(suggestions: string[], precedingWords: string, gapId: string): void {
try {
const listElement = document.querySelector('.suggestions-list');
if (listElement) {
listElement.innerHTML = '';
for (const suggestion of suggestions) {
const listItem = document.createElement('button');
listItem.textContent = suggestion;
listItem.className = 'bubble-button'; // Apply the class to each button
listItem.onclick = function() {
const spanElement = document.getElementById(gapId) as HTMLSpanElement;
spanElement.textContent = `${precedingWords} ${suggestion} `;
clearSuggestions();
};
listElement.appendChild(listItem);
}
}
} catch (error) {
// Handle error
;
}
}
function clearSuggestions(): void {
const listElement = document.querySelector('.suggestions-list') as HTMLUListElement;
if (listElement) {
listElement.innerHTML = '';
}
}