Skip to content

Commit e8ab312

Browse files
committed
add empty states
1 parent 99b80cc commit e8ab312

File tree

4 files changed

+286
-217
lines changed

4 files changed

+286
-217
lines changed

lib/algora_web/live/org/bounties_live.ex

Lines changed: 70 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,23 @@ defmodule AlgoraWeb.Org.BountiesLive do
9797
</div>
9898
</div>
9999
<div :if={@current_status == :open} class="overflow-hidden rounded-xl border border-white/15">
100-
<div class="scrollbar-thin w-full overflow-auto">
101-
<table class="w-full caption-bottom text-sm">
102-
<tbody class="[&_tr:last-child]:border-0">
103-
<%= for %{bounty: bounty, claim_groups: claim_groups} <- @bounty_rows do %>
100+
<%= if Enum.empty?(@bounty_rows) do %>
101+
<div class="flex flex-col items-center justify-center py-16 text-center">
102+
<.icon name="tabler-diamond" class="mb-4 h-16 w-16 text-muted-foreground/50" />
103+
<h3 class="mb-2 text-lg font-semibold text-foreground">No open bounties</h3>
104+
<p class="text-sm text-muted-foreground">
105+
Create bounties by commenting
106+
<code class="mx-1 inline-block rounded bg-emerald-950/75 px-1 py-0.5 font-mono text-xs text-emerald-400 ring-1 ring-emerald-400/25">
107+
/bounty $1000
108+
</code>
109+
on GitHub issues
110+
</p>
111+
</div>
112+
<% else %>
113+
<div class="scrollbar-thin w-full overflow-auto">
114+
<table class="w-full caption-bottom text-sm">
115+
<tbody class="[&_tr:last-child]:border-0">
116+
<%= for %{bounty: bounty, claim_groups: claim_groups} <- @bounty_rows do %>
104117
<tr
105118
class="bg-white/[2%] from-white/[2%] via-white/[2%] to-white/[2%] border-b border-white/15 bg-gradient-to-br transition-colors data-[state=selected]:bg-gray-100 hover:bg-gray-100/50 dark:data-[state=selected]:bg-gray-800 dark:hover:bg-white/[2%]"
106119
data-state="false"
@@ -275,59 +288,70 @@ defmodule AlgoraWeb.Org.BountiesLive do
275288
</td>
276289
</tr>
277290
<% end %>
278-
<% end %>
279-
</tbody>
280-
</table>
281-
</div>
282-
<div :if={@has_more_bounties} class="flex justify-center mt-4" data-load-more-indicator>
283-
<div class="animate-pulse text-gray-400">
284-
<.icon name="tabler-loader" class="h-6 w-6 animate-spin" />
291+
<% end %>
292+
</tbody>
293+
</table>
285294
</div>
286-
</div>
295+
<div :if={@has_more_bounties} class="flex justify-center mt-4" data-load-more-indicator>
296+
<div class="animate-pulse text-gray-400">
297+
<.icon name="tabler-loader" class="h-6 w-6 animate-spin" />
298+
</div>
299+
</div>
300+
<% end %>
287301
</div>
288302
<div :if={@current_status == :paid} class="relative">
289-
<%= for %{transaction: transaction, recipient: recipient, ticket: ticket} <- @transaction_rows do %>
290-
<div class="mb-4 rounded-lg border border-border bg-card p-4">
291-
<div class="flex gap-4">
292-
<div class="flex-1">
293-
<div class="mb-2 font-mono text-2xl font-extrabold text-success">
294-
{Money.to_string!(transaction.net_amount)}
295-
</div>
296-
<div :if={ticket.repository} class="mb-1 text-sm text-muted-foreground">
297-
{ticket.repository.user.provider_login}/{ticket.repository.name}#{ticket.number}
298-
</div>
299-
<div class="font-medium">
300-
{ticket.title}
301-
</div>
302-
<div class="mt-1 text-xs text-muted-foreground">
303-
{Algora.Util.time_ago(transaction.succeeded_at)}
303+
<%= if Enum.empty?(@transaction_rows) do %>
304+
<div class="flex flex-col items-center justify-center rounded-xl border border-white/15 py-16 text-center">
305+
<.icon name="tabler-gift" class="mb-4 h-16 w-16 text-muted-foreground/50" />
306+
<h3 class="mb-2 text-lg font-semibold text-foreground">No completed bounties</h3>
307+
<p class="text-sm text-muted-foreground">
308+
Completed bounties will appear here once they are paid out
309+
</p>
310+
</div>
311+
<% else %>
312+
<%= for %{transaction: transaction, recipient: recipient, ticket: ticket} <- @transaction_rows do %>
313+
<div class="mb-4 rounded-lg border border-border bg-card p-4">
314+
<div class="flex gap-4">
315+
<div class="flex-1">
316+
<div class="mb-2 font-mono text-2xl font-extrabold text-success">
317+
{Money.to_string!(transaction.net_amount)}
318+
</div>
319+
<div :if={ticket.repository} class="mb-1 text-sm text-muted-foreground">
320+
{ticket.repository.user.provider_login}/{ticket.repository.name}#{ticket.number}
321+
</div>
322+
<div class="font-medium">
323+
{ticket.title}
324+
</div>
325+
<div class="mt-1 text-xs text-muted-foreground">
326+
{Algora.Util.time_ago(transaction.succeeded_at)}
327+
</div>
304328
</div>
305-
</div>
306329
307-
<div class="flex w-32 flex-col items-center border-l border-border pl-4">
308-
<h3 class="mb-3 text-xs font-medium uppercase text-muted-foreground">
309-
Awarded to
310-
</h3>
311-
<img
312-
src={recipient.avatar_url}
313-
class="mb-2 h-16 w-16 rounded-full"
314-
alt={recipient.name}
315-
/>
316-
<div class="text-center text-sm font-medium">
317-
{recipient.name}
318-
<div>
319-
{Algora.Misc.CountryEmojis.get(recipient.country)}
330+
<div class="flex w-32 flex-col items-center border-l border-border pl-4">
331+
<h3 class="mb-3 text-xs font-medium uppercase text-muted-foreground">
332+
Awarded to
333+
</h3>
334+
<img
335+
src={recipient.avatar_url}
336+
class="mb-2 h-16 w-16 rounded-full"
337+
alt={recipient.name}
338+
/>
339+
<div class="text-center text-sm font-medium">
340+
{recipient.name}
341+
<div>
342+
{Algora.Misc.CountryEmojis.get(recipient.country)}
343+
</div>
320344
</div>
321345
</div>
322346
</div>
323347
</div>
348+
<% end %>
349+
<div :if={@has_more_transactions} class="flex justify-center mt-4" data-load-more-indicator>
350+
<div class="animate-pulse text-gray-400">
351+
<.icon name="tabler-loader" class="h-6 w-6 animate-spin" />
352+
</div>
324353
</div>
325354
<% end %>
326-
<div :if={@has_more_transactions} class="flex justify-center mt-4" data-load-more-indicator>
327-
<div class="animate-pulse text-gray-400">
328-
<.icon name="tabler-loader" class="h-6 w-6 animate-spin" />
329-
</div>
330-
</div>
331355
</div>
332356
</div>
333357

lib/algora_web/live/org/home_live.ex

Lines changed: 116 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -136,131 +136,161 @@ defmodule AlgoraWeb.Org.HomeLive do
136136
<div class="flex items-center justify-between">
137137
<h2 class="text-lg font-semibold">Open Bounties</h2>
138138
<.link
139+
:if={@open_bounties |> length() > 0}
139140
href={~p"/#{@org.handle}/bounties?status=open"}
140141
class="text-sm text-muted-foreground hover:underline"
141142
>
142143
View all
143144
</.link>
144145
</div>
145-
<div class="relative -ml-4 w-full overflow-auto scrollbar-thin">
146-
<table class="w-full caption-bottom text-sm">
147-
<tbody>
148-
<%= for bounty <- @open_bounties do %>
149-
<tr class="h-10 border-b transition-colors hover:bg-muted/10">
150-
<td class="p-4 py-0 align-middle">
151-
<div class="flex items-center gap-4">
152-
<div class="font-display shrink-0 whitespace-nowrap text-base font-semibold text-success">
153-
{Money.to_string!(bounty.amount)}
154-
</div>
155-
156-
<.link
157-
href={Bounty.url(bounty)}
158-
class="max-w-[400px] truncate text-sm text-foreground hover:underline"
159-
>
160-
{bounty.ticket.title}
161-
</.link>
146+
<%= if Enum.empty?(@open_bounties) do %>
147+
<div class="flex flex-col items-center justify-center py-12 text-center">
148+
<.icon name="tabler-diamond" class="mb-3 h-12 w-12 text-muted-foreground/50" />
149+
<h3 class="mb-1 text-sm font-medium text-foreground">No open bounties</h3>
150+
<p class="text-sm text-muted-foreground">There are no open bounties at the moment</p>
151+
</div>
152+
<% else %>
153+
<div class="relative -ml-4 w-full overflow-auto scrollbar-thin">
154+
<table class="w-full caption-bottom text-sm">
155+
<tbody>
156+
<%= for bounty <- @open_bounties do %>
157+
<tr class="h-10 border-b transition-colors hover:bg-muted/10">
158+
<td class="p-4 py-0 align-middle">
159+
<div class="flex items-center gap-4">
160+
<div class="font-display shrink-0 whitespace-nowrap text-base font-semibold text-success">
161+
{Money.to_string!(bounty.amount)}
162+
</div>
162163
163-
<div
164-
:if={Bounty.path(bounty)}
165-
class="flex shrink-0 items-center gap-1 whitespace-nowrap text-sm text-muted-foreground"
166-
>
167-
<.icon name="tabler-chevron-right" class="h-4 w-4" />
168-
<.link href={Bounty.url(bounty)} class="hover:underline">
169-
{Bounty.path(bounty)}
164+
<.link
165+
href={Bounty.url(bounty)}
166+
class="max-w-[400px] truncate text-sm text-foreground hover:underline"
167+
>
168+
{bounty.ticket.title}
170169
</.link>
170+
171+
<div
172+
:if={Bounty.path(bounty)}
173+
class="flex shrink-0 items-center gap-1 whitespace-nowrap text-sm text-muted-foreground"
174+
>
175+
<.icon name="tabler-chevron-right" class="h-4 w-4" />
176+
<.link href={Bounty.url(bounty)} class="hover:underline">
177+
{Bounty.path(bounty)}
178+
</.link>
179+
</div>
171180
</div>
172-
</div>
173-
</td>
174-
</tr>
175-
<% end %>
176-
</tbody>
177-
</table>
178-
</div>
181+
</td>
182+
</tr>
183+
<% end %>
184+
</tbody>
185+
</table>
186+
</div>
187+
<% end %>
179188
</div>
180189
<!-- Completed Bounties -->
181190
<div class="space-y-4 rounded-xl border bg-card p-6">
182191
<div class="flex items-center justify-between">
183192
<h2 class="text-lg font-semibold">Completed Bounties</h2>
184193
<.link
194+
:if={@transactions |> length() > 0}
185195
href={~p"/#{@org.handle}/bounties?status=completed"}
186196
class="text-sm text-muted-foreground hover:underline"
187197
>
188198
View all
189199
</.link>
190200
</div>
191-
<div class="relative -ml-4 w-full overflow-auto scrollbar-thin">
192-
<table class="w-full caption-bottom text-sm">
193-
<tbody>
194-
<%= for %{transaction: transaction, ticket: ticket} <- @transactions do %>
195-
<tr class="h-10 border-b transition-colors hover:bg-muted/10">
196-
<td class="p-4 py-0 align-middle">
197-
<div class="flex items-center gap-4">
198-
<div class="font-display shrink-0 whitespace-nowrap text-base font-semibold text-success">
199-
{Money.to_string!(transaction.net_amount)}
200-
</div>
201-
202-
<.maybe_link
203-
href={
204-
if ticket.repository,
205-
do:
206-
"https://github.com/#{ticket.repository.user.provider_login}/#{ticket.repository.name}/issues/#{ticket.number}",
207-
else: ticket.url
208-
}
209-
class="max-w-[400px] truncate text-sm text-foreground hover:underline"
210-
>
211-
{ticket.title}
212-
</.maybe_link>
201+
<%= if Enum.empty?(@transactions) do %>
202+
<div class="flex flex-col items-center justify-center py-12 text-center">
203+
<.icon name="tabler-gift" class="mb-3 h-12 w-12 text-muted-foreground/50" />
204+
<h3 class="mb-1 text-sm font-medium text-foreground">No completed bounties</h3>
205+
<p class="text-sm text-muted-foreground">
206+
Completed bounties will appear here
207+
</p>
208+
</div>
209+
<% else %>
210+
<div class="relative -ml-4 w-full overflow-auto scrollbar-thin">
211+
<table class="w-full caption-bottom text-sm">
212+
<tbody>
213+
<%= for %{transaction: transaction, ticket: ticket} <- @transactions do %>
214+
<tr class="h-10 border-b transition-colors hover:bg-muted/10">
215+
<td class="p-4 py-0 align-middle">
216+
<div class="flex items-center gap-4">
217+
<div class="font-display shrink-0 whitespace-nowrap text-base font-semibold text-success">
218+
{Money.to_string!(transaction.net_amount)}
219+
</div>
213220
214-
<div
215-
:if={ticket.repository || ticket.url}
216-
class="flex shrink-0 items-center gap-1 whitespace-nowrap text-sm text-muted-foreground"
217-
>
218-
<.icon name="tabler-chevron-right" class="h-4 w-4" />
219-
<.link
221+
<.maybe_link
220222
href={
221223
if ticket.repository,
222224
do:
223225
"https://github.com/#{ticket.repository.user.provider_login}/#{ticket.repository.name}/issues/#{ticket.number}",
224226
else: ticket.url
225227
}
226-
class="hover:underline"
228+
class="max-w-[400px] truncate text-sm text-foreground hover:underline"
227229
>
228-
{Bounty.path(%{ticket: ticket})}
229-
</.link>
230+
{ticket.title}
231+
</.maybe_link>
232+
233+
<div
234+
:if={ticket.repository || ticket.url}
235+
class="flex shrink-0 items-center gap-1 whitespace-nowrap text-sm text-muted-foreground"
236+
>
237+
<.icon name="tabler-chevron-right" class="h-4 w-4" />
238+
<.link
239+
href={
240+
if ticket.repository,
241+
do:
242+
"https://github.com/#{ticket.repository.user.provider_login}/#{ticket.repository.name}/issues/#{ticket.number}",
243+
else: ticket.url
244+
}
245+
class="hover:underline"
246+
>
247+
{Bounty.path(%{ticket: ticket})}
248+
</.link>
249+
</div>
230250
</div>
231-
</div>
232-
</td>
233-
</tr>
234-
<% end %>
235-
</tbody>
236-
</table>
237-
</div>
251+
</td>
252+
</tr>
253+
<% end %>
254+
</tbody>
255+
</table>
256+
</div>
257+
<% end %>
238258
</div>
239259
</div>
240260
241261
<div class="space-y-4">
242262
<h2 class="text-lg font-semibold">Top Earners</h2>
243263
<div class="rounded-xl border bg-card">
244-
<%= for {earner, idx} <- Enum.with_index(@top_earners) do %>
245-
<div class="flex items-center gap-4 border-b p-4 last:border-0">
246-
<div class="w-8 flex-shrink-0 text-center font-mono text-muted-foreground">
247-
#{idx + 1}
248-
</div>
249-
<.link navigate={User.url(earner)} class="flex flex-1 items-center gap-3">
250-
<.avatar class="h-8 w-8">
251-
<.avatar_image src={earner.avatar_url} alt={earner.name} />
252-
</.avatar>
253-
<div>
254-
<div class="font-medium">
255-
{earner.name} {Algora.Misc.CountryEmojis.get(earner.country)}
264+
<%= if Enum.empty?(@top_earners) do %>
265+
<div class="flex flex-col items-center justify-center py-12 text-center">
266+
<.icon name="tabler-trophy" class="mb-3 h-12 w-12 text-muted-foreground/50" />
267+
<h3 class="mb-1 text-sm font-medium text-foreground">No earners yet</h3>
268+
<p class="text-sm text-muted-foreground">
269+
Top earners will appear here once bounties are completed
270+
</p>
271+
</div>
272+
<% else %>
273+
<%= for {earner, idx} <- Enum.with_index(@top_earners) do %>
274+
<div class="flex items-center gap-4 border-b p-4 last:border-0">
275+
<div class="w-8 flex-shrink-0 text-center font-mono text-muted-foreground">
276+
#{idx + 1}
277+
</div>
278+
<.link navigate={User.url(earner)} class="flex flex-1 items-center gap-3">
279+
<.avatar class="h-8 w-8">
280+
<.avatar_image src={earner.avatar_url} alt={earner.name} />
281+
</.avatar>
282+
<div>
283+
<div class="font-medium">
284+
{earner.name} {Algora.Misc.CountryEmojis.get(earner.country)}
285+
</div>
286+
<div class="text-sm text-muted-foreground">@{User.handle(earner)}</div>
256287
</div>
257-
<div class="text-sm text-muted-foreground">@{User.handle(earner)}</div>
288+
</.link>
289+
<div class="font-display flex-shrink-0 font-medium text-success">
290+
{Money.to_string!(earner.total_earned)}
258291
</div>
259-
</.link>
260-
<div class="font-display flex-shrink-0 font-medium text-success">
261-
{Money.to_string!(earner.total_earned)}
262292
</div>
263-
</div>
293+
<% end %>
264294
<% end %>
265295
</div>
266296
</div>

0 commit comments

Comments
 (0)