@things-factory/auth-ui 6.2.8 → 6.2.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,8 +7,8 @@ import '@operato/i18n/ox-i18n.js'
7
7
  import '@operato/i18n/ox-i18n-selector.js'
8
8
  import '@operato/layout/ox-snack-bar.js'
9
9
 
10
- import { css, html, LitElement } from 'lit'
11
- import { property, query } from 'lit/decorators.js'
10
+ import { css, html, LitElement, nothing } from 'lit'
11
+ import { property, query, state } from 'lit/decorators.js'
12
12
 
13
13
  import { i18next, localize } from '@operato/i18n'
14
14
  import { ScrollbarStyles } from '@operato/styles'
@@ -79,6 +79,7 @@ export abstract class AbstractAuthPage extends localize(i18next)(LitElement) {
79
79
  }
80
80
 
81
81
  render() {
82
+ const { disableUserFavoredLanguage, languages } = this.data || {}
82
83
  var { icon, title, description } = this.applicationMeta
83
84
 
84
85
  return html`
@@ -96,7 +97,7 @@ export abstract class AbstractAuthPage extends localize(i18next)(LitElement) {
96
97
  <form
97
98
  id="form"
98
99
  action="${this.actionUrl}"
99
- method="POST"
100
+ method="post"
100
101
  @keypress=${e => {
101
102
  if (e.key == 'Enter') this._onSubmit(e)
102
103
  }}
@@ -104,19 +105,22 @@ export abstract class AbstractAuthPage extends localize(i18next)(LitElement) {
104
105
  ${this.formfields}
105
106
  </form>
106
107
  ${this.links}
107
- <div id="locale-area">
108
- <label for="locale-selector"><mwc-icon>language</mwc-icon></label>
109
- <ox-i18n-selector
110
- id="locale-selector"
111
- value=${i18next.language || 'en-US'}
112
- @change=${e => {
113
- var locale = e.detail
114
- if (!locale) return
115
-
116
- i18next.changeLanguage(locale)
117
- }}
118
- ></ox-i18n-selector>
119
- </div>
108
+ ${!disableUserFavoredLanguage
109
+ ? html` <div id="locale-area">
110
+ <label for="locale-selector"><mwc-icon>language</mwc-icon></label>
111
+ <ox-i18n-selector
112
+ id="locale-selector"
113
+ value=${i18next.language || 'en-US'}
114
+ .languages=${languages}
115
+ @change=${e => {
116
+ var locale = e.detail
117
+ if (!locale) return
118
+
119
+ i18next.changeLanguage(locale)
120
+ }}
121
+ ></ox-i18n-selector>
122
+ </div>`
123
+ : nothing}
120
124
  </div>
121
125
  </div>
122
126
 
@@ -168,10 +172,10 @@ export abstract class AbstractAuthPage extends localize(i18next)(LitElement) {
168
172
  <mwc-textfield
169
173
  name="email"
170
174
  type="email"
171
- label=${i18next.t('field.email')}
175
+ label=${String(i18next.t('field.email'))}
172
176
  required
173
177
  .value=${email}
174
- .validationMessage=${i18next.t('text.invalid-email')}
178
+ .validationMessage=${String(i18next.t('text.invalid-email'))}
175
179
  autocomplete="username"
176
180
  autocapitalize="off"
177
181
  ></mwc-textfield>
@@ -180,7 +184,7 @@ export abstract class AbstractAuthPage extends localize(i18next)(LitElement) {
180
184
  <mwc-textfield
181
185
  name="password"
182
186
  type="password"
183
- label=${i18next.t('field.password')}
187
+ label=${String(i18next.t('field.password'))}
184
188
  autocomplete="current-password"
185
189
  required
186
190
  ></mwc-textfield>
@@ -193,16 +197,19 @@ export abstract class AbstractAuthPage extends localize(i18next)(LitElement) {
193
197
  }
194
198
 
195
199
  get links() {
196
- const ssoLinks = this.data?.ssoLinks || []
200
+ const { disableUserSignupProcess, ssoLinks = [] } = this.data || {}
197
201
 
198
202
  return html`
199
- <a class="link" href="/auth/signup">
200
- <mwc-button icon="add_task"><ox-i18n msgid="field.sign up"></ox-i18n></mwc-button>
201
- </a>
202
- <a class="link" href="/auth/forgot-password">
203
- <mwc-button icon="lock_open"><ox-i18n msgid="field.forgot-password"></ox-i18n></mwc-button>
204
- </a>
205
-
203
+ ${!disableUserSignupProcess
204
+ ? html`
205
+ <a class="link" href="/auth/signup">
206
+ <mwc-button icon="add_task"><ox-i18n msgid="field.sign up"></ox-i18n></mwc-button>
207
+ </a>
208
+ <a class="link" href="/auth/forgot-password">
209
+ <mwc-button icon="lock_open"><ox-i18n msgid="field.forgot-password"></ox-i18n></mwc-button>
210
+ </a>
211
+ `
212
+ : nothing}
206
213
  ${ssoLinks.map(
207
214
  sso => html`
208
215
  <a class="link" href=${sso.link}>
@@ -6,7 +6,7 @@ import '@operato/i18n/ox-i18n.js'
6
6
  import '@operato/i18n/ox-i18n-selector.js'
7
7
  import '@operato/layout/ox-snack-bar.js'
8
8
 
9
- import { css, html } from 'lit'
9
+ import { css, html, nothing } from 'lit'
10
10
  import { property, query } from 'lit/decorators.js'
11
11
 
12
12
  import { i18next } from '@operato/i18n'
@@ -55,6 +55,7 @@ export abstract class AbstractPasswordReset extends AbstractAuthPage {
55
55
 
56
56
  render() {
57
57
  var { icon, title, description } = this.applicationMeta
58
+ const { disableUserFavoredLanguage, languages } = this.data || {}
58
59
 
59
60
  return html`
60
61
  <div class="wrap">
@@ -69,17 +70,17 @@ export abstract class AbstractPasswordReset extends AbstractAuthPage {
69
70
  <form
70
71
  id="form"
71
72
  action="${this.actionUrl}"
72
- method="POST"
73
+ method="post"
73
74
  @keypress=${e => {
74
75
  if (e.key == 'Enter') this._onSubmit(e)
75
76
  }}
76
77
  >
77
- <input name="token" type="hidden" .value=${this.token} required />
78
+ <input name="token" type="hidden" .value=${this.token || ''} required />
78
79
  <div class="field">
79
80
  <mwc-textfield
80
81
  name="password"
81
82
  type="password"
82
- label=${i18next.t('label.password')}
83
+ label=${String(i18next.t('label.password'))}
83
84
  .pattern=${this.passwordPattern}
84
85
  helper=${this.passwordHelp}
85
86
  helperPersistent
@@ -96,7 +97,7 @@ export abstract class AbstractPasswordReset extends AbstractAuthPage {
96
97
  id="confirm-password"
97
98
  name="confirm-password"
98
99
  type="password"
99
- label=${i18next.t('field.confirm password')}
100
+ label=${String(i18next.t('field.confirm password'))}
100
101
  required
101
102
  ></mwc-textfield>
102
103
  </div>
@@ -105,19 +106,22 @@ export abstract class AbstractPasswordReset extends AbstractAuthPage {
105
106
  <ox-i18n msgid="${this.submitButtonLabel}"></ox-i18n>
106
107
  </mwc-button>
107
108
 
108
- <div id="locale-area">
109
- <label for="locale-selector"><mwc-icon>language</mwc-icon></label>
110
- <ox-i18n-selector
111
- id="locale-selector"
112
- value=${i18next.language || 'en-US'}
113
- @change=${e => {
114
- var locale = e.detail
115
- if (!locale) return
116
-
117
- i18next.changeLanguage(locale)
118
- }}
119
- ></ox-i18n-selector>
120
- </div>
109
+ ${!disableUserFavoredLanguage
110
+ ? html` <div id="locale-area">
111
+ <label for="locale-selector"><mwc-icon>language</mwc-icon></label>
112
+ <ox-i18n-selector
113
+ id="locale-selector"
114
+ value=${i18next.language || 'en-US'}
115
+ .languages=${languages}
116
+ @change=${e => {
117
+ var locale = e.detail
118
+ if (!locale) return
119
+
120
+ i18next.changeLanguage(locale)
121
+ }}
122
+ ></ox-i18n-selector>
123
+ </div>`
124
+ : nothing}
121
125
  </form>
122
126
  </div>
123
127
  </div>
@@ -5,11 +5,11 @@ import './delete-user-popup'
5
5
  import './my-login-history'
6
6
 
7
7
  import { css, html, LitElement } from 'lit'
8
- import { customElement, property, query } from 'lit/decorators.js'
8
+ import { customElement, property, query, state } from 'lit/decorators.js'
9
9
 
10
10
  import { i18next, localize } from '@operato/i18n'
11
11
  import { notify, openPopup } from '@operato/layout'
12
- import { auth } from '@things-factory/auth-base/dist-client'
12
+ import { auth, getLanguages } from '@things-factory/auth-base/dist-client'
13
13
 
14
14
  @customElement('profile-component')
15
15
  export class ProfileComponent extends localize(i18next)(LitElement) {
@@ -109,15 +109,19 @@ export class ProfileComponent extends localize(i18next)(LitElement) {
109
109
  @property({ type: String }) email?: string
110
110
  @property({ type: String }) name?: string
111
111
 
112
+ @state() languages: { code: string; display: string }[] = []
113
+
112
114
  @query('#name') nameEl!: HTMLInputElement
113
115
  @query('#locale') localeEl!: HTMLInputElement
114
116
 
115
- firstUpdated() {
117
+ async firstUpdated() {
116
118
  auth.on('profile', ({ credential }) => {
117
119
  this.setCredential(credential)
118
120
  })
119
121
 
120
122
  this.setCredential(auth.credential)
123
+
124
+ this.languages = await getLanguages()
121
125
  }
122
126
 
123
127
  setCredential(credential) {
@@ -145,6 +149,7 @@ export class ProfileComponent extends localize(i18next)(LitElement) {
145
149
  id="locale"
146
150
  @change=${e => this.onLocaleChanged(e.detail)}
147
151
  value=${i18next.language || 'en-US'}
152
+ .languages=${this.languages}
148
153
  ></ox-i18n-selector>
149
154
 
150
155
  <hr />
@@ -107,12 +107,12 @@ class RolePrivilegeEditor extends localize(i18next)(LitElement) {
107
107
  </ul>
108
108
 
109
109
  <div buttons>
110
- <mwc-button @click=${e => this.onSave()} outlined label="${i18next.t('button.save')}"></mwc-button>
110
+ <mwc-button @click=${e => this.onSave()} outlined label=${String(i18next.t('button.save'))}></mwc-button>
111
111
  <mwc-button
112
112
  @click=${e => this.onDeleteRole()}
113
113
  raised
114
114
  danger
115
- label="${i18next.t('button.delete role')}"
115
+ label=${String(i18next.t('button.delete role'))}
116
116
  ></mwc-button>
117
117
  </div>
118
118
  `
@@ -96,7 +96,7 @@ export class AuthCheckIn extends localize(i18next)(LitElement) {
96
96
  <div class="content">
97
97
  <div class="wrap">
98
98
  <div class="auth-brand">
99
- <img src=${icon} />
99
+ <img src=${icon || ''} />
100
100
  <strong class="name">${title}</strong>
101
101
  <span class="welcome-msg">${description}</span>
102
102
  </div>
@@ -127,14 +127,14 @@ export class AuthCheckIn extends localize(i18next)(LitElement) {
127
127
  <div class="button-container">
128
128
  <mwc-button
129
129
  raised
130
- label="${i18next.t('button.logout')}"
130
+ label=${String(i18next.t('button.logout'))}
131
131
  @click="${() => (location.pathname = '/auth/signout')}"
132
132
  ></mwc-button>
133
133
 
134
134
  ${this.domainType?.toLowerCase() === 'company'
135
135
  ? html`<mwc-button
136
136
  raised
137
- label="${i18next.t('button.register business domain')}"
137
+ label=${String(i18next.t('button.register business domain'))}
138
138
  @click=${e => (location.href = `/public/business-register?email=${this.user?.email}`)}
139
139
  ></mwc-button> `
140
140
  : ''}
@@ -31,7 +31,7 @@ export class ForgotPassword extends AbstractAuthPage {
31
31
  <mwc-textfield
32
32
  name="email"
33
33
  type="email"
34
- label=${i18next.t('label.email')}
34
+ label=${String(i18next.t('label.email'))}
35
35
  .value=${email}
36
36
  required
37
37
  @input=${e => {
@@ -28,32 +28,38 @@ export class AuthSignup extends AbstractSign {
28
28
 
29
29
  return html`
30
30
  <div class="field">
31
- <mwc-textfield name="name" type="text" label=${i18next.t('field.name')} .value=${name} required></mwc-textfield>
31
+ <mwc-textfield
32
+ name="name"
33
+ type="text"
34
+ label=${String(i18next.t('field.name'))}
35
+ .value=${name}
36
+ required
37
+ ></mwc-textfield>
32
38
  </div>
33
39
  <div class="field">
34
40
  <mwc-textfield
35
41
  name="email"
36
42
  type="email"
37
- label=${i18next.t('field.email')}
43
+ label=${String(i18next.t('field.email'))}
38
44
  required
39
45
  .value=${email}
40
- .validationMessage=${i18next.t('text.invalid-email')}
46
+ .validationMessage=${String(i18next.t('text.invalid-email'))}
41
47
  ></mwc-textfield>
42
48
  </div>
43
49
  <div class="field">
44
50
  <mwc-textfield
45
51
  name="password"
46
52
  type="password"
47
- label=${i18next.t('field.password')}
48
- .pattern=${this.passwordPattern}
49
- helper=${this.passwordHelp}
53
+ label=${String(i18next.t('field.password'))}
54
+ .pattern=${this.passwordPattern || ''}
55
+ helper=${this.passwordHelp || ''}
50
56
  helperPersistent
51
57
  required
52
58
  @input=${e => {
53
59
  var val = e.target.value
54
60
  this.confirmPass.setAttribute('pattern', val.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '[$&]'))
55
61
  }}
56
- .validationMessage=${this.passwordHelp}
62
+ .validationMessage=${this.passwordHelp || ''}
57
63
  ></mwc-textfield>
58
64
  </div>
59
65
  <div class="field">
@@ -61,9 +67,9 @@ export class AuthSignup extends AbstractSign {
61
67
  id="confirm-password"
62
68
  name="confirm-password"
63
69
  type="password"
64
- label=${i18next.t('field.confirm password')}
70
+ label=${String(i18next.t('field.confirm password'))}
65
71
  required
66
- .validationMessage=${i18next.t('text.passwords do not match')}
72
+ .validationMessage=${String(i18next.t('text.passwords do not match'))}
67
73
  ></mwc-textfield>
68
74
  </div>
69
75
  <mwc-button class="ui button" raised @click=${e => this._onSubmit(e)}>
@@ -7,7 +7,7 @@ import '@operato/lottie-player';
7
7
  import '@operato/i18n/ox-i18n.js';
8
8
  import '@operato/i18n/ox-i18n-selector.js';
9
9
  import '@operato/layout/ox-snack-bar.js';
10
- import { css, html, LitElement } from 'lit';
10
+ import { css, html, LitElement, nothing } from 'lit';
11
11
  import { property, query } from 'lit/decorators.js';
12
12
  import { i18next, localize } from '@operato/i18n';
13
13
  import { ScrollbarStyles } from '@operato/styles';
@@ -15,6 +15,7 @@ import { isSafari } from '@operato/utils';
15
15
  import { AUTH_STYLE_SIGN } from '../auth-style-sign.js';
16
16
  export class AbstractAuthPage extends localize(i18next)(LitElement) {
17
17
  render() {
18
+ const { disableUserFavoredLanguage, languages } = this.data || {};
18
19
  var { icon, title, description } = this.applicationMeta;
19
20
  return html `
20
21
  <div class="content">
@@ -31,7 +32,7 @@ export class AbstractAuthPage extends localize(i18next)(LitElement) {
31
32
  <form
32
33
  id="form"
33
34
  action="${this.actionUrl}"
34
- method="POST"
35
+ method="post"
35
36
  @keypress=${e => {
36
37
  if (e.key == 'Enter')
37
38
  this._onSubmit(e);
@@ -40,19 +41,22 @@ export class AbstractAuthPage extends localize(i18next)(LitElement) {
40
41
  ${this.formfields}
41
42
  </form>
42
43
  ${this.links}
43
- <div id="locale-area">
44
- <label for="locale-selector"><mwc-icon>language</mwc-icon></label>
45
- <ox-i18n-selector
46
- id="locale-selector"
47
- value=${i18next.language || 'en-US'}
48
- @change=${e => {
49
- var locale = e.detail;
50
- if (!locale)
51
- return;
52
- i18next.changeLanguage(locale);
53
- }}
54
- ></ox-i18n-selector>
55
- </div>
44
+ ${!disableUserFavoredLanguage
45
+ ? html ` <div id="locale-area">
46
+ <label for="locale-selector"><mwc-icon>language</mwc-icon></label>
47
+ <ox-i18n-selector
48
+ id="locale-selector"
49
+ value=${i18next.language || 'en-US'}
50
+ .languages=${languages}
51
+ @change=${e => {
52
+ var locale = e.detail;
53
+ if (!locale)
54
+ return;
55
+ i18next.changeLanguage(locale);
56
+ }}
57
+ ></ox-i18n-selector>
58
+ </div>`
59
+ : nothing}
56
60
  </div>
57
61
  </div>
58
62
 
@@ -97,10 +101,10 @@ export class AbstractAuthPage extends localize(i18next)(LitElement) {
97
101
  <mwc-textfield
98
102
  name="email"
99
103
  type="email"
100
- label=${i18next.t('field.email')}
104
+ label=${String(i18next.t('field.email'))}
101
105
  required
102
106
  .value=${email}
103
- .validationMessage=${i18next.t('text.invalid-email')}
107
+ .validationMessage=${String(i18next.t('text.invalid-email'))}
104
108
  autocomplete="username"
105
109
  autocapitalize="off"
106
110
  ></mwc-textfield>
@@ -109,7 +113,7 @@ export class AbstractAuthPage extends localize(i18next)(LitElement) {
109
113
  <mwc-textfield
110
114
  name="password"
111
115
  type="password"
112
- label=${i18next.t('field.password')}
116
+ label=${String(i18next.t('field.password'))}
113
117
  autocomplete="current-password"
114
118
  required
115
119
  ></mwc-textfield>
@@ -121,16 +125,18 @@ export class AbstractAuthPage extends localize(i18next)(LitElement) {
121
125
  `;
122
126
  }
123
127
  get links() {
124
- var _a;
125
- const ssoLinks = ((_a = this.data) === null || _a === void 0 ? void 0 : _a.ssoLinks) || [];
128
+ const { disableUserSignupProcess, ssoLinks = [] } = this.data || {};
126
129
  return html `
127
- <a class="link" href="/auth/signup">
128
- <mwc-button icon="add_task"><ox-i18n msgid="field.sign up"></ox-i18n></mwc-button>
129
- </a>
130
- <a class="link" href="/auth/forgot-password">
131
- <mwc-button icon="lock_open"><ox-i18n msgid="field.forgot-password"></ox-i18n></mwc-button>
132
- </a>
133
-
130
+ ${!disableUserSignupProcess
131
+ ? html `
132
+ <a class="link" href="/auth/signup">
133
+ <mwc-button icon="add_task"><ox-i18n msgid="field.sign up"></ox-i18n></mwc-button>
134
+ </a>
135
+ <a class="link" href="/auth/forgot-password">
136
+ <mwc-button icon="lock_open"><ox-i18n msgid="field.forgot-password"></ox-i18n></mwc-button>
137
+ </a>
138
+ `
139
+ : nothing}
134
140
  ${ssoLinks.map(sso => html `
135
141
  <a class="link" href=${sso.link}>
136
142
  <mwc-button icon="badge">${i18next.t('label.signin with', { title: sso.title })}</mwc-button>
@@ -1 +1 @@
1
- {"version":3,"file":"abstract-auth-page.js","sourceRoot":"","sources":["../../client/components/abstract-auth-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/mwc-button'\nimport '@material/mwc-icon'\nimport '@material/mwc-icon-button'\nimport '@material/mwc-textfield'\nimport '@operato/lottie-player'\nimport '@operato/i18n/ox-i18n.js'\nimport '@operato/i18n/ox-i18n-selector.js'\nimport '@operato/layout/ox-snack-bar.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { property, query } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { isSafari } from '@operato/utils'\n\nimport { AUTH_STYLE_SIGN } from '../auth-style-sign.js'\n\nexport abstract class AbstractAuthPage extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n position: relative;\n overflow: hidden;\n\n display: flex;\n flex-direction: row;\n\n width: 100vw;\n height: 100vh;\n height: 100dvh;\n }\n .content {\n flex: 1;\n overflow: auto;\n }\n\n [home] {\n position: absolute;\n top: 10px;\n left: 10px;\n font-size: 2em;\n color: white;\n }\n\n [hidden] {\n display: none;\n }\n\n #snackbar {\n width: 100%;\n z-index: 10;\n }\n\n @media print {\n :host {\n width: 100%;\n height: 100%;\n min-height: 100vh;\n min-height: 100dvh;\n }\n }\n `,\n AUTH_STYLE_SIGN\n ]\n\n @property({ type: Object }) data: any\n @property({ type: String }) message?: string\n @property({ type: Object }) detail: any\n @property({ type: String }) redirectTo?: string\n\n @query('#form') formEl!: HTMLFormElement\n\n private _applicationMeta?: {\n icon: string\n title: string\n description: string\n }\n\n render() {\n var { icon, title, description } = this.applicationMeta\n\n return html`\n <div class=\"content\">\n <div class=\"wrap\">\n <div class=\"auth-brand\">\n <img src=${icon} />\n <strong class=\"name\">${title}</strong>\n <span class=\"welcome-msg\">${description}</span>\n </div>\n\n <div class=\"auth-form\">\n <h3><ox-i18n msgid=\"title.${this.pageName}\"></ox-i18n></h3>\n\n <form\n id=\"form\"\n action=\"${this.actionUrl}\"\n method=\"POST\"\n @keypress=${e => {\n if (e.key == 'Enter') this._onSubmit(e)\n }}\n >\n ${this.formfields}\n </form>\n ${this.links}\n <div id=\"locale-area\">\n <label for=\"locale-selector\"><mwc-icon>language</mwc-icon></label>\n <ox-i18n-selector\n id=\"locale-selector\"\n value=${i18next.language || 'en-US'}\n @change=${e => {\n var locale = e.detail\n if (!locale) return\n\n i18next.changeLanguage(locale)\n }}\n ></ox-i18n-selector>\n </div>\n </div>\n </div>\n\n <mwc-icon-button home icon=\"home\" @click=${e => (window.location.href = '/')}></mwc-icon-button>\n <ox-snack-bar id=\"snackbar\" level=\"error\" .message=${this.message}></ox-snack-bar>\n\n ${isSafari()\n ? html``\n : html`\n <div class=\"lottie-container\">\n <lottie-player autoplay loop src=\"../../assets/images/background-animation.json\"></lottie-player>\n </div>\n `}\n </div>\n `\n }\n\n firstUpdated() {\n setTimeout(() => {\n ;(this.renderRoot.querySelector('mwc-textfield') as any).focus()\n }, 100)\n\n this.formEl.reset = () => {\n this.formElements.filter(el => !(el.hidden || el.type == 'hidden')).forEach(el => (el.value = ''))\n }\n }\n\n updated(changed) {\n if (changed.has('data') && this.data) {\n this.message = this.data.message\n this.redirectTo = this.data.redirectTo\n }\n }\n\n abstract get pageName(): string\n abstract get actionUrl(): string\n\n get formElements(): HTMLInputElement[] {\n return Array.from(this.formEl.querySelectorAll('[name]'))\n }\n\n get formfields() {\n const email = this.data?.email || ''\n\n return html`\n <input id=\"redirectTo\" type=\"hidden\" name=\"redirectTo\" .value=${this.redirectTo || '/'} />\n\n <div class=\"field\">\n <mwc-textfield\n name=\"email\"\n type=\"email\"\n label=${i18next.t('field.email')}\n required\n .value=${email}\n .validationMessage=${i18next.t('text.invalid-email')}\n autocomplete=\"username\"\n autocapitalize=\"off\"\n ></mwc-textfield>\n </div>\n <div class=\"field\">\n <mwc-textfield\n name=\"password\"\n type=\"password\"\n label=${i18next.t('field.password')}\n autocomplete=\"current-password\"\n required\n ></mwc-textfield>\n </div>\n\n <mwc-button class=\"ui\" type=\"submit\" raised @click=${e => this._onSubmit(e)}>\n <ox-i18n msgid=\"field.${this.pageName}\"> </ox-i18n>\n </mwc-button>\n `\n }\n\n get links() {\n const ssoLinks = this.data?.ssoLinks || []\n\n return html`\n <a class=\"link\" href=\"/auth/signup\">\n <mwc-button icon=\"add_task\"><ox-i18n msgid=\"field.sign up\"></ox-i18n></mwc-button>\n </a>\n <a class=\"link\" href=\"/auth/forgot-password\">\n <mwc-button icon=\"lock_open\"><ox-i18n msgid=\"field.forgot-password\"></ox-i18n></mwc-button>\n </a>\n\n ${ssoLinks.map(\n sso => html`\n <a class=\"link\" href=${sso.link}>\n <mwc-button icon=\"badge\">${i18next.t('label.signin with', { title: sso.title })}</mwc-button>\n </a>\n `\n )}\n `\n }\n\n async _onSubmit(e) {\n if (this.checkValidity()) {\n this.submit()\n }\n }\n\n checkValidity() {\n return this.formElements.every(el => el.checkValidity())\n }\n\n abstract submit()\n\n showSnackbar({ level, message, timer = 3000 }: { level?: string; message?: string; timer?: number } = {}) {\n const snackbar = this.renderRoot.querySelector('#snackbar') as HTMLElement & {\n level: string\n message: string\n active: boolean\n }\n\n if (level) snackbar.level = level\n if (message) snackbar.message = message\n snackbar.active = true\n\n if (timer > -1)\n setTimeout(() => {\n this.hideSnackbar()\n }, timer)\n }\n\n hideSnackbar() {\n const snackbar = this.renderRoot.querySelector('#snackbar') as HTMLElement & {\n level: string\n message: string\n active: boolean\n }\n\n snackbar.active = false\n }\n\n get applicationMeta() {\n if (!this._applicationMeta) {\n var iconLink: HTMLLinkElement | null = document.querySelector('link[rel=\"application-icon\"]')\n var titleMeta: HTMLMetaElement | null = document.querySelector('meta[name=\"application-name\"]')\n var descriptionMeta: HTMLMetaElement | null = document.querySelector('meta[name=\"application-description\"]')\n\n this._applicationMeta = {\n icon: iconLink?.href || '',\n title: titleMeta?.content || 'Things Factory',\n description: descriptionMeta?.content || 'Reimagining Software'\n }\n }\n\n return this._applicationMeta\n }\n}\n"]}
1
+ {"version":3,"file":"abstract-auth-page.js","sourceRoot":"","sources":["../../client/components/abstract-auth-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/mwc-button'\nimport '@material/mwc-icon'\nimport '@material/mwc-icon-button'\nimport '@material/mwc-textfield'\nimport '@operato/lottie-player'\nimport '@operato/i18n/ox-i18n.js'\nimport '@operato/i18n/ox-i18n-selector.js'\nimport '@operato/layout/ox-snack-bar.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { property, query, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { isSafari } from '@operato/utils'\n\nimport { AUTH_STYLE_SIGN } from '../auth-style-sign.js'\n\nexport abstract class AbstractAuthPage extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n position: relative;\n overflow: hidden;\n\n display: flex;\n flex-direction: row;\n\n width: 100vw;\n height: 100vh;\n height: 100dvh;\n }\n .content {\n flex: 1;\n overflow: auto;\n }\n\n [home] {\n position: absolute;\n top: 10px;\n left: 10px;\n font-size: 2em;\n color: white;\n }\n\n [hidden] {\n display: none;\n }\n\n #snackbar {\n width: 100%;\n z-index: 10;\n }\n\n @media print {\n :host {\n width: 100%;\n height: 100%;\n min-height: 100vh;\n min-height: 100dvh;\n }\n }\n `,\n AUTH_STYLE_SIGN\n ]\n\n @property({ type: Object }) data: any\n @property({ type: String }) message?: string\n @property({ type: Object }) detail: any\n @property({ type: String }) redirectTo?: string\n\n @query('#form') formEl!: HTMLFormElement\n\n private _applicationMeta?: {\n icon: string\n title: string\n description: string\n }\n\n render() {\n const { disableUserFavoredLanguage, languages } = this.data || {}\n var { icon, title, description } = this.applicationMeta\n\n return html`\n <div class=\"content\">\n <div class=\"wrap\">\n <div class=\"auth-brand\">\n <img src=${icon} />\n <strong class=\"name\">${title}</strong>\n <span class=\"welcome-msg\">${description}</span>\n </div>\n\n <div class=\"auth-form\">\n <h3><ox-i18n msgid=\"title.${this.pageName}\"></ox-i18n></h3>\n\n <form\n id=\"form\"\n action=\"${this.actionUrl}\"\n method=\"post\"\n @keypress=${e => {\n if (e.key == 'Enter') this._onSubmit(e)\n }}\n >\n ${this.formfields}\n </form>\n ${this.links}\n ${!disableUserFavoredLanguage\n ? html` <div id=\"locale-area\">\n <label for=\"locale-selector\"><mwc-icon>language</mwc-icon></label>\n <ox-i18n-selector\n id=\"locale-selector\"\n value=${i18next.language || 'en-US'}\n .languages=${languages}\n @change=${e => {\n var locale = e.detail\n if (!locale) return\n\n i18next.changeLanguage(locale)\n }}\n ></ox-i18n-selector>\n </div>`\n : nothing}\n </div>\n </div>\n\n <mwc-icon-button home icon=\"home\" @click=${e => (window.location.href = '/')}></mwc-icon-button>\n <ox-snack-bar id=\"snackbar\" level=\"error\" .message=${this.message}></ox-snack-bar>\n\n ${isSafari()\n ? html``\n : html`\n <div class=\"lottie-container\">\n <lottie-player autoplay loop src=\"../../assets/images/background-animation.json\"></lottie-player>\n </div>\n `}\n </div>\n `\n }\n\n firstUpdated() {\n setTimeout(() => {\n ;(this.renderRoot.querySelector('mwc-textfield') as any).focus()\n }, 100)\n\n this.formEl.reset = () => {\n this.formElements.filter(el => !(el.hidden || el.type == 'hidden')).forEach(el => (el.value = ''))\n }\n }\n\n updated(changed) {\n if (changed.has('data') && this.data) {\n this.message = this.data.message\n this.redirectTo = this.data.redirectTo\n }\n }\n\n abstract get pageName(): string\n abstract get actionUrl(): string\n\n get formElements(): HTMLInputElement[] {\n return Array.from(this.formEl.querySelectorAll('[name]'))\n }\n\n get formfields() {\n const email = this.data?.email || ''\n\n return html`\n <input id=\"redirectTo\" type=\"hidden\" name=\"redirectTo\" .value=${this.redirectTo || '/'} />\n\n <div class=\"field\">\n <mwc-textfield\n name=\"email\"\n type=\"email\"\n label=${String(i18next.t('field.email'))}\n required\n .value=${email}\n .validationMessage=${String(i18next.t('text.invalid-email'))}\n autocomplete=\"username\"\n autocapitalize=\"off\"\n ></mwc-textfield>\n </div>\n <div class=\"field\">\n <mwc-textfield\n name=\"password\"\n type=\"password\"\n label=${String(i18next.t('field.password'))}\n autocomplete=\"current-password\"\n required\n ></mwc-textfield>\n </div>\n\n <mwc-button class=\"ui\" type=\"submit\" raised @click=${e => this._onSubmit(e)}>\n <ox-i18n msgid=\"field.${this.pageName}\"> </ox-i18n>\n </mwc-button>\n `\n }\n\n get links() {\n const { disableUserSignupProcess, ssoLinks = [] } = this.data || {}\n\n return html`\n ${!disableUserSignupProcess\n ? html`\n <a class=\"link\" href=\"/auth/signup\">\n <mwc-button icon=\"add_task\"><ox-i18n msgid=\"field.sign up\"></ox-i18n></mwc-button>\n </a>\n <a class=\"link\" href=\"/auth/forgot-password\">\n <mwc-button icon=\"lock_open\"><ox-i18n msgid=\"field.forgot-password\"></ox-i18n></mwc-button>\n </a>\n `\n : nothing}\n ${ssoLinks.map(\n sso => html`\n <a class=\"link\" href=${sso.link}>\n <mwc-button icon=\"badge\">${i18next.t('label.signin with', { title: sso.title })}</mwc-button>\n </a>\n `\n )}\n `\n }\n\n async _onSubmit(e) {\n if (this.checkValidity()) {\n this.submit()\n }\n }\n\n checkValidity() {\n return this.formElements.every(el => el.checkValidity())\n }\n\n abstract submit()\n\n showSnackbar({ level, message, timer = 3000 }: { level?: string; message?: string; timer?: number } = {}) {\n const snackbar = this.renderRoot.querySelector('#snackbar') as HTMLElement & {\n level: string\n message: string\n active: boolean\n }\n\n if (level) snackbar.level = level\n if (message) snackbar.message = message\n snackbar.active = true\n\n if (timer > -1)\n setTimeout(() => {\n this.hideSnackbar()\n }, timer)\n }\n\n hideSnackbar() {\n const snackbar = this.renderRoot.querySelector('#snackbar') as HTMLElement & {\n level: string\n message: string\n active: boolean\n }\n\n snackbar.active = false\n }\n\n get applicationMeta() {\n if (!this._applicationMeta) {\n var iconLink: HTMLLinkElement | null = document.querySelector('link[rel=\"application-icon\"]')\n var titleMeta: HTMLMetaElement | null = document.querySelector('meta[name=\"application-name\"]')\n var descriptionMeta: HTMLMetaElement | null = document.querySelector('meta[name=\"application-description\"]')\n\n this._applicationMeta = {\n icon: iconLink?.href || '',\n title: titleMeta?.content || 'Things Factory',\n description: descriptionMeta?.content || 'Reimagining Software'\n }\n }\n\n return this._applicationMeta\n }\n}\n"]}
@@ -6,7 +6,7 @@ import '../components/profile-component';
6
6
  import '@operato/i18n/ox-i18n.js';
7
7
  import '@operato/i18n/ox-i18n-selector.js';
8
8
  import '@operato/layout/ox-snack-bar.js';
9
- import { css, html } from 'lit';
9
+ import { css, html, nothing } from 'lit';
10
10
  import { property, query } from 'lit/decorators.js';
11
11
  import { i18next } from '@operato/i18n';
12
12
  import { isSafari } from '@operato/utils';
@@ -21,6 +21,7 @@ export class AbstractPasswordReset extends AbstractAuthPage {
21
21
  }
22
22
  render() {
23
23
  var { icon, title, description } = this.applicationMeta;
24
+ const { disableUserFavoredLanguage, languages } = this.data || {};
24
25
  return html `
25
26
  <div class="wrap">
26
27
  <div class="auth-brand">
@@ -34,18 +35,18 @@ export class AbstractPasswordReset extends AbstractAuthPage {
34
35
  <form
35
36
  id="form"
36
37
  action="${this.actionUrl}"
37
- method="POST"
38
+ method="post"
38
39
  @keypress=${e => {
39
40
  if (e.key == 'Enter')
40
41
  this._onSubmit(e);
41
42
  }}
42
43
  >
43
- <input name="token" type="hidden" .value=${this.token} required />
44
+ <input name="token" type="hidden" .value=${this.token || ''} required />
44
45
  <div class="field">
45
46
  <mwc-textfield
46
47
  name="password"
47
48
  type="password"
48
- label=${i18next.t('label.password')}
49
+ label=${String(i18next.t('label.password'))}
49
50
  .pattern=${this.passwordPattern}
50
51
  helper=${this.passwordHelp}
51
52
  helperPersistent
@@ -62,7 +63,7 @@ export class AbstractPasswordReset extends AbstractAuthPage {
62
63
  id="confirm-password"
63
64
  name="confirm-password"
64
65
  type="password"
65
- label=${i18next.t('field.confirm password')}
66
+ label=${String(i18next.t('field.confirm password'))}
66
67
  required
67
68
  ></mwc-textfield>
68
69
  </div>
@@ -71,19 +72,22 @@ export class AbstractPasswordReset extends AbstractAuthPage {
71
72
  <ox-i18n msgid="${this.submitButtonLabel}"></ox-i18n>
72
73
  </mwc-button>
73
74
 
74
- <div id="locale-area">
75
- <label for="locale-selector"><mwc-icon>language</mwc-icon></label>
76
- <ox-i18n-selector
77
- id="locale-selector"
78
- value=${i18next.language || 'en-US'}
79
- @change=${e => {
80
- var locale = e.detail;
81
- if (!locale)
82
- return;
83
- i18next.changeLanguage(locale);
84
- }}
85
- ></ox-i18n-selector>
86
- </div>
75
+ ${!disableUserFavoredLanguage
76
+ ? html ` <div id="locale-area">
77
+ <label for="locale-selector"><mwc-icon>language</mwc-icon></label>
78
+ <ox-i18n-selector
79
+ id="locale-selector"
80
+ value=${i18next.language || 'en-US'}
81
+ .languages=${languages}
82
+ @change=${e => {
83
+ var locale = e.detail;
84
+ if (!locale)
85
+ return;
86
+ i18next.changeLanguage(locale);
87
+ }}
88
+ ></ox-i18n-selector>
89
+ </div>`
90
+ : nothing}
87
91
  </form>
88
92
  </div>
89
93
  </div>