blob: 9c99ae0be3940cba64ad8cd7f6f3a4b36b0d627f [file] [log] [blame]
/**
* @license
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import '@polymer/iron-input/iron-input';
import '../../shared/gr-button/gr-button';
import {EmailInfo} from '../../../types/common';
import {getAppContext} from '../../../services/app-context';
import {LitElement, css, html} from 'lit';
import {customElement, property, state} from 'lit/decorators.js';
import {sharedStyles} from '../../../styles/shared-styles';
import {grFormStyles} from '../../../styles/gr-form-styles';
import {ValueChangedEvent} from '../../../types/events';
import {fire} from '../../../utils/event-util';
@customElement('gr-email-editor')
export class GrEmailEditor extends LitElement {
@property({type: Boolean}) hasUnsavedChanges = false;
/* private but used in test */
@state() emails: EmailInfo[] = [];
/* private but used in test */
@state() emailsToRemove: EmailInfo[] = [];
/* private but used in test */
@state() newPreferred = '';
readonly restApiService = getAppContext().restApiService;
static override get styles() {
return [
sharedStyles,
grFormStyles,
css`
th {
color: var(--deemphasized-text-color);
text-align: left;
}
#emailTable .emailColumn {
min-width: 32.5em;
width: auto;
}
#emailTable .preferredHeader {
text-align: center;
width: 6em;
}
#emailTable .preferredControl {
cursor: pointer;
height: auto;
text-align: center;
}
#emailTable .preferredControl .preferredRadio {
height: auto;
}
.preferredControl:hover {
outline: 1px solid var(--border-color);
}
`,
];
}
override render() {
return html`<div class="gr-form-styles">
<table id="emailTable">
<thead>
<tr>
<th class="emailColumn">Email</th>
<th class="preferredHeader">Preferred</th>
<th></th>
</tr>
</thead>
<tbody>
${this.emails.map((email, index) => this.renderEmail(email, index))}
</tbody>
</table>
</div>`;
}
private renderEmail(email: EmailInfo, index: number) {
return html`<tr>
<td class="emailColumn">${email.email}</td>
<td class="preferredControl" @click=${this.handlePreferredControlClick}>
<iron-input
class="preferredRadio"
@change=${this.handlePreferredChange}
.bindValue=${email.email}
>
<input
class="preferredRadio"
type="radio"
@change=${this.handlePreferredChange}
name="preferred"
?checked=${email.preferred}
/>
</iron-input>
</td>
<td>
<gr-button
data-index=${index}
@click=${this.handleDeleteButton}
?disabled=${this.checkPreferred(email.preferred)}
class="remove-button"
>Delete</gr-button
>
</td>
</tr>`;
}
loadData() {
return this.restApiService.getAccountEmails().then(emails => {
this.emails = emails ?? [];
});
}
save() {
const promises: Promise<unknown>[] = [];
for (const emailObj of this.emailsToRemove) {
promises.push(this.restApiService.deleteAccountEmail(emailObj.email));
}
if (this.newPreferred) {
promises.push(
this.restApiService.setPreferredAccountEmail(this.newPreferred)
);
}
return Promise.all(promises).then(() => {
this.emailsToRemove = [];
this.newPreferred = '';
this.setHasUnsavedChanges(false);
});
}
private handleDeleteButton(e: Event) {
const target = e.target;
if (!(target instanceof Element)) return;
const indexStr = target.getAttribute('data-index');
if (indexStr === null) return;
const index = Number(indexStr);
const email = this.emails[index];
this.emailsToRemove = [...this.emailsToRemove, email];
this.emails.splice(index, 1);
this.requestUpdate();
this.setHasUnsavedChanges(true);
}
private handlePreferredControlClick(e: Event) {
if (
e.target instanceof HTMLElement &&
e.target.classList.contains('preferredControl') &&
e.target.firstElementChild instanceof HTMLInputElement
) {
e.target.firstElementChild.click();
}
}
private handlePreferredChange(e: Event) {
if (!(e.target instanceof HTMLInputElement)) return;
const preferred = e.target.value;
for (let i = 0; i < this.emails.length; i++) {
if (preferred === this.emails[i].email) {
this.emails[i].preferred = true;
this.requestUpdate();
this.newPreferred = preferred;
this.setHasUnsavedChanges(true);
} else if (this.emails[i].preferred) {
this.emails[i].preferred = false;
this.requestUpdate();
}
}
}
private checkPreferred(preferred?: boolean) {
return preferred ?? false;
}
private setHasUnsavedChanges(value: boolean) {
this.hasUnsavedChanges = value;
fire(this, 'has-unsaved-changes-changed', {value});
}
}
declare global {
interface HTMLElementEventMap {
'has-unsaved-changes-changed': ValueChangedEvent<boolean>;
}
interface HTMLElementTagNameMap {
'gr-email-editor': GrEmailEditor;
}
}