PSTW_CentralizeSystem/Areas/OTcalculate/Views/HrDashboard/HrUserSetting.cshtml
2025-04-29 17:19:25 +08:00

383 lines
18 KiB
Plaintext

@{
ViewBag.Title = "User Settings";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<div class="container">
<div class="row justify-content-center">
<div class="col-6 col-md-6 col-lg-3">
<div class="card card-hover">
<a asp-area="OTcalculate" asp-controller="HrDashboard" asp-action="Rate">
<div class="box bg-success text-center">
<h1 class="font-light text-white"><i class="mdi mdi-currency-usd"></i></h1>
<h6 class="text-white">Rate</h6>
</div>
</a>
</div>
</div>
<div class="col-6 col-md-6 col-lg-3">
<div class="card card-hover">
<a asp-area="OTcalculate" asp-controller="HrDashboard" asp-action="Calendar">
<div class="box bg-purple text-center">
<h1 class="font-light text-white"><i class="mdi mdi-calendar"></i></h1>
<h6 class="text-white">Calendar</h6>
</div>
</a>
</div>
</div>
<div class="col-6 col-md-6 col-lg-3">
<div class="card card-hover">
<a asp-area="OTcalculate" asp-controller="HrDashboard" asp-action="HrUserSetting">
<div class="box bg-megna text-center">
<h1 class="font-light text-white"><i class="mdi mdi-account-settings"></i></h1>
<h6 class="text-white">User Setting</h6>
</div>
</a>
</div>
</div>
</div>
</div>
<div class="container mt-4" id="app">
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link" :class="{ 'bg-purple text-white': activeTab === 'flexi', 'bg-light text-dark': activeTab !== 'flexi' }"
style="border: 1px solid #ddd;" v-on:click="changeTab('flexi')">
Flexi Hour Settings
</a>
</li>
<li class="nav-item">
<a class="nav-link" :class="{ 'bg-purple text-white': activeTab === 'state', 'bg-light text-dark': activeTab !== 'state' }"
style="border: 1px solid #ddd;" v-on:click="changeTab('state')">
Region Update
</a>
</li>
</ul>
<div class="tab-content mt-3">
<div v-if="activeTab === 'flexi'" class="card shadow-sm">
<div class="card m-1">
<form v-on:submit.prevent="updateFlexiHours" data-aos="fade-right">
<div class="d-flex justify-content-center align-items-center mt-3">
<div class="card-body d-flex justify-content-center align-items-center gap-3">
<label for="flexiHour" class="mb-0">Flexi Hour</label>
<select id="flexiHour" class="form-select" v-model="selectedFlexiHourId" style="max-width: 150px;">
<option disabled value="">--Select--</option>
<option v-for="option in flexiHours" :value="option.flexiHourId">{{ option.flexiHour }}</option>
</select>
<button type="button" class="btn btn-danger" v-on:click="clearForm">Clear</button>
<button type="submit" class="btn btn-success">Update Flexi Hour</button>
</div>
</div>
<div class="card-body">
<table id="userDatatable" class="table table-bordered table-hover table-striped">
<thead>
<tr>
<th>Full Name</th>
<th>Department</th>
<th>Current Flexi Hour</th>
<th class="text-center">Select</th>
</tr>
</thead>
</table>
</div>
<div class="d-flex justify-content-center gap-2 my-3">
<button type="button" class="btn btn-danger" v-on:click="clearForm">Clear</button>
<button type="submit" class="btn btn-success">Update Flexi Hour</button>
</div>
</form>
</div>
</div>
<div v-if="activeTab === 'state'" class="card shadow-sm">
<div class="card-body d-flex justify-content-center align-items-center gap-3">
<label class="mb-0">Select State:</label>
<select class="form-select" v-model="selectedStateAll" style="max-width: 150px;">
<option disabled value="">--Select--</option>
<option v-for="state in stateList" :value="state.stateId">{{ state.stateName }}</option>
</select>
<button class="btn btn-danger" v-on:click="clearStateSelection">Cancel</button>
<button class="btn btn-success" v-on:click="saveState">Update State</button>
</div>
<div class="card-body">
<table id="stateUpdateTable" class="table table-bordered table-hover table-striped">
<thead>
<tr>
<th>Full Name</th>
<th>Department</th>
<th>Current State</th>
<th class="text-center">Select</th>
</tr>
</thead>
</table>
</div>
<div class="card-body text-center">
<button class="btn btn-danger" v-on:click="clearStateSelection">Clear Selection</button>
<button class="btn btn-success ms-3" v-on:click="saveState">Update User State</button>
</div>
</div>
</div>
</div>
@section Scripts {
@await Html.PartialAsync("_ValidationScriptsPartial")
<script src="https://unpkg.com/vue@3.2.37/dist/vue.global.js"></script>
<script>
window.onload = function () {
const app = Vue.createApp({
data() {
return {
activeTab: 'flexi',
flexiHours: [],
selectedFlexiHourId: '',
selectedUsers: [],
userList: [],
stateList: [],
selectedStateAll: '',
selectedUsersState: [],
stateUserList: [],
userDatatable: null,
stateDatatable: null
};
},
mounted() {
console.log("Vue App Mounted Successfully");
this.fetchFlexiHours();
this.fetchStates();
this.changeTab('flexi'); // Initialize the default tab
},
methods: {
changeTab(tab) {
this.activeTab = tab;
if (tab === 'flexi') {
this.clearForm();
if (!this.userList.length) {
this.fetchUsers().then(() => this.initiateTable());
} else {
this.initiateTable();
}
} else if (tab === 'state') {
this.clearStateSelection();
if (!this.stateUserList.length) {
this.fetchUsersState().then(() => this.initiateStateTable());
}
else{
this.initiateStateTable();
}
}
},
async updateUserSettings(apiUrl, selectedUsers, selectedValue, successMessage, clearCallback, fetchCallback, valueKey) {
if (!selectedUsers.length || !selectedValue) {
alert("Please select at least one user and a value.");
return;
}
const payload = selectedUsers.map(userId => ({ UserId: userId, [valueKey]: selectedValue }));
try {
const response = await fetch(apiUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload)
});
if (response.ok) {
alert(successMessage);
clearCallback(); // Clears form selections
await fetchCallback(); // Fetches the updated data
} else {
const errorData = await response.json();
alert(errorData.message || "Failed to update. Please try again.");
}
} catch (error) {
console.error("Error updating:", error);
}
},
async fetchFlexiHours() {
try {
const response = await fetch("/OvertimeAPI/GetFlexiHours");
this.flexiHours = await response.json();
console.log("Fetched flexi hours:", this.flexiHours);
} catch (error) {
console.error("Error fetching Flexi Hours:", error);
}
},
async fetchUsers() {
try {
const response = await fetch("/OvertimeAPI/GetUserFlexiHours", { method: "GET" });
if (!response.ok) {
throw new Error('Failed to fetch users');
}
const data = await response.json();
this.userList = data.filter(e => e.fullName !== "MAAdmin" && e.fullName !== "SysAdmin");
console.log("Fetched User data", this.userList);
// Reinitialize DataTable with updated data
this.initiateTable();
} catch (error) {
console.error("Error fetching users:", error);
}
},
async fetchStates() {
try {
const response = await fetch("/OvertimeAPI/GetStatesName");
this.stateList = await response.json();
} catch (error) {
console.error("Error fetching States:", error);
}
},
async fetchUsersState() {
try {
const response = await fetch("/OvertimeAPI/GetUserStates", { method: "GET" });
const data = await response.json();
this.stateUserList = data.filter(e => e.fullName !== "MAAdmin" && e.fullName !== "SysAdmin");
console.log("Fetched state users", this.stateUserList);
// Reinitialize the state table to reflect updated data
this.initiateStateTable();
} catch (error) {
console.error("Error fetching users for State:", error);
}
},
initiateTable() {
if (this.userDatatable) {
this.userDatatable.destroy();
this.userDatatable = null;
}
const self = this;
this.$nextTick(() => {
self.userDatatable = $('#userDatatable').DataTable({
data: self.userList,
columns: [
{ data: "fullName" },
{ data: "departmentName" },
{ data: "flexiHour", defaultContent: "N/A" },
{
data: "userId",
className: "text-center",
render: data => `<input type='checkbox' class='user-checkbox' value='${data}'>`
}
],
destroy: true,
responsive: true
});
$('#userDatatable tbody').off('change').on('change', '.user-checkbox', (e) => {
const userId = $(e.target).val();
if (e.target.checked) {
self.selectedUsers.push(userId);
} else {
self.selectedUsers = self.selectedUsers.filter(id => id !== userId);
}
});
});
},
initiateStateTable() {
if (this.stateDatatable) {
this.stateDatatable.destroy();
this.stateDatatable = null;
}
const self = this;
this.$nextTick(() => {
self.stateDatatable = $('#stateUpdateTable').DataTable({
data: self.stateUserList,
columns: [
{ data: "fullName" },
{ data: "departmentName" },
{ data: "state", defaultContent: "N/A" },
{
data: "id",
className: "text-center",
render: data => `<input type='checkbox' class='state-checkbox' value='${data || ""}'>`
}
],
destroy: true,
responsive: true
});
$('#stateUpdateTable tbody').off('change').on('change', '.state-checkbox', (e) => {
const userId = $(e.target).val();
if (e.target.checked) {
self.selectedUsersState.push(userId);
} else {
self.selectedUsersState = self.selectedUsersState.filter(id => id !== userId);
}
});
});
},
clearForm() {
this.selectedFlexiHourId = '';
this.selectedUsers = [];
if (this.userDatatable) {
this.userDatatable.rows().every(function () {
$(this.node()).find('input[type="checkbox"]').prop('checked', false);
});
}
},
clearStateSelection() {
this.selectedUsersState = [];
if (this.stateDatatable) {
this.stateDatatable.rows().every(function () {
$(this.node()).find('input[type="checkbox"]').prop('checked', false);
});
}
},
async saveState() {
await this.updateUserSettings(
"/OvertimeAPI/UpdateUserStates",
this.selectedUsersState,
this.selectedStateAll,
"State updated successfully!",
this.clearStateSelection,
this.fetchUsersState, // This will fetch the updated state users after the update
"StateId"
);
// Fetch the updated state list to ensure the page reflects the new state data
await this.fetchUsersState(); // This fetch will make sure stateUserList is updated
this.initiateStateTable(); // Reinitialize the state table with new data
},
async updateFlexiHours() {
await this.updateUserSettings(
"/OvertimeAPI/UpdateUserFlexiHours",
this.selectedUsers,
this.selectedFlexiHourId,
"Flexi Hours updated successfully!",
this.clearForm,
this.fetchUsers,
"FlexiHourId"
);
}
}
});
app.mount('#app');
};
</script>
}