785 lines
38 KiB
Plaintext
785 lines
38 KiB
Plaintext
@{
|
|
ViewBag.Title = "User Settings";
|
|
Layout = "~/Views/Shared/_Layout.cshtml";
|
|
}
|
|
|
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
|
|
|
<style>
|
|
|
|
#ApprovalFlowTable {
|
|
|
|
background-color: white;
|
|
|
|
}
|
|
#ApprovalFlowTable th,
|
|
#ApprovalFlowTable td {
|
|
background-color: white !important;
|
|
color: #323;
|
|
}
|
|
</style>
|
|
|
|
<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">Salary</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 & Flow Update
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" :class="{ 'bg-purple text-white': activeTab === 'approval', 'bg-light text-dark': activeTab !== 'approval' }"
|
|
style="border: 1px solid #ddd;" v-on:click="changeTab('approval')">
|
|
Approval Flow
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
|
|
<div class="tab-content mt-3">
|
|
<div v-if="activeTab === 'flexi'" class="card shadow-sm">
|
|
<div class="card m-2">
|
|
<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 m-3">
|
|
<div class="d-flex justify-content-center align-items-center gap-4 flex-wrap mt-4">
|
|
<div class="d-flex align-items-center gap-2 flex-nowrap">
|
|
<label class="form-label mb-0">Select State:</label>
|
|
<select class="form-select form-select-sm" v-model="selectedStateAll" style="width: 150px; font-size: 0.900rem;">
|
|
<option disabled value="">--Select--</option>
|
|
<option v-for="state in stateList" :value="state.stateId">{{ state.stateName }}</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="d-flex align-items-center gap-2 flex-nowrap">
|
|
<label class="form-label mb-0">Select Approval Flow:</label>
|
|
<select class="form-select form-select-sm" v-model="selectedApprovalFlowId" style="width: 150px; font-size: 0.900rem;">
|
|
<option disabled value="">--Select--</option>
|
|
<option v-for="flow in approvalFlowList" :key="flow.approvalFlowId" :value="flow.approvalFlowId">
|
|
{{ flow.approvalName }}
|
|
</option>
|
|
</select>
|
|
</div>
|
|
<div class="d-flex align-items-center gap-2 flex-nowrap">
|
|
<button class="btn btn-danger" v-on:click="clearAllSelectionsStateFlow" style="font-size: 0.900rem; margin-left: 10px;">
|
|
Clear
|
|
</button>
|
|
<button class="btn btn-primary" v-on:click="handleCombinedUpdate" style="font-size: 0.900rem;">
|
|
Update State & Flow
|
|
</button>
|
|
</div>
|
|
|
|
</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>Approval Flow</th>
|
|
<th class="text-center">Select</th>
|
|
</tr>
|
|
</thead>
|
|
</table>
|
|
</div>
|
|
<div class="d-flex justify-content-center gap-2 my-3">
|
|
<button class="btn btn-danger" v-on:click="clearAllSelectionsStateFlow" style="font-size: 0.900rem; margin-left: 10px;">
|
|
Clear
|
|
</button>
|
|
<button class="btn btn-primary" v-on:click="handleCombinedUpdate" style="font-size: 0.900rem;">
|
|
Update State & Flow
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="activeTab === 'approval'" class="card shadow-sm">
|
|
<div class="card m-3">
|
|
<div class="card-body">
|
|
<h5 class="card-title text-center">Create Approval Flow</h5>
|
|
<div class="d-flex justify-content-center">
|
|
<form v-on:submit.prevent="submitApprovalFlow" class="w-75">
|
|
<div class="mb-3">
|
|
<label for="approvalName" class="form-label">Approval Name</label>
|
|
<input type="text" id="approvalName" class="form-control" v-model="approvalFlow.approvalName" placeholder="Enter approval name" required />
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Approval Flow:</label>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="hou" class="form-label ms-3">Head of Unit (HoU) / Executive</label>
|
|
<select id="hou" class="form-select" v-model="approvalFlow.hou">
|
|
<option disabled value="">--Select--</option>
|
|
<option v-for="user in allUsers" :value="user.id">{{ user.fullName }}</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="hod" class="form-label ms-3">Head of Department (HoD)</label>
|
|
<select id="hod" class="form-select" v-model="approvalFlow.hod">
|
|
<option disabled value="">--Select--</option>
|
|
<option v-for="user in allUsers" :value="user.id">{{ user.fullName }}</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="manager" class="form-label ms-3">Manager</label>
|
|
<select id="manager" class="form-select" v-model="approvalFlow.manager">
|
|
<option disabled value="">--Select--</option>
|
|
<option v-for="user in allUsers" :value="user.id">{{ user.fullName }}</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="hr" class="form-label ms-3">HR</label>
|
|
<select id="hr" class="form-select" v-model="approvalFlow.hr" required>
|
|
<option disabled value="">--Select--</option>
|
|
<option v-for="user in allUsers" :value="user.id">{{ user.fullName }}</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-end" style="gap: 10px;">
|
|
<button type="button" class="btn btn-danger" v-on:click="clearFormApproval">Clear</button>
|
|
<button type="submit" class="btn btn-success">Submit Approval Flow</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="d-flex justify-content-center">
|
|
<div class="table-container table-responsive w-100" style="margin-top: 20px; max-width: 900px;">
|
|
<table id="ApprovalFlowTable" class="table table-bordered table-striped align-middle">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th style="width: 50px;">No.</th>
|
|
<th>Approval Name</th>
|
|
<th style="width: 120px;">Action</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-if="approvalFlowList.length === 0">
|
|
<td colspan="3" class="text-center text-muted">No approval flows found.</td>
|
|
</tr>
|
|
<tr v-for="(flow, index) in approvalFlowList" :key="flow.approvalFlowId">
|
|
<td>{{ index + 1 }}</td>
|
|
<td>{{ flow.approvalName }}</td>
|
|
<td>
|
|
<button class="btn btn-sm btn-primary me-2" v-on:click="openEditModal(flow)" title="Edit">
|
|
<i class="bi bi-pencil"></i>
|
|
</button>
|
|
<button class="btn btn-sm btn-danger" v-on:click="deleteApprovalFlow(flow.approvalFlowId)" title="Delete">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Edit Modal -->
|
|
<div class="modal fade" id="editApprovalModal" tabindex="-1" aria-labelledby="editApprovalModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<form v-on:submit.prevent="submitEditApprovalFlow">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="editApprovalModalLabel">Edit Approval Flow</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label class="form-label">Approval Name</label>
|
|
<input type="text" class="form-control" v-model="editFlow.approvalName" required />
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Head of Unit (HoU)</label>
|
|
<select class="form-select" v-model="editFlow.hou">
|
|
<option :value="null">--None--</option>
|
|
<option v-for="user in allUsers" :value="user.id">{{ user.fullName }}</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Head of Department (HoD)</label>
|
|
<select class="form-select" v-model="editFlow.hod">
|
|
<option :value="null">--None--</option>
|
|
<option v-for="user in allUsers" :value="user.id">{{ user.fullName }}</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Manager</label>
|
|
<select class="form-select" v-model="editFlow.manager">
|
|
<option :value="null">--None--</option>
|
|
<option v-for="user in allUsers" :value="user.id">{{ user.fullName }}</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">HR</label>
|
|
<select class="form-select" v-model="editFlow.hr" required>
|
|
<option disabled value="">--Select--</option>
|
|
<option v-for="user in allUsers" :value="user.id">{{ user.fullName }}</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="submit" class="btn btn-success">Save Changes</button>
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</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,
|
|
approvalFlows: [],
|
|
approvalFlowList: [],
|
|
selectedApprovalFlowId: '',
|
|
approvalFlow: {
|
|
approvalName: '',
|
|
hou: '',
|
|
hod: '',
|
|
manager: '',
|
|
hr: ''
|
|
},
|
|
editFlow: {
|
|
approvalId: '',
|
|
approvalName: '',
|
|
hou: '',
|
|
hod: '',
|
|
manager: '',
|
|
hr: ''
|
|
},
|
|
allUsers: []
|
|
|
|
};
|
|
},
|
|
mounted() {
|
|
console.log("Vue App Mounted Successfully");
|
|
this.fetchFlexiHours();
|
|
this.fetchStates();
|
|
this.changeTab('flexi');
|
|
this.fetchAllUsers();
|
|
this.fetchUsersState();
|
|
this.fetchApprovalFlows();
|
|
},
|
|
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.clearAllSelectionsStateFlow();
|
|
if (!this.stateUserList.length) {
|
|
this.fetchUsersState().then(() => {
|
|
this.initiateStateTable();
|
|
this.fetchApprovalFlows();
|
|
});
|
|
} 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 flexi hour.");
|
|
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();
|
|
await fetchCallback();
|
|
} 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);
|
|
|
|
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);
|
|
|
|
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: "approvalName", 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);
|
|
}
|
|
});
|
|
});
|
|
},
|
|
|
|
async handleCombinedUpdate() {
|
|
const hasUsers = this.selectedUsersState.length > 0;
|
|
const hasState = this.selectedStateAll !== '';
|
|
const hasFlow = this.selectedApprovalFlowId !== '';
|
|
|
|
if (!hasUsers && !hasState && !hasFlow) {
|
|
alert("Please choose users, a state, or an approval flow to proceed.");
|
|
this.clearAllSelectionsStateFlow();
|
|
return;
|
|
}
|
|
|
|
if (!hasUsers) {
|
|
alert("Please select at least one user.");
|
|
return;
|
|
}
|
|
|
|
if (!hasState && !hasFlow) {
|
|
alert("Please select either a State or Approval Flow.");
|
|
return;
|
|
}
|
|
|
|
if (hasState) {
|
|
await this.updateUserSettings(
|
|
"/OvertimeAPI/UpdateUserStates",
|
|
this.selectedUsersState,
|
|
this.selectedStateAll,
|
|
"State updated successfully!",
|
|
() => {},
|
|
() => {},
|
|
"StateId"
|
|
);
|
|
}
|
|
|
|
if (hasFlow) {
|
|
const payload = this.selectedUsersState.map(userId => ({
|
|
UserId: userId,
|
|
ApprovalFlowId: this.selectedApprovalFlowId
|
|
}));
|
|
|
|
try {
|
|
const response = await fetch("/OvertimeAPI/UpdateUserApprovalFlow", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(payload)
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json();
|
|
alert(errorData.message || "Failed to update Approval Flow.");
|
|
return;
|
|
}
|
|
|
|
alert("Approval Flow updated successfully!");
|
|
|
|
} catch (error) {
|
|
console.error("Error updating approval flow:", error);
|
|
alert("An unexpected error occurred.");
|
|
}
|
|
}
|
|
|
|
await this.fetchUsersState();
|
|
this.initiateStateTable();
|
|
this.clearAllSelectionsStateFlow();
|
|
},
|
|
|
|
async updateFlexiHours() {
|
|
await this.updateUserSettings(
|
|
"/OvertimeAPI/UpdateUserFlexiHours",
|
|
this.selectedUsers,
|
|
this.selectedFlexiHourId,
|
|
"Flexi Hours updated successfully!",
|
|
this.clearForm,
|
|
this.fetchUsers,
|
|
"FlexiHourId"
|
|
);
|
|
},
|
|
|
|
async fetchAllUsers() {
|
|
try {
|
|
const response = await fetch("/OvertimeAPI/GetAllUsers");
|
|
|
|
if (!response.ok) {
|
|
const errorText = await response.text();
|
|
throw new Error(`Fetch failed: ${response.status} ${errorText}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
console.log("Fetched users:", data);
|
|
|
|
this.allUsers = data.filter(e => e.fullName !== "MAAdmin" && e.fullName !== "SysAdmin");
|
|
} catch (error) {
|
|
console.error("Error fetching all users:", error);
|
|
}
|
|
},
|
|
|
|
async fetchApprovalFlows() {
|
|
try {
|
|
const response = await fetch('/OvertimeAPI/GetApprovalFlowList');
|
|
const data = await response.json();
|
|
this.approvalFlowList = data;
|
|
console.log('Fetched approval flows:', this.approvalFlowList);
|
|
} catch (error) {
|
|
console.error('Error fetching approval flows:', error);
|
|
}
|
|
},
|
|
async submitApprovalFlow() {
|
|
try {
|
|
const payload = { ...this.approvalFlow };
|
|
if (payload.hou === "") payload.hou = null;
|
|
if (payload.hod === "") payload.hod = null;
|
|
if (payload.manager === "") payload.manager = null;
|
|
|
|
const response = await fetch('/OvertimeAPI/CreateApprovalFlow', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(payload)
|
|
});
|
|
|
|
if (response.ok) {
|
|
alert('Approval flow created successfully!');
|
|
this.clearFormApproval();
|
|
await this.fetchApprovalFlows();
|
|
} else {
|
|
const errorData = await response.json();
|
|
alert(errorData.message || 'Failed to create approval flow. Please try again.');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error submitting approval flow:', error);
|
|
alert('An unexpected error occurred.');
|
|
}
|
|
},
|
|
|
|
clearFormApproval() {
|
|
this.approvalFlow = {
|
|
approvalName: '',
|
|
hou: '',
|
|
hod: '',
|
|
manager: '',
|
|
hr: ''
|
|
};
|
|
},
|
|
|
|
async deleteApprovalFlow(approvalId) {
|
|
if (!approvalId) {
|
|
console.error("No approval ID provided for deletion.");
|
|
alert("An error occurred: No approval flow selected for deletion.");
|
|
return;
|
|
}
|
|
|
|
if (!confirm("Are you sure you want to delete this approval flow?")) return;
|
|
|
|
try {
|
|
const response = await fetch(`/OvertimeAPI/DeleteApprovalFlow/${approvalId}`, {
|
|
method: "DELETE"
|
|
});
|
|
|
|
if (response.ok) {
|
|
alert("Approval flow deleted successfully.");
|
|
await this.fetchApprovalFlows();
|
|
} else {
|
|
const errorData = await response.json();
|
|
const errorMessage = errorData.message || "Failed to delete approval flow.";
|
|
|
|
if (response.status === 400) {
|
|
alert(`Error: ${errorMessage}`);
|
|
} else {
|
|
console.error("Error deleting flow:", errorMessage);
|
|
alert(`Error: ${errorMessage}`);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error("An unexpected error occurred during deletion:", error);
|
|
alert(`An unexpected error occurred: ${error.message || "Please try again."}`);
|
|
}
|
|
},
|
|
|
|
clearForm() {
|
|
this.selectedFlexiHourId = '';
|
|
this.selectedUsers = [];
|
|
if (this.userDatatable) {
|
|
this.userDatatable.rows().every(function () {
|
|
$(this.node()).find('input[type="checkbox"]').prop('checked', false);
|
|
});
|
|
}
|
|
},
|
|
|
|
clearAllSelectionsStateFlow() {
|
|
this.selectedStateAll = '';
|
|
this.selectedApprovalFlowId = '';
|
|
this.selectedUsersState = [];
|
|
if (this.stateDatatable) {
|
|
this.stateDatatable.rows().every(function () {
|
|
$(this.node()).find('input[type="checkbox"]').prop('checked', false);
|
|
});
|
|
}
|
|
},
|
|
openEditModal(flow) {
|
|
this.editFlow = { ...flow };
|
|
|
|
console.log(this.editFlow);
|
|
|
|
this.fetchAllUsers().then(() => {
|
|
const modal = new bootstrap.Modal(document.getElementById('editApprovalModal'));
|
|
modal.show();
|
|
});
|
|
},
|
|
|
|
|
|
async submitEditApprovalFlow() {
|
|
try {
|
|
const response = await fetch('/OvertimeAPI/EditApprovalFlow', {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(this.editFlow)
|
|
});
|
|
|
|
if (response.ok) {
|
|
alert('Approval flow updated successfully!');
|
|
await this.fetchApprovalFlows();
|
|
const modalElement = document.getElementById('editApprovalModal');
|
|
const modal = bootstrap.Modal.getInstance(modalElement);
|
|
modal.hide();
|
|
} else {
|
|
const error = await response.json();
|
|
alert(error.message || 'Failed to update approval flow.');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error updating flow:', error);
|
|
alert('Unexpected error occurred.');
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
});
|
|
|
|
app.mount('#app');
|
|
};
|
|
</script>
|
|
} |