Advanced search work started
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -1677,9 +1677,17 @@ function showSearchResultsGrid(matches, searchTerm) {
|
||||
|
||||
// Handle Advanced Search button click
|
||||
function handleAdvancedSearch() {
|
||||
// Navigate to advanced search page
|
||||
// Get search text from input field
|
||||
const searchInput = document.getElementById('searchInput');
|
||||
const searchText = searchInput ? searchInput.value.trim() : '';
|
||||
|
||||
// Navigate to advanced search page with search query parameter
|
||||
if (searchText) {
|
||||
window.location.href = '/quiz/advanced-search?q=' + encodeURIComponent(searchText);
|
||||
} else {
|
||||
window.location.href = '/quiz/advanced-search';
|
||||
}
|
||||
}
|
||||
|
||||
// Set up search input event listeners
|
||||
function initSearchBar() {
|
||||
|
||||
@@ -9,52 +9,62 @@
|
||||
<title>Advanced Search - Product Finder</title>
|
||||
<link rel="stylesheet" href="{{ url_for('products.serve_css', filename='styles.css') }}">
|
||||
<style>
|
||||
.wip-container {
|
||||
.search-container {
|
||||
padding: 30px 40px;
|
||||
}
|
||||
|
||||
.search-header {
|
||||
text-align: center;
|
||||
padding: 60px 40px;
|
||||
}
|
||||
|
||||
.wip-icon {
|
||||
font-size: 80px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.wip-title {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.wip-subtitle {
|
||||
font-size: 18px;
|
||||
color: #666;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.wip-details {
|
||||
max-width: 600px;
|
||||
margin: 0 auto 40px;
|
||||
padding: 20px;
|
||||
background-color: #f9f9f9;
|
||||
border: 1px solid #ddd;
|
||||
.search-input-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.products-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 20px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.product-card {
|
||||
background: white;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
text-align: left;
|
||||
padding: 20px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.wip-details h3 {
|
||||
.product-card:hover {
|
||||
border-color: #6a4c93;
|
||||
box-shadow: 0 4px 12px rgba(106, 76, 147, 0.15);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.product-card h3 {
|
||||
color: #333;
|
||||
margin-bottom: 15px;
|
||||
font-size: 1.1em;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.wip-details ul {
|
||||
list-style-position: inside;
|
||||
.no-results {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: #666;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.wip-details ul li {
|
||||
margin-bottom: 8px;
|
||||
.search-stats {
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
background: #f5f5f5;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@@ -76,32 +86,235 @@
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<div class="wip-container">
|
||||
<div class="wip-icon">🚧</div>
|
||||
<div class="wip-title">Work in Progress</div>
|
||||
<div class="wip-subtitle">Advanced Search Features Coming Soon</div>
|
||||
|
||||
<div class="wip-details">
|
||||
<h3>Planned Features:</h3>
|
||||
<ul>
|
||||
<li>Multi-criteria filtering (type, material, color, size)</li>
|
||||
<li>Price range filters</li>
|
||||
<li>Availability by location</li>
|
||||
<li>Advanced product specifications search</li>
|
||||
<li>Compatibility matching</li>
|
||||
<li>Save and share custom searches</li>
|
||||
</ul>
|
||||
<div class="search-container">
|
||||
<div class="search-header">
|
||||
<h2 style="margin-bottom: 15px;">🔍 Search Products</h2>
|
||||
<p style="color: #666; margin-bottom: 20px;">
|
||||
Search by product code, description, color, material, or any combination.
|
||||
Try: "c1800", "storm door white", "bronze aluminum"
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="result-actions">
|
||||
<button class="back-button" onclick="goBack()">← Go Back</button>
|
||||
<button class="back-button" onclick="goToFinder()" style="margin-left: 10px;">🏠 Back to Product Finder</button>
|
||||
<div class="search-input-container">
|
||||
<input
|
||||
type="text"
|
||||
id="searchInput"
|
||||
placeholder="Enter search terms..."
|
||||
style="width: 100%; padding: 15px 20px; font-size: 16px; border: 2px solid #ddd; border-radius: 8px; box-sizing: border-box;"
|
||||
onkeyup="handleSearch(event)"
|
||||
>
|
||||
<button
|
||||
onclick="performSearch()"
|
||||
style="margin-top: 15px; padding: 15px 30px; font-size: 16px; background-color: #6a4c93; color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 600;"
|
||||
>
|
||||
Search
|
||||
</button>
|
||||
<button
|
||||
onclick="clearSearch()"
|
||||
style="margin-top: 15px; margin-left: 10px; padding: 15px 30px; font-size: 16px; background-color: #ccc; color: #333; border: none; border-radius: 8px; cursor: pointer; font-weight: 600;"
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="searchResults" style="margin-top: 30px;"></div>
|
||||
|
||||
<div class="result-actions" style="margin-top: 30px;">
|
||||
<button class="back-button" onclick="goToFinder()">🏠 Back to Product Finder</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Product data
|
||||
let productData = [];
|
||||
|
||||
// Load product data on page load
|
||||
async function loadProductData() {
|
||||
try {
|
||||
const response = await fetch('/quiz/data/products.json');
|
||||
productData = await response.json();
|
||||
console.log('Loaded', productData.length, 'products');
|
||||
} catch (error) {
|
||||
console.error('Error loading product data:', error);
|
||||
document.getElementById('searchResults').innerHTML = `
|
||||
<div class="no-results">
|
||||
<p style="color: #d32f2f;">⚠️ Error loading product data. Please refresh the page.</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize text for matching (remove spaces, hyphens, special chars, lowercase)
|
||||
function normalizeText(text) {
|
||||
if (!text) return '';
|
||||
return text.toString().toLowerCase()
|
||||
.replace(/[-\s_]/g, '') // Remove hyphens, spaces, underscores
|
||||
.replace(/[^a-z0-9]/g, ''); // Remove other special characters
|
||||
}
|
||||
|
||||
// Check if a value matches a search term (partial match)
|
||||
function matchesTerm(value, term) {
|
||||
if (!value) return false;
|
||||
|
||||
// For arrays (like colors, materials)
|
||||
if (Array.isArray(value)) {
|
||||
return value.some(item => normalizeText(item).includes(term));
|
||||
}
|
||||
|
||||
// For objects (like subType)
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
return Object.values(value).some(v =>
|
||||
v && normalizeText(v).includes(term)
|
||||
);
|
||||
}
|
||||
|
||||
// For strings and numbers
|
||||
return normalizeText(value).includes(term);
|
||||
}
|
||||
|
||||
// Search products with partial matching
|
||||
function searchProducts(searchQuery) {
|
||||
if (!searchQuery || searchQuery.trim() === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Split search query into individual terms
|
||||
const searchTerms = searchQuery.toLowerCase()
|
||||
.split(/\s+/)
|
||||
.filter(term => term.length > 0)
|
||||
.map(term => normalizeText(term));
|
||||
|
||||
console.log('Search terms:', searchTerms);
|
||||
|
||||
// Filter products that match ALL search terms
|
||||
const results = productData.filter(product => {
|
||||
// Each product must match ALL search terms
|
||||
return searchTerms.every(term => {
|
||||
// Check if the term matches any of these fields
|
||||
return (
|
||||
matchesTerm(product.productCode, term) ||
|
||||
matchesTerm(product.id, term) ||
|
||||
matchesTerm(product.description, term) ||
|
||||
matchesTerm(product.category, term) ||
|
||||
matchesTerm(product.baseType, term) ||
|
||||
matchesTerm(product.subType, term) ||
|
||||
matchesTerm(product.materials, term) ||
|
||||
matchesTerm(product.colors, term) ||
|
||||
matchesTerm(product.location, term)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// Display search results
|
||||
function displayResults(results, searchQuery) {
|
||||
const resultsDiv = document.getElementById('searchResults');
|
||||
|
||||
if (results.length === 0) {
|
||||
resultsDiv.innerHTML = `
|
||||
<div class="no-results">
|
||||
<h3 style="color: #333; margin-bottom: 10px;">No products found</h3>
|
||||
<p>No products match "${searchQuery}"</p>
|
||||
<p style="margin-top: 15px; font-size: 0.9em;">Try:</p>
|
||||
<ul style="text-align: left; max-width: 400px; margin: 10px auto;">
|
||||
<li>Fewer or more general terms</li>
|
||||
<li>Different spellings (c1800, c-1800, c 1800)</li>
|
||||
<li>Product categories (storm door, window, slider)</li>
|
||||
<li>Materials (aluminum, vinyl) or colors (white, bronze)</li>
|
||||
</ul>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
let html = `
|
||||
<div class="search-stats">
|
||||
Found <strong>${results.length}</strong> product${results.length !== 1 ? 's' : ''} matching "<strong>${searchQuery}</strong>"
|
||||
</div>
|
||||
<div class="products-grid">
|
||||
`;
|
||||
|
||||
results.forEach(product => {
|
||||
const prodCode = product.productCode || product.id;
|
||||
const desc = product.description || 'No description';
|
||||
const materials = product.materials && product.materials.length > 0
|
||||
? product.materials.join(', ')
|
||||
: 'N/A';
|
||||
const colors = product.colors && product.colors.length > 0
|
||||
? product.colors.join(', ')
|
||||
: 'N/A';
|
||||
const location = product.location || 'N/A';
|
||||
const discontinued = product.discontinued ? ' <span style="color: #d32f2f;">(Discontinued)</span>' : '';
|
||||
|
||||
// Get subtype string
|
||||
let subtypeStr = '';
|
||||
if (product.subType) {
|
||||
const doorType = product.subType.door;
|
||||
const windowType = product.subType.window;
|
||||
if (doorType) subtypeStr = doorType;
|
||||
else if (windowType) subtypeStr = windowType;
|
||||
}
|
||||
|
||||
html += `
|
||||
<div class="product-card" onclick="viewProductDetail('${prodCode}')">
|
||||
<h3>${desc}${discontinued}</h3>
|
||||
<p style="color: #999; font-size: 0.95em; margin-top: 5px;"><strong>${prodCode}</strong></p>
|
||||
<div style="font-size: 0.9em; color: #666; margin-top: 10px;">
|
||||
${product.baseType ? `<strong>Type:</strong> ${product.baseType}<br>` : ''}
|
||||
${subtypeStr ? `<strong>Subtype:</strong> ${subtypeStr}<br>` : ''}
|
||||
<strong>Materials:</strong> ${materials}<br>
|
||||
<strong>Colors:</strong> ${colors}<br>
|
||||
<strong>Location:</strong> ${location}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
html += '</div>';
|
||||
resultsDiv.innerHTML = html;
|
||||
}
|
||||
|
||||
// Perform search
|
||||
function performSearch() {
|
||||
const searchInput = document.getElementById('searchInput');
|
||||
const searchQuery = searchInput.value.trim();
|
||||
|
||||
if (searchQuery === '') {
|
||||
document.getElementById('searchResults').innerHTML = `
|
||||
<div class="no-results">
|
||||
<p>Please enter a search term</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
const results = searchProducts(searchQuery);
|
||||
displayResults(results, searchQuery);
|
||||
}
|
||||
|
||||
// Handle Enter key in search input
|
||||
function handleSearch(event) {
|
||||
if (event.key === 'Enter') {
|
||||
performSearch();
|
||||
}
|
||||
}
|
||||
|
||||
// Clear search
|
||||
function clearSearch() {
|
||||
document.getElementById('searchInput').value = '';
|
||||
document.getElementById('searchResults').innerHTML = '';
|
||||
document.getElementById('searchInput').focus();
|
||||
}
|
||||
|
||||
// View product detail (redirect to product finder with product code)
|
||||
function viewProductDetail(productCode) {
|
||||
window.location.href = `/quiz/?p=${productCode}`;
|
||||
}
|
||||
|
||||
// Load user session info
|
||||
async function loadUserInfo() {
|
||||
try {
|
||||
@@ -146,8 +359,30 @@
|
||||
window.location.href = '{{ url_for("products.quiz_index") }}';
|
||||
}
|
||||
|
||||
// Load user info when page loads
|
||||
loadUserInfo();
|
||||
// Initialize page
|
||||
async function init() {
|
||||
await loadUserInfo();
|
||||
await loadProductData();
|
||||
|
||||
// Check if there's a search query in URL
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const queryParam = urlParams.get('q');
|
||||
|
||||
if (queryParam) {
|
||||
// Populate search input with the query
|
||||
const searchInput = document.getElementById('searchInput');
|
||||
searchInput.value = queryParam;
|
||||
|
||||
// Automatically perform the search
|
||||
performSearch();
|
||||
}
|
||||
|
||||
// Focus on search input
|
||||
document.getElementById('searchInput').focus();
|
||||
}
|
||||
|
||||
// Load when page loads
|
||||
init();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user