almost done
This commit is contained in:
parent
37a33d8a73
commit
23baa4af56
2 changed files with 232 additions and 249 deletions
|
|
@ -1,18 +1,14 @@
|
||||||
<div class="grid h-full place-items-center">
|
<div class="grid h-full place-items-center">
|
||||||
<div class="bg-white shadow-lg rounded-2xl p-8 w-full max-w-md">
|
<div class="bg-white shadow-lg rounded-2xl p-8 w-full max-w-md">
|
||||||
<h1 class="text-2xl font-semibold mb-6 text-gray-700">Edit Profile</h1>
|
<h1 class="text-2xl font-semibold mb-6 text-gray-700">Edit Profile</h1>
|
||||||
|
|
||||||
<div id="isGuestBox" class="border-red-600 rounded-2xl border-2" hidden>
|
<div id="isGuestBox" class="border-red-600 rounded-2xl border-2" hidden>
|
||||||
<h2 class="text-2xl font-semibold text-red-600"> This is a guest Account</h2>
|
<h2 class="text-2xl font-semibold text-red-600">This is a guest Account</h2>
|
||||||
<span class="text-red-600"> You can't change anything here </span>
|
<span class="text-red-600">You can't change anything here</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-1 text-gray-700 rounded-sm border-2 outline-lime-100">
|
<div class="mb-1 text-gray-700 rounded-sm border-2 outline-lime-100">
|
||||||
<label class="inline font-medium mb-1 text-gray-700">AccountType: </label>
|
<label class="inline font-medium mb-1 text-gray-700">AccountType:</label>
|
||||||
<span id="accountType" class="font-medium"></span>
|
<span id="accountType" class="font-medium"><span class="text-red-600">Unknown</span></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- Login Name -->
|
<!-- Login Name -->
|
||||||
<div id="loginNameWrapper" class="py-2" hidden>
|
<div id="loginNameWrapper" class="py-2" hidden>
|
||||||
<label class="block font-medium mb-1 text-gray-700">Login Name</label>
|
<label class="block font-medium mb-1 text-gray-700">Login Name</label>
|
||||||
|
|
@ -20,17 +16,18 @@
|
||||||
</div>
|
</div>
|
||||||
<!-- Login Name -->
|
<!-- Login Name -->
|
||||||
<div id="providerWrapper" class="py-2 mb-1 border-2 border-green-400 rounded-sm" hidden>
|
<div id="providerWrapper" class="py-2 mb-1 border-2 border-green-400 rounded-sm" hidden>
|
||||||
<span class="py-2 mb-1 text-gray-700 text-lg">Provider</span>
|
|
||||||
<div class="flex items-center justify-center gap-4">
|
<div class="flex items-center justify-center gap-4">
|
||||||
<div>
|
<div class="flex-1">
|
||||||
<label class="block font-medium mb-1 text-gray-700">Name</label>
|
<label class="block font-medium mb-1 text-gray-700">Name</label>
|
||||||
<div id="providerNameBox"
|
<div id="providerNameBox"
|
||||||
class="font-medium mb-1 text-gray-700"></div>
|
class="max-w-md p-3 border border-gray-300 rounded-lg overflow-y-auto bg-white text-gray-800 whitespace-pre-wrap">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="flex-1">
|
||||||
<label class="block font-medium mb-1 text-gray-700">User</label>
|
<label class="block font-medium mb-1 text-gray-700">User</label>
|
||||||
<div id="providerUserBox"
|
<div id="providerUserBox"
|
||||||
class="font-medium mb-1 text-gray-700"></div>
|
class="max-w-md p-3 border border-gray-300 rounded-lg overflow-y-auto bg-white text-gray-800 whitespace-pre-wrap">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -39,54 +36,42 @@
|
||||||
<label class="block font-medium mb-1 text-gray-700">Display Name</label>
|
<label class="block font-medium mb-1 text-gray-700">Display Name</label>
|
||||||
<input id="displayNameBox" type="text" placeholder="Display Name" name="DisplayName"
|
<input id="displayNameBox" type="text" placeholder="Display Name" name="DisplayName"
|
||||||
class="w-full px-4 py-2 border border-gray-300 text-gray-700 rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500" />
|
class="w-full px-4 py-2 border border-gray-300 text-gray-700 rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500" />
|
||||||
<button id="displayNameButton" class="w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700">
|
<button id="displayNameButton"
|
||||||
Update
|
class="w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700">Update</button>
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- Password -->
|
<!-- Password -->
|
||||||
<div id="passwordWrapper" class="py-2">
|
<div id="passwordWrapper" class="py-2" hidden hidden>
|
||||||
<label class="block font-medium mb-1 text-gray-700">Change Password</label>
|
<label class="block font-medium mb-1 text-gray-700">Change Password</label>
|
||||||
<input id="passwordBox" type="password" placeholder="New Password" name="Password"
|
<input id="passwordBox" type="password" placeholder="New Password" name="Password"
|
||||||
class="w-full px-4 py-2 border border-gray-300 text-gray-700 rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500" />
|
class="w-full px-4 py-2 border border-gray-300 text-gray-700 rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500" />
|
||||||
<button id="passwordButton" class="w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700">
|
<button id="passwordButton"
|
||||||
Update
|
class="w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700">Update</button>
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- TOTP -->
|
<!-- TOTP -->
|
||||||
<div class="border rounded p-4" id="totpWrapper">
|
<div class="border rounded p-4" id="totpWrapper" hidden>
|
||||||
<h2 class="font-semibold text-lg mb-2">Two-Factor Authentication (TOTP)</h2>
|
<h2 class="font-semibold text-lg mb-2">Two-Factor Authentication (TOTP)</h2>
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<span id="totpStatusText" class="font-medium text-gray-700">Status: Disabled</span>
|
<span id="totpStatusText" class="font-medium text-gray-700">Status: Disabled</span>
|
||||||
|
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<button id="enableTotp" type="button"
|
<button id="enableTotp" type="button"
|
||||||
class="bg-green-600 text-white-700 px-3 py-1 rounded hover:bg-green-700">
|
class="bg-green-600 text-white-700 px-3 py-1 rounded hover:bg-green-700">Enable</button>
|
||||||
Enable
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button id="disableTotp" type="button"
|
<button id="disableTotp" type="button"
|
||||||
class="bg-red-600 text-white-700 px-3 py-1 rounded hover:bg-red-700 hidden">
|
class="bg-red-600 text-white-700 px-3 py-1 rounded hover:bg-red-700 hidden">
|
||||||
Disable
|
Disable
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button id="showSecret" type="button"
|
<button id="showSecret" type="button"
|
||||||
class="bg-blue-600 text-white-700 px-3 py-1 rounded hover:bg-blue-700 hidden">
|
class="bg-blue-600 text-white-700 px-3 py-1 rounded hover:bg-blue-700 hidden">
|
||||||
Show Secret
|
Show Secret
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="totpSecretBox" class="mt-3 text-sm bg-gray-100 border p-2 rounded hidden">
|
<div id="totpSecretBox" class="mt-3 text-sm bg-gray-100 border p-2 rounded hidden">
|
||||||
<canvas id="totpSecretCanvas" class="w-full h-full block"> </canvas>
|
<canvas id="totpSecretCanvas" class="w-full h-full block">
|
||||||
|
</canvas>
|
||||||
<div id="totpSecretText"
|
<div id="totpSecretText"
|
||||||
class="w-full max-w-md p-3 border border-gray-300 rounded-lg overflow-y-auto bg-white text-gray-800 whitespace-pre-wrap">
|
class="w-full max-w-md p-3 border border-gray-300 rounded-lg overflow-y-auto bg-white text-gray-800 whitespace-pre-wrap">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,7 @@ import { isNullish } from "@app/utils";
|
||||||
import client from "@app/api";
|
import client from "@app/api";
|
||||||
import QRCode from "qrcode";
|
import QRCode from "qrcode";
|
||||||
|
|
||||||
type OAuthQRCodeOptions = {
|
/*
|
||||||
label?: string; // e.g. your-app:user@example.com
|
|
||||||
issuer?: string; // e.g. "YourApp"
|
|
||||||
algorithm?: "SHA1" | "SHA256" | "SHA512";
|
|
||||||
digits?: number;
|
|
||||||
period?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders an OAuth2-compatible TOTP QR code into a canvas.
|
* Renders an OAuth2-compatible TOTP QR code into a canvas.
|
||||||
*
|
*
|
||||||
* @param canvas HTMLCanvasElement to draw into
|
* @param canvas HTMLCanvasElement to draw into
|
||||||
|
|
@ -38,219 +30,225 @@ export async function renderOAuth2QRCode(
|
||||||
});
|
});
|
||||||
canvas.style.width = "";
|
canvas.style.width = "";
|
||||||
canvas.style.height = "";
|
canvas.style.height = "";
|
||||||
function removeBgColor(...elem: HTMLElement[]) {
|
}
|
||||||
for (let e of elem) {
|
function removeBgColor(...elem: HTMLElement[]) {
|
||||||
for (let c of e.classList.values()) {
|
for (let e of elem) {
|
||||||
if (c.startsWith("bg-") || c.startsWith("hover:bg-"))
|
for (let c of e.classList.values()) {
|
||||||
e.classList.remove(c);
|
if (c.startsWith("bg-") || c.startsWith("hover:bg-"))
|
||||||
}
|
e.classList.remove(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function route(url: string, _args: { [k: string]: string }) {
|
async function route(url: string, _args: { [k: string]: string }) {
|
||||||
setTitle("Edit Profile");
|
setTitle("Edit Profile");
|
||||||
return {
|
return {
|
||||||
html: page,
|
html: page,
|
||||||
postInsert: async (app: HTMLElement | undefined) => {
|
postInsert: async (app: HTMLElement | undefined) => {
|
||||||
const user = await updateUser();
|
const user = await updateUser();
|
||||||
if (isNullish(user)) return showError("No User");
|
if (isNullish(user)) return showError("No User");
|
||||||
if (isNullish(app)) return showError("Failed to render");
|
if (isNullish(app)) return showError("Failed to render");
|
||||||
let totpState = await (async () => {
|
let totpState = await (async () => {
|
||||||
let res = await client.statusOtp();
|
let res = await client.statusOtp();
|
||||||
if (res.kind === "success")
|
if (res.kind === "success")
|
||||||
return {
|
return {
|
||||||
enabled:
|
enabled:
|
||||||
(res.msg as string) === "statusOtp.success.enabled",
|
(res.msg as string) === "statusOtp.success.enabled",
|
||||||
secret:
|
secret:
|
||||||
(res.msg as string) === "statusOtp.success.enabled"
|
(res.msg as string) === "statusOtp.success.enabled"
|
||||||
? res.payload.secret
|
? res.payload.secret
|
||||||
: null,
|
: null,
|
||||||
};
|
|
||||||
else {
|
|
||||||
showError("Failed to get OTP status");
|
|
||||||
return {
|
|
||||||
enabled: false,
|
|
||||||
secret: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
// ---- Simulated State ----
|
|
||||||
let totpEnabled = totpState.enabled;
|
|
||||||
let totpSecret = totpState.secret; // would come from backend
|
|
||||||
|
|
||||||
let guestBox = app.querySelector<HTMLDivElement>("#isGuestBox")!;
|
|
||||||
let displayNameWrapper = app.querySelector<HTMLDivElement>(
|
|
||||||
"#displayNameWrapper",
|
|
||||||
)!;
|
|
||||||
let displayNameBox =
|
|
||||||
app.querySelector<HTMLInputElement>("#displayNameBox")!;
|
|
||||||
let displayNameButton =
|
|
||||||
app.querySelector<HTMLButtonElement>("#displayNameButton")!;
|
|
||||||
let loginNameWrapper =
|
|
||||||
app.querySelector<HTMLDivElement>("#loginNameWrapper")!;
|
|
||||||
let loginNameBox =
|
|
||||||
app.querySelector<HTMLDivElement>("#loginNameBox")!;
|
|
||||||
let passwordWrapper =
|
|
||||||
app.querySelector<HTMLDivElement>("#passwordWrapper")!;
|
|
||||||
let passwordBox =
|
|
||||||
app.querySelector<HTMLInputElement>("#passwordBox")!;
|
|
||||||
let passwordButton =
|
|
||||||
app.querySelector<HTMLButtonElement>("#passwordButton")!;
|
|
||||||
|
|
||||||
let providerWrapper =
|
|
||||||
app.querySelector<HTMLDivElement>("#providerWrapper")!;
|
|
||||||
let providerNameBox =
|
|
||||||
app.querySelector<HTMLDivElement>("#providerNameBox")!;
|
|
||||||
let providerUserBox =
|
|
||||||
app.querySelector<HTMLDivElement>("#providerUserBox")!;
|
|
||||||
|
|
||||||
let accountTypeBox =
|
|
||||||
app.querySelector<HTMLDivElement>("#accountType")!;
|
|
||||||
displayNameBox.value = user.name;
|
|
||||||
|
|
||||||
guestBox.hidden = !user.guest;
|
|
||||||
|
|
||||||
// ---- DOM Elements ----
|
|
||||||
const totpStatusText = app.querySelector("#totpStatusText")!;
|
|
||||||
const enableBtn =
|
|
||||||
app.querySelector<HTMLButtonElement>("#enableTotp")!;
|
|
||||||
const disableBtn =
|
|
||||||
app.querySelector<HTMLButtonElement>("#disableTotp")!;
|
|
||||||
const showSecretBtn =
|
|
||||||
app.querySelector<HTMLButtonElement>("#showSecret")!;
|
|
||||||
const secretBox = app.querySelector("#totpSecretBox")!;
|
|
||||||
const secretText =
|
|
||||||
app.querySelector<HTMLDivElement>("#totpSecretText")!;
|
|
||||||
const secretCanvas =
|
|
||||||
app.querySelector<HTMLCanvasElement>("#totpSecretCanvas")!;
|
|
||||||
|
|
||||||
if (user.guest) {
|
|
||||||
for (let c of passwordButton.classList.values()) {
|
|
||||||
if (c.startsWith("bg-") || c.startsWith("hover:bg-"))
|
|
||||||
passwordButton.classList.remove(c);
|
|
||||||
}
|
|
||||||
let totpWrapper = app.querySelector<HTMLDivElement>("#totpWrapper")!;
|
|
||||||
|
|
||||||
if (user.guest) {
|
|
||||||
removeBgColor(
|
|
||||||
passwordButton,
|
|
||||||
displayNameButton,
|
|
||||||
enableBtn,
|
|
||||||
disableBtn,
|
|
||||||
showSecretBtn,
|
|
||||||
);
|
|
||||||
|
|
||||||
passwordButton.classList.add(
|
|
||||||
"bg-gray-700",
|
|
||||||
"hover:bg-gray-700",
|
|
||||||
);
|
|
||||||
|
|
||||||
passwordBox.disabled = true;
|
|
||||||
passwordBox.classList.add("color-white");
|
|
||||||
|
|
||||||
displayNameButton.disabled = true;
|
|
||||||
displayNameButton.classList.add("bg-gray-700", "color-white");
|
|
||||||
|
|
||||||
displayNameBox.disabled = true;
|
|
||||||
displayNameBox.classList.add("color-white");
|
|
||||||
enableBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
|
||||||
disableBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
|
||||||
showSecretBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
|
||||||
|
|
||||||
enableBtn.disabled = true;
|
|
||||||
disableBtn.disabled = true;
|
|
||||||
showSecretBtn.disabled = true;
|
|
||||||
|
|
||||||
accountTypeBox.innerText = "Guest";
|
|
||||||
} else if (!isNullish(user.selfInfo?.loginName)) {
|
|
||||||
loginNameWrapper.hidden = false;
|
|
||||||
loginNameBox.innerText = user.selfInfo.loginName;
|
|
||||||
|
|
||||||
accountTypeBox.innerText = "Normal";
|
|
||||||
} else if (
|
|
||||||
!isNullish(user.selfInfo?.providerId) &&
|
|
||||||
!isNullish(user.selfInfo?.providerUser)
|
|
||||||
) {
|
|
||||||
providerWrapper.hidden = false;
|
|
||||||
providerNameBox.innerText = user.selfInfo.providerId;
|
|
||||||
providerUserBox.innerText = user.selfInfo.providerUser;
|
|
||||||
|
|
||||||
enableBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
|
||||||
disableBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
|
||||||
showSecretBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
|
||||||
|
|
||||||
enableBtn.disabled = true;
|
|
||||||
disableBtn.disabled = true;
|
|
||||||
showSecretBtn.disabled = true;
|
|
||||||
|
|
||||||
removeBgColor(enableBtn, disableBtn, showSecretBtn);
|
|
||||||
passwordWrapper.hidden = true;
|
|
||||||
totpWrapper.hidden = true;
|
|
||||||
|
|
||||||
accountTypeBox.innerText = "Provider";
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Update UI ----
|
|
||||||
function refreshTotpUI() {
|
|
||||||
if (totpEnabled) {
|
|
||||||
totpStatusText.textContent = "Status: Enabled";
|
|
||||||
|
|
||||||
enableBtn.classList.add("hidden");
|
|
||||||
disableBtn.classList.remove("hidden");
|
|
||||||
showSecretBtn.classList.remove("hidden");
|
|
||||||
} else {
|
|
||||||
totpStatusText.textContent = "Status: Disabled";
|
|
||||||
|
|
||||||
enableBtn.classList.remove("hidden");
|
|
||||||
disableBtn.classList.add("hidden");
|
|
||||||
showSecretBtn.classList.add("hidden");
|
|
||||||
secretBox.classList.add("hidden");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Button Events ----
|
|
||||||
enableBtn.onclick = async () => {
|
|
||||||
let res = await client.enableOtp();
|
|
||||||
if (res.kind === "success") {
|
|
||||||
navigateTo(url);
|
|
||||||
} else {
|
|
||||||
showError(`failed to activate OTP: ${res.msg}`);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
else {
|
||||||
disableBtn.onclick = async () => {
|
showError("Failed to get OTP status");
|
||||||
let res = await client.disableOtp();
|
return {
|
||||||
if (res.kind === "success") {
|
enabled: false,
|
||||||
navigateTo(url);
|
secret: null,
|
||||||
} else {
|
|
||||||
showError(`failed to deactivate OTP: ${res.msg}`);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
// ---- Simulated State ----
|
||||||
|
let totpEnabled = totpState.enabled;
|
||||||
|
let totpSecret = totpState.secret; // would come from backend
|
||||||
|
|
||||||
showSecretBtn.onclick = () => {
|
let guestBox = app.querySelector<HTMLDivElement>("#isGuestBox")!;
|
||||||
if (!isNullish(totpSecret)) {
|
let displayNameWrapper = app.querySelector<HTMLDivElement>(
|
||||||
secretText.textContent = totpSecret;
|
"#displayNameWrapper",
|
||||||
renderOAuth2QRCode(secretCanvas, totpSecret);
|
)!;
|
||||||
}
|
let displayNameBox =
|
||||||
secretBox.classList.toggle("hidden");
|
app.querySelector<HTMLInputElement>("#displayNameBox")!;
|
||||||
};
|
let displayNameButton =
|
||||||
|
app.querySelector<HTMLButtonElement>("#displayNameButton")!;
|
||||||
|
let loginNameWrapper =
|
||||||
|
app.querySelector<HTMLDivElement>("#loginNameWrapper")!;
|
||||||
|
let loginNameBox =
|
||||||
|
app.querySelector<HTMLDivElement>("#loginNameBox")!;
|
||||||
|
let passwordWrapper =
|
||||||
|
app.querySelector<HTMLDivElement>("#passwordWrapper")!;
|
||||||
|
let passwordBox =
|
||||||
|
app.querySelector<HTMLInputElement>("#passwordBox")!;
|
||||||
|
let passwordButton =
|
||||||
|
app.querySelector<HTMLButtonElement>("#passwordButton")!;
|
||||||
|
|
||||||
displayNameButton.onclick = async () => {
|
let providerWrapper =
|
||||||
let req = await client.changeDisplayName({
|
app.querySelector<HTMLDivElement>("#providerWrapper")!;
|
||||||
changeDisplayNameRequest: { name: displayNameBox.value },
|
let providerNameBox =
|
||||||
});
|
app.querySelector<HTMLDivElement>("#providerNameBox")!;
|
||||||
if (req.kind === "success") {
|
let providerUserBox =
|
||||||
showSuccess("Successfully changed display name");
|
app.querySelector<HTMLDivElement>("#providerUserBox")!;
|
||||||
handleRoute();
|
|
||||||
} else {
|
|
||||||
showError(`Failed to update: ${req.msg}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize UI state
|
let accountTypeBox =
|
||||||
refreshTotpUI();
|
app.querySelector<HTMLDivElement>("#accountType")!;
|
||||||
},
|
displayNameBox.value = user.name;
|
||||||
|
|
||||||
|
guestBox.hidden = !user.guest;
|
||||||
|
|
||||||
|
// ---- DOM Elements ----
|
||||||
|
const totpStatusText = app.querySelector("#totpStatusText")!;
|
||||||
|
const enableBtn =
|
||||||
|
app.querySelector<HTMLButtonElement>("#enableTotp")!;
|
||||||
|
const disableBtn =
|
||||||
|
app.querySelector<HTMLButtonElement>("#disableTotp")!;
|
||||||
|
const showSecretBtn =
|
||||||
|
app.querySelector<HTMLButtonElement>("#showSecret")!;
|
||||||
|
const secretBox = app.querySelector("#totpSecretBox")!;
|
||||||
|
const secretText =
|
||||||
|
app.querySelector<HTMLDivElement>("#totpSecretText")!;
|
||||||
|
const secretCanvas =
|
||||||
|
app.querySelector<HTMLCanvasElement>("#totpSecretCanvas")!;
|
||||||
|
let totpWrapper =
|
||||||
|
app.querySelector<HTMLDivElement>("#totpWrapper")!;
|
||||||
|
|
||||||
|
if (user.guest) {
|
||||||
|
for (let c of passwordButton.classList.values()) {
|
||||||
|
if (c.startsWith("bg-") || c.startsWith("hover:bg-"))
|
||||||
|
passwordButton.classList.remove(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (user.guest) {
|
||||||
|
removeBgColor(
|
||||||
|
passwordButton,
|
||||||
|
displayNameButton,
|
||||||
|
enableBtn,
|
||||||
|
disableBtn,
|
||||||
|
showSecretBtn,
|
||||||
|
);
|
||||||
|
|
||||||
|
passwordButton.classList.add(
|
||||||
|
"bg-gray-700",
|
||||||
|
"hover:bg-gray-700",
|
||||||
|
);
|
||||||
|
|
||||||
|
passwordBox.disabled = true;
|
||||||
|
passwordBox.classList.add("color-white");
|
||||||
|
|
||||||
|
displayNameButton.disabled = true;
|
||||||
|
displayNameButton.classList.add("bg-gray-700", "color-white");
|
||||||
|
|
||||||
|
displayNameBox.disabled = true;
|
||||||
|
displayNameBox.classList.add("color-white");
|
||||||
|
enableBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
||||||
|
disableBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
||||||
|
showSecretBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
||||||
|
|
||||||
|
enableBtn.disabled = true;
|
||||||
|
disableBtn.disabled = true;
|
||||||
|
showSecretBtn.disabled = true;
|
||||||
|
|
||||||
|
accountTypeBox.innerText = "Guest";
|
||||||
|
} else if (!isNullish(user.selfInfo?.loginName)) {
|
||||||
|
loginNameWrapper.hidden = false;
|
||||||
|
loginNameBox.innerText = user.selfInfo.loginName;
|
||||||
|
totpWrapper.hidden =false;
|
||||||
|
passwordWrapper.hidden = false;
|
||||||
|
|
||||||
|
accountTypeBox.innerText = "Normal";
|
||||||
|
} else if (
|
||||||
|
!isNullish(user.selfInfo?.providerId) &&
|
||||||
|
!isNullish(user.selfInfo?.providerUser)
|
||||||
|
) {
|
||||||
|
providerWrapper.hidden = false;
|
||||||
|
providerNameBox.innerText = user.selfInfo.providerId;
|
||||||
|
providerUserBox.innerText = user.selfInfo.providerUser;
|
||||||
|
|
||||||
|
enableBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
||||||
|
disableBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
||||||
|
showSecretBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
||||||
|
|
||||||
|
enableBtn.disabled = true;
|
||||||
|
disableBtn.disabled = true;
|
||||||
|
showSecretBtn.disabled = true;
|
||||||
|
|
||||||
|
removeBgColor(enableBtn, disableBtn, showSecretBtn);
|
||||||
|
passwordWrapper.hidden = true;
|
||||||
|
totpWrapper.hidden = true;
|
||||||
|
|
||||||
|
accountTypeBox.innerText = "Provider";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Update UI ----
|
||||||
|
function refreshTotpUI() {
|
||||||
|
if (totpEnabled) {
|
||||||
|
totpStatusText.textContent = "Status: Enabled";
|
||||||
|
|
||||||
|
enableBtn.classList.add("hidden");
|
||||||
|
disableBtn.classList.remove("hidden");
|
||||||
|
showSecretBtn.classList.remove("hidden");
|
||||||
|
} else {
|
||||||
|
totpStatusText.textContent = "Status: Disabled";
|
||||||
|
|
||||||
|
enableBtn.classList.remove("hidden");
|
||||||
|
disableBtn.classList.add("hidden");
|
||||||
|
showSecretBtn.classList.add("hidden");
|
||||||
|
secretBox.classList.add("hidden");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Button Events ----
|
||||||
|
enableBtn.onclick = async () => {
|
||||||
|
let res = await client.enableOtp();
|
||||||
|
if (res.kind === "success") {
|
||||||
|
navigateTo(url);
|
||||||
|
} else {
|
||||||
|
showError(`failed to activate OTP: ${res.msg}`);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
addRoute("/profile", route);
|
disableBtn.onclick = async () => {
|
||||||
|
let res = await client.disableOtp();
|
||||||
|
if (res.kind === "success") {
|
||||||
|
navigateTo(url);
|
||||||
|
} else {
|
||||||
|
showError(`failed to deactivate OTP: ${res.msg}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
showSecretBtn.onclick = () => {
|
||||||
|
if (!isNullish(totpSecret)) {
|
||||||
|
secretText.textContent = totpSecret;
|
||||||
|
renderOAuth2QRCode(secretCanvas, totpSecret);
|
||||||
|
}
|
||||||
|
secretBox.classList.toggle("hidden");
|
||||||
|
};
|
||||||
|
|
||||||
|
displayNameButton.onclick = async () => {
|
||||||
|
let req = await client.changeDisplayName({
|
||||||
|
changeDisplayNameRequest: {
|
||||||
|
name: displayNameBox.value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (req.kind === "success") {
|
||||||
|
showSuccess("Successfully changed display name");
|
||||||
|
handleRoute();
|
||||||
|
} else {
|
||||||
|
showError(`Failed to update: ${req.msg}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize UI state
|
||||||
|
refreshTotpUI();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
addRoute("/profile", route);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue