import {NgModule} from '@angular/core';
import {TreeModule} from '@eg/share/tree/tree.module';
-import {StaffCommonModule} from '@eg/staff/common.module';
-import {AdminServerRoutingModule} from './routing.module';
import {AdminCommonModule} from '@eg/staff/admin/common.module';
+import {AdminServerRoutingModule} from './routing.module';
import {AdminServerSplashComponent} from './admin-server-splash.component';
import {OrgUnitTypeComponent} from './org-unit-type.component';
-import {OrgUnitComponent} from './org-unit.component';
@NgModule({
declarations: [
AdminServerSplashComponent,
- OrgUnitTypeComponent,
- OrgUnitComponent
+ OrgUnitTypeComponent
],
imports: [
AdminCommonModule,
--- /dev/null
+
+<ngb-tabset #addressTabs *ngIf="orgUnit">
+ <ng-container *ngFor="let type of addrTypes()">
+ <b>type = {{type}}</b>
+
+ <ngb-tab
+ i18n-title id="{{type}}"
+ title="{{type === 'billing_address' ? 'Physical Address' :
+ (type === 'holds_address' ? 'Holds Address' :
+ (type === 'mailing_address' ? 'Mailing Address' : 'ILL Address'))}}">
+
+ <ng-template ngbTabContent>
+ <eg-fm-record-editor idlClass="aoa" readonlyFields="org_unit"
+ [mode]="addr(type).isnew() ? 'create': 'update'"
+ [hideBanner]="true" displayMode="inline" hiddenFields="id"
+ [showDelete]="true" (recordSaved)="addrSaved($event)"
+ (recordDeleted)="addrDeleted($event)"
+ [record]="addr(type)"
+ fieldOrder="address_type,street1,street2,city,county,state,country,post_code,san,valid"
+ >
+ </eg-fm-record-editor>
+
+ <ng-container *ngIf="sharedAddress(addr(type).id())">
+ <div class="alert alert-info">
+ <span i18n>This address is used for multiple address types.</span>
+ <button (click)="cloneAddress(type)"
+ class="btn btn-light ml-3" i18n>Clone As New Address</button>
+ </div>
+ </ng-container>
+ </ng-template>
+ </ngb-tab>
+ </ng-container>
+</ngb-tabset>
+
--- /dev/null
+import {Component, Input, Output, EventEmitter} from '@angular/core';
+import {IdlService, IdlObject} from '@eg/core/idl.service';
+import {OrgService} from '@eg/core/org.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+
+const ADDR_TYPES =
+ ['billing_address', 'holds_address', 'mailing_address', 'ill_address'];
+
+@Component({
+ selector: 'eg-admin-org-address',
+ templateUrl: './org-addr.component.html'
+})
+export class OrgAddressComponent {
+
+ private orgUnit: IdlObject = null;
+
+ private _orgId: number;
+
+ get orgId(): number { return this._orgId; }
+
+ @Input() set orgId(newId: number) {
+ if (newId) {
+ if (!this._orgId || this._orgId !== newId) {
+ this._orgId = newId;
+ this.init();
+ }
+ } else {
+ this._orgId = null;
+ }
+ }
+
+ @Output() addrChange: EventEmitter<IdlObject>;
+
+ constructor(
+ private idl: IdlService,
+ private org: OrgService,
+ private pcrud: PcrudService
+ ) {
+ this.addrChange = new EventEmitter<IdlObject>();
+ }
+
+ init() {
+ if (!this.orgId) { return; }
+
+ return this.pcrud.retrieve('aou', this.orgId,
+ {flesh : 1, flesh_fields : {aou : ADDR_TYPES}},
+ {authoritative: true}
+ ).subscribe(org => {
+ this.orgUnit = org;
+ ADDR_TYPES.forEach(aType => {
+ if (!this.addr(aType)) {
+ this.createAddress(aType);
+ }
+ });
+ });
+ }
+
+ addrTypes(): string[] { // for UI
+ return ADDR_TYPES;
+ }
+
+ // Template shorthand -- get a specific address by type.
+ addr(addrType: string) {
+ return this.orgUnit ? this.orgUnit[addrType]() : null;
+ }
+
+ createAddress(addrType: string) {
+ const addr = this.idl.create('aoa');
+ addr.isnew(true);
+ addr.valid('t');
+ addr.org_unit(this.orgUnit);
+ this.orgUnit[addrType](addr);
+ }
+
+ cloneAddress(addrType: string) {
+
+ // Find the address
+ let fromAddr: IdlObject;
+ ADDR_TYPES.forEach(aType => {
+ if (aType !== addrType &&
+ this.addr(aType).id() === this.addr(addrType).id()) {
+ fromAddr = this.addr(aType);
+ }
+ });
+
+ const addr = this.idl.clone(fromAddr);
+ addr.id(null);
+ addr.isnew(true);
+ addr.valid('t');
+ this.orgUnit[addrType](addr);
+ }
+
+ // True if the provided address is used for more than one addr type.
+ sharedAddress(addrId: number): boolean {
+ return ADDR_TYPES.filter(aType => {
+ return (
+ !this.addr(aType).isnew() && this.addr(aType).id() === addrId
+ );
+ }).length > 1;
+ }
+
+ addrSaved(addr: number | IdlObject) {
+ const id = typeof addr === 'object' ? addr.id() : addr;
+
+ // TODO: update org if needed...
+ }
+
+ addrDeleted(addr: number | IdlObject) {
+ const id = typeof addr === 'object' ? addr.id() : addr;
+ // TODO: update org
+ }
+}
+
--- /dev/null
+import {NgModule} from '@angular/core';
+import {RouterModule, Routes} from '@angular/router';
+import {OrgUnitComponent} from './org-unit.component';
+
+// Since org-unit admin has its own module with page-level components,
+// it needs its own routing module as well to define which component
+// to display at page load time.
+
+const routes: Routes = [{
+ path: '',
+ component: OrgUnitComponent
+}];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+
+export class OrgUnitRoutingModule {}
[disabled]="currentOrg().isnew()">
<ng-template ngbTabContent>
<div class="mt-2">
- <ngb-tabset #addressTabs>
- <ngb-tab title="Physical Address" i18n-title id="physical">
- <ng-template ngbTabContent>
- <eg-fm-record-editor idlClass="aoa" readonlyFields="org_unit"
- [mode]="currentOrg().billing_address().isnew() ? 'create': 'update'"
- [hideBanner]="true" displayMode="inline" hiddenFields="id"
- (recordSaved)="orgSaved()"
- [recordId]="currentOrg().billing_address().isnew() ? null : currentOrg().billing_address().id()"
- [record]="currentOrg().billing_address().isnew() ? currentOrg().billing_address() : null"
- fieldOrder="address_type,street1,street2,city,county,state,country,post_code,san,valid"
- >
- </eg-fm-record-editor>
- </ng-template>
- </ngb-tab>
- <ngb-tab title="Holds Address" i18n-title id="holds">
- <ng-template ngbTabContent>
- <eg-fm-record-editor idlClass="aoa" readonlyFields="org_unit"
- [mode]="currentOrg().holds_address().isnew() ? 'create': 'update'"
- [hideBanner]="true" displayMode="inline" hiddenFields="id"
- (recordSaved)="orgSaved()"
- [recordId]="currentOrg().holds_address().isnew() ? null : currentOrg().holds_address().id()"
- [record]="currentOrg().holds_address().isnew() ? currentOrg().holds_address() : null"
- fieldOrder="address_type,street1,street2,city,county,state,country,post_code,san,valid"
- >
- </eg-fm-record-editor>
- </ng-template>
- </ngb-tab>
- <ngb-tab title="Mailing Address" i18n-title id="mailing">
- <ng-template ngbTabContent>
- <eg-fm-record-editor idlClass="aoa" readonlyFields="org_unit"
- [mode]="currentOrg().mailing_address().isnew() ? 'create': 'update'"
- [hideBanner]="true" displayMode="inline" hiddenFields="id"
- (recordSaved)="orgSaved()"
- [recordId]="currentOrg().mailing_address().isnew() ? null : currentOrg().mailing_address().id()"
- [record]="currentOrg().mailing_address().isnew() ? currentOrg().mailing_address() : null"
- fieldOrder="address_type,street1,street2,city,county,state,country,post_code,san,valid"
- >
- </eg-fm-record-editor>
- </ng-template>
- </ngb-tab>
- <ngb-tab title="ILL Address" i18n-title id="ill">
- <ng-template ngbTabContent>
- <eg-fm-record-editor idlClass="aoa" readonlyFields="org_unit"
- [mode]="currentOrg().ill_address().isnew() ? 'create': 'update'"
- [hideBanner]="true" displayMode="inline" hiddenFields="id"
- (recordSaved)="orgSaved()"
- [recordId]="currentOrg().ill_address().isnew() ? null : currentOrg().ill_address().id()"
- [record]="currentOrg().ill_address().isnew() ? currentOrg().ill_address() : null"
- fieldOrder="address_type,street1,street2,city,county,state,country,post_code,san,valid"
- >
- </eg-fm-record-editor>
- </ng-template>
- </ngb-tab>
- </ngb-tabset>
+ <eg-admin-org-address [orgId]="currentOrg().id()" (addrChange)="addressChanged($event)">
+ </eg-admin-org-address>
</div>
</ng-template>
</ngb-tab>
}
loadAouTree(selectNodeId?: number): Promise<any> {
+
+ const flesh = ['children', 'ou_type', 'hours_of_operation'];
+
return this.pcrud.search('aou', {parent_ou : null},
- {flesh : -1, flesh_fields : {aou : [
- 'children', 'ou_type', 'hours_of_operation', 'ill_address',
- 'holds_address', 'mailing_address', 'billing_address'
- ]}}, {authoritative: true}
+ {flesh : -1, flesh_fields : {aou : flesh}}, {authoritative: true}
+
).toPromise().then(tree => {
this.ingestAouTree(tree);
if (!selectNodeId) { selectNodeId = this.org.root().id(); }
+
const node = this.tree.findNode(selectNodeId);
this.selected = node;
this.tree.selectNode(node);
this.generateHours(orgNode);
}
- this.addAddresses(orgNode);
-
const treeNode = new TreeNode({
id: orgNode.id(),
label: orgNode.name(),
this.selected = $event;
}
- // Fills the org unit in with 'new' addresses for any fields
- // that are missing.
- addAddresses(org: IdlObject) {
- ['billing_address', 'mailing_address', 'holds_address', 'ill_address']
- .forEach(addrType => {
- if (org[addrType]()) { return ; }
- const addr = this.idl.create('aoa');
- addr.isnew(true);
- addr.valid('t');
- addr.org_unit(org.id());
- org[addrType](addr);
- });
- }
-
generateHours(org: IdlObject) {
const hours = this.idl.create('aouhoo');
hours.id(org.id());
callerData: {orgUnit: org}
});
}
+
+ addressChanged(thing: any) {
+ // Reload to pick up org unit address changes.
+ this.orgSaved(this.currentOrg().id());
+ }
}
--- /dev/null
+import {NgModule} from '@angular/core';
+import {TreeModule} from '@eg/share/tree/tree.module';
+import {AdminCommonModule} from '@eg/staff/admin/common.module';
+import {OrgUnitComponent} from './org-unit.component';
+import {OrgAddressComponent} from './org-addr.component';
+import {OrgUnitRoutingModule} from './org-unit-routing.module';
+
+@NgModule({
+ declarations: [
+ OrgUnitComponent,
+ OrgAddressComponent
+ ],
+ imports: [
+ AdminCommonModule,
+ OrgUnitRoutingModule,
+ TreeModule
+ ],
+ exports: [
+ ],
+ providers: [
+ ]
+})
+
+export class OrgUnitModule {
+}
+
+
}, {
path: 'actor/org_unit_type',
component: OrgUnitTypeComponent
-}, {
+}, {
path: 'actor/org_unit',
- component: OrgUnitComponent
+ loadChildren: '@eg/staff/admin/server/org-unit.module#OrgUnitModule'
}, {
path: ':schema/:table',
component: BasicAdminPageComponent