import * as plugins from '../plugins.js'; import { customElement, DeesElement, property, html, type TemplateResult, css, cssManager, state, domtools, } from '@design.estate/dees-element'; // third party catalogs import '@uptime.link/webwidget'; import '@design.estate/dees-catalog'; import { DeesForm, DeesFormSubmit, DeesInputText } from '@design.estate/dees-catalog'; declare global { interface HTMLElementTagNameMap { 'idp-login': IdpLogin; } } @customElement('idp-login') export class IdpLogin extends DeesElement { public static demo = () => html``; public static receptionUrl = 'https://reception.lossless.one/typedrequest'; @property() public activePane: 'login' | 'register' = 'login'; @property() public productOfInterest: string; @property() jwt: string; @property({ reflect: true, type: Object, }) appData: plugins.idpInterfaces.data.IApp; public jwtObserable = new domtools.plugins.smartrx.rxjs.Subject(); constructor() { super(); domtools.elementBasic.setup(); } public static styles = [ cssManager.defaultStyles, css` :host { font-family: 'Geist Sans'; display: block; color: ${cssManager.bdTheme('#333333', '#ffffff')}; } .box { opacity: 0; cursor: pointer; overflow: hidden; transition: all 0.2s ease; height: 0px; } .box.active { opacity: 1 !important; height: 360px; cursor: auto; } .loginbox { } .registerbox { } .boxcontent { margin: 0px 20px; } .info { text-align: center; padding: 32px; line-height: 1.5em; font-size: 12px; font-weight: 600; color: #999; } .registerButton { display: block; transition: all 0.2s ease; will-change: transform; cursor: pointer; } .registerButton:hover { color: #fff; transform: scale(1.02); } `, ]; public render(): TemplateResult { return html` { this.login({ emailAddress: eventArg.detail.data.emailAddress, passwordArg: eventArg.detail.data.password, }); }}" > You'll go here: ${this.appData ? html`${this.appData.appUrl}` : html``} {this.activePane = 'register'}}>You can also register for a new account. { this.register({ emailAddress: eventArg.detail.data.emailAddress, }); }}" > Send Verification Email Already have an account? {this.activePane = 'login'}}>Login instead. `; } public async firstUpdated() { const domtoolsInstance = await this.domtoolsPromise; const loginForm: DeesForm = this.shadowRoot.querySelector('#loginForm'); const loginPasswordInput: DeesInputText = loginForm.querySelector('#loginPasswordInput'); const loginSubmitButton: DeesFormSubmit = loginForm.querySelector('#loginSubmitButton'); const setButtonText = async () => { if (loginPasswordInput.value) { console.log('updating text of loginprompt.') loginSubmitButton.text = 'Login'; } else { loginSubmitButton.text = 'Send magic link (or enter password)'; } }; loginForm.changeSubject.subscribe(() => { console.log(`checking button text ${loginPasswordInput.value}`); setButtonText(); }); setButtonText(); } private login = async (valueArg: { emailAddress: string; passwordArg: string }) => { // lets define the needed requests const loginForm: DeesForm = this.shadowRoot.querySelector('#loginForm'); const loginRequestWithUsernameAndPassword = new domtools.TypedRequest( IdpLogin.receptionUrl, 'loginWithEmailOrUsernameAndPassword' ); const loginRequestWithEmail = new domtools.TypedRequest( IdpLogin.receptionUrl, 'loginWithEmail' ); // lets do the actual logging in if (valueArg.emailAddress && valueArg.passwordArg) { loginForm.setStatus('pending', 'logging in...'); const response = await loginRequestWithUsernameAndPassword .fire({ username: valueArg.emailAddress, // TODO: rename to emailAddress password: valueArg.passwordArg, }) .catch(() => { loginForm.setStatus('error', 'could not log you in. Try Again!'); return; }); if (!response) { return; } if (response.refreshToken) { loginForm.setStatus('pending', 'obtained refreshToken...'); const jwt = await this.handleRefreshToken(response.refreshToken, 0); if (jwt) { loginForm.setStatus('success', 'obtained jwt.'); } else { loginForm.setStatus('error', 'something went wrong'); } } else { } } else if (valueArg.emailAddress && !valueArg.passwordArg) { loginForm.setStatus('pending', 'sending magic link...'); const response = await loginRequestWithEmail.fire({ email: valueArg.emailAddress, }); if (response.status === 'ok') { loginForm.setStatus('success', 'Please check your email!'); } console.log(response); } }; private register = async (valueArg: { emailAddress: string }) => { const registrationForm: DeesForm = this.shadowRoot.querySelector('#registrationForm'); registrationForm.setStatus('pending', 'registering...'); const firstSignupRequest = new domtools.TypedRequest( IdpLogin.receptionUrl, 'firstRegistrationRequest' ); const response = await firstSignupRequest .fire({ email: valueArg.emailAddress, productSlugOfInterest: this.productOfInterest, }) .catch((err) => { registrationForm.setStatus('error', err.message); return null; }); if (response.status === 'ok') { registrationForm.setStatus('success', 'Please check your email!'); } console.log(response); }; public async dispatchJwt(jwtArg?: string) { if (jwtArg !== undefined) { console.log(`dispatching jwt from loginprompt.`); this.jwt = jwtArg; await domtools.plugins.smartdelay.delayFor(200); this.dispatchEvent( new CustomEvent('leleLoginGotJwt', { detail: { jwt: this.jwt, }, }) ); this.jwtObserable.next(this.jwt); } } public async handleRefreshToken(refreshTokenArg: string, delayDispatchMillisArg = 0) { // a refreshToken binds dierctly to a session. // the refresh token is used on a continuous basis to get fresh and short-lived jwts const refreshJwt = new domtools.TypedRequest( IdpLogin.receptionUrl, 'refreshJwt' ); const responseJwt = await refreshJwt.fire({ refreshToken: refreshTokenArg, }); if (responseJwt.jwt) { this.domtools.convenience.smartdelay.delayFor(delayDispatchMillisArg).then(() => { this.dispatchJwt(responseJwt.jwt); }); return responseJwt.jwt; } else { return null; } } }
{this.activePane = 'register'}}>You can also register for a new account.
{this.activePane = 'login'}}>Login instead.