Implemented settings

This commit is contained in:
2026-07-09 21:51:11 +02:00
parent 53c3bb2aff
commit e2800061fc
2 changed files with 361 additions and 1 deletions
+347 -1
View File
@@ -1,7 +1,353 @@
@page "/settings"
@rendermode InteractiveServer
@using System
@using System.Collections.Generic
@using System.Linq
@using System.Threading.Tasks
<h3>Settings</h3>
<PageTitle>Enterprise Suite Settings</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">Corporate Suite Settings</h2>
<p class="text-[13px] text-[#5a6577] mt-1">Configure global travel policies, Lodge Card reconciliation parameters, and GDS sync configurations</p>
</div>
<div class="flex gap-2">
<button @onclick="@(() => SaveAllSettings())" class="flex items-center gap-1.5 px-[16px] py-2 bg-[#0066b3] text-white rounded-lg text-[13px] font-semibold hover:bg-[#003b71] transition-all cursor-pointer shadow-xs">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-4 h-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
Save All Changes
</button>
</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>
}
<!-- Tab Navigation -->
<div class="flex border-b border-[#e4eaf2] mb-6 gap-2">
<button @onclick="@(() => _activeTab = "policy")" class="px-4 py-2 text-[13px] font-semibold border-b-2 transition-all cursor-pointer @(_activeTab == "policy" ? "border-[#0066b3] text-[#0066b3]" : "border-transparent text-[#5a6577] hover:text-[#1f2a3a]")">
Travel Policies
</button>
<button @onclick="@(() => _activeTab = "financial")" class="px-4 py-2 text-[13px] font-semibold border-b-2 transition-all cursor-pointer @(_activeTab == "financial" ? "border-[#0066b3] text-[#0066b3]" : "border-transparent text-[#5a6577] hover:text-[#1f2a3a]")">
Financial & Lodge Card
</button>
<button @onclick="@(() => _activeTab = "gds")" class="px-4 py-2 text-[13px] font-semibold border-b-2 transition-all cursor-pointer @(_activeTab == "gds" ? "border-[#0066b3] text-[#0066b3]" : "border-transparent text-[#5a6577] hover:text-[#1f2a3a]")">
GDS & API Sync
</button>
<button @onclick="@(() => _activeTab = "safety")" class="px-4 py-2 text-[13px] font-semibold border-b-2 transition-all cursor-pointer @(_activeTab == "safety" ? "border-[#0066b3] text-[#0066b3]" : "border-transparent text-[#5a6577] hover:text-[#1f2a3a]")">
Duty of Care & Security
</button>
</div>
<div class="grid grid-cols-1 lg:grid-cols-[2fr_1fr] gap-6">
<!-- Left Column: Settings Pane -->
<div class="bg-white rounded-[10px] shadow-[0_1px_2px_rgba(15,23,42,.06)] border border-[#e4eaf2] p-6 text-left">
@if (_activeTab == "policy")
{
<div class="space-y-6">
<div>
<h3 class="text-base font-bold text-[#1f2a3a]">Corporate Travel Policies</h3>
<p class="text-xs text-[#8a96a8] mt-0.5">Control grade limits, pre-approval workflows, and travel guidelines.</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-[11px] font-bold uppercase text-[#8a96a8] mb-1.5">Max Domestic Hotel Rate (Per Night - ZAR)</label>
<input type="number" @bind="_maxHotelRateDom" class="w-full px-3 py-2 border border-[#c8d3e1] rounded-lg text-xs bg-white text-[#1f2a3a] outline-none focus:border-[#0066b3]" />
<span class="text-[10px] text-[#8a96a8] mt-1 block">Rates exceeding this trigger manager audit warnings.</span>
</div>
<div>
<label class="block text-[11px] font-bold uppercase text-[#8a96a8] mb-1.5">Max International Hotel Rate (Per Night - ZAR)</label>
<input type="number" @bind="_maxHotelRateInt" class="w-full px-3 py-2 border border-[#c8d3e1] rounded-lg text-xs bg-white text-[#1f2a3a] outline-none focus:border-[#0066b3]" />
</div>
</div>
<div class="border-t border-[#e4eaf2] pt-4">
<label class="block text-[11px] font-bold uppercase text-[#8a96a8] mb-2">Flight Cabin Allowance By Corporate Grade</label>
<div class="space-y-3">
<div class="flex items-center justify-between p-2.5 bg-[#f4f7fb] rounded-lg text-xs">
<span class="font-bold text-[#1f2a3a]">Executive (Grade 1-2)</span>
<select @bind="_cabinExec" class="px-2.5 py-1 border border-[#c8d3e1] rounded bg-white text-xs text-[#1f2a3a] outline-none">
<option value="First">First Class</option>
<option value="Business">Business Class</option>
<option value="Premium Economy">Premium Economy</option>
<option value="Economy">Economy</option>
</select>
</div>
<div class="flex items-center justify-between p-2.5 bg-[#f4f7fb] rounded-lg text-xs">
<span class="font-bold text-[#1f2a3a]">Director & Senior Manager (Grade 3-4)</span>
<select @bind="_cabinDirector" class="px-2.5 py-1 border border-[#c8d3e1] rounded bg-white text-xs text-[#1f2a3a] outline-none">
<option value="First">First Class</option>
<option value="Business">Business Class</option>
<option value="Premium Economy">Premium Economy</option>
<option value="Economy">Economy</option>
</select>
</div>
<div class="flex items-center justify-between p-2.5 bg-[#f4f7fb] rounded-lg text-xs">
<span class="font-bold text-[#1f2a3a]">Standard Operational Staff (Grade 5-8)</span>
<select @bind="_cabinStaff" class="px-2.5 py-1 border border-[#c8d3e1] rounded bg-white text-xs text-[#1f2a3a] outline-none">
<option value="First">First Class</option>
<option value="Business">Business Class</option>
<option value="Premium Economy">Premium Economy</option>
<option value="Economy">Economy</option>
</select>
</div>
</div>
</div>
<div class="border-t border-[#e4eaf2] pt-4 space-y-3">
<h4 class="text-xs font-bold text-[#1f2a3a] uppercase">Workflow Pre-Approvals</h4>
<div class="flex items-center justify-between p-1">
<div>
<span class="block text-xs font-semibold text-[#1f2a3a]">Auto-approve compliant bookings</span>
<span class="block text-[11px] text-[#8a96a8]">Domestic bookings within price limit bypass manual manager check.</span>
</div>
<input type="checkbox" @bind="_autoApproveCompliant" class="w-4 h-4 text-[#0066b3] rounded accent-[#0066b3]" />
</div>
<div class="flex items-center justify-between p-1">
<div>
<span class="block text-xs font-semibold text-[#1f2a3a]">Mandate travel reasons</span>
<span class="block text-[11px] text-[#8a96a8]">Force travellers to write business motivations for each reservation.</span>
</div>
<input type="checkbox" @bind="_forceMotivations" class="w-4 h-4 text-[#0066b3] rounded accent-[#0066b3]" />
</div>
</div>
</div>
}
else if (_activeTab == "financial")
{
<div class="space-y-6">
<div>
<h3 class="text-base font-bold text-[#1f2a3a]">Corporate Lodge Card & Financial Rules</h3>
<p class="text-xs text-[#8a96a8] mt-0.5">Manage virtual cards, merchant limits, and global Lodge Card billing.</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-[11px] font-bold uppercase text-[#8a96a8] mb-1.5">Master Lodge Card Account Number</label>
<input type="text" @bind="_lodgeCardNumber" class="w-full px-3 py-2 border border-[#c8d3e1] rounded-lg text-xs bg-white text-[#1f2a3a] font-mono outline-none focus:border-[#0066b3]" />
</div>
<div>
<label class="block text-[11px] font-bold uppercase text-[#8a96a8] mb-1.5">Monthly Credit Authorization Limit (ZAR)</label>
<input type="number" @bind="_lodgeCardLimit" class="w-full px-3 py-2 border border-[#c8d3e1] rounded-lg text-xs bg-white text-[#1f2a3a] font-mono outline-none focus:border-[#0066b3]" />
</div>
</div>
<div class="border-t border-[#e4eaf2] pt-4">
<label class="block text-[11px] font-bold uppercase text-[#8a96a8] mb-2">Merchant Category Code (MCC) Restrictions</label>
<p class="text-[11px] text-[#8a96a8] mb-3">Check categories the Lodge Card and single-use Virtual Cards are authorized to clear.</p>
<div class="grid grid-cols-2 gap-2.5">
<label class="flex items-center gap-2 text-xs text-[#1f2a3a]">
<input type="checkbox" @bind="_mccAirlines" class="w-4 h-4 text-[#0066b3] rounded accent-[#0066b3]" />
MCC 4511: Airlines / Flights
</label>
<label class="flex items-center gap-2 text-xs text-[#1f2a3a]">
<input type="checkbox" @bind="_mccHotels" class="w-4 h-4 text-[#0066b3] rounded accent-[#0066b3]" />
MCC 7011: Hotels &amp; Motels
</label>
<label class="flex items-center gap-2 text-xs text-[#1f2a3a]">
<input type="checkbox" @bind="_mccCarRental" class="w-4 h-4 text-[#0066b3] rounded accent-[#0066b3]" />
MCC 7512: Automobile Rentals
</label>
<label class="flex items-center gap-2 text-xs text-[#1f2a3a]">
<input type="checkbox" @bind="_mccRailroads" class="w-4 h-4 text-[#0066b3] rounded accent-[#0066b3]" />
MCC 4112: Passenger Railways
</label>
</div>
</div>
<div class="border-t border-[#e4eaf2] pt-4">
<label class="block text-[11px] font-bold uppercase text-[#8a96a8] mb-1.5">Automatic Audit Trigger Amount (ZAR)</label>
<input type="number" @bind="_auditTriggerAmount" class="w-full px-3 py-2 border border-[#c8d3e1] rounded-lg text-xs bg-white text-[#1f2a3a] outline-none focus:border-[#0066b3]" />
<p class="text-[10px] text-[#8a96a8] mt-1">Any single travel service booking exceeding this triggers a strict secondary audit trail.</p>
</div>
</div>
}
else if (_activeTab == "gds")
{
<div class="space-y-6">
<div>
<h3 class="text-base font-bold text-[#1f2a3a]">GDS Sync Network &amp; API Configuration</h3>
<p class="text-xs text-[#8a96a8] mt-0.5">Control connections to Sabre, Amadeus, Travelport, and internal databases.</p>
</div>
<div class="space-y-4">
<div>
<label class="block text-[11px] font-bold uppercase text-[#8a96a8] mb-1.5">Primary GDS Partner Feed</label>
<select @bind="_primaryGds" class="w-full px-3 py-2 border border-[#c8d3e1] rounded-lg text-xs bg-white text-[#1f2a3a] outline-none focus:border-[#0066b3]">
<option value="Sabre">Sabre Global Distribution System</option>
<option value="Amadeus">Amadeus Altea Web Services</option>
<option value="Travelport">Travelport Galileo API</option>
<option value="Custom">Custom Enterprise Middleware</option>
</select>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-[11px] font-bold uppercase text-[#8a96a8] mb-1.5">Sabre Client ID / Key</label>
<input type="password" @bind="_gdsClientId" class="w-full px-3 py-2 border border-[#c8d3e1] rounded-lg text-xs bg-white text-[#1f2a3a] outline-none focus:border-[#0066b3]" />
</div>
<div>
<label class="block text-[11px] font-bold uppercase text-[#8a96a8] mb-1.5">Sync Interval (Minutes)</label>
<input type="number" @bind="_syncInterval" class="w-full px-3 py-2 border border-[#c8d3e1] rounded-lg text-xs bg-white text-[#1f2a3a] outline-none focus:border-[#0066b3]" />
</div>
</div>
<div class="p-4 bg-[#e2eefb] text-[#0066b3] border border-blue-100 rounded-lg text-xs space-y-1.5">
<h4 class="font-bold flex items-center gap-1">
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M13 10V3L4 14h7v7l9-11h-7z" /></svg>
Enterprise NDC Optimization Active
</h4>
<p class="leading-relaxed">New Distribution Capability (NDC) routes are prioritized to grab negotiated private corporate fares directly bypassing standard GDS markup.</p>
</div>
</div>
</div>
}
else if (_activeTab == "safety")
{
<div class="space-y-6">
<div>
<h3 class="text-base font-bold text-[#1f2a3a]">Duty of Care &amp; Crisis Response Settings</h3>
<p class="text-xs text-[#8a96a8] mt-0.5">Control GPS tracking rules, automatic alert response and emergency contacts.</p>
</div>
<div class="space-y-4 text-xs">
<div class="flex items-center justify-between p-1">
<div>
<span class="block text-xs font-semibold text-[#1f2a3a]">Real-time mobile tracking</span>
<span class="block text-[11px] text-[#8a96a8]">Ping location coordinates from traveller devices during international transits.</span>
</div>
<input type="checkbox" @bind="_enableGpsTracking" class="w-4 h-4 text-[#0066b3] rounded accent-[#0066b3]" />
</div>
<div class="flex items-center justify-between p-1">
<div>
<span class="block text-xs font-semibold text-[#1f2a3a]">Automatic SOS consultant dispatch</span>
<span class="block text-[11px] text-[#8a96a8]">Instantly dial and loop in standby crisis response agencies on SOS beacon trigger.</span>
</div>
<input type="checkbox" @bind="_enableConsultantSosDispatch" class="w-4 h-4 text-[#0066b3] rounded accent-[#0066b3]" />
</div>
<div class="border-t border-[#e4eaf2] pt-4">
<label class="block text-[11px] font-bold uppercase text-[#8a96a8] mb-1.5">Primary Emergency Crisis Center Number</label>
<input type="text" @bind="_emergencyPhone" class="w-full px-3 py-2 border border-[#c8d3e1] rounded-lg text-xs bg-white text-[#1f2a3a] font-mono outline-none focus:border-[#0066b3]" />
</div>
<div class="border-t border-[#e4eaf2] pt-4">
<label class="block text-[11px] font-bold uppercase text-[#8a96a8] mb-1.5">Global Evacuation Partner Agency</label>
<select @bind="_evacuationPartner" class="w-full px-3 py-2 border border-[#c8d3e1] rounded-lg bg-white text-[#1f2a3a] outline-none focus:border-[#0066b3]">
<option value="International SOS">International SOS Control Center</option>
<option value="Crisis24">Crisis24 Global Security Services</option>
<option value="Medex">Medex International Evacuation</option>
</select>
</div>
</div>
</div>
}
</div>
<!-- Right Column: Settings Summary Dashboard -->
<div class="space-y-6">
<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-[15px] font-bold text-[#1f2a3a] mb-3">Suite Policy Audit</h3>
<p class="text-xs text-[#5a6577] mb-4">A high-level summary of active rules and financial checks running on this deployment.</p>
<div class="space-y-3.5">
<div class="p-3 bg-[#fafcfe] border border-[#e4eaf2] rounded-lg flex justify-between items-center text-xs">
<div>
<span class="block font-bold text-[#1f2a3a]">Hotel Rate Caps</span>
<span class="text-[11px] text-[#8a96a8]">R @_maxHotelRateDom/night dom · R @_maxHotelRateInt/night int</span>
</div>
<span class="bg-[#e2eefb] text-[#0066b3] px-2 py-0.5 rounded text-[10px] font-bold">Active</span>
</div>
<div class="p-3 bg-[#fafcfe] border border-[#e4eaf2] rounded-lg flex justify-between items-center text-xs">
<div>
<span class="block font-bold text-[#1f2a3a]">Approved Air Cabins</span>
<span class="text-[11px] text-[#8a96a8]">Exec: @_cabinExec · Staff: @_cabinStaff</span>
</div>
<span class="bg-[#e3f6ed] text-[#22a06b] px-2 py-0.5 rounded text-[10px] font-bold">Active</span>
</div>
<div class="p-3 bg-[#fafcfe] border border-[#e4eaf2] rounded-lg flex justify-between items-center text-xs">
<div>
<span class="block font-bold text-[#1f2a3a]">Lodge Card Limit</span>
<span class="text-[11px] text-[#8a96a8]">R @_lodgeCardLimit.ToString("N0") monthly</span>
</div>
<span class="bg-[#e3f6ed] text-[#22a06b] px-2 py-0.5 rounded text-[10px] font-bold">Active</span>
</div>
<div class="p-3 bg-[#fafcfe] border border-[#e4eaf2] rounded-lg flex justify-between items-center text-xs">
<div>
<span class="block font-bold text-[#1f2a3a]">Pre-Approvals</span>
<span class="text-[11px] text-[#8a96a8]">@(_autoApproveCompliant ? "Bypass manual checks" : "All bookings manual")</span>
</div>
<span class="bg-[#fff4dd] text-[#b06b00] px-2 py-0.5 rounded text-[10px] font-bold">Configured</span>
</div>
<div class="p-3 bg-[#fafcfe] border border-[#e4eaf2] rounded-lg flex justify-between items-center text-xs">
<div>
<span class="block font-bold text-[#1f2a3a]">Duty of Care Partner</span>
<span class="text-[11px] text-[#8a96a8]">@_evacuationPartner</span>
</div>
<span class="bg-indigo-50 text-indigo-700 px-2 py-0.5 rounded text-[10px] font-bold">Linked</span>
</div>
</div>
</div>
</div>
</div>
</div>
@code {
private string _activeTab = "policy";
private string _alertFeedback = string.Empty;
// Travel Policy bindings
private int _maxHotelRateDom = 2500;
private int _maxHotelRateInt = 5500;
private string _cabinExec = "Business";
private string _cabinDirector = "Premium Economy";
private string _cabinStaff = "Economy";
private bool _autoApproveCompliant = true;
private bool _forceMotivations = false;
// Financial bindings
private string _lodgeCardNumber = "4002 8332 9110 5410";
private double _lodgeCardLimit = 1500000;
private bool _mccAirlines = true;
private bool _mccHotels = true;
private bool _mccCarRental = true;
private bool _mccRailroads = false;
private int _auditTriggerAmount = 25000;
// GDS bindings
private string _primaryGds = "Sabre";
private string _gdsClientId = "SABRE-ENT-99238-PROD";
private int _syncInterval = 15;
// Safety bindings
private bool _enableGpsTracking = true;
private bool _enableConsultantSosDispatch = true;
private string _emergencyPhone = "+27 11 911 2000";
private string _evacuationPartner = "International SOS";
private void SaveAllSettings()
{
_alertFeedback = "Corporate travel configurations successfully updated! Global GDS policies re-audited and synced across all enterprise endpoints.";
StateHasChanged();
}
}
+14
View File
@@ -46,6 +46,8 @@
--color-blue-700: oklch(48.8% 0.243 264.376);
--color-blue-800: oklch(42.4% 0.199 265.638);
--color-blue-950: oklch(28.2% 0.091 267.935);
--color-indigo-50: oklch(96.2% 0.018 272.314);
--color-indigo-700: oklch(45.7% 0.24 277.023);
--color-slate-50: oklch(98.4% 0.003 247.858);
--color-slate-100: oklch(96.8% 0.007 247.896);
--color-slate-200: oklch(92.9% 0.013 255.508);
@@ -1362,6 +1364,9 @@
.bg-green-600 {
background-color: var(--color-green-600);
}
.bg-indigo-50 {
background-color: var(--color-indigo-50);
}
.bg-red-50 {
background-color: var(--color-red-50);
}
@@ -1567,6 +1572,9 @@
.px-\[14px\] {
padding-inline: 14px;
}
.px-\[16px\] {
padding-inline: 16px;
}
.px-\[18px\] {
padding-inline: 18px;
}
@@ -1999,6 +2007,9 @@
.text-green-700 {
color: var(--color-green-700);
}
.text-indigo-700 {
color: var(--color-indigo-700);
}
.text-red-400 {
color: var(--color-red-400);
}
@@ -2054,6 +2065,9 @@
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.accent-\[\#0066b3\] {
accent-color: #0066b3;
}
.opacity-0 {
opacity: 0%;
}