{"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-28T16:31:24","modified_gmt":"2026-07-28T16:31:24","slug":"jobs-tracker-management","status":"publish","type":"page","link":"https:\/\/jobstracker.nhum.in.th\/","title":{"rendered":"Jobs Tracker Management"},"content":{"rendered":"\n<!DOCTYPE html>\n<html>\n<head>\n  <base target=\"_top\">\n  <?!= include('Styles'); ?>\n<\/head>\n<body>\n  <?!= include('Nav'); ?>\n\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=\"\">\n        <label>\u0e0a\u0e37\u0e48\u0e2d\u0e07\u0e32\u0e19<\/label>\n        <input type=\"text\" id=\"job_name\" required>\n\n        <label>\u0e23\u0e32\u0e22\u0e25\u0e30\u0e40\u0e2d\u0e35\u0e22\u0e14<\/label>\n        <textarea id=\"description\" rows=\"2\"><\/textarea>\n\n        <label>\u0e21\u0e2d\u0e1a\u0e2b\u0e21\u0e32\u0e22\u0e43\u0e2b\u0e49<\/label>\n        <select id=\"assigned_to\" required><\/select>\n\n        <label>\u0e01\u0e33\u0e2b\u0e19\u0e14\u0e2a\u0e48\u0e07<\/label>\n        <input type=\"datetime-local\" id=\"deadline\">\n\n        <label>\u0e04\u0e27\u0e32\u0e21\u0e2a\u0e33\u0e04\u0e31\u0e0d<\/label>\n        <select id=\"priority\">\n          <option>\u0e2a\u0e39\u0e07<\/option>\n          <option selected>\u0e01\u0e25\u0e32\u0e07<\/option>\n          <option>\u0e15\u0e48\u0e33<\/option>\n        <\/select>\n\n        <div>\n          <button type=\"submit\" id=\"submitBtn\">\u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01\u0e07\u0e32\u0e19<\/button>\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      <\/form>\n    <\/div>\n\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        <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()\">\n          <option value=\"\">\u0e17\u0e38\u0e01\u0e2a\u0e16\u0e32\u0e19\u0e30<\/option>\n          <option>New<\/option>\n          <option>Notified<\/option>\n          <option>Done<\/option>\n          <option>Overdue<\/option>\n        <\/select>\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><th>\u0e23\u0e2b\u0e31\u0e2a<\/th><th>\u0e0a\u0e37\u0e48\u0e2d\u0e07\u0e32\u0e19<\/th><th>\u0e1c\u0e39\u0e49\u0e23\u0e31\u0e1a\u0e1c\u0e34\u0e14\u0e0a\u0e2d\u0e1a<\/th><th>\u0e01\u0e33\u0e2b\u0e19\u0e14\u0e2a\u0e48\u0e07<\/th><th>\u0e04\u0e27\u0e32\u0e21\u0e2a\u0e33\u0e04\u0e31\u0e0d<\/th><th>\u0e2a\u0e16\u0e32\u0e19\u0e30<\/th><th><\/th><\/tr>\n          <\/thead>\n          <tbody id=\"jobsBody\"><\/tbody>\n        <\/table>\n      <\/div>\n    <\/div>\n  <\/div>\n\n  <script>\n    var allJobs = [];\n    var allTeam = [];\n\n    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    }\n\n    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    }\n\n    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    }\n\n    function fmtDate(d) {\n      if (!d) return '-';\n      return new Date(d).toLocaleString('th-TH', { dateStyle: 'short', timeStyle: 'short' });\n    }\n\n    function renderJobs() {\n      var statusFilter = document.getElementById('filterStatus').value;\n      var search = document.getElementById('searchBox').value.toLowerCase();\n      var body = document.getElementById('jobsBody');\n\n      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); });\n\n      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 '<tr>' +\n          '<td>' + j.job_id + '<\/td>' +\n          '<td>' + j.job_name + '<\/td>' +\n          '<td>' + memberName + '<\/td>' +\n          '<td>' + fmtDate(j.deadline) + '<\/td>' +\n          '<td>' + (j.priority || '-') + '<\/td>' +\n          '<td><span class=\"badge ' + badgeClass(j.status) + '\">' + j.status + '<\/span><\/td>' +\n          '<td><button class=\"secondary\" onclick=\"editJob(\\'' + j.job_id + '\\')\">\u0e41\u0e01\u0e49\u0e44\u0e02<\/button><\/td>' +\n          '<\/tr>';\n      }).join('');\n    }\n\n    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    }\n\n    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    }\n\n    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 = '';\n\n      var handler = function (res) {\n        if (res.success) {\n          msgBox.innerHTML = '<div class=\"msg msg-success\">\u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01\u0e2a\u0e33\u0e40\u0e23\u0e47\u0e08 \u2705<\/div>';\n          resetForm();\n          loadJobs();\n        } else {\n          msgBox.innerHTML = '<div class=\"msg msg-error\">\u0e1c\u0e34\u0e14\u0e1e\u0e25\u0e32\u0e14: ' + (res.message || '') + '<\/div>';\n        }\n      };\n\n      var failHandler = function (err) {\n        msgBox.innerHTML = '<div class=\"msg msg-error\">\u0e1c\u0e34\u0e14\u0e1e\u0e25\u0e32\u0e14: ' + err.message + '<\/div>';\n      };\n\n      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    });\n\n    loadTeamDropdown();\n    loadJobs();\n  <\/script>\n<\/body>\n<\/html>\n\n","protected":false},"excerpt":{"rendered":"<p>\u2795 \u0e40\u0e1e\u0e34\u0e48\u0e21\u0e07\u0e32\u0e19\u0e43\u0e2b\u0e21\u0e48 \u0e0a\u0e37\u0e48\u0e2d\u0e07\u0e32\u0e19 \u0e23\u0e32\u0e22\u0e25\u0e30\u0e40\u0e2d\u0e35\u0e22\u0e14 \u0e21\u0e2d\u0e1a\u0e2b\u0e21\u0e32\u0e22\u0e43\u0e2b\u0e49 \u0e01\u0e33\u0e2b\u0e19\u0e14\u0e2a\u0e48\u0e07 \u0e04\u0e27\u0e32\u0e21\u0e2a\u0e33\u0e04\u0e31\u0e0d \u0e2a\u0e39\u0e07\u0e01\u0e25\u0e32\u0e07\u0e15\u0e48\u0e33 \u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01\u0e07\u0e32\u0e19 \u0e22\u0e01\u0e40\u0e25\u0e34\u0e01\u0e41\u0e01\u0e49\u0e44\u0e02 \ud83d\udccb \u0e23\u0e32\u0e22\u0e01\u0e32\u0e23\u0e07\u0e32\u0e19\u0e17\u0e31\u0e49\u0e07\u0e2b\u0e21\u0e14 \ud83d\udd04 \u0e23\u0e35\u0e40\u0e1f\u0e23\u0e0a \u0e17\u0e38\u0e01\u0e2a\u0e16\u0e32\u0e19\u0e30NewNotifiedDoneOverdue \u0e01\u0e33\u0e25\u0e31\u0e07\u0e42\u0e2b\u0e25\u0e14&#8230; \u0e23\u0e2b\u0e31\u0e2a \u0e0a\u0e37\u0e48\u0e2d\u0e07\u0e32\u0e19 \u0e1c\u0e39\u0e49\u0e23\u0e31\u0e1a\u0e1c\u0e34\u0e14\u0e0a\u0e2d\u0e1a \u0e01\u0e33\u0e2b\u0e19\u0e14\u0e2a\u0e48\u0e07 \u0e04\u0e27\u0e32\u0e21\u0e2a\u0e33\u0e04\u0e31\u0e0d \u0e2a\u0e16\u0e32\u0e19\u0e30<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","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":1,"href":"https:\/\/jobstracker.nhum.in.th\/index.php?rest_route=\/wp\/v2\/pages\/6\/revisions"}],"predecessor-version":[{"id":8,"href":"https:\/\/jobstracker.nhum.in.th\/index.php?rest_route=\/wp\/v2\/pages\/6\/revisions\/8"}],"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}]}}