Add developer application page with form submission that creates tickets in SilverDESK. Includes provisioning service scaffolding for Mattermost, Mailcow, and Gitea account creation. Fixes API key header casing (X-API-Key) and ticket payload to match SilverDESK's CreateTicketDto contract. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
245 lines
12 KiB
Plaintext
245 lines
12 KiB
Plaintext
@page "/developers"
|
|
@using SilverLabs.Website.Models
|
|
@using SilverLabs.Website.Services
|
|
@inject DeveloperApplicationService ApplicationService
|
|
@rendermode InteractiveServer
|
|
|
|
<PageTitle>Join the Team - 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>Join the SilverLabs Team</h1>
|
|
<p class="dev-subtitle">Help us build privacy-first infrastructure. Whether you test our products or write code, there's a place for you.</p>
|
|
</div>
|
|
|
|
@if (_submitted)
|
|
{
|
|
<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>Application Submitted</h2>
|
|
<p>@_resultMessage</p>
|
|
<a href="/" class="dev-btn dev-btn-secondary">Back to Home</a>
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
<EditForm Model="_application" OnValidSubmit="HandleSubmit" FormName="developer-application">
|
|
<DataAnnotationsValidator />
|
|
|
|
<!-- Role Selector -->
|
|
<div class="dev-section">
|
|
<h2 class="dev-section-title">Choose Your Role</h2>
|
|
<div class="role-selector">
|
|
<div class="role-card @(_application.Role == ApplicationRole.Tester ? "role-active" : "")"
|
|
@onclick="() => SelectRole(ApplicationRole.Tester)">
|
|
<div class="role-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="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
|
|
<polyline points="14 2 14 8 20 8"></polyline>
|
|
<line x1="16" y1="13" x2="8" y2="13"></line>
|
|
<line x1="16" y1="17" x2="8" y2="17"></line>
|
|
<polyline points="10 9 9 9 8 9"></polyline>
|
|
</svg>
|
|
</div>
|
|
<h3>Product Tester</h3>
|
|
<p>Test our apps across devices, find bugs, and provide feedback that shapes our products.</p>
|
|
</div>
|
|
|
|
<div class="role-card @(_application.Role == ApplicationRole.Developer ? "role-active" : "")"
|
|
@onclick="() => SelectRole(ApplicationRole.Developer)">
|
|
<div class="role-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">
|
|
<polyline points="16 18 22 12 16 6"></polyline>
|
|
<polyline points="8 6 2 12 8 18"></polyline>
|
|
</svg>
|
|
</div>
|
|
<h3>Developer</h3>
|
|
<p>Contribute code, build modules, and help architect privacy-first solutions.</p>
|
|
</div>
|
|
</div>
|
|
<ValidationMessage For="() => _application.Role" />
|
|
</div>
|
|
|
|
<!-- Personal Details -->
|
|
<div class="dev-section">
|
|
<h2 class="dev-section-title">About You</h2>
|
|
<div class="form-grid">
|
|
<div class="form-group">
|
|
<label for="fullName">Full Name</label>
|
|
<InputText id="fullName" @bind-Value="_application.FullName" class="form-input" placeholder="Jane Doe" />
|
|
<ValidationMessage For="() => _application.FullName" />
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="email">Email Address</label>
|
|
<InputText id="email" @bind-Value="_application.Email" class="form-input" placeholder="jane@example.com" />
|
|
<ValidationMessage For="() => _application.Email" />
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="username">Desired Username</label>
|
|
<InputText id="username" @bind-Value="_application.DesiredUsername" class="form-input" placeholder="janedoe" />
|
|
<span class="form-hint">This will be your handle across SilverLabs services</span>
|
|
<ValidationMessage For="() => _application.DesiredUsername" />
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="timezone">Location / Timezone</label>
|
|
<InputText id="timezone" @bind-Value="_application.Timezone" class="form-input" placeholder="e.g. Europe/London, US/Eastern" />
|
|
<ValidationMessage For="() => _application.Timezone" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Platforms -->
|
|
<div class="dev-section">
|
|
<h2 class="dev-section-title">Devices & Platforms</h2>
|
|
<p class="dev-section-desc">Which platforms do you use or have access to?</p>
|
|
<div class="platform-grid">
|
|
@foreach (var platform in _availablePlatforms)
|
|
{
|
|
var isChecked = _application.Platforms.Contains(platform);
|
|
<label class="platform-chip @(isChecked ? "platform-active" : "")">
|
|
<input type="checkbox" checked="@isChecked"
|
|
@onchange="() => TogglePlatform(platform)" />
|
|
<span>@platform</span>
|
|
</label>
|
|
}
|
|
</div>
|
|
<ValidationMessage For="() => _application.Platforms" />
|
|
</div>
|
|
|
|
<!-- Developer-only: Skills -->
|
|
@if (_application.Role == ApplicationRole.Developer)
|
|
{
|
|
<div class="dev-section dev-section-fade-in">
|
|
<h2 class="dev-section-title">Skills & Experience</h2>
|
|
<p class="dev-section-desc">Tell us about your technical background — languages, frameworks, and any open-source contributions.</p>
|
|
<div class="form-group">
|
|
<InputTextArea id="skills" @bind-Value="_application.Skills" class="form-input form-textarea"
|
|
placeholder="e.g. C#/.NET 5 years, Blazor, PostgreSQL, Docker, contributed to..." rows="5" />
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
<!-- Motivation -->
|
|
<div class="dev-section">
|
|
<h2 class="dev-section-title">Why SilverLabs?</h2>
|
|
<p class="dev-section-desc">What draws you to privacy-first development? What do you hope to contribute?</p>
|
|
<div class="form-group">
|
|
<InputTextArea id="motivation" @bind-Value="_application.Motivation" class="form-input form-textarea"
|
|
placeholder="Tell us what motivates you..." rows="5" />
|
|
<ValidationMessage For="() => _application.Motivation" />
|
|
</div>
|
|
</div>
|
|
|
|
<!-- What You Get -->
|
|
<div class="dev-section dev-perks">
|
|
<h2 class="dev-section-title">What You'll Get</h2>
|
|
<div class="perks-grid">
|
|
<div class="perk-item">
|
|
<strong>@@@("username")@@silverlabs.uk</strong>
|
|
<span>Your own SilverLabs email</span>
|
|
</div>
|
|
<div class="perk-item">
|
|
<strong>SilverDESK</strong>
|
|
<span>Project management & issue tracking</span>
|
|
</div>
|
|
<div class="perk-item">
|
|
<strong>Mattermost</strong>
|
|
<span>Team chat & collaboration</span>
|
|
</div>
|
|
<div class="perk-item">
|
|
<strong>Gitea Access</strong>
|
|
<span>Source code repositories</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Submit -->
|
|
<div class="dev-submit-area">
|
|
@if (!string.IsNullOrEmpty(_errorMessage))
|
|
{
|
|
<div class="dev-error">@_errorMessage</div>
|
|
}
|
|
<button type="submit" class="dev-btn dev-btn-primary" disabled="@_submitting">
|
|
@if (_submitting)
|
|
{
|
|
<span class="btn-spinner"></span>
|
|
<span>Submitting...</span>
|
|
}
|
|
else
|
|
{
|
|
<span>Submit Application</span>
|
|
}
|
|
</button>
|
|
</div>
|
|
</EditForm>
|
|
}
|
|
|
|
<a href="/" class="back-link">← Back to SilverLabs Home</a>
|
|
</div>
|
|
</div>
|
|
|
|
@code {
|
|
private DeveloperApplication _application = new() { Role = ApplicationRole.Tester };
|
|
private bool _submitting;
|
|
private bool _submitted;
|
|
private string? _resultMessage;
|
|
private string? _errorMessage;
|
|
|
|
private readonly string[] _availablePlatforms = { "Windows", "macOS", "Linux", "Android", "iOS", "Other" };
|
|
|
|
private void SelectRole(ApplicationRole role)
|
|
{
|
|
_application.Role = role;
|
|
}
|
|
|
|
private void TogglePlatform(string platform)
|
|
{
|
|
if (_application.Platforms.Contains(platform))
|
|
_application.Platforms.Remove(platform);
|
|
else
|
|
_application.Platforms.Add(platform);
|
|
}
|
|
|
|
private async Task HandleSubmit()
|
|
{
|
|
_errorMessage = null;
|
|
_submitting = true;
|
|
|
|
try
|
|
{
|
|
var (success, message) = await ApplicationService.SubmitApplicationAsync(_application);
|
|
|
|
if (success)
|
|
{
|
|
_resultMessage = message;
|
|
_submitted = true;
|
|
}
|
|
else
|
|
{
|
|
_errorMessage = message;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
_errorMessage = "An unexpected error occurred. Please try again later.";
|
|
}
|
|
finally
|
|
{
|
|
_submitting = false;
|
|
}
|
|
}
|
|
}
|