[Bugfix] Login Modal (#2903)

If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #2889

## Description:

fixes login in modal:
<img width="782" height="330" alt="image"
src="https://github.com/user-attachments/assets/60f1825f-5678-4853-a78b-bbed5198b0fb"
/>
(theres also one more afterwards but that leaks my email and cba to edit
it out)

## Please complete the following:


- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced

## Please put your Discord username so you can be contacted if a bug or
regression is found:

w.o.n
This commit is contained in:
Ryan
2026-01-15 00:56:50 +00:00
committed by GitHub
parent e1d31ef1ee
commit 6719f4177b
5 changed files with 86 additions and 23 deletions
+1
View File
@@ -228,6 +228,7 @@ export class LangSelector extends LitElement {
"stats-modal",
"flag-input-modal",
"flag-input",
"token-login",
];
document.title = this.translateText("main.title") ?? document.title;
+2 -2
View File
@@ -687,7 +687,7 @@ class Client {
// in case it is unset during reload.
this.userSettings.setSelectedPatternName(patternName);
});
this.tokenLoginModal.open(token);
this.tokenLoginModal.openWithToken(token);
} else {
alertAndStrip(`purchase succeeded: ${patternName}`);
this.patternsModal.refresh();
@@ -706,7 +706,7 @@ class Client {
}
strip();
this.tokenLoginModal.open(token);
this.tokenLoginModal.openWithToken(token);
return;
}
+76 -20
View File
@@ -1,17 +1,14 @@
import { html, LitElement } from "lit";
import { customElement, query } from "lit/decorators.js";
import { html } from "lit";
import { customElement } from "lit/decorators.js";
import { tempTokenLogin } from "./Auth";
import { BaseModal } from "./components/BaseModal";
import "./components/Difficulties";
import "./components/PatternButton";
import { modalHeader } from "./components/ui/ModalHeader";
import { translateText } from "./Utils";
@customElement("token-login")
export class TokenLoginModal extends LitElement {
@query("o-modal") private modalEl!: HTMLElement & {
open: () => void;
close: () => void;
};
export class TokenLoginModal extends BaseModal {
private isAttemptingLogin = false;
private retryInterval: NodeJS.Timeout | undefined = undefined;
@@ -27,39 +24,98 @@ export class TokenLoginModal extends LitElement {
}
render() {
const title = translateText("token_login_modal.title");
const content = html`
<div
class="h-full flex flex-col ${this.inline
? "bg-black/60 backdrop-blur-md rounded-2xl border border-white/10 overflow-hidden"
: ""}"
>
${modalHeader({
title,
onBack: () => this.close(),
ariaLabel: translateText("common.back"),
})}
<div class="flex-1 flex flex-col gap-4 p-6">
${this.email ? this.loginSuccess(this.email) : this.loggingIn()}
</div>
</div>
`;
if (this.inline) {
return content;
}
return html`
<o-modal
id="token-login-modal"
title="${translateText("token_login_modal.title")}"
title="${title}"
hideHeader
hideCloseButton
maxWidth="620px"
>
${this.email ? this.loginSuccess(this.email) : this.loggingIn()}
${content}
</o-modal>
`;
}
private loggingIn() {
return html` <p>${translateText("token_login_modal.logging_in")}</p> `;
const loggingText = translateText("token_login_modal.logging_in");
return html`
<div class="flex items-center gap-4">
<div
class="w-12 h-12 rounded-full border border-blue-400/40 bg-blue-500/10 flex items-center justify-center"
>
<div
class="w-6 h-6 border-2 border-blue-400/30 border-t-blue-400 rounded-full animate-spin"
></div>
</div>
<div class="flex flex-col gap-2">
<p class="text-lg font-semibold text-white">${loggingText}</p>
<div class="h-1 w-full bg-white/10 rounded-full overflow-hidden">
<div class="h-full w-1/2 bg-blue-400/80 animate-pulse"></div>
</div>
</div>
</div>
`;
}
private loginSuccess(email: string) {
return html`<p>
${translateText("token_login_modal.success", {
email,
})}
</p> `;
const successText = translateText("token_login_modal.success", { email });
return html`
<div class="flex items-center gap-4">
<div
class="w-12 h-12 rounded-full border border-emerald-400/40 bg-emerald-500/10 flex items-center justify-center"
>
<div class="w-2 h-2 bg-emerald-400 rounded-full animate-pulse"></div>
</div>
<p class="text-base text-white/90">${successText}</p>
</div>
`;
}
public async open(token: string) {
this.token = token;
this.modalEl?.open();
public open(): void {
if (!this.token) {
return;
}
super.open();
clearInterval(this.retryInterval);
this.retryInterval = setInterval(() => this.tryLogin(), 3000);
}
public openWithToken(token: string): void {
this.token = token;
this.email = null;
this.attemptCount = 0;
this.isAttemptingLogin = false;
this.open();
}
public close() {
this.token = null;
clearInterval(this.retryInterval);
this.attemptCount = 0;
this.modalEl?.close();
super.close();
this.isAttemptingLogin = false;
}
+1 -1
View File
@@ -13,7 +13,7 @@ export class PlayPage extends LitElement {
id="page-play"
class="flex flex-col gap-2 w-full max-w-6xl mx-auto px-0 sm:px-4 transition-all duration-300 my-auto min-h-0"
>
<token-login class="w-full hidden"></token-login>
<token-login class="absolute"></token-login>
<!-- Header / Identity Section -->
<div class="grid grid-cols-1 lg:grid-cols-12 gap-2 lg:gap-6 w-full">
@@ -25,6 +25,9 @@ export class OModal extends LitElement {
@property({ type: Boolean })
public hideHeader = false;
@property({ type: String })
public maxWidth = "";
public onClose?: () => void;
public open() {
@@ -67,6 +70,8 @@ export class OModal extends LitElement {
: `relative flex flex-col w-[90%] min-w-[400px] max-w-[900px] m-8 rounded-lg shadow-[0_20px_60px_rgba(0,0,0,0.8)] max-h-[calc(100vh-4rem)] ${
this.alwaysMaximized ? "h-auto" : ""
}`;
const wrapperStyle =
!this.inline && this.maxWidth ? `max-width: ${this.maxWidth};` : "";
return html`
${this.isModalOpen
@@ -78,6 +83,7 @@ export class OModal extends LitElement {
<div
@click=${(e: Event) => e.stopPropagation()}
class="${wrapperClass}"
style="${wrapperStyle}"
>
${this.inline || this.hideCloseButton
? html``