diff --git a/client/web/README.md b/client/web/README.md new file mode 100644 index 0000000..9b34d18 --- /dev/null +++ b/client/web/README.md @@ -0,0 +1,33 @@ +# web client + +## working features 🟢 + +- on page load, recent paste urls get fetched from Pastebin API and get printed + below the textbox +- saving a new paste (non empty string) by clicking the submit button; then the + paste URL gets printed below the textbox + +## local setup 🐳 + +best way to test out the UI is targetting a local version of Pastebin API + +1. have Docker running +2. (see root Readme) tart DynamoDB local instance using `docker compose` +3. (idem) run API Gateway locally + +API endpoint should be `http://127.0.0.1:3000/paste` (if it isn't, simply +change the value in `script.js`) + +4. open `index.html` web app in your favorite browser + +either by openine the file with your browser, or using a local server like [VS Code +Live Server +plugin](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer). +I ❤️ live server for its hot reload capability + +## nice things and gotchas + +### environment switching + +in `index.html`, using html meta tag `` to switch +between production environment (targetting public API) or local API running on `localhost` diff --git a/client/web/index.html b/client/web/index.html new file mode 100644 index 0000000..d1159f7 --- /dev/null +++ b/client/web/index.html @@ -0,0 +1,34 @@ + + + + + + + Pastebin + + + +

Pastebin

+ +
+ +
+

latest pastes

+
+ + + diff --git a/client/web/script.js b/client/web/script.js new file mode 100644 index 0000000..dbee8e1 --- /dev/null +++ b/client/web/script.js @@ -0,0 +1,123 @@ +const environment = document + .querySelector('meta[name="environment"]') + .getAttribute("content"); +const API_URL = + environment === "production" + ? "https://paste.socratic.dev/paste" + : "http://127.0.0.1:3000/paste"; + +const TIMEOUT_MS = 10000; + +function getClientId() { + const queryParams = new URLSearchParams(window.location.search); + const clientId = queryParams.get("cid"); + return clientId !== null ? clientId : null; +} +function utf8ToBase64(str) { + return btoa(unescape(encodeURIComponent(str))); +} + +async function submitText() { + const textInput = document.getElementById("pasteContent"); + const textData = textInput.value; + + let content; + if (textData) { + content = textData; + console.log(`content: {content}`); + } else { + alert("Please enter text to be saved"); + return; + } + + // base64 encode content to preserve formatting + content = utf8ToBase64(content); + + // Create a JSON object with "content" as the key + var data = { + content: content, + }; + + var clientId = getClientId(); + if (clientId !== null) { + data["client_id"] = clientId; + } + + // Convert the JSON object to a string + const jsonData = JSON.stringify(data); + + // Send the data to the API using the fetch API + try { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS); + + const response = await fetch(API_URL, { + method: "POST", + headers: { + accept: "application/json", + "Content-Type": "application/json", + }, + body: jsonData, + signal: controller.signal, + }); + + clearTimeout(timeoutId); + const result = await response.json(); + + // Display the API response on the web page + const responseContainer = document.getElementById("responseContainer"); + var id = result["id"]; + id = id.replace('"', ""); + const url = `${API_URL}?id=${id}`; + responseContainer.innerHTML = `

Visit this URL to view most recent paste: ${url}

`; + textInput.value = ""; //clearing textbox from its value + } catch (error) { + console.error("Error sending data to API:", error); + alert("Error sending data to API"); + } +} + +async function displayPasteUrls() { + var pastebinAPIuri = `${API_URL}/api/pastes`; + var clientId = getClientId(); + console.log("muh client id"); + console.log(clientId); + if (clientId !== null) { + pastebinAPIuri = pastebinAPIuri + "?client_id=" + clientId; + } + + try { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS); + + const response = await fetch(pastebinAPIuri, { + signal: controller.signal, + }); + clearTimeout(timeoutId); + + // Setup timeout for JSON parsing + const jsonPromise = response.json(); + const timeoutPromise = new Promise((_, reject) => + setTimeout(() => reject(new Error("JSON parsing timed out")), TIMEOUT_MS) + ); + + const data = await Promise.race([jsonPromise, timeoutPromise]); + + // Get the div where we'll display the latest Paste Urls + const urlsDiv = document.getElementById("latestPasteUrls"); + + // Display each Url + data.forEach((url) => { + const p = document.createElement("p"); + p.innerHTML = `${url}`; + urlsDiv.appendChild(p); + }); + } catch (error) { + console.error("Error fetching strings from API:", error); + alert("Error fetching strings from API."); + } +} + +window.onload = function () { + displayPasteUrls(); +};