import { subscribeAuthState, type AuthSession } from '@/services/auth-state'; import { mountUserButton, openSignIn, openSignUp } from '@/services/clerk'; import { t } from '@/services/i18n'; import { setTrustedHtml, trustedHtml } from '@/utils/dom-utils'; export class AuthHeaderWidget { private container: HTMLElement; private unsubscribeAuth: (() => void) | null = null; private unmountUserButton: (() => void) | null = null; private onSignInClick?: () => void; private onSettingsClick?: () => void; constructor(onSignInClick?: () => void, onSettingsClick?: () => void) { this.onSignInClick = onSignInClick; this.onSettingsClick = onSettingsClick; this.container = document.createElement('div'); this.container.className = 'auth-header-widget'; this.unsubscribeAuth = subscribeAuthState((state: AuthSession) => { if (state.isPending) { this.renderPending(); return; } this.render(state); }); } public getElement(): HTMLElement { return this.container; } public destroy(): void { this.unmountUserButton?.(); this.unmountUserButton = null; if (this.unsubscribeAuth) { this.unsubscribeAuth(); this.unsubscribeAuth = null; } } private render(state: AuthSession): void { this.unmountUserButton?.(); this.unmountUserButton = null; this.container.classList.remove('auth-header-widget-pending'); this.container.removeAttribute('aria-busy'); setTrustedHtml(this.container, trustedHtml('', "legacy direct innerHTML migration")); if (!state.user) { this.renderSignedOut(); return; } this.renderSignedIn(); } private renderPending(): void { this.unmountUserButton?.(); this.unmountUserButton = null; this.container.classList.add('auth-header-widget-pending'); this.container.setAttribute('aria-busy', 'true'); setTrustedHtml(this.container, trustedHtml('', "legacy direct innerHTML migration")); const signInSkeleton = document.createElement('span'); signInSkeleton.className = 'auth-header-skeleton auth-header-skeleton-signin'; signInSkeleton.setAttribute('aria-hidden', 'true'); this.container.appendChild(signInSkeleton); const signUpSkeleton = document.createElement('span'); signUpSkeleton.className = 'auth-header-skeleton auth-header-skeleton-signup'; signUpSkeleton.setAttribute('aria-hidden', 'true'); this.container.appendChild(signUpSkeleton); } private renderSignedOut(): void { const signInBtn = document.createElement('button'); signInBtn.className = 'auth-signin-btn'; signInBtn.textContent = t('auth.signIn'); signInBtn.addEventListener('click', () => { if (this.onSignInClick) this.onSignInClick(); else openSignIn(); }); this.container.appendChild(signInBtn); const signUpLink = document.createElement('button'); signUpLink.className = 'auth-signup-link'; signUpLink.textContent = t('auth.createAccount'); signUpLink.addEventListener('click', () => openSignUp()); this.container.appendChild(signUpLink); } private renderSignedIn(): void { const userBtnEl = document.createElement('div'); userBtnEl.className = 'auth-clerk-user-button'; this.container.appendChild(userBtnEl); this.unmountUserButton = mountUserButton(userBtnEl); if (this.onSettingsClick) { const settingsBtn = document.createElement('button'); settingsBtn.className = 'auth-settings-btn'; settingsBtn.type = 'button'; settingsBtn.setAttribute('aria-label', t('auth.settings')); settingsBtn.title = t('auth.settings'); setTrustedHtml(settingsBtn, trustedHtml(SETTINGS_ICON, "legacy direct innerHTML migration")); settingsBtn.addEventListener('click', () => this.onSettingsClick?.()); this.container.appendChild(settingsBtn); } } } const SETTINGS_ICON = ``;