Skip to content

Commit

Permalink
Create RouterService to be used centrally in components
Browse files Browse the repository at this point in the history
- Using RouterService prevents the previously happening circular reference
  • Loading branch information
Macavity committed Jan 18, 2024
1 parent 249de53 commit e25ba27
Show file tree
Hide file tree
Showing 13 changed files with 207 additions and 119 deletions.
9 changes: 5 additions & 4 deletions .github/workflows/production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Deployment (Prod) 🚀

on:
workflow_dispatch:

jobs:
deploy:
runs-on: ubuntu-latest
Expand All @@ -26,6 +26,7 @@ jobs:
uses: mansagroup/nrwl-nx-action@v3
with:
targets: build
all: true

- name: Remove not required files
run: |
Expand All @@ -41,12 +42,12 @@ jobs:
port: 22
source: "./*"
target: ${{ secrets.DEPLOYMENT_PATH }}

clear-cache:
name: 🧹 Clear Cache
needs: deploy
runs-on: ubuntu-latest
environment: production
environment: production

steps:
- name: SSH and Clear Symfony Cache
Expand All @@ -59,4 +60,4 @@ jobs:
script: |
cd ${{ secrets.DEPLOYMENT_PATH }}
php81 `which composer` cache
36 changes: 3 additions & 33 deletions apps/client/src/app/app.routing.module.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,16 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AccountSelectionComponent } from './pages/account-selection/account-selection.component';
import { StartComponent } from './pages/start/start.component';

import { CommonModule } from '@angular/common';
import { BalanceOverviewComponent } from './pages/balance-overview/balance-overview.component';
import { TransactionHistoryComponent } from './pages/transaction-history/transaction-history.component';
import { DashboardComponent } from './pages/dashboard/dashboard.component';
import { LoginComponent } from './pages/login/login.component';
import { PlanComponent } from './pages/plan/plan.component';
import { AccountSelectionComponent } from './pages/account-selection/account-selection.component';
import { AccountsResolver } from './services/accounts-resolver.service';

export enum RoutePath {
Home = 'home',
Login = 'login',
AccountSelection = 'accountselection',
Dashboard = 'account/:name/dashboard',
Overview = 'account/:name/overview',
History = 'account/:name/history',
Plan = 'account/:name/plan',
}

export function routeToDashboard(name: string) {
name = decodeURI(name);
return RoutePath.Dashboard.replace(':name', name);
}

export function routeToOverview(name: string) {
console.log({ name });
name = decodeURI(name);
return RoutePath.Overview.replace(':name', name);
}

export function routeToHistory(name: string) {
name = decodeURI(name);
return RoutePath.History.replace(':name', name);
}

export function routeToPlan(name: string) {
name = decodeURI(name);
return RoutePath.Plan.replace(':name', name);
}
import { RoutePath } from './enum/routepath';
import { DashboardComponent } from './pages/dashboard/dashboard.component';

const routes: Routes = [
{
Expand Down
10 changes: 10 additions & 0 deletions apps/client/src/app/enum/routepath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export enum RoutePath {
Home = 'home',
Login = 'login',
Logout = 'logout',
AccountSelection = 'accountselection',
Dashboard = 'account/:name/dashboard',
Overview = 'account/:name/overview',
History = 'account/:name/history',
Plan = 'account/:name/plan',
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ActivatedRoute } from '@angular/router';
import { Observable, of } from 'rxjs';
import { Account } from '@money-sprouts/shared/domain';
import { AccountService } from '../../services/account.service';
import { routeToDashboard } from '../../app.routing.module';
import { RouterService } from '../../services/router.service';
import { RoutePath } from '../../enum/routepath';

@Component({
selector: 'money-sprouts-account-selection',
Expand All @@ -14,7 +15,7 @@ export class AccountSelectionComponent implements OnInit {
accounts$: Observable<Account[]>;

constructor(
private router: Router,
private router: RouterService,
public readonly route: ActivatedRoute,
private accountService: AccountService
) {}
Expand All @@ -36,7 +37,10 @@ export class AccountSelectionComponent implements OnInit {
if (selectedAccount) {
this.accountService.setAccount(selectedAccount);
setTimeout(() => {
this.router.navigate([routeToDashboard(name)]);
this.router.navigateToRouteForAccountName(
RoutePath.Dashboard,
name
);
});
}
}
Expand Down
57 changes: 24 additions & 33 deletions apps/client/src/app/pages/dashboard/dashboard.component.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,9 @@
import { Component, OnInit } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import {
debounceTime,
distinctUntilChanged,
filter,
map,
Observable,
Subject,
takeUntil,
} from 'rxjs';
import { debounceTime, distinctUntilChanged, Observable, Subject } from 'rxjs';
import { Account } from '@money-sprouts/shared/domain';
import { AccountService } from '../../services/account.service';
import {
routeToHistory,
routeToOverview,
routeToPlan,
} from '../../app.routing.module';
import { TranslateService } from '@ngx-translate/core';
import { RouterService } from '../../services/router.service';
import { RoutePath } from '../../enum/routepath';

interface Section {
name: string;
Expand Down Expand Up @@ -52,14 +39,17 @@ export class DashboardComponent implements OnInit {
private destroy$ = new Subject<void>();

constructor(
private router: Router,
private router: RouterService,
private accountService: AccountService
) {}

ngOnInit() {
this.sections;
const urlSegments = this.router.url.split('/');
this.name = urlSegments[2];
setTimeout(() => {
const urlSegments = this.router.getURL().split('/');
this.name = urlSegments[2];
});

this.account$ = this.accountService.currentAccount$.pipe(
debounceTime(300), // waits 300ms between emisssions
distinctUntilChanged((prev, curr) => {
Expand All @@ -71,17 +61,9 @@ export class DashboardComponent implements OnInit {
this.accountService.refreshAccount(account.id);
});

this.router.events
.pipe(
filter((event) => event instanceof NavigationEnd),
map(() => this.router.url.split('/')[2]),
distinctUntilChanged(),
takeUntil(this.destroy$)
)
.subscribe((name) => {
this.name = decodeURI(name);
this.accountService.getAccountByName(name);
});
this.accountService.currentAccount$.subscribe((account: Account) => {
this.name = account.name;
});
}

goToSection(section: string) {
Expand All @@ -92,13 +74,22 @@ export class DashboardComponent implements OnInit {

switch (section) {
case 'DASHBOARD.SECTION_NAME.OVERVIEW':
this.router.navigate([routeToOverview(this.name)]);
this.router.navigateToRouteForAccountName(
RoutePath.Overview,
this.name
);
break;
case 'DASHBOARD.SECTION_NAME.HISTORY':
this.router.navigate([routeToHistory(this.name)]);
this.router.navigateToRouteForAccountName(
RoutePath.History,
this.name
);
break;
case 'DASHBOARD.SECTION_NAME.PLAN':
this.router.navigate([routeToPlan(this.name)]);
this.router.navigateToRouteForAccountName(
RoutePath.Plan,
this.name
);
break;
}
}
Expand Down
2 changes: 1 addition & 1 deletion apps/client/src/app/services/account.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export class AccountService extends Loggable {
* Refreshes data of a single account
*/
refreshAccount(id: number) {
this.getAccount(id).subscribe((account) => {
return this.getAccount(id).subscribe((account) => {
this.setAccount(account);
});
}
Expand Down
11 changes: 2 additions & 9 deletions apps/client/src/app/services/accounts-resolver.service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { Injectable } from '@angular/core';
import {
ActivatedRouteSnapshot,
Resolve,
RouterStateSnapshot,
} from '@angular/router';
import { Resolve } from '@angular/router';
import { Observable } from 'rxjs';
import { Account } from '@money-sprouts/shared/domain';
import { AccountService } from './account.service';
Expand All @@ -12,10 +8,7 @@ import { AccountService } from './account.service';
export class AccountsResolver implements Resolve<Account[]> {
constructor(private accountService: AccountService) {}

resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<Account[]> {
resolve(): Observable<Account[]> {
return this.accountService.getAccounts();
}
}
3 changes: 2 additions & 1 deletion apps/client/src/app/services/customTranslate.loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { TranslateLoader } from '@ngx-translate/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';

export class customTranslate implements TranslateLoader {
constructor(private http: HttpClient) {}
getTranslation(lang: string): Observable<unknown> {
return this.http
.get(`/build/i18n/${lang}.json`)
.pipe(catchError((_) => this.http.get(`/build/i18n/en.json`)));
.pipe(catchError((/*_*/) => this.http.get(`/build/i18n/en.json`)));
}
}
91 changes: 91 additions & 0 deletions apps/client/src/app/services/router.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { TestBed } from '@angular/core/testing';
import { RouterService } from './router.service';
import { Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { RoutePath } from '../enum/routepath';

describe('RouterService', () => {
let service: RouterService;
let mockRouter: Router;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes([])],
}).compileComponents();

mockRouter = TestBed.inject(Router);
service = TestBed.inject(RouterService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});

describe('getUrl', () => {
it('should return the current URL when getURL is called', () => {
const routerService = new RouterService(mockRouter);
const mockUrl = '/home';
jest.spyOn(mockRouter, 'url', 'get').mockReturnValue(mockUrl);
const result = routerService.getURL();
expect(result).toBe(mockUrl);
});
});

describe('navigateToRoute', () => {
it('should navigate to home route', () => {
const routerService = new RouterService(mockRouter);
const navigateSpy = jest.spyOn(routerService.router, 'navigate');
routerService.navigateToRoute(RoutePath.Home);
expect(navigateSpy).toHaveBeenCalledWith([RoutePath.Home]);
});
});

describe('navigateToRouteForAccountName', () => {
it('should navigate to the correct route', () => {
const routerService = new RouterService(mockRouter);
const mockPath = RoutePath.Dashboard;
const mockAccountName = 'testAccount';
const mockTarget = 'account/testAccount/dashboard';
const navigateSpy = jest.spyOn(mockRouter, 'navigate');

routerService.navigateToRouteForAccountName(
mockPath,
mockAccountName
);

expect(navigateSpy).toHaveBeenCalledWith([mockTarget]);
});

it('should not allow an empty account name', () => {
const routerService = new RouterService(mockRouter);
const mockPath = RoutePath.Dashboard;
const mockAccountName = '';

expect(() => {
routerService.navigateToRouteForAccountName(
mockPath,
mockAccountName
);
}).toThrow();
});
});

describe('navigateToDashboard', () => {
it('should navigate to dashboard route for a given account name', () => {
const routerService = new RouterService(mockRouter);
const mockAccountName = 'testAccount';

const navigateSpy = jest.spyOn(
routerService,
'navigateToRouteForAccountName'
);

routerService.navigateToDashboard(mockAccountName);

expect(navigateSpy).toHaveBeenCalledWith(
RoutePath.Dashboard,
mockAccountName
);
});
});
});
Loading

0 comments on commit e25ba27

Please sign in to comment.