import {
ChangeDetectionStrategy,
Component,
computed,
input,
} from '@angular/core';
import { Home } from '@task-stream/web/tracker/domain';
/** «+30 %» or «−10 %» against the week before (nothing when there was none). */
function change(now: number, before: number): string {
if (!before) return now ? 'nuevo' : '';
const pct = Math.round(((now - before) / before) * 100);
return `${pct >= 0 ? '+' : '−'}${Math.abs(pct)} %`;
}
/** How the week goes: mine (and my streak) and my projects' teams. */
@Component({
selector: 'ts-week-stats',
changeDetection: ChangeDetectionStrategy.OnPush,
host: {
class: 'ts-panel',
role: 'region',
'aria-labelledby': 'stats-title',
},
styleUrl: './home-panel.scss',
template: `
La semana
Tickets terminados, últimos 7 días
Tú
{{ me().thisWeek }}
@if (myChange(); as c) {
{{
c
}}
}
@if (me().streak > 1) {
{{ me().streak }} días seguidos terminando algo
} @else if (me().streak === 1) {
Terminaste algo hoy o ayer
} @else {
Sin racha: hoy puede empezar una
}
Tus equipos
{{ team().thisWeek }}
@if (teamChange(); as c) {
{{
c
}}
}
@for (n of team().perDay; track $index) {
= 7"
[attr.title]="n + ' terminados'"
>
}
`,
styles: `
.ts-week {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1rem;
}
.ts-week__label {
margin: 0;
color: var(--ts-muted);
font-size: 0.75rem;
}
.ts-week__value {
display: flex;
align-items: baseline;
gap: 0.5rem;
margin: 0.125rem 0 0.25rem;
font-size: 1.75rem;
font-weight: 700;
}
.ts-week__change {
color: var(--ts-c-green, #2e9e6a);
font-size: 0.8125rem;
font-weight: 600;
&.is-down {
color: var(--ts-muted);
}
}
.ts-week__sub {
margin: 0;
color: var(--ts-ink-soft);
font-size: 0.8125rem;
}
.ts-week__bars {
display: flex;
align-items: flex-end;
gap: 2px;
height: 2.5rem;
span {
flex: 1;
min-height: 2px;
border-radius: 2px 2px 0 0;
background: color-mix(in srgb, var(--ts-brand) 35%, transparent);
&.is-this-week {
background: var(--ts-brand);
}
}
}
`,
})
export class WeekStatsComponent {
readonly me = input.required();
readonly team = input.required();
protected readonly myChange = computed(() =>
change(this.me().thisWeek, this.me().lastWeek),
);
protected readonly teamChange = computed(() =>
change(this.team().thisWeek, this.team().lastWeek),
);
private readonly max = computed(() => Math.max(1, ...this.team().perDay));
protected height(n: number): number {
return (n / this.max()) * 100;
}
}