Login Website Menggunakan Sistem Kode OTP
*Untuk Mendapatkan Full Script tanpa password silahkan Klik Disini*
1. Copy Spreadsheet (Klik disini)
2. Terdapat beberapa kolom yang harus di isi, kecuali kolom OTP yang akan terisi secara otomatis apabila melakukan Login.
3. Buatlah lembar kerja Apps Script dengan cara klik menu Ekstensi/Extensions lalu pilih Apps Script.
4. Terdapat 9 file yang sudah tersedia untuk di masukkan script.
5. Copy dan pastekan script di bawah ini ke Code.gs
Masukkan Password Untuk Melihat Script (Password ada di dalam video)
//Javabitpro.com
let ss = SpreadsheetApp.openById('SESUAIKAN ID SPREADSHEET').getSheets()[0] //Sesuaikan ID Spreadsheet
let data = ss.getDataRange().getValues()
function doGet(e) {
return HtmlService.createTemplateFromFile('login').evaluate()
.addMetaTag('viewport', 'width=device-width, initial-scale=1')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function getUrl() {
var url = ScriptApp.getService().getUrl();
return url;
}
function login(obj) {
let search = data.findIndex(r => r[3] == obj.user && r[4] == obj.password)
let otp = ''
if (search != -1) {
let rowIndex = search + 1
//Logger.log(rowIndex)
for (let i = 0; i < 6; i++) {
otp += Math.floor(Math.random() * 10)
}
ss.getRange(rowIndex, 7).setValue("'" + otp)
let email = ss.getRange(rowIndex, 2).getValue()
let name = ss.getRange(rowIndex, 3).getValue()
let phone = ss.getRange(rowIndex, 6).getValue()
MailApp.sendEmail({
to: email,
subject: 'Konfirmasi Kode OTP Nama '+name+' Nomor Telp: '+phone,
htmlBody:'<b>Kode OTP :</b> '+otp
})
return otp
}
}
//Javabitpro.com
function verifyOTP(obj) {
let otp = obj.input1 + obj.input2 + obj.input3 + obj.input4 + obj.input5 + obj.input6
//Logger.log(otp)
let search = data.findIndex(r => r[6] == otp)
//Logger.log(search)
if (search != -1) {
return otp
}
}
function deleteOTP(otp) {
let output = 'delete OTP'
let search = data.findIndex(r => r[6] == otp)
let rowIndex = search + 1
//Logger.log('แถวที่ ' + rowIndex)
if (search != -1) {
ss.getRange(rowIndex, 7).setValue('')
return output
}
}
function changePage(page){
return HtmlService.createTemplateFromFile(page).evaluate().getContent()
}
//Javabitpro.com
function sendMail(mail){
let ss = SpreadsheetApp.getActive().getSheets()[0]
let find = ss.createTextFinder(mail).findAll()
let output = 'success'
if(find.length == 1){
let email = find[0].offset(0,0).getValue()
let user = find[0].offset(0,2).getValue()
let pass = find[0].offset(0,3).getValue()
Logger.log(email)
Logger.log(pass)
MailApp.sendEmail({
to: email,
subject: 'Informasikan kata sandi',
htmlBody:'<b>Alamat email:</b>'+email+'<br/><b>User:</b>'+user+'<br/><b>Password:</b>'+pass
})
}else{
output = 'Alamat email tidak ada'
}
return output
}
//Javabitpro.com
let ss = SpreadsheetApp.openById('SESUAIKAN ID SPREADSHEET').getSheets()[0] //Sesuaikan ID Spreadsheet
let data = ss.getDataRange().getValues()
function doGet(e) {
return HtmlService.createTemplateFromFile('login').evaluate()
.addMetaTag('viewport', 'width=device-width, initial-scale=1')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function getUrl() {
var url = ScriptApp.getService().getUrl();
return url;
}
function login(obj) {
let search = data.findIndex(r => r[3] == obj.user && r[4] == obj.password)
let otp = ''
if (search != -1) {
let rowIndex = search + 1
//Logger.log(rowIndex)
for (let i = 0; i < 6; i++) {
otp += Math.floor(Math.random() * 10)
}
ss.getRange(rowIndex, 7).setValue("'" + otp)
let email = ss.getRange(rowIndex, 2).getValue()
let name = ss.getRange(rowIndex, 3).getValue()
let phone = ss.getRange(rowIndex, 6).getValue()
MailApp.sendEmail({
to: email,
subject: 'Konfirmasi Kode OTP Nama '+name+' Nomor Telp: '+phone,
htmlBody:'<b>Kode OTP :</b> '+otp
})
return otp
}
}
//Javabitpro.com
function verifyOTP(obj) {
let otp = obj.input1 + obj.input2 + obj.input3 + obj.input4 + obj.input5 + obj.input6
//Logger.log(otp)
let search = data.findIndex(r => r[6] == otp)
//Logger.log(search)
if (search != -1) {
return otp
}
}
function deleteOTP(otp) {
let output = 'delete OTP'
let search = data.findIndex(r => r[6] == otp)
let rowIndex = search + 1
//Logger.log('แถวที่ ' + rowIndex)
if (search != -1) {
ss.getRange(rowIndex, 7).setValue('')
return output
}
}
function changePage(page){
return HtmlService.createTemplateFromFile(page).evaluate().getContent()
}
//Javabitpro.com
function sendMail(mail){
let ss = SpreadsheetApp.getActive().getSheets()[0]
let find = ss.createTextFinder(mail).findAll()
let output = 'success'
if(find.length == 1){
let email = find[0].offset(0,0).getValue()
let user = find[0].offset(0,2).getValue()
let pass = find[0].offset(0,3).getValue()
Logger.log(email)
Logger.log(pass)
MailApp.sendEmail({
to: email,
subject: 'Informasikan kata sandi',
htmlBody:'<b>Alamat email:</b>'+email+'<br/><b>User:</b>'+user+'<br/><b>Password:</b>'+pass
})
}else{
output = 'Alamat email tidak ada'
}
return output
}
Masukkan Password Untuk Melihat Script (Password sama dengan di atas)
<!DOCTYPE html>
<html lang="en">
<head>
<base target="_top">
<title>Login Javabitpro</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap v5.1.3 CDNs -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js" integrity="sha512-STof4xm1wgkfm7heWqFJVn58Hm3EtS31XFaagaa8VMReCXAkQnJZ+jEy8PCC/iT18dFy95WcExNHFTqLyp72eQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<?!= HtmlService.createHtmlOutputFromFile('css').getContent() ?>
<!-- Boxicons CSS -->
<link href="https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css" rel="stylesheet" />
</head>
<body>
<div class="login" style="display: none">
<header class="mb-3 mx-auto">
<i class='bx bxs-lock' style="color: white;"></i>
</header>
<h2 class="text-center text-primary">LOGIN</h2>
<form onsubmit="submitForm(this)">
<div class="form-group ">
<label class="form-label" for="user"><i class='bx bxs-user-circle'></i> Username</label>
<input class="form-control rounded-pill" type="text" id="user" name="user" required>
</div>
<div class="form-group ">
<label class="form-label" for="password"><i class='bx bx-key'></i> Password</label>
<input class="form-control rounded-pill" type="password" id="password" name="password" required>
</div>
<div class="form-group">
<a href="#" onclick="sendMail()">Lupa kata sandi?</a>
</div>
<div class="form-group">
<input class="btn btn-primary rounded-pill" type="submit" value="Login">
</div>
</form>
<?var url = getUrl();?><input type="hidden" value="<?= url ?>" id="url" />
<button id="btnOpenIndex" onclick="linkWeb(<?=url?>)" hidden>Beranda</button>
</div>
<section>
<!-- Button trigger modal -->
<button type="button" id="otp" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#staticBackdrop" hidden>
Launch demo modal
</button>
<!-- Modal -->
<div class="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true" >
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="staticBackdropLabel">OTP</h1>
<button type="button" id="btnClose" class="btn-close" data-bs-dismiss="modal" aria-label="Close" hidden></button>
</div>
<div class="modal-body">
<?!= HtmlService.createHtmlOutputFromFile('otp').getContent() ?>
</div>
</div>
</div>
</div>
</section>
<script>
</script>
<?!= HtmlService.createHtmlOutputFromFile('js').getContent() ?>
</body>
</html>
<style>.footer,.generic-footer{margin-bottom:98px}@media (min-width:52px){.footer,.generic-footer{margin-bottom:78px}}@media (min-width:52px){.footer,.generic-footer{margin-bottom:56px}}@media (min-width:52px){.footer,.generic-footer{margin-bottom:0}}.disclaimer{position:fixed;z-index:9999999;bottom:0;right:0;border-top:2px solid #ff5c62;text-align:center;font-size:14px;font-weight:400;background-color:#fff;padding:5px 10px 5px 10px}.disclaimer a:hover{text-decoration:underline}@media (min-width:52px){.disclaimer{text-align:right;border-left:2px solid red;border-top-left-radius:10px}}@media (min-width:1920px){.disclaimer{width:20%}}</style><div class="disclaimer">Version.02.25.23 @Copyright <a title="https://www.javabitpro.com/" target="_blank" href="https://www.javabitpro.com/" style="color: black;"><b>www.javabitpro.com</b></a></div>
<!DOCTYPE html>
<html lang="en">
<head>
<base target="_top">
<title>Login Javabitpro</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap v5.1.3 CDNs -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js" integrity="sha512-STof4xm1wgkfm7heWqFJVn58Hm3EtS31XFaagaa8VMReCXAkQnJZ+jEy8PCC/iT18dFy95WcExNHFTqLyp72eQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<?!= HtmlService.createHtmlOutputFromFile('css').getContent() ?>
<!-- Boxicons CSS -->
<link href="https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css" rel="stylesheet" />
</head>
<body>
<div class="login" style="display: none">
<header class="mb-3 mx-auto">
<i class='bx bxs-lock' style="color: white;"></i>
</header>
<h2 class="text-center text-primary">LOGIN</h2>
<form onsubmit="submitForm(this)">
<div class="form-group ">
<label class="form-label" for="user"><i class='bx bxs-user-circle'></i> Username</label>
<input class="form-control rounded-pill" type="text" id="user" name="user" required>
</div>
<div class="form-group ">
<label class="form-label" for="password"><i class='bx bx-key'></i> Password</label>
<input class="form-control rounded-pill" type="password" id="password" name="password" required>
</div>
<div class="form-group">
<a href="#" onclick="sendMail()">Lupa kata sandi?</a>
</div>
<div class="form-group">
<input class="btn btn-primary rounded-pill" type="submit" value="Login">
</div>
</form>
<?var url = getUrl();?><input type="hidden" value="<?= url ?>" id="url" />
<button id="btnOpenIndex" onclick="linkWeb(<?=url?>)" hidden>Beranda</button>
</div>
<section>
<!-- Button trigger modal -->
<button type="button" id="otp" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#staticBackdrop" hidden>
Launch demo modal
</button>
<!-- Modal -->
<div class="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true" >
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="staticBackdropLabel">OTP</h1>
<button type="button" id="btnClose" class="btn-close" data-bs-dismiss="modal" aria-label="Close" hidden></button>
</div>
<div class="modal-body">
<?!= HtmlService.createHtmlOutputFromFile('otp').getContent() ?>
</div>
</div>
</div>
</div>
</section>
<script>
</script>
<?!= HtmlService.createHtmlOutputFromFile('js').getContent() ?>
</body>
</html>
<style>.footer,.generic-footer{margin-bottom:98px}@media (min-width:52px){.footer,.generic-footer{margin-bottom:78px}}@media (min-width:52px){.footer,.generic-footer{margin-bottom:56px}}@media (min-width:52px){.footer,.generic-footer{margin-bottom:0}}.disclaimer{position:fixed;z-index:9999999;bottom:0;right:0;border-top:2px solid #ff5c62;text-align:center;font-size:14px;font-weight:400;background-color:#fff;padding:5px 10px 5px 10px}.disclaimer a:hover{text-decoration:underline}@media (min-width:52px){.disclaimer{text-align:right;border-left:2px solid red;border-top-left-radius:10px}}@media (min-width:1920px){.disclaimer{width:20%}}</style><div class="disclaimer">Version.02.25.23 @Copyright <a title="https://www.javabitpro.com/" target="_blank" href="https://www.javabitpro.com/" style="color: black;"><b>www.javabitpro.com</b></a></div>
Masukkan Password Untuk Melihat Script (Password sama dengan di atas)
<!DOCTYPE html>
<html lang="en">
<head>
<base target="_top">
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Kode OTP</title>
<!-- Boxicons CSS -->
<link href="https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css" rel="stylesheet" />
</head>
<body>
<div class="container">
<header>
<i class="bx bxs-check-shield"></i>
</header>
<h4>Masukkan OTP</h4>
<form id="myOTP" onsubmit="checkOTP(this)">
<div class="input-field">
<input type="number" id="input1" name="input1" class="field"/>
<input type="number" id="input2" name="input2" class="field" disabled />
<input type="number" id="input3" name="input3" class="field" disabled />
<input type="number" id="input4" name="input4" class="field" disabled />
<input type="number" id="input5" name="input5" class="field" disabled />
<input type="number" id="input6" name="input6" class="field" disabled />
</div>
<button type="submit" id="btnOTP">Cek OTP</button>
</form>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<base target="_top">
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Kode OTP</title>
<!-- Boxicons CSS -->
<link href="https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css" rel="stylesheet" />
</head>
<body>
<div class="container">
<header>
<i class="bx bxs-check-shield"></i>
</header>
<h4>Masukkan OTP</h4>
<form id="myOTP" onsubmit="checkOTP(this)">
<div class="input-field">
<input type="number" id="input1" name="input1" class="field"/>
<input type="number" id="input2" name="input2" class="field" disabled />
<input type="number" id="input3" name="input3" class="field" disabled />
<input type="number" id="input4" name="input4" class="field" disabled />
<input type="number" id="input5" name="input5" class="field" disabled />
<input type="number" id="input6" name="input6" class="field" disabled />
</div>
<button type="submit" id="btnOTP">Cek OTP</button>
</form>
</div>
</body>
</html>
Masukkan Password Untuk Melihat Script (Password sama dengan di atas)
<style>
@import url('https://fonts.googleapis.com/css2?family=Prompt&display=swap');
* {
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: Prompt, sans-serif;
}
body {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background:url(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPvnMZaE1wDo1V0XvnTDQH9YwACQMegvJZJ9H8z-zCn1_BH9rRNVEp_cl-CuGDTgjI84U9YnsQNEzGWE2zcjsC3Sl8DJRyauajWlhPcly-tnaQtmD0pfZxbUJY2uF40Kj6QNpFtXO8mOUkWjD2DjBjtng6ZCMSaO1ikAulvWZfNe84_-rhLLnLe-a6/s1920/%E2%80%94Pngtree%E2%80%94blue%20background%20design%20with%20business_1605497.png)no-repeat;
background-size:cover;
}
:where(.container, form, .input-field, header) {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.container {
background: #fff;
padding: 30px 65px;
border-radius: 12px;
row-gap: 20px;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
}
.container header {
height: 65px;
width: 65px;
background: #4070f4;
color: #fff;
font-size: 2.5rem;
border-radius: 50%;
}
.container h4 {
font-size: 1.25rem;
color: #333;
font-weight: 500;
}
form .input-field {
flex-direction: row;
column-gap: 10px;
}
.input-field input {
height: 45px;
width: 42px;
border-radius: 6px;
outline: none;
font-size: 1.125rem;
text-align: center;
border: 1px solid #ddd;
}
.input-field input:focus {
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1);
}
.input-field input::-webkit-inner-spin-button,
.input-field input::-webkit-outer-spin-button {
display: none;
}
form button {
margin-top: 25px;
width: 100%;
color: #fff;
font-size: 1rem;
border: none;
padding: 9px 0;
cursor: pointer;
border-radius: 6px;
pointer-events: none;
background: #6e93f7;
transition: all 0.2s ease;
}
form button.active {
background: #4070f4;
pointer-events: auto;
}
form button:hover {
background: #0e4bf1;
}
.login {
width: 360px;
height: min-content;
padding: 20px;
border-radius: 12px;
background: #ffffff;
border:1px solid #BFBFBF;
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
}
.login header{
height: 65px;
width: 65px;
background: #4070f4;
color: #fff;
font-size: 2.5rem;
border-radius: 50%;
}
.login h1 {
font-size: 36px;
margin-bottom: 25px;
}
.login form {
font-size: 20px;
}
.login form .form-group {
margin-bottom: 12px;
}
.login form input[type="submit"] {
font-size: 20px;
margin-top: 5px;
width: 200px;
}
</style>
<style>
@import url('https://fonts.googleapis.com/css2?family=Prompt&display=swap');
* {
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: Prompt, sans-serif;
}
body {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background:url(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPvnMZaE1wDo1V0XvnTDQH9YwACQMegvJZJ9H8z-zCn1_BH9rRNVEp_cl-CuGDTgjI84U9YnsQNEzGWE2zcjsC3Sl8DJRyauajWlhPcly-tnaQtmD0pfZxbUJY2uF40Kj6QNpFtXO8mOUkWjD2DjBjtng6ZCMSaO1ikAulvWZfNe84_-rhLLnLe-a6/s1920/%E2%80%94Pngtree%E2%80%94blue%20background%20design%20with%20business_1605497.png)no-repeat;
background-size:cover;
}
:where(.container, form, .input-field, header) {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.container {
background: #fff;
padding: 30px 65px;
border-radius: 12px;
row-gap: 20px;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
}
.container header {
height: 65px;
width: 65px;
background: #4070f4;
color: #fff;
font-size: 2.5rem;
border-radius: 50%;
}
.container h4 {
font-size: 1.25rem;
color: #333;
font-weight: 500;
}
form .input-field {
flex-direction: row;
column-gap: 10px;
}
.input-field input {
height: 45px;
width: 42px;
border-radius: 6px;
outline: none;
font-size: 1.125rem;
text-align: center;
border: 1px solid #ddd;
}
.input-field input:focus {
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1);
}
.input-field input::-webkit-inner-spin-button,
.input-field input::-webkit-outer-spin-button {
display: none;
}
form button {
margin-top: 25px;
width: 100%;
color: #fff;
font-size: 1rem;
border: none;
padding: 9px 0;
cursor: pointer;
border-radius: 6px;
pointer-events: none;
background: #6e93f7;
transition: all 0.2s ease;
}
form button.active {
background: #4070f4;
pointer-events: auto;
}
form button:hover {
background: #0e4bf1;
}
.login {
width: 360px;
height: min-content;
padding: 20px;
border-radius: 12px;
background: #ffffff;
border:1px solid #BFBFBF;
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
}
.login header{
height: 65px;
width: 65px;
background: #4070f4;
color: #fff;
font-size: 2.5rem;
border-radius: 50%;
}
.login h1 {
font-size: 36px;
margin-bottom: 25px;
}
.login form {
font-size: 20px;
}
.login form .form-group {
margin-bottom: 12px;
}
.login form input[type="submit"] {
font-size: 20px;
margin-top: 5px;
width: 200px;
}
</style>
Masukkan Password Untuk Melihat Script (Password sama dengan di atas)
<script src="https://cdn.jsdelivr.net/npm/gasparesganga-jquery-loading-overlay@2.1.7/dist/loadingoverlay.min.js"></script>
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
<script>
</script>
<script>
var SESSION_TIME = 60 * 1000
var inputs = document.querySelectorAll(".field"),
button = document.querySelector("#btnOTP");
//console.log(inputs)
loadFormOTP()
window.onload = ()=>{
$.LoadingOverlay('show')
try{
lockObj = JSON.parse(lockObj)
}catch(error){
lockObj = {
status: 'none',
exp: 0
}
}
console.log(lockObj)
if(lockObj?.status == 'login' && lockObj?.exp > new Date().getTime()){
linkWeb(url)
$.LoadingOverlay('hide')
}else if(lockObj?.exp < new Date().getTime()){
$.LoadingOverlay('hide')
Swal.fire({
title: 'Batas Waktu Akses',
text: 'Silahkan Login Kembali!'
}).then(()=>{
localStorage.clear('lock')
$('.login').show(200)
})
}else {
$.LoadingOverlay('hide')
$('.login').show(200)
}
}
var url = document.getElementById("url").value;
var lockObj = localStorage.getItem("lock")
function linkWeb(url){
changePage('index')
}
function logout(url){
console.log('Status ' + status)
changePage('login')
}
function changePage(page){
google.script.run.withSuccessHandler(res =>{
document.open()
document.write(res)
document.close()
}).changePage(page)
}
function loading(){
$('.login').LoadingOverlay('show')
}
window.addEventListener("load", () => inputs[0].focus());
function loadFormOTP(){
inputs.forEach((input, index1) => {
input.addEventListener("keyup", (e) => {
const currentInput = input,
nextInput = input.nextElementSibling,
prevInput = input.previousElementSibling;
if (currentInput.value.length > 1) {
currentInput.value = "";
return;
}
if (nextInput && nextInput.hasAttribute("disabled") && currentInput.value !== "") {
nextInput.removeAttribute("disabled");
nextInput.focus();
}
if (e.key === "Backspace") {
inputs.forEach((input, index2) => {
if (index1 <= index2 && prevInput) {
input.setAttribute("disabled", true);
input.value = "";
prevInput.focus();
}
});
}
if (!inputs[5].disabled && inputs[5].value !== "") {
button.classList.add("active");
return;
}
button.classList.remove("active");
});
});
}
function submitForm(obj){
$('.login').LoadingOverlay('show')
event.preventDefault()
google.script.run.withSuccessHandler((otp)=>{
$('.login').LoadingOverlay('hide')
console.log('Kode OTP '+otp)
if(otp != null){
Swal.fire({
position: 'center',
icon: 'success',
title: 'Kode OTP telah terkirim ke email anda!',
showConfirmButton: false,
timer: 1500
})
$('#otp').click()
}else{
Swal.fire({
position: 'center',
icon: 'error',
title: 'Nama pengguna atau sandi salah.!!',
showConfirmButton: false,
timer: 1500
})
}
}).login(obj)
}
function deleteOTP(otp){
google.script.run.withSuccessHandler((output)=>{
if(output == 'delete OTP'){
$('#btnOpenIndex').click()
localStorage.setItem("lock", JSON.stringify({status: 'login', exp: new Date().getTime()+ SESSION_TIME}));
console.log('Login Berhasil')
}
}).deleteOTP(otp)
}
function checkOTP(obj){
loading()
event.preventDefault()
google.script.run.withSuccessHandler((otp)=>{
if(otp != null){
$('#btnClose').click()
$('.login').hide()
Swal.fire({
position: 'center',
icon: 'success',
title: 'Login Berhasil!!',
showConfirmButton: false,
timer: 1500
})
deleteOTP(otp)
}else{
Swal.fire({
position: 'center',
icon: 'error',
title: 'Kode OTP tidak valid!!',
showConfirmButton: false,
timer: 1500
}).then(()=>{
setTimeout(()=>{
$("#myOTP")[0].reset();
inputs.forEach((input) => {
input.setAttribute("disabled", true);
});
inputs[0].removeAttribute("disabled")
inputs[0].value = ""
$('#input1').focus()
console.log('Retry OTP')
},500)
})
}
}).verifyOTP(obj)
}
function sendMail(){
event.preventDefault()
Swal.fire({
title: 'Email untuk menerima kata sandi',
html: `<input type="text" id="email" class="swal2-input" placeholder="email">`,
confirmButtonText: 'Konfirmasi',
focusConfirm: false,
showCancelButton: true,
preConfirm: () => {
const email = Swal.getPopup().querySelector('#email').value
if (!email) {
Swal.showValidationMessage(`Masukkan alamt email anda`)
}else{
Swal.fire({
title: 'Loading!!!',
timerProgressBar: true,
didOpen: () => {
Swal.showLoading()
}
})
google.script.run.withSuccessHandler((output)=>{
if(output == 'success'){
Swal.fire({
position: 'center',
icon: 'success',
title: 'Kata sandi telah dikirim ke alamat email Anda.!!',
showConfirmButton: false,
timer: 1500
})
}else{
Swal.fire({
position: 'center',
icon: 'error',
title: 'Email ini tidak ada di sistem.!!',
showConfirmButton: false,
timer: 1500
})
}
}).sendMail(email)
}
return {email: email }
}
})
}
</script>
<script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script src="https://cdn.jsdelivr.net/npm/gasparesganga-jquery-loading-overlay@2.1.7/dist/loadingoverlay.min.js"></script>
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
<script>
</script>
<script>
var SESSION_TIME = 60 * 1000
var inputs = document.querySelectorAll(".field"),
button = document.querySelector("#btnOTP");
//console.log(inputs)
loadFormOTP()
window.onload = ()=>{
$.LoadingOverlay('show')
try{
lockObj = JSON.parse(lockObj)
}catch(error){
lockObj = {
status: 'none',
exp: 0
}
}
console.log(lockObj)
if(lockObj?.status == 'login' && lockObj?.exp > new Date().getTime()){
linkWeb(url)
$.LoadingOverlay('hide')
}else if(lockObj?.exp < new Date().getTime()){
$.LoadingOverlay('hide')
Swal.fire({
title: 'Batas Waktu Akses',
text: 'Silahkan Login Kembali!'
}).then(()=>{
localStorage.clear('lock')
$('.login').show(200)
})
}else {
$.LoadingOverlay('hide')
$('.login').show(200)
}
}
var url = document.getElementById("url").value;
var lockObj = localStorage.getItem("lock")
function linkWeb(url){
changePage('index')
}
function logout(url){
console.log('Status ' + status)
changePage('login')
}
function changePage(page){
google.script.run.withSuccessHandler(res =>{
document.open()
document.write(res)
document.close()
}).changePage(page)
}
function loading(){
$('.login').LoadingOverlay('show')
}
window.addEventListener("load", () => inputs[0].focus());
function loadFormOTP(){
inputs.forEach((input, index1) => {
input.addEventListener("keyup", (e) => {
const currentInput = input,
nextInput = input.nextElementSibling,
prevInput = input.previousElementSibling;
if (currentInput.value.length > 1) {
currentInput.value = "";
return;
}
if (nextInput && nextInput.hasAttribute("disabled") && currentInput.value !== "") {
nextInput.removeAttribute("disabled");
nextInput.focus();
}
if (e.key === "Backspace") {
inputs.forEach((input, index2) => {
if (index1 <= index2 && prevInput) {
input.setAttribute("disabled", true);
input.value = "";
prevInput.focus();
}
});
}
if (!inputs[5].disabled && inputs[5].value !== "") {
button.classList.add("active");
return;
}
button.classList.remove("active");
});
});
}
function submitForm(obj){
$('.login').LoadingOverlay('show')
event.preventDefault()
google.script.run.withSuccessHandler((otp)=>{
$('.login').LoadingOverlay('hide')
console.log('Kode OTP '+otp)
if(otp != null){
Swal.fire({
position: 'center',
icon: 'success',
title: 'Kode OTP telah terkirim ke email anda!',
showConfirmButton: false,
timer: 1500
})
$('#otp').click()
}else{
Swal.fire({
position: 'center',
icon: 'error',
title: 'Nama pengguna atau sandi salah.!!',
showConfirmButton: false,
timer: 1500
})
}
}).login(obj)
}
function deleteOTP(otp){
google.script.run.withSuccessHandler((output)=>{
if(output == 'delete OTP'){
$('#btnOpenIndex').click()
localStorage.setItem("lock", JSON.stringify({status: 'login', exp: new Date().getTime()+ SESSION_TIME}));
console.log('Login Berhasil')
}
}).deleteOTP(otp)
}
function checkOTP(obj){
loading()
event.preventDefault()
google.script.run.withSuccessHandler((otp)=>{
if(otp != null){
$('#btnClose').click()
$('.login').hide()
Swal.fire({
position: 'center',
icon: 'success',
title: 'Login Berhasil!!',
showConfirmButton: false,
timer: 1500
})
deleteOTP(otp)
}else{
Swal.fire({
position: 'center',
icon: 'error',
title: 'Kode OTP tidak valid!!',
showConfirmButton: false,
timer: 1500
}).then(()=>{
setTimeout(()=>{
$("#myOTP")[0].reset();
inputs.forEach((input) => {
input.setAttribute("disabled", true);
});
inputs[0].removeAttribute("disabled")
inputs[0].value = ""
$('#input1').focus()
console.log('Retry OTP')
},500)
})
}
}).verifyOTP(obj)
}
function sendMail(){
event.preventDefault()
Swal.fire({
title: 'Email untuk menerima kata sandi',
html: `<input type="text" id="email" class="swal2-input" placeholder="email">`,
confirmButtonText: 'Konfirmasi',
focusConfirm: false,
showCancelButton: true,
preConfirm: () => {
const email = Swal.getPopup().querySelector('#email').value
if (!email) {
Swal.showValidationMessage(`Masukkan alamt email anda`)
}else{
Swal.fire({
title: 'Loading!!!',
timerProgressBar: true,
didOpen: () => {
Swal.showLoading()
}
})
google.script.run.withSuccessHandler((output)=>{
if(output == 'success'){
Swal.fire({
position: 'center',
icon: 'success',
title: 'Kata sandi telah dikirim ke alamat email Anda.!!',
showConfirmButton: false,
timer: 1500
})
}else{
Swal.fire({
position: 'center',
icon: 'error',
title: 'Email ini tidak ada di sistem.!!',
showConfirmButton: false,
timer: 1500
})
}
}).sendMail(email)
}
return {email: email }
}
})
}
</script>
<script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script>
Masukkan Password Untuk Melihat Script (Password sama dengan di atas)
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<title>Dashboard</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css"
integrity="sha512-MV7K8+y+gLIBoVD59lQIYicR65iaqukzvf/nwasF0nqhPay5w/9lJmVM2hMDcnK1OnMGCdVK+iQrJ7lzPJQd1w=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js"
integrity="sha512-STof4xm1wgkfm7heWqFJVn58Hm3EtS31XFaagaa8VMReCXAkQnJZ+jEy8PCC/iT18dFy95WcExNHFTqLyp72eQ=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Prompt&display=swap');
* {
font-family: Prompt, sans-serif;
}
.responsive {
max-width: 100%;
height: auto;
}
</style>
</head>
<body>
<?var url = getUrl();?>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a style="pointer-events: none; cursor: default;" href="#" class="navbar-brand" >Javabitpro</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active open-page-btn" id="page0-btn" href="#">Beranda</a>
</li>
<li class="nav-item">
<a class="nav-link active open-page-btn" id="page1-btn" href="#">Halaman 1</a>
</li>
<li class="nav-item">
<a class="nav-link active open-page-btn" id="page2-btn" href="#">Halaman 2</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Menu Bertingkat
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item open-page-btn" href="#" id="page1-btn">Submenu1</a></li>
<li><a class="dropdown-item open-page-btn " href="#" id="page2-btn">Submenu2</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li><a class="dropdown-item open-page-btn" href="#" id="page3-btn">Submenu3</a></li>
</ul>
</li>
</ul>
<form class="d-flex">
<button class="btn btn-warning text-dark" id="btnLogOut" type="submit" onclick="logout(<?=url?>)">Logout</button>
</form>
</div>
</div>
</nav>
<div class="container p-3">
<!-- <h2 class="text-center">Selamat Datang..</h2> -->
<div>
<section id="page0" class="pages">
<?!= HtmlService.createHtmlOutputFromFile('beranda').getContent() ?>
</section>
</div>
</div>
<section id="page1" class="pages">
<?!= HtmlService.createHtmlOutputFromFile('halaman1').getContent() ?>
</section>
<section id="page2" class="pages">
<?!= HtmlService.createHtmlOutputFromFile('halaman2').getContent() ?>
</section>
</div>
<?var url = getUrl();?><input type="hidden" value="<?= url ?>" id="url" />
<script>
$(document).ready(function () {
$(".pages").hide()
$('#page0').show()
});
$(".open-page-btn").click(function () {
event.preventDefault()
let id = $(this).attr("id")
let page = id.replace("-btn", "")
$(".pages").hide()
$("#" + page).show()
})
var lockObj = localStorage.getItem("lock")
var url = document.getElementById("url").value;
window.onload = () => {
try {
lockObj = JSON.parse(lockObj)
} catch (error) {
lockObj = {
status: 'none',
exp: 0
}
}
console.log(lockObj)
if (lockObj?.status == 'logout' || lockObj?.exp < new Date().getTime()) {
logout(url)
} else {
linkWeb(url)
}
}
function linkWeb(url) {
// changePage('index')
// window.open(url+'?page=index','_top')
}
function logout(url) {
let lockObj = {
status: "logout"
// exp : new Date().getTime() + SESSION_TIME
}
localStorage.setItem("lock", JSON.stringify(lockObj));
changePage('login')
}
function changePage(page) {
event.preventDefault()
google.script.run.withSuccessHandler(res => {
document.open()
document.write(res)
document.close()
}).changePage(page)
}
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous">
</script>
</body>
</html>
<style>.footer,.generic-footer{margin-bottom:98px}@media (min-width:52px){.footer,.generic-footer{margin-bottom:78px}}@media (min-width:52px){.footer,.generic-footer{margin-bottom:56px}}@media (min-width:52px){.footer,.generic-footer{margin-bottom:0}}.disclaimer{position:fixed;z-index:9999999;bottom:0;right:0;border-top:2px solid #ff5c62;text-align:center;font-size:14px;font-weight:400;background-color:#fff;padding:5px 10px 5px 10px}.disclaimer a:hover{text-decoration:underline}@media (min-width:52px){.disclaimer{text-align:right;border-left:2px solid red;border-top-left-radius:10px}}@media (min-width:1920px){.disclaimer{width:20%}}</style><div class="disclaimer">Version.02.25.23 @Copyright <a title="https://www.javabitpro.com/" target="_blank" href="https://www.javabitpro.com/" style="color: black;"><b>www.javabitpro.com</b></a></div>
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<title>Dashboard</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css"
integrity="sha512-MV7K8+y+gLIBoVD59lQIYicR65iaqukzvf/nwasF0nqhPay5w/9lJmVM2hMDcnK1OnMGCdVK+iQrJ7lzPJQd1w=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js"
integrity="sha512-STof4xm1wgkfm7heWqFJVn58Hm3EtS31XFaagaa8VMReCXAkQnJZ+jEy8PCC/iT18dFy95WcExNHFTqLyp72eQ=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Prompt&display=swap');
* {
font-family: Prompt, sans-serif;
}
.responsive {
max-width: 100%;
height: auto;
}
</style>
</head>
<body>
<?var url = getUrl();?>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a style="pointer-events: none; cursor: default;" href="#" class="navbar-brand" >Javabitpro</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active open-page-btn" id="page0-btn" href="#">Beranda</a>
</li>
<li class="nav-item">
<a class="nav-link active open-page-btn" id="page1-btn" href="#">Halaman 1</a>
</li>
<li class="nav-item">
<a class="nav-link active open-page-btn" id="page2-btn" href="#">Halaman 2</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Menu Bertingkat
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item open-page-btn" href="#" id="page1-btn">Submenu1</a></li>
<li><a class="dropdown-item open-page-btn " href="#" id="page2-btn">Submenu2</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li><a class="dropdown-item open-page-btn" href="#" id="page3-btn">Submenu3</a></li>
</ul>
</li>
</ul>
<form class="d-flex">
<button class="btn btn-warning text-dark" id="btnLogOut" type="submit" onclick="logout(<?=url?>)">Logout</button>
</form>
</div>
</div>
</nav>
<div class="container p-3">
<!-- <h2 class="text-center">Selamat Datang..</h2> -->
<div>
<section id="page0" class="pages">
<?!= HtmlService.createHtmlOutputFromFile('beranda').getContent() ?>
</section>
</div>
</div>
<section id="page1" class="pages">
<?!= HtmlService.createHtmlOutputFromFile('halaman1').getContent() ?>
</section>
<section id="page2" class="pages">
<?!= HtmlService.createHtmlOutputFromFile('halaman2').getContent() ?>
</section>
</div>
<?var url = getUrl();?><input type="hidden" value="<?= url ?>" id="url" />
<script>
$(document).ready(function () {
$(".pages").hide()
$('#page0').show()
});
$(".open-page-btn").click(function () {
event.preventDefault()
let id = $(this).attr("id")
let page = id.replace("-btn", "")
$(".pages").hide()
$("#" + page).show()
})
var lockObj = localStorage.getItem("lock")
var url = document.getElementById("url").value;
window.onload = () => {
try {
lockObj = JSON.parse(lockObj)
} catch (error) {
lockObj = {
status: 'none',
exp: 0
}
}
console.log(lockObj)
if (lockObj?.status == 'logout' || lockObj?.exp < new Date().getTime()) {
logout(url)
} else {
linkWeb(url)
}
}
function linkWeb(url) {
// changePage('index')
// window.open(url+'?page=index','_top')
}
function logout(url) {
let lockObj = {
status: "logout"
// exp : new Date().getTime() + SESSION_TIME
}
localStorage.setItem("lock", JSON.stringify(lockObj));
changePage('login')
}
function changePage(page) {
event.preventDefault()
google.script.run.withSuccessHandler(res => {
document.open()
document.write(res)
document.close()
}).changePage(page)
}
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous">
</script>
</body>
</html>
<style>.footer,.generic-footer{margin-bottom:98px}@media (min-width:52px){.footer,.generic-footer{margin-bottom:78px}}@media (min-width:52px){.footer,.generic-footer{margin-bottom:56px}}@media (min-width:52px){.footer,.generic-footer{margin-bottom:0}}.disclaimer{position:fixed;z-index:9999999;bottom:0;right:0;border-top:2px solid #ff5c62;text-align:center;font-size:14px;font-weight:400;background-color:#fff;padding:5px 10px 5px 10px}.disclaimer a:hover{text-decoration:underline}@media (min-width:52px){.disclaimer{text-align:right;border-left:2px solid red;border-top-left-radius:10px}}@media (min-width:1920px){.disclaimer{width:20%}}</style><div class="disclaimer">Version.02.25.23 @Copyright <a title="https://www.javabitpro.com/" target="_blank" href="https://www.javabitpro.com/" style="color: black;"><b>www.javabitpro.com</b></a></div>
12. Klik ikon Save