(function (){
'use strict';
document.addEventListener('DOMContentLoaded', function (){
initRoleplayChats();
});
function initRoleplayChats(){
const wrappers=document.querySelectorAll('.brona-roleplay-wrapper');
wrappers.forEach(function (wrapper){
new BronaRoleplayChat(wrapper);
});
}
function BronaRoleplayChat(wrapper){
this.wrapper=wrapper;
this.messagesContainer=wrapper.querySelector('#brona-roleplay-messages');
this.input=wrapper.querySelector('#brona-roleplay-input');
this.sendBtn=wrapper.querySelector('#brona-roleplay-send');
this.restartBtn=wrapper.querySelector('#brona-roleplay-restart');
this.hintBtn=wrapper.querySelector('#brona-roleplay-hint');
this.tipsPanel=wrapper.querySelector('#brona-roleplay-tips');
this.tipsContent=wrapper.querySelector('#brona-tips-content');
this.charCount=wrapper.querySelector('#brona-char-count');
this.turnCount=wrapper.querySelector('#brona-turn-count');
this.scenario=wrapper.dataset.scenario||'hotel_receptionist';
this.level=wrapper.dataset.level||'intermediate';
this.correctionStyle=wrapper.dataset.correction||'gentle';
this.tone=wrapper.dataset.tone||'friendly';
this.maxTurns=parseInt(wrapper.dataset.maxTurns)||10;
this.customScenario=wrapper.dataset.customScenario||'';
this.conversationHistory=[];
this.currentTurn=0;
this.isLoading=false;
this.init();
}
BronaRoleplayChat.prototype.init=function (){
if(!this.input||!this.sendBtn) return;
this.sendBtn.addEventListener('click', this.handleSend.bind(this));
this.input.addEventListener('keydown', this.handleKeydown.bind(this));
this.input.addEventListener('input', this.handleInputChange.bind(this));
this.restartBtn.addEventListener('click', this.handleRestart.bind(this));
this.hintBtn.addEventListener('click', this.handleHint.bind(this));
this.loadGreeting();
};
BronaRoleplayChat.prototype.loadGreeting=function (){
const self=this;
fetch(bronaRoleplay.restUrl + 'greeting', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': bronaRoleplay.nonce
},
body: JSON.stringify({ scenario: this.scenario })
})
.then(function (response){ return response.json(); })
.then(function (data){
if(data.success){
self.addMessage('assistant', data.greeting);
self.conversationHistory.push({
role: 'assistant',
content: data.greeting
});
}})
.catch(function (error){
console.error('Failed to load greeting:', error);
const fallback=bronaRoleplay.scenarios[self.scenario]?.greeting||"Hello! How can I help you today?";
self.addMessage('assistant', fallback);
self.conversationHistory.push({ role: 'assistant', content: fallback });
});
};
BronaRoleplayChat.prototype.handleInputChange=function (){
const length=this.input.value.length;
this.charCount.textContent=length;
if(length > 450){
this.charCount.parentElement.classList.add('near-limit');
}else{
this.charCount.parentElement.classList.remove('near-limit');
}};
BronaRoleplayChat.prototype.handleKeydown=function (e){
if(e.key==='Enter'&&!e.shiftKey){
e.preventDefault();
this.handleSend();
}};
BronaRoleplayChat.prototype.handleSend=function (){
if(this.isLoading) return;
const message=this.input.value.trim();
if(!message) return;
if(this.currentTurn >=this.maxTurns){
this.showTip(bronaRoleplay.strings.maxTurns, 'warning');
return;
}
this.addMessage('user', message);
this.conversationHistory.push({ role: 'user', content: message });
this.input.value='';
this.charCount.textContent='0';
this.currentTurn++;
this.turnCount.textContent=this.currentTurn;
this.sendMessage(message);
};
BronaRoleplayChat.prototype.sendMessage=function (message){
const self=this;
this.setLoading(true);
fetch(bronaRoleplay.restUrl + 'message', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': bronaRoleplay.nonce
},
body: JSON.stringify({
message: message,
conversation_history: this.conversationHistory.slice(0, -1),
scenario: this.scenario,
level: this.level,
correction_style: this.correctionStyle,
tone: this.tone,
custom_scenario: this.customScenario
})
})
.then(function (response){ return response.json(); })
.then(function (data){
self.setLoading(false);
if(data.success){
self.addMessage('assistant', data.ai_response);
self.conversationHistory.push({
role: 'assistant',
content: data.ai_response
});
if(data.teacher_tip){
self.showTip(data.teacher_tip, 'tip', data.corrected_input);
}else{
self.showTip('✓ No major errors detected. Keep practicing to improve fluency and vocabulary.', 'tip', '');
}
self.scrollToBottom();
}else{
self.showTip(data.message||bronaRoleplay.strings.error, 'error');
}})
.catch(function (error){
self.setLoading(false);
console.error('Roleplay error:', error);
self.showTip(bronaRoleplay.strings.connectionError, 'error');
});
};
BronaRoleplayChat.prototype.addMessage=function (role, content){
const messageDiv=document.createElement('div');
messageDiv.className='brona-roleplay-message brona-roleplay-message-' + role;
const avatar=document.createElement('div');
avatar.className='brona-message-avatar';
avatar.textContent=role==='user' ? '👤':'🎭';
const bubble=document.createElement('div');
bubble.className='brona-message-bubble';
bubble.textContent=content;
messageDiv.appendChild(avatar);
messageDiv.appendChild(bubble);
this.messagesContainer.appendChild(messageDiv);
this.scrollToBottom();
};
BronaRoleplayChat.prototype.showTip=function (content, type, correctedInput){
const self=this;
this.tipsPanel.classList.add('brona-tips-updating');
setTimeout(function (){
self.tipsPanel.style.display='block';
self.tipsPanel.className='brona-roleplay-tips-panel brona-tips-' + type;
let html='<p>' + self.escapeHtml(content).replace(/\n/g, '<br>').replace(/•/g, '<br>•') + '</p>';
if(correctedInput){
html +='<div class="brona-corrected-version">';
html +='<strong>✏️ Better version:</strong> ';
html +='<span class="brona-corrected-text">' + self.escapeHtml(correctedInput) + '</span>';
html +='</div>';
}
self.tipsContent.innerHTML=html;
self.tipsPanel.classList.add('brona-tips-updated');
setTimeout(function (){
self.tipsPanel.classList.remove('brona-tips-updated');
}, 600);
}, 100);
};
BronaRoleplayChat.prototype.handleHint=function (){
if(this.isLoading) return;
const self=this;
this.hintBtn.disabled=true;
this.hintBtn.textContent='⏳ Loading...';
fetch(bronaRoleplay.restUrl + 'hint', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': bronaRoleplay.nonce
},
body: JSON.stringify({
conversation_history: this.conversationHistory,
scenario: this.scenario,
level: this.level
})
})
.then(function (response){ return response.json(); })
.then(function (data){
self.hintBtn.disabled=false;
self.hintBtn.textContent='💡 Get Hint';
if(data.success){
self.showTip('💡 Hint: ' + data.hint, 'hint');
}})
.catch(function (error){
self.hintBtn.disabled=false;
self.hintBtn.textContent='💡 Get Hint';
console.error('Hint error:', error);
});
};
BronaRoleplayChat.prototype.handleRestart=function (){
if(!confirm('Start a new conversation? Your current progress will be lost.')){
return;
}
this.conversationHistory=[];
this.currentTurn=0;
this.turnCount.textContent='0';
this.messagesContainer.innerHTML='';
this.tipsPanel.style.display='none';
this.loadGreeting();
};
BronaRoleplayChat.prototype.setLoading=function (loading){
this.isLoading=loading;
this.sendBtn.disabled=loading;
this.input.disabled=loading;
const btnText=this.sendBtn.querySelector('.btn-text');
const btnSpinner=this.sendBtn.querySelector('.btn-spinner');
if(loading){
btnText.style.display='none';
btnSpinner.style.display='inline';
this.addTypingIndicator();
}else{
btnText.style.display='inline';
btnSpinner.style.display='none';
this.removeTypingIndicator();
}};
BronaRoleplayChat.prototype.addTypingIndicator=function (){
const indicator=document.createElement('div');
indicator.className='brona-roleplay-message brona-roleplay-message-assistant brona-typing-indicator';
indicator.innerHTML='<div class="brona-message-avatar">🎭</div><div class="brona-message-bubble"><span class="typing-dots"><span>.</span><span>.</span><span>.</span></span></div>';
indicator.id='brona-typing-indicator';
this.messagesContainer.appendChild(indicator);
this.scrollToBottom();
};
BronaRoleplayChat.prototype.removeTypingIndicator=function (){
const indicator=document.getElementById('brona-typing-indicator');
if(indicator){
indicator.remove();
}};
BronaRoleplayChat.prototype.scrollToBottom=function (){
const container=this.messagesContainer.parentElement;
container.scrollTop=container.scrollHeight;
};
BronaRoleplayChat.prototype.escapeHtml=function (text){
const div=document.createElement('div');
div.textContent=text;
return div.innerHTML;
};})();
(function ($){
'use strict';
var lessonId=window.bronaKlubData ? window.bronaKlubData.lessonId:0;
if(lessonId&&typeof wpdiscuzAjaxObj!=='undefined'){
console.log('Overriding wpDiscuz post ID from', wpdiscuzAjaxObj.wc_post_id, 'to lesson ID:', lessonId);
wpdiscuzAjaxObj.wc_post_id=lessonId;
}
$(document).ready(function (){
console.log('Brona Klub script loaded');
console.log('jQuery version:', $.fn.jquery);
console.log('Button exists:', $('.mark-completed-btn').length);
if(lessonId&&typeof wpdiscuzAjaxObj!=='undefined'){
console.log('(Ready) wpDiscuz post ID:', wpdiscuzAjaxObj.wc_post_id, '-> Lesson ID:', lessonId);
wpdiscuzAjaxObj.wc_post_id=lessonId;
}
if(typeof $.colorbox==='function'){
$('a.colorbox').colorbox({
maxWidth: '90%',
maxHeight: '90%',
opacity: 0.8,
transition: 'fade',
photo: true
});
}
$(document).on('click', '.mark-completed-btn', function (e){
e.preventDefault();
console.log('Button clicked!');
var button=$(this);
var lessonId=button.data('lesson-id');
console.log('Lesson ID:', lessonId);
console.log('AJAX URL:', window.bronaKlubData.ajaxUrl);
if(!lessonId){
alert('Error: Lesson ID not found');
return;
}
button.prop('disabled', true).text('Processing...');
$.ajax({
url: window.bronaKlubData.ajaxUrl,
type: 'POST',
dataType: 'json',
data: {
action: 'mark_lesson_completed',
lesson_id: lessonId,
nonce: window.bronaKlubData.nonce
},
success: function (response){
console.log('AJAX Success:', response);
if(response.success){
button.text('✓ Completed!');
setTimeout(function (){
location.reload();
}, 1000);
}else{
alert('Error: ' + (response.data||'Unable to mark lesson as completed'));
button.prop('disabled', false).text('✓ Mark as Completed');
}},
error: function (xhr, status, error){
console.error('AJAX Error:', status, error);
console.error('Response:', xhr.responseText);
alert('An error occurred: ' + error + '. Please check the console and try again.');
button.prop('disabled', false).text('✓ Mark as Completed');
}});
});
});
})(jQuery);