{"id":175,"date":"2025-09-16T13:10:06","date_gmt":"2025-09-16T13:10:06","guid":{"rendered":"https:\/\/ictstudentprojects.cqu.org.au\/?page_id=175"},"modified":"2025-10-09T03:21:19","modified_gmt":"2025-10-09T03:21:19","slug":"capstone-project","status":"publish","type":"page","link":"https:\/\/ictstudentprojects.cqu.org.au\/index.php\/capstone-project\/","title":{"rendered":""},"content":{"rendered":"\n<script>\n  \/\/ Make the backend base available to app.js without showing an input in the UI.\n  window.CPFR_CONF = Object.assign(window.CPFR_CONF || {}, {\n    base: \"http:\\\/\\\/localhost:8080\"  });\n<\/script>\n\n<main class=\"container\">\n  <!-- Top Bar -->\n  <div class=\"topbar\">\n    <button id=\"btn-home\" class=\"ghost hidden\">Home<\/button>\n\n    <!-- Admin-only nav (visibility handled by JS) -->\n    <button id=\"btn-admin-eoi\" class=\"ghost hidden\">EOI<\/button>\n    <button id=\"btn-admin-projects\" class=\"ghost hidden\">Projects<\/button>\n\n    <!-- Role buttons -->\n    <button id=\"btn-myeoi\" class=\"ghost hidden\">My EOI<\/button>\n    <button id=\"btn-myprojects\" class=\"ghost hidden\">My Projects<\/button>\n    <button id=\"btn-logout\" class=\"ghost hidden\">Logout<\/button>\n  <\/div>\n\n  <section id=\"panel-login\" class=\"auth-container\">\n    <div class=\"auth-left\">\n      <h1>Welcome<\/h1>\n      <p>Login in to access your projects and manage submissions securely.<\/p>\n    <\/div>\n\n    <div class=\"auth-right \">\n      <h2>Log In<\/h2>\n      <div class=\"grid\">\n        <label>Email<br>\n          <input id=\"email\" type=\"email\" placeholder=\"name@example.edu.au\" autocomplete=\"username\" required>\n        <\/label>\n      <\/div>\n      <div class=\"grid\">\n        <label>Password<br>\n          <input id=\"password\" type=\"password\" placeholder=\"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\" autocomplete=\"current-password\" required>\n        <\/label>\n      <\/div>\n      <div class=\"row\">\n        <button id=\"btn-login\" class=\"primary big\">Log in<\/button>\n      <\/div>\n      <div class=\"row\">\n        <button id=\"btn-show-register\" class=\"success big\">Create new account<\/button>\n      <\/div>\n      <p id=\"login-msg\" class=\"muted\" aria-live=\"polite\"><\/p>\n    <\/div>\n  <\/section>\n\n  <!-- Register Container -->\n  <section id=\"panel-register\" class=\"auth-container hidden\">\n    <div class=\"auth-left\">\n      <h1>Create Account<\/h1>\n      <p>Join the Capstone Portal to submit and review projects seamlessly.<\/p>\n\n    <\/div>\n\n    <div class=\"auth-right \">\n      <h2>Create new account<\/h2>\n      <div class=\"grid\">\n        <label>Full name<br>\n          <input id=\"reg-name\" type=\"text\" placeholder=\"Your name\" autocomplete=\"name\" required>\n        <\/label>\n        <label>Email<br>\n          <input id=\"reg-email\" type=\"email\" placeholder=\"name@example.edu.au\" autocomplete=\"email\" required>\n        <\/label>\n      <\/div>\n      <div class=\"grid\">\n        <label>Password<br>\n          <input id=\"reg-pass\" type=\"password\" placeholder=\"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\" autocomplete=\"new-password\" required\n            minlength=\"6\">\n        <\/label>\n        <label>Confirm password<br>\n          <input id=\"reg-pass2\" type=\"password\" placeholder=\"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\" autocomplete=\"new-password\" required\n            minlength=\"6\">\n        <\/label>\n      <\/div>\n      <div class=\"row\">\n        <label>Role<br>\n          <select id=\"reg-role\" required>\n            <option value=\"STUDENT\">Student<\/option>\n            <option value=\"PROPOSER\">Proposer<\/option>\n            <option value=\"ADMIN\">Admin<\/option>\n          <\/select>\n        <\/label>\n      <\/div>\n      <div class=\"row\">\n        <button id=\"btn-register\" class=\"primary big\">Sign up<\/button>\n        <button id=\"btn-cancel-register\" class=\"ghost\">Back to login<\/button>\n      <\/div>\n      <p id=\"register-msg\" class=\"muted\" aria-live=\"polite\"><\/p>\n    <\/div>\n  <\/section>\n\n  <!-- ====================== ROLE PANELS ====================== -->\n\n  <!-- STUDENT -->\n  <section id=\"panel-student\" class=\"card hidden\" data-role=\"STUDENT\">\n    <h2>Student Dashboard<\/h2>\n    <p class=\"muted\">You are logged in as <span id=\"student-name\">\u2014<\/span>.<\/p>\n\n    <div class=\"row\">\n      <h3 style=\"margin-top:1rem\">Approved Projects<\/h3>\n    <\/div>\n    <p class=\"muted\">Click EOI to send your interest to Admin<\/p>\n    <div class=\"row\" style=\"gap:.5rem;align-items:center;margin:.5rem 0;\">\n      <label>Status&nbsp;\n        <select id=\"student-status-filter\">\n          <option value=\"PENDING\">Pending<\/option>\n          <option value=\"ACCEPTED\">Approved<\/option>\n          <option value=\"AVAILABLE\">Available<\/option>\n        <\/select>\n      <\/label>\n      <span class=\"muted\" id=\"student-filter-count\"><\/span>\n    <\/div>\n    <div class=\"table-wrap\">\n      <table class=\"table\" id=\"stud-catalog-table\" aria-describedby=\"student-msg\">\n        <thead>\n          <tr>\n            <th>No.<\/th>\n            <th>ID<\/th>\n            <th>Project<\/th>\n            <th>Discipline<\/th>\n            <th>Actions<\/th>\n          <\/tr>\n        <\/thead>\n        <tbody id=\"stud-catalog-body\"><\/tbody>\n      <\/table>\n    <\/div>\n    <p id=\"student-msg\" class=\"muted\" aria-live=\"polite\"><\/p>\n  <\/section>\n\n  <!-- My EOI Panel -->\n  <section id=\"panel-myeoi\" class=\"card hidden\">\n    <div class=\"row\">\n      <h3 style=\"margin-top:1rem\">My EOI<\/h3>    \n    <\/div>\n      <p class=\"muted\">Track your Expressions of Interest<\/p>\n    <div class=\"row\" style=\"gap:.5rem;align-items:center;margin:.5rem 0;\">\n      <label>Status&nbsp;\n        <select id=\"student-eoi-filter\">\n          <option value=\"PENDING\">Pending<\/option>\n          <option value=\"ACCEPTED\">Approved<\/option>\n          <option value=\"DECLINED\">Declined<\/option>\n        <\/select>\n      <\/label>\n      <span class=\"muted\" id=\"student-eoi-count\"><\/span>\n    <\/div>\n    <div class=\"table-wrap\">\n      <table class=\"table\" id=\"myeoi-table\">\n        <thead>\n          <tr>\n            <th>No.<\/th>\n            <th>EOI ID<\/th>\n            <th>Project<\/th>\n            <th>Discipline<\/th>\n            <th>Status<\/th>\n            <th>Updated<\/th>\n          <\/tr>\n        <\/thead>\n        <tbody id=\"myeoi-body\"><\/tbody>\n      <\/table>\n    <\/div>\n    <p id=\"myeoi-msg\" class=\"muted\" aria-live=\"polite\"><\/p>\n  <\/section>\n\n  <!-- ====================== ADMIN ====================== -->\n  <section id=\"panel-admin\" class=\"card hidden\">\n    <h2>Admin Dashboard<\/h2>\n\n    <!-- Admin Home stats (6 counters) -->\n    <div class=\"grid stats-grid\" id=\"adm-stats\">\n      <!-- Projects -->\n      <div class=\"stat card-sm\">\n        <div class=\"stat-label\">Pending Projects<\/div>\n        <div id=\"adm-stat-pending\" class=\"stat-value\">0<\/div>\n      <\/div>\n      <div class=\"stat card-sm\">\n        <div class=\"stat-label\">Approved Projects<\/div>\n        <div id=\"adm-stat-approved\" class=\"stat-value\">0<\/div>\n      <\/div>\n      <div class=\"stat card-sm\">\n        <div class=\"stat-label\">Rejected Projects<\/div>\n        <div id=\"adm-stat-rejected\" class=\"stat-value\">0<\/div>\n      <\/div>\n\n      <!-- EOIs -->\n      <div class=\"stat card-sm\">\n        <div class=\"stat-label\">Pending EOIs<\/div>\n        <div id=\"adm-stat-eoi-pending\" class=\"stat-value\">0<\/div>\n      <\/div>\n      <div class=\"stat card-sm\">\n        <div class=\"stat-label\">Accepted EOIs<\/div>\n        <div id=\"adm-stat-eoi-accepted\" class=\"stat-value\">0<\/div>\n      <\/div>\n      <div class=\"stat card-sm\">\n        <div class=\"stat-label\">Declined EOIs<\/div>\n        <div id=\"adm-stat-eoi-declined\" class=\"stat-value\">0<\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"admin-actions\" style=\"margin-top:.75rem\">\n      <button id=\"adm-refresh\" class=\"ghost\">Refresh<\/button>\n    <\/div>\n\n    <!-- EOI Approvals table (visible when clicking EOI tab) -->\n\n\n    <div>\n      <div class=\"row\">\n        <h3 style=\"margin-top:1rem\">EOI<\/h3>\n      <\/div>\n      <div class=\"row\" style=\"gap:.5rem;align-items:center;margin:.5rem 0;\">\n        <label>Status&nbsp;\n          <select id=\"admin-eoi-filter\">\n            <option value=\"PENDING\">Pending<\/option>\n            <option value=\"Declined\">Declined<\/option>\n            <option value=\"Accepted\">Accepted<\/option>\n          <\/select>\n        <\/label>\n        <span class=\"muted\" id=\"admin-eoi-filter-count\"><\/span>\n      <\/div>\n    <\/div>\n    <div class=\"table-wrap\">\n      <table class=\"table\" id=\"adm-eoi-table\">\n        <thead>\n          <tr>\n            <th>No.<\/th>\n            <th>EOI ID<\/th>\n            <th>Project<\/th>\n            <th>Discipline<\/th>\n            <th>Student<\/th>\n            <th>Message<\/th>\n            <th>Contact<\/th>\n            <th>Actions<\/th>\n          <\/tr>\n        <\/thead>\n        <tbody id=\"adm-eoi-body\"><\/tbody>\n      <\/table>\n    <\/div>\n\n    <!-- Pending Projects queue (visible when clicking Projects tab) -->\n    <div>\n      <div class=\"row\">\n        <h3 style=\"margin-top:1rem\">Review Projects<\/h3>\n      <\/div>\n      <div class=\"row\" style=\"gap:.5rem;align-items:center;margin:.5rem 0;\">\n        <label>Status&nbsp;\n          <select id=\"admin-status-filter\">\n            <option value=\"PENDING\">Pending<\/option>\n            <option value=\"REJECTED\">Rejected<\/option>\n            <option value=\"APPROVED\">Approved<\/option>\n          <\/select>\n        <\/label>\n        <span class=\"muted\" id=\"admin-filter-count\"><\/span>\n      <\/div>\n    <\/div>\n    <div class=\"table-wrap\">\n      <table class=\"table\" id=\"adm-queue-table\">\n        <thead>\n          <tr>\n            <th>No.<\/th>\n            <th>ID<\/th>\n            <th>Title<\/th>\n            <th>Discipline<\/th>\n            <th>Email<\/th>\n            <th>Submitted<\/th>\n            <th>Actions<\/th>\n          <\/tr>\n        <\/thead>\n        <tbody id=\"adm-queue-body\">\n          <!-- filled by JS -->\n        <\/tbody>\n      <\/table>\n    <\/div>\n  <\/section>\n\n  <!-- PROPOSER: Editor -->\n  <section id=\"panel-proposer-editor\" class=\"card hidden\" data-role=\"PROPOSER\">\n    <h2 id=\"prop-heading\">Proposer: <span id=\"prop-name\">\u2014<\/span><\/h2>\n\n    <div class=\"grid\">\n      <label>Title<br>\n        <input id=\"p-title\" type=\"text\" placeholder=\"Project title\" required minlength=\"3\">\n      <\/label>\n      <label>Discipline<br>\n        <input id=\"p-discipline\" type=\"text\" placeholder=\"e.g., Software Engineering\" required minlength=\"2\">\n      <\/label>\n    <\/div>\n\n    <div class=\"grid\">\n      <label>Objectives<br>\n        <textarea id=\"p-objectives\" rows=\"5\" placeholder=\"At least 20 characters\" required minlength=\"20\"><\/textarea>\n      <\/label>\n      <label>Expected outcomes<br>\n        <textarea id=\"p-outcomes\" rows=\"5\" placeholder=\"At least 20 characters\" required minlength=\"20\"><\/textarea>\n      <\/label>\n    <\/div>\n\n    <div class=\"row\"><strong>Attachment file (required)<\/strong><\/div>\n    <div class=\"row\">\n      <input id=\"p-current-id\" type=\"hidden\">\n      <input id=\"p-upload-file\" type=\"file\" required>\n    <\/div>\n    <div class=\"row\">\n      <button id=\"btn-save-draft\" class=\"primary\">Save draft<\/button>\n      <button id=\"btn-submit-now\" class=\"success\" disabled>Submit now<\/button>\n      <button id=\"btn-reset-form\" class=\"ghost\">Reset<\/button>\n    <\/div>\n    <p id=\"p-msg\" class=\"muted\" aria-live=\"polite\"><\/p>\n  <\/section>\n\n  <!-- PROPOSER: My Projects -->\n  <section id=\"panel-proposer-list\" class=\"card hidden\" data-role=\"PROPOSER\">\n    <div class=\"row\">\n      <h2>My Projects<\/h2>\n      <button id=\"btn-refresh-mine\" class=\"ghost\">Refresh<\/button>\n    <\/div>\n\n    <div class=\"row\" style=\"gap:.5rem;align-items:center;margin:.5rem 0;\">\n      <label>Status&nbsp;\n        <select id=\"mine-status-filter\">\n          <option value=\"ALL\">All<\/option>\n          <option value=\"DRAFT\">Draft<\/option>\n          <option value=\"PENDING\">Pending<\/option>\n          <option value=\"APPROVED\">Approved<\/option>\n          <option value=\"REJECTED\">Rejected<\/option>\n          <option value=\"WITHDRAWN\">Withdrawn<\/option>\n        <\/select>\n      <\/label>\n      <span class=\"muted\" id=\"mine-filter-count\"><\/span>\n    <\/div>\n\n    <table class=\"table\" id=\"mine-table\">\n      <thead>\n        <tr>\n          <th>ID<\/th>\n          <th>Title<\/th>\n          <th>Status<\/th>\n          <th>Updated<\/th>\n          <th>Actions<\/th>\n        <\/tr>\n      <\/thead>\n      <tbody><\/tbody>\n    <\/table>\n    <p id=\"mine-msg\" class=\"muted\" aria-live=\"polite\"><\/p>\n  <\/section>\n\n  <!-- Toast -->\n  <div id=\"toast\" class=\"toast hidden\" role=\"status\" aria-live=\"polite\"><\/div>\n<\/main>\n\n<!-- Guard for mandatory fields -->\n<script>\n  (function () {\n    const panel = document.getElementById('panel-proposer-editor');\n    const btn = document.getElementById('btn-submit-now');\n    if (!panel || !btn) return;\n\n    const requiredFields = [\n      '#p-title',\n      '#p-discipline',\n      '#p-objectives',\n      '#p-outcomes',\n      '#p-upload-file'\n    ].map(sel => panel.querySelector(sel)).filter(Boolean);\n\n    function isValid(el) {\n      if (el.type === 'file') {\n        return el.files && el.files.length > 0;\n      }\n      if (typeof el.checkValidity === 'function') {\n        return el.checkValidity();\n      }\n      return !!el.value.trim();\n    }\n\n    function updateButton() {\n      const ok = requiredFields.every(isValid);\n      btn.disabled = !ok;\n    }\n\n    requiredFields.forEach(el => {\n      el.addEventListener('input', updateButton);\n      el.addEventListener('change', updateButton);\n    });\n\n    btn.addEventListener('click', e => {\n      if (btn.disabled) {\n        e.preventDefault();\n        e.stopPropagation();\n        requiredFields.find(f => !isValid(f))?.reportValidity?.();\n      }\n    });\n\n    updateButton();\n  })();\n<\/script>\n\n<style>\n  #btn-submit-now[disabled] {\n    opacity: .6;\n    cursor: not-allowed;\n  }\n\n  .stats-grid {\n    display: grid;\n    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n    gap: .75rem;\n    margin-top: .5rem;\n  }\n\n  .stat.card-sm {\n    padding: .75rem .9rem;\n    border-radius: .75rem;\n    background: rgba(255, 255, 255, .03);\n  }\n\n  .stat-label {\n    font-size: .9rem;\n    opacity: .8;\n  }\n\n  .stat-value {\n    font-size: 1.6rem;\n    font-weight: 700;\n    margin-top: .25rem;\n  }\n<\/style>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":8,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-175","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/ictstudentprojects.cqu.org.au\/index.php\/wp-json\/wp\/v2\/pages\/175","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ictstudentprojects.cqu.org.au\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/ictstudentprojects.cqu.org.au\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/ictstudentprojects.cqu.org.au\/index.php\/wp-json\/wp\/v2\/users\/8"}],"replies":[{"embeddable":true,"href":"https:\/\/ictstudentprojects.cqu.org.au\/index.php\/wp-json\/wp\/v2\/comments?post=175"}],"version-history":[{"count":12,"href":"https:\/\/ictstudentprojects.cqu.org.au\/index.php\/wp-json\/wp\/v2\/pages\/175\/revisions"}],"predecessor-version":[{"id":261,"href":"https:\/\/ictstudentprojects.cqu.org.au\/index.php\/wp-json\/wp\/v2\/pages\/175\/revisions\/261"}],"wp:attachment":[{"href":"https:\/\/ictstudentprojects.cqu.org.au\/index.php\/wp-json\/wp\/v2\/media?parent=175"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}