Skip to content

Commit

Permalink
Merge pull request #8005 from ever-co/fix/page-route-service
Browse files Browse the repository at this point in the history
[Feat] Registered Page Routes Dynamically
  • Loading branch information
rahul-rocket authored Jul 24, 2024
2 parents 9406ccf + d7dbf10 commit b6c41e0
Show file tree
Hide file tree
Showing 9 changed files with 308 additions and 68 deletions.
23 changes: 23 additions & 0 deletions apps/gauzy/src/app/pages/jobs/job.routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Route } from '@angular/router';
import { PageRouteService } from '@gauzy/ui-core/core';
import { JobLayoutComponent } from './job-layout/job-layout.component';

/**
* Creates jobs routes for the application
* @param _pageRouteService An instance of PageRouteService
* @returns An array of Route objects
*/
export const createRoutes = (_pageRouteService: PageRouteService): Route[] => [
{
path: '',
component: JobLayoutComponent,
children: [
{
path: '',
redirectTo: 'employee',
pathMatch: 'full'
},
..._pageRouteService.getPageLocationRoutes('jobs')
]
}
];
64 changes: 0 additions & 64 deletions apps/gauzy/src/app/pages/jobs/jobs-routing.module.ts

This file was deleted.

90 changes: 86 additions & 4 deletions apps/gauzy/src/app/pages/jobs/jobs.module.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,95 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { JobSearchUiModule } from '@gauzy/plugins/job-search-ui';
import { RouterModule, ROUTES } from '@angular/router';
import { SharedModule } from '@gauzy/ui-core/shared';
import { JobsRoutingModule } from './jobs-routing.module';
import { PageRouteService } from '@gauzy/ui-core/core';
import { JobLayoutComponent } from './job-layout/job-layout.component';
import { JobTableComponentsModule } from './table-components/job-table-components.module';
import { createRoutes } from './job.routes';

@NgModule({
declarations: [JobLayoutComponent],
imports: [CommonModule, JobsRoutingModule, SharedModule, JobTableComponentsModule, JobSearchUiModule]
imports: [CommonModule, RouterModule.forChild([]), SharedModule, JobTableComponentsModule],
providers: [
{
provide: ROUTES,
useFactory: (pageRouteService: PageRouteService) => createRoutes(pageRouteService),
deps: [PageRouteService],
multi: true
}
]
})
export class JobsModule {}
export class JobsModule {
constructor(readonly _pageRouteService: PageRouteService) {
// Register Job Browser Page Routes
_pageRouteService.registerPageRoute({
// Register the location 'jobs'
location: 'jobs',
// Register the path 'search'
path: 'search',
// Register the loadChildren function to load the MatchingModule lazy module
loadChildren: () => import('./search/search.module').then((m) => m.SearchModule),
// Register the data object
data: {
selectors: {
date: true,
employee: true,
project: false,
team: false
}
}
});
// Register Job Matching Page Routes
_pageRouteService.registerPageRoute({
// Register the location 'jobs'
location: 'jobs',
// Register the path 'matching'
path: 'matching',
// Register the loadChildren function to load the MatchingModule lazy module
loadChildren: () => import('./matching/matching.module').then((m) => m.MatchingModule),
// Register the data object
data: {
selectors: {
date: true,
employee: true,
project: false,
team: false
}
}
});
// Register Job Proposal Template Page Routes
_pageRouteService.registerPageRoute({
// Register the location 'jobs'
location: 'jobs',
// Register the path 'proposal-template'
path: 'proposal-template',
// Register the loadChildren function to load the ProposalTemplateModule lazy module
loadChildren: () =>
import('./proposal-template/proposal-template.module').then((m) => m.ProposalTemplateModule),
// Register the data object
data: {
selectors: {
project: false
}
}
});
// Register Job Employee Page Routes
_pageRouteService.registerPageRoute({
// Register the location 'jobs'
location: 'jobs',
// Register the path 'employee'
path: 'employee',
// Register the loadChildren function to load the EmployeesModule lazy module
loadChildren: () => import('./employees/employees.module').then((m) => m.EmployeesModule),
// Register the data object
data: {
selectors: {
date: true,
employee: true,
project: false,
team: false
}
}
});
}
}
9 changes: 9 additions & 0 deletions packages/plugins/job-search-ui/src/lib/search.routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Route } from '@angular/router';
import { PageRouteService } from '@gauzy/ui-core/core';

/**
* Creates jobs browse routes for the application
* @param _pageRouteService An instance of PageRouteService
* @returns An array of Route objects
*/
export const createRoutes = (_pageRouteService: PageRouteService): Route[] => [];
14 changes: 14 additions & 0 deletions packages/ui-core/core/src/lib/common/component-registry-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* @description
* Type representing the possible page locations for dynamic routes and tabs.
*
* This type is used to identify different sections of the application where dynamic
* routes and tabs can be registered. Each value corresponds to a specific page or
* section in the application. This allows for flexible and dynamic routing based
* on the context and requirements of the application.
*
* Possible values:
* - 'dashboard': The main dashboard page of the application.
* - 'jobs': The jobs or job search section of the application.
*/
export type PageRouteLocationId = 'dashboard' | 'jobs';
1 change: 1 addition & 0 deletions packages/ui-core/core/src/lib/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,4 @@ export * from './translatable';
export * from './upwork';
export * from './users';
export * from './warehouse';
export * from './page';
2 changes: 2 additions & 0 deletions packages/ui-core/core/src/lib/services/page/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './page-route.service';
export * from './page-route.types';
131 changes: 131 additions & 0 deletions packages/ui-core/core/src/lib/services/page/page-route.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { Injectable } from '@angular/core';
import { Route } from '@angular/router';
import { PageRouteLocationConfig } from './page-route.types';
import { PageRouteLocationId } from '../../common/component-registry-types';

@Injectable({
providedIn: 'root'
})
export class PageRouteService {
/**
* Registry for storing page route configurations.
*
* This Map stores arrays of PageRouteConfig objects, keyed by PageRouteLocationId.
*/
private readonly registry = new Map<PageRouteLocationId, PageRouteLocationConfig[]>();

/**
* Register a single page route configuration.
*
* This method registers a new page route configuration in the service's internal registry.
* It ensures that the configuration has a valid location property and checks if a route
* with the same location already exists to prevent duplicate entries. If the configuration
* is valid and unique, it adds it to the registry.
*
* @param config The configuration for the page route.
* @throws Will throw an error if the configuration does not have a location property.
* @throws Will throw an error if a route with the same location has already been registered.
*/
registerPageRoute(config: PageRouteLocationConfig): void {
// Check if the configuration has a location property
if (!config.location) {
throw new Error('Page route configuration must have a location property');
}

// Get all registered routes for the specified location
const routes = this.registry.get(config.location) || [];

// Check if a route with the same location and path already exists
const isMatchingRoute = routes.some(
(route: PageRouteLocationConfig) => route.location === config.location && route.path === config.path
);

// Check if a route with the same location already exists
if (isMatchingRoute) {
throw new Error(
`A page with the location "${config.location}" and path "${config.path}" has already been registered`
);
}

// Add the new route configuration to the list of routes for the specified location
routes.push(config);

// Update the registry with the new list of routes for the specified location
this.registry.set(config.location, routes);
}

/**
* Register multiple page route configurations.
*
* This method registers multiple new page route configurations in the service's internal registry.
* It ensures that each configuration has a valid location property and checks if a route with the same
* location already exists to prevent duplicate entries. If the configurations are valid and unique,
* it adds them to the registry.
*
* @param configs The array of configurations for the page routes.
* @throws Will throw an error if a route with the same location and path has already been registered.
*/
registerPageRoutes(configs: PageRouteLocationConfig[]): void {
configs.forEach((config) => this.registerPageRoute(config));
}

/**
* Get all registered routes for a specific location.
*
* This method retrieves all registered route configurations for a specified location identifier.
* It maps the internal route configurations to Angular Route objects.
*
* @param location The page location identifier.
* @returns The array of registered routes for the specified location.
*/
getPageLocationRoutes(location: PageRouteLocationId): Route[] {
// Get all registered routes for the specified location
let configs = this.registry.get(location) || [];

// Use a Set to track unique location-path combinations
const locationPaths = new Set<string>();

// Create a unique identifier for the combination of location and path
configs = configs.filter((config: PageRouteLocationConfig) => {
// Create a unique identifier for the combination of location and path
const identifier = `${config.location}-${config.path}`;

// Check if the unique identifier is already in the Set
if (locationPaths.has(identifier)) {
return false; // Duplicate found, filter it out
}

// Add the unique identifier to the Set
locationPaths.add(identifier);
return true; // Not a duplicate, keep it
});

// Map each route configuration to a route object
return configs.map((config: PageRouteLocationConfig) => {
// Create a new route object
const route: Route = {
path: config.path,
pathMatch: config.path ? 'prefix' : 'full',
data: config.data || {},
canActivate: config.canActivate || []
};

// Check if the route configuration has a component or loadChildren property
if (config.component) {
// Set the component property to the config object
route.component = config.component;
} else if (config.loadChildren) {
// Set the loadChildren property to the config object
route.loadChildren = config.loadChildren;
}

// Check if the route configuration has additional route options
if (config.route) {
Object.assign(route, config.route);
}

// Return the route object
return route;
});
}
}
42 changes: 42 additions & 0 deletions packages/ui-core/core/src/lib/services/page/page-route.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Route } from '@angular/router';
import { PageRouteLocationId } from '../../common/component-registry-types';

/**
* Page route configuration.
*/
export interface PageRouteLocationConfig {
/**
* The location identifier for the page route.
*/
location: PageRouteLocationId;

/**
* The path to navigate to when the page is selected.
*/
path: string;

/**
* Optional component to render for the route.
*/
component?: any;

/**
* Optional loadChildren function to load a module lazily.
*/
loadChildren?: () => Promise<any>;

/**
* Optional data to associate with the route.
*/
data?: any;

/**
* Optional guards to apply to the route.
*/
canActivate?: any[];

/**
* Additional route configuration options.
*/
route?: Route;
}

0 comments on commit b6c41e0

Please sign in to comment.