11 Commits 94ec05477d ... fa388423ea

Auteur SHA1 Message Date
  Christopher Leggett fa388423ea Fixes note orientation reversal code il y a 5 ans
  Christopher Leggett e8b0f3cabe Implements adding and editing notes. il y a 5 ans
  Christopher Leggett d32e3e3501 Fixed bug causing wrong credential to be removed from DOM. il y a 5 ans
  Christopher Leggett 5f8994a437 Implements reversing note orientation when noteuser changes. il y a 5 ans
  Christopher Leggett bf5f79d155 Sets creds to be sorted by date descending il y a 5 ans
  Christopher Leggett 403cc36dcd Implements live update when adding credentials il y a 5 ans
  Christopher Leggett 0f86e6e32a Rewrites credential delete so it live-updates for everyone. il y a 5 ans
  Christopher Leggett 08436cc1fd Removes credential from credlist live on delete il y a 5 ans
  Christopher Leggett 40cf04e1c7 Cleans up broadcasting code to specify channels. il y a 5 ans
  Christopher Leggett 7a2a908379 Removes unnecessary comment. il y a 5 ans
  Christopher Leggett 57b3ec0780 Changes credential update to use more specific channel names. il y a 5 ans

+ 2 - 2
app/Events/AssetUpdated.php

@@ -25,7 +25,7 @@ class AssetUpdated implements ShouldBroadcast
      */
     public function __construct($asset)
     {
-        $this->data = $asset->toJson();
+        $this->data = $asset;
         $this->pcextra = json_encode(unserialize($asset->pcextra));
     }
 
@@ -36,6 +36,6 @@ class AssetUpdated implements ShouldBroadcast
      */
     public function broadcastOn()
     {
-        return new Channel('assets');
+        return new Channel('asset.'.$this->data->pcid);
     }
 }

+ 42 - 0
app/Events/CredentialAdded.php

@@ -0,0 +1,42 @@
+<?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;
+
+class CredentialAdded implements ShouldBroadcast
+{
+    use Dispatchable, InteractsWithSockets, SerializesModels;
+
+    public $credential;
+
+    /**
+     * Create a new event instance.
+     *
+     * @return void
+     */
+    public function __construct($credential)
+    {
+        $this->credential = $credential;
+    }
+
+    /**
+     * Get the channels the event should broadcast on.
+     *
+     * @return \Illuminate\Broadcasting\Channel|array
+     */
+    public function broadcastOn()
+    {
+        if ($this->credential->pcid != 0) {
+            return new Channel('credlist.pcid.'.$this->credential->pcid);
+        } else {
+            return new Channel('credlist.groupid.'.$this->credential->groupid);
+        }
+    }
+}

+ 44 - 0
app/Events/CredentialDeleted.php

@@ -0,0 +1,44 @@
+<?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\Credential;
+
+class CredentialDeleted implements ShouldBroadcast
+{
+    use Dispatchable, InteractsWithSockets, SerializesModels;
+
+    public $credential;
+
+    /**
+     * Create a new event instance.
+     *
+     * @return void
+     */
+    public function __construct($credential)
+    {
+        $array = json_decode($credential, true);
+        $this->credential = $array;
+    }
+
+    /**
+     * Get the channels the event should broadcast on.
+     *
+     * @return \Illuminate\Broadcasting\Channel|array
+     */
+    public function broadcastOn()
+    {
+        if ($this->credential['pcid'] != 0) {
+            return new Channel('credlist.pcid.'.$this->credential['pcid']);
+        } else {
+            return new Channel('credlist.groupid.'.$this->credential['groupid']);
+        }
+    }
+}

+ 3 - 3
app/Events/CredentialUpdated.php

@@ -15,7 +15,7 @@ class CredentialUpdated implements ShouldBroadcast
 {
     use Dispatchable, InteractsWithSockets, SerializesModels;
 
-    public $data;
+    public $credential;
 
     /**
      * Create a new event instance.
@@ -24,7 +24,7 @@ class CredentialUpdated implements ShouldBroadcast
      */
     public function __construct($credential)
     {
-        $this->data = $credential->toJson();
+        $this->credential = $credential;
     }
 
     /**
@@ -34,6 +34,6 @@ class CredentialUpdated implements ShouldBroadcast
      */
     public function broadcastOn()
     {
-        return new Channel('credentials');
+        return new Channel('credential.'.$this->credential->credid);
     }
 }

+ 2 - 2
app/Events/WorkOrderUpdated.php

@@ -24,7 +24,7 @@ class WorkOrderUpdated implements ShouldBroadcast
      */
     public function __construct($workOrder)
     {
-        $this->data = $workOrder->toJson();
+        $this->data = $workOrder;
 
     }
 
@@ -35,6 +35,6 @@ class WorkOrderUpdated implements ShouldBroadcast
      */
     public function broadcastOn()
     {
-        return new Channel('work-orders');
+        return new Channel('work-order.'.$this->data->woid);
     }
 }

+ 5 - 1
app/Http/Controllers/Api/CredentialsController.php

@@ -42,6 +42,7 @@ class CredentialsController extends Controller
         $credential->credq = ' ';
         $credential->creda = ' ';
         $credential->save();
+        event(new \App\Events\CredentialAdded($credential));
         return response()->json($credential, 200);
     }
 
@@ -82,6 +83,9 @@ class CredentialsController extends Controller
      */
     public function destroy(Credential $credential)
     {
-        //
+        $deletedCred = $credential->toJson();
+        $credential->delete();
+        event(new \App\Events\CredentialDeleted($deletedCred));
+        return response()->json("", 204);
     }
 }

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

@@ -0,0 +1,73 @@
+<?php
+
+namespace App\Http\Controllers\Api;
+
+use App\Http\Controllers\Controller;
+use App\WorkOrderNote;
+use Illuminate\Http\Request;
+
+class WorkOrderNotesController extends Controller
+{
+    /**
+     * Display a listing of the resource.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function index()
+    {
+        //
+    }
+
+    /**
+     * Store a newly created resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return \Illuminate\Http\Response
+     */
+    public function store(Request $request)
+    {
+        $workOrderNote = new WorkOrderNote();
+        $workOrderNote->notetype = $request->input('notetype');
+        $workOrderNote->thenote = $request->input('thenote');
+        $workOrderNote->noteuser = $request->input('noteuser');
+        $workOrderNote->woid = $request->input('woid');
+        $workOrderNote->save();
+        return response()->json($workOrderNote, 200);
+    }
+
+    /**
+     * Display the specified resource.
+     *
+     * @param  \App\WorkOrderNote  $workOrderNote
+     * @return \Illuminate\Http\Response
+     */
+    public function show(WorkOrderNote $workOrderNote)
+    {
+        //
+    }
+
+    /**
+     * Update the specified resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \App\WorkOrderNote  $workOrderNote
+     * @return \Illuminate\Http\Response
+     */
+    public function update(Request $request, WorkOrderNote $workOrderNote)
+    {
+        $workOrderNote->thenote = $request->input('thenote');
+        $workOrderNote->save();
+        return response()->json($workOrderNote, 200);
+    }
+
+    /**
+     * Remove the specified resource from storage.
+     *
+     * @param  \App\WorkOrderNote  $workOrderNote
+     * @return \Illuminate\Http\Response
+     */
+    public function destroy(WorkOrderNote $workOrderNote)
+    {
+        //
+    }
+}

+ 1 - 1
app/WorkOrderNote.php

@@ -10,7 +10,7 @@ class WorkOrderNote extends Model
     protected $primaryKey = 'noteid';
 
     const CREATED_AT = 'notetime';
-    const MODIFIED_AT = null;
+    const UPDATED_AT = null;
 
     public function workOrder() {
         return $this->belongsTo('App\WorkOrder', 'woid');

+ 490 - 176
public/js/app.js

@@ -2008,8 +2008,8 @@ __webpack_require__.r(__webpack_exports__);
   mounted: function mounted() {
     var _this = this;
 
-    Echo.channel('assets').listen('AssetUpdated', function (e) {
-      _this.data = JSON.parse(e.data);
+    Echo.channel('asset.' + this.data.pcid).listen('AssetUpdated', function (e) {
+      _this.data = e.data;
       _this.pcextra = JSON.parse(e.pcextra);
     });
   },
@@ -2342,6 +2342,47 @@ __webpack_require__.r(__webpack_exports__);
       });
       return list;
     }
+  },
+  methods: {
+    deleteCred: function deleteCred(index) {
+      this.credentials.splice(index, 1);
+    }
+  },
+  mounted: function mounted() {
+    var _this = this;
+
+    if (this.pcid) {
+      Echo.channel('credlist.pcid.' + this.pcid).listen('CredentialDeleted', function (e) {
+        var deletedCred = e.credential;
+
+        var index = _this.credentials.findIndex(function (credential) {
+          return credential.credid === deletedCred['credid'];
+        });
+
+        console.log(index);
+        $('#credential' + deletedCred['credid'] + 'deleteModal').modal('hide');
+
+        _this.deleteCred(index);
+      }).listen('CredentialAdded', function (e) {
+        _this.credentials.unshift(e.credential);
+      });
+    }
+
+    if (this.groupid) {
+      Echo.channel('credlist.groupid.' + this.groupid).listen('CredentialDeleted', function (e) {
+        var deletedCred = e.credential;
+
+        var index = _this.credentials.findIndex(function (credential) {
+          return credential.groupid === deletedCred['groupid'];
+        });
+
+        $('#credential' + deletedCred['credid'] + 'deleteModal').modal('hide');
+
+        _this.deleteCred(index);
+      }).listen('CredentialAdded', function (e) {
+        _this.credentials.unshift(e.credential);
+      });
+    }
   }
 });
 
@@ -2387,6 +2428,18 @@ __webpack_require__.r(__webpack_exports__);
 //
 //
 //
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
 /* harmony default export */ __webpack_exports__["default"] = ({
   props: ['credential', 'descriptions'],
   data: function data() {
@@ -2398,24 +2451,20 @@ __webpack_require__.r(__webpack_exports__);
   mounted: function mounted() {
     var _this = this;
 
-    Echo.channel('credentials').listen('CredentialUpdated', function (e) {
-      // This part could potentially use a refactor.
-      // Probably needs a credential list component to listen for this
-      // even and update the corresponding credential. Currently every
-      // credential on the page receives this event and checks whether it was intended
-      // for its credential or not. I would imagine this could cause a problem
-      // on the group page, which will potentially have a lot more credentials from
-      // various assets. Better solution may be to have a credentials list component
-      // That listens for credential update events and updates the appropriate credential.
-      // There would still be multiples of those on the group credentials page, but an
-      // order of magnitude less of those than of individual credentials.
-      // It also may not be a big deal performance wise to do it like this, not sure.
-      var eData = JSON.parse(e.data);
-
-      if (_this.data.credid === eData.credid) {
-        _this.data = eData;
-      }
+    Echo.channel('credential.' + this.data.credid).listen('CredentialUpdated', function (e) {
+      _this.data = e.credential;
     });
+  },
+  methods: {
+    deleteCredential: function deleteCredential() {
+      var _this2 = this;
+
+      axios["delete"]('/api/credentials/' + this.data.credid, this.data).then(function (response) {
+        $('#credential' + _this2.data.credid + 'deleteModal').modal('hide');
+      })["catch"](function (error) {
+        console.error(error);
+      });
+    }
   }
 });
 
@@ -2451,16 +2500,15 @@ __webpack_require__.r(__webpack_exports__);
 
 /***/ }),
 
-/***/ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/notes.vue?vue&type=script&lang=js&":
-/*!****************************************************************************************************************************************************************!*\
-  !*** ./node_modules/babel-loader/lib??ref--4-0!./node_modules/vue-loader/lib??vue-loader-options!./resources/js/components/notes.vue?vue&type=script&lang=js& ***!
-  \****************************************************************************************************************************************************************/
+/***/ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/note-form-modal.vue?vue&type=script&lang=js&":
+/*!**************************************************************************************************************************************************************************!*\
+  !*** ./node_modules/babel-loader/lib??ref--4-0!./node_modules/vue-loader/lib??vue-loader-options!./resources/js/components/note-form-modal.vue?vue&type=script&lang=js& ***!
+  \**************************************************************************************************************************************************************************/
 /*! exports provided: default */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
-/* harmony import */ var _mixins_dateMixin__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../mixins/dateMixin */ "./resources/js/mixins/dateMixin.js");
 //
 //
 //
@@ -2478,6 +2526,77 @@ __webpack_require__.r(__webpack_exports__);
 //
 //
 //
+/* harmony default export */ __webpack_exports__["default"] = ({
+  props: {
+    populateWith: {
+      type: Object
+    },
+    modalId: {
+      type: String,
+      require: true
+    },
+    noteType: {
+      type: Number
+    },
+    noteUser: {
+      type: String
+    },
+    woid: {
+      type: Number
+    }
+  },
+  data: function data() {
+    return {
+      note: {}
+    };
+  },
+  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();
+        });
+      }
+    },
+    hideModal: function hideModal() {
+      $('#' + this.modalId).modal('hide');
+    }
+  }
+});
+
+/***/ }),
+
+/***/ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/notes.vue?vue&type=script&lang=js&":
+/*!****************************************************************************************************************************************************************!*\
+  !*** ./node_modules/babel-loader/lib??ref--4-0!./node_modules/vue-loader/lib??vue-loader-options!./resources/js/components/notes.vue?vue&type=script&lang=js& ***!
+  \****************************************************************************************************************************************************************/
+/*! exports provided: default */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var _mixins_dateMixin__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../mixins/dateMixin */ "./resources/js/mixins/dateMixin.js");
+//
+//
+//
+//
+//
 //
 //
 //
@@ -2503,11 +2622,27 @@ __webpack_require__.r(__webpack_exports__);
 
 /* harmony default export */ __webpack_exports__["default"] = ({
   mixins: [_mixins_dateMixin__WEBPACK_IMPORTED_MODULE_0__["default"]],
-  props: ['initialnotes', 'authusername'],
+  props: ['initialnotes', 'authusername', 'noteType', 'woid'],
   data: function data() {
     return {
-      notes: this.initialnotes
+      notes: Object.values(this.initialnotes),
+      currentOrder: 'order-first'
     };
+  },
+  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';
+        } else {
+          this.currentOrder = 'order-first';
+        }
+      }
+
+      return this.currentOrder;
+    }
   }
 });
 
@@ -2641,8 +2776,8 @@ __webpack_require__.r(__webpack_exports__);
   mounted: function mounted() {
     var _this = this;
 
-    Echo.channel('work-orders').listen('WorkOrderUpdated', function (e) {
-      _this.data = JSON.parse(e.data);
+    Echo.channel('work-order.' + this.data.woid).listen('WorkOrderUpdated', function (e) {
+      _this.data = e.data;
     });
   }
 });
@@ -49562,6 +49697,59 @@ var render = function() {
         }
       }),
       _vm._v(" "),
+      _c(
+        "modal",
+        {
+          attrs: {
+            id: "credential" + this.data.credid + "deleteModal",
+            tabindex: "-1"
+          }
+        },
+        [
+          _c(
+            "h5",
+            {
+              staticClass: "modal-title",
+              attrs: {
+                slot: "header",
+                id: "credential" + this.data.credid + "deleteModalLabel"
+              },
+              slot: "header"
+            },
+            [_vm._v("\r\n            Delete Credential\r\n        ")]
+          ),
+          _vm._v(" "),
+          _c("div", { attrs: { slot: "body" }, slot: "body" }, [
+            _vm._v("\r\n            Are you sure?\r\n        ")
+          ]),
+          _vm._v(" "),
+          _c("div", { attrs: { slot: "footer" }, slot: "footer" }, [
+            _c(
+              "button",
+              {
+                staticClass: "btn btn-secondary",
+                attrs: { type: "button", "data-dismiss": "modal" }
+              },
+              [_vm._v("Cancel")]
+            ),
+            _vm._v(" "),
+            _c(
+              "button",
+              {
+                staticClass: "btn btn-danger",
+                attrs: { type: "button" },
+                on: {
+                  click: function($event) {
+                    return _vm.deleteCredential()
+                  }
+                }
+              },
+              [_vm._v("Confirm")]
+            )
+          ])
+        ]
+      ),
+      _vm._v(" "),
       _c("div", { staticClass: "row no-gutters" }, [
         _c("div", { staticClass: "h5 col-3 text-left" }, [
           _vm._v(_vm._s(this.data.creddesc))
@@ -49647,7 +49835,19 @@ var render = function() {
               [_c("i", { staticClass: "fas fa-fw fa-edit" })]
             ),
             _vm._v(" "),
-            _vm._m(2)
+            _c(
+              "button",
+              {
+                staticClass: "btn btn-sm btn-danger p-lg-1",
+                attrs: {
+                  type: "button",
+                  "data-toggle": "modal",
+                  "data-target":
+                    "#credential" + this.data.credid + "deleteModal"
+                }
+              },
+              [_c("i", { staticClass: "fas fa-fw fa-trash-alt" })]
+            )
           ]
         )
       ])
@@ -49671,19 +49871,6 @@ var staticRenderFns = [
     return _c("label", { attrs: { for: "password" } }, [
       _c("i", { staticClass: "fas fa-fw fa-key" })
     ])
-  },
-  function() {
-    var _vm = this
-    var _h = _vm.$createElement
-    var _c = _vm._self._c || _h
-    return _c(
-      "button",
-      {
-        staticClass: "btn btn-sm btn-danger p-lg-1",
-        attrs: { type: "button" }
-      },
-      [_c("i", { staticClass: "fas fa-fw fa-trash-alt" })]
-    )
   }
 ]
 render._withStripped = true
@@ -49784,6 +49971,107 @@ render._withStripped = true
 
 
 
+/***/ }),
+
+/***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/note-form-modal.vue?vue&type=template&id=0435c624&":
+/*!******************************************************************************************************************************************************************************************************************!*\
+  !*** ./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options!./resources/js/components/note-form-modal.vue?vue&type=template&id=0435c624& ***!
+  \******************************************************************************************************************************************************************************************************************/
+/*! exports provided: render, staticRenderFns */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "render", function() { return render; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "staticRenderFns", function() { return staticRenderFns; });
+var render = function() {
+  var _vm = this
+  var _h = _vm.$createElement
+  var _c = _vm._self._c || _h
+  return _c(
+    "modal",
+    {
+      attrs: {
+        id: _vm.modalId,
+        tabindex: "-1",
+        role: "dialog",
+        "aria-labelledby": _vm.modalId + "Label"
+      }
+    },
+    [
+      _c(
+        "h5",
+        {
+          staticClass: "modal-title",
+          attrs: { slot: "header", id: _vm.modalId + "Label" },
+          slot: "header"
+        },
+        [_vm._v("\n                Edit Note\n            ")]
+      ),
+      _vm._v(" "),
+      _c("div", { attrs: { slot: "body" }, slot: "body" }, [
+        _c("div", { staticClass: "form-group" }, [
+          _c("label", { attrs: { for: "content" } }, [_vm._v("Content")]),
+          _vm._v(" "),
+          _c("textarea", {
+            directives: [
+              {
+                name: "model",
+                rawName: "v-model",
+                value: _vm.note.thenote,
+                expression: "note.thenote"
+              }
+            ],
+            staticClass: "form-control",
+            attrs: {
+              name: "content" + _vm.note.noteid,
+              id: "content" + _vm.note.noteid
+            },
+            domProps: { value: _vm.note.thenote },
+            on: {
+              input: function($event) {
+                if ($event.target.composing) {
+                  return
+                }
+                _vm.$set(_vm.note, "thenote", $event.target.value)
+              }
+            }
+          })
+        ])
+      ]),
+      _vm._v(" "),
+      _c("div", { attrs: { slot: "footer" }, slot: "footer" }, [
+        _c(
+          "button",
+          {
+            staticClass: "btn btn-secondary",
+            attrs: { type: "button", "data-dismiss": "modal" }
+          },
+          [_vm._v("Close")]
+        ),
+        _vm._v(" "),
+        _c(
+          "button",
+          {
+            staticClass: "btn btn-primary",
+            attrs: { type: "button" },
+            on: {
+              click: function($event) {
+                return _vm.updateNote(_vm.note)
+              }
+            }
+          },
+          [_vm._v("Save")]
+        )
+      ])
+    ]
+  )
+}
+var staticRenderFns = []
+render._withStripped = true
+
+
+
 /***/ }),
 
 /***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/notes.vue?vue&type=template&id=73d141f4&":
@@ -49804,151 +50092,106 @@ var render = function() {
   return _c(
     "ul",
     { staticClass: "list-unstyled" },
-    _vm._l(this.notes, function(note) {
-      return _c(
-        "li",
-        { key: note.noteid, staticClass: "row no-gutters mb-2" },
-        [
-          _c(
-            "modal",
-            {
+    [
+      _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")]
+      ),
+      _vm._v(" "),
+      _vm._l(this.notes, function(note, index) {
+        return _c(
+          "li",
+          { key: index, staticClass: "row no-gutters mb-2" },
+          [
+            _c("note-form-modal", {
               attrs: {
-                id: "note" + note.noteid + "editModal",
-                tabindex: "-1",
-                role: "dialog",
-                "aria-labelledby": "note" + note.noteid + "editModalLabel"
+                "modal-id": "note" + note.noteid + "editModal",
+                "populate-with": note
               }
-            },
-            [
-              _c(
-                "h5",
-                {
-                  staticClass: "modal-title",
-                  attrs: {
-                    slot: "header",
-                    id: "note" + note.noteid + "editModalLabel"
-                  },
-                  slot: "header"
-                },
-                [_vm._v("\n                Edit Note\n            ")]
-              ),
-              _vm._v(" "),
-              _c("div", { attrs: { slot: "body" }, slot: "body" }, [
-                _c("div", { staticClass: "form-group" }, [
-                  _c("label", { attrs: { for: "content" } }, [
-                    _vm._v("Content")
-                  ]),
-                  _vm._v(" "),
-                  _c("textarea", {
-                    directives: [
-                      {
-                        name: "model",
-                        rawName: "v-model",
-                        value: note.thenote,
-                        expression: "note.thenote"
-                      }
-                    ],
-                    staticClass: "form-control",
-                    attrs: {
-                      name: "content" + note.noteid,
-                      id: "content" + note.noteid
-                    },
-                    domProps: { value: note.thenote },
-                    on: {
-                      input: function($event) {
-                        if ($event.target.composing) {
-                          return
-                        }
-                        _vm.$set(note, "thenote", $event.target.value)
-                      }
-                    }
-                  })
-                ])
-              ]),
-              _vm._v(" "),
-              _c("div", { attrs: { slot: "footer" }, slot: "footer" }, [
+            }),
+            _vm._v(" "),
+            _c(
+              "div",
+              {
+                staticClass: "col-md-1 d-flex flex-column mx-md-3",
+                class: _vm.setOrder(index)
+              },
+              [
+                _c("div", { staticClass: "text-center p-0 m-0" }, [
+                  _vm._v(_vm._s(note.noteuser))
+                ]),
+                _vm._v(" "),
                 _c(
-                  "button",
-                  {
-                    staticClass: "btn btn-secondary",
-                    attrs: { type: "button", "data-dismiss": "modal" }
-                  },
-                  [_vm._v("Close")]
+                  "div",
+                  { staticClass: "text-muted text-small text-center p-0 m-0" },
+                  [_vm._v(_vm._s(_vm.getHRDate(note.notetime)))]
                 ),
                 _vm._v(" "),
                 _c(
-                  "button",
-                  {
-                    staticClass: "btn btn-primary",
-                    attrs: { type: "button" },
-                    on: {
-                      click: function($event) {
-                        return _vm.updateNote(note.noteid)
-                      }
-                    }
-                  },
-                  [_vm._v("Save")]
+                  "div",
+                  { staticClass: "btn-group justify-content-center p-0 m-0" },
+                  [
+                    _vm.authusername === note.noteuser ||
+                    _vm.authusername === "admin"
+                      ? [
+                          _c(
+                            "button",
+                            {
+                              staticClass: "btn btn-sm btn-primary m-1",
+                              attrs: {
+                                "data-toggle": "modal",
+                                "data-target":
+                                  "#note" + note.noteid + "editModal"
+                              }
+                            },
+                            [_c("i", { staticClass: "fas fa-fw fa-edit" })]
+                          ),
+                          _vm._v(" "),
+                          _vm._m(0, true),
+                          _vm._v(" "),
+                          _vm._m(1, true)
+                        ]
+                      : _vm._e()
+                  ],
+                  2
                 )
-              ])
-            ]
-          ),
-          _vm._v(" "),
-          _c("div", { staticClass: "col-md-1 d-flex flex-column mx-md-3" }, [
-            _c("div", { staticClass: "text-center p-0 m-0" }, [
-              _vm._v(_vm._s(note.noteuser))
-            ]),
-            _vm._v(" "),
-            _c(
-              "div",
-              { staticClass: "text-muted text-small text-center p-0 m-0" },
-              [_vm._v(_vm._s(_vm.getHRDate(note.notetime)))]
+              ]
             ),
             _vm._v(" "),
-            _c(
-              "div",
-              { staticClass: "btn-group justify-content-center p-0 m-0" },
-              [
-                _vm.authusername === note.noteuser ||
-                _vm.authusername === "admin"
-                  ? [
-                      _c(
-                        "button",
-                        {
-                          staticClass: "btn btn-sm btn-primary m-1",
-                          attrs: {
-                            "data-toggle": "modal",
-                            "data-target": "#note" + note.noteid + "editModal"
-                          }
-                        },
-                        [_c("i", { staticClass: "fas fa-fw fa-edit" })]
-                      ),
-                      _vm._v(" "),
-                      _vm._m(0, true),
-                      _vm._v(" "),
-                      _vm._m(1, true)
-                    ]
-                  : _vm._e()
-              ],
-              2
-            )
-          ]),
-          _vm._v(" "),
-          _c("div", { staticClass: "col-md-10" }, [
-            _c("div", { staticClass: "card m-2" }, [
-              _c("div", { staticClass: "card-body p-2" }, [
-                _vm._v(
-                  "\n                    " +
-                    _vm._s(note.thenote) +
-                    "\n                "
-                )
+            _c("div", { staticClass: "col-md-10" }, [
+              _c("div", { staticClass: "card m-2" }, [
+                _c("div", { staticClass: "card-body p-2" }, [
+                  _vm._v(
+                    "\n                    " +
+                      _vm._s(note.thenote) +
+                      "\n                "
+                  )
+                ])
               ])
             ])
-          ])
-        ],
-        1
-      )
-    }),
-    0
+          ],
+          1
+        )
+      })
+    ],
+    2
   )
 }
 var staticRenderFns = [
@@ -62463,6 +62706,7 @@ Vue.component('errorlist', __webpack_require__(/*! ./components/errorlist.vue */
 Vue.component('credential-form-modal', __webpack_require__(/*! ./components/credential-form-modal.vue */ "./resources/js/components/credential-form-modal.vue")["default"]);
 Vue.component('autocomplete-custom-dropdown', __webpack_require__(/*! ./components/autocomplete-custom-dropdown.vue */ "./resources/js/components/autocomplete-custom-dropdown.vue")["default"]);
 Vue.component('credential-list', __webpack_require__(/*! ./components/credential-list.vue */ "./resources/js/components/credential-list.vue")["default"]);
+Vue.component('note-form-modal', __webpack_require__(/*! ./components/note-form-modal.vue */ "./resources/js/components/note-form-modal.vue")["default"]);
 /**
  * Next, we will create a fresh Vue application instance and attach it to
  * the page. Then, you may begin adding components to this application
@@ -62529,6 +62773,7 @@ window.Pusher = __webpack_require__(/*! pusher-js */ "./node_modules/pusher-js/d
 window.Echo = new laravel_echo__WEBPACK_IMPORTED_MODULE_0__["default"]({
   broadcaster: 'pusher',
   key: "upccrt",
+  authEndpoint: '/broadcasting/auth',
   wsHost: window.location.hostname,
   wsPort: 6001,
   disableStats: true
@@ -63070,6 +63315,75 @@ __webpack_require__.r(__webpack_exports__);
 
 
 
+/***/ }),
+
+/***/ "./resources/js/components/note-form-modal.vue":
+/*!*****************************************************!*\
+  !*** ./resources/js/components/note-form-modal.vue ***!
+  \*****************************************************/
+/*! exports provided: default */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var _note_form_modal_vue_vue_type_template_id_0435c624___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./note-form-modal.vue?vue&type=template&id=0435c624& */ "./resources/js/components/note-form-modal.vue?vue&type=template&id=0435c624&");
+/* harmony import */ var _note_form_modal_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./note-form-modal.vue?vue&type=script&lang=js& */ "./resources/js/components/note-form-modal.vue?vue&type=script&lang=js&");
+/* empty/unused harmony star reexport *//* harmony import */ var _node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js */ "./node_modules/vue-loader/lib/runtime/componentNormalizer.js");
+
+
+
+
+
+/* normalize component */
+
+var component = Object(_node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__["default"])(
+  _note_form_modal_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__["default"],
+  _note_form_modal_vue_vue_type_template_id_0435c624___WEBPACK_IMPORTED_MODULE_0__["render"],
+  _note_form_modal_vue_vue_type_template_id_0435c624___WEBPACK_IMPORTED_MODULE_0__["staticRenderFns"],
+  false,
+  null,
+  null,
+  null
+  
+)
+
+/* hot reload */
+if (false) { var api; }
+component.options.__file = "resources/js/components/note-form-modal.vue"
+/* harmony default export */ __webpack_exports__["default"] = (component.exports);
+
+/***/ }),
+
+/***/ "./resources/js/components/note-form-modal.vue?vue&type=script&lang=js&":
+/*!******************************************************************************!*\
+  !*** ./resources/js/components/note-form-modal.vue?vue&type=script&lang=js& ***!
+  \******************************************************************************/
+/*! exports provided: default */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var _node_modules_babel_loader_lib_index_js_ref_4_0_node_modules_vue_loader_lib_index_js_vue_loader_options_note_form_modal_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/babel-loader/lib??ref--4-0!../../../node_modules/vue-loader/lib??vue-loader-options!./note-form-modal.vue?vue&type=script&lang=js& */ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/note-form-modal.vue?vue&type=script&lang=js&");
+/* empty/unused harmony star reexport */ /* harmony default export */ __webpack_exports__["default"] = (_node_modules_babel_loader_lib_index_js_ref_4_0_node_modules_vue_loader_lib_index_js_vue_loader_options_note_form_modal_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__["default"]); 
+
+/***/ }),
+
+/***/ "./resources/js/components/note-form-modal.vue?vue&type=template&id=0435c624&":
+/*!************************************************************************************!*\
+  !*** ./resources/js/components/note-form-modal.vue?vue&type=template&id=0435c624& ***!
+  \************************************************************************************/
+/*! exports provided: render, staticRenderFns */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_note_form_modal_vue_vue_type_template_id_0435c624___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!../../../node_modules/vue-loader/lib??vue-loader-options!./note-form-modal.vue?vue&type=template&id=0435c624& */ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/note-form-modal.vue?vue&type=template&id=0435c624&");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "render", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_note_form_modal_vue_vue_type_template_id_0435c624___WEBPACK_IMPORTED_MODULE_0__["render"]; });
+
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "staticRenderFns", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_note_form_modal_vue_vue_type_template_id_0435c624___WEBPACK_IMPORTED_MODULE_0__["staticRenderFns"]; });
+
+
+
 /***/ }),
 
 /***/ "./resources/js/components/notes.vue":

+ 1 - 0
resources/js/app.js

@@ -33,6 +33,7 @@ Vue.component('errorlist', require('./components/errorlist.vue').default);
 Vue.component('credential-form-modal', require('./components/credential-form-modal.vue').default);
 Vue.component('autocomplete-custom-dropdown', require('./components/autocomplete-custom-dropdown.vue').default);
 Vue.component('credential-list', require('./components/credential-list.vue').default);
+Vue.component('note-form-modal', require('./components/note-form-modal.vue').default);
 
 /**
  * Next, we will create a fresh Vue application instance and attach it to

+ 1 - 0
resources/js/bootstrap.js

@@ -36,6 +36,7 @@ window.Pusher = require('pusher-js');
 window.Echo = new Echo({
     broadcaster: 'pusher',
     key: process.env.MIX_PUSHER_APP_KEY,
+    authEndpoint: '/broadcasting/auth',
     wsHost: window.location.hostname,
     wsPort: 6001,
     disableStats: true,

+ 2 - 2
resources/js/components/assetinfo.vue

@@ -64,9 +64,9 @@ export default {
         }
     },
     mounted() {
-        Echo.channel('assets')
+        Echo.channel('asset.'+this.data.pcid)
                 .listen('AssetUpdated', (e) => {
-                this.data = JSON.parse(e.data);
+                this.data = e.data;
                 this.pcextra = JSON.parse(e.pcextra);
             });
     },

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

@@ -39,5 +39,41 @@ export default {
             return list
         }
     },
+    methods: {
+        deleteCred: function(index) {
+            this.credentials.splice(index, 1);
+        }
+    },
+    mounted () {
+        if (this.pcid) {
+            Echo.channel('credlist.pcid.'+this.pcid)
+                .listen('CredentialDeleted', (e) => {
+                    let deletedCred = e.credential
+                    let index = this.credentials.findIndex((credential) => {
+                        return credential.credid === deletedCred['credid']
+                    })
+                    console.log(index)
+                    $('#credential'+deletedCred['credid']+'deleteModal').modal('hide');
+                    this.deleteCred(index);
+                })
+                .listen('CredentialAdded', (e) => {
+                    this.credentials.unshift(e.credential)
+                })
+        }
+        if (this.groupid) {
+            Echo.channel('credlist.groupid.'+this.groupid)
+                .listen('CredentialDeleted', (e) => {
+                    let deletedCred = e.credential
+                    let index = this.credentials.findIndex((credential) => {
+                        return credential.groupid === deletedCred['groupid']
+                    })
+                    $('#credential'+deletedCred['credid']+'deleteModal').modal('hide');
+                    this.deleteCred(index);
+                })
+                .listen('CredentialAdded', (e) => {
+                    this.credentials.unshift(e.credential)
+                })
+        }
+    }
 }
 </script>

+ 23 - 17
resources/js/components/credential.vue

@@ -1,6 +1,18 @@
 <template>
 <div class="bg-lightgray m-1 p-2 border rounded container-fluid">
     <credential-form-modal :descriptions="creddescList" :modal-id="'credential'+this.data.credid+'editModal'" :populateWith="this.data"></credential-form-modal>
+    <modal :id="'credential'+this.data.credid+'deleteModal'" tabindex="-1">
+        <h5 slot="header" class="modal-title" :id="'credential'+this.data.credid+'deleteModalLabel'">
+            Delete Credential
+        </h5>
+        <div slot="body">
+            Are you sure?
+        </div>
+        <div slot="footer">
+            <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
+            <button type="button" class="btn btn-danger" @click=deleteCredential()>Confirm</button>
+        </div>
+    </modal>
     <div class="row no-gutters">
         <div class="h5 col-3 text-left">{{this.data.creddesc}}</div>
         <div class="col-9 text-right">{{this.data.creddate}}</div>
@@ -24,7 +36,7 @@
         </div>
         <div class="btn-group col-lg-2 align-self-end w-25 w-lg-auto" role="group" aria-label="Edit and Delete">
             <button type="button" class="btn btn-sm btn-secondary p-lg-1" data-toggle="modal" :data-target="'#credential'+this.data.credid+'editModal'"><i class="fas fa-fw fa-edit"></i></button>
-            <button type="button" class="btn btn-sm btn-danger p-lg-1"><i class="fas fa-fw fa-trash-alt"></i></button>
+            <button type="button" class="btn btn-sm btn-danger p-lg-1" data-toggle="modal" :data-target="'#credential'+this.data.credid+'deleteModal'"><i class="fas fa-fw fa-trash-alt"></i></button>
         </div>
     </div>
 </div>
@@ -39,24 +51,18 @@ export default {
         }
     },
     mounted() {
-        Echo.channel('credentials')
+        Echo.channel('credential.'+this.data.credid)
             .listen('CredentialUpdated', (e) => {
-                // This part could potentially use a refactor.
-                // Probably needs a credential list component to listen for this
-                // even and update the corresponding credential. Currently every
-                // credential on the page receives this event and checks whether it was intended
-                // for its credential or not. I would imagine this could cause a problem
-                // on the group page, which will potentially have a lot more credentials from
-                // various assets. Better solution may be to have a credentials list component
-                // That listens for credential update events and updates the appropriate credential.
-                // There would still be multiples of those on the group credentials page, but an
-                // order of magnitude less of those than of individual credentials.
-                // It also may not be a big deal performance wise to do it like this, not sure.
-                let eData = JSON.parse(e.data);
-                if (this.data.credid === eData.credid) {
-                    this.data = eData;
-                }
+                this.data = e.credential;
             });
+    },
+    methods: {
+        deleteCredential() {
+            axios.delete('/api/credentials/' + this.data.credid, this.data)
+                .then(response => {
+                    $('#credential'+this.data.credid+'deleteModal').modal('hide');
+                }).catch(error => { console.error(error) })
+        }
     }
 }
 </script>

+ 74 - 0
resources/js/components/note-form-modal.vue

@@ -0,0 +1,74 @@
+<template>
+    <modal :id="modalId" tabindex="-1" role="dialog" :aria-labelledby="modalId+'Label'">
+                <h5 slot="header" class="modal-title" :id="modalId+'Label'">
+                    Edit Note
+                </h5>
+                <div slot="body">
+                    <div class="form-group">
+                        <label for="content">Content</label>
+                        <textarea :name="'content'+note.noteid" :id="'content'+note.noteid" class="form-control" v-model="note.thenote"></textarea>
+                    </div>
+                </div>
+                <div slot="footer">
+                    <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
+                    <button type="button" class="btn btn-primary" @click="updateNote(note)">Save</button>
+                </div>
+            </modal>
+</template>
+<script>
+export default {
+    props: {
+        populateWith: {
+            type: Object,
+        },
+        modalId: {
+            type: String,
+            require: true
+        },
+        noteType: {
+            type: Number
+        },
+        noteUser: {
+            type: String
+        },
+        woid: {
+            type: Number
+        }
+    },
+    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))
+        }
+    },
+    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()
+                    })
+            }
+        },
+        hideModal () {
+            $('#'+this.modalId).modal('hide')
+        }
+    }
+}
+</script>

+ 22 - 19
resources/js/components/notes.vue

@@ -1,22 +1,10 @@
 <template>
     <ul class="list-unstyled">
-        <li class="row no-gutters mb-2" v-bind:key="note.noteid" v-for="note in this.notes">
-            <modal :id="'note'+note.noteid+'editModal'" tabindex="-1" role="dialog" :aria-labelledby="'note'+note.noteid+'editModalLabel'">
-                <h5 slot="header" class="modal-title" :id="'note'+note.noteid+'editModalLabel'">
-                    Edit Note
-                </h5>
-                <div slot="body">
-                    <div class="form-group">
-                        <label for="content">Content</label>
-                        <textarea :name="'content'+note.noteid" :id="'content'+note.noteid" class="form-control" v-model="note.thenote"></textarea>
-                    </div>
-                </div>
-                <div slot="footer">
-                    <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
-                    <button type="button" class="btn btn-primary" @click="updateNote(note.noteid)">Save</button>
-                </div>
-            </modal>
-            <div class="col-md-1 d-flex flex-column mx-md-3">
+        <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>
+        <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="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">
@@ -41,10 +29,25 @@
 import dateMixin from '../mixins/dateMixin'
 export default {
     mixins:[dateMixin],
-    props: ['initialnotes', 'authusername'],
+    props: ['initialnotes', 'authusername', 'noteType', 'woid'],
     data () {
         return {
-            notes: this.initialnotes,
+            notes: Object.values(this.initialnotes),
+            currentOrder: 'order-first'
+        }
+    },
+    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'
+                } else {
+                    this.currentOrder = 'order-first'
+                }
+            }
+            return this.currentOrder
         }
     }
 }

+ 2 - 2
resources/js/components/woinfo.vue

@@ -38,9 +38,9 @@
             }
         },
         mounted() {
-            Echo.channel('work-orders')
+            Echo.channel('work-order.'+this.data.woid)
                 .listen('WorkOrderUpdated', (e) => {
-                    this.data = JSON.parse(e.data);
+                    this.data = e.data;
                 });
         }
     }

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

@@ -39,7 +39,7 @@
                         </div>
                         @endif
                         <div class="tab-pane" id="credentials" role="tabpanel" aria-labelledby="credentials-tab">
-                            <credential-list :credential-list="{{$workOrder->asset->credentials}}" :descriptions="{{App\CredDesc::all()}}" :pcid="{{$workOrder->asset->pcid}}"></credential-list>
+                            <credential-list :credential-list="{{$workOrder->asset->credentials->sortByDesc('creddate')->values()}}" :descriptions="{{App\CredDesc::all()}}" :pcid="{{$workOrder->asset->pcid}}"></credential-list>
                         </div>
                     </div>
                 </div>
@@ -81,7 +81,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}}"></notes>
+                    <notes :initialnotes="{{$workOrder->notes->where('notetype', '0')}}" authusername="{{Auth::user()->username}}" :note-type="0" :woid="{{$workOrder->woid}}"></notes>
                 </div>
             </div>
         </div>
@@ -91,7 +91,7 @@
             <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}}"></notes>
+                    <notes :initialnotes="{{$workOrder->notes->where('notetype', '1')}}" authusername="{{Auth::user()->username}}" :note-type="1" :woid="{{$workOrder->woid}}"></notes>
                 </div>
             </div>
         </div>

+ 4 - 0
routes/api.php

@@ -21,6 +21,9 @@ Route::middleware('auth:api')->group( function() {
     Route::get('/workorders/{workOrder}', 'Api\WorkOrdersController@show');
     Route::put('/workorders/{workOrder}', 'Api\WorkOrdersController@update');
 
+    Route::post('/workorders/notes', 'Api\WorkOrderNotesController@store');
+    Route::put('/workorders/notes/{workOrderNote}', 'Api\WorkOrderNotesController@update');
+
     Route::put('/assets/{asset}', 'Api\AssetsController@update');
 
     Route::get('/stores', 'Api\StoresController@index');
@@ -28,6 +31,7 @@ Route::middleware('auth:api')->group( function() {
 
     Route::post('/credentials', 'Api\CredentialsController@store');
     Route::put('/credentials/{credential}', 'Api\CredentialsController@update');
+    Route::delete('/credentials/{credential}', 'Api\CredentialsController@destroy');
 
     Route::get('credtypes', 'Api\CredDescController@index');