Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experimental Alert #2871

Merged
merged 25 commits into from
Feb 23, 2023
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ea3b525
Create a secondary entry for the experimental alert
mark-drastrup Feb 13, 2023
97df49e
Add the alert path to tsconfig files
mark-drastrup Feb 13, 2023
4a231b6
Refactor alertController from promises to observables
mark-drastrup Feb 13, 2023
b1b64c9
Fix broken tests
mark-drastrup Feb 13, 2023
84695fb
Create showcase component
mark-drastrup Feb 13, 2023
506dcf4
Rename the controller to include 'Experimental'
mark-drastrup Feb 13, 2023
d31c9a2
Fix bug that prevents the bookcook from running
mark-drastrup Feb 13, 2023
50d3450
WIP: update cookbook example
mark-drastrup Feb 13, 2023
f1f6bb2
Create a secondary entry for the experimental alert
mark-drastrup Feb 13, 2023
ce552a6
Add the alert path to tsconfig files
mark-drastrup Feb 13, 2023
df946c5
Refactor alertController from promises to observables
mark-drastrup Feb 13, 2023
c32bafe
Fix broken tests
mark-drastrup Feb 13, 2023
a6681e4
Create showcase component
mark-drastrup Feb 13, 2023
38a8781
Rename the controller to include 'Experimental'
mark-drastrup Feb 13, 2023
572b4b5
Fix bug that prevents the bookcook from running
mark-drastrup Feb 13, 2023
670ea02
WIP: update cookbook example
mark-drastrup Feb 13, 2023
d9bab93
Merge branch '2855/experimental-alert' of https://github.com/kirbydes…
mark-drastrup Feb 17, 2023
90bf3e8
Create a module for the alert
mark-drastrup Feb 17, 2023
5823f19
Remove IonicModule from the alert module
mark-drastrup Feb 17, 2023
00e1a9e
Update the cookbook example
mark-drastrup Feb 17, 2023
204d0f1
Update the cookbook according to review comments
mark-drastrup Feb 21, 2023
4455b05
Remove shorthand names
mark-drastrup Feb 21, 2023
2876645
Fix broken tests and arrange beforeEach according to AAA
mark-drastrup Feb 21, 2023
513df3a
Fix broken tests
mark-drastrup Feb 21, 2023
f342a6d
Merge branch 'develop' into 2855/experimental-alert
mark-drastrup Feb 23, 2023
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
@@ -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 = {
title: 'Alert With Icon',
message: 'This message can have more than 1 line.',
mark-drastrup marked this conversation as resolved.
Show resolved Hide resolved
okBtn: 'I agree',
cancelBtn: 'Take me back',
icon: { name: 'warning', themeColor: 'warning' },
};

export const observableCodeSnippet = `showAlert() {
const alert = this.alertController.showAlert(config);
alert?.onWillDismiss.subscribe((response) => {
mark-drastrup marked this conversation as resolved.
Show resolved Hide resolved
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(
mark-drastrup marked this conversation as resolved.
Show resolved Hide resolved
map((remainingSeconds) => \`Time remaining: \${remainingSeconds}\`)
);
const config: AlertExperimentalConfig = {
title: title$,
icon: {
name: 'clock',
themeColor: 'warning',
},
message: message$,
okBtn: 'Logout',
mark-drastrup marked this conversation as resolved.
Show resolved Hide resolved
cancelBtn: 'Take me back',
mark-drastrup marked this conversation as resolved.
Show resolved Hide resolved
};

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',
okBtn: 'I agree',
cancelBtn: '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)',
okBtn: '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',
cancelBtn: 'Get me out of here',
okBtn: { 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.',
okBtn: 'I agree',
cancelBtn: '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$,
okBtn: 'Logout',
cancelBtn: '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-example></cookbook-alert-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