From d06b5aabaec31cd5fa70e5466b97342fbacc246c Mon Sep 17 00:00:00 2001 From: Sam Hadow Date: Sat, 17 Feb 2024 02:03:03 +0100 Subject: [PATCH] filters interactivity + fix in fetch, flask and SQL requests --- src/app.py | 22 ++++++++++ src/db.py | 31 +++++++++++++- web/app.html | 4 +- web/app.js | 33 ++++++++++++++- web/fetch.js | 116 ++++++++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 195 insertions(+), 11 deletions(-) diff --git a/src/app.py b/src/app.py index e8e0d27..abbc5da 100644 --- a/src/app.py +++ b/src/app.py @@ -119,6 +119,28 @@ def data_item_request(): print("fetching data item") return jsonify(get_item()) +@app.route('/app/dataitem-filtered',methods = ['POST']) +def data_item_request_filtered(): + print("fetching data item") + data = request.get_json() + filters_string = data.get('filters') + if len(filters_string)>0 : + lists_uuid = filters_string.split('#') + else: + lists_uuid = [] + return jsonify(get_item_filtered(lists_uuid)) + +@app.route('/app/datahistory-filtered',methods = ['POST']) +def data_history_request_filtered(): + print("fetching data history") + data = request.get_json() + filters_string = data.get('filters') + if len(filters_string)>0 : + lists_uuid = filters_string.split('#') + else: + lists_uuid = [] + return jsonify(get_history_filtered(lists_uuid)) + @app.route('/app/datalist',methods = ['GET']) def data_list_request(): if request.method == 'GET': diff --git a/src/db.py b/src/db.py index b836f97..688bee5 100644 --- a/src/db.py +++ b/src/db.py @@ -103,7 +103,7 @@ def get_item_filtered(lists_uuid): FROM item i """ for i in range(n_filters): - sql_request += f', content c{str(i)}' + sql_request += f', listcontent c{str(i)}' sql_request += ' WHERE ' for i,uuid in enumerate(lists_uuid): sql_request += f' i.uuid = c{str(i)}.item_uuid and c{str(i)}.list_uuid = {str(uuid)} and' @@ -120,6 +120,35 @@ def get_item_filtered(lists_uuid): results = get_item() return results +def get_history_filtered(lists_uuid): + ''' + return history of items in a every specified lists (list of itemlist uuid) + all history if filter is empty + ''' + n_filters = len(lists_uuid) + if n_filters > 0: + sql_request = """ + SELECT uuid, quantity, discount_percentage, price, currency, h_timestamp + FROM history h + """ + for i in range(n_filters): + sql_request += f', listcontent c{str(i)}' + sql_request += ' WHERE ' + for i,uuid in enumerate(lists_uuid): + sql_request += f' h.uuid = c{str(i)}.item_uuid and c{str(i)}.list_uuid = {str(uuid)} and' + + sql_request = sql_request[:-3] # remove last 'and' + + connection = connect_db() + cursor = connection.cursor() + cursor.execute(sql_request) + results = cursor.fetchall() + cursor.close() + connection.close() + else: + results = get_history() + return results + def get_item_keys(): '''return items id and attributes from database''' connection = connect_db() diff --git a/web/app.html b/web/app.html index 1fdaa38..d532245 100644 --- a/web/app.html +++ b/web/app.html @@ -33,9 +33,7 @@ -
diff --git a/web/app.js b/web/app.js index f00f2b2..e19b2b3 100644 --- a/web/app.js +++ b/web/app.js @@ -32,7 +32,9 @@ window.onresize = function(){ location.reload(); } function render_graphs_wrapper() { - get_data().then(function(data){ + const checked = getCheckedCheckboxIds('.checkbox-filters'); + const id_array = checked.map(str => str.substring(9)); + get_data_filtered(id_array).then(function(data){ render_graphs(data[0], data[1], show_hidden); }) } @@ -49,6 +51,35 @@ function refresh_graphs() { // render graphs render_graphs_wrapper(); +// filters checkboxes +function filters_checkboxes() { + fetch_list().then(function(data){ + const node = d3.select("#filters_checkboxes"); + for (const itemlist of data) { + var label = node.append("label"); + var input = label.append("input") + .attr("type", "checkbox") + .attr("class", "checkbox-filters") + .attr("id", `checkbox-${itemlist.uuid}`); + label.append("span") + .text(`${itemlist.name}`); + node.append("br"); + } + }) +} +filters_checkboxes() +// listen to filters changes +$(document).ready(function(){ + $('#filters').on('show.bs.dropdown', function () { + console.log("Opening dropdown"); + }); + + $('#filters').on('hidden.bs.dropdown', function () { + // console.log("Dropdown hidden"); + refresh_graphs(); + }); +}); + // add item document.getElementById("addbutton").addEventListener("click", addItem); diff --git a/web/fetch.js b/web/fetch.js index 3820ff5..b62a549 100644 --- a/web/fetch.js +++ b/web/fetch.js @@ -53,12 +53,104 @@ async function fetch_item() { } } -async function get_data() { - items_data = await fetch_item(); - history_data = await fetch_history(); - // console.log(items_data) - // console.log(history_data) - return Array(items_data, history_data); +async function fetch_history_filtered(id_array) { + try { + // SELECT uuid, itemid, skuid, choice, attributes, image, show + const apiUrl = `${currentUrl}app/datahistory-filtered`; + filters_string = id_array.join('#'); + const postData = { + filters: filters_string + }; + + const requestOptions = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(postData) + }; + + const response = await fetch(apiUrl, requestOptions) + .catch(error => { + console.error('Error during POST request:', error); + }); + + if (response.ok) { + const rawData = await response.json(); + var dateFormat = d3.timeParse("%a, %d %b %Y %H:%M:%S GMT"); + // SELECT uuid, quantity, discount_percentage, price, currency, h_timestamp + let historyData = rawData.map(d => ({ + uuid: d[0], + value: parseFloat(d[3].replace('$', '')), + currency: d[4], + date: dateFormat(d[5]), + })); + return historyData; + } else { + throw new Error('Error in server response'); + } + } catch (error) { + console.error('Error fetching data item: ', error); + throw error; + } +} + +async function fetch_item_filtered(id_array) { + try { + // SELECT uuid, itemid, skuid, choice, attributes, image, show + const apiUrl = `${currentUrl}app/dataitem-filtered`; + filters_string = id_array.join('#'); + const postData = { + filters: filters_string + }; + + const requestOptions = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(postData) + }; + + const response = await fetch(apiUrl, requestOptions) + .catch(error => { + console.error('Error during POST request:', error); + }); + + if (response.ok) { + const rawData = await response.json(); + const items = rawData.reduce((item, row) => { + const uuid = row[0]; + + const itemid = row[1]; + const skuid = row[2]; + const choice = row[3]; + const attributes = row[4]; + const image = row[5]; + const show = row[6]; + + const values = { + itemid: itemid, + skuid: skuid, + choice: choice, + attributes: attributes, + image: image, + show: show, + }; + + item[uuid] = values; + + return item; + }, {}); + + return items; + } else { + throw new Error('Error in server response'); + } + } catch (error) { + console.error('Error fetching data item: ', error); + throw error; + } } async function fetch_list() { @@ -77,3 +169,15 @@ async function fetch_list() { throw error; } } + +async function get_data() { + items_data = await fetch_item(); + history_data = await fetch_history(); + return Array(items_data, history_data); +} + +async function get_data_filtered(id_array) { + items_data = await fetch_item_filtered(id_array); + history_data = await fetch_history_filtered(id_array); + return Array(items_data, history_data); +}