ChatGPT Session in the Making and Source-Code of "[MAIN PROGRAM] UNDONE HOUSEHOLD WORKs WEB-PROGRAM v2/MAIN" POST

ChatGPT SESSION in Making "[MAIN PROGRAM] UNDONE HOUSEHOLD WORKs WEB-PROGRAM v2/MAIN" POST
CLICK HERE !!


SOURCE CODE

<!-- ========================================================= -->
<!-- ========== HELLO FIREBASE TESTER (REMOVABLE BLOCK) ====== -->
<!-- ========== You can delete everything in this box ========= -->
<!-- ========================================================= -->

<div id="test_status" style="
  padding:10px;
  margin:10px 0;
  border:1px solid #aaa;
  border-radius:8px;
  background:#f4f4f4;">
  Waiting to test Firebase…
</div>

<button onclick="testWrite()"
style="padding:8px 12px; border-radius:6px; background:#1976d2; color:white;">
Write Test Data
</button>

<button onclick="testRead()"
style="padding:8px 12px; border-radius:6px; background:#4caf50; color:white;">
Read Test Data
</button>

<button onclick="deleteTester()"
style="padding:8px 12px; border-radius:6px; background:#c62828; color:white;">
Delete Tester Data
</button>

<!-- ========================================================= -->
<!-- ========== END OF HELLO FIREBASE TESTER BLOCK =========== -->
<!-- ========== MAIN APP (CRUD) STARTS BELOW ================= -->
<!-- ========================================================= -->

<!-- ================================ -->
<!--  SIMPLE STYLE (BOX + TABLE)     -->
<!-- ================================ -->
<style>
  .box {
    border:1px solid #aaa;
    padding:15px;
    border-radius:10px;
    margin:15px 0;
    background:#f7f7f7;
  }
  .label {
    font-weight:bold;
    margin-top:10px;
    display:block;
  }
  .btn {
    background:#1976d2;
    color:#fff;
    padding:6px 12px;
    border-radius:5px;
    cursor:pointer;
    margin-top:8px;
    display:inline-block;
    text-decoration:none;
    font-size:14px;
  }
  .btn-red {
    background:#c62828;
    color:#fff;
  }
  input, select, textarea {
    width:100%;
    padding:5px;
    margin-top:6px;
    border:1px solid #888;
    border-radius:6px;
    box-sizing:border-box;
  }
  table {
    width:100%;
    border-collapse:collapse;
    margin-top:20px;
  }
  th, td {
    border:1px solid #aaa;
    padding:8px;
    font-size:14px;
    vertical-align:top;
  }
  th {
    background:#e0e0e0;
  }
</style>

<!-- ================================ -->
<!--  CATEGORY MANAGER (CRUD)        -->
<!-- ================================ -->
<div class="box">
  <h3>Category Manager (CRUD)</h3>

  <label class="label">ADD NEW Category:</label>
  <input id="cat_new_name" placeholder="Example: Household, Maintenance, etc." />
  <div class="btn" onclick="addCategory()">Add Category</div>

  <h4>Existing Categories</h4>
  <table id="cat_table">
    <tr>
      <th>Category</th>
      <th>Actions</th>
    </tr>
  </table>
</div>

<!-- ================================ -->
<!--  TASK CREATOR                   -->
<!-- ================================ -->
<div class="box">
  <h3>Create New Task</h3>

  <label class="label">Task Title:</label>
  <input id="task_title" />

  <label class="label">Category:</label>
  <select id="task_category_select" onchange="onCategorySelectChange('create')">
    <!-- options filled by JS from Categories table -->
  </select>

  <div id="task_category_custom_wrapper" style="display:none;">
    <label class="label">ADD NEW:</label>
    <input id="task_category_custom" placeholder="Custom category name" />
  </div>

  <div class="btn" onclick="createTask()">Create Task</div>
</div>

<!-- ================================ -->
<!--  TASK LIST + CATEGORY FILTER    -->
<!-- ================================ -->
<div class="box">
  <h3>Task List</h3>

  <label class="label">Filter by Category:</label>
  <select id="category_filter" onchange="categoryFilterChanged()">
    <option value="">(All Categories)</option>
  </select>

  <table id="task_table">
    <tr>
      <th>Task ID</th>
      <th>Title</th>
      <th>Category</th>
      <th>Overall Status</th>
      <th>Manage</th>
    </tr>
  </table>
</div>

<!-- ================================ -->
<!--  PHASE MANAGER                  -->
<!-- ================================ -->
<div class="box" id="phase_box" style="display:none;">
  <h3>Phase Manager</h3>
  <div id="phase_task_id"></div>

  <label class="label">Category for this Task:</label>
  <select id="task_category_edit_select" onchange="onCategorySelectChange('edit')">
    <!-- options filled by JS from Categories table -->
  </select>

  <div id="task_category_edit_custom_wrapper" style="display:none;">
    <label class="label">ADD NEW:</label>
    <input id="task_category_edit_custom" placeholder="Custom category name" />
  </div>
  <div class="btn" onclick="saveTaskCategory()">Save Category</div>

  <hr />

  <label class="label">Phase Number:</label>
  <select id="phase_number"></select>

  <label class="label">Phase Status:</label>
  <select id="phase_status"></select>

  <label class="label">Phase Description:</label>
  <textarea id="phase_desc" rows="3"></textarea>

  <div class="btn" onclick="addPhase()">Add Phase</div>

  <h4>Existing Phases:</h4>
  <table id="phase_table">
    <tr>
      <th>Phase</th>
      <th>Status</th>
      <th>Description</th>
    </tr>
  </table>
</div>

<!-- ================================ -->
<!--  SPREADSHEET IMPORTER           -->
<!-- ================================ -->
<div class="box">
  <h3>Upload Spreadsheet → Import to Firebase</h3>
  <p style="font-size:13px;margin-bottom:8px;">
    Expected columns in sheet: <b>Title</b>, <b>Phase Number</b>, <b>Phase Status</b>,
    <b>Description</b>, and optional <b>Category</b>.<br/>
    Value <code>na</code> or <code>not available</code> in Category will be stored as blank.
  </p>
  <input type="file" id="file_input" />
  <div class="btn" onclick="importSheet()">Upload &amp; Import</div>
</div>

<!-- ================================ -->
<!--  SCRIPT LOADING (Firebase + XLSX)-->
<!-- ================================ -->
<script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-database.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>

<!-- ================================ -->
<!--  MAIN APP SCRIPT (CDATA WRAPPED)-->
<!-- ================================ -->
<script type="text/javascript">
//<![CDATA[
(function () {
  var rdb = null;
  var CURRENT_TASK = null;
  var CURRENT_FILTER_CATEGORY = ""; // ""=all, "__blank__"=no category, others=exact value
  var CATEGORIES = []; // {id: "...", name: "Household"}

  var statusBox = document.getElementById("test_status");

  // ---- INITIALIZE FIREBASE ----
  var config = {
    apiKey: "AIzaSyAF5r6Rvu-DmoV-vf47wYTZfarpVGmNYR0",
    authDomain: "ronin-11938.firebaseapp.com",
    databaseURL: "https://ronin-11938-default-rtdb.firebaseio.com",
    projectId: "ronin-11938",
    storageBucket: "ronin-11938.firebasestorage.app",
    messagingSenderId: "823368889742",
    appId: "1:823368889742:web:609e16ace214b94a0df"
  };

  try {
    if (firebase.apps && firebase.apps.length > 0) {
      firebase.app();
    } else {
      firebase.initializeApp(config);
    }
  } catch (e) {}

  rdb = firebase.database();
  if (statusBox) {
    statusBox.innerHTML = "<b>Firebase initialized!</b><br>Try writing or reading.";
  }

  // ---- TEST WRITE ----
  window.testWrite = function () {
    if (!rdb) { alert("Firebase not ready yet."); return; }
    var testId = "hello_" + new Date().getTime();
    rdb.ref("TESTER/" + testId).set({
      msg: "Hello from Blogger!",
      time: new Date().toString()
    }).then(function () {
      if (statusBox) {
        statusBox.innerHTML = "<b>Write Success!</b><br>Data written under: TESTER/" + testId;
      } else {
        alert("Write Success: TESTER/" + testId);
      }
    }).catch(function (err) {
      if (statusBox) {
        statusBox.innerHTML = "<b>Write Error:</b> " + err;
      } else {
        alert("Write Error: " + err);
      }
    });
  };

  // ---- TEST READ ----
  window.testRead = function () {
    if (!rdb) { alert("Firebase not ready yet."); return; }
    rdb.ref("TESTER").limitToLast(1).once("value").then(function (snap) {
      var data = snap.val();
      if (statusBox) {
        statusBox.innerHTML = "<b>Read Success!</b><br>Latest entry:<br>"
          + JSON.stringify(data, null, 2);
      } else {
        alert("Read Success: " + JSON.stringify(data));
      }
    }).catch(function (err) {
      if (statusBox) {
        statusBox.innerHTML = "<b>Read Error:</b> " + err;
      } else {
        alert("Read Error: " + err);
      }
    });
  };

  // ---- TEST DELETE ----
  window.deleteTester = function () {
    if (!rdb) { alert("Firebase not ready yet."); return; }
    if (!confirm("Delete all TESTER data?")) return;
    rdb.ref("TESTER").remove().then(function () {
      if (statusBox) {
        statusBox.innerHTML = "<b>TESTER data deleted.</b>";
      } else {
        alert("TESTER data deleted.");
      }
    }).catch(function (err) {
      if (statusBox) {
        statusBox.innerHTML = "<b>Delete Error:</b> " + err;
      } else {
        alert("Delete Error: " + err);
      }
    });
  };

  // ------------------------------
  // Normalize category (handles "na" / "not available")
  // ------------------------------
  function normalizeCategory(value) {
    if (!value) return "";
    var v = ("" + value).replace(/^\s+|\s+$/g, "").toLowerCase();
    if (v === "na" || v === "not available") return "";
    return ("" + value).replace(/^\s+|\s+$/g, "");
  }

  // ------------------------------
  // Phase dropdown generators
  // ------------------------------
  function setupPhaseDropdowns() {
    var phaseSelect = document.getElementById("phase_number");
    var statusSelect = document.getElementById("phase_status");
    if (!phaseSelect || !statusSelect) return;

    var i, suffix;
    for (i = 1; i <= 20; i++) {
      if (i === 1) suffix = "1st phase";
      else if (i === 2) suffix = "2nd phase";
      else if (i === 3) suffix = "3rd phase";
      else suffix = i + "th phase";

      var opt = document.createElement("option");
      opt.value = suffix;
      opt.appendChild(document.createTextNode(suffix));
      phaseSelect.appendChild(opt);
    }

    var optDone = document.createElement("option");
    optDone.value = "done!";
    optDone.appendChild(document.createTextNode("done!"));
    statusSelect.appendChild(optDone);

    var optNY = document.createElement("option");
    optNY.value = "not yet";
    optNY.appendChild(document.createTextNode("not yet"));
    statusSelect.appendChild(optNY);
  }

  // ------------------------------
  // CATEGORY CRUD
  // ------------------------------
  function loadCategories() {
    if (!rdb) return;
    rdb.ref("Categories").once("value").then(function (snap) {
      var data = snap.val() || {};
      CATEGORIES = [];
      var id;

      for (id in data) {
        if (!data.hasOwnProperty(id)) continue;
        var name = normalizeCategory(data[id].name || "");
        if (name) {
          CATEGORIES.push({ id: id, name: name });
        }
      }

      // If no categories yet, create defaults once
      if (CATEGORIES.length === 0) {
        var defaults = ["Household", "Maintenance", "Office", "Personal"];
        for (var i = 0; i < defaults.length; i++) {
          var ref = rdb.ref("Categories").push();
          ref.set({ name: defaults[i] });
        }
        loadCategories();
        return;
      }

      buildCategoryManagerTable();
      rebuildCategoryDropdowns();
      loadTasks();
    });
  }

  function buildCategoryManagerTable() {
    var table = document.getElementById("cat_table");
    if (!table) return;

    table.innerHTML =
      "<tr>" +
      "<th>Category</th>" +
      "<th>Actions</th>" +
      "</tr>";

    for (var i = 0; i < CATEGORIES.length; i++) {
      var cat = CATEGORIES[i];
      var row = table.insertRow(-1);

      var c1 = row.insertCell(0);
      var c2 = row.insertCell(1);

      c1.appendChild(document.createTextNode(cat.name));

      var btnDel = document.createElement("span");
      btnDel.className = "btn btn-red";
      btnDel.appendChild(document.createTextNode("Delete"));
      btnDel.setAttribute("onclick", "deleteCategory('" + cat.id + "')");
      c2.appendChild(btnDel);
    }
  }

  function addCategory() {
    if (!rdb) { alert("Firebase not ready yet."); return; }
    var input = document.getElementById("cat_new_name");
    if (!input) return;
    var name = normalizeCategory(input.value || "");
    if (!name) {
      alert("Category name is empty or invalid.");
      return;
    }
    var ref = rdb.ref("Categories").push();
    ref.set({ name: name }).then(function () {
      input.value = "";
      loadCategories();
    }).catch(function (err) {
      alert("Error adding category: " + err);
    });
  }

  function deleteCategory(catId) {
    if (!rdb) return;
    if (!confirm("Delete this category? This will NOT change existing tasks' category strings.")) return;
    rdb.ref("Categories/" + catId).remove().then(function () {
      loadCategories();
    }).catch(function (err) {
      alert("Error deleting category: " + err);
    });
  }

  function rebuildCategoryDropdowns() {
    var selCreate = document.getElementById("task_category_select");
    var selEdit = document.getElementById("task_category_edit_select");

    function fillDropdown(sel, includeCustom) {
      if (!sel) return;
      sel.innerHTML = "";

      var optNone = document.createElement("option");
      optNone.value = "__none__";
      optNone.appendChild(document.createTextNode("(none)"));
      sel.appendChild(optNone);

      for (var i = 0; i < CATEGORIES.length; i++) {
        var cat = CATEGORIES[i];
        var o = document.createElement("option");
        o.value = cat.name;
        o.appendChild(document.createTextNode(cat.name));
        sel.appendChild(o);
      }

      if (includeCustom) {
        var optCustom = document.createElement("option");
        optCustom.value = "__custom__";
        optCustom.appendChild(document.createTextNode("Custom (ADD NEW)"));
        sel.appendChild(optCustom);
      }
    }

    fillDropdown(selCreate, true);
    fillDropdown(selEdit, true);
  }

  // ------------------------------
  // Category dropdown change (show/hide custom input)
  // ------------------------------
  function onCategorySelectChange(mode) {
    if (mode === "create") {
      var sel = document.getElementById("task_category_select");
      var wrap = document.getElementById("task_category_custom_wrapper");
      if (!sel || !wrap) return;
      if (sel.value === "__custom__") {
        wrap.style.display = "block";
      } else {
        wrap.style.display = "none";
        var inp = document.getElementById("task_category_custom");
        if (inp) inp.value = "";
      }
    } else if (mode === "edit") {
      var sel2 = document.getElementById("task_category_edit_select");
      var wrap2 = document.getElementById("task_category_edit_custom_wrapper");
      if (!sel2 || !wrap2) return;
      if (sel2.value === "__custom__") {
        wrap2.style.display = "block";
      } else {
        wrap2.style.display = "none";
        var inp2 = document.getElementById("task_category_edit_custom");
        if (inp2) inp2.value = "";
      }
    }
  }

  // ------------------------------
  // Get final category from dropdown + custom input
  // ------------------------------
  function resolveCategory(mode) {
    if (mode === "create") {
      var sel = document.getElementById("task_category_select");
      var inp = document.getElementById("task_category_custom");
      var val = sel ? sel.value : "__none__";
      if (val === "__custom__") {
        var custom = inp ? normalizeCategory(inp.value || "") : "";
        return custom;
      } else if (val === "__none__") {
        return "";
      } else {
        return normalizeCategory(val);
      }
    } else if (mode === "edit") {
      var sel2 = document.getElementById("task_category_edit_select");
      var inp2 = document.getElementById("task_category_edit_custom");
      var val2 = sel2 ? sel2.value : "__none__";
      if (val2 === "__custom__") {
        var custom2 = inp2 ? normalizeCategory(inp2.value || "") : "";
        return custom2;
      } else if (val2 === "__none__") {
        return "";
      } else {
        return normalizeCategory(val2);
      }
    }
    return "";
  }

  function setEditCategoryUI(catVal) {
    var sel = document.getElementById("task_category_edit_select");
    var wrap = document.getElementById("task_category_edit_custom_wrapper");
    var inp = document.getElementById("task_category_edit_custom");
    if (!sel || !wrap || !inp) return;

    var clean = normalizeCategory(catVal || "");

    if (!clean) {
      sel.value = "__none__";
      wrap.style.display = "none";
      inp.value = "";
      return;
    }

    var found = false;
    for (var i = 0; i < CATEGORIES.length; i++) {
      if (CATEGORIES[i].name === clean) {
        sel.value = clean;
        found = true;
        break;
      }
    }

    if (found) {
      wrap.style.display = "none";
      inp.value = "";
    } else {
      sel.value = "__custom__";
      wrap.style.display = "block";
      inp.value = clean;
    }
  }

  // ------------------------------
  // Create Task (global)
  // ------------------------------
  function createTask() {
    if (!rdb) { alert("Firebase not ready yet."); return; }

    var titleInput = document.getElementById("task_title");
    var title = titleInput ? titleInput.value : "";
    title = title.replace(/^\s+|\s+$/g, "");

    if (!title) {
      alert("Task title is empty.");
      return;
    }

    var category = resolveCategory("create");
    var taskId = (new Date().getTime()).toString();

    rdb.ref("Tasks/" + taskId).set({
      task_title: title,
      category: category,
      overall_status: "ongoing"
    }).then(function () {
      alert("Task created!");
      if (titleInput) titleInput.value = "";
      var inpCustom = document.getElementById("task_category_custom");
      if (inpCustom) inpCustom.value = "";
      var sel = document.getElementById("task_category_select");
      if (sel) sel.value = "__none__";
      onCategorySelectChange("create");
      loadTasks();
    }).catch(function (err) {
      alert("Error creating task: " + err);
    });
  }

  // ------------------------------
  // Load Tasks
  // ------------------------------
  function loadTasks() {
    var table = document.getElementById("task_table");
    var selFilter = document.getElementById("category_filter");
    if (!table || !rdb) return;

    table.innerHTML =
      "<tr>" +
      "<th>Task ID</th>" +
      "<th>Title</th>" +
      "<th>Category</th>" +
      "<th>Overall Status</th>" +
      "<th>Manage</th>" +
      "</tr>";

    rdb.ref("Tasks").once("value").then(function (snap) {
      var data = snap.val() || {};

      if (selFilter) {
        var existing = {};
        var id;
        for (id in data) {
          if (!data.hasOwnProperty(id)) continue;
          var catVal = normalizeCategory(data[id].category || "");
          if (catVal) existing[catVal] = true;
        }
        selFilter.innerHTML = "";
        var optAll = document.createElement("option");
        optAll.value = "";
        optAll.appendChild(document.createTextNode("(All Categories)"));
        selFilter.appendChild(optAll);

        var optBlank = document.createElement("option");
        optBlank.value = "__blank__";
        optBlank.appendChild(document.createTextNode("(No Category)"));
        selFilter.appendChild(optBlank);

        var catsList = [];
        var c;
        for (c in existing) {
          if (existing.hasOwnProperty(c)) catsList.push(c);
        }
        catsList.sort();
        for (var i = 0; i < catsList.length; i++) {
          var o = document.createElement("option");
          o.value = catsList[i];
          o.appendChild(document.createTextNode(catsList[i]));
          selFilter.appendChild(o);
        }

        var j;
        for (j = 0; j < selFilter.options.length; j++) {
          if (selFilter.options[j].value === CURRENT_FILTER_CATEGORY) {
            selFilter.selectedIndex = j;
            break;
          }
        }
      }

      var tid;
      for (tid in data) {
        if (!data.hasOwnProperty(tid)) continue;
        var t = data[tid];
        var catClean = normalizeCategory(t.category || "");

        if (CURRENT_FILTER_CATEGORY === "__blank__") {
          if (catClean) continue;
        } else if (CURRENT_FILTER_CATEGORY) {
          if (catClean !== CURRENT_FILTER_CATEGORY) continue;
        }

        var row = table.insertRow(-1);
        var c1 = row.insertCell(0);
        var c2 = row.insertCell(1);
        var c3 = row.insertCell(2);
        var c4 = row.insertCell(3);
        var c5 = row.insertCell(4);

        c1.appendChild(document.createTextNode(tid));
        c2.appendChild(document.createTextNode(t.task_title || ""));
        c3.appendChild(document.createTextNode(catClean || ""));
        c4.appendChild(document.createTextNode(t.overall_status || ""));

        var btn = document.createElement("span");
        btn.className = "btn";
        btn.appendChild(document.createTextNode("Phases"));
        btn.setAttribute("onclick", "openPhaseEditor('" + tid + "')");
        c5.appendChild(btn);
      }
    });
  }

  function categoryFilterChanged() {
    var sel = document.getElementById("category_filter");
    if (!sel) return;
    CURRENT_FILTER_CATEGORY = sel.value || "";
    loadTasks();
  }

  function loadTaskCategory(taskId) {
    if (!rdb) return;
    rdb.ref("Tasks/" + taskId).once("value").then(function (snap) {
      var t = snap.val() || {};
      var cat = normalizeCategory(t.category || "");
      setEditCategoryUI(cat);
    });
  }

  function saveTaskCategory() {
    if (!rdb) { alert("Firebase not ready yet."); return; }
    if (!CURRENT_TASK) { alert("No task selected."); return; }

    var cat = resolveCategory("edit");
    rdb.ref("Tasks/" + CURRENT_TASK).update({
      category: cat
    }).then(function () {
      alert("Category updated.");
      loadTasks();
    }).catch(function (err) {
      alert("Error updating category: " + err);
    });
  }

  function openPhaseEditor(taskId) {
    CURRENT_TASK = taskId;
    var infoDiv = document.getElementById("phase_task_id");
    if (infoDiv) {
      infoDiv.innerHTML = "<b>Task ID:</b> " + taskId;
    }
    var box = document.getElementById("phase_box");
    if (box) {
      box.style.display = "block";
    }

    loadTaskCategory(taskId);
    loadPhases(taskId);
  }

  function addPhase() {
    if (!rdb) { alert("Firebase not ready yet."); return; }
    if (!CURRENT_TASK) { alert("No task selected."); return; }

    var pnEl = document.getElementById("phase_number");
    var psEl = document.getElementById("phase_status");
    var descEl = document.getElementById("phase_desc");

    var pn = pnEl ? pnEl.value : "";
    var ps = psEl ? psEl.value : "";
    var desc = descEl ? descEl.value : "";
    if (!pn) { alert("Choose phase number."); return; }
    if (!ps) { alert("Choose phase status."); return; }

    var phaseId = (new Date().getTime()).toString();

    var updates = {};
    updates["TaskPhases/" + CURRENT_TASK + "/" + phaseId] = true;
    updates["PhaseDetails/" + phaseId] = {
      task_id: CURRENT_TASK,
      phase_number: pn,
      phase_status: ps,
      phase_description: desc
    };

    rdb.ref().update(updates).then(function () {
      updateOverallStatus(CURRENT_TASK);
      loadPhases(CURRENT_TASK);
      alert("Phase added.");
      if (descEl) descEl.value = "";
    }).catch(function (err) {
      alert("Error adding phase: " + err);
    });
  }

  function loadPhases(taskId) {
    var table = document.getElementById("phase_table");
    if (!table || !rdb) return;

    table.innerHTML =
      "<tr>" +
      "<th>Phase</th>" +
      "<th>Status</th>" +
      "<th>Description</th>" +
      "</tr>";

    rdb.ref("TaskPhases/" + taskId).once("value").then(function (snap) {
      var map = snap.val();
      if (!map) return;

      var pid;
      for (pid in map) {
        if (!map.hasOwnProperty(pid)) continue;

        (function (pidCopy) {
          rdb.ref("PhaseDetails/" + pidCopy).once("value").then(function (psnap) {
            var ph = psnap.val();
            if (!ph) return;

            var row = table.insertRow(-1);
            var c1 = row.insertCell(0);
            var c2 = row.insertCell(1);
            var c3 = row.insertCell(2);

            c1.appendChild(document.createTextNode(ph.phase_number || ""));
            c2.appendChild(document.createTextNode(ph.phase_status || ""));
            c3.appendChild(document.createTextNode(ph.phase_description || ""));
          });
        })(pid);
      }
    });
  }

  function updateOverallStatus(taskId) {
    if (!rdb) return;

    var phaseListRef = rdb.ref("TaskPhases/" + taskId);
    phaseListRef.once("value").then(function (snapshot) {
      var phaseIds = snapshot.val();
      if (!phaseIds) return;

      var total = 0;
      var doneCount = 0;
      var promises = [];

      var pid;
      for (pid in phaseIds) {
        if (!phaseIds.hasOwnProperty(pid)) continue;

        (function (pidCopy) {
          var p = rdb.ref("PhaseDetails/" + pidCopy).once("value").then(function (ps) {
            var v = ps.val();
            total++;
            if (v && v.phase_status === "done!") {
              doneCount++;
            }
          });
          promises.push(p);
        })(pid);
      }

      Promise.all(promises).then(function () {
        var newStatus = (total > 0 && total === doneCount) ? "finished" : "ongoing";
        rdb.ref("Tasks/" + taskId).update({ overall_status: newStatus }).then(function () {
          loadTasks();
        });
      });
    });
  }

  function importSheet() {
    if (!rdb) { alert("Firebase not ready yet."); return; }
    var input = document.getElementById("file_input");
    if (!input || !input.files || input.files.length === 0) {
      alert("Please choose a file first.");
      return;
    }

    var file = input.files[0];
    var reader = new FileReader();

    reader.onload = function (e) {
      var data = new Uint8Array(e.target.result);
      var workbook = XLSX.read(data, { type: "array" });
      var firstSheetName = workbook.SheetNames[0];
      var ws = workbook.Sheets[firstSheetName];
      var rows = XLSX.utils.sheet_to_json(ws, { defval: "" });

      if (!rows || rows.length === 0) {
        alert("Sheet is empty or headers are missing.");
        return;
      }

      var i;
      for (i = 0; i < rows.length; i++) {
        var row = rows[i];
        var title = row["Title"] || "";
        if (!title) continue;

        var phaseNumber = row["Phase Number"] || "1st phase";
        var phaseStatus = row["Phase Status"] || "not yet";
        var desc = row["Description"] || "";
        var categoryRaw = row["Category"] || "";
        var category = normalizeCategory(categoryRaw);

        var taskId = (new Date().getTime()).toString() + "_" + i;
        var phaseId = (new Date().getTime() + i + 1).toString();

        var updates = {};
        updates["Tasks/" + taskId] = {
          task_title: title,
          category: category,
          overall_status: "ongoing"
        };
        updates["TaskPhases/" + taskId + "/" + phaseId] = true;
        updates["PhaseDetails/" + phaseId] = {
          task_id: taskId,
          phase_number: phaseNumber,
          phase_status: phaseStatus,
          phase_description: desc
        };

        rdb.ref().update(updates);
        updateOverallStatus(taskId);
      }

      alert("Import finished. Check Task List.");
      loadTasks();
    };

    reader.readAsArrayBuffer(file);
  }

  window.createTask = createTask;
  window.openPhaseEditor = openPhaseEditor;
  window.addPhase = addPhase;
  window.importSheet = importSheet;
  window.categoryFilterChanged = categoryFilterChanged;
  window.addCategory = addCategory;
  window.deleteCategory = deleteCategory;
  window.onCategorySelectChange = onCategorySelectChange;
  window.saveTaskCategory = saveTaskCategory;

  function initApp() {
    setupPhaseDropdowns();
    loadCategories();
  }

  if (document.readyState === "complete" || document.readyState === "interactive") {
    setTimeout(initApp, 0);
  } else {
    document.addEventListener("DOMContentLoaded", initApp);
  }

})();
//]]>
</script>

Comments

Popular posts from this blog

[MAIN PROGRAM] UNDONE HOUSEHOLD WORKs WEB-PROGRAM v2/MAIN

PENDING ITEMs [REVISION] v0