initial commit
This commit is contained in:
@@ -0,0 +1,285 @@
|
||||
@using Indotalent.ConfigBackEnd.Extensions
|
||||
@using Indotalent.Features.Organization.Employee
|
||||
@using Indotalent.Features.Organization.Employee.Cqrs
|
||||
@using Indotalent.Shared.Utils
|
||||
@using MudBlazor
|
||||
@implements IDisposable
|
||||
@inject EmployeeService EmployeeService
|
||||
@inject ISnackbar Snackbar
|
||||
|
||||
<style>
|
||||
.field-label { font-size: 13px; font-weight: 700; color: #424242; margin-bottom: 4px; display: block; }
|
||||
.section-header { font-weight: 800; color: #0D47A1; letter-spacing: 0.5px; margin-bottom: 8px; }
|
||||
</style>
|
||||
|
||||
<MudPaper Elevation="0" Square="true" Class="pa-6 mb-3 d-flex align-center justify-space-between" Style="border: 1px solid #DCEBFA;">
|
||||
<div class="d-flex align-center gap-4">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.ArrowBack" OnClick="() => OnCancel.InvokeAsync()" />
|
||||
<div>
|
||||
<MudText Typo="Typo.h5" Style="font-weight: 900; color: #1a1a1a;">@(ReadOnly ? "Employee Profile" : "Edit Employee")</MudText>
|
||||
<MudText Typo="Typo.body2" Style="color: #64748b;">Managing records for @_model.FirstName @_model.LastName</MudText>
|
||||
</div>
|
||||
</div>
|
||||
</MudPaper>
|
||||
|
||||
<MudPaper Elevation="0" Outlined="true" Class="pa-8" Style="border-radius: 0px; border: 1px solid #DCEBFA;">
|
||||
@if (_isLoadingData)
|
||||
{
|
||||
<div class="d-flex flex-column align-center pa-10">
|
||||
<MudProgressCircular Color="Color.Primary" Indeterminate="true" />
|
||||
<MudText Class="mt-4">Synchronizing Records...</MudText>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudForm @ref="_form" Model="_model">
|
||||
<MudStack Spacing="6">
|
||||
|
||||
<MudGrid Spacing="3">
|
||||
<MudItem xs="12"><div class="section-header">BASIC IDENTITY</div><MudDivider /></MudItem>
|
||||
<MudItem xs="6">
|
||||
<label class="field-label">Employee Code</label>
|
||||
<MudTextField @bind-Value="_model.Code" For="@(() => _model.Code)" Validation="@(_validator.ValidateValue())" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
<MudItem xs="6">
|
||||
<label class="field-label">Salary Grade</label>
|
||||
<MudSelect @bind-Value="_model.GradeId"
|
||||
For="@(() => _model.GradeId)"
|
||||
Validation="@(_validator.ValidateValue())"
|
||||
ReadOnly="ReadOnly"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense"
|
||||
Dense="true">
|
||||
@foreach (var item in _lookupData.Grades)
|
||||
{
|
||||
<MudSelectItem Value="@item.Id">
|
||||
<div class="d-flex justify-space-between w-100 gap-4">
|
||||
<MudText Typo="Typo.body2"><b>@item.Name</b> (@item.Code)</MudText>
|
||||
<MudText Typo="Typo.caption" Style="color: #64748b;">
|
||||
Range: @item.SalaryFrom.ToString("N0") - @item.SalaryTo.ToString("N0")
|
||||
</MudText>
|
||||
</div>
|
||||
</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudItem>
|
||||
<MudItem xs="4">
|
||||
<label class="field-label">First Name</label>
|
||||
<MudTextField @bind-Value="_model.FirstName" For="@(() => _model.FirstName)" Validation="@(_validator.ValidateValue())" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
<MudItem xs="4">
|
||||
<label class="field-label">Middle Name</label>
|
||||
<MudTextField @bind-Value="_model.MiddleName" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
<MudItem xs="4">
|
||||
<label class="field-label">Last Name</label>
|
||||
<MudTextField @bind-Value="_model.LastName" For="@(() => _model.LastName)" Validation="@(_validator.ValidateValue())" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<MudGrid Spacing="3">
|
||||
<MudItem xs="12" Class="mt-2"><div class="section-header">PAYROLL & BANKING</div><MudDivider /></MudItem>
|
||||
<MudItem xs="6">
|
||||
<label class="field-label">Basic Salary (Monthly)</label>
|
||||
<MudNumericField @bind-Value="_model.BasicSalary"
|
||||
For="@(() => _model.BasicSalary)"
|
||||
Validation="@(_validator.ValidateValue())"
|
||||
ReadOnly="ReadOnly"
|
||||
HideSpinButtons="false"
|
||||
Step="1"
|
||||
Min="0"
|
||||
Format="N0"
|
||||
Adornment="Adornment.Start"
|
||||
AdornmentIcon="@Icons.Material.Filled.Payments"
|
||||
AdornmentColor="Color.Success"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense" />
|
||||
|
||||
@if (!string.IsNullOrEmpty(_model.GradeId))
|
||||
{
|
||||
var selectedGrade = _lookupData.Grades.FirstOrDefault(x => x.Id == _model.GradeId);
|
||||
if (selectedGrade != null)
|
||||
{
|
||||
<MudText Typo="Typo.caption" Color="Color.Info" Class="mt-1">
|
||||
Allowed range: <b>@selectedGrade.SalaryFrom.ToString("N0")</b> - <b>@selectedGrade.SalaryTo.ToString("N0")</b>
|
||||
</MudText>
|
||||
}
|
||||
}
|
||||
</MudItem>
|
||||
<MudItem xs="6">
|
||||
<label class="field-label">Salary Bank Name</label>
|
||||
<MudTextField @bind-Value="_model.SalaryBankName" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
<MudItem xs="6">
|
||||
<label class="field-label">Bank Account Name</label>
|
||||
<MudTextField @bind-Value="_model.SalaryBankAccountName" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
<MudItem xs="6">
|
||||
<label class="field-label">Bank Account Number</label>
|
||||
<MudTextField @bind-Value="_model.SalaryBankAccountNumber" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<MudGrid Spacing="3">
|
||||
<MudItem xs="12" Class="mt-2"><div class="section-header">PERSONAL DETAILS</div><MudDivider /></MudItem>
|
||||
<MudItem xs="6"><label class="field-label">Place of Birth</label><MudTextField @bind-Value="_model.PlaceOfBirth" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="6"><label class="field-label">Date of Birth</label><MudDatePicker @bind-Date="_model.DateOfBirth" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="4">
|
||||
<label class="field-label">Gender</label>
|
||||
<MudSelect @bind-Value="_model.Gender" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" Dense="true">
|
||||
<MudSelectItem Value="@("Male")">Male</MudSelectItem>
|
||||
<MudSelectItem Value="@("Female")">Female</MudSelectItem>
|
||||
</MudSelect>
|
||||
</MudItem>
|
||||
<MudItem xs="4"><label class="field-label">Marital Status</label><MudTextField @bind-Value="_model.MaritalStatus" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="4"><label class="field-label">Religion</label><MudTextField @bind-Value="_model.Religion" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="4"><label class="field-label">Identity Number (KTP)</label><MudTextField @bind-Value="_model.IdentityNumber" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="4"><label class="field-label">Tax Number (NPWP)</label><MudTextField @bind-Value="_model.TaxNumber" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="4"><label class="field-label">Blood Type</label><MudTextField @bind-Value="_model.BloodType" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="12"><label class="field-label">Last Education</label><MudTextField @bind-Value="_model.LastEducation" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<MudGrid Spacing="3">
|
||||
<MudItem xs="12" Class="mt-2"><div class="section-header">ORGANIZATIONAL</div><MudDivider /></MudItem>
|
||||
<MudItem xs="4">
|
||||
<label class="field-label">Branch</label>
|
||||
<MudSelect @bind-Value="_model.BranchId" For="@(() => _model.BranchId)" Validation="@(_validator.ValidateValue())" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" Dense="true">
|
||||
@foreach (var item in _lookupData.Branches) { <MudSelectItem Value="@item.Id">@item.Name</MudSelectItem> }
|
||||
</MudSelect>
|
||||
</MudItem>
|
||||
<MudItem xs="4">
|
||||
<label class="field-label">Department</label>
|
||||
<MudSelect @bind-Value="_model.DepartmentId" For="@(() => _model.DepartmentId)" Validation="@(_validator.ValidateValue())" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" Dense="true">
|
||||
@foreach (var item in _lookupData.Departments) { <MudSelectItem Value="@item.Id">@item.Name</MudSelectItem> }
|
||||
</MudSelect>
|
||||
</MudItem>
|
||||
<MudItem xs="4">
|
||||
<label class="field-label">Designation</label>
|
||||
<MudSelect @bind-Value="_model.DesignationId" For="@(() => _model.DesignationId)" Validation="@(_validator.ValidateValue())" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" Dense="true">
|
||||
@foreach (var item in _lookupData.Designations) { <MudSelectItem Value="@item.Id">@item.Name</MudSelectItem> }
|
||||
</MudSelect>
|
||||
</MudItem>
|
||||
<MudItem xs="4"><label class="field-label">Joined Date</label><MudDatePicker @bind-Date="_model.JoinedDate" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="4"><label class="field-label">Resigned Date</label><MudDatePicker @bind-Date="_model.ResignedDate" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="4"><label class="field-label">Employee Status</label><MudTextField @bind-Value="_model.EmployeeStatus" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="6"><label class="field-label">Employment Type</label><MudTextField @bind-Value="_model.EmploymentType" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="12"><label class="field-label">Job Description</label><MudTextField @bind-Value="_model.JobDescription" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" Lines="2" /></MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<MudGrid Spacing="3">
|
||||
<MudItem xs="12" Class="mt-2"><div class="section-header">ADDRESS & CONTACT</div><MudDivider /></MudItem>
|
||||
<MudItem xs="6">
|
||||
<label class="field-label">Email</label>
|
||||
<MudTextField @bind-Value="_model.Email" For="@(() => _model.Email)" Validation="@(_validator.ValidateValue())" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
<MudItem xs="6"><label class="field-label">Phone</label><MudTextField @bind-Value="_model.Phone" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="12"><label class="field-label">Street Address</label><MudTextField @bind-Value="_model.StreetAddress" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="4"><label class="field-label">City</label><MudTextField @bind-Value="_model.City" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="4"><label class="field-label">Province</label><MudTextField @bind-Value="_model.StateProvince" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="4"><label class="field-label">Zip Code</label><MudTextField @bind-Value="_model.ZipCode" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<MudGrid Spacing="3">
|
||||
<MudItem xs="12" Class="mt-2"><div class="section-header">SOCIAL MEDIA</div><MudDivider /></MudItem>
|
||||
<MudItem xs="4"><label class="field-label">LinkedIn</label><MudTextField @bind-Value="_model.SocialMediaLinkedIn" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="4"><label class="field-label">Instagram</label><MudTextField @bind-Value="_model.SocialMediaInstagram" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="4"><label class="field-label">TikTok</label><MudTextField @bind-Value="_model.SocialMediaTikTok" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="6"><label class="field-label">Facebook</label><MudTextField @bind-Value="_model.SocialMediaFacebook" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="6"><label class="field-label">X (Twitter)</label><MudTextField @bind-Value="_model.SocialMediaX" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<MudGrid Spacing="3">
|
||||
<MudItem xs="12" Class="mt-2"><div class="section-header">ADDITIONAL</div><MudDivider /></MudItem>
|
||||
<MudItem xs="4"><label class="field-label">Other Info 1</label><MudTextField @bind-Value="_model.OtherInformation1" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="4"><label class="field-label">Other Info 2</label><MudTextField @bind-Value="_model.OtherInformation2" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
<MudItem xs="4"><label class="field-label">Other Info 3</label><MudTextField @bind-Value="_model.OtherInformation3" ReadOnly="ReadOnly" Variant="Variant.Outlined" Margin="Margin.Dense" /></MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<MudGrid Spacing="3">
|
||||
<MudItem xs="12" Class="mt-4">
|
||||
<MudText Typo="Typo.button" Color="Color.Primary" Style="font-weight: 800;">Audit History</MudText>
|
||||
<MudDivider Class="mt-2 mb-4" />
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6">
|
||||
<MudText Typo="Typo.subtitle2">Created At</MudText>
|
||||
<MudText Typo="Typo.body2" Style="color: #1a1a1a; font-weight: 600;">@DateTimeExtensions.ToString(_model.CreatedAt)</MudText>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6">
|
||||
<MudText Typo="Typo.subtitle2">Created By</MudText>
|
||||
<MudText Typo="Typo.body2" Style="color: #1a1a1a; font-weight: 600;">@(!string.IsNullOrEmpty(_model.CreatedBy) ? _model.CreatedBy : "System")</MudText>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6">
|
||||
<MudText Typo="Typo.subtitle2">Last Updated At</MudText>
|
||||
<MudText Typo="Typo.body2" Style="color: #1a1a1a; font-weight: 600;">@DateTimeExtensions.ToString(_model.UpdatedAt)</MudText>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6">
|
||||
<MudText Typo="Typo.subtitle2">Last Updated By</MudText>
|
||||
<MudText Typo="Typo.body2" Style="color: #1a1a1a; font-weight: 600;">@(!string.IsNullOrEmpty(_model.UpdatedBy) ? _model.UpdatedBy : "System")</MudText>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<div class="d-flex justify-end gap-2 mt-10">
|
||||
<MudButton OnClick="() => OnCancel.InvokeAsync()" Variant="Variant.Outlined" Style="border: 1px solid #e0e0e0; border-radius: 4px; text-transform: none; font-weight: 700;">@(ReadOnly ? "Back to List" : "Cancel")</MudButton>
|
||||
@if (!ReadOnly)
|
||||
{
|
||||
<MudButton Color="Color.Primary" Variant="Variant.Filled" OnClick="Submit" Disabled="_processing" Style="border-radius: 4px; text-transform: none; font-weight: 700;">
|
||||
@if (_processing) { <MudProgressCircular Class="ms-n1" Size="Size.Small" Indeterminate="true" /> <MudText Class="ms-2">Updating...</MudText> }
|
||||
else { <MudText>Save Changes</MudText> }
|
||||
</MudButton>
|
||||
}
|
||||
</div>
|
||||
</MudStack>
|
||||
</MudForm>
|
||||
}
|
||||
</MudPaper>
|
||||
|
||||
@code {
|
||||
[Parameter] public UpdateEmployeeRequest Data { get; set; } = new();
|
||||
[Parameter] public bool ReadOnly { get; set; } = false;
|
||||
[Parameter] public EventCallback OnCancel { get; set; }
|
||||
[Parameter] public EventCallback OnSuccess { get; set; }
|
||||
|
||||
private MudForm? _form;
|
||||
private UpdateEmployeeRequest _model = new();
|
||||
private UpdateEmployeeValidator _validator = new();
|
||||
|
||||
private LookupResponse _lookupData = new();
|
||||
private bool _processing = false;
|
||||
private bool _isLoadingData = true;
|
||||
private bool _isDisposed = false;
|
||||
|
||||
public void Dispose() => _isDisposed = true;
|
||||
|
||||
protected override void OnInitialized() { _model = Data; }
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try {
|
||||
_isLoadingData = true;
|
||||
var response = await EmployeeService.GetLookupAsync();
|
||||
if (response?.IsSuccess == true)
|
||||
{
|
||||
_lookupData = response.Value ?? new();
|
||||
}
|
||||
} finally {
|
||||
if (!_isDisposed) { _isLoadingData = false; StateHasChanged(); }
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Submit()
|
||||
{
|
||||
await _form!.Validate();
|
||||
if (!_form.IsValid) return;
|
||||
|
||||
_processing = true;
|
||||
try {
|
||||
var res = await EmployeeService.UpdateEmployeeAsync(_model);
|
||||
await Task.Delay(500);
|
||||
if (res?.IsSuccess == true)
|
||||
{
|
||||
Snackbar.Add("Updated successfully", Severity.Success);
|
||||
await OnSuccess.InvokeAsync();
|
||||
}
|
||||
} finally { _processing = false; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user