import {
ChangeDetectionStrategy,
Component,
DestroyRef,
effect,
inject,
signal,
untracked,
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { RouterLink } from '@angular/router';
import { PiActionButtonComponent, PiEmptyStateComponent } from '@pi/ui';
import { ToastService } from '@task-stream/web/shared/ui';
import { ProjectFacade } from '@task-stream/web/tracker/application';
import { IssueSummary, IssuesGateway } from '@task-stream/web/tracker/domain';
import { timeAgo } from '../ui/copy';
/** /p/:key/trash — tickets deleted in the last 30 days, to bring back. */
@Component({
selector: 'ts-trash-page',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [RouterLink, PiActionButtonComponent, PiEmptyStateComponent],
template: `
@if (issues().length) {
@for (issue of issues(); track issue.id) {
-
{{
issue.key
}}
{{ issue.title }}
{{
issue.trashedAt ? ago(issue.trashedAt) : ''
}}
@if (project.canContribute()) {
}
}
} @else if (loaded()) {
}
`,
styles: `
.ts-trash {
margin: 0;
padding: 0.25rem 0;
list-style: none;
}
.ts-trash__row {
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto auto;
gap: 0.75rem;
align-items: center;
padding: 0.5rem 0.875rem;
border-top: 1px solid var(--ts-line);
&:first-child {
border-top: 0;
}
}
.ts-trash__title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
`,
})
export class TrashPage {
protected readonly project = inject(ProjectFacade);
private readonly gateway = inject(IssuesGateway);
private readonly toast = inject(ToastService);
private readonly destroyRef = inject(DestroyRef);
protected readonly issues = signal([]);
protected readonly loaded = signal(false);
protected readonly ago = timeAgo;
constructor() {
effect(() => {
const projectId = this.project.project()?.id;
if (projectId) untracked(() => this.reload(projectId));
});
}
protected restore(issue: IssueSummary): void {
this.gateway
.restore(issue.id)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe({
next: () => {
this.toast.success(`${issue.key} recuperado`);
this.issues.update((list) => list.filter((i) => i.id !== issue.id));
},
error: (error) =>
this.toast.error(
(error as { message?: string })?.message?.split('\n')[0] ||
'No se pudo recuperar',
),
});
}
private reload(projectId: string): void {
this.gateway
.trashed(projectId)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe({
next: (issues) => {
this.issues.set(issues);
this.loaded.set(true);
},
error: () => this.loaded.set(true),
});
}
}