goiintra/public_html/js/install_wait_modal.js

1091 lines
30 KiB
JavaScript

window.InstallWait = window.InstallWait || {
step: 1,
customer: null,
job: null,
category: 0,
pickup: [],
schedule: { date:'', note:'' },
photos: []
};
const IW_CATEGORY_COLORS = {
0: 'transparent', // 없음
1: '#ff4d4f',
2: '#1677ff',
3: '#52c41a',
4: '#fa9614',
5: '#9254de'
};
/* 슬라이드 이동 (100vw 기준) */
function goInstallWaitStep(step) {
const wrapper = document.querySelector('.install-wait-steps-wrapper');
if (!wrapper) return; // DOM 아직 없으면 그냥 나감
wrapper.style.transform = `translateX(-${(step - 1) * 100}%)`;
}
/* ============================
STEP 1
============================ */
function initAddInstallWaitModal() {
const input = document.getElementById('customerSearchInput');
const result = document.getElementById('customerSearchResult');
const btnNext = document.getElementById('btnStep1Next');
$('#addInstallWaitModal')
.one('shown.bs.modal', function () {
const input = document.getElementById('customerSearchInput');
if (input) input.focus();
});
btnNext.onclick = () => {
if (!InstallWait.customer) return;
goInstallWaitStep(2);
initInstallWaitStep2();
};
let timer = null;
input.addEventListener('input', function () {
const keyword = this.value.trim();
clearTimeout(timer);
if (keyword.length < 2) {
result.innerHTML = '';
btnNext.disabled = true;
return;
}
timer = setTimeout(() => {
api('search_customer', { keyword }, rows => {
if (!rows || !rows.length) {
result.innerHTML = `<div class="text-muted text-center py-3">No customer found<br>The customer may already be in the wait list or already assigned.</div>`;
return;
}
result.innerHTML = rows.map(r => `
<div class="p-2 border-bottom customer-row"
data-uid="${r.c_uid}"
data-account="${r.c_accountno}"
data-name="${r.c_name}"
data-address="${r.c_address}"
data-city="${r.c_city}"
data-postal="${r.c_postal}"
data-phone="${r.c_phone || ''}">
<div class="fw-bold">${r.c_accountno} - ${r.c_name}</div>
<div class="small text-muted">${r.c_address}, ${r.c_city}</div>
</div>
`).join('');
bindCustomerRowEvents();
});
}, 300);
});
}
function bindCustomerRowEvents() {
const btnNext = document.getElementById('btnStep1Next');
let selected = null;
document.querySelectorAll('.customer-row').forEach(row => {
row.onclick = function () {
if (selected === this) {
this.classList.remove('selected');
selected = null;
InstallWait.customer = null;
btnNext.disabled = true;
btnNext.classList.remove('active-step');
return;
}
document.querySelectorAll('.customer-row').forEach(r => r.classList.remove('selected'));
this.classList.add('selected');
selected = this;
InstallWait.customer = {
uid: this.dataset.uid,
account: this.dataset.account,
name: this.dataset.name,
address: this.dataset.address,
city: this.dataset.city,
postal: this.dataset.postal,
phone: this.dataset.phone
};
btnNext.disabled = false;
btnNext.classList.add('active-step');
};
});
}
/* ============================
STEP 2
============================ */
function syncCustomerFromStep2() {
const map = {
account: 'iwCustomerAccount',
name: 'iwCustomerName',
address: 'iwCustomerAddress',
city: 'iwCustomerCity',
postal: 'iwCustomerPostal',
phone: 'iwCustomerPhone'
};
Object.keys(map).forEach(k => {
InstallWait.customer[k] =
document.getElementById(map[k]).value.trim();
});
}
function syncCustomerToInputs() {
const c = InstallWait.customer || {};
iwCustomerAccount.value = c.account || '';
iwCustomerName.value = c.name || '';
iwCustomerAddress.value = c.address || '';
iwCustomerCity.value = c.city || '';
iwCustomerPostal.value = c.postal || '';
iwCustomerPhone.value = c.phone || '';
}
function initInstallWaitStep2() {
syncCustomerToInputs();
document.getElementById('btnStep2Back').onclick = () => {
goInstallWaitStep(1);
};
bindJobSelection();
bindStep2Next();
}
function bindJobSelection() {
const cards = document.querySelectorAll('.iw-job-card');
const btnNext = btnStep2Next;
let selected = null;
cards.forEach(card => {
card.onclick = () => {
if (selected === card) {
card.classList.remove('active');
selected = null;
InstallWait.job = null;
btnNext.disabled = true;
return;
}
cards.forEach(c => c.classList.remove('active'));
card.classList.add('active');
selected = card;
InstallWait.job = { type: card.dataset.job };
btnNext.disabled = false;
btnNext.classList.add('active-step');
};
});
}
function bindStep2Next() {
btnStep2Next.onclick = () => {
if (!InstallWait.job) return;
syncCustomerFromStep2();
const memberUid = document.getElementById('installWaitContext').dataset.memberUid || '';
api('install_wait_create_draft', {
c_uid: InstallWait.customer.uid,
job_type: InstallWait.job.type,
account: InstallWait.customer.account,
name: InstallWait.customer.name,
address: InstallWait.customer.address,
city: InstallWait.customer.city,
postal: InstallWait.customer.postal,
phone: InstallWait.customer.phone,
member_uid: memberUid
}, res => {
if (!res || !res.ok || !res.iw_uid) return;
InstallWait.iw_uid = res.iw_uid;
goInstallWaitStep(3);
initInstallWaitStep3();
});
};
}
/* ============================
STEP 3
============================ */
function initInstallWaitStep3() {
btnStep3Back.onclick = () => {
// id 없으면 그냥 back
if (!InstallWait.iw_uid) {
goInstallWaitStep(2);
return;
}
const iw_uid = InstallWait.iw_uid;
if (!confirm('Delete this install request?')) return;
btnStep3Back.disabled = true;
api('install_wait_delete', { iw_uid }, (res) => {
btnStep3Back.disabled = false;
if (!res || !res.ok) {
// alert(res?.msg || 'Delete failed');
showPopupMessage(res?.msg || 'Delete failed', 'error', 1500);
return;
} else {
showPopupMessage('Successfully Deleted', 'success', 1500);
}
const rowEl = btnStep3Back.closest('.install-wait-row');
if (rowEl) rowEl.remove();
// 로컬 상태 초기화
InstallWait.iw_uid = null;
InstallWait.pickup = [];
InstallWait.schedule = { date:'', note:'' };
InstallWait.photos = [];
// Step3 UI 잔상 제거
const area = document.getElementById('iwStep3ContainerArea');
if (area) area.innerHTML = '';
goInstallWaitStep(2);
initInstallWaitStep2();
return;
});
};
// Complete 버튼
btnStep3Complete.onclick = () => {
if (!InstallWait.iw_uid) {
// alert('Invalid install wait');
showPopupMessage('Invalid install wait', 'error', 1500);
return;
}
// 컨테이너 선택여부
if (!validateContainersBeforeComplete()) {
return;
}
// set parameter
const twoOn = document.getElementById('btnTwoPerson').classList.contains('iw-toggle-on');
const recOn = document.getElementById('btnRecurring').classList.contains('iw-toggle-on');
const oilOn = document.getElementById('btnNeedOilPickup').classList.contains('iw-toggle-on');
const payload = {
iw_uid: InstallWait.iw_uid,
request_at: document.getElementById('iwRequestDate').value || null,
due_date: document.getElementById('iwScheduleDate').value || null,
lock_date: document.getElementById('iwLockDate').checked ? 1 : 0,
request_by: document.getElementById('iwRequestBy').value || null,
request_note: document.getElementById('iwRequestNote').value || null,
cs_note: document.getElementById('iwCsNote').value || null,
work_note: document.getElementById('iwWorkNote').value || null,
person_cnt: twoOn ? 2 : null,
person_reason: twoOn ? document.getElementById('iwTwoPersonReason').value : null,
scheduled: recOn ? 1 : 0,
scheduled_cycle: recOn ? document.getElementById('iwRecurringDays').value: 0,
need_oil: oilOn ? 1 : 0,
category: InstallWait.category || 0
};
btnStep3Complete.disabled = true;
// 1단계: install_wait complete
api('install_wait_complete', payload, (res) => {
if (!res || !res.ok) {
btnStep3Complete.disabled = false;
//alert('Failed to complete install request');
showPopupMessage('Save failed', 'error', 1500);
return;
}
// 2단계: 사진 업로드 있을 때
const files = document.getElementById('iwPhotos').files;
if (!files || files.length === 0) {
showPopupMessage('Successfully Saved', 'success', 1000);
finishInstallWaitComplete();
return;
}
const memberUid = document.getElementById('installWaitContext').dataset.memberUid || '';
const fd = new FormData();
fd.append('actionStr', 'ADDIMAGE');
fd.append('i_type', 'install_order');
fd.append('i_customeruid', InstallWait.customer.uid);
fd.append('i_memberuid', memberUid);
fd.append('i_createdby', memberUid);
fd.append('i_note', 'Before Install');
fd.append('i_sourceuid', InstallWait.iw_uid);
[...files].forEach(file => {
fd.append('upload_file[]', file);
});
fetch('/lib/user_process.php', {
method: 'POST',
body: fd
})
.then(() => {
showPopupMessage('Successfully Saved', 'success', 1000);
finishInstallWaitComplete();
})
.catch(() => {
//alert('Install completed, but image upload failed');
showPopupMessage('Saved (photo failed)', 'error', 1500);
finishInstallWaitComplete();
});
});
};
InstallWait.pickup = InstallWait.pickup || [];
InstallWait.category = 0;
setStep3Title();
renderStep3ActionBoxes();
loadCurrentContainersIfNeeded();
renderCategorySelector();
bindStep3Toggles();
fillRequestBySelect('Customer');
initInstallWaitDatePickers();
}
function setStep3Title() {
const jobLabel = InstallWait.job?.type || '';
const acct = InstallWait.customer?.account ? ` of ${InstallWait.customer.account}` : '';
const titleEl = document.getElementById('iwStep3Title');
if (titleEl) titleEl.innerText = `Step 3 of 3 - ${jobLabel}${acct} Detail`;
}
function renderStep3ActionBoxes() {
const area = document.getElementById('iwStep3ContainerArea');
area.innerHTML = '';
const jobType = InstallWait.job?.type;
if (!jobType) return;
// Row 1 : CURRENT | PICKUP
if (['PICKUP','EXCHANGE','INSTALL','RELOCATE','CLEAN'].includes(jobType)) {
area.insertAdjacentHTML('beforeend', `
<div class="iw-action-row">
${renderActionBox('CURRENT')}
<div><i class="bi bi-arrow-left-right"></i></div>
${renderActionBox('PICKUP')}
</div>
`);
}
// Row 2 : SELECT | INSTALL
if (['INSTALL','EXCHANGE'].includes(jobType)) {
area.insertAdjacentHTML('beforeend', `
<div class="iw-action-row">
${renderActionBox('SELECT')}
<div><i class="bi bi-arrow-left-right"></i></div>
${renderActionBox('INSTALL')}
</div>
`);
}
bindSelectInstallEvents();
}
function renderActionBox(action) {
const icon = {
CURRENT: 'bi-archive',
PICKUP: 'bi-dash-circle',
SELECT: 'bi-plus-square',
INSTALL: 'bi-plus-circle',
RELOCATE: 'bi-arrow-left-right'
}[action] || 'bi-box';
const colorClass =
action === 'PICKUP' ? 'pickup'
: action === 'INSTALL' ? 'install'
: '';
let content = '';
// CURRENT
if (action === 'CURRENT') {
content = `<div class="text-muted small">Loading...</div>`;
}
// SELECT 전용 UI
if (action === 'SELECT') {
content = renderSelectInstallUI();
}
return `
<div class="task-action-box" data-action="${action}">
<div class="task-action-title ${colorClass}">
<i class="bi ${icon}"></i> ${action}
</div>
<div class="mt-2 container-chips" data-action="${action}">
${content}
</div>
</div>
`;
}
function renderCategorySelector() {
const wrap = document.getElementById('iwCategorySelectorWrap');
if (!wrap) return;
wrap.innerHTML = `
<div class="iw-cat-box">
${[0,1,2,3,4,5].map(i => `
<button type="button"
class="iw-cat-btn ${InstallWait.category == i ? 'active' : ''}"
data-value="${i}"
style="
width:18px;
height:18px;
border-radius:50%;
border:1px solid;
background:${IW_CATEGORY_COLORS[i]};
">
</button>
`).join('')}
</div>
`;
}
function countTaskChips(action) {
// action: 'PICKUP' | 'INSTALL'
const wrap = document.querySelector(`.container-chips[data-action="${action}"]`);
if (!wrap) return 0;
// 프로젝트에서 chip 클래스가 여러 개일 수 있어서 span.chip 기준으로 카운트
return wrap.querySelectorAll('span.chip').length;
}
function validateContainersBeforeComplete() {
const jobType = (InstallWait.job?.type || '').toUpperCase();
const pickupCnt = countTaskChips('PICKUP');
const installCnt = countTaskChips('INSTALL');
// EXCHANGE: 둘 다 있어야 함
if (jobType === 'EXCHANGE') {
if (pickupCnt < 1 || installCnt < 1) {
//alert('EXCHANGE requires containers in BOTH Pickup and Install. Please select containers.');
showPopupMessage('Please select containers.', 'error', 1500);
return false;
}
return true;
}
// INSTALL: install에 있어야 함
if (jobType === 'INSTALL') {
if (installCnt < 1) {
//alert('Please select at least 1 container in Install.');
showPopupMessage('Please select containers.', 'error', 1500);
return false;
}
return true;
}
// PICKUP: pickup에 있어야 함
if (jobType === 'PICKUP') {
if (pickupCnt < 1) {
//alert('Please select at least 1 container in Pickup.');
showPopupMessage('Please select containers.', 'error', 1500);
return false;
}
return true;
}
// 다른 타입(혹시 RELOCATE/CLEAN 등 Step3에서도 쓰면 정책 정해서 추가)
return true;
}
function loadCurrentContainersIfNeeded(onDone) {
const jobType = InstallWait.job?.type;
if (!['PICKUP','EXCHANGE','INSTALL','RELOCATE','CLEAN'].includes(jobType)) {
if (typeof onDone === 'function') onDone();
return;
}
const wrap = document.querySelector('.container-chips[data-action="CURRENT"]');
if (!wrap) {
if (typeof onDone === 'function') onDone();
return;
}
api('get_customer_containers_active',
{ c_uid: InstallWait.customer.uid },
rows => {
if (!rows || rows.length === 0) {
wrap.innerHTML = `<div class="text-muted small">No active containers</div>`;
if (typeof onDone === 'function') onDone();
return;
}
wrap.innerHTML = rows.map(renderContainerChip).join('');
bindCurrentContainerChipEvents();
if (typeof onDone === 'function') onDone();
}
);
}
function renderContainerChip(c) {
const type = (c.cc_type || '').toUpperCase();
const icon = getContainerIconByType(type);
const isRestaurantOwned = c.cc_owner_type === 'O';
const chipClass = isRestaurantOwned
? 'chip chip-restaurant iw-current-chip'
: 'chip chip-company iw-current-chip';
const ownerBadge = isRestaurantOwned
? '<span class="chip-owner">O</span>'
: '';
const flags =
(c.cc_has_lock === 'Y' ? ' <i class="bi bi-lock-fill"></i>' : '') +
(c.cc_has_wheel === 'Y' ? ' <i class="bi bi-gear-fill"></i>' : '') +
(c.cc_has_woodframe === 'Y'
? ' <i class="bi bi-bounding-box-circles"></i>'
: '');
const used = c.cc_is_used === 'Y' ? 'Used ' : '';
return `
<span class="${chipClass}"
data-type="${c.cc_type}"
data-capacity="${c.cc_capacity || ''}"
data-is_used="${c.cc_is_used || 'N'}"
data-owner_type="${c.cc_owner_type || 'C'}"
data-has_lock="${c.cc_has_lock || 'N'}"
data-has_wheel="${c.cc_has_wheel || 'N'}"
data-has_frame="${c.cc_has_woodframe || 'N'}">
${ownerBadge}
<i class="bi ${icon}"></i>
${used}${c.cc_type}
${flags}
</span>
`;
}
function bindCurrentContainerChipEvents() {
const jobType = InstallWait.job?.type;
const disableClick = ['INSTALL','RELOCATE','CLEAN'].includes(jobType);
const currentWrap = document.querySelector('.container-chips[data-action="CURRENT"]');
const pickupWrap = document.querySelector('.container-chips[data-action="PICKUP"]');
if (!currentWrap || !pickupWrap) return;
currentWrap.querySelectorAll('.iw-current-chip').forEach(chip => {
chip.onclick = () => {
if (disableClick) {
// 클릭은 막고, 시각적 피드백만 줄 수도 있음
chip.classList.add('disabled');
return;
}
pickupWrap.appendChild(chip);
upsertPickupContainers();
bindPickupContainerChipEvents();
};
});
}
function bindPickupContainerChipEvents() {
const currentWrap = document.querySelector('.container-chips[data-action="CURRENT"]');
const pickupWrap = document.querySelector('.container-chips[data-action="PICKUP"]');
if (!currentWrap || !pickupWrap) return;
pickupWrap.querySelectorAll('.iw-current-chip').forEach(chip => {
chip.onclick = () => {
// UI 이동
currentWrap.appendChild(chip);
// PICKUP 기준으로 다시 업설트
upsertPickupContainers();
// 이벤트 재바인딩
bindCurrentContainerChipEvents();
};
});
}
function chipKeyFromDataset(ds){
const norm = v => (v ?? '').toString();
return [
norm(ds.type).toUpperCase(),
norm(ds.capacity),
norm(ds.is_used),
norm(ds.owner_type),
norm(ds.has_lock),
norm(ds.has_wheel),
norm(ds.has_frame),
].join('|');
}
function chipKeyFromIwcRow(r){
const norm = v => (v ?? '').toString();
return [
norm(r.iwc_type).toUpperCase(),
norm(r.iwc_capacity),
norm(r.iwc_is_used || 'N'),
norm(r.iwc_owner_type || 'C'),
norm(r.iwc_has_lock || 'N'),
norm(r.iwc_has_wheel || 'N'),
norm(r.iwc_has_woodframe || 'N'),
].join('|');
}
function applyPickupFromDBToCurrent(pickupRows) {
const currentWrap = document.querySelector('.container-chips[data-action="CURRENT"]');
const pickupWrap = document.querySelector('.container-chips[data-action="PICKUP"]');
if (!currentWrap || !pickupWrap) return;
// key → remaining count
const pickupCountMap = {};
(pickupRows || []).forEach(r => {
const key = chipKeyFromIwcRow(r);
pickupCountMap[key] = (pickupCountMap[key] || 0) + 1;
});
// CURRENT에서 하나씩 매칭
[...currentWrap.querySelectorAll('.iw-current-chip')].forEach(chip => {
const key = chipKeyFromDataset(chip.dataset);
if (pickupCountMap[key] > 0) {
pickupWrap.appendChild(chip);
pickupCountMap[key]--; // ⭐ 하나 소비
}
});
bindCurrentContainerChipEvents();
bindPickupContainerChipEvents();
}
function upsertPickupContainers() {
const pickupWrap = document.querySelector('.container-chips[data-action="PICKUP"]');
if (!pickupWrap) return;
const items = [...pickupWrap.querySelectorAll('.iw-current-chip')].map(el => ({
action: 'PICKUP',
type: el.dataset.type,
capacity: el.dataset.capacity || null,
is_used: el.dataset.is_used || 'N',
owner_type: el.dataset.owner_type || 'C',
has_lock: el.dataset.has_lock || 'N',
has_wheel: el.dataset.has_wheel || 'N',
has_frame: el.dataset.has_frame || 'N'
}));
api('install_wait_upsert_containers', {
iw_uid: InstallWait.iw_uid,
action: 'PICKUP',
items
});
}
function renderSelectInstallUI() {
const binOptions = Object.entries(window.IW_BINS || {})
.map(([key, label]) =>
`<option value="${key}">${label}</option>`
).join('');
return `
<div class="iw-select-install">
<div class="d-flex align-items-center mb-2">
<!-- 왼쪽: 옵션들 -->
<div class="d-flex gap-2 align-items-center flex-grow-1">
<button type="button" id="iwSelectUsed"
class="btn btn-sm btn-outline-secondary">
Used
</button>
<select id="iwSelectType" class="form-select form-select-sm">
<option value="">Select bin</option>
${binOptions}
</select>
<input type="number"
id="iwSelectCapacity"
class="form-control form-control-sm iw-inline-ctrl"
placeholder="L"
readonly>
<button type="button"
class="btn btn-sm btn-outline-secondary iw-opt"
data-opt="L" title="Lock">
<i class="bi bi-lock-fill"></i>
</button>
<button type="button"
class="btn btn-sm btn-outline-secondary iw-opt"
data-opt="W" title="Wheel">
<i class="bi bi-gear-fill"></i>
</button>
<button type="button"
class="btn btn-sm btn-outline-secondary iw-opt"
data-opt="F" title="Frame">
<i class="bi bi-bounding-box-circles"></i>
</button>
</div>
<!-- 오른쪽: Add -->
<button type="button"
id="iwAddInstall"
class="btn btn-sm btn-success ms-2 iw-add-btn">
<i class="bi bi-plus-lg"></i>
<span class="ms-1">Add</span>
</button>
</div>
</div>
`;
}
function bindSelectInstallEvents() {
const usedBtn = document.getElementById('iwSelectUsed');
const typeSel = document.getElementById('iwSelectType');
const capInp = document.getElementById('iwSelectCapacity');
if (!usedBtn || !typeSel) return;
usedBtn.onclick = () => {
usedBtn.classList.toggle('active');
};
// 타입 선택 시 용량 자동 표시
typeSel.onchange = () => {
const val = typeSel.value;
// CB 는 직접 입력
if (val === 'CB') {
capInp.readOnly = false;
capInp.value = '';
capInp.focus();
return;
} else if (val === 'D') {
capInp.value = '200';
return;
}
capInp.readOnly = true;
const m = val.match(/^(\d+)/);
capInp.value = m ? m[1] : '';
};
// 악세사리 토글
document.querySelectorAll('.iw-opt').forEach(btn => {
btn.onclick = () => btn.classList.toggle('active');
});
// Add → INSTALL 이동
document.getElementById('iwAddInstall').onclick = addInstallFromSelect;
}
function addInstallFromSelect() {
const type = document.getElementById('iwSelectType').value;
if (!type) return showPopupMessage('Select container type.', 'error', 1500); //alert('Select container type');
const capacity = document.getElementById('iwSelectCapacity').value || null;
const is_used = document.getElementById('iwSelectUsed').classList.contains('active') ? 'Y' : 'N';
const has_lock = document.querySelector('.iw-opt[data-opt="L"]').classList.contains('active') ? 'Y' : 'N';
const has_wheel = document.querySelector('.iw-opt[data-opt="W"]').classList.contains('active') ? 'Y' : 'N';
const has_frame = document.querySelector('.iw-opt[data-opt="F"]').classList.contains('active') ? 'Y' : 'N';
const installWrap = document.querySelector('.container-chips[data-action="INSTALL"]');
const icon = getContainerIconByType(type);
const chip = `
<span class="chip chip-company iw-install-chip"
data-type="${type}"
data-capacity="${capacity || ''}"
data-is_used="${is_used}"
data-has_lock="${has_lock}"
data-has_wheel="${has_wheel}"
data-has_frame="${has_frame}">
<i class="bi ${icon}"></i>
${is_used === 'Y' ? 'Used ' : ''}${type}
${has_lock === 'Y' ? ' <i class="bi bi-lock-fill"></i>' : ''}
${has_wheel === 'Y' ? ' <i class="bi bi-gear-fill"></i>' : ''}
${has_frame === 'Y' ? ' <i class="bi bi-bounding-box-circles"></i>' : ''}
</span>
`;
installWrap.insertAdjacentHTML('beforeend', chip);
bindInstallChipEvents();
upsertInstallContainers();
}
function upsertInstallContainers() {
const wrap = document.querySelector('.container-chips[data-action="INSTALL"]');
const items = [...wrap.querySelectorAll('.iw-install-chip')].map(el => ({
action: 'INSTALL',
type: el.dataset.type,
capacity: el.dataset.capacity || null,
is_used: el.dataset.is_used || 'N',
has_lock: el.dataset.has_lock || 'N',
has_wheel: el.dataset.has_wheel || 'N',
has_frame: el.dataset.has_frame || 'N',
owner_type: 'C'
}));
api('install_wait_upsert_containers', {
iw_uid: InstallWait.iw_uid,
action: 'INSTALL',
items
});
}
function bindInstallChipEvents() {
const installWrap = document.querySelector('.container-chips[data-action="INSTALL"]');
if (!installWrap) return;
installWrap.querySelectorAll('.iw-install-chip').forEach(chip => {
chip.onclick = () => {
chip.remove();
upsertInstallContainers();
};
});
}
function initInstallWaitDatePickers() {
if (!$.fn.datepicker) return;
$('.date-picker-form').datepicker({
dateFormat: 'yy-mm-dd',
changeMonth: true,
changeYear: true
});
}
function fillRequestBySelect(selectedValue = 'Customer') {
const sel = document.getElementById('iwRequestBy');
if (!sel || !window.IW_REQUEST_BY_OPTIONS) return;
sel.innerHTML = window.IW_REQUEST_BY_OPTIONS;
if (!sel.querySelector(`option[value="${selectedValue}"]`)) {
selectedValue = 'Customer';
}
sel.value = selectedValue;
}
// 이미지 여부 체크
function checkCustomerHasImages(customerUid, iwUid) {
if (!customerUid || !iwUid) return;
const btn = document.getElementById('btnViewPhotos');
if (!btn) return;
const params = new URLSearchParams({
customer_uid: customerUid,
i_type: 'install_order'
});
fetch('/lib/customer_image.php?' + params.toString())
.then(res => res.text())
.then(html => {
const temp = document.createElement('div');
temp.innerHTML = html;
const slider = temp.querySelector('#customerImageSlider');
if (!slider) {
btn.classList.add('d-none');
return;
}
let meta = [];
try {
meta = JSON.parse(slider.dataset.meta || '[]');
} catch (e) {
console.error('image meta parse error:', e);
btn.classList.add('d-none');
return;
}
const hasImage = meta.some(m => {
return parseInt(m.sourceuid || 0, 10) === parseInt(iwUid || 0, 10);
});
console.log('hasImage:', hasImage, 'iwUid:', iwUid, 'meta:', meta);
if (hasImage) {
btn.classList.remove('d-none');
btn.onclick = () => openCustomerImages(customerUid);
} else {
btn.classList.add('d-none');
}
})
.catch(() => {
btn.classList.add('d-none');
});
}
function bindStep3Toggles() {
const btnTwo = document.getElementById('btnTwoPerson');
const reason = document.getElementById('iwTwoPersonReason');
btnTwo.onclick = () => {
const on = btnTwo.classList.toggle('iw-toggle-on');
reason.disabled = !on;
if (!on) reason.value = '';
};
const btnRec = document.getElementById('btnRecurring');
const days = document.getElementById('iwRecurringDays');
btnRec.onclick = () => {
const on = btnRec.classList.toggle('iw-toggle-on');
days.disabled = !on;
if (!on) days.value = '';
};
const btnOil = document.getElementById('btnNeedOilPickup');
btnOil.onclick = () => {
btnOil.classList.toggle('iw-toggle-on');
};
bindCategoryEvents();
}
function bindCategoryEvents() {
document.querySelectorAll('.iw-cat-btn').forEach(btn => {
btn.onclick = function() {
document.querySelectorAll('.iw-cat-btn')
.forEach(b => b.classList.remove('active'));
this.classList.add('active');
InstallWait.category = parseInt(this.dataset.value, 10);
};
});
}
function getContainerIconByType(type) {
type = (type || '').toUpperCase();
if (type.includes('D')) return 'bi-database-fill'; // Drum
if (type.includes('B') && !type.includes('BUCKET'))
return 'bi-archive-fill'; // Bin
return 'bi-box2'; // Fallback
}
function renderDbChipCommon(r, cls) {
const type = (r.iwc_type || '').toUpperCase();
const icon = getContainerIconByType(type);
const isRestaurantOwned = (r.iwc_owner_type || 'C') === 'O';
const chipClass = isRestaurantOwned
? `chip chip-restaurant ${cls}`
: `chip chip-company ${cls}`;
const ownerBadge = isRestaurantOwned ? '<span class="chip-owner">O</span>' : '';
const flags =
(r.iwc_has_lock === 'Y' ? ' <i class="bi bi-lock-fill"></i>' : '') +
(r.iwc_has_wheel === 'Y' ? ' <i class="bi bi-gear-fill"></i>' : '') +
((r.iwc_has_woodframe || 'N') === 'Y'
? ' <i class="bi bi-bounding-box-circles"></i>'
: '');
const used = r.iwc_is_used === 'Y' ? 'Used ' : '';
return `
<span class="${chipClass}"
data-type="${r.iwc_type}"
data-capacity="${r.iwc_capacity || ''}"
data-is_used="${r.iwc_is_used || 'N'}"
data-owner_type="${r.iwc_owner_type || 'C'}"
data-has_lock="${r.iwc_has_lock || 'N'}"
data-has_wheel="${r.iwc_has_wheel || 'N'}"
data-has_frame="${r.iwc_has_woodframe || 'N'}">
${ownerBadge}
<i class="bi ${icon}"></i>
${used}${r.iwc_type}
${flags}
</span>
`;
}
function renderPickupChipFromDB(r) {
return renderDbChipCommon(r, 'iw-current-chip'); // PICKUP는 current-chip 클래스 재사용
}
function renderInstallChipFromDB(r) {
return renderDbChipCommon(r, 'iw-install-chip');
}
// Complete 액션 종료 후
function finishInstallWaitComplete() {
const modalEl = document.getElementById('addInstallWaitModal');
// 모달 완전히 닫힌 뒤 리로드
modalEl.addEventListener('hidden.bs.modal', function onHidden() {
modalEl.removeEventListener('hidden.bs.modal', onHidden);
// 상태 정리
InstallWait = { step: 1 };
// 이 시점에 리로드
location.reload();
});
// 모달 닫기 (애니메이션 시작)
const modal = bootstrap.Modal.getInstance(modalEl);
if (modal) modal.hide();
}