Implemented Profile

This commit is contained in:
2026-07-09 22:13:59 +02:00
parent e2800061fc
commit 029a90e69d
3 changed files with 276 additions and 2 deletions
@@ -51,7 +51,7 @@
JD
</div>
<div class="flex flex-col text-left leading-tight hidden sm:flex">
<span class="text-[12px] font-semibold text-[#1f2a3a]">Jane Doe</span>
<span class="text-[12px] font-semibold text-[#1f2a3a]">J. Mokoena</span>
<span class="text-[11px] text-[#8a96a8]">Travel Bookings Admin</span>
</div>
</a>
+270 -1
View File
@@ -1,7 +1,276 @@
@page "/profile"
@rendermode InteractiveServer
@using System
@using System.Collections.Generic
@using System.Linq
@using System.Threading.Tasks
<h3>Profile</h3>
<PageTitle>VIP Traveller Profile - J. Mokoena</PageTitle>
<div class="max-w-[1600px] mx-auto pb-8">
<!-- Page Header -->
<div class="flex flex-col sm:flex-row justify-between items-start sm:items-end mb-[22px] gap-3">
<div>
<h2 class="text-[22px] font-bold text-[#1f2a3a] tracking-tight outline-none focus:outline-none select-none" tabindex="-1">Traveller Profile</h2>
<p class="text-[13px] text-[#5a6577] mt-1">Manage corporate travel credentials, frequent flyer integrations, active visas and personal preferences</p>
</div>
<div class="flex gap-2">
<span class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-semibold bg-[#e3f6ed] text-[#22a06b]">
<span class="w-2 h-2 rounded-full bg-[#22a06b]"></span>
VIP Executive Account Verified (Grade 1)
</span>
</div>
</div>
@* Alert / Feedback Notification *@
@if (!string.IsNullOrEmpty(_alertFeedback))
{
<div class="mb-6 p-4 bg-[#effaf3] border-l-4 border-[#22a06b] rounded-r-lg text-sm text-[#1b8054] flex items-center gap-2.5 shadow-xs animate-in fade-in duration-300">
<svg class="w-5 h-5 text-[#22a06b] shrink-0" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span>@_alertFeedback</span>
</div>
}
<div class="grid grid-cols-1 lg:grid-cols-[1fr_2fr] gap-6">
<!-- Left Column: Quick Profile Card & Stats -->
<div class="space-y-6">
<!-- 1. Avatar & Corporate details -->
<div class="bg-white rounded-[10px] shadow-[0_1px_2px_rgba(15,23,42,.06)] border border-[#e4eaf2] p-6 text-center relative overflow-hidden">
<div class="absolute top-0 left-0 right-0 h-2 bg-gradient-to-r from-[#003b71] to-[#00a3a1]"></div>
<div class="w-24 h-24 rounded-full bg-gradient-to-br from-[#003b71] to-[#00a3a1] text-white flex items-center justify-center font-bold text-3xl mx-auto mb-4 border-4 border-white shadow-md">
JM
</div>
<h3 class="text-lg font-bold text-[#1f2a3a]">Jabulani Mokoena</h3>
<p class="text-xs font-semibold text-[#0066b3]">Executive Chief Director</p>
<p class="text-[11px] text-[#8a96a8] mt-1">SAQA Corporate Strategy &amp; Finance</p>
<div class="mt-4 pt-4 border-t border-[#e4eaf2] text-left space-y-2.5 text-xs">
<div class="flex justify-between">
<span class="text-[#8a96a8]">Email</span>
<span class="font-semibold text-[#1f2a3a]">j.mokoena@saqa.co.za</span>
</div>
<div class="flex justify-between">
<span class="text-[#8a96a8]">Mobile</span>
<span class="font-semibold text-[#1f2a3a]">+27 82 555 0192</span>
</div>
<div class="flex justify-between">
<span class="text-[#8a96a8]">Base Office</span>
<span class="font-semibold text-[#1f2a3a]">Pretoria (HQ)</span>
</div>
<div class="flex justify-between">
<span class="text-[#8a96a8]">Cost Centre</span>
<span class="font-semibold text-[#1f2a3a] font-mono text-[#0066b3]">CC-FIN-701</span>
</div>
</div>
<button @onclick="@(() => TriggerProfileSync())" class="w-full mt-5 px-4 py-2 border border-[#0066b3] text-[#0066b3] hover:bg-[#e2eefb] font-bold text-xs rounded-lg transition-colors cursor-pointer">
馃攧 Sync HR Profile Credentials
</button>
</div>
<!-- 2. Year-to-Date Travel Stats -->
<div class="bg-white rounded-[10px] shadow-[0_1px_2px_rgba(15,23,42,.06)] border border-[#e4eaf2] p-5 text-left">
<h3 class="text-xs font-bold text-[#1f2a3a] uppercase tracking-wider mb-3">YTD Corporate Travel Stats</h3>
<div class="grid grid-cols-2 gap-4">
<div class="p-3 bg-[#fafcfe] border border-[#e4eaf2] rounded-lg text-center">
<span class="block text-[10px] text-[#8a96a8] font-semibold uppercase">Flights</span>
<span class="text-xl font-bold text-[#1f2a3a]">14</span>
</div>
<div class="p-3 bg-[#fafcfe] border border-[#e4eaf2] rounded-lg text-center">
<span class="block text-[10px] text-[#8a96a8] font-semibold uppercase">Hotel Nights</span>
<span class="text-xl font-bold text-[#1f2a3a]">12</span>
</div>
<div class="p-3 bg-[#fafcfe] border border-[#e4eaf2] rounded-lg text-center">
<span class="block text-[10px] text-[#8a96a8] font-semibold uppercase">Carbon Footprint</span>
<span class="text-xs font-bold text-emerald-600">4.8 Tonnes</span>
</div>
<div class="p-3 bg-[#fafcfe] border border-[#e4eaf2] rounded-lg text-center">
<span class="block text-[10px] text-[#8a96a8] font-semibold uppercase">Billed to Lodge</span>
<span class="text-xs font-bold text-[#0066b3]">R 245,390</span>
</div>
</div>
</div>
</div>
<!-- Right Column: Interactive Preferences, Active Visas, loyalty Programs -->
<div class="space-y-6">
<!-- 1. Personal Travel Preferences Form -->
<div class="bg-white rounded-[10px] shadow-[0_1px_2px_rgba(15,23,42,.06)] border border-[#e4eaf2] p-6 text-left">
<div class="flex justify-between items-center mb-4">
<div>
<h3 class="text-[15px] font-bold text-[#1f2a3a]">Traveller Preferences</h3>
<p class="text-[12px] text-[#8a96a8] mt-0.5">Automated booking defaults locked into the GDS profile parser</p>
</div>
<span class="bg-[#e2eefb] text-[#0066b3] px-2.5 py-[3px] rounded-full text-[11px] font-semibold">Active</span>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 text-xs">
<div>
<label class="block text-[10px] font-bold uppercase text-[#8a96a8] mb-1">Default Flight Seating</label>
<select @bind="_seatPreference" class="w-full px-3 py-2 border border-[#c8d3e1] rounded-lg bg-white text-[#1f2a3a] outline-none focus:border-[#0066b3]">
<option value="Window">Window Seat (First choice)</option>
<option value="Aisle">Aisle Seat</option>
<option value="Exit Row">Extra Legroom / Exit Row</option>
</select>
</div>
<div>
<label class="block text-[10px] font-bold uppercase text-[#8a96a8] mb-1">Dietary Requirement</label>
<select @bind="_dietaryPreference" class="w-full px-3 py-2 border border-[#c8d3e1] rounded-lg bg-white text-[#1f2a3a] outline-none focus:border-[#0066b3]">
<option value="Standard">Standard Meal</option>
<option value="Vegetarian">Hindu Vegetarian (AVML)</option>
<option value="Halal">Halal (MOML)</option>
<option value="Kosher">Kosher (KSML)</option>
</select>
</div>
<div>
<label class="block text-[10px] font-bold uppercase text-[#8a96a8] mb-1">Hotel Bed Type Preference</label>
<select @bind="_bedPreference" class="w-full px-3 py-2 border border-[#c8d3e1] rounded-lg bg-white text-[#1f2a3a] outline-none focus:border-[#0066b3]">
<option value="King">King size bed</option>
<option value="Twin">Two double beds (Twin)</option>
</select>
</div>
<div>
<label class="block text-[10px] font-bold uppercase text-[#8a96a8] mb-1">Default Car Group</label>
<select @bind="_carPreference" class="w-full px-3 py-2 border border-[#c8d3e1] rounded-lg bg-white text-[#1f2a3a] outline-none focus:border-[#0066b3]">
<option value="SUV">Group D - Midsize SUV</option>
<option value="Sedan">Group C - Fullsize Sedan</option>
<option value="Luxury">Group G - Elite / Luxury</option>
</select>
</div>
</div>
<div class="mt-4 pt-4 border-t border-[#e4eaf2] flex justify-end">
<button @onclick="@(() => SavePreferences())" class="px-4 py-2 bg-[#0066b3] text-white font-bold text-xs rounded-lg hover:bg-[#003b71] cursor-pointer shadow-xs">
Save Preferences
</button>
</div>
</div>
<!-- 2. Active Passport & Visas -->
<div class="bg-white rounded-[10px] shadow-[0_1px_2px_rgba(15,23,42,.06)] border border-[#e4eaf2] p-6 text-left">
<div class="flex justify-between items-center mb-4">
<div>
<h3 class="text-[15px] font-bold text-[#1f2a3a]">Passport &amp; Active Visas</h3>
<p class="text-[12px] text-[#8a96a8] mt-0.5">Scanned credentials checked against immigration guidelines during visa-booking workflow</p>
</div>
<span class="text-xs text-[#0066b3] font-bold flex items-center gap-1">
馃攽 Encypted Vault
</span>
</div>
<div class="space-y-3">
<!-- Passport -->
<div class="p-3.5 border border-[#e4eaf2] rounded-lg bg-gradient-to-r from-white to-[#fafcfe] flex justify-between items-center text-xs">
<div>
<span class="block font-bold text-[#1f2a3a]">South African Passport</span>
<span class="text-[11px] font-mono text-[#8a96a8]">Doc No: AA9923812 路 Expires: 12 Jan 2031</span>
</div>
<span class="text-[10px] font-bold text-[#22a06b] bg-[#e3f6ed] px-2 py-0.5 rounded">Primary</span>
</div>
<!-- Visa 1 -->
<div class="p-3.5 border border-[#e4eaf2] rounded-lg bg-gradient-to-r from-white to-[#fafcfe] flex justify-between items-center text-xs">
<div>
<span class="block font-bold text-[#1f2a3a]">United Kingdom Standard Visitor Visa</span>
<span class="text-[11px] font-mono text-[#8a96a8]">Ref: UKV-882190B 路 Multi-Entry 路 Expires: 05 Jun 2028</span>
</div>
<span class="text-[10px] font-bold text-[#22a06b] bg-[#e3f6ed] px-2 py-0.5 rounded">Valid</span>
</div>
<!-- Visa 2 -->
<div class="p-3.5 border border-[#e4eaf2] rounded-lg bg-gradient-to-r from-white to-[#fafcfe] flex justify-between items-center text-xs">
<div>
<span class="block font-bold text-[#1f2a3a]">United States Business Visa (B1/B2)</span>
<span class="text-[11px] font-mono text-[#8a96a8]">Ref: USV-0992381 路 10-Year Multi 路 Expires: 19 Oct 2031</span>
</div>
<span class="text-[10px] font-bold text-[#22a06b] bg-[#e3f6ed] px-2 py-0.5 rounded">Valid</span>
</div>
</div>
</div>
<!-- 3. Frequent Flyer & Loyalty Programs -->
<div class="bg-white rounded-[10px] shadow-[0_1px_2px_rgba(15,23,42,.06)] border border-[#e4eaf2] p-6 text-left">
<div class="flex justify-between items-center mb-4">
<div>
<h3 class="text-[15px] font-bold text-[#1f2a3a]">Frequent Flyer Integrations</h3>
<p class="text-[12px] text-[#8a96a8] mt-0.5">Direct GDS link to auto-claim points on personal frequent flyer portfolios</p>
</div>
<button @onclick="@(() => LinkNewProgram())" class="px-2.5 py-1 bg-white border border-[#e4eaf2] text-[11px] text-[#5a6577] hover:text-[#1f2a3a] font-semibold rounded-lg transition-colors cursor-pointer">
+ Add Program
</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-3">
@foreach (var program in _loyaltyPrograms)
{
<div class="p-3.5 border border-[#e4eaf2] rounded-lg bg-[#f4f7fb] text-left">
<span class="block text-[10px] text-[#8a96a8] font-bold uppercase">@program.Airline</span>
<span class="block text-xs font-bold text-[#1f2a3a] mt-1 truncate">@program.Level Tier</span>
<span class="block text-[10px] font-mono text-[#5a6577] mt-0.5">No: @program.Number</span>
</div>
}
</div>
</div>
</div>
</div>
</div>
@code {
private string _alertFeedback = string.Empty;
// Traveller Preference Bindings
private string _seatPreference = "Window";
private string _dietaryPreference = "Vegetarian";
private string _bedPreference = "King";
private string _carPreference = "SUV";
// Loyalty Program Class
public class LoyaltyProgram
{
public string Airline { get; set; } = string.Empty;
public string Level { get; set; } = string.Empty;
public string Number { get; set; } = string.Empty;
}
private List<LoyaltyProgram> _loyaltyPrograms = new()
{
new() { Airline = "South African Airways", Level = "SAA Voyager Gold", Number = "VS-992381" },
new() { Airline = "British Airways", Level = "Executive Club Silver", Number = "BA-882019" },
new() { Airline = "Emirates Airlines", Level = "Skywards Silver", Number = "EK-110294" }
};
private void TriggerProfileSync()
{
_alertFeedback = "Securing OAuth handshake... Traveller biographical credentials, frequent flyer balances and visa records successfully synchronized with the central SAQA HR Portal!";
StateHasChanged();
}
private void SavePreferences()
{
_alertFeedback = $"Traveller preferences successfully updated in the GDS master profile! Future bookings will lock in seating: {_seatPreference}, dietary: {_dietaryPreference}, room: {_bedPreference} bed, and car preference.";
StateHasChanged();
}
private void LinkNewProgram()
{
_loyaltyPrograms.Add(new LoyaltyProgram
{
Airline = "Qatar Airways",
Level = "Privilege Club Gold",
Number = "QR-" + new Random().Next(100000, 999999)
});
_alertFeedback = "New frequent flyer integration added successfully!";
StateHasChanged();
}
}
+5
View File
@@ -3018,6 +3018,11 @@
grid-template-columns: 1fr 1fr 1fr 1fr auto;
}
}
.lg\:grid-cols-\[1fr_2fr\] {
@media (width >= 64rem) {
grid-template-columns: 1fr 2fr;
}
}
.lg\:grid-cols-\[2fr_1fr\] {
@media (width >= 64rem) {
grid-template-columns: 2fr 1fr;