183 lines
6.3 KiB
Vue
183 lines
6.3 KiB
Vue
<script setup>
|
|
import ActionSettingsWheelButton from "@/components/displays/buttons/ActionSettingsWheelButton.vue";
|
|
import ActionSettingsWheelItem from "@/components/displays/buttons/ActionSettingsWheelItem.vue";
|
|
import { showEditUserForm } from "@/components/forms/superUser/editUserForm.vue";
|
|
import {
|
|
getLimitedBackofficeDepartments,
|
|
getLimitedBackofficeRoles,
|
|
limitedBackofficeErrorMessage,
|
|
migrateLimitedBackofficeEmployee,
|
|
unwrapLimitedBackofficeResponse,
|
|
} from "@/services/limitedBackoffice.js";
|
|
import Swal from "sweetalert2";
|
|
|
|
defineProps({
|
|
objects: {
|
|
type: Array,
|
|
default: () => [],
|
|
},
|
|
});
|
|
|
|
const emit = defineEmits(["migrated"]);
|
|
|
|
const editUser = (user) => {
|
|
showEditUserForm(user.id, user.customer_number, user.display_name, user.group_id, {
|
|
limitedBackofficeManaged: Boolean(user.limited_backoffice_managed),
|
|
});
|
|
};
|
|
|
|
const escapeHtml = (value) =>
|
|
String(value ?? "")
|
|
.replaceAll("&", "&")
|
|
.replaceAll("<", "<")
|
|
.replaceAll(">", ">")
|
|
.replaceAll('"', """)
|
|
.replaceAll("'", "'");
|
|
|
|
const canMigrateToLimitedBackoffice = (user) =>
|
|
Number(user?.customer_number) === 0 && !Boolean(user?.limited_backoffice_managed);
|
|
|
|
const migrateUser = async (user) => {
|
|
try {
|
|
const [departmentsResponse, rolesResponse] = await Promise.all([
|
|
getLimitedBackofficeDepartments(),
|
|
getLimitedBackofficeRoles(),
|
|
]);
|
|
const departments = unwrapLimitedBackofficeResponse(departmentsResponse) || [];
|
|
const roles = unwrapLimitedBackofficeResponse(rolesResponse) || [];
|
|
|
|
if (!Array.isArray(departments) || departments.length === 0 || !Array.isArray(roles) || roles.length === 0) {
|
|
throw new Error("Limited backoffice roles or departments are unavailable.");
|
|
}
|
|
|
|
const roleOptions = roles
|
|
.filter((role) => role?.key && role?.key !== "superuser")
|
|
.map((role) => {
|
|
const selected = role.key === "cashier" ? " selected" : "";
|
|
return `<option value="${escapeHtml(role.key)}"${selected}>${escapeHtml(role.label || role.key)}</option>`;
|
|
})
|
|
.join("");
|
|
const departmentOptions = departments
|
|
.map(
|
|
(department) => `
|
|
<label class="checkbox is-block has-text-left mb-2">
|
|
<input type="checkbox" class="limited-migration-department" value="${escapeHtml(department.id)}" />
|
|
${escapeHtml(department.name || `Department ${department.id}`)}
|
|
</label>
|
|
`
|
|
)
|
|
.join("");
|
|
|
|
const result = await Swal.fire({
|
|
title: "Migrate employee",
|
|
html: `
|
|
<div class="field has-text-left">
|
|
<label class="label">Employee</label>
|
|
<p>${escapeHtml(user.display_name || `#${user.id}`)}</p>
|
|
</div>
|
|
<div class="field has-text-left">
|
|
<label class="label" for="limited-migration-role">Role</label>
|
|
<div class="control">
|
|
<div class="select is-fullwidth">
|
|
<select id="limited-migration-role">${roleOptions}</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="field has-text-left">
|
|
<label class="label">Departments</label>
|
|
<div class="control">${departmentOptions}</div>
|
|
</div>
|
|
`,
|
|
showCancelButton: true,
|
|
confirmButtonText: "Migrate",
|
|
preConfirm: async () => {
|
|
const role = document.getElementById("limited-migration-role")?.value;
|
|
const departmentIds = Array.from(document.querySelectorAll(".limited-migration-department:checked")).map(
|
|
(checkbox) => Number(checkbox.value)
|
|
);
|
|
|
|
if (!role || departmentIds.length === 0) {
|
|
Swal.showValidationMessage("Select a role and at least one department.");
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
await migrateLimitedBackofficeEmployee(user.id, {
|
|
role_key: role,
|
|
department_ids: departmentIds,
|
|
});
|
|
return true;
|
|
} catch (error) {
|
|
Swal.showValidationMessage(limitedBackofficeErrorMessage(error, "Could not migrate employee."));
|
|
return false;
|
|
}
|
|
},
|
|
});
|
|
|
|
if (result.isConfirmed) {
|
|
await Swal.fire("Employee migrated");
|
|
emit("migrated");
|
|
}
|
|
} catch (error) {
|
|
await Swal.fire("Error", limitedBackofficeErrorMessage(error, "Could not migrate employee."), "error");
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div class="table-container">
|
|
<table class="table is-fullwidth is-striped is-hoverable" data-testid="superuser-users-table">
|
|
<thead>
|
|
<tr>
|
|
<th>{{ $t("objects.columns.id") }}</th>
|
|
<th>{{ $t("tables.users.name") }}</th>
|
|
<th>{{ $t("tables.users.role") }}</th>
|
|
<th class="has-text-right">{{ $t("tables.actions") }}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-for="user in objects" :key="user.id" :data-testid="`superuser-users-row-${user.id}`">
|
|
<td>{{ user.id }}</td>
|
|
<td>{{ user.display_name }}</td>
|
|
<td>{{ user.group_id }}</td>
|
|
<td class="has-text-right users-table__actions-cell">
|
|
<div class="buttons is-justify-content-flex-end">
|
|
<!-- Settings wheel -->
|
|
<ActionSettingsWheelButton
|
|
:customer_number="user.customer_number"
|
|
:user_id="user.id"
|
|
:data-testid="`superuser-user-actions-${user.id}`"
|
|
>
|
|
<template #actions>
|
|
<ActionSettingsWheelItem
|
|
:click-action="() => editUser(user)"
|
|
icon="fas fa-user-edit"
|
|
:label="$t('global.edit')"
|
|
:test-id="`superuser-user-edit-${user.id}`"
|
|
/>
|
|
<ActionSettingsWheelItem
|
|
v-if="canMigrateToLimitedBackoffice(user)"
|
|
:click-action="() => migrateUser(user)"
|
|
icon="fas fa-random"
|
|
:label="$t('superuser.pages.employees.migrate_to_limited_backoffice')"
|
|
:test-id="`superuser-user-migrate-limited-${user.id}`"
|
|
/>
|
|
</template>
|
|
</ActionSettingsWheelButton>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr v-if="objects.length === 0">
|
|
<td colspan="4">{{ $t("global.no_data") }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.users-table__actions-cell {
|
|
white-space: nowrap;
|
|
}
|
|
</style>
|