🛠️

- add show price preference(store in cookies)
This commit is contained in:
2026-06-12 17:36:57 +08:00
parent 3f386e5e38
commit 9e9788ea22
13 changed files with 320 additions and 18 deletions
+84 -3
View File
@@ -34,13 +34,37 @@
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Price (USD) *</label>
<div class="relative">
<!-- Input mode toggle -->
<div class="flex gap-1 mb-2 bg-gray-100 rounded-lg p-0.5 text-xs">
<button type="button" id="priceModeTotal" onclick="setPriceMode('total')"
class="flex-1 py-1.5 rounded-md font-medium transition bg-white shadow text-primary">
Total Price
</button>
<button type="button" id="priceModeUnit" onclick="setPriceMode('unit')"
class="flex-1 py-1.5 rounded-md font-medium transition text-gray-500">
Per Sqft
</button>
</div>
<!-- Total price input (default visible) -->
<div class="relative" id="totalPriceGroup">
<span class="absolute left-3 top-3 text-gray-500 font-medium">$</span>
<input type="number" name="price" required min="0"
<input type="number" id="totalPriceInput" name="price" required min="0"
value="{{ values.price|default('') }}"
placeholder="450,000"
class="w-full pl-8 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-accent outline-none transition">
</div>
<!-- Unit price input (hidden by default) -->
<div class="relative hidden" id="unitPriceGroup">
<span class="absolute left-3 top-3 text-gray-500 font-medium">$</span>
<input type="number" id="unitPriceInput" min="0" step="0.01"
placeholder="225"
class="w-full pl-8 pr-12 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-accent outline-none transition">
<span class="absolute right-3 top-3 text-gray-400 text-sm">/sqft</span>
</div>
<!-- Reference total when in unit mode -->
<p class="text-xs text-gray-400 mt-1 hidden" id="priceRef">
Total: <span id="priceRefValue">$0</span>
</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Property Type *</label>
@@ -71,7 +95,7 @@
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Area (sqft) *</label>
<input type="number" name="area_sqft" required min="0"
<input type="number" id="areaSqftInput" name="area_sqft" required min="0"
value="{{ values.area_sqft|default('') }}"
placeholder="2000"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-accent outline-none transition">
@@ -170,4 +194,61 @@
</div>
</form>
</div>
<script>
(function() {
var priceMode = 'total';
window.setPriceMode = function(mode) {
priceMode = mode;
var totalGroup = document.getElementById('totalPriceGroup');
var unitGroup = document.getElementById('unitPriceGroup');
var totalBtn = document.getElementById('priceModeTotal');
var unitBtn = document.getElementById('priceModeUnit');
var ref = document.getElementById('priceRef');
var priceInput = document.getElementById('totalPriceInput');
if (mode === 'total') {
totalGroup.classList.remove('hidden');
unitGroup.classList.add('hidden');
ref.classList.add('hidden');
totalBtn.classList.add('bg-white', 'shadow', 'text-primary');
totalBtn.classList.remove('text-gray-500');
unitBtn.classList.remove('bg-white', 'shadow', 'text-primary');
unitBtn.classList.add('text-gray-500');
} else {
totalGroup.classList.add('hidden');
unitGroup.classList.remove('hidden');
ref.classList.remove('hidden');
unitBtn.classList.add('bg-white', 'shadow', 'text-primary');
unitBtn.classList.remove('text-gray-500');
totalBtn.classList.remove('bg-white', 'shadow', 'text-primary');
totalBtn.classList.add('text-gray-500');
updateTotalFromUnit();
}
};
function getArea() {
return parseInt(document.getElementById('areaSqftInput').value) || 0;
}
function updateTotalFromUnit() {
var unitVal = parseFloat(document.getElementById('unitPriceInput').value) || 0;
var area = getArea();
var total = Math.round(unitVal * area);
document.getElementById('totalPriceInput').value = total || '';
document.getElementById('priceRefValue').textContent = '$' + total.toLocaleString();
}
document.getElementById('unitPriceInput').addEventListener('input', updateTotalFromUnit);
document.getElementById('areaSqftInput').addEventListener('input', function() {
if (priceMode === 'unit') updateTotalFromUnit();
});
// Ensure total price is synced before form submission
document.querySelector('form').addEventListener('submit', function() {
if (priceMode === 'unit') updateTotalFromUnit();
});
})();
</script>
{% endblock %}
+1 -1
View File
@@ -82,7 +82,7 @@
<div>
<div class="flex items-center justify-between flex-wrap gap-4">
<h1 class="text-3xl font-bold text-primary">{{ prop.title }}</h1>
<span class="text-3xl font-extrabold text-accent">${{ "{:,}".format(prop.price) }}</span>
<span class="text-3xl font-extrabold text-accent">{{ prop.price|price_fmt(price_pref, prop.area_sqft) }}</span>
</div>
<p class="flex items-center text-gray-500 mt-2">
<svg class="w-5 h-5 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+91 -3
View File
@@ -32,12 +32,36 @@
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Price (USD) *</label>
<div class="relative">
<!-- Input mode toggle -->
<div class="flex gap-1 mb-2 bg-gray-100 rounded-lg p-0.5 text-xs">
<button type="button" id="priceModeTotal" onclick="setPriceMode('total')"
class="flex-1 py-1.5 rounded-md font-medium transition bg-white shadow text-primary">
Total Price
</button>
<button type="button" id="priceModeUnit" onclick="setPriceMode('unit')"
class="flex-1 py-1.5 rounded-md font-medium transition text-gray-500">
Per Sqft
</button>
</div>
<!-- Total price input (default visible) -->
<div class="relative" id="totalPriceGroup">
<span class="absolute left-3 top-3 text-gray-500 font-medium">$</span>
<input type="number" name="price" required min="0"
<input type="number" id="totalPriceInput" name="price" required min="0"
value="{{ prop.price }}"
class="w-full pl-8 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-accent outline-none transition">
</div>
<!-- Unit price input (hidden by default) -->
<div class="relative hidden" id="unitPriceGroup">
<span class="absolute left-3 top-3 text-gray-500 font-medium">$</span>
<input type="number" id="unitPriceInput" min="0" step="0.01"
placeholder="225"
class="w-full pl-8 pr-12 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-accent outline-none transition">
<span class="absolute right-3 top-3 text-gray-400 text-sm">/sqft</span>
</div>
<!-- Reference total when in unit mode -->
<p class="text-xs text-gray-400 mt-1 hidden" id="priceRef">
Total: <span id="priceRefValue">$0</span>
</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Property Type *</label>
@@ -67,7 +91,7 @@
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Area (sqft) *</label>
<input type="number" name="area_sqft" required min="0"
<input type="number" id="areaSqftInput" name="area_sqft" required min="0"
value="{{ prop.area_sqft }}"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-accent outline-none transition">
</div>
@@ -173,4 +197,68 @@
</div>
</form>
</div>
<script>
(function() {
var priceMode = 'total';
window.setPriceMode = function(mode) {
priceMode = mode;
var totalGroup = document.getElementById('totalPriceGroup');
var unitGroup = document.getElementById('unitPriceGroup');
var totalBtn = document.getElementById('priceModeTotal');
var unitBtn = document.getElementById('priceModeUnit');
var ref = document.getElementById('priceRef');
if (mode === 'total') {
totalGroup.classList.remove('hidden');
unitGroup.classList.add('hidden');
ref.classList.add('hidden');
totalBtn.classList.add('bg-white', 'shadow', 'text-primary');
totalBtn.classList.remove('text-gray-500');
unitBtn.classList.remove('bg-white', 'shadow', 'text-primary');
unitBtn.classList.add('text-gray-500');
} else {
totalGroup.classList.add('hidden');
unitGroup.classList.remove('hidden');
ref.classList.remove('hidden');
unitBtn.classList.add('bg-white', 'shadow', 'text-primary');
unitBtn.classList.remove('text-gray-500');
totalBtn.classList.remove('bg-white', 'shadow', 'text-primary');
totalBtn.classList.add('text-gray-500');
updateTotalFromUnit();
}
};
function getArea() {
return parseInt(document.getElementById('areaSqftInput').value) || 0;
}
function updateTotalFromUnit() {
var unitVal = parseFloat(document.getElementById('unitPriceInput').value) || 0;
var area = getArea();
var total = Math.round(unitVal * area);
document.getElementById('totalPriceInput').value = total || '';
document.getElementById('priceRefValue').textContent = '$' + total.toLocaleString();
}
document.getElementById('unitPriceInput').addEventListener('input', updateTotalFromUnit);
document.getElementById('areaSqftInput').addEventListener('input', function() {
if (priceMode === 'unit') updateTotalFromUnit();
});
// Initialize unit price from existing values
var priceInput = document.getElementById('totalPriceInput');
var areaInput = document.getElementById('areaSqftInput');
if (priceInput.value && areaInput.value && parseInt(areaInput.value) > 0) {
var unitPrice = parseInt(priceInput.value) / parseInt(areaInput.value);
document.getElementById('unitPriceInput').value = Math.round(unitPrice * 100) / 100;
}
// Ensure total price is synced before form submission
document.querySelector('form').addEventListener('submit', function() {
if (priceMode === 'unit') updateTotalFromUnit();
});
})();
</script>
{% endblock %}
+7 -2
View File
@@ -30,7 +30,12 @@
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Price Range (USD)</label>
<label class="block text-sm font-medium text-gray-700 mb-1">
Price Range
{% if price_pref == 'sqft' %}
<span class="text-xs text-gray-400 font-normal">(per sqft)</span>
{% endif %}
</label>
<div class="flex gap-2">
<input type="number" name="min_price" value="{{ min_price|default('') }}"
placeholder="Min" min="0"
@@ -86,7 +91,7 @@
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
{% from "components/property_card.html" import property_card %}
{% for prop in properties %}
{{ property_card(prop) }}
{{ property_card(prop, price_pref) }}
{% endfor %}
</div>