LP1904036 surveys and more addresses
authorBill Erickson <berickxx@gmail.com>
Mon, 22 Mar 2021 20:34:47 +0000 (16:34 -0400)
committerGalen Charlton <gmc@equinoxOLI.org>
Fri, 28 Oct 2022 00:13:28 +0000 (20:13 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Jane Sandberg <js7389@princeton.edu>
Signed-off-by: Galen Charlton <gmc@equinoxOLI.org>
Open-ILS/src/eg2/src/app/staff/circ/patron/edit.component.html
Open-ILS/src/eg2/src/app/staff/circ/patron/edit.component.ts
Open-ILS/src/eg2/src/app/staff/circ/patron/resolver.service.ts

index 2412f67..57558f8 100644 (file)
     </div>
   </div>
 
-  <div class="alert alert-success p-2 m-3" i18n>User Settings</div>
+  <div class="alert alert-success p-2 m-3 d-flex">
+    <div class="m-auto font-weight-bold" i18n>User Settings</div>
+  </div>
 
   <ng-container *ngTemplateOutlet="userSettingsInputRow; context: 
     {args: {settingName: 'opac.default_phone'}}">
     </div>
   </ng-container>
 
-  <ng-container *ngFor="let addr of patron.addresses(); let index = index">
-    <div class="alert alert-success p-2 m-3 d-flex">
-      <div class="col-lg-3" i18n>Address</div>
-      <div class="col-lg-9">
-        <div class="form-check form-check-inline mr-2">
-          <input class="form-check-input" type="checkbox" 
-            name="addr-{{addr.id()}}-mailing" id="addr-{{addr.id()}}-mailing" 
-            [ngModel]="addr.id() == patron.mailing_address().id()"
-            (ngModelChange)="setAddrType('mailing', addr, $event)"/>
-          <label class="form-check-label" 
-            for="addr-{{addr.id()}}-mailing" i18n>Mailing</label>
-        </div>
-        <div class="form-check form-check-inline mr-2">
-          <input class="form-check-input" type="checkbox" 
-            name="addr-{{addr.id()}}-billing" id="addr-{{addr.id()}}-billing" 
-            [ngModel]="addr.id() == patron.billing_address().id()"
-            (ngModelChange)="setAddrType('billing', addr, $event)"/>
-          <label class="form-check-label" 
-            for="addr-{{addr.id()}}-billing" i18n>Physical</label>
+  <div class="alert alert-success p-2 m-3 d-flex">
+    <div class="m-auto font-weight-bold" i18n>Addresses</div>
+  </div>
+
+  <div class="mb-2" *ngFor="let addr of nonDeletedAddresses(); let index = index">
+
+    <div class="alert alert-info p-1">
+      <div class="row">
+        <div class="col-lg-3" i18n>Address #{{index + 1}}</div>
+        <div class="col-lg-9">
+          <div class="form-check form-check-inline mr-2">
+            <input class="form-check-input" type="checkbox" 
+              name="addr-{{addr.id()}}-mailing" id="addr-{{addr.id()}}-mailing" 
+              [ngModel]="addr.id() == patron.mailing_address().id()"
+              (ngModelChange)="setAddrType('mailing', addr, $event)"/>
+            <label class="form-check-label" 
+              for="addr-{{addr.id()}}-mailing" i18n>Mailing</label>
+          </div>
+          <div class="form-check form-check-inline mr-2">
+            <input class="form-check-input" type="checkbox" 
+              name="addr-{{addr.id()}}-billing" id="addr-{{addr.id()}}-billing" 
+              [ngModel]="addr.id() == patron.billing_address().id()"
+              (ngModelChange)="setAddrType('billing', addr, $event)"/>
+            <label class="form-check-label" 
+              for="addr-{{addr.id()}}-billing" i18n>Physical</label>
+          </div>
+          <button class="btn btn-danger" (click)="deleteAddr(addr)" i18n>Delete</button>
         </div>
-        <button class="btn btn-danger" (click)="deleteAddr(addr)" i18n>Delete</button>
       </div>
     </div>
     <ng-container *ngTemplateOutlet="fieldRow; context: {args: {template: 
     <ng-container *ngTemplateOutlet="fieldRow; context: {args: {template: 
       fieldCheckbox, field: 'within_city_limits', cls: 'aua', path: 'addresses', index: index}}">
     </ng-container>
-  </ng-container>
+  </div>
 
   <button class="btn btn-success" (click)="newAddr()" i18n>New Address</button>
 
-  <div class="alert alert-success p-2 m-3" i18n>Statistical Categories</div>
+  <div class="alert alert-success p-2 m-3 d-flex">
+    <div class="m-auto font-weight-bold" i18n>Statistical Categories</div>
+  </div>
 
   <div class="row pt-1 pb-1 mt-1" *ngFor="let stat of statCats">
    <div class="col-lg-3 field-label">
    </div>
   </div>
 
-  <div class="alert alert-success p-2 m-3" i18n>Surveys</div>
+  <div class="alert alert-success p-2 m-3 d-flex">
+    <div class="m-auto font-weight-bold" i18n>Surveys</div>
+  </div>
 
-  <div class="row pt-1 pb-1 mt-1" *ngFor="let survey of surveys">
-   <div class="col-lg-3 field-label">
-    <label for="asv-{{survey.id()}}-input">{{survey.name()}}</label>
-   </div>
-   <div class="col-lg-3">
+  <div class="card pt-1 pb-1 mt-1" *ngFor="let survey of surveys">
+    <div class="card-header">{{survey.name()}}</div>
+    <div class="card-body">
+      <div class="row pt-1 pb-1 mt-1" *ngFor="let question of survey.questions()">
+        <div class="col-lg-3 field-label">
+          <label for="asvq-{{question.id()}}-input">{{question.question()}}</label>
+        </div>
+        <div class="col-lg-3">
+          <eg-combobox
+            domId="asvq-{{question.id()}}-input"
+            name="asvq-{{question.id()}}-input"
+            [entries]="surveyQuestionAnswers(question)"
+            (onChange)="applySurveyResponse(question, $event)">
+          </eg-combobox>
+        </div>
+      </div>
+    </div>
   </div>
 
 </div>
index 4d5a52c..e96149d 100644 (file)
@@ -361,6 +361,25 @@ export class EditComponent implements OnInit {
         this.userSettings[name] = value;
     }
 
+    applySurveyResponse(question: IdlObject, answer: ComboboxEntry) {
+        if (!this.patron.survey_responses()) {
+            this.patron.survey_responses([]);
+        }
+
+        const responses = this.patron.survey_responses()
+            .filter(resp => resp.question() !== question.id());
+
+        const resp = this.idl.create('asvr');
+        resp.isnew(true);
+        resp.survey(question.survey());
+        resp.question(question.id());
+        resp.answer(answer.id);
+        resp.usr(this.patron.id());
+        resp.answer_date('now');
+        responses.push(resp);
+        this.patron.survey_responses(responses);
+    }
+
     // Called as the model changes.
     // This may be called many times before the final value is applied,
     // so avoid any heavy lifting here.  See afterFieldChange();
@@ -568,14 +587,57 @@ export class EditComponent implements OnInit {
     }
 
     deleteAddr(addr: IdlObject) {
+        const addresses = this.patron.addresses();
+        let promise = Promise.resolve(false);
+
+        if (this.patron.isnew() && addresses.length === 1) {
+            promise = this.serverStore.getItem(
+                'ui.patron.registration.require_address');
+        }
+
+        promise.then(required => {
+            if (required) {
+                // TODO alert and exit
+                return;
+            }
+
+            // Roll the mailing/billing designation to another
+            // address when needed.
+            if (this.patron.mailing_address().id() === addr.id()) {
+                this.setAddrType('mailing', addr, false);
+            }
+
+            if (this.patron.billing_address().id() === addr.id()) {
+                this.setAddrType('billing', addr, false);
+            }
+
+            if (addr.isnew()) {
+                let idx = 0;
+
+                addresses.some((a, i) => {
+                    if (a.id() === addr.id()) { idx = i; return true; }
+                });
+
+                // New addresses can be discarded
+                addresses.splice(idx, 1);
+
+            } else {
+                addr.isdeleted(true);
+            }
+        });
     }
 
     newAddr() {
         const addr = this.idl.create('aua');
+        addr.id(this.autoId--);
         addr.isnew(true);
         addr.valid('t');
         this.patron.addresses().push(addr);
     }
+
+    nonDeletedAddresses(): IdlObject[] {
+        return this.patron.addresses().filter(a => !a.isdeleted());
+    }
 }
 
 
index 7f96c44..90cf9df 100644 (file)
@@ -44,6 +44,7 @@ export class PatronResolver implements Resolve<Promise<any[]>> {
           'circ.staff_client.do_not_auto_attempt_print',
           'circ.disable_patron_credit',
           'sms.enable',
+          'ui.patron.registration.require_address',
           'credit.processor.default'
         ]).then(settings => {
             this.context.noTallyClaimsReturned =