fix: show location (country, city, district) in product edit modal
- JSON endpoint now joins locations+categories+subcategories for full info - Edit form shows location tags (country, city, district) at top - Location hidden when adding new product (no location yet) - All fields properly filled by fillEditForm on edit - Category and subcategory side by side in edit form
This commit is contained in:
@@ -438,6 +438,26 @@ pre { font-size: 0.8rem; white-space: pre-wrap; word-break: break-all; max-width
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.pf-location-row {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.pf-loc-tag {
|
||||
display: inline-block;
|
||||
padding: 0.2rem 0.5rem;
|
||||
background: #e0e7ff;
|
||||
color: #3730a3;
|
||||
border-radius: 999px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.pf-location {
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
|
||||
@@ -48,7 +48,16 @@ router.post('/products/:id/delete', async (req, res) => {
|
||||
});
|
||||
|
||||
router.get('/products/:id/json', async (req, res) => {
|
||||
const p = await db.getAsync('SELECT * FROM products WHERE id=?', [req.params.id]);
|
||||
const p = await db.getAsync(
|
||||
`SELECT p.*, l.country, l.city, l.district, c.name as category_name,
|
||||
COALESCE(sc.name, '') as subcategory_name
|
||||
FROM products p
|
||||
LEFT JOIN locations l ON p.location_id = l.id
|
||||
LEFT JOIN categories c ON p.category_id = c.id
|
||||
LEFT JOIN subcategories sc ON p.subcategory_id = sc.id
|
||||
WHERE p.id = ?`,
|
||||
[req.params.id]
|
||||
);
|
||||
if (!p) return res.status(404).json({ error: 'Not found' });
|
||||
res.json(p);
|
||||
});
|
||||
|
||||
@@ -75,7 +75,7 @@ document.querySelectorAll('.tree-toggle').forEach(el=>{el.addEventListener('clic
|
||||
const loc=el.dataset.loc, cat=el.dataset.cat, sub=el.dataset.sub, all=el.dataset.all;
|
||||
if(loc||cat||sub||all){ let u='/catalog?'; if(loc) u+='loc='+loc; if(cat) u+='cat='+cat; if(sub) u+='sub='+sub; location.href=u; }
|
||||
})});
|
||||
function openAdd(){ document.getElementById('modal-body').innerHTML=addFormTpl; document.getElementById('product-modal').style.display='flex'; }
|
||||
function openAdd(){ document.getElementById('modal-body').innerHTML=addFormTpl; const loc=document.getElementById('pf-location'); if(loc)loc.style.display='none'; document.getElementById('product-modal').style.display='flex'; }
|
||||
async function openEdit(id){ const r=await fetch('/catalog/products/'+id+'/json'); const p=await r.json();
|
||||
document.getElementById('modal-body').innerHTML=editFormTpl.replace('/__ID__/','/'+p.id+'/'); fillEditForm(p); document.getElementById('product-modal').style.display='flex'; }
|
||||
function fillEditForm(p){ const f=document.getElementById('product-modal').querySelector('form'); if(!f)return;
|
||||
@@ -84,7 +84,13 @@ function fillEditForm(p){ const f=document.getElementById('product-modal').query
|
||||
f.querySelector('[name=photo_url]').value=p.photo_url||''; f.querySelector('[name=hidden_photo_url]').value=p.hidden_photo_url||'';
|
||||
f.querySelector('[name=hidden_coordinates]').value=p.hidden_coordinates||''; f.querySelector('[name=hidden_description]').value=p.hidden_description||'';
|
||||
f.querySelector('[name=private_data]').value=p.private_data||''; f.querySelector('[name=category_id]').value=p.category_id||'';
|
||||
updateSubcats(p.category_id,p.subcategory_id); }
|
||||
updateSubcats(p.category_id,p.subcategory_id);
|
||||
const loc=document.getElementById('pf-location');
|
||||
if(loc&&(p.country||p.city||p.district)){
|
||||
loc.style.display=''; document.getElementById('pf-country').textContent=p.country||'';
|
||||
document.getElementById('pf-city').textContent=p.city||''; document.getElementById('pf-district').textContent=p.district||'';
|
||||
} else if(loc){loc.style.display='none';}
|
||||
}
|
||||
function updateSubcats(catId,selSub){ const ss=document.getElementById('product-modal').querySelector('[name=subcategory_id]'); if(!ss)return;
|
||||
ss.innerHTML='<option value="">-- Subcategory --</option>'; subcats.forEach(s=>{if(s.category_id==catId){const o=document.createElement('option');o.value=s.id;o.textContent=s.name;if(s.id==selSub)o.selected=true;ss.appendChild(o)}}); }
|
||||
document.getElementById('product-modal').addEventListener('click',e=>{if(e.target===document.getElementById('product-modal'))document.getElementById('product-modal').style.display='none'});
|
||||
|
||||
@@ -3,6 +3,14 @@ export function renderProductEditForm(action, catOptions, subcatJson) {
|
||||
const title = isEdit ? 'Edit Product' : 'Add Product';
|
||||
return `<h2>${title}</h2>
|
||||
<form method="POST" action="${action}" enctype="multipart/form-data" class="product-form">
|
||||
<div class="pf-group pf-location" id="pf-location" style="display:none">
|
||||
<label>Location</label>
|
||||
<div class="pf-location-row">
|
||||
<span class="pf-loc-tag" id="pf-country"></span>
|
||||
<span class="pf-loc-tag" id="pf-city"></span>
|
||||
<span class="pf-loc-tag" id="pf-district"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-group">
|
||||
<label>Name</label>
|
||||
<input name="name" required placeholder="Product name">
|
||||
@@ -17,15 +25,17 @@ export function renderProductEditForm(action, catOptions, subcatJson) {
|
||||
<input name="quantity_in_stock" type="number" min="0" value="0" placeholder="0">
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-group">
|
||||
<label>Category</label>
|
||||
<select name="category_id" required onchange="updateSubcats(this.value)">
|
||||
<option value="">-- Select --</option>${catOptions}
|
||||
</select>
|
||||
</div>
|
||||
<div class="pf-group">
|
||||
<label>Subcategory</label>
|
||||
<select name="subcategory_id"><option value="">-- Subcategory --</option></select>
|
||||
<div class="pf-row">
|
||||
<div class="pf-group">
|
||||
<label>Category</label>
|
||||
<select name="category_id" required onchange="updateSubcats(this.value)">
|
||||
<option value="">-- Select --</option>${catOptions}
|
||||
</select>
|
||||
</div>
|
||||
<div class="pf-group">
|
||||
<label>Subcategory</label>
|
||||
<select name="subcategory_id"><option value="">-- Subcategory --</option></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-group">
|
||||
<label>Description</label>
|
||||
@@ -49,11 +59,9 @@ export function renderProductEditForm(action, catOptions, subcatJson) {
|
||||
<label>Or Upload Hidden Photo</label>
|
||||
<input type="file" name="hidden_photo_file" accept="image/*" class="pf-file">
|
||||
</div>
|
||||
<div class="pf-row">
|
||||
<div class="pf-group">
|
||||
<label>Hidden Coordinates</label>
|
||||
<input name="hidden_coordinates" placeholder="lat,lng">
|
||||
</div>
|
||||
<div class="pf-group">
|
||||
<label>Hidden Coordinates</label>
|
||||
<input name="hidden_coordinates" placeholder="lat,lng">
|
||||
</div>
|
||||
<div class="pf-group">
|
||||
<label>Hidden Description</label>
|
||||
|
||||
Reference in New Issue
Block a user