diff --git a/app.py b/app.py index 4c019ef..e13aeba 100644 --- a/app.py +++ b/app.py @@ -1681,22 +1681,51 @@ def logout(): @app.route('/dashboard') @login_required def dashboard(): - """Enhanced project-centric dashboard""" + """Enhanced project-centric dashboard with search filters""" try: user = User.query.get(session['user_id']) - - # Get ALL QR codes and projects for project-centric view - qr_codes = QRCode.query.order_by(QRCode.created_date.desc()).all() + + # Get search parameters from URL + search_name = request.args.get('search_name', '').strip() + search_status = request.args.get('search_status', '').strip() + + # Build QR codes query with filters + qr_query = QRCode.query + + # Apply name filter if provided + if search_name: + qr_query = qr_query.filter(QRCode.name.ilike(f'%{search_name}%')) + + # Apply status filter if provided + if search_status == 'active': + qr_query = qr_query.filter(QRCode.active_status == True) + elif search_status == 'inactive': + qr_query = qr_query.filter(QRCode.active_status == False) + + # Execute query + qr_codes = qr_query.order_by(QRCode.created_date.desc()).all() projects = Project.query.order_by(Project.name.asc()).all() - - # Log dashboard access with project info - logger_handler.logger.info(f"User {session['username']} accessed project dashboard: {len(qr_codes)} QR codes, {len(projects)} projects") - + + # Log dashboard access with filter info + filter_info = [] + if search_name: + filter_info.append(f"name contains '{search_name}'") + if search_status: + filter_info.append(f"status is {search_status}") + + log_message = f"User {session['username']} accessed dashboard: {len(qr_codes)} QR codes" + if filter_info: + log_message += f" (filtered: {', '.join(filter_info)})" + + logger_handler.logger.info(log_message) + return render_template('dashboard.html', user=user, qr_codes=qr_codes, - projects=projects) - + projects=projects, + search_name=search_name, + search_status=search_status) + except Exception as e: logger_handler.log_database_error('dashboard_load', e) print(f"Error loading dashboard: {e}") @@ -1741,6 +1770,22 @@ def project_qr_codes(project_id): print(f"Error loading project QR codes: {e}") flash('Error loading project QR codes. Please try again.', 'error') return redirect(url_for('dashboard')) + +@app.route('/dashboard/search', methods=['GET']) +@login_required +def search_qr_codes(): + """Search QR codes - redirect to dashboard with filters""" + search_name = request.args.get('search_name', '').strip() + search_status = request.args.get('search_status', '').strip() + + # Log search activity + logger_handler.logger.info( + f"User {session['username']} searched QR codes: " + f"name='{search_name}', status='{search_status}'" + ) + + # Redirect to dashboard with search parameters + return redirect(url_for('dashboard', search_name=search_name, search_status=search_status)) @app.route('/api/dashboard/stats') @login_required diff --git a/static/css/dashboard.css b/static/css/dashboard.css index 8b736bb..59b0af7 100644 --- a/static/css/dashboard.css +++ b/static/css/dashboard.css @@ -1337,3 +1337,99 @@ border-top: 1px solid var(--gray-200); background: var(--gray-50); } + +/* ============================================ + QR Code Search Section + ============================================ */ +.search-section { + background: var(--white); + border: 1px solid var(--gray-200); + border-radius: var(--radius-xl); + padding: var(--spacing-6); + margin-bottom: var(--spacing-6); +} + +.search-form { + width: 100%; +} + +.search-inputs { + display: flex; + gap: var(--spacing-4); + align-items: flex-end; + flex-wrap: wrap; +} + +.search-input-group { + display: flex; + flex-direction: column; + gap: var(--spacing-2); + flex: 1; + min-width: 250px; + max-width: 400px; +} + +.search-input-group label { + font-size: var(--font-size-sm); + font-weight: 600; + color: var(--gray-700); + display: flex; + align-items: center; + gap: var(--spacing-2); +} + +.search-input, +.search-select { + padding: 0.75rem 1rem; + border: 1px solid var(--gray-300); + border-radius: var(--radius-lg); + font-size: var(--font-size-base); + transition: var(--transition); + width: 100%; + box-sizing: border-box; +} + +.search-input:focus, +.search-select:focus { + outline: none; + border-color: var(--primary-color); + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1); +} + +.search-actions { + display: flex; + align-items: flex-end; + flex-shrink: 0; +} + +.search-actions .btn { + min-width: 120px; + white-space: nowrap; +} + +/* Responsive Design */ +@media (max-width: 992px) { + .search-input-group { + min-width: 200px; + } +} + +@media (max-width: 768px) { + .search-inputs { + flex-direction: column; + align-items: stretch; + } + + .search-input-group { + max-width: 100%; + min-width: 100%; + } + + .search-actions { + width: 100%; + } + + .search-actions .btn { + width: 100%; + } +} \ No newline at end of file diff --git a/templates/dashboard.html b/templates/dashboard.html index 1675719..47035ab 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -981,6 +981,58 @@ Management{% endblock %} {% block extra_head %} padding: var(--spacing-4); } } + +/* ============================================ + Search Results Banner + ============================================ */ +.search-results-banner { + background: linear-gradient(135deg, #dbeafe, #bfdbfe); + border: 1px solid #3b82f6; + border-radius: var(--radius-lg); + padding: var(--spacing-4) var(--spacing-6); + margin-bottom: var(--spacing-6); + animation: slideIn 0.3s ease; +} + +.search-results-content { + display: flex; + align-items: center; + gap: var(--spacing-3); + color: #1e40af; + flex-wrap: wrap; +} + +.search-results-content i { + font-size: 1.2rem; +} + +.search-results-content span { + flex: 1; + font-weight: 500; + min-width: 250px; +} + +.search-results-content .btn-sm { + padding: 0.5rem 1rem; + font-size: var(--font-size-sm); + height: auto; + white-space: nowrap; +} + +@media (max-width: 768px) { + .search-results-banner { + padding: var(--spacing-3) var(--spacing-4); + } + + .search-results-content { + flex-direction: column; + align-items: flex-start; + } + + .search-results-content .btn-sm { + width: 100%; + } +} {% endblock %} {% block content %}
No QR codes match your search criteria. Try adjusting your filters.
+ + + Clear Filters + ++ No QR codes match your search criteria. + {% if search_name %}Try a different name{% endif %} + {% if search_name and search_status %} or {% endif %} + {% if search_status %}try changing the status filter{% endif %}. +
+ + + Clear Filters + + {% elif not projects %} @@ -1385,23 +1653,15 @@ Management{% endblock %} {% block extra_head %} Get started by creating your first project and QR codes to organize your digital assets effectively. -