Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,39 +40,54 @@ <h4>Change Types</h4>
</ng-template>
<div class="tab-content">
<h4>{{ 'ALARM.LOCATION_MODE' | translate }}</h4>
<mat-radio-group [formControl]="form.controls.distanceMode" class="distance-radio-group" (change)="onDistanceModeChange()">
<mat-radio-button value="areas">
<div class="radio-label">
<mat-icon>map</mat-icon>
<div>
<strong>{{ 'ALARM.USE_AREAS' | translate }}</strong>
<p class="radio-hint">{{ 'ALARM.USE_AREAS_HINT' | translate }}</p>

<p class="scope-current">
<app-where-chip
[distance]="data.distance"
[editable]="false"
[overrideAreas]="data.overrideAreas"
[overrideLocationLabel]="data.overrideLocationLabel" />
<span class="scope-hint">{{ 'WHERE.EDIT_FROM_CARD' | translate }}</span>
</p>

@if (isAreaScoped()) {
<!-- Areas and a radius are mutually exclusive upstream, so this control cannot describe an
area-confined alarm. Offering it would let a save send both and be refused. -->
} @else {
<mat-radio-group [formControl]="form.controls.distanceMode" class="distance-radio-group" (change)="onDistanceModeChange()">
<mat-radio-button value="areas">
<div class="radio-label">
<mat-icon>map</mat-icon>
<div>
<strong>{{ 'ALARM.USE_AREAS' | translate }}</strong>
<p class="radio-hint">{{ 'ALARM.USE_AREAS_HINT' | translate }}</p>
</div>
</div>
</div>
</mat-radio-button>
<mat-radio-button value="distance">
<div class="radio-label">
<mat-icon>straighten</mat-icon>
<div>
<strong>{{ 'ALARM.SET_DISTANCE' | translate }}</strong>
<p class="radio-hint">{{ 'ALARM.SET_DISTANCE_HINT' | translate }}</p>
</mat-radio-button>
<mat-radio-button value="distance">
<div class="radio-label">
<mat-icon>straighten</mat-icon>
<div>
<strong>{{ 'ALARM.SET_DISTANCE' | translate }}</strong>
<p class="radio-hint">{{ 'ALARM.SET_DISTANCE_HINT' | translate }}</p>
</div>
</div>
</div>
</mat-radio-button>
</mat-radio-group>
</mat-radio-button>
</mat-radio-group>

@if (form.controls.distanceMode.value === 'distance') {
<mat-form-field appearance="outline" class="full-width">
<mat-label>{{ 'ALARM.DISTANCE_LABEL' | translate }}</mat-label>
<input matInput type="number" [formControl]="form.controls.distanceKm" min="0" step="0.1" />
<span matSuffix>{{ 'ALARM.DISTANCE_SUFFIX' | translate }}</span>
</mat-form-field>
}
@if (form.controls.distanceMode.value === 'distance') {
<mat-form-field appearance="outline" class="full-width">
<mat-label>{{ 'ALARM.DISTANCE_LABEL' | translate }}</mat-label>
<input matInput type="number" [formControl]="form.controls.distanceKm" min="0" step="0.1" />
<span matSuffix>{{ 'ALARM.DISTANCE_SUFFIX' | translate }}</span>
</mat-form-field>
}

<app-delivery-preview
[mode]="form.controls.distanceMode.value === 'areas' ? 'areas' : 'distance'"
[distanceKm]="form.controls.distanceKm.value ?? 0">
</app-delivery-preview>
<app-delivery-preview
[mode]="form.controls.distanceMode.value === 'areas' ? 'areas' : 'distance'"
[distanceKm]="form.controls.distanceKm.value ?? 0">
</app-delivery-preview>
}

<h4>{{ 'ALARM.MESSAGE_SETTINGS' | translate }}</h4>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,16 @@ mat-slide-toggle {
min-width: 0;
}
}

.scope-current {
align-items: center;
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin: 0 0 1rem;
}

.scope-hint {
color: var(--mat-sys-on-surface-variant, rgb(0 0 0 / 60%));
font-size: 0.75rem;
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { FortChangeService } from '../../core/services/fort-change.service';
import { I18nService } from '../../core/services/i18n.service';
import { DeliveryPreviewComponent } from '../../shared/components/delivery-preview/delivery-preview.component';
import { TemplateSelectorComponent } from '../../shared/components/template-selector/template-selector.component';
import { WhereChipComponent } from '../../shared/components/where-chip/where-chip.component';

@Component({
imports: [
Expand All @@ -37,6 +38,7 @@ import { TemplateSelectorComponent } from '../../shared/components/template-sele
TranslatePipe,
TemplateSelectorComponent,
DeliveryPreviewComponent,
WhereChipComponent,
],
selector: 'app-fort-change-edit-dialog',
standalone: true,
Expand Down Expand Up @@ -67,6 +69,11 @@ export class FortChangeEditDialogComponent {

saving = signal(false);

/** True when the alarm is confined to areas, which the areas-or-distance control cannot express. */
isAreaScoped(): boolean {
return (this.data.overrideAreas?.length ?? 0) > 0;
}

onDistanceModeChange(): void {
if (this.form.controls.distanceMode.value === 'areas') this.form.controls.distanceKm.setValue(0);
else if (!this.form.controls.distanceKm.value) this.form.controls.distanceKm.setValue(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,12 @@ <h3>{{ formatFortType(item.fortType) }}</h3>
</div>
</div>
<div class="distance-chip-row">
@if (item.distance === 0) {
<span class="distance-chip area-mode"><mat-icon>map</mat-icon> {{ 'ALARM.USING_AREAS' | translate }}</span>
} @else {
<span class="distance-chip distance-mode"><mat-icon>straighten</mat-icon> {{ formatDistance(item.distance) }}</span>
}
<app-where-chip
[distance]="item.distance"
[overrideAreas]="item.overrideAreas"
[overrideLocationLabel]="item.overrideLocationLabel"
[profileAreas]="profileAreas()"
(click)="editScope(item); $event.stopPropagation()" />
</div>
</mat-card-content>
<mat-card-actions align="end">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ import { firstValueFrom } from 'rxjs';
import { FortChangeAddDialogComponent } from './fort-change-add-dialog.component';
import { FortChangeEditDialogComponent } from './fort-change-edit-dialog.component';
import { FortChange } from '../../core/models';
import { AreaService } from '../../core/services/area.service';
import { FortChangeService } from '../../core/services/fort-change.service';
import { I18nService } from '../../core/services/i18n.service';
import { ConfirmDialogComponent, ConfirmDialogData } from '../../shared/components/confirm-dialog/confirm-dialog.component';
import { DistanceDialogComponent } from '../../shared/components/distance-dialog/distance-dialog.component';
import { WhereChipComponent } from '../../shared/components/where-chip/where-chip.component';
import { WhereSheetComponent, WhereSheetData } from '../../shared/components/where-sheet/where-sheet.component';
import { AlarmScope, scopeOf, scopeToFields } from '../../shared/utils/alarm-scope';

@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
Expand All @@ -33,21 +37,27 @@ import { DistanceDialogComponent } from '../../shared/components/distance-dialog
MatSnackBarModule,
MatProgressSpinnerModule,
TranslatePipe,
WhereChipComponent,
],
selector: 'app-fort-change-list',
standalone: true,
styleUrl: './fort-change-list.component.scss',
templateUrl: './fort-change-list.component.html',
})
export class FortChangeListComponent implements OnInit {
private readonly areaService = inject(AreaService);
private readonly destroyRef = inject(DestroyRef);
private readonly dialog = inject(MatDialog);
private readonly fortChangeService = inject(FortChangeService);
private readonly i18n = inject(I18nService);
private readonly snackBar = inject(MatSnackBar);
readonly fortChanges = signal<FortChange[]>([]);
readonly loading = signal(true);
/** Only used to word the inherited scope honestly; empty produces the more cautious wording. */
readonly profileAreas = signal<string[]>([]);

readonly selectedIds = signal(new Set<number>());

readonly selectMode = signal(false);

async bulkDelete(): Promise<void> {
Expand Down Expand Up @@ -170,6 +180,29 @@ export class FortChangeListComponent implements OnInit {
});
}

/** Change one alarm's delivery scope from its card, without opening the whole edit dialog. */
editScope(item: FortChange): void {
const data: WhereSheetData = {
profileAreas: this.profileAreas(),
scope: scopeOf(item.overrideLocationLabel, item.overrideAreas, item.distance),
};

this.dialog
.open(WhereSheetComponent, { width: '520px', autoFocus: false, data })
.afterClosed()
.subscribe((scope?: AlarmScope) => {
if (!scope) return;

this.fortChangeService.update(item.uid, scopeToFields(scope)).subscribe({
error: () => this.snackBar.open(this.i18n.instant('WHERE.SCOPE_SAVE_ERROR'), this.i18n.instant('COMMON.OK'), { duration: 4000 }),
next: () => {
this.snackBar.open(this.i18n.instant('WHERE.SCOPE_SAVED'), this.i18n.instant('COMMON.OK'), { duration: 2500 });
this.loadItems();
},
});
});
}

formatChangeTypes(types: string[]): string {
if (!types || types.length === 0) return this.i18n.instant('FORT_CHANGES.ALL_CHANGES');
return types
Expand Down Expand Up @@ -222,6 +255,7 @@ export class FortChangeListComponent implements OnInit {
}

ngOnInit(): void {
this.loadProfileAreas();
this.loadItems();
}

Expand Down Expand Up @@ -265,4 +299,8 @@ export class FortChangeListComponent implements OnInit {
}
});
}

private loadProfileAreas(): void {
this.areaService.getSelected().subscribe({ error: () => undefined, next: areas => this.profileAreas.set(areas) });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,39 +32,54 @@ <h4>{{ 'RAIDS.SPECIFIC_GYM' | translate }}</h4>
</ng-template>
<div class="tab-content">
<h4>{{ 'ALARM.LOCATION_MODE' | translate }}</h4>
<mat-radio-group [formControl]="form.controls.distanceMode" class="distance-radio-group" (change)="onDistanceModeChange()">
<mat-radio-button value="areas">
<div class="radio-label">
<mat-icon>map</mat-icon>
<div>
<strong>{{ 'ALARM.USE_AREAS' | translate }}</strong>
<p class="radio-hint">{{ 'ALARM.USE_AREAS_HINT' | translate }}</p>

<p class="scope-current">
<app-where-chip
[distance]="data.distance"
[editable]="false"
[overrideAreas]="data.overrideAreas"
[overrideLocationLabel]="data.overrideLocationLabel" />
<span class="scope-hint">{{ 'WHERE.EDIT_FROM_CARD' | translate }}</span>
</p>

@if (isAreaScoped()) {
<!-- Areas and a radius are mutually exclusive upstream, so this control cannot describe an
area-confined alarm. Offering it would let a save send both and be refused. -->
} @else {
<mat-radio-group [formControl]="form.controls.distanceMode" class="distance-radio-group" (change)="onDistanceModeChange()">
<mat-radio-button value="areas">
<div class="radio-label">
<mat-icon>map</mat-icon>
<div>
<strong>{{ 'ALARM.USE_AREAS' | translate }}</strong>
<p class="radio-hint">{{ 'ALARM.USE_AREAS_HINT' | translate }}</p>
</div>
</div>
</div>
</mat-radio-button>
<mat-radio-button value="distance">
<div class="radio-label">
<mat-icon>straighten</mat-icon>
<div>
<strong>{{ 'ALARM.SET_DISTANCE' | translate }}</strong>
<p class="radio-hint">{{ 'ALARM.SET_DISTANCE_HINT' | translate }}</p>
</mat-radio-button>
<mat-radio-button value="distance">
<div class="radio-label">
<mat-icon>straighten</mat-icon>
<div>
<strong>{{ 'ALARM.SET_DISTANCE' | translate }}</strong>
<p class="radio-hint">{{ 'ALARM.SET_DISTANCE_HINT' | translate }}</p>
</div>
</div>
</div>
</mat-radio-button>
</mat-radio-group>
</mat-radio-button>
</mat-radio-group>

@if (form.controls.distanceMode.value === 'distance') {
<mat-form-field appearance="outline" class="full-width">
<mat-label>{{ 'ALARM.DISTANCE_LABEL' | translate }}</mat-label>
<input matInput type="number" [formControl]="form.controls.distanceKm" min="0" step="0.1" />
<span matSuffix>{{ 'ALARM.DISTANCE_SUFFIX' | translate }}</span>
</mat-form-field>
}
@if (form.controls.distanceMode.value === 'distance') {
<mat-form-field appearance="outline" class="full-width">
<mat-label>{{ 'ALARM.DISTANCE_LABEL' | translate }}</mat-label>
<input matInput type="number" [formControl]="form.controls.distanceKm" min="0" step="0.1" />
<span matSuffix>{{ 'ALARM.DISTANCE_SUFFIX' | translate }}</span>
</mat-form-field>
}

<app-delivery-preview
[mode]="form.controls.distanceMode.value === 'areas' ? 'areas' : 'distance'"
[distanceKm]="form.controls.distanceKm.value ?? 0">
</app-delivery-preview>
<app-delivery-preview
[mode]="form.controls.distanceMode.value === 'areas' ? 'areas' : 'distance'"
[distanceKm]="form.controls.distanceKm.value ?? 0">
</app-delivery-preview>
}

<h4>{{ 'ALARM.MESSAGE_SETTINGS' | translate }}</h4>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,16 @@ mat-slide-toggle {
min-width: 0;
}
}

.scope-current {
align-items: center;
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin: 0 0 1rem;
}

.scope-hint {
color: var(--mat-sys-on-surface-variant, rgb(0 0 0 / 60%));
font-size: 0.75rem;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { I18nService } from '../../core/services/i18n.service';
import { DeliveryPreviewComponent } from '../../shared/components/delivery-preview/delivery-preview.component';
import { GymPickerComponent } from '../../shared/components/gym-picker/gym-picker.component';
import { TemplateSelectorComponent } from '../../shared/components/template-selector/template-selector.component';
import { WhereChipComponent } from '../../shared/components/where-chip/where-chip.component';
import { AUTO_DELETE, isAutoDelete, preserve } from '../../shared/utils/clean-flags';

@Component({
Expand All @@ -36,6 +37,7 @@ import { AUTO_DELETE, isAutoDelete, preserve } from '../../shared/utils/clean-fl
TemplateSelectorComponent,
DeliveryPreviewComponent,
GymPickerComponent,
WhereChipComponent,
],
selector: 'app-gym-edit-dialog',
standalone: true,
Expand Down Expand Up @@ -81,6 +83,11 @@ export class GymEditDialogComponent {
}
}

/** True when the alarm is confined to areas, which the areas-or-distance control cannot express. */
isAreaScoped(): boolean {
return (this.data.overrideAreas?.length ?? 0) > 0;
}

onDistanceModeChange(): void {
if (this.form.controls.distanceMode.value === 'areas') this.form.controls.distanceKm.setValue(0);
else if (!this.form.controls.distanceKm.value) this.form.controls.distanceKm.setValue(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,12 @@ <h3>{{ getTeamName(gym.team) }}</h3>
</div>
<mat-card-content>
<div class="distance-chip-row">
@if (gym.distance === 0) {
<span class="distance-chip area-mode"><mat-icon>map</mat-icon> {{ 'ALARM.USING_AREAS' | translate }}</span>
} @else {
<span class="distance-chip distance-mode"><mat-icon>straighten</mat-icon> {{ formatDistance(gym.distance) }}</span>
}
<app-where-chip
[distance]="gym.distance"
[overrideAreas]="gym.overrideAreas"
[overrideLocationLabel]="gym.overrideLocationLabel"
[profileAreas]="profileAreas()"
(click)="editScope(gym); $event.stopPropagation()" />
</div>
</mat-card-content>
<mat-card-actions align="end">
Expand Down
Loading
Loading