picture qol fixes

This commit is contained in:
Shiro-Nek0
2026-02-26 23:55:49 -03:00
parent 184f2722bf
commit c7c0b3feb2
2 changed files with 105 additions and 17 deletions

22
app.py
View File

@@ -245,6 +245,28 @@ def bulk_delete():
print(f"Bulk delete failed: {e}") print(f"Bulk delete failed: {e}")
return jsonify({"error": str(e)}), 500 return jsonify({"error": str(e)}), 500
@app.route('/upload_image', methods=['POST'])
@login_required
def upload_image():
if 'image' not in request.files or 'barcode' not in request.form:
return jsonify({"error": "Missing data"}), 400
file = request.files['image']
barcode = request.form['barcode']
if file.filename == '' or not barcode:
return jsonify({"error": "Invalid data"}), 400
# Detect extension
ext = mimetypes.guess_extension(file.mimetype) or '.jpg'
filename = f"{barcode}{ext}"
filepath = os.path.join(CACHE_DIR, filename)
file.save(filepath)
# Return the relative path for the frontend
return jsonify({"status": "success", "image_url": f"/static/cache/{filename}"}), 200
if __name__ == '__main__': if __name__ == '__main__':
init_db() init_db()
socketio.run(app, host='0.0.0.0', port=5000, debug=True) socketio.run(app, host='0.0.0.0', port=5000, debug=True)

View File

@@ -121,9 +121,11 @@
/* ── Price tag ── */ /* ── Price tag ── */
.price-tag { .price-tag {
font-size: 2.2rem; font-size: 2.8rem;
/* Slightly larger for the wider card */
font-weight: 800; font-weight: 800;
color: var(--text-main); color: var(--accent);
/* Optional: uses your accent color for better visibility */
} }
/* ── Table ── */ /* ── Table ── */
@@ -185,8 +187,13 @@
/* ── Product image ── */ /* ── Product image ── */
#display-img { #display-img {
max-width: 160px; width: 100%;
max-height: 160px; /* Allows it to fill the new width */
max-width: 250px;
/* Increased from 160px */
height: auto;
max-height: 250px;
/* Increased from 160px */
object-fit: contain; object-fit: contain;
} }
@@ -279,7 +286,7 @@
<div class="row g-3"> <div class="row g-3">
<!-- ── LEFT COLUMN ── --> <!-- ── LEFT COLUMN ── -->
<div class="col-12 col-lg-4"> <div class="col-12 col-lg-5">
<!-- New product prompt --> <!-- New product prompt -->
<div id="new-product-prompt" <div id="new-product-prompt"
@@ -313,17 +320,32 @@
required> required>
<input class="form-control mb-2" type="number" name="price" id="form-price" <input class="form-control mb-2" type="number" name="price" id="form-price"
placeholder="Precio (CLP)" required> placeholder="Precio (CLP)" required>
<input class="form-control mb-3" type="text" name="image_url" id="form-image"
placeholder="URL Imagen"> <div class="input-group mb-3">
<button type="submit" class="btn btn-accent w-100"> <input class="form-control" type="text" name="image_url" id="form-image"
<i class="bi bi-floppy me-1"></i>Guardar Cambios placeholder="URL Imagen">
</button> <input type="file" id="camera-input" accept="image/*" capture="environment"
style="display: none;" onchange="handleFileUpload(this)">
<button class="btn btn-outline-secondary" type="button"
onclick="document.getElementById('camera-input').click()">
<i class="bi bi-camera"></i>
</button>
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-accent flex-grow-1">
<i class="bi bi-floppy me-1"></i>Guardar
</button>
<button type="button" class="btn btn-secondary" onclick="clearForm()">
<i class="bi bi-eraser"></i>
</button>
</div>
</form> </form>
</div> </div>
</div> </div>
<!-- ── RIGHT COLUMN ── --> <!-- ── RIGHT COLUMN ── -->
<div class="col-12 col-lg-8"> <div class="col-12 col-lg-7">
<div class="discord-card p-3"> <div class="discord-card p-3">
<!-- Bulk actions bar --> <!-- Bulk actions bar -->
@@ -559,10 +581,15 @@
dismissPrompt(); dismissPrompt();
document.getElementById('form-barcode').value = b; document.getElementById('form-barcode').value = b;
document.getElementById('form-name').value = n; document.getElementById('form-name').value = n;
// If p is undefined (from scan_error), set value to empty string
document.getElementById('form-price').value = (p !== undefined && p !== null) ? p : ''; document.getElementById('form-price').value = (p !== undefined && p !== null) ? p : '';
document.getElementById('form-image').value = i || ''; document.getElementById('form-image').value = i || '';
document.getElementById('form-title').innerText = t; document.getElementById('form-title').innerText = t;
// ADD THESE LINES TO UPDATE THE PREVIEW CARD
document.getElementById('display-img').src = i || './static/placeholder.png';
document.getElementById('display-name').innerText = n || 'Producto Nuevo';
document.getElementById('display-price').innerText = clp.format(p || 0);
document.getElementById('display-barcode').innerText = b;
} }
function dismissPrompt() { function dismissPrompt() {
@@ -574,7 +601,7 @@
document.getElementById('editModal').dataset.barcode = b; document.getElementById('editModal').dataset.barcode = b;
document.getElementById('editModal').dataset.name = n; document.getElementById('editModal').dataset.name = n;
document.getElementById('editModal').dataset.price = p; document.getElementById('editModal').dataset.price = p;
document.getElementById('editModal').dataset.image = i; document.getElementById('editModal').dataset.image = i; // This captures the image
} }
function confirmEdit() { function confirmEdit() {
@@ -621,10 +648,49 @@
document.getElementById('selected-count').innerText = document.getElementById('selected-count').innerText =
document.querySelectorAll('.product-checkbox:checked').length; document.querySelectorAll('.product-checkbox:checked').length;
} }
function clearSelection() {
document.querySelectorAll('.product-checkbox').forEach(cb => cb.checked = false); function clearForm() {
document.getElementById('select-all').checked = false; document.getElementById('product-form').reset();
updateBulkBar(); document.getElementById('form-title').innerText = 'Editar / Crear';
// Reset preview card
document.getElementById('display-img').src = './static/placeholder.png';
document.getElementById('display-name').innerText = 'Esperando scan...';
document.getElementById('display-price').innerText = '$0';
document.getElementById('display-barcode').innerText = '';
}
async function handleFileUpload(input) {
const barcode = document.getElementById('form-barcode').value;
if (!barcode) {
alert("Primero escanea o ingresa un código de barras.");
input.value = '';
return;
}
const file = input.files[0];
if (!file) return;
const formData = new FormData();
formData.append('image', file);
formData.append('barcode', barcode);
try {
const res = await fetch('/upload_image', {
method: 'POST',
body: formData
});
const data = await res.json();
if (res.ok) {
document.getElementById('form-image').value = data.image_url;
document.getElementById('display-img').src = data.image_url;
} else {
alert("Error al subir imagen: " + data.error);
}
} catch (err) {
console.error(err);
alert("Error de conexión al subir imagen.");
}
} }
function applyBulkPrice() { function applyBulkPrice() {