profileShare

rasmusjy / splitapp-backend-modular-monolith

Read-only snapshot

No repository description.

main default branch 418 files Expires Sep 13, 2026, 9:06 AM
Details.cshtml 6,924 bytes
1 @model SplitApp.WebApp.Application.DTO.TripPollBllDto
2
3 @{
4 ViewData["Title"] = Localizer["Poll Results"];
5 var tripId = (Guid)ViewData["TripId"]!;
6 var userId = (Guid)ViewData["UserId"]!;
7 var isCreator = (bool)ViewData["IsCreator"]!;
8 var isClosed = Model.ClosedAt != null;
9 var totalVotes = Model.Options?.Sum(o => o.VoteCount) ?? 0;
10 var maxVotes = Model.Options?.Max(o => o.VoteCount) ?? 0;
11 }
12
13 <div class="row justify-content-center">
14 <div class="col-lg-8">
15 <!-- Header -->
16 <div class="d-flex justify-content-between align-items-start mb-4 flex-wrap gap-3">
17 <div>
18 <h1 style="font-size: 1.5rem; margin-bottom: var(--sa-space-2);">@Model.Question</h1>
19 <div class="d-flex align-items-center gap-3" style="font-size: 0.9rem; color: var(--sa-gray-500);">
20 @if (isClosed)
21 {
22 <span class="d-flex align-items-center gap-1">
23 <span class="sa-status-dot sa-status-dot-pending"></span> @Localizer["Closed"]
24 </span>
25 }
26 else
27 {
28 <span class="d-flex align-items-center gap-1">
29 <span class="sa-status-dot sa-status-dot-active sa-status-dot-pulse"></span> @Localizer["Open"]
30 </span>
31 }
32 <span>@Localizer["Created by"] @(Model.CreatedByUser != null ? $"{Model.CreatedByUser.FirstName} {Model.CreatedByUser.LastName}" : "?")</span>
33 <span>@totalVotes @Localizer["total votes"]</span>
34 @if (Model.AllowMultipleVotes)
35 {
36 <span><i class="bi bi-check2-all me-1"></i>@Localizer["Multiple votes allowed"]</span>
37 }
38 </div>
39 </div>
40 <div class="d-flex gap-2">
41 @if (isCreator && !isClosed)
42 {
43 <form asp-action="Close" asp-route-id="@Model.Id" method="post" style="display:inline">
44 <button type="submit" class="sa-btn sa-btn-sm" style="background: var(--sa-warning); color: #fff;">
45 <i class="bi bi-lock-fill"></i> @Localizer["Close Poll"]
46 </button>
47 </form>
48 }
49 <a asp-action="Index" asp-route-tripId="@tripId" class="sa-btn sa-btn-ghost sa-btn-sm">
50 <i class="bi bi-arrow-left"></i> @Localizer["Back"]
51 </a>
52 </div>
53 </div>
54
55 <!-- Options -->
56 @if (Model.Options != null)
57 {
58 <div class="d-flex flex-column gap-3">
59 @foreach (var option in Model.Options.OrderBy(o => o.DisplayOrder))
60 {
61 var voteCount = option.VoteCount;
62 var percentage = totalVotes > 0 ? (int)(voteCount * 100.0 / totalVotes) : 0;
63 var userVoted = option.VoterUserIds.Contains(userId);
64 var isWinning = voteCount == maxVotes && maxVotes > 0;
65
66 <div class="sa-poll-option @(userVoted ? "sa-poll-option-voted" : "") @(isWinning && isClosed ? "sa-poll-option-winner" : "")">
67 <div class="d-flex justify-content-between align-items-center mb-3">
68 <div class="d-flex align-items-center gap-2">
69 <strong style="font-size: 1rem;">@option.Text</strong>
70 @if (userVoted)
71 {
72 <span class="sa-badge sa-badge-solid-secondary" style="font-size: 0.65rem;">
73 <i class="bi bi-check2"></i> @Localizer["Your vote"]
74 </span>
75 }
76 @if (isWinning && isClosed)
77 {
78 <span class="sa-badge sa-badge-accent" style="font-size: 0.65rem;">
79 <i class="bi bi-trophy-fill"></i> @Localizer["Winner"]
80 </span>
81 }
82 </div>
83 <div class="d-flex align-items-center gap-3">
84 <span style="font-size: 0.9rem; color: var(--sa-gray-500);">
85 @voteCount @Localizer["votes"] (@percentage%)
86 </span>
87 @if (!isClosed)
88 {
89 <form asp-action="Vote" method="post" style="display:inline">
90 <input type="hidden" name="pollId" value="@Model.Id" />
91 <input type="hidden" name="optionId" value="@option.Id" />
92 <button type="submit" class="sa-btn sa-btn-sm sa-btn-pill @(userVoted ? "sa-btn-secondary" : "sa-btn-ghost")">
93 @(userVoted ? Localizer["Unvote"] : Localizer["Vote"])
94 </button>
95 </form>
96 }
97 </div>
98 </div>
99
100 @{
101 var barClass = isWinning && isClosed ? "sa-progress-bar-success"
102 : userVoted ? "sa-progress-bar"
103 : "sa-progress-bar-primary";
104 }
105 <div class="sa-progress">
106 <div class="sa-progress-bar @barClass" data-width="@percentage%"></div>
107 </div>
108
109 @if (!Model.IsAnonymous && option.Voters.Any())
110 {
111 <div class="d-flex gap-1 mt-2 flex-wrap">
112 @foreach (var voter in option.Voters)
113 {
114 var voterName = $"{voter.FirstName} {voter.LastName}".Trim();
115 var voterInitial = $"{(voter.FirstName.Length > 0 ? voter.FirstName[0].ToString() : "")}{(voter.LastName.Length > 0 ? voter.LastName[0].ToString() : "")}";
116 <span class="sa-avatar sa-avatar-sm sa-avatar-@((voter.Id.GetHashCode() % 8 + 8) % 8 + 1)"
117 title="@voterName" style="border: none; width: 26px; height: 26px; font-size: 0.6rem;">@voterInitial</span>
118 }
119 </div>
120 }
121 </div>
122 }
123 </div>
124 }
125 </div>
126 </div>
127