diff --git a/src/app/clients/clients.service.ts b/src/app/clients/clients.service.ts index 95bcd6903..242b5ed85 100644 --- a/src/app/clients/clients.service.ts +++ b/src/app/clients/clients.service.ts @@ -16,6 +16,18 @@ export class ClientsService { */ constructor(private http: HttpClient) { } + getFilteredClients(orderBy: string, sortOrder: string, orphansOnly: boolean, displayName: string, officeId: any): Observable { + let httpParams = new HttpParams() + .set('displayName', displayName) + .set('orphansOnly', orphansOnly.toString()) + .set('sortOrder', sortOrder) + .set('orderBy', orderBy); + if (officeId) { + httpParams = httpParams.set('officeId', officeId); + } + return this.http.get('/clients', { params: httpParams }); + } + getClients(orderBy: string, sortOrder: string, offset: number, limit: number): Observable { const httpParams = new HttpParams() .set('offset', offset.toString()) diff --git a/src/app/groups/create-group/create-group.component.html b/src/app/groups/create-group/create-group.component.html new file mode 100644 index 000000000..eaf26308e --- /dev/null +++ b/src/app/groups/create-group/create-group.component.html @@ -0,0 +1,131 @@ +
+ + + +
+ + + +
+ + + Name + + + Group Name is required + + + Group Name cannot begin with a special character or number + + + + + Office + + + {{ office.name }} + + + + Office is required + + + + + Staff + + + {{ staff.displayName }} + + + + + + Active + + + + Activation Date + + + + + Activation Date is required + + + + + External id + + + + + Submitted on + + + + + Submission Date is required + + + + + Add Clients + + + +
+ + + + {{ client.displayName }} + + + +
+ +
+
+
Client Details
+ +
+
+
Name
+
{{clientChoice.value.displayName}}
+
+
+
Id
+
{{clientChoice.value.id}}
+
+
+
Office
+
{{clientChoice.value.officeName}}
+
+
+ + +

Selected Clients

+
+ + {{client.displayName}} +
+
+ +
+ +
+ + + + + + +
+ +
+ +
diff --git a/src/app/groups/create-group/create-group.component.scss b/src/app/groups/create-group/create-group.component.scss new file mode 100644 index 000000000..9530da9a5 --- /dev/null +++ b/src/app/groups/create-group/create-group.component.scss @@ -0,0 +1,26 @@ +.container { + max-width: 37rem; + } + +.mat-table { + display: block; + font-family: Tahoma, Verdana; + width: 50%; +} + +.mat-row, +.mat-header-row { + display: flex; + border-bottom-width: 1px; + border-bottom-style: solid; + align-items: center; + min-height: 48px; + padding: 0 24px; +} + +.mat-cell, +.mat-header-cell { + flex: 1; + overflow: hidden; + word-wrap: break-word; +} diff --git a/src/app/groups/create-group/create-group.component.spec.ts b/src/app/groups/create-group/create-group.component.spec.ts new file mode 100644 index 000000000..40c206cbe --- /dev/null +++ b/src/app/groups/create-group/create-group.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CreateGroupComponent } from './create-group.component'; + +describe('CreateGroupComponent', () => { + let component: CreateGroupComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CreateGroupComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CreateGroupComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/groups/create-group/create-group.component.ts b/src/app/groups/create-group/create-group.component.ts new file mode 100644 index 000000000..c6da51c1d --- /dev/null +++ b/src/app/groups/create-group/create-group.component.ts @@ -0,0 +1,167 @@ +/** Angular Imports */ +import { Component, OnInit, AfterViewInit } from '@angular/core'; +import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms'; +import { Router, ActivatedRoute } from '@angular/router'; +import { DatePipe } from '@angular/common'; + +/** Custom Services */ +import { GroupsService } from '../groups.service'; +import { ClientsService } from '../../clients/clients.service'; + +/** + * Create Group component. + */ +@Component({ + selector: 'mifosx-create-group', + templateUrl: './create-group.component.html', + styleUrls: ['./create-group.component.scss'] +}) +export class CreateGroupComponent implements OnInit, AfterViewInit { + + /** Minimum date allowed. */ + minDate = new Date(2000, 0, 1); + /** Maximum date allowed. */ + maxDate = new Date(); + /** Group form. */ + groupForm: FormGroup; + /** Office data. */ + officeData: any; + /** Client data. */ + clientsData: any = []; + /** Staff data. */ + staffData: any; + /** Client Members. */ + clientMembers: any[] = []; + /** ClientChoice. */ + clientChoice = new FormControl(''); + + /** + * Retrieves the offices data from `resolve`. + * @param {FormBuilder} formBuilder Form Builder. + * @param {ActivatedRoute} route Activated Route. + * @param {Router} router Router for navigation. + * @param {ClientsService} clientsService CentersService. + * @param {GroupsService} groupService GroupsService. + * @param {DatePipe} datePipe Date Pipe to format date. + */ + constructor(private formBuilder: FormBuilder, + private route: ActivatedRoute, + private router: Router, + private clientsService: ClientsService, + private groupService: GroupsService, + private datePipe: DatePipe) { + this.route.data.subscribe( (data: {offices: any} ) => { + this.officeData = data.offices; + }); + } + + /** + * Creates and sets the group form. + */ + ngOnInit() { + this.createGroupForm(); + } + + /** + * Subscribes to Clients search filter: + */ + ngAfterViewInit() { + this.clientChoice.valueChanges.subscribe( (value: string) => { + if (value.length >= 2) { + this.clientsService.getFilteredClients('displayName', 'ASC', true, value, this.groupForm.get('officeId').value) + .subscribe( (data: any) => { + this.clientsData = data.pageItems; + }); + } + }); + } + + /** + * Creates the group form. + */ + createGroupForm() { + this.groupForm = this.formBuilder.group({ + 'name': ['', [Validators.required, Validators.pattern('(^[A-z]).*')]], + 'officeId': ['', Validators.required], + 'submittedOnDate': ['', Validators.required], + 'staffId': [''], + 'externalId': [''], + 'active': [false], + }); + this.buildDependencies(); + } + + /** + * Sets the staff and clients data each time the user selects a new office. + * Adds form control Activation Date if active. + */ + buildDependencies() { + this.groupForm.get('officeId').valueChanges.subscribe((option: any) => { + this.groupService.getStaff(option).subscribe(data => { + this.staffData = data['staffOptions']; + if (this.staffData === undefined) { + this.groupForm.controls['staffId'].disable(); + } else { + this.groupForm.controls['staffId'].enable(); + } + }); + }); + this.groupForm.get('active').valueChanges.subscribe((bool: boolean) => { + if (bool) { + this.groupForm.addControl('activationDate', new FormControl('', Validators.required)); + } else { + this.groupForm.removeControl('activationDate'); + } + }); + } + + /** + * Add client. + */ + addClient() { + if (!this.clientMembers.includes(this.clientChoice.value)) { + this.clientMembers.push(this.clientChoice.value); + } + } + + /** + * Remove client. + * @param index Client's array index. + */ + removeClient(index: number) { + this.clientMembers.splice(index, 1); + } + + /** + * Displays Client name in form control input. + * @param {any} client Client data. + * @returns {string} Client name if valid otherwise undefined. + */ + displayClient(client: any): string | undefined { + return client ? client.displayName : undefined; + } + + /** + * Submits the group form and creates group, + * if successful redirects to groups. + */ + submit() { + const submittedOnDate: Date = this.groupForm.value.submittedOnDate; + const activationDate: Date = this.groupForm.value.activationDate; + // TODO: Update once language and date settings are setup + const dateFormat = 'dd MMMM yyyy'; + this.groupForm.patchValue({ + submittedOnDate: this.datePipe.transform(submittedOnDate, dateFormat), + activationDate: this.datePipe.transform(activationDate, dateFormat) + }); + const group = this.groupForm.value; + group.locale = 'en'; + group.dateFormat = dateFormat; + group.clientMembers = []; + this.clientMembers.forEach((client: any) => group.clientMembers.push(client.id)); + this.groupService.createGroup(group).subscribe((response: any) => { + this.router.navigate(['../groups']); + }); + } + +} diff --git a/src/app/groups/groups-routing.module.ts b/src/app/groups/groups-routing.module.ts index c2d87e934..1be2dd4bb 100644 --- a/src/app/groups/groups-routing.module.ts +++ b/src/app/groups/groups-routing.module.ts @@ -14,12 +14,14 @@ import { GroupsViewComponent } from './groups-view/groups-view.component'; import { GeneralTabComponent } from './groups-view/general-tab/general-tab.component'; import { NotesTabComponent } from './groups-view/notes-tab/notes-tab.component'; import { CommitteeTabComponent } from './groups-view/committee-tab/committee-tab.component'; +import { CreateGroupComponent } from './create-group/create-group.component'; /** Custom Resolvers */ import { GroupViewResolver } from './common-resolvers/group-view.resolver'; import { GroupAccountsResolver } from './common-resolvers/group-account.resolver'; import { GroupSummaryResolver } from './common-resolvers/group-summary.resolver'; import { GroupNotesResolver } from './common-resolvers/group-notes.resolver'; +import { OfficesResolver } from 'app/accounting/common-resolvers/offices.resolver'; /** Groups Routes */ const routes: Routes = [ @@ -32,13 +34,20 @@ const routes: Routes = [ path: '', component: GroupsComponent, }, + { + path: 'create', + component: CreateGroupComponent, + data: { title: extract('Create Group'), breadcrumb: 'Create' }, + resolve: { + offices: OfficesResolver + } + }, { path: ':groupId', component: GroupsViewComponent, data: { title: extract('View Group'), routeParamBreadcrumb: 'groupId' }, resolve: { - groupViewData: GroupViewResolver, - + groupViewData: GroupViewResolver }, children: [ { diff --git a/src/app/groups/groups.component.html b/src/app/groups/groups.component.html index ad044b7fc..4caa2094d 100644 --- a/src/app/groups/groups.component.html +++ b/src/app/groups/groups.component.html @@ -7,7 +7,7 @@ Show Closed Groups
-
@@ -52,4 +52,3 @@ - \ No newline at end of file diff --git a/src/app/groups/groups.module.ts b/src/app/groups/groups.module.ts index c30bbf176..1d9160e0c 100644 --- a/src/app/groups/groups.module.ts +++ b/src/app/groups/groups.module.ts @@ -14,6 +14,7 @@ import { GroupsViewComponent } from './groups-view/groups-view.component'; import { GeneralTabComponent } from './groups-view/general-tab/general-tab.component'; import { NotesTabComponent } from './groups-view/notes-tab/notes-tab.component'; import { CommitteeTabComponent } from './groups-view/committee-tab/committee-tab.component'; +import { CreateGroupComponent } from './create-group/create-group.component'; /** * Groups Module @@ -32,7 +33,8 @@ import { CommitteeTabComponent } from './groups-view/committee-tab/committee-tab GroupsViewComponent, GeneralTabComponent, NotesTabComponent, - CommitteeTabComponent + CommitteeTabComponent, + CreateGroupComponent ], providers: [DatePipe] }) diff --git a/src/app/groups/groups.service.ts b/src/app/groups/groups.service.ts index f49efdfc5..c7fc5db30 100644 --- a/src/app/groups/groups.service.ts +++ b/src/app/groups/groups.service.ts @@ -113,4 +113,23 @@ export class GroupsService { return this.http.delete(`/groups/${groupId}/notes/${noteId}`); } + /** + * @param {number} officeId Office Id of office to get staff for. + * @returns {Observable} + */ + getStaff(id: number) { + const httpParams = new HttpParams() + .set('officeId', id.toString()) + .set('staffInSelectedOfficeOnly', 'true'); + return this.http.get('/groups/template', { params: httpParams }); + } + + /** + * @param {any} group Group to be created. + * @returns {Observable} + */ + createGroup(group: any): Observable { + return this.http.post('/groups', group); + } + }