From 5b5a11a96d5a8ad3859783200df17185cb188de2 Mon Sep 17 00:00:00 2001 From: Marco Allegretti Date: Thu, 5 Feb 2026 13:48:06 +0100 Subject: [PATCH] ux: improve proposals states --- frontend/src/pages/proposals.astro | 70 +++++++++++++++++++++++-- frontend/src/pages/proposals/[id].astro | 47 +++++++++++++++-- 2 files changed, 111 insertions(+), 6 deletions(-) diff --git a/frontend/src/pages/proposals.astro b/frontend/src/pages/proposals.astro index adbccb8..a26cd3b 100644 --- a/frontend/src/pages/proposals.astro +++ b/frontend/src/pages/proposals.astro @@ -44,7 +44,7 @@ import { API_BASE as apiBase } from '../lib/api'; -
+

Loading proposals...

@@ -78,6 +78,62 @@ import { API_BASE as apiBase } from '../lib/api'; container.innerHTML = html; } + function renderErrorState(message) { + const container = document.getElementById('proposals-list'); + if (!container) return; + + container.innerHTML = ` +
+

${message}

+

Check your connection and try again.

+
+ + Browse communities +
+
+ `; + + document.getElementById('retry-load')?.addEventListener('click', loadProposals); + } + + function renderEmptyState(isFiltered) { + const container = document.getElementById('proposals-list'); + if (!container) return; + + container.innerHTML = ` +
+

${isFiltered ? 'No proposals match your filters.' : 'No proposals found.'}

+

Try adjusting search, status, or sort.

+
+ + Go to communities +
+
+ `; + + document.getElementById('reset-filters')?.addEventListener('click', () => { + const searchInput = document.getElementById('search-input'); + const statusFilter = document.getElementById('status-filter'); + const sortFilter = document.getElementById('sort-filter'); + if (searchInput) searchInput.value = ''; + if (statusFilter) statusFilter.value = ''; + if (sortFilter) sortFilter.value = 'newest'; + filterProposals(); + }); + } + + function hasActiveFilters() { + const searchInput = document.getElementById('search-input'); + const statusFilter = document.getElementById('status-filter'); + const sortFilter = document.getElementById('sort-filter'); + + const query = searchInput?.value.toLowerCase().trim() || ''; + const status = statusFilter?.value || ''; + const sort = sortFilter?.value || 'newest'; + + return Boolean(query || status || sort !== 'newest'); + } + async function loadProposals() { const container = document.getElementById('proposals-list'); if (!container) return; @@ -88,7 +144,7 @@ import { API_BASE as apiBase } from '../lib/api'; allProposals = await res.json(); renderProposals(allProposals); } catch (error) { - container.innerHTML = '

Failed to load proposals.

'; + renderErrorState('Failed to load proposals.'); } } @@ -97,7 +153,7 @@ import { API_BASE as apiBase } from '../lib/api'; if (!container) return; if (proposals.length === 0) { - container.innerHTML = '

No proposals found.

'; + renderEmptyState(hasActiveFilters()); return; } @@ -171,6 +227,14 @@ import { API_BASE as apiBase } from '../lib/api'; gap: 1rem; } + .state-actions { + margin-top: 1.25rem; + display: flex; + gap: 0.75rem; + justify-content: center; + flex-wrap: wrap; + } + .proposal-card { display: block; padding: 1.1rem; diff --git a/frontend/src/pages/proposals/[id].astro b/frontend/src/pages/proposals/[id].astro index aa9dfc2..4bbc571 100644 --- a/frontend/src/pages/proposals/[id].astro +++ b/frontend/src/pages/proposals/[id].astro @@ -28,6 +28,24 @@ const proposalId = id ?? ''; let quadraticAllocations = {}; let starRatings = {}; + function renderProposalErrorState(message) { + const container = document.getElementById('proposal-content'); + if (!container) return; + + container.innerHTML = ` +
+

${escapeHtml(message)}

+

It may have been deleted, or you may not have access.

+
+ + Back to proposals +
+
+ `; + + document.getElementById('retry-proposal')?.addEventListener('click', loadProposal); + } + function escapeHtml(value) { return String(value || '').replace(/[&<>"']/g, function(ch) { switch (ch) { @@ -407,7 +425,7 @@ const proposalId = id ?? ''; } } catch (error) { - container.innerHTML = '
Proposal not found
'; + renderProposalErrorState('Proposal not found.'); } } @@ -600,7 +618,12 @@ const proposalId = id ?? ''; const comments = await res.json(); if (comments.length === 0) { - container.innerHTML = '

No comments yet. Be the first to share your thoughts!

'; + container.innerHTML = ` +
+

No comments yet.

+

Be the first to share your thoughts.

+
+ `; return; } @@ -619,7 +642,17 @@ const proposalId = id ?? ''; `; }).join(''); } catch (e) { - container.innerHTML = '

Failed to load comments

'; + container.innerHTML = ` +
+

Failed to load comments.

+

Try again in a moment.

+
+ +
+
+ `; + + document.getElementById('retry-comments')?.addEventListener('click', loadComments); } } @@ -659,6 +692,14 @@ const proposalId = id ?? ''; max-width: 880px; } + .state-actions { + margin-top: 1.25rem; + display: flex; + gap: 0.75rem; + justify-content: center; + flex-wrap: wrap; + } + .results-chart-host { display: none; }