@page "/dashboard/employee" @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization @rendermode @(new InteractiveServerRenderMode(prerender: false)) @attribute [Authorize] @inject ApiClientService ApiClient @inject NavigationManager Navigation @inject IJSRuntime JS @inject AuthenticationStateProvider AuthStateProvider Employee Dashboard

Team Member

My Work

Tasks, deadlines, and your progress in one place.

@if (isLoading) {
Loading dashboard...
} else if (!string.IsNullOrWhiteSpace(errorMessage)) {
@errorMessage
} else {

In Progress

Tasks currently being worked on

@InProgressTasks.Count
@if (InProgressTasks.Any()) { @foreach (var task in InProgressTasks) {
@task.Title
@GetProjectName(task.ProjectId)
@task.DueDate.ToString("yyyy-MM-dd")
@GetDueLabel(task)
} } else {
No tasks in progress right now.
}

To Do & Upcoming

Tasks waiting for action or coming up soon

@TodoUpcomingTasks.Count
@if (TodoUpcomingTasks.Any()) { @foreach (var task in TodoUpcomingTasks) {
@task.Title
@GetProjectName(task.ProjectId)
@task.DueDate.ToString("yyyy-MM-dd")
@GetDueLabel(task)
} } else {
No upcoming tasks found.
}

Overdue

Tasks past their due date

@OverdueTasks.Count
@if (OverdueTasks.Any()) { @foreach (var task in OverdueTasks) {
@task.Title
@GetProjectName(task.ProjectId)
@task.DueDate.ToString("yyyy-MM-dd")
@DaysOverdue(task)
} } else {
No overdue tasks. Nice work.
}

@CalendarMonthLabel

@CalendarTodayLabel

@foreach (var day in WeekdayLabels) { @day }
@foreach (var cell in CalendarCells) { }

Related Tasks

Tasks marked on @SelectedDateLabel

@if (SelectedDateTasks.Any()) { @foreach (var task in SelectedDateTasks) {
@task.Title
@GetProjectName(task.ProjectId)
@task.DueDate.ToString("yyyy-MM-dd")
@GetDueLabel(task)
} } else {
No tasks are scheduled for this day.
}
}
@code { private bool isLoading = true; private string? errorMessage; private long currentUserId; private List tasks = new(); private List projects = new(); private DateTime selectedDate = DateTime.Today; private readonly string[] WeekdayLabels = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; private List CalendarCells => BuildCalendarCells(); private List SelectedDateTasks => tasks .Where(task => task.DueDate.Date == selectedDate.Date) .OrderBy(task => task.StatusId) .ThenBy(task => task.DueDate) .ToList(); private string SelectedDateLabel => selectedDate.ToString("dddd, MMM d"); private string CalendarMonthLabel => selectedDate.ToString("MMMM yyyy"); private string CalendarTodayLabel => DateTime.Today.ToString("dddd, d"); private string CurrentTimeLabel => DateTime.Now.ToString("h:mm tt"); private string TimeZoneLabel { get { var offset = TimeZoneInfo.Local.GetUtcOffset(DateTime.Now); var sign = offset >= TimeSpan.Zero ? "+" : "-"; var hours = Math.Abs(offset.Hours); var minutes = Math.Abs(offset.Minutes); return minutes == 0 ? $"GMT{sign}{hours}" : $"GMT{sign}{hours}:{minutes:00}"; } } private List InProgressTasks => tasks .Where(task => task.StatusId == AppTaskStatus.InProgress) .OrderBy(task => task.DueDate) .ToList(); private List TodoUpcomingTasks => tasks .Where(task => task.StatusId == AppTaskStatus.Todo || (task.StatusId != AppTaskStatus.Done && task.DueDate.Date >= DateTime.Today)) .OrderBy(task => task.DueDate) .ToList(); private List OverdueTasks => tasks .Where(task => task.DueDate.Date < DateTime.Today && task.StatusId != AppTaskStatus.Done) .OrderBy(task => task.DueDate) .ToList(); private List SummaryMetrics => BuildSummaryMetrics(); protected override async Task OnInitializedAsync() { await LoadDashboardData(); } protected override async Task OnAfterRenderAsync(bool firstRender) { await JS.InvokeVoidAsync("initIcons"); } private async Task LoadDashboardData() { isLoading = true; errorMessage = null; try { var authState = await AuthStateProvider.GetAuthenticationStateAsync(); var user = authState.User; var idStr = user.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value; if (idStr != null) { long.TryParse(idStr, out currentUserId); } var client = ApiClient.CreateClient(); var tasksResult = await client.GetFromJsonAsync>>($"User/{currentUserId}/tasks", Serialization.CaseInsensitive); var projectsResult = await client.GetFromJsonAsync>("Project", Serialization.CaseInsensitive); if (tasksResult?.IsSuccess == true && tasksResult.Value != null) { tasks = tasksResult.Value.ToList(); } else { tasks = new List(); } selectedDate = DateTime.Today; projects = projectsResult ?? new List(); } catch (Exception ex) { errorMessage = $"Failed to load dashboard data: {ex.Message}"; } finally { isLoading = false; } } private void SelectDate(DateTime date) { selectedDate = date.Date; } private void PrevMonth() { selectedDate = selectedDate.AddMonths(-1); } private void NextMonth() { selectedDate = selectedDate.AddMonths(1); } private List BuildSummaryMetrics() { var inProgress = tasks.Count(task => task.StatusId == AppTaskStatus.InProgress); var todo = tasks.Count(task => task.StatusId == AppTaskStatus.Todo); var dueSoon = tasks.Count(task => task.StatusId != AppTaskStatus.Done && task.DueDate.Date >= DateTime.Today && task.DueDate.Date <= DateTime.Today.AddDays(3)); var completed = tasks.Count(task => task.StatusId == AppTaskStatus.Done); var overdue = tasks.Count(task => task.DueDate.Date < DateTime.Today && task.StatusId != AppTaskStatus.Done); return new List { new("timer-reset", "active", inProgress.ToString(), "In Progress", "rounded-2xl bg-violet-700 p-3 text-white", "text-sm font-semibold text-violet-700"), new("list-checks", "queued", todo.ToString(), "To Do", "rounded-2xl bg-cyan-600 p-3 text-white", "text-sm font-semibold text-cyan-600"), new("calendar-clock", "soon", dueSoon.ToString(), "Due Soon", "rounded-2xl bg-amber-500 p-3 text-white", "text-sm font-semibold text-amber-600"), new("circle-check-big", "done", completed.ToString(), "Completed", "rounded-2xl bg-emerald-600 p-3 text-white", "text-sm font-semibold text-emerald-600"), new("triangle-alert", "late", overdue.ToString(), "Overdue", "rounded-2xl bg-rose-600 p-3 text-white", "text-sm font-semibold text-rose-600") }; } private List BuildCalendarCells() { var firstOfMonth = new DateTime(selectedDate.Year, selectedDate.Month, 1); var start = firstOfMonth.AddDays(-(int)firstOfMonth.DayOfWeek); var end = start.AddDays(42); var dateMap = tasks .Where(task => task.DueDate.Date >= start.Date && task.DueDate.Date < end.Date) .GroupBy(task => task.DueDate.Date) .ToDictionary(group => group.Key, group => group.ToList()); var cells = new List(); for (var i = 0; i < 42; i++) { var date = start.AddDays(i); dateMap.TryGetValue(date.Date, out var dayTasks); dayTasks ??= new List(); cells.Add(new CalendarCellViewModel( date, date.Month == selectedDate.Month, date.Date == selectedDate.Date, dayTasks.Select(task => GetStatusColor(task.StatusId)).ToList(), dayTasks.Count)); } return cells; } private string GetProjectName(long projectId) { return projects.FirstOrDefault(project => project.Id == projectId)?.Name ?? $"Project #{projectId}"; } private string GetStatusColor(AppTaskStatus statusId) => statusId switch { AppTaskStatus.Todo => "#22d3ee", AppTaskStatus.InProgress => "#3b82f6", AppTaskStatus.Done => "#10b981", _ => "#94a3b8" }; private string GetCalendarCellClasses(CalendarCellViewModel cell) { var classes = new List { "min-h-[52px] rounded-2xl border p-2 text-left transition-colors" }; if (cell.IsSelected) { classes.Add("border-violet-500 bg-violet-600"); } else if (cell.IsCurrentMonth) { classes.Add("border-slate-200 bg-white hover:border-violet-200 hover:bg-slate-50"); } else { classes.Add("border-slate-100 bg-slate-50 text-slate-400"); } return string.Join(" ", classes); } private string GetDueLabel(TaskDto task) { var days = (task.DueDate.Date - DateTime.Today).Days; if (task.StatusId == AppTaskStatus.Done) { return "Done"; } if (days < 0) { return $"{Math.Abs(days)}d ago"; } if (days == 0) { return "Today"; } return $"{days}d left"; } private string GetDueTextClass(TaskDto task) { var days = (task.DueDate.Date - DateTime.Today).Days; if (task.StatusId == AppTaskStatus.Done) { return "text-emerald-600"; } if (days < 0) { return "text-rose-600"; } if (days <= 3) { return "text-amber-500"; } return "text-sky-600"; } private string DaysOverdue(TaskDto task) { var days = (DateTime.Today - task.DueDate.Date).Days; return days <= 0 ? "Due today" : $"{days}d ago"; } private sealed record CalendarCellViewModel( DateTime Date, bool IsCurrentMonth, bool IsSelected, List TaskDots, int TaskCount); }