diff --git a/BlazorApp/Components/Pages/Developers.razor b/BlazorApp/Components/Pages/Developers.razor
index a1c6df2..875e74d 100644
--- a/BlazorApp/Components/Pages/Developers.razor
+++ b/BlazorApp/Components/Pages/Developers.razor
@@ -2,6 +2,7 @@
@using SilverLabs.Website.Models
@using SilverLabs.Website.Services
@inject DeveloperApplicationService ApplicationService
+@inject IJSRuntime JS
@rendermode InteractiveServer
Join the Team - SilverLabs
@@ -85,8 +86,9 @@
-
+
+ Leave blank to use your @@silverlabs.uk address
@@ -256,10 +258,35 @@
private readonly string[] _availablePlatforms = { "Windows", "macOS", "Linux", "Android", "iOS", "Other" };
- private static readonly List<(string Id, string Label)> _timezones = TimeZoneInfo.GetSystemTimeZones()
- .OrderBy(tz => tz.BaseUtcOffset)
- .Select(tz => (tz.Id, $"(UTC{(tz.BaseUtcOffset >= TimeSpan.Zero ? "+" : "")}{tz.BaseUtcOffset:hh\\:mm}) {tz.DisplayName}"))
- .ToList();
+ private static readonly List<(string Id, string Label)> _timezones = new()
+ {
+ ("Pacific/Midway", "(UTC-11:00) Midway Island"),
+ ("Pacific/Honolulu", "(UTC-10:00) Hawaii"),
+ ("America/Anchorage", "(UTC-09:00) Alaska"),
+ ("America/Los_Angeles", "(UTC-08:00) Pacific Time (US & Canada)"),
+ ("America/Denver", "(UTC-07:00) Mountain Time (US & Canada)"),
+ ("America/Chicago", "(UTC-06:00) Central Time (US & Canada)"),
+ ("America/New_York", "(UTC-05:00) Eastern Time (US & Canada)"),
+ ("America/Caracas", "(UTC-04:00) Venezuela"),
+ ("America/Halifax", "(UTC-04:00) Atlantic Time (Canada)"),
+ ("America/Sao_Paulo", "(UTC-03:00) Brazil"),
+ ("Atlantic/South_Georgia","(UTC-02:00) Mid-Atlantic"),
+ ("Atlantic/Azores", "(UTC-01:00) Azores"),
+ ("Europe/London", "(UTC+00:00) London, Dublin, Lisbon"),
+ ("Europe/Berlin", "(UTC+01:00) Berlin, Paris, Amsterdam"),
+ ("Europe/Bucharest", "(UTC+02:00) Bucharest, Helsinki, Athens"),
+ ("Europe/Moscow", "(UTC+03:00) Moscow, Istanbul"),
+ ("Asia/Dubai", "(UTC+04:00) Dubai, Baku"),
+ ("Asia/Karachi", "(UTC+05:00) Karachi, Tashkent"),
+ ("Asia/Kolkata", "(UTC+05:30) Mumbai, New Delhi"),
+ ("Asia/Dhaka", "(UTC+06:00) Dhaka, Almaty"),
+ ("Asia/Bangkok", "(UTC+07:00) Bangkok, Jakarta"),
+ ("Asia/Shanghai", "(UTC+08:00) Beijing, Singapore, Perth"),
+ ("Asia/Tokyo", "(UTC+09:00) Tokyo, Seoul"),
+ ("Australia/Sydney", "(UTC+10:00) Sydney, Melbourne"),
+ ("Pacific/Noumea", "(UTC+11:00) Solomon Islands"),
+ ("Pacific/Auckland", "(UTC+12:00) Auckland, Fiji"),
+ };
private static readonly System.Text.RegularExpressions.Regex UsernamePattern =
new(@"^[a-zA-Z0-9_-]{3,30}$", System.Text.RegularExpressions.RegexOptions.Compiled);
@@ -269,6 +296,26 @@
private bool IsSubmitDisabled =>
_submitting || _usernameCheckState == UsernameCheckState.Taken || _usernameCheckState == UsernameCheckState.Checking;
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (firstRender && string.IsNullOrEmpty(_application.Timezone))
+ {
+ try
+ {
+ var detectedTz = await JS.InvokeAsync("eval", "Intl.DateTimeFormat().resolvedOptions().timeZone");
+ if (!string.IsNullOrEmpty(detectedTz) && _timezones.Any(tz => tz.Id == detectedTz))
+ {
+ _application.Timezone = detectedTz;
+ StateHasChanged();
+ }
+ }
+ catch
+ {
+ // Browser may not support Intl API — ignore
+ }
+ }
+ }
+
private void SelectRole(ApplicationRole role)
{
_application.Role = role;
diff --git a/BlazorApp/Models/DeveloperApplication.cs b/BlazorApp/Models/DeveloperApplication.cs
index 3f51768..db5d99a 100644
--- a/BlazorApp/Models/DeveloperApplication.cs
+++ b/BlazorApp/Models/DeveloperApplication.cs
@@ -8,9 +8,8 @@ public class DeveloperApplication
[StringLength(100, MinimumLength = 2)]
public string FullName { get; set; } = string.Empty;
- [Required(ErrorMessage = "Email is required")]
[EmailAddress(ErrorMessage = "Invalid email address")]
- public string Email { get; set; } = string.Empty;
+ public string? Email { get; set; }
[Required(ErrorMessage = "Username is required")]
[RegularExpression(@"^[a-zA-Z0-9_-]{3,30}$", ErrorMessage = "Username must be 3-30 characters, letters, numbers, hyphens and underscores only")]
diff --git a/BlazorApp/Services/DeveloperApplicationService.cs b/BlazorApp/Services/DeveloperApplicationService.cs
index 8455dae..298b646 100644
--- a/BlazorApp/Services/DeveloperApplicationService.cs
+++ b/BlazorApp/Services/DeveloperApplicationService.cs
@@ -48,11 +48,16 @@ public class DeveloperApplicationService
{
try
{
+ // Use silverlabs.uk address when no personal email provided
+ var effectiveEmail = string.IsNullOrWhiteSpace(application.Email)
+ ? $"{application.DesiredUsername}@silverlabs.uk"
+ : application.Email.Trim();
+
// 1. Register user on SilverDESK
var registerPayload = new
{
username = application.DesiredUsername,
- email = application.Email,
+ email = effectiveEmail,
password = application.Password,
fullName = application.FullName
};
@@ -111,7 +116,7 @@ public class DeveloperApplicationService
userId,
ticketId,
fullName = application.FullName,
- email = application.Email,
+ email = effectiveEmail,
desiredUsername = application.DesiredUsername,
timezone = application.Timezone,
appliedRole = application.Role.ToString(),
@@ -126,29 +131,29 @@ public class DeveloperApplicationService
if (appResponse.IsSuccessStatusCode)
{
- _logger.LogInformation("DeveloperApplication record created for {Email}", application.Email);
+ _logger.LogInformation("DeveloperApplication record created for {Email}", effectiveEmail);
}
else
{
var appError = await appResponse.Content.ReadAsStringAsync();
_logger.LogWarning("Failed to create DeveloperApplication record for {Email}: {StatusCode} - {Body}",
- application.Email, appResponse.StatusCode, appError);
+ effectiveEmail, appResponse.StatusCode, appError);
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to create DeveloperApplication record for {Email} — user and ticket were created successfully",
- application.Email);
+ effectiveEmail);
}
_logger.LogInformation("Developer application submitted for {Email} as {Role} — user registered and ticket created",
- application.Email, application.Role);
+ effectiveEmail, application.Role);
return (true, "Application submitted successfully! Your SilverDESK account has been created.", token);
}
catch (Exception ex)
{
- _logger.LogError(ex, "Error submitting developer application for {Email}", application.Email);
+ _logger.LogError(ex, "Error submitting developer application for {Username}", application.DesiredUsername);
return (false, "Unable to connect to the application service. Please try again later.", null);
}
}
@@ -177,12 +182,16 @@ public class DeveloperApplicationService
private static string FormatTicketBody(DeveloperApplication app)
{
+ var effectiveEmail = string.IsNullOrWhiteSpace(app.Email)
+ ? $"{app.DesiredUsername}@silverlabs.uk"
+ : app.Email.Trim();
+
var sb = new StringBuilder();
sb.AppendLine("## Developer Program Application");
sb.AppendLine();
sb.AppendLine($"**Role:** {app.Role}");
sb.AppendLine($"**Full Name:** {app.FullName}");
- sb.AppendLine($"**Email:** {app.Email}");
+ sb.AppendLine($"**Email:** {effectiveEmail}");
sb.AppendLine($"**Desired Username:** {app.DesiredUsername}");
sb.AppendLine($"**Timezone:** {app.Timezone}");
sb.AppendLine();