From fd2e4909f6563e493048bbad9eb00ccd0cc70ab2 Mon Sep 17 00:00:00 2001 From: Katrina Wheelan <katrina.wheelan@detroitmi.gov> Date: Thu, 18 Jul 2024 16:44:50 -0400 Subject: [PATCH 1/4] #22 added place to save edit status of funds --- src/index.html | 2 +- src/js/components/table/subcomponents/data.js | 2 +- src/js/utils/data_utils/budget_data_handlers.js | 8 +++++--- src/js/views/02_baseline_landing_page/helpers.js | 4 ++-- src/js/views/08_summary/helpers.js | 3 ++- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/index.html b/src/index.html index 4eb97e9..e85b8dc 100644 --- a/src/index.html +++ b/src/index.html @@ -94,7 +94,7 @@ <h3 id="supp-title" class="accordion-title"> <div class="accordion summary-accordion"></div> </div> <div class="add-init-btn-div"> - <button class="btn btn-add-init">Add another initiative</button> + <button class="btn btn-add-init">Add new initiative</button> </div> </div> diff --git a/src/js/components/table/subcomponents/data.js b/src/js/components/table/subcomponents/data.js index 9342721..7f28afb 100644 --- a/src/js/components/table/subcomponents/data.js +++ b/src/js/components/table/subcomponents/data.js @@ -62,7 +62,7 @@ function loadFunds(){ for (const key in fundDict) { if (fundDict.hasOwnProperty(key)) { resultArray.push({ - Fund: fundDict[key] // Use the value directly + Fund: fundDict[key]['name'] // Use the value directly }); } } diff --git a/src/js/utils/data_utils/budget_data_handlers.js b/src/js/utils/data_utils/budget_data_handlers.js index 598af9e..01e7426 100644 --- a/src/js/utils/data_utils/budget_data_handlers.js +++ b/src/js/utils/data_utils/budget_data_handlers.js @@ -8,13 +8,14 @@ export const FundLookupTable = { update : function(fundData){ const table = this.retrieve(); for (let fund of Object.keys(fundData)){ - // fund = toString(fund); // add to lookup table if not in there already if (!table[fund]){ // get fund name const fundName = fundData[fund][0]['Fund Name']; // add fund to dictionary - table[fund] = fundName; + table[fund] = {}; + table[fund]['name'] = fundName; + table[fund]['viewed'] = false; } } // save any updates @@ -24,7 +25,8 @@ export const FundLookupTable = { this.save({}); }, getName : function(number){ - return this.retrieve()[number]; + if(number == '') { return '' }; + return this.retrieve()[number]['name']; }, listFunds : function(){ return Object.keys(this.retrieve()); diff --git a/src/js/views/02_baseline_landing_page/helpers.js b/src/js/views/02_baseline_landing_page/helpers.js index 6963fcd..a1d60e4 100644 --- a/src/js/views/02_baseline_landing_page/helpers.js +++ b/src/js/views/02_baseline_landing_page/helpers.js @@ -41,8 +41,8 @@ function allowRowSelection(){ }); } -export async function initializeFundTable(){ - await Table.Data.loadFunds(); +export function initializeFundTable(){ + Table.Data.loadFunds(); Table.adjustWidth('30%'); Table.show(); Table.Columns.assignClasses(fundCols); diff --git a/src/js/views/08_summary/helpers.js b/src/js/views/08_summary/helpers.js index 933e034..0315209 100644 --- a/src/js/views/08_summary/helpers.js +++ b/src/js/views/08_summary/helpers.js @@ -16,7 +16,7 @@ export function summaryView(){ // prompt buttons Prompt.Buttons.Right.updateText('Download Excel'); - Prompt.Buttons.Left.updateText('Go back to home'); + Prompt.Buttons.Left.updateText('Start over'); // add button links Prompt.Buttons.Left.addAction(returnToWelcome); Prompt.Buttons.Right.addAction(downloadXLSX); @@ -47,4 +47,5 @@ const returnToWelcome = () => {visitPage('welcome')} export function disablePromptButtons(){ Prompt.Buttons.Left.removeAction(returnToWelcome); Prompt.Buttons.Right.removeAction(downloadXLSX); + Prompt.Buttons.Right.enable(); } \ No newline at end of file From 02a4939b19cc16ff2712b9c5edb0c58d732d309a Mon Sep 17 00:00:00 2001 From: Katrina Wheelan <katrina.wheelan@detroitmi.gov> Date: Fri, 19 Jul 2024 12:20:15 -0400 Subject: [PATCH 2/4] #22 FundLookUp table records viewed funds; updated logic to cycle through funds --- src/js/components/accordion/accordion.css | 4 +-- src/js/components/nav_buttons/nav_buttons.js | 8 +++++- src/js/components/table/subcomponents/data.js | 18 +++++++------ src/js/utils/common_utils.js | 8 ------ .../utils/data_utils/budget_data_handlers.js | 23 +++++++++++++++++ src/js/views/03_revenue/helpers.js | 6 ++--- src/js/views/06_nonpersonnel/helpers.js | 5 ++-- src/js/views/07_new_initiatives/helpers.js | 6 ++--- src/js/views/view_logic.js | 25 +++++++++++-------- 9 files changed, 64 insertions(+), 39 deletions(-) diff --git a/src/js/components/accordion/accordion.css b/src/js/components/accordion/accordion.css index 45257e7..998772e 100644 --- a/src/js/components/accordion/accordion.css +++ b/src/js/components/accordion/accordion.css @@ -18,7 +18,7 @@ .accordion-table { width: 100%; - font-size: 1.25em; + font-size: 1.2em; /* border-collapse: separate; This is required for rounded corners */ } @@ -49,7 +49,7 @@ span.amount { } .accordion-header button { - font-size: 0.8em; + font-size: 0.6em; } .btn-add-init { diff --git a/src/js/components/nav_buttons/nav_buttons.js b/src/js/components/nav_buttons/nav_buttons.js index e3c6e16..4d9d362 100644 --- a/src/js/components/nav_buttons/nav_buttons.js +++ b/src/js/components/nav_buttons/nav_buttons.js @@ -31,7 +31,13 @@ function enable(button_id) { const Next = { disable : function() { disable('btn-next') }, - enable : function() { enable('btn-next') } + enable : function() { enable('btn-next') }, + addAction : function(fn) { + document.querySelector(`#btn-next`).addEventListener('click', fn); + }, + removeAction : function(fn) { + document.querySelector(`#btn-next`).removeEventListener('click', fn); + }, } const Last = { diff --git a/src/js/components/table/subcomponents/data.js b/src/js/components/table/subcomponents/data.js index 7f28afb..a12a68d 100644 --- a/src/js/components/table/subcomponents/data.js +++ b/src/js/components/table/subcomponents/data.js @@ -58,15 +58,17 @@ function loadFunds(){ // get list of funds from storage const fundDict = FundLookupTable.retrieve(); // build out data in correct format - const resultArray = []; - for (const key in fundDict) { - if (fundDict.hasOwnProperty(key)) { - resultArray.push({ - Fund: fundDict[key]['name'] // Use the value directly - }); + const ret = []; + Object.keys(fundDict).forEach(key => { + // determine if the fund has already been edited + if (fundDict[key]['viewed']){ + // todo: add a checkmark here + ret.push({'Fund' : fundDict[key]['name'] + ' (Edited)'}); + } else { + ret.push({'Fund' : fundDict[key]['name']}); } - } - fillTable(resultArray); + }); + fillTable(ret); } diff --git a/src/js/utils/common_utils.js b/src/js/utils/common_utils.js index 17e13a4..3e92ad2 100644 --- a/src/js/utils/common_utils.js +++ b/src/js/utils/common_utils.js @@ -32,14 +32,6 @@ export function displayWithCommas(value) { return formatCurrency(value).replace('$', ''); } -function delay(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - -export async function pauseExecution(seconds) { - await delay(seconds * 1000); // convert to milliseconds -} - export function cleanString(str){ return str.toLowerCase().replaceAll(' ', '-'); } diff --git a/src/js/utils/data_utils/budget_data_handlers.js b/src/js/utils/data_utils/budget_data_handlers.js index 01e7426..0a80041 100644 --- a/src/js/utils/data_utils/budget_data_handlers.js +++ b/src/js/utils/data_utils/budget_data_handlers.js @@ -30,6 +30,29 @@ export const FundLookupTable = { }, listFunds : function(){ return Object.keys(this.retrieve()); + }, + editFund : function(fund){ + const table = this.retrieve(); + if (table[fund]){ + table[fund]['viewed'] = true; + this.save(table); + } else { + console.error('No fund selected.'); + } + + }, + listUneditedFunds : function(){ + const table = this.retrieve(); + const ret = []; + this.listFunds().forEach(key => { + if (!table[key]['viewed']){ + ret.push(key); + } + }); + return ret; + }, + fundsLeft : function(){ + return (this.listUneditedFunds().length > 0); } } diff --git a/src/js/views/03_revenue/helpers.js b/src/js/views/03_revenue/helpers.js index 47d8d2e..06709c5 100644 --- a/src/js/views/03_revenue/helpers.js +++ b/src/js/views/03_revenue/helpers.js @@ -3,7 +3,7 @@ import { formatCurrency } from '../../utils/common_utils.js' import { REVENUE } from '../../init.js' import Body from '../../components/body/body.js' import NavButtons from '../../components/nav_buttons/nav_buttons.js' -import { pauseAndContinue } from '../view_logic.js' +import { nextPage } from '../view_logic.js' import Subtitle from '../../components/header/header.js' import Modal from '../../components/modal/modal.js' import Form from '../../components/form/form.js' @@ -23,7 +23,7 @@ export function preparePageView(){ export function setUpNavButtons(){ // clicking 'confirm' will also take us to the next page - Prompt.Buttons.Left.addAction(pauseAndContinue); + Prompt.Buttons.Left.addAction(nextPage); // TODO: allow user to edit revenue here Modal.Link.add('option2'); handleErrorComment(); @@ -31,7 +31,7 @@ export function setUpNavButtons(){ export function removeButtonEvents(){ // remove event listeners on prompt buttons - Prompt.Buttons.Left.removeAction(pauseAndContinue); + Prompt.Buttons.Left.removeAction(nextPage); Modal.Link.remove('option2'); } diff --git a/src/js/views/06_nonpersonnel/helpers.js b/src/js/views/06_nonpersonnel/helpers.js index c31d998..a24a960 100644 --- a/src/js/views/06_nonpersonnel/helpers.js +++ b/src/js/views/06_nonpersonnel/helpers.js @@ -4,6 +4,8 @@ import Table from "../../components/table/table.js"; import Body from "../../components/body/body.js"; import NavButtons from "../../components/nav_buttons/nav_buttons.js"; import Subtitle from "../../components/header/header.js"; +import { FundLookupTable } from "../../utils/data_utils/budget_data_handlers.js"; +import { CurrentFund } from "../../utils/data_utils/local_storage_handlers.js"; const nonPersonnelColumns = [ { title: 'FY26 Request', className: 'request', isCost: true }, @@ -26,9 +28,6 @@ export function preparePageView(){ // update page text Subtitle.update('Non-Personnel'); Prompt.Text.update('Select an action item for each non-personnel line item from last year.'); - - // just enable next for now - // TODO: only enable when all info is entered NavButtons.Next.enable(); } diff --git a/src/js/views/07_new_initiatives/helpers.js b/src/js/views/07_new_initiatives/helpers.js index 7e65a27..62ee00e 100644 --- a/src/js/views/07_new_initiatives/helpers.js +++ b/src/js/views/07_new_initiatives/helpers.js @@ -5,7 +5,7 @@ import Form from '../../components/form/form.js' import Table from '../../components/table/table.js' import Body from '../../components/body/body.js' import NavButtons from '../../components/nav_buttons/nav_buttons.js' -import { pauseAndContinue } from '../view_logic.js' +import { nextPage } from '../view_logic.js' import Subtitle from '../../components/header/header.js' import Sidebar from '../../components/sidebar/sidebar.js' @@ -28,7 +28,7 @@ export function initializePageView() { Prompt.Buttons.Left.updateText('Yes'); Prompt.Buttons.Right.updateText('No'); // clicking 'no new initialitives' will also take us to the next page - Prompt.Buttons.Right.addAction(pauseAndContinue); + Prompt.Buttons.Right.addAction(nextPage); Prompt.Buttons.Left.addAction(NavButtons.Next.enable); } @@ -114,7 +114,7 @@ export function removeModalLinks(){ } export function removePromptButtonListeners(){ - Prompt.Buttons.Right.removeAction(pauseAndContinue); + Prompt.Buttons.Right.removeAction(nextPage); Prompt.Buttons.Left.removeAction(NavButtons.Next.enable); Modal.clear(); } \ No newline at end of file diff --git a/src/js/views/view_logic.js b/src/js/views/view_logic.js index f4a9448..581483c 100644 --- a/src/js/views/view_logic.js +++ b/src/js/views/view_logic.js @@ -7,9 +7,8 @@ import { loadNonpersonnelPage } from './06_nonpersonnel/main.js'; import { loadBaselineLandingPage } from './02_baseline_landing_page/main.js'; import { cleanUpSummaryPage, loadSummaryPage } from './08_summary/main.js'; import { loadUploadPage } from './01_upload/main.js'; -import { pauseExecution } from '../utils/common_utils.js'; - -import { CurrentPage } from '../utils/data_utils/local_storage_handlers.js'; +import { CurrentPage, CurrentFund } from '../utils/data_utils/local_storage_handlers.js'; +import { FundLookupTable } from '../utils/data_utils/budget_data_handlers.js'; export let PAGES = { 'welcome' : initializeWelcomePage, @@ -50,10 +49,19 @@ export function nextPage(){ // clean up current page if (CLEANUP[page_state]) { CLEANUP[page_state]() }; - - // Check if there is a next key + + // if on non-personnel, circle back to fund selection unless all funds are edited + if (CurrentPage.load() == 'nonpersonnel'){ + // mark fund as viewed/edited + FundLookupTable.editFund(CurrentFund.number()); + // if any funds left to edit, go back to that page + if ( FundLookupTable.fundsLeft() ){ + visitPage('baseline-landing'); + return; + } + } if (currentIndex >= 0 && currentIndex < keys.length - 1) { - // Get the next key + // Check if there is a next key, and get it const nextKey = keys[currentIndex + 1]; // go to that page visitPage(nextKey); @@ -78,9 +86,4 @@ export function lastPage(){ // go to that page visitPage(lastKey); } -} - -export async function pauseAndContinue(){ - await pauseExecution(0.1); - nextPage(); } \ No newline at end of file From 162495cf61f853bf64b350bf34524569e56b212e Mon Sep 17 00:00:00 2001 From: Katrina Wheelan <katrina.wheelan@detroitmi.gov> Date: Fri, 19 Jul 2024 15:37:59 -0400 Subject: [PATCH 3/4] #22 use fontawesome to add a checkmark next to edited funds --- src/css/common.css | 12 ++++++++++-- src/index.html | 2 ++ src/js/components/table/subcomponents/data.js | 11 ++++++++--- src/js/components/table/table.css | 7 ++++++- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/css/common.css b/src/css/common.css index b6e336a..26127be 100644 --- a/src/css/common.css +++ b/src/css/common.css @@ -53,6 +53,14 @@ body, button, input, textarea, select, .sidebar, table { margin: 0; } -div.row { +/* Font awesome */ + +i.fas.fa-check { + font-size: 1.5em; + color: var(--spiritgreen); + margin-right: 10px; +} + +/* div.row { margin: 0px; -} \ No newline at end of file +} */ \ No newline at end of file diff --git a/src/index.html b/src/index.html index e85b8dc..8e1d261 100644 --- a/src/index.html +++ b/src/index.html @@ -9,6 +9,8 @@ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> <!-- Google fonts --> <link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;700&display=swap" rel="stylesheet"> +<!-- Font Awesome CSS --> +<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"> <!-- Bootstrap JS and its dependencies (jQuery & Popper.js) --> <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.9.4/dist/umd/popper.min.js" crossorigin="anonymous"></script> diff --git a/src/js/components/table/subcomponents/data.js b/src/js/components/table/subcomponents/data.js index a12a68d..809ac0c 100644 --- a/src/js/components/table/subcomponents/data.js +++ b/src/js/components/table/subcomponents/data.js @@ -25,7 +25,7 @@ function fillTable(data) { const row = document.createElement('tr'); Object.values(item).forEach(val => { const cell = document.createElement('td'); - cell.textContent = val; + cell.innerHTML = val; row.appendChild(cell); }); tbody.appendChild(row); @@ -63,9 +63,14 @@ function loadFunds(){ // determine if the fund has already been edited if (fundDict[key]['viewed']){ // todo: add a checkmark here - ret.push({'Fund' : fundDict[key]['name'] + ' (Edited)'}); + ret.push({'Fund' : `<span class = 'viewed-fund'> + <i class="fas fa-check"></i> + ${fundDict[key]['name']} + </span>`}); } else { - ret.push({'Fund' : fundDict[key]['name']}); + ret.push({'Fund' : `<span class = 'unviewed-fund'> + ${fundDict[key]['name']} + </span>`}); } }); fillTable(ret); diff --git a/src/js/components/table/table.css b/src/js/components/table/table.css index a8c20ad..5f2f784 100644 --- a/src/js/components/table/table.css +++ b/src/js/components/table/table.css @@ -96,4 +96,9 @@ div.table-container { .hover-effect:hover { cursor: pointer; background-color: var(--verypalegreen); -} \ No newline at end of file +} + +/* Fund table */ +.fund-name > .viewed-fund { + color: gray; +} From 4765d5ab2ef7870f9e6f953fc2b169ff68f7154d Mon Sep 17 00:00:00 2001 From: Katrina Wheelan <katrina.wheelan@detroitmi.gov> Date: Fri, 19 Jul 2024 15:59:53 -0400 Subject: [PATCH 4/4] #22 redirect to summary page after edit from summary page --- src/js/views/08_summary/helpers.js | 7 ++++++- src/js/views/view_logic.js | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/js/views/08_summary/helpers.js b/src/js/views/08_summary/helpers.js index 0315209..21dd1ea 100644 --- a/src/js/views/08_summary/helpers.js +++ b/src/js/views/08_summary/helpers.js @@ -5,15 +5,20 @@ import Subtitle from "../../components/header/header.js"; import { visitPage } from "../view_logic.js"; import { Accordion } from "../../components/accordion/accordion.js"; import { downloadXLSX } from "../../utils/data_utils/XLSX_handlers.js"; -import { Baseline } from '../../utils/data_utils/local_storage_handlers.js'; +import { Baseline, CurrentFund } from '../../utils/data_utils/local_storage_handlers.js'; import { TARGET } from '../../init.js'; import { formatCurrency } from '../../utils/common_utils.js'; export function summaryView(){ + + // show/hide elements Body.reset(); Accordion.build(); Accordion.show(); + // set fund to none + CurrentFund.reset(); + // prompt buttons Prompt.Buttons.Right.updateText('Download Excel'); Prompt.Buttons.Left.updateText('Start over'); diff --git a/src/js/views/view_logic.js b/src/js/views/view_logic.js index 581483c..b32751d 100644 --- a/src/js/views/view_logic.js +++ b/src/js/views/view_logic.js @@ -60,6 +60,14 @@ export function nextPage(){ return; } } + + // unless on personnel (which will go to overtime), return to summary if all funds are viewed + const returnPages = ['revenue', 'nonpersonnel', 'new-inits', 'overtime']; + if (!FundLookupTable.fundsLeft() && returnPages.includes(CurrentPage.load())) { + visitPage('summary'); + return; + } + if (currentIndex >= 0 && currentIndex < keys.length - 1) { // Check if there is a next key, and get it const nextKey = keys[currentIndex + 1];