diff --git a/assets/css/forum-styles.css b/assets/css/forum-styles.css index bbd7c50..0be7fbc 100644 --- a/assets/css/forum-styles.css +++ b/assets/css/forum-styles.css @@ -584,7 +584,7 @@ body { border-radius: 5px; padding: 20px; margin: 20px auto; /* center horizontally */ - max-width: 600px; /* limit width */ + /* max-width: 600px; */ color: #ddd; /* text color */ text-align: center; align-items: center; @@ -596,7 +596,7 @@ body { background-color:#000000; width: 90%; font-size: 1.8rem; - color: #4d0000; + color: #fff3f3; text-align: center; align-items: center; /* you could style the list items or bullet if you like */ @@ -616,7 +616,17 @@ body { background-color: #14161a; border: 1px solid #8caeb0; border-radius: 4px; - color: #5c0101; + color: #f19c9c; +} + +.invite-form input.invite-input { + padding: 1rem; + font-size: 2rem; + line-height: 2; + background-color: #14161a; + border: 1px solid #8caeb0; + border-radius: 4px; + color: #dddddd; } .publish-card-button { @@ -707,6 +717,43 @@ body { background-color: #281e1e; } +.approve-invite-list-button { + background-color: rgba(32, 88, 34, 0.554); + color: #fff; + border: none; + border-radius: 1vw; + padding: 1vh,2vh; + cursor: pointer; + font-size: 1.1rem; + transition: background-color 0.2s ease; +} + +.approve-invite-list-button:hover { + background-color: rgba(34, 186, 47, 0.84); /* a darker variant */ +} + +.invite-approvals strong { + display: inline-block; +} + +.invite-item { + margin-bottom: 0.5em; + background-color: rgba(31, 31, 31, 0.595); + border: 1px solid #444; + border-radius: 6px; + color: #ccc; + padding: 1rem; +} + +/* Top row: use flex for horizontal arrangement */ +.invite-top-row { + display: flex; + background-color:#173c52ae; + flex-wrap: wrap; + gap: 1rem; + align-items: center; + justify-content: center; +} /* Responsive Design */ @media (max-width: 768px) { diff --git a/assets/js/AdminTools.js b/assets/js/AdminTools.js index f1c296d..b2d62df 100644 --- a/assets/js/AdminTools.js +++ b/assets/js/AdminTools.js @@ -33,7 +33,7 @@ const loadMinterAdminToolsPage = async () => {
+ + + @@ -63,10 +87,10 @@ const loadMinterAdminToolsPage = async () => { document.body.appendChild(mainContent) - addToolsPageEventListeners() + await addToolsPageEventListeners() } -function addToolsPageEventListeners() { +const addToolsPageEventListeners= async () => { document.getElementById("toggle-blocklist-button").addEventListener("click", async () => { const container = document.getElementById("blocklist-container") // toggle show/hide @@ -116,6 +140,32 @@ function addToolsPageEventListeners() { alert(`"${nameToRemove}" removed from the block list (if it was present).`) }) + document.getElementById("invite-user-button").addEventListener("click", async () => { + const inviteInput = document.getElementById("invite-input") + const nameOrAddress = inviteInput.value.trim() + if (!nameOrAddress) return + + try { + // We'll call some function handleManualInvite(nameOrAddress) + await handleManualInvite(nameOrAddress) + inviteInput.value = "" + + } catch (err) { + console.error("Error inviting user:", err) + alert("Failed to invite user.") + } + }) + + document.getElementById("create-group-invite").addEventListener("click", async () => { + const inviteContainer = document.getElementById("invite-container") + // Toggle display + inviteContainer.style.display = (inviteContainer.style.display === "none" ? "flex" : "none") + // If showing, load the pending invites + if (inviteContainer.style.display === "flex") { + const pendingInvites = await fetchPendingInvites() + await displayPendingInviteDetails(pendingInvites) + } + }) } const displayBlockList = (blockedNames) => { @@ -131,4 +181,139 @@ const displayBlockList = (blockedNames) => { ` } +const fetchPendingInvites = async () => { + try { + const { finalInviteTxs, pendingInviteTxs } = await fetchAllInviteTransactions() + return pendingInviteTxs + } catch (err) { + console.error("Error fetching pending invites:", err) + return [] + } +} + +const handleManualInvite = async (nameOrAddress) => { + const addressInfo = await getAddressInfo(nameOrAddress) + let address = addressInfo.address + if (addressInfo && address) { + console.log(`address is ${address}`) + } else { + // it might be a Qortal name => getNameInfo + const nameData = await getNameInfo(nameOrAddress) + if (!nameData || !nameData.owner) { + throw new Error(`Cannot find valid address for ${nameOrAddress}`) + } + address = nameData.owner + } + + const adminPublicKey = await getPublicKeyByName(userState.accountName) + const timeToLive = 864000 // e.g. 10 days in seconds + const fee = 0.01 + let txGroupId = 694 + + // build the raw invite transaction + const rawInviteTransaction = await createGroupInviteTransaction( + address, + adminPublicKey, + 694, + address, + timeToLive, + txGroupId, + fee + ) + + // sign + const signedTransaction = await qortalRequest({ + action: "SIGN_TRANSACTION", + unsignedBytes: rawInviteTransaction + }) + if (!signedTransaction) { + throw new Error("SIGN_TRANSACTION returned null. Possibly user canceled or an older UI?") + } + + // process + const processResponse = await processTransaction(signedTransaction) + if (!processResponse) { + throw new Error("Failed to process transaction. Possibly canceled or error from Qortal Core.") + } + + alert(`Invite transaction submitted for ${nameOrAddress}. Wait for confirmation.`) +} + + +const displayPendingInviteDetails = async (pendingInvites) => { + const invitesContainer = document.getElementById('pending-invites-display') + if (!pendingInvites || pendingInvites.length === 0) { + invitesContainer.innerHTML = "No pending invites found.
" + return + } + + let html = `No Approvals Found
" + + html += ` +${inviteTx.signature.slice(0, 8)}...
+ Invitee:${inviteeName}
+ Date:${dateStr}
+ CreatorName:${creatorName}
+ Total Approvals:${approvalCount}
+ +