From 113c2f06329e364967fd5fe8167012126e776689 Mon Sep 17 00:00:00 2001 From: Jadowyne Ulve Date: Tue, 12 Aug 2025 17:08:54 -0500 Subject: [PATCH] Implemented suggestions on recipe new sku modal --- .../database_recipes.cpython-313.pyc | Bin 38648 -> 39933 bytes .../__pycache__/recipes_api.cpython-313.pyc | Bin 16797 -> 17505 bytes application/recipes/database_recipes.py | 27 +++++++++ application/recipes/recipes_api.py | 13 +++- .../recipes/static/js/recipeEditHandler.js | 56 ++++++++++++++++++ .../recipes/templates/recipe_edit.html | 7 ++- static/css/dark-mode.css | 6 +- 7 files changed, 105 insertions(+), 4 deletions(-) diff --git a/application/recipes/__pycache__/database_recipes.cpython-313.pyc b/application/recipes/__pycache__/database_recipes.cpython-313.pyc index 72db4bb534e7779a38e3cb42c158e6d7189fafdb..a2753f95822a3ff1be3387aacf79865e41cf6ace 100644 GIT binary patch delta 2090 zcmZWpZA?>F7`~^sr-jm%LR+B4N%<&k6(?JSDBuTLP>`Z>K?PAP*kK)3Jndq}MA#;q zC@Aa|-J)@tEz6SWOgulf{h4#J#XmEs%f^;v*%JM+Z#Q+inVG%ka-G{e$$k5r=Xu_9 z&OPtjd*_tyuXl9T8y1U6!coAFY%cB^wPq3jsBdnlP|>@kErc1BLWQ;_DTdZ$#n@_^ zV^ETi*Q1hxiePj~vc{Mnc<1O9lg3&U-{{HwKA%_y%@&Qeq1lRxPWMbi+uRrCm= zY!yvMG)+Z0N+BF4u9E-X%5+r4t>iv*q#LJu?BCNRvvbmHJ5W1VJ5={gYQ`SxAHSta*&XC| z3d+Ol@7{EydbQvyrl&>pH$fO!30xdLz z#M^xKj3&9L7U7?nZC%?s!ing%*!?<2H_i9P%ULz5Y&nLw_)q!_M+v|q>npV0Q$yI!Jjh&DVJmGWv{fccm7z{1aJXb?)^hxx@ z__F#us*wXq2aO@QkN>1(Vj@4$^1Y7#vL>HshFQ(cbUPZ};`^GNQ-(2F(^hS0rU}$8 z@Y5T_u2adU+H>zGf7h{+?m)vezF?DM>R2w`75PC{U(*l$(G7+k)TxeNjXEjag*czz zi|x`Ib|PfG5H5AWk+_|TmM?*Ocx#vA*YtfjJJU0%EZ59w{164Y(Rt;L>L5Hy&D$xX3!CwuH`MgCPMb}$gWp)DTk1W;@2kr zx&#}09dH(sdC{}&Q_HdeIJkR>;YG2?9=JZ}OPMZUjtB~*4iwlr1)ML!J`slCn}v_S z#(_uaD>&W3VE{yleS7=qQ6vuWlY1{~H78@(3e(`D1Eur?O8m@7NG2~qJ@^bDmO2QJ z7G}E4n<8D2M5H0o5$%q!*HF0lpTmOXFmeIX7|=D=2LjM`Fx)5p6HNRM)IMgSQJH8? zCfbgP?qZ^$m}np-I)sUiV4~_wl$VJTGEpZc3dBS$n7DK%u8)ZuW8(FgcqJwduO3YO p&apHJ%Er=7Zz4$DXnNYI70i%knMkYv;{Uer3!{{s!S*A8!Bv delta 1345 zcmZXSe@t6d6vw&mz59S-v8=zKz*yH7Xe1bM!znIB9Ni$JEIgJltYugY9f@?gYqZF) zf;Jn)$?BP=!%S!Vu|M4Y@kULIiHTYK!|1|HO!&t{o^=WWI98zLAJ!1gd74sJ0>&Pu5swvev3j zI`)`W4eAC)>M%lzX4TrtUEAJ0hUKtTr`2A*8j3_Lr#jHJZL$xnw~Y-}q z+8PvjtafXMA}^9#kq^nE$dBYz)QIF$)P&?$6hLZJ)Qr@ms0AsYs1>PM(a!Bl#qC?Q zV1S<4wjHt~t#)MB9g&@OBxpt8Yu0r1|E1ey$3ytxATkqSq}_@lNFhb-cbprx^Ezf& zv_p<-bwT+^XRXc;VBePH=sh`|4Z!v8Nj`)Ez?VHC8NatjXK|SCX*CB>6bE6eyKzU| z%u~6;+4OYoM0QS$p#C13zcYp@ZDZIcSL4qz=-T@^i_2Sk-Hclp_*fbbFoPWdv#-D> zP`D{eeK&M7jwlX8D)t~7g-R^S4#A}hEzqAZVWZazf5d$JF|_<7J^iZ&S}q@m8i!DT z(ey(w*H;bogDx|L!e3P~Jb2t-lkh{V3Emv?^J!EA^3$OKgFOyY69MoilKe>&du2Z1 zX2ukv+!+2PHhpzy>8wrwzdjGsi?HTh23{@T`1KqutpQsy&g`I*VhIWOnWA=ki_e4A{@O&Mk$w_;w^VJ+|Gi?|KQD|v&l1$lM; zPo1xz(glg-qaQy1jm`>iW2w*e0wpccvP?@6vgrWazwF~L<95GHEIXJ{LWFFWPo94L zI)mQg7yMOJ5^}3p)Xf5=Ey3B9N6i-rUxJ$}_u+;0QrMLyVLvTrXgLe6wpJJ~b@SJ7 zo0MltK)pTP9){Rjl2=e%keAoKwHwaLI1^+163P{M`@)FMUV(v1hq*>)ori2C!rwxa zuvHAfXO)r@a2I9cQEfaC?F8%Mbb&@%jjEtw6f}T>=1S1$2$~c@lOd@0g8D6}qk{S+ zs2PIFEvU|d$|oB^$pxt)K I&GiWT8|V;P(EtDd diff --git a/application/recipes/__pycache__/recipes_api.cpython-313.pyc b/application/recipes/__pycache__/recipes_api.cpython-313.pyc index caa1dd554432b19dc225ef694c05ddd89b085cce..cf7a6fc1c8257cdba15e3e53a2992fe350532fb2 100644 GIT binary patch delta 1466 zcmaiz+fN%u6o+^AVhpSe*nk~#i7$c00b>Gn6cj=mRdoOXZEy)egiy;Y*x(DydX?ZP z2~|@ijUuJi2$d#k6rvWDO6^1TrR_`dC*Y#it;DVRWP)9KD`_LzB6mKqnlaj59HTc(Mx>xR~zz?QU2h8P6rbJ zH`+>nEX}jtE^R@0Afhc|vTPcL=qMi2zOa18l?_n)bv#It^@-|X&_@7$fKl>Gy$4Nd zRkkRP&XJ1^UKG|IG%T_xLd?w`G(ftWqtw1j?K$mH^ZOi`cH3E;AlTjZci;_or(q1j zg~-?LuEsN9>Isxl%gbXg2>NBs-5UE7 zv+?^JR#>orW-yckUk0SfIbUnV+tj>IKjjpuX{#eCkDzV(zG2Zda=FWfX31LDvPA~> z{VKb`zE12%{3xpp9El-xgFNi^+irngPC-vX_t8({Ci%VFgVwahp6948N=Jjw#W6V& zTaulFv?flxK-vS%HT$K75SJiCIeFCKAh#uftOV-O5P3H+fbMAD1vXh{1f1-ES%4lB zzXv89Z^lkGx@=Zg>99awqWD+DpN~PrKabVX3s={B6y4K?dtYGDD0%bvN0d@uyRboL zJRuW(*DaZ9e|Rb8pHnlL6<;Epjzr06Lp}Q=Lzb*=c1$4I3abf)*Z@nX&^A^^rdV3-gmP&0|9OeJNU3813wWXSni*VXC}9};@GBs*m-`GgFivT-(K z?Bx#8O^g=MGM=VmdIf?w2U;Uz^BPp55lp;=^p0@eU`0QUfJJ@k!iG5P|5LbEuv~PWq2O<&9__ rJ*{O}Qyy7z$g*v1*+H$}qRKpS&60xX2lvDIo%6lto_o*PoFnNO zqW@M{s8z79>G|XE75jqTNLm+cJH#$k6OURQQgXG@tDGk~!oj7IXZyODk|LVf5^lkY zd%t8UT~OtAvi}RT3tpGSih59V7SV$6LZiV-2BbklSWO1uZ8=AVq|fCMB^idx6;{#- zH!8x+{>bd0R8YC3GKFwo7{Md1A|i+=tXpb+AGT$w)%2pf52~!rL;YyV73MOFQ&SEd zat$GfSsg@_($+OqAjaGol@LkpWzXo6qcPuD(jOOjagy3_W0YYvkD{9Xv!L-`$_^Sw zvy%beVa?WlGg}&Z6NoVcMf_E$CR?ZlLvlVWIiu#qV2ldP6f_KG`J;z1RFD`I#PdD< z-Kdyio;g$%6NO@0@kOK17fp9;+?-@#GBgWgqf7CK2F;y_(EQ zAM8Jr2WQY@M2#-N2gD=|`VxLIOarj#94i^Y=x#gZ2f7U-bq+EwE!Odb+<~1F4#Pdv zk9_>M9_@yW~Mw$xGHqJ4Z{>ESaCIxZrE^j zX_uJeJzK&$oAEly*AP{jhf#!;(f~rvNgtw#Q<^fumeZiG`ZWURA7vRiaJ!2Qdt;fC z?Y0f$!{B!}khJv3eNsuh@UHnOqtJ3(yUe1W*b-9kpr{PiTcY_Kp+}g9v%z?qi(G`4 zZT+Mdl%Cd8a_#{ZqeF-wLPX$b&{@PhViAECqiMu4OnFS&Rc5lmQ3!L=il<*ijPSkP OQSeorM?!=iV}YNWW&4x> diff --git a/application/recipes/database_recipes.py b/application/recipes/database_recipes.py index 56e374d..39bfe18 100644 --- a/application/recipes/database_recipes.py +++ b/application/recipes/database_recipes.py @@ -125,6 +125,33 @@ def getPicturePath(site:str, payload:tuple): cur.execute(f"SELECT picture_path FROM {site}_recipes WHERE id=%s;", payload) rows = cur.fetchone()[0] return rows + +def getFuzzyMatch(site: str, payload, convert=True, conn=None): + matches = [] + self_conn = False + sql = f"SELECT id, item_name FROM {site}_items WHERE LOWER(item_name) ILIKE '%%' || LOWER(TRIM(%s)) || '%%';" + try: + if not conn: + database_config = config.config() + conn = psycopg2.connect(**database_config) + conn.autocommit = True + self_conn = True + print(payload) + with conn.cursor() as cur: + cur.execute(sql, (payload,)) + rows = cur.fetchall() + print(rows) + if rows and convert: + matches = [postsqldb.tupleDictionaryFactory(cur.description, row) for row in rows] + elif rows and not convert: + matches = rows + + if self_conn: + conn.close() + + return matches + except Exception as error: + return error def selectSiteTuple(payload, convert=True): """ payload (tuple): (site_name,) """ diff --git a/application/recipes/recipes_api.py b/application/recipes/recipes_api.py index bb08bc8..2ea447c 100644 --- a/application/recipes/recipes_api.py +++ b/application/recipes/recipes_api.py @@ -228,7 +228,6 @@ def saveRecipeItem(): return jsonify({'recipe': recipe, 'error': False, 'message': f'Recipe Item {updated_line['item_name']} was updated successful!'}) return jsonify({'recipe': recipe, 'error': True, 'message': f'method {request.method} not allowed!'}) - @recipes_api.route('/api/receiptRecipe', methods=["POST"]) @access_api.login_required def receiptRecipe(): @@ -239,4 +238,14 @@ def receiptRecipe(): if not status: return jsonify(status=400, message=message) return jsonify(status=201, message="Recipe Transacted Successfully!") - return jsonify(status=405, message=f"{request.method} is not an allowed method on this endpoint!") \ No newline at end of file + return jsonify(status=405, message=f"{request.method} is not an allowed method on this endpoint!") + +@recipes_api.route('/api/fuzzy-match') +@access_api.login_required +def fuzzyMatchItems(): + query = request.args.get('q', '').strip().lower() + site_name = session['selected_site'] + print(query) + matches = database_recipes.getFuzzyMatch(site_name, query, convert=False) + return jsonify(status=201, message="matches fetched Successfully!", matches=matches) + \ No newline at end of file diff --git a/application/recipes/static/js/recipeEditHandler.js b/application/recipes/static/js/recipeEditHandler.js index f02b709..03d500c 100644 --- a/application/recipes/static/js/recipeEditHandler.js +++ b/application/recipes/static/js/recipeEditHandler.js @@ -379,6 +379,62 @@ async function openNewSKUModal() { UIkit.modal(itemsModal).show(); } + + +// Suggestions for new sku Model +var fullsuggestions = ''; +var shortsuggestions = ''; +async function showMoreSuggestions(){ + document.getElementById('similar-items-list').innerHTML = fullsuggestions; +} + +async function showLessSuggestions(){ + document.getElementById('similar-items-list').innerHTML = shortsuggestions; +} + +document.getElementById('newSKUName').addEventListener('input', async function(e) { + let query = e.target.value.trim(); + if(query.length === 0) { + document.getElementById('suggestions').innerHTML = ''; + return; + } + let resp = await fetch(`/recipes/api/fuzzy-match?q=${encodeURIComponent(query)}`); + let data = await resp.json(); + let matches = data.matches + let total_matches = 3 + let html = ` Similar item(s) found: ` + let fullhtml = ' Similar item(s) found: ' + + if(matches.length){ + document.getElementById('item-warning').hidden = false + if (matches.length < total_matches){ + total_matches = matches.length + } + + for (let i = 0; i < total_matches; i++){ + html = html + `${matches[i][1]}, ` + fullhtml = fullhtml + `${matches[i][1]}, ` + shortsuggestions = html + fullsuggestions = fullhtml + } + + for (let i = total_matches + 1; i < matches.length; i++){ + fullhtml = fullhtml + `${matches[i][1]}, ` + fullsuggestions = fullhtml + `Show less` + } + + if(matches.length > 3 ){ + html = html + `${matches.length - (total_matches+1)} more matches...` + } + shortsuggestions = html + document.getElementById('similar-items-list').innerHTML = html; + } else { + document.getElementById('item-warning').hidden = true + document.getElementById('similar-items-list').innerHTML = ''; + } +}); + + let pagination_current = 1; let pagination_end = 10; let search_string = ""; diff --git a/application/recipes/templates/recipe_edit.html b/application/recipes/templates/recipe_edit.html index 36dacd5..42a7342 100644 --- a/application/recipes/templates/recipe_edit.html +++ b/application/recipes/templates/recipe_edit.html @@ -341,8 +341,13 @@
- +
+
+

Similar item(s) found:

+
Are you sure you want to add a new item?
+
+
    diff --git a/static/css/dark-mode.css b/static/css/dark-mode.css index 4ba64e5..851f9d7 100644 --- a/static/css/dark-mode.css +++ b/static/css/dark-mode.css @@ -254,7 +254,11 @@ select, option { color: var(--error-text); } - +.uk-alert { + background-color: rgba(255, 115, 0, 0.404); + color: var(--primary-text); + border-radius: var(--radius); +} /* Darkmode settings for planner plage */