Files
app/ts_web/elements/idp-loginprompt.ts
T
2025-11-30 22:35:24 +00:00

259 lines
7.3 KiB
TypeScript

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';
import { IdpState } from '../states/idp.state.js';
declare global {
interface HTMLElementTagNameMap {
'idp-loginprompt': IdpLoginPrompt;
}
}
@customElement('idp-loginprompt')
export class IdpLoginPrompt extends DeesElement {
public static demo = () => html`<idp-loginprompt></idp-loginprompt>`;
@property()
accessor productOfInterest: string;
@property()
accessor jwt: string;
@property({
reflect: true,
type: Object,
})
accessor appData: plugins.idpInterfaces.data.IApp;
public jwtObserable = new domtools.plugins.smartrx.rxjs.Subject<string>();
constructor() {
super();
domtools.elementBasic.setup();
}
public static styles = [
cssManager.defaultStyles,
css`
:host {
--foreground: hsl(0 0% 98%);
--muted-foreground: hsl(240 5% 64.9%);
font-family: 'Geist Sans', -apple-system, BlinkMacSystemFont, sans-serif;
display: block;
color: var(--foreground);
}
.form-header {
margin-bottom: 32px;
text-align: center;
}
.form-header h2 {
font-size: 24px;
font-weight: 600;
color: var(--foreground);
margin: 0 0 8px 0;
letter-spacing: -0.02em;
}
.form-header p {
font-size: 14px;
color: var(--muted-foreground);
margin: 0;
}
dees-form {
display: flex;
flex-direction: column;
gap: 16px;
}
.form-footer {
margin-top: 24px;
text-align: center;
font-size: 14px;
color: var(--muted-foreground);
}
.form-footer a {
color: var(--foreground);
text-decoration: none;
font-weight: 500;
cursor: pointer;
transition: opacity 0.15s ease;
}
.form-footer a:hover {
opacity: 0.8;
}
`,
];
public render(): TemplateResult {
return html`
<idp-centercontainer>
<div class="form-header">
<h2>Sign in to your account</h2>
<p>Enter your credentials to continue</p>
</div>
<dees-form
id="loginForm"
@formData="${(eventArg) => {
this.login({
emailAddress: eventArg.detail.data.emailAddress,
passwordArg: eventArg.detail.data.password,
});
}}"
>
<dees-input-text
id="loginEmailInput"
.required=${true}
key="emailAddress"
label="Email or Username"
></dees-input-text>
<dees-input-text
.id=${'loginPasswordInput'}
.key=${'password'}
.label=${'Password'}
.isPasswordBool=${true}
></dees-input-text>
<dees-form-submit id="loginSubmitButton"></dees-form-submit>
</dees-form>
<div class="form-footer">
Don't have an account? <a @click=${async () => {
const idpState = await IdpState.getSingletonInstance();
idpState.domtools.router.pushUrl('/register');
}}>Create one</a>
</div>
</idp-centercontainer>
`;
}
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 disable the register button
const registerButton: plugins.deesCatalog.DeesButton = this.shadowRoot.querySelector('.registerButton');
registerButton.disabled = true;
// lets define the needed requests
const idpState = await IdpState.getSingletonInstance();
const loginForm: DeesForm = this.shadowRoot.querySelector('#loginForm');
const loginRequestWithUsernameAndPassword =
new domtools.TypedRequest<plugins.idpInterfaces.request.IReq_LoginWithEmailOrUsernameAndPassword>(
'/typedrequest',
'loginWithEmailOrUsernameAndPassword'
);
const loginRequestWithEmail =
new domtools.TypedRequest<plugins.idpInterfaces.request.IReq_LoginWithEmail>(
'/typedrequest',
'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 idpState.idpClient.refreshJwt(response.refreshToken);
if (jwt) {
loginForm.setStatus('success', 'obtained jwt.');
idpState.domtools.router.pushUrl('/account');
} 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);
}
};
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 focus() {
(
this.shadowRoot.querySelector('#loginEmailInput') as plugins.deesCatalog.DeesInputText
).focus();
}
public async show() {
await this.updateComplete;
const centerContainer = this.shadowRoot.querySelector('idp-centercontainer');
await centerContainer.show();
}
public async hide() {
await this.updateComplete;
const centerContainer = this.shadowRoot.querySelector('idp-centercontainer');
await centerContainer.hide();
}
}