/* ── Bijnor Services – Frontend App v2.1.0 ──────────────────────────────────
* Mobile-first customer + staff portal PWA
* Requires: BS_Ajax.url, BS_Ajax.nonce (localized by PHP via wp_localize_script)
*
* ⚠️ All functions MUST be defined as inline named methods inside window.BSApp.
* Do NOT declare functions with var/const/let outside this object.
* Separate declarations cause ReferenceError on some shared hosting (Hostinger).
* ─────────────────────────────────────────────────────────────────────────── */
(function () {
'use strict';
/* ════════════════════════════════════════════════════════════════════════
BSApp — Single global namespace for the entire frontend application.
Provides: customer status check, repair enquiry, pick & drop scheduling,
staff mobile portal (OTP login, claim management, payment QR),
Excel upload and template download.
════════════════════════════════════════════════════════════════════════ */
window.BSApp = {
/* ── App State ───────────────────────────────────────────────── */
version: '2.1.0',
currentView: 'home',
prevView: null,
staffMode: false,
staffId: 0,
staffName: '',
otpTimer: null,
activeClaim: null,
/* ────────────────────────────────────────────────────────────────
INIT — Entry point called on DOMContentLoaded
──────────────────────────────────────────────────────────────── */
init: function init() {
var app = this;
// Build the app shell if it doesn't exist yet
if (!document.getElementById('bs-app-root')) {
app.buildShell();
}
// Restore staff session from cookie (persists across page loads)
var sid = app.getCookie('bs_staff_id');
var sname = app.getCookie('bs_staff_name');
if (sid && sname) {
app.staffMode = true;
app.staffId = parseInt(sid, 10);
app.staffName = sname;
}
// Upgrade PHP shortcode forms with AJAX behaviour
app.upgradePhpForms();
// Show home view inside the app shell
app.showView('home');
},
/* ────────────────────────────────────────────────────────────────
SHELL BUILDER
Creates #bs-app-root if the page doesn't already have it.
Injects before the first .entry-content paragraph.
──────────────────────────────────────────────────────────────── */
buildShell: function buildShell() {
var logoSrc = (window.BS_Ajax && BS_Ajax.logo_url) ? BS_Ajax.logo_url : '';
var div = document.createElement('div');
div.id = 'bs-app-root';
div.className = 'bs-app';
div.innerHTML =
'
' +
'
';
var anchor = document.querySelector(
'.entry-content, .page-content, main, #main, #content, article'
);
if (anchor) {
anchor.insertBefore(div, anchor.firstChild);
} else {
document.body.insertBefore(div, document.body.firstChild);
}
},
/* ────────────────────────────────────────────────────────────────
PHP FORM UPGRADE
Intercepts server-rendered shortcode forms and converts them
to AJAX calls so the page doesn't need a full reload.
──────────────────────────────────────────────────────────────── */
upgradePhpForms: function upgradePhpForms() {
// [bijnor_enquiry] form
var eq = document.querySelector('.bs-enquiry-form form');
if (eq) {
eq.addEventListener('submit', function (e) {
BSApp.handlePhpEnquirySubmit(e, eq);
});
}
// [bijnor_imei_check] form
var im = document.querySelector('.bs-imei-check form');
if (im) {
im.addEventListener('submit', function (e) {
BSApp.handlePhpImeiSubmit(e, im);
});
}
},
/* ────────────────────────────────────────────────────────────────
NAVIGATION
──────────────────────────────────────────────────────────────── */
showView: function showView(viewName, data) {
this.prevView = this.currentView;
this.currentView = viewName;
var container = document.getElementById('bs-view-container');
var backBtn = document.getElementById('bs-back-btn');
if (!container) { return; }
// Back button visibility
if (backBtn) {
backBtn.style.display = (viewName === 'home') ? 'none' : 'inline-block';
}
// Staff session badge
var badge = document.getElementById('bs-staff-badge');
if (badge) {
if (this.staffMode) {
badge.style.display = 'inline-block';
badge.textContent = '\uD83D\uDC64 ' + this.staffName;
} else {
badge.style.display = 'none';
}
}
// Route to view renderer
switch (viewName) {
case 'home': this.renderHome(container); break;
case 'status': this.renderStatusCheck(container); break;
case 'enquiry': this.renderEnquiryForm(container); break;
case 'pickup': this.renderPickDrop(container); break;
case 'payment': this.renderPaymentView(container, data); break;
case 'otp-login': this.renderOtpLogin(container); break;
case 'staff-home': this.renderStaffHome(container); break;
case 'staff-claims': this.renderStaffClaims(container); break;
case 'staff-detail': this.renderStaffClaimDetail(container, data); break;
case 'excel-upload': this.renderExcelUpload(container); break;
case 'about': this.renderAbout(container); break;
default: this.renderHome(container); break;
}
},
goBack: function goBack() {
var map = {
'staff-detail': 'staff-claims',
'staff-claims': 'staff-home',
'staff-home': 'home',
'otp-login': 'home',
'payment': this.prevView || 'home',
};
var target = map[this.currentView] || this.prevView || 'home';
this.showView(target);
},
setHeader: function setHeader(title) {
var el = document.getElementById('bs-header-title');
if (el) { el.textContent = title; }
},
/* ────────────────────────────────────────────────────────────────
HOME SCREEN
──────────────────────────────────────────────────────────────── */
renderHome: function renderHome(container) {
this.setHeader('Bijnor Services');
var staffCard = this.staffMode
? '' +
'
\uD83D\uDCCB My Claims ' +
'
View and manage your assigned claims
' +
'
'
: '' +
'
\uD83D\uDC64 Staff Login ' +
'
Log in to manage your assigned repair claims
' +
'
';
container.innerHTML =
'' +
'
' +
'
\uD83D\uDD0D Check Repair / Claim Status ' +
'
Enter your IMEI or claim number to track your repair
' +
'
' +
'
' +
'
\uD83D\uDEE0\uFE0F Request a Repair ' +
'
Submit a new Samsung repair or Bajaj insurance enquiry
' +
'
' +
'
' +
'
\uD83D\uDE9A Schedule Pick & Drop ' +
'
Book a doorstep pickup and delivery for your device
' +
'
' +
staffCard +
'
' +
'
\u2139\uFE0F About Bijnor Services ' +
'
Samsung authorized service center & Bajaj insurance claim point
' +
'
' +
'
';
},
/* ────────────────────────────────────────────────────────────────
STATUS CHECK — PUBLIC (no login required)
──────────────────────────────────────────────────────────────── */
renderStatusCheck: function renderStatusCheck(container) {
this.setHeader('Check Status');
container.innerHTML =
'' +
'
' +
'Enter your IMEI number or claim number to check the current status of your repair or insurance claim.' +
'
' +
'
' +
'IMEI or Claim Number ' +
' ' +
'
' +
'
\uD83D\uDD0D Check Now ' +
'
' +
'
';
var inp = document.getElementById('status-query');
if (inp) {
inp.focus();
inp.addEventListener('keydown', function (e) {
if (e.key === 'Enter') { BSApp.checkStatus(); }
});
}
},
checkStatus: function checkStatus() {
var q = ((document.getElementById('status-query') || {}).value || '').trim();
if (!q) {
this.showError('status-result', 'Please enter an IMEI or claim number.');
return;
}
this.showLoader('status-result');
this.ajax('bs_public_status_check', { query: q }, function (d) {
if (d.success && d.data) {
BSApp.renderClaimStatusResult('status-result', d.data);
} else {
BSApp.renderNotFound('status-result', q);
}
}, function () {
BSApp.showError('status-result', 'Could not connect. Please check your internet and try again.');
});
},
renderClaimStatusResult: function renderClaimStatusResult(containerId, claim) {
var statusColors = {
'Open': '#1565c0',
'In Progress': '#fb8c00',
'Repair Complete':'#43a047',
'Closed': '#43a047',
'Delivered': '#43a047',
'Cancelled': '#e53935',
'Repudiated': '#e53935',
};
var sc = statusColors[claim.claim_status] || '#555';
var mob = (claim.mobile || '').replace(/\D/g, '');
var wa = 'https://wa.me/91' + mob + '?text=' +
encodeURIComponent('Hi, I am following up on my repair/claim: ' + claim.claim_number);
var html =
'' +
'
\u2705 Record Found ' +
'
' +
'Claim No. ' + this.esc(claim.claim_number) + ' ' +
'Customer ' + this.esc(claim.customer_name) + ' ' +
'Device ' +
this.esc((claim.manufacturer || '') + (claim.model_number ? ' ' + claim.model_number : '')) +
' ' +
'Status ' +
this.esc(claim.claim_status) + ' ' +
'Stage ' + this.esc(claim.workflow_status || '\u2014') + ' ' +
'Registered ' + this.esc(claim.registration_date || '\u2014') + ' ' +
'
' +
'
' +
'
';
var el = document.getElementById(containerId);
if (el) { el.innerHTML = html; }
},
renderNotFound: function renderNotFound(containerId, query) {
var wa = 'https://wa.me/919999999999?text=' +
encodeURIComponent('Hi, I want to check status for IMEI/claim: ' + query);
var html =
'' +
'
No record found for: ' + this.esc(query) + '
' +
'
' +
'If you recently submitted a repair, allow some time for it to be registered.' +
'
' +
'
' +
'\uD83D\uDCAC Ask on WhatsApp ' +
'
';
var el = document.getElementById(containerId);
if (el) { el.innerHTML = html; }
},
/* ────────────────────────────────────────────────────────────────
PHP FORM AJAX UPGRADES
──────────────────────────────────────────────────────────────── */
handlePhpEnquirySubmit: function handlePhpEnquirySubmit(e, form) {
e.preventDefault();
// Inject a result container before the form
var existing = form.parentNode.querySelector('#php-eq-result');
if (!existing) {
existing = document.createElement('div');
existing.id = 'php-eq-result';
form.parentNode.insertBefore(existing, form);
}
var fd = new FormData(form);
var data = {
name: (fd.get('bs_name') || '').trim(),
mobile: (fd.get('bs_mobile') || '').trim(),
device: (fd.get('bs_device') || '').trim(),
issue: (fd.get('bs_issue') || '').trim(),
imei: (fd.get('bs_imei') || '').trim(),
};
var btn = form.querySelector('button[type=submit]');
if (btn) { btn.disabled = true; btn.textContent = '\u23F3 Submitting\u2026'; }
this.ajax('bs_public_enquiry', data, function (d) {
if (btn) { btn.disabled = false; btn.textContent = 'Submit Enquiry'; }
if (d.success) {
existing.className = 'bs-success';
existing.textContent = 'Thank you! We will contact you on ' + data.mobile + ' shortly.';
form.reset();
} else {
existing.className = 'bs-error';
existing.textContent = d.data || 'Submission failed. Please try again.';
}
}, function () {
if (btn) { btn.disabled = false; btn.textContent = 'Submit Enquiry'; }
existing.className = 'bs-error';
existing.textContent = 'Network error. Please try again.';
});
},
handlePhpImeiSubmit: function handlePhpImeiSubmit(e, form) {
e.preventDefault();
var inp = form.querySelector('input[name=bs_imei]');
var q = inp ? inp.value.trim() : '';
if (!q) { return; }
// Find or create result container
var res = form.parentNode.querySelector('#php-imei-result');
if (!res) {
res = document.createElement('div');
res.id = 'php-imei-result';
form.parentNode.appendChild(res);
}
// Remove old PHP-rendered result card if present
var old = form.parentNode.querySelector('.bs-result-card');
if (old) { old.remove(); }
this.showLoader('php-imei-result');
this.ajax('bs_public_status_check', { query: q }, function (d) {
if (d.success && d.data) {
BSApp.renderClaimStatusResult('php-imei-result', d.data);
} else {
BSApp.renderNotFound('php-imei-result', q);
}
}, function () {
BSApp.showError('php-imei-result', 'Could not connect. Please try again.');
});
},
/* ────────────────────────────────────────────────────────────────
ENQUIRY FORM — PUBLIC (inside app shell)
──────────────────────────────────────────────────────────────── */
renderEnquiryForm: function renderEnquiryForm(container) {
this.setHeader('Request a Repair');
container.innerHTML =
'';
},
submitEnquiry: function submitEnquiry(e) {
e.preventDefault();
var form = document.getElementById('bs-enquiry-form');
if (!form) { return; }
var data = {
name: (form.querySelector('[name=name]').value || '').trim(),
mobile: (form.querySelector('[name=mobile]').value || '').trim(),
device: (form.querySelector('[name=device]').value || '').trim(),
issue: (form.querySelector('[name=issue]').value || '').trim(),
imei: (form.querySelector('[name=imei]').value || '').trim(),
service_type: (form.querySelector('[name=service_type]').value|| ''),
};
if (!data.name) {
this.showError('enquiry-msg', 'Please enter your name.');
return;
}
if (!/^[0-9]{10}$/.test(data.mobile)) {
this.showError('enquiry-msg', 'Please enter a valid 10-digit mobile number.');
return;
}
var btn = form.querySelector('button[type=submit]');
if (btn) { btn.disabled = true; btn.textContent = '\u23F3 Submitting\u2026'; }
this.ajax('bs_public_enquiry', data, function (d) {
if (btn) { btn.disabled = false; btn.textContent = '\u2705 Submit Enquiry'; }
if (d.success) {
BSApp.showSuccess('enquiry-msg',
'\uD83C\uDF89 Enquiry submitted! We will call you at ' + data.mobile + ' shortly.');
form.reset();
} else {
BSApp.showError('enquiry-msg', d.data || 'Submission failed. Please try again.');
}
}, function () {
if (btn) { btn.disabled = false; btn.textContent = '\u2705 Submit Enquiry'; }
BSApp.showError('enquiry-msg', 'Network error. Please try again.');
});
},
/* ────────────────────────────────────────────────────────────────
PICK & DROP SCHEDULING — PUBLIC
──────────────────────────────────────────────────────────────── */
renderPickDrop: function renderPickDrop(container) {
this.setHeader('Pick & Drop');
var tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
var minDate = tomorrow.toISOString().split('T')[0];
container.innerHTML =
'' +
'
' +
'Schedule a doorstep pickup. Our team will collect your device, repair it, and return it at your convenience.' +
'
' +
'
' +
'
' +
'' +
'Your Name * ' +
' ' +
'
' +
'' +
'Mobile Number * ' +
' ' +
'
' +
'' +
'Pickup Address * ' +
' ' +
'
' +
'' +
'Device Details ' +
' ' +
'
' +
'' +
'Preferred Pickup Date * ' +
' ' +
'
' +
'' +
'Preferred Time Slot ' +
'' +
'Morning (9 AM \u2013 12 PM) ' +
'Afternoon (12 PM \u2013 4 PM) ' +
'Evening (4 PM \u2013 7 PM) ' +
' ' +
'
' +
'' +
'Issue / Notes ' +
' ' +
'
' +
'' +
'\uD83D\uDE9A Schedule Pickup ' +
' ' +
'
';
},
submitPickDrop: function submitPickDrop(e) {
e.preventDefault();
var form = document.getElementById('bs-pickup-form');
if (!form) { return; }
var g = function (n) { return (form.querySelector('[name=' + n + ']').value || '').trim(); };
var data = {
name: g('name'),
mobile: g('mobile'),
address: g('address'),
device: g('device'),
pickup_date: g('pickup_date'),
time_slot: g('time_slot'),
issue: g('issue'),
};
if (!data.name || !data.mobile || !data.address || !data.pickup_date) {
this.showError('pickup-msg', 'Please fill in all required fields.');
return;
}
if (!/^[0-9]{10}$/.test(data.mobile)) {
this.showError('pickup-msg', 'Please enter a valid 10-digit mobile number.');
return;
}
var btn = form.querySelector('button[type=submit]');
if (btn) { btn.disabled = true; btn.textContent = '\u23F3 Scheduling\u2026'; }
this.ajax('bs_public_pickup', data, function (d) {
if (btn) { btn.disabled = false; btn.textContent = '\uD83D\uDE9A Schedule Pickup'; }
if (d.success) {
BSApp.showSuccess('pickup-msg',
'\uD83C\uDF89 Pickup scheduled! Reference: ' +
(d.data && d.data.ref ? d.data.ref : 'Confirmed') +
'. Our team will call ' + data.mobile + ' to confirm the slot.');
form.reset();
} else {
BSApp.showError('pickup-msg', d.data || 'Scheduling failed. Please try again.');
}
}, function () {
if (btn) { btn.disabled = false; btn.textContent = '\uD83D\uDE9A Schedule Pickup'; }
BSApp.showError('pickup-msg', 'Network error. Please try again.');
});
},
/* ────────────────────────────────────────────────────────────────
UPI PAYMENT QR
──────────────────────────────────────────────────────────────── */
renderPaymentView: function renderPaymentView(container, data) {
this.setHeader('Pay via UPI');
data = data || {};
var amount = data.amount || '';
var claimNo = data.claimNo || '';
var upiId = data.upiId || 'bijnorservices@upi';
var upiName = data.upiName || 'Bijnor Services';
var qrUrl = this.generateQRUrl(amount, claimNo, upiId, upiName);
container.innerHTML =
'' +
'
' +
'Scan with PhonePe, Google Pay, Paytm or any UPI app
' +
'
' +
'
' +
'
' +
(amount
? '
' +
'\u20B9' + this.formatCurrency(amount) + '
'
: '') +
'
' + this.esc(upiName) + '
' +
'
' + this.esc(upiId) + '
' +
(claimNo
? '
Ref: ' +
this.esc(claimNo) + '
'
: '') +
'
' +
'
' +
'After payment, share the confirmation screenshot on WhatsApp.' +
'
' +
'
' +
'
';
},
generateQRUrl: function generateQRUrl(amount, claimNo, upiId, upiName) {
upiId = upiId || 'bijnorservices@upi';
upiName = upiName || 'Bijnor Services';
var upiStr =
'upi://pay?pa=' + encodeURIComponent(upiId) +
'&pn=' + encodeURIComponent(upiName) +
'&tn=' + encodeURIComponent('Payment – ' + (claimNo || 'Repair Service'));
if (amount) {
upiStr += '&am=' + encodeURIComponent(String(amount)) + '&cu=INR';
}
return 'https://api.qrserver.com/v1/create-qr-code/?size=220x220&data=' +
encodeURIComponent(upiStr);
},
showPaymentQR: function showPaymentQR(amount, claimNo, upiId, upiName) {
this.showView('payment', {
amount: amount,
claimNo: claimNo,
upiId: upiId,
upiName: upiName,
});
},
/* ────────────────────────────────────────────────────────────────
OTP STAFF LOGIN
──────────────────────────────────────────────────────────────── */
renderOtpLogin: function renderOtpLogin(container) {
this.setHeader('Staff Login');
container.innerHTML =
'' +
'
' +
'Enter your registered mobile number to receive a one-time login code.' +
'
' +
'
' +
'
' +
'
' +
'Mobile Number ' +
' ' +
'
' +
'
Send OTP ' +
'
' +
'
' +
'
' +
'Enter OTP ' +
' ' +
' ' +
' ' +
'
' +
'
Verify & Login ' +
'
' +
'Resend OTP ' +
'
' +
'
';
var inp = document.getElementById('otp-mobile');
if (inp) {
inp.focus();
inp.addEventListener('keydown', function (e) {
if (e.key === 'Enter') { BSApp.sendOtp(); }
});
}
},
sendOtp: function sendOtp() {
var mobile = ((document.getElementById('otp-mobile') || {}).value || '').trim();
if (!/^[0-9]{10}$/.test(mobile)) {
this.showError('otp-msg', 'Please enter a valid 10-digit mobile number.');
return;
}
this.clearMsg('otp-msg');
this.ajax('bs_staff_send_otp', { mobile: mobile }, function (d) {
if (d.success) {
var s1 = document.getElementById('otp-step-1');
var s2 = document.getElementById('otp-step-2');
if (s1) { s1.style.display = 'none'; }
if (s2) { s2.style.display = 'block'; }
BSApp.startOtpTimer();
BSApp.showSuccess('otp-msg',
'OTP sent to ' + mobile + '. Valid for 10 minutes.');
} else {
BSApp.showError('otp-msg',
d.data || 'Mobile not registered. Contact admin to be added as staff.');
}
}, function () {
BSApp.showError('otp-msg', 'Network error. Please try again.');
});
},
verifyOtp: function verifyOtp() {
var mobile = ((document.getElementById('otp-mobile') || {}).value || '').trim();
var code = ((document.getElementById('otp-code') || {}).value || '').trim();
if (!code || code.length < 4) {
this.showError('otp-msg', 'Please enter the OTP from your SMS.');
return;
}
this.clearMsg('otp-msg');
this.ajax('bs_staff_verify_otp', { mobile: mobile, otp: code }, function (d) {
if (d.success) {
BSApp.staffMode = true;
BSApp.staffId = parseInt(d.data.user_id, 10);
BSApp.staffName = d.data.display_name || 'Staff';
BSApp.setCookie('bs_staff_id', String(d.data.user_id), 1);
BSApp.setCookie('bs_staff_name', BSApp.staffName, 1);
if (BSApp.otpTimer) { clearInterval(BSApp.otpTimer); }
BSApp.showView('staff-home');
} else {
BSApp.showError('otp-msg', d.data || 'Incorrect OTP. Please try again.');
}
}, function () {
BSApp.showError('otp-msg', 'Network error. Please try again.');
});
},
resendOtp: function resendOtp() {
if (this.otpTimer) { clearInterval(this.otpTimer); }
this.clearMsg('otp-msg');
var s1 = document.getElementById('otp-step-1');
var s2 = document.getElementById('otp-step-2');
if (s1) { s1.style.display = 'block'; }
if (s2) { s2.style.display = 'none'; }
},
startOtpTimer: function startOtpTimer() {
var seconds = 60;
var display = document.getElementById('otp-timer-display');
var resend = document.getElementById('otp-resend-btn');
if (resend) { resend.disabled = true; }
if (this.otpTimer) { clearInterval(this.otpTimer); }
this.otpTimer = setInterval(function () {
seconds--;
if (display) {
display.textContent = '(' + seconds + 's)';
}
if (seconds <= 0) {
clearInterval(BSApp.otpTimer);
if (display) { display.textContent = ''; }
if (resend) { resend.disabled = false; }
}
}, 1000);
},
/* ────────────────────────────────────────────────────────────────
STAFF HOME DASHBOARD
──────────────────────────────────────────────────────────────── */
renderStaffHome: function renderStaffHome(container) {
this.setHeader('Staff Dashboard');
container.innerHTML =
'' +
'
' +
'
Welcome back, ' +
'' + this.esc(this.staffName) + '
' +
'
' +
'
' +
'
' +
'
\u2014
' +
'
Total
' +
'
' +
'
' +
'
\u2014
' +
'
Open
' +
'
' +
'
' +
'
\u2014
' +
'
Overdue
' +
'
' +
'
' +
'
\u2014
' +
'
High
' +
'
' +
'
' +
'
' +
'
\uD83D\uDCCB My Claims ' +
'
View, search and update your assigned claims
' +
'
' +
'
' +
'
\uD83D\uDCC2 Upload Excel ' +
'
Upload Bajaj ExportReqReport (.xls / .xlsx)
' +
'
' +
'
' +
'
\u2B07\uFE0F Download CSV Template ' +
'
Get the claim entry template for manual filing
' +
'
' +
'
' +
'
\uD83D\uDEAA Logout ' +
'
Sign out of the staff portal
' +
'
' +
'
';
this.loadStaffStats();
},
loadStaffStats: function loadStaffStats() {
this.ajax('bs_alert_stats', {}, function (d) {
if (!d.success) { return; }
var s = d.data;
['total', 'open', 'overdue', 'high'].forEach(function (k) {
var el = document.getElementById('ss-' + k);
if (el) { el.textContent = (s[k] !== undefined ? s[k] : '\u2014'); }
});
}, null);
},
staffLogout: function staffLogout() {
this.staffMode = false;
this.staffId = 0;
this.staffName = '';
this.deleteCookie('bs_staff_id');
this.deleteCookie('bs_staff_name');
this.showView('home');
},
/* ────────────────────────────────────────────────────────────────
STAFF CLAIMS LIST
──────────────────────────────────────────────────────────────── */
renderStaffClaims: function renderStaffClaims(container) {
this.setHeader('My Claims');
container.innerHTML =
'' +
'
' +
'
' +
'' +
'All Status ' +
'Open ' +
'In Progress ' +
'Closed ' +
' ' +
'' +
'All Priority ' +
'\uD83D\uDD34 High ' +
'\uD83D\UDFE1 Medium ' +
'\uD83D\uDD35 Low ' +
' ' +
'
' +
'
' +
'
';
// Live search with debounce
var timer;
var inp = document.getElementById('staff-search');
if (inp) {
inp.addEventListener('input', function () {
clearTimeout(timer);
timer = setTimeout(function () { BSApp.loadStaffClaims(); }, 350);
});
}
this.loadStaffClaims();
},
loadStaffClaims: function loadStaffClaims() {
var search = ((document.getElementById('staff-search') || {}).value || '').trim();
var status = ((document.getElementById('sc-status') || {}).value || '');
var priority = ((document.getElementById('sc-priority') || {}).value || '');
this.showLoader('staff-claims-wrap');
this.ajax('bs_get_claims', {
search: search, status: status, priority: priority, paged: 1,
}, function (d) {
if (!d.success) {
BSApp.showError('staff-claims-wrap', 'Could not load claims. Please try again.');
return;
}
var rows = d.data.rows || [];
var el = document.getElementById('staff-claims-wrap');
if (!el) { return; }
if (!rows.length) {
el.innerHTML =
'No claims found.
';
return;
}
el.innerHTML = rows.map(function (r) {
return BSApp.buildClaimCard(r);
}).join('');
}, function () {
BSApp.showError('staff-claims-wrap', 'Network error. Please try again.');
});
},
buildClaimCard: function buildClaimCard(r) {
var pc = { high: '#e53935', medium: '#fb8c00', low: '#1e88e5' };
var p = (r.priority || 'low').toLowerCase();
var fee = parseFloat(r.processing_fee || 0);
return '' +
'
' +
'' + this.esc(r.claim_number) + ' ' +
'' +
p.toUpperCase() + ' ' +
'
' +
'
' +
this.esc(r.customer_name) + ' · ' + this.esc(r.mobile) +
'
' +
'
' +
this.esc(r.claim_status || '\u2014') + ' · ' +
(r.ageing_days || 0) + ' days · ' +
'\u20B9' + this.formatCurrency(fee) +
(r.fee_received ? ' \u2705' : ' \u23F3') +
'
' +
'
';
},
/* ────────────────────────────────────────────────────────────────
STAFF CLAIM DETAIL
──────────────────────────────────────────────────────────────── */
viewStaffClaim: function viewStaffClaim(claimId) {
this.showView('staff-detail', { id: claimId });
},
renderStaffClaimDetail: function renderStaffClaimDetail(container, data) {
this.setHeader('Claim Detail');
var claimId = (data && data.id) ? data.id : 0;
this.showLoader('bs-view-container');
this.ajax('bs_get_claim_detail', { id: claimId }, function (d) {
if (!d.success || !d.data) {
BSApp.showError('bs-view-container', 'Could not load claim details.');
return;
}
BSApp.activeClaim = d.data;
BSApp.buildDetailView(container, d.data);
}, function () {
BSApp.showError('bs-view-container', 'Network error. Please try again.');
});
},
buildDetailView: function buildDetailView(container, c) {
var pc = { high: '#e53935', medium: '#fb8c00', low: '#1e88e5' };
var p = (c.priority || 'low').toLowerCase();
var fee = parseFloat(c.custom_payment_amount || c.processing_fee || 0);
var upiId = (window.BS_Ajax && BS_Ajax.upi_id) ? BS_Ajax.upi_id : 'bijnorservices@upi';
var mob = (c.mobile || '').replace(/\D/g, '');
var waMsg = encodeURIComponent(
'Hi ' + (c.customer_name || '') + ', your claim ' + c.claim_number +
' — please check for updates.');
container.innerHTML =
'' +
/* ── Info card ── */
'
' +
'
' +
'
' +
'
' + this.esc(c.claim_number) + ' ' +
'
' + this.esc(c.customer_name) + '
' +
'
' + this.esc(c.mobile) + '
' +
'
' +
'
' +
p.toUpperCase() + ' ' +
'
' +
'
' +
'
' +
'Manufacturer ' +
'' + this.esc(c.manufacturer || '\u2014') + ' ' +
'Model ' +
'' + this.esc(c.model_number || '\u2014') + ' ' +
'Serial / IMEI ' +
'' + this.esc(c.serial_number || '\u2014') + ' ' +
'Sum Insured ' +
'\u20B9' + this.formatCurrency(c.sum_insured || 0) + ' ' +
'Processing Fee ' +
'\u20B9' + this.formatCurrency(fee) + ' ' +
(c.fee_received ? '\u2705 Paid' : '\u23F3 Pending') + ' ' +
'Claim Status ' +
'' + this.esc(c.claim_status || '\u2014') + ' ' +
'Workflow ' +
'' + this.esc(c.workflow_status || '\u2014') + ' ' +
'Age ' +
'' + (c.ageing_days || 0) + ' days ' +
'
' +
'
' +
/* ── Quick actions ── */
'
' +
/* ── Update status ── */
'
' +
'
Update Claim Status ' +
'
' +
'
' +
'— Select new status — ' +
'Open ' +
'In Progress ' +
'Repair Complete ' +
'Pickup Ready ' +
'Closed ' +
'Delivered ' +
'Cancelled ' +
' ' +
'
Update Status ' +
'
' +
/* ── Mark paid (only if not yet paid) ── */
(c.fee_received ? '' :
'
' +
'
Mark Payment Received ' +
'
' +
'
' +
'\u2705 Mark \u20B9' + this.formatCurrency(fee) + ' as Paid ' +
'
'
) +
'
';
},
doUpdateStatus: function doUpdateStatus(claimId) {
var sel = document.getElementById('new-status');
var status = sel ? sel.value : '';
if (!status) {
this.showError('status-up-msg', 'Please select a new status.');
return;
}
this.ajax('bs_update_claim_status', { id: claimId, status: status }, function (d) {
if (d.success) {
BSApp.showSuccess('status-up-msg', '\u2705 Status updated to: ' + status);
} else {
BSApp.showError('status-up-msg', d.data || 'Update failed.');
}
}, function () {
BSApp.showError('status-up-msg', 'Network error. Please try again.');
});
},
doMarkPaid: function doMarkPaid(claimId) {
this.ajax('bs_mark_paid', { id: claimId }, function (d) {
if (d.success) {
BSApp.showSuccess('pay-up-msg', '\u2705 Payment marked as received.');
var btn = document.querySelector(
'button[onclick*="doMarkPaid(' + claimId + ')"]');
if (btn) { btn.disabled = true; btn.textContent = '\u2705 Paid'; }
} else {
BSApp.showError('pay-up-msg', d.data || 'Update failed.');
}
}, function () {
BSApp.showError('pay-up-msg', 'Network error. Please try again.');
});
},
/* ────────────────────────────────────────────────────────────────
EXCEL UPLOAD
──────────────────────────────────────────────────────────────── */
renderExcelUpload: function renderExcelUpload(container) {
this.setHeader('Upload Excel');
container.innerHTML =
'' +
'
' +
'Upload the Bajaj ExportReqReport file (.xls or .xlsx). ' +
'Claims will be inserted or updated by claim number automatically.' +
'
' +
'
' +
'
' +
'' +
'
\uD83D\uDCC2
' +
'
' +
'
' +
'Supported: .xls and .xlsx (Bajaj ExportReqReport format)
' +
'
' +
'' +
'\uD83D\uDE80 Upload & Sync ' +
' ' +
'
' +
'' +
'\u2B07\uFE0F Download CSV Template ' +
'
' +
'
';
},
handleExcelUpload: async function handleExcelUpload(e) {
e.preventDefault();
var form = document.getElementById('bs-excel-form');
var fileInput = document.getElementById('bs-excel-file');
if (!form || !fileInput || !fileInput.files || !fileInput.files.length) {
BSApp.showError('excel-msg', 'Please select a .xls or .xlsx file.');
return;
}
var btn = form.querySelector('button[type=submit]');
if (btn) { btn.disabled = true; btn.textContent = '\u23F3 Processing\u2026'; }
BSApp.clearMsg('excel-msg');
var fd = new FormData(form);
fd.append('action', 'bs_upload_excel');
fd.append('nonce', window.BS_Ajax ? BS_Ajax.nonce : '');
try {
var url = window.BS_Ajax ? BS_Ajax.url : '/wp-admin/admin-ajax.php';
var res = await fetch(url, {
method: 'POST',
credentials: 'include',
body: fd,
});
var data = await res.json();
if (btn) { btn.disabled = false; btn.textContent = '\uD83D\uDE80 Upload & Sync'; }
if (data.success) {
var r = data.data || {};
BSApp.showSuccess('excel-msg',
'\u2705 Upload complete! ' +
'Inserted: ' + (r.inserted || 0) + ' | ' +
'Updated: ' + (r.updated || 0) + ' | ' +
'Skipped: ' + (r.skipped || 0) +
(r.errors ? ' | Errors: ' + r.errors : ''));
form.reset();
} else {
var msg = (data.data && data.data.message)
? data.data.message
: (data.data || 'Upload failed. Please try again.');
BSApp.showError('excel-msg', msg);
}
} catch (err) {
if (btn) { btn.disabled = false; btn.textContent = '\uD83D\uDE80 Upload & Sync'; }
BSApp.showError('excel-msg', 'Network error: ' + (err.message || 'Please try again.'));
}
},
/* ────────────────────────────────────────────────────────────────
EXCEL TEMPLATE DOWNLOAD
Generates a CSV with standard claim entry headers and saves it.
──────────────────────────────────────────────────────────────── */
downloadExcelTemplate: function downloadExcelTemplate() {
var headers = [
'Customer Name',
'Mobile',
'Email',
'Device Brand',
'Device Model',
'Issue Description',
'IMEI / Serial Number',
'Claim Number',
'Policy Number',
'Sum Insured',
'Claim Status',
'Workflow Status',
'Registration Date',
'Loss Date',
'Loss Type',
'Address',
'City',
'State',
'Comments',
];
var sample = [
'Sample Customer',
'9876543210',
'customer@email.com',
'Samsung',
'Galaxy A55',
'Screen cracked, touch not working',
'358901234567890',
'CLM/26/001',
'POL/26/00001',
'15000',
'Open',
'Inspection Initiated',
new Date().toLocaleDateString('en-IN'),
'',
'Accidental Damage',
'123 Main Street, Near Clock Tower',
'Bijnor',
'Uttar Pradesh',
'Device received in working condition except screen',
];
var rows = [headers, sample];
var csv = rows.map(function (row) {
return row.map(function (cell) {
var s = String(cell === null || cell === undefined ? '' : cell);
if (s.indexOf(',') >= 0 || s.indexOf('"') >= 0 || s.indexOf('\n') >= 0) {
s = '"' + s.replace(/"/g, '""') + '"';
}
return s;
}).join(',');
}).join('\r\n');
var blob = new Blob(['\uFEFF' + csv], { type: 'text/csv;charset=utf-8;' });
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = 'bijnor-claim-template.csv';
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
setTimeout(function () { URL.revokeObjectURL(url); }, 1000);
},
/* ────────────────────────────────────────────────────────────────
ABOUT PAGE
──────────────────────────────────────────────────────────────── */
renderAbout: function renderAbout(container) {
this.setHeader('About Us');
container.innerHTML =
'' +
'
' +
'
Bijnor Services ' +
'
' +
'Samsung Authorized Service Center & ' +
'Bajaj Allianz Insurance Claim Point' +
'
' +
'
' +
'
' +
'\uD83D\uDCCD Address: Bijnor, Uttar Pradesh, India
' +
'
' +
'\uD83D\uDCDE Contact: Available via WhatsApp
' +
'
' +
'\uD83D\uDD50 Hours: Mon \u2013 Sat, 10 AM \u2013 7 PM
' +
'
' +
'\u2139\uFE0F Note: Sunday by appointment only
' +
'
' +
'
' +
'
Our Services ' +
'
' +
'\u2705 Samsung Mobile Repair (Authorized Center)
' +
'
' +
'\u2705 Bajaj Allianz Insurance Claim Processing
' +
'
' +
'\u2705 Doorstep Pick & Drop Service
' +
'
' +
'\u2705 Genuine Spare Parts & Warranty
' +
'
' +
'\u2705 All Major Mobile Brands Serviced
' +
'
' +
'\u2705 UPI / Online Payment Accepted
' +
'
' +
'
';
},
/* ────────────────────────────────────────────────────────────────
AJAX CORE
──────────────────────────────────────────────────────────────── */
ajax: function ajax(action, data, onSuccess, onError) {
var params = { action: action };
if (window.BS_Ajax && BS_Ajax.nonce) {
params.nonce = BS_Ajax.nonce;
}
if (data) {
var k;
for (k in data) {
if (Object.prototype.hasOwnProperty.call(data, k)) {
params[k] = data[k];
}
}
}
var ajaxUrl = window.BS_Ajax ? BS_Ajax.url : '/wp-admin/admin-ajax.php';
fetch(ajaxUrl, {
method: 'POST',
credentials: 'include',
body: new URLSearchParams(params),
})
.then(function (r) {
if (!r.ok) { throw new Error('HTTP ' + r.status); }
return r.json();
})
.then(function (d) {
if (typeof onSuccess === 'function') { onSuccess(d); }
})
.catch(function (err) {
console.error('BSApp.ajax error [' + action + ']:', err);
if (typeof onError === 'function') { onError(err); }
});
},
/* ────────────────────────────────────────────────────────────────
UI HELPERS
──────────────────────────────────────────────────────────────── */
showLoader: function showLoader(id) {
var el = (typeof id === 'string') ? document.getElementById(id) : id;
if (el) { el.innerHTML = '
'; }
},
showError: function showError(id, msg) {
var el = (typeof id === 'string') ? document.getElementById(id) : id;
if (el) {
el.innerHTML = '' + this.esc(msg) + '
';
}
},
showSuccess: function showSuccess(id, html) {
var el = (typeof id === 'string') ? document.getElementById(id) : id;
if (el) {
el.innerHTML = '' + html + '
';
}
},
clearMsg: function clearMsg(id) {
var el = (typeof id === 'string') ? document.getElementById(id) : id;
if (el) { el.innerHTML = ''; }
},
/* ────────────────────────────────────────────────────────────────
FORMAT HELPERS
──────────────────────────────────────────────────────────────── */
formatCurrency: function formatCurrency(n) {
return (parseFloat(n) || 0).toLocaleString('en-IN', {
minimumFractionDigits: 0,
maximumFractionDigits: 2,
});
},
formatDate: function formatDate(d) {
if (!d) { return '\u2014'; }
var dt = new Date(d);
return isNaN(dt.getTime())
? String(d)
: dt.toLocaleDateString('en-IN', {
day: '2-digit', month: 'short', year: 'numeric',
});
},
esc: function esc(str) {
return String(str === null || str === undefined ? '' : str)
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
},
/* ────────────────────────────────────────────────────────────────
COOKIE HELPERS
──────────────────────────────────────────────────────────────── */
getCookie: function getCookie(name) {
var m = document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)');
return m ? decodeURIComponent(m.pop()) : '';
},
setCookie: function setCookie(name, value, days) {
var d = new Date();
d.setTime(d.getTime() + (days * 86400000));
document.cookie = name + '=' + encodeURIComponent(value) +
';expires=' + d.toUTCString() +
';path=/;SameSite=Lax';
},
deleteCookie: function deleteCookie(name) {
document.cookie = name + '=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/;';
},
/* ────────────────────────────────────────────────────────────────
WHATSAPP HELPER
──────────────────────────────────────────────────────────────── */
whatsappLink: function whatsappLink(mobile, message) {
var num = String(mobile || '').replace(/\D/g, '');
if (num.length === 10) { num = '91' + num; }
return 'https://wa.me/' + num +
(message ? '?text=' + encodeURIComponent(message) : '');
},
}; /* ── end window.BSApp ── */
/* ── Auto-initialize ────────────────────────────────────────────────── */
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () {
window.BSApp.init();
});
} else {
window.BSApp.init();
}
}()); /* ── end IIFE ── */
https://bijnorservices.in/wp-sitemap-posts-post-1.xml https://bijnorservices.in/wp-sitemap-posts-page-1.xml https://bijnorservices.in/wp-sitemap-taxonomies-category-1.xml https://bijnorservices.in/wp-sitemap-users-1.xml