diff --git a/.gitignore b/.gitignore
index 80e7df3..5127805 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
# Ignore all .xlsx files
-*.xlsx
+# *.xlsx
# Logs
logs
diff --git a/js/components/file_upload/file_upload.css b/js/components/file_upload/file_upload.css
new file mode 100644
index 0000000..c2e0a7e
--- /dev/null
+++ b/js/components/file_upload/file_upload.css
@@ -0,0 +1,3 @@
+#file-input {
+ margin-left: 40%;
+}
\ No newline at end of file
diff --git a/js/components/file_upload/file_upload.js b/js/components/file_upload/file_upload.js
new file mode 100644
index 0000000..df3a647
--- /dev/null
+++ b/js/components/file_upload/file_upload.js
@@ -0,0 +1,32 @@
+import { processWorkbook } from "../../utils/data_utils/XLSX_handlers.js";
+
+export const FileUpload = {
+ init : function() {
+ const inputObject = document.getElementById('file-input');
+ inputObject.addEventListener('change', function(event) {readXL(event) });
+ },
+ show : function(){
+ const inputObject = document.getElementById('file-input');
+ inputObject.style.display = '';
+ },
+ hide : function(){
+ const inputObject = document.getElementById('file-input');
+ inputObject.style.display = 'none';
+ }
+}
+
+function readXL(event) {
+ const file = event.target.files[0];
+
+ if (file) {
+ const reader = new FileReader();
+ reader.onload = function(e) {
+ const arrayBuffer = e.target.result;
+ processWorkbook(arrayBuffer);
+ };
+ reader.onerror = function(err) {
+ console.error('Error reading file:', err);
+ };
+ reader.readAsArrayBuffer(file); // Read the file as an ArrayBuffer
+ }
+}
\ No newline at end of file
diff --git a/sample_data/sample_detail_sheet.xlsx b/sample_data/sample_detail_sheet.xlsx
new file mode 100644
index 0000000..97f1c03
Binary files /dev/null and b/sample_data/sample_detail_sheet.xlsx differ
diff --git a/src/data/law_dept_sample/OT.json b/src/data/law_dept_sample/OT.json
deleted file mode 100644
index 8d6aeae..0000000
--- a/src/data/law_dept_sample/OT.json
+++ /dev/null
@@ -1,14 +0,0 @@
-[
- {
- "Account String": "1000-29320-320010",
- "Cost Center" : "Law Administration",
- "Overtime Wages": 15000,
- "Overtime Salary": 15000
- },
- {
- "Account String": "1000-29320-320010",
- "Cost Center" : "Law Department Grants",
- "Overtime Wages": 15000,
- "Overtime Salary": 0
- }
-]
\ No newline at end of file
diff --git a/src/data/law_dept_sample/funds.json b/src/data/law_dept_sample/funds.json
deleted file mode 100644
index 03df948..0000000
--- a/src/data/law_dept_sample/funds.json
+++ /dev/null
@@ -1,6 +0,0 @@
-[
- { "ID" : "1000",
- "Name" : "General Fund"},
- { "ID" : "29320",
- "Name" : "Sample Grant Fund"}
-]
\ No newline at end of file
diff --git a/src/data/law_dept_sample/nonpersonnel_data.json b/src/data/law_dept_sample/nonpersonnel_data.json
deleted file mode 100644
index 0b8493a..0000000
--- a/src/data/law_dept_sample/nonpersonnel_data.json
+++ /dev/null
@@ -1,29 +0,0 @@
-[
- {
- "Vendor": "Law Firm LLC",
- "CPA #" : "765421",
- "Account String": "1000-29320-320010",
- "Object Name": "Consulting",
- "End of Contract": "12/31/2024",
- "Amount Remaining" : 50000,
- "FY26 Request": 100000
- },
- {
- "Vendor": "Office Supplier",
- "CPA #" : "1234567",
- "Account String": "1000-29320-320010",
- "Object Name": "Office Supplies",
- "End of Contract": "12/31/2026",
- "Amount Remaining" : 500000,
- "FY26 Request": 10000
- },
- {
- "Vendor": "Software Co.",
- "CPA #" : "9876543",
- "Account String": "1000-29320-320010",
- "Object Name": "Information Technology",
- "End of Contract": "6/1/2025",
- "Amount Remaining" : 30000,
- "FY26 Request": 30000
- }
-]
\ No newline at end of file
diff --git a/src/data/law_dept_sample/personnel_data.json b/src/data/law_dept_sample/personnel_data.json
deleted file mode 100644
index 27d97c9..0000000
--- a/src/data/law_dept_sample/personnel_data.json
+++ /dev/null
@@ -1,23 +0,0 @@
-[
- {
- "Job Name (Type)": "Deputy Counsel (Regular)",
- "Account String": "1000-29320-320010",
- "Service" : "Appeals",
- "FY26 FTEs": 1,
- "Average Projected Salary": "150000"
- },
- {
- "Job Name (Type)": "Legal Secretary (Regular)",
- "Account String": "1000-29320-320010",
- "Service" : "FOIA",
- "FY26 FTEs": 2,
- "Average Projected Salary": "55000"
- },
- {
- "Job Name (Type)": "Assistant Counsel (Regular)",
- "Account String": "1000-29320-320010",
- "Service" : "Appeals",
- "FY26 FTEs": 10,
- "Average Projected Salary": "80000"
- }
-]
\ No newline at end of file
diff --git a/src/data/law_dept_sample/services.json b/src/data/law_dept_sample/services.json
deleted file mode 100644
index 2a4dd15..0000000
--- a/src/data/law_dept_sample/services.json
+++ /dev/null
@@ -1,10 +0,0 @@
-[
- { "id" : "",
- "name" : "Select"},
- { "id" : "Appeals",
- "name" : "Appeals"},
- { "id" : "FOIA",
- "name" : "FOIA" },
- { "id" : "Lobbying",
- "name" : "Lobbying"}
-]
\ No newline at end of file
diff --git a/src/data/law_dept_sample/strings.json b/src/data/law_dept_sample/strings.json
deleted file mode 100644
index 955a422..0000000
--- a/src/data/law_dept_sample/strings.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "1000" : {
- "label" : "General Fund",
- "appropriations" : {
- "29320" : {
- "label" : "Efficient and Innovative Operations Support",
- "cost centers" : {
- "320010" : { "label" : "Law Administration" },
- "321111" : { "label" : "Law Department Grants" }
- }
- }
- }
- },
-
- "2119" : {
- "label" : "FY2020 MIDC Grant",
- "appropriations" : {
- "21206" : {
- "label" : "2023 Michigan Indigent Defense Commission",
- "cost centers" : {
- "320010" : { "label" : "Law Administration" },
- "321111" : { "label" : "Law Department Grants" }
- }
- }
- }
- },
-
- "2490" : {
- "label" : "Construction Code Fund",
- "appropriations" : {
- "25130" : {
- "label" : "BSEED Safe Buildings",
- "cost centers" : {
- "320010" : { "label" : "Law Administration" }
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/index.html b/src/index.html
index 6ebef8e..c23ad87 100644
--- a/src/index.html
+++ b/src/index.html
@@ -58,6 +58,9 @@
Baseline
+
+
+
diff --git a/src/js/components/body/body.js b/src/js/components/body/body.js
index 836ac38..83df631 100644
--- a/src/js/components/body/body.js
+++ b/src/js/components/body/body.js
@@ -2,6 +2,7 @@ import './body.css';
import Welcome from '../../components/welcome/welcome.js'
import { Accordion } from '../accordion/accordion.js';
+import { FileUpload } from '../file_upload/file_upload.js';
import Modal from '../modal/modal.js';
import NavButtons from '../nav_buttons/nav_buttons.js';
import Prompt from '../prompt/prompt.js';
@@ -18,6 +19,7 @@ function resetPage() {
Table.hide();
Sidebar.hide();
Accordion.hide();
+ FileUpload.hide();
// disable next button
NavButtons.Next.disable();
Prompt.Buttons.reset();
diff --git a/src/js/components/table/subcomponents/cells.js b/src/js/components/table/subcomponents/cells.js
index 122c1be..fe061d7 100644
--- a/src/js/components/table/subcomponents/cells.js
+++ b/src/js/components/table/subcomponents/cells.js
@@ -29,7 +29,6 @@ function createEditableCell(cellClass, isCost){
textbox.type = 'text';
if (isCost){
var value = cell.getAttribute('value');
- console.log(value);
} else {
var value = cell.textContent;
}
diff --git a/src/js/components/table/subcomponents/data.js b/src/js/components/table/subcomponents/data.js
index 1846d0d..9342721 100644
--- a/src/js/components/table/subcomponents/data.js
+++ b/src/js/components/table/subcomponents/data.js
@@ -3,38 +3,33 @@ import { CurrentFund, CurrentPage, loadTableData, saveTableData } from "../../..
function fillTable(data) {
try {
- if(Array.isArray(data)) {
- const table = document.getElementById('main-table');
- const thead = table.querySelector('thead');
- const tbody = table.querySelector('tbody');
-
- // clear existing data
- thead.innerHTML = '';
- tbody.innerHTML = '';
-
- // Create table header row
- const headerRow = document.createElement('tr');
- Object.keys(data[0]).forEach(key => {
- const header = document.createElement('th');
- header.textContent = key;
- headerRow.appendChild(header);
+ const table = document.getElementById('main-table');
+ const thead = table.querySelector('thead');
+ const tbody = table.querySelector('tbody');
+
+ // clear existing data
+ thead.innerHTML = '';
+ tbody.innerHTML = '';
+
+ // Create table header row
+ const headerRow = document.createElement('tr');
+ Object.keys(data[0]).forEach(key => {
+ const header = document.createElement('th');
+ header.textContent = key;
+ headerRow.appendChild(header);
+ });
+ thead.appendChild(headerRow);
+
+ // Create table body rows
+ data.forEach(item => {
+ const row = document.createElement('tr');
+ Object.values(item).forEach(val => {
+ const cell = document.createElement('td');
+ cell.textContent = val;
+ row.appendChild(cell);
});
- thead.appendChild(headerRow);
-
- // Create table body rows
- data.forEach(item => {
- const row = document.createElement('tr');
- Object.values(item).forEach(val => {
- const cell = document.createElement('td');
- cell.textContent = val;
- row.appendChild(cell);
- });
- tbody.appendChild(row);
- });
-
- } else {
- console.error('Empty table saved in localStorage.');
- }
+ tbody.appendChild(row);
+ });
} catch(error) {
console.error('No table saved in localStorage:', error);
}
@@ -42,10 +37,20 @@ function fillTable(data) {
}
async function loadFromStorage(){
- // look up table in storage and pass to table load function
- const key = `${CurrentPage.load()}_${CurrentFund.number()}`;
+ // look up table in storage and pass to table load function\
+ if (CurrentFund.number()){
+ var key = `${CurrentPage.load()}_${CurrentFund.number()}`;
+ } else {
+ var key = CurrentPage.load();
+ }
const data = await loadTableData(key);
- fillTable(data);
+ if (!data){
+ // if no table in storage, return 0
+ return 0;
+ } else {
+ fillTable(data);
+ return 1;
+ }
}
diff --git a/src/js/components/table/table.css b/src/js/components/table/table.css
index eec709a..a8c20ad 100644
--- a/src/js/components/table/table.css
+++ b/src/js/components/table/table.css
@@ -49,7 +49,7 @@ div.table-container {
/* max-width: calc(100vw - var(--sidebar-width)); */
/* margin: auto; */
max-height: max(350px, 6vh);
- min-height: 350px;
+ /* min-height: 350px; */
}
diff --git a/src/js/init.js b/src/js/init.js
index dc48f42..5bc282c 100644
--- a/src/js/init.js
+++ b/src/js/init.js
@@ -2,7 +2,6 @@
import '../css/common.css';
// import functions
-import { fetchAndProcessExcel } from './utils/data_utils/XLSX_handlers.js';
import { CurrentPage } from './utils/data_utils/local_storage_handlers.js';
// path for my laptop
@@ -11,7 +10,7 @@ export let DATA_ROOT = '../../../data/law_dept_sample/'
// export let DATA_ROOT = '../../budget-request-demo/data/law_dept_sample/'
export let REVENUE = 0;
-export let TARGET = 20000000;
+export let TARGET = 14000000;
export var FISCAL_YEAR = '26';
export var OT_FRINGE = 0.0765;
diff --git a/src/js/utils/data_utils/XLSX_handlers.js b/src/js/utils/data_utils/XLSX_handlers.js
index 28db656..1bb8dae 100644
--- a/src/js/utils/data_utils/XLSX_handlers.js
+++ b/src/js/utils/data_utils/XLSX_handlers.js
@@ -3,28 +3,7 @@
import { SHEETS } from '../../init.js';
import { FundLookupTable, Services } from './budget_data_handlers.js';
import { removeNewLines } from '../common_utils.js';
-
-export async function fetchAndProcessExcel(filePath) {
- fetch(filePath)
- .then(response => {
- if (!response.ok) {
- throw new Error('Network response was not ok');
- }
- return response.arrayBuffer(); // return the ArrayBuffer
- })
- .then(data => {
- try {
- // Read the data into a workbook
- const workbook = XLSX.read(data, { type: 'array' });
- processWorkbook(workbook);
- } catch (err) {
- console.error('Error reading the Excel file:', err);
- }
- })
- .catch(error => {
- console.error('Error fetching the Excel file:', error);
- });
-}
+import { Baseline } from './local_storage_handlers.js';
function deleteTopRowsUntilFullData(data) {
// function to try to find the top of the usable data
@@ -32,7 +11,6 @@ function deleteTopRowsUntilFullData(data) {
while (!fullDataRowFound && data.length > 0) {
const row = data[0]; // Get the top row
- //console.log(row);
let hasAllData = true;
for (const cell of row) {
@@ -53,13 +31,14 @@ function deleteTopRowsUntilFullData(data) {
return data;
}
-function processWorkbook(workbook) {
+export function processWorkbook(arrayBuffer) {
+ const workbook = XLSX.read(arrayBuffer, { type: 'array' });
workbook.SheetNames.forEach(sheetName => {
// only convert sheets we need
if (Object.keys(SHEETS).includes(sheetName)) {
// read in sheets
const sheet = workbook.Sheets[sheetName];
- const rawData = XLSX.utils.sheet_to_json(sheet, { header: 1, defval: null });
+ const rawData = XLSX.utils.sheet_to_json(sheet, { header: 1, defval: '' });
// Clean the data by removing top rows with incomplete data
const dataRows = deleteTopRowsUntilFullData(rawData);
@@ -121,4 +100,57 @@ function processWorkbook(workbook) {
}
}
});
+
+ console.log('all excel data saved');
+}
+
+// Utility function to append a sheet to the workbook if data is present
+function appendSheetToWorkbook(workbook, data, sheetName) {
+ if (data.length > 0) {
+ const sheet = XLSX.utils.json_to_sheet(data);
+ XLSX.utils.book_append_sheet(workbook, sheet, sheetName);
+ }
}
+
+export function downloadXLSX() {
+ const baseline = new Baseline();
+ const workbook = XLSX.utils.book_new(); // Create a new workbook
+
+ const dataMap = {
+ Personnel: 'personnel',
+ Overtime: 'overtime',
+ NonPersonnel: 'nonpersonnel',
+ Revenue: 'revenue'
+ };
+
+ const sheetData = {
+ Personnel: [],
+ Overtime: [],
+ NonPersonnel: [],
+ Revenue: []
+ };
+
+ baseline.funds.forEach(fund => {
+ Object.keys(dataMap).forEach(sheetName => {
+ if (fund[dataMap[sheetName]] && fund[dataMap[sheetName]].table) {
+ sheetData[sheetName].push(...fund[dataMap[sheetName]].table);
+ }
+ });
+ });
+
+ Object.keys(sheetData).forEach(sheetName => {
+ appendSheetToWorkbook(workbook, sheetData[sheetName], sheetName);
+ });
+
+ // Generate a downloadable file
+ const wbout = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
+ const blob = new Blob([wbout], { type: 'application/octet-stream' });
+
+ // Create a link and trigger the download
+ const link = document.createElement("a");
+ link.href = URL.createObjectURL(blob);
+ link.download = "baseline_data.xlsx";
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+}
\ No newline at end of file
diff --git a/src/js/utils/data_utils/budget_data_handlers.js b/src/js/utils/data_utils/budget_data_handlers.js
index a809fe3..598af9e 100644
--- a/src/js/utils/data_utils/budget_data_handlers.js
+++ b/src/js/utils/data_utils/budget_data_handlers.js
@@ -13,7 +13,6 @@ export const FundLookupTable = {
if (!table[fund]){
// get fund name
const fundName = fundData[fund][0]['Fund Name'];
- console.log(fundName);
// add fund to dictionary
table[fund] = fundName;
}
diff --git a/src/js/views/01_upload/helpers.js b/src/js/views/01_upload/helpers.js
index cec26e4..aadc069 100644
--- a/src/js/views/01_upload/helpers.js
+++ b/src/js/views/01_upload/helpers.js
@@ -2,8 +2,8 @@ import Subtitle from '../../components/header/header.js'
import Prompt from '../../components/prompt/prompt.js'
import NavButtons from '../../components/nav_buttons/nav_buttons.js'
import Body from "../../components/body/body.js";
-import { fetchAndProcessExcel } from '../../utils/data_utils/XLSX_handlers.js';
import { DATA_ROOT } from '../../init.js';
+import { FileUpload } from '../../components/file_upload/file_upload.js';
export function initializePageView() {
@@ -13,18 +13,13 @@ export function initializePageView() {
// prepare page view
Body.reset();
NavButtons.show();
+ FileUpload.show();
// update page text
Subtitle.update('Excel Upload');
+ Prompt.Text.update(`Upload the baseline detail sheet given by your budget analyst.`);
- // TODO: update to make upload actually work
- Prompt.Text.update(`Placeholder for Excel Upload`);
- Prompt.Buttons.Left.updateText('Upload');
- Prompt.Buttons.Left.show();
- Prompt.Buttons.Left.addAction(uploadExcelAction);
-}
-
-async function uploadExcelAction() {
- await fetchAndProcessExcel(DATA_ROOT + 'sample_detail_sheet.xlsx');
+ // show and initialize file upload; enable continue after file saved in local storage
+ FileUpload.init();
NavButtons.Next.enable();
}
\ No newline at end of file
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/04.5_OT/helpers.js b/src/js/views/04.5_OT/helpers.js
index d3e22d6..3f7ae0b 100644
--- a/src/js/views/04.5_OT/helpers.js
+++ b/src/js/views/04.5_OT/helpers.js
@@ -50,19 +50,22 @@ function OTRowOnEdit(){
}
export async function initializeOTTable(){
- // load table data from json
- await Table.Data.load();
- //after table is loaded, fill it
- Table.show();
- Table.Columns.addAtEnd( '0', 'Hourly Employee Overtime (Wages)');
- Table.Columns.addAtEnd( '0', 'Salaried Employee Overtime (Salary)');
- // Table.Columns.addAtEnd( '0', 'Total Cost (including benefits)');
- Table.Columns.addAtEnd(Table.Buttons.edit_confirm_btns, 'Edit');;
- assignClasses();
- // add up the baseline costs and update sidebar
- updateDisplayandTotals();
- // activate edit buttons
- Table.Buttons.Edit.init(OTRowOnEdit, updateDisplayandTotals);
+ // load table data from local storage
+ if(await Table.Data.load()) {
+ //after table is loaded, fill it
+ Table.show();
+ Table.Columns.addAtEnd( '0', 'Hourly Employee Overtime (Wages)');
+ Table.Columns.addAtEnd( '0', 'Salaried Employee Overtime (Salary)');
+ // Table.Columns.addAtEnd( '0', 'Total Cost (including benefits)');
+ Table.Columns.addAtEnd(Table.Buttons.edit_confirm_btns, 'Edit');;
+ assignClasses();
+ // add up the baseline costs and update sidebar
+ updateDisplayandTotals();
+ // activate edit buttons
+ Table.Buttons.Edit.init(OTRowOnEdit, updateDisplayandTotals);
+ } else {
+ Prompt.Text.update('No overtime expenses for this fund.')
+ }
}
function calculateTotalCost(wages, salary, fringe){
diff --git a/src/js/views/04_personnel/helpers.js b/src/js/views/04_personnel/helpers.js
index 18af98c..712ff0a 100644
--- a/src/js/views/04_personnel/helpers.js
+++ b/src/js/views/04_personnel/helpers.js
@@ -53,17 +53,20 @@ function personnelRowOnEdit(){
}
export async function initializePersonnelTable(){
- // load table data from json
- await Table.Data.load();
- //after table is loaded, show it
- Table.show();
- Table.Columns.addAtEnd(Table.Buttons.edit_confirm_btns, 'Edit');
- assignClasses();
- // add up the baseline costs and update sidebar
- updateDisplayandTotals();
- // activate edit buttons
- Table.Buttons.Edit.init(personnelRowOnEdit, updateDisplayandTotals);
- initializeRowAddition();
+ // load table data from local storage
+ if(await Table.Data.load()) {
+ //after table is loaded, show it
+ Table.show();
+ Table.Columns.addAtEnd(Table.Buttons.edit_confirm_btns, 'Edit');
+ assignClasses();
+ // add up the baseline costs and update sidebar
+ updateDisplayandTotals();
+ // activate edit buttons
+ Table.Buttons.Edit.init(personnelRowOnEdit, updateDisplayandTotals);
+ initializeRowAddition();
+ } else {
+ Prompt.Text.update('No personnel expenses for this fund.')
+ }
}
function initializeRowAddition(){
@@ -89,7 +92,6 @@ function updateDisplayandTotals(){
// update total column
Table.Cell.updateValue(rows[i], 'total-baseline', total_baseline_cost);
-
}
// Save the table after all updates are done
diff --git a/src/js/views/05_nonpersonnel/helpers.js b/src/js/views/05_nonpersonnel/helpers.js
index 0939b9d..3cec10f 100644
--- a/src/js/views/05_nonpersonnel/helpers.js
+++ b/src/js/views/05_nonpersonnel/helpers.js
@@ -21,8 +21,8 @@ const nonPersonnelColumns = [
{ title : 'Account String', className : 'account-string'},
{ title : 'CPA #', className : 'cpa'},
{ title : 'Contract End Date', className : 'contract-end'},
- { title: 'Recurring or One-Time', className: 'recurring'}
-
+ { title: 'Recurring or One-Time', className: 'recurring'},
+ { title: 'Object Name', className: 'object'}
];
export function preparePageView(){
@@ -41,15 +41,18 @@ export function preparePageView(){
}
export async function initializeNonpersonnelTable(){
- // load table data from json
- await Table.Data.load();
- //after table is loaded, fill it
- Table.show();
- Table.Columns.addAtEnd(Table.Buttons.edit_confirm_btns, "Edit");
- // assign cost classes
- Table.Columns.assignClasses(nonPersonnelColumns);
- // enable editing
- Table.Buttons.Edit.init(nonPersonnelRowOnEdit, Table.save);
+ // load table data from storage
+ if(await Table.Data.load()) {
+ //after table is loaded, fill it
+ Table.show();
+ Table.Columns.addAtEnd(Table.Buttons.edit_confirm_btns, "Edit");
+ // assign cost classes
+ Table.Columns.assignClasses(nonPersonnelColumns);
+ // enable editing
+ Table.Buttons.Edit.init(nonPersonnelRowOnEdit, Table.save);
+ } else {
+ Prompt.Text.update('No personnel expenses for this fund.')
+ }
}
function nonPersonnelRowOnEdit(){
diff --git a/src/js/views/06_new_initiatives/helpers.js b/src/js/views/06_new_initiatives/helpers.js
index d5b74a1..6e8773f 100644
--- a/src/js/views/06_new_initiatives/helpers.js
+++ b/src/js/views/06_new_initiatives/helpers.js
@@ -5,9 +5,9 @@ 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 Subtitle from '../../components/header/header.js'
import Sidebar from '../../components/sidebar/sidebar.js'
+import { nextPage } from '../view_logic.js'
export function initializePageView() {
// Prepare page view
@@ -24,7 +24,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);
}
@@ -45,70 +45,73 @@ export function setUpForm() {
ii). Why is the initiative needed? What is the value-add to residents? What is the Department’s plan for implementing the Initiative?
iii). Why can’t the Initiative be funded with the Department’s baseline budget?`, 'Explanation', true);
- Form.NewField.numericInput('What is your ballpark estimate of TOTAL ADDITONAL expenses associated with this initiative?', 'Revenue', false);
+ Form.NewField.numericInput('What is your ballpark estimate of TOTAL ADDITONAL expenses associated with this initiative?', 'Ballpark Total', false);
Form.NewField.numericInput('Estimate of ADDITONAL personnel cost?', 'Personnel Cost', false);
Form.NewField.numericInput('Estimate of ADDITONAL nonpersonnel cost?', 'Non-personnel Cost', false);
Form.NewField.numericInput('Estimate of ADDITONAL revenue (if applicable)?', 'Revenue', false);
- // TODO: implement this option
- // Form.NewField.numericInput(`If you cannot answer the above, please provide a ballpark estimate of
- // the TOTAL ADDITONAL cost associated with this initiative`,
- // 'Ballpark Total', false);
-
Form.SubmitButton.add();
// Initialize form submission to table data
Modal.Submit.init(handleNewInitSubmission);
}
-export function setUpTable() {
- // Set up table
- Table.clear();
- Table.adjustWidth('70%');
- Table.Buttons.AddRow.updateText('Add another new initiative');
-}
-
function assignClasses() {
// record columns and their classes
- const personnelColumns = [
+ const initiativesCols = [
{ title: 'Initiative Name', className: 'init-name' },
{ title: `Explanation`, className: 'explanation' },
+ { title: 'Ballpark Total', className: 'total', isCost: true },
{ title: 'Revenue', className: 'revenue', isCost: true },
{ title: 'Personnel Cost', className: 'personnel', isCost: true },
{ title: 'Non-personnel Cost', className: 'nonpersonnel', isCost: true }
];
// assign cost classes
- Table.Columns.assignClasses(personnelColumns)
+ Table.Columns.assignClasses(initiativesCols)
+}
+
+export async function initializeInitTable(){
+ // load table data from storage
+ if(await Table.Data.load()) {
+ //after table is loaded, fill it
+ assignClasses();
+ Table.adjustWidth('70%');
+ Table.Buttons.AddRow.updateText('Add another new initiative');
+ tableView();
+ }
}
-export function handleNewInitSubmission(event){
+function handleNewInitSubmission(event){
// get answers from form, hide form, show answers in table
const responses = Form.fetchAllResponses(event);
// make sure it's not an empty response
if (Object.values(responses)[0] != ''){
-
- // change page view
- Modal.hide();
- Prompt.hide();
-
// add data to table
Table.Rows.add(responses);
- assignClasses();
- Table.show();
- Table.Buttons.AddRow.show();
// save it
Table.save();
+ tableView();
}
}
+function tableView() {
+ // change page view
+ Table.show();
+ Modal.hide();
+ Prompt.hide();
+ assignClasses();
+ Table.Buttons.AddRow.show();
+ NavButtons.Next.enable();
+}
+
export function removeModalLinks(){
Modal.Link.remove('option1');
Modal.Link.remove('add-btn');
}
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/06_new_initiatives/main.js b/src/js/views/06_new_initiatives/main.js
index fb44921..90bf05c 100644
--- a/src/js/views/06_new_initiatives/main.js
+++ b/src/js/views/06_new_initiatives/main.js
@@ -1,5 +1,5 @@
-import { initializePageView, setUpModal, setUpForm, setUpTable, removeModalLinks, removePromptButtonListeners } from './helpers.js'
+import { initializePageView, setUpModal, setUpForm, removeModalLinks, removePromptButtonListeners, initializeInitTable } from './helpers.js'
import { CurrentPage } from '../../utils/data_utils/local_storage_handlers.js'
@@ -9,7 +9,7 @@ export function loadNewInitiatives() {
initializePageView();
setUpModal();
setUpForm();
- setUpTable();
+ initializeInitTable();
}
export function cleanUpInitiativesPage() {
diff --git a/src/js/views/07_summary/main.js b/src/js/views/07_summary/main.js
index 0b82682..60e200b 100644
--- a/src/js/views/07_summary/main.js
+++ b/src/js/views/07_summary/main.js
@@ -4,16 +4,17 @@ import Body from "../../components/body/body.js";
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";
export function loadSummaryPage(){
//update page state
CurrentPage.update('summary');
summaryView();
- // basicView();
}
export function cleanUpSummaryPage(){
Prompt.Buttons.Right.removeAction(returnToWelcome);
+ Prompt.Buttons.Left.removeAction(downloadXLSX);
}
export function summaryView(){
@@ -29,8 +30,9 @@ export function summaryView(){
// update page text
Subtitle.update('Summary');
- // TODO: update to make dynamic
+ // add button links
Prompt.Buttons.Right.addAction(returnToWelcome);
+ Prompt.Buttons.Left.addAction(downloadXLSX);
}
diff --git a/src/js/views/view_logic.js b/src/js/views/view_logic.js
index 70c5507..d4f2b76 100644
--- a/src/js/views/view_logic.js
+++ b/src/js/views/view_logic.js
@@ -78,9 +78,4 @@ export function lastPage(){
// go to that page
visitPage(lastKey);
}
-}
-
-export async function pauseAndContinue(){
- await pauseExecution(0.5);
- nextPage();
}
\ No newline at end of file