profileShare

rasmusjy / splitapp-backend-microservices

Read-only snapshot

No repository description.

main default branch 501 files Expires Sep 13, 2026, 9:06 AM
WishlistClientController.cs 8,752 bytes
1 using System.Security.Claims;
2 using SplitApp.WebApp.Application.DTO;
3 using SplitApp.WebApp.Application.Services;
4 using SplitApp.Modules.Trips.Domain.Entities;
5 using SplitApp.Modules.Trips.Domain.Enums;
6 using SplitApp.Modules.Expenses.Domain.Entities;
7 using SplitApp.Modules.Expenses.Domain.Enums;
8 using Microsoft.AspNetCore.Authorization;
9 using Microsoft.AspNetCore.Identity;
10 using Microsoft.AspNetCore.Mvc;
11 using Microsoft.AspNetCore.Mvc.Rendering;
12
13 namespace SplitApp.WebApp.Controllers;
14
15 [Authorize]
16 public class WishlistClientController : Controller
17 {
18 private readonly ITripService _tripService;
19 private readonly IWishlistService _wishlistService;
20
21 public WishlistClientController(
22 ITripService tripService,
23 IWishlistService wishlistService)
24 {
25 _tripService = tripService;
26 _wishlistService = wishlistService;
27 }
28
29 private Guid GetUserId() => Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
30
31 // GET: WishlistClient?tripId=xxx
32 public async Task<IActionResult> Index(Guid tripId)
33 {
34 var userId = GetUserId();
35 if (!await _tripService.IsParticipantAsync(tripId, userId)) return Forbid();
36
37 var trip = await _tripService.GetByIdAsync(tripId, userId);
38 if (trip == null) return NotFound();
39
40 var items = await _wishlistService.GetByTripIdAsync(tripId, userId);
41
42 ViewData["CurrentUserId"] = userId;
43
44 var model = items.Select(item => new WishlistItemViewModel
45 {
46 Id = item.Id,
47 AddedByUserId = item.AddedByUserId,
48 Title = item.Title,
49 Description = item.Description,
50 Category = item.Category,
51 Priority = item.Priority,
52 EstimatedCost = item.EstimatedCost,
53 Url = item.Url,
54 Location = item.Location,
55 IsCompleted = item.IsCompleted,
56 AddedByName = item.AddedByUserFullName ?? "Unknown",
57 VoteCount = item.VoteCount,
58 UserHasVoted = item.VoterUserIds.Contains(userId)
59 }).ToList();
60
61 ViewData["TripId"] = tripId;
62 ViewData["TripName"] = trip.Name;
63
64 return View(model);
65 }
66
67 // GET: WishlistClient/Create?tripId=xxx
68 public async Task<IActionResult> Create(Guid tripId)
69 {
70 var userId = GetUserId();
71 if (!await _tripService.IsParticipantAsync(tripId, userId)) return Forbid();
72
73 ViewData["TripId"] = tripId;
74 PopulateEnumDropdowns();
75 return View(new TripWishlistItemBllDto { TripId = tripId });
76 }
77
78 // POST: WishlistClient/Create
79 [HttpPost]
80 [ValidateAntiForgeryToken]
81 public async Task<IActionResult> Create(TripWishlistItemBllDto item)
82 {
83 var userId = GetUserId();
84
85 if (ModelState.IsValid)
86 {
87 var (created, errorCode) = await _wishlistService.CreateAsync(item, userId);
88 if (created == null)
89 {
90 if (errorCode == "forbidden") return Forbid();
91 return NotFound();
92 }
93 return RedirectToAction(nameof(Index), new { tripId = item.TripId });
94 }
95
96 ViewData["TripId"] = item.TripId;
97 PopulateEnumDropdowns();
98 return View(item);
99 }
100
101 // POST: WishlistClient/Vote/5
102 [HttpPost]
103 [ValidateAntiForgeryToken]
104 public async Task<IActionResult> Vote(Guid id)
105 {
106 var userId = GetUserId();
107
108 var item = await _wishlistService.GetByIdRawAsync(id);
109 if (item == null) return NotFound();
110
111 var (ok, errorCode) = await _wishlistService.ToggleVoteAsync(id, userId);
112 if (!ok)
113 {
114 return errorCode switch
115 {
116 "notfound" => NotFound(),
117 "forbidden" => Forbid(),
118 _ => NotFound()
119 };
120 }
121
122 return RedirectToAction(nameof(Index), new { tripId = item.TripId });
123 }
124
125 // POST: WishlistClient/Complete/5
126 [HttpPost]
127 [ValidateAntiForgeryToken]
128 public async Task<IActionResult> Complete(Guid id)
129 {
130 var userId = GetUserId();
131
132 var item = await _wishlistService.GetByIdRawAsync(id);
133 if (item == null) return NotFound();
134
135 var (ok, errorCode) = await _wishlistService.ToggleCompleteAsync(id, userId);
136 if (!ok)
137 {
138 return errorCode switch
139 {
140 "notfound" => NotFound(),
141 "forbidden" => Forbid(),
142 _ => NotFound()
143 };
144 }
145
146 return RedirectToAction(nameof(Index), new { tripId = item.TripId });
147 }
148
149 // GET: WishlistClient/Edit/5
150 public async Task<IActionResult> Edit(Guid id)
151 {
152 var userId = GetUserId();
153
154 var item = await _wishlistService.GetByIdAsync(id, userId);
155 if (item == null)
156 {
157 var raw = await _wishlistService.GetByIdRawAsync(id);
158 if (raw == null) return NotFound();
159 return Forbid();
160 }
161
162 if (item.AddedByUserId != userId) return Forbid();
163
164 ViewData["TripId"] = item.TripId;
165 PopulateEnumDropdowns();
166 return View(item);
167 }
168
169 // POST: WishlistClient/Edit/5
170 [HttpPost]
171 [ValidateAntiForgeryToken]
172 public async Task<IActionResult> Edit(Guid id, TripWishlistItemBllDto item)
173 {
174 if (id != item.Id) return NotFound();
175
176 var userId = GetUserId();
177
178 if (ModelState.IsValid)
179 {
180 var preUpdate = await _wishlistService.GetByIdRawAsync(id);
181 if (preUpdate == null) return NotFound();
182
183 var (ok, errorCode) = await _wishlistService.UpdateAsync(id, item, userId);
184 if (!ok)
185 {
186 return errorCode switch
187 {
188 "notfound" => NotFound(),
189 "forbidden" => Forbid(),
190 _ => NotFound()
191 };
192 }
193
194 return RedirectToAction(nameof(Index), new { tripId = preUpdate.TripId });
195 }
196
197 var raw = await _wishlistService.GetByIdRawAsync(id);
198 if (raw == null) return NotFound();
199 ViewData["TripId"] = raw.TripId;
200 PopulateEnumDropdowns();
201 return View(item);
202 }
203
204 // GET: WishlistClient/Delete/5
205 public async Task<IActionResult> Delete(Guid id)
206 {
207 var userId = GetUserId();
208
209 var item = await _wishlistService.GetByIdAsync(id, userId);
210 if (item == null)
211 {
212 var raw = await _wishlistService.GetByIdRawAsync(id);
213 if (raw == null) return NotFound();
214 return Forbid();
215 }
216 if (item.AddedByUserId != userId) return Forbid();
217
218 // Re-fetch with includes via trip items list
219 var tripItems = await _wishlistService.GetByTripIdAsync(item.TripId, userId);
220 var itemWithDetails = tripItems.FirstOrDefault(w => w.Id == id);
221
222 ViewData["TripId"] = item.TripId;
223 return View(itemWithDetails ?? item);
224 }
225
226 // POST: WishlistClient/Delete/5
227 [HttpPost, ActionName("Delete")]
228 [ValidateAntiForgeryToken]
229 public async Task<IActionResult> DeleteConfirmed(Guid id)
230 {
231 var userId = GetUserId();
232
233 var existing = await _wishlistService.GetByIdRawAsync(id);
234 if (existing == null) return NotFound();
235 var tripId = existing.TripId;
236
237 var (ok, errorCode) = await _wishlistService.DeleteAsync(id, userId);
238 if (!ok)
239 {
240 return errorCode switch
241 {
242 "notfound" => NotFound(),
243 "forbidden" => Forbid(),
244 _ => NotFound()
245 };
246 }
247
248 return RedirectToAction(nameof(Index), new { tripId });
249 }
250
251 private void PopulateEnumDropdowns()
252 {
253 ViewData["Categories"] = new SelectList(
254 Enum.GetValues<EWishlistCategory>().Select(e => new { Value = (int)e, Text = e.ToString() }),
255 "Value", "Text");
256 ViewData["Priorities"] = new SelectList(
257 Enum.GetValues<EWishlistPriority>().Select(e => new { Value = (int)e, Text = e.ToString() }),
258 "Value", "Text");
259 }
260 }
261
262 public class WishlistItemViewModel
263 {
264 public Guid Id { get; set; }
265 public Guid AddedByUserId { get; set; }
266 public string Title { get; set; } = default!;
267 public string? Description { get; set; }
268 public EWishlistCategory Category { get; set; }
269 public EWishlistPriority Priority { get; set; }
270 public decimal? EstimatedCost { get; set; }
271 public string? Url { get; set; }
272 public string? Location { get; set; }
273 public bool IsCompleted { get; set; }
274 public string AddedByName { get; set; } = default!;
275 public int VoteCount { get; set; }
276 public bool UserHasVoted { get; set; }
277 }
278