@@ -287,6 +287,7 @@ defmodule AlgoraWeb.Org.JobLive do
287
287
contributions = { Map . get ( @ contributions_map , match . user . id , [ ] ) }
288
288
contract_type = "bring_your_own "
289
289
anonymized = { @ current_org . hiring_subscription != :active }
290
+ heatmap_data = { Map . get ( @ heatmaps_map , match . user . id ) }
290
291
/>
291
292
</ div >
292
293
<% end %>
@@ -608,12 +609,39 @@ defmodule AlgoraWeb.Org.JobLive do
608
609
609
610
contributions_map = fetch_applicants_contributions ( developers , socket . assigns . job . tech_stack )
610
611
612
+ # Fetch heatmaps for all developers
613
+ heatmaps_map =
614
+ developers
615
+ |> Enum . map ( & & 1 . id )
616
+ |> AlgoraCloud.Profiles . list_heatmaps ( )
617
+ |> Map . new ( fn heatmap -> { heatmap . user_id , heatmap . data } end )
618
+
619
+ # Trigger async sync for missing heatmaps if connected
620
+ if connected? ( socket ) do
621
+ missing_heatmap_users =
622
+ developers
623
+ |> Enum . reject ( & Map . has_key? ( heatmaps_map , & 1 . id ) )
624
+
625
+ if length ( missing_heatmap_users ) > 0 do
626
+ enqueue_heatmap_sync ( missing_heatmap_users )
627
+ end
628
+ end
629
+
611
630
socket
612
631
|> assign ( :developers , developers )
613
632
|> assign ( :applicants , sort_by_contributions ( socket . assigns . job , all_applicants , contributions_map ) )
614
633
|> assign ( :matches , matches )
615
634
|> assign ( :truncated_matches , truncated_matches )
616
635
|> assign ( :contributions_map , contributions_map )
636
+ |> assign ( :heatmaps_map , heatmaps_map )
637
+ end
638
+
639
+ defp enqueue_heatmap_sync ( users ) do
640
+ Task . start ( fn ->
641
+ for user <- users do
642
+ AlgoraCloud.Profiles . sync_heatmap_by ( id: user . id )
643
+ end
644
+ end )
617
645
end
618
646
619
647
defp enqueue_screening ( socket , users ) do
@@ -969,11 +997,56 @@ defmodule AlgoraWeb.Org.JobLive do
969
997
<% end %>
970
998
</ div >
971
999
</ div >
1000
+
1001
+ < . heatmap_display :if = { @ heatmap_data && not @ anonymized } heatmap_data = { @ heatmap_data } />
1002
+ </ div >
1003
+ </ div >
1004
+ """
1005
+ end
1006
+
1007
+ defp heatmap_display ( assigns ) do
1008
+ ~H"""
1009
+ < div class = "mt-4 " >
1010
+ < div class = "flex items-center justify-between mb-2 " >
1011
+ < div class = "text-xs text-muted-foreground uppercase font-semibold " >
1012
+ { get_in ( @ heatmap_data , [ "totalContributions" ] ) } contributions in the last year
1013
+ </ div >
1014
+ </ div >
1015
+ < div class = "grid grid-cols-[repeat(17,1fr)] gap-1 " >
1016
+ <%= for week <- get_in ( @ heatmap_data , [ "weeks" ] ) |> Enum . take ( - 17 ) do %>
1017
+ < div class = "grid grid-rows-7 gap-1 " >
1018
+ <%= for day <- week [ "contributionDays" ] do %>
1019
+ < div
1020
+ class = { "h-3 w-3 rounded-sm #{ get_contribution_color ( day [ "contributionCount" ] ) } " }
1021
+ title = { "#{ day [ "contributionCount" ] } contributions on #{ format_date ( day [ "date" ] ) } " }
1022
+ >
1023
+ </ div >
1024
+ <% end %>
1025
+ </ div >
1026
+ <% end %>
972
1027
</ div >
973
1028
</ div >
974
1029
"""
975
1030
end
976
1031
1032
+ defp get_contribution_color ( count ) do
1033
+ cond do
1034
+ count == 0 -> "bg-muted/50"
1035
+ count in 1 .. 5 -> "bg-success-400/40"
1036
+ count in 6 .. 10 -> "bg-success-400/50"
1037
+ count in 11 .. 15 -> "bg-success-400/70"
1038
+ count in 16 .. 20 -> "bg-success-400/90"
1039
+ true -> "bg-success-400"
1040
+ end
1041
+ end
1042
+
1043
+ defp format_date ( date_string ) do
1044
+ date_string
1045
+ |> String . replace ( "T00:00:00.000+00:00" , "" )
1046
+ |> Date . from_iso8601! ( )
1047
+ |> Calendar . strftime ( "%B %d, %Y" )
1048
+ end
1049
+
977
1050
defp social_links do
978
1051
[
979
1052
{ :website , "tabler-world" } ,
0 commit comments