C# Radzen Blazor Gantt Chart

I finally realized I need to use the backtick and not the front tick to insert code!
herebelow is the code for a GanttChart in c# in a simplistic way. the code needs cleaning up, but it is working.
should there be something missing, please advise.
NB: if you change this into a component please share the code.

@page "/gantt-chart"

@using System.Net.Http
@using System.Threading.Tasks
@using System.Text.Json
@inject HttpClient Http
@inject GanttChartService ganttChartService
@inject TooltipService tooltipService
@using System.Linq
@using static GanttChart

<style>
    body
    {
        font-family: Arial, sans-serif;
        margin: 0;
        padding: 0;
        width: 2000px;
    }

    .gantt-container
    {
        display: flex;
        width: 100%;
        height: 600px;
        font-size: 10px;
    }
    .gantt-tasks,
    .gantt-timeline
    {
        border: 1px solid #ccc;
        overflow: auto;
        position: relative;
    }

    .gantt-tasks
    {
        width: 35%;
    }

    .gantt-timeline
    {
        width: 65%;
    }

    table
    {
        border-collapse: collapse;
        width: 100%;
    }

    th,
    td
    {
        padding: 5px;
        border: 1px solid #ccc;
        white-space: nowrap;
        text-align: left;
        height: 30px;
        color: black;
    }

        th:nth-child(4),
        td:nth-child(4)
        {
            text-align: right;
            /* width: 10px; */
        }

        th:nth-child(7),
        td:nth-child(7)
        {
            text-align: right;
            /* width: 10px; */
        }

    th
    {
        background: #333;
        color: #fff;
        position: sticky;
        top: 0;
        z-index: 10;
    }

    thead
    {
        height: 50px;
        font-size: 14px;
    }

    tr
    {
        background-color: white;
    }

    .day-cell
    {
        text-align: center;
        background: #f0f0f0;
        font-size: 9px;
        color: black;
        writing-mode: vertical-rl;
    }
    .gantt-task
    {
        background-color: #3498db;
        color: #fff;
        text-align: center;
        border-radius: 10px;
        overflow: hidden;
        position: absolute;
        height: 25px;
        padding-top: 5px;
        top: 3px;
        z-index: 1;
    }

    .gantt-task-container
    {
        position: relative;
        height: 100%;
        width: 100%;
    }

    .gantt-task-background
    {
        background-color: #3498db;
        position: absolute;
        height: 25px;
        border-radius: 10px;
        z-index: 2;
    }

    .gantt-task-text
    {
        position: absolute;
        text-align: center;
        margin-top: 7px;
        margin-left: 10px;
        z-index: 5;
        opacity: 1 !important;
    }

    .gantt-task-progress
    {
        background-color: #2ecc71;
        height: 25px;
        border-radius: 10px 0 0 10px;
        position: absolute;
        z-index: 3;
    }

    .company-row
    {
        background: #f0f0f0;
        cursor: pointer;
    }

    .collapse-icon
    {
        margin-right: 5px;
        cursor: pointer;
    }

    .button-container
    {
        display: flex;
        justify-content: flex-start;
        margin-bottom: 10px;
    }

    .gantt-container
    {
        position: relative;
        padding-top: 10px;
       
    }
</style>
<PageTitle>GanttChart</PageTitle>

<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0.5rem" Class="rz-p-4 rz-mb-6 rz-border-radius-4" Style="border: var(--rz-grid-cell-border);width: 1440px">
    <input type="text" @bind="searchQuery" placeholder="Search..." class="search-input ms-5" @oninput="@(async (e) => await FilterTasks())" />
    <RadzenButton Click="ExpandAll" Text="Expand All" ButtonStyle="ButtonStyle.Primary" class="rz-border-radius-6" />
    <RadzenButton Click="CollapseAll" Text="Collapse All" ButtonStyle="ButtonStyle.Primary" class="rz-border-radius-6" />
</RadzenStack>
<RadzenCard Variant="Variant.Filled" Class="rz-border-radius-5 rz-background-color-base-700 gantt-container" Style="overflow: auto;">
    <RadzenStack Orientation="Orientation.Horizontal" JustifyContent="JustifyContent.Start" Gap="1rem" Style="width: 1500px">
        <table class="table table-bordered">
            <thead>
                <tr>
                    <th>Priority Area</th>
                    <th>Main Topic</th>
                    <th>Expert</th>
                    <th>Days Allocated</th>
                    <th>Start</th>
                    <th>Deadline</th>
                    <th>% Completed</th>
                    <th>Status</th>
                    @for (int i = 0; i <= totalDays; i++)
                    {
                        var date = startDate.AddDays(i);
                        <th class="day-cell">@FormatDate(date)</th>
                    }
                </tr>
            </thead>
            <tbody>
                @foreach (var companyGroup in filteredTasks.GroupBy(t => t.Company))
                {
                    <tr class="company-row" @onclick="() => ToggleCompany(companyGroup.Key)">
                        <td colspan="150"><span class="collapse-icon">@GetCollapseIcon(companyGroup.Key)</span>@companyGroup.Key</td>
                        @for (int i = 0; i <= totalDays; i++)
                        {
                            <td></td>
                        }
                    </tr>
                    @if (IsCompanyExpanded(companyGroup.Key))
                    {
                        @foreach (var task in companyGroup)
                        {
                            <tr>
                                <td>@task.PriorityArea</td>
                                <td>@task.MainTopic</td>
                                <td>@task.Expert</td>
                                <td>@task.Allocated</td>
                                <td>@task.Start.ToString("dd-MM-yy")</td>
                                <td>@task.Deadline.ToString("dd-MM-yy")</td>
                                <td>@task.PercentCompleted</td>
                                <td>@task.Status</td>
                                <td class="timeline-row" colspan="212" style="position: relative; height: 30px;">

                                    @{
                                        var date = startDate.AddDays(5);
                                        var numfromstart = minStartDate * 30;
                                        var tDuration = Math.Round(GetTaskDurationWidth(task) * 30);
                                        var pDuration = Math.Round((tDuration * task.PercentCompleted) / 100);
                                    }

                                    <div class="gantt-task-container" style="left:@(GetDaysFromMinStartDate(task) * 100.0 / totalDays)%;">
                                        <div class="gantt-task-background" Text="Left" style="width:@(tDuration)px;" >
                                           
                                        </div>
                                        <div class="gantt-task-progress" style="width:@(pDuration)px;"></div>
                                        <div class="gantt-task-text">@(task.PercentCompleted) %</div>

                                    </div>

                                </td>
                            </tr>
                        }
                    }
                }
            </tbody>
        </table>
    </RadzenStack>
</RadzenCard>

@code {
    private List<GTask> tasks = new();
    private List<GTask> filteredTasks = new();
    private DateTime startDate = new DateTime(2024, 1, 1);
    private DateTime endDate = new DateTime(2024, 7, 30);
    private int totalDays => (endDate - startDate).Days;
    private string searchQuery = "";
    private IEnumerable<GChart.Models.GanttChart.BUTest> bUTests;
    private HashSet<string> expandedCompanies = new HashSet<string>();
    private int minStartDate = 0;

    protected override async Task OnInitializedAsync()
    {
        try
        {
            bUTests = await ganttChartService.GetBUTests(new Query { Filter = $@"i => i.Company.Contains(@0) || i.PriorityArea.Contains(@0) || i.Expert.Contains(@0) || i.MainTopic.Contains(@0) || i.Status.Contains(@0)", FilterParameters = new object[] { searchQuery } });
            tasks = ConvertBUTestToGTask(bUTests);
            filteredTasks = new List<GTask>(tasks);

            CreateTimelineData();
        }
        catch (Exception e)
        {
            Console.WriteLine($"Failed to load data: {e.Message}");
        }
    }

    public List<GTask> ConvertBUTestToGTask(System.Collections.Generic.IEnumerable<GChart.Models.GanttChart.BUTest> bUTests)
    {
        return bUTests.Select(buTest => new GTask
            {
                Company = buTest.Company,
                PriorityArea = buTest.PriorityArea,
                MainTopic = buTest.MainTopic,
                Expert = buTest.Expert,
                Allocated = buTest.Allocated ?? 0,
                Start = buTest.Start ?? DateTime.MinValue,
                Deadline = buTest.Deadline ?? DateTime.MaxValue,
                PercentCompleted = Math.Round(buTest.PercentCompleted * 100 ?? 0),
                Status = buTest.Status,
                IsExpanded = buTest.IsExpanded ?? true,
                Timeline = new Dictionary<string, string>() // Initialize Timeline if needed
            }).ToList();
    }

    private string FormatDate(DateTime date)
    {
        return date.ToString("dd-MM-yy");
    }

    private async Task FilterTasks()
    {
        filteredTasks = tasks.Where(task =>
            task.GetType().GetProperties().Any(prop =>
                prop.GetValue(task)?.ToString().ToLower().Contains(searchQuery.ToLower()) == true
            )
        ).ToList();
        CreateTimelineData();
    }

    private void CreateTimelineData()
    {
        foreach (var task in filteredTasks)
        {
            task.Timeline = new Dictionary<string, string>();
            for (int i = 0; i <= totalDays; i++)
            {
                var date = startDate.AddDays(i);
                if (date >= task.Start && date <= task.Deadline)
                {
                    task.Timeline[date.ToString("dd-MM-yy")] = $"{task.PercentCompleted}%";
                }
                else
                {
                    task.Timeline[date.ToString("dd-MM-yy")] = string.Empty;
                }
            }
        }
    }

    private void ExpandAll()
    {
        expandedCompanies = new HashSet<string>(filteredTasks.Select(t => t.Company));
    }

    private void CollapseAll()
    {
        expandedCompanies.Clear();
    }

    private void ToggleCompany(string company)
    {
        if (expandedCompanies.Contains(company))
        {
            expandedCompanies.Remove(company);
        }
        else
        {
            expandedCompanies.Add(company);
        }
    }

    private bool IsCompanyExpanded(string company)
    {
        return expandedCompanies.Contains(company);
    }

    private string GetCollapseIcon(string company)
    {
        return expandedCompanies.Contains(company) ? "▼" : "►";
    }

    private bool IsDateWithinTaskRange(DateTime date, GTask task)
    {
        return date >= task.Start && date <= task.Deadline;
    }

    private double GetTaskDurationWidth(GTask task)
    {
        var totalTaskDays = (task.Deadline - task.Start).Days + 1;
        return totalTaskDays * 100.0 / totalDays;
    }

    private int GetDaysFromMinStartDate(GChart.Components.Pages.GanttChart.GTask task)
    {
        var minStartDate = filteredTasks.Min(t => t.Start);
        return (task.Start - minStartDate).Days;
    }
    public class GTask
    {
        public string Company { get; set; }
        public string PriorityArea { get; set; }
        public string MainTopic { get; set; }
        public string Expert { get; set; }
        public int Allocated { get; set; }
        public DateTime Start { get; set; }
        public DateTime Deadline { get; set; }
        public double PercentCompleted { get; set; }
        public string Status { get; set; }
        public bool IsExpanded { get; set; } = true; 
        public Dictionary<string, string> Timeline { get; set; } = new(); 
    }
}