Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,29 @@
@inject IDispatcher Dispatcher
@inject IState<HeaderBarState> State

<MudAppBar Dense="true" DisableGutters="true" Class="pl-1">
<MudAppBar Color="Color.Primary">
@if (State.Value.ShowBackButton)
{
<MudIconButton
Icon="@Icons.Material.Filled.ArrowBack"
OnClick="HandleNavigateBack"
Class="pl-0"/>
Edge="Edge.Start"
Color="Color.Inherit"
OnClick="HandleNavigateBack"/>
}

<MudText Typo="Typo.h6" Class="pl-0">@State.Value.Title</MudText>
<MudText Typo="Typo.h5">@State.Value.Title</MudText>
<MudSpacer />

@if (State.Value.ShowFeedbackButton)
{
<MudIconButton
Icon="@Icons.Material.Filled.TagFaces"
OnClick="HandleShowEventFeedback" />
<MudButton
EndIcon="@Icons.Material.Filled.TagFaces"
Size="Size.Small"
OnClick="HandleShowEventFeedback"
Color="Color.Inherit"
Variant="Variant.Outlined">
Feedback
</MudButton>
}

</MudAppBar>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,56 +1,144 @@
@using PocketDDD.BlazorClient.Features.Home.Store;
@using System.Text.Json;
@using PocketDDD.BlazorClient.Features.Session.Store;
@using PocketDDD.BlazorClient.Features.Home.Store
@inherits FluxorComponent

@inject NavigationManager NavigationManager
@inject IState<HomeState> State
@inject IDispatcher Dispatcher

<MudList Clickable="true">
@foreach(var timeSlot in State.Value.EventMetaData)
<MudList Class="pt-0 mud-background-gray" Dense="true">
@foreach (var timeSlot in State.Value.Timeslots)
{
<MudListSubheader Class="pb-0 pl-1 border-b border-solid mud-border-primary">
<MudText Typo="Typo.h6">
@timeSlot.From.ToString("h:mm")
@timeSlot.From.ToString("tt").ToLowerInvariant()
</MudText>
<MudListSubheader Class="pt-2 pb-1">
<MudPaper Width="fit-content" Class="mud-theme-primary border-solid py-2 px-6 my-0">
<MudText Typo="Typo.h6" Align="Align.Center">
@timeSlot.From.LocalDateTime.ToString("h:mm")
@timeSlot.From.LocalDateTime.ToString("tt").ToLowerInvariant()
</MudText>
</MudPaper>
</MudListSubheader>
@if(timeSlot.Info is not null)

if (timeSlot.Info is not null)
{
<MudListItem Class="ml-6">
<MudText Typo="Typo.h5">@timeSlot.Info</MudText>
<MudListItem>
<MudPaper Outlined="true" Class="px-4 py-2">
<MudText Typo="Typo.h6">@timeSlot.Info</MudText>
</MudPaper>
</MudListItem>
}
@foreach(var sessionItem in timeSlot.Sessions.Select((session, index) => (session, index)))

foreach (var room in timeSlot.Rooms)
{
<MudListItem OnClick="() => HandleViewSession(sessionItem.session.Id)">
<MudPaper Class="pa-4">
<MudText Typo="Typo.subtitle1">
@WhenBookmarkedShowIcon(sessionItem.session)
@sessionItem.session.Title
</MudText>
<MudText Typo="Typo.subtitle2">@sessionItem.session.SpeakerName</MudText>
<MudText Typo="Typo.subtitle2">@sessionItem.session.RoomName</MudText>
</MudPaper>
<MudListItem>
<MudCard Outlined="true">
<MudCardHeader Class="pb-0">
<CardHeaderContent>
<MudText Typo="Typo.body1">
@room.RoomName
</MudText>
<MudDivider Class="@GetTrackDividerStylesForRoom(room)"
DividerType="DividerType.FullWidth"/>
</CardHeaderContent>
</MudCardHeader>
<MudCardContent Class="py-2">
@for (var i = 0; i < room.Sessions.Count; i++)
{
var session = room.Sessions[i];
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Stretch">
<MudStack>
<MudText Typo="Typo.h6">@session.Title</MudText>
<MudText Typo="Typo.subtitle1">@session.SpeakerName</MudText>
</MudStack>
<MudStack Justify="Justify.SpaceBetween" AlignItems="AlignItems.End" Spacing="0">
<MudToggleIconButton
ToggledChanged="@(_ => HandleToggleSessionBookmarked(session))"
Toggled="@session.IsBookmarked"
Color="@Color.Default"
Icon="@Icons.Material.Filled.BookmarkBorder"
ToggledIcon="@Icons.Material.Filled.Bookmark"
ToggledColor="@Color.Primary"
title="@(session.IsBookmarked ? "Unbookmark session" : "Bookmark session")"/>
@ShowSessionLength(session)
</MudStack>
</MudStack>
<MudButton OnClick="() => HandleViewSession(session.Id)" FullWidth="true"
Variant="Variant.Outlined" Class="my-2">
More details
</MudButton>
@if (i < room.Sessions.Count - 1)
{
<MudDivider Class="@GetMultiTalkDividerStylesForRoom(room)"
DividerType="DividerType.Middle"/>
}
}
</MudCardContent>
</MudCard>
</MudListItem>

@if (sessionItem.index != timeSlot.Sessions.Count -1)
{
<MudDivider />
}
}
}

</MudList>

@code{
RenderFragment? WhenBookmarkedShowIcon(Features.Home.Store.Session session) =>
session.IsBookmarked
? @<MudIcon Icon="@Icons.Material.Filled.Bookmark" Title="Bookmarked" />
: null;

RenderFragment ShowSessionLength(Session session)
{
var colour = Color.Info;

if (session.Length == TimeSpan.FromMinutes(30))
colour = Color.Secondary;
else if (session.Length == TimeSpan.FromMinutes(15))
colour = Color.Tertiary;

return @<MudChip Color="@colour" Variant="Variant.Outlined">@GetTimeSpanDisplayText(session.Length)</MudChip>;
}

private string GetBorderColourForRoom(Room room)
{
string colour;

if (room.RoomName.Contains('1'))
colour = "mud-border-tertiary";
else if (room.RoomName.Contains('2'))
colour = "mud-border-primary";
else if (room.RoomName.Contains('3'))
colour = "mud-border-secondary";
else
colour = "mud-border-info";

return colour;
}

private string GetTrackDividerStylesForRoom(Room room)
{
return $"{GetBorderColourForRoom(room)}";
}

private string GetMultiTalkDividerStylesForRoom(Room room)
{
return $"{GetBorderColourForRoom(room)} ma-4";
}

private static string GetTimeSpanDisplayText(TimeSpan timeSpan)
{
if (timeSpan < TimeSpan.FromHours(1))
{
return $"{timeSpan.Minutes} minutes";
}

return timeSpan == TimeSpan.FromHours(1) ? "1 hour" : $"{timeSpan.TotalHours:F1} hours";
}

}

@code {
void HandleViewSession(int sessionId) => NavigationManager.NavigateTo($"session/{sessionId}");

void HandleViewSession(int sessionId)
{
NavigationManager.NavigateTo($"session/{sessionId}");
}

void HandleToggleSessionBookmarked(Session session)
{
Dispatcher.Dispatch(new ToggleBookmarkedAction(session.Id, !session.IsBookmarked));
}

}
Original file line number Diff line number Diff line change
@@ -1,31 +1,66 @@
using PocketDDD.Shared.API.ResponseDTOs;
using System.Collections.Immutable;
using System.Collections.Immutable;
using PocketDDD.Shared.API.ResponseDTOs;

namespace PocketDDD.BlazorClient.Features.Home.Store;

public static class EventDataMapper
{
public static IImmutableList<TimeSlot> ToHomeStateModel(this EventDataResponseDTO eventData, ICollection<int> sessionBookmarks) =>
eventData.TimeSlots.Select(ts => new TimeSlot
public static IImmutableList<TimeSlot> ToHomeStateModel(this EventDataResponseDTO eventData,
ICollection<int> sessionBookmarks)
{
// The break timeslots don't have any sessions but still need to be included so starting from eventData.TimeSlots
var allTimeSlotDtosSortedByTimeAndLength = eventData.TimeSlots.OrderBy(t => t.From).ThenByDescending(t => t.To);

// Group together the timeslots, rooms and sessions
Dictionary<TimeSlot, List<(Room room, Session session)>> timeslotRoomSessions =
allTimeSlotDtosSortedByTimeAndLength.ToDictionary(
timeSlotDto => new TimeSlot { From = timeSlotDto.From, To = timeSlotDto.To, Info = timeSlotDto.Info },
timeSlotDto => eventData.Sessions.Where(s => s.TimeSlotId == timeSlotDto.Id)
.Select(s =>
(
new Room
{
RoomName = eventData.Tracks.Single(track => track.Id == s.TrackId).RoomName
},
new Session
{
Id = s.Id,
From = timeSlotDto.From,
To = timeSlotDto.To,
Title = s.Title,
SpeakerName = s.Speaker,
IsBookmarked = sessionBookmarks.Contains(s.Id)
})
).ToList()
);

//Deduplicate time slots
// Sometimes one timeslot may overlap another e.g. 2 x 15 min sessions in one room and 1 x 30 min session in another at the same time
// We want to take the longer timeslot
var deduplicatedTimeSlotRoomSessions = new Dictionary<TimeSlot, List<(Room room, Session session)>>();
foreach (var (timeSlot, roomsAndSessionsInTimeslot) in timeslotRoomSessions)
{
Id = ts.Id,
From = ts.From.LocalDateTime,
To = ts.To.LocalDateTime,
Info = ts.Info,
Sessions = eventData.Sessions
.Where(s => s.TimeSlotId == ts.Id)
.Select(s => new Session
{
Id = s.Id,
SpeakerName = s.Speaker,
Title = s.Title,
TrackName = eventData.Tracks.Single(tr => tr.Id == s.TrackId).Name,
RoomName = eventData.Tracks.Single(tr => tr.Id == s.TrackId).RoomName,
IsBookmarked = sessionBookmarks.Contains(s.Id)
})
.OrderBy(s => s.TrackName)
.ToImmutableList()
})
.OrderBy(ts => ts.From)
.ToImmutableList();
var encompassingTimeslot =
deduplicatedTimeSlotRoomSessions.Keys.SingleOrDefault(k =>
k.From <= timeSlot.From && k.To >= timeSlot.To);
if (encompassingTimeslot is not null)
deduplicatedTimeSlotRoomSessions[encompassingTimeslot].AddRange(roomsAndSessionsInTimeslot);
else
deduplicatedTimeSlotRoomSessions.Add(timeSlot, roomsAndSessionsInTimeslot);
}

//And now group by room and fit them into the actual types we want to use
var homeStateModel = deduplicatedTimeSlotRoomSessions.Select(timeslotRoomSession => timeslotRoomSession.Key with
{
Rooms = timeslotRoomSession.Value.GroupBy(tuple => tuple.room, tuple => tuple.session)
.Select(g => g.Key with
{
Sessions = g.OrderBy(s => s.From).ToImmutableList()
})
.OrderBy(r => r.RoomName)
.ToImmutableList()
}).ToImmutableList();

return homeStateModel;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ public record SetCurrentUser(LoginResultDTO Result);
public record LoadDataAction();
public record SetUserLoggedInAction();
public record SetEventMetaDataAction(EventDataResponseDTO EventData, ICollection<int> SessionBookmarks);
public record ToggleBookmarkedAction(int SessionId, bool Bookmarked);
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
using Fluxor;
using MudBlazor;
using PocketDDD.BlazorClient.Features.Session.Store;
using PocketDDD.BlazorClient.Features.Sync.Store;
using PocketDDD.BlazorClient.Services;
using PocketDDD.Shared.API.RequestDTOs;
using System.Collections.ObjectModel;

namespace PocketDDD.BlazorClient.Features.Home.Store;

public class HomeEffects
{
private readonly IState<HomeState> _state;
private readonly IDialogService _dialog;
private readonly LocalStorageContext _localStorage;
private readonly IPocketDDDApiService _pocketDDDAPI;
private readonly IDialogService _dialog;
private readonly IState<HomeState> _state;

public HomeEffects(IState<HomeState> state, IDispatcher dispatcher, LocalStorageContext localStorage,
IPocketDDDApiService pocketDDDAPI, IDialogService dialog)
public HomeEffects(IState<HomeState> state, IDispatcher dispatcher, LocalStorageContext localStorage,
IPocketDDDApiService pocketDDDAPI, IDialogService dialog)
{
_state = state;
_localStorage = localStorage;
Expand All @@ -38,4 +34,17 @@ public async Task OnLoadData(LoadDataAction action, IDispatcher dispatcher)
if (eventData is not null)
dispatcher.Dispatch(new SetEventMetaDataAction(eventData, sessionBookmarks));
}

[EffectMethod]
public async Task OnToggleSessionBookmarked(ToggleBookmarkedAction action, IDispatcher dispatcher)
{
var bookmarks = await _localStorage.SessionBookmarks.GetOrDefaultAsync();

if (action.Bookmarked && !bookmarks.Contains(action.SessionId))
bookmarks.Add(action.SessionId);
else if (!action.Bookmarked && bookmarks.Contains(action.SessionId))
bookmarks.Remove(action.SessionId);

await _localStorage.SessionBookmarks.SetAsync(bookmarks);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ state with
{
Loading = false,
FailedToLoad = false,
EventMetaData = action.EventData.ToHomeStateModel(action.SessionBookmarks)
Timeslots = action.EventData.ToHomeStateModel(action.SessionBookmarks)
};

//[ReducerMethod]
Expand Down
Loading
Loading