301 lines
8.8 KiB
TypeScript
301 lines
8.8 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';
|
|
|
|
declare global {
|
|
interface HTMLElementTagNameMap {
|
|
'idp-login': IdpLogin;
|
|
}
|
|
}
|
|
|
|
@customElement('idp-login')
|
|
export class IdpLogin extends DeesElement {
|
|
public static demo = () => html`<idp-login></idp-login>`;
|
|
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<string>();
|
|
|
|
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`
|
|
<div class="loginbox box ${this.activePane === 'login' ? 'active' : ''}">
|
|
<div class="boxcontent">
|
|
<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-Address 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>
|
|
<div class="info">
|
|
You'll go here: ${this.appData ? html`${this.appData.appUrl}` : html``}
|
|
<p><span class="registerButton" @click=${() => {this.activePane = 'register'}}>You can also register for a new account.</span></p>
|
|
</div>
|
|
</dees-form>
|
|
</div>
|
|
</div>
|
|
<div class="registerbox box ${this.activePane === 'register' ? 'active' : ''}">
|
|
<div class="boxcontent">
|
|
<dees-form
|
|
id="registrationForm"
|
|
@formData="${(eventArg) => {
|
|
this.register({
|
|
emailAddress: eventArg.detail.data.emailAddress,
|
|
});
|
|
}}"
|
|
>
|
|
<dees-input-text
|
|
.required=${true}
|
|
key="emailAddress"
|
|
label="Email-Address"
|
|
></dees-input-text>
|
|
<dees-input-checkbox .label="${'Agree to the Terms and Conditions'}"></dees-input-checkbox>
|
|
<dees-form-submit>Send Verification Email</dees-form-submit>
|
|
<div class="info">
|
|
Already have an account?
|
|
<p><span class="registerButton" @click=${() => {this.activePane = 'login'}}>Login instead.</span></p>
|
|
</div>
|
|
</dees-form>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
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<plugins.idpInterfaces.request.IReq_LoginWithEmailOrUsernameAndPassword>(
|
|
IdpLogin.receptionUrl,
|
|
'loginWithEmailOrUsernameAndPassword'
|
|
);
|
|
const loginRequestWithEmail =
|
|
new domtools.TypedRequest<plugins.idpInterfaces.request.IReq_LoginWithEmail>(
|
|
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<plugins.idpInterfaces.request.IReq_FirstRegistration>(
|
|
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<plugins.idpInterfaces.request.IReq_RefreshJwt>(
|
|
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;
|
|
}
|
|
}
|
|
}
|