Primo commit
This commit is contained in:
@@ -1,370 +1,383 @@
|
||||
/**
|
||||
* Team Rules Page
|
||||
* Manage closing days, parking guarantees, and exclusions
|
||||
*
|
||||
* Rules are set at manager level for their parking pool.
|
||||
* Manage closing days, guarantees, and exclusions
|
||||
* Office-centric model
|
||||
*/
|
||||
|
||||
let currentUser = null;
|
||||
let selectedManagerId = null;
|
||||
let managerUsers = [];
|
||||
let offices = [];
|
||||
let currentOfficeId = null;
|
||||
let officeUsers = [];
|
||||
let currentWeeklyClosingDays = [];
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
currentUser = await api.requireAuth();
|
||||
if (!currentUser) return;
|
||||
|
||||
// Only managers and admins can access
|
||||
if (currentUser.role === 'employee') {
|
||||
// Only admins and managers can access this page
|
||||
if (currentUser.role !== 'admin' && currentUser.role !== 'manager') {
|
||||
window.location.href = '/presence';
|
||||
return;
|
||||
}
|
||||
|
||||
await loadManagers();
|
||||
await loadOffices();
|
||||
setupEventListeners();
|
||||
});
|
||||
|
||||
async function loadManagers() {
|
||||
const response = await api.get('/api/managers');
|
||||
if (response && response.ok) {
|
||||
const managers = await response.json();
|
||||
const select = document.getElementById('managerSelect');
|
||||
async function loadOffices() {
|
||||
const select = document.getElementById('officeSelect');
|
||||
const card = document.getElementById('officeSelectionCard');
|
||||
|
||||
// Filter to managers this user can see
|
||||
let filteredManagers = managers;
|
||||
// Only Admins can see the office selector
|
||||
if (currentUser.role !== 'admin') {
|
||||
if (card) card.style.display = 'none';
|
||||
}
|
||||
|
||||
const response = await api.get('/api/offices');
|
||||
if (response && response.ok) {
|
||||
offices = await response.json();
|
||||
|
||||
let filteredOffices = offices;
|
||||
if (currentUser.role === 'manager') {
|
||||
// Manager only sees themselves
|
||||
filteredManagers = managers.filter(m => m.id === currentUser.id);
|
||||
// Manager only sees their own office
|
||||
if (currentUser.office_id) {
|
||||
filteredOffices = offices.filter(o => o.id === currentUser.office_id);
|
||||
} else {
|
||||
filteredOffices = [];
|
||||
}
|
||||
}
|
||||
|
||||
// Show managers in dropdown
|
||||
let totalManagers = 0;
|
||||
let firstManagerId = null;
|
||||
|
||||
filteredManagers.forEach(manager => {
|
||||
filteredOffices.forEach(office => {
|
||||
const option = document.createElement('option');
|
||||
option.value = manager.id;
|
||||
// Show manager name with user count and parking quota
|
||||
const userCount = manager.managed_user_count || 0;
|
||||
const quota = manager.parking_quota || 0;
|
||||
option.textContent = `${manager.name} (${userCount} users, ${quota} spots)`;
|
||||
option.value = office.id;
|
||||
option.textContent = office.name;
|
||||
select.appendChild(option);
|
||||
totalManagers++;
|
||||
if (!firstManagerId) firstManagerId = manager.id;
|
||||
});
|
||||
|
||||
// Auto-select if only one manager
|
||||
if (totalManagers === 1 && firstManagerId) {
|
||||
select.value = firstManagerId;
|
||||
await selectManager(firstManagerId);
|
||||
// Auto-select for managers
|
||||
if (currentUser.role === 'manager' && filteredOffices.length === 1) {
|
||||
select.value = filteredOffices[0].id;
|
||||
loadOfficeRules(filteredOffices[0].id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function selectManager(managerId) {
|
||||
selectedManagerId = managerId;
|
||||
|
||||
if (!managerId) {
|
||||
async function loadOfficeRules(officeId) {
|
||||
if (!officeId) {
|
||||
document.getElementById('rulesContent').style.display = 'none';
|
||||
document.getElementById('noManagerMessage').style.display = 'block';
|
||||
document.getElementById('noOfficeMessage').style.display = 'block';
|
||||
return;
|
||||
}
|
||||
|
||||
currentOfficeId = officeId;
|
||||
document.getElementById('rulesContent').style.display = 'block';
|
||||
document.getElementById('noManagerMessage').style.display = 'none';
|
||||
document.getElementById('noOfficeMessage').style.display = 'none';
|
||||
|
||||
// Load users for this office (for dropdowns)
|
||||
await loadOfficeUsers(officeId);
|
||||
|
||||
await Promise.all([
|
||||
loadWeeklyClosingDays(),
|
||||
loadClosingDays(),
|
||||
loadGuarantees(),
|
||||
loadExclusions(),
|
||||
loadManagerUsers()
|
||||
loadWeeklyClosingDays(officeId),
|
||||
loadClosingDays(officeId),
|
||||
loadGuarantees(officeId),
|
||||
loadExclusions(officeId)
|
||||
]);
|
||||
}
|
||||
|
||||
async function loadWeeklyClosingDays() {
|
||||
const response = await api.get(`/api/managers/${selectedManagerId}/weekly-closing-days`);
|
||||
async function loadOfficeUsers(officeId) {
|
||||
const response = await api.get(`/api/offices/${officeId}/users`);
|
||||
if (response && response.ok) {
|
||||
officeUsers = await response.json();
|
||||
}
|
||||
}
|
||||
|
||||
// Weekly Closing Days
|
||||
async function loadWeeklyClosingDays(officeId) {
|
||||
const response = await api.get(`/api/offices/${officeId}/weekly-closing-days`);
|
||||
if (response && response.ok) {
|
||||
const days = await response.json();
|
||||
const weekdays = days.map(d => d.weekday);
|
||||
currentWeeklyClosingDays = days;
|
||||
const activeWeekdays = days.map(d => d.weekday);
|
||||
|
||||
// Update checkboxes
|
||||
document.querySelectorAll('#weeklyClosingDays input[type="checkbox"]').forEach(cb => {
|
||||
const weekday = parseInt(cb.dataset.weekday);
|
||||
cb.checked = weekdays.includes(weekday);
|
||||
cb.checked = activeWeekdays.includes(weekday);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function loadManagerUsers() {
|
||||
const response = await api.get(`/api/managers/${selectedManagerId}/users`);
|
||||
if (response && response.ok) {
|
||||
managerUsers = await response.json();
|
||||
updateUserSelects();
|
||||
async function saveWeeklyClosingDays() {
|
||||
const btn = document.getElementById('saveWeeklyClosingDaysBtn');
|
||||
if (!btn) return;
|
||||
|
||||
const originalText = btn.textContent;
|
||||
btn.disabled = true;
|
||||
btn.textContent = 'Salvataggio...';
|
||||
|
||||
try {
|
||||
const promises = [];
|
||||
const checkboxes = document.querySelectorAll('#weeklyClosingDays input[type="checkbox"]');
|
||||
|
||||
for (const cb of checkboxes) {
|
||||
const weekday = parseInt(cb.dataset.weekday);
|
||||
const isChecked = cb.checked;
|
||||
const existingEntry = currentWeeklyClosingDays.find(d => d.weekday === weekday);
|
||||
|
||||
if (isChecked && !existingEntry) {
|
||||
// Add
|
||||
promises.push(api.post(`/api/offices/${currentOfficeId}/weekly-closing-days`, { weekday }));
|
||||
} else if (!isChecked && existingEntry) {
|
||||
// Remove
|
||||
promises.push(api.delete(`/api/offices/${currentOfficeId}/weekly-closing-days/${existingEntry.id}`));
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
utils.showMessage('Giorni di chiusura aggiornati', 'success');
|
||||
await loadWeeklyClosingDays(currentOfficeId);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
utils.showMessage('Errore durante il salvataggio', 'error');
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
btn.textContent = originalText;
|
||||
}
|
||||
}
|
||||
|
||||
function updateUserSelects() {
|
||||
['guaranteeUser', 'exclusionUser'].forEach(selectId => {
|
||||
const select = document.getElementById(selectId);
|
||||
select.innerHTML = '<option value="">Select user...</option>';
|
||||
managerUsers.forEach(user => {
|
||||
const option = document.createElement('option');
|
||||
option.value = user.id;
|
||||
option.textContent = user.name;
|
||||
select.appendChild(option);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function loadClosingDays() {
|
||||
const response = await api.get(`/api/managers/${selectedManagerId}/closing-days`);
|
||||
|
||||
// Closing Days
|
||||
async function loadClosingDays(officeId) {
|
||||
const response = await api.get(`/api/offices/${officeId}/closing-days`);
|
||||
const container = document.getElementById('closingDaysList');
|
||||
|
||||
if (response && response.ok) {
|
||||
const days = await response.json();
|
||||
|
||||
if (days.length === 0) {
|
||||
container.innerHTML = '';
|
||||
container.innerHTML = '<p class="text-muted">Nessun giorno di chiusura specifico.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = days.map(day => `
|
||||
<div class="rule-item">
|
||||
<div class="rule-info">
|
||||
<span class="rule-date">${utils.formatDateDisplay(day.date)}</span>
|
||||
${day.reason ? `<span class="rule-reason">${day.reason}</span>` : ''}
|
||||
<strong>${utils.formatDateDisplay(day.date)}${day.end_date ? ' - ' + utils.formatDateDisplay(day.end_date) : ''}</strong>
|
||||
${day.reason ? `<span class="rule-note">${day.reason}</span>` : ''}
|
||||
</div>
|
||||
<button class="btn-icon btn-danger" onclick="deleteClosingDay('${day.id}')">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="3 6 5 6 21 6"></polyline>
|
||||
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
|
||||
</svg>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
}
|
||||
|
||||
function formatDateRange(startDate, endDate) {
|
||||
if (!startDate && !endDate) return '';
|
||||
if (startDate && !endDate) return `From ${utils.formatDateDisplay(startDate)}`;
|
||||
if (!startDate && endDate) return `Until ${utils.formatDateDisplay(endDate)}`;
|
||||
return `${utils.formatDateDisplay(startDate)} - ${utils.formatDateDisplay(endDate)}`;
|
||||
async function addClosingDay(data) {
|
||||
const response = await api.post(`/api/offices/${currentOfficeId}/closing-days`, data);
|
||||
if (response && response.ok) {
|
||||
await loadClosingDays(currentOfficeId);
|
||||
document.getElementById('closingDayModal').style.display = 'none';
|
||||
document.getElementById('closingDayForm').reset();
|
||||
} else {
|
||||
const error = await response.json();
|
||||
alert(error.detail || 'Impossibile aggiungere il giorno di chiusura');
|
||||
}
|
||||
}
|
||||
|
||||
async function loadGuarantees() {
|
||||
const response = await api.get(`/api/managers/${selectedManagerId}/guarantees`);
|
||||
async function deleteClosingDay(id) {
|
||||
if (!confirm('Eliminare questo giorno di chiusura?')) return;
|
||||
const response = await api.delete(`/api/offices/${currentOfficeId}/closing-days/${id}`);
|
||||
if (response && response.ok) {
|
||||
await loadClosingDays(currentOfficeId);
|
||||
}
|
||||
}
|
||||
|
||||
// Guarantees
|
||||
async function loadGuarantees(officeId) {
|
||||
const response = await api.get(`/api/offices/${officeId}/guarantees`);
|
||||
const container = document.getElementById('guaranteesList');
|
||||
|
||||
if (response && response.ok) {
|
||||
const guarantees = await response.json();
|
||||
|
||||
if (guarantees.length === 0) {
|
||||
container.innerHTML = '';
|
||||
container.innerHTML = '<p class="text-muted">Nessuna garanzia di parcheggio attiva.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = guarantees.map(g => {
|
||||
const dateRange = formatDateRange(g.start_date, g.end_date);
|
||||
return `
|
||||
container.innerHTML = guarantees.map(g => `
|
||||
<div class="rule-item">
|
||||
<div class="rule-info">
|
||||
<span class="rule-name">${g.user_name}</span>
|
||||
${dateRange ? `<span class="rule-date-range">${dateRange}</span>` : ''}
|
||||
<strong>${g.user_name || 'Utente sconosciuto'}</strong>
|
||||
<span class="rule-dates">
|
||||
${g.start_date ? 'Dal ' + utils.formatDateDisplay(g.start_date) : 'Da sempre'}
|
||||
${g.end_date ? ' al ' + utils.formatDateDisplay(g.end_date) : ''}
|
||||
</span>
|
||||
${g.notes ? `<span class="rule-note">${g.notes}</span>` : ''}
|
||||
</div>
|
||||
<button class="btn-icon btn-danger" onclick="deleteGuarantee('${g.id}')">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="3 6 5 6 21 6"></polyline>
|
||||
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
|
||||
</svg>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
`}).join('');
|
||||
`).join('');
|
||||
}
|
||||
}
|
||||
|
||||
async function loadExclusions() {
|
||||
const response = await api.get(`/api/managers/${selectedManagerId}/exclusions`);
|
||||
const container = document.getElementById('exclusionsList');
|
||||
|
||||
async function addGuarantee(data) {
|
||||
const response = await api.post(`/api/offices/${currentOfficeId}/guarantees`, data);
|
||||
if (response && response.ok) {
|
||||
const exclusions = await response.json();
|
||||
if (exclusions.length === 0) {
|
||||
container.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = exclusions.map(e => {
|
||||
const dateRange = formatDateRange(e.start_date, e.end_date);
|
||||
return `
|
||||
<div class="rule-item">
|
||||
<div class="rule-info">
|
||||
<span class="rule-name">${e.user_name}</span>
|
||||
${dateRange ? `<span class="rule-date-range">${dateRange}</span>` : ''}
|
||||
</div>
|
||||
<button class="btn-icon btn-danger" onclick="deleteExclusion('${e.id}')">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="3 6 5 6 21 6"></polyline>
|
||||
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
`}).join('');
|
||||
}
|
||||
}
|
||||
|
||||
// Delete functions
|
||||
async function deleteClosingDay(id) {
|
||||
if (!confirm('Delete this closing day?')) return;
|
||||
const response = await api.delete(`/api/managers/${selectedManagerId}/closing-days/${id}`);
|
||||
if (response && response.ok) {
|
||||
await loadClosingDays();
|
||||
await loadGuarantees(currentOfficeId);
|
||||
document.getElementById('guaranteeModal').style.display = 'none';
|
||||
document.getElementById('guaranteeForm').reset();
|
||||
} else {
|
||||
const error = await response.json();
|
||||
alert(error.detail || 'Impossibile aggiungere la garanzia');
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteGuarantee(id) {
|
||||
if (!confirm('Remove this parking guarantee?')) return;
|
||||
const response = await api.delete(`/api/managers/${selectedManagerId}/guarantees/${id}`);
|
||||
if (!confirm('Eliminare questa garanzia?')) return;
|
||||
const response = await api.delete(`/api/offices/${currentOfficeId}/guarantees/${id}`);
|
||||
if (response && response.ok) {
|
||||
await loadGuarantees();
|
||||
await loadGuarantees(currentOfficeId);
|
||||
}
|
||||
}
|
||||
|
||||
// Exclusions
|
||||
async function loadExclusions(officeId) {
|
||||
const response = await api.get(`/api/offices/${officeId}/exclusions`);
|
||||
const container = document.getElementById('exclusionsList');
|
||||
|
||||
if (response && response.ok) {
|
||||
const exclusions = await response.json();
|
||||
|
||||
if (exclusions.length === 0) {
|
||||
container.innerHTML = '<p class="text-muted">Nessuna esclusione attiva.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = exclusions.map(e => `
|
||||
<div class="rule-item">
|
||||
<div class="rule-info">
|
||||
<strong>${e.user_name || 'Utente sconosciuto'}</strong>
|
||||
<span class="rule-dates">
|
||||
${e.start_date ? 'Dal ' + utils.formatDateDisplay(e.start_date) : 'Da sempre'}
|
||||
${e.end_date ? ' al ' + utils.formatDateDisplay(e.end_date) : ''}
|
||||
</span>
|
||||
${e.notes ? `<span class="rule-note">${e.notes}</span>` : ''}
|
||||
</div>
|
||||
<button class="btn-icon btn-danger" onclick="deleteExclusion('${e.id}')">
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
}
|
||||
|
||||
async function addExclusion(data) {
|
||||
const response = await api.post(`/api/offices/${currentOfficeId}/exclusions`, data);
|
||||
if (response && response.ok) {
|
||||
await loadExclusions(currentOfficeId);
|
||||
document.getElementById('exclusionModal').style.display = 'none';
|
||||
document.getElementById('exclusionForm').reset();
|
||||
} else {
|
||||
const error = await response.json();
|
||||
alert(error.detail || 'Impossibile aggiungere l\'esclusione');
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteExclusion(id) {
|
||||
if (!confirm('Remove this parking exclusion?')) return;
|
||||
const response = await api.delete(`/api/managers/${selectedManagerId}/exclusions/${id}`);
|
||||
if (!confirm('Eliminare questa esclusione?')) return;
|
||||
const response = await api.delete(`/api/offices/${currentOfficeId}/exclusions/${id}`);
|
||||
if (response && response.ok) {
|
||||
await loadExclusions();
|
||||
await loadExclusions(currentOfficeId);
|
||||
}
|
||||
}
|
||||
|
||||
function setupEventListeners() {
|
||||
// Manager selection
|
||||
document.getElementById('managerSelect').addEventListener('change', (e) => {
|
||||
selectManager(e.target.value);
|
||||
});
|
||||
function populateUserSelects() {
|
||||
const selects = ['guaranteeUser', 'exclusionUser'];
|
||||
selects.forEach(id => {
|
||||
const select = document.getElementById(id);
|
||||
const currentVal = select.value;
|
||||
select.innerHTML = '<option value="">Seleziona utente...</option>';
|
||||
|
||||
// Weekly closing day checkboxes
|
||||
document.querySelectorAll('#weeklyClosingDays input[type="checkbox"]').forEach(cb => {
|
||||
cb.addEventListener('change', async (e) => {
|
||||
const weekday = parseInt(e.target.dataset.weekday);
|
||||
|
||||
if (e.target.checked) {
|
||||
// Add weekly closing day
|
||||
const response = await api.post(`/api/managers/${selectedManagerId}/weekly-closing-days`, { weekday });
|
||||
if (!response || !response.ok) {
|
||||
e.target.checked = false;
|
||||
const error = await response.json();
|
||||
alert(error.detail || 'Failed to add weekly closing day');
|
||||
}
|
||||
} else {
|
||||
// Remove weekly closing day - need to find the ID first
|
||||
const getResponse = await api.get(`/api/managers/${selectedManagerId}/weekly-closing-days`);
|
||||
if (getResponse && getResponse.ok) {
|
||||
const days = await getResponse.json();
|
||||
const day = days.find(d => d.weekday === weekday);
|
||||
if (day) {
|
||||
const deleteResponse = await api.delete(`/api/managers/${selectedManagerId}/weekly-closing-days/${day.id}`);
|
||||
if (!deleteResponse || !deleteResponse.ok) {
|
||||
e.target.checked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
officeUsers.forEach(user => {
|
||||
const option = document.createElement('option');
|
||||
option.value = user.id;
|
||||
option.textContent = user.name;
|
||||
select.appendChild(option);
|
||||
});
|
||||
});
|
||||
|
||||
// Modal openers
|
||||
document.getElementById('addClosingDayBtn').addEventListener('click', () => {
|
||||
document.getElementById('closingDayForm').reset();
|
||||
document.getElementById('closingDayModal').style.display = 'flex';
|
||||
if (currentVal) select.value = currentVal;
|
||||
});
|
||||
|
||||
document.getElementById('addGuaranteeBtn').addEventListener('click', () => {
|
||||
document.getElementById('guaranteeForm').reset();
|
||||
document.getElementById('guaranteeModal').style.display = 'flex';
|
||||
});
|
||||
|
||||
document.getElementById('addExclusionBtn').addEventListener('click', () => {
|
||||
document.getElementById('exclusionForm').reset();
|
||||
document.getElementById('exclusionModal').style.display = 'flex';
|
||||
});
|
||||
|
||||
// Modal closers
|
||||
['closeClosingDayModal', 'cancelClosingDay'].forEach(id => {
|
||||
document.getElementById(id).addEventListener('click', () => {
|
||||
document.getElementById('closingDayModal').style.display = 'none';
|
||||
});
|
||||
});
|
||||
|
||||
['closeGuaranteeModal', 'cancelGuarantee'].forEach(id => {
|
||||
document.getElementById(id).addEventListener('click', () => {
|
||||
document.getElementById('guaranteeModal').style.display = 'none';
|
||||
});
|
||||
});
|
||||
|
||||
['closeExclusionModal', 'cancelExclusion'].forEach(id => {
|
||||
document.getElementById(id).addEventListener('click', () => {
|
||||
document.getElementById('exclusionModal').style.display = 'none';
|
||||
});
|
||||
});
|
||||
|
||||
// Form submissions
|
||||
document.getElementById('closingDayForm').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
const data = {
|
||||
date: document.getElementById('closingDate').value,
|
||||
reason: document.getElementById('closingReason').value || null
|
||||
};
|
||||
const response = await api.post(`/api/managers/${selectedManagerId}/closing-days`, data);
|
||||
if (response && response.ok) {
|
||||
document.getElementById('closingDayModal').style.display = 'none';
|
||||
await loadClosingDays();
|
||||
} else {
|
||||
const error = await response.json();
|
||||
alert(error.detail || 'Failed to add closing day');
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('guaranteeForm').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
const data = {
|
||||
user_id: document.getElementById('guaranteeUser').value,
|
||||
start_date: document.getElementById('guaranteeStartDate').value || null,
|
||||
end_date: document.getElementById('guaranteeEndDate').value || null
|
||||
};
|
||||
const response = await api.post(`/api/managers/${selectedManagerId}/guarantees`, data);
|
||||
if (response && response.ok) {
|
||||
document.getElementById('guaranteeModal').style.display = 'none';
|
||||
await loadGuarantees();
|
||||
} else {
|
||||
const error = await response.json();
|
||||
alert(error.detail || 'Failed to add guarantee');
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('exclusionForm').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
const data = {
|
||||
user_id: document.getElementById('exclusionUser').value,
|
||||
start_date: document.getElementById('exclusionStartDate').value || null,
|
||||
end_date: document.getElementById('exclusionEndDate').value || null
|
||||
};
|
||||
const response = await api.post(`/api/managers/${selectedManagerId}/exclusions`, data);
|
||||
if (response && response.ok) {
|
||||
document.getElementById('exclusionModal').style.display = 'none';
|
||||
await loadExclusions();
|
||||
} else {
|
||||
const error = await response.json();
|
||||
alert(error.detail || 'Failed to add exclusion');
|
||||
}
|
||||
});
|
||||
|
||||
// Modal background clicks
|
||||
utils.setupModalClose('closingDayModal');
|
||||
utils.setupModalClose('guaranteeModal');
|
||||
utils.setupModalClose('exclusionModal');
|
||||
}
|
||||
|
||||
// Make delete functions globally accessible
|
||||
function setupEventListeners() {
|
||||
// Office select
|
||||
document.getElementById('officeSelect').addEventListener('change', (e) => {
|
||||
loadOfficeRules(e.target.value);
|
||||
});
|
||||
|
||||
// Save Weekly closing days
|
||||
const saveBtn = document.getElementById('saveWeeklyClosingDaysBtn');
|
||||
if (saveBtn) {
|
||||
saveBtn.addEventListener('click', saveWeeklyClosingDays);
|
||||
}
|
||||
|
||||
// Modals
|
||||
const modals = [
|
||||
{ id: 'closingDayModal', btn: 'addClosingDayBtn', close: 'closeClosingDayModal', cancel: 'cancelClosingDay' },
|
||||
{ id: 'guaranteeModal', btn: 'addGuaranteeBtn', close: 'closeGuaranteeModal', cancel: 'cancelGuarantee' },
|
||||
{ id: 'exclusionModal', btn: 'addExclusionBtn', close: 'closeExclusionModal', cancel: 'cancelExclusion' }
|
||||
];
|
||||
|
||||
modals.forEach(m => {
|
||||
document.getElementById(m.btn).addEventListener('click', () => {
|
||||
if (m.id !== 'closingDayModal') populateUserSelects();
|
||||
document.getElementById(m.id).style.display = 'flex';
|
||||
});
|
||||
document.getElementById(m.close).addEventListener('click', () => {
|
||||
document.getElementById(m.id).style.display = 'none';
|
||||
});
|
||||
document.getElementById(m.cancel).addEventListener('click', () => {
|
||||
document.getElementById(m.id).style.display = 'none';
|
||||
});
|
||||
utils.setupModalClose(m.id);
|
||||
});
|
||||
|
||||
// Forms
|
||||
document.getElementById('closingDayForm').addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
addClosingDay({
|
||||
date: document.getElementById('closingDate').value,
|
||||
end_date: document.getElementById('closingEndDate').value || null,
|
||||
reason: document.getElementById('closingReason').value || null
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('guaranteeForm').addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
addGuarantee({
|
||||
user_id: document.getElementById('guaranteeUser').value,
|
||||
start_date: document.getElementById('guaranteeStartDate').value || null,
|
||||
end_date: document.getElementById('guaranteeEndDate').value || null,
|
||||
notes: document.getElementById('guaranteeNotes').value || null
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('exclusionForm').addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
addExclusion({
|
||||
user_id: document.getElementById('exclusionUser').value,
|
||||
start_date: document.getElementById('exclusionStartDate').value || null,
|
||||
end_date: document.getElementById('exclusionEndDate').value || null,
|
||||
notes: document.getElementById('exclusionNotes').value || null
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Global functions
|
||||
window.deleteClosingDay = deleteClosingDay;
|
||||
window.deleteGuarantee = deleteGuarantee;
|
||||
window.deleteExclusion = deleteExclusion;
|
||||
|
||||
Reference in New Issue
Block a user