Skip to content

Commit 51af24a

Browse files
Vaibhav  BhallaVaibhav  Bhalla
authored andcommitted
feat(arc): implement breadcrumb feature
GH-126
1 parent 3f9dda5 commit 51af24a

File tree

13 files changed

+94
-55
lines changed

13 files changed

+94
-55
lines changed

package-lock.json

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
export const USERS = [
1+
import {TitleDetails, UserDetails} from './user-title.interface';
2+
3+
export const USERS: UserDetails[] = [
24
{id: '123', name: 'John Doe', email: 'john.doe123@example.com'},
35
{id: '124', name: 'Jane Smith', email: 'jane.smith124@example.com'},
46
];
5-
export const TITLES = [
7+
export const TITLES: TitleDetails[] = [
68
{id: '1', title: 'Contract.pdf'},
79
{id: '2', title: 'Appointment.pdf'},
810
];
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
export interface User {
1+
export interface UserDetails {
22
id: string;
33
name: string;
44
email: string;
55
}
6-
export interface Title {
6+
export interface TitleDetails {
77
id: string;
88
title: string;
99
}

projects/arc-lib/src/lib/components/breadcrumb/breadcrumb-demo/user-title/user-title.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import {Component} from '@angular/core';
22
import {ActivatedRoute} from '@angular/router';
3-
import {Title} from '../user-title.interface';
3+
import {TitleDetails} from '../user-title.interface';
44

55
@Component({
66
selector: 'lib-user-title',
77
templateUrl: './user-title.component.html',
88
})
99
export class UserTitleComponent {
10-
title: Title;
10+
title: TitleDetails;
1111
constructor(private readonly route: ActivatedRoute) {
1212
this.title = this.route.snapshot.data['document'];
1313
}

projects/arc-lib/src/lib/components/breadcrumb/breadcrumb-demo/user-title/user-title.resolver.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ import {Injectable} from '@angular/core';
22
import {ActivatedRouteSnapshot} from '@angular/router';
33
import {Observable} from 'rxjs';
44
import {TitleService} from './user-title.service';
5-
import {Title} from '../user-title.interface';
5+
import {TitleDetails} from '../user-title.interface';
66

77
@Injectable()
88
export class TitleResolver {
99
constructor(private readonly titleService: TitleService) {}
1010

11-
resolve(route: ActivatedRouteSnapshot): Observable<Title> {
11+
resolve(route: ActivatedRouteSnapshot): Observable<TitleDetails> {
1212
const id = route.paramMap.get('id');
13+
console.log(this.titleService.getTitleById(id));
1314
return this.titleService.getTitleById(id);
1415
}
1516
}

projects/arc-lib/src/lib/components/breadcrumb/breadcrumb-demo/user-title/user-title.service.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import {Injectable} from '@angular/core';
22
import {Observable, of} from 'rxjs';
33
import {TITLES} from '../mock-data.constants';
4+
import {TitleDetails} from '../user-title.interface';
45

56
@Injectable()
67
export class TitleService {
78
private readonly titles = TITLES;
89

9-
getTitleById(id: string): Observable<any> {
10+
getTitleById(id: string): Observable<TitleDetails> {
1011
const title = this.titles.find(u => u.id === id);
1112
return of(title);
1213
}

projects/arc-lib/src/lib/components/breadcrumb/breadcrumb-demo/user/user.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {CommonModule} from '@angular/common';
22
import {Component} from '@angular/core';
33
import {ActivatedRoute, RouterModule} from '@angular/router';
4-
import {User} from '../user-title.interface';
4+
import {UserDetails} from '../user-title.interface';
55
import {UserResolver} from './user.resolver';
66

77
@Component({
@@ -11,7 +11,7 @@ import {UserResolver} from './user.resolver';
1111
imports: [CommonModule, RouterModule],
1212
})
1313
export class UserComponent {
14-
user: User;
14+
user: UserDetails;
1515

1616
constructor(private readonly route: ActivatedRoute) {
1717
this.user = this.route.snapshot.data['user'];

projects/arc-lib/src/lib/components/breadcrumb/breadcrumb-demo/user/user.resolver.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import {Injectable} from '@angular/core';
22
import {ActivatedRouteSnapshot} from '@angular/router';
33
import {Observable} from 'rxjs';
44
import {UserService} from './user.service';
5-
import {User} from '../user-title.interface';
5+
import {UserDetails} from '../user-title.interface';
66

77
@Injectable()
88
export class UserResolver {
99
constructor(private readonly userService: UserService) {}
1010

11-
resolve(route: ActivatedRouteSnapshot): Observable<User> {
11+
resolve(route: ActivatedRouteSnapshot): Observable<UserDetails> {
1212
const id = route.paramMap.get('id');
1313
return this.userService.getUserById(id);
1414
}

projects/arc-lib/src/lib/components/breadcrumb/breadcrumb-demo/user/user.service.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import {Injectable} from '@angular/core';
22
import {Observable, of} from 'rxjs';
33
import {USERS} from '../mock-data.constants';
4+
import {UserDetails} from '../user-title.interface';
45

56
@Injectable()
67
export class UserService {
78
private readonly users = USERS;
89

9-
getUserById(id: string): Observable<any> {
10+
getUserById(id: string): Observable<UserDetails> {
1011
const user = this.users.find(u => u.id === id);
1112
return of(user);
1213
}

projects/arc-lib/src/lib/components/breadcrumb/breadcrumb.component.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {Component, Input, isDevMode, OnInit} from '@angular/core';
22
import {CommonModule} from '@angular/common';
33
import {Breadcrumb} from './breadcrumb.interface';
44
import {BreadcrumbService} from './breadcrumb.service';
5-
import {Observable} from 'rxjs';
5+
import {Observable, Subject, takeUntil} from 'rxjs';
66
import {RouterModule} from '@angular/router';
77

88
@Component({
@@ -22,14 +22,19 @@ export class BreadcrumbComponent implements OnInit {
2222
@Input() itemClass = 'breadcrumb-item';
2323

2424
expanded = false;
25+
private destroy$ = new Subject<void>();
2526
constructor(private readonly breadcrumbService: BreadcrumbService) {}
2627
ngOnInit(): void {
27-
this.breadcrumbs$.subscribe(breadcrumbs => {
28+
this.breadcrumbs$.pipe(takeUntil(this.destroy$)).subscribe(breadcrumbs => {
2829
if (isDevMode()) {
2930
console.log('Breadcrumbs:', breadcrumbs);
3031
}
3132
});
3233
}
34+
ngOnDestroy(): void {
35+
this.destroy$.next();
36+
this.destroy$.complete();
37+
}
3338
toggleExpand() {
3439
this.expanded = true;
3540
}

projects/arc-lib/src/lib/components/breadcrumb/breadcrumb.service.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,25 @@ export class BreadcrumbService {
5353
private _resolveLabel(route: ActivatedRouteSnapshot, path: string): string {
5454
const breadcrumbData = route.routeConfig.data?.['breadcrumb'];
5555

56-
if (typeof breadcrumbData === 'function') {
57-
return breadcrumbData(route.data, route.paramMap, route);
58-
}
59-
if (typeof breadcrumbData === 'string') {
60-
return breadcrumbData;
61-
}
62-
if (route.routeConfig.path?.startsWith(':')) {
63-
const paramName = route.routeConfig.path.slice(1);
64-
return route.params[paramName] ?? paramName;
56+
const conditions: [boolean, () => string][] = [
57+
[
58+
typeof breadcrumbData === 'function',
59+
() => breadcrumbData(route.data, route.paramMap, route),
60+
],
61+
[typeof breadcrumbData === 'string', () => breadcrumbData],
62+
[
63+
route.routeConfig.path?.startsWith(':'),
64+
() => {
65+
const paramName = route.routeConfig.path.slice(1);
66+
return route.params[paramName] ?? paramName;
67+
},
68+
],
69+
];
70+
71+
for (const [condition, action] of conditions) {
72+
if (condition) return action();
6573
}
74+
6675
return this._toTitleCase(path);
6776
}
6877

projects/arc/src/app/main/main-routing.module.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import {NgModule} from '@angular/core';
2-
import {RouterModule, Routes} from '@angular/router';
2+
import {ParamMap, RouterModule, Routes} from '@angular/router';
33
import {MainComponent} from './main.component';
44
import {UserComponent} from '@project-lib/components/breadcrumb/breadcrumb-demo/user/user.component';
55
import {UserResolver} from '@project-lib/components/breadcrumb/breadcrumb-demo/user/user.resolver';
66
import {UserTitleComponent} from '@project-lib/components/breadcrumb/breadcrumb-demo/user-title/user-title.component';
77
import {TitleResolver} from '@project-lib/components/breadcrumb/breadcrumb-demo/user-title/user-title.resolver';
8+
import {
9+
TitleDetails,
10+
UserDetails,
11+
} from '@project-lib/components/breadcrumb/breadcrumb-demo/user-title.interface';
812

913
const routes: Routes = [
1014
{
@@ -40,7 +44,7 @@ const routes: Routes = [
4044
component: UserComponent,
4145
resolve: {user: UserResolver},
4246
data: {
43-
breadcrumb: (data: any, params: any) =>
47+
breadcrumb: (data: {user?: UserDetails}, params: ParamMap) =>
4448
data.user?.name ?? `User #${params.get('id')}`,
4549
},
4650
children: [
@@ -49,7 +53,7 @@ const routes: Routes = [
4953
component: UserTitleComponent,
5054
resolve: {document: TitleResolver},
5155
data: {
52-
breadcrumb: (data: any, params: any) =>
56+
breadcrumb: (data: {document?: TitleDetails}, params: ParamMap) =>
5357
data.document?.title ?? `Document #${params.get('id')}`,
5458
},
5559
},

projects/saas-ui/src/app/on-boarding/components/add-tenant/add-tenant.component.ts

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
1-
import { Location } from '@angular/common';
2-
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
3-
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
4-
import { ActivatedRoute, Router } from '@angular/router';
5-
import { NbToastrService } from '@nebular/theme';
6-
import { AnyObject } from '@project-lib/core/api';
7-
import { environment } from 'projects/saas-ui/src/environment';
8-
import { Lead } from '../../../shared/models';
9-
import { BillingPlanService } from '../../../shared/services/billing-plan-service';
10-
import { OnBoardingService } from '../../../shared/services/on-boarding-service';
11-
12-
declare let Stripe: any;
1+
import {Location} from '@angular/common';
2+
import {
3+
AfterViewInit,
4+
Component,
5+
ElementRef,
6+
OnInit,
7+
ViewChild,
8+
} from '@angular/core';
9+
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
10+
import {ActivatedRoute, Router} from '@angular/router';
11+
import {NbToastrService} from '@nebular/theme';
12+
import {AnyObject} from '@project-lib/core/api';
13+
import {environment} from 'projects/saas-ui/src/environment';
14+
import {Lead} from '../../../shared/models';
15+
import {BillingPlanService} from '../../../shared/services/billing-plan-service';
16+
import {OnBoardingService} from '../../../shared/services/on-boarding-service';
17+
import {Stripe} from '@stripe/stripe-js';
18+
declare let Stripe: (key: string) => Stripe;
1319

1420
@Component({
1521
selector: 'app-add-tenant',
@@ -36,11 +42,18 @@ export class AddTenantComponent implements OnInit, AfterViewInit {
3642
private billingPlanService: BillingPlanService,
3743
) {
3844
this.addTenantForm = this.fb.group({
39-
key: ['', [Validators.required, Validators.maxLength(10), Validators.pattern('^[a-zA-Z][a-zA-Z0-9]*$')]],
45+
key: [
46+
'',
47+
[
48+
Validators.required,
49+
Validators.maxLength(10),
50+
Validators.pattern('^[a-zA-Z][a-zA-Z0-9]*$'),
51+
],
52+
],
4053
domains: [''],
41-
planId: [null, Validators.required], // Mark planId as required
42-
paymentMethod: ['payment_source'], // Specify Stripe as payment method
43-
paymentToken: ['', Validators.required] // New FormControl for Stripe token
54+
planId: [null, Validators.required], // Mark planId as required
55+
paymentMethod: ['payment_source'], // Specify Stripe as payment method
56+
paymentToken: ['', Validators.required], // New FormControl for Stripe token
4457
});
4558
}
4659

@@ -67,14 +80,14 @@ export class AddTenantComponent implements OnInit, AfterViewInit {
6780
fontSmoothing: 'antialiased',
6881
fontSize: '16px',
6982
'::placeholder': {
70-
color: '#aab7c4'
71-
}
83+
color: '#aab7c4',
84+
},
7285
},
7386
invalid: {
7487
color: '#fa755a',
75-
iconColor: '#fa755a'
76-
}
77-
}
88+
iconColor: '#fa755a',
89+
},
90+
},
7891
});
7992

8093
this.cardElement.mount(this.cardNumberElement.nativeElement);
@@ -83,7 +96,7 @@ export class AddTenantComponent implements OnInit, AfterViewInit {
8396
this.cardElement.on('change', (event: any) => {
8497
if (event.error) {
8598
this.toastrService.danger(event.error.message, 'Error');
86-
this.addTenantForm.get('paymentToken')?.setValue(''); // Clear paymentToken on error
99+
this.addTenantForm.get('paymentToken')?.setValue(''); // Clear paymentToken on error
87100
} else if (event.complete) {
88101
this.generateStripeToken();
89102
}
@@ -92,7 +105,7 @@ export class AddTenantComponent implements OnInit, AfterViewInit {
92105

93106
// Generate token and set it to the form when payment details are complete
94107
async generateStripeToken() {
95-
const { token, error } = await this.stripe.createToken(this.cardElement);
108+
const {token, error} = await this.stripe.createToken(this.cardElement);
96109
if (error) {
97110
this.toastrService.danger(error.message, 'Error');
98111
} else {
@@ -115,7 +128,7 @@ export class AddTenantComponent implements OnInit, AfterViewInit {
115128

116129
this.onboardingService.addTenant(domainData, this.leadId).subscribe(
117130
() => this.router.navigate(['/tenant/registration/complete']),
118-
error => this.toastrService.danger('Registration failed', 'Error')
131+
error => this.toastrService.danger('Registration failed', 'Error'),
119132
);
120133
}
121134
}
@@ -128,13 +141,15 @@ export class AddTenantComponent implements OnInit, AfterViewInit {
128141
},
129142
error => {
130143
this.toastrService.danger('Failed to fetch lead data', 'Error');
131-
}
144+
},
132145
);
133146
}
134147

135148
updateDomainFromEmail() {
136149
if (this.leadData && this.leadData.email) {
137-
const emailDomain = this.leadData.email?.substring(this.leadData.email.lastIndexOf('@') + 1);
150+
const emailDomain = this.leadData.email?.substring(
151+
this.leadData.email.lastIndexOf('@') + 1,
152+
);
138153
if (emailDomain) {
139154
this.addTenantForm.get('domains').setValue(emailDomain);
140155
}

0 commit comments

Comments
 (0)