document.addEventListener("DOMContentLoaded", function () { const loginLink = document.getElementById('login-link'); // Login button container const userInfoDiv = document.getElementById('user-info'); // User info container (after login) const logoutButton = document.getElementById('logout-button'); // Logout button const userNameDisplay = document.getElementById('user-name'); // Where to display the username const userButton = document.getElementById('user-button'); // User initials button const token = localStorage.getItem('authToken'); // Get token from localStorage const menuButton = document.querySelector(".menu-button"); // const sidebar = document.querySelector(".sidebar"); const overlay = document.querySelector(".overlay"); const content = document.querySelector("#content"); // Main content area // const nextChapterButton = document.getElementById("nextChapterButton"); const loadingContainer = document.getElementById('loading-container'); // Loading container const loadingBar = document.getElementById('loading-bar'); // Loading bar const loadingText = document.getElementById('loading-text'); // Loading text // Show loading bar when the page starts loadingContainer.style.display = 'flex'; // Fetch and initialize data from MongoDB fetch('https://thevera-botveradb.hf.space/get_chapter_titles') // fetch('https://thevera-botveradb.hf.space/get_chapters') .then(response => response.json()) .then(responseData => { if (responseData.success) { initializePage(responseData.data); } else { console.error('Error loading data:', responseData.message); } // Hide the loading bar after data is loaded loadingContainer.style.display = 'none'; }) .catch(error => { console.error('Error loading data:', error); // Hide the loading bar in case of error loadingContainer.style.display = 'none'; }); if (token) { // Check token validity with backend fetch('https://thevera-botveradb.hf.space/validate_token', { method: 'GET', headers: { 'Authorization': `Bearer ${token}` } }) .then(response => response.json()) .then(data => { if (data.message === "Token is valid!") { // Token is valid, decode it to get user info const userObject = jwt_decode(token); // Decode the token to get user info const email = userObject.email; // Assuming the email is stored in the token const username = email.split('@')[0]; // Extract username (first part of email) // Update UI with user's info userNameDisplay.innerText = username; // Display first part of email as username userInfoDiv.style.display = 'block'; // Show user info section // Change user button to show user's initials const userInitials = username.charAt(0).toUpperCase(); // Get first letter of username userButton.innerHTML = `
${userInitials}
`; // Display initials // Show the logout button and hide the login link logoutButton.style.display = 'inline'; loginLink.style.display = 'none'; } else { // Token is invalid, clear invalid token localStorage.removeItem('authToken'); console.log('Invalid token, user not logged in.'); loginLink.style.display = 'inline'; // Show login link } }) .catch(error => { console.error('Error:', error); // Handle the error (e.g., network issues) localStorage.removeItem('authToken'); // Clear token in case of error loginLink.style.display = 'inline'; // Show login link }); } else { // No token found, show login link console.log('No token found, user not logged in.'); loginLink.style.display = 'inline'; } // Logout functionality if (logoutButton) { logoutButton.onclick = function() { localStorage.removeItem('authToken'); // Clear token window.location.reload(); // Refresh page to update UI }; } // Optional: If you want to show the dropdown when clicking on the user initials button if (userButton) { userButton.addEventListener('click', () => { const userDropdown = document.getElementById('user-dropdown'); userDropdown.style.display = userDropdown.style.display === 'block' ? 'none' : 'block'; }); } console.log("DOM loaded: Checking for nextChapterButton"); // Ensure the button exists before attaching the event listener if (nextChapterButton) { nextChapterButton.addEventListener("click", function () { console.log("Next Chapter button clicked"); loadNextChapter(); }); } else { console.error("nextChapterButton not found in the DOM."); } // Sidebar toggle for mobile and desktop menuButton.addEventListener("click", function () { if (sidebar && overlay && content) { sidebar.classList.toggle("shown"); overlay.classList.toggle("active"); // Adjust content margin when sidebar is visible if (sidebar.classList.contains("shown")) { content.style.marginLeft = "250px"; // Sidebar width } else { content.style.marginLeft = "0"; } } }); // Close sidebar on overlay click for mobile view overlay.addEventListener("click", function () { if (sidebar && overlay && content) { sidebar.classList.remove("shown"); overlay.classList.remove("active"); content.style.marginLeft = "0"; // Reset content margin } }); }); // Handle toggle for "Shastra Collection" header document.getElementById('shastraHeader').addEventListener('click', function() { const shastraList = document.getElementById('shastraList'); shastraList.classList.toggle('hidden'); // Toggle the 'hidden' class on the sidebar }); // Handle auto-click when any content inside the list is clicked // document.getElementById('shastraList').addEventListener('click', function () { // document.getElementById('shastraHeader').click(); // Simulate a click on the header // }); let chaptersArray = []; let currentChapterIndex = -1; // Initialize with -1 as default to indicate no chapter is loaded yet function initializePage(data) { const shastraList = document.getElementById('shastraList'); if (!shastraList) { console.error("Element with ID 'shastraList' not found."); return; } Object.keys(data).forEach((collection) => { const mainGroupItem = document.createElement('li'); mainGroupItem.textContent = collection; mainGroupItem.classList.add('main-group'); const itemList = document.createElement('ul'); itemList.classList.add('nested-list'); itemList.style.display = 'none'; data[collection].forEach((item) => { if (item.skandaTitle) { const skandaGroup = document.createElement('li'); skandaGroup.textContent = item.skandaTitle; skandaGroup.classList.add('skanda-group'); const skandaChapterList = document.createElement('ul'); skandaChapterList.classList.add('nested-list'); skandaChapterList.style.display = 'none'; item.chapters.forEach((chapter) => { const chapterItem = document.createElement('li'); chapterItem.textContent = chapter.chapterTitle; chapterItem.classList.add('chapter-item'); chapterItem.addEventListener('click', (event) => { event.stopPropagation(); fetchChapterData(chapter.chapterTitle).then(chapterDetails => { if (chapterDetails) { loadChapter(chapterDetails); closeSidebarOnMobile(); } }); }); skandaChapterList.appendChild(chapterItem); // Populate chaptersArray with chapter metadata (title only for now) chaptersArray.push({ chapterTitle: chapter.chapterTitle }); }); skandaGroup.addEventListener('click', (event) => { event.stopPropagation(); skandaChapterList.style.display = skandaChapterList.style.display === 'none' ? 'block' : 'none'; }); skandaGroup.appendChild(skandaChapterList); itemList.appendChild(skandaGroup); } else { const chapterItem = document.createElement('li'); chapterItem.textContent = item.chapterTitle; chapterItem.classList.add('chapter-item'); chapterItem.addEventListener('click', (event) => { event.stopPropagation(); fetchChapterData(item.chapterTitle).then(chapterDetails => { if (chapterDetails) { loadChapter(chapterDetails); closeSidebarOnMobile(); } }); }); itemList.appendChild(chapterItem); // Populate chaptersArray with chapter metadata (title only for now) chaptersArray.push({ chapterTitle: item.chapterTitle }); } }); mainGroupItem.addEventListener('click', () => { itemList.style.display = itemList.style.display === 'none' ? 'block' : 'none'; }); mainGroupItem.appendChild(itemList); shastraList.appendChild(mainGroupItem); }); } async function fetchChapterData(chapterTitle) { try { const response = await fetch(`https://thevera-botveradb.hf.space/get_chapter_details?chapterTitle=${encodeURIComponent(chapterTitle)}`); const result = await response.json(); if (response.ok && result.success) { return result.data; // Return chapter details } else { console.error("Error fetching chapter details:", result.message); return null; } } catch (error) { console.error("Error in fetchChapterData:", error); return null; } } // Function to fetch audio URL async function fetchAudioUrl(chapterTitle) { try { const response = await fetch(`https://thevera-botveradb.hf.space/get_audio_url?chapterTitle=${encodeURIComponent(chapterTitle)}`); const result = await response.json(); if (response.ok && result.success) { return result.audioUrl; } else { console.error('Error fetching audio:', result.message); return null; } } catch (error) { console.error('Error fetching audio:', error); return null; } } async function loadChapter(chapter) { console.log("Loading chapter..."); const chapterTitle = document.getElementById('chapterTitle'); const slokeContent = document.getElementById('slokeContent'); const videoPlayer = document.getElementById('videoPlayer'); const transcriptBlock = document.getElementById('transcript'); // Ensure the elements are loaded correctly if (!chapterTitle || !slokeContent || !videoPlayer || !transcriptBlock) { console.error("Missing elements in chapter display."); return; } // Reset content chapterTitle.textContent = 'Loading...'; // Temporary loading message slokeContent.innerHTML = ''; videoPlayer.src = ''; transcriptBlock.innerHTML = ''; // Clear all transcript content try { // Fetch chapter details from the backend const chapterDetails = await fetchChapterData(chapter.chapterTitle); if (!chapterDetails) { chapterTitle.textContent = 'Chapter details not found.'; return; } // Update UI with chapter details chapterTitle.textContent = chapterDetails.about || chapterDetails.chapterTitle || 'Chapter Details'; // Process and display the slokes const slokesArray = chapterDetails.slokes ? chapterDetails.slokes.split('\n') : []; slokesArray.forEach((slokeText) => { const slokeElement = document.createElement('p'); slokeElement.classList.add('sloke-text'); slokeElement.innerHTML = slokeText.replace(/श्लोक \d+:/g, '$&'); const speakIcon = createSpeakIcon(slokeText); slokeElement.appendChild(speakIcon); slokeContent.appendChild(slokeElement); }); // Update video and transcript blocks videoPlayer.src = chapterDetails.video || ''; const transcriptArray = chapterDetails.transcript ? chapterDetails.transcript.split('\n') : []; transcriptArray.forEach((transcriptText) => { const transcriptElement = document.createElement('p'); transcriptElement.classList.add('transcript-text'); transcriptElement.textContent = transcriptText; // Add transcript text transcriptBlock.appendChild(transcriptElement); }); // Show the content blocks document.querySelector('.main').classList.add('active'); document.querySelector('.sloke-block').classList.add('active'); document.querySelector('.video-block').classList.add('active'); document.querySelector('.transcript-block').classList.add('active'); // Setup play buttons setupPlayAllButton(slokesArray); setupPlayAllTranscriptButton(transcriptArray); // Auto-click to minimize the sidebar group const chapterGroup = document.querySelector(`.main-group`); if (chapterGroup) { chapterGroup.click(); // This simulates a click to collapse the group } // Update currentChapterIndex for "Next Chapter" functionality currentChapterIndex = chaptersArray.findIndex(ch => ch.chapterTitle === chapter.chapterTitle); console.log("Updated Current Index:", currentChapterIndex); document.getElementById('shastraHeader').click(); // Simulate a click on the header } catch (error) { console.error("Error loading chapter details:", error); chapterTitle.textContent = 'Failed to load chapter details. Please try again.'; } } function loadNextChapter() { console.log("Next Chapter clicked..."); if (currentChapterIndex + 1 < chaptersArray.length) { currentChapterIndex++; // Increment currentChapterIndex to move to the next chapter // Auto-click to minimize the sidebar group const chapterGroup = document.querySelector(`.main-group`); if (chapterGroup) { chapterGroup.click(); // This simulates a click to collapse the group } loadChapter(chaptersArray[currentChapterIndex]); } else { alert("This is the last chapter."); } } function closeSidebarOnMobile() { const sidebar = document.querySelector(".sidebar"); const overlay = document.querySelector(".overlay"); if (window.innerWidth < 768 && sidebar && overlay) { sidebar.classList.remove("shown"); overlay.classList.remove("active"); } } // Other functions such as createSpeakIcon, cleanSlokText, playTTS, and setupPlayAllButton remain as you provided. function createSpeakIcon(slokeText) { const speakIcon = document.createElement('i'); speakIcon.classList.add('fas', 'fa-volume-up', 'speak-icon'); speakIcon.setAttribute('title', 'Speak Slok'); speakIcon.addEventListener('click', () => { console.log(`Speaking: ${slokeText}`); playTTS(slokeText); }); return speakIcon; } function cleanSlokText(text) { // Regex to match and remove introductory (e.g., "श्लोक 1:") and ending markers (e.g., "१") return text.replace(/श्लोक \d+: /g, '').replace(/ \d+$/g, ''); } let currentSlokeIndex = 0; // Track the current sloke index const audioPlayer = document.getElementById('audioPlayer'); // Play all slokes function (replace your existing setupPlayAllButton function) function setupPlayAllButton(slokesArray) { const playAllButton = document.getElementById('playAllButton'); playAllButton.onclick = async () => { currentSlokeIndex = 0; // Reset to start playNextSloke(slokesArray); }; } // Function to play each sloke in sequence async function playNextSloke(slokesArray) { if (currentSlokeIndex >= slokesArray.length) { return; // End if all slokes have been played } // Clean and highlight the current sloke text // const slokeText = cleanSlokText(slokesArray[currentSlokeIndex]); const slokeText = slokesArray[currentSlokeIndex]; highlightCurrentSloke(currentSlokeIndex); // Generate TTS audio for the current sloke text playTTS(slokeText).then(() => { // Move to the next sloke after the current one finishes currentSlokeIndex++; playNextSloke(slokesArray); }); } // Function to highlight the current sloke and scroll it into view function highlightCurrentSloke(index) { const slokeElements = document.querySelectorAll('.sloke-text'); // Assume each sloke text has this class // Remove previous highlights slokeElements.forEach(el => el.classList.remove('highlight')); // Highlight and scroll the current sloke const currentSloke = slokeElements[index]; if (currentSloke) { currentSloke.classList.add('highlight'); currentSloke.scrollIntoView({ behavior: "smooth", block: "center" }); } } let currentTranscriptIndex = 0; // Track the current transcript index // Setup Play All for Transcript function setupPlayAllTranscriptButton(transcriptArray) { const playAllTranscriptButton = document.getElementById('playTranscriptButton'); playAllTranscriptButton.onclick = async () => { currentTranscriptIndex = 0; // Reset to start playNextTranscript(transcriptArray); }; } // Function to play each transcript in sequence async function playNextTranscript(transcriptArray) { if (currentTranscriptIndex >= transcriptArray.length) { return; // End if all transcripts have been played } // Highlight the current transcript text highlightCurrentTranscript(currentTranscriptIndex); // Generate TTS audio for the current transcript text const transcriptText = transcriptArray[currentTranscriptIndex]; playTTS(transcriptText).then(() => { // Move to the next transcript after the current one finishes currentTranscriptIndex++; playNextTranscript(transcriptArray); }); } // Function to highlight the current transcript text function highlightCurrentTranscript(index) { const allTranscripts = document.querySelectorAll('.transcript-text'); allTranscripts.forEach((transcript, i) => { if (i === index) { transcript.classList.add('highlight'); // Add highlight class } else { transcript.classList.remove('highlight'); // Remove highlight class } }); } let currentAudio; // Global variable to hold the audio object for server-generated audio let isPlaying = false; // Track play/pause state for playback let currentUtterance; // Track current SpeechSynthesisUtterance for sa-IN playback // async function playTTS(text) { // console.log('Playing TTS for:', text); // text = cleanSlokText(text); // if (!text || text.trim() === '') { // console.error('No text provided'); // return; // } // try { // const audioUrl = await getAudioUrlForSloke(text); // if (audioUrl) { // console.log('Fetched audio URL:', audioUrl); // const audioPlayer = document.getElementById('audioPlayer'); // audioPlayer.src = audioUrl; // // Clear any previous errors // audioPlayer.onerror = null; // audioPlayer.load(); // await audioPlayer.play(); // audioPlayer.onended = () => { // console.log('Playback completed'); // }; // } else { // console.warn('No audio URL found for the sloke'); // } // } catch (error) { // console.error('Error during playback:', error); // } // } async function playTTS(text) { console.log('Speaking mantra'); var cleanText = cleanSlokText(text); if (!text || text.trim() === '') { console.error('No text provided'); return; } // Try fetching the saved audio URL from Google Drive or another source const audioUrl = await getAudioUrlForSloke(text); // Function to fetch the URL of saved audio if (audioUrl) { console.log('Fetched audio URL:', audioUrl); // If we get a valid audio URL, play it return new Promise((resolve, reject) => { const audioPlayer = document.getElementById('audioPlayer'); audioPlayer.src = audioUrl; audioPlayer.onerror = null; audioPlayer.load(); audioPlayer.play(); // Resolve the promise when playback ends audioPlayer.onended = () => { isPlaying = false; URL.revokeObjectURL(audioUrl); // Clean up URL resolve(); }; // Reject the promise if there's an error audioPlayer.onerror = (event) => { console.error('Playback error:', event); reject(event); }; isPlaying = true; }); } else { // If no saved audio is available or there’s an error, fallback to server-based TTS console.warn('Saved audio not found, using server-side TTS.'); const serverUrl = "https://thevera-botveradb.hf.space/generate_sanskrit_audio"; try { const response = await fetch(serverUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ cleanText }) }); if (!response.ok) { throw new Error('Failed to fetch audio from server'); } const audioBlob = await response.blob(); const audioUrl = URL.createObjectURL(audioBlob); return new Promise((resolve, reject) => { const audioPlayer = document.getElementById('audioPlayer'); audioPlayer.src = audioUrl; audioPlayer.play(); audioPlayer.onended = () => { isPlaying = false; URL.revokeObjectURL(audioUrl); // Clean up URL resolve(); }; audioPlayer.onerror = (event) => { console.error('Server-based TTS playback error:', event); reject(event); }; isPlaying = true; }); } catch (error) { console.error('Error calling server:', error); throw error; } } } // Function to fetch the audio URL for a given sloke async function getAudioUrlForSloke(text) { try { const response = await fetch(`https://thevera-botveradb.hf.space/get_audio_url?slokeText=${encodeURIComponent(text)}`); if (!response.ok) { throw new Error('Failed to fetch audio URL'); } const data = await response.json(); return data.audioUrl; // Assuming the API returns { audioUrl: 'URL' } } catch (error) { console.error('Error fetching audio URL:', error); return null; // Return null if an error occurs, so it falls back to server-side TTS } } // async function playTTS(text) { // console.log('Speaking mantra'); // text = cleanSlokText(text); // if (!text || text.trim() === '') { // console.error('No text provided'); // return; // } // const synth = window.speechSynthesis; // let voices = synth.getVoices(); // if (voices.length === 0) { // voices = await new Promise(resolve => { // const id = setInterval(() => { // voices = synth.getVoices(); // if (voices.length > 0) { // clearInterval(id); // resolve(voices); // } // }, 10); // }); // } // const sanskritVoice = voices.find(voice => voice.lang === 'sa-IN'); // if (sanskritVoice) { // synth.cancel(); // Stop any ongoing speech synthesis // return new Promise((resolve, reject) => { // try { // speakSloke(text); // Use the speakSloke function for speech synthesis // isPlaying = true; // Set playback status // resolve(); // Immediately resolve since speakSloke doesn't support events // } catch (error) { // console.error('TTS playback error:', error); // reject(error); // Reject the promise if an error occurs // } // }); // } else { // // Fallback to server-based TTS audio // console.warn('sa-IN voice not available, using server.'); // const serverUrl = "https://thevera-botveradb.hf.space/generate_sanskrit_audio"; // try { // const response = await fetch(serverUrl, { // method: "POST", // headers: { "Content-Type": "application/json" }, // body: JSON.stringify({ text }) // }); // if (!response.ok) { // throw new Error('Failed to fetch audio from server'); // } // const audioBlob = await response.blob(); // const audioUrl = URL.createObjectURL(audioBlob); // return new Promise((resolve, reject) => { // // Use the default audio player for playback // const audioPlayer = document.getElementById('audioPlayer'); // audioPlayer.src = audioUrl; // audioPlayer.play(); // // Resolve the promise when playback ends // audioPlayer.onended = () => { // isPlaying = false; // URL.revokeObjectURL(audioUrl); // Clean up URL // resolve(); // }; // // Reject the promise if there's an error // audioPlayer.onerror = (event) => { // console.error('Server-based TTS playback error:', event); // reject(event); // }; // isPlaying = true; // }); // } catch (error) { // console.error('Error calling server:', error); // throw error; // } // } // } // The speakSloke function can now be integrated with playTTS if desired function speakSloke(text) { // Normalize and preprocess the text const normalizedText = text .normalize("NFC") .replace(/ऽ/g, " "); // Replace avagraha with a space for better pronunciation // Split the text into meaningful phrases const phrases = normalizedText.split(/[।॥]/).filter(phrase => phrase.trim().length > 0); let phraseIndex = 0; function speakNextPhrase() { if (phraseIndex >= phrases.length) return; const currentPhrase = phrases[phraseIndex].trim(); const utterance = new SpeechSynthesisUtterance(currentPhrase); // Set voice and TTS parameters for a bold, heavy tone utterance.lang = "sa-IN"; utterance.pitch = 0.8; // Lower pitch for a deeper, heavier voice utterance.rate = 0.8; // Slower rate for gravitas and clarity utterance.volume = 1.0; // Full volume for boldness // Select the male Sanskrit voice const voices = speechSynthesis.getVoices(); const sanskritVoice = voices.find(voice => voice.lang === "sa-IN" && voice.name.includes("Male")); if (sanskritVoice) { utterance.voice = sanskritVoice; } else { throw new Error('sa-IN voice is unavailable'); } // Handle completion of the current phrase utterance.onend = () => { phraseIndex++; setTimeout(speakNextPhrase, 500); // Slightly longer pause for dramatic effect }; // Handle errors gracefully utterance.onerror = (error) => { console.error(`Error speaking phrase: ${currentPhrase}`, error); phraseIndex++; setTimeout(speakNextPhrase, 500); }; console.log(`Speaking phrase with bold voice: ${currentPhrase}`); // Debugging speechSynthesis.speak(utterance); } speakNextPhrase(); // Start speaking the sloke } // Donate Model Function // Get elements const donateButton = document.getElementById('donateButton'); const donateModal = document.getElementById('donateModal'); const closeBtn = document.querySelector('.close'); const amountButtons = document.querySelectorAll('.amount-btn'); const customAmountInput = document.getElementById('customAmount'); const donateForm = document.getElementById('donateForm'); const openUpiAppButton = document.getElementById('openUpiApp'); // Donation amount logic let selectedAmount = 0; // Handle predefined amount buttons amountButtons.forEach(button => { button.addEventListener('click', () => { selectedAmount = parseInt(button.dataset.amount); // Get amount from button's data attribute customAmountInput.value = ''; // Clear custom amount input amountButtons.forEach(btn => btn.classList.remove('selected')); // Deselect other buttons button.classList.add('selected'); // Highlight selected button }); }); // Handle custom amount input customAmountInput.addEventListener('input', () => { selectedAmount = parseInt(customAmountInput.value) || 0; // Set amount or default to 0 amountButtons.forEach(btn => btn.classList.remove('selected')); // Deselect predefined buttons }); // Open modal donateButton.onclick = function () { donateModal.style.display = "block"; // Show the modal } // Close modal closeBtn.onclick = function () { donateModal.style.display = "none"; // Hide the modal } // Close modal when clicking outside it window.onclick = function (event) { if (event.target === donateModal) { donateModal.style.display = "none"; } } // Submit form donateForm.addEventListener('submit', async (e) => { e.preventDefault(); // Get user details const name = document.getElementById('name').value.trim(); const email = document.getElementById('email').value.trim(); // Validate inputs if (!name || !email) { alert("Please enter your name and email."); return; } if (!selectedAmount || isNaN(selectedAmount) || selectedAmount <= 0) { alert("Please select or enter a valid donation amount."); return; } // Prepare donation data const donationData = { name, email, amount: selectedAmount }; try { logger.log(donationData) console.log(donationData) // Save to MongoDB via API const response = await fetch('https://thevera-botveradb.hf.space/save-donation', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(donationData), }); console.log(response) if (response.ok) { alert("Thank you for your donation!"); donateModal.style.display = "none"; } else { const errorData = await response.json(); alert(`Error: ${errorData.error || "Something went wrong. Please try again."}`); } } catch (error) { alert("Unable to process your donation. Please try again later."); console.error(error); } }); // Open UPI payment app openUpiAppButton.onclick = function () { if (!selectedAmount || isNaN(selectedAmount) || selectedAmount <= 0) { alert("Please select or enter a valid donation amount."); return; } // UPI payment link with amount const upiLink = `upi://pay?pa=sumandas24-4@okaxis&pn=Suman+Das&am=${selectedAmount}&cu=INR`; window.open(upiLink, '_blank'); }; // When the user clicks on the Donate button, open the modal // donateButton.onclick = function() { // donateModal.style.display = "block"; // } // When the user clicks on (x), close the modal // closeBtn.onclick = function() { // donateModal.style.display = "none"; // } // When the user clicks outside the modal, close it // window.onclick = function(event) { // if (event.target == donateModal) { // donateModal.style.display = "none"; // } // } // Open UPI app (works for mobile only) // openUpiAppButton.onclick = function() { // const upiLink = "upi://pay?pa=sumandas24-4@okaxis&pn=Suman+Das&url=https://bhagvat-ras.static.hf.space/index.html"; // Replace with actual UPI link // window.open(upiLink, '_blank'); // };