diff options
| -rw-r--r-- | .idea/vcs.xml | 6 | ||||
| -rw-r--r-- | abc.csv | 3 | ||||
| -rw-r--r-- | manifest.json | 9 | ||||
| -rw-r--r-- | ui.html | 381 |
4 files changed, 383 insertions, 16 deletions
diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="VcsDirectoryMappings"> + <mapping directory="$PROJECT_DIR$" vcs="Git" /> + </component> +</project>
\ No newline at end of file @@ -0,0 +1,3 @@ +ID,Memberships → Name,Memberships → Email,Event Venue - Venue → Name +21383,Fathima Dilsha,fdilsha689@gmail.com,"Farook College, Kozhikode" + diff --git a/manifest.json b/manifest.json index 8c494b0..8e47e24 100644 --- a/manifest.json +++ b/manifest.json @@ -9,10 +9,17 @@ "editorType": [ "figma" ], + "menu": [ + { "name": "Generate Gradient", "command": "generate" } + ], "ui": "ui.html", "networkAccess": { "allowedDomains": [ - "none" + "https://accounts.google.com", + "https://www.googleapis.com", + "https://oauth2.googleapis.com", + "https://*.googleusercontent.com", + "https://www.figma.com" ] } }
\ No newline at end of file @@ -1,17 +1,368 @@ -<h2>Rectangle Creator</h2> -<p>Count: <input id="count" type="number" value="5"></p> -<button id="create">Create</button> -<button id="cancel">Cancel</button> -<script> +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Certificate Generator</title> + <style> + body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + padding: 20px; + margin: 0; + color: #333; + } + + h2 { + margin-top: 0; + margin-bottom: 16px; + text-align: center; + color: #333; + } + + .section { + margin-bottom: 24px; + padding: 16px; + border-radius: 8px; + background-color: #f9f9f9; + border: 1px solid #eaeaea; + } + + .section-title { + font-weight: 600; + margin-top: 0; + margin-bottom: 12px; + font-size: 16px; + } + + button { + background-color: #18A0FB; + color: white; + border: none; + padding: 8px 16px; + border-radius: 6px; + font-size: 14px; + cursor: pointer; + transition: background-color 0.2s; + width: 100%; + } + + button:hover { + background-color: #0D8DE3; + } + + button:disabled { + background-color: #cccccc; + cursor: not-allowed; + } + + input[type="text"] { + width: 100%; + padding: 8px; + margin: 6px 0 12px 0; + font-size: 14px; + border: 1px solid #ccc; + border-radius: 4px; + box-sizing: border-box; + } + + input[type="file"] { + width: 100%; + margin: 6px 0 12px 0; + } + + .status { + margin-top: 10px; + padding: 8px; + border-radius: 4px; + font-size: 14px; + text-align: center; + } + + .success { + background-color: #e3fcef; + color: #0C6B58; + } + + .error { + background-color: #ffebe6; + color: #c41d00; + } + + .info { + background-color: #e6f4ff; + color: #0055CC; + } + + .progress-container { + width: 100%; + background-color: #e0e0e0; + border-radius: 4px; + margin: 12px 0; + } + + .progress-bar { + height: 10px; + border-radius: 4px; + background-color: #18A0FB; + width: 0%; + transition: width 0.3s; + } + </style> +</head> +<body> + <h2>Certificate Generator</h2> + + <div class="section"> + <h3 class="section-title">1. Google Drive Authentication</h3> + <button id="googleSignIn">Open Google Auth Page</button> + <p>After authorization, copy the access token and paste it below:</p> + <input type="text" id="accessToken" placeholder="Paste your access token here"> + <button id="submitToken">Submit Token</button> + <p id="authStatus" class="status info">Not signed in</p> + </div> + + <div class="section"> + <h3 class="section-title">2. Set Google Drive Folder</h3> + <p>Enter the ID of the Google Drive folder where certificates will be saved:</p> + <input type="text" id="folderId" placeholder="Folder ID (from Drive URL)"> + <button id="saveFolder">Save Folder</button> + <p id="folderStatus" class="status"></p> + </div> + + <div class="section"> + <h3 class="section-title">3. Upload Participant Data</h3> + <p>Upload CSV with columns: ID, Memberships → Name, Event Venue - Venue → Name</p> + <input type="file" id="csvUpload" accept=".csv"> + <button id="processCSV">Generate Certificates</button> + + <div class="progress-container" style="display: none;"> + <div class="progress-bar"></div> + </div> + + <p id="statusMessage" class="status"></p> + </div> -document.getElementById('create').onclick = () => { - const textbox = document.getElementById('count'); - const count = parseInt(textbox.value, 10); - parent.postMessage({ pluginMessage: { type: 'create-shapes', count } }, '*') -} + <script> + let accessToken = null; + + // Google Sign-In handler + document.getElementById("googleSignIn").onclick = () => { + const clientId = "771418999986-hm447mvuigafqi90fl3pk5f93d3nc93r.apps.googleusercontent.com"; + const redirectUri = encodeURIComponent('https://rishikrishna.me/oauthcnf/callback.html'); + const scope = encodeURIComponent('https://www.googleapis.com/auth/drive.file'); + const responseType = 'token'; + const authUrl = `https://accounts.google.com/o/oauth2/auth?client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scope}&response_type=${responseType}&prompt=consent`; -document.getElementById('cancel').onclick = () => { - parent.postMessage({ pluginMessage: { type: 'cancel' } }, '*') -} - -</script> + window.open(authUrl, '_blank'); + + document.getElementById("authStatus").innerText = "Auth page opened. Please copy the access token and paste it below."; + document.getElementById("authStatus").className = "status info"; + }; + + // Handle manually submitted token + document.getElementById("submitToken").onclick = () => { + const token = document.getElementById("accessToken").value.trim(); + + if (!token) { + document.getElementById("authStatus").innerText = "Please enter a valid access token"; + document.getElementById("authStatus").className = "status error"; + return; + } + + // Send token to plugin + parent.postMessage({ + pluginMessage: { + type: "auth-success", + token: token + } + }, "*"); + + // Update UI + document.getElementById("authStatus").innerText = "Token submitted"; + document.getElementById("authStatus").className = "status success"; + }; + + // Save folder ID handler + document.getElementById("saveFolder").onclick = () => { + const folderId = document.getElementById("folderId").value.trim(); + + if (!folderId) { + document.getElementById("folderStatus").innerText = "Please enter a valid folder ID"; + document.getElementById("folderStatus").className = "status error"; + return; + } + + // Send to plugin + parent.postMessage({ + pluginMessage: { + type: "save-folder", + folderId: folderId + } + }, "*"); + + // Update UI + document.getElementById("folderStatus").innerText = "Saving folder ID..."; + document.getElementById("folderStatus").className = "status info"; + }; + + // Process CSV handler + document.getElementById("processCSV").onclick = () => { + const fileInput = document.getElementById("csvUpload"); + const file = fileInput.files[0]; + + if (!file) { + document.getElementById("statusMessage").innerText = "Please select a CSV file"; + document.getElementById("statusMessage").className = "status error"; + return; + } + + // Show progress bar with 0% + showProgressBar(0, 100); + + // Update status + document.getElementById("statusMessage").innerText = "Reading CSV file..."; + document.getElementById("statusMessage").className = "status info"; + + // Read file + const reader = new FileReader(); + reader.onload = function(event) { + parent.postMessage({ + pluginMessage: { + type: "upload-csv", + data: event.target.result + } + }, "*"); + }; + + reader.onerror = function() { + document.getElementById("statusMessage").innerText = "Error reading file"; + document.getElementById("statusMessage").className = "status error"; + hideProgressBar(); + }; + + reader.readAsText(file); + }; + + // Listen for messages from plugin + window.onmessage = (event) => { + const msg = event.data.pluginMessage; + if (!msg) return; + + if (msg.type === "auth-status" && msg.status === "signed-in") { + document.getElementById("authStatus").innerText = "Signed in"; + document.getElementById("authStatus").className = "status success"; + } + + if (msg.type === "folder-status" && msg.folderId) { + document.getElementById("folderId").value = msg.folderId; + document.getElementById("folderStatus").innerText = "Folder set: " + msg.folderId; + document.getElementById("folderStatus").className = "status success"; + } + + if (msg.type === "auth-success-confirmed") { + document.getElementById("authStatus").innerText = "Signed in"; + document.getElementById("authStatus").className = "status success"; + } + + if (msg.type === "folder-saved") { + document.getElementById("folderStatus").innerText = "Folder ID saved successfully"; + document.getElementById("folderStatus").className = "status success"; + } + + if (msg.type === "error") { + document.getElementById("statusMessage").innerText = msg.message; + document.getElementById("statusMessage").className = "status error"; + hideProgressBar(); + } + + if (msg.type === "status") { + document.getElementById("statusMessage").innerText = msg.message; + document.getElementById("statusMessage").className = "status info"; + } + + if (msg.type === "progress") { + showProgressBar(msg.current, msg.total); + } + + if (msg.type === "success") { + document.getElementById("statusMessage").innerText = msg.message; + document.getElementById("statusMessage").className = "status success"; + hideProgressBar(); + } + + if (msg.type === "upload-to-drive") { + uploadToDrive(msg.pdfBase64, msg.fileName, msg.metadata, msg.accessToken); + } + }; + + // Function to handle Drive upload + async function uploadToDrive(pdfBase64, fileName, metadata, token) { + try { + // Convert base64 to blob + const binaryString = atob(pdfBase64); + const bytes = new Uint8Array(binaryString.length); + for (let i = 0; i < binaryString.length; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + const blob = new Blob([bytes], { type: 'application/pdf' }); + + // Create form data + const formData = new FormData(); + formData.append('metadata', new Blob([JSON.stringify(metadata)], { type: 'application/json' })); + formData.append('file', blob); + + // Upload to Drive + const response = await fetch('https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart', { + method: 'POST', + headers: { + 'Authorization': `Bearer ${token}` + }, + body: formData + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(errorData.error?.message || `Upload failed with status: ${response.status}`); + } + + const result = await response.json(); + + // Notify plugin of success + parent.postMessage({ + pluginMessage: { + type: 'upload-success', + fileId: result.id, + fileName: fileName + } + }, '*'); + } catch (error) { + console.error('Error uploading to Drive:', error); + + // Notify plugin of error + parent.postMessage({ + pluginMessage: { + type: 'error', + message: `Upload failed: ${error.message}` + } + }, '*'); + } + } + + // Helper functions for progress bar + function showProgressBar(current, total) { + const container = document.querySelector('.progress-container'); + const bar = document.querySelector('.progress-bar'); + + container.style.display = 'block'; + + const percentage = (current / total) * 100; + bar.style.width = `${percentage}%`; + } + + function hideProgressBar() { + const container = document.querySelector('.progress-container'); + container.style.display = 'none'; + } + </script> +</body> +</html>
\ No newline at end of file |
