|
13 | 13 |
|
14 | 14 | <MudLoading @bind-Loading="_isLoading" Darken Overlap>
|
15 | 15 | <MudGrid Style="height: 600px">
|
16 |
| - <MudItem Class="chat-selector-window" md="3" lg="3" xl="3" xxl="3"> |
17 |
| - <MudList Clickable> |
18 |
| - <MudListSubheader> |
19 |
| - <UserAutoComplete SelectedUserChanged="StartNewChat" /> |
20 |
| - </MudListSubheader> |
21 |
| - @foreach (var chat in _chats) |
22 |
| - { |
23 |
| - <MudListItem OnClick="@(() => SelectChat(chat))" Dense="true" Class="chat-selector"> |
24 |
| - |
25 |
| - <MudAvatar Size="Size.Large" Class="mr-3"> |
26 |
| - <MudImage Src="@chat.GetChatImage(_currentUser.Id)" loading="lazy" Alt="Avatar" /> |
27 |
| - </MudAvatar> |
28 |
| - <MudText> |
29 |
| - @if (chat.HasUnreadMessages) |
30 |
| - { |
31 |
| - <b>@chat.GetDisplayName(_currentUser.Id) (@chat.UnreadMessageCount)</b> |
32 |
| - } |
33 |
| - else |
34 |
| - { |
35 |
| - @chat.GetDisplayName(_currentUser.Id) |
36 |
| - } |
37 |
| - </MudText> |
38 |
| - |
39 |
| - </MudListItem> |
40 |
| - <MudDivider DividerType="DividerType.FullWidth" /> |
41 |
| - |
42 |
| - } |
43 |
| - </MudList> |
44 |
| - </MudItem> |
| 16 | + |
| 17 | + <ChatSelector CurrentUser="_currentUser" Chats="_chats" SelectChatCallback="SelectChat" StartNewChatCallback="StartNewChat"/> |
45 | 18 |
|
46 | 19 | <MudItem md="1" lg="1" xl="1" xxl="1">
|
47 |
| - <MudDivider Vertical DividerType="DividerType.FullWidth" /> |
| 20 | + <MudDivider Vertical DividerType="DividerType.FullWidth"/> |
48 | 21 | </MudItem>
|
49 | 22 |
|
50 |
| - <MudItem id="chat-message-window" Class="chat-message-window" md="8" lg="8" xl="8" xxl="8"> |
| 23 | + <MudItem Class="chat-message-window" md="8" lg="8" xl="8" xxl="8"> |
51 | 24 | @if (_activeChat != null)
|
52 | 25 | {
|
53 | 26 | <MudList Class="chat-message-list" DisablePadding Dense>
|
54 |
| - @* ReSharper disable once UnusedParameter.Local *@ |
55 |
| - <Virtualize Items="_activeChat.Messages" Context="message" OverscanCount="8" ItemSize="80"> |
56 |
| - @if (IsMessageFromSelf(message)) |
57 |
| - { |
58 |
| - <MudListItem Class="message-from-self"> |
59 |
| - |
60 |
| - <MudTooltip Placement="Placement.Top" ShowOnClick ShowOnHover="false" Arrow Text="@message.SentUtc.DisplayExactTime()"> |
61 |
| - <MudTooltip ShowOnHover Arrow Text="@message.SentUtc.DisplayTimePassed()"> |
62 |
| - <MudChip Text="@message.Text" |
63 |
| - Class="chat-chip px-2 py-1" /> |
64 |
| - </MudTooltip> |
65 |
| - </MudTooltip> |
66 |
| - </MudListItem> |
67 |
| - } |
68 |
| - else |
69 |
| - { |
70 |
| - <MudListItem> |
71 |
| - <MudTooltip Placement="Placement.Top" ShowOnClick ShowOnHover="false" Arrow Text="@message.SentUtc.DisplayExactTime()"> |
72 |
| - <MudTooltip ShowOnHover Arrow Text="@message.SentUtc.DisplayTimePassed()"> |
73 |
| - <MudChip Class="pl-0 pb-0 chat-chip"> |
74 |
| - <MudAvatar Size="Size.Medium" Class="mr-2"> |
75 |
| - <MudImage Src="@GetRecipientsProfilePictureUrl(message)" loading="lazy" Alt="Avatar" /> |
76 |
| - </MudAvatar> |
77 |
| - @message.Text |
78 |
| - </MudChip> |
79 |
| - </MudTooltip> |
80 |
| - </MudTooltip> |
81 |
| - </MudListItem> |
82 |
| - } |
83 |
| - |
84 |
| - </Virtualize> |
| 27 | + |
| 28 | + <ChatMessageList CurrentUser="_currentUser" ActiveChat="_activeChat" /> |
| 29 | + |
85 | 30 |
|
86 | 31 | <MudAnimate @ref="_messageSuccessfullySentAnimation"
|
87 | 32 | AnimationType="AnimationType.Fade"
|
88 | 33 | AnimationTiming="AnimationTiming.EaseIn"
|
89 | 34 | Delay="500"
|
90 |
| - Selector=".message-sent-successfully-container" /> |
| 35 | + Selector=".message-sent-successfully-container"/> |
| 36 | + |
| 37 | + @if (LastMessageWasSentSuccessfullyByCurrentUser) |
| 38 | + { |
| 39 | + <div title="Din besked er blevet sendt" class="message-sent-successfully-container"> |
| 40 | + <MudIcon Icon="@Icons.Material.Outlined.CheckCircleOutline" |
| 41 | + Class="message-sent-successfully"/> |
| 42 | + </div> |
| 43 | + } |
91 | 44 |
|
92 |
| - @if (LastMessageWasSentSuccessfullyByCurrentUser) |
93 |
| - { |
94 |
| - <div title="Din besked er blevet sendt" class="message-sent-successfully-container"> |
95 |
| - <MudIcon Icon="@Icons.Material.Outlined.CheckCircleOutline" |
96 |
| - Class="message-sent-successfully" /> |
97 |
| - </div> |
98 |
| - } |
99 |
| - <div class="flex-spacer"></div> |
| 45 | + <div class="flex-spacer"></div> |
100 | 46 |
|
101 | 47 | <MudTextField @bind-Value="_userText"
|
102 |
| - FullWidth |
103 |
| - Immediate |
104 |
| - AutoFocus |
| 48 | + id="chat-message-input" |
| 49 | + FullWidth |
| 50 | + Immediate |
| 51 | + AutoFocus |
105 | 52 | Adornment="Adornment.End"
|
106 | 53 | TextUpdateSuppression="false"
|
107 | 54 | OnKeyDown="SendMessageOnEnter"
|
108 | 55 | AdornmentIcon="@Icons.Material.Filled.Send"
|
109 | 56 | AdornmentColor="@(string.IsNullOrEmpty(_userText) ? Color.Default : Color.Primary)"
|
110 |
| - OnAdornmentClick="SendMessage" /> |
| 57 | + OnAdornmentClick="SendMessage"/> |
111 | 58 | </MudList>
|
112 | 59 | }
|
113 |
| - |
114 | 60 | </MudItem>
|
115 | 61 | </MudGrid>
|
116 |
| - |
117 | 62 | </MudLoading>
|
| 63 | + |
118 | 64 | @code {
|
119 |
| - // TODO: Select currently displayed chat using this, when we update to dotnet 8 |
120 |
| - [SupplyParameterFromQuery] |
| 65 | + [Parameter] |
121 | 66 | public Guid? ChatId { get; set; }
|
122 | 67 |
|
123 | 68 | private UserProfile? _currentUser;
|
124 |
| - private UserSlim _currentUserSlim = null!; |
125 | 69 | private List<ChatDto> _chats = new();
|
126 | 70 | private ChatDto? _activeChat;
|
127 | 71 |
|
|
163 | 107 | return;
|
164 | 108 | }
|
165 | 109 |
|
166 |
| - _currentUserSlim = _currentUser.ToUserSlim(); |
167 |
| - |
168 | 110 | _chats = await ChatService.GetChats(_currentUser.Id);
|
| 111 | + if (ChatId is not null) |
| 112 | + { |
| 113 | + _activeChat = _chats.FirstOrDefault(chat => chat.Id == ChatId); |
| 114 | + } |
169 | 115 |
|
170 | 116 | ChatSignalRClient.OnChatStarted(chat =>
|
171 | 117 | {
|
|
227 | 173 | _activeChat.Messages = await ChatService.GetChatMessages(_activeChat.Id);
|
228 | 174 |
|
229 | 175 | StateHasChanged();
|
230 |
| - |
231 |
| - await ScrollToBottom(); |
232 | 176 | }
|
233 | 177 |
|
234 | 178 | private async Task SelectChat(ChatDto chat)
|
|
237 | 181 | if (_isActiveChatPublished)
|
238 | 182 | {
|
239 | 183 | await LoadMessages();
|
240 |
| - // We call this twice to ensure we're at the very bottom. Silly but easy |
| 184 | + |
241 | 185 | await ScrollToBottom();
|
242 | 186 |
|
| 187 | + await FocusMessageInput(); |
| 188 | + |
243 | 189 | if (chat.HasUnreadMessages)
|
244 | 190 | {
|
245 | 191 | await ChatService.MarkMessagesAsRead(_activeChat.Id);
|
|
248 | 194 | }
|
249 | 195 | }
|
250 | 196 |
|
| 197 | + private async Task FocusMessageInput() => await JsRuntime.InvokeVoidAsync("scrollFunctions.focusMessageInput"); |
| 198 | + |
251 | 199 | private async Task ScrollToBottom() => await JsRuntime.InvokeVoidAsync("scrollFunctions.scrollToTheBottomOfChat");
|
252 | 200 |
|
253 | 201 | private void BackToList() => _activeChat = null;
|
|
264 | 212 | ChatId = _activeChat.Id,
|
265 | 213 | Id = NewId.NextGuid(),
|
266 | 214 | SentUtc = DateTime.UtcNow,
|
267 |
| - SenderId = _currentUserSlim.Id, |
| 215 | + SenderId = _currentUser!.Id, |
268 | 216 | Text = _userText
|
269 | 217 | };
|
270 | 218 |
|
|
292 | 240 | }
|
293 | 241 | }
|
294 | 242 |
|
295 |
| - private bool IsMessageFromSelf(ChatMessageDto message) => message.SenderId == _currentUser!.Id; |
296 |
| - |
297 | 243 | private async Task StartNewChat(IEnumerable<UserSlim> users)
|
298 | 244 | {
|
299 | 245 | var userList = users.ToList();
|
300 |
| - if (userList.Count() == 1) |
| 246 | + if (userList.Count == 1) |
301 | 247 | {
|
302 | 248 | var userIdsToFind = new[] { userList.First().Id, _currentUser!.Id };
|
303 | 249 | var existingChat = _chats.FirstOrDefault(chat => chat.Recipients.Count == 2 &&
|
|
311 | 257 | }
|
312 | 258 |
|
313 | 259 | var newChat = new ChatDto
|
314 |
| - { |
315 |
| - Id = NewId.NextGuid(), |
316 |
| - Recipients = new List<UserSlim> { _currentUserSlim }, |
317 |
| - LastMessageSentUtc = DateTime.UtcNow, |
318 |
| - StartedUtc = DateTime.UtcNow |
319 |
| - }; |
| 260 | + { |
| 261 | + Id = NewId.NextGuid(), |
| 262 | + Recipients = new List<UserSlim> { _currentUser!.ToUserSlim() }, |
| 263 | + LastMessageSentUtc = DateTime.UtcNow, |
| 264 | + StartedUtc = DateTime.UtcNow |
| 265 | + }; |
320 | 266 |
|
321 | 267 | foreach (var user in userList.Where(u => u.Id != _currentUser!.Id))
|
322 | 268 | {
|
|
331 | 277 | _chats.Insert(0, newChat);
|
332 | 278 |
|
333 | 279 | _isActiveChatPublished = false;
|
| 280 | + |
334 | 281 | await SelectChat(newChat);
|
335 | 282 | }
|
336 |
| - |
337 |
| - private string GetRecipientsProfilePictureUrl(ChatMessageDto message) |
338 |
| - => _activeChat? |
339 |
| - .Recipients |
340 |
| - .FirstOrDefault(recipient => recipient.Id == message.SenderId)?.ProfilePictureUrl |
341 |
| - ?? ProfileConstants.Default_Profile_Picture; |
342 | 283 | }
|
0 commit comments