Skip to content

Commit ac6a43c

Browse files
feat: adding a plain web client html and js code
1 parent bc1d4d0 commit ac6a43c

File tree

3 files changed

+190
-0
lines changed

3 files changed

+190
-0
lines changed

client/web/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# web client
2+
3+
## working features 🟢
4+
5+
- on page load, recent paste urls get fetched from Pastebin API and get printed
6+
below the textbox
7+
- saving a new paste (non empty string) by clicking the submit button; then the
8+
paste URL gets printed below the textbox
9+
10+
## local setup 🐳
11+
12+
best way to test out the UI is targetting a local version of Pastebin API
13+
14+
1. have Docker running
15+
2. (see root Readme) tart DynamoDB local instance using `docker compose`
16+
3. (idem) run API Gateway locally
17+
18+
API endpoint should be `http://127.0.0.1:3000/paste` (if it isn't, simply
19+
change the value in `script.js`)
20+
21+
4. open `index.html` web app in your favorite browser
22+
23+
either by openine the file with your browser, or using a local server like [VS Code
24+
Live Server
25+
plugin](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer).
26+
I ❤️ live server for its hot reload capability
27+
28+
## nice things and gotchas
29+
30+
### environment switching
31+
32+
in `index.html`, using html meta tag `<meta name="environment" content="production">` to switch
33+
between production environment (targetting public API) or local API running on `localhost`

client/web/index.html

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta name="environment" content="local">
5+
<meta charset="UTF-8" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Pastebin</title>
8+
<style>
9+
body {
10+
font-family: Arial, sans-serif;
11+
margin: 20px;
12+
text-align: center;
13+
}
14+
textarea {
15+
width: 80%;
16+
height: 200px;
17+
margin-bottom: 10px;
18+
}
19+
</style>
20+
</head>
21+
<body>
22+
<h1>Pastebin</h1>
23+
<textarea
24+
id="pasteContent"
25+
placeholder="Paste your text here..."
26+
></textarea>
27+
<br />
28+
<button onclick="submitText()">Submit</button>
29+
<div id="responseContainer"></div>
30+
<h2>latest pastes</h2>
31+
<div id="latestPasteUrls"></div>
32+
<script src="script.js"></script>
33+
</body>
34+
</html>

client/web/script.js

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
const environment = document
2+
.querySelector('meta[name="environment"]')
3+
.getAttribute("content");
4+
const API_URL =
5+
environment === "production"
6+
? "https://paste.socratic.dev/paste"
7+
: "http://127.0.0.1:3000/paste";
8+
9+
const TIMEOUT_MS = 10000;
10+
11+
function getClientId() {
12+
const queryParams = new URLSearchParams(window.location.search);
13+
const clientId = queryParams.get("cid");
14+
return clientId !== null ? clientId : null;
15+
}
16+
function utf8ToBase64(str) {
17+
return btoa(unescape(encodeURIComponent(str)));
18+
}
19+
20+
async function submitText() {
21+
const textInput = document.getElementById("pasteContent");
22+
const textData = textInput.value;
23+
24+
let content;
25+
if (textData) {
26+
content = textData;
27+
console.log(`content: {content}`);
28+
} else {
29+
alert("Please enter text to be saved");
30+
return;
31+
}
32+
33+
// base64 encode content to preserve formatting
34+
content = utf8ToBase64(content);
35+
36+
// Create a JSON object with "content" as the key
37+
var data = {
38+
content: content,
39+
};
40+
41+
var clientId = getClientId();
42+
if (clientId !== null) {
43+
data["client_id"] = clientId;
44+
}
45+
46+
// Convert the JSON object to a string
47+
const jsonData = JSON.stringify(data);
48+
49+
// Send the data to the API using the fetch API
50+
try {
51+
const controller = new AbortController();
52+
const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
53+
54+
const response = await fetch(API_URL, {
55+
method: "POST",
56+
headers: {
57+
accept: "application/json",
58+
"Content-Type": "application/json",
59+
},
60+
body: jsonData,
61+
signal: controller.signal,
62+
});
63+
64+
clearTimeout(timeoutId);
65+
const result = await response.json();
66+
67+
// Display the API response on the web page
68+
const responseContainer = document.getElementById("responseContainer");
69+
var id = result["id"];
70+
id = id.replace('"', "");
71+
const url = `${API_URL}?id=${id}`;
72+
responseContainer.innerHTML = `<p>Visit this URL to view most recent paste: <a href=${url}>${url}</a></p>`;
73+
textInput.value = ""; //clearing textbox from its value
74+
} catch (error) {
75+
console.error("Error sending data to API:", error);
76+
alert("Error sending data to API");
77+
}
78+
}
79+
80+
async function displayPasteUrls() {
81+
var pastebinAPIuri = `${API_URL}/api/pastes`;
82+
var clientId = getClientId();
83+
console.log("muh client id");
84+
console.log(clientId);
85+
if (clientId !== null) {
86+
pastebinAPIuri = pastebinAPIuri + "?client_id=" + clientId;
87+
}
88+
89+
try {
90+
const controller = new AbortController();
91+
const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
92+
93+
const response = await fetch(pastebinAPIuri, {
94+
signal: controller.signal,
95+
});
96+
clearTimeout(timeoutId);
97+
98+
// Setup timeout for JSON parsing
99+
const jsonPromise = response.json();
100+
const timeoutPromise = new Promise((_, reject) =>
101+
setTimeout(() => reject(new Error("JSON parsing timed out")), TIMEOUT_MS)
102+
);
103+
104+
const data = await Promise.race([jsonPromise, timeoutPromise]);
105+
106+
// Get the div where we'll display the latest Paste Urls
107+
const urlsDiv = document.getElementById("latestPasteUrls");
108+
109+
// Display each Url
110+
data.forEach((url) => {
111+
const p = document.createElement("p");
112+
p.innerHTML = `<a href="${url}" target="_blank">${url}</a>`;
113+
urlsDiv.appendChild(p);
114+
});
115+
} catch (error) {
116+
console.error("Error fetching strings from API:", error);
117+
alert("Error fetching strings from API.");
118+
}
119+
}
120+
121+
window.onload = function () {
122+
displayPasteUrls();
123+
};

0 commit comments

Comments
 (0)