Skip to content

Commit

Permalink
feat: add new builder pattern to handle pre-grouping
Browse files Browse the repository at this point in the history
`// Create parent toastconst parent = new HotToastBuilder(template, toast)  .setOptions({
position: 'top-right',    className: 'custom-class'  });// Add childrennotifications.map(n =>   new
HotToastBuilder(n.message, toast)    .setOptions(n.options)).forEach(child =>
parent.addChild(child));// Create and show when readyconst ref =
parent.create();ref.afterGroupRefsAttached.subscribe(() => ref.show());`

fix #9
  • Loading branch information
shhdharmen committed Dec 6, 2024
1 parent 39347a7 commit 8b59a9a
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 27 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"scripts": {
"ng": "ng",
"start": "ng serve",
"start:lib": "ng build @ngxpert/hot-toast --watch",
"build": "ng build",
"unit": "npm run cy:open",
"test": "npm run ci:cy-run",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
}
</div>

@if (toast.visible) {
<div
role="list"
class="hot-toast-bar-base-group"
Expand All @@ -78,5 +79,6 @@
></hot-toast-group-item>
}
</div>
}
</div>
</div>
86 changes: 86 additions & 0 deletions projects/ngxpert/hot-toast/src/lib/hot-toast-builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { Content } from '@ngneat/overview';
import { CreateHotToastRef, ToastOptions } from './hot-toast.model';
import { HotToastService } from './hot-toast.service';
import { Observable } from 'rxjs';

type ToastMethod = 'show' | 'success' | 'error' | 'warning' | 'info' | 'loading';

export class HotToastBuilder<DataType = unknown> {
private options: ToastOptions<DataType>;
private groupChildren: HotToastBuilder<unknown>[] = [];
private toastRef: CreateHotToastRef<DataType>;

constructor(private message: Content, private service: HotToastService) {
this.options = {};
}

setOptions(options: ToastOptions<DataType>): this {
this.options = { ...this.options, ...options };
return this;
}

addChild(child: HotToastBuilder<unknown>): this {
this.groupChildren.push(child);
return this;
}

get afterGroupRefsAttached(): Observable<CreateHotToastRef<unknown>[]> {
return this.toastRef?.afterGroupRefsAttached;
}

private addChildrenToOptions() {
if (this.groupChildren.length > 0) {
const children = this.groupChildren.map((child) => ({
options: {
message: child.message,
...child.options,
},
}));

this.options.group = {
...this.options.group,
children,
};
}
}

// Create method that creates but doesn't show the toast. Call show() to show the toast.
create(method: ToastMethod = 'show'): CreateHotToastRef<DataType> {
this.addChildrenToOptions();
this.toastRef = this.service[method](this.message, {
...this.options,
...{ visible: false },
}) as CreateHotToastRef<DataType>;
return this.toastRef;
}

private createToast(method: ToastMethod): CreateHotToastRef<DataType> {
this.addChildrenToOptions();
this.toastRef = this.service[method](this.message, this.options) as CreateHotToastRef<DataType>;
return this.toastRef;
}

show(): CreateHotToastRef<DataType> {
return this.createToast('show');
}

success(): CreateHotToastRef<DataType> {
return this.createToast('success');
}

error(): CreateHotToastRef<DataType> {
return this.createToast('error');
}

warning(): CreateHotToastRef<DataType> {
return this.createToast('warning');
}

info(): CreateHotToastRef<DataType> {
return this.createToast('info');
}

loading(): CreateHotToastRef<DataType> {
return this.createToast('loading');
}
}
6 changes: 6 additions & 0 deletions projects/ngxpert/hot-toast/src/lib/hot-toast-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export class HotToastRef<DataType = DefaultDataType> implements HotToastRefProps
/** Subject for notifying the user that the toast has been closed. */
private _onGroupToggle = new Subject<HotToastGroupEvent>();

private _componentRef: { changeDetectorRef: { detectChanges: () => void } };

constructor(private toast: Toast<DataType>) {}

set data(data: DataType) {
Expand Down Expand Up @@ -87,4 +89,8 @@ export class HotToastRef<DataType = DefaultDataType> implements HotToastRefProps
event: this.groupExpanded ? 'expand' : 'collapse',
});
}

show() {
this.toast.visible = true;
}
}
1 change: 1 addition & 0 deletions projects/ngxpert/hot-toast/src/lib/hot-toast.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ export interface HotToastRefProps<DataType> {
* @since 1.1.0
*/
toggleGroup: (eventData?: { byAction: boolean }) => void;
show: () => void;
}

/** Event that is emitted when a toast is dismissed. */
Expand Down
1 change: 1 addition & 0 deletions projects/ngxpert/hot-toast/src/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './lib/hot-toast.service';
export * from './lib/hot-toast.provide';
export * from './lib/hot-toast.model';
export * from './lib/hot-toast-ref';
export * from './lib/hot-toast-builder';
43 changes: 32 additions & 11 deletions src/app/sections/grouping/grouping.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { CodeComponent } from 'src/app/shared/components/code/code.component';
import { HtmlPipe } from 'src/app/shared/pipes/html.pipe';
import { NgClass } from '@angular/common';
import { preGroupingTS, preGroupingHTML, preGroupingCSS, postGroupingTS } from './snippets';
import { HotToastBuilder } from '@ngxpert/hot-toast';

@Component({
selector: 'app-grouping',
Expand Down Expand Up @@ -99,9 +100,9 @@ export class GroupingComponent implements OnInit {
{
id: 'grouping-pre',
title: 'Show Pre-Grouped Notifications',
subtitle: `<p class="mb-2">If you need to group toasts, you can use <b><code>group.children</code></b> option. This is useful if you want to show for example notifications as grouped items.</p>
subtitle: `<p class="mb-2">You can create grouped toasts using the builder pattern. First create the parent and child toasts, then connect them using <b><code>addChild()</code></b>.</p>
<p class="text-md bg-toast-200 p-4 rounded-2xl p-4">
👉 You can access children group toast references using <b><code>toastRef.groupsRefs</code></b>
👉 Create toasts with <b><code>create()</code></b> and show them after all refs are attached using <b><code>afterGroupRefsAttached</code></b>
</p>
`,
emoji: '🔔',
Expand All @@ -112,15 +113,7 @@ export class GroupingComponent implements OnInit {
css: preGroupingCSS,
},
action: () => {
this.toast.show(this.ngTemplateGroup, {
position: 'top-right',
autoClose: false,
className: 'hot-toast-custom-class',
group: {
className: 'hot-toast-custom-class',
children: this.childNotifications(this.ngTemplateGroupItem),
},
});
this.showPreGroupedNotifications();
},
},
{
Expand Down Expand Up @@ -164,4 +157,32 @@ export class GroupingComponent implements OnInit {
click(e: Example) {
e.action();
}

showPreGroupedNotifications() {
// Create parent toast first but don't show it
const parentBuilder = new HotToastBuilder(this.ngTemplateGroup, this.toast).setOptions({
position: 'top-right',
autoClose: false,
className: 'hot-toast-custom-class',
group: {
className: 'hot-toast-custom-class',
},
});

// Create child toasts
const children = this.childNotifications(this.ngTemplateGroupItem).map((child) => {
return new HotToastBuilder(child.options.message, this.toast).setOptions(child.options);
});

// Add children to parent
children.forEach((child) => parentBuilder.addChild(child));

// Create the toast with all children (but don't show yet)
const parentRef = parentBuilder.create();

// Once all refs are attached, show the parent toast
parentRef.afterGroupRefsAttached.subscribe(() => {
parentRef.show();
});
}
}
35 changes: 19 additions & 16 deletions src/app/sections/grouping/snippets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,29 +65,32 @@ readonly childNotifications = (ngTemplateGroupItem: Content): HotToastGroupChild
];`;

export const preGroupingTS = `
@ViewChild('groupTemplate') ngTemplateGroup;
@ViewChild('groupItemTemplate') ngTemplateGroupItem;
toast = inject(HotToastService);
showPreGroupedNotifications() {
this.toast.show(ngTemplateGroup, {
const parentBuilder = new HotToastBuilder(ngTemplateGroup, toast)
.setOptions({
position: 'top-right',
autoClose: false,
className: 'hot-toast-custom-class',
group: {
className: 'hot-toast-custom-class',
children: this.childNotifications(this.ngTemplateGroupItem),
className: 'hot-toast-custom-class'
}
})
}
});
visibleToasts(toastRefs: CreateHotToastRef&lt;unknown>[]) {
return toastRefs.filter((t) => t.getToast().visible).length;
}
// Create child toasts
const children = childNotifications(ngTemplateGroupItem).map((child) => {
return new HotToastBuilder(child.options.message, toast)
.setOptions(child.options);
});
${childNotifications}
`;
// Add children to parent
children.forEach((child) => parentBuilder.addChild(child));
// Create the toast with all children (but don't show yet)
const parentRef = parentBuilder.create();
// Once all refs are attached, show the parent toast
parentRef.afterGroupRefsAttached.subscribe(() => {
parentRef.show();
});`;

export const preGroupingHTML = `
&lt;ng-template #groupTemplate let-toastRef>
Expand Down

0 comments on commit 8b59a9a

Please sign in to comment.