Skip to content

Commit

Permalink
Experimental Alert (#2871)
Browse files Browse the repository at this point in the history
  • Loading branch information
mark-drastrup authored and SigurdVilstrup committed Mar 21, 2023
1 parent b86d682 commit fe5a421
Show file tree
Hide file tree
Showing 26 changed files with 740 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<button kirby-button (click)="showAlert()">Show alert</button>
<button kirby-button (click)="showAlertWithIcon()">Show alert with icon</button>
<button kirby-button (click)="showAlertWithoutCancel()">Show alert without cancel</button>
<button kirby-button (click)="showDestructiveAlert()" class="destructive">
Show destructive alert
</button>
<button kirby-button (click)="showAlertWithNewline()">Show alert with newline</button>
<button kirby-button (click)="showAlertWithDynamicValues()">Show alert with dynamic values</button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import { Component } from '@angular/core';
import { of, Subject, timer } from 'rxjs';
import { map, takeUntil, takeWhile } from 'rxjs/operators';

import {
AlertExperimentalConfig,
AlertExperimentalController,
} from '@kirbydesign/designsystem/alert-experimental';
import { ToastConfig, ToastController } from '@kirbydesign/designsystem';

const alertConfigWithIcon: AlertExperimentalConfig = {
title: 'Alert With Icon',
message: 'This is an alert with an icon.',
okButton: 'I agree',
cancelButton: 'Take me back',
icon: { name: 'warning', themeColor: 'warning' },
};

export const observableCodeSnippet = `showAlert() {
const alert = this.alertController.showAlert(config);
alert.onWillDismiss.subscribe((response) => {
const { role, data } = response;
...
});
alert.onDidDismiss.subscribe((response) => {
const { role, data } = response;
...
});
}`;

@Component({
selector: 'cookbook-alert-experimental-example',
templateUrl: './alert-experimental-example.component.html',
styles: [':host { display: block; }'],
})
export class AlertExperimentalExampleComponent {
static readonly alertConfigWithIcon = `const config: AlertExperimentalConfig = ${AlertExperimentalExampleComponent.stringify(
alertConfigWithIcon
)}
this.alertController.showAlert(config);`;

private static stringify(value: any): string {
return JSON.stringify(value, null, '\t')
.replace(/"(\w+)\":/g, '$1:')
.replace(/"/g, "'");
}

private alertClose$: Subject<void> = new Subject<void>();

static readonly alertConfigWithDynamicValues = `const title$ = of('Need more time?');
const message$ = remainingSeconds$.pipe(
map((remainingSeconds) => \`Time remaining: \${remainingSeconds}\`)
);
const config: AlertExperimentalConfig = {
title: title$,
icon: {
name: 'clock',
themeColor: 'warning',
},
message: message$,
okBtn: 'Logout',
cancelBtn: 'Take me back',
};
this.alertController.showAlert(config);`;
constructor(
private alertController: AlertExperimentalController,
private toastController: ToastController
) {}

showAlert() {
const config: AlertExperimentalConfig = {
title: 'Default Alert',
message: 'The default alert is just a title, a message, an OK and (optional) cancel button',
okButton: 'I agree',
cancelButton: 'Take me back',
};

const alert = this.alertController.showAlert(config);

alert.onDidDismiss.subscribe((result) => {
this.onAlertClosed(result.data);
});
}

showAlertWithIcon() {
const alert = this.alertController.showAlert(alertConfigWithIcon);

alert.onDidDismiss.subscribe((result) => {
this.onAlertClosed(result.data);
});
}

showAlertWithoutCancel() {
const config: AlertExperimentalConfig = {
title: 'Alert Without Cancel',
message: 'This is an alert that can only be acknowledged (no cancel option)',
okButton: 'I understand',
};

const alert = this.alertController.showAlert(config);

alert.onDidDismiss.subscribe((result) => {
this.onAlertClosed(result.data);
});
}

showDestructiveAlert() {
const config: AlertExperimentalConfig = {
title: 'Desctructive Alert',
message:
'This is to indicate that something destructive will happen when clicking the OK button',
cancelButton: 'Get me out of here',
okButton: { text: 'Confirm', isDestructive: true },
};

const alert = this.alertController.showAlert(config);

alert.onDidDismiss.subscribe((result) => {
this.onAlertDestructiveClosed(result.data);
});
}

showAlertWithNewline() {
const config: AlertExperimentalConfig = {
title: 'Alert with newline',
message: 'This is message one.\n\nThis is message two.',
okButton: 'I agree',
cancelButton: 'Take me back',
};

const alert = this.alertController.showAlert(config);

alert.onDidDismiss.subscribe((result) => {
this.onAlertClosed(result.data);
});
}

showAlertWithDynamicValues() {
const countdownTimeInSeconds = 60;
const countdownTimeInMs = countdownTimeInSeconds * 1000;
const intervalInMs = 1000;
const toRemainingTimeInMs = (count: number) => countdownTimeInMs - count * intervalInMs;
const toSeconds = (timeInMs: number) => Math.ceil(timeInMs / 1000);

const remainingTime$ = timer(0, intervalInMs).pipe(
map(toRemainingTimeInMs),
takeUntil(this.alertClose$),
takeWhile((countdownTimeInMs) => countdownTimeInMs >= 0)
);

const title$ = of('Need more time?');
const message$ = remainingTime$.pipe(
map((remainingTimeInMs) => `Time remaining: ${toSeconds(remainingTimeInMs)}`)
);
const config: AlertExperimentalConfig = {
title: title$,
icon: {
name: 'clock',
themeColor: 'warning',
},
message: message$,
okButton: 'Logout',
cancelButton: 'Take me back',
};

const alert = this.alertController.showAlert(config);

alert.onDidDismiss.subscribe((result) => {
this.onAlertClosed(result.data);
});
}

private onAlertClosed(result?: boolean) {
const config: ToastConfig = {
message: `Alert selection: ${result}`,
messageType: result ? 'success' : 'warning',
durationInMs: 1500,
};
this.toastController.showToast(config);
this.alertClose$.next();
}

private onAlertDestructiveClosed(result?: boolean) {
const config: ToastConfig = {
message: result ? 'Message deleted' : 'Nothing happened',
messageType: result ? 'warning' : 'success',
durationInMs: 1500,
};
this.toastController.showToast(config);
}
}
2 changes: 2 additions & 0 deletions apps/cookbook/src/app/examples/examples.common.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AccordionExampleComponent } from './accordion-example/accordion-example.component';
import { ActionSheetExampleComponent } from './action-sheet-example/action-sheet-example.component';
import { AlertExampleComponent } from './alert-example/alert-example.component';
import { AlertExperimentalExampleComponent } from './alert-experimental-example/alert-experimental-example.component';
import { AvatarExampleComponent } from './avatar-example/avatar-example.component';
import { ButtonExampleComponent } from './button-example/button-example.component';
import { CalendarCardExampleComponent } from './calendar-example/calendar-card-example.component';
Expand Down Expand Up @@ -69,6 +70,7 @@ export const COMPONENT_DECLARATIONS: any[] = [
ActionSheetExampleComponent,
CheckboxExampleComponent,
AlertExampleComponent,
AlertExperimentalExampleComponent,
ToastExampleComponent,
ToggleExampleComponent,
EmptyStateExampleComponent,
Expand Down
2 changes: 2 additions & 0 deletions apps/cookbook/src/app/examples/examples.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from '@kirbydesign/designsystem';
import { SlideModule } from '@kirbydesign/designsystem/slide';

import { AlertExperimentalModule } from '@kirbydesign/designsystem/alert-experimental';
import { CodeViewerModule } from '../shared/code-viewer/code-viewer.module';
import { AccordionExampleModule } from './accordion-example/accordion-example.module';
import { AvatarExampleModule } from './avatar-example/avatar-example.module';
Expand Down Expand Up @@ -71,6 +72,7 @@ const IMPORTS = [
ExperimentalExamplesModule,
DataTableExampleModule,
SlideModule,
AlertExperimentalModule,
];

@NgModule({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<div class="example">
<cookbook-alert-experimental-example></cookbook-alert-experimental-example>
<p>&nbsp;</p>
<p>
To show an alert, inject the Kirby
<code>AlertExperimentalController</code>
in your constructor, create an
<code>AlertExperimentalConfig</code>
and pass it to
<code>alertController.showAlert</code>
.
<cookbook-code-viewer [ts]="alertConfigWithIcon"></cookbook-code-viewer>
</p>
<p>
<code>title</code>
and
<code>message</code>
properties in
<code>AlertExperimentalConfig</code>
also accept an Observable for dynamic values:
<br />
<em>
(see "Example on github" for implementation details of the
<code>remainingSeconds$</code>
timer)
</em>
:
<cookbook-code-viewer [ts]="alertConfigWithDynamicValues"></cookbook-code-viewer>
</p>
<p>
<em>[Optional]</em>
If you need to obtain data back from the alert, you can subscribe to the
<code>onWillDismiss</code>
and
<code>onDidDismiss</code>
events like this:
<!-- prettier-ignore -->
<cookbook-code-viewer [ts]="observableCodeSnippet"></cookbook-code-viewer>
</p>
<h4>Alert config properties:</h4>
<cookbook-api-description-properties
[properties]="properties"
></cookbook-api-description-properties>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Component } from '@angular/core';
import {
AlertExperimentalExampleComponent,
observableCodeSnippet,
} from '../../examples/alert-experimental-example/alert-experimental-example.component';
import { ApiDescriptionProperty } from '../../shared/api-description/api-description-properties/api-description-properties.component';
@Component({
selector: 'cookbook-alert-showcase',
templateUrl: './alert-experimental-showcase.component.html',
preserveWhitespaces: true,
})
export class AlertExperimentalShowcaseComponent {
alertConfigWithIcon: string = AlertExperimentalExampleComponent.alertConfigWithIcon;
alertConfigWithDynamicValues: string =
AlertExperimentalExampleComponent.alertConfigWithDynamicValues;
observableCodeSnippet: string = observableCodeSnippet;

properties: ApiDescriptionProperty[] = [
{
name: 'title',
description: 'The title of the alert',
type: ['string | Observable<string>'],
},
{
name: 'message',
description:
"(Optional) The message shown under the title (or icon if specified). Use '\\n' for newline.",
type: ['string | Observable<string>'],
},
{
name: 'icon',
description: '(Optional) Icon to be shown below the title',
type: ['{ name: string }', '{ name: string, themeColor: string }'],
},
{
name: 'okBtn',
description:
'(Optional) Defines the text that will appear on the OK button and if it should be destructive',
defaultValue: 'OK',
type: ['string', '{ text: string, isDestructive: boolean }'],
},
{
name: 'cancelBtn',
description:
'(Optional) The text that will appear on the cancel button. If not defined the cancel button will not be shown.',
type: ['string'],
},
];
}
2 changes: 2 additions & 0 deletions apps/cookbook/src/app/showcase/showcase.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ChartExampleConfigBaseBarComponent } from '../examples/charts-example/e
import { AccordionShowcaseComponent } from './accordion-showcase/accordion-showcase.component';
import { ActionSheetShowcaseComponent } from './action-sheet-showcase/action-sheet-showcase.component';
import { AlertShowcaseComponent } from './alert-showcase/alert-showcase.component';
import { AlertExperimentalShowcaseComponent } from './alert-experimental-showcase/alert-experimental-showcase.component';
import { AvatarShowcaseComponent } from './avatar-showcase/avatar-showcase.component';
import { BadgeShowcaseComponent } from './badge-showcase/badge-showcase.component';
import { ButtonShowcaseComponent } from './button-showcase/button-showcase.component';
Expand Down Expand Up @@ -83,6 +84,7 @@ export const COMPONENT_EXPORTS: any[] = [
ActionSheetShowcaseComponent,
CheckboxShowcaseComponent,
AlertShowcaseComponent,
AlertExperimentalShowcaseComponent,
ToastShowcaseComponent,
ToggleShowcaseComponent,
ToggleButtonShowcaseComponent,
Expand Down
5 changes: 5 additions & 0 deletions apps/cookbook/src/app/showcase/showcase.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ModalRoutingExperimentalExamplePage2Component } from '../examples/modal
import { AccordionShowcaseComponent } from './accordion-showcase/accordion-showcase.component';
import { ActionSheetShowcaseComponent } from './action-sheet-showcase/action-sheet-showcase.component';
import { AlertShowcaseComponent } from './alert-showcase/alert-showcase.component';
import { AlertExperimentalShowcaseComponent } from './alert-experimental-showcase/alert-experimental-showcase.component';
import { AvatarShowcaseComponent } from './avatar-showcase/avatar-showcase.component';
import { BadgeShowcaseComponent } from './badge-showcase/badge-showcase.component';
import { ButtonShowcaseComponent } from './button-showcase/button-showcase.component';
Expand Down Expand Up @@ -227,6 +228,10 @@ export const routes: Routes = [
path: 'alert',
component: AlertShowcaseComponent,
},
{
path: 'alert-experimental',
component: AlertExperimentalShowcaseComponent,
},
{
path: 'badge',
component: BadgeShowcaseComponent,
Expand Down
5 changes: 4 additions & 1 deletion apps/cookbook/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@
"@kirbydesign/designsystem/data-table": ["libs/designsystem/data-table/index.ts"],
"@kirbydesign/designsystem/reorder-list": ["libs/designsystem/reorder-list/index.ts"],
"@kirbydesign/designsystem/toast": ["libs/designsystem/toast/index.ts"],
"@kirbydesign/designsystem/grid": ["libs/designsystem/grid/index.ts"],
"@kirbydesign/designsystem/grid": ["libs/designsystem/grid/index.ts"],
"@kirbydesign/designsystem/alert-experimental": [
"libs/designsystem/alert-experimental/index.ts"
]
},
"target": "es2020"
},
Expand Down
5 changes: 4 additions & 1 deletion apps/flows/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@
"@kirbydesign/designsystem/data-table": ["libs/designsystem/data-table/index.ts"],
"@kirbydesign/designsystem/reorder-list": ["libs/designsystem/reorder-list/index.ts"],
"@kirbydesign/designsystem/toast": ["libs/designsystem/toast/index.ts"],
"@kirbydesign/designsystem/grid": ["libs/designsystem/grid/index.ts"],
"@kirbydesign/designsystem/grid": ["libs/designsystem/grid/index.ts"],
"@kirbydesign/designsystem/alert-experimental": [
"libs/designsystem/alert-experimental/index.ts"
]
},
"target": "es2020"
},
Expand Down
1 change: 1 addition & 0 deletions libs/designsystem/alert-experimental/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './src/index';
1 change: 1 addition & 0 deletions libs/designsystem/alert-experimental/ng-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Loading

0 comments on commit fe5a421

Please sign in to comment.