let caseid = ''; let catid = ''; let case_access_token = ''; let state = 'new'; let root_domain = getRootDomain(window.location); let params = new URLSearchParams(window.location.search); let last_caseinfo_md5 = ""; let pause_case_documents_syncing = false; let document_uploading = false; let documentAnalyseFailover = false; let summaryAnalyseFailover = false; let rantokmizeRunning = false; let currentAudio = null; // This variable will hold the currently playing audio let audioVolume = 1.0; // This variable will hold the currently playing audio let socket = null; let months_long, months, days_long, days; const sourcePage = window.location.pathname.split('/')[1]; const reference = getQueryParam('ref'); const userAgentString = navigator.userAgent; let currentOpenDatePickerTd; // This will hold the td that was clicked // MAIN $(document).ready(function() { months_long = _settings.translations.js_months_long.toLowerCase().split('|'); months = _settings.translations.js_months_short.toLowerCase().split('|'); days_long = _settings.translations.js_weekdays_long.toLowerCase().split('|'); days = _settings.translations.js_weekdays_short.toLowerCase().split('|'); console.log("LegalAI script (WEB)"); let caseForm = document.getElementById('case_form'); let savedVolumeState = get_cookie("audioVolumeState"); if (savedVolumeState) { let $volumeButton = $('#speak_volume'); setVolumeState($volumeButton, savedVolumeState); // If the saved state is muted, apply the shake animation if (savedVolumeState === "muted") { $volumeButton.addClass('fa-shake'); setTimeout(function() { $volumeButton.removeClass('fa-shake'); }, 2500); // remove the animation classes after it completes } } $(document).on('click', function(e){ // If the clicked element is not part of the tooltip if (!$(e.target).closest('.tooltip').length) { $(".tooltip").each(function() { // Check if the tooltip is initialized if ($(this).tooltip("instance")) { $(this).tooltip("close"); } }); } // If the clicked element is not part of the PDF preview, hide the preview if (!$(e.target).closest('#pdf-preview').length) { $('#pdf-preview').hide(); } }); $('#speak_volume').click(function() { let currentState = $(this).hasClass('fa-volume-high') ? 'muted' : 'high'; setVolumeState($(this), currentState); }); }); async function newWssSocket( case_access_token ){ // If socket is already connected, close it. if (isSocketConnected()) { socket.close(); socket = null; // Set socket to null to ensure a fresh connection. } // Hash the case_access_token const sha512_case_access_token = await sha512( case_access_token ); // Now create a new WebSocket connection socket = new WebSocket( 'wss://wss.legalai.cloud/' + sha512_case_access_token ); socket.addEventListener('message', function(e) { console.log( 'Received data:', e.data ); if ( /^legalai\|\d+$/.test( e.data ) ){ checkCaseInfo(); } }); } function isSocketConnected(){ return socket && socket.readyState === WebSocket.OPEN; } function showDialog(title, text) { $('
').html(text).dialog({ title: title, modal: true, buttons: { Ok: function() { $(this).dialog("close"); // close the dialog when the Ok button is clicked stopSpeaking(); } }, close: function() { $(this).remove(); // remove the dialog from the DOM after it's closed } }); } function showConfirmDialog(title, text, callback, relativeElement = null) { $('
', { text: text }).dialog({ title: $('
').html(title).text(), modal: true, width: function() { return Math.max($(window).width() * 0.3, 360); }, position: relativeElement ? { my: 'right top', of: relativeElement } : { my: 'center', at: 'center', of: window }, buttons: [ { text: _settings.translations.yes, click: function() { callback(true); // Call the callback with `true` when Yes is clicked $(this).dialog("close"); } }, { text: _settings.translations.no, click: function() { callback(false); // Call the callback with `false` when No is clicked $(this).dialog("close"); } } ], close: function() { $(this).remove(); } }); } function bdgujd( s ){ return JSON.parse( decompressData( s ) ); } function ucfirst(str) { return str.charAt(0).toUpperCase() + str.slice(1); } function styleOddRows() { $('#case-table table tbody tr').each(function(index) { $(this).toggleClass('odd', index % 2 !== 0); $(this).toggleClass('even', index % 2 == 0); }); } // Function to initialize tooltips function initializeTooltips() { $(".tooltip").tooltip({ items: ".tooltip", content: function() { return $(this).data("tooltiptext"); }, track: true }); } function sortTable() { let rows = $('#case-table table tbody tr').get(); // Get all rows as an array // Sort the array based on data-timestamp rows.sort(function(a, b) { let aTimestamp = $(a).find('.date-info').attr('data-timestamp'); let bTimestamp = $(b).find('.date-info').attr('data-timestamp'); if (aTimestamp > bTimestamp) { return 1; } if (aTimestamp < bTimestamp) { return -1; } return 0; }); // Append the sorted rows back to the table $.each(rows, function(index, row) { $('#case-table table').children('tbody').append(row); }); if (currentOpenDatePickerTd) { let newOffset = currentOpenDatePickerTd.offset(); $('.ui-datepicker').css({ top: newOffset.top + currentOpenDatePickerTd.innerHeight(), left: newOffset.left }); } } function formatDate(unixTimestamp) { const date = new Date(unixTimestamp * 1000); // Convert to milliseconds const day = date.getDate().toString().padStart(2, '0'); // Ensure the day is always 2 digits const month = months[date.getMonth()]; const year = date.getFullYear(); const dayOfWeek = ucfirst( days[date.getDay()] ); // Extract the hours and minutes, padding with zeros if needed const hours = date.getHours().toString().padStart(2, '0'); const minutes = date.getMinutes().toString().padStart(2, '0'); return `${dayOfWeek} ${day}. ${month} ${year} kl.${hours}:${minutes}`; } function setDateInfo() { $('#case-table table td.date-info').each(function() { const unixTimestamp = $(this).attr('data-timestamp'); const formattedDate = formatDate(unixTimestamp); $(this).html(formattedDate); }); sortTable(); // Call sortTable after updating date info styleOddRows(); } // Function to be called on click function handleDateInfoClick(tdElement) { currentOpenDatePickerTd = $(tdElement); // Set the current td let input = $('') .attr('type', 'text') .css({ position: 'absolute', left: $(tdElement).offset().left, top: $(tdElement).offset().top, width: 0, height: $(tdElement).innerHeight(), opacity: 0 }) .appendTo('body'); let initialDate = new Date($(tdElement).attr('data-timestamp') * 1000); // Create a Date object from the Unix timestamp input.datetimepicker({ firstDay: 1, // Monday dateFormat: 'dd.mm.yy', timeFormat: 'HH:mm', dayNamesMin: days.map( day => ucfirst( day ) ), monthNames: months_long.map( month => ucfirst( month ) ), monthNamesShort: months.map( month => ucfirst( month ) ), timeText: _settings.translations.js_time_text, hourText: _settings.translations.js_hour_text, minuteText: _settings.translations.js_minute_text, currentText: $('
').html(_settings.translations.js_current_text ).text(), closeText: $('
').html( _settings.translations.js_close_text ).text(), beforeShow: function(dateTimeText, inst) { pause_case_documents_syncing = true; setDateInfo(); }, onSelect: function(dateTimeText, inst) { $('.ui_tpicker_hour_label').text('Hour'); // For hour label $('.ui_tpicker_minute_label').text('Minute'); // For minute label $('.ui_tpicker_time_label').text('Time'); // For general time label let unixTimestamp = $.datepicker.parseDateTime('dd.mm.yy', 'HH:mm', dateTimeText).getTime() / 1000; // Convert to Unix timestamp $(this).closest('td').attr('data-timestamp', unixTimestamp); $(tdElement).attr('data-timestamp', unixTimestamp); setDateInfo(); let document_id = $(tdElement).closest('tr').attr('data-nid'); timestampDocument( case_access_token, document_id, unixTimestamp ); }, onClose: function(dateTimeText, inst) { let unixTimestamp = $.datepicker.parseDateTime('dd.mm.yy', 'HH:mm', dateTimeText).getTime() / 1000; // Convert to Unix timestamp $(this).closest('td').attr('data-timestamp', unixTimestamp); $(tdElement).attr('data-timestamp', unixTimestamp); setDateInfo(); let document_id = $(tdElement).closest('tr').attr('data-nid'); timestampDocument( case_access_token, document_id, unixTimestamp ); $('#case-table table tbody tr').removeClass('sorting-drag'); currentOpenDatePickerTd = null; pause_case_documents_syncing = false; } }); input.datetimepicker('setDate', initialDate); input.datetimepicker('show'); } // This function uploads a file using AJAX function uploadFile(file) { let formData = new FormData(); formData.append('case_access_token', case_access_token); formData.append('file', file); document_uploading = true; pause_case_documents_syncing = true; $('#upload-overlay').css('display', 'flex'); let info_text = _settings.translations.uploading_file; $('#upload-overlay div button span').text( info_text ); speak( info_text, 'female'); // Set the cursor to 'progress' document.body.style.cursor = 'progress'; $.ajax({ xhrFields: { withCredentials: true }, url: 'https://api.'+ root_domain +'/api/2023-06/case_document_upload', // replace with the URL of your file upload endpoint type: 'POST', data: formData, cache: false, contentType: false, processData: false, timeout: 60000, // 60 seconds (break if loading file takes to long) success: function(response) { console.log('File uploaded successfully'); // let info_text = htmlDecode( "Filen er lastet opp. Den vil nå blir bearbeidet og lagt til i dokumentoversikten innen kort tid." ); info_text = htmlDecode( _settings.translations.file_being_analyzed ); $('#upload-overlay div button span').text( info_text ); speak( info_text, 'female', function(){ document_uploading = false; pause_case_documents_syncing = false; // Set a delay to check and hide the overlay after 60 seconds (fallback) documentAnalyseFailover = setTimeout(function() { if ($('#upload-overlay').css('display') !== 'none') { // Restore mouse cursor and remove "upload and processing" overlay document.body.style.cursor = 'auto'; $('#upload-overlay').hide(); info_text = htmlDecode( _settings.translations.file_analyze_error ); speak( info_text, 'female', function(){ showDialog( _settings.translations.uploading, info_text ); }); } }, 60000 ); // One minute }); }, error: function(response) { $('#upload-overlay').hide(); console.log('File upload error'); document.body.style.cursor = 'auto'; info_text = htmlDecode( _settings.translations.file_upload_error ); speak( info_text, 'female', function(){ showDialog( _settings.translations.uploading, info_text ); document_uploading = false; pause_case_documents_syncing = false; }); } }); } function getSessionCaseAccessToken( sourcePage ){ $.ajax({ url: 'https://api.'+ root_domain +'/api/2023-06/session_case_access_token', type: 'GET', contentType: 'application/json', xhrFields: { withCredentials: true }, success: function( response, textStatus, jqXHR) { if (jqXHR.status === 200) { // Case is in Reviewing state - redirect to infopage if ( response.data.case_access_token && response.data.case_access_token.length > 0 ){ case_access_token = response.data.case_access_token; catid = response.data.catid; have_clientinfo = response.data.have_clientinfo; loginInit( catid, case_access_token ); if ( sourcePage == 'w1' ){ checkCaseAccessTokenState(); } else if ( sourcePage == 'w2' ){ checkCaseInfo(); } else if ( sourcePage == 'w3' && have_clientinfo ){ console.log( 'page w3' ); $('#div-postform').hide(); } } else { console.log('No case_access_token'); if ( sourcePage != 'w1' ){ top.window.location.href = '/w1'; } } } else if (jqXHR.status === 304) { console.log('No changes'); } else { console.error('Error fetching case info:', response.status); } }, error: function(jqXHR, textStatus, errorThrown) { console.error('Error fetching case info:', textStatus, errorThrown); } }); } function deleteSession(){ $.ajax({ url: 'https://api.'+ root_domain +'/api/2023-06/session_case_access_token', type: 'DELETE', contentType: 'application/json', xhrFields: { withCredentials: true }, success: function( response, textStatus, jqXHR) { if ( jqXHR.status === 200 ){ top.document.location.href = '/w1'; } else { console.error('Error deleting session:', response.status); } }, error: function(jqXHR, textStatus, errorThrown) { console.error('Error with server to delete session:', textStatus, errorThrown); } }); } function checkCaseAccessTokenState(){ if ( case_access_token && case_access_token.length > 0 ){ console.log( 'Existing(w) CASE_ACCESS_TOKEN: '+ case_access_token ); // loginInit( catid, case_access_token ); // Set up our HTTP request fetch( 'https://api.'+ root_domain +'/api/2023-06/case_info', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ 'case_access_token': case_access_token } ) }) .then( response=>response.json() ) .then( data=> { console.log( 'Success2:', data ); if ( data.status.code == 200 ){ state = data.caseinfo.state; console.log( state ); if ( state == 'active' ){ $('#part0').hide(); $('#part1_4 #case_button-explanation').dblclick(); } else if ( state == 'reviewing' && sourcePage != 'w3' ){ top.window.location.href = '/w3'; } } } ) .catch( ( error )=>{ console.error( 'Error2:', error ); }); } } function checkCaseInfo(){ if ( case_access_token && case_access_token.length > 0 && pause_case_documents_syncing == false ){ console.log( 'Existing(w) CASE_ACCESS_TOKEN: '+ case_access_token ); $.ajax({ url: 'https://api.'+ root_domain +'/api/2023-06/case_info', type: 'POST', contentType: 'application/json', xhrFields: { withCredentials: true }, data: JSON.stringify({ 'case_access_token': case_access_token, // Replace with the actual case token 'last_md5': last_caseinfo_md5 // Include the last known MD5 hash }), success: function( response, textStatus, jqXHR) { if (jqXHR.status === 200) { last_caseinfo_md5 = response.currentMd5; // Assuming the MD5 is included in the response data // Case is in Reviewing state - redirect to infopage if ( response.caseinfo ){ console.log( 'Case info has changed:', response.caseinfo ); if ( response.caseinfo.state == 'reviewing' && sourcePage != 'w3' ){ top.window.location.href = '/w3'; } else if ( $('#chat_div-summary').length ){ if ( response.caseinfo.summary == '' || $('
').html( response.caseinfo.summary ).text() == '' ){ // summary = '
'+ _settings.translations.working_on_summary +'
'; // $('#div-buttons1').hide(); summary = response.caseinfo.explanation; // console.log( 'Setting summaryAnalyseFailover timeout'); // summaryAnalyseFailover = setTimeout( function(){ // console.log( 'Doing: checkCaseInfo()' ); // last_caseinfo_md5 = ""; // checkCaseInfo(); // }, 120000 ); // Two minutes } else if ( $('
').html( response.caseinfo.summary ).text() == '' ){ // summary = _settings.translations.unable_to_create_summary; summary = $.trim( response.caseinfo.explanation ); $('#div-buttons1').slideDown(); } else { clearTimeout(summaryAnalyseFailover); console.log('summaryAnalyseFailover cleared'); summary = $.trim( response.caseinfo.summary ); $('#div-buttons1').slideDown(); } updateDiv('chat_div-summary', summary, true); } else { updateEmail( response.caseinfo.case_email_token ); updateTableData( response.caseinfo ); } } } else if ( jqXHR.status === 304 ){ console.log('Case info has not changed.'); // console.error('Error fetching case info:', response.status); } }, error: function( jqXHR, textStatus, errorThrown ){ if ( jqXHR.status === 403 ){ case_access_token = ''; console.log('No access.'); $("
") .attr("title", _settings.translations.access_denied) .text(_settings.translations.no_access_message) .dialog({ modal: true, buttons: { "OK": function() { $(this).dialog("close"); // Redirect to root path '/' after clicking OK window.location.href = '/'; } }, close: function() { $(this).dialog("destroy").remove(); } }); } console.error('ERROR fetching case info:', textStatus, errorThrown); } }); } } function rantokmize(text, div, delay, onComplete) { let decodedText = htmlDecode(text); let pieces = decodedText.split(/(?=\s|\b)/g); clearTimeout(rantokmizeRunning); // Add the fa-angles-down icon under the div using the ::before pseudo-element $("#" + div).css("position", "relative").addClass("show-icon"); console.log("rantokmize: " + div); let i = 0; let wasClicked = false; $("#" + div).on('click', function() { wasClicked = true; }); function processPiece() { if (i >= pieces.length || wasClicked ) { if (wasClicked) { updateDiv(div, text, true); $("#" + div).removeClass("show-icon"); stopSpeaking(); } // Remove the fa-angles-down icon once writing is done $("#" + div).removeClass("show-icon"); // Call the provided onComplete callback if (onComplete && typeof onComplete === "function") { onComplete(); } return; } let piece = pieces[i]; if (piece.length > 5 || (piece.length > 2 && Math.random() < 0.66)) { let randomIndex = Math.floor(Math.random() * piece.length / 1.7); updateDiv(div, piece.substring(0, randomIndex), false); pieces[i] = piece.substring(randomIndex); } else { updateDiv(div, piece, false); i++; } rantokmizeRunning = setTimeout(processPiece, delay); } processPiece(); // Kick off the process } function speak(text, voice, onStarted) { if (typeof voice === 'undefined') { voice = 'female'; } // Make the POST request to the text-to-speech endpoint fetch("https://api."+ root_domain +"/api/2023-06/text2speech", { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ text: text.replace(/[:\n]/g, '. '), engine: 'google', voice: voice, language: _settings.language }) }) .then(response => response.json()) .then(data => { stopSpeaking(); // Parse the response if needed currentAudio = new Audio(data.mp3file); currentAudio.volume = audioVolume; if ( userAgentString.match( /iPhone/i ) || userAgentString.match( /iPad/i ) ){ onStarted(); } else { // Add an event listener for the 'canplaythrough' event currentAudio.addEventListener('canplaythrough', function() { console.log('The mp3file is ready to be played without interruptions.'); if ( userAgentString.match( /iPhone/i ) || userAgentString.match( /iPad/i ) ){ // alert('2 '+userAgentString); } // Start playing the audio currentAudio.play(); // Call the onStarted callback after playing has started if (onStarted && typeof onStarted === "function") { onStarted(); } }); } }) .catch((error) => { console.error('Error fetching mp3file:', error); }); } function stopSpeaking() { if (currentAudio) { currentAudio.pause(); // Manually trigger the 'ended' event let event = new Event('ended'); currentAudio.dispatchEvent(event); } } function copyToClipboard( element ){ let $temp = $(""); $("body").append($temp); $temp.val($(element).text()).select(); document.execCommand("copy"); $temp.remove(); } function htmlDecode(input){ let doc = new DOMParser().parseFromString(input, "text/html"); return doc.documentElement.textContent; } function updateDiv(div, text, shouldSet) { $(div).slideDown(); // Replace all new line characters with HTML line breaks text = text.replace(/\n/g, '
'); // If shouldSet is true, set the innerHTML. Otherwise, append. if (shouldSet) { document.getElementById(div).innerHTML = text; } else { document.getElementById(div).innerHTML += text; } } function updateSummary(case_access_token, newSummary) { $.ajax({ xhrFields: { withCredentials: true }, url: 'https://api.'+ root_domain +'/api/2023-06/case_summary_update', type: 'PATCH', contentType: 'application/json', data: JSON.stringify({ 'case_access_token': case_access_token, 'summary': newSummary }), success: function(response, textStatus, jqXHR) { if (jqXHR.status === 200) { console.log('Summary updated successfully:', response.data); // You can add any logic to be executed after a successful summary update here } else { console.error('Error updating summary:', response.status); } }, error: function(jqXHR, textStatus, errorThrown) { console.error('Error updating summary:', textStatus, errorThrown); } }); } function requestSummary(case_access_token) { console.log('Summary request comment out'); window.top.location.href = '/w2'; // $.ajax({ // xhrFields: { // withCredentials: true // }, // url: 'https://api.'+ root_domain +'/api/2023-06/case_summary_request', // type: 'POST', // contentType: 'application/json', // data: JSON.stringify({ // 'case_access_token': case_access_token // }), // success: function(response, textStatus, jqXHR) { // if ( jqXHR.status === 200 ){ // window.top.location.href = '/w2'; // console.log('Summary request successfully:', response.data); // } else { // console.error('Error summary request:', response.status); // } // }, // error: function(jqXHR, textStatus, errorThrown) { // console.error('Error summary request:', textStatus, errorThrown); // } // }); } function setVolumeState($speakVolumeButton, state) { if (state === "muted" || (state === undefined && $speakVolumeButton.hasClass('fa-volume-high'))) { $speakVolumeButton.removeClass('fa-volume-high').addClass('fa-volume-mute'); audioVolume = 0.0; if (currentAudio) { currentAudio.volume = 0.0; // Mute } set_cookie("audioVolumeState", "muted", 30, "/"); } else { $speakVolumeButton.removeClass('fa-volume-mute').addClass('fa-volume-high'); audioVolume = 1.0; if (currentAudio) { currentAudio.volume = 1.0; } set_cookie("audioVolumeState", "high", 30, "/"); } } function getFontAwesomeIconForFileExtension(fileExtension) { const iconToExtensionMap = { 'fa-file-pdf': ['pdf'], 'fa-file-word': ['doc', 'docx'], 'fa-file-excel': ['xls', 'xlsx'], 'fa-file-powerpoint': ['ppt', 'pptx'], 'fa-file-image': ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tiff'], 'fa-file-audio': ['mp3', 'wav', 'ogg', 'flac'], 'fa-file-video': ['mp4', 'avi', 'mkv', 'webm'], 'fa-file-csv': ['csv', 'tsv'], 'fa-file-archive': ['zip', 'rar', 'tar', 'gz', '7z'], 'fa-file-code': ['js', 'html', 'css', 'php', 'py', 'c', 'cpp', 'java', 'rb', 'xml', 'json'] }; for (let icon in iconToExtensionMap) { if (iconToExtensionMap[icon].includes(fileExtension.replace('.', '').toLowerCase())) { return icon; } } return 'fa-file'; // Default icon } set_cookie = function( c_name, value, exdays, path, samesite = 'Strict' ){ let expires = new Date(); expires.setTime(expires.getTime() + (exdays * 86400000)); let c_value = escape(value); if (exdays !== null) { c_value = c_value + "; expires=" + expires.toUTCString(); } if (path !== null) { c_value = c_value + "; path=" + path; } // Add secure flag if the page is accessed over HTTPS if ( window.location.protocol === "https:" ){ c_value += "; secure"; } // Add samesite attribute c_value += "; samesite=" + samesite; document.cookie = c_name + "=" + c_value; } get_cookie = function(c_name) { let cookies = document.cookie.split(";").map(cookie => cookie.trim().split("=")); for (let [name, value] of cookies) { if (name === c_name) { return decodeURIComponent(value); } } } // W1 function checkMsnSyntax( case_access_token, msn, callback ){ let apiEndpoint = "https://api."+ root_domain +"/api/2023-06/case_init"; fetch(apiEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ msn: msn, language: _settings.language, reference: reference }) }) .then(response => response.json()) .then(data => { callback(data); }) .catch((error) => { // console.error('Error fetching the msn validation endpoint:', error); // callback('Server error. Please try again later.'); }); } function updateEmail( case_email_token ){ if ( case_email_token && $('#part2 #case-email').text() == '' ){ $('#part2 #case-email').text( 'sak-'+ case_email_token +'@legalai.as' ); } } function loginInit( catid, case_access_token ){ if ( catid && catid.length > 0 && case_access_token && case_access_token.length > 0 ){ set_cookie( "catid", catid, 1, "/cdn" ); // Enable Websocket newWssSocket( case_access_token ); // Clean the browser url cleanUrl(); // Change login header button to logout $('#login-logout').text( _settings.translations.log_out ).attr('href', '/w1#utlogging'); } } function pincodeValidate( msn, pincode ){ let apiEndpoint = "https://api."+ root_domain +"/api/2023-06/case_msn-pincode_verify"; // Make the PATCH request to update the document timestamp update fetch(apiEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ msn: msn, pincode: pincode }) }) .then(response => response.json()) .then(data => { if ( data.status.code === 200 ){ state = data.state; case_access_token = data.data.case_access_token; catid = data.data.catid; loginInit( catid, case_access_token ); if ( state == 'pending' ){ $('#contentPincodeValidate').dialog('close'); $('#part1').slideUp(); info_text = htmlDecode( _settings.translations.welcome_to_legal_service_platform ); $('#div-init').slideUp(); $('#div-part1').slideUp(); speak( info_text, 'female', function() { $('#part1_2').slideDown(); div = 'chat_div-dialog'; updateDiv(div, "", true); rantokmize( info_text, div, 82, function() { $('#chat_button-part1_2').slideDown(); }); }); } else if ( state == 'active' ){ $('#contentPincodeValidate').dialog('close'); $('#part1_2').slideUp(); $('#part1_4 #case_button-explanation').dblclick(); } else { $('#contentPincodeValidate').dialog('close'); $('#part1_2').slideUp(); $('#part1_4 #case_button-explanation').dblclick(); } } else if ( data.status.code === 403 ){ let info_text = _settings.translations.system_update_message; speak( info_text, 'female', function(){ showDialog(_settings.translations.system_update_title, info_text ); }); } else { let info_text = _settings.translations.incorrect_pin_message; speak( info_text, 'female', function(){ showDialog( _settings.translations.incorrect_pin_title, info_text ); }); console.error('Error validating pincode:', data.status.message); // Handle failure: show an error message or perform other error handling } }) .catch((error) => { console.error('Error fetching the update timestamp endpoint:', error); }); } function updateTableData( data ){ let row; let scrollRow; let documents = data.documents; // Store identifiers of existing rows const existingIds = $('#part2 #case-table tbody tr').map(function() { return $(this).data('nid'); }).get(); // Clear existing rows $('#part2 #case-table tbody').empty(); if ($.isEmptyObject(documents)) { $('#part2 #instructional').show(); $('#part2 #documents').hide(); // Append a message if no documents $('#part2 #case-table thead').hide(); $('#part2 #chat_button-part2').hide(); $('#part2 #case-table tbody').append('
'+ _settings.translations.no_documents +'
'); } else { // $('#part2 #instructional').hide(); $('#part2 #documents').show(); $('#part2 #case-table thead').show(); $('#part2 #chat_button-part2').slideDown(); // Iterate through the documents and append them to the table $.each(documents, function(index, document) { let nid = document.document_id; let datetime = new Date(document.document_timestamp * 1000).toLocaleString(); let documentname = document.document_name; let note = ''+ documentname + ''; // HTML decode before comparing if ( $('
').html( document.document_summary ).text() == '' ){ note += '
'+ _settings.translations.summary_not_available +'
'; } else { note += '
• ' + document.document_summary.replace( /\n/g, '
• ' ) +'
'; } // Extract tags from the object and convert them to an array of tag values let tagsArray = Object.values(document.tags); let icons = []; // Check for 'attachment' in tagsArray if (tagsArray.includes('attachment')) { icons.push(''); } else { icons = tagsArray.map(function(tag) { if (tag === 'upload') { return ''; } else if (tag === 'email') { return ''; } else { return tag; // Keep the tag value as is if not recognized } }); } // Join icons into a string let tags = icons.reverse().join(' '); row = $('' + datetime + '' + note + '' + tags + ' '); $('#part2 #case-table tbody').append(row); if ( existingIds.length > 0 && Object.keys(data.documents).length > existingIds.length && !existingIds.includes( nid ) ){ shouldScroll = true; // set the flag to true let start = performance.now(); requestAnimationFrame(function animate(time) { let timeFraction = (time - start) / 3000; // 3 seconds duration if (timeFraction > 1) timeFraction = 1; // Calculate the border color's opacity based on the time fraction. let opacity = 1 - timeFraction; let bgColor = `rgba(100, 123, 158, ${opacity})`; // #647b9e in rgba format row.find('td').css('background-color', bgColor); // apply to all 'td' elements within 'row' if (timeFraction < 1) { requestAnimationFrame(animate); } else { row.find('td').css('background-color', 'unset'); // Unset the background-color for all 'td' elements after animation } }); scrollRow = row; } }); // Restore mouse cursor and remove "upload and processing" overlay, if any if ($('#upload-overlay').css('display') !== 'none') { document.body.style.cursor = 'auto'; $('#upload-overlay').hide(); clearTimeout(documentAnalyseFailover); } setDateInfo(); initializeTooltips(); if ( scrollRow ){ // Scroll the tr to the top of the screen $('html, body').animate({ scrollTop: scrollRow.offset().top }, 1000); // 1000ms duration for the scroll animation } } } function openPreview(url, iconPosition) { if (previewCache[url]) { // Use cached canvas if available displayPreview(previewCache[url], iconPosition); return; } pdfjsLib.getDocument(url).promise.then(function(pdf) { pdf.getPage(1).then(function(page) { let scale = 1.0; if ( document.body.clientWidth < 767 ){ scale = 0.5; } let viewport = page.getViewport({ scale: scale }); if (viewport.width > 500) { scale = 500 / viewport.width; } viewport = page.getViewport({ scale: scale }); let canvas = document.createElement('canvas'); canvas.width = viewport.width; canvas.height = viewport.height; let ctx = canvas.getContext('2d'); let renderContext = { canvasContext: ctx, viewport: viewport }; let renderTask = page.render(renderContext); renderTask.promise.then(function() { previewCache[url] = canvas; // Cache the rendered canvas displayPreview(canvas, iconPosition); }); }); }); } function displayPreview(canvas, iconPosition) { $('#pdf-preview').html(canvas).show(); let leftPosition = iconPosition.left - canvas.width - 10; let topPosition = iconPosition.top; // Calculate the potential bottom position let bottomPosition = window.innerHeight - (iconPosition.top + $('#pdf-preview').height()); // Check if the bottom of the PDF preview would be out of the viewport if (bottomPosition < 0) { // Adjust the topPosition so the bottom of the preview aligns with the bottom of the icon topPosition = iconPosition.top - $('#pdf-preview').height(); // Now check if placing at the top will make it go out of the viewport if (topPosition < 0) { // If so, center the preview in the viewport topPosition = (window.innerHeight - $('#pdf-preview').height()) / 2; } } $('#pdf-preview').css({ 'left': leftPosition, 'top': topPosition }); } function timestampDocument( case_access_token, document_id, new_timestamp ){ if ( case_access_token === undefined || document_id === undefined || new_timestamp === undefined ) { console.log('CASE_ACCESS_TOKEN, DOCUMENT_ID, or NEW_TIMESTAMP is not defined'); return; } let apiEndpoint = "https://api."+ root_domain +"/api/2023-06/case_document-timestamp_update"; // Make the PATCH request to update the document timestamp update fetch(apiEndpoint, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ case_access_token: case_access_token, document_id: document_id, timestamp: new_timestamp }) }) .then(response => response.json()) .then(data => { if (data.status.code === 200) { console.log('The timestamp was updated successfully.'); // Handle success: update the UI or redirect the user as needed checkCaseInfo(); } else { console.error('Error updating timestamp:', data.status.message); // Handle failure: show an error message or perform other error handling } }) .catch((error) => { console.error('Error fetching the update timestamp endpoint:', error); }); } function nameDocument( case_access_token, document_id, new_name ){ if ( case_access_token === undefined || document_id === undefined || new_name === undefined ) { console.log('CASE_ACCESS_TOKEN, DOCUMENT_ID, or NEW_NAME is not defined'); return; } let apiEndpoint = "https://api."+ root_domain +"/api/2023-06/case_document-name_update"; // Make the PATCH request to update the document timestamp update fetch(apiEndpoint, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ case_access_token: case_access_token, document_id: document_id, document_name: new_name }) }) .then(response => response.json()) .then(data => { if (data.status.code === 200) { console.log('The document name was updated successfully.'); // Handle success: update the UI or redirect the user as needed checkCaseInfo(); } else { console.error('Error updating document name:', data.status.message); // Handle failure: show an error message or perform other error handling } }) .catch((error) => { console.error('Error fetching the update document name endpoint:', error); }); } function summaryDocument( case_access_token, document_id, new_summary ){ if ( case_access_token === undefined || document_id === undefined || new_summary === undefined ) { console.log('CASE_ACCESS_TOKEN, DOCUMENT_ID, or NEW_SUMMARY is not defined'); return; } let apiEndpoint = "https://api."+ root_domain +"/api/2023-06/case_document-summary_update"; // Make the PATCH request to update the document timestamp update fetch(apiEndpoint, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ case_access_token: case_access_token, document_id: document_id, document_summary: new_summary }) }) .then(response => response.json()) .then(data => { if (data.status.code === 200) { console.log('The document summary was updated successfully.'); // Handle success: update the UI or redirect the user as needed checkCaseInfo(); } else { console.error('Error updating document summary:', data.status.message); // Handle failure: show an error message or perform other error handling } }) .catch((error) => { console.error('Error fetching the update document summary endpoint:', error); }); } function deleteDocument(case_access_token, document_id) { if ( case_access_token === undefined || document_id === undefined ) { console.log('CASE_ACCESS_TOKEN or DOCUMENT_ID is not defined'); return; } let apiEndpoint = "https://api."+ root_domain +"/api/2023-06/case_document_delete"; // Make the DELETE request to delete the document fetch(apiEndpoint, { method: 'DELETE', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ case_access_token: case_access_token, document_id: document_id }) }) .then(response => response.json()) .then(data => { if (data.status.code === 200) { console.log('The document was deleted successfully.'); // Handle success: update the UI or redirect the user as needed checkCaseInfo(); } else { console.error('Error deleting document:', data.status.message); // Handle failure: show an error message or perform other error handling } }) .catch((error) => { console.error('Error fetching the delete document endpoint:', error); }); } function openPDF(pdfPath) { $('#pdf-embed').attr('src', pdfPath); $('#pdf-overlay').show(); } // W2 function makeEditable() { $('#div-buttons1').slideUp(); $('#div-buttons2').slideDown(); let div = $('#chat_div-summary'); let content = div.html().replace(/
/g, '\n'); let textarea = $('