Skip to content

[Admin] Component: Create event details - UI component #214 #293

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 43 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
986d5fe
Feat: 어드민 UI 컴포넌트 Page 추가
KYJKY Sep 1, 2024
aa36c46
Test: 어드민 UI 컴포넌트 테스트 추가
KYJKY Sep 1, 2024
b6d13d1
Feat: 버튼 추가
KYJKY Sep 1, 2024
15b36d4
Merge branch 'main' into feature/214-create-event-details
KYJKY Sep 2, 2024
765a28f
Fix: 피드백 적용
KYJKY Sep 3, 2024
7af315d
Update PlaygroundApp Model 최신화
KYJKY Sep 3, 2024
560c359
Merge: main > Task #214
KYJKY Sep 7, 2024
b578fb2
Refactor: 컴포넌트 수정
KYJKY Sep 7, 2024
70cbc7c
Feat: NodaTime을 사용하여 Time Zone Option 추가
KYJKY Sep 9, 2024
59d5eb7
Feat: 기본값 및 이벤트 설정
KYJKY Sep 9, 2024
6524e01
Refactor: 불필요한 코드 정리
KYJKY Sep 9, 2024
77681cc
Refactor: Time Zone Select 높이 수정
KYJKY Sep 9, 2024
197d7ee
Refactor: CSS 적용 방식 수정 - 외부 스타일 시트 적용
KYJKY Sep 9, 2024
ecb1b2a
Revert "Refactor: CSS 적용 방식 수정 - 외부 스타일 시트 적용"
KYJKY Sep 9, 2024
0fbcc1f
Refactor: 이벤트 종료 날짜 기본값 수정 (오늘 기준 다음날로 적용)
KYJKY Sep 9, 2024
a52fa78
Refactor: NewEventDetailsComponent.razor
KYJKY Sep 19, 2024
1c7b77e
Merge branch 'main' into feature/214-create-event-details
KYJKY Sep 19, 2024
ad18000
Refactor: Remove @temp~ variables
KYJKY Sep 19, 2024
a4b8b4e
Fix: FluentDatePicker, FluentTimePicker ValueChanged error fix
KYJKY Sep 19, 2024
4597c16
Refactor: NewEventDetailsComponent.razor
KYJKY Sep 28, 2024
57475f5
Test: Add NewEventDetailsComponent.razor test
KYJKY Sep 28, 2024
a361c2e
Merge branch 'main' into feature/214-create-event-details
KYJKY Sep 28, 2024
41ce714
Test: Add input test
KYJKY Sep 28, 2024
19fc5a1
Fix: delete inject
KYJKY Sep 28, 2024
9181344
Feat: Get local browser timezone
KYJKY Sep 29, 2024
88f32ef
Refactor: Add JS error handling
KYJKY Sep 29, 2024
60e851a
Refactor: NewEventDetailsComponent.razor
KYJKY Oct 1, 2024
c636124
Test: Add init timezone test
KYJKY Oct 1, 2024
1a3cd8c
Merge branch 'main' into feature/214-create-event-details
KYJKY Oct 3, 2024
6bf9e4f
Fix: Browser Timezone > System Timezone
KYJKY Oct 3, 2024
7c13476
Fix: Test error fix (Now > UtcNow)
KYJKY Oct 4, 2024
77fd773
Fix: add attribute Culture to FluentDatePicker
KYJKY Oct 5, 2024
d5b9d02
Fix: Add culture info in OnAfterRenderAsync
KYJKY Oct 5, 2024
4587101
Feat: Convert from Windows timezone to IANA timezone using TimeZoneCo…
KYJKY Oct 5, 2024
225ff36
Test: Convert from Windows timezone to IANA timezone using TimeZoneCo…
KYJKY Oct 5, 2024
ad7ee1f
Fix: Check OS to get timezone
KYJKY Oct 5, 2024
50d38bf
Test: Refactoring NewEventDetailsPageTests
KYJKY Oct 5, 2024
02ff26f
Test: Refactoring NewEventDetailsPageTests
KYJKY Oct 5, 2024
7e3bdfa
Merge branch 'main' into feature/214-create-event-details
KYJKY Oct 6, 2024
77cf3a1
Refactor: Refactoring NewEventDetailsComponent and test
KYJKY Oct 6, 2024
ff6ed0e
Merge branch 'main' into feature/214-create-event-details
KYJKY Oct 12, 2024
8713a32
Test: Add NewEventDetailsPageTests.cs to AppHost test
KYJKY Oct 12, 2024
e77caa0
Merge branch 'main' into feature/214-create-event-details
KYJKY Oct 12, 2024
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 @@ -10,6 +10,7 @@
<PackageReference Include="Microsoft.FluentUI.AspNetCore.Components" Version="$(FluentUIVersion)" />
<PackageReference Include="Microsoft.FluentUI.AspNetCore.Components.Emoji" Version="$(FluentUIVersion)" />
<PackageReference Include="Microsoft.FluentUI.AspNetCore.Components.Icons" Version="$(FluentUIVersion)" />
<PackageReference Include="NodaTime" Version="3.1.12" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
<PageTitle>New event</PageTitle>

<h1>New event</h1>

<NewEventDetailsComponent Id="admin-new-event" @rendermode="InteractiveServer" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
@using AzureOpenAIProxy.PlaygroundApp.Clients
@using AzureOpenAIProxy.PlaygroundApp.Models;

@using System.Globalization

@using NodaTime
@using NodaTime.Extensions
@using NodaTime.TimeZones

<FluentLayout Id="@Id">
@if (adminEventDetails == null)
{
<p><em>Loading...</em></p>
}
else
{
<FluentHeader>New Event</FluentHeader>
<FluentBodyContent>
<section>
<h2>Event Infomation</h2>

<FluentStack Class="create-fluent-stack" Orientation="Orientation.Horizontal" VerticalAlignment="VerticalAlignment.Center">
<FluentLabel For="event-title" Class="create-input-label">Title</FluentLabel>
<FluentTextField Id="event-title" Name="title" TextFieldType="TextFieldType.Text" Required />
</FluentStack>

<FluentStack Class="create-fluent-stack" Orientation="Orientation.Horizontal" VerticalAlignment="VerticalAlignment.Center">
<FluentLabel For="event-summary" Class="create-input-label">Summary</FluentLabel>
<FluentTextField id="event-summary" TextFieldType="TextFieldType.Text" Required />
</FluentStack>

<FluentStack Class="create-fluent-stack" Orientation="Orientation.Horizontal" VerticalAlignment="VerticalAlignment.Center">
<FluentLabel For="event-description" Class="create-input-label">Description</FluentLabel>
<FluentTextArea Id="event-description" Style="width:300px" />
</FluentStack>

<FluentStack Class="create-fluent-stack" Orientation="Orientation.Horizontal" VerticalAlignment="VerticalAlignment.Center">
<FluentLabel For="event-start-date" Class="create-input-label">Event Start Date</FluentLabel>
<FluentDatePicker Id="event-start-date" Value="@adminEventDetails.DateStart.DateTime" ValueChanged="@(e => adminEventDetails.DateStart = e.Value)" Culture="System.Globalization.CultureInfo.CurrentCulture" />

Check warning on line 39 in src/AzureOpenAIProxy.PlaygroundApp/Components/UI/Admin/NewEventDetailsComponent.razor

View workflow job for this annotation

GitHub Actions / build-test

Nullable value type may be null.
<FluentTimePicker Id="event-start-time" Value="@adminEventDetails.DateStart.DateTime" ValueChanged="@(e => adminEventDetails.DateStart = e.Value)" />

Check warning on line 40 in src/AzureOpenAIProxy.PlaygroundApp/Components/UI/Admin/NewEventDetailsComponent.razor

View workflow job for this annotation

GitHub Actions / build-test

Nullable value type may be null.
</FluentStack>

<FluentStack Class="create-fluent-stack" Orientation="Orientation.Horizontal" VerticalAlignment="VerticalAlignment.Center">
<FluentLabel For="event-end-date" Class="create-input-label">Event End Date</FluentLabel>
<FluentDatePicker Id="event-end-date" Value="@adminEventDetails.DateEnd.DateTime" ValueChanged="@(e => adminEventDetails.DateEnd = e.Value)" Culture="System.Globalization.CultureInfo.CurrentCulture" />

Check warning on line 45 in src/AzureOpenAIProxy.PlaygroundApp/Components/UI/Admin/NewEventDetailsComponent.razor

View workflow job for this annotation

GitHub Actions / build-test

Nullable value type may be null.
<FluentTimePicker Id="event-end-time" Value="@adminEventDetails.DateEnd.DateTime" ValueChanged="@(e => adminEventDetails.DateEnd = e.Value)" />

Check warning on line 46 in src/AzureOpenAIProxy.PlaygroundApp/Components/UI/Admin/NewEventDetailsComponent.razor

View workflow job for this annotation

GitHub Actions / build-test

Nullable value type may be null.
</FluentStack>

<FluentStack Class="create-fluent-stack" Orientation="Orientation.Horizontal" VerticalAlignment="VerticalAlignment.Center">
<FluentLabel For="event-timezone" Class="create-input-label">Time Zone</FluentLabel>
<FluentSelect Id="event-timezone" @bind-Value="@adminEventDetails.TimeZone" Height="500px" TOption="string" Required>
@foreach (var timeZone in timeZoneList)
{
<FluentOption Value="@timeZone.Id">@timeZone.Id</FluentOption>
}
</FluentSelect>
</FluentStack>
</section>

<section>
<h2>Event Organizer</h2>

<FluentStack Class="create-fluent-stack" Orientation="Orientation.Horizontal" VerticalAlignment="VerticalAlignment.Center">
<FluentLabel For="event-organizer-name" Class="create-input-label">Organizer Name</FluentLabel>
<FluentTextField Id="event-organizer-name" TextFieldType="TextFieldType.Text" Required />
</FluentStack>


<FluentStack Class="create-fluent-stack" Orientation="Orientation.Horizontal" VerticalAlignment="VerticalAlignment.Center">
<FluentLabel For="event-organizer-email" Class="create-input-label">Organizer Email</FluentLabel>
<FluentTextField Id="event-organizer-email" TextFieldType="TextFieldType.Email" Required />
</FluentStack>
</section>

<section>
<h2>Event Coorganizers</h2>

<FluentStack Class="create-fluent-stack" Orientation="Orientation.Horizontal" VerticalAlignment="VerticalAlignment.Center">
<FluentLabel For="event-coorgnizer-name" Class="create-input-label">Coorgnizer Name</FluentLabel>
<FluentTextField Id="event-coorgnizer-name" TextFieldType="TextFieldType.Text" Required />
</FluentStack>

<FluentStack Class="create-fluent-stack" Orientation="Orientation.Horizontal" VerticalAlignment="VerticalAlignment.Center">
<FluentLabel For="event-coorgnizer-email" Class="create-input-label">Coorgnizer Email</FluentLabel>
<FluentTextField Id="event-coorgnizer-email" TextFieldType="TextFieldType.Email" Required />
</FluentStack>
</section>

<section>
<h2>Event Configuration</h2>

<FluentStack Class="create-fluent-stack" Orientation="Orientation.Horizontal" VerticalAlignment="VerticalAlignment.Center">
<FluentLabel For="event-max-token-cap" Class="create-input-label">Max Token Cap</FluentLabel>
<FluentNumberField Id="event-max-token-cap" @bind-Value="adminEventDetails.MaxTokenCap" Required />
</FluentStack>

<FluentStack Class="create-fluent-stack" Orientation="Orientation.Horizontal" VerticalAlignment="VerticalAlignment.Center">
<FluentLabel For="event-daily-request-cap" Class="create-input-label">Daily Request Cap</FluentLabel>
<FluentNumberField Id="event-daily-request-cap" @bind-Value="adminEventDetails.DailyRequestCap" Required />
</FluentStack>
</section>

<section class="button-section">
<FluentButton Id="admin-event-detail-add" Appearance="Appearance.Accent" Class="button" OnClick="AddEvent">Add Event</FluentButton>
<FluentButton Id="admin-event-detail-cancel" Appearance="Appearance.Outline" Class="button" OnClick="CancelEvent">Cancel</FluentButton>
</section>
</FluentBodyContent>
}
</FluentLayout>


@code {
private List<DateTimeZone>? timeZoneList;
private AdminEventDetails? adminEventDetails;
private DateTimeOffset currentTime = DateTimeOffset.UtcNow;

[Parameter]
public string? Id { get; set; }

protected override async Task OnInitializedAsync()
{
adminEventDetails = adminEventDetails == null ? new() : adminEventDetails;

timeZoneList = DateTimeZoneProviders.Tzdb.GetAllZones().ToList();

CultureInfo customCulture = (CultureInfo)CultureInfo.CurrentCulture.Clone();
customCulture.DateTimeFormat.ShortDatePattern = "yyyy-MM-dd";
customCulture.DateTimeFormat.ShortTimePattern = "HH:mm";

CultureInfo.DefaultThreadCurrentCulture = customCulture;
CultureInfo.DefaultThreadCurrentUICulture = customCulture;
}

protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var timezoneId = GetIanaTimezoneId();
currentTime = GetCurrentDateTimeOffset(timezoneId);

adminEventDetails.DateStart = currentTime.AddHours(1).AddMinutes(-currentTime.Minute);
adminEventDetails.DateEnd = currentTime.AddDays(1).AddHours(1).AddMinutes(-currentTime.Minute);
adminEventDetails.TimeZone = timezoneId;

await InvokeAsync(StateHasChanged);
}
}

private async Task AddEvent()
{
await Task.CompletedTask;
}

private async Task CancelEvent()
{
await Task.CompletedTask;
}

private string GetIanaTimezoneId()
{
string timezoneId = TimeZoneInfo.Local.Id;

if (OperatingSystem.IsWindows())
{
if (TimeZoneInfo.TryConvertWindowsIdToIanaId(timezoneId, out var ianaTimezoneId))
{
timezoneId = ianaTimezoneId;
}
}

return timezoneId;
}

private DateTimeOffset GetCurrentDateTimeOffset(string timezoneId)
{
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timezoneId);

return TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, timeZoneInfo);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
section {
margin-bottom: 100px
}

::deep .create-input-label {
width: 200px;
--type-ramp-base-font-size: 22px;
}

::deep .create-fluent-stack {
height: 100px;
}

.button-section {
display: flex;
justify-content: center;
gap: 50px;
}

.button {
width: 150px;
height: 50px;
font-size: 16px;
margin: 0 10px;
}
118 changes: 59 additions & 59 deletions src/AzureOpenAIProxy.PlaygroundApp/Models/AdminEventDetails.cs
Original file line number Diff line number Diff line change
@@ -1,60 +1,60 @@
using System.Text.Json.Serialization;
namespace AzureOpenAIProxy.PlaygroundApp.Models;
/// <summary>
/// This represent the event detail data for response by admin event endpoint.
/// </summary>
public class AdminEventDetails : EventDetails
{
/// <summary>
/// Gets or sets the event description.
/// </summary>
public string? Description { get; set; }
/// <summary>
/// Gets or sets the event start date.
/// </summary>
[JsonRequired]
public DateTimeOffset DateStart { get; set; }
/// <summary>
/// Gets or sets the event end date.
/// </summary>
[JsonRequired]
public DateTimeOffset DateEnd { get; set; }
/// <summary>
/// Gets or sets the event start to end date timezone.
/// </summary>
[JsonRequired]
public string TimeZone { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the event active status.
/// </summary>
[JsonRequired]
public bool IsActive { get; set; }
/// <summary>
/// Gets or sets the event organizer name.
/// </summary>
[JsonRequired]
public string OrganizerName { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the event organizer email.
/// </summary>
[JsonRequired]
public string OrganizerEmail { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the event coorganizer name.
/// </summary>
public string? CoorganizerName { get; set; }
/// <summary>
/// Gets or sets the event coorganizer email.
/// </summary>
public string? CoorganizerEmail { get; set; }
using System.Text.Json.Serialization;

namespace AzureOpenAIProxy.PlaygroundApp.Models;

/// <summary>
/// This represent the event detail data for response by admin event endpoint.
/// </summary>
public class AdminEventDetails : EventDetails
{
/// <summary>
/// Gets or sets the event description.
/// </summary>
public string? Description { get; set; }

/// <summary>
/// Gets or sets the event start date.
/// </summary>
[JsonRequired]
public DateTimeOffset DateStart { get; set; }

/// <summary>
/// Gets or sets the event end date.
/// </summary>
[JsonRequired]
public DateTimeOffset DateEnd { get; set; }

/// <summary>
/// Gets or sets the event start to end date timezone.
/// </summary>
[JsonRequired]
public string TimeZone { get; set; } = string.Empty;

/// <summary>
/// Gets or sets the event active status.
/// </summary>
[JsonRequired]
public bool IsActive { get; set; }

/// <summary>
/// Gets or sets the event organizer name.
/// </summary>
[JsonRequired]
public string OrganizerName { get; set; } = string.Empty;

/// <summary>
/// Gets or sets the event organizer email.
/// </summary>
[JsonRequired]
public string OrganizerEmail { get; set; } = string.Empty;

/// <summary>
/// Gets or sets the event coorganizer name.
/// </summary>
public string? CoorganizerName { get; set; }

/// <summary>
/// Gets or sets the event coorganizer email.
/// </summary>
public string? CoorganizerEmail { get; set; }
}
Loading
Loading