Skip to content

Commit

Permalink
Add Columns To Organization Project Employee Entity (#8165)
Browse files Browse the repository at this point in the history
Add Columns To Organization Project Employee Entity (#8165)
  • Loading branch information
GloireMutaliko21 authored Sep 22, 2024
1 parent 0ee485f commit 2ae5096
Show file tree
Hide file tree
Showing 32 changed files with 6,709 additions and 1,242 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
IOrganization,
OrganizationContactBudgetTypeEnum,
IOrganizationContact,
IImageAsset
IImageAsset,
IOrganizationProjectEmployee
} from '@gauzy/contracts';
import { NbStepperComponent } from '@nebular/theme';
import { debounceTime, filter, tap } from 'rxjs/operators';
Expand Down Expand Up @@ -332,50 +333,91 @@ export class ContactMutationComponent extends TranslationBaseComponent implement
}

const { id: organizationId, tenantId } = this.organization;

const data = this.contMainForm.value;
const budget = this.budgetForm.value;
const location = this.locationFormDirective.getValue();
const { fax, fiscalInformation, website } = this.contMainForm.getRawValue();

const { coordinates } = location['loc'];
delete location['loc'];
const locationData = this.locationFormDirective.getValue();
const { fax, fiscalInformation, website } = this.contMainForm.value;

// Extract and destructure coordinates
const { coordinates, ...location } = locationData.loc;
const [latitude, longitude] = coordinates;

// Combining form data with additional properties
// Construct the contact object
const contact = {
latitude,
longitude,
fiscalInformation,
website,
fax,
...location,
organizationId,
organization: { id: organizationId },
tenantId,
tenant: { id: tenantId },
...(this.organizationContact?.contact?.id ? { id: this.organizationContact?.contact?.id } : {})
...(this.organizationContact?.contact?.id && { id: this.organizationContact.contact.id })
};

/**
* Constructs an array of member objects from a list of member or selected employee IDs.
* Each ID is mapped to a corresponding employee object, filtering out any non-existent (falsy) members.
*/
let memberIds = this.members || this.selectedEmployeeIds || [];
let members = memberIds.map((id) => this.employees.find((e) => e.id === id)).filter(Boolean);
// Consolidate member IDs and retrieve corresponding employees
const members = this.getSelectedMembers();

if (!members.length) members = this.selectedMembers;
// Retrieve and process projects with assigned members
const projects = this.assignMembersToProjects(data.projects ?? [], members);

//
let projects = data.projects ?? [];
projects.forEach((project: IOrganizationProject) => {
if (Array.isArray(project.members)) {
project.members.push(...members);
} else {
project.members = [...members];
}
// Step 5: Emit the consolidated data
this.emitConsolidatedData({ budget, data, projects, members, contact });
}

/**
* Retrieves selected members based on member IDs or selected employees.
* @returns An array of IEmployee objects.
*/
private getSelectedMembers(): IEmployee[] {
// Step 1: Get the list of member IDs
const memberIds = this.members || this.selectedEmployeeIds || [];

// Step 2: Find corresponding IEmployee objects and filter out any falsy values
const members = memberIds.map((id) => this.employees.find((e) => e.id === id)).filter(Boolean);

// Fallback to selectedMembers if no members found
return members.length ? members : this.selectedMembers;
}

/**
* Assigns selected members to each project by transforming them into IOrganizationProjectEmployee objects.
* @param projects The array of projects to which members will be assigned.
* @param members The array of selected IEmployee objects.
* @returns The updated array of projects with assigned members.
*/
private assignMembersToProjects(projects: IOrganizationProject[], members: IEmployee[]): IOrganizationProject[] {
return projects.map((project: IOrganizationProject) => {
// Get the project members and transform them into IOrganizationProjectEmployee objects
const projectMembers: IOrganizationProjectEmployee[] = members.map((employee: IEmployee) =>
this.transformToProjectEmployee(employee, project, this.organization)
);

return {
...project,
members: Array.isArray(project.members) ? [...project.members, ...projectMembers] : [...projectMembers]
};
});
}

/**
* Emits the consolidated data for further processing.
*
* @param payload The data to be emitted.
*/
private emitConsolidatedData(payload: {
budget: any;
data: any;
projects: IOrganizationProject[];
members: IEmployee[];
contact: any;
}) {
const { budget, data, projects, members, contact } = payload;
const { id: organizationId, tenantId } = this.organization;

// Emit the consolidated data
this.addOrEditOrganizationContact.emit({
...budget,
...data,
Expand All @@ -386,10 +428,30 @@ export class ContactMutationComponent extends TranslationBaseComponent implement
organization: { id: organizationId },
tenantId,
tenant: { id: tenantId },
...(this.organizationContact?.id ? { id: this.organizationContact?.id } : {})
...(this.organizationContact?.id && { id: this.organizationContact.id })
});
}

/**
* Transforms an IEmployee into an IOrganizationProjectEmployee.
*
* @param employee The employee to transform.
* @param project The project to associate with the employee.
* @param organization The organization context.
* @returns The transformed IOrganizationProjectEmployee object.
*/
private transformToProjectEmployee = (
employee: IEmployee,
project: IOrganizationProject,
organization: IOrganization
): IOrganizationProjectEmployee => ({
...employee,
organizationProject: project, // Assign the current project
organizationProjectId: project.id, // Assign the project's ID
organizationId: organization.id, // Assign the organization's ID
tenantId: organization.tenantId // Assign the organization's tenant ID
});

/**
* Updates the 'tags' field in 'contMainForm' with the selected tags and validate the form.
* @param tags An array of selected tag objects.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ import {
PermissionsEnum,
ComponentLayoutStyleEnum,
CrudActionEnum,
IEmployee,
ITag,
IOrganizationProject
IOrganizationProject,
ID,
IOrganizationProjectEmployee
} from '@gauzy/contracts';
import { API_PREFIX, ComponentEnum, distinctUntilChange } from '@gauzy/ui-core/common';
import {
Expand Down Expand Up @@ -54,7 +55,7 @@ export class ProjectListComponent extends PaginationFilterBaseComponent implemen
public viewComponentName: ComponentEnum;
public dataLayoutStyle = ComponentLayoutStyleEnum.TABLE;
public componentLayoutStyleEnum = ComponentLayoutStyleEnum;
public selectedEmployeeId: IEmployee['id'] | null;
public selectedEmployeeId: ID | null;
public selectedProject: IOrganizationProject;
public organization: IOrganization;
public smartTableSource: ServerDataSource;
Expand Down Expand Up @@ -218,12 +219,12 @@ export class ProjectListComponent extends PaginationFilterBaseComponent implemen
return;
}

const { tenantId } = this._store.user;
const { id: organizationId } = this.organization;
// Extract organization ID and tenant ID from the organization object
const { id: organizationId, tenantId } = this.organization;

this.smartTableSource = new ServerDataSource(this._httpClient, {
endPoint: `${API_PREFIX}/organization-projects/pagination`,
relations: ['organizationContact', 'organization', 'members', 'members.user', 'tags', 'teams'],
relations: ['organizationContact', 'members.employee.user', 'tags', 'teams'],
join: {
alias: 'organization_project',
leftJoin: {
Expand All @@ -245,7 +246,9 @@ export class ProjectListComponent extends PaginationFilterBaseComponent implemen
resultMap: (project: IOrganizationProject) => {
return Object.assign({}, project, {
...this.privatePublicProjectMapper(project),
employeesMergedTeams: [project.members]
employeesMergedTeams: [
project.members.map((member: IOrganizationProjectEmployee) => member.employee)
]
});
},
finalize: () => {
Expand Down Expand Up @@ -301,6 +304,7 @@ export class ProjectListComponent extends PaginationFilterBaseComponent implemen

/**
* Maps an organization project based on user permissions and project visibility.
*
* @param project The project to be mapped.
* @returns The mapped project.
*/
Expand All @@ -316,11 +320,14 @@ export class ProjectListComponent extends PaginationFilterBaseComponent implemen

/**
* Filters project members to include only the ones that match the current user's ID.
*
* @param project The project with members.
* @returns The project with filtered members.
*/
private filterProjectMembers(project: IOrganizationProject): IOrganizationProject {
project.members = project.members.filter((member: IEmployee) => member.id === this._store.userId);
project.members = project.members.filter(
(member: IOrganizationProjectEmployee) => member.employeeId === this._store.user?.employeeId
);
return project;
}

Expand Down Expand Up @@ -438,7 +445,7 @@ export class ProjectListComponent extends PaginationFilterBaseComponent implemen
}
this.setFilter({ field: 'tags', search: tagIds });
},
sort: false
isSortable: false
}
};
break;
Expand Down
21 changes: 17 additions & 4 deletions packages/contracts/src/organization-projects.model.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IEmployee } from './employee.model';
import { IEmployee, IEmployeeEntityInput } from './employee.model';
import { IRelationalOrganizationContact } from './organization-contact.model';
import { ITaggable } from './tag.model';
import { ITask } from './task.model';
Expand All @@ -11,6 +11,7 @@ import { IOrganizationProjectModule } from './organization-project-module.model'
import { CrudActionEnum, ProjectBillingEnum, ProjectOwnerEnum } from './organization.model';
import { CurrenciesEnum } from './currency.model';
import { TaskStatusEnum } from './task-status.model';
import { IRelationalRole } from './role.model';
import { IBasePerTenantAndOrganizationEntityModel, ID } from './base-entity.model'; // Base Entities
import { CustomFieldsObject } from './shared-types'; // Shared Types

Expand All @@ -32,7 +33,7 @@ export interface IOrganizationProjectBase
endDate?: Date;
billing?: ProjectBillingEnum;
currency?: CurrenciesEnum;
members?: IEmployee[];
members?: IOrganizationProjectEmployee[];
public?: boolean;
owner?: ProjectOwnerEnum;
tasks?: ITask[];
Expand Down Expand Up @@ -84,15 +85,27 @@ export interface IOrganizationProjectsFindInput
organizationTeamId?: ID;
}

export interface IOrganizationProjectCreateInput extends IOrganizationProjectBase {}
export interface IOrganizationProjectCreateInput extends IOrganizationProjectBase {
managers?: IOrganizationProjectEmployee[];
}

export interface IOrganizationProjectUpdateInput extends IOrganizationProjectBase, IOrganizationProjectSetting {}
export interface IOrganizationProjectUpdateInput extends IOrganizationProjectCreateInput {}

export interface IOrganizationProjectStoreState {
project: IOrganizationProject;
action: CrudActionEnum;
}

export interface IOrganizationProjectEmployee
extends IBasePerTenantAndOrganizationEntityModel,
IEmployeeEntityInput,
IRelationalRole {
organizationProject: IOrganizationProject;
organizationProjectId: ID;
isManager?: boolean;
assignedAt?: Date;
}

// Task List Type Enum
export enum TaskListTypeEnum {
GRID = 'GRID',
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/core/entities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ import {
OrganizationLanguage,
OrganizationPosition,
OrganizationProject,
OrganizationProjectEmployee,
OrganizationProjectModule,
OrganizationRecurringExpense,
OrganizationSprint,
Expand Down Expand Up @@ -221,6 +222,7 @@ export const coreEntities = [
OrganizationLanguage,
OrganizationPosition,
OrganizationProject,
OrganizationProjectEmployee,
OrganizationProjectModule,
OrganizationRecurringExpense,
OrganizationSprint,
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/core/entities/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export * from '../../organization-employment-type/organization-employment-type.e
export * from '../../organization-language/organization-language.entity';
export * from '../../organization-position/organization-position.entity';
export * from '../../organization-project/organization-project.entity';
export * from '../../organization-project/organization-project-employee.entity';
export * from '../../organization-project-module/organization-project-module.entity';
export * from '../../organization-recurring-expense/organization-recurring-expense.entity';
export * from '../../organization-sprint/organization-sprint.entity';
Expand Down
Loading

0 comments on commit 2ae5096

Please sign in to comment.