{"id":6,"date":"2026-07-28T16:31:24","date_gmt":"2026-07-28T16:31:24","guid":{"rendered":"https:\/\/jobstracker.nhum.in.th\/?page_id=6"},"modified":"2026-07-28T23:34:23","modified_gmt":"2026-07-28T23:34:23","slug":"jobs-tracker-management","status":"publish","type":"page","link":"https:\/\/jobstracker.nhum.in.th\/","title":{"rendered":"Jobs Tracker Management"},"content":{"rendered":"\n<p><!DOCTYPE html><br \/>\n<html><br \/>\n<head><br \/>\n  <base target=\"_top\"><br \/>\n  <?!= include('Styles'); ?><br \/>\n<\/head><br \/>\n<body><br \/>\n  <?!= include('Nav'); ?><\/p>\n<div class=\"container\">\n<div class=\"card\">\n<h2 id=\"formTitle\">\u2795 \u0e40\u0e1e\u0e34\u0e48\u0e21\u0e07\u0e32\u0e19\u0e43\u0e2b\u0e21\u0e48<\/h2>\n<form id=\"jobForm\">\n        <input type=\"hidden\" id=\"job_id\" value=\"\"><br \/>\n        <label>\u0e0a\u0e37\u0e48\u0e2d\u0e07\u0e32\u0e19<\/label><br \/>\n        <input type=\"text\" id=\"job_name\" required><\/p>\n<p>        <label>\u0e23\u0e32\u0e22\u0e25\u0e30\u0e40\u0e2d\u0e35\u0e22\u0e14<\/label><br \/>\n        <textarea id=\"description\" rows=\"2\"><\/textarea><\/p>\n<p>        <label>\u0e21\u0e2d\u0e1a\u0e2b\u0e21\u0e32\u0e22\u0e43\u0e2b\u0e49<\/label><br \/>\n        <select id=\"assigned_to\" required><\/select><\/p>\n<p>        <label>\u0e01\u0e33\u0e2b\u0e19\u0e14\u0e2a\u0e48\u0e07<\/label><br \/>\n        <input type=\"datetime-local\" id=\"deadline\"><\/p>\n<p>        <label>\u0e04\u0e27\u0e32\u0e21\u0e2a\u0e33\u0e04\u0e31\u0e0d<\/label><br \/>\n        <select id=\"priority\"><option>\u0e2a\u0e39\u0e07<\/option><option selected>\u0e01\u0e25\u0e32\u0e07<\/option><option>\u0e15\u0e48\u0e33<\/option><\/select><\/p>\n<div>\n          <button type=\"submit\" id=\"submitBtn\">\u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01\u0e07\u0e32\u0e19<\/button><br \/>\n          <button type=\"button\" class=\"secondary\" id=\"cancelEditBtn\" style=\"display:none;\" onclick=\"resetForm()\">\u0e22\u0e01\u0e40\u0e25\u0e34\u0e01\u0e41\u0e01\u0e49\u0e44\u0e02<\/button>\n        <\/div>\n<div id=\"formMsg\"><\/div>\n<\/p><\/form>\n<\/p><\/div>\n<div class=\"card\">\n<div class=\"toolbar\">\n<h2 style=\"margin:0;\">\ud83d\udccb \u0e23\u0e32\u0e22\u0e01\u0e32\u0e23\u0e07\u0e32\u0e19\u0e17\u0e31\u0e49\u0e07\u0e2b\u0e21\u0e14<\/h2>\n<p>        <button class=\"secondary\" onclick=\"loadJobs()\">\ud83d\udd04 \u0e23\u0e35\u0e40\u0e1f\u0e23\u0e0a<\/button>\n      <\/div>\n<div class=\"filter-row\">\n        <select id=\"filterStatus\" onchange=\"renderJobs()\"><option value=\"\">\u0e17\u0e38\u0e01\u0e2a\u0e16\u0e32\u0e19\u0e30<\/option><option>New<\/option><option>Notified<\/option><option>Done<\/option><option>Overdue<\/option><\/select><br \/>\n        <input type=\"text\" id=\"searchBox\" placeholder=\"\u0e04\u0e49\u0e19\u0e2b\u0e32\u0e0a\u0e37\u0e48\u0e2d\u0e07\u0e32\u0e19...\" oninput=\"renderJobs()\">\n      <\/div>\n<div id=\"jobsLoading\" class=\"loading\">\u0e01\u0e33\u0e25\u0e31\u0e07\u0e42\u0e2b\u0e25\u0e14&#8230;<\/div>\n<div class=\"table-scroll\">\n<table id=\"jobsTable\" style=\"display:none;\">\n<thead>\n<tr>\n<th>\u0e23\u0e2b\u0e31\u0e2a<\/th>\n<th>\u0e0a\u0e37\u0e48\u0e2d\u0e07\u0e32\u0e19<\/th>\n<th>\u0e1c\u0e39\u0e49\u0e23\u0e31\u0e1a\u0e1c\u0e34\u0e14\u0e0a\u0e2d\u0e1a<\/th>\n<th>\u0e01\u0e33\u0e2b\u0e19\u0e14\u0e2a\u0e48\u0e07<\/th>\n<th>\u0e04\u0e27\u0e32\u0e21\u0e2a\u0e33\u0e04\u0e31\u0e0d<\/th>\n<th>\u0e2a\u0e16\u0e32\u0e19\u0e30<\/th>\n<th><\/th>\n<\/tr>\n<\/thead>\n<tbody id=\"jobsBody\"><\/tbody>\n<\/table><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<p>  <script>\n    var allJobs = [];\n    var allTeam = [];<\/p>\n<p>    function loadTeamDropdown() {\n      google.script.run.withSuccessHandler(function (team) {\n        allTeam = team;\n        var sel = document.getElementById('assigned_to');\n        sel.innerHTML = team.filter(function (m) { return m.active !== false; }).map(function (m) {\n          return '<option value=\"' + m.member_id + '\">' + m.name + '<\/option>';\n        }).join('');\n      }).getAllTeamList();\n    }<\/p>\n<p>    function loadJobs() {\n      document.getElementById('jobsLoading').style.display = 'block';\n      document.getElementById('jobsTable').style.display = 'none';\n      google.script.run.withSuccessHandler(function (jobs) {\n        allJobs = jobs;\n        renderJobs();\n        document.getElementById('jobsLoading').style.display = 'none';\n        document.getElementById('jobsTable').style.display = 'table';\n      }).getJobsList();\n    }<\/p>\n<p>    function badgeClass(status) {\n      if (status === 'New') return 'badge-new';\n      if (status === 'Notified') return 'badge-notified';\n      if (status === 'Done') return 'badge-done';\n      if (status === 'Overdue') return 'badge-overdue';\n      return '';\n    }<\/p>\n<p>    function fmtDate(d) {\n      if (!d) return '-';\n      return new Date(d).toLocaleString('th-TH', { dateStyle: 'short', timeStyle: 'short' });\n    }<\/p>\n<p>    function renderJobs() {\n      var statusFilter = document.getElementById('filterStatus').value;\n      var search = document.getElementById('searchBox').value.toLowerCase();\n      var body = document.getElementById('jobsBody');<\/p>\n<p>      var filtered = allJobs.filter(function (j) {\n        if (statusFilter && j.status !== statusFilter) return false;\n        if (search && (j.job_name || '').toLowerCase().indexOf(search) === -1) return false;\n        return true;\n      }).sort(function (a, b) { return new Date(b.created_at) - new Date(a.created_at); });<\/p>\n<p>      body.innerHTML = filtered.map(function (j) {\n        var member = allTeam.find(function (m) { return m.member_id === j.assigned_to; });\n        var memberName = member ? member.name : j.assigned_to;\n        return '<\/p>\n<tr>' +\n          '<\/p>\n<td>' + j.job_id + '<\/td>\n<p>' +\n          '<\/p>\n<td>' + j.job_name + '<\/td>\n<p>' +\n          '<\/p>\n<td>' + memberName + '<\/td>\n<p>' +\n          '<\/p>\n<td>' + fmtDate(j.deadline) + '<\/td>\n<p>' +\n          '<\/p>\n<td>' + (j.priority || '-') + '<\/td>\n<p>' +\n          '<\/p>\n<td><span class=\"badge ' + badgeClass(j.status) + '\">' + j.status + '<\/span><\/td>\n<p>' +\n          '<\/p>\n<td><button class=\"secondary\" onclick=\"editJob('' + j.job_id + '')\">\u0e41\u0e01\u0e49\u0e44\u0e02<\/button><\/td>\n<p>' +\n          '<\/tr>\n<p>';\n      }).join('');\n    }<\/p>\n<p>    function editJob(jobId) {\n      var job = allJobs.find(function (j) { return j.job_id === jobId; });\n      if (!job) return;\n      document.getElementById('formTitle').innerText = '\u270f\ufe0f \u0e41\u0e01\u0e49\u0e44\u0e02\u0e07\u0e32\u0e19: ' + job.job_id;\n      document.getElementById('job_id').value = job.job_id;\n      document.getElementById('job_name').value = job.job_name;\n      document.getElementById('description').value = job.description || '';\n      document.getElementById('assigned_to').value = job.assigned_to;\n      document.getElementById('deadline').value = job.deadline ? new Date(job.deadline).toISOString().slice(0, 16) : '';\n      document.getElementById('priority').value = job.priority || '\u0e01\u0e25\u0e32\u0e07';\n      document.getElementById('submitBtn').innerText = '\u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01\u0e01\u0e32\u0e23\u0e41\u0e01\u0e49\u0e44\u0e02';\n      document.getElementById('cancelEditBtn').style.display = 'inline-block';\n      window.scrollTo(0, 0);\n    }<\/p>\n<p>    function resetForm() {\n      document.getElementById('jobForm').reset();\n      document.getElementById('job_id').value = '';\n      document.getElementById('formTitle').innerText = '\u2795 \u0e40\u0e1e\u0e34\u0e48\u0e21\u0e07\u0e32\u0e19\u0e43\u0e2b\u0e21\u0e48';\n      document.getElementById('submitBtn').innerText = '\u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01\u0e07\u0e32\u0e19';\n      document.getElementById('cancelEditBtn').style.display = 'none';\n    }<\/p>\n<p>    document.getElementById('jobForm').addEventListener('submit', function (e) {\n      e.preventDefault();\n      var jobId = document.getElementById('job_id').value;\n      var form = {\n        job_name: document.getElementById('job_name').value,\n        description: document.getElementById('description').value,\n        assigned_to: document.getElementById('assigned_to').value,\n        deadline: document.getElementById('deadline').value,\n        priority: document.getElementById('priority').value,\n      };\n      var msgBox = document.getElementById('formMsg');\n      msgBox.innerHTML = '';<\/p>\n<p>      var handler = function (res) {\n        if (res.success) {\n          msgBox.innerHTML = '<\/p>\n<div class=\"msg msg-success\">\u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01\u0e2a\u0e33\u0e40\u0e23\u0e47\u0e08 \u2705<\/div>\n<p>';\n          resetForm();\n          loadJobs();\n        } else {\n          msgBox.innerHTML = '<\/p>\n<div class=\"msg msg-error\">\u0e1c\u0e34\u0e14\u0e1e\u0e25\u0e32\u0e14: ' + (res.message || '') + '<\/div>\n<p>';\n        }\n      };<\/p>\n<p>      var failHandler = function (err) {\n        msgBox.innerHTML = '<\/p>\n<div class=\"msg msg-error\">\u0e1c\u0e34\u0e14\u0e1e\u0e25\u0e32\u0e14: ' + err.message + '<\/div>\n<p>';\n      };<\/p>\n<p>      if (jobId) {\n        google.script.run.withSuccessHandler(handler).withFailureHandler(failHandler).updateJobEntry(jobId, form);\n      } else {\n        google.script.run.withSuccessHandler(handler).withFailureHandler(failHandler).createJobEntry(form);\n      }\n    });<\/p>\n<p>    loadTeamDropdown();\n    loadJobs();\n  <\/script><br \/>\n<\/body><br \/>\n<\/html><\/p>\n\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"page-blank.php","meta":{"footnotes":""},"class_list":["post-6","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/jobstracker.nhum.in.th\/index.php?rest_route=\/wp\/v2\/pages\/6","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jobstracker.nhum.in.th\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/jobstracker.nhum.in.th\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/jobstracker.nhum.in.th\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jobstracker.nhum.in.th\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=6"}],"version-history":[{"count":2,"href":"https:\/\/jobstracker.nhum.in.th\/index.php?rest_route=\/wp\/v2\/pages\/6\/revisions"}],"predecessor-version":[{"id":13,"href":"https:\/\/jobstracker.nhum.in.th\/index.php?rest_route=\/wp\/v2\/pages\/6\/revisions\/13"}],"wp:attachment":[{"href":"https:\/\/jobstracker.nhum.in.th\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=6"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}