Skip to content

Commit

Permalink
Merge pull request #427 from funidata/DS-269-alert
Browse files Browse the repository at this point in the history
[Alert, Alert Group, Alert Service]: New components and service
  • Loading branch information
RiinaKuu committed Sep 19, 2024
2 parents a10938b + 64931cf commit 8d1a0fb
Show file tree
Hide file tree
Showing 59 changed files with 641 additions and 729 deletions.
4 changes: 2 additions & 2 deletions ngx-fudis/projects/dev/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<ng-container *transloco="let t">
<div class="root-style">
<!-- <fudis-alert-group /> -->
<fudis-alert-group />

<fudis-grid [columns]="4" [marginTop]="'lg'">
<fudis-grid-item [columns]="'3 / 4'" [alignSelfX]="'end'" [alignSelfY]="'end'">
Expand All @@ -24,7 +24,7 @@
<fudis-heading [level]="3" fudisGridItem [columns]="'auto'">
<fudis-link [href]="'#'" [title]="'Link inside a heading'"></fudis-link>
</fudis-heading>
<!-- <fudis-button [label]="'Trigger alert'" (handleClick)="triggerAlert()" /> -->
<fudis-button [label]="'Trigger alert'" (handleClick)="triggerAlert()" />
<fudis-button [label]="'Open dialog with form'" (handleClick)="openDialog()" />
<fudis-body-text *ngIf="_message"
>This value comes from the closed dialog input:
Expand Down
24 changes: 11 additions & 13 deletions ngx-fudis/projects/dev/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Component, Inject, OnInit } from '@angular/core';
import { TranslocoService } from '@ngneat/transloco';
import {
// FudisAlertService,
FudisAlertService,
FudisDialogService,
FudisGridService,
FudisTranslationService,
Expand All @@ -10,7 +10,7 @@ import {
} from 'ngx-fudis';
import { DOCUMENT } from '@angular/common';
import { FudisSelectOption, FudisCheckboxOption } from 'dist/ngx-fudis/lib/types/forms';
// import { FudisAlert } from 'dist/ngx-fudis/lib/types/miscellaneous';
import { FudisAlert } from 'dist/ngx-fudis/lib/types/miscellaneous';
import { DialogTestContentComponent } from './dialog-test/dialog-test-content/dialog-test-content.component';
import { FudisGridAlign } from 'projects/ngx-fudis/src/lib/types/grid';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
Expand All @@ -28,7 +28,7 @@ export class AppComponent implements OnInit {
private _translocoService: TranslocoService,
private _gridService: FudisGridService,
private _fudisLanguage: FudisTranslationService,
// private _alertService: FudisAlertService,
private _alertService: FudisAlertService,
private _errorSummaryService: FudisErrorSummaryService,
private _breakpointService: FudisBreakpointService,
) {
Expand Down Expand Up @@ -93,16 +93,14 @@ export class AppComponent implements OnInit {
this.getApplicationFontSize();
}

// triggerAlert(): void {
// const newAlert: FudisAlert = {
// message: 'Something dangerous MIGHT happen.',
// type: 'warning',
// id: 'my-own-id-3',
// routerLinkUrl: '/',
// linkTitle: 'More info about this warning.',
// };
// this._alertService.addAlert(newAlert);
// }
triggerAlert(): void {
const newAlert: FudisAlert = {
message: this._translocoService.selectTranslate('alertText'),
type: 'warning',
id: 'my-own-id-3',
};
this._alertService.addAlert(newAlert);
}

getApplicationFontSize(): void {
this.fontSize = getComputedStyle(
Expand Down
1 change: 1 addition & 0 deletions ngx-fudis/projects/dev/src/assets/i18n/en.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"alertText": "Something dangerous MIGHT happen",
"label": "This is text input",
"change_language": "Change language",
"helpText": "This is English.",
Expand Down
1 change: 1 addition & 0 deletions ngx-fudis/projects/dev/src/assets/i18n/fi.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"alertText": "Jotain kamalaa voipi tapahtua",
"label": "Tämä on tekstikenttä",
"change_language": "Vaihda kieli",
"helpText": "Kivaa jos näet minut suomeksi!",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
<section
*ngIf="_visible"
*ngIf="(_visible | async) && (_alertService.alerts | async) as alerts"
class="fudis-alert-group fudis-alert-group__{{ position }}"
[attr.aria-label]="_alertList().length > 0 ? _alertGroupLabel + ': ' + _alertList().length : null"
[attr.aria-label]="alerts.length > 0 ? (_alertGroupLabel | async) + ': ' + alerts.length : null"
>
<ng-container *ngFor="let alert of _alertList()">
<ng-container *ngFor="let alert of alerts">
<fudis-alert
[initialFocus]="alert.initialFocus"
[variant]="alert.type"
[message]="alert.message"
[id]="alert.id"
[htmlId]="alert.htmlId"
[buttonId]="alert.buttonId"
[linkTitle]="alert.linkTitle"
[link]="alert.routerLinkUrl"
/>
</ng-container>
</section>
Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { MockComponent } from 'ng-mocks';
import { AlertGroupComponent } from './alert-group.component';
import { FudisDialogService } from '../../../services/dialog/dialog.service';
import { BodyTextComponent } from '../../typography/body-text/body-text.component';
import { FudisAlertService } from '../../../services/alert/alert.service';
import { FudisAlert } from '../../../types/miscellaneous';
import { FudisAlert, fudisAlertPositionArray } from '../../../types/miscellaneous';
import { AlertComponent } from '../alert/alert.component';
import { IconComponent } from '../../icon/icon.component';
import { getElement, sortClasses } from '../../../utilities/tests/utilities';
import { BehaviorSubject } from 'rxjs';
import { SimpleChange } from '@angular/core';

// TODO: fix & refactor when these are again published

describe.skip('AlertGroupComponent', () => {
describe('AlertGroupComponent', () => {
let component: AlertGroupComponent;
let fixture: ComponentFixture<AlertGroupComponent>;
let alertService: FudisAlertService;
let dialogService: FudisDialogService;

beforeEach(() => {
TestBed.configureTestingModule({
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [MatDialogModule],
declarations: [
AlertGroupComponent,
BodyTextComponent,
AlertComponent,
BodyTextComponent,
MockComponent(IconComponent),
],
providers: [
Expand All @@ -39,7 +38,10 @@ describe.skip('AlertGroupComponent', () => {
useValue: [],
},
],
});
}).compileComponents();

alertService = TestBed.inject(FudisAlertService);
dialogService = TestBed.inject(FudisDialogService);
fixture = TestBed.createComponent(AlertGroupComponent);
component = fixture.componentInstance;
fixture.detectChanges();
Expand All @@ -50,55 +52,33 @@ describe.skip('AlertGroupComponent', () => {
});

describe('Basic inputs', () => {
it('should have default CSS classes', () => {
const element = getElement(fixture, 'section');

expect(sortClasses(element.className)).toEqual(
sortClasses('fudis-alert-group fudis-alert-group__fixed'),
);
});

it('should have absolute position', () => {
component.position = 'absolute';
fixture.detectChanges();

const element = getElement(fixture, 'section');

expect(sortClasses(element.className)).toEqual(
sortClasses('fudis-alert-group fudis-alert-group__absolute'),
);
});

it('should have static position', () => {
component.position = 'static';
fixture.detectChanges();

const element = getElement(fixture, 'section');

expect(sortClasses(element.className)).toEqual(
sortClasses('fudis-alert-group fudis-alert-group__static'),
);
it('should update CSS class according to position input', () => {
fudisAlertPositionArray.forEach((position) => {
const element = getElement(fixture, '.fudis-alert-group');
fixture.componentRef.setInput('position', `${position}`);
fixture.detectChanges();

expect(sortClasses(element.className)).toEqual(
sortClasses(`fudis-alert-group fudis-alert-group__${position}`),
);
});
});
});

describe('Functionality with services', () => {
beforeEach(() => {
alertService = TestBed.inject(FudisAlertService);
dialogService = TestBed.inject(FudisDialogService);

jest.spyOn(alertService, 'getAlertsSignal').mockImplementation();

const firstAlert: FudisAlert = {
message: 'Test message',
message: new BehaviorSubject<string>('Test message'),
id: 'my-test-id-1',
type: 'info',
};

const secondAlert: FudisAlert = {
message: 'Second test message',
message: new BehaviorSubject<string>('Second test message'),
id: 'my-test-id-2',
type: 'warning',
};

alertService.addAlert(firstAlert);
alertService.addAlert(secondAlert);
});
Expand All @@ -111,7 +91,7 @@ describe.skip('AlertGroupComponent', () => {
expect(childAlerts.length).toEqual(2);
});

it('should have one alert as children after one is dismissed', () => {
it('should have one alert as child after one is dismissed', () => {
alertService.dismissAlert('my-test-id-1');
fixture.detectChanges();

Expand All @@ -123,7 +103,7 @@ describe.skip('AlertGroupComponent', () => {
});

it('should not be visible, if Dialog is open', () => {
dialogService.setDialogOpenSignal(true);
dialogService.setDialogOpenStatus(true);

fixture.detectChanges();

Expand All @@ -132,7 +112,7 @@ describe.skip('AlertGroupComponent', () => {
});

it('should be visible, if Dialog is closed', () => {
dialogService.setDialogOpenSignal(false);
dialogService.setDialogOpenStatus(false);

fixture.detectChanges();

Expand All @@ -141,11 +121,14 @@ describe.skip('AlertGroupComponent', () => {
});

it('should not be visible, if Dialog is not open and Alert Group is inside dialog', () => {
component.insideDialog = true;
dialogService.setDialogOpenStatus(false);

component.ngAfterViewInit();
component.insideDialog = true;
component.ngOnChanges({
insideDialog: new SimpleChange('false', component.insideDialog, true),
});

fixture.detectChanges();
fixture.autoDetectChanges();

expect(fixture.nativeElement.querySelector('section')).toBeNull();
expect(component.getVisibleStatus()).toEqual(false);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,82 +1,85 @@
import { ChangeDetectorRef, Component, Input, AfterViewInit, Signal, effect } from '@angular/core';

import { FudisAlertElement } from '../../../types/miscellaneous';
import { Component, Input, effect, OnChanges, ChangeDetectionStrategy } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import {
FudisAlertElement,
FudisAlertPosition,
FudisComponentChanges,
} from '../../../types/miscellaneous';
import { FudisTranslationService } from '../../../services/translation/translation.service';
import { FudisAlertService } from '../../../services/alert/alert.service';
import { FudisDialogService } from '../../../services/dialog/dialog.service';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';

@Component({
selector: 'fudis-alert-group',
templateUrl: './alert-group.component.html',
styleUrls: ['./alert-group.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AlertGroupComponent implements AfterViewInit {
export class AlertGroupComponent implements OnChanges {
constructor(
private _alertService: FudisAlertService,
protected _alertService: FudisAlertService,
private _translationService: FudisTranslationService,
private readonly _changeDetectorRef: ChangeDetectorRef,
private _dialogService: FudisDialogService,
) {
effect(() => {
this._alertList = this._alertService.getAlertsSignal();
// TODO: To Observable
this._alertGroupLabel = this._translationService.getTranslations()().ALERT.HEADING_LABEL;
this._dialogService
.getDialogOpenStatus()
.pipe(takeUntilDestroyed())
.subscribe((value) => {
this._setVisibility(value);
});

this._dialogStatus = this._dialogService.getDialogOpenSignal()();

this._setVisibility();
effect(() => {
this._alertGroupLabel.next(this._translationService.getTranslations()().ALERT.HEADING_LABEL);
});
}

/**
* CSS position of alerts. Defaults to fixed.
* CSS position of alerts
*/
@Input() position: 'fixed' | 'absolute' | 'static' = 'fixed';
@Input() position: FudisAlertPosition = 'fixed';

/**
* Boolean to determine if Alert Group is used as child in Fudis Dialog.
* Boolean to determine if Alert Group is used inside Fudis Dialog Component
*/
@Input() insideDialog: boolean = false;
@Input() insideDialog: boolean;

/**
* List of Alerts fetched from service
* List of Alerts fetched from Alert Service
*/
protected _alertList: Signal<FudisAlertElement[]>;
protected _alertList = new BehaviorSubject<FudisAlertElement[]>([]);

/**
* Label for section element containing alerts
*/
protected _alertGroupLabel: string;
protected _alertGroupLabel = new BehaviorSubject<string>('');

/**
* Boolean to determine if Alert group is visible. Used with _dialogStatus boolean.
* Boolean to determine if Alert group is visible
*/
protected _visible: boolean = false;
protected _visible = new BehaviorSubject<boolean>(false);

/**
* Boolean from service to determine if Fudis Dialog is open.
*/
private _dialogStatus: boolean;

ngAfterViewInit(): void {
this._setVisibility();
ngOnChanges(changes: FudisComponentChanges<AlertGroupComponent>): void {
if (changes.insideDialog?.currentValue !== changes.insideDialog?.previousValue) {
this._setVisibility(this._dialogService.getDialogOpenStatus().value);
}
}

/**
* Getter for visible status
* Get Alert Group's visible status
*/
public getVisibleStatus(): boolean {
return this._visible;
return this._visible.value;
}

/**
* Set visibility when Fudis Dialog is opened and closed.
* Set visibility when Fudis Dialog is opened and closed
*/
private _setVisibility(): void {
if ((this._dialogStatus && this.insideDialog) || (!this._dialogStatus && !this.insideDialog)) {
this._visible = true;
private _setVisibility(dialogStatus: boolean): void {
if ((dialogStatus && this.insideDialog) || (!dialogStatus && !this.insideDialog)) {
this._visible.next(true);
} else {
this._visible = false;
this._visible.next(false);
}
}
}
Loading

0 comments on commit 8d1a0fb

Please sign in to comment.