All checks were successful
Build and Deploy / deploy (push) Successful in 41s
Ticket replies now include full onboarding info (webmail, IMAP/SMTP, Mattermost, Gitea, SilverDESK URLs) instead of raw provisioning status. Confirmation success page uses clickable service links with email client config details. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
358 lines
12 KiB
Plaintext
358 lines
12 KiB
Plaintext
@page "/developers/confirm/{Token}"
|
|
@inject HttpClient Http
|
|
@inject NavigationManager Navigation
|
|
@inject IConfiguration Configuration
|
|
@rendermode InteractiveServer
|
|
|
|
<PageTitle>Activate Your Accounts - SilverLabs</PageTitle>
|
|
|
|
<div class="main-content visible">
|
|
<header class="header">
|
|
<img src="logo.png" alt="SilverLabs Logo" class="logo">
|
|
</header>
|
|
|
|
<div class="dev-container">
|
|
<div class="dev-header">
|
|
<h1>Activate Your Accounts</h1>
|
|
<p class="dev-subtitle">Confirm your identity to provision your SilverLabs developer accounts.</p>
|
|
</div>
|
|
|
|
@if (_loading)
|
|
{
|
|
<div class="dev-section" style="text-align: center; padding: 3rem;">
|
|
<div class="btn-spinner" style="width: 32px; height: 32px; margin: 0 auto 1rem;"></div>
|
|
<p style="color: rgba(255,255,255,0.6);">Loading deployment details...</p>
|
|
</div>
|
|
}
|
|
else if (_invalidToken)
|
|
{
|
|
<div class="dev-section" style="text-align: center; padding: 3rem;">
|
|
<div class="confirm-icon confirm-icon-error">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<circle cx="12" cy="12" r="10"></circle>
|
|
<line x1="15" y1="9" x2="9" y2="15"></line>
|
|
<line x1="9" y1="9" x2="15" y2="15"></line>
|
|
</svg>
|
|
</div>
|
|
<h2 style="color: #f87171; margin-bottom: 0.75rem;">Invalid or Expired Link</h2>
|
|
<p style="color: rgba(255,255,255,0.6); max-width: 400px; margin: 0 auto;">This confirmation link is no longer valid. It may have expired or already been used. Please contact an administrator if you need a new link.</p>
|
|
</div>
|
|
}
|
|
else if (_provisioned)
|
|
{
|
|
<div class="dev-success-panel">
|
|
<div class="success-icon">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
|
|
<polyline points="22 4 12 14.01 9 11.01"></polyline>
|
|
</svg>
|
|
</div>
|
|
<h2>Accounts Activated</h2>
|
|
<p>@_resultMessage</p>
|
|
<div class="confirm-services">
|
|
<a href="https://mail.silverlined.uk" target="_blank" class="confirm-service-item confirm-service-link">
|
|
<strong>Email</strong>
|
|
<span>@(_username)@@silverlabs.uk</span>
|
|
</a>
|
|
<a href="https://ops.silverlined.uk" target="_blank" class="confirm-service-item confirm-service-link">
|
|
<strong>Mattermost</strong>
|
|
<span>Team chat & collaboration</span>
|
|
</a>
|
|
<a href="https://git.silverlabs.uk" target="_blank" class="confirm-service-item confirm-service-link">
|
|
<strong>Gitea</strong>
|
|
<span>Source code repositories</span>
|
|
</a>
|
|
<a href="https://silverdesk.silverlabs.uk" target="_blank" class="confirm-service-item confirm-service-link">
|
|
<strong>SilverDESK</strong>
|
|
<span>Support & tickets</span>
|
|
</a>
|
|
</div>
|
|
<div class="confirm-email-config">
|
|
<strong>Email Client Setup</strong>
|
|
<div class="confirm-email-detail"><span>IMAP:</span> mail.silverlined.uk:993 (SSL)</div>
|
|
<div class="confirm-email-detail"><span>SMTP:</span> mail.silverlined.uk:465 (SSL)</div>
|
|
</div>
|
|
<p class="dev-account-note">All accounts use the same password you just entered.</p>
|
|
<div class="dev-success-actions">
|
|
<a href="https://silverdesk.silverlabs.uk" target="_blank" class="dev-btn dev-btn-primary">Go to SilverDESK</a>
|
|
<a href="/" class="dev-btn dev-btn-secondary">Back to Home</a>
|
|
</div>
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
<div class="dev-section">
|
|
<h2 class="dev-section-title">Confirm Your Identity</h2>
|
|
<p class="dev-section-desc">Enter your SilverDESK password to activate your accounts. All services will use this same password.</p>
|
|
|
|
<div class="confirm-user-info">
|
|
<div class="confirm-user-field">
|
|
<span class="confirm-label">Username</span>
|
|
<span class="confirm-value">@_username</span>
|
|
</div>
|
|
<div class="confirm-user-field">
|
|
<span class="confirm-label">Email</span>
|
|
<span class="confirm-value">@_email</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group" style="margin-top: 1.5rem; max-width: 400px;">
|
|
<label for="password">SilverDESK Password</label>
|
|
<input id="password" type="password" class="form-input" @bind="_password"
|
|
@bind:event="oninput" @onkeydown="HandleKeyDown" placeholder="Enter your password" />
|
|
</div>
|
|
|
|
@if (!string.IsNullOrEmpty(_errorMessage))
|
|
{
|
|
<div class="dev-error" style="margin-top: 1rem;">@_errorMessage</div>
|
|
}
|
|
|
|
<div style="margin-top: 1.5rem;">
|
|
<button class="dev-btn dev-btn-primary" disabled="@_submitting" @onclick="HandleConfirm">
|
|
@if (_submitting)
|
|
{
|
|
<span class="btn-spinner"></span>
|
|
<span>Activating accounts...</span>
|
|
}
|
|
else
|
|
{
|
|
<span>Activate My Accounts</span>
|
|
}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
<a href="/" class="back-link">← Back to SilverLabs Home</a>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.confirm-icon-error {
|
|
width: 72px;
|
|
height: 72px;
|
|
margin: 0 auto 1.5rem;
|
|
background: rgba(248, 113, 113, 0.15);
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.confirm-icon-error svg {
|
|
width: 36px;
|
|
height: 36px;
|
|
stroke: #f87171;
|
|
}
|
|
|
|
.confirm-user-info {
|
|
display: flex;
|
|
gap: 2rem;
|
|
margin-top: 1rem;
|
|
padding: 1rem;
|
|
background: rgba(0, 0, 0, 0.2);
|
|
border-radius: 10px;
|
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
}
|
|
|
|
.confirm-user-field {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.25rem;
|
|
}
|
|
|
|
.confirm-label {
|
|
font-size: 0.78rem;
|
|
color: rgba(255, 255, 255, 0.4);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
}
|
|
|
|
.confirm-value {
|
|
font-size: 1rem;
|
|
color: #4DD0E1;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.confirm-services {
|
|
display: grid;
|
|
grid-template-columns: repeat(4, 1fr);
|
|
gap: 1rem;
|
|
margin: 1.5rem auto;
|
|
max-width: 600px;
|
|
}
|
|
|
|
.confirm-service-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: 0.75rem;
|
|
background: rgba(255, 255, 255, 0.04);
|
|
border-radius: 10px;
|
|
text-align: center;
|
|
}
|
|
|
|
.confirm-service-link {
|
|
text-decoration: none;
|
|
border: 1px solid rgba(77, 208, 225, 0.15);
|
|
transition: background 0.2s, border-color 0.2s;
|
|
}
|
|
|
|
.confirm-service-link:hover {
|
|
background: rgba(77, 208, 225, 0.08);
|
|
border-color: rgba(77, 208, 225, 0.35);
|
|
}
|
|
|
|
.confirm-service-item strong {
|
|
color: #4DD0E1;
|
|
font-size: 0.95rem;
|
|
margin-bottom: 0.2rem;
|
|
}
|
|
|
|
.confirm-service-item span {
|
|
color: rgba(255, 255, 255, 0.55);
|
|
font-size: 0.8rem;
|
|
}
|
|
|
|
.confirm-email-config {
|
|
margin: 1rem auto;
|
|
max-width: 360px;
|
|
padding: 0.75rem 1rem;
|
|
background: rgba(0, 0, 0, 0.2);
|
|
border-radius: 8px;
|
|
border: 1px solid rgba(255, 255, 255, 0.06);
|
|
font-size: 0.82rem;
|
|
}
|
|
|
|
.confirm-email-config strong {
|
|
display: block;
|
|
color: rgba(255, 255, 255, 0.5);
|
|
font-size: 0.72rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
margin-bottom: 0.4rem;
|
|
}
|
|
|
|
.confirm-email-detail {
|
|
color: rgba(255, 255, 255, 0.6);
|
|
padding: 0.15rem 0;
|
|
}
|
|
|
|
.confirm-email-detail span {
|
|
color: rgba(255, 255, 255, 0.4);
|
|
font-size: 0.8rem;
|
|
}
|
|
|
|
@@media (max-width: 768px) {
|
|
.confirm-user-info {
|
|
flex-direction: column;
|
|
gap: 0.75rem;
|
|
}
|
|
|
|
.confirm-services {
|
|
grid-template-columns: repeat(2, 1fr);
|
|
}
|
|
}
|
|
</style>
|
|
|
|
@code {
|
|
[Parameter] public string Token { get; set; } = "";
|
|
|
|
private bool _loading = true;
|
|
private bool _invalidToken;
|
|
private bool _provisioned;
|
|
private bool _submitting;
|
|
private string? _username;
|
|
private string? _email;
|
|
private string? _password;
|
|
private string? _errorMessage;
|
|
private string? _resultMessage;
|
|
|
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
{
|
|
if (!firstRender) return;
|
|
|
|
try
|
|
{
|
|
var baseUrl = Navigation.BaseUri.TrimEnd('/');
|
|
using var client = new HttpClient();
|
|
var response = await client.GetAsync($"{baseUrl}/api/developers/deployment-info/{Token}");
|
|
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var data = await response.Content.ReadFromJsonAsync<DeploymentInfo>();
|
|
_username = data?.Username;
|
|
_email = data?.Email;
|
|
}
|
|
else
|
|
{
|
|
_invalidToken = true;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
_invalidToken = true;
|
|
}
|
|
|
|
_loading = false;
|
|
StateHasChanged();
|
|
}
|
|
|
|
private async Task HandleKeyDown(KeyboardEventArgs e)
|
|
{
|
|
if (e.Key == "Enter" && !_submitting && !string.IsNullOrEmpty(_password))
|
|
await HandleConfirm();
|
|
}
|
|
|
|
private async Task HandleConfirm()
|
|
{
|
|
if (string.IsNullOrEmpty(_password))
|
|
{
|
|
_errorMessage = "Please enter your password.";
|
|
return;
|
|
}
|
|
|
|
_errorMessage = null;
|
|
_submitting = true;
|
|
StateHasChanged();
|
|
|
|
try
|
|
{
|
|
var baseUrl = Navigation.BaseUri.TrimEnd('/');
|
|
using var client = new HttpClient();
|
|
var payload = new { token = Token, password = _password };
|
|
var response = await client.PostAsJsonAsync($"{baseUrl}/api/developers/confirm-deployment", payload);
|
|
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var result = await response.Content.ReadFromJsonAsync<ProvisionResult>();
|
|
_resultMessage = result?.Message ?? "Accounts activated successfully.";
|
|
_provisioned = true;
|
|
}
|
|
else if ((int)response.StatusCode == 401)
|
|
{
|
|
_errorMessage = "Incorrect password. Please enter the password you created when you applied.";
|
|
}
|
|
else if ((int)response.StatusCode == 404)
|
|
{
|
|
_invalidToken = true;
|
|
}
|
|
else
|
|
{
|
|
_errorMessage = "Something went wrong. Please try again or contact an administrator.";
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
_errorMessage = "Connection error. Please try again.";
|
|
}
|
|
finally
|
|
{
|
|
_submitting = false;
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
|
|
private record DeploymentInfo(string Username, string Email, string FullName, DateTime ExpiresAt);
|
|
private record ProvisionResult(bool Success, string Message);
|
|
}
|