Implemented suggestions on recipe new sku modal

This commit is contained in:
Jadowyne Ulve 2025-08-12 17:08:54 -05:00
parent 78d79f9a57
commit 113c2f0632
7 changed files with 105 additions and 4 deletions

View File

@ -126,6 +126,33 @@ def getPicturePath(site:str, payload:tuple):
rows = cur.fetchone()[0] rows = cur.fetchone()[0]
return rows 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): def selectSiteTuple(payload, convert=True):
""" payload (tuple): (site_name,) """ """ payload (tuple): (site_name,) """
site = () site = ()

View File

@ -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': 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!'}) return jsonify({'recipe': recipe, 'error': True, 'message': f'method {request.method} not allowed!'})
@recipes_api.route('/api/receiptRecipe', methods=["POST"]) @recipes_api.route('/api/receiptRecipe', methods=["POST"])
@access_api.login_required @access_api.login_required
def receiptRecipe(): def receiptRecipe():
@ -240,3 +239,13 @@ def receiptRecipe():
return jsonify(status=400, message=message) return jsonify(status=400, message=message)
return jsonify(status=201, message="Recipe Transacted Successfully!") return jsonify(status=201, message="Recipe Transacted Successfully!")
return jsonify(status=405, message=f"{request.method} is not an allowed method on this endpoint!") 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)

View File

@ -379,6 +379,62 @@ async function openNewSKUModal() {
UIkit.modal(itemsModal).show(); 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 = `<span uk-icon="icon: warning"></span> Similar item(s) found: `
let fullhtml = '<span uk-icon="icon: warning"></span> 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 + `<a class="uk-link-muted" href="/items/${matches[i][0]}" target="_blank"><strong>${matches[i][1]}</strong></a>, `
fullhtml = fullhtml + `<a class="uk-link-muted" href="/items/${matches[i][0]}" target="_blank"><strong>${matches[i][1]}</strong></a>, `
shortsuggestions = html
fullsuggestions = fullhtml
}
for (let i = total_matches + 1; i < matches.length; i++){
fullhtml = fullhtml + `<a class="uk-link-muted" href="/items/${matches[i][0]}" target="_blank"><strong>${matches[i][1]}</strong></a>, `
fullsuggestions = fullhtml + `<a class="uk-link-muted" onclick="showLessSuggestions()"><strong>Show less</strong></a>`
}
if(matches.length > 3 ){
html = html + `<a class="uk-link-muted" onclick="showMoreSuggestions()"><strong>${matches.length - (total_matches+1)}</strong></a> 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_current = 1;
let pagination_end = 10; let pagination_end = 10;
let search_string = ""; let search_string = "";

View File

@ -341,8 +341,13 @@
<div class="uk-margin-small"> <div class="uk-margin-small">
<label class="uk-form-label" for="newSKUName">Item Name</label> <label class="uk-form-label" for="newSKUName">Item Name</label>
<div class="uk-form-controls"> <div class="uk-form-controls">
<input class="uk-input" id="newSKUName" type="text" placeholder=""> <input class="uk-input" id="newSKUName" autocomplete="off" type="text" placeholder="">
</div> </div>
<div id="item-warning" class="uk-alert uk-alert-warning uk-padding-small uk-margin-small-top">
<p class="uk-text-small uk-margin-small-top uk-margin-remove-bottom" id="similar-items-list"><span uk-icon="icon: warning"></span><strong>Similar item(s) found:</strong></p>
<div class="uk-text-small uk-margin-remove-top">Are you sure you want to add a new item?</div>
</div>
<ul id="suggestions"></ul>
</div> </div>
<div class="uk-margin-small"> <div class="uk-margin-small">
<label class="uk-form-label" for="newSKUSubtype">Item Type</label> <label class="uk-form-label" for="newSKUSubtype">Item Type</label>

View File

@ -254,7 +254,11 @@ select, option {
color: var(--error-text); 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 */ /* Darkmode settings for planner plage */