Browse Source

Upload files to 'public_html/scripts'

david.ortiz11 4 years ago
parent
commit
d29ef82d87
3 changed files with 1190 additions and 265 deletions
  1. 203
    0
      public_html/scripts/hazards.js
  2. 418
    265
      public_html/scripts/inventory.js
  3. 569
    0
      public_html/scripts/laboratory.js

+ 203
- 0
public_html/scripts/hazards.js View File

@@ -0,0 +1,203 @@
1
+/*  Authors         :   Carlos C. Corrada-Bravo
2
+                        David J. Ortiz-Rivera
3
+
4
+    Organization    :   Centro de Desarrollo y Consultoria Computacional
5
+    Project         :   OPASO Material Registry   
6
+    File            :   hazard.js
7
+    Description     :   Generate hazard menu/tables */
8
+
9
+/* global variables */
10
+var next = 0;
11
+
12
+/* fetch ghs codes */ 
13
+$(document).ready(fetch_ghs);
14
+
15
+/* set_listeners() - listen for events */
16
+function set_listeners(){
17
+    /* sort table */
18
+    $(".sort").click(function(){
19
+        sort_key = $(this).attr("value");
20
+
21
+        if(sort_key === "mat_name"){
22
+            $(".sort-material").show();
23
+            $(".sort-alt").hide();
24
+        }
25
+        else{
26
+            $(`.${sort_key}`).show();
27
+            $(".sort-material").hide();
28
+        }
29
+        full_sort(next,sort_key);
30
+    });
31
+
32
+    /* redirect to code page */
33
+    $(".ghs").click(function(){
34
+        let code = $(this).attr("value");
35
+        if(code){
36
+            window.location.href = `/hazards?ghs=${code}`;
37
+        }
38
+
39
+        /* display error */
40
+        else{
41
+            set_alert("error","GHS code not found")
42
+        }
43
+    });
44
+
45
+    /* download file */
46
+    $(".download-option").click(function(){
47
+        /* extract args */
48
+        $("html").addClass("wait");
49
+        let download_type = $(this).attr("value");
50
+
51
+        /* generate file */
52
+        $.post("/scripts/opaso",{query: 24,download_type: download_type,ghs: get_arg("ghs")},function(data){
53
+            // console.log(data);
54
+            /* extract response */
55
+            let response = JSON.parse(data);
56
+            let status = response["status"];
57
+
58
+            /* handle by status */
59
+            switch(status){
60
+                case "success":                 /* on success, generate table */
61
+                    var link=element_gen("a",{href: response["url"],download: response["file_name"]});
62
+                    link.click();
63
+                    break;
64
+                
65
+                case "expired":                 /* on expired, redirect to index */
66
+                    window.location.href = "/?error=session_expired";
67
+                    break;
68
+
69
+                default:                        /* on error, display message */
70
+                    /* display alert */
71
+                    set_alert(status,response["message"]);
72
+                    break;
73
+            }
74
+
75
+            $("html").removeClass("wait");
76
+        });
77
+    });
78
+}
79
+
80
+/* table_gen(ghs: object) - generate material table */
81
+function table_gen(ghs){
82
+    for(var g in ghs){
83
+        let tr = element_gen("tr",{id: g});
84
+        for(var field in ghs[g]){
85
+            switch(field){
86
+                case "material":                /* material, extract id */
87
+                    var link = element_gen("a",{class: "mat-link",text: ghs[g][field]["mat_name"],href: `materials?mat_id=${ghs[g][field]["mat_id"]}`,target: "_blank",rel: "noopener noreferrer"});
88
+                    var attrs = {value: "mat_name",mat_id: ghs[g][field]["mat_id"],childs: {link}};
89
+                    break;
90
+
91
+                case "manufacturer":            /* manufacturer, extract id */
92
+                    var attrs ={value: "man_name",man_id: ghs[g][field]["man_id"],text: ghs[g][field]["man_name"]};
93
+                    break;
94
+
95
+                case "laboratory":              /* laboratory, extract id */
96
+                    var link = element_gen("a",{class: "lab-link",text: ghs[g][field]["lab_room"],href: `laboratory?lab_id=${ghs[g][field]["lab_id"]}`,target: "_blank",rel: "noopener noreferrer"});
97
+                    var attrs = {value: "lab_room",lab_id: ghs[g][field]["lab_id"],childs: {link}};
98
+                    break;
99
+
100
+                case "sds":                     /* generate sds link */
101
+                    if(!ghs[g][field]){
102
+                        ghs[g][field] = "-";
103
+                    }
104
+                    var icon = element_gen("i",{class: "fas fa-link"});
105
+                    var link = element_gen("a",{href: decodeURI(ghs[g][field]),target: "_blank",rel: "noopener noreferrer",childs: {icon}});
106
+                    var attrs = {value: field,childs: {link}};
107
+                    break;
108
+
109
+                default:                        /* default */
110
+                    if(!ghs[g][field]){
111
+                        ghs[g][field] = "-";
112
+                    }
113
+                    var attrs = {value: field,text: ghs[g][field]};
114
+                    break;
115
+            }
116
+            
117
+            var td = element_gen("td",attrs);
118
+            tr.append(td);
119
+        }
120
+
121
+        $("tbody").append(tr);
122
+    }
123
+
124
+    $(".processing").hide();
125
+    setTimeout(function(){
126
+        set_listeners();
127
+        $(".hazard").show();
128
+        $(".main-wrapper").show();
129
+    },250);
130
+}
131
+
132
+/*  fetch_ghs() - fetch ghs codes */
133
+function fetch_ghs(){
134
+    /* verify if ghs is set */
135
+    var ghs = get_arg("ghs");
136
+    if(ghs){
137
+        /* fetch materials */
138
+        $.post("/scripts/opaso",{query: 26,ghs: ghs},function(data){
139
+            // console.log(data);
140
+            /* extract response */
141
+            let response = JSON.parse(data);
142
+            let status = response["status"];
143
+
144
+            /* handle by status */
145
+            switch(status){
146
+                case "success":                 /* on success, generate table */
147
+                    $(".title").text(ghs);
148
+                    $(".description").text(response["description"]);
149
+                    table_gen(response["ghs"]);
150
+                    next = Object.keys(response["ghs"]).length;
151
+                    $(".table-total").text(`Total: ${next}`);
152
+                    break;
153
+
154
+                case "expired":                  /* on expired, redirect to index */
155
+                    window.location.href = "/?error=session_expired";
156
+                    break;
157
+
158
+                default:                        /* on error, display message */
159
+                    set_alert(status,response["message"]);
160
+                    break;
161
+            }
162
+        });
163
+
164
+    }
165
+
166
+    /* fetch all codes */
167
+    else{
168
+        $.post("/scripts/opaso",{query: 25},function(data){
169
+            // console.log(data);
170
+            /* extract response */
171
+            let response = JSON.parse(data);
172
+            let status = response["status"];
173
+
174
+            /* handle by status */
175
+            switch(status){
176
+                case "success":                 /* on success, generate ghs menu */
177
+                    ghs = response["ghs"];
178
+                    for(var code in ghs){
179
+                        var gc = element_gen("span",{class: "ghs-code",text: code});
180
+                        var w = element_gen("div",{class: "ghs",value: code,childs: {gc}});
181
+                        var m = element_gen("div",{class: "ghs-wrapper col-lg-1",value: code,childs: {w}});
182
+                        $(".ghs-codes").append(m);
183
+                    }
184
+
185
+                    $(".processing").hide();
186
+                    setTimeout(function(){
187
+                        set_listeners();
188
+                        $(".ghs-codes").show();
189
+                        $(".main-wrapper").show();
190
+                    },250);
191
+                    break;
192
+
193
+                case "expired":                  /* on expired, redirect to index */
194
+                    window.location.href = "/?error=session_expired";
195
+                    break;
196
+
197
+                default:                        /* on error, display message */
198
+                    set_alert(status,response["message"]);
199
+                    break;
200
+            }
201
+        });
202
+    }
203
+}

+ 418
- 265
public_html/scripts/inventory.js View File

@@ -4,309 +4,462 @@
4 4
     Organization    :   Centro de Desarrollo y Consultoria Computacional
5 5
     Project         :   OPASO Material Registry   
6 6
     File            :   inventory.js
7
-    Description     :   Fetch lab inventory */
8
-
9
-/* globals */ 
10
-var editing,form_is_active,inventory,new_inventory,text;
11
-
12
-/* get_inventory() - fetch lab inventory from server */ 
13
-function get_inventory(){
14
-    var laboratory = get_arg("lab");    /* get lab id from url */
15
-    $.post("/scripts/opaso.php",{query: 4,laboratory: laboratory},function(data){
16
-        console.log(data);
17
-        try{    
18
-            var response = JSON.parse(data);    /* parse response as json */ 
19
-            switch(response["status"]){
20
-                case "success":                 /* on success, generate table body */ 
21
-                    /* update inventory header */ 
22
-                    $(".header").text(response["laboratory"]);
23
-                    /* extract inventory from response and generate table body */ 
24
-                    inventory = response["inventory"];
25
-                    var tbody = create_element("tbody","inventory-body");
26
-                    var row_index = 1;
27
-                    for(var row in inventory){
28
-                        /* generate option buttons */ 
29
-                        var edit = create_button("Edit","fas fa-pen","btn options","edit");
30
-                        var copy = create_button("Copy","fas fa-copy","btn options","copy");
31
-                        var remove = create_button("Remove","fas fa-minus-square","btn options","remove");
32
-                        /* append buttons to cell */ 
33
-                        var options = create_element("td","options-cell");
34
-                        options.append(edit,copy,remove);
35
-                        /* generate table row */
36
-                        var index = create_element("td","index",row_index);
37
-                        var tr = create_element("tr","inventory-row");
38
-                        tr.setAttribute("id",row);
39
-                        tr.append(options,index);
40
-                        /* generate inventory columns */ 
41
-                        for(var col in inventory[row]){
42
-                            var cell = create_element("td","inventory-cell",inventory[row][col]);
43
-                            cell.setAttribute("val",col);   /* identify cell field */
44
-                            tr.append(cell);
45
-                        }
46
-                        tbody.append(tr);
47
-                        row_index += 1;
48
-                    }
49
-                    $(".table").append(tbody);
50
-                    break;
51
-                case "error":                   /* on error, display message */ 
52
-                    display_error(response["error"]);
53
-                    break;
54
-                default:                        /* undefined status */
55
-                    display_error("Undefined status.");
56
-                    break;
7
+    Description     :   Generate inventory table */
57 8
 
58
-            }
59
-            set_listeners();                    /* listen for cell/button clicks */
60
-            loading_screen(false);              /* hide loading screen */
61
-        }
62
-        catch(error){
63
-            console.log(error.message);
64
-            display_error(error.message);
65
-        }
66
-    });
9
+/* save inventory data globally */ 
10
+var editing,inventory,form,text,timeout,i,next;
11
+var sort_key = "material";
12
+
13
+/* fetch inventory */
14
+$(document).ready(function(){
15
+    link_gen();
16
+    fetch_inventory();
17
+});
18
+
19
+/* display_form() - animate form  */
20
+function display_form(){
21
+    $(".form-shader").addClass("fade-in");
22
+    $(".edit-form").addClass("slide-down");
67 23
 }
68
-/* set_listeners() - set listeners for cell/button clicks */ 
24
+
25
+/* hide_form() - hide form  */
26
+function hide_form(){
27
+    $(".edit-form").removeClass("slide-down");
28
+    setTimeout(function(){
29
+        $(".form-shader").removeClass("fade-in");
30
+    },250);
31
+}
32
+
33
+/* set_listeners() - listen for events */ 
69 34
 function set_listeners(){
70
-    /* set listener for option buttons */ 
71
-    $(".options").click(function(){
35
+    /* option queries */ 
36
+    $(".action").click(function(){
72 37
         /* extract args */ 
73 38
         var option = $(this).attr("id");
74
-        var row = $(this).parent().parent().attr("id"); /* row id */
39
+        i = $(this).parent().parent().attr("id");
40
+
41
+        /* handle by option */
75 42
         switch(option){
76
-            case "edit":        /* edit inventory row (fallthrough) */
77
-            case "copy":        /* copy inventory row */
78
-                $(".form-header").text(option + " entry");
79
-                set_form(row);  /* populate form */
80
-                $(".submit").attr("id",option);
81
-                $(".submit").attr("val",row);
82
-                $(".close-form").attr("val",row);
43
+            case "edit":        /* edit row, populate row */
44
+                set_form();
83 45
                 break;
84
-            case "remove":       /* delete row form inventory */
85
-                /* extract arg */ 
86
-                var laboratory = get_arg("lab");
87
-                $.post("/scripts/opaso.php",{query: 8,laboratory: laboratory,eid: row},function(data){  /* send row to be deleted */
88
-                    // console.log(data);
89
-                    try{    
90
-                        var response = JSON.parse(data);    /* parse response as json */ 
91
-                        switch(response["status"]){
92
-                            case "success":                 /* on success, generate table body */ 
93
-                                break;
94
-                            case "error":                   /* on error, display message */ 
95
-                                display_error(response["error"]);
96
-                                break;
97
-                            default:                        /* undefined status */
98
-                                display_error("Undefined status.");
99
-                                break;
100
-                        }
101
-                    }
102
-                    catch(error){
103
-                        display_error(error.message);
104
-                    }
105
-                });
46
+
47
+            case "remove":      /* delete row, confirm */
48
+                set_confirm("Do you wish to delete entry from inventory?",option);
106 49
                 break;
107
-            default:                        /* undefined option */
108
-                display_error("Undefined option.");
50
+
51
+            default:            /* undefined, display alert */
52
+                set_alert("error","Invalid option")
109 53
                 break;
110 54
         }
111 55
     });
56
+
57
+    /* submit query */
58
+    $("#yes").click(function(){
59
+        hide_confirm();
60
+        $.post("/scripts/opaso",{query: 8,lab_id: get_arg("lab_id"),data: JSON.stringify(inventory[i])},function(data){
61
+            // console.log(data);
62
+            /* extract response */
63
+            let response = JSON.parse(data);
64
+            let status = response["status"];
65
+            /* handle by status */
66
+            switch(status){
67
+                 case "expired":                  /* on expired, redirect to index */
68
+                    window.location.href = "/?error=session_expired";
69
+                    break;
70
+
71
+                case "success":                 /* on success, generate table body */
72
+                    $(`#${i}`).remove();
73
+                    next -= 1;
74
+                    $(".table-total").text(`Total: ${next}`);
75
+
76
+                default:                            /* on success/error, display message */
77
+                    set_alert(status,response["message"]);
78
+                    break;
79
+            }
80
+        });
81
+    });
82
+
83
+    /* cancel query */
84
+    $("#no").click(hide_confirm);
85
+
112 86
     /* set listener for form submit button */
113 87
     $(".submit").click(function(){
114
-        /* extract args */ 
115
-        var option = $(this).attr("id");
116
-        var row = $(this).attr("val"); /* row id */
117
-        var laboratory = get_arg("lab");
118
-        /* set query for option */
119
-        var query = null;
120
-        switch(option){
121
-            case "edit":        /* edit row */
122
-                query = 6;
123
-                break;
124
-            case "copy":        /* copy row */
125
-                query = 7;
126
-                break;
127
-            default:        /* undefined option */ 
128
-                display_error("Undefined option.");
129
-                break;
130
-        }
131
-        /* get and validate form fields */ 
132
-        var form = get_form(row);
133
-        if(valid(form) && form_is_active){
134
-            reset_form();   /* reset form */ 
135
-            /* submit query for row */
136
-            console.log(JSON.stringify(form));
137
-            $.post("/scripts/opaso.php",{query: query,laboratory: laboratory,eid: row, fields: JSON.stringify(form)},function(data){
138
-                console.log(data);
139
-                /* parse response as json and display result of query */ 
140
-                try{    
141
-                    var response = JSON.parse(data);    /* parse response as json */ 
142
-                    switch(response["status"]){
143
-                        case "success":                 /* on success, generate table body */ 
144
-                            break;
145
-                        case "error":                   /* on error, display message */ 
146
-                            display_error(response["error"]);
147
-                            break;
148
-                        default:                        /* undefined status */
149
-                            display_error("Undefined status.");
150
-                            break;
151
-                    }
152
-                }
153
-                /* handle error */ 
154
-                catch(error){
155
-                    display_error(error.message);
88
+        if(get_form()){
89
+            /* submit query */
90
+            hide_form();
91
+            $.post("/scripts/opaso",{query: 6,lab_id: get_arg("lab_id"),mat_id: inventory[i]["material"]["mat_id"],man_id: inventory[i]["manufacturer"]["man_id"],uom: inventory[i]["uom"],capacity: inventory[i]["capacity"],data: JSON.stringify(form)},function(data){
92
+                // console.log(data);
93
+                /* extract response */
94
+                let response = JSON.parse(data);
95
+                let status = response["status"];
96
+
97
+                /* handle by status */
98
+                switch(status){
99
+                    case "expired":                     /* on expired, redirect to index */
100
+                        window.location.href = "/?error=session_expired";
101
+                        break;
102
+
103
+                    case "success":                     /* on success, update inventory */
104
+                    // console.log(inventory[i],form);
105
+                        for(var field in form){
106
+                            if(field === "mat_name"){
107
+                                inventory[i]["material"][field] = form[field];
108
+                            }
109
+
110
+                            else if(field === "man_name"){
111
+                                inventory[i]["manufacturer"][field] = form[field];
112
+                            }
113
+
114
+                            else{
115
+                                inventory[i][field] = form[field];
116
+                            }
117
+
118
+                            if(field === "sds"){
119
+                                $(`#${i}`).find(`td[value=${field}]`).find("span").attr("href",form[field]);
120
+                            }
121
+                            else{
122
+                                $(`#${i}`).find(`td[value=${field}]`).text(form[field]);   
123
+                            }
124
+                        }
125
+                        // console.log(inventory[i]);
126
+
127
+                    default:                            /* on success/error, display message */
128
+                        set_alert(status,response["message"]);
129
+                        break;
156 130
                 }
157 131
             });
158 132
         }
159
-        /* non-valid form, display warning */ 
160
-        else{
161
-            $(".fields-required").show();
133
+        /* invalid form, display warning */ 
134
+        else{            
135
+            set_alert("error","All fields required");
162 136
         }
163 137
     });
164
-    /* set listener for form close buttons */
165
-    $(".close-form").click(function(){
166
-        reset_form();   /* reset form */
167
-    });
168
-    /* set listener for double clicks on cells */ 
169
-    $(".inventory-cell").dblclick(function(){
170
-        /* generate text area if user isn't editing */ 
138
+
139
+    /* edit cell */ 
140
+    $(".entry-cell").dblclick(function(){
141
+        /* verify if user is editing */ 
171 142
         if(!editing){
172
-            $(this).height($(this).height());   /* avoid cell from collapsing */ 
173
-            $(this).css("padding","0px");       /* remove padding */
174
-            /* generate textarea with text from clicked cell */
175
-            text = $(this).text();
176
-            var textarea = create_element("textarea","edit-text",text);
177
-            textarea.style.width = $(this).width() + "px";
178
-            textarea.style.height = $(this).height() + "px";
179
-            /* insert text area into DOM */ 
143
+            $(this).height($(this).height());
144
+            $(this).css("padding","0px");
145
+
146
+            if($(this).attr("value") === "sds"){
147
+                text = $(this).find("span").attr("href");
148
+            }
149
+            else{
150
+                text = $(this).text();
151
+            }
152
+
153
+            i = $(this).parent().attr("id");
154
+            var textarea = element_gen("textarea",{class: "edit",text: text});
180 155
             $(this).html(textarea);
181
-            editing = true;     /* user is editing */ 
156
+            editing = true;
182 157
         }
183 158
     });
184
-    /* set listener for clicks on body */ 
185
-    $("body").click(function(element){
186
-        /* extract class of clicked element */ 
187
-        var target = $(element.target).attr("class");
188
-        if(editing && target != "edit-text"){
189
-            /* extract text from textarea and field and row id */ 
190
-            var delta_text = $(".edit-text").val();
191
-            var field = $(".edit-text").parent().val();
192
-            var row = $(".edit-text").parent().parent().attr("id");
193
-            /* reset styling and insert text to cell */ 
194
-            $(".edit-text").parent().removeAttr("style");
195
-            $(".edit-text").parent().html(delta_text);
196
-            editing = false;    /* deactivate editing */
197
-            /* submit row changes to inventory */
198
-            if(text != delta_text){
199
-                /* extract arg */
200
-                var laboratory = get_arg("lab");
201
-                /* send new field text */ 
202
-                $.post("/scripts/opaso.php",{query: 5,laboratory: laboratory,eid: row,text: delta_text, field: field},function(data){
203
-                    console.log(data);
204
-                    try{    
205
-                        var response = JSON.parse(data);    /* parse response as json */ 
206
-                        switch(response["status"]){
207
-                            case "success":                 /* on success, generate table body */ 
208
-                                break;
209
-                            case "error":                   /* on error, display message */ 
210
-                                display_error(response["error"]);
211
-                                break;
212
-                            default:                        /* undefined status */
213
-                                display_error("Undefined status.");
214
-                                break;
215
-                        }
216
-                    }
217
-                    catch(error){
218
-                        display_error(error.message);
219
-                    }
220
-                });
221
-            }
159
+
160
+    /* submit cell edit */ 
161
+    $("body").click(function(event){ 
162
+        var t = $(event.target).attr("class");
163
+        if(editing && t !== "edit"){
164
+            edit_field();
222 165
         }
223
-        /* reset form on exit */
224
-        else if(form_is_active && target == "form-window"){
225
-            reset_form();   /* reset form */
166
+    });
167
+
168
+    /* submit cell edit */ 
169
+    $(document).on("keypress",function(event){
170
+        if(event.which == 13 && editing){
171
+            event.preventDefault();
172
+            edit_field();
226 173
         }
227 174
     });
228
-    /* set listener for dropdown menu */ 
229
-    $( ".navbar-wrapper" ).hover(function(){},   /* on hover in, do nothing */ 
230
-        /* on hover out, hide dropdown menu */ 
231
-        function(){
232
-            /* check if menu is visible */ 
233
-            if($(".dropdown-menu").is(':visible')){
234
-                $(".dropdown-menu").removeClass("show");    /* hide menu */
235
-            }
175
+
176
+    /* hide form */ 
177
+    $(".close-form").click(function(e){
178
+        if(e.target === e.currentTarget){
179
+            hide_form();
236 180
         }
237
-    );
238
-}
239
-/* reset_form() - reset form and its styling */
240
-function reset_form(){
241
-    /* reset styling (label) */ 
242
-    $(".required-field").each(function(){
243
-        $(this).removeClass("required-field");
244
-        $(this).text($(this).text().replace("*",""));
245 181
     });
246
-    /* reset styling (input) */ 
247
-    $(".empty-field").each(function(){
248
-        $(this).removeClass("empty-field");
182
+
183
+    /* hide confirm alert */
184
+    $(".hide-confirm").click(function(e){
185
+        if(e.target === e.currentTarget){
186
+            hide_confirm();
187
+        }
249 188
     });
250
-    /* hide from */ 
251
-    $(".form-window").hide();
252
-    $(".fields-required").hide();
253
-    form_is_active = false;   /* deactivate form */
254 189
 }
255
-/* valid(form: dictionary) - check for invalid form entries */
256
-function valid(form){
257
-    var valid = true;
258
-    for(var field in form){
259
-        /* highlight empty fields */ 
260
-        if(!form[field]){
261
-            /* if not currently highlighted */
262
-            if($("[for=" + field + "]").attr("class") != "required-field"){
263
-                /* highlight label */ 
264
-                $("[for=" + field + "]").text($("[for=" + field + "]").text() + "*");
265
-                $("[for=" + field + "]").addClass("required-field");
266
-                /* highlight field */ 
267
-                $("[name=" + field + "]").addClass("empty-field");
268
-            }
269
-            valid = false;
190
+
191
+/* edit_field() - update material field */ 
192
+function edit_field(){
193
+    /* extract text */ 
194
+    var delta = $(".edit").val();
195
+    var field = $(".edit").parent().attr("value");
196
+
197
+    if(text != delta){
198
+
199
+        // console.log(inventory,i,inventory[i]);
200
+
201
+        let data = {mat_id: inventory[i]["material"]["mat_id"],man_id: inventory[i]["manufacturer"]["man_id"],capacity: inventory[i]["capacity"], uom: inventory[i]["uom"]};
202
+        
203
+        if(field === "capacity"){
204
+            data["prev_capacity"] = text;
205
+            data["new_capacity"] = delta;
206
+            total = inventory[i]["total"];
207
+            data["quantity"] = Math.ceil(total/delta);
208
+        }
209
+
210
+        else if(field === "total"){
211
+            data["total"] = delta;
212
+            data["quantity"] = Math.ceil(delta/data["capacity"]);
213
+        }
214
+
215
+        else if(field === "quantity"){
216
+            data["quantity"] = delta;
217
+            data["total"] = delta * data["capacity"];
218
+        }
219
+
220
+        else if(field === "uom"){
221
+            data["prev_uom"] = text;
222
+            data["new_uom"] = delta;
270 223
         }
271
-        /* remove styling for non empty fields */ 
224
+
272 225
         else{
273
-            /* if currently highlighted... */
274
-            if($("[for=" + field + "]").attr("class") == "required-field"){
275
-                /* reset styling for label */
276
-                $("[for=" + field + "]").text($("[for=" + field + "]").text().replace("*",""));
277
-                $("[for=" + field + "]").removeClass("required-field");
278
-                /* reset styling for field */ 
279
-                $("[name=" + field + "]").removeClass("empty-field");
226
+            data[field] = delta;
227
+        }
228
+        
229
+        /* update field */
230
+        $.post("/scripts/opaso",{query: 5,lab_id: get_arg("lab_id"),data: JSON.stringify(data),field: field},function(data){
231
+            // console.log(data);
232
+            /* extract response */
233
+            let response = JSON.parse(data);
234
+            let status = response["status"];
235
+            /* handle by status */
236
+            switch(status){
237
+                case "expired":                  /* on expired, redirect to index */
238
+                    window.location.href = "/?error=session_expired";
239
+                    break;
240
+
241
+                case "success":                 /* on success, update entry */
242
+                    if(field === "mat_name"){
243
+                        inventory[i]["material"][field] = delta;
244
+                    }
245
+                    else if(field === "man_name"){
246
+                        inventory[i]["manufacturer"][field] = delta;
247
+                    }
248
+                    else if(field === "total"){
249
+                        inventory[i]["quantity"] = Math.ceil(delta/inventory[i]["capacity"]);
250
+                        $(`#${i}`).find("td[value=quantity]").text(inventory[i]["quantity"]);   
251
+
252
+                    }
253
+
254
+                    else if(field === "capacity"){
255
+                        total = inventory[i]["total"];
256
+                        inventory[i]["quantity"] = Math.ceil(total/delta);
257
+                        $(`#${i}`).find("td[value=quantity]").text(inventory[i]["quantity"]);   
258
+                    }
259
+
260
+                    else if(field === "quantity"){
261
+                        inventory[i]["total"] = delta * inventory[i]["capacity"];
262
+                        $(`#${i}`).find("td[value=total]").text(inventory[i]["total"]);   
263
+                    }
264
+
265
+                    if(field === "sds"){
266
+                        var icon = element_gen("i",{class: "fas fa-link"});
267
+                        var link = element_gen("span",{class: "sds",href: decodeURI(delta),target: "_blank",rel: "noopener noreferrer",childs: {icon}});
268
+                        $(".edit").parent().html(link);
269
+                    }
270
+
271
+                    else{
272
+                        $(".edit").parent().html(delta);   
273
+                    }
274
+
275
+                    if(field !== "mat_name" && field !== "man_name"){
276
+                        inventory[i][field] = delta;
277
+                    }
278
+
279
+                    $(".edit").parent().removeAttr("style");
280
+
281
+
282
+
283
+                default:                        /* on error, display message */
284
+                    if(field === "sds"){
285
+                        var icon = element_gen("i",{class: "fas fa-link"});
286
+                        var link = element_gen("span",{class: "sds",href: decodeURI(text),target: "_blank",rel: "noopener noreferrer",childs: {icon}});
287
+                        $(".edit").parent().html(link);
288
+                    }
289
+
290
+                    else{
291
+                        $(".edit").parent().html(text);   
292
+                    }
293
+
294
+                    /* reset styling */
295
+                    $(".edit").parent().removeAttr("style");
296
+                    set_alert(status,response["message"]);
297
+                    break;
280 298
             }
299
+        });
300
+    }
301
+    else{
302
+        if(field === "sds"){
303
+            var icon = element_gen("i",{class: "fas fa-link"});
304
+            var link = element_gen("span",{class: "sds",href: decodeURI(text),target: "_blank",rel: "noopener noreferrer",childs: {icon}});
305
+            $(".edit").parent().html(link);
281 306
         }
307
+        else{
308
+            $(".edit").parent().html(text); 
309
+            $(".edit").parent().removeAttr("style");  
310
+        }  
282 311
     }
312
+
313
+    editing = false;
314
+}
315
+
316
+/* get_form(row: string) - get form data from row */
317
+function get_form(){
318
+    form = {};
319
+    var valid = true;
320
+
321
+    $(".material-input").each(function(){
322
+        var id = $(this).attr("id");
323
+        // var s = `.${id}`;
324
+        var field = $(this).attr("name");
325
+
326
+        /* highlight */
327
+        if(!is_valid($(this).val())){
328
+            // $(s).show();
329
+            valid = false;
330
+            $(this).addClass("invalid");
331
+        }
332
+
333
+        /* unhighlight */
334
+        else{
335
+            // $(s).hide();
336
+            $(this).removeClass("invalid");
337
+        }
338
+
339
+        form[field] = $(this).val();
340
+    });
341
+
283 342
     return valid; 
284 343
 }
285
-/* get_form(row: string) - get form data */
286
-function get_form(row){
287
-    var form = {};
288
-    for(var col in inventory[row]){
289
-        form[col] = $("[name=" + col + "]").val();
344
+/* set_form() - populate form using inventory data */
345
+function set_form(){
346
+    for(var field in inventory[i]){
347
+        if(field === "material"){
348
+            var s = "mat_name";
349
+            var val = inventory[i][field][s];
350
+        }
351
+
352
+        else if(field === "manufacturer"){
353
+            var s = "man_name";
354
+            var val = inventory[i][field][s]
355
+        }
356
+
357
+        else{
358
+            var s = field;
359
+            var val = inventory[i][field];
360
+        }
361
+        
362
+        $(`input[name=${s}]`).val(val);
290 363
     }
291
-    return form;
364
+
365
+    display_form();
292 366
 }
293
-/* set_form(row: string) - populate form using inventory data */
294
-function set_form(row){
295
-    /* fill form input by name */ 
296
-    for(var col in inventory[row]){
297
-        $("[name=" + col + "]").val(inventory[row][col]);
367
+
368
+/* table_gen(inventory: dictionary) - generate table body */
369
+function table_gen(data){
370
+    /* extract entries */
371
+    for(var d in data){
372
+        /* generate table row */
373
+        let tr = element_gen("tr",{class: "entry-row",id: d});
374
+        for(var field in data[d]){
375
+            switch(field){
376
+                case "material":                /* material, extract id */
377
+                    var link = element_gen("a",{class: "mat-link",text: data[d][field]["mat_name"],href: `materials?mat_id=${data[d][field]["mat_id"]}`,target: "_blank",rel: "noopener noreferrer"});
378
+                    var attributes = {class: "entry-cell",value: "mat_name",mat_id: data[d][field]["mat_id"],childs: {link}};
379
+                    break;
380
+
381
+                case "manufacturer":            /* manufacturer, extract id */
382
+                    var attributes ={class: "entry-cell",value: "man_name",man_id: data[d][field]["man_id"],text: data[d][field]["man_name"]};
383
+                    break;
384
+
385
+                case "sds":                     /* generate sds link */
386
+                    if(!data[d][field]){
387
+                        data[d][field] = "-";
388
+                    }
389
+                    var icon = element_gen("i",{class: "fas fa-link"});
390
+                    var link = element_gen("span",{class: "sds",href: decodeURI(data[d][field]),target: "_blank",rel: "noopener noreferrer",childs: {icon}});
391
+                    var attributes = {class: "entry-cell",value: field,childs: {link}};
392
+                    break;
393
+
394
+                default:                        /* default */
395
+                    if(!data[d][field]){
396
+                        data[d][field] = "-";
397
+                    }
398
+                    var attributes = {class: "entry-cell",value: field,text: data[d][field]};
399
+                    break;
400
+            }
401
+            
402
+            var td = element_gen("td",attributes);
403
+            tr.append(td);
404
+        }
405
+
406
+        /* generate actions cell */
407
+        let actions = {edit:{class: "t-icon material-icons",icon: "notes"},remove: {class: "t-icon material-icons",icon: "close"}};
408
+        var td = element_gen("td",{class: "actions-cell"});
409
+        
410
+        /* generate actions */
411
+        for(var action in actions){
412
+            var icon = element_gen("i",{class: actions[action]["class"],text: actions[action]["icon"]});
413
+            var button = element_gen("button",{class: "button action",id: action,value: d,title: action,childs: {icon}});
414
+            td.append(button);
415
+        }
416
+
417
+        /* append */
418
+        tr.append(td);
419
+        $("tbody").append(tr);
298 420
     }
299
-    /* display form */ 
300
-    $(".form-window").show();
301
-    /* form is active */
302
-    form_is_active = true;
421
+
422
+    /* display inventory */
423
+    $(".processing").hide();
424
+    setTimeout(function(){
425
+        set_listeners();
426
+        $(".main-wrapper").show();
427
+    },250);
303 428
 }
304
-/* Load navbar and footer into document and fetch inventory */ 
305
-$(document).ready(function(){
306
-    $(".navbar-wrapper").load("/navbar.html",function(){
307
-        $(".footer-wrapper").load("/footer.html",function(){
308
-            current();          /* highlight current navbar link */
309
-            get_inventory();    /* fetch inventory from server */
429
+
430
+/* fetch_inventory() - fetch lab inventory */ 
431
+function fetch_inventory(){
432
+    /* extract lab id */
433
+    let lab_id = get_arg("lab_id");
434
+    if(is_valid(lab_id)){
435
+        $.post("/scripts/opaso",{query: 4,lab_id: lab_id},function(data){
436
+            // console.log(data);
437
+            /* extract response */
438
+            response = JSON.parse(data);
439
+            status = response["status"];
440
+
441
+            /* handle by status */
442
+            switch(status){
443
+                case "success":                 /* on success, generate table */
444
+                    inventory = response["lab"]["inventory"];
445
+
446
+                    /* generate inventory table */
447
+                    table_gen(inventory);
448
+                    next = Object.keys(inventory).length;
449
+                    $(".table-total").text(`Total: ${next}`);
450
+                    break;
451
+                case "expired":                 /* on expired, redirect */
452
+                    window.location.href = "/?error=session_expired";
453
+                    break;
454
+
455
+                default:                        /* on error, display message */
456
+                    set_alert(status,response["message"]);
457
+                    break;
458
+            }
310 459
         });
311
-    });
312
-});
460
+    }
461
+    /* missing args */
462
+    else{
463
+        set_alert("error","One or more arguments missing");
464
+    }
465
+}

+ 569
- 0
public_html/scripts/laboratory.js View File

@@ -0,0 +1,569 @@
1
+/*  Authors         :   Carlos C. Corrada-Bravo
2
+                        David J. Ortiz-Rivera
3
+
4
+    Organization    :   Centro de Desarrollo y Consultoria Computacional
5
+    Project         :   OPASO Material Registry   
6
+    File            :   laboratory.js
7
+    Description     :   Generate and display laboratory inventory */
8
+
9
+/* save inventory data globaly */
10
+var controlTimeout,control,total,r,next,transaction,row,form,admin
11
+var active = false;
12
+var sort_key = "mat_name";
13
+let lab_id = get_arg("lab_id");
14
+
15
+/* set listeners when document is ready */ 
16
+$(document).ready(function(){
17
+    link_gen();
18
+    laboratory();
19
+});
20
+
21
+function display_form(type,transaction){
22
+    let f = `.${type}-form`;
23
+    let s = `#${type}-submit`;
24
+    $(".form-shader").addClass("fade-in")
25
+    $(f).addClass("c-form");
26
+    $(f).addClass("slide-down");
27
+    $(s).attr("value",transaction);
28
+}
29
+
30
+/* hide_form() - hide form  */
31
+function hide_form(){
32
+    $(".c-form").removeClass("slide-down");
33
+    setTimeout(function(){
34
+        $(".form-shader").removeClass("fade-in");
35
+    },250);
36
+}
37
+
38
+/* main_transaction() - handle main transactions */
39
+function main_transaction(){
40
+    /* extract args */
41
+    let s = `#${r}`;
42
+    let amount = parseFloat($("#transaction").val());
43
+    var uom = $(s).find("td[value=uom]").text();
44
+    var mat_id = $(s).find("td[value=mat_name]").attr("mat_id");
45
+    var man_id = $(s).find("td[value=man_name]").attr("man_id");
46
+    let capacity = parseFloat($(s).find("td[value=capacity]").text());
47
+
48
+    
49
+    /* calculate material left */
50
+    if(transaction === "add"){
51
+        total += amount;
52
+    }
53
+    else{
54
+        total -= amount;
55
+    }
56
+
57
+    /* query server */
58
+    hide_form();
59
+    $.post("/scripts/opaso",{query: 9,lab_id: lab_id,mat_id: mat_id,man_id: man_id,capacity: capacity,transaction: transaction,total: total,amount: amount,uom: uom},function(data){
60
+        // console.log(data);
61
+        /* extract response */
62
+        let response = JSON.parse(data);
63
+        let status = response["status"];
64
+
65
+        /* handle by status */
66
+        switch(status){
67
+            case "success":                 /* on success, update total/quantity */                      
68
+                if(total < 1){
69
+                    $(s).remove();
70
+                    $(".table-total").text($(".inventory-body tr").length);
71
+                }
72
+
73
+                /* update quantity */
74
+                else{
75
+                    $("#total").val(total);
76
+                    $("#transaction").val(0);
77
+                    let containers = total/capacity;
78
+                    $(s).find("td[value=quantity]").text(Math.ceil(containers));
79
+                    $(s).find("td[value=total]").text(total);
80
+                }
81
+
82
+                set_alert(status,"Transaction complete");
83
+                break;
84
+            
85
+            case "expired":                  /* on expired, redirect to index */
86
+                window.location.href = "/?error=session_expired";
87
+                break;
88
+
89
+            default:                        /* on error, display message */
90
+                set_alert(status,response["message"]);
91
+                break;
92
+        }
93
+    });
94
+}
95
+
96
+/* add_material() - add material to inventory */
97
+function add_material(){
98
+    /* generate material entries */
99
+    row = {};
100
+    form = {};
101
+    row[next] = {};
102
+
103
+    /* populate entries */
104
+    $(".material-input").each(function(){
105
+        /* extract field name */
106
+        var field = $(this).attr("name");
107
+        /* generate inventory row */
108
+        switch(field){
109
+            case "quantity":
110
+                /* calculate total */
111
+                row[next][field] = $(this).val();
112
+                let mtotal = parseFloat(form["capacity"]) * parseFloat($(this).val());
113
+                form["total"] = mtotal;
114
+                row[next]["total"] = mtotal;
115
+                break;
116
+
117
+            case "mat_name":
118
+            case "man_name":
119
+            case "capacity":
120
+            case "uom":
121
+            case "location":
122
+                row[next][field] = $(this).val();
123
+                break;
124
+        }
125
+        
126
+        /* set field entry */
127
+        form[field] = $(this).val();
128
+    });
129
+
130
+    /* query server */
131
+    hide_form();
132
+    $.post("/scripts/opaso",{query: 10,lab_id: lab_id,data: JSON.stringify(form)},function(data){
133
+        // console.log(data);
134
+        /* extract response */
135
+        let response = JSON.parse(data);
136
+        let status = response["status"];
137
+
138
+        /* handle by status */
139
+        switch(status){
140
+            case "expired":                  /* on expired, redirect to index */
141
+                window.location.href = "/?error=session_expired";
142
+                break;
143
+
144
+            case "success":                 /* on success, update inventory */
145
+                // console.log(row);
146
+                /* extract args */
147
+                let mat_id = response["mat_id"];
148
+                let man_id = response["man_id"];
149
+                let s_uom = form["uom"].toLowerCase();
150
+                let s_total = parseFloat(form["total"]);
151
+                let s_capacity = parseFloat(form["capacity"]);
152
+                let s_man_name = form["man_name"].toLowerCase();
153
+
154
+                
155
+                /* verify if material exists */
156
+                var flag = true;
157
+                let s = `td[mat_id=${mat_id}]`;
158
+                $(s).each(function(){
159
+                    /* extract args */
160
+                    var capacity = parseFloat($(this).parent().find("td[value=capacity]").text());
161
+                    var man_name = $(this).parent().find("td[value=man_name]").text().toLowerCase();
162
+                    var uom = $(this).parent().find("td[value=uom]").text().toLowerCase();
163
+
164
+                    /* update quantities */
165
+                    if((capacity === s_capacity) && (man_name === s_man_name) && (uom === s_uom)){
166
+                        var ntotal = parseFloat($(this).parent().find("td[value=total]").text()) + s_total;
167
+                        var containers = ntotal/capacity;
168
+                        $(this).parent().find("td[value=total]").text(ntotal);
169
+                        $(this).parent().find("td[value=quantity]").text(Math.ceil(containers));
170
+                        flag = false;  
171
+                    }
172
+                });  
173
+                
174
+                /* generate table row */
175
+                if(flag){
176
+                    let tr = element_gen("tr",{class: "entry-row",id: next});
177
+                    for(var r in row){
178
+                        for(var field in row[r]){
179
+                            /* identify material */
180
+                            if(field === "mat_name"){
181
+                                var attributes = {class: "entry-cell",mat_id: mat_id,text: row[r][field],value: field};
182
+                            }
183
+
184
+                            /* identify material */
185
+                            else if(field === "man_name"){
186
+                                if(!row[r][field]){
187
+                                    row[r][field] = "-";
188
+                                }
189
+
190
+                                var attributes = {class: "entry-cell",man_id: man_id,text: row[r][field],value: field};
191
+                            }
192
+                            else{
193
+                                if(!row[r][field]){
194
+                                    row[r][field] = "-";
195
+                                }
196
+
197
+                                var attributes = {class: "entry-cell",text: row[r][field],value: field};   
198
+                            }
199
+
200
+                            var td = element_gen("td",attributes);
201
+                            tr.append(td);
202
+                        }
203
+                        
204
+                        let actions = {add:{class: "t-icon material-icons",icon: "add"},use: {class: "t-icon material-icons",icon: "remove"},offer: {class: "t-icon material-icons",icon: "redeem"},discard: {class: "t-icon material-icons",icon: "delete"}};
205
+                        var td = element_gen("td",{class: "actions-cell"});
206
+                        for(var action in actions){
207
+                            var icon = element_gen("i",{class: actions[action]["class"],text: actions[action]["icon"]});
208
+                            var button = element_gen("button",{class: "button action",id: action,title: action,childs: {icon}});
209
+                            td.append(button);
210
+                        }
211
+                    }
212
+
213
+                    /* append */
214
+                    tr.append(td);
215
+                    $(".inventory-body").append(tr);
216
+
217
+                    /* sort table */
218
+                    next += 1;
219
+                    full_sort(next,sort_key);
220
+                    $(".table-total").text(`Total: ${next}`);
221
+                }
222
+            
223
+            default:                    /* on success/error, display message */
224
+                set_alert(status,response["message"]);
225
+                break;
226
+        }
227
+    });
228
+}
229
+
230
+/* transaction - handle material transactions */
231
+function transaction(){
232
+    /* extract args */
233
+    transaction = $(this).attr("id");
234
+    r = $(this).parent().parent().attr("id");
235
+    let s = `#${r}`;
236
+    total = parseFloat($(s).find("td[value=total]").text());
237
+    uom = $(s).find("td[value=uom]").text();
238
+    let header = `${transaction} material (${uom})`;
239
+    $(".main-header").text(header);
240
+
241
+    
242
+    /* hide total capacity */
243
+    if(transaction === "add"){
244
+        $(".total").hide();
245
+    }
246
+
247
+    /* set total quantity */
248
+    else{
249
+        $("#total").val(total);
250
+        $(".total").show();
251
+    }
252
+
253
+    $("#transaction").val(0);
254
+    $(".transaction-label").text(transaction);
255
+    display_form("main",transaction);
256
+}
257
+
258
+/* fetch_material() - fetch material data */
259
+function fetch_material(){
260
+    /* extract key */
261
+    let mat_name = $(this).text();
262
+    let mat_id = $(this).attr("mat_id");
263
+    let uom = $(this).parent().find("td[value=uom]").text();
264
+    let man_id = $(this).parent().find("td[value=man_name]").attr("man_id");
265
+    let capacity = $(this).parent().find("td[value=capacity]").text();
266
+    
267
+    $.post("/scripts/opaso",{query: 12,lab_id: lab_id,mat_id: mat_id,man_id: man_id,capacity: capacity,uom: uom},function(data){
268
+        // console.log(data);
269
+        /* extract response */
270
+        let response = JSON.parse(data);
271
+        let status = response["status"];
272
+
273
+        /* handle by status */
274
+        switch(status){
275
+            case "success":                 /* on success, generate material data */
276
+                let material = response["material"];
277
+                $("h5[value=mat_name]").text(mat_name);
278
+                var href = `/materials?mat_id=${mat_id}`;
279
+                $(".material-link").attr("href",href);
280
+
281
+                for(var a in material){
282
+                    let s = `span[value=${a}]`;
283
+                    if(a === "sds" && material[a]){
284
+                        var icon = element_gen("i",{class: "fas fa-link"});
285
+                        var link = element_gen("a",{href: decodeURIComponent(material[a]),target: "_blank",rel: "noopener noreferrer",childs: {icon}});
286
+                        $(s).html(link);
287
+                    }
288
+
289
+                    else{
290
+                        /* correct null values */
291
+                        if(!material[a]){
292
+                            material[a] = "-";
293
+                        }
294
+                        
295
+                        $(s).text(material[a]);
296
+                    }
297
+                }
298
+                
299
+                $(".material-data-shader").addClass("slide-right");
300
+                break;
301
+            
302
+            case "expired":                 /* on expired, redirect to index */
303
+                window.location.href = "/?error=session_expired";
304
+                break;
305
+
306
+            default:                        /* on error, display message */
307
+                set_alert(status,response["message"]);
308
+                break;
309
+        }
310
+    });
311
+}
312
+
313
+/* set_listeners() - listen for events */
314
+function set_listeners(){
315
+    /* sort table */
316
+    $(".sort").click(function(){
317
+        sort_key = $(this).attr("value");
318
+        if(sort_key === "mat_name"){
319
+            $(".sort-material").show();
320
+            $(".sort-alt").hide();
321
+        }
322
+
323
+        else{
324
+            $(".sort-alt").show();
325
+            $(".sort-material").hide();
326
+        }
327
+
328
+        full_sort(next,sort_key);
329
+    });
330
+
331
+    /* add/use material */
332
+    $("tbody").on("click",".action",transaction);
333
+    
334
+    /* add material to inventory */
335
+    $(".add-material").click(function(){
336
+        display_form("add","add-material");
337
+    });
338
+    
339
+    /* handle popover */
340
+    $("tbody td[value=mat_name]").click(fetch_material);
341
+
342
+    
343
+    /* handle form submit */
344
+    $(".submit").click(function(){
345
+        /* add material */
346
+        transaction = $(this).attr("value");
347
+
348
+        if(transaction === "add-material"){
349
+            /* verify null fields */
350
+            var valid = true;
351
+            $(".material-input").each(function(){
352
+                var field = $(this).attr("name");
353
+
354
+                /* highlight */
355
+                if(!$(this).val()){
356
+                    valid = false;
357
+                    $(this).addClass("invalid");
358
+                }
359
+
360
+                /* unhighlight */
361
+                else{
362
+                    $(this).removeClass("invalid");
363
+                }
364
+            });
365
+
366
+            /* valid form */
367
+            if(valid){
368
+                set_confirm("Do you wish to add entry to inventory?",transaction);
369
+            }
370
+
371
+            /* invalid form */
372
+            else{
373
+                set_alert("warning","All fields required");
374
+            }
375
+        }
376
+
377
+        /* main transactions */
378
+        else{
379
+            /* validate amount */
380
+            let amount = parseFloat($("#transaction").val());
381
+            if((transaction === "add" || amount <= total) && amount > 0){
382
+                /* generate message */
383
+                let s = `#${r}`;
384
+                let uom = $(s).find("td[value=uom]").text();
385
+                let material = $(s).find("td[value=mat_name]").text();
386
+                let verb = transaction.charAt(0).toUpperCase() + transaction.slice(1);
387
+                let message = `${verb} ${amount}${uom} of ${material}. Is this correct?`;
388
+                
389
+                /* configure alert */
390
+                set_confirm(message,transaction);
391
+            }
392
+
393
+            /* amount not valid */
394
+            else{
395
+                set_alert("error","Please correct transaction amount");
396
+            }  
397
+        }
398
+    });
399
+
400
+    /* handle query submit */
401
+    $("#yes").click(function(){
402
+        transaction = $(this).attr("value");
403
+        
404
+        /* add material */
405
+        if(transaction === "add-material"){
406
+            add_material();
407
+        }
408
+       
409
+        /* main transactions */
410
+        else{
411
+            main_transaction(transaction);
412
+        }
413
+
414
+        hide_confirm();
415
+    });
416
+
417
+    /* handle query cancel */
418
+    $(".hide-confirm").click(function(element){
419
+        /* prevent child propagation */
420
+        if(element.target === element.currentTarget){
421
+            hide_confirm();
422
+        }
423
+    });
424
+
425
+    /* close form */ 
426
+    $(".close-form").click(function(element){
427
+        if(element.target === element.currentTarget){
428
+            hide_form();
429
+        }
430
+    });
431
+
432
+    /* hide material data */ 
433
+    $(".hide-material-data").click(function(element){
434
+        if(element.target === element.currentTarget){
435
+            $(".material-data-shader").removeClass("slide-right");
436
+        }
437
+    });
438
+
439
+    /* download file */
440
+    $(".download-option").click(function(){
441
+        /* extract args */
442
+        $("html").addClass("wait");
443
+        let download_type = $(this).attr("value");
444
+
445
+        /* generate file */
446
+        $.post("/scripts/opaso",{query: 24,download_type: download_type,lab_id: get_arg("lab_id")},function(data){
447
+            // console.log(data);
448
+            /* extract response */
449
+            let response = JSON.parse(data);
450
+            let status = response["status"];
451
+
452
+            /* handle by status */
453
+            switch(status){
454
+                case "success":                 /* on success, generate table */
455
+                    var link=element_gen("a",{href: response["url"],download: response["file_name"]});
456
+                    link.click();
457
+                    break;
458
+                
459
+                case "expired":                 /* on expired, redirect to index */
460
+                    window.location.href = "/?error=session_expired";
461
+                    break;
462
+
463
+                default:                        /* on error, display message */
464
+                    set_alert(status,response["message"]);
465
+                    break;
466
+            }
467
+
468
+            $("html").removeClass("wait");
469
+        });
470
+    });
471
+}
472
+
473
+/* table_gen(data: dictionary) - generate table body */
474
+function table_gen(data){
475
+    for(var d in data){
476
+        /* generate table row */
477
+        let tr = element_gen("tr",{class: "entry-row",id: d});
478
+        let fields = data[d];
479
+        for(var field in fields){
480
+            /* identify material */
481
+            if(field === "material"){
482
+                var attributes = {class: "entry-cell",mat_id: fields[field]["mat_id"],text: fields[field]["mat_name"],value: "mat_name"};
483
+            }
484
+
485
+            /* identify material */
486
+            else if(field === "manufacturer"){
487
+                if(!fields[field]["man_name"]){
488
+                    fields[field]["man_name"] = "-";
489
+                }
490
+                var attributes = {class: "entry-cell",man_id: fields[field]["man_id"],text: fields[field]["man_name"],value: "man_name"};
491
+            }
492
+            else{
493
+                /* correct null entries */
494
+                if(!fields[field]){
495
+                    fields[field] = "-";
496
+                }
497
+                var attributes = {class: "entry-cell",text: fields[field],value: field};   
498
+            }
499
+
500
+            /* generate cell */
501
+            var td = element_gen("td",attributes);
502
+            tr.append(td);
503
+        }
504
+            
505
+        let actions = {add:{class: "t-icon material-icons",icon: "add"},use: {class: "t-icon material-icons",icon: "remove"},offer: {class: "t-icon material-icons",icon: "redeem"},discard: {class: "t-icon material-icons",icon: "delete"}};
506
+        var td = element_gen("td",{class: "actions-cell"});
507
+        for(var action in actions){
508
+            var icon = element_gen("i",{class: actions[action]["class"],text: actions[action]["icon"]});
509
+            var button = element_gen("button",{class: "button action",id: action,title: action,childs: {icon}});
510
+            td.append(button);
511
+        }
512
+
513
+        /* append */
514
+        tr.append(td);
515
+        $(".inventory-body").append(tr);
516
+    }
517
+
518
+    $(".processing").hide();
519
+    setTimeout(function(){
520
+        $(".main-wrapper").show();
521
+    },250);
522
+}
523
+
524
+/* laboratory() - fetch lab inventory */ 
525
+function laboratory(){
526
+    /* avoid null queries */
527
+    if(is_valid(lab_id)){
528
+        $.post("/scripts/opaso",{query: 3,lab_id: lab_id},function(data){
529
+            // console.log(data);
530
+            /* extract response */
531
+            let response = JSON.parse(data)
532
+            let status = response["status"];
533
+
534
+            /* handle by status */
535
+            switch(status){
536
+                case "success":                 /* on success, generate inventory */
537
+                    let inventory = response["lab"]["inventory"];
538
+                    let personnel = response["lab"]["personnel"];
539
+
540
+                    /* generate personnel table */
541
+                    for(var p in personnel){
542
+                        var name = element_gen("td",{class: "entry-cell person-name",text: personnel[p]["person_name"]});
543
+                        var access_level = element_gen("td",{class: "entry-cell access-level",text: personnel[p]["access_level"]});
544
+                        var person = element_gen("tr",{class: "personnel-row",childs:{name,access_level}});
545
+                        $(".personnel-body").append(person);
546
+                    }
547
+                    
548
+                    table_gen(inventory);
549
+                    set_listeners();
550
+                    next = Object.keys(inventory).length;
551
+                    $(".table-total").text(`Total: ${next}`);
552
+                    break;
553
+                
554
+                case "expired":                 /* on expired, redirect to index */
555
+                    window.location.href = "/?error=session_expired";
556
+                    break;
557
+
558
+                default:                        /* on error, display message */
559
+                    /* display alert */
560
+                    set_alert(status,response["message"]);
561
+                    break;
562
+            }
563
+        });
564
+    }
565
+    /* missing arg */
566
+    else{
567
+        set_alert(status,"One or more arguments are missing");
568
+    }
569
+}