antigravity-tc 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/bin/reset-password.js +4 -4
- package/dev.md +1 -1
- package/env.example +1 -1
- package/index.js +3 -3
- package/package.json +2 -2
- package/server.js +40 -4
- package/src/paths.js +28 -0
- package/web/dist/admin.html +1 -1
- package/web/dist/assets/{admin-Boto8g_O.js → admin-z_Di_0VN.js} +1 -2
package/README.md
CHANGED
|
@@ -91,6 +91,7 @@ Lokasi default **mengikuti OS tempat package di-install** — tanpa konfigurasi
|
|
|
91
91
|
|
|
92
92
|
| Isi | Keterangan |
|
|
93
93
|
| --- | --- |
|
|
94
|
+
| `.env` | Konfigurasi — dibuat otomatis dari `env.example` saat pertama kali jalan |
|
|
94
95
|
| `logs/donation-logs.sqlite` | Log donasi (auto-migrasi dari instalasi lama) |
|
|
95
96
|
| `bin/cloudflared` | Binary tunnel (auto-download per OS) |
|
|
96
97
|
| `logs/launcher.log` | Log saat auto-start |
|
package/bin/reset-password.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
// Hard reset password admin ATC kembali ke default.
|
|
3
3
|
// Pakai: antigravity-tc-reset-password [--yes]
|
|
4
4
|
|
|
5
|
-
const path = require('path');
|
|
6
5
|
const http = require('http');
|
|
7
6
|
const readline = require('readline');
|
|
8
7
|
|
|
9
|
-
// .env
|
|
10
|
-
|
|
8
|
+
// .env hidup di ~/.antigravity-tc/.env (konsisten dengan index.js).
|
|
9
|
+
const { ENV_PATH, ensureEnvFile } = require('../src/paths');
|
|
10
|
+
require('dotenv').config({ path: ensureEnvFile(), quiet: true });
|
|
11
11
|
|
|
12
12
|
const { getConfig } = require('../src/config');
|
|
13
13
|
|
|
@@ -56,7 +56,7 @@ async function main() {
|
|
|
56
56
|
console.log('bukan dari dashboard — reset di sini tidak akan mengubahnya.');
|
|
57
57
|
console.log('');
|
|
58
58
|
console.log('Solusi : hapus/ubah baris APP_PASSWORD di .env, lalu restart aplikasi.');
|
|
59
|
-
console.log(`Lokasi : ${
|
|
59
|
+
console.log(`Lokasi : ${ENV_PATH}`);
|
|
60
60
|
process.exit(0);
|
|
61
61
|
}
|
|
62
62
|
|
package/dev.md
CHANGED
|
@@ -18,7 +18,7 @@ cp env.example .env # lalu isi nilai
|
|
|
18
18
|
npm run build:web # build frontend sekali sebelum jalan dari source
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
File `.env`
|
|
21
|
+
File `.env` hidup di **`~/.antigravity-tc/.env`** (bukan folder project/cwd). Saat pertama kali jalan, app otomatis membuatnya dari `env.example` — atau memigrasi `.env` lama di folder project bila ada. Override lokal saat development tetap bisa dengan mengedit file itu.
|
|
22
22
|
|
|
23
23
|
### Variabel `.env`
|
|
24
24
|
|
package/env.example
CHANGED
package/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const path = require('path');
|
|
3
|
-
// .env
|
|
4
|
-
//
|
|
5
|
-
require('dotenv').config({ path:
|
|
3
|
+
// .env hidup di ~/.antigravity-tc/.env (dibuat otomatis dari env.example saat
|
|
4
|
+
// pertama kali jalan) — bukan di folder project/cwd.
|
|
5
|
+
require('dotenv').config({ path: require('./src/paths').ensureEnvFile(), quiet: true });
|
|
6
6
|
|
|
7
7
|
const fs = require('fs');
|
|
8
8
|
const os = require('os');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "antigravity-tc",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Antigravity Token Collector — tray app untuk mengumpulkan & mengelola donasi token Antigravity ke 9Router",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"vite"
|
|
38
38
|
],
|
|
39
39
|
"author": "hifzi",
|
|
40
|
-
|
|
40
|
+
"repository": {
|
|
41
41
|
"type": "git",
|
|
42
42
|
"url": "https://github.com/hifzi/antigravity-tc"
|
|
43
43
|
},
|
package/server.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const path = require('path');
|
|
3
|
-
// .env
|
|
4
|
-
//
|
|
5
|
-
require('dotenv').config({ path:
|
|
3
|
+
// .env hidup di ~/.antigravity-tc/.env (dibuat otomatis dari env.example saat
|
|
4
|
+
// pertama kali jalan) — wajib dimuat sebelum konstanta env di bawah dibaca.
|
|
5
|
+
require('dotenv').config({ path: require('./src/paths').ensureEnvFile(), quiet: true });
|
|
6
6
|
|
|
7
7
|
const http = require('http');
|
|
8
8
|
const https = require('https');
|
|
@@ -56,7 +56,7 @@ const OAUTH_CLIENT_ID = process.env.OAUTH_CLIENT_ID || decodeBuiltin(BUILTIN_OAU
|
|
|
56
56
|
const OAUTH_CLIENT_SECRET = process.env.OAUTH_CLIENT_SECRET || decodeBuiltin(BUILTIN_OAUTH_CLIENT_SECRET_ENC);
|
|
57
57
|
const OAUTH_METHOD = ['popup', 'new_tab', 'new-tab'].includes(String(process.env.OAUTH_METHOD || '').toLowerCase())
|
|
58
58
|
? (String(process.env.OAUTH_METHOD).toLowerCase() === 'popup' ? 'popup' : 'tab')
|
|
59
|
-
: '
|
|
59
|
+
: 'popup';
|
|
60
60
|
const CONFIGURED_APP_ORIGIN = new URL(APP_URL).origin;
|
|
61
61
|
|
|
62
62
|
const OAUTH_SCOPE = [
|
|
@@ -1128,6 +1128,42 @@ const server = http.createServer(async (req, res) => {
|
|
|
1128
1128
|
return res.end();
|
|
1129
1129
|
}
|
|
1130
1130
|
|
|
1131
|
+
// --- API EXPORT CSV SELURUH DONASI (bukan hanya halaman aktif) ---
|
|
1132
|
+
if (req.method === 'GET' && pathname === '/api/donations/export') {
|
|
1133
|
+
if (!requireAdmin(req, res)) return;
|
|
1134
|
+
try {
|
|
1135
|
+
const db = getLogDb();
|
|
1136
|
+
const rows = db.prepare(`
|
|
1137
|
+
SELECT donor_name, donor_email, requested_for, source, status,
|
|
1138
|
+
created_at, access_token, refresh_token, expiry
|
|
1139
|
+
FROM donation_logs
|
|
1140
|
+
ORDER BY created_at DESC
|
|
1141
|
+
`).all();
|
|
1142
|
+
db.close();
|
|
1143
|
+
|
|
1144
|
+
const header = ['Name', 'Email', 'RequestedFor', 'Source', 'Status', 'CreatedAt', 'AccessToken', 'RefreshToken', 'Expiry'];
|
|
1145
|
+
const csv = [header, ...rows.map((row) => [
|
|
1146
|
+
row.donor_name,
|
|
1147
|
+
row.donor_email,
|
|
1148
|
+
row.requested_for,
|
|
1149
|
+
row.source,
|
|
1150
|
+
row.status,
|
|
1151
|
+
row.created_at,
|
|
1152
|
+
row.access_token || '',
|
|
1153
|
+
row.refresh_token || '',
|
|
1154
|
+
row.expiry || '',
|
|
1155
|
+
])]
|
|
1156
|
+
.map((row) => row.map((col) => `"${String(col).replace(/"/g, '""')}"`).join(','))
|
|
1157
|
+
.join('\r\n');
|
|
1158
|
+
|
|
1159
|
+
res.setHeader('Content-Type', 'text/csv; charset=utf-8');
|
|
1160
|
+
res.setHeader('Content-Disposition', `attachment; filename="donasi-token-${new Date().toISOString().slice(0, 10)}.csv"`);
|
|
1161
|
+
return res.end(csv);
|
|
1162
|
+
} catch (error) {
|
|
1163
|
+
return sendJSON(res, 500, { success: false, error: error.message });
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1131
1167
|
if (req.method === 'GET' && pathname === '/api/donations') {
|
|
1132
1168
|
if (!requireAdmin(req, res)) return;
|
|
1133
1169
|
try {
|
package/src/paths.js
CHANGED
|
@@ -5,6 +5,31 @@ const fs = require('fs');
|
|
|
5
5
|
const APP_DIR = path.join(os.homedir(), '.antigravity-tc');
|
|
6
6
|
const LOGS_DIR = path.join(APP_DIR, 'logs');
|
|
7
7
|
const BIN_DIR = path.join(APP_DIR, 'bin');
|
|
8
|
+
const ENV_PATH = path.join(APP_DIR, '.env');
|
|
9
|
+
const ENV_EXAMPLE_PATH = path.join(__dirname, '..', 'env.example');
|
|
10
|
+
const LEGACY_ENV_PATH = path.join(__dirname, '..', '.env');
|
|
11
|
+
|
|
12
|
+
// .env hidup di ~/.antigravity-tc/.env. Saat pertama kali jalan:
|
|
13
|
+
// 1) jika sudah ada → pakai apa adanya;
|
|
14
|
+
// 2) jika ada .env lama di folder project → migrasi (copy) satu kali;
|
|
15
|
+
// 3) jika belum ada sama sekali → salin dari env.example.
|
|
16
|
+
function ensureEnvFile() {
|
|
17
|
+
if (fs.existsSync(ENV_PATH)) return ENV_PATH;
|
|
18
|
+
try {
|
|
19
|
+
ensureAppDirs();
|
|
20
|
+
if (fs.existsSync(LEGACY_ENV_PATH)) {
|
|
21
|
+
fs.copyFileSync(LEGACY_ENV_PATH, ENV_PATH);
|
|
22
|
+
console.log(`[env] Migrasi .env lama → ${ENV_PATH}`);
|
|
23
|
+
} else if (fs.existsSync(ENV_EXAMPLE_PATH)) {
|
|
24
|
+
fs.copyFileSync(ENV_EXAMPLE_PATH, ENV_PATH);
|
|
25
|
+
console.log(`[env] Membuat ${ENV_PATH} dari env.example — silakan sesuaikan bila perlu.`);
|
|
26
|
+
} else {
|
|
27
|
+
fs.writeFileSync(ENV_PATH, 'PORT=3456\nAPP_PASSWORD=\n');
|
|
28
|
+
console.log(`[env] Membuat ${ENV_PATH}`);
|
|
29
|
+
}
|
|
30
|
+
} catch (e) {}
|
|
31
|
+
return ENV_PATH;
|
|
32
|
+
}
|
|
8
33
|
|
|
9
34
|
// Default lokasi database 9Router mengikuti OS tempat app di-install:
|
|
10
35
|
// - Windows : %APPDATA%/9router/db/data.sqlite
|
|
@@ -51,9 +76,12 @@ module.exports = {
|
|
|
51
76
|
APP_DIR,
|
|
52
77
|
LOGS_DIR,
|
|
53
78
|
BIN_DIR,
|
|
79
|
+
ENV_PATH,
|
|
80
|
+
ENV_EXAMPLE_PATH,
|
|
54
81
|
LOG_DB_PATH: path.join(LOGS_DIR, 'donation-logs.sqlite'),
|
|
55
82
|
DEFAULT_9ROUTER_DB,
|
|
56
83
|
CLOUDFLARED_BIN: path.join(BIN_DIR, process.platform === 'win32' ? 'cloudflared.exe' : 'cloudflared'),
|
|
57
84
|
ensureAppDirs,
|
|
85
|
+
ensureEnvFile,
|
|
58
86
|
migrateLegacyLogDb,
|
|
59
87
|
};
|
package/web/dist/admin.html
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
href="https://fonts.googleapis.com/css2?family=Archivo+Black&family=Space+Grotesk:wght@400;500;700&display=swap"
|
|
12
12
|
rel="stylesheet"
|
|
13
13
|
/>
|
|
14
|
-
<script type="module" crossorigin src="/assets/admin-
|
|
14
|
+
<script type="module" crossorigin src="/assets/admin-z_Di_0VN.js"></script>
|
|
15
15
|
<link rel="modulepreload" crossorigin href="/assets/styles-pGt3BQwq.js">
|
|
16
16
|
<link rel="stylesheet" crossorigin href="/assets/styles-WqBkvfmY.css">
|
|
17
17
|
<link rel="stylesheet" crossorigin href="/assets/admin-DPInPm4J.css">
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import{B as e,C as t,E as n,F as r,G as i,H as a,I as o,J as s,K as c,L as l,M as u,N as d,O as f,P as p,R as m,S as h,T as g,V as _,W as v,_ as y,a as b,b as x,c as S,d as C,f as w,g as T,i as E,j as D,k as O,l as k,m as A,n as j,o as ee,p as te,q as ne,r as M,s as re,t as ie,u as ae,v as oe,w as N,x as P,y as F}from"./styles-pGt3BQwq.js";function I(e,t=`success`){L.message=e,L.type=t,L.visible=!0,clearTimeout(R),R=setTimeout(()=>{L.visible=!1},3e3)}var L,R,z=s((()=>{w(),L=e({message:``,type:`success`,visible:!1}),R=null})),se,ce=s((()=>{w(),z(),se={__name:`ToastHost`,setup(e){return(e,t)=>(p(),n(`div`,{class:v([`toast`,[a(L).type,{show:a(L).visible}]])},c(a(L).message),3))}}}));function le({title:e,message:t,confirmLabel:n=`Ya, Lanjutkan`,cancelLabel:r=`Batal`,danger:i=!1}={}){return new Promise(a=>{V.title=e,V.message=t,V.confirmLabel=n,V.cancelLabel=r,V.danger=i,V.resolve=a,V.open=!0})}function B(e){V.resolve&&V.resolve(e),V.resolve=null,V.open=!1}var V,ue=s((()=>{w(),V=e({open:!1,title:``,message:``,confirmLabel:`Ya, Lanjutkan`,cancelLabel:`Batal`,danger:!1,resolve:null})})),de=s((()=>{})),H,fe,pe,me,he,ge,_e=s((()=>{w(),k(),ue(),de(),M(),H={class:`confirm-card`,role:`dialog`,"aria-modal":`true`},fe={class:`confirm-title`},pe={class:`confirm-message`},me={class:`confirm-actions`},he={__name:`ConfirmDialog`,setup(e){function r(e){e.key===`Escape`&&B(!1)}return d(()=>document.addEventListener(`keydown`,r)),u(()=>document.removeEventListener(`keydown`,r)),(e,r)=>(p(),N(P,{to:`body`},[a(V).open?(p(),n(`div`,{key:0,class:`confirm-overlay`,onClick:r[2]||=F(e=>a(B)(!1),[`self`])},[t(`div`,H,[t(`div`,{class:v([`confirm-icon`,{danger:a(V).danger}])},[O(S,{name:a(V).danger?`alert`:`check-circle`,size:26},null,8,[`name`])],2),t(`h2`,fe,c(a(V).title),1),t(`p`,pe,c(a(V).message),1),t(`div`,me,[t(`button`,{class:`btn btn-secondary`,onClick:r[0]||=e=>a(B)(!1)},[O(S,{name:`x`,size:16}),f(` `+c(a(V).cancelLabel),1)]),t(`button`,{class:v([`btn`,a(V).danger?`btn-danger`:`btn-primary`]),onClick:r[1]||=e=>a(B)(!0)},[O(S,{name:a(V).danger?`trash`:`check`,size:16},null,8,[`name`]),f(` `+c(a(V).confirmLabel),1)],2)])])])):g(``,!0)]))}},ge=j(he,[[`__scopeId`,`data-v-2e9843c0`]])}));function ve(){return new Date().toLocaleString(`id-ID`)}async function ye(){try{let e=await E(`/api/password-status`);K.passwordIsDefault=e.isDefault}catch{K.passwordIsDefault=!1}}async function be(){try{let e=await E(`/api/session`);K.authed=!!e.success}catch{K.authed=!1}K.authChecked=!0,ye()}async function xe(e){if(!(await b(`/api/verify-password`,{password:e})).success)throw Error(`Password salah`);K.authed=!0,K.connStatus=`Terhubung`,await Promise.all([U(!1),W()])}async function Se(){try{await fetch(`/api/logout`,{method:`POST`})}catch{}Be(),K.authed=!1,K.view=`dashboard`,ye(),I(`🚪 Logout berhasil`,`success`)}async function U(e=!0){let t=await E(`/api/donations?page=${K.page}&pageSize=10`);if(!t.success)throw Error(t.error||`Gagal memuat donation logs`);K.donations=t.donations||[],K.page=t.page,K.pageCount=t.pageCount,K.total=t.total,K.stats=t.stats||K.stats,K.lastSync=ve(),e&&I(`✅ Dashboard diperbarui`,`success`)}async function Ce(e){let t=K.page+e;t<1||t>K.pageCount||(K.page=t,await U(!1))}async function we(e){let t=K.donations.find(t=>t.id===e);if(await le({title:`Hapus Log Donasi?`,message:t?`Log donasi dari "${t.name}" (${t.email}) akan dihapus permanen. Token yang sudah tersimpan di 9Router tidak ikut terhapus.`:`Log donasi ini akan dihapus permanen.`,confirmLabel:`Ya, Hapus`,danger:!0}))try{let t=await re(await fetch(`/api/donations/${encodeURIComponent(e)}`,{method:`DELETE`}));if(!t.success)throw Error(t.error);K.page>1&&K.donations.length===1&&--K.page,await U(!1),I(`✅ Log donasi dihapus`,`success`)}catch(e){I(`❌ `+e.message,`error`)}}async function Te(e){K.ceLoadingId=e;try{let t=await b(`/api/donations/${encodeURIComponent(e)}/check-eligibility`);if(!t.success)throw Error(t.error||`Check eligibility gagal`);K.eligibilityLog={data:t,id:e},I(t.eligible?`✅ Token eligible`:`⚠️ Token belum eligible`,t.eligible?`success`:`error`)}catch(e){I(`❌ `+e.message,`error`)}finally{K.ceLoadingId=null}}async function Ee(e){try{let t=await b(`/api/donations/${encodeURIComponent(e)}/sync`);if(!t.success)throw Error(t.error);I(`🔄 ${t.message} (${t.email})`,`success`)}catch(e){I(`❌ Sync gagal: `+e.message,`error`)}}function De(){let e=[[`Name`,`Email`,`RequestedFor`,`Source`,`Status`,`CreatedAt`,`AccessToken`,`RefreshToken`,`Expiry`],...K.donations.map(e=>[e.name,e.email,e.requestedFor||`sahabat`,e.source,e.status,e.createdAt,e.accessToken||``,e.refreshToken||``,e.expiry||``])].map(e=>e.map(e=>`"${String(e).replace(/"/g,`""`)}"`).join(`,`)).join(`
|
|
2
|
-
`),t=new Blob([e],{type:`text/csv;charset=utf-8;`}),n=URL.createObjectURL(t),r=document.createElement(`a`);r.href=n,r.download=`donasi-token-${Date.now()}.csv`,r.click(),I(`✅ Data berhasil diexport`,`success`)}async function Oe(e){if(e)try{let t=await e.text();I(`✅ ${(await b(`/api/donations/import`,{csv:t})).message}`,`success`),await U(!1)}catch(e){I(`❌ Import gagal: `+e.message,`error`)}}function ke(){let e=screen.width/2-250,t=screen.height/2-300,n=window.open(`/auth/google`,`g`,`width=500,height=600,top=${t},left=${e}`);if(!n)return I(`Popup diblokir`,`error`);let r=setInterval(()=>{n.closed&&(clearInterval(r),window.removeEventListener(`message`,i))},500);function i(e){e.source===n&&(!e.data||typeof e.data!=`object`||!Object.prototype.hasOwnProperty.call(e.data,`success`)||(clearInterval(r),window.removeEventListener(`message`,i),e.data.success?(K.tokenData=e.data.token,e.data.user&&(K.name=e.data.user.name||``,K.email=e.data.user.email||``),K.eligibilityResult=null,I(`✅ Login berhasil`,`success`)):I(`❌ Login gagal: `+(e.data.error||`Tidak diketahui`),`error`)))}window.addEventListener(`message`,i)}async function Ae(){try{let e=await b(`/api/keychain`);K.tokenData=e.token,K.eligibilityResult=null,I(`✅ Token diambil`,`success`)}catch(e){I(`❌ `+e.message,`error`)}}async function je(){let e=K.pasteInput.trim();if(!e)return I(`Paste dulu`,`error`);try{let t=await b(`/api/decode`,{raw:e});K.tokenData=t.token,K.eligibilityResult=null,I(`✅ Decode berhasil`,`success`)}catch(e){I(`❌ `+e.message,`error`)}}async function Me(){if(K.tokenData)try{let e=await b(`/api/check-eligibility`,{accessToken:K.tokenData.accessToken});if(!e.success)throw Error(e.error);K.eligibilityResult={eligible:e.eligible,message:e.message,verificationUrl:e.verificationUrl||null}}catch(e){I(`❌ `+e.message,`error`)}}function Ne(){return K.name.trim()?K.email.trim()?K.tokenData?!0:(I(`Ambil token`,`error`),!1):(I(`Email wajib`,`error`),!1):(I(`Name wajib`,`error`),!1)}async function Pe(){if(Ne())try{let e=await b(`/api/generate`,{name:K.name.trim(),email:K.email.trim(),accessToken:K.tokenData.accessToken,refreshToken:K.tokenData.refreshToken,expiry:K.tokenData.expiry,scope:K.scope.trim(),projectId:K.projectId.trim()});if(!e.success)throw Error(e.error);K.output=e.query,I(`✅ ${e.isUpdate?`Query UPDATE`:`Query INSERT`}!`,`success`)}catch(e){I(`❌ `+e.message,`error`)}}async function Fe(){if(Ne())try{let e=await b(`/api/insert`,{name:K.name.trim(),email:K.email.trim(),accessToken:K.tokenData.accessToken,refreshToken:K.tokenData.refreshToken,expiry:K.tokenData.expiry,scope:K.scope.trim(),projectId:K.projectId.trim(),requestedFor:`admin-panel`,source:`admin`});if(!e.success)throw Error(e.error);await U(!1),I(`✅ `+e.message,`success`)}catch(e){I(`❌ `+e.message,`error`)}}function Ie(){navigator.clipboard.writeText(K.output),I(`Copied!`,`success`)}function Le(){let e=new Blob([K.output],{type:`text/sql`}),t=URL.createObjectURL(e),n=document.createElement(`a`);n.href=t,n.download=`insert-${Date.now()}.sql`,n.click()}function Re(){K.name=``,K.email=``,K.scope=``,K.projectId=``,K.pasteInput=``,K.output=``,K.tokenData=null,K.eligibilityResult=null,I(`🔄 Reset selesai`,`success`)}async function W(){try{let e=await E(`/api/settings`);K.settings=e,K.passwordIsDefault=e.passwordIsDefault}catch(e){I(`❌ Gagal memuat pengaturan: `+e.message,`error`)}}function ze(){q||=setInterval(async()=>{try{let e=await E(`/api/settings`);e.success&&(K.settings=e,K.passwordIsDefault=e.passwordIsDefault)}catch{}},4e3)}function Be(){q&&=(clearInterval(q),null)}async function Ve(e,t){let n=await b(`/api/password`,{currentPassword:e,newPassword:t});if(!n.success)throw Error(n.error||`Gagal mengganti password`);I(`✅ `+n.message+`. Tunnel sekarang bisa diaktifkan.`,`success`),await W()}async function He(e){I(`✅ `+(await b(`/api/settings`,{nineRouterDbPath:e})).message,`success`),await W()}async function Ue(){let e=!(K.settings&&K.settings.autoStart);try{let t=await b(`/api/autostart`,{enabled:e});if(!t.success)throw Error(t.error||`Gagal mengubah auto start`);I(`✅ `+t.message,`success`)}catch(e){I(`❌ `+e.message,`error`)}await W()}function G(e){K.settings&&(K.settings.tunnel=e)}async function We(){let e=!(K.settings&&K.settings.tunnel&&K.settings.tunnel.enabled);G({enabled:!1,url:null,status:e?`starting`:`stopping`}),Ge();try{let t=await b(`/api/tunnel`,{enabled:e});if(!t.success)throw Error(t.error||`Gagal mengubah status tunnel`);G(t.tunnel),I(e?`✅ Tunnel aktif: `+(t.tunnel.url||`-`):`✅ Tunnel dimatikan`,`success`)}catch(e){I(`❌ `+e.message,`error`);try{let e=await E(`/api/tunnel`);e.success&&G(e.tunnel)}catch{}}}function Ge(){J||=setInterval(async()=>{try{let e=await E(`/api/tunnel`);e.success&&(G(e.tunnel),e.tunnel.status!==`starting`&&Ke())}catch{}},2e3)}function Ke(){J&&=(clearInterval(J),null)}var K,q,J,Y=s((()=>{w(),ee(),z(),ue(),K=e({authed:!1,authChecked:!1,view:`dashboard`,passwordIsDefault:!0,connStatus:`Belum login`,lastSync:`-`,donations:[],page:1,pageCount:1,total:0,stats:{tokenCount:0,donorCount:0,todayCount:0},eligibilityLog:null,ceLoadingId:null,tokenData:null,tokenTab:`google`,name:``,email:``,scope:``,projectId:``,pasteInput:``,output:``,advancedOpen:!1,eligibilityResult:null,settings:null}),q=null,J=null})),qe=s((()=>{})),Je,Ye,Xe,Ze,Qe,$e,et,tt,nt,rt,it,at=s((()=>{w(),C(),k(),Y(),z(),qe(),M(),Je={class:`mx-auto mt-8 max-w-md neo-card p-8 text-center sm:p-10`},Ye={class:`neo-display mt-4 inline-flex items-center justify-center gap-3 text-2xl`},Xe={class:`login-lock`},Ze={class:`mt-6 text-left`},Qe={class:`field`},$e=[`disabled`],et=[`disabled`],tt={key:0,class:`spinner`},nt={key:0,class:`default-pass-hint`},rt={__name:`LoginCard`,setup(e){let r=_(``),i=_(!1);async function o(){if(!i.value){i.value=!0;try{await xe(r.value),r.value=``}catch(e){I(`❌ `+(e.message||`Password salah`),`error`)}finally{i.value=!1}}}return(e,s)=>(p(),n(`div`,Je,[O(ae,{width:150,class:`mx-auto`}),t(`h2`,Ye,[t(`span`,Xe,[O(S,{name:`lock`,size:22})]),s[1]||=f(` Dashboard Manager `,-1)]),s[5]||=t(`p`,{class:`mt-3 text-sm font-medium`},`Masukkan password untuk mengakses dashboard.`,-1),t(`div`,Ze,[t(`div`,Qe,[s[2]||=t(`label`,{for:`adminPass`},`Password`,-1),m(t(`input`,{id:`adminPass`,"onUpdate:modelValue":s[0]||=e=>r.value=e,type:`password`,placeholder:`Password`,disabled:i.value,onKeydown:oe(o,[`enter`])},null,40,$e),[[T,r.value]])])]),t(`button`,{class:`btn btn-primary mt-2 w-full`,disabled:i.value,onClick:o},[i.value?(p(),n(`span`,tt)):(p(),N(S,{key:1,name:`arrow-right`,size:16})),s[3]||=t(`span`,null,`Masuk`,-1)],8,et),a(K).passwordIsDefault?(p(),n(`div`,nt,[...s[4]||=[t(`strong`,null,`Password default:`,-1),f(),t(`code`,null,`1234567890`,-1),t(`br`,null,null,-1),f(` Demi keamanan, segera ganti password di menu `,-1),t(`strong`,null,`Pengaturan → Keamanan`,-1),f(` setelah login. `,-1)]])):g(``,!0)]))}},it=j(rt,[[`__scopeId`,`data-v-8cb9a1a5`]])})),ot=s((()=>{})),st,ct,X,lt,ut,dt,ft=s((()=>{w(),k(),ot(),M(),st={class:`dd-root`},ct=[`onClick`],X=e({id:null}),lt=0,ut={__name:`DropdownMenu`,props:{items:{type:Array,required:!0}},emits:[`select`],setup(e,{emit:a}){let o=a,s=++lt,f=h(()=>X.id===s),m=_(null),y=_(null),b=_({});async function C(){if(f.value){X.id=null;return}X.id=s,await D(),w()}function w(){let e=m.value,t=y.value;if(!e||!t)return;let n=e.getBoundingClientRect(),r=t.getBoundingClientRect(),i=n.bottom+8;i+r.height>window.innerHeight-8&&(i=Math.max(8,n.top-r.height-8));let a=n.right-r.width;a=Math.min(Math.max(a,8),window.innerWidth-8-r.width),b.value={top:`${Math.round(i)}px`,left:`${Math.round(a)}px`}}function T(e){X.id=null,o(`select`,e.key)}function E(e){if(!f.value)return;let t=e.target;m.value?.contains(t)||y.value?.contains(t)||(X.id=null)}function k(e){e.key===`Escape`&&f.value&&(X.id=null)}function A(){f.value&&(X.id=null)}return d(()=>{document.addEventListener(`click`,E),document.addEventListener(`keydown`,k),window.addEventListener(`scroll`,A,!0),window.addEventListener(`resize`,A)}),u(()=>{document.removeEventListener(`click`,E),document.removeEventListener(`keydown`,k),window.removeEventListener(`scroll`,A,!0),window.removeEventListener(`resize`,A)}),(a,o)=>(p(),n(`div`,st,[t(`button`,{ref_key:`triggerRef`,ref:m,class:`btn btn-secondary btn-icon dd-trigger`,title:`Aksi`,onClick:F(C,[`stop`])},[O(S,{name:`more`,size:18})],512),(p(),N(P,{to:`body`},[O(te,{name:`dd`},{default:l(()=>[f.value?(p(),n(`div`,{key:0,ref_key:`panelRef`,ref:y,class:`dd-panel`,style:i(b.value)},[(p(!0),n(x,null,r(e.items,e=>(p(),n(`button`,{key:e.key,class:v([`dd-item`,{danger:e.danger}]),onClick:F(t=>T(e),[`stop`])},[O(S,{name:e.icon,size:16},null,8,[`name`]),t(`span`,null,c(e.label),1)],10,ct))),128))],4)):g(``,!0)]),_:1})]))]))}},dt=j(ut,[[`__scopeId`,`data-v-ecad6e79`]])})),pt=s((()=>{})),mt,ht,gt,_t,vt,yt,bt,Z,xt=s((()=>{w(),pt(),M(),mt={class:`terminal`},ht={class:`terminal-head`},gt={class:`terminal-name`},_t={class:`ttime`},vt={class:`ttext`},yt={key:0,class:`tline t-info`},bt={__name:`Terminal`,props:{name:{type:String,default:`log`},lines:{type:Array,default:()=>[]},height:{type:String,default:`230px`}},setup(e){let a=e,s=_(null);return o(()=>a.lines.length,()=>{D(()=>{let e=s.value;e&&(e.scrollTop=e.scrollHeight)})}),(a,o)=>(p(),n(`div`,mt,[t(`div`,ht,[o[0]||=t(`span`,{class:`tdot td-r`},null,-1),o[1]||=t(`span`,{class:`tdot td-y`},null,-1),o[2]||=t(`span`,{class:`tdot td-g`},null,-1),t(`span`,gt,c(e.name),1)]),t(`div`,{ref_key:`bodyRef`,ref:s,class:`terminal-body`,style:i({height:e.height})},[(p(!0),n(x,null,r(e.lines,(e,r)=>(p(),n(`div`,{key:r,class:v([`tline`,e.cls||`t-info`])},[t(`span`,_t,c(e.time),1),t(`span`,vt,c(e.text),1)],2))),128)),e.lines.length?g(``,!0):(p(),n(`div`,yt,[...o[3]||=[t(`span`,{class:`ttext`},`menunggu output…`,-1)]]))],4)]))}},Z=j(bt,[[`__scopeId`,`data-v-5b0ac08c`]])})),St=s((()=>{})),Ct,wt,Tt,Et,Dt,Ot,kt,At,jt,Mt,Nt,Pt,Ft,It=s((()=>{w(),k(),xt(),z(),St(),M(),Ct={class:`sync-card`,role:`dialog`,"aria-modal":`true`},wt={class:`sync-head`},Tt={class:`sync-head-icon`},Et={key:0,class:`sync-body`},Dt={class:`sync-actions`},Ot={key:1,class:`sync-body`},kt={class:`sync-progress`},At={class:`sync-progress-bar`},jt={class:`sync-progress-text`},Mt={key:0,class:`sync-done`},Nt={class:`sync-actions`},Pt={__name:`SyncAllDialog`,props:{open:{type:Boolean,default:!1}},emits:[`close`],setup(r,{emit:a}){let o=r,s=a,l=e({phase:`confirm`,total:0,processed:0,inserted:0,updated:0,errors:0,doneMessage:``}),m=e([]),_=null,v=h(()=>l.total?Math.round(l.processed/l.total*100):0);function y(e,t=`t-info`){m.push({time:new Date().toLocaleTimeString(`id-ID`),text:e,cls:t})}function b(e){e.type===`start`?(l.total=e.total,y(`Mulai sync ${e.total} data ke 9Router…`)):e.type===`log`?(l.processed=e.index,e.action===`inserted`?(l.inserted++,y(`[${e.index}/${l.total}] INSERT ${e.email}`,`t-ok`)):e.action===`updated`?(l.updated++,y(`[${e.index}/${l.total}] UPDATE ${e.email}`,`t-warn`)):(l.errors++,y(`[${e.index}/${l.total}] ERROR ${e.email} — ${e.message}`,`t-error`))):e.type===`done`?y(`Selesai: ${e.inserted} baru, ${e.updated} diupdate, ${e.errors} error.`):e.type===`error`&&y(`GAGAL: ${e.message}`,`t-error`)}async function x(){l.phase=`running`,m.length=0,l.total=0,l.processed=0,l.inserted=0,l.updated=0,l.errors=0,_=new AbortController;try{let e=await fetch(`/api/donations/sync-all`,{method:`POST`,signal:_.signal});if(!e.ok){let t=`HTTP ${e.status}`;try{let n=await e.json();n&&n.error&&(t=n.error)}catch{}y(`GAGAL: ${t}`,`t-error`),l.phase=`done`,l.doneMessage=`Sync gagal dijalankan.`;return}let t=e.body.getReader(),n=new TextDecoder,r=``;for(;;){let{done:e,value:i}=await t.read();if(e)break;r+=n.decode(i,{stream:!0});let a=r.split(`
|
|
1
|
+
import{B as e,C as t,E as n,F as r,G as i,H as a,I as o,J as s,K as c,L as l,M as u,N as d,O as f,P as p,R as m,S as h,T as g,V as _,W as v,_ as y,a as b,b as x,c as S,d as C,f as w,g as T,i as E,j as D,k as O,l as k,m as A,n as j,o as ee,p as te,q as ne,r as M,s as re,t as ie,u as ae,v as oe,w as N,x as P,y as F}from"./styles-pGt3BQwq.js";function I(e,t=`success`){L.message=e,L.type=t,L.visible=!0,clearTimeout(R),R=setTimeout(()=>{L.visible=!1},3e3)}var L,R,z=s((()=>{w(),L=e({message:``,type:`success`,visible:!1}),R=null})),se,ce=s((()=>{w(),z(),se={__name:`ToastHost`,setup(e){return(e,t)=>(p(),n(`div`,{class:v([`toast`,[a(L).type,{show:a(L).visible}]])},c(a(L).message),3))}}}));function le({title:e,message:t,confirmLabel:n=`Ya, Lanjutkan`,cancelLabel:r=`Batal`,danger:i=!1}={}){return new Promise(a=>{V.title=e,V.message=t,V.confirmLabel=n,V.cancelLabel=r,V.danger=i,V.resolve=a,V.open=!0})}function B(e){V.resolve&&V.resolve(e),V.resolve=null,V.open=!1}var V,ue=s((()=>{w(),V=e({open:!1,title:``,message:``,confirmLabel:`Ya, Lanjutkan`,cancelLabel:`Batal`,danger:!1,resolve:null})})),de=s((()=>{})),H,fe,pe,me,he,ge,_e=s((()=>{w(),k(),ue(),de(),M(),H={class:`confirm-card`,role:`dialog`,"aria-modal":`true`},fe={class:`confirm-title`},pe={class:`confirm-message`},me={class:`confirm-actions`},he={__name:`ConfirmDialog`,setup(e){function r(e){e.key===`Escape`&&B(!1)}return d(()=>document.addEventListener(`keydown`,r)),u(()=>document.removeEventListener(`keydown`,r)),(e,r)=>(p(),N(P,{to:`body`},[a(V).open?(p(),n(`div`,{key:0,class:`confirm-overlay`,onClick:r[2]||=F(e=>a(B)(!1),[`self`])},[t(`div`,H,[t(`div`,{class:v([`confirm-icon`,{danger:a(V).danger}])},[O(S,{name:a(V).danger?`alert`:`check-circle`,size:26},null,8,[`name`])],2),t(`h2`,fe,c(a(V).title),1),t(`p`,pe,c(a(V).message),1),t(`div`,me,[t(`button`,{class:`btn btn-secondary`,onClick:r[0]||=e=>a(B)(!1)},[O(S,{name:`x`,size:16}),f(` `+c(a(V).cancelLabel),1)]),t(`button`,{class:v([`btn`,a(V).danger?`btn-danger`:`btn-primary`]),onClick:r[1]||=e=>a(B)(!0)},[O(S,{name:a(V).danger?`trash`:`check`,size:16},null,8,[`name`]),f(` `+c(a(V).confirmLabel),1)],2)])])])):g(``,!0)]))}},ge=j(he,[[`__scopeId`,`data-v-2e9843c0`]])}));function ve(){return new Date().toLocaleString(`id-ID`)}async function ye(){try{let e=await E(`/api/password-status`);K.passwordIsDefault=e.isDefault}catch{K.passwordIsDefault=!1}}async function be(){try{let e=await E(`/api/session`);K.authed=!!e.success}catch{K.authed=!1}K.authChecked=!0,ye()}async function xe(e){if(!(await b(`/api/verify-password`,{password:e})).success)throw Error(`Password salah`);K.authed=!0,K.connStatus=`Terhubung`,await Promise.all([U(!1),W()])}async function Se(){try{await fetch(`/api/logout`,{method:`POST`})}catch{}Be(),K.authed=!1,K.view=`dashboard`,ye(),I(`🚪 Logout berhasil`,`success`)}async function U(e=!0){let t=await E(`/api/donations?page=${K.page}&pageSize=10`);if(!t.success)throw Error(t.error||`Gagal memuat donation logs`);K.donations=t.donations||[],K.page=t.page,K.pageCount=t.pageCount,K.total=t.total,K.stats=t.stats||K.stats,K.lastSync=ve(),e&&I(`✅ Dashboard diperbarui`,`success`)}async function Ce(e){let t=K.page+e;t<1||t>K.pageCount||(K.page=t,await U(!1))}async function we(e){let t=K.donations.find(t=>t.id===e);if(await le({title:`Hapus Log Donasi?`,message:t?`Log donasi dari "${t.name}" (${t.email}) akan dihapus permanen. Token yang sudah tersimpan di 9Router tidak ikut terhapus.`:`Log donasi ini akan dihapus permanen.`,confirmLabel:`Ya, Hapus`,danger:!0}))try{let t=await re(await fetch(`/api/donations/${encodeURIComponent(e)}`,{method:`DELETE`}));if(!t.success)throw Error(t.error);K.page>1&&K.donations.length===1&&--K.page,await U(!1),I(`✅ Log donasi dihapus`,`success`)}catch(e){I(`❌ `+e.message,`error`)}}async function Te(e){K.ceLoadingId=e;try{let t=await b(`/api/donations/${encodeURIComponent(e)}/check-eligibility`);if(!t.success)throw Error(t.error||`Check eligibility gagal`);K.eligibilityLog={data:t,id:e},I(t.eligible?`✅ Token eligible`:`⚠️ Token belum eligible`,t.eligible?`success`:`error`)}catch(e){I(`❌ `+e.message,`error`)}finally{K.ceLoadingId=null}}async function Ee(e){try{let t=await b(`/api/donations/${encodeURIComponent(e)}/sync`);if(!t.success)throw Error(t.error);I(`🔄 ${t.message} (${t.email})`,`success`)}catch(e){I(`❌ Sync gagal: `+e.message,`error`)}}async function De(){try{let e=await fetch(`/api/donations/export`);if(!e.ok){let t=`HTTP ${e.status}`;try{let n=await e.json();n&&n.error&&(t=n.error)}catch{}throw Error(t)}let t=await e.blob(),n=URL.createObjectURL(t),r=document.createElement(`a`);r.href=n,r.download=`donasi-token-${Date.now()}.csv`,r.click(),URL.revokeObjectURL(n),I(`✅ Seluruh data berhasil diexport`,`success`)}catch(e){I(`❌ Export gagal: `+e.message,`error`)}}async function Oe(e){if(e)try{let t=await e.text();I(`✅ ${(await b(`/api/donations/import`,{csv:t})).message}`,`success`),await U(!1)}catch(e){I(`❌ Import gagal: `+e.message,`error`)}}function ke(){let e=screen.width/2-250,t=screen.height/2-300,n=window.open(`/auth/google`,`g`,`width=500,height=600,top=${t},left=${e}`);if(!n)return I(`Popup diblokir`,`error`);let r=setInterval(()=>{n.closed&&(clearInterval(r),window.removeEventListener(`message`,i))},500);function i(e){e.source===n&&(!e.data||typeof e.data!=`object`||!Object.prototype.hasOwnProperty.call(e.data,`success`)||(clearInterval(r),window.removeEventListener(`message`,i),e.data.success?(K.tokenData=e.data.token,e.data.user&&(K.name=e.data.user.name||``,K.email=e.data.user.email||``),K.eligibilityResult=null,I(`✅ Login berhasil`,`success`)):I(`❌ Login gagal: `+(e.data.error||`Tidak diketahui`),`error`)))}window.addEventListener(`message`,i)}async function Ae(){try{let e=await b(`/api/keychain`);K.tokenData=e.token,K.eligibilityResult=null,I(`✅ Token diambil`,`success`)}catch(e){I(`❌ `+e.message,`error`)}}async function je(){let e=K.pasteInput.trim();if(!e)return I(`Paste dulu`,`error`);try{let t=await b(`/api/decode`,{raw:e});K.tokenData=t.token,K.eligibilityResult=null,I(`✅ Decode berhasil`,`success`)}catch(e){I(`❌ `+e.message,`error`)}}async function Me(){if(K.tokenData)try{let e=await b(`/api/check-eligibility`,{accessToken:K.tokenData.accessToken});if(!e.success)throw Error(e.error);K.eligibilityResult={eligible:e.eligible,message:e.message,verificationUrl:e.verificationUrl||null}}catch(e){I(`❌ `+e.message,`error`)}}function Ne(){return K.name.trim()?K.email.trim()?K.tokenData?!0:(I(`Ambil token`,`error`),!1):(I(`Email wajib`,`error`),!1):(I(`Name wajib`,`error`),!1)}async function Pe(){if(Ne())try{let e=await b(`/api/generate`,{name:K.name.trim(),email:K.email.trim(),accessToken:K.tokenData.accessToken,refreshToken:K.tokenData.refreshToken,expiry:K.tokenData.expiry,scope:K.scope.trim(),projectId:K.projectId.trim()});if(!e.success)throw Error(e.error);K.output=e.query,I(`✅ ${e.isUpdate?`Query UPDATE`:`Query INSERT`}!`,`success`)}catch(e){I(`❌ `+e.message,`error`)}}async function Fe(){if(Ne())try{let e=await b(`/api/insert`,{name:K.name.trim(),email:K.email.trim(),accessToken:K.tokenData.accessToken,refreshToken:K.tokenData.refreshToken,expiry:K.tokenData.expiry,scope:K.scope.trim(),projectId:K.projectId.trim(),requestedFor:`admin-panel`,source:`admin`});if(!e.success)throw Error(e.error);await U(!1),I(`✅ `+e.message,`success`)}catch(e){I(`❌ `+e.message,`error`)}}function Ie(){navigator.clipboard.writeText(K.output),I(`Copied!`,`success`)}function Le(){let e=new Blob([K.output],{type:`text/sql`}),t=URL.createObjectURL(e),n=document.createElement(`a`);n.href=t,n.download=`insert-${Date.now()}.sql`,n.click()}function Re(){K.name=``,K.email=``,K.scope=``,K.projectId=``,K.pasteInput=``,K.output=``,K.tokenData=null,K.eligibilityResult=null,I(`🔄 Reset selesai`,`success`)}async function W(){try{let e=await E(`/api/settings`);K.settings=e,K.passwordIsDefault=e.passwordIsDefault}catch(e){I(`❌ Gagal memuat pengaturan: `+e.message,`error`)}}function ze(){q||=setInterval(async()=>{try{let e=await E(`/api/settings`);e.success&&(K.settings=e,K.passwordIsDefault=e.passwordIsDefault)}catch{}},4e3)}function Be(){q&&=(clearInterval(q),null)}async function Ve(e,t){let n=await b(`/api/password`,{currentPassword:e,newPassword:t});if(!n.success)throw Error(n.error||`Gagal mengganti password`);I(`✅ `+n.message+`. Tunnel sekarang bisa diaktifkan.`,`success`),await W()}async function He(e){I(`✅ `+(await b(`/api/settings`,{nineRouterDbPath:e})).message,`success`),await W()}async function Ue(){let e=!(K.settings&&K.settings.autoStart);try{let t=await b(`/api/autostart`,{enabled:e});if(!t.success)throw Error(t.error||`Gagal mengubah auto start`);I(`✅ `+t.message,`success`)}catch(e){I(`❌ `+e.message,`error`)}await W()}function G(e){K.settings&&(K.settings.tunnel=e)}async function We(){let e=!(K.settings&&K.settings.tunnel&&K.settings.tunnel.enabled);G({enabled:!1,url:null,status:e?`starting`:`stopping`}),Ge();try{let t=await b(`/api/tunnel`,{enabled:e});if(!t.success)throw Error(t.error||`Gagal mengubah status tunnel`);G(t.tunnel),I(e?`✅ Tunnel aktif: `+(t.tunnel.url||`-`):`✅ Tunnel dimatikan`,`success`)}catch(e){I(`❌ `+e.message,`error`);try{let e=await E(`/api/tunnel`);e.success&&G(e.tunnel)}catch{}}}function Ge(){J||=setInterval(async()=>{try{let e=await E(`/api/tunnel`);e.success&&(G(e.tunnel),e.tunnel.status!==`starting`&&Ke())}catch{}},2e3)}function Ke(){J&&=(clearInterval(J),null)}var K,q,J,Y=s((()=>{w(),ee(),z(),ue(),K=e({authed:!1,authChecked:!1,view:`dashboard`,passwordIsDefault:!0,connStatus:`Belum login`,lastSync:`-`,donations:[],page:1,pageCount:1,total:0,stats:{tokenCount:0,donorCount:0,todayCount:0},eligibilityLog:null,ceLoadingId:null,tokenData:null,tokenTab:`google`,name:``,email:``,scope:``,projectId:``,pasteInput:``,output:``,advancedOpen:!1,eligibilityResult:null,settings:null}),q=null,J=null})),qe=s((()=>{})),Je,Ye,Xe,Ze,Qe,$e,et,tt,nt,rt,it,at=s((()=>{w(),C(),k(),Y(),z(),qe(),M(),Je={class:`mx-auto mt-8 max-w-md neo-card p-8 text-center sm:p-10`},Ye={class:`neo-display mt-4 inline-flex items-center justify-center gap-3 text-2xl`},Xe={class:`login-lock`},Ze={class:`mt-6 text-left`},Qe={class:`field`},$e=[`disabled`],et=[`disabled`],tt={key:0,class:`spinner`},nt={key:0,class:`default-pass-hint`},rt={__name:`LoginCard`,setup(e){let r=_(``),i=_(!1);async function o(){if(!i.value){i.value=!0;try{await xe(r.value),r.value=``}catch(e){I(`❌ `+(e.message||`Password salah`),`error`)}finally{i.value=!1}}}return(e,s)=>(p(),n(`div`,Je,[O(ae,{width:150,class:`mx-auto`}),t(`h2`,Ye,[t(`span`,Xe,[O(S,{name:`lock`,size:22})]),s[1]||=f(` Dashboard Manager `,-1)]),s[5]||=t(`p`,{class:`mt-3 text-sm font-medium`},`Masukkan password untuk mengakses dashboard.`,-1),t(`div`,Ze,[t(`div`,Qe,[s[2]||=t(`label`,{for:`adminPass`},`Password`,-1),m(t(`input`,{id:`adminPass`,"onUpdate:modelValue":s[0]||=e=>r.value=e,type:`password`,placeholder:`Password`,disabled:i.value,onKeydown:oe(o,[`enter`])},null,40,$e),[[T,r.value]])])]),t(`button`,{class:`btn btn-primary mt-2 w-full`,disabled:i.value,onClick:o},[i.value?(p(),n(`span`,tt)):(p(),N(S,{key:1,name:`arrow-right`,size:16})),s[3]||=t(`span`,null,`Masuk`,-1)],8,et),a(K).passwordIsDefault?(p(),n(`div`,nt,[...s[4]||=[t(`strong`,null,`Password default:`,-1),f(),t(`code`,null,`1234567890`,-1),t(`br`,null,null,-1),f(` Demi keamanan, segera ganti password di menu `,-1),t(`strong`,null,`Pengaturan → Keamanan`,-1),f(` setelah login. `,-1)]])):g(``,!0)]))}},it=j(rt,[[`__scopeId`,`data-v-8cb9a1a5`]])})),ot=s((()=>{})),st,ct,X,lt,ut,dt,ft=s((()=>{w(),k(),ot(),M(),st={class:`dd-root`},ct=[`onClick`],X=e({id:null}),lt=0,ut={__name:`DropdownMenu`,props:{items:{type:Array,required:!0}},emits:[`select`],setup(e,{emit:a}){let o=a,s=++lt,f=h(()=>X.id===s),m=_(null),y=_(null),b=_({});async function C(){if(f.value){X.id=null;return}X.id=s,await D(),w()}function w(){let e=m.value,t=y.value;if(!e||!t)return;let n=e.getBoundingClientRect(),r=t.getBoundingClientRect(),i=n.bottom+8;i+r.height>window.innerHeight-8&&(i=Math.max(8,n.top-r.height-8));let a=n.right-r.width;a=Math.min(Math.max(a,8),window.innerWidth-8-r.width),b.value={top:`${Math.round(i)}px`,left:`${Math.round(a)}px`}}function T(e){X.id=null,o(`select`,e.key)}function E(e){if(!f.value)return;let t=e.target;m.value?.contains(t)||y.value?.contains(t)||(X.id=null)}function k(e){e.key===`Escape`&&f.value&&(X.id=null)}function A(){f.value&&(X.id=null)}return d(()=>{document.addEventListener(`click`,E),document.addEventListener(`keydown`,k),window.addEventListener(`scroll`,A,!0),window.addEventListener(`resize`,A)}),u(()=>{document.removeEventListener(`click`,E),document.removeEventListener(`keydown`,k),window.removeEventListener(`scroll`,A,!0),window.removeEventListener(`resize`,A)}),(a,o)=>(p(),n(`div`,st,[t(`button`,{ref_key:`triggerRef`,ref:m,class:`btn btn-secondary btn-icon dd-trigger`,title:`Aksi`,onClick:F(C,[`stop`])},[O(S,{name:`more`,size:18})],512),(p(),N(P,{to:`body`},[O(te,{name:`dd`},{default:l(()=>[f.value?(p(),n(`div`,{key:0,ref_key:`panelRef`,ref:y,class:`dd-panel`,style:i(b.value)},[(p(!0),n(x,null,r(e.items,e=>(p(),n(`button`,{key:e.key,class:v([`dd-item`,{danger:e.danger}]),onClick:F(t=>T(e),[`stop`])},[O(S,{name:e.icon,size:16},null,8,[`name`]),t(`span`,null,c(e.label),1)],10,ct))),128))],4)):g(``,!0)]),_:1})]))]))}},dt=j(ut,[[`__scopeId`,`data-v-ecad6e79`]])})),pt=s((()=>{})),mt,ht,gt,_t,vt,yt,bt,Z,xt=s((()=>{w(),pt(),M(),mt={class:`terminal`},ht={class:`terminal-head`},gt={class:`terminal-name`},_t={class:`ttime`},vt={class:`ttext`},yt={key:0,class:`tline t-info`},bt={__name:`Terminal`,props:{name:{type:String,default:`log`},lines:{type:Array,default:()=>[]},height:{type:String,default:`230px`}},setup(e){let a=e,s=_(null);return o(()=>a.lines.length,()=>{D(()=>{let e=s.value;e&&(e.scrollTop=e.scrollHeight)})}),(a,o)=>(p(),n(`div`,mt,[t(`div`,ht,[o[0]||=t(`span`,{class:`tdot td-r`},null,-1),o[1]||=t(`span`,{class:`tdot td-y`},null,-1),o[2]||=t(`span`,{class:`tdot td-g`},null,-1),t(`span`,gt,c(e.name),1)]),t(`div`,{ref_key:`bodyRef`,ref:s,class:`terminal-body`,style:i({height:e.height})},[(p(!0),n(x,null,r(e.lines,(e,r)=>(p(),n(`div`,{key:r,class:v([`tline`,e.cls||`t-info`])},[t(`span`,_t,c(e.time),1),t(`span`,vt,c(e.text),1)],2))),128)),e.lines.length?g(``,!0):(p(),n(`div`,yt,[...o[3]||=[t(`span`,{class:`ttext`},`menunggu output…`,-1)]]))],4)]))}},Z=j(bt,[[`__scopeId`,`data-v-5b0ac08c`]])})),St=s((()=>{})),Ct,wt,Tt,Et,Dt,Ot,kt,At,jt,Mt,Nt,Pt,Ft,It=s((()=>{w(),k(),xt(),z(),St(),M(),Ct={class:`sync-card`,role:`dialog`,"aria-modal":`true`},wt={class:`sync-head`},Tt={class:`sync-head-icon`},Et={key:0,class:`sync-body`},Dt={class:`sync-actions`},Ot={key:1,class:`sync-body`},kt={class:`sync-progress`},At={class:`sync-progress-bar`},jt={class:`sync-progress-text`},Mt={key:0,class:`sync-done`},Nt={class:`sync-actions`},Pt={__name:`SyncAllDialog`,props:{open:{type:Boolean,default:!1}},emits:[`close`],setup(r,{emit:a}){let o=r,s=a,l=e({phase:`confirm`,total:0,processed:0,inserted:0,updated:0,errors:0,doneMessage:``}),m=e([]),_=null,v=h(()=>l.total?Math.round(l.processed/l.total*100):0);function y(e,t=`t-info`){m.push({time:new Date().toLocaleTimeString(`id-ID`),text:e,cls:t})}function b(e){e.type===`start`?(l.total=e.total,y(`Mulai sync ${e.total} data ke 9Router…`)):e.type===`log`?(l.processed=e.index,e.action===`inserted`?(l.inserted++,y(`[${e.index}/${l.total}] INSERT ${e.email}`,`t-ok`)):e.action===`updated`?(l.updated++,y(`[${e.index}/${l.total}] UPDATE ${e.email}`,`t-warn`)):(l.errors++,y(`[${e.index}/${l.total}] ERROR ${e.email} — ${e.message}`,`t-error`))):e.type===`done`?y(`Selesai: ${e.inserted} baru, ${e.updated} diupdate, ${e.errors} error.`):e.type===`error`&&y(`GAGAL: ${e.message}`,`t-error`)}async function x(){l.phase=`running`,m.length=0,l.total=0,l.processed=0,l.inserted=0,l.updated=0,l.errors=0,_=new AbortController;try{let e=await fetch(`/api/donations/sync-all`,{method:`POST`,signal:_.signal});if(!e.ok){let t=`HTTP ${e.status}`;try{let n=await e.json();n&&n.error&&(t=n.error)}catch{}y(`GAGAL: ${t}`,`t-error`),l.phase=`done`,l.doneMessage=`Sync gagal dijalankan.`;return}let t=e.body.getReader(),n=new TextDecoder,r=``;for(;;){let{done:e,value:i}=await t.read();if(e)break;r+=n.decode(i,{stream:!0});let a=r.split(`
|
|
3
2
|
`);r=a.pop();for(let e of a)e.trim()&&b(JSON.parse(e))}}catch(e){e.name===`AbortError`?y(`Sync dibatalkan.`,`t-error`):y(`GAGAL: ${e.message}`,`t-error`),l.phase=`done`,l.doneMessage=`Sync berhenti di tengah jalan.`;return}l.phase=`done`,l.doneMessage=`Selesai: ${l.inserted} baru, ${l.updated} diupdate, ${l.errors} error dari ${l.total} data.`,I(`✅ `+l.doneMessage,`success`)}function C(){_&&_.abort()}function w(){l.phase!==`running`&&s(`close`)}function T(e){e.key===`Escape`&&o.open&&l.phase!==`running`&&s(`close`)}return d(()=>document.addEventListener(`keydown`,T)),u(()=>document.removeEventListener(`keydown`,T)),(e,a)=>(p(),N(P,{to:`body`},[r.open?(p(),n(`div`,{key:0,class:`sync-overlay`,onClick:F(w,[`self`])},[t(`div`,Ct,[t(`div`,wt,[t(`span`,Tt,[O(S,{name:`database`,size:20})]),a[3]||=t(`div`,null,[t(`h2`,{class:`sync-title`},`Sync Semua ke 9Router`),t(`p`,{class:`sync-sub`},`Upsert seluruh donasi (key: email) ke providerConnections`)],-1),l.phase===`running`?g(``,!0):(p(),n(`button`,{key:0,class:`btn btn-secondary btn-icon`,title:`Tutup`,onClick:a[0]||=e=>s(`close`)},[O(S,{name:`x`,size:15})]))]),l.phase===`confirm`?(p(),n(`div`,Et,[a[6]||=t(`p`,{class:`sync-message`},[f(` Seluruh data donasi yang memiliki token akan dimasukkan ke database 9Router. Cocok setelah `),t(`strong`,null,`export → import di tempat lain`),f(`: data yang belum ada akan di-`),t(`strong`,null,`INSERT`),f(` (priority urutan terakhir), yang sudah ada akan di-`),t(`strong`,null,`UPDATE`),f(`. `)],-1),t(`div`,Dt,[t(`button`,{class:`btn btn-secondary`,onClick:a[1]||=e=>s(`close`)},[O(S,{name:`x`,size:15}),a[4]||=f(` Batal `,-1)]),t(`button`,{class:`btn btn-primary`,onClick:x},[O(S,{name:`play`,size:15}),a[5]||=f(` Mulai Sync `,-1)])])])):(p(),n(`div`,Ot,[t(`div`,kt,[t(`div`,At,[t(`div`,{class:`sync-progress-fill`,style:i({width:`${v.value}%`})},null,4)]),t(`span`,jt,c(l.processed)+`/`+c(l.total||`…`)+` (`+c(v.value)+`%)`,1)]),O(Z,{name:`sync-9router.log`,lines:m},null,8,[`lines`]),l.phase===`done`?(p(),n(`p`,Mt,c(l.doneMessage),1)):g(``,!0),t(`div`,Nt,[l.phase===`running`?(p(),n(`button`,{key:0,class:`btn btn-secondary`,onClick:C},[O(S,{name:`x`,size:15}),a[7]||=f(` Batalkan `,-1)])):g(``,!0),l.phase===`done`?(p(),n(`button`,{key:1,class:`btn btn-primary`,onClick:a[2]||=e=>s(`close`)},[O(S,{name:`check`,size:15}),a[8]||=f(` Selesai `,-1)])):g(``,!0)])]))])])):g(``,!0)]))}},Ft=j(Pt,[[`__scopeId`,`data-v-79db2475`]])})),Lt=s((()=>{})),Rt,zt,Bt,Vt,Ht,Ut,Wt,Gt,Kt,qt,Jt,Yt,Xt,Zt,Qt,$t,en,tn,nn,rn,an,on,sn,cn,ln,un,dn,fn,pn,mn,hn,gn,_n,vn,yn,bn,xn,Sn,Cn,wn,Tn,En,Dn,On,kn,An,jn,Mn,Nn,Pn,Fn,In,Ln,Rn,zn,Bn,Vn,Hn,Un,Wn,Gn,Kn,qn,Jn,Yn,Xn,Zn,Qn,$n,er,tr,nr,rr,ir,ar,or,sr,cr,lr,ur,dr,fr,pr,mr,hr,gr,_r,vr,yr,br,xr,Sr,Cr,wr,Tr,Er,Dr,Or,kr=s((()=>{w(),k(),ft(),It(),Y(),z(),Lt(),M(),Rt={class:`space-y-10`},zt={class:`grid gap-6 md:grid-cols-3`},Bt={class:`neo-card stat-card bg-[#fef08a] p-6`},Vt={class:`stat-icon`},Ht={class:`neo-display mt-3 text-3xl`},Ut={class:`neo-card stat-card bg-[#bbf7d0] p-6`},Wt={class:`stat-icon`},Gt={class:`neo-display mt-3 text-3xl`},Kt={class:`neo-card stat-card bg-[#fdba74] p-6`},qt={class:`stat-icon`},Jt={class:`neo-display mt-3 text-3xl`},Yt={class:`neo-card p-6 sm:p-8`},Xt={class:`card-title`},Zt={class:`step step-pink`},Qt={class:`link-grid`},$t={class:`field !mb-0`},en={class:`link-result`},tn=[`disabled`],nn=[`href`],rn={class:`link-basis`},an={class:`neo-card p-6 sm:p-8`},on={class:`card-title`},sn={class:`step`},cn={class:`overflow-x-auto rounded-[6px] border-4 border-black`},ln={class:`data-table min-w-full border-collapse bg-white`},un={class:`border-2 border-black font-bold`},dn={class:`border-2 border-black`},fn={class:`border-2 border-black`},pn={class:`border-2 border-black`},mn={class:`border-2 border-black`},hn={class:`border-2 border-black`},gn={class:`border-2 border-black`},_n={key:0},vn={class:`mt-5 flex flex-wrap items-center justify-between gap-3`},yn={class:`text-sm font-bold`},bn={class:`flex gap-3`},xn=[`disabled`],Sn=[`disabled`],Cn={key:0,class:`temporary-check-log p-6 sm:p-8`,"aria-live":`polite`},wn={class:`flex flex-wrap items-center justify-between gap-3`},Tn={class:`flex items-center gap-3`},En={class:`step`},Dn={class:`mt-5`},On={class:`mt-2 text-sm font-bold`},kn={class:`mt-1 text-xs`},An={key:0,class:`mt-2 flex items-start gap-2 text-sm font-bold`},jn={key:1,class:`mt-3 flex flex-wrap gap-2`},Mn=[`href`],Nn={class:`mt-4`},Pn={class:`grid gap-10 lg:grid-cols-2`},Fn={class:`space-y-10`},In={class:`neo-card p-6 sm:p-8`},Ln={class:`card-title`},Rn={class:`step step-teal`},zn={class:`grid gap-5 sm:grid-cols-2`},Bn={class:`field`},Vn={class:`field`},Hn={class:`neo-card p-6 sm:p-8`},Un={class:`card-title`},Wn={class:`step step-green`},Gn={class:`mb-5 grid gap-3 sm:grid-cols-3`},Kn={key:0},qn={key:1},Jn={key:2},Yn={class:`field`},Xn={key:0,class:`neo-card p-6 sm:p-8`},Zn={class:`card-title`},Qn={class:`step step-blue`},$n={class:`ml-auto`},er={class:`token-preview`},tr={class:`row`},nr={class:`value truncate`},rr={class:`row`},ir={class:`value truncate`},ar={class:`row`},or={class:`value`},sr={key:1,class:`neo-card p-6 sm:p-8`},cr={class:`card-title`},lr={class:`step step-orange`},ur={key:1},dr=[`href`],fr={class:`space-y-10`},pr={class:`neo-card p-6 sm:p-8`},mr={class:`inline-flex items-center gap-2`},hr={class:`mt-5`},gr={class:`field`},_r={class:`field`},vr={class:`neo-card p-6 sm:p-8`},yr={class:`card-title`},br={class:`step step-yellow`},xr={class:`space-y-4`},Sr={key:0,class:`neo-card p-6 sm:p-8`},Cr={class:`card-title`},wr={class:`step step-blue`},Tr=[`value`],Er={class:`mt-5 flex flex-wrap gap-3`},Dr={__name:`DashboardView`,setup(e){let i=_(``),o=window.location.origin,s=h(()=>{let e=i.value.trim();return e?`${o}/?for=${encodeURIComponent(e)}`:``});async function l(){let e=s.value;if(e)try{await navigator.clipboard.writeText(e),I(`📋 Link donasi tersalin`,`success`)}catch{I(`❌ Gagal menyalin link`,`error`)}}let u=h(()=>K.tokenData?.expiry?new Date(K.tokenData.expiry)<new Date:!1),d=h(()=>K.eligibilityLog?.data||null),b=h(()=>K.eligibilityLog?.id||null),C=_(!1),w=[{key:`ce`,label:`Check Eligibility`,icon:`check-circle`},{key:`sync`,label:`Sync ke 9Router`,icon:`refresh`},{key:`delete`,label:`Hapus`,icon:`trash`,danger:!0}];function E(e,t){e===`ce`?Te(t.id):e===`sync`?Ee(t.id):e===`delete`&&we(t.id)}function D(e){return e===`Success`?`badge-success`:e===`Pending`?`badge-warning`:`badge-error`}function k(e){try{return new Date(e).toLocaleString(`id-ID`)}catch{return e}}return(e,h)=>(p(),n(`div`,Rt,[t(`section`,zt,[t(`article`,Bt,[t(`span`,Vt,[O(S,{name:`bolt`,size:20})]),h[26]||=t(`p`,{class:`text-xs font-bold uppercase`},`Total Token Terkumpul`,-1),t(`p`,Ht,c(a(K).stats?.tokenCount??0),1)]),t(`article`,Ut,[t(`span`,Wt,[O(S,{name:`user`,size:20})]),h[27]||=t(`p`,{class:`text-xs font-bold uppercase`},`Total Donatur`,-1),t(`p`,Gt,c(a(K).stats?.donorCount??0),1)]),t(`article`,Kt,[t(`span`,qt,[O(S,{name:`clock`,size:20})]),h[28]||=t(`p`,{class:`text-xs font-bold uppercase`},`Donasi Hari Ini`,-1),t(`p`,Jt,c(a(K).stats?.todayCount??0),1)])]),t(`section`,Yt,[t(`div`,Xt,[t(`span`,Zt,[O(S,{name:`link`,size:14})]),h[29]||=f(` Generate Link Donasi `,-1)]),t(`div`,Qt,[t(`div`,$t,[h[30]||=t(`label`,{for:`linkName`},`Nama Calon Donatur (penerima link)`,-1),m(t(`input`,{id:`linkName`,"onUpdate:modelValue":h[0]||=e=>i.value=e,type:`text`,placeholder:`cth: Sahabat Terbaikku`},null,512),[[T,i.value]])]),t(`div`,en,[t(`div`,{class:v([`url-box`,{empty:!s.value}])},[O(S,{name:`link`,size:14,class:`url-icon`}),t(`span`,null,c(s.value||`Link muncul otomatis setelah nama diisi…`),1)],2),t(`button`,{class:`btn btn-primary link-copy`,disabled:!s.value,onClick:l},[O(S,{name:`copy`,size:15}),h[31]||=f(` Copy `,-1)],8,tn),s.value?(p(),n(`a`,{key:0,class:`btn btn-secondary link-open`,href:s.value,target:`_blank`,rel:`noopener`,title:`Buka link di tab baru`},[O(S,{name:`external`,size:15})],8,nn)):g(``,!0)])]),t(`p`,rn,[O(S,{name:`bolt`,size:13}),h[32]||=f(` Link otomatis mengikuti alamat yang Anda buka sekarang: `,-1),t(`strong`,null,c(a(o)),1),h[33]||=f(` — localhost, tunnel, maupun domain custom Anda. `,-1)])]),t(`section`,an,[t(`div`,on,[t(`span`,sn,[O(S,{name:`list`,size:14})]),h[35]||=f(` Daftar Donasi `,-1),h[36]||=t(`span`,{class:`badge badge-warning`},`Live Table`,-1),t(`button`,{class:`btn btn-primary ml-auto px-4 py-2 text-xs`,title:`Sinkronkan SEMUA donasi ke database 9Router (upsert by email)`,onClick:h[1]||=e=>C.value=!0},[O(S,{name:`database`,size:14}),h[34]||=f(` Sync Semua `,-1)])]),t(`div`,cn,[t(`table`,ln,[h[38]||=t(`thead`,null,[t(`tr`,{class:`bg-black text-white`},[t(`th`,{class:`border-2 border-black text-left`},`Nama`),t(`th`,{class:`border-2 border-black text-left`},`Email`),t(`th`,{class:`border-2 border-black text-left`},`Diminta untuk`),t(`th`,{class:`border-2 border-black text-left`},`Sumber`),t(`th`,{class:`border-2 border-black text-left`},`Status`),t(`th`,{class:`border-2 border-black text-left`},`Waktu`),t(`th`,{class:`border-2 border-black text-left`},`Aksi`)])],-1),t(`tbody`,null,[(p(!0),n(x,null,r(a(K).donations,(e,r)=>(p(),n(`tr`,{key:e.id,class:v(r%2==0?`bg-[#fffef0]`:`bg-white`)},[t(`td`,un,c(e.name),1),t(`td`,dn,c(e.email),1),t(`td`,fn,c(e.requestedFor||`sahabat`),1),t(`td`,pn,c(e.source),1),t(`td`,mn,[t(`span`,{class:v([`badge`,D(e.status)])},c(e.status),3)]),t(`td`,hn,c(k(e.createdAt)),1),t(`td`,gn,[O(dt,{items:w,onSelect:t=>E(t,e)},null,8,[`onSelect`])])],2))),128)),a(K).donations.length?g(``,!0):(p(),n(`tr`,_n,[...h[37]||=[t(`td`,{colspan:`7`,class:`border-2 border-black px-3 py-4 text-center text-sm font-bold`},`Belum ada data donasi.`,-1)]]))])])]),t(`div`,vn,[t(`span`,yn,`Halaman `+c(a(K).page)+` / `+c(a(K).pageCount)+` (`+c(a(K).total)+` data)`,1),t(`div`,bn,[t(`button`,{class:`btn btn-secondary px-4 py-2 text-sm`,disabled:a(K).page<=1,onClick:h[2]||=e=>a(Ce)(-1)},`← Sebelumnya`,8,xn),t(`button`,{class:`btn btn-secondary px-4 py-2 text-sm`,disabled:a(K).page>=a(K).pageCount,onClick:h[3]||=e=>a(Ce)(1)},`Berikutnya →`,8,Sn)])])]),O(Ft,{open:C.value,onClose:h[4]||=e=>C.value=!1},null,8,[`open`]),d.value?(p(),n(`section`,Cn,[t(`div`,wn,[t(`div`,Tn,[t(`span`,En,[O(S,{name:`check-circle`,size:14})]),h[39]||=t(`div`,null,[t(`h2`,{class:`neo-display text-xl`},`Temporary Eligibility Test Log`),t(`p`,{class:`mt-2 text-xs font-bold`},`Hasil ini hanya tampil sementara di browser dan tidak disimpan ke database.`)],-1)]),t(`button`,{class:`btn btn-secondary px-4 py-2 text-xs`,onClick:h[5]||=e=>a(K).eligibilityLog=null},[O(S,{name:`x`,size:14}),h[40]||=f(` Close `,-1)])]),t(`div`,Dn,[t(`span`,{class:v([`badge`,d.value.eligible?`badge-success`:`badge-error`])},c(d.value.status||(d.value.eligible?`Eligible`:`Not eligible`)),3),t(`p`,On,c(d.value.message||`-`),1),t(`p`,kn,`Checked at: `+c(d.value.checkedAt||`-`),1),d.value.tokenRefreshed?(p(),n(`p`,An,[O(S,{name:`refresh`,size:16}),t(`span`,null,[h[41]||=f(`Access token expired/nearly expired. Token berhasil di-refresh dan diperbarui di donation logs.`,-1),h[42]||=t(`br`,null,null,-1),f(`Expiry baru: `+c(d.value.expiry||`-`),1)])])):g(``,!0),d.value.status===`verification_required`&&d.value.validationUrl?(p(),n(`div`,jn,[t(`a`,{class:`btn btn-google`,href:d.value.validationUrl,target:`_blank`,rel:`noopener`},[O(S,{name:`check-circle`,size:16}),h[43]||=f(` Verify Account `,-1)],8,Mn),t(`button`,{class:`btn btn-secondary`,type:`button`,onClick:h[6]||=e=>a(Te)(b.value)},[O(S,{name:`refresh`,size:16}),h[44]||=f(` Recheck `,-1)])])):g(``,!0)]),t(`pre`,Nn,c(JSON.stringify(d.value.details||{},null,2)),1)])):g(``,!0),t(`div`,Pn,[t(`section`,Fn,[t(`div`,In,[t(`div`,Ln,[t(`span`,Rn,[O(S,{name:`user`,size:14})]),h[45]||=f(` Informasi Akun 9Router`,-1)]),t(`div`,zn,[t(`div`,Bn,[h[46]||=t(`label`,{for:`name`},`Name`,-1),m(t(`input`,{id:`name`,"onUpdate:modelValue":h[7]||=e=>a(K).name=e,type:`text`,placeholder:`Akan terisi otomatis`},null,512),[[T,a(K).name]])]),t(`div`,Vn,[h[47]||=t(`label`,{for:`email`},`Email`,-1),m(t(`input`,{id:`email`,"onUpdate:modelValue":h[8]||=e=>a(K).email=e,type:`email`,placeholder:`Akan terisi otomatis`},null,512),[[T,a(K).email]])])])]),t(`div`,Hn,[t(`div`,Un,[t(`span`,Wn,[O(S,{name:`key`,size:14})]),h[48]||=f(` Ambil Token`,-1)]),t(`div`,Gn,[t(`div`,{class:v([`tab`,{active:a(K).tokenTab===`google`}]),onClick:h[9]||=e=>a(K).tokenTab=`google`},[O(S,{name:`globe`,size:15}),h[49]||=f(` Login Google `,-1)],2),t(`div`,{class:v([`tab`,{active:a(K).tokenTab===`keychain`}]),onClick:h[10]||=e=>a(K).tokenTab=`keychain`},[O(S,{name:`key`,size:15}),h[50]||=f(` Keychain `,-1)],2),t(`div`,{class:v([`tab`,{active:a(K).tokenTab===`paste`}]),onClick:h[11]||=e=>a(K).tokenTab=`paste`},[O(S,{name:`clipboard`,size:15}),h[51]||=f(` Paste Base64 `,-1)],2)]),a(K).tokenTab===`google`?(p(),n(`div`,Kn,[t(`button`,{class:`btn btn-google`,onClick:h[12]||=e=>a(ke)()},[O(S,{name:`globe`,size:16}),h[52]||=f(` Login dengan Google `,-1)])])):a(K).tokenTab===`keychain`?(p(),n(`div`,qn,[t(`button`,{class:`btn btn-primary w-full`,onClick:h[13]||=e=>a(Ae)()},[O(S,{name:`key`,size:16}),h[53]||=f(` Ambil dari Keychain `,-1)])])):(p(),n(`div`,Jn,[t(`div`,Yn,[h[54]||=t(`label`,{for:`pasteInput`},`Paste Keychain Backup`,-1),m(t(`textarea`,{id:`pasteInput`,"onUpdate:modelValue":h[14]||=e=>a(K).pasteInput=e,rows:`4`,placeholder:`go-keyring-base64:...`},null,512),[[T,a(K).pasteInput]])]),t(`button`,{class:`btn btn-primary w-full`,onClick:h[15]||=e=>a(je)()},[O(S,{name:`unlock`,size:16}),h[55]||=f(` Decode `,-1)])]))]),a(K).tokenData?(p(),n(`div`,Xn,[t(`div`,Zn,[t(`span`,Qn,[O(S,{name:`eye`,size:14})]),h[56]||=f(` Token Preview `,-1),t(`span`,$n,[t(`span`,{class:v([`badge`,u.value?`badge-warning`:`badge-success`])},c(u.value?`EXPIRED`:`VALID`),3)])]),t(`div`,er,[t(`div`,tr,[h[57]||=t(`span`,{class:`label`},`Access Token:`,-1),t(`span`,nr,c(a(K).tokenData.accessToken),1)]),t(`div`,rr,[h[58]||=t(`span`,{class:`label`},`Refresh Token:`,-1),t(`span`,ir,c(a(K).tokenData.refreshToken),1)]),t(`div`,ar,[h[59]||=t(`span`,{class:`label`},`Expiry:`,-1),t(`span`,or,c(a(K).tokenData.expiry),1)])])])):g(``,!0),a(K).tokenData?(p(),n(`div`,sr,[t(`div`,cr,[t(`span`,lr,[O(S,{name:`check-circle`,size:14})]),h[60]||=f(` Eligibility Check`,-1)]),a(K).eligibilityResult?(p(),n(`div`,ur,[t(`div`,{class:v([`badge`,a(K).eligibilityResult.eligible?`badge-success`:`badge-error`])},c(a(K).eligibilityResult.eligible?`OK`:`GAGAL`)+` — `+c(a(K).eligibilityResult.message||`Gagal`),3),a(K).eligibilityResult.verificationUrl?(p(),n(`a`,{key:0,href:a(K).eligibilityResult.verificationUrl,target:`_blank`,class:`btn btn-google mt-3`,style:{"text-decoration":`none`}},[O(S,{name:`external`,size:16}),h[62]||=f(` Verifikasi Manual`,-1)],8,dr)):g(``,!0),a(K).eligibilityResult.verificationUrl?(p(),n(`button`,{key:1,class:`btn btn-secondary mt-3 w-full`,onClick:h[17]||=e=>a(Me)()},[O(S,{name:`refresh`,size:16}),h[63]||=f(` Cek Ulang `,-1)])):g(``,!0)])):(p(),n(`button`,{key:0,class:`btn btn-primary w-full`,onClick:h[16]||=e=>a(Me)()},[O(S,{name:`check-circle`,size:16}),h[61]||=f(` Cek Eligibility Akun `,-1)]))])):g(``,!0)]),t(`section`,fr,[t(`div`,pr,[t(`div`,{class:`cursor-pointer text-sm font-bold`,onClick:h[18]||=e=>a(K).advancedOpen=!a(K).advancedOpen},[t(`span`,mr,[O(S,{name:`sliders`,size:15}),f(` `+c(a(K).advancedOpen?`▼`:`▶`)+` Advanced Options `,1)])]),m(t(`div`,hr,[t(`div`,gr,[h[64]||=t(`label`,{for:`scope`},`Scope`,-1),m(t(`textarea`,{id:`scope`,"onUpdate:modelValue":h[19]||=e=>a(K).scope=e,rows:`2`},null,512),[[T,a(K).scope]])]),t(`div`,_r,[h[65]||=t(`label`,{for:`projectId`},`Project ID`,-1),m(t(`input`,{id:`projectId`,"onUpdate:modelValue":h[20]||=e=>a(K).projectId=e,type:`text`,placeholder:`fresh-catcher-x5fd2`},null,512),[[T,a(K).projectId]])])],512),[[y,a(K).advancedOpen]])]),t(`div`,vr,[t(`div`,yr,[t(`span`,br,[O(S,{name:`bolt`,size:14})]),h[66]||=f(` Generate & Execute`,-1)]),t(`div`,xr,[t(`button`,{class:`btn btn-primary w-full`,onClick:h[21]||=e=>a(Pe)()},[O(S,{name:`bolt`,size:16}),h[67]||=f(` Generate SQL Query Only `,-1)]),t(`button`,{class:`btn btn-success w-full`,onClick:h[22]||=e=>a(Fe)()},[O(S,{name:`database`,size:16}),h[68]||=f(` Generate & Insert ke 9Router `,-1)])])]),a(K).output?(p(),n(`div`,Sr,[t(`div`,Cr,[t(`span`,wr,[O(S,{name:`file`,size:14})]),h[69]||=f(` Output SQL Query`,-1)]),t(`textarea`,{value:a(K).output,readonly:``,rows:`12`,class:`output-textarea`},null,8,Tr),t(`div`,Er,[t(`button`,{class:`btn btn-primary`,onClick:h[23]||=e=>a(Ie)()},[O(S,{name:`copy`,size:16}),h[70]||=f(` Copy`,-1)]),t(`button`,{class:`btn btn-secondary`,onClick:h[24]||=e=>a(Le)()},[O(S,{name:`download`,size:16}),h[71]||=f(` Download .sql`,-1)]),t(`button`,{class:`btn btn-success`,onClick:h[25]||=e=>a(Re)()},[O(S,{name:`undo`,size:16}),h[72]||=f(` Reset`,-1)])])])):g(``,!0)])])]))}},Or=j(Dr,[[`__scopeId`,`data-v-d630ffa5`]])})),Ar=s((()=>{})),jr,Mr,Nr,Pr,Fr,Ir,Lr,Rr,zr,Br,Vr,Hr,Ur,Wr,Gr=s((()=>{w(),k(),xt(),z(),Y(),Ar(),M(),jr={class:`tun-card`,role:`dialog`,"aria-modal":`true`},Mr={class:`tun-head`},Nr={class:`tun-head-icon`},Pr={key:0,class:`tun-body`},Fr={class:`tun-actions`},Ir={key:1,class:`tun-body`},Lr={key:0,class:`tun-result`},Rr={class:`tun-url`},zr={key:1,class:`tun-ok`},Br={key:2,class:`tun-fail`},Vr={class:`tun-actions`},Hr={key:1,class:`tun-running`},Ur={__name:`TunnelDialog`,props:{open:{type:Boolean,default:!1}},emits:[`close`],setup(r,{emit:i}){let a=r,o=i,s=e({phase:`confirm`,resultUrl:``,errorMessage:``,doneMessage:``}),l=e([]);function m(e,t=`t-info`){l.push({time:new Date().toLocaleTimeString(`id-ID`),text:e,cls:t})}function h(e){if(e.type===`start`)m(`Memulai aktivasi tunnel publik…`);else if(e.type===`log`){let t=e.level===`ok`?`t-ok`:e.level===`error`?`t-error`:e.level===`warn`?`t-warn`:`t-info`;m(e.text,t)}else e.type===`done`?(s.resultUrl=e.url||``,s.doneMessage=e.already?`Tunnel sudah aktif sebelumnya.`:`Tunnel aktif dan siap dibagikan!`,m(`URL publik: ${e.url}`,`t-ok`)):e.type===`error`&&(s.errorMessage=e.message,m(`GAGAL: ${e.message}`,`t-error`))}async function _(){s.phase=`running`,l.length=0,s.resultUrl=``,s.errorMessage=``;try{let e=await fetch(`/api/tunnel`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({enabled:!0})});if(!e.ok){let t=`HTTP ${e.status}`;try{let n=await e.json();n&&n.error&&(t=n.error)}catch{}m(`GAGAL: ${t}`,`t-error`),s.errorMessage=t,s.phase=`done`;return}let t=e.body.getReader(),n=new TextDecoder,r=``;for(;;){let{done:e,value:i}=await t.read();if(e)break;r+=n.decode(i,{stream:!0});let a=r.split(`
|
|
4
3
|
`);r=a.pop();for(let e of a)e.trim()&&h(JSON.parse(e))}}catch(e){m(`GAGAL: ${e.message}`,`t-error`),s.errorMessage=e.message}s.phase=`done`,s.resultUrl&&(I(`🌐 Tunnel aktif: `+s.resultUrl,`success`),Ke(),await W())}async function v(){if(s.resultUrl)try{await navigator.clipboard.writeText(s.resultUrl),I(`📋 URL tunnel tersalin`,`success`)}catch{I(`❌ Gagal menyalin URL`,`error`)}}function y(){s.phase!==`running`&&o(`close`)}function b(e){e.key===`Escape`&&a.open&&s.phase!==`running`&&o(`close`)}return d(()=>document.addEventListener(`keydown`,b)),u(()=>document.removeEventListener(`keydown`,b)),(e,i)=>(p(),N(P,{to:`body`},[r.open?(p(),n(`div`,{key:0,class:`tun-overlay`,onClick:F(y,[`self`])},[t(`div`,jr,[t(`div`,Mr,[t(`span`,Nr,[O(S,{name:`globe`,size:20})]),i[3]||=t(`div`,null,[t(`h2`,{class:`tun-title`},`Aktivasi Tunnel Publik`),t(`p`,{class:`tun-sub`},`Cloudflare Quick Tunnel — gratis, tanpa akun`)],-1),s.phase===`running`?g(``,!0):(p(),n(`button`,{key:0,class:`btn btn-secondary btn-icon`,title:`Tutup`,onClick:i[0]||=e=>o(`close`)},[O(S,{name:`x`,size:15})]))]),s.phase===`confirm`?(p(),n(`div`,Pr,[i[6]||=t(`p`,{class:`tun-message`},[f(` Mengaktifkan tunnel akan membuat dashboard & halaman donasi Anda bisa diakses publik lewat URL `),t(`strong`,null,`*.trycloudflare.com`),f(`. Aktivasi pertama `),t(`strong`,null,`mendownload cloudflared ±30 MB`),f(` — progresnya akan tampil di terminal, jadi Anda bisa melihat sampai mana prosesnya. `)],-1),t(`div`,Fr,[t(`button`,{class:`btn btn-secondary`,onClick:i[1]||=e=>o(`close`)},[O(S,{name:`x`,size:15}),i[4]||=f(` Batal `,-1)]),t(`button`,{class:`btn btn-primary`,onClick:_},[O(S,{name:`play`,size:15}),i[5]||=f(` Aktifkan Tunnel `,-1)])])])):(p(),n(`div`,Ir,[O(Z,{name:`tunnel-activation.log`,lines:l,height:`260px`},null,8,[`lines`]),s.phase===`done`&&s.resultUrl?(p(),n(`div`,Lr,[t(`div`,Rr,c(s.resultUrl),1),t(`button`,{class:`btn btn-primary`,onClick:v},[O(S,{name:`copy`,size:15}),i[7]||=f(` Copy URL `,-1)])])):g(``,!0),s.phase===`done`&&s.resultUrl?(p(),n(`p`,zr,c(s.doneMessage)+` Bagikan URL ini ke calon donatur.`,1)):g(``,!0),s.phase===`done`&&s.errorMessage?(p(),n(`p`,Br,c(s.errorMessage),1)):g(``,!0),t(`div`,Vr,[s.phase===`done`?(p(),n(`button`,{key:0,class:`btn btn-primary`,onClick:i[2]||=e=>o(`close`)},[O(S,{name:`check`,size:15}),i[8]||=f(` Selesai `,-1)])):(p(),n(`span`,Hr,[...i[9]||=[t(`span`,{class:`spinner`},null,-1),f(` Memproses…`,-1)]]))])]))])])):g(``,!0)]))}},Wr=j(Ur,[[`__scopeId`,`data-v-c6ed99b8`]])})),Kr=s((()=>{})),qr,Jr,Yr,Xr,Zr,Qr,$r,ei,ti,ni,ri,ii,ai,oi,si,ci,li,ui,di,fi,pi,mi,Q,hi,gi,_i,vi,yi,bi,xi,Si,Ci=s((()=>{w(),k(),Gr(),Y(),z(),Kr(),M(),qr={class:`space-y-10`},Jr={class:`grid gap-10 lg:grid-cols-2`},Yr={class:`neo-card p-6 sm:p-8`},Xr={class:`card-title`},Zr={class:`step step-yellow`},Qr={class:`field`},$r={class:`field`},ei={class:`field`},ti=[`disabled`],ni={key:0,class:`spinner`},ri={class:`neo-card p-6 sm:p-8`},ii={class:`card-title`},ai={class:`step step-blue`},oi={key:0,class:`warning-box mt-4`},si={class:`wb-icon`},ci={key:1,class:`tunnel-url-box mt-4`},li=[`href`],ui={class:`mt-5`},di=[`disabled`],fi={key:0,class:`spinner`},pi={class:`neo-card p-6 sm:p-8`},mi={class:`card-title`},Q={class:`step step-teal`},hi={class:`field`},gi=[`value`],_i={class:`flex flex-wrap gap-3`},vi={class:`neo-card p-6 sm:p-8`},yi={class:`card-title`},bi={class:`step step-green`},xi={__name:`SettingsView`,setup(e){let r=_(``),i=_(``),o=_(``),s=_(!1),l=_(!1),u=_(``),d=_(!1),y=h(()=>K.settings?.tunnel||{enabled:!1,url:null,status:`stopped`}),b=h(()=>!!K.settings?.passwordIsDefault),x=h(()=>y.value.status===`starting`||y.value.status===`stopping`),C=h(()=>{let e={running:[`badge-success`,`AKTIF`],starting:[`badge-warning`,`MEMULAI...`],stopping:[`badge-warning`,`MENGHENTIKAN...`],stopped:[`badge-error`,`MATI`]};return e[y.value.status]||e.stopped}),w=h(()=>{let e=K.settings;return e?e.nineRouterDbPendingPath?e.nineRouterDbPendingExists?[`badge-warning`,`TERSIMPAN · FILE ADA · TUNGGU RESTART`]:[`badge-error`,`TERSIMPAN · FILE TIDAK ADA · TUNGGU RESTART`]:e.nineRouterDbExists?[`badge-success`,`FILE DITEMUKAN`]:[`badge-error`,`FILE TIDAK DITEMUKAN`]:[`badge-warning`,`Memuat...`]}),E=h(()=>{if(d.value)return u.value;let e=K.settings;return e?.nineRouterDbPendingPath||e?.nineRouterDbPath||``});function D(e){d.value=!0,u.value=e.target.value}async function k(){if(!s.value){if(!r.value)return I(`❌ Password lama wajib diisi`,`error`);if(i.value.trim().length<8)return I(`❌ Password baru minimal 8 karakter`,`error`);if(i.value.trim()!==o.value.trim())return I(`❌ Konfirmasi password tidak sama`,`error`);if(i.value.trim()===`1234567890`)return I(`❌ Tidak boleh sama dengan password default`,`error`);s.value=!0;try{await Ve(r.value,i.value.trim()),r.value=``,i.value=``,o.value=``}catch(e){I(`❌ `+e.message,`error`)}finally{s.value=!1}}}async function A(){await He(E.value.trim()),d.value=!1}async function j(){d.value=!0,u.value=``,await A()}async function ee(){if(y.value.url)try{await navigator.clipboard.writeText(y.value.url),I(`📋 URL tunnel tersalin`,`success`)}catch{I(`❌ Gagal menyalin URL`,`error`)}}function te(){y.value.enabled?We():l.value=!0}return(e,u)=>(p(),n(`div`,qr,[t(`div`,Jr,[t(`section`,Yr,[t(`div`,Xr,[t(`span`,Zr,[O(S,{name:`lock`,size:14})]),u[5]||=f(` Keamanan — Ganti Password`,-1)]),t(`div`,{class:v([`badge mb-5`,a(K).settings?.passwordIsDefault?`badge-error`:`badge-success`])},c(a(K).settings?.passwordIsDefault?`PASSWORD DEFAULT`:`PASSWORD CUSTOM`),3),t(`div`,Qr,[u[6]||=t(`label`,{for:`currentPassword`},`Password Lama`,-1),m(t(`input`,{id:`currentPassword`,"onUpdate:modelValue":u[0]||=e=>r.value=e,type:`password`,placeholder:`Password saat ini`},null,512),[[T,r.value]])]),t(`div`,$r,[u[7]||=t(`label`,{for:`newPassword`},`Password Baru`,-1),m(t(`input`,{id:`newPassword`,"onUpdate:modelValue":u[1]||=e=>i.value=e,type:`password`,placeholder:`Minimal 8 karakter`},null,512),[[T,i.value]])]),t(`div`,ei,[u[8]||=t(`label`,{for:`confirmPassword`},`Ulangi Password Baru`,-1),m(t(`input`,{id:`confirmPassword`,"onUpdate:modelValue":u[2]||=e=>o.value=e,type:`password`,placeholder:`Ketik ulang password baru`},null,512),[[T,o.value]]),u[9]||=t(`p`,{class:`hint`},`Password baru minimal 8 karakter dan tidak boleh sama dengan password default.`,-1)]),t(`button`,{class:`btn btn-primary w-full`,disabled:s.value,onClick:k},[s.value?(p(),n(`span`,ni)):(p(),N(S,{key:1,name:`lock`,size:16})),u[10]||=t(`span`,null,`Ganti Password`,-1)],8,ti)]),t(`section`,ri,[t(`div`,ii,[t(`span`,ai,[O(S,{name:`globe`,size:14})]),u[11]||=f(` Tunnel Publik (Cloudflare)`,-1)]),t(`span`,{class:v([`badge`,C.value[0]])},c(C.value[1]),3),b.value?(p(),n(`div`,oi,[t(`span`,si,[O(S,{name:`alert`,size:20})]),u[12]||=t(`span`,null,[t(`strong`,null,`Tunnel terkunci.`),f(` Password masih default sehingga tunnel tidak bisa diaktifkan. Ganti password di menu `),t(`strong`,null,`Keamanan`),f(` terlebih dahulu.`)],-1)])):g(``,!0),y.value.url&&y.value.status===`running`?(p(),n(`div`,ci,[t(`a`,{href:y.value.url,target:`_blank`,rel:`noopener`},c(y.value.url),9,li),t(`button`,{class:`btn btn-secondary px-4 py-2 text-xs`,onClick:ee},[O(S,{name:`copy`,size:14}),u[13]||=f(` Copy `,-1)])])):g(``,!0),t(`div`,ui,[t(`button`,{class:`btn btn-primary w-full`,disabled:x.value||b.value,onClick:te},[x.value?(p(),n(`span`,fi)):(p(),N(S,{key:1,name:y.value.enabled?`stop`:`play`,size:16},null,8,[`name`])),t(`span`,null,c(y.value.enabled?`Matikan Tunnel`:`Aktifkan Tunnel`),1)],8,di)]),u[14]||=t(`div`,{class:`field mt-5`},[t(`p`,{class:`hint`},[f(`Bagikan URL `),t(`strong`,null,`*.trycloudflare.com`),f(` ke donatur supaya bisa membuka halaman donasi tanpa tahu IP/komputer Anda. Aktivasi pertama mendownload cloudflared ±30 MB.`)])],-1)]),t(`section`,pi,[t(`div`,mi,[t(`span`,Q,[O(S,{name:`database`,size:14})]),u[15]||=f(` Database 9Router`,-1)]),t(`div`,{class:v([`badge mb-5`,w.value[0]])},c(w.value[1]),3),t(`div`,hi,[u[16]||=t(`label`,{for:`nineRouterDbPath`},`Lokasi file data.sqlite`,-1),t(`input`,{id:`nineRouterDbPath`,type:`text`,spellcheck:`false`,placeholder:`/Users/you/.9router/db/data.sqlite`,value:E.value,onInput:D},null,40,gi),u[17]||=t(`p`,{class:`hint`},`Ubah kalau 9Router ter-install di lokasi non-standar. Kosongkan untuk memakai default. Perubahan berlaku setelah aplikasi direstart.`,-1)]),t(`div`,_i,[t(`button`,{class:`btn btn-primary`,onClick:A},[O(S,{name:`check`,size:16}),u[18]||=f(` Simpan`,-1)]),t(`button`,{class:`btn btn-secondary`,onClick:j},[O(S,{name:`undo`,size:16}),u[19]||=f(` Path Default`,-1)])])]),t(`section`,vi,[t(`div`,yi,[t(`span`,bi,[O(S,{name:`power`,size:14})]),u[20]||=f(` Auto Start (Saat Login)`,-1)]),t(`div`,{class:v([`badge mb-5`,a(K).settings?.autoStart?`badge-success`:`badge-error`])},c(a(K).settings?.autoStart?`AKTIF`:`NONAKTIF`),3),t(`button`,{class:`btn btn-primary w-full`,onClick:u[3]||=(...e)=>a(Ue)&&a(Ue)(...e)},[O(S,{name:a(K).settings?.autoStart?`stop`:`play`,size:16},null,8,[`name`]),f(` `+c(a(K).settings?.autoStart?`Matikan Auto Start`:`Aktifkan Auto Start`),1)]),u[21]||=t(`div`,{class:`field mt-5`},[t(`p`,{class:`hint`},`Aplikasi berjalan otomatis di mode tray saat macOS login. Bisa juga di-toggle dari icon tray.`)],-1)])]),O(Wr,{open:l.value,onClose:u[4]||=e=>l.value=!1},null,8,[`open`])]))}},Si=j(xi,[[`__scopeId`,`data-v-1ed6ed88`]])})),wi=s((()=>{})),Ti,Ei,Di,Oi,ki,Ai,ji,Mi,Ni,Pi,Fi,$,Ii=s((()=>{w(),C(),ce(),_e(),k(),at(),kr(),Ci(),Y(),wi(),M(),Ti={class:`p-4 sm:p-6 lg:p-8`},Ei={key:1,class:`mx-auto max-w-6xl space-y-10`},Di={class:`neo-card p-6 sm:p-8`},Oi={class:`flex flex-col gap-6 lg:flex-row lg:items-center lg:justify-between`},ki={class:`flex items-center gap-5`},Ai={class:`flex flex-wrap gap-3`},ji={class:`mt-6 grid gap-3 sm:grid-cols-2`},Mi={class:`neo-card-soft bg-[#fef08a] px-4 py-3 text-sm font-bold`},Ni={class:`neo-card-soft bg-[#bbf7d0] px-4 py-3 text-sm font-bold`},Pi={class:`nav-tabs`,"aria-label":`Menu utama`},Fi={__name:`App`,setup(e){let r=_(null);function i(e){K.view=e,e===`dashboard`?(Be(),U(!1).catch(()=>{})):(W(),ze())}function o(e){let t=e.target.files&&e.target.files[0];e.target.value=``,Oe(t)}return d(()=>{be().then(()=>{K.authed&&(K.connStatus=`Terhubung`,U(!1).catch(()=>{}))})}),(e,s)=>(p(),n(`div`,Ti,[a(K).authed?(p(),n(`main`,Ei,[t(`header`,Di,[t(`div`,Oi,[t(`div`,ki,[O(ae,{width:92,class:`hidden sm:block`}),s[6]||=t(`div`,null,[t(`p`,{class:`text-sm font-bold`},`Bismillah, Selamat Datang Admin`),t(`h1`,{class:`neo-display mt-2 text-3xl sm:text-4xl`},`Dashboard Donasi Antigravity`),t(`p`,{class:`mt-3 text-sm font-medium`},`Kelola token dari Google / Keychain ke 9Router Database.`)],-1)]),t(`div`,Ai,[t(`button`,{class:`btn btn-secondary`,onClick:s[0]||=e=>a(De)()},[O(S,{name:`download`,size:16}),s[7]||=f(` Export Data`,-1)]),t(`button`,{class:`btn btn-secondary`,onClick:s[1]||=e=>r.value.click()},[O(S,{name:`upload`,size:16}),s[8]||=f(` Import Data`,-1)]),t(`button`,{class:`btn btn-primary`,onClick:s[2]||=e=>a(U)()},[O(S,{name:`refresh`,size:16}),s[9]||=f(` Refresh`,-1)]),t(`button`,{class:`btn btn-success`,onClick:s[3]||=e=>a(Se)()},[O(S,{name:`logout`,size:16}),s[10]||=f(` Logout`,-1)])]),t(`input`,{ref_key:`importFileInput`,ref:r,type:`file`,accept:`.csv,text/csv`,class:`hidden`,onChange:o},null,544)]),t(`div`,ji,[t(`div`,Mi,[s[11]||=f(`Status Koneksi: `,-1),t(`span`,null,c(a(K).connStatus),1)]),t(`div`,Ni,[s[12]||=f(`Sinkron Terakhir: `,-1),t(`span`,null,c(a(K).lastSync),1)])])]),t(`nav`,Pi,[t(`div`,{class:v([`tab`,{active:a(K).view===`dashboard`}]),onClick:s[4]||=e=>i(`dashboard`)},[O(S,{name:`home`,size:16}),s[13]||=f(` Dashboard `,-1)],2),t(`div`,{class:v([`tab`,{active:a(K).view===`settings`}]),onClick:s[5]||=e=>i(`settings`)},[O(S,{name:`sliders`,size:16}),s[14]||=f(` Pengaturan `,-1)],2)]),a(K).view===`dashboard`?(p(),N(Or,{key:0})):(p(),N(Si,{key:1}))])):(p(),N(it,{key:0})),O(ge),O(se)]))}},$=j(Fi,[[`__scopeId`,`data-v-108271c8`]])}));ne((()=>{w(),Ii(),ie(),A($).mount(`#app`)}))();
|