Files

110 lines
5.0 KiB
JavaScript

// Shared controls for the customer page and service workspace.
var SupportUI = {
initAttachments(container, label){
container.addEventListener('error', function(event){
const image = event.target;
if(!image || image.tagName !== 'IMG' || !image.classList.contains('message-image') || image.dataset.unavailable) return;
image.dataset.unavailable = '1';
image.hidden = true;
const hint = document.createElement('span');
hint.className = 'attachment-unavailable';
hint.textContent = typeof label === 'function' ? label() : label;
image.after(hint);
}, true);
},
async enableNotifications(button){
if(!('Notification' in window)) return;
try{
const permission = await Notification.requestPermission();
button.setAttribute('aria-pressed', String(permission === 'granted'));
}catch(error){}
},
notify(title, body){
if(!document.hidden || !('Notification' in window) || Notification.permission !== 'granted') return;
try{
const notice = new Notification(title, {body:body});
notice.onclick = function(){ window.focus(); notice.close(); };
}catch(error){}
},
addRating(container, sid, labels){
const request = labels.fetch || fetch;
const box = document.createElement('section');
box.className = 'service-rating';
const question = document.createElement('p');
question.textContent = labels.question;
box.appendChild(question);
const choices = document.createElement('div');
choices.className = 'rating-choices';
box.appendChild(choices);
const status = document.createElement('p');
status.setAttribute('role', 'status');
box.appendChild(status);
let sending = false;
[1, 2, 3, 4, 5].forEach(function(stars){
const button = document.createElement('button');
button.type = 'button';
button.textContent = '★';
button.setAttribute('aria-label', stars+' / 5');
button.onmouseenter = function(){
Array.from(choices.children).forEach(function(item, index){ item.classList.toggle('selected', index < stars); });
};
button.onclick = async function(){
if(sending) return;
sending = true;
Array.from(choices.children).forEach(function(item){ item.disabled = true; });
try{
const response = await request('/api/rate', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({sid:sid, stars:stars, comment:''})});
const data = await response.json();
if(!response.ok || !data.ok) throw new Error('Rating failed');
box.textContent = labels.thanks+' '+ '★'.repeat(stars);
}catch(error){
sending = false;
status.textContent = labels.failed;
Array.from(choices.children).forEach(function(item){ item.disabled = false; });
}
};
choices.appendChild(button);
});
container.appendChild(box);
return box;
},
initEmoji(button, panel, input, onInsert){
const emojis = ['😊', '😂', '👍', '❤️', '🙏', '😅', '😢', '🎉', '📦', '🚚'];
function close(){
panel.hidden = true;
button.setAttribute('aria-expanded', 'false');
}
button.onclick = function(){
panel.hidden = !panel.hidden;
button.setAttribute('aria-expanded', String(!panel.hidden));
};
emojis.forEach(function(emoji){
const choice = document.createElement('button');
choice.type = 'button';
choice.textContent = emoji;
choice.onclick = function(){
const start = input.selectionStart == null ? input.value.length : input.selectionStart;
const end = input.selectionEnd == null ? start : input.selectionEnd;
input.value = input.value.slice(0, start) + emoji + input.value.slice(end);
close();
input.focus({preventScroll:true});
input.setSelectionRange(start + emoji.length, start + emoji.length);
if(onInsert) onInsert();
};
panel.appendChild(choice);
});
['pointerdown','mousedown'].forEach(function(name){
document.addEventListener(name, function(event){
if(!panel.hidden && !panel.contains(event.target) && !button.contains(event.target)) close();
});
});
document.addEventListener('keydown', function(event){
if(event.key === 'Escape' && !panel.hidden){
close();
button.focus({preventScroll:true});
}
});
return {close:close};
}
};