Files
reactive-mail-server/frontend/src/app/pages/settings/my-mailboxes.section.ts
T
Liosha84andClaude Opus 5.5 3d9fc77201
continuous-integration/drone/pr Build is passing
Левая панель: комбобокс ящиков; добавление ящиков — в Настройки; выделение в цвете темы
- MAILBOX: <select> со своими, общими и добавленными ящиками (непрочитанные в скобках),
  выбор — переключение; список и форма «добавить» из левой панели убраны.
- Settings → MY MAILBOXES (у всех): список ящиков, «убрать» добавленный, «добавить» по паролю.
- Выбранная папка, ссылка и палитра — nav-active в --primary-color темы
  (было фиксированное розовое — в Neon Cyan баклажановое).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 20:10:54 +01:00

96 lines
4.5 KiB
TypeScript

import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatIconModule } from '@angular/material/icon';
import { ApiService } from '../../core/api.service';
import { AuthService } from '../../core/auth.service';
import { MailStateService } from '../../core/mail-state.service';
import { MailboxEntry, errorText } from '../../core/models';
import { DialogService } from '../../ui/dialog.service';
import { ToastService } from '../../ui/toast.service';
/** Settings → MY MAILBOXES (everyone): mailboxes in the sidebar combobox — add one by its password, remove an added one. */
@Component({
selector: 'app-my-mailboxes-section',
imports: [FormsModule, MatIconModule],
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'block' },
template: `
<section class="glass-panel static p-5 md:p-6 h-full" aria-labelledby="my-boxes-title">
<h2 id="my-boxes-title" class="text-lg font-orbitron font-bold text-cyan-300 flex items-center gap-2 mb-4 border-b border-cyan-500/20 pb-2">
<mat-icon class="text-pink-500">alternate_email</mat-icon> MY MAILBOXES
</h2>
<ul class="space-y-1 mb-4" aria-label="Your mailboxes">
@for (b of state.boxes(); track b.email) {
<li class="flex items-center gap-2 px-2 py-1 rounded-lg border border-cyan-500/15">
<mat-icon class="!text-lg text-slate-400 shrink-0">{{ b.shared ? 'groups' : b.kind === 'OWN' ? 'person' : 'link' }}</mat-icon>
<span class="flex-grow truncate font-mono text-sm text-slate-200">{{ b.email }}</span>
<span class="text-[11px] font-mono text-slate-500">{{ b.kind === 'OWN' ? 'own' : b.shared ? 'shared' : 'added' }}</span>
@if (b.kind !== 'OWN') {
<button type="button" class="ghost-btn !py-1 hover:text-rose-400" (click)="leave(b)"
[attr.aria-label]="'Remove ' + b.email + ' from my mailboxes'" title="Remove from my mailboxes">
<mat-icon>close</mat-icon></button>
}
</li>
}
</ul>
<form class="grid grid-cols-1 md:grid-cols-[1fr_1fr_auto] gap-3 items-end" (ngSubmit)="attach()" aria-label="Add a mailbox">
<div><label class="synth-label" for="att-email">Mailbox</label>
<input id="att-email" name="attEmail" class="synth-input" [(ngModel)]="email" autocomplete="off" placeholder="name&#64;domain"></div>
<div><label class="synth-label" for="att-pw">Its password</label>
<input id="att-pw" name="attPw" type="password" class="synth-input" [(ngModel)]="password" autocomplete="off"></div>
<button type="submit" class="cyber-btn px-4 py-2 rounded-lg text-xs font-bold"><mat-icon>link</mat-icon> ADD</button>
</form>
</section>
`
})
export class MyMailboxesSection {
readonly state = inject(MailStateService);
private api = inject(ApiService);
private auth = inject(AuthService);
private dialogs = inject(DialogService);
private toasts = inject(ToastService);
email = '';
password = '';
constructor() {
this.state.refreshBoxes();
}
attach(): void {
const email = this.email.trim().toLowerCase();
if (!email || !this.password) { this.toasts.error('Mailbox and its password'); return; }
this.api.attachMailbox(email, this.password).subscribe({
next: b => {
this.email = this.password = '';
this.toasts.ok(b.email + ' added — pick it in the MAILBOX list on the left');
this.state.refreshBoxes();
},
error: e => this.toasts.error(errorText(e))
});
}
leave(b: MailboxEntry): void {
this.dialogs.confirm(`Remove ${b.email}?`, b.shared
? 'It disappears from your list. An administrator can give it back.'
: 'It disappears from your list. Add it again with its password.', 'Remove', true).subscribe(ok => {
if (ok === null) return;
this.api.leaveMailbox(b.email).subscribe({
next: () => {
this.toasts.ok(b.email + ' removed');
if (b.email === this.auth.email()) {
// removed the one we are in — back to the own mailbox
this.api.mailboxSession(this.state.boxes().find(x => x.kind === 'OWN')?.email ?? '').subscribe({
next: session => { this.state.reset(); this.auth.switchTo(session); location.assign('/'); },
error: () => location.assign('/')
});
return;
}
this.state.refreshBoxes();
},
error: e => this.toasts.error(errorText(e))
});
});
}
}