6 Commits fa388423ea ... a303bee78b

Author SHA1 Message Date
  Christopher Leggett a303bee78b Rewrites props in notes to do type validation. 5 years ago
  Christopher Leggett 54981a28a2 Another shot at implementing the note orientation switching. 5 years ago
  Christopher Leggett 6f3031770f Removed code that caused notes to reverse orientation on user switch. 5 years ago
  Christopher Leggett 5e6cd1e58c Implements live update when adding notes. 5 years ago
  Christopher Leggett 4cd4f20e74 Sets timezone to EST 5 years ago
  Christopher Leggett 72f7aeba42 Swaps note create modal for collapsible form. 5 years ago

+ 39 - 0
app/Events/WorkOrderNoteAdded.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace App\Events;
+
+use Illuminate\Broadcasting\Channel;
+use Illuminate\Broadcasting\InteractsWithSockets;
+use Illuminate\Broadcasting\PresenceChannel;
+use Illuminate\Broadcasting\PrivateChannel;
+use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
+use Illuminate\Foundation\Events\Dispatchable;
+use Illuminate\Queue\SerializesModels;
+use App\WorkOrderNote;
+
+class WorkOrderNoteAdded implements ShouldBroadcast
+{
+    use Dispatchable, InteractsWithSockets, SerializesModels;
+
+    public $note;
+
+    /**
+     * Create a new event instance.
+     *
+     * @return void
+     */
+    public function __construct($note)
+    {
+        $this->note = $note;
+    }
+
+    /**
+     * Get the channels the event should broadcast on.
+     *
+     * @return \Illuminate\Broadcasting\Channel|array
+     */
+    public function broadcastOn()
+    {
+        return new Channel('wonotes.'.$this->note->notetype.'.'.$this->note->woid);
+    }
+}

+ 1 - 0
app/Http/Controllers/Api/WorkOrderNotesController.php

@@ -32,6 +32,7 @@ class WorkOrderNotesController extends Controller
         $workOrderNote->noteuser = $request->input('noteuser');
         $workOrderNote->woid = $request->input('woid');
         $workOrderNote->save();
+        event(new \App\Events\WorkOrderNoteAdded($workOrderNote));
         return response()->json($workOrderNote, 200);
     }
 

+ 1 - 1
config/app.php

@@ -67,7 +67,7 @@ return [
     |
     */
 
-    'timezone' => 'UTC',
+    'timezone' => 'America/New_York',
 
     /*
     |--------------------------------------------------------------------------

+ 174 - 59
public/js/app.js

@@ -2359,7 +2359,6 @@ __webpack_require__.r(__webpack_exports__);
           return credential.credid === deletedCred['credid'];
         });
 
-        console.log(index);
         $('#credential' + deletedCred['credid'] + 'deleteModal').modal('hide');
 
         _this.deleteCred(index);
@@ -2529,7 +2528,8 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony default export */ __webpack_exports__["default"] = ({
   props: {
     populateWith: {
-      type: Object
+      type: Object,
+      require: true
     },
     modalId: {
       type: String,
@@ -2547,32 +2547,14 @@ __webpack_require__.r(__webpack_exports__);
   },
   data: function data() {
     return {
-      note: {}
+      note: JSON.parse(JSON.stringify(this.populateWith))
     };
   },
-  mounted: function mounted() {
-    if (!this.populateWith) {
-      this.note = {
-        thenote: '',
-        notetype: this.noteType,
-        noteuser: this.noteUser,
-        woid: this.woid
-      };
-    } else {
-      this.note = JSON.parse(JSON.stringify(this.populateWith));
-    }
-  },
   methods: {
     updateNote: function updateNote(note) {
-      if (this.populateWith) {
-        axios.put('/api/workorders/notes/' + note.noteid, note).then(function (response) {
-          hideModal();
-        });
-      } else {
-        axios.post('/api/workorders/notes', note).then(function (response) {
-          hideModal();
-        });
-      }
+      axios.put('/api/workorders/notes/' + note.noteid, note).then(function (response) {
+        hideModal();
+      });
     },
     hideModal: function hideModal() {
       $('#' + this.modalId).modal('hide');
@@ -2619,29 +2601,98 @@ __webpack_require__.r(__webpack_exports__);
 //
 //
 //
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
 
 /* harmony default export */ __webpack_exports__["default"] = ({
   mixins: [_mixins_dateMixin__WEBPACK_IMPORTED_MODULE_0__["default"]],
-  props: ['initialnotes', 'authusername', 'noteType', 'woid'],
+  props: {
+    initialnotes: {
+      type: Array,
+      "default": []
+    },
+    authusername: {
+      type: String,
+      required: true
+    },
+    noteType: {
+      type: Number,
+      required: true
+    },
+    woid: {
+      type: Number,
+      required: true
+    }
+  },
   data: function data() {
     return {
-      notes: Object.values(this.initialnotes),
-      currentOrder: 'order-first'
+      notes: this.initialnotes,
+      newNote: {
+        notetype: this.noteType,
+        thenote: '',
+        noteuser: this.authusername,
+        woid: this.woid
+      }
     };
   },
+  computed: {
+    noteOrders: function noteOrders() {
+      return this.getNoteOrders(this.notes);
+    }
+  },
+  mounted: function mounted() {
+    var _this = this;
+
+    Echo.channel('wonotes.' + this.noteType + '.' + this.woid).listen('WorkOrderNoteAdded', function (e) {
+      _this.notes.push(e.note);
+    }).listen('WorkOrderNoteEdited', function (e) {
+      var index = _this.notes.findIndex(function (note) {
+        return note.noteid === e.note.noteid;
+      });
+
+      _this.notes[index] = e.note;
+    }).listen('WorkOrderNoteDeleted', function (e) {
+      var index = _this.notes.findIndex(function (note) {
+        return note.noteid === e.noteid;
+      });
+
+      _this.notes.splice(index, 1);
+    });
+  },
   methods: {
-    setOrder: function setOrder(index) {
-      if (index === 0) {
-        this.currentOrder = 'order-first';
-      } else if (this.notes[index].noteuser !== this.notes[index - 1].noteuser) {
-        if (this.currentOrder === 'order-first') {
-          this.currentOrder = 'order-last';
+    createNote: function createNote() {
+      var _this2 = this;
+
+      axios.post('/api/workorders/notes', this.newNote).then(function (response) {
+        $('#note' + _this2.noteType + 'add').collapse('hide');
+        _this2.newNote.thenote = '';
+      });
+    },
+    getNoteOrders: function getNoteOrders(notes) {
+      var noteOrders = [];
+      notes.forEach(function (note, index) {
+        if (index === 0) {
+          noteOrders[index] = 'order-first';
+        } else if (note.noteuser !== notes[index - 1].noteuser) {
+          if (noteOrders[index - 1] === 'order-first') {
+            noteOrders[index] = 'order-last';
+          } else {
+            noteOrders[index] = 'order-first';
+          }
         } else {
-          this.currentOrder = 'order-first';
+          noteOrders[index] = noteOrders[index - 1];
         }
-      }
-
-      return this.currentOrder;
+      });
+      return noteOrders;
     }
   }
 });
@@ -50093,27 +50144,91 @@ var render = function() {
     "ul",
     { staticClass: "list-unstyled" },
     [
-      _c("note-form-modal", {
-        attrs: {
-          "modal-id": "note" + _vm.noteType + "CreateModal",
-          "note-type": _vm.noteType,
-          woid: _vm.woid,
-          "note-user": _vm.authusername
-        }
-      }),
-      _vm._v(" "),
-      _c(
-        "button",
-        {
-          staticClass: "btn btn-primary",
-          attrs: {
-            type: "button",
-            "data-toggle": "modal",
-            "data-target": "#note" + _vm.noteType + "CreateModal"
-          }
-        },
-        [_c("i", { staticClass: "fas fa-fw fa-plus" }), _vm._v(" Add New Note")]
-      ),
+      _c("div", { staticClass: "row" }, [
+        _c(
+          "div",
+          {
+            staticClass:
+              "col-md-2 d-flex justify-content-center justify-content-md-start"
+          },
+          [
+            _c(
+              "button",
+              {
+                staticClass: "btn btn-primary m-2",
+                attrs: {
+                  type: "button",
+                  "data-toggle": "collapse",
+                  "data-target": "#note" + _vm.noteType + "add"
+                }
+              },
+              [
+                _c("i", { staticClass: "fas fa-fw fa-plus" }),
+                _vm._v(" Add New Note")
+              ]
+            )
+          ]
+        ),
+        _vm._v(" "),
+        _c("div", { staticClass: "col-md-10" }, [
+          _c(
+            "div",
+            {
+              staticClass: "collapse",
+              attrs: { id: "note" + _vm.noteType + "add" }
+            },
+            [
+              _c(
+                "div",
+                {
+                  staticClass:
+                    "d-flex flex-wrap flex-md-nowrap justify-content-center"
+                },
+                [
+                  _c("textarea", {
+                    directives: [
+                      {
+                        name: "model",
+                        rawName: "v-model",
+                        value: _vm.newNote.thenote,
+                        expression: "newNote.thenote"
+                      }
+                    ],
+                    staticClass: "form-control",
+                    attrs: {
+                      name: "newnote" + _vm.noteType,
+                      id: "newnote" + _vm.noteType
+                    },
+                    domProps: { value: _vm.newNote.thenote },
+                    on: {
+                      input: function($event) {
+                        if ($event.target.composing) {
+                          return
+                        }
+                        _vm.$set(_vm.newNote, "thenote", $event.target.value)
+                      }
+                    }
+                  }),
+                  _vm._v(" "),
+                  _c(
+                    "button",
+                    {
+                      staticClass: "btn btn-secondary m-2",
+                      attrs: { type: "button" },
+                      on: {
+                        click: function($event) {
+                          return _vm.createNote()
+                        }
+                      }
+                    },
+                    [_vm._v("Save")]
+                  )
+                ]
+              )
+            ]
+          )
+        ])
+      ]),
       _vm._v(" "),
       _vm._l(this.notes, function(note, index) {
         return _c(
@@ -50131,7 +50246,7 @@ var render = function() {
               "div",
               {
                 staticClass: "col-md-1 d-flex flex-column mx-md-3",
-                class: _vm.setOrder(index)
+                class: _vm.noteOrders[index]
               },
               [
                 _c("div", { staticClass: "text-center p-0 m-0" }, [

+ 0 - 1
resources/js/components/credential-list.vue

@@ -52,7 +52,6 @@ export default {
                     let index = this.credentials.findIndex((credential) => {
                         return credential.credid === deletedCred['credid']
                     })
-                    console.log(index)
                     $('#credential'+deletedCred['credid']+'deleteModal').modal('hide');
                     this.deleteCred(index);
                 })

+ 6 - 24
resources/js/components/note-form-modal.vue

@@ -20,6 +20,7 @@ export default {
     props: {
         populateWith: {
             type: Object,
+            require: true
         },
         modalId: {
             type: String,
@@ -37,34 +38,15 @@ export default {
     },
     data () {
         return {
-            note: {}
-        }
-    },
-    mounted () {
-        if(!this.populateWith) {
-            this.note = {
-                thenote: '',
-                notetype: this.noteType,
-                noteuser: this.noteUser,
-                woid: this.woid,
-            }
-        } else {
-            this.note = JSON.parse(JSON.stringify(this.populateWith))
+            note: JSON.parse(JSON.stringify(this.populateWith))
         }
     },
     methods: {
         updateNote (note) {
-            if (this.populateWith) {
-                axios.put('/api/workorders/notes/' + note.noteid, note)
-                    .then((response) => {
-                        hideModal()
-                    })
-            } else {
-                axios.post('/api/workorders/notes', note)
-                    .then((response) => {
-                        hideModal()
-                    })
-            }
+            axios.put('/api/workorders/notes/' + note.noteid, note)
+                .then((response) => {
+                    hideModal()
+                })
         },
         hideModal () {
             $('#'+this.modalId).modal('hide')

+ 83 - 15
resources/js/components/notes.vue

@@ -1,10 +1,21 @@
 <template>
     <ul class="list-unstyled">
-        <note-form-modal :modal-id="'note'+noteType+'CreateModal'" :note-type="noteType" :woid="woid" :note-user="authusername"></note-form-modal>
-        <button type="button" data-toggle="modal" :data-target="'#note'+noteType+'CreateModal'" class="btn btn-primary"><i class="fas fa-fw fa-plus"></i> Add New Note</button>
+            <div class="row">
+                <div class="col-md-2 d-flex justify-content-center justify-content-md-start">
+                    <button type="button" data-toggle="collapse" :data-target="'#note'+noteType+'add'" class="btn btn-primary m-2"><i class="fas fa-fw fa-plus"></i> Add New Note</button>
+                </div>
+                <div class="col-md-10">
+                    <div class="collapse" :id="'note'+noteType+'add'">
+                        <div class="d-flex flex-wrap flex-md-nowrap justify-content-center">
+                            <textarea :name="'newnote'+noteType" :id="'newnote'+noteType" class="form-control" v-model="newNote.thenote"></textarea>
+                            <button type="button" class="btn btn-secondary m-2" @click="createNote()">Save</button>
+                        </div>
+                    </div>
+                </div>
+            </div>
         <li class="row no-gutters mb-2" v-bind:key="index" v-for="(note, index) in this.notes">
             <note-form-modal :modal-id="'note'+note.noteid+'editModal'" :populate-with="note"></note-form-modal>
-            <div class="col-md-1 d-flex flex-column mx-md-3" :class="setOrder(index)">
+            <div class="col-md-1 d-flex flex-column mx-md-3" :class="noteOrders[index]">
                 <div class="text-center p-0 m-0">{{note.noteuser}}</div>
                 <div class="text-muted text-small text-center p-0 m-0">{{getHRDate(note.notetime)}}</div>
                 <div class="btn-group justify-content-center p-0 m-0">
@@ -29,25 +40,82 @@
 import dateMixin from '../mixins/dateMixin'
 export default {
     mixins:[dateMixin],
-    props: ['initialnotes', 'authusername', 'noteType', 'woid'],
+    props: {
+        initialnotes: {
+            type: Array,
+            default: [],
+        },
+        authusername: {
+            type: String,
+            required: true,
+        },
+        noteType: {
+            type: Number,
+            required: true,
+        },
+        woid: {
+            type: Number,
+            required: true,
+        }
+    },
     data () {
         return {
-            notes: Object.values(this.initialnotes),
-            currentOrder: 'order-first'
+            notes: this.initialnotes,
+            newNote: {
+                notetype: this.noteType,
+                thenote: '',
+                noteuser: this.authusername,
+                woid: this.woid
+            },
+        }
+    },
+    computed: {
+        noteOrders () {
+            return this.getNoteOrders(this.notes)
         }
     },
+    mounted () {
+        Echo.channel('wonotes.'+this.noteType+'.'+this.woid)
+            .listen('WorkOrderNoteAdded', (e) => {
+                this.notes.push(e.note)
+            })
+            .listen('WorkOrderNoteEdited', (e) => {
+                let index = this.notes.findIndex((note) => {
+                    return note.noteid === e.note.noteid
+                })
+                this.notes[index] = e.note
+            })
+            .listen('WorkOrderNoteDeleted', (e) => {
+                let index = this.notes.findIndex((note) => {
+                    return note.noteid === e.noteid
+                })
+                this.notes.splice(index, 1)
+            })
+    },
     methods: {
-        setOrder (index) {
-            if (index === 0) {
-                this.currentOrder = 'order-first'
-            } else if (this.notes[index].noteuser !== this.notes[index-1].noteuser) {
-                if (this.currentOrder === 'order-first') {
-                    this.currentOrder = 'order-last'
+        createNote () {
+            axios.post('/api/workorders/notes', this.newNote)
+                    .then((response) => {
+                        $('#note'+this.noteType+'add').collapse('hide')
+                        this.newNote.thenote = ''
+                    })
+        },
+        getNoteOrders(notes) {
+            let noteOrders = []
+            notes.forEach((note,index) =>{
+                if (index === 0) {
+                    noteOrders[index] = 'order-first'
+                } else if (note.noteuser !== notes[index-1].noteuser) {
+                    if (noteOrders[index-1] === 'order-first') {
+                        noteOrders[index] = 'order-last'
+                    } else {
+                        noteOrders[index] = 'order-first'
+                    }
                 } else {
-                    this.currentOrder = 'order-first'
+                    noteOrders[index] = noteOrders[index-1]
                 }
-            }
-            return this.currentOrder
+            })
+            return noteOrders
         }
     }
 }

+ 3 - 5
resources/views/workorders/show.blade.php

@@ -2,8 +2,7 @@
 
 @section('content')
 
-<div id="app">
-    <div class="container-fluid">
+<div class="container-fluid">
     <div class="row my-3">
         <div class="col-lg-6">
             <div class="card h-100">
@@ -81,7 +80,7 @@
             <div class="card">
                 <div class="card-body">
                     <h5 class="card-title">Customer Notes</h5>
-                    <notes :initialnotes="{{$workOrder->notes->where('notetype', '0')}}" authusername="{{Auth::user()->username}}" :note-type="0" :woid="{{$workOrder->woid}}"></notes>
+                    <notes :initialnotes='{{ $workOrder->notes->where('notetype', '0')->values() }}' authusername="{{Auth::user()->username}}" :note-type="0" :woid="{{$workOrder->woid}}"></notes>
                 </div>
             </div>
         </div>
@@ -91,12 +90,11 @@
             <div class="card">
                 <div class="card-body">
                     <h5 class="card-title">Private/Billing Notes</h5>
-                    <notes :initialnotes="{{$workOrder->notes->where('notetype', '1')}}" authusername="{{Auth::user()->username}}" :note-type="1" :woid="{{$workOrder->woid}}"></notes>
+                    <notes :initialnotes='{{ $workOrder->notes->where('notetype', '1')->values() }}' authusername="{{Auth::user()->username}}" :note-type="1" :woid="{{$workOrder->woid}}"></notes>
                 </div>
             </div>
         </div>
     </div>
-    </div>
 </div>
 
 @endsection