Lots of base additons

This commit is contained in:
Jadowyne Ulve 2024-10-11 22:35:40 -05:00
parent 9a57fa7ad6
commit f042c7ca82
31 changed files with 556 additions and 89 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

92
api.py
View File

@ -4,12 +4,59 @@ from config import config
database_api= Blueprint('database_api', __name__) database_api= Blueprint('database_api', __name__)
def paginate_with_params(cur, limit, offset, params):
sql = f"SELECT * FROM main_items LEFT JOIN main_logistics_info ON main_items.logistics_info_id = main_logistics_info.id"
count = f"SELECT COUNT(*) FROM main_items LEFT JOIN main_logistics_info ON main_items.logistics_info_id = main_logistics_info.id"
# WHERE search_string LIKE '%{search_string}%'
strings = []
count_strings = []
if params['search_string'] != "":
s = params['search_string']
strings.append(f" search_string LIKE '%{s}%'")
count_strings.append(f" search_string LIKE '%{s}%'")
if params['view'] == 1:
s = params['view']
strings.append(f" main_logistics_info.quantity_on_hand <> 0.00")
count_strings.append(f" main_logistics_info.quantity_on_hand <> 0.00")
# LIMIT {limit} OFFSET {offset};"
if len(strings) > 0:
sql = f"{sql} WHERE{" AND".join(strings)}"
if len(count_strings) > 0:
count = f"{count} WHERE{" AND".join(count_strings)}"
sql = f"{sql} ORDER BY main_logistics_info.quantity_on_hand LIMIT {limit} OFFSET {offset};"
count = f"{count};"
print(count)
print(sql)
cur.execute(sql)
pantry_inventory = cur.fetchall()
cur.execute(count)
count = cur.fetchone()[0]
return pantry_inventory, count
def paginate_default(cur, limit, offset):
sql = f"SELECT * FROM main_items LEFT JOIN main_logistics_info ON main_items.logistics_info_id = main_logistics_info.id LIMIT %s OFFSET %s;"
cur.execute(sql, (limit, offset))
pantry_inventory = cur.fetchall()
cur.execute("SELECT COUNT(*) FROM main_items;")
count = cur.fetchone()[0]
return pantry_inventory, count
@database_api.route("/getItems") @database_api.route("/getItems")
def pagninate_items(): def pagninate_items():
print("hello") print("hello")
page = int(request.args.get('page', 1)) page = int(request.args.get('page', 1))
limit = int(request.args.get('limit', 10)) limit = int(request.args.get('limit', 10))
search_string = str(request.args.get('search_text', "")) search_string = str(request.args.get('search_text', ""))
sort_order = int(request.args.get('sort_order', 1))
view = int(request.args.get('view', 0))
offset = (page - 1) * limit offset = (page - 1) * limit
@ -20,26 +67,22 @@ def pagninate_items():
with psycopg2.connect(**database_config) as conn: with psycopg2.connect(**database_config) as conn:
try: try:
with conn.cursor() as cur: with conn.cursor() as cur:
if search_string != "": pantry_inventory, count = paginate_with_params(
sql = f"SELECT * FROM main_items LEFT JOIN main_logistics_info ON main_items.logistics_info_id = main_logistics_info.id WHERE search_string LIKE '%{search_string}%' LIMIT {limit} OFFSET {offset};" cur, limit, offset,
cur.execute(sql) {'search_string': search_string,
pantry_inventory = cur.fetchall() 'view': view}
cur.execute(f"SELECT COUNT(*) FROM main_items WHERE search_string LIKE '%{search_string}%';") )
count = cur.fetchone()[0]
else:
sql = f"SELECT * FROM main_items LEFT JOIN main_logistics_info ON main_items.logistics_info_id = main_logistics_info.id LIMIT %s OFFSET %s;"
cur.execute(sql, (limit, offset))
pantry_inventory = cur.fetchall()
cur.execute("SELECT COUNT(*) FROM main_items;")
count = cur.fetchone()[0]
print(sql)
print(count, math.ceil(count/limit))
except (Exception, psycopg2.DatabaseError) as error: except (Exception, psycopg2.DatabaseError) as error:
print(error) print(error)
pantry_inventory = sorted(pantry_inventory, key=lambda x: x[2]) if sort_order == 0:
pantry_inventory = sorted(pantry_inventory, key=lambda x: x[1])
if sort_order == 1:
pantry_inventory = sorted(pantry_inventory, key=lambda x: x[2])
if sort_order == 2:
pantry_inventory = sorted(pantry_inventory, key=lambda x: x[18])
return jsonify({'items': pantry_inventory, "end": math.ceil(count/limit)}) return jsonify({'items': pantry_inventory, "end": math.ceil(count/limit)})
@ -63,4 +106,17 @@ def get_item():
except (Exception, psycopg2.DatabaseError) as error: except (Exception, psycopg2.DatabaseError) as error:
print(error) print(error)
return render_template(f"item_page/index.html", item=item) return render_template(f"item_page/index.html", item=item)
@database_api.route("/addGroup")
def addGroup():
name = str(request.args.get('name', ""))
description = str(request.args.get('description', ""))
group_type = str(request.args.get('type', ""))
state = "FAILED"
if name or description or group_type == "":
print("this is empty")
return jsonify({'state': state})

16
main.py
View File

@ -310,6 +310,11 @@ def delete_site(site_name):
drop_table(f'sites/{site_name}/sql/drop/logistics_info.sql') drop_table(f'sites/{site_name}/sql/drop/logistics_info.sql')
drop_table(f'sites/{site_name}/sql/drop/zones.sql') drop_table(f'sites/{site_name}/sql/drop/zones.sql')
drop_table(f'sites/{site_name}/sql/drop/locations.sql') drop_table(f'sites/{site_name}/sql/drop/locations.sql')
drop_table(f'sites/{site_name}/sql/drop/vendors.sql')
drop_table(f'sites/{site_name}/sql/drop/receipt_items.sql')
drop_table(f'sites/{site_name}/sql/drop/receipts.sql')
drop_table(f'sites/{site_name}/sql/drop/recipes.sql')
drop_table(f'sites/{site_name}/sql/drop/shopping_lists.sql')
def create_site(site_name): def create_site(site_name):
@ -326,6 +331,12 @@ def create_site(site_name):
create_table(f'sites/{site_name}/sql/create/item.sql') create_table(f'sites/{site_name}/sql/create/item.sql')
create_table(f'sites/{site_name}/sql/create/zones.sql') create_table(f'sites/{site_name}/sql/create/zones.sql')
create_table(f'sites/{site_name}/sql/create/locations.sql') create_table(f'sites/{site_name}/sql/create/locations.sql')
create_table(f'sites/{site_name}/sql/create/vendors.sql')
create_table(f'sites/{site_name}/sql/create/receipt_items.sql')
create_table(f'sites/{site_name}/sql/create/receipts.sql')
create_table(f'sites/{site_name}/sql/create/recipes.sql')
create_table(f'sites/{site_name}/sql/create/shopping_lists.sql')
sql = f"INSERT INTO {site_name}_zones(name) VALUES (%s) RETURNING id;" sql = f"INSERT INTO {site_name}_zones(name) VALUES (%s) RETURNING id;"
sqltwo = f"INSERT INTO {site_name}_locations(uuid, name, zone_id, items) VALUES (%s, %s, %s, %s);" sqltwo = f"INSERT INTO {site_name}_locations(uuid, name, zone_id, items) VALUES (%s, %s, %s, %s);"
@ -411,7 +422,8 @@ def parse_csv(path_to_csv):
if line[0] != "id": if line[0] != "id":
payload["item_info"]["packaging"] = line[10] payload["item_info"]["packaging"] = line[10]
payload["item_info"]["uom"] = line[13] payload["item_info"]["uom"] = line[13]
payload["item_info"]["cost"] = line[15] if line[15] != "":
payload["item_info"]["cost"] = line[15]
if line[17] != "None": if line[17] != "None":
payload["item_info"]["safety_stock"] = line[17] payload["item_info"]["safety_stock"] = line[17]
qty = float(line[30]) qty = float(line[30])
@ -432,4 +444,4 @@ if __name__ == "__main__":
for k, v in items.items(): for k, v in items.items():
print(f"{k}: {v}") print(f"{k}: {v}")
""" """
parse_csv(r"C:\\Users\\jadow\Downloads\\2024-10-02-Pantry.csv") parse_csv(r"C:\\Users\\jadow\\Documents\\code\\postgresql python\\postgresql-python\\2024-10-02-Pantry.csv")

View File

@ -6,6 +6,22 @@ Manage.py is where the databases and configuration is set up. Its a CLI for quic
MyPantry App. MyPantry App.
""" """
def rename_unique_sql(site_name):
files = os.walk(f"sites/{site_name}/sql/unique")
sql_files = []
for file in files:
sql_files = file[2]
for file_name in sql_files:
words = None
with open(f"sites/{site_name}/sql/unique/{file_name}", "r") as file:
words = file.read()
words = words.replace("%sitename%", site_name)
with open(f"sites/{site_name}/sql/unique/{file_name}", "w") as file:
file.write(words)
def rename_drop_sql(site_name): def rename_drop_sql(site_name):
files = os.walk(f"sites/{site_name}/sql/drop") files = os.walk(f"sites/{site_name}/sql/drop")
@ -60,6 +76,7 @@ def create():
shutil.copytree(f"sites/default/sql", f"sites/{site_name}/sql") shutil.copytree(f"sites/default/sql", f"sites/{site_name}/sql")
rename_create_sql(site_name) rename_create_sql(site_name)
rename_drop_sql(site_name) rename_drop_sql(site_name)
rename_unique_sql(site_name)
with open(f"sites/{site_name}/site.ini", "w+") as config: with open(f"sites/{site_name}/site.ini", "w+") as config:
config.write(f"[site]\n") config.write(f"[site]\n")

View File

@ -3,6 +3,7 @@ CREATE TABLE IF NOT EXISTS %sitename%_items(
barcode VARCHAR(255) NOT NULL, barcode VARCHAR(255) NOT NULL,
item_name VARCHAR(255) NOT NULL, item_name VARCHAR(255) NOT NULL,
brand INTEGER, brand INTEGER,
description TEXT;
tags TEXT [], tags TEXT [],
links JSONB, links JSONB,
item_info_id INTEGER NOT NULL, item_info_id INTEGER NOT NULL,

View File

@ -6,4 +6,4 @@ CREATE TABLE IF NOT EXISTS %sitename%_receipt_items (
qty FLOAT8 NOT NULL, qty FLOAT8 NOT NULL,
data JSONB, data JSONB,
status VARCHAR (64) status VARCHAR (64)
) );

View File

@ -5,4 +5,4 @@ CREATE TABLE IF NOT EXISTS %sitename%_vendors (
creation_date TIMESTAMP NOT NULL, creation_date TIMESTAMP NOT NULL,
created_by TIMESTAMP NOT NULL, created_by TIMESTAMP NOT NULL,
phone_number VARCHAR(32) phone_number VARCHAR(32)
) );

View File

@ -0,0 +1 @@
DROP TABLE %sitename%_receipt_items CASCADE;

View File

@ -0,0 +1 @@
DROP TABLE %sitename%_receipts CASCADE;

View File

@ -0,0 +1 @@
DROP TABLE %sitename%_recipes CASCADE;

View File

@ -0,0 +1 @@
DROP TABLE %sitename%_shopping_lists CASCADE;

View File

@ -0,0 +1 @@
DROP TABLE %sitename%_vendors CASCADE;

View File

@ -9,36 +9,37 @@ WHERE %sitename%_items.id=%s;
01 - barcode 01 - barcode
02 - item_name 02 - item_name
03 - brand (id) 03 - brand (id)
04 - tags 04 - description
05 - links 05 - tags
06 - item_info_id 06 - links
07 - logistics_info_id 07 - item_info_id
08 - food_info_id 08 - logistics_info_id
09 - row_type 09 - food_info_id
10 - item_type 10 - row_type
11 - search_string 11 - item_type
12 - logistics_info_id 12 - search_string
13 - barcode 13 - logistics_info_id
14 - primary_location 14 - barcode
15 - auto_issue_location 15 - primary_location
16 - dynamic_locations 16 - auto_issue_location
17 - location_data 17 - dynamic_locations
18 - quantity_on_hand 18 - location_data
19 - item_info_id 19 - quantity_on_hand
20 - barcode 20 - item_info_id
21 - linked_items 21 - barcode
22 - shopping_lists 22 - linked_items
23 - recipes 23 - shopping_lists
24 - groups 24 - recipes
25 - packaging 25 - groups
26 - uom 26 - packaging
27 - cost 27 - uom
28 - safety_stock 28 - cost
29 - lead_time_days 29 - safety_stock
30 - ai_pick 30 - lead_time_days
31 - food_info_id 31 - ai_pick
32 - food_groups 32 - food_info_id
33 - ingrediants 33 - food_groups
34 - nutrients 34 - ingrediants
35 - expires 35 - nutrients
36 - expires
*/ */

View File

@ -1,6 +1,6 @@
[site] [site]
site_name=main site_name=main
site_owner=jadowyne site_owner=
email= email=
[defaults] [defaults]

View File

@ -4,7 +4,7 @@ CREATE TABLE IF NOT EXISTS main_items(
item_name VARCHAR(255) NOT NULL, item_name VARCHAR(255) NOT NULL,
brand INTEGER, brand INTEGER,
tags TEXT [], tags TEXT [],
links TEXT [], links JSONB,
item_info_id INTEGER NOT NULL, item_info_id INTEGER NOT NULL,
logistics_info_id INTEGER NOT NULL, logistics_info_id INTEGER NOT NULL,
food_info_id INTEGER, food_info_id INTEGER,

View File

@ -0,0 +1,9 @@
CREATE TABLE IF NOT EXISTS main_receipt_items (
id SERIAL PRIMARY KEY,
type VARCHAR(255) NOT NULL,
barcode VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
qty FLOAT8 NOT NULL,
data JSONB,
status VARCHAR (64)
);

View File

@ -0,0 +1,10 @@
CREATE TABLE IF NOT EXISTS main_receipts (
id SERIAL PRIMARY KEY,
receipt_id INTEGER NOT NULL,
receipt_status VARCHAR (64) NOT NULL,
date_submitted TIMESTAMP NOT NULL,
submitted_by INTEGER NOT NULL,
vendor_id INTEGER,
files JSONB,
UNIQUE(receipt_id)
);

View File

@ -0,0 +1,12 @@
CREATE TABLE IF NOT EXISTS main_recipes (
id SERIAL PRIMARY KEY,
name VARCHAR,
author INTEGER,
description TEXT,
creation_date TIMESTAMP,
custom_items JSONB,
pantry_items JSONB,
group_items JSONB,
instructions TEXT [],
picture_path TEXT
);

View File

@ -0,0 +1,13 @@
CREATE TABLE IF NOT EXISTS main_shopping_lists (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
pantry_items JSONB,
custom_items JSONB,
recipes JSONB,
groups JSONB,
author INTEGER,
creation_date TIMESTAMP,
type VARCHAR(64),
UNIQUE(name)
);

View File

@ -0,0 +1,8 @@
CREATE TABLE IF NOT EXISTS main_vendors (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
address VARCHAR(255),
creation_date TIMESTAMP NOT NULL,
created_by TIMESTAMP NOT NULL,
phone_number VARCHAR(32)
);

View File

@ -0,0 +1 @@
DROP TABLE main_receipt_items CASCADE;

View File

@ -0,0 +1 @@
DROP TABLE main_receipts CASCADE;

View File

@ -0,0 +1 @@
DROP TABLE main_recipes CASCADE;

View File

@ -0,0 +1 @@
DROP TABLE main_shopping_lists CASCADE;

View File

@ -0,0 +1 @@
DROP TABLE main_vendors CASCADE;

View File

@ -2,4 +2,43 @@ SELECT * FROM main_items
LEFT JOIN main_logistics_info ON main_items.logistics_info_id = main_logistics_info.id LEFT JOIN main_logistics_info ON main_items.logistics_info_id = main_logistics_info.id
LEFT JOIN main_item_info ON main_items.item_info_id = main_item_info.id LEFT JOIN main_item_info ON main_items.item_info_id = main_item_info.id
LEFT JOIN main_food_info ON main_items.food_info_id = main_food_info.id LEFT JOIN main_food_info ON main_items.food_info_id = main_food_info.id
WHERE main_items.id=%s; WHERE main_items.id=%s;
/*
00 - item_id
01 - barcode
02 - item_name
03 - brand (id)
04 - tags
05 - links
06 - item_info_id
07 - logistics_info_id
08 - food_info_id
09 - row_type
10 - item_type
11 - search_string
12 - logistics_info_id
13 - barcode
14 - primary_location
15 - auto_issue_location
16 - dynamic_locations
17 - location_data
18 - quantity_on_hand
19 - item_info_id
20 - barcode
21 - linked_items
22 - shopping_lists
23 - recipes
24 - groups
25 - packaging
26 - uom
27 - cost
28 - safety_stock
29 - lead_time_days
30 - ai_pick
31 - food_info_id
32 - food_groups
33 - ingrediants
34 - nutrients
35 - expires
*/

View File

@ -4,78 +4,177 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" charset="utf-8" />
<title>My Pantry</title> <title>My Pantry</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@materializecss/materialize@2.0.3-alpha/dist/css/materialize.min.css" /> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@materializecss/materialize@2.0.3-alpha/dist/css/materialize.min.css" />
<!-- Material Icons -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" /> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
<!-- Material Symbols - Outlined Set -->
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" rel="stylesheet" />
<!-- Material Symbols - Rounded Set -->
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded" rel="stylesheet" />
<!-- Material Symbols - Sharp Set -->
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/@materializecss/materialize@2.0.3-alpha/dist/js/materialize.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/@materializecss/materialize@2.0.3-alpha/dist/js/materialize.min.js"></script>
</head> </head>
<style>
.hand-pointer {
cursor: pointer;
}
[type="radio"]:checked + span:after {
border: 2px solid rgb(0 128 0 / 30%); /* Outline color */
background-color: rgb(0 128 0 / 30%); /* Fill color */
}
</style>
<body> <body>
<div class="container section"> <div class="container section" style="padding-bottom: 72px;">
<div class="row"> <div class="row">
<div class="col s9 m6 offset-m3 input-field outlined align-center"> <div class="col s9 m6 offset-m3 input-field outlined align-center">
<i class="material-icons prefix">search</i> <i class="material-icons prefix">search</i>
<input style="border-radius: 20px; border: 1px solid #ccc;" id="search" name="search" type="search" placeholder="Search" value=""> <input style="border-radius: 20px; border: 1px solid #ccc;" id="search" name="search" type="search" placeholder="Search" value="">
</div> </div>
<div class="col s3"> <div class="col s3">
<a class="btn waves-effect waves-light center-align right tooltipped" data-position="bottom" data-tooltip="Open up filter options." style="margin-top: 5px;" onclick="hideFilters()"><i class="material-icons">tune</i></a> <a class="btn waves-effect waves-light center-align right tooltipped green lighten-3 black-text text-darken-2 z-depth-0" data-position="bottom" data-tooltip="Open up filter options." style="margin-right: 5px; margin-top:0px; border-radius: 20px 10px 20px 10px;" onclick="hideFilters()"><i class="material-icons">tune</i></a>
</div> </div>
<div class="col s12 hide" id="filter_options"> <div class="col s12 hide" id="filter_options" style="padding: 20px">
<div class="row"> <!-- This is for basic views -->
<div class="row center">
<div class="col s12">
<p>Change Views</p>
</div>
<div class="col s6 m4 l2">
<label>
<input name="group3" type="radio" checked onclick="changeView(0)"/>
<span>All</span>
</label>
</div>
<div class="col s6 m4 l2">
<label>
<input name="group3" type="radio" onclick="changeView(1)"/>
<span>Non Zero Items</span>
</label>
</div>
<div class="col s12 divider"></div>
</div>
<!-- This is for sorting values -->
<div class="row center">
<div class="col s12">
<p>Sort Items By</p>
</div>
<div class="col s6 m4 l2">
<label>
<input name="group2" type="radio" onclick="changeSort(0)"/>
<span>Barcode</span>
</label>
</div>
<div class="col s6 m4 l2">
<label>
<input name="group2" type="radio" checked onclick="changeSort(1)"/>
<span>Item Name</span>
</label>
</div>
<div class="col s6 m4 l2">
<label>
<input name="group2" type="radio" onclick="changeSort(2)"/>
<span>Quantity on Hand</span>
</label>
</div>
<div class="col s12 divider"></div>
</div>
<!-- Set the number of items -->
<div class="row center">
<div class="col s12"> <div class="col s12">
<p>Item Limit</p> <p>Set Items Per Page</p>
</div> </div>
<div class="col s2"> <div class="col s6 m4 l2">
<label> <label>
<input name="group1" type="radio" checked onclick="changeLimit(25)"/> <input name="group1" type="radio" checked onclick="changeLimit(25)"/>
<span>25 items</span> <span>25 items</span>
</label> </label>
</div> </div>
<div class="col s2"> <div class="col s6 m4 l2">
<label> <label>
<input name="group1" type="radio" onclick="changeLimit(50)"/> <input name="group1" type="radio" onclick="changeLimit(50)"/>
<span>50 items</span> <span>50 items</span>
</label> </label>
</div> </div>
<div class="col s2"> <div class="col s6 m4 l2">
<label> <label>
<input name="group1" type="radio" onclick="changeLimit(75)"/> <input name="group1" type="radio" onclick="changeLimit(75)"/>
<span>75 itesm</span> <span>75 itesm</span>
</label> </label>
</div> </div>
<div class="col s2"> <div class="col s6 m4 l2">
<label> <label>
<input name="group1" type="radio" onclick="changeLimit(100)"/> <input name="group1" type="radio" onclick="changeLimit(100)"/>
<span>100 items</span> <span>100 items</span>
</label> </label>
</div> </div>
<div class="col s6 m4 l2">
<label>
<input name="group1" type="radio" onclick="changeLimit(150)"/>
<span>150 items</span>
</label>
</div>
<div class="col s6 m4 l2">
<label>
<input name="group1" type="radio" onclick="changeLimit(200)"/>
<span>200 items</span>
</label>
</div>
<div class="col s12 divider"></div> <div class="col s12 divider"></div>
</div> </div>
</div> </div>
<div class="col s12"> <div class="col s12 z-depth-0">
<div class="collection" id="collection_list"> <div class="z-depth-0" id="cards">
</div> </div>
</div> </div>
<div class="col s12 center" id="pagination_list"> <div class="col s12 center" id="pagination_list">
<ul class="pagination"> <ul class="pagination">
<li id="first" class="waves-effect"><a><i class="material-icons">first_page</i></a></li> <li id="first" class="waves-effect hand-pointer"><a class="green lighten-3" style="display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 10px;"><i class="material-icons">first_page</i></a></li>
<li id="back" class="waves-effect"><a><i class="material-icons">chevron_left</i></a></li> <li id="back" class="waves-effect hand-pointer" ><a class="green lighten-3" style="display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 10px;"><i class="material-icons">chevron_left</i></a></li>
<li id="current_page" class="flow-text">page_number</li> <li id="current_page" style="padding-top: 7px; padding-left: 5px; padding-right: 5px; font-size: 18px;">page_number</li>
<li id="forward" class="waves-effect"><a><i class="material-icons">chevron_right</i></a></li> <li id="forward" class="waves-effect hand-pointer"><a class="green lighten-3" style="display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 10px;"><i class="material-icons">chevron_right</i></a></li>
<li id="last" class="waves-effect"><a><i class="material-icons">last_page</i></a></li> <li id="last" class="waves-effect hand-pointer"><a class="green lighten-3" style="display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 10px;"><i class="material-icons">last_page</i></a></li>
</ul> </ul>
</div> </div>
</div> </div>
</div> </div>
<div class="fixed-action-btn">
<a class="btn-floating btn-large">
<i class="large material-icons">more_vert</i>
</a>
<ul>
<li><a class="btn-floating blue darken-1"><i class="material-icons">playlist_add</i></a></li>
<li><a class="btn-floating green darken-1"><i class="material-icons">download</i></a></li>
</ul>
</div>
</body> </body>
<script> <script>
let current_page = 1 let current_page = 1
let end_page = 10 let end_page = 10
let sort_order = 1
let view = 0
let limit = 50 let limit = 50
let filter_state = "hidden" let filter_state = "hidden"
let searchText = "" let searchText = ""
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.collapsible');
var instances = M.Collapsible.init(elems, {
// specify options here
});
});
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.fixed-action-btn');
var instances = M.FloatingActionButton.init(elems, {
// specify options here
});
});
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
update_list() update_list()
}); });
@ -108,6 +207,10 @@
url.searchParams.append('page', current_page); url.searchParams.append('page', current_page);
url.searchParams.append('limit', limit); url.searchParams.append('limit', limit);
url.searchParams.append('search_text', searchText); url.searchParams.append('search_text', searchText);
url.searchParams.append('sort_order', sort_order);
url.searchParams.append('view', view);
fetch(url) fetch(url)
.then(response => response.json()) .then(response => response.json())
@ -127,24 +230,79 @@
document.getElementById('last').classList.add("waves-effect") document.getElementById('last').classList.add("waves-effect")
}; };
const collection = document.getElementById('collection_list'); //<ul class="collapsible">
collection.style = "border: 0px; gap: 12px;" // <li>
while(collection.firstChild){ // <div class="collapsible-header"><i class="material-icons">filter_drama</i>First</div>
collection.removeChild(collection.firstChild); //<div class="collapsible-body"><span>Lorem ipsum dolor sit amet.</span></div>
} // </li>
//</ul>
const cards = document.getElementById("cards")
const dummy_div = document.createElement('div')
const list_collapsible = document.createElement('ul')
list_collapsible.classList.add("collapsible")
list_collapsible.classList.add("popout")
list_collapsible.style = "background: white;"
data.items.forEach(item => { data.items.forEach(item => {
const collection_item = document.createElement('a');
collection_item.classList.add('collection-item');
collection_item.classList.add('truncate');
collection_item.href = `/getItem?id=${item[0]}`
collection_item.style = "border-radius: 20px; border: 1px solid #ccc; margin-top: 5px;"
let qty = item[18] let qty = item[18]
let roundedQty = qty.toFixed(2) let roundedQty = qty.toFixed(2)
collection_item.innerHTML = `${item[2]}<span class="badge hide-on-small-only indigo lighten-4" style="border-radius: 20px;" data-badge-caption="">${roundedQty}</span>`; var list_item = document.createElement('li')
collection.appendChild(collection_item); list_item.classList.add("z-depth-0")
}) list_item.style = "background: white;"
var header = document.createElement("div")
header.classList.add("collapsible-header")
header.style = "box-shadow: none !important; background: white; border: 1px solid rgb(150 150 150 / 30%); border-radius: 10px 10px 0px 0px;"
header.innerHTML = `<i class='material-symbols-outlined'>grocery</i>${item[2]}
<span class="badge green lighten-4 black-text text-darken-2 z-depth-0" style="border-radius: 5px;">Qty: ${roundedQty}</span>`
var body = document.createElement('div')
body.classList.add("collapsible-body")
body.style = "box-shadow: none !important; background: rgb(0 128 0 / 10%); border: 1px solid rgb(150 150 150 / 30%); border-radius: 0px 0px 10px 10px;"
var description = document.createElement('div')
description.classList.add("col")
description.classList.add("s12")
description.innerHTML = `
<span>Lorem ipsum dolor sit amet. This is a description for ${item[2]}</span>
<div class="divider s12" style="margin-bottom: 5px; margin-top: 5px;"></div>`
var button_group = document.createElement('div')
button_group.classList.add("row")
button_group.style = "margin-bottom: 0px; padding-bottom: 0px;"
button_group.innerHTML = `
<div class="col s12" style="align-items: center;">
<a class="btn right green lighten-3 black-text text-darken-2 z-depth-0 tooltipped" data-position="bottom" data-tooltip="Edit Item" style="display: inline-flex; border-radius: 20px 10px 20px 10px;">
<i class='material-icons'>edit</i>
</a>
<a class="btn right green lighten-3 black-text text-darken-2 z-depth-0 tooltipped" data-position="left" data-tooltip="Transactions" style="display: inline-flex; margin-right: 5px; margin-top:0px; border-radius: 20px 10px 20px 10px;">
<i class='material-icons'>list_alt</i>
</a>
</div>`
body.appendChild(description)
body.appendChild(button_group)
list_item.appendChild(header)
list_item.appendChild(body)
list_collapsible.appendChild(list_item)
});
dummy_div.appendChild(list_collapsible)
cards.innerHTML = dummy_div.innerHTML
var elems = document.querySelectorAll('.collapsible');
var instances = M.Collapsible.init(elems, {
// specify options here
});
var elems = document.querySelectorAll('.tooltipped');
var instances = M.Tooltip.init(elems, {
// specify options here
});
document.getElementById("current_page").innerHTML = `${String(current_page)} / ${String(end_page)}` document.getElementById("current_page").innerHTML = `${String(current_page)} / ${String(end_page)}`
}) })
@ -157,6 +315,16 @@
update_list() update_list()
}; };
function changeSort(order){
sort_order = order
update_list()
}
function changeView(view_num){
view = view_num
update_list()
}
function hideFilters(){ function hideFilters(){
if (filter_state == "hidden"){ if (filter_state == "hidden"){
document.getElementById("filter_options").classList.remove("hide"); document.getElementById("filter_options").classList.remove("hide");

108
templates/workshop.html Normal file
View File

@ -0,0 +1,108 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" charset="utf-8" />
<title>Workshop</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@materializecss/materialize@2.0.3-alpha/dist/css/materialize.min.css" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/@materializecss/materialize@2.0.3-alpha/dist/js/materialize.min.js"></script>
</head>
<body>
<div class="container">
<div class="section">
<div class="row">
<div class="col s12">
<div class="row">
<div class="col s12 m9" style="background-color: whitesmoke;">
<p class="flow-text" style="text-align: center; padding: 10px;"> Welcome to you personalized workshop, this is where you can add/create/modify
alot of the items and functions in your site. These modals will walk you through what basic info you will need
in order to further expand on your site.</p>
</div>
<div class="col s12 m3" style="background-color: aliceblue;">
<div class="col s6 m6 m-2">
<a class="btn elevated green modal-trigger" href="#modal1" style="width: 100%;">Add Group</a>
</div>
<div class="col s6 m6 m-2">
<button class="btn elevated orange" style="width: 100%;">Add Item</button>
</div>
<div class="col s6 m6 m-2">
<button class="btn elevated blue" style="width: 100%;">Add Shopping List</button>
</div>
<div class="col s6 m6 m-2">
<button class="btn elevated purple" style="width: 100%;">Add Recipe</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="modal1" class="modal">
<div class="modal-content">
<h4>Adding a Group...</h4>
<div class="row">
<div class="col s12">
<div class="card-panel">
<span class="blue-text">Groups are internal "grouping" of items that can be of the same type, tag, process, etc. The point of them is that you
can keep track of all of one thing in a list for quick reference.</span>
</div>
</div>
<div class="col s12 m6 input-field outlined p-2">
<input id="group_name" type="text" placeholder=" " maxlength="64">
<label for="group_name">Group Name</label>
<!--<span class="supporting-text">Supporting Text</span>-->
</div>
<div class="input-field col s12 m6 p-2">
<select id="group_type">
<option value="plain" selected>Plain Group</option>
<option value="exclusive">Exclusive Group</option>
<option value="inclusive">Inclusive Group</option>
</select>
<label for="group_type">Group Type</label>
</div>
<div class="input-field col s12 p-2">
<textarea id="group_description" class="materialize-textarea" placeholder="A short description for what this group represents..."></textarea>
<label for="group_description">Group Description</label>
</div>
</div>
</div>
<div class="modal-footer">
<a onclick="addGroup()" class="waves-effect btn">Add</a>
</div>
</div>
</body>
<script>
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.modal');
var instances = M.Modal.init(elems, {
// specify options here
});
});
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('select');
var instances = M.FormSelect.init(elems, {
// specify options here
});
});
function addGroup(){
var name = document.getElementById("group_name").value
var description = document.getElementById("group_description").value
var type = document.getElementById("group_type").value
const url = new URL('/addGroup', window.location.origin);
url.searchParams.append('name', name);
url.searchParams.append('description', description);
url.searchParams.append('type', type);
fetch(url)
.then(response => response.json())
.then(data => {
console.log(data)
})
}
</script>
</html>

View File

@ -4,6 +4,9 @@ app = Flask(__name__)
app.register_blueprint(api.database_api) app.register_blueprint(api.database_api)
@app.route("/workshop")
def workshop():
return render_template("workshop.html")
@app.route("/") @app.route("/")
def home(): def home():