--- /dev/null
+<eg-string #deleteFailedString i18n-text text="Disassociation of Course Material failed or was not allowed"></eg-string>
+<eg-string #deleteSuccessString i18n-text text="Disassociation of Course Material succeeded"></eg-string>
+<eg-string #successString i18n-text text="Association of Course Material succeeded"></eg-string>
+<eg-string #failedString i18n-text text="Association of Course Material failed or was not allowed"></eg-string>
+<eg-string #differentLibraryString i18n-text text="Material exists at a different library"></eg-string>
+
+<ng-template #dialogContent>
+ <div class="modal-header bg-info">
+ <h4 class="modal-title" i18n>Course Materials</h4>
+ <button type="button" class="close"
+ i18n-aria-label aria-label="Close" (click)="close()">
+ <span aria-hidden="true">×</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <div class="row">
+ <div class="col-md-4">
+ <div class="input-group">
+ <div class="input-group-prepend">
+ <span class="input-group-text" i18n>Barcode</span>
+ </div>
+ <input type="text" [(ngModel)]="barcodeInput" />
+ </div>
+ </div>
+ <div class="col-md-5">
+ <div class="input-group">
+ <div class="input-group-prepend">
+ <span class="input-group-text" i18n>Relationship</span>
+ </div>
+ <input type="text" [(ngModel)]="relationshipInput" placeholder-i18n placeholder="e.g. Required" />
+ </div>
+ </div>
+ <div class="col-md-3">
+ <button class="btn btn-outline-dark" (click)="associateItem(barcodeInput, relationshipInput)" i18n [disabled]="!barcodeInput">Add Material</button>
+ </div>
+ </div>
+ <div class="mt-3">
+ <eg-grid #materialGrid [dataSource]="gridDataSource">
+ <eg-grid-toolbar-action label="Delete Selected" i18n-label (onClick)="deleteSelected($event)">
+ </eg-grid-toolbar-action>
+
+ <eg-grid-column path="id" [index]=true [hidden]="true" label="ID" i18n-label></eg-grid-column>
+ <eg-grid-column label="Barcode" i18n-label name="barcode" [cellTemplate]="barcodeCellTemplate"></eg-grid-column>
+ <eg-grid-column label="Title" i18n-label name="title" [cellTemplate]="titleCellTemplate"></eg-grid-column>
+ <eg-grid-column path="call_number.label" label="Call Number" i18n-label></eg-grid-column>
+ <eg-grid-column path="call_number.prefix.label" [hidden]="true" label="Call Number Prefix" i18n-label hidden></eg-grid-column>
+ <eg-grid-column path="call_number.suffix.label" [hidden]="true" label="Call Number Suffix" i18n-label hidden></eg-grid-column>
+ <eg-grid-column path="circ_modifier" label="Circulation Modifier" i18n-label></eg-grid-column>
+ <eg-grid-column path="circ_lib.shortname" label="Circulation Library" i18n-label></eg-grid-column>
+ <eg-grid-column path="_relationship" label="Relationship" i18n-label></eg-grid-column>
+ </eg-grid>
+ </div>
+ </div>
+ <ng-template #barcodeCellTemplate let-entry="row">
+ <span>
+ <a class="pl-1"
+ href="/eg/staff/cat/item/{{entry.id()}}">
+ {{entry.barcode()}}
+ </a>
+ </span>
+ </ng-template>
+ <ng-template #titleCellTemplate let-entry="row">
+ <span>
+ <a class="pl-1"
+ href="/eg/staff/cat/catalog/record/{{entry.call_number().record()}}">
+ {{entry._title}}
+ </a>
+ </span>
+ </ng-template>
+</ng-template>
\ No newline at end of file
--- /dev/null
+import {Component, Input, ViewChild, OnInit, TemplateRef} from '@angular/core';
+import {Observable, Observer, of} from 'rxjs';
+import {DialogComponent} from '@eg/share/dialog/dialog.component';
+import {AuthService} from '@eg/core/auth.service';
+import {NetService} from '@eg/core/net.service';
+import {OrgService} from '@eg/core/org.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {Pager} from '@eg/share/util/pager';
+import {NgbModal, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap';
+import {GridDataSource} from '@eg/share/grid/grid';
+import {GridComponent} from '@eg/share/grid/grid.component';
+import {IdlObject, IdlService} from '@eg/core/idl.service';
+import {StringComponent} from '@eg/share/string/string.component';
+import {ToastService} from '@eg/share/toast/toast.service';
+
+@Component({
+ selector: 'eg-course-associate-material-dialog',
+ templateUrl: './course-associate-material.component.html'
+})
+
+export class CourseAssociateMaterialComponent extends DialogComponent {
+
+ @ViewChild('materialsGrid', {static: true}) materialsGrid: GridComponent;
+ @ViewChild('deleteFailedString', { static: true }) deleteFailedString: StringComponent;
+ @ViewChild('deleteSuccessString', { static: true }) deleteSuccessString: StringComponent;
+ @ViewChild('successString', { static: true }) successString: StringComponent;
+ @ViewChild('failedString', { static: true }) failedString: StringComponent;
+ @ViewChild('differentLibraryString', { static: true }) differentLibraryString: StringComponent;
+ @Input() table_name = "Course Materials";
+ @Input() barcodeInput: String;
+ @Input() relationshipInput: String;
+ currentCourse: IdlObject;
+ materials: any[];
+ gridDataSource: GridDataSource;
+
+ constructor(
+ private auth: AuthService,
+ private idl: IdlService,
+ private net: NetService,
+ private pcrud: PcrudService,
+ private org: OrgService,
+ private modal: NgbModal,
+ private toast: ToastService
+ ) {
+ super(modal);
+ this.gridDataSource = new GridDataSource();
+ }
+
+ ngOnInit() {
+ this.gridDataSource.getRows = (pager: Pager, sort: any[]) => {
+ return this.fetchMaterials(pager);
+ }
+ }
+
+ deleteSelected(items) {
+ let item_ids = [];
+ items.forEach(item => {
+ this.gridDataSource.data.splice(this.gridDataSource.data.indexOf(item, 0), 1);
+ item_ids.push(item.id())
+ });
+ this.pcrud.search('acmcm', {course: this.currentCourse.id(), item: item_ids}).subscribe(res => {
+ res.isdeleted(true);
+ this.pcrud.autoApply(res).subscribe(
+ val => {
+ console.debug('deleted: ' + val);
+ this.deleteSuccessString.current().then(str => this.toast.success(str));
+ },
+ err => {
+ this.deleteFailedString.current()
+ .then(str => this.toast.danger(str));
+ }
+ );
+ });
+ }
+
+ associateItem(barcode, relationship) {
+ if (barcode) {
+ this.pcrud.search('acp', {barcode: barcode}).subscribe(item => {
+ let material = this.idl.create('acmcm');
+ material.item(item.id());
+ material.course(this.currentCourse.id());
+ if (relationship) material.relationship(relationship);
+ this.pcrud.create(material).subscribe(
+ val => {
+ console.debug('created: ' + val);
+ if (item.circ_lib() != this.currentCourse.owning_lib()) {
+ this.differentLibraryString.current().then(str => this.toast.warning(str));
+ } else {
+ this.successString.current().then(str => this.toast.success(str));
+ }
+ this.fetchItem(item.id(), relationship);
+ this.barcodeInput = "";
+ this.relationshipInput = "";
+ }, err => {
+ this.failedString.current().then(str => this.toast.danger(str));
+ });
+ });
+ }
+ }
+
+ fetchMaterials(pager: Pager): Observable<any> {
+ return new Observable<any>(observer => {
+ this.materials.forEach(material => {
+ this.fetchItem(material.item, material.relationship);
+ });
+ observer.complete();
+ });
+ }
+
+ fetchItem(itemId, relationship): Promise<any> {
+ return new Promise((resolve, reject) => {
+ this.net.request(
+ 'open-ils.circ',
+ 'open-ils.circ.copy_details.retrieve',
+ this.auth.token(), itemId
+ ).subscribe(res => {
+ if (res) {
+ let item = res.copy;
+ item.call_number(res.volume);
+ item.circ_lib(this.org.get(item.circ_lib()));
+ item._title = res.mvr.title();
+ item._relationship = relationship;
+ this.gridDataSource.data.push(item);
+ }
+ }, err => {
+ reject(err);
+ }, () => resolve(this.gridDataSource.data));
+ });
+ }
+}
\ No newline at end of file
<eg-string #deleteSuccessString i18n-text text="Delete of {{table_name}} succeeded"></eg-string>
<eg-string #flairTooltip i18n-text text="Limited Editing"></eg-string>
+<eg-course-associate-material-dialog #courseMaterialDialog>
+</eg-course-associate-material-dialog>
<div class="w-100 mt-2 mb-2">
<eg-grid #grid idlClass={{idl_class}}
[dataSource]="grid_source"
<eg-grid-toolbar-button
label="Create {{table_name}}" (onClick)="createNew()" i18n-label>
</eg-grid-toolbar-button>
+ <eg-grid-toolbar-action label="View Materials" i18n-label (onClick)="openMaterialsDialog($event)">
+ </eg-grid-toolbar-action>
<eg-grid-toolbar-action label="Edit Selected" i18n-label (onClick)="editSelected($event)">
</eg-grid-toolbar-action>
<eg-grid-toolbar-action label="Delete Selected" i18n-label (onClick)="deleteSelected($event)">
import {Component, Input, ViewChild, OnInit} from '@angular/core';
import {IdlObject} from '@eg/core/idl.service';
import {PcrudService} from '@eg/core/pcrud.service';
+import {AuthService} from '@eg/core/auth.service';
+import {NetService} from '@eg/core/net.service';
+import {OrgService} from '@eg/core/org.service';
import {GridComponent} from '@eg/share/grid/grid.component';
import {Pager} from '@eg/share/util/pager';
import {GridDataSource, GridColumn} from '@eg/share/grid/grid';
import {StringComponent} from '@eg/share/string/string.component';
import {ToastService} from '@eg/share/toast/toast.service';
+import {CourseAssociateMaterialComponent
+ } from './course-associate-material.component';
+
@Component({
templateUrl: './course-list.component.html'
})
@ViewChild('updateFailedString', { static: false }) updateFailedString: StringComponent;
@ViewChild('deleteFailedString', { static: true }) deleteFailedString: StringComponent;
@ViewChild('deleteSuccessString', { static: true }) deleteSuccessString: StringComponent;
+ @ViewChild('courseMaterialDialog', {static: true})
+ private courseMaterialDialog: CourseAssociateMaterialComponent;
@Input() sort_field: string;
@Input() idl_class = "acmc";
@Input() dialog_size: 'sm' | 'lg' = 'lg';
@Input() table_name = "Course";
grid_source: GridDataSource = new GridDataSource();
+ currentMaterials: any[] = [];
search_value = '';
constructor(
+ private auth: AuthService,
+ private net: NetService,
+ private org: OrgService,
private pcrud: PcrudService,
private toast: ToastService,
){}
() => this.grid.reload()
);
};
+
+ fetchCourseMaterials(course, currentMaterials): Promise<any> {
+ return new Promise((resolve, reject) => {
+ this.pcrud.search('acmcm', {course: course}).subscribe(res => {
+ if (res) this.fleshItemDetails(res.item(), res.relationship());
+ }, err => {
+ reject(err);
+ }, () => resolve(this.courseMaterialDialog.gridDataSource.data));
+ });
+ }
+
+ fleshItemDetails(itemId, relationship): Promise<any> {
+ return new Promise((resolve, reject) => {
+ this.net.request(
+ 'open-ils.circ',
+ 'open-ils.circ.copy_details.retrieve',
+ this.auth.token(), itemId
+ ).subscribe(res => {
+ if (res) {
+ let item = res.copy;
+ item.call_number(res.volume);
+ item._title = res.mvr.title();
+ item.circ_lib(this.org.get(item.circ_lib()));
+ item._relationship = relationship;
+ this.courseMaterialDialog.gridDataSource.data.push(item);
+ }
+ }, err => {
+ reject(err);
+ }, () => resolve(this.courseMaterialDialog.gridDataSource.data));
+ });
+ }
+
+ openMaterialsDialog(course) {
+ let currentMaterials = []
+ this.courseMaterialDialog.gridDataSource.data = [];
+ this.fetchCourseMaterials(course[0].id(), currentMaterials).then(res => {
+ this.courseMaterialDialog.currentCourse = course[0];
+ this.courseMaterialDialog.materials = currentMaterials;
+ this.courseMaterialDialog.open({size: 'lg'}).subscribe(res => {
+ console.log(res);
+ });
+ });
+ }
}
import {TreeModule} from '@eg/share/tree/tree.module';
import {AdminCommonModule} from '@eg/staff/admin/common.module';
import {CourseListComponent} from './course-list.component';
+import {CourseAssociateMaterialComponent} from './course-associate-material.component';
import {CourseReservesRoutingModule} from './routing.module';
@NgModule({
declarations: [
- CourseListComponent
+ CourseListComponent,
+ CourseAssociateMaterialComponent
],
imports: [
AdminCommonModule,