|
22 | 22 | </md-icon-button> |
23 | 23 |
|
24 | 24 | <h2> |
25 | | - @EditContext.EventContext.OriginalEvent.Title |
| 25 | + @RenderStringDiff(originalEvent.Title, modifiedEvent.Title) |
26 | 26 | </h2> |
27 | 27 | <ul class="property-list"> |
28 | 28 | @if (modifiedEvent is { SourceCalendar: PersonalMoodleCalendarLive, Subject: { } subject }) |
|
34 | 34 | } |
35 | 35 | <li> |
36 | 36 | <md-icon>event</md-icon> |
37 | | - @RenderDateDiff(originalEvent.Start, modifiedEvent.Start) |
| 37 | + @RenderDateDiff(EditContext.EventContext) |
38 | 38 | </li> |
39 | 39 | @if (!string.IsNullOrWhiteSpace(originalEvent.Location) || !string.IsNullOrWhiteSpace(modifiedEvent.Location)) |
40 | 40 | { |
41 | 41 | <li> |
42 | 42 | <md-icon>location_on</md-icon> |
43 | | - @modifiedEvent.Location |
| 43 | + @RenderStringDiff(originalEvent.Location, modifiedEvent.Location) |
44 | 44 | </li> |
45 | 45 | } |
46 | 46 | @if (modifiedEvent.Teachers is [_, ..]) |
|
156 | 156 | : null; |
157 | 157 | } |
158 | 158 | <connected-button-select |
159 | | - value="@selectedCategoryId" |
| 159 | + value="@(selectedCategoryId ?? -1)" |
160 | 160 | @onchange="@(async ev => |
161 | 161 | { |
162 | 162 | int categoryId = int.Parse((string)ev.Value!); |
|
175 | 175 | ResetCallback="@(() => ResetModifications(typeof(CategoryModification)))"/> |
176 | 176 | </div> |
177 | 177 |
|
| 178 | + @{ |
| 179 | + Duration? commonOriginalLength = selectedEvents |
| 180 | + .Select(e => e.OriginalEvent.End - e.OriginalEvent.Start) |
| 181 | + .Distinct() |
| 182 | + .SingleOtherwiseNull(); |
| 183 | + Duration? commonModifiedLength = selectedEvents |
| 184 | + .Select(e => e.ModifiedEvent.End - e.ModifiedEvent.Start) |
| 185 | + .Distinct() |
| 186 | + .SingleOtherwiseNull(); |
| 187 | + bool anyLengthModifications = selectedEvents.Any(e => e.Modifications.Any(m => m.Action is LengthModification)); |
| 188 | + } |
| 189 | + @if (commonOriginalLength is { TotalMinutes: 60 + 45 or 120 + 45 } || anyLengthModifications) |
| 190 | + { |
| 191 | + <div style="margin-top: 16px"> |
| 192 | + Hossz |
| 193 | + </div> |
| 194 | + <div class="option-with-reset-button"> |
| 195 | + @{ |
| 196 | + Duration? commonLengthModification = |
| 197 | + commonOriginalLength is { } original && commonModifiedLength is { } modified |
| 198 | + ? modified - original |
| 199 | + : null; |
| 200 | + } |
| 201 | + <div> |
| 202 | + @if (commonOriginalLength is { TotalMinutes: 60 + 45 or 120 + 45 }) |
| 203 | + { |
| 204 | + <connected-button-select> |
| 205 | + <connected-button-select-option |
| 206 | + selected="@(commonLengthModification is { TotalTicks: 0 })" |
| 207 | + @onclick="@(() => ResetModifications(typeof(LengthModification)))"> |
| 208 | + Eredeti (15 p szünet) |
| 209 | + </connected-button-select-option> |
| 210 | + <connected-button-select-option |
| 211 | + selected="@(commonLengthModification is { TotalMinutes: -15 })" |
| 212 | + @onclick="@(() => AddModification(new LengthModification { Length = commonOriginalLength.Value - Duration.FromMinutes(15) }))"> |
| 213 | + Szünet nélkül (-15 p) |
| 214 | + </connected-button-select-option> |
| 215 | + </connected-button-select> |
| 216 | + } |
| 217 | + </div> |
| 218 | + <ResetButton |
| 219 | + IsVisible="@(anyLengthModifications)" |
| 220 | + ResetCallback="@(() => ResetModifications(typeof(LengthModification)))"/> |
| 221 | + </div> |
| 222 | + } |
| 223 | + |
| 224 | + <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)); margin-top: 16px; gap: 8px"> |
| 225 | + @{ |
| 226 | + string? commonTitle = selectedEvents |
| 227 | + .Select(e => e.ModifiedEvent.Title) |
| 228 | + .Distinct() |
| 229 | + .SingleOtherwiseNullClass(); |
| 230 | + bool anyTitleModifications = selectedEvents.Any(e => e.Modifications.Any(m => m.Action is TitleModification)); |
| 231 | + } |
| 232 | + @if (commonTitle is { } || anyTitleModifications) |
| 233 | + { |
| 234 | + <MdOutlinedTextField label="Cím" |
| 235 | + Value="@commonTitle" |
| 236 | + ValueChanged="@((string? newTitle) => |
| 237 | + { |
| 238 | + if (newTitle == null) |
| 239 | + return Task.CompletedTask; |
| 240 | + return AddModification(new TitleModification { NewTitle = newTitle }); |
| 241 | + })"> |
| 242 | + <ResetButton slot="trailing-icon" |
| 243 | + IsVisible="@(anyTitleModifications)" |
| 244 | + ResetCallback="@(() => ResetModifications(typeof(TitleModification)))"/> |
| 245 | + </MdOutlinedTextField> |
| 246 | + } |
| 247 | + |
| 248 | + @{ |
| 249 | + string? commonLocation = selectedEvents |
| 250 | + .Select(e => e.ModifiedEvent.Location) |
| 251 | + .Distinct() |
| 252 | + .SingleOtherwiseNullClass(); |
| 253 | + bool anyLocationModifications = selectedEvents.Any(e => e.Modifications.Any(m => m.Action is LocationModification)); |
| 254 | + } |
| 255 | + @if (commonLocation is { } || anyLocationModifications) |
| 256 | + { |
| 257 | + <MdOutlinedTextField |
| 258 | + label="Hely" |
| 259 | + Value="@commonLocation" |
| 260 | + ValueChanged="@((string? newLocation) => |
| 261 | + { |
| 262 | + if (newLocation == null) |
| 263 | + return Task.CompletedTask; |
| 264 | + return AddModification(new LocationModification { NewLocation = newLocation }); |
| 265 | + })"> |
| 266 | + <ResetButton slot="trailing-icon" |
| 267 | + IsVisible="@(anyLocationModifications)" |
| 268 | + ResetCallback="@(() => ResetModifications(typeof(LocationModification)))"/> |
| 269 | + </MdOutlinedTextField> |
| 270 | + } |
| 271 | + </div> |
178 | 272 | </div> |
179 | 273 | </div> |
180 | 274 |
|
|
244 | 338 | await CalendarUpdatedCallback.InvokeAsync(); |
245 | 339 | } |
246 | 340 |
|
247 | | - private static RenderFragment RenderDateDiff(Instant original, Instant modified) |
| 341 | + private static RenderFragment RenderStringDiff(string original, string modified) |
| 342 | + { |
| 343 | + if (original == modified || string.IsNullOrWhiteSpace(original)) |
| 344 | + return @<text>@modified</text>; |
| 345 | + return @<text><del>@original</del> @modified</text>; |
| 346 | + } |
| 347 | + |
| 348 | + private static RenderFragment RenderDateDiff(EventContext eventContext) |
248 | 349 | { |
249 | | - var ogZonedDateTime = original.InZone(SharedUtils.HungarianTimeZone); |
250 | | - var modZonedDateTime = modified.InZone(SharedUtils.HungarianTimeZone); |
251 | | - var ogDate = ogZonedDateTime.Date; |
252 | | - var ogTime = ogZonedDateTime.TimeOfDay; |
253 | | - var modDate = modZonedDateTime.Date; |
254 | | - var modTime = modZonedDateTime.TimeOfDay; |
255 | | - bool datesEqual = ogDate == modDate; |
256 | | - bool timesEqual = ogTime == modTime; |
257 | | - if (datesEqual && timesEqual) |
258 | | - return @<text>@Format(modDate), @Format(modTime)</text>; |
259 | | - if (!datesEqual && !timesEqual) |
260 | | - return @<text><sub>@Format(ogDate), @Format(ogTime)</sub> @Format(modDate), @Format(modTime)</text>; |
261 | | - if (!datesEqual) |
262 | | - return @<text><sub>@Format(ogDate)</sub> @Format(modDate), @Format(modTime)</text>; |
263 | | - return @<text>@Format(ogDate), <sub>@Format(ogTime)</sub> @Format(modTime)</text>; |
| 350 | + Instant currentInstant = SystemClock.Instance.GetCurrentInstant(); |
| 351 | + string original = DateFormatter.Format(eventContext.OriginalEvent.Start, eventContext.OriginalEvent.End, currentInstant); |
| 352 | + string modified = DateFormatter.Format(eventContext.ModifiedEvent.Start, eventContext.ModifiedEvent.End, currentInstant); |
| 353 | + return RenderStringDiff(original, modified); |
264 | 354 | } |
265 | 355 |
|
266 | 356 | private static string Format(LocalDate localDate) |
|
0 commit comments