function ConsoleLog(logText) {
// Check if the URL contains the parameter "debug=true"
const urlParams = new URLSearchParams(window.location.search);
const debugMode = urlParams.get('debug');
// If debug is set to true, log the text
if (debugMode === 'true') {
console.log(logText);
}
}
/**
* LoadMethods is in the start page head tag, this is just a place to store the code
* It sets the initial states and contains code for the getjob button click event.
* getJob.addEventListener('click') -> this event has Prompt 1 builtin in
* Prompt 1 -> queries LLM with jobTitle and JobDescription and returns Segments in an array and JobDescriptionSummary
*/
function LoadMethods()
{
try
{
// Select the form element and the loader elements
const form = document.querySelector('#wf-form-chatgptForm');
const resultWrap = document.querySelector('#statement-component');
const resultLoader = document.querySelector('#statement-loader');
const resultText = document.querySelector('#statement-text');
const getJob = document.querySelector('#btnGetJob');
const getJobNewSearch = document.querySelector('#btnGetJob_NewSearch');
const generateJobDescription = document.querySelector('#openWizard');
const generateJobDescription_NewSearch = document.querySelector('#openWizard-newSearch');
const getJobChat = document.querySelector('#btnGetJobChat');
const getStarted = document.querySelector('#btnGetStarted');
const getStartedBottom = document.querySelector('#get-started-free');
const learnMoreBtn = document.querySelector('#btnLearnMore-1');
const learnMoreBtn_Agency = document.querySelector('#btnLearnMore_Agency');
const checkStatusBtn = document.querySelector('#btnCheckStatus');
const btnCancel = document.querySelector('#btnCancel');
const newSearch = document.querySelector('#NewSearch');
const submitConsent = document.querySelector('#btnSubmitConsent');
var txtJobTitle = document.getElementById('jobTitle');
var jobInput = document.getElementById('jobInput');
var txtJobDescription = document.getElementById('jobDescription');
var btnLogInOut = document.getElementById('btnLogInOut');
var promptLogin = document.getElementById('admin-prompt-login');
//var
// agency
const getStartedBottom_Agency = document.querySelector('#get-started-free_Agency');
const getStarted_Agency = document.querySelector('#btnGetStarted_Agency');
if(jobInput)
{
jobInput.addEventListener('click', (event) => {
// empty ui
var addResponsibilitiesContainter = document.getElementById('add-repsonsibilities-container');
if(addResponsibilitiesContainter)
{
addResponsibilitiesContainter.innerHTML = '';
}
var responsibilitiesContainter = document.getElementById('responsibilities');
var AI_responsibilitiesContainter = document.getElementById('ai-responsibilities');
/*if(responsibilitiesContainter)
{
responsibilitiesContainter.innerHTML = '';
}*/
if(AI_responsibilitiesContainter)
{
AI_responsibilitiesContainter.innerHTML = '';
}
// clear this of values - decided against that. keep them
//selectedResponsibilities = [];
// reset to the first step
document.querySelectorAll(".wizard-step").forEach(step => {
step.style.display = "none";
});
document.querySelector('#step1').style.display = "block";
// trigger modal
$('#wizard-modal').css('z-index', '10001').animate({ opacity: 1 }).show();
// set focus to field
$('#wizard-modal #jobTitle').focus();
});
$('#wizard-modal .close-btn-w').click(function()
{
$('#wizard-modal').animate({ opacity: 0 }).hide();
});
$('#n8n-modal .close-btn-w').click(function()
{
$('#n8n-modal').animate({ opacity: 0 }).hide();
});
}
$('#custom-task-modal .close-btn-w').click(function()
{
$('#custom-task-modal').animate({ opacity: 0 }).hide();
});
var generateCustomBtn = document.getElementById('generate-steps-button');
if(generateCustomBtn)
{
generateCustomBtn.addEventListener('click', (event) =>
{
// validate
var isValid = true;
if($('#activity-name').val().length == 0)
{
$('#validateCustomName').text('Please enter a name for your task (min characters: 5)').show();
isValid = false;
}
if($('#activity-description').val().length == 0)
{
$('#validateCustomDescription').text('Please enter a concise description of your task (min characters: 50)').show();
isValid = false;
}
if($('#output-type').val() == "")
{
$('#validateCustomOutput').text('Please select a desired output for your custom task').show();
isValid = false;
}
if(isValid)
{
var customModal = document.querySelector('#custom-task-modal');
var button = customModal.querySelector("#generate-steps-button"); //document.getElementById("update-listing-button");
var buttonText = customModal.querySelector('#button-text'); //document.getElementById("button-text");
var spinner = customModal.querySelector('#spinner'); //document.getElementById("spinner");
var errorMsg = customModal.querySelector('#custom-activity-error');
// Disable button and show spinner
button.disabled = true;
spinner.style.display = "inline-block";
errorMsg.style.display = "none";
// submit to server
var MYPEAS_payload = {};
MYPEAS_payload["CustomActivityData"] = {};
MYPEAS_payload["ActivityName"] = $('#activity-name').val();
MYPEAS_payload["ActivityDescription"] = $('#activity-description').val();
MYPEAS_payload["DesiredOutput"] = $('#output-type').val();
MYPEAS_payload["promptDescription"] = "CustomActivity";
var memberID = localStorage.getItem("memberID");
if(memberID)
{
MYPEAS_payload["memberID"] = memberID;
}
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// switch to processing UI
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
// Hide spinner and enable button
spinner.style.display = "none";
button.disabled = false;
result = JSON.parse(result);
ConsoleLog("result (object): ", result); // result (object): {"message":"processing"}
ConsoleLog("result (stringified): ", JSON.stringify(result)); // "{\"message\":\"processing\"}"
var message = result["message"];
// check the return string
// refresh page as it will now be on the profile
switch(message)
{
case "Custom Task Failed":
// alert user that it failed
errorMsg.style.display = "block";
break;
case "Custom Task Created":
// perhapes show a message that it completed for 1.5 second then
// refresh page
/*setTimeout(function() {
location.reload();
}, 1500);*/
location.reload();
break;
}
}).catch(error => {
// Hide spinner and enable button
spinner.style.display = "none";
button.disabled = false;
errorMsg.style.display = "block";
console.error("Error generating custom task", error);
});
}
});
}
// How to use it:
if (isTestModeEnabled())
{
// Code to execute when testmode is true
ConsoleLog('Test mode is active!');
var testOnly = document.getElementById('testOnly');
if(testOnly)
{
$(testOnly).show();
}
// show the profile selecion tools
var industryDropdown = document.getElementById('industryDropdown');
var emailDropdown = document.getElementById('emailDropdown');
var jobDropdown = document.getElementById('jobDropdown');
const emailTextField = document.getElementById('email-submit');
if(industryDropdown)
{
industryDropdown.addEventListener('change', fetchJobDataByDropdown);
}
if(emailDropdown)
{
emailDropdown.addEventListener('change', () => {
const selectedEmail = emailDropdown.value;
emailTextField.value = selectedEmail;
password.value = "TestPassword9$";
});
}
if(jobDropdown)
{
jobDropdown.addEventListener('change', fetchJobDataByDropdown);
}
}
// waitlist mode - this only happens when user has got through waitlist
// only applies to user home page (not agency or admin)
if (!(window.location.href.toLowerCase().includes('/agency') || window.location.href.toLowerCase().includes('/admin')))
{
if (isWaitModeEnabled())
{
// show
// hide
$('#btnJoinWaitlist').hide();
$('#join-waitlist-bottom').hide();
$('#waitlist-container').hide();
$('#invite-launcher').hide();
// show
$('#btnGetStarted').show().css('display', 'block');
$('#get-started-free').show().css('display', 'block');
$('#Form-container').show();
}
else
{
$('#btnGetStarted').show().css('display', 'none');
$('#get-started-free').show().css('display', 'none');
$('#Form-container').hide();
}
}
// join waitlist
var joinWaitList = document.getElementById('btnJoinWaitlist');
var joinWaitListBottom = document.getElementById('join-waitlist-bottom');
var skipWaitListBottom = document.getElementById('btn-skip-wait-bottom');
var signUpWaitList = document.getElementById('btnSubmitWaitlist');
var inviteLauncher = document.getElementById('invite-launcher');
if(joinWaitList)
{
// open modal
inviteLauncher.addEventListener('click', (event) =>
{
redeemMode("waitlist");
$('#redeem-invitation-modal').animate({ opacity: 1 }).show();
});
// close modal
$('#redeem-invitation-modal .close-btn-w').click(function(){
$('#redeem-invitation-modal').animate({ opacity: 0 }).hide();
$('#linkedin-modal').animate({ opacity: 0 }).hide();
unLockScroll();
});
// scroll to sign up form
joinWaitList.addEventListener('click', (event) =>
{
$('html, body').animate({
//scrollTop: $('#waitlist-container').offset().top - 50
scrollTop: $('#skipwaitlist-container').offset().top - 50
}, 500);
});
joinWaitListBottom.addEventListener('click', (event) =>
{
$('html, body').animate({
//scrollTop: $('#waitlist-container').offset().top - 50
scrollTop: $('#skipwaitlist-container').offset().top - 50
}, 500);
});
// sign up form for waitlist
signUpWaitList.addEventListener('click', (event) =>
{
var waitingListContainer = document.getElementById('waitlist-container');
var loading_spinner = waitingListContainer.querySelector('#waitlist-loading');
var firstName = document.getElementById('waitlist_txt_FirstName');
var Surname = document.getElementById('waitlist_txt_Surname');
var email = document.getElementById('waitlist_txt_email');
var failed = false;
var validationMessages = [];
var validateFirstName = waitingListContainer.querySelector('#validateFirstName');
var validateSurname = waitingListContainer.querySelector('#validateSurname');
var validateEmail = waitingListContainer.querySelector('#validateEmail');
var validateConsent = waitingListContainer.querySelector('#validateConsent');
var validateCaptcha = waitingListContainer.querySelector('#validateCaptcha');
var checkboxContactAgreeTerms = waitingListContainer.querySelector('#checkbox_email');
var hiddenCaptchaValue = document.getElementById('hcv').value;
var honeypot = document.getElementById('consent_check');
// validate waitlist
var MYPEAS_payload = {};
MYPEAS_payload["firstName"] = firstName.value;
MYPEAS_payload["Surname"] = Surname.value;
MYPEAS_payload["promptDescription"] = "JoinWaitList";
MYPEAS_payload["email"] = email.value;
MYPEAS_payload["WaitListData"] = {};
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// hide all validation messages
validateFirstName.style.display = 'none';
validateFirstName.style.color = 'red';
validateSurname.style.display = 'none';
validateSurname.style.color = 'red';
validateEmail.style.display = 'none';
validateEmail.style.color = 'red';
validateConsent.style.display = 'none';
validateConsent.style.color = 'red';
validateCaptcha.style.display = 'none';
validateCaptcha.style.color = 'red';
if(firstName.value.length < 2)
{
failed = true;
validateJobTitle.textContent = "First name is too short";
validateJobTitle.style.display = 'block';
validationMessages.push(validateJobTitle.id);
}
if(Surname.value.length < 2)
{
failed = true;
validateJobDescription.textContent = "Surname is too short";
validateJobDescription.style.display = 'block';
validationMessages.push(validateJobDescription.id);
}
if(!isValidEmail(email.value))
{
failed = true;
validateEmail.textContent = "Please enter a valid email";
validateEmail.style.display = 'block';
validationMessages.push(validateEmail.id);
}
if(!consentChecked(checkboxContactAgreeTerms))
{
failed = true;
validateConsent.textContent = "Consent required.";
validateConsent.style.display = 'block';
validationMessages.push(validateConsent.id);
}
// check for solved captcha
if(hiddenCaptchaValue == "")
{
failed = true;
validateCaptcha.textContent = "Please confirm you are not a robot!";
validateCaptcha.style.display = 'block';
validationMessages.push(validateCaptcha.id);
//document.getElementById('hcv').value
}
if(!failed)
{
// hide button
$(signUpWaitList).hide();
// show spinner
$(loading_spinner).show();
// submit to server
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("result (object): ", result); // result (object): {"message":"processing"}
ConsoleLog("result (stringified): ", JSON.stringify(result)); // "{\"message\":\"processing\"}"
var message = result["message"];
// show button
$(signUpWaitList).show();
// hide spinner
$(loading_spinner).hide();
switch(message)
{
case "success":
// clear the other fields
// clear values
firstName.value = "";
Surname.value = "";
email.value = "";
OpenModal("Sorted", "We will be in touch soon!", false, false);
break;
case "failed":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "You have a profile currently processing.", "promptDescription": promptDescription}),
};
*/
//ShowProcessing("processing");
OpenModal("Please Note", "We encountered a problem. Please try again later.", false, false);
break;
case "already signed up":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "You have exceeded your free account profile limit", "promptDescription": promptDescription}),
};
*/
OpenModal("Please Note", "You have already signed up to the waiting list.", false, false);
break;
}
})
.catch(error => {
console.error("Error calling RegisterWaitList: ", error);
// show button
$(signUpWaitList).show();
// hide spinner
$(loading_spinner).hide();
});
}
if(failed)
{
// scroll to first error
$('html, body').animate({
scrollTop: $('#' + validationMessages[0]).offset().top - 50
}, 500);
}
});
// skip waitlist
skipWaitListBottom.addEventListener('click', (event) =>
{
// scroll to skipwaitlist container
$('html, body').animate({
scrollTop: $('#skipwaitlist-container').offset().top - 50
}, 500);
});
// submit invitation code redeem
var submitInviteCode = document.getElementById('btnSubmitInviteCode');
submitInviteCode.addEventListener('click', (event) => {
var redeemInvitationContainer = document.getElementById('redeem-invitation-modal');
var email = redeemInvitationContainer.querySelector('#txtRedeemEmail');
var invitationCode = redeemInvitationContainer.querySelector('#txtInviteCode');
var validateEmail = redeemInvitationContainer.querySelector('#validateRedeemEmail');
var validateInvitationCode = redeemInvitationContainer.querySelector('#validateInviteCode');
// validate fields
var failed = false;
var validationMessages = [];
var MYPEAS_payload = {};
MYPEAS_payload["email"] = email.value;
MYPEAS_payload["invitationCode"] = invitationCode.value;
MYPEAS_payload["promptDescription"] = "RedeemInvitation";
MYPEAS_payload["redeemInviteData"] = {};
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// hide all validation messages
validateEmail.style.display = 'none';
validateEmail.style.color = 'red';
validateInvitationCode.style.display = 'none';
validateInvitationCode.style.color = 'red';
if(invitationCode.value.length < 8)
{
failed = true;
validateInvitationCode.textContent = "Invitation code is too short";
validateInvitationCode.style.display = 'block';
validationMessages.push(validateInvitationCode.id);
}
// check the field is visible
if(!isValidEmail(email.value) && $('#txtRedeemEmail').is(":visible"))
{
failed = true;
validateEmail.textContent = "Please enter a valid email";
validateEmail.style.display = 'block';
validationMessages.push(validateEmail.id);
}
// if its linkedin based. dont send to server
var sendToServer = true;
if(!$('#txtRedeemEmail').is(":visible"))
{
sendToServer = false;
}
if(!failed && !sendToServer)
{
// show loading
var loading_spinner = document.getElementById('invitation-code-loading');
$(loading_spinner).show();
// hide button
var invitationCodeSubmit = document.getElementById('btnSubmitInviteCode');
$(invitationCodeSubmit).hide();
var enableUX = function(){
// show button
$(invitationCodeSubmit).show();
// hide spinner
$(loading_spinner).hide();
// clear the other fields
email.value = "";
invitationCode.value = "";
// show non wait-list version
// store in localstorage
localStorage.setItem("waitmode", "unlocked");
showUnlocked();
// hide invitation modal
$('#redeem-invitation-modal .close-btn-w').click();
OpenModal("Welcome", "Your personal invitation code has been accepted!", false, false);
};
setTimeout(enableUX, 2000);
}
if(!failed && sendToServer)
{
// show loading
var loading_spinner = document.getElementById('invitation-code-loading');
$(loading_spinner).show();
// hide button
var invitationCodeSubmit = document.getElementById('btnSubmitInviteCode');
$(invitationCodeSubmit).hide();
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("result (object): ", result); // result (object): {"message":"processing"}
ConsoleLog("result (stringified): ", JSON.stringify(result)); // "{\"message\":\"processing\"}"
var message = result["message"];
// show button
$(invitationCodeSubmit).show();
// hide spinner
$(loading_spinner).hide();
switch(message)
{
case "success":
// clear the other fields
email.value = "";
invitationCode.value = "";
// show non wait-list version
// store in localstorage
localStorage.setItem("waitmode", "unlocked");
showUnlocked();
// hide invitation modal
$('#redeem-invitation-modal .close-btn-w').click();
OpenModal("Welcome", "Your personal invitation code has been accepted!", false, false);
break;
case "invalid code":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "You have a profile currently processing.", "promptDescription": promptDescription}),
};
*/
//ShowProcessing("processing");
OpenModal("Problem", "This invitation code is invalid.", false, false);
break;
}
})
.catch(error => {
console.error("Error calling RegisterWaitList: ", error);
// show button
$(invitationCodeSubmit).show();
// hide spinner
$(loading_spinner).hide();
});
}
if(failed)
{
// scroll to first error
$('html, body').animate({
scrollTop: $('#' + validationMessages[0]).offset().top - 50
}, 500);
}
});
}
// access code
var accessLauncher = document.getElementById('invite-launcher');
var accessauncher = document.getElementById('invite-launcher');
$('#linkedin-modal .close-btn-w').click(function(){
$('#linkedin-modal').animate({ opacity: 0 }).hide();
unLockScroll();
});
$('#invite-launcher-access').click(function(){
// open redeem modal
$('#redeem-invitation-modal').animate({ opacity: 100 }).show();
// set to linkedIn mode
redeemMode("linkedin");
// close this modal
$('#linkedin-modal .close-btn-w').click();
});
if(btnLogInOut)
{
btnLogInOut.addEventListener('click', (event) => {
/*Log in
Log in */
var currentText = $('#btnLogInOut').text();
switch(currentText)
{
case "Log Out":
// trigger logout
LogOut();
break;
case "Log In":
// prompt user to login
OpenCloseLoginModal("open");
break;
}
});
}
if(promptLogin)
{
promptLogin.addEventListener('click', (event) => {
// prompt user to login
OpenCloseLoginModal("open");
});
}
if(form)
{
// Add a submit event listener to the form
form.addEventListener('submit', (event) => {
// Prevent the default form submission behavior
event.preventDefault();
});
}
/*
Generate job description with AI
*/
// button deprecated
if(generateJobDescription)
{
generateJobDescription.addEventListener('click', (event) => {
// empty ui
var responsibilitiesContainter = document.getElementById('responsibilities');
var AI_responsibilitiesContainter = document.getElementById('ai-responsibilities');
var addResponsibilitiesContainter = document.getElementById('add-repsonsibilities-container');
if(addResponsibilitiesContainter)
{
addResponsibilitiesContainter.innerHTML = '';
}
/*if(responsibilitiesContainter)
{
responsibilitiesContainter.innerHTML = '';
}*/
if(AI_responsibilitiesContainter)
{
AI_responsibilitiesContainter.innerHTML = '';
}
// clear this of values
//selectedResponsibilities = [];
$('#wizard-modal').css('z-index', '10001').animate({ opacity: 1 }).show();
});
$('#wizard-modal .close-btn-w').click(function()
{
$('#wizard-modal').animate({ opacity: 0 }).hide();
});
}
if(generateJobDescription_NewSearch)
{
generateJobDescription_NewSearch.addEventListener('click', (event) => {
// empty ui
var responsibilitiesContainter = document.getElementById('responsibilities');
var AI_responsibilitiesContainter = document.getElementById('ai-responsibilities');
var addResponsibilitiesContainter = document.getElementById('add-repsonsibilities-container');
if(addResponsibilitiesContainter)
{
addResponsibilitiesContainter.innerHTML = '';
}
if(responsibilitiesContainter)
{
responsibilitiesContainter.innerHTML = '';
}
/*if(AI_responsibilitiesContainter)
{
AI_responsibilitiesContainter.innerHTML = '';
}*/
// clear this of values
selectedResponsibilities = [];
$('#wizard-modal').css('z-index', '10001').animate({ opacity: 1 }).show();
});
$('#wizard-modal .close-btn-w').click(function()
{
$('#wizard-modal').animate({ opacity: 0 }).hide();
});
}
/* Click "GENERATE button" */
/* created our own button as the submit kept submitting whatever we tried */
/* prompt completion */
if(getJob)
{
getJob.addEventListener('click', (event) => {
try
{
/* TO DO */
/* If user clicks prompt again, then store the current job in a hidden field (allow max 5) */
/* Create a function to load stored jobs */
/* Create a function to delete stored jobs */
/* Create membership where user stores data in database */
var isUserLoggedIn = checkLoggedIn();
// Always start new search fresh
if(!isUserLoggedIn)
{
ClearStorage();
}
// Prevent the default form submission behavior
event.preventDefault();
/*
TEST WITH THIS DATA
var MYPEAS_payload = JSON.parse(event.body).MYPEAS_payload;
var promptDescription = JSON.parse(event.body).MYPEAS_payload.promptDescription;
var registered = JSON.parse(event.body).MYPEAS_payload.registered;
var memberIDValue = JSON.parse(event.body).MYPEAS_payload.memberID || "";
var emailAddress = JSON.parse(event.body).MYPEAS_payload.email;
*/
// Get the values of the form fields
const JobTitle = document.getElementById('jobTitle').value;
const IndustryTitle = $('#wizard_industry').text();
const IndustryId = $('#wizard_industry').val();
const JobDescription = document.getElementById('jobDescription').value;
const email = document.getElementById('email-submit').value.toLowerCase();
const password = document.getElementById('password').value;
var hiddenCaptchaValue = document.getElementById('hcv').value;
var honeypot = document.getElementById('consent_check');
var formContainer = document.getElementById('Form-container');
var consentCheckbox = formContainer.querySelector('#checkbox_email')
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = JobTitle;
MYPEAS_payload["Industry"] = IndustryTitle;
MYPEAS_payload["IndustryId"] = IndustryId;
MYPEAS_payload["JobDescription"] = JobDescription;
//MYPEAS_payload["promptDescription"] = "Prompt1";
MYPEAS_payload["promptDescription"] = "Signup";
//MYPEAS_payload["promptDescription"] = "promptTest";
MYPEAS_payload["registered"] = "true"; // should always be true now that user provides password at start page
MYPEAS_payload["email"] = email;
MYPEAS_payload["password"] = password;
// Get the client's time zone
const clientTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
MYPEAS_payload["timeZone"] = clientTimeZone;
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// validate fields
var failed = false;
var validationMessages = [];
// validation messages
/*var validateJobTitle = document.getElementById('validateJobTitle');
var validateJobDescription = document.getElementById('validateJobDescription');
var validateEmail = document.getElementById('validateEmail');
var validatePassword = document.getElementById('validatePassword');
var validateConsent = document.getElementById('validateConsent');
var validateCaptcha = document.getElementById('validateCaptcha');*/
var validateJobTitle = document.querySelector('#Form-container').querySelector('#validateJobTitle');
var validateJobDescription = document.querySelector('#Form-container').querySelector('#validateJobDescription');
var validateEmail = document.querySelector('#Form-container').querySelector('#validateEmail');
var validatePassword = document.querySelector('#Form-container').querySelector('#validatePassword');
var validateConsent = document.querySelector('#Form-container').querySelector('#validateConsent');
var validateCaptcha = document.querySelector('#Form-container').querySelector('#validateCaptcha');
// hide all validation messages
validateJobTitle.style.display = 'none';
validateJobTitle.style.color = 'red';
validateJobDescription.style.display = 'none';
validateJobDescription.style.color = 'red';
validateEmail.style.display = 'none';
validateEmail.style.color = 'red';
validatePassword.style.display = 'none';
validatePassword.style.color = 'red';
validateConsent.style.display = 'none';
validateConsent.style.color = 'red';
validateCaptcha.style.display = 'none';
validateCaptcha.style.color = 'red';
if(JobTitle.length < 3)
{
failed = true;
validateJobTitle.textContent = "Job Title is too short";
validateJobTitle.style.display = 'block';
validationMessages.push(validateJobTitle.id);
}
/* FYI jobData is defined in the webflow main page as a global variable
// Store user selections globally
let jobData = {
title: "",
industry: "",
responsibilities: []
};
*/
if(JobDescription.length < 100 && (JobDescription.trim() !== 'Generated by AI' && jobData))
{
failed = true;
validateJobDescription.textContent = "Job Description is too short";
validateJobDescription.style.display = 'block';
validationMessages.push(validateJobDescription.id);
}
if(JobDescription.trim() == 'Generated by AI' && jobData)
{
var GeneratedJobDescription = generatedJobDescription(jobData);
// use jobData to create a jobdescription
MYPEAS_payload["JobDescription"] = GeneratedJobDescription;
}
if(!isValidEmail(email))
{
failed = true;
validateEmail.textContent = "Please enter a valid email";
validateEmail.style.display = 'block';
validationMessages.push(validateEmail.id);
}
if(!isValidPassword(password))
{
failed = true;
validatePassword.textContent = "Minimum length of 8 characters, contains at least one uppercase letter, one lowercase letter, one number, and one special character";
validatePassword.style.display = 'block';
validationMessages.push(validatePassword.id);
}
if(!consentChecked(consentCheckbox))
{
failed = true;
validateConsent.textContent = "Consent required.";
validateConsent.style.display = 'block';
validationMessages.push(validateConsent.id);
}
// check for solved captcha
/*if(hiddenCaptchaValue == "")
{
failed = true;
validateCaptcha.textContent = "Please confirm you are not a robot!";
validateCaptcha.style.display = 'block';
validationMessages.push(validateCaptcha.id);
//document.getElementById('hcv').value
}*/
if (honeypot && honeypot.checked)
{
failed = true;
}
if(!failed)
{
// switch to processing UI
// hide formcontainer
$('#Form-container').hide();
// hide waitlistcontainer
$('#waitlist-container').hide();
// hide learn more
$('#learn-more-container').hide();
// hide invite launcher
$('#invite-launcher').hide();
// show processing containter
// add email to processing email field
$('#CheckStatusAddress').text(email);
$('#processing-container').show();
// hide background video
$('.background-video').hide();
$('.background-video-agency').hide();
// hide buttons
$('#button-box').hide();
// add email to localstorage
localStorage.setItem("email", email);
localStorage.setItem("processStatus", "processing/updating");
// trigger timer
attempts = 0;
startCheckStatusIntervals();
MetaTrackEvent("CompleteRegistration");
ShowProcessing("processing");
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("result (object): ", result); // result (object): {"message":"processing"}
ConsoleLog("result (stringified): ", JSON.stringify(result)); // "{\"message\":\"processing\"}"
var message = result["message"];
// NOTE if logged in you will use this button in a specific circumstance
// circumstance: user has cancelled a failed search, has no previous profile and needs to begin a "new search"
// check if logged in/and/or no profile
// if you have no profile the backend will never say you have exceeded limits
switch(message)
{
case "processing":
case "updating":
// hide loading and show message to check back
// can't do this
break;
/* Signup */
case "You have a profile currently processing.":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "You have a profile currently processing.", "promptDescription": promptDescription}),
};
*/
//ShowProcessing("processing");
OpenModal("Please Note", "You have a profile currently processing. Until that is complete you cannot request another on this account.", false, false);
break;
case "You have exceeded your free account profile limit":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "You have exceeded your free account profile limit", "promptDescription": promptDescription}),
};
*/
HideProcessing("loggedOut");
RejectHomepageSearch();
OpenModal("Upgrade", "You have exceeded your free account profile limit. Please purchase credit to perform more revisions.", false, true);
break;
case "You have exceeded your paid account profile limit":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "You have exceeded your paid account profile limit", "promptDescription": promptDescription}),
};
*/
HideProcessing("loggedOut");
RejectHomepageSearch();
OpenModal("Upgrade", "You have exceeded your paid account profile limit. Please purchase credit to perform more revisions.", false, true);
break;
// tell user to log in
case "Account Exists. Wrong Password Entered":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Account Exists. Wrong Password Entered", "promptDescription": promptDescription}),
}; */
OpenModal("Problem", "Please check your login details", false, false);
break;
/* Login */
// user is validated
case "User Validated":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "User Validated", "promptDescription": promptDescription, "profile": checkUserObj["profile"], "processStatus": checkUserObj["processStatus"]}),
}; */
// add useful info to localstorage
/*
const user = {
memberID: items.length > 0 && items[0].hasOwnProperty('memberID') ? items[0].memberID : null,
profile: items.length > 0 && items[0].hasOwnProperty('profile') ? items[0].profile : null,
processStatus: items.length > 0 && items[0].hasOwnProperty('processStatus') ? items[0].profile : null,
registered: items.length > 0 && items[0].hasOwnProperty('registered') ? items[0].registered : null,
passwordHash: items.length > 0 && items[0].hasOwnProperty('passwordHash') ? items[0].passwordHash : null,
paidAccount: items.length > 0 && items[0].hasOwnProperty('paidAccount') ? items[0].paidAccount : null,
revisions: items.length > 0 && items[0].hasOwnProperty('revisions') ? items[0].revisions : 0,
mypeasPayload: items.length > 0 && items[0].hasOwnProperty('mypeasPayload') ? items[0].mypeasPayload : null,
userExists: items.length > 0,
};
*/
localStorage.setItem("memberID", checkUserObj["memberID"]);
localStorage.setItem("favourites", checkUserObj["favourites"]);
localStorage.setItem("auth_token", checkUserObj["auth_token"]);
localStorage.setItem("auth_token_date_created", checkUserObj["auth_token_date_created"]);
break;
// tell user to log in
// failed to validate user
case "Account Exists. Wrong Password Entered":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Account Exists. Wrong Password Entered", "promptDescription": promptDescription}),
};
*/
OpenModal("Problem", "Please check your login details", false, false);
break;
/* ForgotPassword */
case "Password Changed":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Password Changed", "promptDescription": promptDescription}),
};
*/
// update user interface and close loading
// clear local storage and cookies
localStorage.clear();
// can't delete the cookies, so set their values to expired. so we force UX to require new login
// redirect to home page
location.href = '/?login=true';
break;
/* DeleteAccount */
case "":
/*
*/
break;
}
});
}
if(failed)
{
// scroll to first error
$('html, body').animate({
scrollTop: $('#Form-container #' + validationMessages[0]).offset().top - 50
}, 500);
}
}
catch(errGetJob)
{
// hide loading and show "something went wrong" message
ConsoleLog('error name: ' + errGetJob.name);
ConsoleLog('error message: ' + errGetJob.messsage);
ConsoleLog('error stacktrace: ' + errGetJob.stack);
}
});
}
if(getStarted)
{
getStarted.addEventListener('click', (event) => {
$('html, body').animate({
//scrollTop: $('#wf-form-chatgptForm').offset().top - 95
scrollTop: $('#Form-container').offset().top - 95
}, 500);
});
}
if(getStartedBottom)
{
getStartedBottom.addEventListener('click', (event) => {
$('html, body').animate({
//scrollTop: $('#wf-form-chatgptForm').offset().top - 95
scrollTop: $('#Form-container').offset().top - 95
}, 500);
});
}
if(getStarted_Agency)
{
getStarted_Agency.addEventListener('click', (event) => {
$('html, body').animate({
//scrollTop: $('#wf-form-chatgptForm').offset().top - 95
scrollTop: $('#Form-container').offset().top - 95
}, 500);
});
}
if(getStartedBottom_Agency)
{
getStartedBottom_Agency.addEventListener('click', (event) => {
$('html, body').animate({
//scrollTop: $('#wf-form-chatgptForm').offset().top - 95
scrollTop: $('#Form-container').offset().top - 95
}, 500);
});
}
if(learnMoreBtn)
{
learnMoreBtn.addEventListener('click', (event) => {
$('html, body').animate({
scrollTop: $('#learn-more-container').offset().top - 50
}, 500);
});
}
if(learnMoreBtn_Agency)
{
//btnPlayVideo
//btnLearnMore_Agency
learnMoreBtn_Agency.addEventListener('click', (event) => {
$('html, body').animate({
scrollTop: $('#learn-more-container').offset().top - 50
}, 500);
});
}
if(checkStatusBtn)
{
checkStatusBtn.addEventListener('click', (event) => {
CheckStatus();
});
}
if(btnCancel)
{
btnCancel.removeEventListener('click', Cancel);
btnCancel.addEventListener('click', Cancel);
}
/* Click "New Seatch" button */
if(newSearch)
{
newSearch.addEventListener('click', (event) => {
try
{
FooterView("NewSearch");
}
catch(errNewSearch)
{
ConsoleLog('error name: ' + errNewSearch.name);
ConsoleLog('error message: ' + errNewSearch.messsage);
ConsoleLog('error stacktrace: ' + errNewSearch.stack);
}
});
}
if(getJobNewSearch)
{
getJobNewSearch.addEventListener('click', (event) => {
try
{
// Prevent the default form submission behavior
event.preventDefault();
// Get the values of the form fields
const JobTitle = document.getElementById('jobTitle').value;
const JobDescription = document.getElementById('jobDescription').value;
var email = localStorage.getItem("email");
var memberID = localStorage.getItem("memberID");
var auth_token = localStorage.getItem("auth_token");
var hiddenCaptchaValue = document.getElementById('hcv').value;
var honeypot = document.getElementById('consent_check');
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = JobTitle;
MYPEAS_payload["JobDescription"] = JobDescription;
//MYPEAS_payload["promptDescription"] = "Prompt1";
MYPEAS_payload["promptDescription"] = "NewSearch";
//MYPEAS_payload["promptDescription"] = "promptTest";
MYPEAS_payload["registered"] = "true"; // should always be true now that user provides password at start page
MYPEAS_payload["email"] = email;
MYPEAS_payload["memberID"] = memberID;
MYPEAS_payload["auth_token"] = auth_token;
// Get the client's time zone
const clientTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
MYPEAS_payload["timeZone"] = clientTimeZone;
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// validate fields
var failed = false;
var validationMessages = [];
// validation messages
var validateJobTitle = document.getElementById('validateJobTitle');
var validateJobDescription = document.getElementById('validateJobDescription');
var validateCaptcha = document.getElementById('validateCaptcha');
// hide all validation messages
validateJobTitle.style.display = 'none';
validateJobTitle.style.color = 'red';
validateJobDescription.style.display = 'none';
validateJobDescription.style.color = 'red';
validateCaptcha.style.display = 'none';
validateCaptcha.style.color = 'red';
if(JobTitle.length < 3)
{
failed = true;
validateJobTitle.textContent = "Job Title is too short";
validateJobTitle.style.display = 'block';
validationMessages.push(validateJobTitle.id);
}
if(JobDescription.length < 100)
{
failed = true;
validateJobDescription.textContent = "Job Description is too short";
validateJobDescription.style.display = 'block';
validationMessages.push(validateJobDescription.id);
}
// check for solved captcha
/*if(hiddenCaptchaValue == "")
{
failed = true;
validateCaptcha.textContent = "Please confirm you are not a robot!";
validateCaptcha.style.display = 'block';
validationMessages.push(validateCaptcha.id);
//document.getElementById('hcv').value
}*/
if (honeypot && honeypot.checked)
{
failed = true;
}
if(!failed)
{
// switch to processing UI
// hide formcontainer
$('#Form-container').hide();
// hide waitlistcontainer
$('#waitlist-container').hide();
// hide learn more
$('#learn-more-container').hide();
// hide invite launcher
$('#invite-launcher').hide();
// show processing containter
// add email to processing email field
$('#CheckStatusAddress').text(email);
$('#processing-container').show();
// hide background video
$('.background-video').hide();
$('.background-video-agency').hide();
/*$('.hcv-container').show();
$('#hero-holder').show();
$('#background-image-hero').show(); */
// hide buttons
$('#button-box').hide();
ShowProcessing("processing");
// trigger timer
attempts = 0;
startCheckStatusIntervals();
localStorage.setItem("processStatus", "processing/updating");
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("result (object): ", result); // result (object): {"message":"processing"}
ConsoleLog("result (stringified): ", JSON.stringify(result)); // "{\"message\":\"processing\"}"
var message = result["message"];
switch(message)
{
case "processing":
case "updating":
// hide loading and show message to check back
// can't do this
break;
/* Signup */
case "You have a profile currently processing.":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "You have a profile currently processing.", "promptDescription": promptDescription}),
};
*/
OpenModal("Please Note", "You have a profile currently processing. Until that is complete you cannot request another on this account.", false, false);
break;
case "You have exceeded your free account profile limit":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "You have exceeded your free account profile limit", "promptDescription": promptDescription}),
};
*/
OpenModal("Please Note", "You have exceeded your free account profile limit. Please purchase credit to perform more revisions.", false, true);
break;
case "You have exceeded your paid account profile limit":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "You have exceeded your paid account profile limit", "promptDescription": promptDescription}),
};
*/
OpenModal("Please Note", "You have exceeded your paid account profile limit. Please purchase credit to perform more revisions.", false, true);
break;
// tell user to log in
case "Account Exists. Wrong Password Entered":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Account Exists. Wrong Password Entered", "promptDescription": promptDescription}),
}; */
OpenModal("Please Note", "You have exceeded your paid account profile limit. Please purchase credit to perform more revisions.", false, true);
break;
/* Login */
// user is validated
case "User Validated":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "User Validated", "promptDescription": promptDescription, "profile": checkUserObj["profile"], "processStatus": checkUserObj["processStatus"]}),
}; */
// add useful info to localstorage
/*
const user = {
memberID: items.length > 0 && items[0].hasOwnProperty('memberID') ? items[0].memberID : null,
profile: items.length > 0 && items[0].hasOwnProperty('profile') ? items[0].profile : null,
processStatus: items.length > 0 && items[0].hasOwnProperty('processStatus') ? items[0].profile : null,
registered: items.length > 0 && items[0].hasOwnProperty('registered') ? items[0].registered : null,
passwordHash: items.length > 0 && items[0].hasOwnProperty('passwordHash') ? items[0].passwordHash : null,
paidAccount: items.length > 0 && items[0].hasOwnProperty('paidAccount') ? items[0].paidAccount : null,
revisions: items.length > 0 && items[0].hasOwnProperty('revisions') ? items[0].revisions : 0,
mypeasPayload: items.length > 0 && items[0].hasOwnProperty('mypeasPayload') ? items[0].mypeasPayload : null,
userExists: items.length > 0,
};
*/
localStorage.setItem("memberID", result["memberID"]);
localStorage.setItem("favourites", checkUserObj["favourites"]);
localStorage.setItem("auth_token", result["auth_token"]);
localStorage.setItem("auth_token_date_created", result["auth_token_date_created"]);
break;
// tell user to log in
// failed to validate user
case "Account Exists. Wrong Password Entered":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Account Exists. Wrong Password Entered", "promptDescription": promptDescription}),
};
*/
OpenModal("Problem", "Please check your login details", false, true);
break;
/* ForgotPassword */
case "Password Changed":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Password Changed", "promptDescription": promptDescription}),
};
*/
// update user interface and close loading
// clear local storage and cookies
localStorage.clear();
// can't delete the cookies, so set their values to expired. so we force UX to require new login
// redirect to home page
location.href = '/?login=true';
break;
/* CheckStatus */
case "ProcessStatus returned":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "ProcessStatus returned", "promptDescription": promptDescription, "processStatus": returnProcessStatus}),
};
*/
// update processing page
var processStatus = result["processStatus"];
switch(processStatus)
{
case "updating":
case "processing":
// uses the default content
$('#UpdateStatusTextH1').text("AI Profile is still " + processStatus);
$('#UpdateStatusTextP1').text("Estimated time: 3 minutes");
$('#UpdateStatusTextP2').text("We will email you when it is ready at " + email);
$('#CheckStatusAddress').text(email);
// show check status button
// hide retry button
$('#btnCheckStatus').show();
$('#btnRetry').hide();
// hide cancel button
$('#btnCancel').hide();
break;
case "complete":
case "completed":
// display message and use try again button
$('#UpdateStatusTextH1').text("AI Profile is Ready");
// hide retry and check status buttons
$('#btnCheckStatus').hide();
$('#btnRetry').hide();
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "complete", "promptDescription": promptDescription, "processStatus": returnProcessStatus}),
};
*/
// redirect to profile
// load profile in UI - look into making this all work cleanly
setTimeout(function()
{ LoadExistingProfile(result["profile"]);
}, 2000);
break;
case "failed":
// show retry button
// hide check status button
$('#btnCheckStatus').hide();
$('#btnRetry').show();
// use profile that was returned by failed - if present
var profileStored = localStorage.getItem("profile");
if(profileStored && profileStored != "")
{
// also show cancel button if there is a profile to fall back on
$('#btnCancel').show();
var btnRetry = document.getElementById("btnRetry");
btnRetry.addEventListener('click', (event) => {
try
{
// send email back to server to do retry
// NEXT: where do i get email from
var email = localStorage.getItem("email");
// replace with memberID delivered by checkstatus
var memberID = localStorage.getItem("memberID");
var auth_token = localStorage.getItem("auth_token");
// make sure it sends to login if these arent present
var MYPEAS_payload = {};
MYPEAS_payload["promptDescription"] = "retry";
MYPEAS_payload["memberID"] = memberID;
MYPEAS_payload["auth_token"] = auth_token;
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
requestData["RetryObj"] = {};
//requestData["RetryObj"]["email"] = email;
requestData["RetryObj"]["memberID"] = memberID;
requestData["RetryObj"]["auth_token"] = auth_token;
localStorage.setItem("processStatus", "processing/updating");
// set page to show processing or updating UI
// uses the default content
$('#UpdateStatusTextH1').text("AI Profile is still " + processStatus);
$('#UpdateStatusTextP1').text("Estimated time: 3 minutes");
$('#UpdateStatusTextP2').text("We will email you when it is ready at " + email);
$('#CheckStatusAddress').text(email);
// show check status button
// hide retry button
$('#btnCheckStatus').show();
$('#btnRetry').hide();
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
// we won't wait for this
});
}
catch(err)
{
console.error('Error:', err.message);
console.error('Stacktrace:', err.stack);
}
});
var btnCancel = document.getElementById("btnCancel");
btnCancel.removeEventListener('click', Cancel);
btnCancel.addEventListener('click', Cancel);
}
// display message and use try again button
$('#UpdateStatusTextH1').text("AI Profile " + processStatus);
$('#UpdateStatusTextP1').text("Your profile encountered a problem and did not complete.");
$('#UpdateStatusTextP2').text("Would you like to try again?");
$('#CheckStatusAddress').text("");
// update localstorage
break;
}
break;
}
});
}
if(failed)
{
// scroll to first error
$('html, body').animate({
scrollTop: $('#' + validationMessages[0]).offset().top - 50
}, 500);
}
}
catch(errNewSearch)
{
ConsoleLog('error name: ' + errNewSearch.name);
ConsoleLog('error message: ' + errNewSearch.messsage);
ConsoleLog('error stacktrace: ' + errNewSearch.stack);
}
});
}
/* close modal buttons */
// close the modal using the close button
$('#modal-popup .close-btn-w').click(function(){
$('#modal-popup').animate({ opacity: 0 }).hide();
unLockScroll();
/*$('.modal-popup').each(function() {
if ($(this).is(':visible')) {
$(this).animate({ opacity: 0 }).hide();
unLockScroll();
}
});*/
/*
// close the modal using the close button
$('.close-btn-w').click(function(){
$('.modal-popup').each(function() {
if ($(this).is(':visible')) {
$(this).animate({ opacity: 0 }).hide();
unLockScroll();
}
});
});
*/
});
// close login modal login-modal
$('#login-modal .close-btn-w').click(function(){
$('#login-modal').animate({ opacity: 0 }).hide();
unLockScroll();
/*$('.modal-popup').each(function() {
if ($(this).is(':visible')) {
$(this).animate({ opacity: 0 }).hide();
unLockScroll();
}
});*/
});
// close forgotpassword modal forgot-password-modal
$('#forgot-password-modal .close-btn-w').click(function(){
$('#forgot-password-modal').animate({ opacity: 0 }).hide();
unLockScroll();
/* open login modal */
// close button - go back to login modal
OpenCloseLoginModal("open");
/*$('.modal-popup').each(function() {
if ($(this).is(':visible')) {
$(this).animate({ opacity: 0 }).hide();
unLockScroll();
}
});*/
});
var btnSubmitLogin = document.getElementById("btnSubmitLogin");
if(btnSubmitLogin)
{
btnSubmitLogin.addEventListener('click', (event) => {
event.preventDefault();
var email = document.getElementById("txtLoginEmail").value.toLowerCase();
var password = document.getElementById("txtLoginPassword").value;
if (window.location.href.toLowerCase().includes('/agency'))
{
SubmitLogin_Agency(email, password);
}
else if(window.location.href.toLowerCase().includes('/admin'))
{
SubmitLogin_Admin(email, password);
}
else
{
SubmitLogin(email, password);
}
});
}
var ForgotPassword = document.getElementById('ForgotPassword');
if(ForgotPassword)
{
ForgotPassword.addEventListener('click', (event) => {
// show forgotpassword
event.preventDefault();
// close the modal using the close button
OpenCloseLoginModal("close");
// open forgotpassword modal
OpenCloseForgotPasswordModal("open");
});
}
var btnSubmitForgotPassword = document.getElementById("btnSubmitForgotPassword");
if(btnSubmitForgotPassword)
{
if (window.location.href.toLowerCase().includes('/agency'))
{
btnSubmitForgotPassword.addEventListener('click', (event) => {
event.preventDefault();
SubmitForgotPassword_Agency();
});
}
else
{
btnSubmitForgotPassword.addEventListener('click', (event) => {
event.preventDefault();
SubmitForgotPassword();
});
}
}
var btnSubmitResetPassword = document.getElementById("btnResetPassword");
if(btnSubmitResetPassword)
{
btnSubmitResetPassword.addEventListener('click', (event) => {
event.preventDefault();
if (window.location.href.toLowerCase().includes('/agency'))
{
ResetPassword_Agency();
}
else
{
ResetPassword();
}
});
}
var btnPurchaseCredits = document.getElementById("btnPurchaseCredit");
if(btnPurchaseCredits)
{
btnPurchaseCredits.addEventListener('click', (event) => {
event.preventDefault();
const currentURL = window.location.href; // Get the current URL
// agency
if (currentURL.includes("/agency"))
{
ConsoleLog("The page URL contains '/agency'");
// Do something if /agency is found
}
else
{
// customer
$('#btnBuyNow').click();
}
});
}
var btnMyAccount = document.getElementById('btnMyAccount');
if (btnMyAccount) {
btnMyAccount.addEventListener('click', (event) =>
{
event.preventDefault();
if (window.location.href.toLowerCase().includes('/agency'))
{
OpenAccountModal_Agency();
}
else
{
OpenAccountModal();
}
});
}
var btnMyFavourites = document.getElementById("btnFavourites");
if(btnMyFavourites)
{
btnMyFavourites.addEventListener('click', (event) => {
event.preventDefault();
OpenFavourites();
});
}
var btnTools = document.getElementById("btnTools");
if(btnTools)
{
btnTools.addEventListener('click', (event) => {
event.preventDefault();
const baseUrl = window.location.origin; // Get the base URL
const newPath = "/app-listing/my-tools"; // Path to add
const newUrl = `${baseUrl}${newPath}`; // Combine base URL with the path
window.location.href = newUrl; // Navigate to the new URL
});
}
// close category modal
$('#category-modal .close-btn-w').click(function(){
CloseCategoryModal();
});
// close lead gen modal
$('#lead-modal .close-btn-w').click(function(){
CloseLeadModal();
});
// close app modal
$('#app-modal .close-btn-w').click(function(){
CloseAppModal();
});
// close favourites modal
$('#favourites-modal .close-btn-w').click(function(){
CloseFavouritesModal();
});
// close my account modal
$('#account-modal .close-btn-w').click(function(){
CloseAccountModal();
});
// close delete-account-modal
$('#delete-account-modal .close-btn-w').click(function(){
CloseDeleteModal();
});
// close calendar modal
$('#calendar-holder-modal .close-btn-w').click(function(){
CloseCalendarModal();
});
// close document outline
$('#generate-document-outline-modal .close-btn-w').click(function(){
CloseDocumentOutlineModal();
});
// copy text button on generate document outline
$('#generate-document-outline-modal #copy-document-outline').click(function(){
var document_outline_text = document.getElementById('generatedDocumentStore');
copyHiddenFieldValue(document_outline_text.id);
//copyTextFromDiv(document_outline_text);
});
// close the modal using the close button
$('#new-search-holder .close-btn-w').click(function()
{
$('#new-search-holder').animate({ opacity: 0 }).hide();
});
var btnNewSearchModal_Submit = document.getElementById("btnGetJob-new");
if(btnNewSearchModal_Submit)
{
btnNewSearchModal_Submit.addEventListener('click', (event) => {
try
{
// Prevent the default form submission behavior
event.preventDefault();
// Get the values of the form fields
//var holder = document.querySelector('#new-search-holder');
const JobTitle = document.getElementById('jobTitle-new').value;
const JobDescription = document.getElementById('jobDescription-new').value;
var email = localStorage.getItem("email");
var memberID = localStorage.getItem("memberID");
var auth_token = localStorage.getItem("auth_token");
var hiddenCaptchaValue = document.getElementById('hcv').value;
var honeypot = document.getElementById('consent_check_new');
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = JobTitle;
MYPEAS_payload["JobDescription"] = JobDescription;
//MYPEAS_payload["promptDescription"] = "Prompt1";
MYPEAS_payload["promptDescription"] = "NewSearch";
//MYPEAS_payload["promptDescription"] = "promptTest";
MYPEAS_payload["registered"] = "true"; // should always be true now that user provides password at start page
MYPEAS_payload["email"] = email;
MYPEAS_payload["memberID"] = memberID;
MYPEAS_payload["auth_token"] = auth_token;
// Get the client's time zone
const clientTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
MYPEAS_payload["timeZone"] = clientTimeZone;
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// validate fields
var failed = false;
var validationMessages = [];
// validation messages
var validateJobTitle = document.getElementById('validateJobTitle-new');
var validateJobDescription = document.getElementById('validateJobDescription-new');
var validateCaptcha = document.getElementById('validateCaptcha-new');
// hide all validation messages
validateJobTitle.style.display = 'none';
validateJobTitle.style.color = 'red';
validateJobDescription.style.display = 'none';
validateJobDescription.style.color = 'red';
validateCaptcha.style.display = 'none';
validateCaptcha.style.color = 'red';
if(JobTitle.length < 3)
{
failed = true;
validateJobTitle.textContent = "Job Title is too short";
validateJobTitle.style.display = 'block';
validationMessages.push(validateJobTitle.id);
}
if(JobDescription.length < 100 && (JobDescription.trim() !== 'Generated by AI' && jobData))
{
failed = true;
validateJobDescription.textContent = "Job Description is too short";
validateJobDescription.style.display = 'block';
validationMessages.push(validateJobDescription.id);
}
if(JobDescription.trim() == 'Generated by AI' && jobData)
{
var GeneratedJobDescription = generatedJobDescription(jobData);
// use jobData to create a jobdescription
MYPEAS_payload["JobDescription"] = GeneratedJobDescription;
}
// check for solved captcha
/*if(hiddenCaptchaValue == "")
{
failed = true;
validateCaptcha.textContent = "Please confirm you are not a robot!";
validateCaptcha.style.display = 'block';
validationMessages.push(validateCaptcha.id);
//document.getElementById('hcv').value
}*/
if (honeypot && honeypot.checked)
{
failed = true;
}
if(!failed)
{
// switch to processing UI
// hide formcontainer
//$('#Form-container').hide();
// hide waitlistcontainer
$('#waitlist-container').hide();
// hide invite launcher
$('#invite-launcher').hide();
// hide learn more
$('#learn-more-container').hide();
$('#segments-and-activities').hide();
// show processing containter
// add email to processing email field
$('#CheckStatusAddress').text(email);
$('#processing-container').show();
// hide background video
$('.background-video').hide();
$('.background-video-agency').hide();
$('#hero-holder').show();
$('.hcv-container').show();
$('#background-image-hero').show();
// hide buttons
$('#button-box').hide();
// close new search modal
OpenCloseNewSearchModal("close");
ShowProcessing("processing");
// trigger timer
attempts = 0;
startCheckStatusIntervals();
localStorage.setItem("processStatus", "processing/updating");
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("result (object): ", result); // result (object): {"message":"processing"}
ConsoleLog("result (stringified): ", JSON.stringify(result)); // "{\"message\":\"processing\"}"
var message = result["message"];
switch(message)
{
case "processing":
case "updating":
// hide loading and show message to check back
// can't do this
break;
/* Signup */
case "You have a profile currently processing.":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "You have a profile currently processing.", "promptDescription": promptDescription}),
};
*/
OpenModal("Please Note", "You have a profile currently processing. Until that is complete you cannot request another on this account.", false, false);
break;
case "You have exceeded your free account profile limit":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "You have exceeded your free account profile limit", "promptDescription": promptDescription}),
};
*/
ProcessingRequestShowUX();
OpenModal("Upgrade", "You have exceeded your free account profile limit. Please purchase credit to perform more revisions.", false, true);
break;
case "You have exceeded your paid account profile limit":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "You have exceeded your paid account profile limit", "promptDescription": promptDescription}),
};
*/
ProcessingRequestShowUX();
OpenModal("Upgrade", "You have exceeded your paid account profile limit. Please purchase credit to perform more revisions.", false, true);
break;
// tell user to log in
case "Account Exists. Wrong Password Entered":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Account Exists. Wrong Password Entered", "promptDescription": promptDescription}),
}; */
OpenModal("Problem", "Please check your login details", false, false);
break;
/* Login */
// user is validated
case "User Validated":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "User Validated", "promptDescription": promptDescription, "profile": checkUserObj["profile"], "processStatus": checkUserObj["processStatus"]}),
}; */
// add useful info to localstorage
/*
const user = {
memberID: items.length > 0 && items[0].hasOwnProperty('memberID') ? items[0].memberID : null,
profile: items.length > 0 && items[0].hasOwnProperty('profile') ? items[0].profile : null,
processStatus: items.length > 0 && items[0].hasOwnProperty('processStatus') ? items[0].profile : null,
registered: items.length > 0 && items[0].hasOwnProperty('registered') ? items[0].registered : null,
passwordHash: items.length > 0 && items[0].hasOwnProperty('passwordHash') ? items[0].passwordHash : null,
paidAccount: items.length > 0 && items[0].hasOwnProperty('paidAccount') ? items[0].paidAccount : null,
revisions: items.length > 0 && items[0].hasOwnProperty('revisions') ? items[0].revisions : 0,
mypeasPayload: items.length > 0 && items[0].hasOwnProperty('mypeasPayload') ? items[0].mypeasPayload : null,
userExists: items.length > 0,
};
*/
localStorage.setItem("memberID", result["memberID"]);
localStorage.setItem("auth_token", result["auth_token"]);
localStorage.setItem("auth_token_date_created", result["auth_token_date_created"]);
break;
// tell user to log in
// failed to validate user
case "Account Exists. Wrong Password Entered":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Account Exists. Wrong Password Entered", "promptDescription": promptDescription}),
};
*/
OpenModal("Problem", "Please check your login details", false, false);
break;
/* ForgotPassword */
case "Password Changed":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Password Changed", "promptDescription": promptDescription}),
};
*/
// update user interface and close loading
// clear local storage and cookies
localStorage.clear();
// can't delete the cookies, so set their values to expired. so we force UX to require new login
// redirect to home page
location.href = '/?login=true';
break;
/* CheckStatus */
case "ProcessStatus returned":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "ProcessStatus returned", "promptDescription": promptDescription, "processStatus": returnProcessStatus}),
};
*/
// update processing page
var processStatus = result["processStatus"];
switch(processStatus)
{
case "updating":
case "processing":
// uses the default content
$('#UpdateStatusTextH1').text("AI Profile is still " + processStatus);
$('#UpdateStatusTextP1').text("Estimated time: 3 minutes");
$('#UpdateStatusTextP2').text("We will email you when it is ready at " + email);
$('#CheckStatusAddress').text(email);
// show check status button
// hide retry button
$('#btnCheckStatus').show();
$('#btnRetry').hide();
// hide cancel button
$('#btnCancel').hide();
break;
case "complete":
case "completed":
// display message and use try again button
$('#UpdateStatusTextH1').text("AI Profile is Ready");
// hide retry and check status buttons
$('#btnCheckStatus').hide();
$('#btnRetry').hide();
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "complete", "promptDescription": promptDescription, "processStatus": returnProcessStatus}),
};
*/
// redirect to profile
// load profile in UI - look into making this all work cleanly
setTimeout(function()
{ LoadExistingProfile(result["profile"]);
}, 2000);
break;
case "failed":
// show retry button
// hide check status button
$('#btnCheckStatus').hide();
$('#btnRetry').show();
// use profile that was returned by failed - if present
var profileStored = localStorage.getItem("profile");
if(profileStored && profileStored != "")
{
// also show cancel button if there is a profile to fall back on
$('#btnCancel').show();
var btnRetry = document.getElementById("btnRetry");
btnRetry.addEventListener('click', (event) => {
try
{
// send email back to server to do retry
// NEXT: where do i get email from
var email = localStorage.getItem("email");
// replace with memberID delivered by checkstatus
var memberID = localStorage.getItem("memberID");
var auth_token = localStorage.getItem("auth_token");
// make sure it sends to login if these arent present
var MYPEAS_payload = {};
MYPEAS_payload["promptDescription"] = "retry";
MYPEAS_payload["memberID"] = memberID;
MYPEAS_payload["auth_token"] = auth_token;
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
requestData["RetryObj"] = {};
//requestData["RetryObj"]["email"] = email;
requestData["RetryObj"]["memberID"] = memberID;
requestData["RetryObj"]["auth_token"] = auth_token;
localStorage.setItem("processStatus", "processing/updating");
// set page to show processing or updating UI
// uses the default content
$('#UpdateStatusTextH1').text("AI Profile is still " + processStatus);
$('#UpdateStatusTextP1').text("Estimated time: 3 minutes");
$('#UpdateStatusTextP2').text("We will email you when it is ready at " + email);
$('#CheckStatusAddress').text(email);
// show check status button
// hide retry button
$('#btnCheckStatus').show();
$('#btnRetry').hide();
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
// we won't wait for this
});
}
catch(err)
{
console.error('Error:', err.message);
console.error('Stacktrace:', err.stack);
}
});
var btnCancel = document.getElementById("btnCancel");
btnCancel.removeEventListener('click', Cancel);
btnCancel.addEventListener('click', Cancel);
}
// display message and use try again button
$('#UpdateStatusTextH1').text("AI Profile " + processStatus);
$('#UpdateStatusTextP1').text("Your profile encountered a problem and did not complete.");
$('#UpdateStatusTextP2').text("Would you like to try again?");
$('#CheckStatusAddress').text("");
// update localstorage
break;
}
break;
}
var resultObj = tryParse(result);
});
}
if(failed)
{
// scroll to first error
$('html, body').animate({
scrollTop: $('#' + validationMessages[0]).offset().top - 50
}, 500);
}
}
catch(errNewSearch)
{
ConsoleLog('error name: ' + errNewSearch.name);
ConsoleLog('error message: ' + errNewSearch.messsage);
ConsoleLog('error stacktrace: ' + errNewSearch.stack);
}
});
}
var btnAgencySignup = document.getElementById("btnAgencySignup");
if(btnAgencySignup)
{
btnAgencySignup.addEventListener('click', (event) => {
// Always start new search fresh
ClearStorage();
// Prevent the default form submission behavior
event.preventDefault();
// Get the values of the form fields
const agentFirstName = document.getElementById('agent-first-name').value;
const agentSurname = document.getElementById('agent-surname').value;
const agentCompanyName = document.getElementById('agent-company-name').value;
const agentWorkEmail = document.getElementById('agent-work-email').value;
const agentPassword = document.getElementById('agent-password').value;
var formContainer = document.getElementById('Form-container');
var agentPhoneCode = formContainer.querySelector('#countryCode').value;
var agentPhoneNo = formContainer.querySelector('#telephone').value;
var agentLocationCode = formContainer.querySelector('#countrySelect').value;
var agentLocationName = $('#Form-container #countrySelect option:selected').text();
var hiddenCaptchaValue = document.getElementById('hcv').value;
var MYPEAS_payload = {};
MYPEAS_payload["requestDescription"] = "Signup";
MYPEAS_payload["FirstName"] = agentFirstName;
MYPEAS_payload["Surname"] = agentSurname;
MYPEAS_payload["CompanyName"] = agentCompanyName;
MYPEAS_payload["WorkEmail"] = agentWorkEmail;
MYPEAS_payload["email"] = agentWorkEmail;
MYPEAS_payload["Password"] = agentPassword;
MYPEAS_payload["password"] = agentPassword;
// Get the client's time zone
const clientTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
MYPEAS_payload["timeZone"] = clientTimeZone;
MYPEAS_payload["Location"] = {"locationName": agentLocationName, "locationCode": agentLocationCode};
MYPEAS_payload["TelephoneCode"] = agentPhoneCode;
MYPEAS_payload["TelephoneNo"] = agentPhoneNo;
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// Validate fields
var failed = false;
var validationMessages = [];
// Validation messages
var validateAgentFirstName = document.getElementById('validateAgentFirstName');
var validateAgentSurname = document.getElementById('validateAgentSurname');
var validateAgentCompanyName = document.getElementById('validateAgentCompanyName');
var validateAgentWorkEmail = document.getElementById('validateAgentWorkEmail');
var validateAgentPassword = document.getElementById('validateAgentPassword');
var validatePhoneCode = document.getElementById('validateAgentTelephoneCode');
var validatePhoneNo = document.getElementById('validateAgentWorkTelephone');
var validateLocation = document.getElementById('validateAgentLocation');
// Hide all validation messages
validateAgentFirstName.style.display = 'none';
validateAgentFirstName.style.color = 'red';
validateAgentSurname.style.display = 'none';
validateAgentSurname.style.color = 'red';
validateAgentCompanyName.style.display = 'none';
validateAgentCompanyName.style.color = 'red';
validateAgentWorkEmail.style.display = 'none';
validateAgentWorkEmail.style.color = 'red';
validateAgentPassword.style.display = 'none';
validateAgentPassword.style.color = 'red';
validatePhoneCode.style.display = 'none';
validatePhoneCode.style.color = 'red';
validatePhoneNo.style.display = 'none';
validatePhoneNo.style.color = 'red';
validateLocation.style.display = 'none';
validateLocation.style.color = 'red';
if (agentFirstName.length === 0) {
failed = true;
validateAgentFirstName.textContent = "First Name is required";
validateAgentFirstName.style.display = 'block';
validationMessages.push(validateAgentFirstName.id);
}
if (agentSurname.length === 0) {
failed = true;
validateAgentSurname.textContent = "Surname is required";
validateAgentSurname.style.display = 'block';
validationMessages.push(validateAgentSurname.id);
}
if (agentCompanyName.length === 0) {
failed = true;
validateAgentCompanyName.textContent = "Company Name is required";
validateAgentCompanyName.style.display = 'block';
validationMessages.push(validateAgentCompanyName.id);
}
if (!isValidEmail(agentWorkEmail)) {
failed = true;
validateAgentWorkEmail.textContent = "Please enter a valid email";
validateAgentWorkEmail.style.display = 'block';
validationMessages.push(validateAgentWorkEmail.id);
}
if (!isValidPassword(agentPassword)) {
failed = true;
validateAgentPassword.textContent = "Minimum length of 8 characters, contains at least one uppercase letter, one lowercase letter, one number, and one special character";
validateAgentPassword.style.display = 'block';
validationMessages.push(validateAgentPassword.id);
}
var nameRegex = /^[A-Za-z\s\-]+$/; // Regex to allow letters, spaces, and hyphens
// validate location
var locationName = $('#Form-container #countrySelect option:selected').text();
var locationCode = $('#Form-container #countrySelect').val();
if(locationName.trim() == "" || locationCode.trim() == "" )
{
failed = true;
validateLocation.style.display = 'block';
validationMessages.push(validateLocation.id);
}
// validate phone
// validate country code
if (!agentPhoneCode.trim())
{
validatePhoneCode.textContent = 'Country Code is required';
validatePhoneCode.style.display = 'block';
failed = true;
validationMessages.push(validatePhoneCode.id);
}
else
{
validatePhoneCode.style.display = 'none';
}
// Validate Telephone
if (!agentPhoneCode.trim())
{
validatePhoneCode.textContent = 'Country Code is required';
validatePhoneCode.style.display = 'block';
failed = true;
validationMessages.push(validatePhoneCode.id);
}
else
{
validatePhoneCode.style.display = 'none';
}
// Validate Telephone
if (!agentPhoneNo.trim())
{
validatePhoneNo.textContent = 'Telephone is required.';
validatePhoneNo.style.display = 'block';
failed = true;
validationMessages.push(validatePhoneNo.id);
}
else if (agentPhoneCode.trim() === "+44" && agentPhoneNo.trim().length < 11)
{
validatePhoneNo.textContent = 'Telephone number must be at least 11 digits for +44 country code.';
validatePhoneNo.style.display = 'block';
failed = true;
validationMessages.push(validatePhoneNo.id);
}
else
{
validatePhoneNo.style.display = 'none';
}
// If validation fails, do something (e.g., prevent form submission, show error messages)
if (failed) {
ConsoleLog("Validation failed:", validationMessages);
// scroll to first error
$('html, body').animate({
scrollTop: $('#' + validationMessages[0]).offset().top - 50
}, 500);
}
if(!failed)
{
// submit to server
$('#main-content').hide();
$('#main-spinner').show();
// show hero image
$('.background-video').hide();
$('.background-video-agency').hide();
// hide buttons
$('#button-box').hide();
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("result (object): ", result); // result (object): {"message":"processing"}
ConsoleLog("result (stringified): ", JSON.stringify(result)); // "{\"message\":\"processing\"}"
var message = result["message"];
switch(message)
{
/* Login */
// user is validated
case "Account Created":
case "User Validated":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "User Validated", "promptDescription": promptDescription, "profile": checkUserObj["profile"], "processStatus": checkUserObj["processStatus"]}),
}; */
// add useful info to localstorage
/*
const user = {
memberID: items.length > 0 && items[0].hasOwnProperty('memberID') ? items[0].memberID.S : null,
emailAddress: items.length > 0 && items[0].hasOwnProperty('emailAddress') ? items[0].emailAddress.S : null,
accountInfo: items.length > 0 && items[0].hasOwnProperty('accountInfo') ? items[0].accountInfo.S : null,
auth_token: items.length > 0 && items[0].hasOwnProperty('auth_token') ? items[0].auth_token.S : null,
auth_token_date_created: items.length > 0 && items[0].hasOwnProperty('auth_token_date_created') ? items[0].auth_token_date_created.S : null,
passwordHash: items.length > 0 && items[0].hasOwnProperty('passwordHash') ? items[0].passwordHash.S : null,
passwordSalt: items.length > 0 && items[0].hasOwnProperty('passwordSalt') ? items[0].passwordSalt.S : null,
credits: items.length > 0 && items[0].hasOwnProperty('revisions') ? items[0].revisions.S : 0,
orderHistory: items.length > 0 && items[0].hasOwnProperty('orderHistory') ? items[0].orderHistory.S : null,
userExists: items.length > 0,
};
*/
/*
result (stringified): {"message":"Account Created","memberID":"PwamvyxRR0","auth_token":"9yMgGqNqWA","auth_token_date_created":"2024-07-15T14:46:46.523Z","accountInfo":"{\"requestDescription\":\"Signup\",\"memberID\":\"PwamvyxRR0\",\"FirstName\":\"Ade\",\"Surname\":\"Molajo\",\"CompanyName\":\"Flex Luthor Limited\",\"WorkEmail\":\"ademolajo@gmail.com\",\"Password\":\"Mypeasbola27!\",\"Location\":{\"locationName\":\"United Kingdom\",\"locationCode\":\"GB\"},\"TelephoneCode\":\"+44\",\"TelephoneNo\":\"07738715181\",\"referralCode\":\"PwamvyxRR0\",\"bookingAccountId\":\"98cb9584-dfe2-4b80-95fa-9722bdee8e7c\",\"bookingAccountPw\":\"oJJSHnhN3zuY\",\"bookingLink\":\"https://luthorflex-2.youcanbook.me\",\"ApprovedStatus\":\"processing\"}","orderHistory":"","credits":"0"}
*/
localStorage.setItem("memberID", result["memberID"]);
localStorage.setItem("credits", result["credits"]);
localStorage.setItem("accountInfo", result["accountInfo"]);
localStorage.setItem("orderHistory", result["orderHistory"]);
localStorage.setItem("StripeInvoices", result["StripeInvoices"] || "[]");
localStorage.setItem("auth_token", result["auth_token"]);
localStorage.setItem("auth_token_date_created", result["auth_token_date_created"]);
localStorage.setItem("agencyMember", true);
// HIDE PRELOAD
HidePreLoad();
// format UX for Agency dashboard
// hide formcontainer
$('#Form-container').hide();
// hide waitlistcontainer
$('#waitlist-container').hide();
// hide learn more
$('#learn-more-container').hide();
// hide invite launcher
$('#invite-launcher').hide();
$('#main-content').show();
$('#main-spinner').hide();
// hide background video - show hero image
$('.background-video').hide();
$('.background-video-agency').hide();
$('#hero-holder').show();
$('.hcv-container').show();
$('#background-image-hero').show();
// hide buttons
$('#button-box').hide();
// change buttons in navbar
// show nav buttons
ShowNavButtons_Agency();
$(btnLogInOut).text("Log Out");
/// populate dashboard fields
// show dashboard fields
$('.agency-account-info-holder').show();
// load agency member profile in UI
LoadAgencyAccount(result["accountInfo"], result);
// hide background video - show hero image
$('.background-video').hide();
$('.background-video-agency').hide();
break;
// tell user to log in
// failed to validate user
case "Account Exists. Wrong Password Entered":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Account Exists. Wrong Password Entered", "promptDescription": promptDescription}),
};
*/
// HIDE PRELOAD
HidePreLoad();
// reset visibility
$('#main-content').show();
$('#main-spinner').hide();
// show video
$('.background-video').show();
$('.background-video-agency').show();
// show buttons
$('#button-box').show();
OpenModal("Problem", "Account Already Exists. Please check your login details", false, true);
break;
case "Account Creation Failed":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Account Creation Failed"}),
};
*/
// HIDE PRELOAD
HidePreLoad();
// reset visibility
$('#main-content').show();
$('#main-spinner').hide();
// show video
$('.background-video').show();
$('.background-video-agency').show();
// show buttons
$('#button-box').show();
OpenModal("Problem", "Account Creation Failed, Please Try Again Later", false, true);
break;
}
});
// load agency dashboard
// id=agency-account-info-holder
}
// If validation passes, proceed with form submission or other actions
ConsoleLog("Validation passed. Submitting form...");
});
}
// add lead gen slider events
var slider = document.getElementById('budgetSlider');
var output = document.getElementById('budgetDisplay');
// Update the display value when the slider is moved
if(slider)
{
slider.oninput = function() {
output.innerHTML = '£' + parseInt(this.value).toLocaleString('en-GB');
};
// Initial call to start the questionnaire
showNext('q1');
}
var AddCalendarBtn = document.getElementById("addCalendar");
if(AddCalendarBtn)
{
AddCalendarBtn.addEventListener('click', (event) =>
{
//var url = 'https://app.youcanbook.me/'; window.open(url, '_blank').focus();
// show loading spinner
$('#calendar-spinner').show();
var calendarMessage = "";
// hide message
$('#calendar-message').text(calendarMessage).hide();
// check url has 200 status code
var calendlyLink = $('#calendly-link').val();
// send to server
$('#calendar-message').text(calendarMessage).hide();
// NEXT: where do i get email from
var email = localStorage.getItem("email");
// replace with memberID delivered by checkstatus
var memberID = localStorage.getItem("memberID");
var auth_token = localStorage.getItem("auth_token");
// make sure it sends to login if these arent present
var MYPEAS_payload = {};
MYPEAS_payload["requestDescription"] = "AddCalendarLink";
MYPEAS_payload["memberID"] = memberID;
MYPEAS_payload["auth_token"] = auth_token;
MYPEAS_payload["bookingLink"] = calendlyLink;
MYPEAS_payload["bookingType"] = "Calendly";
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
requestData["AddCalendarObj"] = {};
requestData["AddCalendarObj"]["memberID"] = memberID;
requestData["AddCalendarObj"]["auth_token"] = auth_token;
requestData["AddCalendarObj"]["bookingLink"] = calendlyLink;
requestData["AddCalendarObj"]["bookingType"] = "Calendly";
// send to server and store
// submit to server
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("result (object): ", result); // result (object): {"message":"processing"}
ConsoleLog("result (stringified): ", JSON.stringify(result)); // "{\"message\":\"processing\"}"
var message = result["message"];
// hide spinner
$('#calendar-spinner').hide();
switch(message)
{
case "Calendar Added":
// set message
calendarMessage = "Calendly Link Updated";
$('#calendar-message').text(calendarMessage).show();
var accountInfo = result["accountInfo"];
// set link in localstorage
localStorage.setItem("accountInfo", accountInfo);
break;
case "No Calendar Found":
// set message
calendarMessage = "Calendly Link Not Valid";
$('#calendar-message').text(calendarMessage).show();
// set link in localstorage
break;
default:
// set message
calendarMessage = "Calendly Link Update Failed";
$('#calendar-message').text(calendarMessage).show();
break;
}
})
.catch(error => {
console.error("Error calling AddCalendarLink: ", error);
// hide spinner
$('#calendar-spinner').hide();
// set message
calendarMessage = "Calendly Link Update Failed";
$('#calendar-message').text(calendarMessage).show();
});
});
}
// close the agency account modal using the close button
$('#agency-account-modal .close-btn-w').click(function()
{
CloseModal_Agency_Account();
});
var upgradeProBtn = document.getElementById("btnUpgradePro");
var upgradeProPlusBtn = document.getElementById("btnUpgradeProPlus");
var upgradeProButtons = document.querySelectorAll("#btnUpgradePro"); // Get all buttons with the class
upgradeProButtons.forEach(button => {
button.addEventListener('click', (event) => {
event.preventDefault();
const currentURL = window.location.href; // Get the current URL
// agency
if (currentURL.includes("/agency"))
{
ConsoleLog("The page URL contains '/agency'");
// Do something if /agency is found
}
else
{
// customer
//$('#btnBuyNow').click();
// this is for webflow
//document.getElementById('btnBuyNow').click();
}
});
});
var upgradeProPlusButtons = document.querySelectorAll("#btnUpgradeProPlus");
upgradeProPlusButtons.forEach(button => {
button.addEventListener('click', (event) => {
// Prevent the default form submission behavior
event.preventDefault();
const currentURL = window.location.href; // Get the current URL
// agency
if (currentURL.includes("/agency"))
{
ConsoleLog("The page URL contains '/agency'");
// Do something if /agency is found
}
else
{
// customer
//$('#btnBuyNow').click();
//document.getElementById('btnBuyNow_Plus').click();
}
});
});
/* close checkout confirmation */
$('#loading-update-modal .close-btn-w').click(function(){
$('#loading-update-modal').animate({ opacity: 0 }).hide();
unLockScroll();
});
$('#reset-password-modal .close-btn-w').click(function(){
OpenCloseResetPasswordModal("close");
});
/* admin close modal */
$('#approve-modal .close-btn-w').click(function(){
$('#approve-modal').animate({ opacity: 0 }).hide();
unLockScroll();
});
/*$('#launch-invite-moda-access').hide();
$('#already-commented-link').hide();*/
/* $('#launch-invite-moda-access').click(function(){
}); */
$('#already-commented-link').click(function(){
// show access code
var accessCode = localStorage.getItem("accessCode");
if(!accessCode)
{
accessCode = generateRandomString(8);
}
$('#linkedin-modal #accessCode').val(accessCode);
$('#skipwaitlist-container #accessCode').val(accessCode);
$('#linkedin-modal #accessCodeHolder').show();
localStorage.setItem("accessCode", accessCode);
// hide linkedin button
$('#linkedin-modal #goToLinkedinHolder').hide();
// hide 'i have an access code'
$('#linkedin-modal #launch-invite-moda-access').hide();
// hide already added
$('#linkedin-modal #already-commented-link').hide();
// hide waitlist advice text
$('#list-counter-popup').hide();
$('#linkedin-message').hide();
});
/*$('#launch-invite-moda-access').click(function(){
// open
// show access code
var accessCode = localStorage.getItem("accessCode");
if(!accessCode)
{
accessCode = generateRandomString(8);
}
$('#linkedin-modal #accessCode').val(accessCode);
$('#skipwaitlist-container #accessCode').val(accessCode);
$('#linkedin-modal #accessCodeHolder').show();
localStorage.setItem("accessCode", accessCode);
// hide linkedin button
$('#linkedin-modal #goToLinkedinHolder').hide();
}); */
$('#info-modal .close-btn-w').click(function(){
CloseInfoModal();
});
// hide HITL modal
$('#HITL-modal .close-btn-w').click(function(){
$('#HITL-modal').animate({ opacity: 0 }).hide();
});
$('#assumptions-modal .close-btn-w').click(function(){
$('#assumptions-modal').animate({ opacity: 0 }).hide();
});
$('#n8n-info-modal .close-btn-w').click(function(){
$('#n8n-info-modal').animate({ opacity: 0 }).hide();
});
}
catch(err)
{
ConsoleLog('error name: ' + err.name);
ConsoleLog('error message: ' + err.messsage);
ConsoleLog('error stacktrace: ' + err.stack);
// reset changes
// re-enable these fields
SearchJobEnable(true);
// clear all loading screens
LoaderView(false);
CancelSimulateGPT();
}
}
function copyTextFromDiv(divId) {
const div = document.getElementById(divId);
// Create a temporary textarea to hold the text
const tempTextArea = document.createElement('textarea');
tempTextArea.value = div.textContent;
document.body.appendChild(tempTextArea);
// Select the text and copy
tempTextArea.select();
tempTextArea.setSelectionRange(0, 99999); // For large text
navigator.clipboard.writeText(tempTextArea.value)
.then(() => {
alert('Text copied to clipboard!');
})
.catch(err => {
console.error('Error copying text: ', err);
});
// Clean up
document.body.removeChild(tempTextArea);
}
function lockScroll(){
setTimeout(function () {
let scrollPosition = [];
let marginB;
let marginR;
var $html = $('html');
var $body = $('body');
let initWidth = $body.outerWidth();
let initHeight = $body.outerHeight();
scrollPosition = [
self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
];
$html.css('overflow', 'hidden');
window.scrollTo(scrollPosition[0], scrollPosition[1]);
marginR = $body.outerWidth()-initWidth;
marginB = $body.outerHeight()-initHeight;
$body.css({'margin-right': marginR,'margin-bottom': marginB});
}, 10);
}
function unLockScroll(){
setTimeout(function () {
let scrollPosition = [];
let marginB;
let marginR;
var $html = $('html');
var $body = $('body');
$html.css('overflow', 'initial');
//window.scrollTo(scrollPosition[0], scrollPosition[1]);
$body.css({'margin-right': 0, 'margin-bottom': 0});
}, 10);
}
function isValidEmail(email)
{
const regex = /^(([^<>()[\]\\.,;:\s@\"]+)(\.[^<>()[\]\\.,;:\s@\"]+)*)@(([^<>()[\]\\.,;:\s@\"]+)\.)+(([^<>()[\]\\.,;:\s@\"]{1,6})|([^\s]{2,}))$/;
return regex.test(email);
}
function isValidPassword(password) {
const hasMinimumLength = password.length >= 8;
const hasUpperCaseLetter = /[A-Z]/.test(password);
const hasLowerCaseLetter = /[a-z]/.test(password);
const hasDigit = /[0-9]/.test(password);
const hasSpecialCharacter = /[^a-zA-Z0-9]/.test(password);
const isValid =
hasMinimumLength &&
hasUpperCaseLetter &&
hasLowerCaseLetter &&
hasDigit &&
hasSpecialCharacter;
return isValid;
}
function consentChecked(checkbox)
{
//const checkbox = document.getElementById('checkbox_email');
if (checkbox.checked) {
ConsoleLog('The consent checkbox is checked.');
} else {
ConsoleLog('The consent checkbox is not checked.');
}
return checkbox.checked;
}
function isEmptyObject(obj) {
return Object.keys(obj).length === 0;
}
function ShowPreLoad()
{
// hide nav buttons
var btnMyAccount = document.getElementById('btnMyAccount');
var btnMyFavourites = document.getElementById("btnFavourites");
var btnLogInOut = document.getElementById("btnLogInOut");
var btnTools = document.getElementById('btnTools');
// Set the display CSS property to none to hide them
if (btnMyAccount) btnMyAccount.style.display = 'none';
if (btnMyFavourites) btnMyFavourites.style.display = 'none';
if (btnLogInOut) btnLogInOut.style.display = 'none';
if (btnTools) {
btnTools.style.display = 'none';
//btnTools.style.display = 'inline'; // Makes it visible and inline
//btnTools.style.maxWidth = '940px'; // Sets the max width to 940px
}
//hide page content
var bgVideo = document.getElementById('background-video');
var mainContent = document.getElementById('main-content');
if (bgVideo) bgVideo.style.display = 'none';
if (mainContent) mainContent.style.display = 'none';
// show spinner
var mainSpinner = document.getElementById('main-spinner');
if(mainSpinner) mainSpinner.style.display = 'block';
}
function HidePreLoad()
{
//hide page content
var bgVideo = document.getElementById('background-video');
var mainContent = document.getElementById('main-content');
if (bgVideo) bgVideo.style.display = 'block';
if (mainContent) mainContent.style.display = 'block';
// show spinner
var mainSpinner = document.getElementById('main-spinner');
if(mainSpinner) mainSpinner.style.display = 'none';
// if agency page give them the buttons back
if(window.location.href.toLowerCase().includes('/agency'))
{
var isUserLoggedIn = checkLoggedIn();
switch(isUserLoggedIn)
{
case true:
var btnMyAccount = document.getElementById('btnMyAccount');
var btnLogInOut = document.getElementById("btnLogInOut");
if(btnMyAccount) btnMyAccount.style.display = 'block';
if(btnLogInOut) btnLogInOut.style.display = 'block';
break;
case false:
var btnLogInOut = document.getElementById("btnLogInOut");
if(btnLogInOut) btnLogInOut.style.display = 'block';
break;
}
}
}
function ShowNavButtons()
{
var btnMyAccount = document.getElementById('btnMyAccount');
var btnMyFavourites = document.getElementById("btnFavourites");
var btnLogInOut = document.getElementById("btnLogInOut");
var btnTools = document.getElementById('btnTools');
if (btnMyAccount) btnMyAccount.style.display = 'block';
if (btnMyFavourites) btnMyFavourites.style.display = 'block';
if (btnLogInOut) btnLogInOut.style.display = 'block';
if (btnTools) {
btnTools.style.display = 'block';
//btnTools.style.display = 'inline'; // Makes it visible and inline
//btnTools.style.maxWidth = '940px'; // Sets the max width to 940px
}
}
function ShowNavButtons_Agency()
{
var btnMyAccount = document.getElementById('btnMyAccount');
var btnLogInOut = document.getElementById("btnLogInOut");
if (btnMyAccount) btnMyAccount.style.display = 'block';
if (btnLogInOut) btnLogInOut.style.display = 'block';
}
function HideNavButtons()
{
var btnMyAccount = document.getElementById('btnMyAccount');
var btnMyFavourites = document.getElementById("btnFavourites");
var btnLogInOut = document.getElementById("btnLogInOut");
var btnAgency = document.getElementById("btnAgency");
var btnTools = document.getElementById("btnTools");
if (btnMyAccount) btnMyAccount.style.display = 'none';
if (btnMyFavourites) btnMyFavourites.style.display = 'none';
if (btnLogInOut) btnLogInOut.style.display = 'none';
if (btnAgency) btnAgency.style.display = 'none';
if (btnTools) btnTools.style.display = 'none';
}
function CheckStart()
{
// check if logged in
// localstorage
var agencyMember = localStorage.getItem("agencyMember") || null;
var adminMember = localStorage.getItem("adminMember") || null;
var isUserLoggedIn = checkLoggedIn();
var btnAgency = document.getElementById('btnAgency');
var btnMyAccount = document.getElementById('btnMyAccount');
var btnMyFavourites = document.getElementById("btnFavourites");
var btnLogInOut = document.getElementById("btnLogInOut");
var btnTools = document.getElementById("btnTools");
var btnAgencySignup = document.getElementById("btnAgencySignup");
var containerWaitList = document.getElementById('waitlist-container');
var skipContainer = document.getElementById('skipwaitlist-container');
var bookingPage = isBookingPage();
var adminPage = isAdminPage();
var mainContent = document.getElementById("main-content");
var bookingContent = document.getElementById("Booking-Content");
var backgroundVideo = document.getElementById("background-video");
var linkedinModal = document.getElementById("linkedin-modal");
var codeGeneratorContainer = document.getElementById('admin-account-code-generator');
var sendRecruitAgencyContainer = document.getElementById("admin-account-send-email");
if(bookingPage)
{
// hide agency and login buttons in nav bar
$(btnLogInOut).hide();
$(btnAgency).hide();
// hide main-content
$(mainContent).hide();
// hide background video
$(backgroundVideo).hide();
// show booking-content
$(bookingContent).show();
// hide linkedin-modal
$(linkedinModal).hide();
// load calendly embed
var embedURL = getParameterByName('calLink');
if (embedURL) {
embedURL = addParameterToURL(embedURL, "embed_domain", window.location.host);
//embedURL = addParameterToURL(embedURL, "embed_domain", "example.com");
embedURL = addParameterToURL(embedURL, "embed_type", "Inline");
// Ensure the Calendly script is loaded before calling Calendly.initInlineWidget
window.addEventListener('load', () => {
const container = document.getElementById('Booking-Holder');
Calendly.initInlineWidget({
url: embedURL,
parentElement: container,
resize: true,
prefill: {},
utm: {}
});
// hide spinner in 5 seconds if still visible
var mainSpinner = document.getElementById('main-spinner');
setTimeout(function(){if(mainSpinner) mainSpinner.style.display = 'none'; console.log('timed out spinner');}, 5000);
window.addEventListener("message", function(e) {
if (isCalendlyEvent(e)) {
const eventName = e.data.event;
const eventDetails = e.data.payload;
switch (eventName) {
case 'calendly.profile_page_viewed':
console.log('Profile page viewed');
break;
case 'calendly.event_type_viewed':
console.log('Event type page viewed');
console.log('cancelled spinner');
// hide the spinner
if(mainSpinner) mainSpinner.style.display = 'none';
break;
case 'calendly.date_and_time_selected':
console.log('Date and time selected');
break;
case 'calendly.event_scheduled':
console.log('Booking completed:', eventDetails);
//alert('Booking confirmed!'); // Display an alert
// send to server
const requestData = {};
requestData["MYPEAS_payload"] = {};
// identifies the agency
requestData["MYPEAS_payload"]["AGENCYCODE"] = GetParam("agencyID");
// identifies the user
requestData["MYPEAS_payload"]["MEMBERID"] = GetParam("memberID");
requestData["MYPEAS_payload"]["requestDescription"] = "ConfirmBooking";
// send request to store booking info on server
// Make an API call to API gateway
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("Send Booking Link return: ",JSON.stringify(result));
var message = result["message"];
switch(message)
{
case "Agency Found and updated":
console.log("booking stored");
// update requests in local storage
break;
case "Agency Not Found (ConfirmBooking Failed)":
console.log("booking NOT stored");
break;
}
});
break;
default:
console.log('Unknown Calendly event:', eventName);
}
}
});
});
console.log("set all listeners");
} else {
console.error('No "calLink" parameter found in the URL.');
}
}
if(adminPage)
{
if(isUserLoggedIn)
{
$(btnAgency).hide();
$(btnLogInOut).text("Log Out");
var storedMemberID = localStorage.getItem("memberID");
var storedAuthToken = localStorage.getItem("auth_token");
// request profile
var MYPEAS_payload = {};
MYPEAS_payload["requestDescription"] = "LoginAdmin";
MYPEAS_payload["registered"] = "true"; // should always be true now that user provides password at start page
MYPEAS_payload["memberID"] = storedMemberID; // get from storage
MYPEAS_payload["auth_token"] = storedAuthToken; // get from storage
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("login status return: ",JSON.stringify(result));
HidePreLoad();
/*return {
statusCode: 200,
body: JSON.stringify({"message": "Profile Found", "promptDescription": promptDescription, "profile": checkUserObj["profile"], "processStatus": checkUserObj["processStatus"]}),
}; */
var processStatus = result["message"];
switch(processStatus)
{
case "validated":
// if completed and not empty - load profile in UI
var memberID = result["memberID"];
var authToken = result["auth_token"];
var auth_token_date_created = result["auth_token_date_created"];
var approvalsData = result["approvalData"];
// set memberID
localStorage.setItem("memberID", memberID);
// set auth_token
localStorage.setItem("auth_token", authToken);
localStorage.setItem("auth_token_date_created", auth_token_date_created);
localStorage.setItem("adminMember", "true");
// show the nav buttons
var btnLogInOut = document.getElementById("btnLogInOut");
var btnAgency = document.getElementById("btnAgency");
var containerWaitList = document.getElementById('waitlist-container');
var skipContainer = document.getElementById('skipwaitlist-container');
var promptLogin = document.getElementById('admin-prompt-login');
$(btnLogInOut).show();
$(btnAgency).hide();
$(btnLogInOut).text("Log Out");
$(containerWaitList).hide();
$(skipContainer).hide();
$(codeGeneratorContainer).show();
$(sendRecruitAgencyContainer).show();
// populate the cards
// load approvals
LoadApprovals(approvalsData);
// close modal
OpenCloseLoginModal("close");
// hide prompt login
$(promptLogin).hide();
removeParam("login");
break;
case "rejected":
case "notauthenticated":
case "failed":
// require login
// clear local storage and cookies
localStorage.clear();
// can't delete the cookies, so set their values to expired. so we force UX to require new login
// redirect to home page
location.href = '/admin?login=true';
break;
}
});
}
if(!isUserLoggedIn)
{
HidePreLoad();
$(btnMyAccount).hide();
$(btnMyFavourites).hide();
$(btnTools).hide();
$(btnLogInOut).show();
$(btnAgency).show();
$(btnLogInOut).text("Log In");
}
}
if(!bookingPage && !adminPage)
{
// main user website
if(!agencyMember && !window.location.href.toLowerCase().includes('/agency'))
{
if(isUserLoggedIn)
{
$('#linkedin-modal').hide();
$(btnMyAccount).show();
$(btnMyFavourites).show();
$(btnTools).show();
$(btnLogInOut).show();
$(btnAgency).hide();
$(btnLogInOut).text("Log Out");
$(containerWaitList).hide();
$(skipContainer).hide();
// check if return from product purchase
// On page load - check URL
const urlParams = new URLSearchParams(window.location.search);
const sessionId = urlParams.get('session_id'); // cs_abc123
const isSuccess = urlParams.get('success'); // true
if (sessionId && isSuccess === 'true') {
// Start polling - check every 2 seconds
pollForOrderCompletion(sessionId, 'check-order-status');
}
else
{
var storedProcessStatus = localStorage.getItem("processStatus");
var queryStringContainsProcessing = false;
const queryString = window.location.search;
const keyValue = 'processStatus=processing'; // Replace with your actual key-value pair
var keyValues = ['processStatus=processing', 'processStatus=updating'];
for(var x = 0; x < keyValues.length; x++)
{
if (queryString.includes(keyValues[x]))
{
queryStringContainsProcessing = true;
break;
}
}
// processing/updating/failed
if(storedProcessStatus == "processing/updating" || storedProcessStatus == "processing" || storedProcessStatus == "updating" || storedProcessStatus == "failed" || queryStringContainsProcessing)
{
// THIS SAYS STATUS NOT START
CheckStatus();
}
// not processing - check server for completed profile - if failed show retry
if(!(storedProcessStatus == "processing/updating" || storedProcessStatus == "processing" || storedProcessStatus == "updating" || storedProcessStatus == "failed" || queryStringContainsProcessing))
{
var storedMemberID = localStorage.getItem("memberID");
var storedAuthToken = localStorage.getItem("auth_token");
// request profile
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = "";
MYPEAS_payload["JobDescription"] = "";
MYPEAS_payload["promptDescription"] = "RequestProfile";
MYPEAS_payload["registered"] = "true"; // should always be true now that user provides password at start page
MYPEAS_payload["memberID"] = storedMemberID; // get from storage
MYPEAS_payload["auth_token"] = storedAuthToken; // get from storage
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("processStatus return: ",JSON.stringify(result));
HidePreLoad();
/*return {
statusCode: 200,
body: JSON.stringify({"message": "Profile Found", "promptDescription": promptDescription, "profile": checkUserObj["profile"], "processStatus": checkUserObj["processStatus"]}),
}; */
var processStatus = result["processStatus"];
switch(processStatus)
{
case "complete":
case "completed":
// if completed - load profile in UI
var profile = result["profile"];
var favourites = result["favourites"] || JSON.stringify([]);
var memberID = result["memberID"];
var authToken = result["auth_token"];
var auth_token_date_created = result["auth_token_date_created"];
var accountInfo = result["accountInfo"] || JSON.stringify({});
var orderHistory = result["orderHistory"] || JSON.stringify([]);
var StripeInvoices = result["StripeInvoices"] || JSON.stringify([]);
var revisions = result["revisions"] || "0";
var optIn = result["optIn"] !== undefined ? result["optIn"] : true;
var paidAccount = result["paidAccount"] !== undefined ? result["paidAccount"] : "false";
if(paidAccount !== undefined)
{
localStorage.setItem("paidAccount", paidAccount);
}
else
{
localStorage.setItem("paidAccount", "false");
}
if(optIn !== undefined)
{
// set optin in localstorage
localStorage.setItem("optIn", optIn);
}
else
{
localStorage.setItem("optIn", true);
}
if(accountInfo == "")
{
accountInfo = JSON.stringify({});
}
if(orderHistory == "")
{
orderHistory = JSON.stringify([]);
}
HideProcessing("loggedIn");
// set profile in localstorage
localStorage.setItem("profile", JSON.stringify(profile));
localStorage.setItem("favourites", favourites);
// set memberID
localStorage.setItem("memberID", memberID);
// set auth_token
localStorage.setItem("auth_token", authToken);
localStorage.setItem("auth_token_date_created", auth_token_date_created);
localStorage.setItem("processStatus", "complete");
localStorage.setItem("accountInfo", accountInfo);
localStorage.setItem("orderHistory", orderHistory);
localStorage.setItem("StripeInvoices", StripeInvoices);
localStorage.setItem("revisions", revisions);
// load profile in UI - look into making this all work cleanly
LoadExistingProfile(result["profile"]);
// close modal
OpenCloseLoginModal("close");
// we want to prompt user to complete details if missing from account
// check accountInfo - this checks if accountinfo is complete
accountInfo = JSON.parse(accountInfo);
if(!checkAccountInfo(accountInfo))
{
/*OpenAccountModal();
// show red text saying enter missing information
$('#modal-message-account').text("** Complete Your Account Information **").show();*/
// create an onboarding modal
OpenOnboardModal();
}
firstLoad();
break;
case "failed":
var profile = result["profile"];
var favourites = result["favourites"] || JSON.stringify([]);
var memberID = result["memberID"];
var authToken = result["auth_token"];
var auth_token_date_created = result["auth_token_date_created"];
var accountInfo = result["accountInfo"] || JSON.stringify({});
var orderHistory = result["orderHistory"] || JSON.stringify([]);
var StripeInvoices = result["StripeInvoices"] || JSON.stringify([]);
var revisions = result["revisions"] || "0";
var optIn = result["optIn"] !== undefined ? result["optIn"] : true;
var paidAccount = result["paidAccount"] !== undefined ? result["paidAccount"] : "false";
if(paidAccount !== undefined)
{
localStorage.setItem("paidAccount", paidAccount);
}
else
{
localStorage.setItem("paidAccount", "false");
}
if(optIn !== undefined)
{
// set optin in localstorage
localStorage.setItem("optIn", optIn);
}
else
{
localStorage.setItem("optIn", "true");
}
if(accountInfo == "")
{
accountInfo = JSON.stringify({});
}
if(orderHistory == "")
{
orderHistory = JSON.stringify([]);
}
HideProcessing("loggedIn");
// set profile in localstorage
localStorage.setItem("profile", JSON.stringify(profile));
localStorage.setItem("favourites", favourites);
// set memberID
localStorage.setItem("memberID", memberID);
// set auth_token
localStorage.setItem("auth_token", authToken);
localStorage.setItem("auth_token_date_created", auth_token_date_created);
localStorage.setItem("processStatus", "failed");
localStorage.setItem("accountInfo", accountInfo);
localStorage.setItem("orderHistory", orderHistory);
localStorage.setItem("StripeInvoices", StripeInvoices);
localStorage.setItem("revisions", revisions);
// load profile in UI - look into making this all work cleanly
if(profile && (profile != "" && profile != "\"\""))
{
LoadExistingProfile(result["profile"]);
}
else
{
// if there is no profile
// need to allow new search
NewSearch();
ShowNavButtons();
}
// close modal
OpenCloseLoginModal("close");
// we want to prompt user to complete details if missing from account
// check accountInfo - this checks if accountinfo is complete
// add breakpoints and refresh page
break;
case "processing":
case "updating":
// if processing
ShowProcessing(processStatus);
break;
case "notauthenticated":
// require login
// clear local storage and cookies
localStorage.clear();
// can't delete the cookies, so set their values to expired. so we force UX to require new login
// redirect to home page
location.href = '/?login=true';
break;
}
});
}
}
}
if(!isUserLoggedIn)
{
HidePreLoad();
$(btnMyAccount).hide();
$(btnMyFavourites).hide();
$(btnTools).hide();
$(btnLogInOut).show();
$(btnAgency).show();
$(btnLogInOut).text("Log In");
// check for query strings
// 1. Get the query string from the URL:
const queryString = window.location.search;
// 2. Create a URLSearchParams object to parse the query string:
const urlParams = new URLSearchParams(queryString);
var triggerLinkedIn = true;
// 3. Iterate through each key-value pair using forEach:
urlParams.forEach((value, key) => {
switch (key) {
case 'processStatus':
removeParam(key);
ConsoleLog('ProcessStatus:', value);
// Perform actions specific to the parameter
// redirect to home page
location.href = '/?login=true';
triggerLinkedIn = false;
break;
case 'reset-password':
removeParam(key);
ConsoleLog('ResetPassword:', value);
// Perform actions specific to the parameter
OpenCloseResetPasswordModal("open");
triggerLinkedIn = false;
break;
case 'login':
removeParam(key);
ConsoleLog('Login:', value);
// Perform actions specific to the parameter
OpenCloseLoginModal("open");
triggerLinkedIn = false;
break;
default:
ConsoleLog(`Unknown parameter: ${key} with value: ${value}`);
}
});
if(triggerLinkedIn)
{
// Update the counter initially
calculateWaitlistNumber();
$('#linkedin-modal').animate({ opacity: 100 }).show();
//unLockScroll();
// check for param from linkedin
// check for query strings
// 1. Get the query string from the URL:
const queryString = window.location.search;
// 2. Create a URLSearchParams object to parse the query string:
const urlParams = new URLSearchParams(queryString);
// 3. Iterate through each key-value pair using forEach:
urlParams.forEach((value, key) => {
switch (key) {
case 'access':
// show already commented link
//$('#already-commented-holder').show();
$('#already-commented-link').show();
break;
default:
//$('#already-commented-holder').hide();
$('#already-commented-link').hide();
break;
}
});
// check for 'requestedAccess'
var requestedAccessItem = localStorage.getItem("requestedAccess");
if(requestedAccessItem)
{
// show access code
var accessCode = localStorage.getItem("accessCode");
if(!accessCode)
{
accessCode = generateRandomString(8);
}
$('#linkedin-modal #accessCode').val(accessCode);
$('#skipwaitlist-container #accessCode').val(accessCode);
$('#linkedin-modal #accessCodeHolder').show();
localStorage.setItem("accessCode", accessCode);
// hide linkedin button
$('#linkedin-modal #goToLinkedinHolder').hide();
// hide 'i have an access code'
$('#linkedin-modal #launch-invite-moda-access').hide();
// hide already added
$('#linkedin-modal #already-commented-link').hide();
// hide waitlist advice text
$('#list-counter-popup').hide();
$('#linkedin-message').hide();
}
}
if (isWaitModeEnabled())
{
// this mean no longer in wait mode if true
// hide the popup for linkedin
// close this modal
$('#linkedin-modal .close-btn-w').click();
// hide the skip waitlist container
$('#skipwaitlist-container').hide();
// hide skip waitlist button at bottom
$('#btn-skip-wait-bottom').hide();
}
CancelWaitlist();
}
}
// agency website
if(agencyMember && window.location.href.toLowerCase().includes('/agency'))
{
// check if return from product purchase
// On page load - check URL
const urlParams = new URLSearchParams(window.location.search);
const sessionId = urlParams.get('session_id'); // cs_abc123
const isSuccess = urlParams.get('success'); // true
if (sessionId && isSuccess === 'true')
{
// Start polling - check every 2 seconds
pollForOrderCompletion(sessionId, 'check-agency-order-status');
}
else
{
if(isUserLoggedIn)
{
$(btnAgency).hide();
$(btnLogInOut).text("Log Out");
var storedMemberID = localStorage.getItem("memberID");
var storedAuthToken = localStorage.getItem("auth_token");
// request profile
var MYPEAS_payload = {};
MYPEAS_payload["requestDescription"] = "RequestProfile";
MYPEAS_payload["registered"] = "true"; // should always be true now that user provides password at start page
MYPEAS_payload["memberID"] = storedMemberID; // get from storage
MYPEAS_payload["auth_token"] = storedAuthToken; // get from storage
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("login status return: ",JSON.stringify(result));
HidePreLoad();
/*return {
statusCode: 200,
body: JSON.stringify({"message": "Profile Found", "promptDescription": promptDescription, "profile": checkUserObj["profile"], "processStatus": checkUserObj["processStatus"]}),
}; */
var processStatus = result["message"];
switch(processStatus)
{
case "Profile Found":
case "User Validated":
ConsoleLog("2");
// if completed and not empty - load profile in UI
var memberID = result["memberID"];
var authToken = result["auth_token"];
var auth_token_date_created = result["auth_token_date_created"];
var accountInfo = result["accountInfo"] || JSON.stringify({});
var orderHistory = result["orderHistory"] || JSON.stringify([]);
var bookingHistory = result["bookingHistory"] || JSON.stringify([]);
var credits = result["credits"] || "0";
var requests = result["requests"] || JSON.stringify([]);
var optIn = result["optIn"] !== undefined ? result["optIn"] : true;
var StripeInvoices = result["StripeInvoices"] || JSON.stringify([]);
if(optIn !== undefined)
{
// set optin in localstorage
localStorage.setItem("optIn", optIn);
}
else
{
localStorage.setItem("optIn", "true");
}
if(accountInfo == "")
{
accountInfo = JSON.stringify({});
}
var ApprovedStatus = accountInfo["ApprovedStatus"];
if(orderHistory == "")
{
orderHistory = JSON.stringify([]);
}
if(bookingHistory == "")
{
bookingHistory = JSON.stringify([]);
}
HideProcessing("loggedIn");
// set memberID
localStorage.setItem("memberID", memberID);
localStorage.setItem("agencyMember", true);
// set auth_token
localStorage.setItem("auth_token", authToken);
localStorage.setItem("auth_token_date_created", auth_token_date_created);
localStorage.setItem("accountInfo", accountInfo);
localStorage.setItem("orderHistory", orderHistory);
localStorage.setItem("StripeInvoices", StripeInvoices);
localStorage.setItem("bookingHistory", bookingHistory);
localStorage.setItem("credits", credits);
localStorage.setItem("requests", requests);
// load agency member profile in UI
LoadAgencyAccount(accountInfo, result);
// close modal
OpenCloseLoginModal("close");
// hide background video - show hero image
$('.background-video').hide();
$('.background-video-agency').hide();
break;
case "Account Does Not Exist":
case "Account Exists. Wrong Password Entered":
case "notauthenticated":
// require login
// clear local storage and cookies
localStorage.clear();
// can't delete the cookies, so set their values to expired. so we force UX to require new login
// redirect to home page
location.href = '/agency?login=true';
break;
}
});
}
if(!isUserLoggedIn)
{
HidePreLoad();
$(btnAgency).hide();
btnAgencySignup.addEventListener('click', (event) => {
// Always start new search fresh
ClearStorage();
// Prevent the default form submission behavior
event.preventDefault();
// Get the values of the form fields
const agentFirstName = document.getElementById('agent-first-name').value;
const agentSurname = document.getElementById('agent-surname').value;
const agentCompanyName = document.getElementById('agent-company-name').value;
const agentWorkEmail = document.getElementById('agent-work-email').value;
const agentPassword = document.getElementById('agent-password').value;
var formContainer = document.getElementById('Form-container');
var agentPhoneCode = formContainer.querySelector('#countryCode').value;
var agentPhoneNo = formContainer.querySelector('#telephone').value;
var agentLocationCode = formContainer.querySelector('#countrySelect').value;
var agentLocationName = $('#Form-container #countrySelect option:selected').text();
var hiddenCaptchaValue = document.getElementById('hcv').value;
var MYPEAS_payload = {};
MYPEAS_payload["requestDescription"] = "Signup";
MYPEAS_payload["FirstName"] = agentFirstName;
MYPEAS_payload["Surname"] = agentSurname;
MYPEAS_payload["CompanyName"] = agentCompanyName;
MYPEAS_payload["WorkEmail"] = agentWorkEmail;
MYPEAS_payload["email"] = agentWorkEmail;
MYPEAS_payload["Password"] = agentPassword;
MYPEAS_payload["password"] = agentPassword;
// Get the client's time zone
const clientTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
MYPEAS_payload["timeZone"] = clientTimeZone;
MYPEAS_payload["Location"] = {"locationName": agentLocationName, "locationCode": agentLocationCode};
MYPEAS_payload["TelephoneCode"] = agentPhoneCode;
MYPEAS_payload["TelephoneNo"] = agentPhoneNo;
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// Validate fields
var failed = false;
var validationMessages = [];
// Validation messages
var validateAgentFirstName = document.getElementById('validateAgentFirstName');
var validateAgentSurname = document.getElementById('validateAgentSurname');
var validateAgentCompanyName = document.getElementById('validateAgentCompanyName');
var validateAgentWorkEmail = document.getElementById('validateAgentWorkEmail');
var validateAgentPassword = document.getElementById('validateAgentPassword');
var validatePhoneCode = document.getElementById('validateAgentTelephoneCode');
var validatePhoneNo = document.getElementById('validateAgentWorkTelephone');
var validateLocation = document.getElementById('validateAgentLocation');
// Hide all validation messages
validateAgentFirstName.style.display = 'none';
validateAgentFirstName.style.color = 'red';
validateAgentSurname.style.display = 'none';
validateAgentSurname.style.color = 'red';
validateAgentCompanyName.style.display = 'none';
validateAgentCompanyName.style.color = 'red';
validateAgentWorkEmail.style.display = 'none';
validateAgentWorkEmail.style.color = 'red';
validateAgentPassword.style.display = 'none';
validateAgentPassword.style.color = 'red';
validatePhoneCode.style.display = 'none';
validatePhoneCode.style.color = 'red';
validatePhoneNo.style.display = 'none';
validatePhoneNo.style.color = 'red';
validateLocation.style.display = 'none';
validateLocation.style.color = 'red';
if (agentFirstName.length === 0) {
failed = true;
validateAgentFirstName.textContent = "First Name is required";
validateAgentFirstName.style.display = 'block';
validationMessages.push(validateAgentFirstName.id);
}
if (agentSurname.length === 0) {
failed = true;
validateAgentSurname.textContent = "Surname is required";
validateAgentSurname.style.display = 'block';
validationMessages.push(validateAgentSurname.id);
}
if (agentCompanyName.length === 0) {
failed = true;
validateAgentCompanyName.textContent = "Company Name is required";
validateAgentCompanyName.style.display = 'block';
validationMessages.push(validateAgentCompanyName.id);
}
if (!isValidEmail(agentWorkEmail)) {
failed = true;
validateAgentWorkEmail.textContent = "Please enter a valid email";
validateAgentWorkEmail.style.display = 'block';
validationMessages.push(validateAgentWorkEmail.id);
}
if (!isValidPassword(agentPassword)) {
failed = true;
validateAgentPassword.textContent = "Minimum length of 8 characters, contains at least one uppercase letter, one lowercase letter, one number, and one special character";
validateAgentPassword.style.display = 'block';
validationMessages.push(validateAgentPassword.id);
}
var nameRegex = /^[A-Za-z\s\-]+$/; // Regex to allow letters, spaces, and hyphens
// validate location
var locationName = $('#Form-container #countrySelect option:selected').text();
var locationCode = $('#Form-container #countrySelect').val();
if(locationName.trim() == "" || locationCode.trim() == "" )
{
failed = true;
validateLocation.style.display = 'block';
validationMessages.push(validateLocation.id);
}
// validate phone
// validate country code
if (!agentPhoneCode.trim())
{
validatePhoneCode.textContent = 'Country Code is required';
validatePhoneCode.style.display = 'block';
failed = true;
validationMessages.push(validatePhoneCode.id);
}
else
{
validatePhoneCode.style.display = 'none';
}
// Validate Telephone
if (!agentPhoneNo.trim())
{
validatePhoneNo.textContent = 'Telephone is required.';
validatePhoneNo.style.display = 'block';
failed = true;
validationMessages.push(validatePhoneNo.id);
}
else if (agentPhoneCode.trim() === "+44" && agentPhoneNo.trim().length < 11)
{
validatePhoneNo.textContent = 'Telephone number must be at least 11 digits for +44 country code.';
validatePhoneNo.style.display = 'block';
failed = true;
validationMessages.push(validatePhoneNo.id);
}
else
{
validatePhoneNo.style.display = 'none';
}
// If validation fails, do something (e.g., prevent form submission, show error messages)
if (failed) {
ConsoleLog("Validation failed:", validationMessages);
// scroll to first error
$('html, body').animate({
scrollTop: $('#' + validationMessages[0]).offset().top - 50
}, 500);
}
if(!failed)
{
// submit to server
$('#main-content').hide();
$('#main-spinner').show();
// show hero image
$('.background-video').hide();
$('.background-video-agency').hide();
// hide buttons
$('#button-box').hide();
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("result (object): ", result); // result (object): {"message":"processing"}
ConsoleLog("result (stringified): ", JSON.stringify(result)); // "{\"message\":\"processing\"}"
var message = result["message"];
switch(message)
{
/* Login */
// user is validated
case "Account Created":
case "User Validated":
var optIn = result["optIn"] !== undefined ? result["optIn"] : true;
if(optIn !== undefined)
{
// set optin in localstorage
localStorage.setItem("optIn", optIn);
}
else
{
localStorage.setItem("optIn", "true");
}
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "User Validated", "promptDescription": promptDescription, "profile": checkUserObj["profile"], "processStatus": checkUserObj["processStatus"]}),
}; */
// add useful info to localstorage
/*
const user = {
memberID: items.length > 0 && items[0].hasOwnProperty('memberID') ? items[0].memberID.S : null,
emailAddress: items.length > 0 && items[0].hasOwnProperty('emailAddress') ? items[0].emailAddress.S : null,
accountInfo: items.length > 0 && items[0].hasOwnProperty('accountInfo') ? items[0].accountInfo.S : null,
auth_token: items.length > 0 && items[0].hasOwnProperty('auth_token') ? items[0].auth_token.S : null,
auth_token_date_created: items.length > 0 && items[0].hasOwnProperty('auth_token_date_created') ? items[0].auth_token_date_created.S : null,
passwordHash: items.length > 0 && items[0].hasOwnProperty('passwordHash') ? items[0].passwordHash.S : null,
passwordSalt: items.length > 0 && items[0].hasOwnProperty('passwordSalt') ? items[0].passwordSalt.S : null,
credits: items.length > 0 && items[0].hasOwnProperty('revisions') ? items[0].revisions.S : 0,
orderHistory: items.length > 0 && items[0].hasOwnProperty('orderHistory') ? items[0].orderHistory.S : null,
userExists: items.length > 0,
};
*/
localStorage.setItem("memberID", result["memberID"]);
localStorage.setItem("credits", result["credits"]);
localStorage.setItem("accountInfo", result["accountInfo"]);
localStorage.setItem("orderHistory", result["orderHistory"]);
localStorage.setItem("StripeInvoices", result["StripeInvoices"] || "[]");
localStorage.setItem("auth_token", result["auth_token"]);
localStorage.setItem("auth_token_date_created", result["auth_token_date_created"]);
localStorage.setItem("agencyMember", true);
// HIDE PRELOAD
HidePreLoad();
// format UX for Agency dashboard
// hide formcontainer
$('#Form-container').hide();
// hide waitlistcontainer
$('#waitlist-container').hide();
// hide learn more
$('#learn-more-container').hide();
// hide invite launcher
$('#invite-launcher').hide();
$('#main-content').show();
$('#main-spinner').hide();
// hide background video - show hero image
$('.background-video').hide();
$('.background-video-agency').hide();
$('#hero-holder').show();
$('.hcv-container').show();
$('#background-image-hero').show();
// hide buttons
$('#button-box').hide();
// change buttons in navbar
// show nav buttons
ShowNavButtons_Agency();
$(btnLogInOut).text("Log Out");
/// populate dashboard fields
// show dashboard fields
$('.agency-account-info-holder').show();
// load agency member profile in UI
LoadAgencyAccount(result["accountInfo"], result);
// hide background video - show hero image
$('.background-video').hide();
$('.background-video-agency').hide();
break;
// tell user to log in
// failed to validate user
case "Account Exists. Wrong Password Entered":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Account Exists. Wrong Password Entered", "promptDescription": promptDescription}),
};
*/
// reset visibility
$('#main-content').show();
$('#main-spinner').hide();
// show video
$('.background-video').show();
// show buttons
$('#button-box').show();
OpenModal("Problem", "Please check your login details", false, true);
break;
case "Account Creation Failed":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Account Creation Failed"}),
};
*/
// reset visibility
$('#main-content').show();
$('#main-spinner').hide();
// show video
$('.background-video').show();
// show buttons
$('#button-box').show();
OpenModal("Problem", "Account Creation Failed, Please Try Again Later", false, true);
break;
}
});
// load agency dashboard
// id=agency-account-info-holder
}
// If validation passes, proceed with form submission or other actions
ConsoleLog("Validation passed. Submitting form...");
});
}
}
}
// logged in agency user, arriving on non-agency site gets sent to agency page
if(agencyMember && !window.location.href.toLowerCase().includes('/agency') && isUserLoggedIn)
{
// send to agency page
window.location = '/agency';
}
// logged in user arriving at agency page gets redirected to main user page
if(!agencyMember && window.location.href.toLowerCase().includes('/agency') && isUserLoggedIn)
{
// send to home page
window.location = '/';
}
// basically fresh visitor to agency page
if(!agencyMember && window.location.href.toLowerCase().includes('/agency') && !isUserLoggedIn)
{
HidePreLoad();
// show form-container
$('#Form-container').show();
$('#get-started-free_Agency').hide();
// check for query strings
// 1. Get the query string from the URL:
const queryString = window.location.search;
// 2. Create a URLSearchParams object to parse the query string:
const urlParams = new URLSearchParams(queryString);
// 3. Iterate through each key-value pair using forEach:
urlParams.forEach((value, key) => {
switch (key) {
case 'processStatus':
removeParam(key);
ConsoleLog('ProcessStatus:', value);
// Perform actions specific to the parameter
// redirect to home page
location.href = '/?login=true';
break;
case 'reset-password':
removeParam(key);
ConsoleLog('ResetPassword:', value);
// Perform actions specific to the parameter
OpenCloseResetPasswordModal("open");
break;
case 'login':
removeParam(key);
ConsoleLog('Login:', value);
// Perform actions specific to the parameter
OpenCloseLoginModal("open");
break;
default:
ConsoleLog(`Unknown parameter: ${key} with value: ${value}`);
}
});
}
}
}
async function pollForOrderCompletion(sessionId, operation) {
const memberID = localStorage.getItem("memberID");
const authToken = localStorage.getItem("auth_token");
let attempts = 0;
const maxAttempts = 30; // 1 minute total
const pollInterval = setInterval(async () => {
attempts++;
try {
// Call your Lambda to check if order was processed
const response = await fetch('https://j8glspknjh.execute-api.eu-west-1.amazonaws.com/Production/Checkout', {
method: 'POST',
body: JSON.stringify({
operation: operation,
sessionId: sessionId, // cs_abc123
memberID: memberID,
authToken: authToken
})
});
const result = await response.json();
if (result.orderProcessed) {
// ✅ Webhook completed! Order found in database
clearInterval(pollInterval);
if(!window.location.href.toLowerCase().includes('/agency'))
{
// Update localStorage with new account status
if (result.paidAccount) localStorage.setItem("paidAccount", result.paidAccount);
if (result.revisions) localStorage.setItem("revisions", result.revisions);
// Redirect to profile
setTimeout(() => {
window.location.href = '/';
}, 500);
}
else
{
// Redirect to agency profile
setTimeout(() => {
window.location.href = './';
}, 500);
}
}
else if (attempts >= maxAttempts) {
// ❌ Timeout - webhook might have failed
clearInterval(pollInterval);
OpenModal("Processing", "Your payment was successful. If credits don't appear shortly, please contact support@mypeas.ai", false, false);
// Redirect to profile
setTimeout(() => {
window.location.href = './';
}, 3000);
}
// If orderProcessed is false, keep polling...
} catch (error) {
console.error('Polling error:', error);
if (attempts >= maxAttempts) {
clearInterval(pollInterval);
//OpenModal("Error", "Please contact support@mypeas.ai", false, false);
OpenModal("Problem", "If credits don't appear shortly, please contact support@mypeas.ai", false, false);
// Redirect to profile
setTimeout(() => {
window.location.href = './';
}, 3000);
}
}
}, 2000); // Poll every 2 seconds
}
function CancelWaitlist()
{
// hide
$('#btnJoinWaitlist').hide();
$('#join-waitlist-bottom').hide();
$('#waitlist-container').hide();
$('#invite-launcher').hide();
$('#skipwaitlist-container').hide();
$('#get-started-free').hide();
// close this modal
$('#linkedin-modal .close-btn-w').click();
// hide skip waitlist button at bottom
$('#btn-skip-wait-bottom').hide();
// show
$('#btnGetStarted').show().css('display', 'block');
$('#get-started-free').show().css('display', 'block');
$('#Form-container').show();
}
function calculateWaitlistNumber() {
const currentTime = new Date();
const currentHour = currentTime.getHours();
const listCounter = document.getElementById("list-counter");
var listCounterPopup = document.getElementById("list-counter-popup-span");
let waitlistNumber;
// If it's before 6 PM, decrease the number as the day progresses
if (currentHour < 18) {
// Start at 1200 at 8 AM and decrease down to 800 by 6 PM
const startWaitlist = 1200;
const endWaitlist = 800;
const startHour = 8;
const endHour = 18;
if (currentHour >= startHour) {
// Calculate proportionally how far through the day we are and adjust the waitlist number
const progress = (currentHour - startHour) / (endHour - startHour);
waitlistNumber = Math.floor(startWaitlist - progress * (startWaitlist - endWaitlist));
} else {
waitlistNumber = startWaitlist; // Early in the day, still high waitlist number
}
}
// After 6 PM, increase the waitlist number again
else {
// Between 6 PM and midnight, the waitlist grows back up to 1200
const startWaitlist = 800;
const endWaitlist = 1200;
const startHour = 18;
const endHour = 24;
const progress = (currentHour - startHour) / (endHour - startHour);
waitlistNumber = Math.floor(startWaitlist + progress * (endWaitlist - startWaitlist));
}
// Update the displayed waitlist number
listCounter.textContent = waitlistNumber;
listCounterPopup.textContent = waitlistNumber;
$('#linkedin-modal').animate({ opacity: 1 }).show();
}
/* Booking Page code */
function isBookingPage()
{
// Get the URL parameters
const urlParams = new URLSearchParams(window.location.search);
// Check if the required parameters are present
const hasBooking = urlParams.has('calLink');
const hasAgencyID = urlParams.has('agencyID');
const hasMemberID = urlParams.has('memberID');
// If all parameters are present, return true, otherwise redirect
if (hasBooking && hasAgencyID && hasMemberID)
{
return true;
}
else if(hasBooking && !(hasAgencyID && hasMemberID))
{
window.location.href = 'https://mypeas.ai';
}
else
{
return false;
}
}
function getParameterByName(name, url) {
if (!url) url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^]*)|&|#|$)");
var results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
function addParameterToURL(url, paramName, paramValue)
{
const urlObject = new URL(url);
urlObject.searchParams.set(paramName, paramValue);
return urlObject.toString();
}
function isCalendlyEvent(e) {
console.log('e: ',e);
console.log('origin: ',e.origin);
console.log('event', e.data.event);
console.log('isCalendlyEvent: ',e.origin === "https://calendly.com" && e.data.event && e.data.event.indexOf("calendly.") === 0);
return e.origin === "https://calendly.com" && e.data.event && e.data.event.indexOf("calendly.") === 0;
}
/* END booking page code */
function CheckApp()
{
// check which page you are on
// listing vs my-tools
var isListingPage = false;
var isMyToolsPage = false;
// check url
var currentUrl = window.location.href;
var urlDirectory = "/app-listing/listing";
if(currentUrl.toLowerCase().includes("/app-listing/listing"))
{
HideNavButtons();
urlDirectory = "/app-listing/listing";
isListingPage = true;
CheckApp_ListingPage();
}
if(currentUrl.toLowerCase().includes("/app-listing/my-tools"))
{
var isUserLoggedIn = checkLoggedIn();
var paramTest = getParameterByName("test", null);
var isTest = false;
if(paramTest)
{
isTest = true;
}
if(isUserLoggedIn || isTest)
{
urlDirectory = "/app-listing/my-tools";
isMyToolsPage = true;
HideNavButtons();
CheckApp_MyToolsPage();
// set tools if present
Check_Stored_Tools();
// add invoices
createInvoiceTable();
}
else
{
// redirect to home
window.location = window.location.origin;
}
}
if(!isListingPage && !isMyToolsPage)
{
// check for query strings
// 1. Get the query string from the URL:
const queryString = window.location.search;
// 2. Create a URLSearchParams object to parse the query string:
const urlParams = new URLSearchParams(queryString);
// 3. Check for 'appname' parameter and its value:
const appName = urlParams.get('appname');
/*if (!appName || appName.trim() === '') {
// Redirect to root if missing or empty value
window.location.href = '/';
return; // Prevent further execution if redirected
}*/
// 4. Iterate through each key-value pair using forEach:
urlParams.forEach((value, key) => {
switch (key)
{
case 'appname':
ConsoleLog('appName:', value);
var decodedAppName = value ? decodeURIComponent(value) : "";
ConsoleLog('appName (decoded):', decodedAppName);
SearchApp("Name", decodedAppName);
break;
}
});
}
}
// Store a persistent reference to the event handler
let handleAddFaqClick = null;
function CheckApp_ListingPage()
{
// check for query params
var paramSuccess = getParameterByName("success", null);
var paramCancel = getParameterByName("cancel", null);
if(paramSuccess)
{
$('#success-banner').show();
}
if(paramCancel)
{
$('#cancel-banner').show();
}
// check local storage
var storedListing = localStorage.getItem("createOrUpdateListing");
setData('#submit-new-tool-holder', null);
if(storedListing && paramCancel)
{
// load UI from localstorage
/*
const payload = {
operation: 'createOrUpdateListing',
payload: {
AppTitle: document.getElementById('app-heading').textContent,
AppHeadline: document.getElementById('app-subheading').textContent,
AppScreenshot: document.getElementById('app-hero-image').src,
AppDescription: document.getElementById('app-description').textContent,
AppCategory: appData.task,
WebsiteLink: document.getElementById('app-URL').value,
FAQs: JSON.stringify(faqs),
Paid: false, // Default, can be updated as needed
DateOfPayment: DateOfPayment,
},
};
*/
// create listingObj from localstorage
var listingObj = {};
storedListing = JSON.parse(storedListing);
// get the payload from the stripe session
// get param from the url to request stripe session object
// we cant store the data in metadata as the description is longer than the 500 characters
listingObj.objectID = storedListing.payload.AppId;
listingObj.name = storedListing.payload.AppTitle;
listingObj.useCase = storedListing.payload.AppHeadline;
listingObj.task = storedListing.payload.AppCategory; // task is category/group
listingObj.screenshot = storedListing.payload.AppScreenshot;
listingObj.siteUrl = storedListing.payload.WebsiteLink;
listingObj.description = storedListing.payload.AppDescription;
listingObj.faqs = storedListing.payload.FAQs;
/*var appData;
appData.name;
appData.useCase;
appData.task;
appData.screenshot;
appData.useCase;
appData.siteUrl;
appData.description;*/
setData("#app-holder", listingObj);
}
// check for submit type
if(paramCancel)
{
// DETERMINE SUBMIT TYPE: buy listing OR update listing
var accountInfo = localStorage.getItem("accountInfo") || null;
if(accountInfo)
{
accountInfo = JSON.parse(accountInfo);
// create and populate
// get owned tools
var tools = accountInfo["tools"] || [];
// loop over tools and find appids
// Extracting AppId values
//const appIds = accountInfo.tools.map(tool => tool.AppId);
const appIds = tools.map(tool => tool.AppId);
// Output the result
console.log(appIds);
// compare current appId to the collection of AppId values
var appId = "";
if(listingObj)
{
appId = listingObj.objectID;
}
// Check if appId exists in appIds
if (appIds.includes(appId))
{
console.log("Match found for appId:", appId);
// Add any actions to execute when there's a match
// show update
$('#update-listing-holder').show();
$('#make-purchase-holder').hide();
}
else
{
console.log("No match found for appId:", appId);
// show purchase
$('#make-purchase-holder').show();
$('#update-listing-holder').hide();
}
}
}
// if success - use stored listing to populate UI - server may still be updating databases
// NEW* if success just hide those fields and show success banner
if(storedListing && paramSuccess)
{
// change the ui for purchased listing
//$('#product-description').hide();
$('#edit-heading').hide();
$('#edit-tagline').hide();
$('#edit-hero-image').hide();
$('#edit-description').hide();
$('#edit-url').hide();
$('#add-faq').hide();
$('#make-purchase-holder').hide();
$('#what-is-mypeas-holder').hide();
$('#welcome-banner').hide();
$('#edit-category').hide();
// make uneditable
// appURL.contentEditable = true;
var AppDescription = document.getElementById('app-description');
var AppCategory = document.getElementById('app-category');
var AppUrl = document.getElementById('app-URL');
AppDescription.contentEditable = false;
AppCategory.contentEditable = false;
AppUrl.contentEditable = false;
// load UI from localstorage
/*
const payload = {
operation: 'createOrUpdateListing',
payload: {
AppTitle: document.getElementById('app-heading').textContent,
AppHeadline: document.getElementById('app-subheading').textContent,
AppScreenshot: document.getElementById('app-hero-image').src,
AppDescription: document.getElementById('app-description').textContent,
AppCategory: appData.task,
WebsiteLink: document.getElementById('app-URL').value,
FAQs: JSON.stringify(faqs),
Paid: false, // Default, can be updated as needed
DateOfPayment: DateOfPayment,
},
};
*/
// create listingObj from localstorage
var listingObj = {};
storedListing = JSON.parse(storedListing);
// get the payload from the stripe session
// get param from the url to request stripe session object
// we cant store the data in metadata as the description is longer than the 500 characters
listingObj.objectID = storedListing.payload.AppId;
listingObj.name = storedListing.payload.AppTitle;
listingObj.useCase = storedListing.payload.AppHeadline;
listingObj.task = storedListing.payload.AppCategory; // task is category/group
listingObj.screenshot = storedListing.payload.AppScreenshot;
listingObj.siteUrl = storedListing.payload.WebsiteLink;
listingObj.description = storedListing.payload.AppDescription;
listingObj.faqs = storedListing.payload.FAQs;
/*var appData;
appData.name;
appData.useCase;
appData.task;
appData.screenshot;
appData.useCase;
appData.siteUrl;
appData.description;*/
setData("#app-holder", listingObj);
// hide both submit options
$('#update-listing-holder').hide();
$('#make-purchase-holder').hide();
}
// default to load listing info
// all other circumstances use the data from the server
if(!(storedListing && paramSuccess) && !(storedListing && paramCancel))
{
// set up fields to work
if(!paramCancel && !paramSuccess)
{
// if listing
var btnEditHeading = document.getElementById("edit-heading");
var btnEditSubheading = document.getElementById("edit-tagline");
var btnEditImage = document.getElementById("edit-hero-image");
var uploadButton = document.getElementById("upload-button");
var btnEditDescription = document.getElementById("edit-description");
var btnAddFAQ = document.getElementById("add-faq");
var btnEditUrl = document.getElementById("edit-url");
var btnOpenUrl = document.getElementById("visit-website");
var appURL = document.getElementById('app-URL');
var appId = document.getElementById('app-id');
if(appURL)
{
appURL.addEventListener("focus", () => {
appURL.style.border = "2px solid blue";
appURL.style.backgroundColor = "lightblue";
appURL.style.boxShadow = "0px 0px 5px rgba(0, 0, 0, 0.5)";
});
appURL.addEventListener("blur", () => {
appURL.style.border = "1px solid lightgray";
appURL.style.backgroundColor = "";
appURL.style.boxShadow = "";
});
appURL.addEventListener("paste", (event) => {
event.preventDefault(); // Prevent default paste behavior
// Get the plain text from the clipboard
const plainText = (event.clipboardData || window.clipboardData).getData('text');
// Insert the plain text at the current caret position
const selection = window.getSelection();
if (!selection.rangeCount) return;
// Get the current range and replace it with plain text
const range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(document.createTextNode(plainText));
});
}
btnOpenUrl.addEventListener('click', (event) => {
event.preventDefault();
var appLink = appURL.textContent;
if(appLink && appLink.trim() !== "")
{
window.open(appLink, '_blank', 'noopener');
}
});
btnEditUrl.addEventListener('click', (event) => {
event.preventDefault();
appURL.contentEditable = true;
appURL.focus();
});
var appHeading = document.getElementById("app-heading");
appHeading.addEventListener("focus", () => {
var placeholder = "Heading";
if(appHeading.textContent.trim() == placeholder)
{
appHeading.textContent = "";
// Set a minimum width when the content is empty
appHeading.style.minWidth = '200px'; // Adjust the value as needed
}
appHeading.style.border = "2px solid blue";
appHeading.style.backgroundColor = "lightblue";
appHeading.style.boxShadow = "0px 0px 5px rgba(0, 0, 0, 0.5)";
});
appHeading.addEventListener("blur", () => {
var placeholder = "Heading";
if(appHeading.textContent.trim() == "")
{
appHeading.textContent = placeholder;
}
appHeading.style.border = "";
appHeading.style.backgroundColor = "";
appHeading.style.boxShadow = "";
});
appHeading.addEventListener("paste", (event) => {
event.preventDefault(); // Prevent default paste behavior
// Get the plain text from the clipboard
const plainText = (event.clipboardData || window.clipboardData).getData('text');
// Insert the plain text at the current caret position
const selection = window.getSelection();
if (!selection.rangeCount) return;
// Get the current range and replace it with plain text
const range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(document.createTextNode(plainText));
});
btnEditHeading.addEventListener('click', (event) => {
// show forgotpassword
event.preventDefault();
/*$('#app-heading-update').show();
$('#app-heading').hide();*/
appHeading.contentEditable = true;
appHeading.focus();
});
var appSubheading = document.getElementById("app-subheading");
appSubheading.addEventListener("focus", () => {
var placeholder = "App tagline text";
if(appSubheading.textContent.trim() == placeholder)
{
appSubheading.textContent = "";
// Set a minimum width when the content is empty
appSubheading.style.minWidth = '200px'; // Adjust the value as needed
}
appSubheading.style.border = "2px solid blue";
appSubheading.style.backgroundColor = "lightblue";
appSubheading.style.boxShadow = "0px 0px 5px rgba(0, 0, 0, 0.5)";
});
appSubheading.addEventListener("blur", () => {
var placeholder = "App tagline text";
if(appSubheading.textContent.trim() == "")
{
appSubheading.textContent = placeholder;
}
appSubheading.style.border = "";
appSubheading.style.backgroundColor = "";
appSubheading.style.boxShadow = "";
});
appSubheading.addEventListener("paste", (event) => {
event.preventDefault(); // Prevent default paste behavior
// Get the plain text from the clipboard
const plainText = (event.clipboardData || window.clipboardData).getData('text');
// Insert the plain text at the current caret position
const selection = window.getSelection();
if (!selection.rangeCount) return;
// Get the current range and replace it with plain text
const range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(document.createTextNode(plainText));
});
btnEditSubheading.addEventListener('click', (event) => {
// show forgotpassword
event.preventDefault();
/*$('#app-subheading-update').show();
$('#app-subheading').hide(); */
appSubheading.contentEditable = true;
appSubheading.focus();
});
btnEditImage.addEventListener('click', (event) => {
// show forgotpassword
event.preventDefault();
$('#app-hero-image-update').show();
// file picker
$('#app-screenshot').show();
// update button
$('#upload-button').show();
});
if (uploadButton)
{
uploadButton.addEventListener('click', async (event) => {
event.preventDefault();
const screenshotInput = document.getElementById('app-screenshot'); // File input for new screenshot
if (screenshotInput.files.length > 0) {
const file = screenshotInput.files[0];
const folderName = 'images';
// Convert file to Base64 using FileReader
const fileBuffer = await fileToBase64(file); // Base64-encoded string
const payload = { folderName, fileBuffer };
const apiUrl = 'https://9halovn749.execute-api.eu-west-1.amazonaws.com/default/CreateListing';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify({ operation: 'generateScreenshotUploadUrl', payload }),
})
.then(response => response.json()) // Parse the response as JSON
.then(data => {
console.log("Upload response received:", data);
// Check if the response contains a valid imageUrl
if (data && typeof data === 'object' && data.imageUrl && typeof data.imageUrl === 'string' && data.imageUrl.startsWith('https://flexluthor.s3.eu-west-2.amazonaws.com/'))
{
console.log("Valid image URL detected:", data.imageUrl);
// Update the src of the image only if the URL is valid
const appHeroImg = document.getElementById('app-hero-image');
if (appHeroImg) {
appHeroImg.src = data.imageUrl;
} else {
console.warn('Element with id "app-hero-image" not found.');
}
// Clear the file selection
if (screenshotInput) {
screenshotInput.value = null;
} else {
console.warn('Element with id "screenshotInput" not found.');
}
}
else
{
console.warn("Response did not contain a valid image URL.", data);
}
})
.catch(error => {
console.error("Upload failed:", error);
});
}
});
}
var appDescription = document.getElementById('app-description');
appDescription.addEventListener("focus", () => {
var placeholder = "Description of Your AI solution";
if(appDescription.textContent.trim() == placeholder)
{
appDescription.textContent = "";
// Set a minimum width when the content is empty
appDescription.style.minWidth = '200px'; // Adjust the value as needed
}
appDescription.style.border = "2px solid blue";
appDescription.style.backgroundColor = "lightblue";
appDescription.style.boxShadow = "0px 0px 5px rgba(0, 0, 0, 0.5)";
appDescription.style.padding = '14px';
appDescription.style.whiteSpace = 'pre-wrap';
appDescription.style.padding = '14px';
appDescription.style.wordWrap = 'break-word';
appDescription.style.overflowWrap = 'break-word';
appDescription.style.maxWidth = '100%';
appDescription.style.overflow = 'hidden';
//appDescription.style.outline = 'none';
/*
Description of Your AI solution
*/
});
appDescription.addEventListener("blur", () => {
var placeholder = "Description of Your AI solution";
if(appDescription.textContent.trim() == "")
{
appDescription.textContent = placeholder;
}
appDescription.style.whiteSpace = 'pre-wrap';
appDescription.style.padding = '14px';
appDescription.style.border = "1px solid lightgray";
appDescription.style.backgroundColor = "";
appDescription.style.boxShadow = "";
});
appDescription.addEventListener("paste", (event) => {
event.preventDefault(); // Prevent default paste behavior
// Get the plain text from the clipboard
const plainText = (event.clipboardData || window.clipboardData).getData('text');
// Insert the plain text at the current caret position
const selection = window.getSelection();
if (!selection.rangeCount) return;
// Get the current range and replace it with plain text
const range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(document.createTextNode(plainText));
});
btnEditDescription.addEventListener('click', (event) => {
// show forgotpassword
event.preventDefault();
/*$('#app-description-update').show();
$('#app-description').hide();
var appDescription = document.getElementById("app-description");
const formattedText = appDescription.textContent.replace(/\n/g, " "); // Replace newlines with for HTML
// Get the textarea element
const textarea = document.getElementById('app-description-update');
// Set the textarea's value with the formatted text
textarea.value = formattedText;
// Create a temporary selection element (optional)
const selection = document.createRange();
selection.selectNodeContents(textarea);
try {
// Attempt to copy the selection (if supported)
const successful = document.execCommand('copy');
const msg = successful ? 'Formatted text copied!' : 'Browser may not support copying.';
alert(msg);
} catch (err) {
console.error('Copying failed:', err);
alert('Failed to copy text. Consider manual copy/paste.');
} finally {
// Cleanup the temporary selection (if created)
selection.detach();
}*/
appDescription.contentEditable = true;
appDescription.focus();
});
// add app category
var appCategory = document.getElementById('app-category');
appCategory.addEventListener("focus", () => {
appCategory.style.border = "2px solid blue";
appCategory.style.backgroundColor = "lightblue";
appCategory.style.boxShadow = "0px 0px 5px rgba(0, 0, 0, 0.5)";
appCategory.style.whiteSpace = 'pre-wrap';
appCategory.style.wordWrap = 'break-word';
appCategory.style.overflowWrap = 'break-word';
appCategory.style.maxWidth = '100%';
appCategory.style.overflow = 'hidden';
appCategory.style.wordBreak = 'break-word';
//appCategory.style.outline = 'none';
});
appCategory.addEventListener("blur", () => {
appCategory.style.border = "1px solid lightgray";
appCategory.style.backgroundColor = "";
appCategory.style.boxShadow = "";
});
appCategory.addEventListener("paste", (event) => {
event.preventDefault(); // Prevent default paste behavior
// Get the plain text from the clipboard
const plainText = (event.clipboardData || window.clipboardData).getData('text');
// Insert the plain text at the current caret position
const selection = window.getSelection();
if (!selection.rangeCount) return;
// Get the current range and replace it with plain text
const range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(document.createTextNode(plainText));
});
var btnEditCategory = document.getElementById('edit-category');
btnEditCategory.addEventListener('click', (event) => {
event.preventDefault();
appCategory.contentEditable = true;
appCategory.focus();
});
const faqList = document.getElementById('faq-list');
// Function to add a new FAQ input pair
/*function addFaqEntry(question = '', answer = '') {
const faqDiv = document.createElement('div');
faqDiv.style.marginBottom = "10px";
faqDiv.classList.add('faq-entry');
faqDiv.innerHTML = `
Remove
`;
faqList.appendChild(faqDiv);
const removeButton = faqDiv.querySelector('.remove-faq');
removeButton.addEventListener('click', () => {
faqDiv.remove();
});
}
// Add event listener to the "Add FAQ" button
btnAddFAQ.addEventListener('click', () => addFaqEntry());*/
// Function to ensure only one event listener is attached to btnAddFAQ
function setupFaqButtonListener() {
// If the handler hasn’t been set yet, define it
if (!handleAddFaqClick) {
handleAddFaqClick = function () {
addFaqEntry();
};
}
// Remove any existing listener before adding a new one
btnAddFAQ.removeEventListener('click', handleAddFaqClick);
btnAddFAQ.addEventListener('click', handleAddFaqClick);
}
// Function to add a new FAQ input pair
function addFaqEntry(question = '', answer = '') {
const faqDiv = document.createElement('div');
faqDiv.style.marginBottom = "10px";
faqDiv.classList.add('faq-entry');
faqDiv.innerHTML = `
Remove
`;
faqList.appendChild(faqDiv);
const removeButton = faqDiv.querySelector('.remove-faq');
removeButton.addEventListener('click', () => {
faqDiv.remove();
});
}
// Call this function whenever the event listener needs to be ensured
setupFaqButtonListener();
}
// check for query strings
// 1. Get the query string from the URL:
const queryString = window.location.search;
// 2. Create a URLSearchParams object to parse the query string:
const urlParams = new URLSearchParams(queryString);
// 3. Check for 'appname' parameter and its value:
const appName = urlParams.get('appname');
/*if (!appName || appName.trim() === '') {
// Redirect to root if missing or empty value
window.location.href = '/';
return; // Prevent further execution if redirected
}*/
// 4. Iterate through each key-value pair using forEach:
urlParams.forEach((value, key) => {
switch (key)
{
case 'appname':
ConsoleLog('appName:', value);
var decodedAppName = value ? decodeURIComponent(value) : "";
ConsoleLog('appName (decoded):', decodedAppName);
SearchApp("Name", decodedAppName);
break;
}
});
}
}
function CheckApp_MyToolsPage()
{
// check which page you are on
// listing vs my-tools
var isListingPage = false;
var isMyToolsPage = false;
// check url
var currentUrl = window.location.href;
var urlDirectory = "/app-listing/listing";
setData('#submit-new-tool-holder',null);
if(currentUrl.toLowerCase().includes("/app-listing/listing"))
{
urlDirectory = "/app-listing/listing";
isListingPage = true;
}
if(currentUrl.toLowerCase().includes("/app-listing/my-tools"))
{
urlDirectory = "/app-listing/my-tools";
isMyToolsPage = true;
}
// check for query params
var paramSuccess = getParameterByName("success", null);
var paramCancel = getParameterByName("cancel", null);
if(paramSuccess)
{
$('#success-banner').show();
// just hide those fields
// this is default
}
if(paramCancel)
{
$('#cancel-banner').show();
}
// check local storage
var storedListing = localStorage.getItem("createOrUpdateListing");
// if success - use stored listing to populate UI - server may still be updating databases
// just hide those fields
if(storedListing && paramCancel)
{
// load UI from localstorage
/*
const payload = {
operation: 'createOrUpdateListing',
payload: {
AppTitle: document.getElementById('app-heading').textContent,
AppHeadline: document.getElementById('app-subheading').textContent,
AppScreenshot: document.getElementById('app-hero-image').src,
AppDescription: document.getElementById('app-description').textContent,
AppCategory: appData.task,
WebsiteLink: document.getElementById('app-URL').value,
FAQs: JSON.stringify(faqs),
Paid: false, // Default, can be updated as needed
DateOfPayment: DateOfPayment,
},
};
*/
// create listingObj from localstorage
var listingObj = {};
storedListing = JSON.parse(storedListing);
// get the payload from the stripe session
// get param from the url to request stripe session object
// we cant store the data in metadata as the description is longer than the 500 characters
listingObj.objectID = storedListing.payload.AppId;
listingObj.name = storedListing.payload.AppTitle;
listingObj.useCase = storedListing.payload.AppHeadline;
listingObj.task = storedListing.payload.AppCategory; // task is category/group
listingObj.screenshot = storedListing.payload.AppScreenshot;
listingObj.siteUrl = storedListing.payload.WebsiteLink;
listingObj.description = storedListing.payload.AppDescription;
listingObj.faqs = storedListing.payload.FAQs;
// Example Usage
/*const sessionId = 'cs_test_a1s3CompJydFm46qju3jqyKoeIcu3P2nUhNuuzoknQlYFqDbY1jIqQAccb'; // Replace with a valid session ID
getSession(sessionId).then(session => {
if (session) {
console.log('Retrieved session:', session);
} else {
console.log('Failed to retrieve session.');
}
});*/
/*var appData;
appData.name;
appData.useCase;
appData.task;
appData.screenshot;
appData.useCase;
appData.siteUrl;
appData.description;*/
setData("#app-holder", listingObj);
// show fields
document.getElementById('submit-new-tool-holder').style.display = 'block';
}
// var StripeInvoices = result["StripeInvoices"] || JSON.stringify([]);
//localStorage.setItem("StripeInvoices", result["StripeInvoices"] || "[]");
//localStorage.setItem("StripeInvoices", StripeInvoices);
// default is handled in CheckApp
if(!paramCancel && !paramSuccess)
{
// if listing
var btnEditHeading = document.getElementById("edit-heading");
var btnEditSubheading = document.getElementById("edit-tagline");
var btnEditImage = document.getElementById("edit-hero-image");
var uploadButton = document.getElementById("upload-button");
var btnEditDescription = document.getElementById("edit-description");
var btnAddFAQ = document.getElementById("add-faq");
var btnEditUrl = document.getElementById("edit-url");
var btnOpenUrl = document.getElementById("visit-website");
var appURL = document.getElementById('app-URL');
var appId = document.getElementById('app-id');
if(appURL)
{
appURL.addEventListener("focus", () => {
appURL.style.border = "2px solid blue";
appURL.style.backgroundColor = "lightblue";
appURL.style.boxShadow = "0px 0px 5px rgba(0, 0, 0, 0.5)";
});
appURL.addEventListener("blur", () => {
appURL.style.border = "1px solid lightgray";
appURL.style.backgroundColor = "";
appURL.style.boxShadow = "";
});
appURL.addEventListener("paste", (event) => {
event.preventDefault(); // Prevent default paste behavior
// Get the plain text from the clipboard
const plainText = (event.clipboardData || window.clipboardData).getData('text');
// Insert the plain text at the current caret position
const selection = window.getSelection();
if (!selection.rangeCount) return;
// Get the current range and replace it with plain text
const range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(document.createTextNode(plainText));
});
}
btnOpenUrl.addEventListener('click', (event) => {
event.preventDefault();
var appLink = appURL.textContent;
if(appLink && appLink.trim() !== "")
{
window.open(appLink, '_blank', 'noopener');
}
});
btnEditUrl.addEventListener('click', (event) => {
event.preventDefault();
appURL.contentEditable = true;
appURL.focus();
});
var appHeading = document.getElementById("app-heading");
appHeading.addEventListener("focus", () => {
var placeholder = "Heading";
if(appHeading.textContent.trim() == placeholder)
{
appHeading.textContent = "";
// Set a minimum width when the content is empty
appHeading.style.minWidth = '200px'; // Adjust the value as needed
}
appHeading.style.border = "2px solid blue";
appHeading.style.backgroundColor = "lightblue";
appHeading.style.boxShadow = "0px 0px 5px rgba(0, 0, 0, 0.5)";
});
appHeading.addEventListener("blur", () => {
var placeholder = "Heading";
if(appHeading.textContent.trim() == "")
{
appHeading.textContent = placeholder;
}
appHeading.style.border = "";
appHeading.style.backgroundColor = "";
appHeading.style.boxShadow = "";
});
appHeading.addEventListener("paste", (event) => {
event.preventDefault(); // Prevent default paste behavior
// Get the plain text from the clipboard
const plainText = (event.clipboardData || window.clipboardData).getData('text');
// Insert the plain text at the current caret position
const selection = window.getSelection();
if (!selection.rangeCount) return;
// Get the current range and replace it with plain text
const range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(document.createTextNode(plainText));
});
btnEditHeading.addEventListener('click', (event) => {
// show forgotpassword
event.preventDefault();
/*$('#app-heading-update').show();
$('#app-heading').hide();*/
appHeading.contentEditable = true;
appHeading.focus();
});
var appSubheading = document.getElementById("app-subheading");
appSubheading.addEventListener("focus", () => {
var placeholder = "App tagline text";
if(appSubheading.textContent.trim() == placeholder)
{
appSubheading.textContent = "";
// Set a minimum width when the content is empty
appSubheading.style.minWidth = '200px'; // Adjust the value as needed
}
appSubheading.style.border = "2px solid blue";
appSubheading.style.backgroundColor = "lightblue";
appSubheading.style.boxShadow = "0px 0px 5px rgba(0, 0, 0, 0.5)";
});
appSubheading.addEventListener("blur", () => {
var placeholder = "App tagline text";
if(appSubheading.textContent.trim() == "")
{
appSubheading.textContent = placeholder;
}
appSubheading.style.border = "";
appSubheading.style.backgroundColor = "";
appSubheading.style.boxShadow = "";
});
appSubheading.addEventListener("paste", (event) => {
event.preventDefault(); // Prevent default paste behavior
// Get the plain text from the clipboard
const plainText = (event.clipboardData || window.clipboardData).getData('text');
// Insert the plain text at the current caret position
const selection = window.getSelection();
if (!selection.rangeCount) return;
// Get the current range and replace it with plain text
const range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(document.createTextNode(plainText));
});
btnEditSubheading.addEventListener('click', (event) => {
// show forgotpassword
event.preventDefault();
/*$('#app-subheading-update').show();
$('#app-subheading').hide(); */
appSubheading.contentEditable = true;
appSubheading.focus();
});
btnEditImage.addEventListener('click', (event) => {
// show forgotpassword
event.preventDefault();
$('#app-hero-image-update').show();
// file picker
$('#app-screenshot').show();
// update button
$('#upload-button').show();
});
if (uploadButton)
{
uploadButton.addEventListener('click', async (event) => {
event.preventDefault();
const screenshotInput = document.getElementById('app-screenshot'); // File input for new screenshot
if (screenshotInput.files.length > 0) {
const file = screenshotInput.files[0];
const folderName = 'images';
// Convert file to Base64 using FileReader
const fileBuffer = await fileToBase64(file); // Base64-encoded string
const payload = { folderName, fileBuffer };
const apiUrl = 'https://9halovn749.execute-api.eu-west-1.amazonaws.com/default/CreateListing';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify({ operation: 'generateScreenshotUploadUrl', payload }),
})
.then(response => response.json()) // Parse the response as JSON
.then(data => {
console.log("Upload response received:", data);
// Check if the response contains a valid imageUrl
if (data && typeof data === 'object' && data.imageUrl && typeof data.imageUrl === 'string' && data.imageUrl.startsWith('https://flexluthor.s3.eu-west-2.amazonaws.com/'))
{
console.log("Valid image URL detected:", data.imageUrl);
// Update the src of the image only if the URL is valid
const appHeroImg = document.getElementById('app-hero-image');
if (appHeroImg) {
appHeroImg.src = data.imageUrl;
} else {
console.warn('Element with id "app-hero-image" not found.');
}
// Clear the file selection
if (screenshotInput) {
screenshotInput.value = null;
} else {
console.warn('Element with id "screenshotInput" not found.');
}
}
else
{
console.warn("Response did not contain a valid image URL.", data);
}
})
.catch(error => {
console.error("Upload failed:", error);
});
}
});
}
var appDescription = document.getElementById('app-description');
appDescription.addEventListener("focus", () => {
var placeholder = "Description of Your AI solution";
if(appDescription.textContent.trim() == placeholder)
{
appDescription.textContent = "";
// Set a minimum width when the content is empty
appDescription.style.minWidth = '200px'; // Adjust the value as needed
}
appDescription.style.border = "2px solid blue";
appDescription.style.backgroundColor = "lightblue";
appDescription.style.boxShadow = "0px 0px 5px rgba(0, 0, 0, 0.5)";
appDescription.style.whiteSpace = 'pre-wrap';
appDescription.style.padding = '14px';
appDescription.style.wordWrap = 'break-word';
appDescription.style.overflowWrap = 'break-word';
appDescription.style.maxWidth = '100%';
appDescription.style.overflow = 'hidden';
//appDescription.style.outline = 'none';
});
appDescription.addEventListener("blur", () => {
var placeholder = "Description of Your AI solution";
if(appDescription.textContent.trim() == "")
{
appDescription.textContent = placeholder;
}
appDescription.style.whiteSpace = 'pre-wrap';
appDescription.style.padding = '14px';
appDescription.style.border = "1px solid lightgray";
appDescription.style.backgroundColor = "";
appDescription.style.boxShadow = "";
});
appDescription.addEventListener("paste", (event) => {
event.preventDefault(); // Prevent default paste behavior
// Get the plain text from the clipboard
const plainText = (event.clipboardData || window.clipboardData).getData('text');
// Insert the plain text at the current caret position
const selection = window.getSelection();
if (!selection.rangeCount) return;
// Get the current range and replace it with plain text
const range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(document.createTextNode(plainText));
});
btnEditDescription.addEventListener('click', (event) => {
// show forgotpassword
event.preventDefault();
/*$('#app-description-update').show();
$('#app-description').hide();
var appDescription = document.getElementById("app-description");
const formattedText = appDescription.textContent.replace(/\n/g, " "); // Replace newlines with for HTML
// Get the textarea element
const textarea = document.getElementById('app-description-update');
// Set the textarea's value with the formatted text
textarea.value = formattedText;
// Create a temporary selection element (optional)
const selection = document.createRange();
selection.selectNodeContents(textarea);
try {
// Attempt to copy the selection (if supported)
const successful = document.execCommand('copy');
const msg = successful ? 'Formatted text copied!' : 'Browser may not support copying.';
alert(msg);
} catch (err) {
console.error('Copying failed:', err);
alert('Failed to copy text. Consider manual copy/paste.');
} finally {
// Cleanup the temporary selection (if created)
selection.detach();
}*/
appDescription.contentEditable = true;
appDescription.focus();
});
// add app category
var appCategory = document.getElementById('app-category');
appCategory.addEventListener("focus", () => {
appCategory.style.border = "2px solid blue";
appCategory.style.backgroundColor = "lightblue";
appCategory.style.boxShadow = "0px 0px 5px rgba(0, 0, 0, 0.5)";
appCategory.style.whiteSpace = 'pre-wrap';
appCategory.style.wordWrap = 'break-word';
appCategory.style.overflowWrap = 'break-word';
appCategory.style.maxWidth = '100%';
appCategory.style.overflow = 'hidden';
appCategory.style.wordBreak = 'break-word';
//appCategory.style.outline = 'none';
});
appCategory.addEventListener("blur", () => {
appCategory.style.border = "1px solid lightgray";
appCategory.style.backgroundColor = "";
appCategory.style.boxShadow = "";
});
appCategory.addEventListener("paste", (event) => {
event.preventDefault(); // Prevent default paste behavior
// Get the plain text from the clipboard
const plainText = (event.clipboardData || window.clipboardData).getData('text');
// Insert the plain text at the current caret position
const selection = window.getSelection();
if (!selection.rangeCount) return;
// Get the current range and replace it with plain text
const range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(document.createTextNode(plainText));
});
var btnEditCategory = document.getElementById('edit-category');
btnEditCategory.addEventListener('click', (event) => {
event.preventDefault();
appCategory.contentEditable = true;
appCategory.focus();
});
const faqList = document.getElementById('faq-list');
// Function to add a new FAQ input pair
/*function addFaqEntry(question = '', answer = '') {
const faqDiv = document.createElement('div');
faqDiv.style.marginBottom = "10px";
faqDiv.classList.add('faq-entry');
faqDiv.innerHTML = `
Remove
`;
faqList.appendChild(faqDiv);
const removeButton = faqDiv.querySelector('.remove-faq');
removeButton.addEventListener('click', () => {
faqDiv.remove();
});
}
// Add event listener to the "Add FAQ" button
btnAddFAQ.addEventListener('click', () => addFaqEntry());*/
// Function to ensure only one event listener is attached to btnAddFAQ
function setupFaqButtonListener() {
// If the handler hasn’t been set yet, define it
if (!handleAddFaqClick) {
handleAddFaqClick = function () {
addFaqEntry();
};
}
// Remove any existing listener before adding a new one
btnAddFAQ.removeEventListener('click', handleAddFaqClick);
btnAddFAQ.addEventListener('click', handleAddFaqClick);
}
// Function to add a new FAQ input pair
function addFaqEntry(question = '', answer = '') {
const faqDiv = document.createElement('div');
faqDiv.style.marginBottom = "10px";
faqDiv.classList.add('faq-entry');
faqDiv.innerHTML = `
Remove
`;
faqList.appendChild(faqDiv);
const removeButton = faqDiv.querySelector('.remove-faq');
removeButton.addEventListener('click', () => {
faqDiv.remove();
});
}
// Call this function whenever the event listener needs to be ensured
setupFaqButtonListener();
}
}
function Check_Stored_Tools()
{
// check account for stored tools
// populates "my tools" section
var accountInfo = JSON.parse(localStorage.getItem("accountInfo"));
var mytools = accountInfo["tools"] || [];
if(mytools.length > 0)
{
// show mytools container
displayTools(mytools);
$('#mytools').show();
}
}
async function getSession(sessionId) {
try {
var apiUrl = 'https://j8glspknjh.execute-api.eu-west-1.amazonaws.com/Production/Checkout';
const response = await fetch(apiUrl, {
method: 'POST',
body: JSON.stringify({
operation: 'get-session',
sessionId: sessionId
}),
});
if (!response.ok) {
throw new Error(`Error retrieving session: ${response.statusText}`);
}
const sessionData = await response.json();
console.log('Session Data:', sessionData);
return sessionData;
} catch (error) {
console.error('Error retrieving session:', error);
return null;
}
}
function checkLoggedIn()
{
var agencyMember = localStorage.getItem("agencyMember") || null;
var memberID = localStorage.getItem("memberID") || null;
var authToken = localStorage.getItem("auth_token") || null;
var authTokenCreated = localStorage.getItem("auth_token_date_created") || null;
if(memberID && authToken && authTokenCreated)
{
if(!isAMonthOld(authTokenCreated))
{
return true;
}
}
return false;
}
function getCurrentDateString() {
return new Date().toISOString();
}
function isAWeekOld(dateString) {
const oneWeek = 7 * 24 * 60 * 60 * 1000; // milliseconds in a week
const givenDate = new Date(dateString);
const currentDate = new Date();
return (currentDate - givenDate) > oneWeek;
}
function isAWeekOldUnix(unixTimestamp) {
const oneWeekInSeconds = 7 * 24 * 60 * 60; // Seconds in a week
const givenDateInSeconds = unixTimestamp; // Assuming input is in seconds
const currentDateInSeconds = Math.floor(Date.now() / 1000); // Get current time in seconds
return (currentDateInSeconds - givenDateInSeconds) > oneWeekInSeconds;
}
function isAMonthOld(dateString) {
// Get milliseconds in a month (assuming 30 days)
const oneMonth = 30 * 24 * 60 * 60 * 1000;
// Use similar logic as in isAWeekOld
const givenDate = new Date(dateString);
const currentDate = new Date();
return (currentDate - givenDate) > oneMonth;
}
function isMoreThanXHoursOldUnix(unixTimestamp, hours) {
const secondsPerHour = 60 * 60; // Calculate seconds in one hour
const currentTimestamp = Math.floor(Date.now() / 1000); // Get current Unix timestamp in seconds
const timeDifference = currentTimestamp - unixTimestamp; // Get time difference in seconds
return timeDifference > hours * secondsPerHour; // Check if it exceeds the threshold
}
function ShowProcessing(mode)
{
var email = localStorage.getItem("email");
// switch to processing UI
// hide formcontainer
$('#Form-container').hide();
// hide waitlistcontainer
$('#waitlist-container').hide();
// hide learn more
$('#learn-more-container').hide();
// hide invite launcher
$('#invite-launcher').hide();
// show processing containter
// add email to processing email field
$('#CheckStatusAddress').text(email);
$('#processing-container').show();
// hide background video
$('.background-video').hide();
$('.background-video-agency').hide();
// hide buttons
$('#button-box').hide();
// add email to localstorage
localStorage.setItem("email", email);
localStorage.setItem("processStatus", mode);
switch(mode)
{
case "processing":
case "updating":
case "processing/updating":
// uses the default content
$('#UpdateStatusTextH1').text("AI Profile is still " + mode);
$('#UpdateStatusTextP1').text("Estimated time: 3 minutes");
$('#UpdateStatusTextP2').text("We will email you when it is ready at " + email);
$('#CheckStatusAddress').text(email);
// show check status button
// hide retry button
$('#btnCheckStatus').show();
$('#btnRetry').hide();
// hide cancel button
$('#btnCancel').hide();
break;
case "failed":
// hide check status button
$('#btnCheckStatus').hide();
$('#btnRetry').show();
$('#btnCancel').show();
// display message and use try again button
$('#UpdateStatusTextH1').text("AI Profile " + mode);
$('#UpdateStatusTextP1').text("Your profile encountered a problem and did not complete.");
$('#UpdateStatusTextP2').text("Would you like to try again?");
$('#CheckStatusAddress').text("");
// think we need to set the click listener on btnRetry
var btnRetry = document.getElementById("btnRetry");
btnRetry.removeEventListener('click', Retry);
btnRetry.addEventListener('click', Retry);
var btnCancel = document.getElementById("btnCancel");
btnCancel.removeEventListener('click', Cancel);
btnCancel.addEventListener('click', Cancel);
break;
}
}
function HideProcessing(mode)
{
switch(mode)
{
case "loggedOut":
break;
case "loggedIn":
// hide formcontainer
$('#Form-container').hide();
// hide waitlistcontainer
$('#waitlist-container').hide();
// hide learn more
$('#learn-more-container').hide();
// hide invite launcher
$('#invite-launcher').hide();
// hide processing containter
$('#processing-container').hide();
// hide background video
$('.background-video').hide();
$('.background-video-agency').hide();
$('#hero-holder').show();
$('.hcv-container').show();
$('#background-image-hero').show();
// hide buttons
$('#button-box').hide();
break;
}
}
function Cancel()
{
// use profile that was returned by failed - if present
var profileStored = localStorage.getItem("profile");
// load original profile
if(profileStored && (profileStored != "" && profileStored != "\"\""))
{
HideProcessing("loggedIn");
ShowPreLoad();
LoadExistingProfile(profileStored);
HidePreLoad();
HideProcessing("loggedIn"); // called again to hide background video (that is shown by hidepreload)
ProcessingRequestShowUX();
firstLoad();
// show navbar buttons
ShowNavButtons();
// update server to completed
var storedMemberID = localStorage.getItem("memberID");
var storedAuthToken = localStorage.getItem("auth_token");
UpdateDBField(storedMemberID, storedAuthToken, "processStatus", "complete")
.then(message => {
// dont parse as UpdateDBField only returns the message
switch(message)
{
case "FieldUpdate Complete":
ConsoleLog("task cancelled");
break;
case "FieldUpdate Failed":
ConsoleLog("task cancellation failed");
break;
}
})
.catch(error => console.error("Error calling UpdateDBField: ", error));
/*switch(cancelUpdate)
{
case "no update message returned":
case "no update message returned":
break;
}*/
//
}
else
{
// if there is no profile
// need to allow new search
NewSearch();
ShowNavButtons();
}
}
function Retry()
{
try
{
// send email back to server to do retry
// NEXT: where do i get email from
var email = localStorage.getItem("email");
// replace with memberID delivered by checkstatus
var memberID = localStorage.getItem("memberID");
var auth_token = localStorage.getItem("auth_token");
// make sure it sends to login if these arent present
var MYPEAS_payload = {};
MYPEAS_payload["promptDescription"] = "retry";
MYPEAS_payload["memberID"] = memberID;
MYPEAS_payload["auth_token"] = auth_token;
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
requestData["RetryObj"] = {};
//requestData["RetryObj"]["email"] = email;
requestData["RetryObj"]["memberID"] = memberID;
requestData["RetryObj"]["auth_token"] = auth_token;
localStorage.setItem("processStatus", "processing/updating");
var processStatus = "processing/updating";
// set page to show processing or updating UI
// uses the default content
$('#UpdateStatusTextH1').text("AI Profile is " + processStatus);
$('#UpdateStatusTextP1').text("Estimated time: 3 minutes");
$('#UpdateStatusTextP2').text("We will email you when it is ready at " + email);
//$('#CheckStatusAddress').text(email);
// show check status button
// hide retry button
$('#btnCheckStatus').show();
$('#btnRetry').hide();
// hide cancel button
$('#btnCancel').hide();
// trigger timer
attempts = 0;
startCheckStatusIntervals();
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
// we won't wait for this
});
}
catch(err)
{
console.error('Error:', err.message);
console.error('Stacktrace:', err.stack);
}
}
function NewSearch()
{
// show hero image
// hide background video
$('.background-video').hide();
$('.background-video-agency').hide();
$('#hero-holder').show();
$('.hcv-container').show();
$('#background-image-hero').show();
// hide waitlist container
$('#waitlist-container').hide();
// hide invite launcher
$('#invite-launcher').hide();
// hide processing containter
$('#processing-container').hide();
// hide email and password fields, but pre-fill
var email = localStorage.getItem("email");
$('#email-submit').hide();
$('#email-submit').val(email);
$('#password').hide();
$('#password').val('');
// hide consent checkbox, but pre-check
$('#checkbox-email').hide(); // this is the label that holds it
$("#checkbox_email").prop("checked", true); // this makes the underlying checkbox checked
// hide buttons
$('#button-box').hide();
// generate button event
// hide sign up job generate button
$('#btnGetJob').hide();
// show new search generate button
$('#btnGetJob_NewSearch').show();
$('#Form-container').show();
$('#learn-more-container').hide();
$('#segments-and-activities').hide();
// i think this works as is, but we need to test
}
//function UpdateDBField(email, password, fieldName, fieldValue)
async function UpdateDBField(memberID, authToken, fieldName, fieldValue)
{
try {
// request profile
var UpdateValue = {};
//UpdateValue["email"] = email; // get from storage
//UpdateValue["password"] = password; // get from storage
UpdateValue["memberID"] = memberID;
UpdateValue["auth_token"] = authToken;
UpdateValue["fieldName"] = fieldName;
UpdateValue["fieldValue"] = fieldValue;
const requestData = {};
requestData["UpdateValue"] = UpdateValue;
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
const response = await fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
});
const result = await response.json();
ConsoleLog("update return: ",JSON.stringify(result));
return result["message"];
}
catch (error) {
console.error("Error calling UpdateDBField:", error);
// You can log the error and return a specific message here (optional)
return "Error updating account information";
}
}
function LogOut()
{
ConsoleLog('log out called');
// change the login/logout button
// clear cookies
clearCookies();
// delete all localstorage items
localStorage.clear();
// go back to homescreen
if (window.location.href.toLowerCase().includes('/agency'))
{
location.href = "/agency";
}
else if(window.location.href.toLowerCase().includes('/admin'))
{
location.href = "/admin";
}
else
{
location.href = "/";
}
}
function clearCookies() {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
const equalIndex = cookie.indexOf('=');
const name = equalIndex > -1 ? cookie.substr(0, equalIndex) : cookie;
document.cookie = name + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/';
}
}
function LogIn()
{
// trigger login modal
OpenCloseLoginModal("open");
// send email and password
// on return
// set profile in localstorage
}
function SubmitLogin(email, password)
{
var failed = false;
var validateEmail = document.getElementById('validateLoginEmail');
var validatePassword = document.getElementById('validateLoginPassword');
var validationMessages = [];
// hide all validation messages
validateEmail.style.display = 'none';
validateEmail.style.color = 'red';
validatePassword.style.display = 'none';
validatePassword.style.color = 'red';
// validate loging fields
if(!isValidEmail(email))
{
failed = true;
validateEmail.textContent = "Please enter a valid email";
validateEmail.style.display = 'block';
validationMessages.push(validateEmail.id);
}
//if(!isValidPassword(password))
if(!(password.length >= 8))
{
failed = true;
validatePassword.textContent = "Please enter a valid password";
validatePassword.style.display = 'block';
validationMessages.push(validatePassword.id);
}
if(!failed)
{
// clear localstorage
localStorage.clear();
// show loading
$('#login-modal #login-loading').show();
$('#login-modal #btnSubmitLogin').hide();
// submit to server
// request profile
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = "";
MYPEAS_payload["JobDescription"] = "";
MYPEAS_payload["promptDescription"] = "Login";
MYPEAS_payload["registered"] = "true"; // should always be true now that user provides password at start page
MYPEAS_payload["email"] = email; // get from storage
MYPEAS_payload["password"] = password; // get from storage
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
// empty storage
localStorage.clear();
// hide loading
$('#login-modal #login-loading').hide();
$('#login-modal #btnSubmitLogin').show();
ConsoleLog("Login return: ",JSON.stringify(result));
/*return {
statusCode: 200,
body: JSON.stringify({"message": "Profile Found", "promptDescription": promptDescription, "profile": checkUserObj["profile"], "processStatus": checkUserObj["processStatus"]}),
}; */
// successful validation
if(result.hasOwnProperty("profile"))
{
// show the nav buttons
var btnMyAccount = document.getElementById('btnMyAccount');
var btnMyFavourites = document.getElementById("btnFavourites");
var btnTools = document.getElementById("btnTools");
var btnLogInOut = document.getElementById("btnLogInOut");
var btnAgency = document.getElementById("btnAgency");
var containerWaitList = document.getElementById('waitlist-container');
var skipContainer = document.getElementById('skipwaitlist-container');
$(btnMyAccount).show();
$(btnMyFavourites).show();
$(btnTools).show();
$(btnLogInOut).show();
$(btnAgency).hide();
$(btnLogInOut).text("Log Out");
$(containerWaitList).hide();
$(skipContainer).hide();
ConsoleLog("1");
// add email to localstorage
localStorage.setItem("email", email);
// hide linkedin modal
var processStatus = result["processStatus"];
switch(processStatus)
{
case "complete":
case "completed":
ConsoleLog("2");
// check not empty profile
var profile = result.profile;
if(profile || (profile !== "" && profile !== "\"\""))
{
// hide learn more
$('#learn-more-container').hide();
if(profile == "")
{
HideProcessing("loggedIn");
NewSearch();
ShowNavButtons();
}
if(profile != "")
{
// if completed and not empty - load profile in UI
profile = result["profile"];
var favourites = result["favourites"] || JSON.stringify([]);
var memberID = result["memberID"];
var authToken = result["auth_token"];
var auth_token_date_created = result["auth_token_date_created"];
var accountInfo = result["accountInfo"] || JSON.stringify({});
var orderHistory = result["orderHistory"] || JSON.stringify([]);
var StripeInvoices = result["StripeInvoices"] || JSON.stringify([]);
var revisions = result["revisions"] || "0";
var optIn = result["optIn"] !== undefined ? result["optIn"] : true;
var paidAccount = result["paidAccount"] !== undefined ? result["paidAccount"] : "false";
if(paidAccount !== undefined)
{
localStorage.setItem("paidAccount", paidAccount);
}
else
{
localStorage.setItem("paidAccount", "false");
}
if(optIn !== undefined)
{
// set optin in localstorage
localStorage.setItem("optIn", optIn);
}
else
{
localStorage.setItem("optIn", "true");
}
if(accountInfo == "")
{
accountInfo = JSON.stringify({});
}
if(orderHistory == "")
{
orderHistory = JSON.stringify([]);
}
HideProcessing("loggedIn");
// set profile in localstorage
localStorage.setItem("profile", JSON.stringify(profile));
localStorage.setItem("favourites", favourites);
// set memberID
localStorage.setItem("memberID", memberID);
// set auth_token
localStorage.setItem("auth_token", authToken);
localStorage.setItem("auth_token_date_created", auth_token_date_created);
localStorage.setItem("processStatus", "complete");
localStorage.setItem("accountInfo", accountInfo);
localStorage.setItem("orderHistory", orderHistory);
localStorage.setItem("StripeInvoices", StripeInvoices);
localStorage.setItem("revisions", revisions);
// load profile in UI - look into making this all work cleanly
ConsoleLog("call LoadExistingProfile");
LoadExistingProfile(profile);
// close modal
OpenCloseLoginModal("close");
// we want to prompt user to complete details if missing from account
// check accountInfo - this checks if accountinfo is complete
accountInfo = JSON.parse(accountInfo);
if(!checkAccountInfo(accountInfo))
{
/*OpenAccountModal();
// show red text saying enter missing information
$('#modal-message-account').text("** Complete Your Account Information **").show();*/
OpenOnboardModal();
}
firstLoad();
}
}
else
{
OpenCloseLoginModal("close");
HideProcessing("loggedIn");
NewSearch();
ShowNavButtons();
}
break;
case "failed":
// if failed - show retry
// create a function for this
//var revertProfile = result["RevertProfile"];
// or revert option if profile is present
// if user chooses cancel then we just use the profile returned (the original profile)
var profile = result["profile"];
var favourites = result["favourites"] || JSON.stringify([]);
var memberID = result["memberID"];
var authToken = result["auth_token"];
var auth_token_date_created = result["auth_token_date_created"];
var accountInfo = result["accountInfo"] || JSON.stringify({});
var orderHistory = result["orderHistory"] || JSON.stringify([]);
var StripeInvoices = result["StripeInvoices"] || JSON.stringify([]);
var revisions = result["revisions"] || "0";
var optIn = result["optIn"] !== undefined ? result["optIn"] : true;
var paidAccount = result["paidAccount"] !== undefined ? result["paidAccount"] : "false";
if(paidAccount !== undefined)
{
localStorage.setItem("paidAccount", paidAccount);
}
else
{
localStorage.setItem("paidAccount", "false");
}
if(optIn !== undefined)
{
// set optin in localstorage
localStorage.setItem("optIn", optIn);
}
else
{
localStorage.setItem("optIn", "true");
}
if(accountInfo == "")
{
accountInfo = JSON.stringify({});
}
if(orderHistory == "")
{
orderHistory = JSON.stringify([]);
}
HideProcessing("loggedIn");
// set profile in localstorage
localStorage.setItem("profile", JSON.stringify(profile));
localStorage.setItem("favourites", favourites);
// set memberID
localStorage.setItem("memberID", memberID);
// set auth_token
localStorage.setItem("auth_token", authToken);
localStorage.setItem("auth_token_date_created", auth_token_date_created);
localStorage.setItem("processStatus", "failed");
localStorage.setItem("accountInfo", accountInfo);
localStorage.setItem("orderHistory", orderHistory);
localStorage.setItem("StripeInvoices", StripeInvoices);
localStorage.setItem("revisions", revisions);
ShowProcessing(processStatus);
// close modal
OpenCloseLoginModal("close");
// we want to prompt user to complete details if missing from account
// check accountInfo - this checks if accountinfo is complete
// add breakpoints and refresh page
break;
case "processing":
case "updating":
case "processing/updating":
var profile = result["profile"];
var favourites = result["favourites"] || JSON.stringify([]);
var memberID = result["memberID"];
var authToken = result["auth_token"];
var auth_token_date_created = result["auth_token_date_created"];
var optIn = result["optIn"] !== undefined ? result["optIn"] : true;
var paidAccount = result["paidAccount"] !== undefined ? result["paidAccount"] : "false";
if(paidAccount !== undefined)
{
localStorage.setItem("paidAccount", paidAccount);
}
else
{
localStorage.setItem("paidAccount", "false");
}
if(optIn !== undefined)
{
// set optin in localstorage
localStorage.setItem("optIn", optIn);
}
else
{
localStorage.setItem("optIn", "true");
}
localStorage.setItem("profile", JSON.stringify(profile));
localStorage.setItem("favourites", favourites);
// set memberID
localStorage.setItem("memberID", memberID);
// set auth_token
localStorage.setItem("auth_token", authToken);
localStorage.setItem("auth_token_date_created", auth_token_date_created);
localStorage.setItem("processStatus", processStatus);
// if processing
ShowProcessing(processStatus);
// close modal
OpenCloseLoginModal("close");
break;
}
}
// validation failed
if(!result.hasOwnProperty("profile"))
{
/*// fail to validate - tell user to login
return {
statusCode: 200,
body: JSON.stringify({"message": "Account Exists. Wrong Password Entered", "promptDescription": promptDescription}),
};
}*/
var message = result["message"];
if(message == "Account Exists. Wrong Password Entered")
{
validationMessages = [];
failed = true;
validatePassword.textContent = "Wrong Password Entered";
validatePassword.style.display = 'block';
validationMessages.push(validatePassword.id);
}
if(message == "Account Does Not Exist")
{
validationMessages = [];
failed = true;
validateEmail.textContent = "Please check account details";
validateEmail.style.display = 'block';
validationMessages.push(validatePassword.id);
}
}
});
}
if(failed)
{
// scroll to first error
$('html, body').animate({
scrollTop: $('#' + validationMessages[0]).offset().top - 50
}, 500);
}
}
function SubmitLogin_Agency(email, password)
{
var failed = false;
var validateEmail = document.getElementById('validateLoginEmail');
var validatePassword = document.getElementById('validateLoginPassword');
var validationMessages = [];
// hide all validation messages
validateEmail.style.display = 'none';
validateEmail.style.color = 'red';
validatePassword.style.display = 'none';
validatePassword.style.color = 'red';
// validate loging fields
if(!isValidEmail(email))
{
failed = true;
validateEmail.textContent = "Please enter a valid email";
validateEmail.style.display = 'block';
validationMessages.push(validateEmail.id);
}
//if(!isValidPassword(password))
if(!(password.length >= 8))
{
failed = true;
validatePassword.textContent = "Please enter a valid password";
validatePassword.style.display = 'block';
validationMessages.push(validatePassword.id);
}
if(!failed)
{
// clear localstorage
localStorage.clear();
// show loading
$('#login-modal #modal-spinner').show();
$('#login-modal #login-loading').show();
$('#login-modal #btnSubmitLogin').hide();
// submit to server
// request profile
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = "";
MYPEAS_payload["JobDescription"] = "";
MYPEAS_payload["requestDescription"] = "Login";
MYPEAS_payload["registered"] = "true"; // should always be true now that user provides password at start page
MYPEAS_payload["email"] = email; // get from storage
MYPEAS_payload["password"] = password; // get from storage
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
// empty storage
localStorage.clear();
// hide loading
$('#login-modal #modal-spinner').hide();
$('#login-modal #login-loading').hide();
$('#login-modal #btnSubmitLogin').show();
ConsoleLog("Login return: ",JSON.stringify(result));
/*return {
statusCode: 200,
body: JSON.stringify({"message": "Profile Found", "promptDescription": promptDescription, "profile": checkUserObj["profile"], "processStatus": checkUserObj["processStatus"]}),
}; */
// successful validation
if(result.hasOwnProperty("memberID"))
{
// show the nav buttons
var btnMyAccount = document.getElementById('btnMyAccount');
var btnLogInOut = document.getElementById("btnLogInOut");
var btnAgency = document.getElementById("btnAgency");
$(btnMyAccount).show();
$(btnLogInOut).show();
$(btnAgency).hide();
$(btnLogInOut).text("Log Out");
ConsoleLog("1");
// add email to localstorage
localStorage.setItem("email", email);
var message = result["message"];
switch(message)
{
case "Profile Found":
case "User Validated":
ConsoleLog("2");
// if completed and not empty - load profile in UI
var memberID = result["memberID"];
var authToken = result["auth_token"];
var auth_token_date_created = result["auth_token_date_created"];
var accountInfo = result["accountInfo"] || JSON.stringify({});
var orderHistory = result["orderHistory"] || JSON.stringify([]);
var StripeInvoices = result["StripeInvoices"] || JSON.stringify([]);
var bookingHistory = result["bookingHistory"] || JSON.stringify([]);
var credits = result["credits"] || "0";
// this is the request sent to users for a booking to be made
var requests = result["requests"];
var optIn = result["optIn"] !== undefined ? result["optIn"] : true;
if(optIn !== undefined)
{
// set optin in localstorage
localStorage.setItem("optIn", optIn);
}
else
{
localStorage.setItem("optIn", "true");
}
if(accountInfo == "")
{
accountInfo = JSON.stringify({});
}
var ApprovedStatus = accountInfo["ApprovedStatus"];
if(orderHistory == "")
{
orderHistory = JSON.stringify([]);
}
if(bookingHistory == "")
{
bookingHistory = JSON.stringify([]);
}
HideProcessing("loggedIn");
// set memberID
localStorage.setItem("memberID", memberID);
localStorage.setItem("agencyMember", true);
// set auth_token
localStorage.setItem("auth_token", authToken);
localStorage.setItem("auth_token_date_created", auth_token_date_created);
localStorage.setItem("accountInfo", accountInfo);
localStorage.setItem("orderHistory", orderHistory);
localStorage.setItem("StripeInvoices", StripeInvoices);
localStorage.setItem("bookingHistory", bookingHistory);
localStorage.setItem("credits", credits);
localStorage.setItem("requests", requests);
// load agency member profile in UI
LoadAgencyAccount(accountInfo, result);
// close modal
OpenCloseLoginModal("close");
// hide background video - show hero image
$('.background-video').hide();
$('.background-video-agency').hide();
// check for calendly link
if (typeof accountInfo === 'string')
{
try
{
accountInfo = JSON.parse(accountInfo);
}
catch (error)
{
console.error("Error parsing JSON property:", error);
}
}
var calendarLink = accountInfo["bookingLink"];
var calendarPresent = false;
if(calendarLink && calendarLink != "")
{
calendarPresent = true;
}
if(!calendarPresent)
{
// prompt user to add calendar and open modal
OpenCalendarModal();
}
break;
case "Account Exists. Wrong Password Entered":
validationMessages = [];
failed = true;
validatePassword.textContent = "Wrong Password Entered";
validatePassword.style.display = 'block';
validationMessages.push(validatePassword.id);
break;
case "Account Does Not Exist":
failed = true;
validateEmail.textContent = "Please check account details";
validateEmail.style.display = 'block';
validationMessages.push(validatePassword.id);
localStorage.clear();
break;
}
}
// validation failed
if(!result.hasOwnProperty("memberID"))
{
/*// fail to validate - tell user to login
return {
statusCode: 200,
body: JSON.stringify({"message": "Account Exists. Wrong Password Entered", "promptDescription": promptDescription}),
};
}*/
var message = result["message"];
if(message == "Account Exists. Wrong Password Entered")
{
validationMessages = [];
failed = true;
validatePassword.textContent = "Wrong Password Entered";
validatePassword.style.display = 'block';
validationMessages.push(validatePassword.id);
}
}
});
}
if(failed)
{
// scroll to first error
$('html, body').animate({
scrollTop: $('#' + validationMessages[0]).offset().top - 50
}, 500);
}
}
function SubmitLogin_Admin(email, password)
{
var failed = false;
var validateEmail = document.getElementById('validateLoginEmail');
var validatePassword = document.getElementById('validateLoginPassword');
var validationMessages = [];
// hide all validation messages
validateEmail.style.display = 'none';
validateEmail.style.color = 'red';
validatePassword.style.display = 'none';
validatePassword.style.color = 'red';
// validate loging fields
if(!isValidEmail(email))
{
failed = true;
validateEmail.textContent = "Please enter a valid email";
validateEmail.style.display = 'block';
validationMessages.push(validateEmail.id);
}
//if(!isValidPassword(password))
if(!(password.length >= 8))
{
failed = true;
validatePassword.textContent = "Please enter a valid password";
validatePassword.style.display = 'block';
validationMessages.push(validatePassword.id);
}
if(!failed)
{
// clear localstorage
localStorage.clear();
// show loading
$('#login-modal #login-loading').show();
$('#login-modal #btnSubmitLogin').hide();
// submit to server
// request profile
var MYPEAS_payload = {};
MYPEAS_payload["requestDescription"] = "LoginAdmin";
MYPEAS_payload["email"] = email; // get from storage
MYPEAS_payload["password"] = password; // get from storage
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
// empty storage
localStorage.clear();
ConsoleLog("LoginAdmin return: ",JSON.stringify(result));
// hide loading
$('#login-modal #login-loading').hide();
$('#login-modal #btnSubmitLogin').show();
ConsoleLog("1");
// add email to localstorage
localStorage.setItem("email", email);
var processStatus = result["message"];
switch(processStatus)
{
case "validated":
// if validated it returns the agency info for approvals
var memberID = result["memberID"];
var authToken = result["auth_token"];
var auth_token_date_created = result["auth_token_date_created"];
var approvalsData = result["approvalData"];
// set memberID
localStorage.setItem("memberID", memberID);
// set auth_token
localStorage.setItem("auth_token", authToken);
localStorage.setItem("auth_token_date_created", auth_token_date_created);
localStorage.setItem("adminMember", "true");
// show the nav buttons
var btnLogInOut = document.getElementById("btnLogInOut");
var btnAgency = document.getElementById("btnAgency");
var containerWaitList = document.getElementById('waitlist-container');
var skipContainer = document.getElementById('skipwaitlist-container');
var promptLogin = document.getElementById('admin-prompt-login');
var codeGeneratorContainer = document.getElementById('admin-account-code-generator');
var sendRecruitAgencyContainer = document.getElementById("admin-account-send-email");
$(btnLogInOut).show();
$(btnAgency).hide();
$(btnLogInOut).text("Log Out");
$(containerWaitList).hide();
$(skipContainer).hide();
$(codeGeneratorContainer).show();
$(sendRecruitAgencyContainer).show();
// populate the cards
// load approvals
LoadApprovals(approvalsData);
// close modal
OpenCloseLoginModal("close");
// hide prompt login
$(promptLogin).hide();
removeParam("login");
break;
case "rejected":
case "notauthenticated":
case "failed":
// require login
// clear local storage and cookies
localStorage.clear();
// can't delete the cookies, so set their values to expired. so we force UX to require new login
// redirect to home page
location.href = '/admin?login=true';
break;
}
});
}
if(failed)
{
// scroll to first error
$('html, body').animate({
scrollTop: $('#' + validationMessages[0]).offset().top - 50
}, 500);
}
}
function checkAccountInfo(accountInfo)
{
var accountComplete = true;
if(!accountInfo.hasOwnProperty("firstname") || (accountInfo.hasOwnProperty("firstname") && accountInfo["firstname"] == ""))
{
accountComplete = false;
}
if(!accountInfo.hasOwnProperty("surname") || (accountInfo.hasOwnProperty("surname") && accountInfo["surname"] == ""))
{
accountComplete = false;
}
if(!accountInfo.hasOwnProperty("location") || (accountInfo.hasOwnProperty("location") && !accountInfo["location"].hasOwnProperty("locationName")))
{
accountComplete = false;
}
// add an extra so that old users can see the new onboarding experience
if(!accountInfo.hasOwnProperty("onboard"))
{
accountComplete = false;
}
return accountComplete;
}
/*
Admin page js
*/
function RequestAdmin()
{
var storedMemberID = localStorage.getItem("memberID");
var storedAuthToken = localStorage.getItem("auth_token");
var btnLogInOut = document.getElementById("btnLogInOut");
var btnAgency = document.getElementById("btnAgency");
var containerWaitList = document.getElementById('waitlist-container');
var skipContainer = document.getElementById('skipwaitlist-container');
var promptLogin = document.getElementById('admin-prompt-login');
var codeGeneratorContainer = document.getElementById('admin-account-code-generator');
var sendRecruitAgencyContainer = document.getElementById("admin-account-send-email");
// request profile
var MYPEAS_payload = {};
MYPEAS_payload["requestDescription"] = "RequestAdmin";
MYPEAS_payload["memberID"] = storedMemberID; // get from storage
MYPEAS_payload["auth_token"] = storedAuthToken; // get from storage
MYPEAS_payload["ApprovalsFlag"] = {};
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("processStatus return: ",JSON.stringify(result));
var processStatus = result["message"];
switch(processStatus)
{
case "validated":
// if validated it returns the agency info for approvals
var memberID = result["memberID"];
var authToken = result["auth_token"];
var auth_token_date_created = result["auth_token_date_created"];
var approvalsData = result["approvalData"];
// set memberID
localStorage.setItem("memberID", memberID);
// set auth_token
localStorage.setItem("auth_token", authToken);
localStorage.setItem("auth_token_date_created", auth_token_date_created);
localStorage.setItem("adminMember", "true");
$(btnLogInOut).show();
$(btnAgency).hide();
$(btnLogInOut).text("Log Out");
$(containerWaitList).hide();
$(skipContainer).hide();
$(codeGeneratorContainer).show();
$(sendRecruitAgencyContainer).show();
// populate the cards
// load approvals
LoadApprovals(approvalsData);
// close modal
OpenCloseLoginModal("close");
// hide prompt login
$(promptLogin).hide();
break;
case "rejected":
case "notauthenticated":
case "failed":
// require login
// clear local storage and cookies
localStorage.clear();
// can't delete the cookies, so set their values to expired. so we force UX to require new login
// redirect to home page
location.href = '/admin?login=true';
break;
}
});
}
function LoadApprovals(approvalData)
{
const container = document.getElementById('dashboard-info-container');
container.innerHTML = ''; // Clear the container before appending new data
if (approvalData.length === 0) {
const noApprovalsMessage = document.createElement('div');
noApprovalsMessage.className = 'no-approvals-message';
noApprovalsMessage.innerText = 'No approvals at this time';
container.appendChild(noApprovalsMessage);
}
approvalData.forEach(approval => {
approval = JSON.parse(approval["accountInfo"]["S"]);
const card = document.createElement('div');
card.className = 'approval-card';
const companyName = approval.CompanyName;
const websiteUrl = `https://${approval.WorkEmail.split('@')[1]}`;
const contactNo = `${approval.TelephoneCode}${approval.TelephoneNo}`;
const workEmail = approval.WorkEmail;
card.innerHTML = `
${companyName}
${websiteUrl}
Contact No: ${contactNo}
Email: ${workEmail}
Approval Status: ${approval.ApprovedStatus}
`;
break;
case "InviteSent":
`
Reject
`;
break;
case "processing":
card.innerHTML = card.innerHTML +
/*`Sent YCBM invite */
`Approve
Reject
`;
break;
}
container.appendChild(card);
});
$('.admin-account-info-holder').show();
}
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(() => {
alert('Copied to clipboard');
}).catch(err => {
console.error('Could not copy text: ', err);
});
}
function confirmInvite(memberID, email, button) {
// Also add flag to agency account
var MYPEAS_payload = {};
MYPEAS_payload["requestDescription"] = "InviteSent";
MYPEAS_payload["InviteFlag"] = {};
// add agency data
MYPEAS_payload["agencyMemberID"] = memberID; // get from storage
MYPEAS_payload["agencyEmail"] = email; // get from storage
MYPEAS_payload["ApprovedStatus"] = "InviteSent";
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("message return: ",JSON.stringify(result));
var message = result["message"];
switch(message)
{
case "Completed":
OpenModal("Success", "Invite Confirmed: Agency account updated", false);
button.nextSibling.nextSibling.disabled = false; // Enable the "Approve" button
break;
case "failed":
OpenModal("Failed", "Not Confirmed: Agency account NOT updated", false);
break;
}
});
}
var ClickListener;
function LoadApprovalModal(callingElement, memberID, approvedStatus)
{
// uncheck the validation boxes
var approvalModal = document.querySelector("#approve-modal");
const checkboxes = approvalModal.querySelectorAll('input[type="checkbox"]');
checkboxes.forEach(checkbox => {
checkbox.checked = false;
});
// set the clickevent on the approvebtn
const ApproveBtn = document.querySelector('#ApproveBtn');
if(ClickListener)
{
ApproveBtn.removeEventListener('click', ClickListener);
}
ClickListener = () => { ApproveAgency(callingElement, memberID, approvedStatus)};
ApproveBtn.addEventListener('click', ClickListener);
// open modal
OpenApprovalModal();
}
function OpenApprovalModal()
{
$('#approve-modal').animate({ opacity: 1 }).show();
}
function CloseApprovalModal()
{
$('#approve-modal').animate({ opacity: 0 }).hide();
unLockScroll();
}
function areAllCheckboxesChecked() {
const calendarCheck = document.getElementById("calendarCheck").checked;
const removeCalendarCheck = document.getElementById("removeCalendarCheck").checked;
const zoomCheck = document.getElementById("zoomCheck").checked;
const bookingPageCheck = document.getElementById("bookingPageCheck").checked;
return calendarCheck && removeCalendarCheck && zoomCheck && bookingPageCheck;
}
function ApproveAgency(callingElement, memberID, approvedStatus) {
// validate checkboxes before send
/*if (areAllCheckboxesChecked())
{*/
ConsoleLog("All checkboxes are checked!");
// disable element until call back from server
callingElement.prop('disabled', true);
// change updating message
callingElement.parent().find('#UpdatingStatus').text("Updating Status on server");
var storedMemberID = localStorage.getItem("memberID");
var storedAuthToken = localStorage.getItem("auth_token");
// request profile
var MYPEAS_payload = {};
MYPEAS_payload["requestDescription"] = "ApproveAccount";
MYPEAS_payload["memberID"] = storedMemberID; // get from storage
MYPEAS_payload["auth_token"] = storedAuthToken; // get from storage
MYPEAS_payload["ApprovalsFlag"] = {};
// add agency data
MYPEAS_payload["agencyMemberID"] = memberID; // get from storage
MYPEAS_payload["ApprovedStatus"] = approvedStatus;
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("message return: ",JSON.stringify(result));
var processStatus = result["message"];
switch(processStatus)
{
case "Completed":
// if validated it returns the agency info for approvals
// change updating message
callingElement.parent().find('#UpdatingStatus').text("Completed");
break;
case "failed":
// change updating message
callingElement.parent().find('#UpdatingStatus').text("Fadiled Status update");
break;
}
});
// Your logic to approve the agency
ConsoleLog(`Agency with memberID ${memberID} approved`);
/* }
else
{
ConsoleLog("Not all checkboxes are checked.");
window.alert("Not all checkboxes are checked.");
// ... your code to handle the unchecked state (e.g., display an error message)
}*/
}
// Example approval data for testing
/*
const approvalData = [
{
CompanyName: "Example Corp",
WorkEmail: "contact@example.com",
TelephoneCode: "+1",
TelephoneNo: "1234567890",
bookingLink: "https://example.com/booking",
memberID: "12345"
},
// Add more data objects as needed
];
LoadApprovals(approvalData);*/
/*
END Admin page
*/
function BuyPaidCredits()
{
}
// add to order confirmation page
// use fetch to update the server
function OpenModal_OrderConfirmation(Title, Message, isLoading)
{
switch(isLoading)
{
case true:
// hide close button
$('#loading-update-modal .close-btn-w').hide();
$('#loading-update-modal #modal-spinner').show();
break;
case false:
$('#loading-update-modal .close-btn-w').show();
$('#loading-update-modal #modal-spinner').hide();
break;
}
// set title text
$('#loading-update-modal #modal-title').text(Title);
// set message text
$('#loading-update-modal #modal-message').text(Message);
// animate and show
$('#loading-update-modal ').animate({ opacity: 1 }).show();
}
function CloseModal_OrderConfirmation()
{
// close the modal using the close button
$('#loading-update-modal .close-btn-w').click(function(){
/*$('.modal-popup').each(function() {
if ($(this).is(':visible')) {
$(this).animate({ opacity: 0 }).hide();
unLockScroll();
}
});*/
$('#loading-update-modal').animate({ opacity: 0 }).hide();
unLockScroll();
});
// add it first, then call it
$('#loading-update-modal .close-btn-w').click();
}
function OpenNewSearchDialog()
{
//$('#new-search-holder').animate({ opacity: 1 }).show();
var newSearchHolder = document.querySelector('#new-search-holder');
// empty ui
var addResponsibilitiesContainter = newSearchHolder.querySelector('#add-repsonsibilities-container');
if(addResponsibilitiesContainter)
{
addResponsibilitiesContainter.innerHTML = '';
}
var responsibilitiesContainter = newSearchHolder.querySelector('#responsibilities');
var AI_responsibilitiesContainter = newSearchHolder.querySelector('#ai-responsibilities');
/*if(responsibilitiesContainter)
{
responsibilitiesContainter.innerHTML = '';
}*/
if(AI_responsibilitiesContainter)
{
AI_responsibilitiesContainter.innerHTML = '';
}
// clear this of values - decided against that. keep them
//selectedResponsibilities = [];
// reset to the first step
newSearchHolder.querySelectorAll(".wizard-step").forEach(step => {
step.style.display = "none";
});
newSearchHolder.querySelector('#step1').style.display = "block";
// trigger modal
$('#new-search-holder').css('z-index', '10001').animate({ opacity: 1 }).show();
// set focus to field
$('#new-search-holder #jobTitle').focus();
}
function CloseModal_New_Search()
{
$('#new-search-holder').animate({ opacity: 0 }).hide();
unLockScroll();
}
function CloseModal_Agency_Account()
{
$('#agency-account-modal').animate({ opacity: 0 }).hide();
unLockScroll();
}
function findCountryTaxes() {
let result = {
full: "",
message: "",
currencySymbol: "",
currencyAbbreviation: "",
amount: ""
};
var countryTaxesContainer = [...document.querySelectorAll('.w-commerce-commercecheckoutordersummaryextraitemslistitem div')]
.find(element => element.textContent.toLowerCase().includes("country taxes".toLowerCase()))?.parentElement;
if (countryTaxesContainer) {
var taxAmountElement = countryTaxesContainer.querySelector('div[data-wf-bindings*="CommercePrice"]');
if (taxAmountElement) {
var taxAmountText = taxAmountElement.textContent.trim();
result.full = taxAmountText;
result.message = "Tax present";
// Attempt to extract the numeric part as a string
let numericPattern = /[\d.,]+/;
let matches = taxAmountText.match(numericPattern);
if (matches) {
result.amount = matches[0];
// Extract non-numeric parts as potential currency symbols or abbreviations
let nonNumericParts = taxAmountText.replace(numericPattern, '').trim();
// Heuristic to guess symbol and abbreviation
let symbolMatch = nonNumericParts.match(/[\D]/);
if (symbolMatch) {
result.currencySymbol = symbolMatch[0];
}
let abbreviationMatch = nonNumericParts.match(/[A-Za-z]{3}/);
if (abbreviationMatch) {
result.currencyAbbreviation = abbreviationMatch[0];
}
}
} else {
result.message = "Tax amount element not found within the country taxes container.";
}
} else {
result.message = "Country Taxes container not found.";
}
return result;
}
// Example usage:
/*var taxDetails = findCountryTaxes();
ConsoleLog(taxDetails);*/
// Initialize an array to hold parts of the address
var addressParts = [];
function StoreInvoiceObject()
{
var invoiceObj = {};
invoiceObj["invoice-client-name"] = $('#invoice-client-name').text() || "";
invoiceObj["invoice-order-number"] = GetParam("orderId") || "";
invoiceObj["OrderID"] = GetParam("orderId") || "";
invoiceObj["invoice-order-date"] = getCurrentDateString();
invoiceObj["invoice-purchase-subtotal"] = $('#invoice-purchase-subtotal').text() || "";
invoiceObj["invoice-purchase-countrytaxes"] = findCountryTaxes() || "";
invoiceObj["invoice-purchase-total"] = $('#invoice-purchase-total').text() || "";
// Add each address part to the array if present
addToAddress('#invoice-address-1');
addToAddress('#invoice-address-2');
addToAddress('#invoice-address-city');
addToAddress('#invoice-address-state');
addToAddress('#invoice-address-postcode');
addToAddress('#invoice-address-country');
// Join the parts with a comma to create a comma-separated string
var addressString = addressParts.join(', ');
invoiceObj["invoice-address"] = addressString;
ConsoleLog(addressString); // Log the address string to the console or use as needed
// itemised billing
// create an array of items in the order, titles, quantities, prices
return invoiceObj;
}
// Function to add text of an element to the addressParts array if it's not empty
function addToAddress(selector)
{
var text = $(selector).text().trim();
if (text)
{
addressParts.push(text);
}
}
function analyseOrder() {
var orderObj = {};
var totalCredits = 0;
var totalOrderType = "";
var itemsArray = [];
$('[id=order-item-holder]').each(function() {
try {
// Extract order information with null/undefined checks
var orderTitle = $(this).find('[id=order-title]').text().trim();
if (orderTitle === "") {
orderTitle = "Unknown Title";
}
var quantityElement = $(this).find('[id=order-quantity]');
var quantity = 0;
if (quantityElement.length > 0) {
quantity = parseInt(quantityElement.text().trim(), 10);
if (isNaN(quantity)) {
quantity = 0;
}
}
// Find order price with null/undefined checks and fallback
var orderPriceText = $(this).closest('.w-commerce-commercecheckoutorderitem').find('.order-price').text().trim();
var orderPriceMatch = orderPriceText.match(/([£$€¥])\s*([\d.,]+)\s*([A-Z]{3})/i);
var orderPriceCurrency = "Unknown";
var orderPriceValue = 0;
var orderPriceCurrencyCode = "Unknown";
if (orderPriceMatch) {
orderPriceCurrency = orderPriceMatch[1];
orderPriceValue = parseFloat(orderPriceMatch[2].replace(/[^\d.]/g, ''));
orderPriceCurrencyCode = orderPriceMatch[3].toUpperCase();
}
// Calculate credits with default for unknown order types
var orderType = "unknown";
var credits = 0;
switch (orderTitle) {
case "AI profile + 2 revisions":
orderType = "employee_profile";
credits = 3;
break;
case "AI profile + 8 revisions":
orderType = "employee_profile";
credits = 9;
break;
case "AI Meeting Accelerator (3 meetings)":
orderType = "agency_meeting_credit";
credits = 3;
break;
case "AI Meeting Accelerator (10 meetings)":
orderType = "agency_meeting_credit";
credits = 10;
break;
default:
console.warn("Unknown order type: " + orderTitle);
}
var orderCredits = quantity * credits;
totalCredits += orderCredits;
// Create item object
var item = {
orderType: orderType,
credits: orderCredits,
orderTitle: orderTitle,
quantity: quantity,
orderPrice: {
currency: orderPriceCurrency,
currencyCode: orderPriceCurrencyCode,
value: orderPriceValue
},
totalPrice: quantity * orderPriceValue
};
itemsArray.push(item);
totalOrderType = orderType;
// Output
ConsoleLog("Order Type:", orderType);
ConsoleLog("Order Credits:", orderCredits);
} catch (error) {
console.error("Error processing order (unexpected):", error);
}
});
ConsoleLog("Total Credits:", totalCredits);
ConsoleLog("Items Array:", itemsArray);
ConsoleLog("Credit Type:", totalOrderType);
orderObj["totalCredits"] = totalCredits;
orderObj["itemsArray"] = itemsArray;
orderObj["creditType"] = totalOrderType;
return orderObj;
}
function PaidAccountUpdate()
{
// take the orderid, store in user account so cant duplicate purchase
var orderId = GetParam("orderId");
// use a modal to block the interface until complete
OpenModal_OrderConfirmation("Confirming Purchase", "Thanks for your purchase. We are adding paid credits to your account.", true);
var PaidUpdateData = {};
// change this. get memberID from localstorage. set this
PaidUpdateData["memberID"] = localStorage.getItem("memberID");
PaidUpdateData["authToken"] = localStorage.getItem("auth_token");
PaidUpdateData["orderID"] = GetParam("orderId");
// NEXT
// write a loop to check through all $('[id=order-title]')
// discern between consumer buying profile credits and agent buying meeting credits
// create a total number of credits for AI Meeting Accelerator based on Quantity in each type
// AI Meeting Accelerator fuels your sales team with qualified AI/automation leads and pre-booked consultations. Target motivated businesses ready to invest in your solutions. Schedule a demo today!
var orderObj = analyseOrder();
/*PaidUpdateData["creditType"] = orderObj["creditType"];
PaidUpdateData["totalCredits"] = orderObj["totalCredits"];*/
// NEXT - add invoice item information from itemsArray
PaidUpdateData["invoiceData"] = StoreInvoiceObject();
// add itemsArray
PaidUpdateData["invoiceData"]["itemsArray"] = orderObj["itemsArray"];
PaidUpdateData["invoiceData"]["creditType"] = orderObj["creditType"];
PaidUpdateData["invoiceData"]["totalCredits"] = orderObj["totalCredits"];
// https://mypeas.ai/?reset-password=yes&OTC=${OTC}&memberID=${memberIDValue}
// url depends on client type
// Make an API call to API gateway
creditType = orderObj["creditType"];
switch(creditType)
{
case "employee_profile":
PaidUpdateData["promptDescription"] = "PaidUpdate";
var requestData = {};
requestData["PaidUpdateData"] = PaidUpdateData;
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("PaidUpdate return: ",JSON.stringify(result));
// create a paid flag, so the profile returned is different if paid
// store the orderId on server to prevent duplicates
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Upgraded to Paid", "promptDescription": promptDescription}), //, "profile": checkUserObj["profile"]
};
*/
switch(result.message)
{
/* UpgradeAccount */
case "Upgraded to Paid":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Upgraded to Paid", "promptDescription": promptDescription, "profile": checkUserObj["profile"], "paidAccount": checkUserObj["paidAccount"], "revisions": checkUserObj["revisions"]}), //, "profile": checkUserObj["profile"]
};
*/
CloseModal_OrderConfirmation();
// update storage
localStorage.setItem("paidAccount", result["paidAccount"]);
ConsoleLog("paid account updated: " + result["paidAccount"]);
// click back to profile
var btnBackToProfile = document.getElementById('btnBackToProfile');
if(btnBackToProfile)
{
btnBackToProfile.click();
}
break;
/* UpgradeAccount */
case "PaidUpdate Failed":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "PaidUpdate Failed"})
};
*/
ConsoleLog("paid account update failed");
function updateRetriesUrl(maxRetries = 5) {
// Get the current URL
const url = new URL(window.location.href);
// Get the current value of the "retries" parameter, or initialize it to 0
let retries = parseInt(url.searchParams.get("retries")) || 0;
// Check if the maximum retries have been reached
if (retries >= maxRetries) {
// Maximum retries reached, handle the error or display a message
// ... (e.g., alert("Maximum retries exceeded. Please try again later."))
return url.toString(); // Return the current URL without further updates
}
// Increment the retry count
retries++;
// Update the "retries" parameter in the URL
url.searchParams.set("retries", retries);
// Return the updated URL
return url.toString();
}
// Example usage:
const updatedUrl = updateRetriesUrl();
// Redirect the browser to the updated URL only if retries are still allowed
if (updatedUrl !== window.location.href) { // Check for changes before redirection
window.location.href = updatedUrl;
}
else
{
// alert user that failed and to contact us to activate your credit
CloseModal_OrderConfirmation();
OpenModal("Problem", "Please contact us at support@mypeas.ai to activate your credit", false, false);
}
// Additional notes:
/* This code uses the `URL` object to parse and manipulate the URL components.
* The `parseInt` function is used to convert the retrieved "retries" value from a string to an integer.
* The `maxRetries` parameter allows you to specify the maximum allowed retry count.
* You can call this function multiple times to increment the retry count further. */
break;
/* UpgradeAccount */
case "Already activated credit":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Already activated credit", "promptDescription": promptDescription, "profile": checkUserObj["profile"], "paidAccount": checkUserObj["paidAccount"], "revisions": checkUserObj["revisions"]}), //, "profile": checkUserObj["profile"]
};
*/
CloseModal_OrderConfirmation();
// give message that this order was already activated
OpenModal("Message", "You have already activated this purchase", false, false);
break;
}
});
break;
case "agency_meeting_credit":
var requestData = {};
PaidUpdateData["promptDescription"] = "AddCredits";
requestData["PaidCreditsData"] = PaidUpdateData;
requestData["MYPEAS_payload"] = {};
requestData["MYPEAS_payload"]["requestDescription"] = "AddCredits";
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("AddCredits return: ",JSON.stringify(result));
// create a paid flag, so the profile returned is different if paid
// store the orderId on server to prevent duplicates
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Added Credits", "credits": checkUserObj["credits"], "orderHistory": checkUserObj["orderHistory"]}), //, "profile": checkUserObj["profile"]
};
*/
switch(result.message)
{
/* UpgradeAccount */
case "Added Credits":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Upgraded to Paid", "promptDescription": promptDescription, "profile": checkUserObj["profile"], "paidAccount": checkUserObj["paidAccount"], "revisions": checkUserObj["revisions"]}), //, "profile": checkUserObj["profile"]
};
*/
CloseModal_OrderConfirmation();
// update storage
localStorage.setItem("credits", result["credits"]);
localStorage.setItem("orderHistory", result["orderHistory"]);
localStorage.setItem("StripeInvoices", result["StripeInvoices"]);
localStorage.setItem("accountInfo", result["accountInfo"]);
ConsoleLog("credits balance updated: " + result["credits"]);
break;
/* UpgradeAccount */
case "AddCredits Failed":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "AddCredits Failed"})
};
*/
ConsoleLog("add credits failed");
function updateRetriesUrl(maxRetries = 5) {
// Get the current URL
const url = new URL(window.location.href);
// Get the current value of the "retries" parameter, or initialize it to 0
let retries = parseInt(url.searchParams.get("retries")) || 0;
// Check if the maximum retries have been reached
if (retries >= maxRetries) {
// Maximum retries reached, handle the error or display a message
// ... (e.g., alert("Maximum retries exceeded. Please try again later."))
return url.toString(); // Return the current URL without further updates
}
// Increment the retry count
retries++;
// Update the "retries" parameter in the URL
url.searchParams.set("retries", retries);
// Return the updated URL
return url.toString();
}
// Example usage:
const updatedUrl = updateRetriesUrl();
// Redirect the browser to the updated URL only if retries are still allowed
if (updatedUrl !== window.location.href) { // Check for changes before redirection
window.location.href = updatedUrl;
}
else
{
// alert user that failed and to contact us to activate your credit
CloseModal_OrderConfirmation();
OpenModal("Problem", "Please contact us at support@mypeas.ai to activate your credit", false, false);
}
// Additional notes:
/* This code uses the `URL` object to parse and manipulate the URL components.
* The `parseInt` function is used to convert the retrieved "retries" value from a string to an integer.
* The `maxRetries` parameter allows you to specify the maximum allowed retry count.
* You can call this function multiple times to increment the retry count further. */
break;
/* UpgradeAccount */
case "Already activated credit":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Already activated credit", "promptDescription": promptDescription, "profile": checkUserObj["profile"], "paidAccount": checkUserObj["paidAccount"], "revisions": checkUserObj["revisions"]}), //, "profile": checkUserObj["profile"]
};
*/
CloseModal_OrderConfirmation();
// give message that this order was already activated
OpenModal("Message", "You have already activated this purchase", false, false);
break;
}
});
break;
}
}
/*
New stripe integration for main site checkout
*/
async function initiateCheckout(productType) {
try {
// Show loading state
showLoadingState();
// Get user info from localStorage
const userInfo = {
memberID: localStorage.getItem("memberID"),
authToken: localStorage.getItem("auth_token")
};
// Validate user is logged in
if (!userInfo.memberID || !userInfo.authToken) {
alert("Please log in before purchasing");
hideLoadingState();
return;
}
var currentOrigin = window.location.origin;
var successUrl = `${currentOrigin}?&success=true`;
var cancelUrl = `${currentOrigin}?&cancel=true`;
// Call your Lambda to create Stripe checkout session
const response = await fetch('https://j8glspknjh.execute-api.eu-west-1.amazonaws.com/Production/Checkout', {
method: 'POST',
body: JSON.stringify({
operation: 'create-main-site-checkout-session',
productType: productType,
successUrl: successUrl,
cancelUrl: cancelUrl,
userInfo: userInfo
})
});
const result = await response.json();
if (result.url) {
// Redirect to Stripe checkout
window.location.href = result.url;
} else {
throw new Error('Failed to create checkout session');
}
} catch (error) {
console.error('Checkout failed:', error);
hideLoadingState();
alert('Checkout failed. Please try again.');
}
}
function showLoadingState() {
document.querySelectorAll('.upgrade-button').forEach(btn => {
btn.disabled = true;
btn.textContent = 'Loading...';
});
}
function hideLoadingState() {
document.querySelectorAll('.upgrade-button').forEach((btn, index) => {
btn.disabled = false;
btn.textContent = 'Upgrade';
});
}
function OpenDeleteAccount()
{
// hide loading spinner
$('#spinner-holder-flex-delete-account').hide();
// show submit button
$('#btnDeleteAccountSubmit').show();
// clear fields
var deletePassword = document.getElementById('txtDeleteAccountPassword');
var deleteText = document.getElementById('txtDeleteAccountWord');
deletePassword.value = "";
deleteText.value = "";
// validation fields
var validateDeletePassword = document.getElementById('validateDeletePassword');
validateDeletePassword.style.display = 'none';
validateDeletePassword.style.color = 'red';
var validateDeleteText = document.getElementById('validateDeleteWord');
validateDeleteText.style.display = 'none';
validateDeleteText.style.color = 'red';
// animate and show
$('#delete-account-modal').animate({ opacity: 1 }).show();
// z axis
bringModalToFront('delete-account-modal');
}
function ValidateDeleteAccount()
{
var email = localStorage.getItem("email");
var failed = false;
var password = $('#txtDeleteAccountPassword').val();
var typedWord = $('#txtDeleteAccountWord').val();
// validation fields
var validateDeletePassword = document.getElementById('validateDeletePassword');
validateDeletePassword.style.display = 'none';
validateDeletePassword.style.color = 'red';
var validateDeleteText = document.getElementById('validateDeleteWord');
validateDeleteText.style.display = 'none';
validateDeleteText.style.color = 'red';
// validate password format
if(!isValidPassword(password))
{
failed = true;
validateDeletePassword.textContent = "Please enter your password";
validateDeletePassword.style.display = 'block';
}
// validate typed word
if(typedWord.toLowerCase() != "DELETE".toLowerCase())
{
failed = true;
}
if(!failed)
{
// show spinner
$('#spinner-holder-flex-delete-account').show();
// hide submit button
$('#btnDeleteAccountSubmit').hide();
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = "";
MYPEAS_payload["JobDescription"] = "";
MYPEAS_payload["promptDescription"] = "DeleteAccount";
MYPEAS_payload["registered"] = "true"; // should always be true now that user provides password at start page
MYPEAS_payload["email"] = email;
MYPEAS_payload["password"] = "";
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
// hide spinner again
$('#spinner-holder-flex-delete-account').hide();
// show submit button
$('#btnDeleteAccountSubmit').show();
switch(result.message)
{
case "Account Deleted":
localStorage.clear();
// redirect to home page
location.href = '/?login=true';
break;
case "Internal Server Error":
case "Failed Account Deleted":
// close modal
$('#delete-account-modal').animate({ opacity: 0 }).hide();
// open modal and show failed account delete
OpenModal("Problem", "There was a problem deleting your account. Please try again or contact us for assistance.", false, false);
break;
default:
break;
}
ConsoleLog("processStatus return: ",JSON.stringify(result));
});
}
}
function OpenModal(Title, Message, isLoading, requestCredit)
{
// set title text
$('#modal-popup #modal-title').text(Title).show();
// set message text
$('#modal-popup #modal-message').text(Message).show();
switch(isLoading)
{
case true:
$('#modal-popup .close-btn-w').hide();
$('#modal-popup #modal-spinner').show();
break;
case false:
$('#modal-popup .close-btn-w').show();
$('#modal-popup #modal-spinner').hide();
break;
}
switch(requestCredit)
{
case true:
// cancel timer if running
stopCheckStatusIntervals();
// not using it anymore
$('#modal-popup #btnPurchaseCredit').hide();
$('#modal-popup #pricing-table').show();
$('#modal-popup .close-btn-w').show();
$('#modal-popup #modal-spinner').hide();
$('#modal-popup #btnPurchaseCredit').text("PURCHASE CREDITS");
if(Title == "Maximize Your AI Potential")
{
$('#modal-popup #upgrade-message').show();
$('#modal-popup #modal-message').hide();
$('#modal-popup #btnPurchaseCredit').text("UPGRADE NOW");
}
break;
case false:
$('#modal-popup #upgrade-message').hide();
$('#modal-popup #pricing-table').hide();
$('#modal-popup #btnPurchaseCredit').hide();
break;
}
// animate and show
$('#modal-popup ').animate({ opacity: 1 }).show();
}
function CloseModal()
{
// close the modal using the close button
$('#modal-popup .close-btn-w').click(function(){
/*$('.modal-popup').each(function() {
if ($(this).is(':visible')) {
$(this).animate({ opacity: 0 }).hide();
unLockScroll();
}
});*/
$('#modal-popup').animate({ opacity: 0 }).hide();
unLockScroll();
});
$('#modal-popup').animate({ opacity: 0 }).hide();
unLockScroll();
}
function OpenCloseLoginModal(mode)
{
switch(mode)
{
case "open":
// hide loading if present
$('#login-modal .close-btn-w').show();
$('#login-modal #modal-spinner').hide();
// animate and show
$('#login-modal ').animate({ opacity: 1 }).show();
break;
case "close":
// close the modal using the close button
$('#login-modal').animate({ opacity: 0 }).hide();
unLockScroll();
break;
}
}
function OpenCloseNewSearchModal(mode)
{
switch(mode)
{
case "open":
// clear field values
const JobTitle = document.getElementById('jobTitle-new');
const JobDescription = document.getElementById('jobDescription-new');
if(JobTitle){ JobTitle.value = "";}
if(JobDescription){ JobDescription.value = "";}
// hide loading if present
$('#new-search-holder .close-btn-w').show();
$('#new-search-holder #modal-spinner').hide();
// animate and show
$('#new-search-holder ').animate({ opacity: 1 }).show();
break;
case "close":
// close the modal using the close button
$('#new-search-holder').animate({ opacity: 0 }).hide();
unLockScroll();
break;
}
}
function ForgotPassword()
{
// set onlick - in loadmethods
var ForgotPassword = document.getElementById('ForgotPassword');
ForgotPassword.addEventListener('click', (event) => {
// show forgotpassword
event.preventDefault();
// close the modal using the close button
OpenCloseLoginModal("close");
// open forgotpassword modal
OpenCloseForgotPasswordModal("open");
});
// validate email in btnSubmitForgotPassword
}
function OpenCloseForgotPasswordModal(mode)
{
switch(mode)
{
case "open":
// hide login modal
OpenCloseLoginModal("close");
// hide loading if present
$('#forgot-password-modal .close-btn-w').show();
$('#forgot-password-modal #modal-spinner').hide();
// hide success message
$('#forgot-password-message').hide();
// show main form
$('#ForgotPasswordFormBlock').show();
// animate and show
$('#forgot-password-modal').animate({ opacity: 1 }).show();
break;
case "close":
// close the modal using the close button
$('#forgot-password-modal').animate({ opacity: 0 }).hide();
unLockScroll();
OpenCloseLoginModal("open");
break;
}
}
function OpenCloseResetPasswordModal(mode)
{
switch(mode)
{
case "open":
// hide all modals
$('.close-btn-w').each(function() {
if ($(this).is(':visible')) {
$(this).click();
}
});
// hide loading if present
$('#reset-password-modal .close-btn-w').show();
$('#reset-password-modal #modal-spinner').hide();
// hide success message
$('#reset-confirm-message').hide();
// show main form
$('#reset-form').show();
// animate and show
$('#reset-password-modal').animate({ opacity: 1 }).show();
break;
case "close":
// close the modal using the close button
$('#reset-password-modal').animate({ opacity: 0 }).hide();
unLockScroll();
//OpenCloseLoginModal("open");
break;
}
}
/* category modal */
function OpenCategoryModal(isLoading, Title, Message)
{
// clear any results
$('#category-modal #category-content-holder').empty();
// always show loading initially
//$('#category-modal .close-btn-w').hide();
$('#category-modal #modal-spinner').show();
// hide it when results found or not found
/*switch(isLoading)
{
case true:
$('#category-modal .close-btn-w').hide();
$('#category-modal #modal-spinner').show();
break;
case false:
$('#category-modal .close-btn-w').show();
$('#category-modal #modal-spinner').hide();
break;
}*/
// set title text
$('#category-modal #category-title').text(Title);
// set message text
$('#category-modal #category-subheading').text("More " + Title + " related AI applications");
// animate and show
$('#category-modal ').animate({ opacity: 1 }).show();
}
/* favourites modal */
function OpenFavourtiesModal(isLoading, Title, Message)
{
// clear any results
$('#favourites-modal #favourites-content-holder').empty();
// always show loading initially
$('#favourites-modal #modal-spinner').show();
// hide it when results found or not found
// set title text
$('#favourites-modal #favourites-title').text(Title);
// set message text
$('#favourites-modal #favourites-subheading').text("A collection of apps you have saved");
// animate and show
$('#favourites-modal ').animate({ opacity: 1 }).show();
}
/* lead modal */
function OpenLeadModal(isLoading, Title, Message)
{
// reset fields - do this at end
// set title text
$('#lead-modal #modal-title').text(Title);
// set message text
$('#lead-modal #modal-message').text(Message);
// animate and show
$('#lead-modal').animate({ opacity: 1 }).show();
// append countries to select
addCountrySelect(document.getElementById('countrySelect_holder'));
// append country codes
addCountryCode(document.getElementById('countryCode_holder'));
// reset form to q1
showNext('q1');
}
function addCountrySelect(container)
{
var selectHTML = `
Select Location
Afghanistan
Albania
Algeria
American Samoa
Andorra
Angola
Anguilla
Antarctica
Antigua and Barbuda
Argentina
Armenia
Aruba
Australia
Austria
Azerbaijan
Bahrain
Bangladesh
Barbados
Belarus
Belgium
Belize
Benin
Bermuda
Bhutan
Bolivia
Bosnia and Herzegovina
Botswana
Bouvet Island
Brazil
British Indian Ocean Territory
British Virgin Islands
Brunei
Bulgaria
Burkina Faso
Burundi
Côte d'Ivoire
Cambodia
Cameroon
Canada
Cape Verde
Cayman Islands
Central African Republic
Chad
Chile
China
Christmas Island
Cocos (Keeling) Islands
Colombia
Comoros
Congo
Cook Islands
Costa Rica
Croatia
Cuba
Cyprus
Czech Republic
Democratic Republic of the Congo
Denmark
Djibouti
Dominica
Dominican Republic
East Timor
Ecuador
Egypt
El Salvador
Equatorial Guinea
Eritrea
Estonia
Ethiopia
Faeroe Islands
Falkland Islands
Fiji
Finland
Former Yugoslav Republic of Macedonia
France
France, Metropolitan
French Guiana
French Polynesia
French Southern Territories
Gabon
Georgia
Germany
Ghana
Gibraltar
Greece
Greenland
Grenada
Guadeloupe
Guam
Guatemala
Guinea
Guinea-Bissau
Guyana
Haiti
Heard and Mc Donald Islands
Honduras
Hong Kong
Hungary
Iceland
India
Indonesia
Iran
Iraq
Ireland
Israel
Italy
Jamaica
Japan
Jordan
Kazakhstan
Kenya
Kiribati
Kuwait
Kyrgyzstan
Laos
Latvia
Lebanon
Lesotho
Liberia
Libya
Liechtenstein
Lithuania
Luxembourg
Macau
Madagascar
Malawi
Malaysia
Maldives
Mali
Malta
Marshall Islands
Martinique
Mauritania
Mauritius
Mayotte
Mexico
Micronesia
Moldova
Monaco
Mongolia
Montenegro
Montserrat
Morocco
Mozambique
Myanmar
Namibia
Nauru
Nepal
Netherlands
Netherlands Antilles
New Caledonia
New Zealand
Nicaragua
Niger
Nigeria
Niue
Norfolk Island
North Korea
Northern Marianas
Norway
Oman
Pakistan
Palau
Palestine
Panama
Papua New Guinea
Paraguay
Peru
Philippines
Pitcairn Islands
Poland
Portugal
Puerto Rico
Qatar
Reunion
Romania
Russia
Rwanda
São Tomé and Príncipe
Saint Helena
St. Pierre and Miquelon
Saint Kitts and Nevis
Saint Lucia
Saint Vincent and the Grenadines
Samoa
San Marino
Saudi Arabia
Senegal
Serbia
Seychelles
Sierra Leone
Singapore
Slovakia
Slovenia
Solomon Islands
Somalia
South Africa
South Georgia and the South Sandwich Islands
South Korea
Spain
Sri Lanka
Sudan
Suriname
Svalbard and Jan Mayen Islands
Swaziland
Sweden
Switzerland
Syria
Taiwan
Tajikistan
Tanzania
Thailand
The Bahamas
The Gambia
Togo
Tokelau
Tonga
Trinidad and Tobago
Tunisia
Turkey
Turkmenistan
Turks and Caicos Islands
Tuvalu
US Virgin Islands
Uganda
Ukraine
United Arab Emirates
United Kingdom
United States
United States Minor Outlying Islands
Uruguay
Uzbekistan
Vanuatu
Vatican City
Venezuela
Vietnam
Wallis and Futuna Islands
Western Sahara
Yemen
Zambia
Zimbabwe
`;
/*if($('#countrySelect').length == 0)
{
container.append(selectHTML);
}*/
//var countrySelect = document.getElementById('countrySelect');
var countrySelect = container.querySelector('#countrySelect');
if (countrySelect === null) { // Equivalent to jQuery's length check
container.innerHTML = "";
container.innerHTML += selectHTML; // Assuming selectHTML is a string containing your HTML
}
// check for agency
const currentUrl = window.location.href;
const regex = /\/agency/; // Regular expression to match '/agency'
countrySelect = container.querySelector('#countrySelect');
if (currentUrl.match(regex)) {
// URL contains '/agency'
ConsoleLog("The URL contains '/agency'");
// Add the classes to the existing classList
countrySelect.classList.add('w-input', 'text-field');
}
}
function addCountryCode(container)
{
var countryCode = `
Afghanistan +93
Albania +355
Algeria +213
American Samoa +1-684
Andorra +376
Angola +244
Anguilla +1-264
Antarctica +672
Antigua and Barbuda +1-268
Argentina +54
Armenia +374
Aruba +297
Australia +61
Austria +43
Azerbaijan +994
Bahamas +1-242
Bahrain +973
Bangladesh +880
Barbados +1-246
Belarus +375
Belgium +32
Belize +501
Benin +229
Bermuda +1-441
Bhutan +975
Bolivia +591
Bosnia and Herzegovina +387
Botswana +267
Brazil +55
British Indian Ocean Territory +246
British Virgin Islands +1-284
Brunei +673
Bulgaria +359
Burkina Faso +226
Burundi +257
Cambodia +855
Cameroon +237
Canada +1
Cape Verde +238
Cayman Islands +1-345
Central African Republic +236
Chad +235
Chile +56
China +86
Christmas Island +61
Cocos Islands +61
Colombia +57
Comoros +269
Cook Islands +682
Costa Rica +506
Croatia +385
Cuba +53
Curacao +599
Cyprus +357
Czech Republic +420
Democratic Republic of the Congo +243
Denmark +45
Djibouti +253
Dominica +1-767
Dominican Republic +1-809
Dominican Republic +1-829
Dominican Republic +1-849
East Timor +670
Ecuador +593
Egypt +20
El Salvador +503
Equatorial Guinea +240
Eritrea +291
Estonia +372
Ethiopia +251
Falkland Islands +500
Faroe Islands +298
Fiji +679
Finland +358
France +33
French Polynesia +689
Gabon +241
Gambia +220
Georgia +995
Germany +49
Ghana +233
Gibraltar +350
Greece +30
Greenland +299
Grenada +1-473
Guam +1-671
Guatemala +502
Guernsey +44-1481
Guinea +224
Guinea-Bissau +245
Guyana +592
Haiti +509
Honduras +504
Hong Kong +852
Hungary +36
Iceland +354
India +91
Indonesia +62
Iran +98
Iraq +964
Ireland +353
Isle of Man +44-1624
Israel +972
Italy +39
Ivory Coast +225
Jamaica +1-876
Japan +81
Jersey +44-1534
Jordan +962
Kazakhstan +7
Kenya +254
Kiribati +686
Kosovo +383
Kuwait +965
Kyrgyzstan +996
Laos +856
Latvia +371
Lebanon +961
Lesotho +266
Liberia +231
Libya +218
Liechtenstein +423
Lithuania +370
Luxembourg +352
Macau +853
Macedonia +389
Madagascar +261
Malawi +265
Malaysia +60
Maldives +960
Mali +223
Malta +356
Marshall Islands +692
Mauritania +222
Mauritius +230
Mayotte +262
Mexico +52
Micronesia +691
Moldova +373
Monaco +377
Mongolia +976
Montenegro +382
Montserrat +1-664
Morocco +212
Mozambique +258
Myanmar +95
Namibia +264
Nauru +674
Nepal +977
Netherlands +31
Netherlands Antilles +599
New Caledonia +687
New Zealand +64
Nicaragua +505
Niger +227
Nigeria +234
Niue +683
North Korea +850
Northern Mariana Islands +1-670
Norway +47
Oman +968
Pakistan +92
Palau +680
Palestine +970
Panama +507
Papua New Guinea +675
Paraguay +595
Peru +51
Philippines +63
Pitcairn +64
Poland +48
Portugal +351
Puerto Rico +1-787
Puerto Rico +1-939
Qatar +974
Republic of the Congo +242
Reunion +262
Romania +40
Russia +7
Rwanda +250
Saint Barthelemy +590
Saint Helena +290
Saint Kitts and Nevis +1-869
Saint Lucia +1-758
Saint Martin +590
Saint Pierre and Miquelon +508
Saint Vincent and the Grenadines +1-784
Samoa +685
San Marino +378
Sao Tome and Principe +239
Saudi Arabia +966
Senegal +221
Serbia +381
Seychelles +248
Sierra Leone +232
Singapore +65
Sint Maarten +1-721
Slovakia +421
Slovenia +386
Solomon Islands +677
Somalia +252
South Africa +27
South Korea +82
South Sudan +211
Spain +34
Sri Lanka +94
Sudan +249
Suriname +597
Svalbard and Jan Mayen +47
Swaziland +268
Sweden +46
Switzerland +41
Syria +963
Taiwan +886
Tajikistan +992
Tanzania +255
Thailand +66
Togo +228
Tokelau +690
Tonga +676
Trinidad and Tobago +1-868
Tunisia +216
Turkey +90
Turkmenistan +993
Turks and Caicos Islands +1-649
Tuvalu +688
U.S. Virgin Islands +1-340
Uganda +256
Ukraine +380
United Arab Emirates +971
United Kingdom +44
United States +1
Uruguay +598
Uzbekistan +998
Vanuatu +678
Vatican +379
Venezuela +58
Vietnam +84
Wallis and Futuna +681
Western Sahara +212
Yemen +967
Zambia +260
Zimbabwe +263
`;
/*if($('#countryCode').length == 0)
{
container.append(countryCode);
}*/
var countryCodeElement = container.querySelector('#countryCode');
if (countryCodeElement === null) {
container.innerHTML = "";
container.innerHTML += countryCode; // Assuming countryCode is a string of HTML
}
// check for agency
const currentUrl = window.location.href;
const regex = /\/agency/; // Regular expression to match '/agency'
countryCodeElement = container.querySelector('#countryCode');
if (currentUrl.match(regex)) {
// URL contains '/agency'
ConsoleLog("The URL contains '/agency'");
// Add the classes to the existing classList
countryCodeElement.classList.add('w-input', 'text-field');
}
}
function CreateMyAccount()
{
var myaccount = `
Select a location country
Enter a valid email address
Purchase History
Show Invoices
Notifications
Opted-Out
Delete Account
DELETE ACCOUNT
`;
$('#accountInfoContainer').append(myaccount);
// set event listener
var buyCreditBtn = document.getElementById('myAccountBuyBtn');
if(buyCreditBtn)
{
buyCreditBtn.addEventListener('click', (event) => {
CloseAccountModal();
OpenModal("Maximize Your AI Potential", "Need more help with your AI Strategy? Unlock it with a paid account", false, true);
});
}
}
function CreateOnboardUI()
{
/*
add confetti
https://www.npmjs.com/package/js-confetti
https://codepen.io/ieatwebsites/pen/KKBvywP
*/
var myaccount = `
Discover how to supercharge your productivity and workflows with the right AI tools. MYPEAS helps you map out your job tasks, identify where AI can make a difference, and match you with solutions from our database of 10,000+ AI-powered solutions.
Generative AI has the power to transform your work, but it’s hard to see all its possibilities. There are things AI can do that you may not even know are possible—opportunities hiding in plain sight.
An AI roadmap simplifies this by breaking down your role into clear segments, activities, and steps. This helps you see exactly where AI can make a difference—streamlining tasks, saving time, and maximizing your productivity.
Next
Your MYPEAS.AI roadmap analyzes your job description within the context of your role, breaking it down into segments, activities, and steps.
This structure highlights where AI can make a real impact, helping integrate it into your workflows for enhanced productivity and efficiency.
.
Segments
Activities
Steps
The main components or responsibilities that make up a job role.
The potential tasks or actions performed within each job segment.
The detailed, sequential actions needed to complete each activity.
Explore suggested reports for your activities and generate document outlines for the deliverables.
Evaluate the potential efficiency gains from automating or applying AI solutions to the steps
Next
Feature
Free (Jumpstart)
Profile Management
1 Profile Creation
Workflow Analysis
1 Workflow per Activity
AI App Recommendations
Recommendations for 1 Workflow per Activity
AI Automation Evaluation
Insights for 1 Workflow per Activity
What do I get if I upgrade?
Feature
Pro (Optimize)
Profile Management
Multiple Profile Revisions
Workflow Analysis
All Workflows per Activity with Advanced Automation Insights
AI App Recommendations
All AI App Recommendations
AI Automation Evaluation
Complete Performance Gain Insights
What do I get for free?
Next
Enter your company surname
Select a location country
Let's Go!
`;
$('#onboardInfoContainer').append(myaccount);
// set initial titles
$('#description-holder').hide();
$('#onboard-modal #modal-title').text('Welcome to .MYPEAS.AI');
$('#onboard-modal #onboardSubheading').text("AI won't replace you, somebody using AI will.");
}
function CreateMyAccount_Agency()
{
var myaccount = `
Select a location country
Enter a valid email address
Purchase History
Show Invoices
Booking History
Show History
Notifications
Opted-Out
Delete Account
DELETE ACCOUNT
`;
$('#agency-account-modal #accountInfoContainer').append(myaccount);
}
function OptOut(accountType)
{
var currentText = $('#OptInOut').text();
var optOut = false;
switch(currentText)
{
case "Opted-In":
optOut = true;
break;
case "Opted-Out":
optOut = false;
break;
}
switch(accountType)
{
case "user":
var storedMemberID = localStorage.getItem("memberID");
var storedAuthToken = localStorage.getItem("auth_token");
// request profile
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = "";
MYPEAS_payload["JobDescription"] = "";
MYPEAS_payload["promptDescription"] = "ChangeStatus";
//MYPEAS_payload["newOptIn"] = "ChangeStatus";
MYPEAS_payload["registered"] = "true"; // should always be true now that user provides password at start page
MYPEAS_payload["memberID"] = storedMemberID; // get from storage
MYPEAS_payload["auth_token"] = storedAuthToken; // get from storage
var requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
/* NEXT */
// show spinner
$('#OptInOut').hide();
$('#OptInOut_Loading').show();
$('#OptInOut_message').hide();
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => {
if (response.ok) { // Check for successful response (2xx status codes)
return response.text();
} else {
throw new Error(`API returned error status: ${response.status}`);
}
})
//.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("ChangeStatus return: ",JSON.stringify(result));
// hide spinner
$('#OptInOut_Loading').hide();
// show message for success or failure
var message = result["message"];
switch(message)
{
// change text on button (opt in or opt out)
case "OptInUpdate Complete":
var optIn = result["optIn"];
switch(optIn)
{
case true:
case "true":
$('#OptInOut').text('Opted-In').show();
break;
case false:
case "false":
$('#OptInOut').text('Opted-Out').show();
break;
}
// set optin in localstorage
localStorage.setItem("optIn", optIn);
break;
case "Failed to update":
$('#OptInOut').show();
$('#OptInOut_message').text('Something went wrong. Your settings did not get changed.').show();
break;
}
})
.catch(error => {
console.error("Error calling OptOut: ", error);
// hide spinner
$('#OptInOut_Loading').hide();
$('#OptInOut').show();
$('#OptInOut_message').text('Something went wrong. Your settings did not get changed.').show();
});
break;
case "agency":
var storedMemberID = localStorage.getItem("memberID");
var storedAuthToken = localStorage.getItem("auth_token");
// request profile
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = "";
MYPEAS_payload["JobDescription"] = "";
MYPEAS_payload["requestDescription"] = "ChangeStatus";
MYPEAS_payload["registered"] = "true"; // should always be true now that user provides password at start page
MYPEAS_payload["memberID"] = storedMemberID; // get from storage
MYPEAS_payload["auth_token"] = storedAuthToken; // get from storage
var requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
/* NEXT */
// show spinner
$('#OptInOut').hide();
$('#OptInOut_Loading').show();
$('#OptInOut_message').hide();
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => {
if (response.ok) { // Check for successful response (2xx status codes)
return response.text();
} else {
throw new Error(`API returned error status: ${response.status}`);
}
})
//.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("ChangeStatus return: ",JSON.stringify(result));
// hide spinner
$('#OptInOut_Loading').hide();
// show message for success or failure
var message = result["message"];
switch(message)
{
// change text on button (opt in or opt out)
case "OptInUpdate Complete":
var optIn = result["optIn"];
// if completed - load profile in UI
if(optOut)
{
$('#OptInOut').text('Opted-Out').show();
}
else
{
$('#OptInOut').text('Opted-In').show();
}
// set optin in localstorage
localStorage.setItem("optIn", optIn);
break;
case "Failed to update":
$('#OptInOut').show();
$('#OptInOut_message').text('Something went wrong. Your settings did not get changed.').show();;
break;
}
})
.catch(error => {
console.error("Error calling OptOut: ", error);
// hide spinner
$('#OptInOut_Loading').hide();
$('#OptInOut').show();
$('#OptInOut_message').text('Something went wrong. Your settings did not get changed.').show();
});
break;
}
}
function Unsubscribe()
{
var failed = false;
var email = document.getElementById('email');
var validateEmail = document.querySelector('#unsubscribe-message');
validateEmail.style.display = 'none';
validateEmail.style.color = 'red';
var submitButton = document.getElementById('submitButton');
var spinner = document.getElementById('Unsubscribe_Loading');
// validate email
if(!isValidEmail(email.value))
{
failed = true;
validateEmail.textContent = "Please enter a valid email";
validateEmail.style.display = 'block';
}
if(!failed)
{
// disable button
submitButton.disabled = true;
// show spinner
$(spinner).show();
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = "";
MYPEAS_payload["JobDescription"] = "";
MYPEAS_payload["promptDescription"] = "Unsubscribe";
var emailAddress = email.value;
MYPEAS_payload["emailAddress"] = emailAddress;
var requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// send to server
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => {
if (response.ok) { // Check for successful response (2xx status codes)
return response.text();
} else {
throw new Error(`API returned error status: ${response.status}`);
}
})
.then(result => {
result = JSON.parse(result);
ConsoleLog("result (object): ", result); // result (object): {"message":"processing"}
var message = result["message"];
// enable button
submitButton.disabled = false;
// hide spinner
$(spinner).hide();
switch(message)
{
case "Unsubscribe Complete":
validateEmail.textContent = "You have been unsubscribed.";
validateEmail.style.color = 'black';
validateEmail.style.display = 'block';
break;
case "Unsubscribe: user NOT found":
validateEmail.textContent = "This email address is not registered.";
validateEmail.style.display = 'block';
break;
case "Failed to update":
validateEmail.textContent = "Something went wrong. Please try again.";
validateEmail.style.display = 'block';
break;
}
})
.catch(error => {
console.error("Error calling Unsubscribe: ", error);
// enable button
submitButton.disabled = false;
// hide spinner
$(spinner).hide();
// show message
validateEmail.textContent = "Something went wrong. Please try again.";
validateEmail.style.display = 'block';
});
}
}
function Unsubscribe_Agency()
{
var failed = false;
var email = document.getElementById('email');
var validateEmail = document.querySelector('#unsubscribe-message');
validateEmail.style.display = 'none';
validateEmail.style.color = 'red';
var submitButton = document.getElementById('submitButton');
var spinner = document.getElementById('Unsubscribe_Loading');
// validate email
if(!isValidEmail(email.value))
{
failed = true;
validateEmail.textContent = "Please enter a valid email";
validateEmail.style.display = 'block';
}
if(!failed)
{
// disable button
submitButton.disabled = true;
// show spinner
$(spinner).show();
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = "";
MYPEAS_payload["JobDescription"] = "";
MYPEAS_payload["requestDescription"] = "Unsubscribe";
var emailAddress = email.value;
MYPEAS_payload["emailAddress"] = emailAddress;
var requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// send to server
// Make an API call to API gateway - return will just indicate that it is processing
//var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => {
if (response.ok) { // Check for successful response (2xx status codes)
return response.text();
} else {
throw new Error(`API returned error status: ${response.status}`);
}
})
.then(result => {
result = JSON.parse(result);
ConsoleLog("result (object): ", result); // result (object): {"message":"processing"}
var message = result["message"];
// enable button
submitButton.disabled = false;
// hide spinner
$(spinner).hide();
switch(message)
{
case "Unsubscribe Complete":
validateEmail.textContent = "You have been unsubscribed.";
validateEmail.style.color = 'black';
validateEmail.style.display = 'block';
break;
case "Unsubscribe: user NOT found":
validateEmail.textContent = "This email address is not registered.";
validateEmail.style.display = 'block';
break;
case "Failed to update":
validateEmail.textContent = "Something went wrong. Please try again.";
validateEmail.style.display = 'block';
break;
}
})
.catch(error => {
console.error("Error calling Unsubscribe: ", error);
// enable button
submitButton.disabled = false;
// hide spinner
$(spinner).hide();
// show message
validateEmail.textContent = "Something went wrong. Please try again.";
validateEmail.style.display = 'block';
});
}
}
function ShowDashboardProcesssing(ApprovedStatus)
{
switch(ApprovedStatus)
{
case "Approved":
case "approved":
ApprovedStatus = `
Your agency account is currently in Approved `;
break;
case "processing":
ApprovedStatus = `
Your agency account is currently in Review `;
break;
case "AwaitingApproval":
ApprovedStatus = `
Your agency account is currently Awaiting Approval `;
break;
case "InviteSent":
ApprovedStatus = `
📅 Your agency account requires a calendar
Your bookings and calendar scheduling are hosted by YouCanBookMe™.
You need to connect your calendar before clients can book a call with you.
Check your email for your MYPEAS.AI team calendar invitation.
📅 I have added my Calendar
📧 Your invitation to join our YouCanBook.me team is waiting for you. Be sure to check your spam folder if you don't see it right away. We're excited to have you onboard!
Simply follow the link and accept the invite
Then click "Manager Your Account" and add your calendar to ensure that your availability is always accurate, preventing double bookings and saving you precious time.
📅 I have added my Calendar
`;
checkCalendarAdded();
break;
case "rejected":
ApprovedStatus = `
Your agency account was Rejected `;
break;
}
var dashboard = `
`;
$('#dashboard-info-container').append(dashboard);
$('#agency-account-info-holder #modal-message').hide();
$('.agency-account-info-holder').show();
}
function confirmCalendar()
{
// refresh page to trigger check for calendar
window.scrollTo(0, 0);
ShowPreLoad();
location.reload();
}
function checkCalendarAdded()
{
try
{
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = "";
MYPEAS_payload["JobDescription"] = "";
MYPEAS_payload["requestDescription"] = "CheckCalendar";
MYPEAS_payload["registered"] = "true"; // should always be true now that user provides password at start page
MYPEAS_payload["agencyMemberID"] = localStorage.getItem("memberID"); // get from storage
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
var message = result["message"];
ConsoleLog("Calendar Check: ",message);
switch(message)
{
case "Calendar Found":
confirmCalendar();
break;
case "No Calendar Found":
//ShowDashboardProcesssing("InviteSent");
HidePreLoad();
break;
case "No Calendar Found - User Does Not Exist":
//ShowDashboardProcesssing("InviteSent");
HidePreLoad();
break;
}
$('.background-video').hide();
$('.background-video-agency').hide();
});
}
catch (error)
{
console.error("Error checkCalendarAdded:", error);
//ShowDashboardProcesssing("InviteSent");
HidePreLoad();
$('.background-video').hide();
$('.background-video-agency').hide();
}
}
function CreateDashboard(accountInfo, profile)
{
var credits = profile["credits"] || "0";
var sendCount = 0;
var requests = JSON.parse(localStorage.getItem('requests'));
if(requests)
{
sendCount = requests.length;
}
var maxSend = 0;
maxSend = 2 * parseInt(credits);
if(accountInfo?.nopurchases && accountInfo["nopurchases"] == "true")
{
maxSend = 2;
}
// if maxSend = 0. prompt user to purchase credits
if(maxSend < 1)
{
$('#sendCount').text(sendCount);
$('#outOfText').text("");
$('#maxSend').text("");
// trigger
OpenModal("Credit Balance Empty", "You can't connect with any more clients. Purchase more credits.", false, true);
// show purchase options
DashboardShowProducts();
}
/*
// update nopurchases property
var accountInfo = JSON.parse(checkUserObj["accountInfo"]);
if(accountInfo["nopurchases"] == "true")
{
accountInfo["nopurchases"] = "false";
await UpdateDBField(MYPEAS_payload["AGENCYCODE"], "", "accountInfo", JSON.stringify(accountInfo));
}
var requests = JSON.parse(accountInfo['requests']);
var credits = '';
if(requests.length > (2 * credits))
{
OpenModal("Insufficient Credits", "You can't make any more requests as you have more than twice the number of requests than your credit would pay for. Buy more credits to continue", false, true);
}
if((requests.length > (2 * credits)) && accountInfo["nopurchases"] == "false")
{
sendLink = false;
OpenModal("Insufficient Credits", "You can't make any more requests as you have more than twice the number of requests than your credit would pay for. Buy more credits to continue", false, true);
}
if(requests.length > 1 && accountInfo["nopurchases"] == "true")
{
sendLink = false;
OpenModal("Insufficient Credits", "You can't make any more requests in a 48 hour period. Purchase credits to remove this restriction", false, true);
}
*/
// clear initially
$('#dashboard-info-container').empty();
$('#booking-requests-container').empty();
var dashboard = `
Current Balance
${credits} credits
Your Calendar
Set My Availability
`;
var bookingrequests = `
Send your calendar availability
Requests Sent: ${sendCount} out of ${maxSend}
In a 48 hour period you can send max 2X your credit balance number of requests. [Learn More]
Customers who have requested consultations
`;
$('#dashboard-info-container').append(dashboard);
$('#booking-requests-container').append(bookingrequests);
if(maxSend < 1)
{
$('#sendCount').text(sendCount);
$('#outOfText').text("");
$('#maxSend').text("");
}
/* Add loading spinner */
// Get the original element by ID
const originalElement = document.getElementById("login-loading");
if (originalElement) {
// Clone the original element
const clonedElement = originalElement.cloneNode(true); // true for deep clone (clones children as well)
// Modify the cloned element's ID and class
clonedElement.id = "requests-loading"; // Replace with your desired new ID
clonedElement.classList.remove("login-loading"); // Remove the old class (if needed)
clonedElement.classList.add("requests-loading"); // Replace with your desired new class
// Append to your jQuery element
$("#meetingRequestsLoading").append(clonedElement); // Replace #yourJqueryElement with your jQuery selector
} else {
console.error("Element with ID 'login-loading' not found.");
}
$('.agency-account-info-holder').show();
// create booking requests
// make request for booking requests
var requestData = {};
requestData["requestDescription"] = "GetRequests";
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://dg5wsg1ref.execute-api.eu-west-1.amazonaws.com/Production/BookingRequests';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
var message = result["message"];
ConsoleLog("Booking Requests response: " + message);
/* hide loading spinner */
$('#requests-loading').hide();
$('#meetingRequestsContainer').show();
switch(message)
{
case "returned booking requests":
// create booking request table if not present
var bookingRequests = result["bookingRequests"];
CreateBookingRequests(bookingRequests, accountInfo);
break;
case "no booking requests":
// show no new booking requests message
break;
case "failed booking requests":
// show something went wrong message
break;
}
});
}
function OpenLearnMore()
{
OpenModal("Credit Information", "We restrict how many meeting request links you can send as you are not billed until a meeting is scheduled. This prevents you from booking way more meetings than you budgeted for. If your credits enter negative balance you will not be able to send any more meeting links. Any overdraft will be cleared when you next make a meetings credit purchase.", false, false);
}
async function isValidCalendlyLink(url) {
// Define the regex pattern for a valid Calendly link
const calendlyRegex = /^(https?:\/\/)?(www\.)?calendly\.com\/[a-zA-Z0-9-_]+(\/[a-zA-Z0-9-_]+)?$/;
// First, test the URL format using regex
if (!calendlyRegex.test(url)) {
return false;
}
try {
// Perform a fetch request to check for 200 status
const response = await fetch(url, { method: 'HEAD' });
// Return true if the status is 200
return response.status === 200;
} catch (error) {
// If there's an error (e.g., network issues), return false
return false;
}
}
function CreateBookingRequests(bookingRequests, accountInfo)
{
//bookingRequests = testBookingRequests;
// Example usage: Assuming you have a container in your HTML with the ID 'meetingRequestsContainer'
const cardListContainer = document.getElementById('meetingRequestsContainer');
//cardListContainer.appendChild(generateBookingCards(bookingRequests));
cardListContainer.appendChild(generateBookingCards(bookingRequests, accountInfo));
}
const testBookingRequests = [
{
memberID: "member-123",
requestDate: Math.floor(Date.now() / 1000), // Current timestamp
queryInfo: JSON.stringify({ // Assuming queryInfo is an object
location: "New York City",
budget: "$2,000 - $3,000",
goal: "Website Redesign",
servicesNeeded: "Web Development, UX Design"
}),
responseCount: 2
},
{
memberID: "member-456",
requestDate: Math.floor(Date.now() / 1000) - (24 * 60 * 60), // Yesterday
queryInfo: JSON.stringify({
location: "Los Angeles",
budget: "$5,000+",
goal: "Branding and Marketing",
servicesNeeded: "Graphic Design, Social Media Strategy"
}),
responseCount: 0
},
{
memberID: "member-789",
requestDate: Math.floor(Date.now() / 1000) - (3 * 24 * 60 * 60), // 3 days ago
queryInfo: JSON.stringify({
location: "Paris, France",
budget: "€3,000 - €5,000",
goal: "E-commerce Website",
servicesNeeded: "Web Development, Payment Integration"
}),
responseCount: 1
},
{
memberID: "member-012",
requestDate: Math.floor(Date.now() / 1000) - (6 * 24 * 60 * 60), // 6 days ago
queryInfo: JSON.stringify({
location: "Berlin, Germany",
budget: "€4,000+",
goal: "Mobile App Development",
servicesNeeded: "iOS Development, Android Development, UI/UX"
}),
responseCount: 2
},
{
memberID: "member-345",
requestDate: Math.floor(Date.now() / 1000), // Current timestamp
queryInfo: JSON.stringify({
location: "Rome, Italy",
budget: "€2,500 - €4,000",
goal: "Promotional Video",
servicesNeeded: "Videography, Editing, Motion Graphics"
}),
responseCount: 0
}
];
function generateBookingCards(bookingRequests, accountInfo) {
const cardsContainer = document.createElement('div');
cardsContainer.classList.add('cards-container'); // For styling
bookingRequests.forEach(request => {
const card = document.createElement('div');
card.classList.add('booking-card');
card.dataset.memberId = request.memberID;
// Data Rows (divs)
const dataRows = document.createElement('div');
dataRows.classList.add('new-card-data-rows');
if (request.hasOwnProperty("queryInfo") && typeof request["queryInfo"] === 'string') {
try {
request["queryInfo"] = JSON.parse(request["queryInfo"]);
} catch (error) {
console.error("Error parsing JSON property:", error);
}
}
const headings = ['Location', 'Budget', 'Goal', 'Services Needed'];
const values = [request.queryInfo?.country.text, request.queryInfo?.budget, request.queryInfo?.primaryGoal.text, request.queryInfo?.servicesNeeded.text];
for (let i = 0; i < headings.length; i++) {
const row = document.createElement('div');
row.classList.add('new-card-row');
const headingCell = document.createElement('div');
headingCell.classList.add('new-card-cell', 'new-heading-cell');
headingCell.textContent = headings[i];
row.appendChild(headingCell);
const valueCell = document.createElement('div');
valueCell.classList.add('new-card-cell', 'new-value-cell');
valueCell.textContent = values[i] || '\u00A0'; // non-breaking space to ensure line height
row.appendChild(valueCell);
dataRows.appendChild(row);
}
card.appendChild(dataRows);
// Button
const button = document.createElement('button');
button.classList.add('send-calendar-button'); // Changed class to connect-button
button.textContent = 'Send Calendar Link';
// Set margin-top directly in the style attribute
button.style.marginTop = '10px';
// add event listener that sends booking request memberID and booking page link to server
button.addEventListener('click', function() {
var bookingLinkPresent = !!accountInfo?.bookingLink;
if(bookingLinkPresent)
{
// 1. Create a URL object for easy manipulation:
const url = new URL(accountInfo["bookingLink"]);
// 2. Add or update parameter using the URLSearchParams API:
url.searchParams.set("AGENCYCODE", accountInfo["memberID"]);
// 3. Return the modified URL as a string:
var bookingLink = url.toString();
// check limits
var requests = localStorage.getItem("requests");
// stored as string
requests = JSON.parse(requests);
var maxParseAttempts = 10; // Maximum allowed parsing attempts
while (typeof requests === 'string' && maxParseAttempts > 0)
{
try
{
requests = JSON.parse(requests);
} catch (error)
{
console.error("Error parsing requests:", error);
break; // Exit loop on parsing failure
}
maxParseAttempts--;
}
var credits = localStorage.getItem("credits");
credits = parseInt(credits) || 0;
// check for expiration - currently 48 hours
var expirationPeriod = 48;
requests = deleteExpiredRequests(requests, expirationPeriod);
// PREVENT DUPLICATE
// check if the requestId is already present in the requests array
var matches = requests.filter(matchRequest => matchRequest.requestID == request.requestId);
if (matches && matches.length > 0) {
OpenModal("Booking Link Sent", "You have already sent your booking link to this Customer for this query", false, false);
} else {
// update accountinfo and requests in localstorage
var sendLink = true;
if ((requests.length > (2 * credits)) && accountInfo["nopurchases"] == "false") {
sendLink = false;
if(credits > 0)
{
OpenModal("Insufficient Credits", "You can't make any more requests as you have more than twice the number of requests than your credit would pay for. Buy more credits to continue", false, true);
// show purchase options
DashboardShowProducts();
}
if(credits <= 0)
{
OpenModal("Insufficient Credits", "You can't make any more requests. Purchase more credits.", false, true);
// show purchase options
DashboardShowProducts();
}
}
if (requests.length > 1 && accountInfo["nopurchases"] == "true") {
sendLink = false;
OpenModal("Insufficient Credits", "You can't make any more requests in a 48 hour period. Purchase credits to remove this restriction", false, true);
// show purchase options
DashboardShowProducts();
}
if (sendLink) {
const now = new Date();
const unixTimestamp = Math.floor(now.getTime() / 1000);
var newRequest = createRequest(unixTimestamp, request.requestId, request.memberID, localStorage.getItem("memberID"));
requests.push(newRequest);
SendBookingLink(request.requestId, request.memberID, bookingLink, accountInfo, requests);
}
}
}
if(!bookingLinkPresent)
{
// prompt user to add calendly link
OpenCalendarModal();
}
});
card.appendChild(button);
cardsContainer.appendChild(card);
});
return cardsContainer;
}
// add check for calendar in profile
function SendBookingLink(requestId, memberID, bookingLink, accountInfo, requests)
{
try
{
if (typeof accountInfo === 'string')
{
try
{
accountInfo = JSON.parse(accountInfo);
}
catch (error)
{
console.error("Error parsing JSON property:", error);
}
}
// check accountinfo for calendly link
var calendarLink = accountInfo["bookingLink"];
var calendarPresent = false;
if(calendarLink && calendarLink != "")
{
calendarPresent = true;
}
if(calendarPresent)
{
var requestData = {};
var SendCalendarData = {};
SendCalendarData["requestDescription"] = "SendCalendar";
SendCalendarData["requestMemberID"] = memberID;
SendCalendarData["requestId"] = requestId;
SendCalendarData["providerBookingLink"] = bookingLink;
SendCalendarData["agencyMemberId"] = accountInfo["memberID"];
SendCalendarData["auth_token"] = localStorage.getItem("auth_token");
SendCalendarData["agencyBookingId"] = accountInfo["bookingAccountId"];
const now = new Date();
const unixTimestamp = Math.floor(now.getTime() / 1000);
// request creation date by agency (not the date the lead was created by the user)
SendCalendarData["creationDate"] = unixTimestamp;
// update requests on server
SendCalendarData["requests"] = JSON.stringify(requests);
requestData["SendCalendarData"] = SendCalendarData;
requestData["MYPEAS_payload"] = {};
requestData["MYPEAS_payload"]["requestDescription"] = "SendCalendar";
// check they have not exceeded limit
$('#requests-loading').show();
$('#meetingRequestsContainer').hide();
// Make an API call to API gateway
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
var message = result["message"];
$('#requests-loading').hide();
$('#meetingRequestsContainer').show();
switch(message)
{
case "Booking Link Sent":
// store updated requests and accountInfo
var requests = result["requests"] || JSON.stringify([]);
var accountInfo = result["accountInfo"] || JSON.stringify({});
localStorage.setItem("requests", requests);
if(accountInfo == "")
{
accountInfo = JSON.stringify({});
}
localStorage.setItem("accountInfo", accountInfo);
// give visual feedback to agency
OpenModal("Booking Link Sent", "You have successfully sent your booking link to this customer.", false, false);
// store the updates to accountinfo and requests
/*localStorage.setItem("accountInfo", result["accountInfo"]);
localStorage.setItem("requests", result["requests"]);*/
// update ux for tally of sent links
updateSendLimit();
break;
case "Calendar missing":
// show alert with username and password to log in and button to open the website
OpenCalendarModal();
break;
case "Sending Booking Link Failed":
OpenModal("Problem", "Your booking link was not sent", false, false);
break;
}
});
}
if(!calendarPresent)
{
// prompt user to add calendar and open modal
OpenCalendarModal();
}
}
catch(error)
{
console.error("Error calling SendBookingLik: ", error)
$('#requests-loading').hide();
$('#meetingRequestsContainer').show();
}
}
function updateSendLimit()
{
var credits = localStorage.getItem("credits");
var sendCount = JSON.parse(localStorage.getItem("requests")).length || 0;
var accountInfo = JSON.parse(localStorage.getItem("accountInfo"));
var maxSend = 0;
maxSend = 2 * parseInt(credits);
if(accountInfo?.nopurchases && accountInfo["nopurchases"] == "true")
{
maxSend = 2;
}
$('#sendCount').text(sendCount);
$('#outOfText').text(" out of ");
$('#maxSend').text(maxSend);
// if maxSend = 0. prompt user to purchase credits
if(maxSend < 1)
{
$('#sendCount').text(sendCount);
$('#outOfText').text("");
$('#maxSend').text("");
// trigger
OpenModal("Credit Balance Empty", "You can't connect with any more clients. Purchase more credits.", false, true);
// show purchase options
DashboardShowProducts();
}
}
function DashboardShowProducts()
{
$('#dashboard-buy-credits').show();
// scroll into view
$('html, body').animate({
scrollTop: $('#dashboard-buy-credits').offset().top - 50
}, 500);
}
function sendRequest()
{
var requests = localStorage.getItem("requests") || null;
var credits = localStorage.getItem("credits") || '0';
if(requests)
{
requests = JSON.parse(requests);
var maxParseAttempts = 10; // Maximum allowed parsing attempts
while (typeof requests === 'string' && maxParseAttempts > 0)
{
try
{
requests = JSON.parse(requests);
} catch (error)
{
console.error("Error parsing requests:", error);
break; // Exit loop on parsing failure
}
maxParseAttempts--;
}
credits = parseInt(credits);
if(requests.length > (2 * credits))
{
OpenModal("Insufficient Credits", "You can't make any more requests as you have more than twice the number of requests than your credit would pay for. Buy more credits to continue", false, true);
}
}
}
function createRequest(timestamp, ID, memberID, agencyMemberID) {
return {
requestDate: timestamp,
requestID: ID,
memberID: memberID,
agencyMemberID: agencyMemberID
};
}
// EXAMPLE: Generating Unix timestamps:
/*const requests = [
createRequest(Date.now(), { clientId: 123, topic: "AI Strategy" }),
createRequest(Date.now() - (2 * 24 * 60 * 60 * 1000), { clientId: 456, topic: "Chatbot Development" }),
createRequest(Date.now() - (5 * 24 * 60 * 60 * 1000), { clientId: 789, topic: "Data Analysis" })
];*/
// Counting requests (unchanged)
function countRequests(requests) {
return requests.length;
}
// Deleting expired requests with Unix timestamps
function deleteExpiredRequests(requests, hours) {
const now = new Date();
const nowInSeconds = Math.floor(now / 1000); // Current time in seconds
const expirationThreshold = nowInSeconds - (hours * 60 * 60); // Threshold in seconds
//return requests.filter(request => request.timestamp > expirationThreshold);
return requests.filter(request => request.requestDate > expirationThreshold);
}
function CreateSetCalendar(accountInfo)
{
$('#calendar-holder-container').show();
// set values
var calendlyLink = accountInfo["bookingLink"];
var calendlyLinkInput = document.getElementById('calendly-link');
calendlyLinkInput.value = calendlyLink;
}
function copyUsername() {
const usernameInput = document.getElementById('ycbm-username');
usernameInput.select();
document.execCommand('copy');
}
function copyPassword() {
const passwordInput = document.getElementById('ycmb-password');
passwordInput.select();
document.execCommand('copy');
}
function togglePassword() {
const passwordInput = document.getElementById('ycmb-password');
const passwordButton = event.target;
if (passwordInput.type === 'password') {
passwordInput.type = 'text';
passwordButton.textContent = 'Hide';
} else {
passwordInput.type = 'password';
passwordButton.textContent = 'Show';
}
}
function ShowInvoices()
{
if ($('#btnShowInvoices').text() == 'Show Invoices')
{
$('.invoice').show();
$('#btnShowInvoices').text('Hide Invoices');
}
else
{
document.getElementById('invoice-container').innerHTML = "";
$('.invoice').hide();
$('#btnShowInvoices').text('Show Invoices');
}
}
function AddInvoices_OLD(invoiceArray)
{
/*var invoiceArray = [
{
"invoice-client-name": "Client Name 1",
"invoice-order-number": "123456",
"OrderID": "Order123",
"invoice-order-date": "2023-02-28",
"invoice-purchase-subtotal": "100.00",
"invoice-purchase-countrytaxes": "20.00",
"invoice-purchase-total": "120.00",
"invoice-address": "123 Main Street, Anytown"
},
// Add more invoiceObj objects as needed
];*/
// Function to generate and insert HTML for each invoiceObj
invoiceArray.forEach(function(invoiceObj) {
var dynamicHtml = '
' +
'
' + invoiceObj["invoice-order-date"] + '
' +
'
' +
'[View Invoice] ' +
'
' +
'
';
// Insert the dynamically created HTML after the '#invoice-rule' element
// If you want all elements inserted exactly after '#invoice-rule', use .after() in combination with .last()
$('#invoice-rule').last().after(dynamicHtml);
});
}
function AddInvoices(invoiceArray)
{
// Function to generate and insert HTML for each Stripe invoice
invoiceArray.forEach(function(invoiceObj) {
var dynamicHtml = '
' +
'
' + invoiceObj.invoiceDate + '
' +
'
' +
'[View Invoice] ' +
'
' +
'
';
// Insert the dynamically created HTML after the '#invoice-rule' element
$('#invoice-rule').last().after(dynamicHtml);
});
}
// Function to open Stripe invoice in new tab/window
function ViewStripeInvoice(invoiceUrl) {
window.open(invoiceUrl, '_blank');
}
function ViewInvoice(OrderID)
{
var orderHistory = localStorage.getItem("orderHistory");
if(orderHistory)
{
orderHistory = JSON.parse(orderHistory);
var matchingOrder = orderHistory.find(invoiceObject => invoiceObject.OrderID === OrderID);
if(matchingOrder)
{
ConsoleLog(matchingOrder);
// create invoice
generateInvoice(matchingOrder);
// show download button
$('#Download').show();
}
}
}
function CreatePDF()
{
// Calculate the A4 width in pixels for a typical screen resolution
/*const a4WidthInPixels = 210 / 25.4 * 96; // Convert mm to inches and multiply by screen DPI
const scale = window.devicePixelRatio; // Get the actual device pixel ratio
html2canvas(document.getElementById("invoice-container"), {
scale: scale,
windowWidth: a4WidthInPixels
}).then(canvas => {
const pdf = new jspdf.jsPDF('p', 'mm', 'a4');
// Define margins (for example, 10mm on each side)
const margins = {
top: 10,
bottom: 10,
left: 10,
right: 10
};
// Calculate the width and height of the image within the margins
const contentWidth = 210 - margins.left - margins.right;
const contentHeight = (canvas.height * contentWidth) / canvas.width;
// Add the image data to the PDF within the margins
const imgData = canvas.toDataURL('image/jpeg', 1.0);
pdf.addImage(imgData, 'JPEG', margins.left, margins.top, contentWidth, contentHeight);
// Save the PDF with a filename
pdf.save('mypeas-invoice.pdf');
});*/
html2canvas(document.getElementById("invoice-container"), {
scale: 2 * window.devicePixelRatio, // Double the DPI by multiplying the scale
windowWidth: document.getElementById("invoice-container").offsetWidth
}).then(canvas => {
const pdf = new jspdf.jsPDF('p', 'mm', 'a4');
// Define margins (for example, 10mm on each side)
const margins = {
top: 10,
bottom: 10,
left: 10,
right: 10
};
// Calculate the width and height of the image within the margins
var contentWidth = 210 - margins.left - margins.right; // A4 width in mm minus left and right margins
var scaledWidth = canvas.width * (contentWidth / canvas.width);
var scaledHeight = canvas.height * (contentWidth / canvas.width); // Maintain aspect ratio
// Adjust the scaled height if it's larger than the page height minus top and bottom margins
var pageHeight = 297 - margins.top - margins.bottom; // A4 height in mm minus top and bottom margins
if (scaledHeight > pageHeight) {
var scaledRatio = pageHeight / scaledHeight;
scaledWidth *= scaledRatio;
scaledHeight *= scaledRatio;
}
// Convert the canvas to a data URL
var imgData = canvas.toDataURL('image/jpeg', 1.0);
// Add the image data to the PDF within the margins
pdf.addImage(imgData, 'JPEG', margins.left, margins.top, scaledWidth, scaledHeight);
// Save the PDF with a filename
pdf.save('mypeas-invoice.pdf');
});
}
function generateInvoice(invoiceObj) {
var invoiceHTML = `
Bill To:
Client Name ${invoiceObj["invoice-client-name"]}
Address ${invoiceObj["invoice-address"]}
Invoice # ${invoiceObj["invoice-order-number"]}
Invoice Date ${invoiceObj["invoice-order-date"]}
Order ID ${invoiceObj["OrderID"]}
Description
Amount in GBP
MYPEAS.AI services
${invoiceObj["invoice-purchase-subtotal"]}
`;
/*// Iterating over itemsArray and adding each item to the invoice table
invoiceObj["itemsArray"].forEach(function(item) {
invoiceHTML += `
${item["orderTitle"]}
£${item["orderPrice"]["value"]}
`;
});*/
/*invoiceHTML += `
${invoiceObj["orderTitle"]}
£${invoiceObj["orderPrice"]}
`;*/
invoiceHTML += `
Subtotal
${invoiceObj["invoice-purchase-subtotal"]}
Tax
${invoiceObj["invoice-purchase-countrytaxes"]["amount"]}
Total
${invoiceObj["invoice-purchase-total"]}
`;
document.getElementById('invoice-container').innerHTML = invoiceHTML;
}
function ShowBookingHistory()
{
/*
Show History
*/
if ($('#btnBookingHistory').text() == 'Show History')
{
$('.booking').show();
$('#btnBookingHistory').text('Hide History');
}
else
{
$('.booking').hide();
$('#btnBookingHistory').text('Show History');
}
}
function OpenAccountModal()
{
$('#account-modal #modal-message-account').hide();
$('#account-modal #account-message').hide().text("");
// empty the account modal
$('#account-modal #accountInfoContainer').empty();
CreateMyAccount();
/*
var accountInfo = {};
accountInfo["firstname"] = firstname;
accountInfo["surname"] = surname;
accountInfo["location"] = {"locationName": locationName, "locationCode": locationCode};
accountInfo["email"] = email;
*/
/*var accountInfo = {
// Simulated profile data
firstname: 'John',
surname: "Doe",
location: {locationCode: "GB", locationName: "United Kingdom"},
email: 'john.doe@example.com',
accountType: 'lite',
referralCode: 'ABC123'
};*/
var accountInfo = localStorage.getItem("accountInfo") || null;
if(accountInfo)
{
accountInfo = JSON.parse(accountInfo);
// create and populate
populateAccountFields(accountInfo);
}
/*var invoiceArray = localStorage.getItem("orderHistory") || null;
if(invoiceArray && invoiceArray != "")
{
invoiceArray = JSON.parse(invoiceArray);
AddInvoices(invoiceArray);
}*/
var invoiceArray = localStorage.getItem("StripeInvoices") || null;
if(invoiceArray && invoiceArray != "")
{
invoiceArray = JSON.parse(invoiceArray);
AddInvoices(invoiceArray);
}
//var optIn = result["optIn"] !== undefined ? result["optIn"] : true;
var optIn = localStorage.getItem("optIn");
if(optIn !== undefined)
{
switch(optIn)
{
case true:
case "true":
$('#OptInOut').text('Opted-In').show();
break;
case false:
case "false":
$('#OptInOut').text('Opted-Out').show();
break;
}
}
// animate and show
$('#account-modal ').animate({ opacity: 1 }).show();
}
function OpenOnboardModal()
{
// hide myaccount and my apps
$('#btnFavourites').hide();
$('#btnMyAccount').hide();
$('#onboard-modal #modal-message-account').hide();
$('#onboard-modal #account-message').hide().text("");
// empty the account modal
$('#onboard-modal #onboardInfoContainer').empty();
CreateOnboardUI();
/*
var accountInfo = {};
accountInfo["firstname"] = firstname;
accountInfo["surname"] = surname;
accountInfo["location"] = {"locationName": locationName, "locationCode": locationCode};
accountInfo["email"] = email;
*/
/*var accountInfo = {
// Simulated profile data
firstname: 'John',
surname: "Doe",
location: {locationCode: "GB", locationName: "United Kingdom"},
email: 'john.doe@example.com',
accountType: 'lite',
referralCode: 'ABC123'
};*/
var accountInfo = localStorage.getItem("accountInfo") || null;
if(accountInfo)
{
accountInfo = JSON.parse(accountInfo);
// create and populate
populateOnboardFields(accountInfo);
}
// animate and show
lockScroll();
$('#onboard-modal ').animate({ opacity: 1 }).show();
}
function OpenAccountModal_Agency()
{
$('#agency-account-modal #modal-message-account').hide();
$('#agency-account-modal #account-message').hide().text("");
// empty the account modal
$('#agency-account-modal #accountInfoContainer').empty();
CreateMyAccount_Agency();
/*
var accountInfo = {};
accountInfo["firstname"] = firstname;
accountInfo["surname"] = surname;
accountInfo["location"] = {"locationName": locationName, "locationCode": locationCode};
accountInfo["email"] = email;
*/
/*var accountInfo = {
// Simulated profile data
firstname: 'John',
surname: "Doe",
location: {locationCode: "GB", locationName: "United Kingdom"},
email: 'john.doe@example.com',
accountType: 'lite',
referralCode: 'ABC123'
};*/
var accountInfo = localStorage.getItem("accountInfo") || null;
if(accountInfo)
{
accountInfo = JSON.parse(accountInfo);
// create and populate
populateAccountFields_Agency(accountInfo);
}
// order history - USE stripeinvoices instead
var invoiceArray = localStorage.getItem("StripeInvoices") || null;
//var invoiceArray = localStorage.getItem("orderHistory") || null;
if(invoiceArray && invoiceArray != "")
{
invoiceArray = JSON.parse(invoiceArray);
AddInvoices_Agency(invoiceArray);
}
// booking history
var bookingArray = localStorage.getItem("bookingHistory") || null;
if(bookingArray && bookingArray != "")
{
bookingArray = JSON.parse(bookingArray);
AddBookings_Agency(bookingArray);
}
var optIn = localStorage.getItem("optIn");
if(optIn !== undefined)
{
switch(optIn)
{
case true:
case "true":
$('#OptInOut').text('Opted-In').show();
break;
case false:
case "false":
$('#OptInOut').text('Opted-Out').show();
break;
}
}
// animate and show
$('#agency-account-modal').animate({ opacity: 1 }).show();
}
function AddBookings_Agency(bookingArray) {
// Ensure the input is an array
if (!Array.isArray(bookingArray)) {
console.error("AddBookings_Agency: Input is not a valid array.");
return;
}
// Iterate through the array
bookingArray.forEach(function(bookingRecord) {
// A quick check to make sure bookingRecord is a valid object before proceeding
if (!bookingRecord || typeof bookingRecord !== 'object') {
console.warn("Skipping invalid booking record.");
return; // Skip this iteration
}
// Use the nullish coalescing operator (??) to provide default values
const clientName = bookingRecord["ClientName"] ?? "N/A";
const createdDate = bookingRecord["Created"] ?? "N/A";
const bookingStatus = bookingRecord["BookingStatus"] ?? "N/A";
// Use optional chaining (?.) and nullish coalescing to safely access nested properties
const locationName = bookingRecord?.Location?.locationName ?? "N/A";
// The rest of your HTML generation code...
const dynamicHtml =
`
Client Name
${clientName}
Meeting Info
Created: ${createdDate} ${locationName}
`;
// Insert the dynamically created HTML
$('#agency-account-modal #booking-rule').last().after(dynamicHtml);
});
}
function AddBookings_Agency_OLD(bookingArray)
{
/*
bookingRecord["ClientID"] = customerObj["memberID"]; //
bookingRecord["TimeZone"] = MYPEAS_payload["timeZone"]; //
bookingRecord["BookingStatus"] = mode; //
bookingRecord["StartTime"] = MYPEAS_payload["startsAt"]; //
bookingRecord["BookingRef"] = MYPEAS_payload["bookingRef"]; //
bookingRecord["ClientName"] = MYPEAS_payload["firstName"] + " " + MYPEAS_payload["lastName"];
];*/
// Function to generate and insert HTML for each invoiceObj
bookingArray.forEach(function(bookingRecord) {
var dynamicHtml =
'
' +
'
Client Name
' +
'
' + bookingRecord["ClientName"] + '
' +
'
' +
'
' +
'
Meeting Info
' +
// MYPEAS_payload["Location"] = {"locationName": agentLocationName, "locationCode": agentLocationCode};
'
Created: ' + bookingRecord["Created"] + ' ' + bookingRecord["Location"]["locationName"] + '
' +
'
' +
'
' +
'
Status
' +
'
' + bookingRecord["BookingStatus"] + '
' +
'
';
// Insert the dynamically created HTML after the '#invoice-rule' element
// If you want all elements inserted exactly after '#invoice-rule', use .after() in combination with .last()
$('#agency-account-modal #booking-rule').last().after(dynamicHtml);
});
}
function populateAccountFields(accountInfo)
{
// only populate if the fields are not present
if($('#accountInfoContainer #email').val().trim().length == 0)
{
var accountModal = document.getElementById("account-modal");
var firstnameInputContainer = accountModal.querySelector('#firstnameInputContainer');
var surnameInputContainer = accountModal.querySelector('#surnameInputContainer');
var locationInputContainer = accountModal.querySelector('#locationInputContainer');
var emailInput = accountModal.querySelector('#email');
var accountType = accountModal.querySelector('#accountType');
var accountActionButton = accountModal.querySelector('#accountActionButton');
var referralCodeInput = accountModal.querySelector('#referralCode');
var confirmDeleteAccountBtn = document.querySelector('#btnDeleteAccountSubmit');
// Name
firstnameInputContainer.innerHTML = '
';
surnameInputContainer.innerHTML = '
';
if ('firstname' in accountInfo)
{
firstnameInputContainer.innerHTML = '
';
surnameInputContainer.innerHTML = '
';
}
// Location
// this will create the field
if($('#accountModal #countrySelect').length == 0)
{
addCountrySelect(accountModal.querySelector('#locationInputContainer'));
$('#account-modal #countrySelect').addClass("w-field");
}
// set the value
if("location" in accountInfo)
{
var location = accountInfo.location;
$('#account-modal #locationInputContainer #countrySelect').val(location.locationCode);
}
else
{
$('#account-modal #locationInputContainer #countrySelect').val("");
}
// Email
if("email" in accountInfo)
{
emailInput.value = accountInfo.email;
}
// Account Type
/*if("accountType" in accountInfo)
{
accountType.value = accountInfo.accountType;
updateAccountButton(accountType.value);
}
accountType.addEventListener('change', function() {
updateAccountButton(this.value);
});
// disable this field but make it black
$('#accountType').prop('disabled', true); // Disable the dropdown*/
// credit balance (number of credits/revisions available)
var revisions = localStorage.getItem("revisions") || "0";
$('#account-modal #creditBalance').val(revisions);
// Access and style the relevant elements like dropdown, options, borders, etc.
const dropdown = $('#account-modal #accountType');
dropdown.css('color', 'black');
dropdown.css('border', '1px solid black');
$('#account-modal #accountType').addClass("w-field");
/*var purchaseCreditsButton = document.getElementById('accountActionButton');
purchaseCreditsButton.addEventListener('click', function() {
//updateAccountButton(this.value);
// go to purchase credit page
$('#btnBuyNow').click();
});*/
var purchaseCreditsHolder = accountModal.querySelector("#purchaseCreditsHolder");
// Select the div you want to duplicate and the container where you want to append it
const productHolder = accountModal.querySelector("#product-holder");
// Clone the div
/* const clonedDiv = productHolder.cloneNode(true);
// Append the cloned div to the container
purchaseCreditsHolder.appendChild(clonedDiv);
$('#purchaseCreditsHolder #product-holder').show();
$('#purchaseCreditsHolder #btnBuyNow').text("Purchase Credit");*/
// change this so that it triggers the openmodal with purchase credit true
// this is called in loadmethods
/*var buyCreditBtn = document.getElementById('myAccountBuyBtn');
buyCreditBtn.addEventListener('click', (event) => {
OpenModal("Maximize Your AI Potential", "Need more help with your AI Strategy? Unlock it with a paid account", false, true);
});*/
//
var saveChangesBtn = document.getElementById("accountSaveChangesButton");
saveChangesBtn.addEventListener('click', function() {
SaveChanges();
});
// Referral Code
if("referralCode" in accountInfo)
{
referralCodeInput.value = accountInfo.referralCode;
}
var deleteAccountBtn = document.getElementById("deleteAccount");
deleteAccountBtn.addEventListener('click', function() {
OpenDeleteAccount();
});
confirmDeleteAccountBtn.addEventListener('click', function() {
ValidateDeleteAccount();
});
}
}
function populateOnboardFields(accountInfo)
{
// only populate if the fields are not present
//if($('#onboardInfoContainer #email').val().trim().length == 0)
if($('#onboardInfoContainer #firstname').length == 0)
{
var onboardModal = document.getElementById("onboard-modal");
var firstnameInputContainer = onboardModal.querySelector('#firstnameInputContainer');
var surnameInputContainer = onboardModal.querySelector('#surnameInputContainer');
var locationInputContainer = onboardModal.querySelector('#locationInputContainer');
var industryInputContainer = onboardModal.querySelector('#industryInputContainer'); ;
var companyInputContainer = onboardModal.querySelector('#companyInputContainer'); ;
var emailInput = onboardModal.querySelector('#email');
// Name
firstnameInputContainer.innerHTML = '
';
surnameInputContainer.innerHTML = '
';
//industryInputContainer.innerHTML = '
';
industryInputContainer.innerHTML = '
';
companyInputContainer.innerHTML = ' ';
if ('firstname' in accountInfo)
{
firstnameInputContainer.innerHTML = ' ';
surnameInputContainer.innerHTML = ' ';
}
// Location
// this will create the field
if($('#onboard-modeal #countrySelect').length == 0)
{
addCountrySelect(onboardModal.querySelector('#locationInputContainer'));
$('#onboard-modal #countrySelect').addClass("w-field");
}
// set the value
if("location" in accountInfo)
{
var location = accountInfo.location;
$('#onboard-modal #locationInputContainer #countrySelect').val(location.locationCode);
}
else
{
$('#onboard-modal #locationInputContainer #countrySelect').val("");
}
if("company" in accountInfo)
{
companyInputContainer.innerHTML = ' ';
}
else
{
companyInputContainer.innerHTML = ' ';
}
//GetIndustry();
if("industry" in accountInfo)
{
industryInputContainer.innerHTML = ' ';
}
else
{
industryInputContainer.innerHTML = ' ';
}
new TomSelect('#onboard_industry', {
create: false,
load: (query, callback) => {
// Fetch data from your S3 bucket
fetch('https://flexluthor.s3.eu-west-2.amazonaws.com/industry_list.json')
.then(response => response.json())
.then(data => {
// Filter data based on query
const filteredData = data.filter(item => item.label.toLowerCase().includes(query.toLowerCase()));
callback(filteredData);
})
.catch(error => console.error('Error fetching data:', error));
},
valueField: "id",
labelField: "label",
searchField: "label",
placeholder: "Enter your industry..."/*,
onChange: (value) => {
if (value) {
console.log("User selected a valid option:", value);
// Perform validation or further actions here
validateSelection(value);
} else {
console.log("Invalid selection or empty value.");
}
}*/
});
var onboardNext1 = document.getElementById('onboardNext_1');
var onboardNext2 = document.getElementById('onboardNext_2');
var onboardNext3 = document.getElementById('onboardNext_3');
var onboardNext4 = document.getElementById('onboardNext_4');
onboardNext1.addEventListener('click', function() {
//OnboardingNext(1);
// skip slide 2 until we update onboarding for new UI
OnboardingNext(2);
});
onboardNext2.addEventListener('click', function() {
OnboardingNext(2);
});
onboardNext3.addEventListener('click', function() {
OnboardingNext(3);
});
onboardNext4.addEventListener('click', function() {
OnboardingNext(4);
});
}
}
function GetIndustry()
{
//https://flexluthor.s3.eu-west-2.amazonaws.com/industry_list.json
new TomSelect('#onboard_industry', {
create: false,
load: (query, callback) => {
// Fetch data from your S3 bucket
fetch('https://flexluthor.s3.eu-west-2.amazonaws.com/industry_list.json')
.then(response => response.json())
.then(data => {
// Filter data based on query
const filteredData = data.filter(item => item.text.toLowerCase().includes(query.toLowerCase()));
callback(filteredData);
})
.catch(error => console.error('Error fetching data:', error));
},
valueField: "id",
labelField: "label",
searchField: "label",
placeholder: "Enter your industry...",
onChange: (value) => {
if (value) {
console.log("User selected a valid option:", value);
// Perform validation or further actions here
validateSelection(value);
} else {
console.log("Invalid selection or empty value.");
}
}
});
new TomSelect("#onboard_industry", {
options: industryData,
valueField: "id",
labelField: "label",
searchField: "label",
placeholder: "Enter your industry...",
create: false, // Prevents free-form input
onChange: (value) => {
if (value) {
console.log("User selected a valid option:", value);
// Perform validation or further actions here
//validateSelection(value);
} else {
console.log("Invalid selection or empty value.");
}
}
});
}
function populateAccountFields_Agency(accountInfo)
{
// only populate if the fields are not present
if($('#agency-account-modal #accountInfoContainer #email').val().trim().length == 0)
{
var agencyAccountModal = document.getElementById("agency-account-modal");
var firstnameInputContainer = agencyAccountModal.querySelector('#firstnameInputContainer');
var surnameInputContainer = agencyAccountModal.querySelector('#surnameInputContainer');
var surnameInputContainer = agencyAccountModal.querySelector('#surnameInputContainer');
var companyInputContainer = agencyAccountModal.querySelector('#companyInputContainer');
var locationInputContainer = agencyAccountModal.querySelector('#agent-account-location-container');
var emailInputContainer = agencyAccountModal.querySelector('#emailInputContainer');
var telephoneInputContainer = agencyAccountModal.querySelector('#agent-account-telephone-container');
var emailInput = agencyAccountModal.querySelector('#email');
var phoneInput = agencyAccountModal.querySelector('#phone');
var accountType = agencyAccountModal.querySelector('#accountType');
var accountActionButton = agencyAccountModal.querySelector('#accountActionButton');
var referralCodeInput = agencyAccountModal.querySelector('#referralCode');
// Name
firstnameInputContainer.innerHTML = ' ';
surnameInputContainer.innerHTML = ' ';
if ('FirstName' in accountInfo)
{
firstnameInputContainer.innerHTML = ' ';
surnameInputContainer.innerHTML = ' ';
}
// company name
companyInputContainer.innerHTML = ' ';
if ('CompanyName' in accountInfo)
{
companyInputContainer.innerHTML = ' ';
}
// Email
if("WorkEmail" in accountInfo)
{
emailInput.value = accountInfo.WorkEmail;
}
// telephone
// phone country code
if($('#agency-account-modal #countryCode').length == 0)
{
addCountryCode(document.querySelector("#agency-account-modal #agent-account-telephone-container"));
}
// phone number
// set value
if("TelephoneCode" in accountInfo)
{
$("#agency-account-modal #countryCode").val(accountInfo.TelephoneCode);
}
if("TelephoneNo" in accountInfo)
{
$("#agency-account-modal #phone").val(accountInfo.TelephoneNo);
}
// Location
// this will create the field
if($('#agency-account-modal #countrySelect').length == 0)
{
addCountrySelect(document.querySelector("#agency-account-modal #agent-account-location-container"));
$('#agency-account-modal #countrySelect').addClass("w-field");
}
// set the value
if("Location" in accountInfo)
{
var location = accountInfo.Location;
$('#agency-account-modal #agent-account-location-container #countrySelect').val(location.locationCode);
}
else
{
$('#agency-account-modal #agent-account-location-container #countrySelect').val("");
}
// Credit balance
// credit balance (number of credits to purchase leads)
var revisions = localStorage.getItem("credits") || "0";
$('#creditBalance').val(revisions);
/*var purchaseCreditsButton = document.getElementById('accountActionButton');
purchaseCreditsButton.addEventListener('click', function() {
//updateAccountButton(this.value);
// go to purchase credit page
$('#btnBuyNow').click();
});*/
var purchaseCreditsHolder = document.getElementById("purchaseCreditsHolder");
// Select the div you want to duplicate and the container where you want to append it
const productHolder = document.getElementById("dashboard-buy-credits");
// Clone the div
const clonedDiv = productHolder.cloneNode(true);
// Append the cloned div to the container
purchaseCreditsHolder.appendChild(clonedDiv);
$('#agency-account-modal #purchaseCreditsHolder #dashboard-buy-credits').show();
var saveChangesBtn = document.getElementById("accountSaveChangesButton");
saveChangesBtn.addEventListener('click', function() {
SaveChanges_Agency();
});
// Referral Code
if("referralCode" in accountInfo)
{
referralCodeInput.value = accountInfo.referralCode;
}
var deleteAccountBtn = document.getElementById("deleteAccount");
deleteAccountBtn.addEventListener('click', function() {
OpenDeleteAccount();
});
}
}
function AddInvoices_Agency(invoiceArray)
{
// Function to generate and insert HTML for each invoiceObj
invoiceArray.forEach(function(invoiceObj) {
var dynamicHtml = '' +
'
' + invoiceObj.invoiceDate + '
' +
'
' +
'[View Invoice] ' +
'
' +
'
';
// Insert the dynamically created HTML after the '#invoice-rule' element
// If you want all elements inserted exactly after '#invoice-rule', use .after() in combination with .last()
$('#agency-account-modal #invoice-rule').last().after(dynamicHtml);
});
}
function updateAccountButton(accountType)
{
//var button = document.getElementById('accountActionButton');
var button = document.getElementById('btnBuyNow');
/*if (accountType === 'lite') {
button.textContent = 'Upgrade to Pro';
} else {
button.textContent = 'Purchase Credits';
}*/
button.textContent = 'Purchase Credits';
}
function copyReferralCode() {
var referralCodeInput = document.getElementById('referralCode');
referralCodeInput.select();
document.execCommand('copy');
alert('Referral code copied to clipboard.');
}
function OpenCalendarModal()
{
// hide spinner and // hide message
$('#calendar-spinner').hide();
var calendarMessage = "";
// hide message
$('#calendar-message').text(calendarMessage).hide();
// animate and show
$('#calendar-holder-modal').animate({ opacity: 1 }).show();
}
function SaveChanges()
{
try
{
var accountModal = document.querySelector('#account-modal');
// input fields
var inputfirstName = accountModal.querySelector('#firstname');
var inputsurname = accountModal.querySelector('#surname');
var inputlocation = accountModal.querySelector('#countrySelect');
var inputemail = accountModal.querySelector('#email');
// validate fields
var failed = false;
var validateFirstName = accountModal.querySelector('#validateAccountfirstname');
var validateSurname = accountModal.querySelector('#validateAccountSurname');
var validateLocation = accountModal.querySelector('#validateLocation');
var validateEmail = accountModal.querySelector('#validateAccountEmail');
var validationMessages = [];
// hide all validation messages
validateEmail.style.display = 'none';
validateFirstName.style.display = 'none';
validateSurname.style.display = 'none';
validateLocation.style.display = 'none';
var email = $('#account-modal #email').val();
if(!isValidEmail(email))
{
failed = true;
validateEmail.textContent = "Please enter a valid email";
validateEmail.style.display = 'block';
validationMessages.push(validateEmail.id);
}
var nameRegex = /^[A-Za-z\s\-]+$/; // Regex to allow letters, spaces, and hyphens
var firstname = $('#account-modal #firstname').val();
var surname = $('#account-modal #surname').val();
var locationName = $('#account-modal #countrySelect option:selected').text();
var locationCode = $('#account-modal #countrySelect').val();
if(firstname.trim() == "" || !nameRegex.test(firstname.trim()))
{
failed = true;
//validateFirstName.textContent = "Please enter a valid email";
validateFirstName.style.display = 'block';
validationMessages.push(validateFirstName.id);
}
if(surname.trim() == "" || !nameRegex.test(surname.trim()))
{
failed = true;
//validateFirstName.textContent = "Please enter a valid email";
validateSurname.style.display = 'block';
validationMessages.push(validateSurname.id);
}
if(locationName.trim() == "" || locationCode.trim() == "" )
{
failed = true;
validateLocation.style.display = 'block';
validationMessages.push(validateLocation.id);
}
if(!failed)
{
// disable the buttons until complete
$("#accountActionButton").prop("disabled", true);
$("#accountSaveChangesButton").prop("disabled", true);
$("#deleteAccount").prop("disabled", true);
$('#account-modal #modal-spinner').show();
var accountInfo = {};
accountInfo["firstname"] = firstname;
accountInfo["surname"] = surname;
accountInfo["location"] = {"locationName": locationName, "locationCode": locationCode};
accountInfo["email"] = email;
var accountType = localStorage.getItem("paidAccount");
switch(accountType)
{
case "true":
accountInfo["accountType"] = "full";
break;
case "false":
accountInfo["accountType"] = "lite";
break;
}
var memberID = localStorage.getItem("memberID");
var authToken = localStorage.getItem("auth_token");
accountInfo["referralCode"] = memberID;
// show spinner
$('#account-modal #modal-spinner').show();
// updatefield on server
UpdateDBField(memberID, authToken, "accountInfo", JSON.stringify(accountInfo))
.then(message => {
// re-enable
$("#accountActionButton").prop("disabled", false);
$("#accountSaveChangesButton").prop("disabled", false);
$("#deleteAccount").prop("disabled", false);
switch(message)
{
case "FieldUpdate Complete":
ConsoleLog("account updated");
$('#account-modal #modal-spinner').hide();
$('#account-message').show().text("Your changes were successfully saved.");
localStorage.setItem("accountInfo", JSON.stringify(accountInfo));
break;
case "FieldUpdate Failed":
case "Error updating account information":
case "Error updating account information":
ConsoleLog("account update failed");
$('#account-modal #modal-spinner').hide();
$('#account-message').show().text("There was a problem updating your account information. Please try again.");
break;
}
})
.catch(error => console.error("Error calling UpdateDBField: ", error));
}
}
catch(err)
{
// re-enable
$("#accountActionButton").prop("disabled", false);
$("#accountSaveChangesButton").prop("disabled", false);
$("#deleteAccount").prop("disabled", false);
$('#account-modal #modal-spinner').hide();
}
}
function OnboardingNext(step)
{
try
{
switch(step)
{
case 1:
$('#onboard-progress #onboard-progress-1').removeClass('inactive');
$('#onboard-progress #onboard-progress-2').removeClass('inactive');
//$('#onboard-progress #onboard-progress-3').removeClass('inactive');
//$('#onboard-progress #onboard-progress-4').removeClass('inactive');
// change titles
$('#onboard-modal #modal-title').text("What is in my MYPEAS.AI roadmap?");
$('#onboardSubheading').text("A Clear Path to Unlocking AI’s Potential in Your Role");
// populate the message paragraph
$('#description-holder').show();
$('#onboard_start_description').text('Your MYPEAS.AI roadmap gives you a customized, step-by-step guide to integrating AI into your work. By breaking down your role into segments, activities, and steps, it reveals exactly where AI can provide real impact.');
$('#description-holder').hide();
// hide this page
$('#onboard1').hide();
// show next page
$('#onboard2').show();
break;
case 2:
$('#onboard-progress #onboard-progress-1').removeClass('inactive');
$('#onboard-progress #onboard-progress-2').removeClass('inactive');
$('#onboard-progress #onboard-progress-3').removeClass('inactive');
//$('#onboard-progress #onboard-progress-4').removeClass('inactive');
// hide this page
$('#onboard1').hide();
$('#onboard2').hide();
// show next page
$('#onboard3').show();
// With your free account, you’ll receive a curated AI roadmap and essential recommendations
// change titles
$('#onboard-modal #modal-title').text("What do I get in my Free account?");
$('#onboardSubheading').text("Your AI Roadmap for Smarter Workflows");
// populate the message paragraph
$('#description-holder').show();
$('#onboard_start_description').text('With your free account, you’ll receive a curated AI roadmap and essential recommendations—but upgrade to Pro to unlock the complete and comprehensive, profile tailored to your role.');
break;
case 3:
$('#onboard-progress #onboard-progress-1').removeClass('inactive');
$('#onboard-progress #onboard-progress-2').removeClass('inactive');
$('#onboard-progress #onboard-progress-3').removeClass('inactive');
$('#onboard-progress #onboard-progress-4').removeClass('inactive');
// hide this page
$('#onboard3').hide();
// show next page
$('#onboard4').show();
// change titles
$('#onboard-modal #modal-title').text("You're nearly set!");
$('#onboardSubheading').text("Complete your profile information");
// populate the message paragraph
$('#description-holder').show();
$('#onboard_start_description').text('Your roadmap is personal. We tailor the AI roadmap to your specific role and work environment, making the recommendations more relevant and impactful for your unique needs.');
break;
case 4:
var onboardModal = document.querySelector('#onboard-modal');
// input fields
var inputfirstName = onboardModal.querySelector('#firstname');
var inputsurname = onboardModal.querySelector('#surname');
var inputlocation = onboardModal.querySelector('#countrySelect');
// validate fields
var failed = false;
var validateFirstName = onboardModal.querySelector('#validateAccountfirstname');
var validateSurname = onboardModal.querySelector('#validateAccountSurname');
var validateLocation = onboardModal.querySelector('#validateLocation');
var validateIndustry = onboardModal.querySelector('#validateIndustry');
var validateCompany = onboardModal.querySelector('#validateCompany');
var validationMessages = [];
// hide all validation messages
validateFirstName.style.display = 'none';
validateSurname.style.display = 'none';
validateLocation.style.display = 'none';
validateIndustry.style.display = 'none';
validateCompany.style.display = 'none';
var nameRegex = /^[A-Za-z\s\-]+$/; // Regex to allow letters, spaces, and hyphens
var firstname = $('#onboard-modal #firstname').val();
var surname = $('#onboard-modal #surname').val();
var locationName = $('#onboard-modal #countrySelect option:selected').text();
var locationCode = $('#onboard-modal #countrySelect').val();
var industryCode = $('#onboard-modal #onboard_industry').val();
var company = $('#onboard-modal #onboard_company').val();
if(firstname.trim() == "" || !nameRegex.test(firstname.trim()))
{
failed = true;
//validateFirstName.textContent = "Please enter a valid email";
validateFirstName.style.display = 'block';
validationMessages.push(validateFirstName.id);
}
if(surname.trim() == "" || !nameRegex.test(surname.trim()))
{
failed = true;
//validateFirstName.textContent = "Please enter a valid email";
validateSurname.style.display = 'block';
validationMessages.push(validateSurname.id);
}
if(locationName.trim() == "" || locationCode.trim() == "" )
{
failed = true;
validateLocation.style.display = 'block';
validationMessages.push(validateLocation.id);
}
if(industryCode.trim() == "")
{
failed = true;
validateIndustry.style.display = 'block';
validationMessages.push(validateIndustry.id);
}
if(company.trim() == "")
{
failed = true;
validateCompany.style.display = 'block';
validationMessages.push(validateCompany.id);
}
if(!failed)
{
// disable the buttons until complete
//$("#onboardNext_3").prop("disabled", true);
$('#onboard-modal #modal-spinner').show();
var email = localStorage.getItem("email");
var accountInfo = {};
accountInfo["firstname"] = firstname;
accountInfo["surname"] = surname;
accountInfo["location"] = {"locationName": locationName, "locationCode": locationCode};
accountInfo["email"] = email;
accountInfo["company"] = company;
accountInfo["industry"] = industryCode;
accountInfo["onboard"] = true;
var accountType = localStorage.getItem("paidAccount");
switch(accountType)
{
case "true":
accountInfo["accountType"] = "full";
break;
case "false":
accountInfo["accountType"] = "lite";
break;
}
var memberID = localStorage.getItem("memberID");
var authToken = localStorage.getItem("auth_token");
accountInfo["referralCode"] = memberID;
// show spinner
$('#onboard-modal #modal-spinner').show();
// updatefield on server
UpdateDBField(memberID, authToken, "accountInfo", JSON.stringify(accountInfo))
.then(message => {
// re-enable
$("#onboardNext").prop("disabled", false);
switch(message)
{
case "FieldUpdate Complete":
ConsoleLog("account updated: onboarded");
$('#onboard-modal #modal-spinner').hide();
// go to next page
localStorage.setItem("accountInfo", JSON.stringify(accountInfo));
break;
case "FieldUpdate Failed":
case "Error updating account information":
case "Error updating account information":
ConsoleLog("account update failed: not onboarded");
$('#onboard-modal #modal-spinner').hide();
//$('#onboard-modal #account-message').show().text("There was a problem updating your account information. Please try again.");
break;
}
})
.catch(error => console.error("Error calling UpdateDBField: ", error));
// save the accountinfo updates
// scrolltop
// reset as it closes
$('#onboard-progress #onboard-progress-1').addClass('inactive');
$('#onboard-progress #onboard-progress-2').addClass('inactive');
$('#onboard-progress #onboard-progress-3').addClass('inactive');
// hide this page
$('#onboard3').hide();
// show next page
$('#onboard1').show();
// show myaccount and my apps
$('#btnFavourites').show();
$('#btnMyAccount').show();
// trigger confetti
TriggerConfetti();
// scroll top
window.scrollTo({
top: 0,
behavior: 'smooth'
});
// close the modal
CloseOnboardModal();
}
break;
}
}
catch(err)
{
// re-enable
$("#onboardNext").prop("disabled", false);
$('#onboard-modal #modal-spinner').hide();
}
}
function SaveChanges_Agency()
{
try
{
var accountModal = document.querySelector('#account-modal');
// input fields
var inputfirstName = accountModal.querySelector('#firstname');
var inputsurname = accountModal.querySelector('#surname');
var inputlocation = accountModal.querySelector('#countrySelect');
var inputemail = accountModal.querySelector('#email');
// validate fields
var failed = false;
var validateFirstName = accountModal.querySelector('#validateAccountfirstname');
var validateSurname = accountModal.querySelector('#validateAccountSurname');
var validateLocation = accountModal.querySelector('#validateLocation');
var validateEmail = accountModal.querySelector('#validateAccountEmail');
var validationMessages = [];
// hide all validation messages
validateEmail.style.display = 'none';
validateFirstName.style.display = 'none';
validateSurname.style.display = 'none';
validateLocation.style.display = 'none';
var email = $('#account-modal #email').val();
if(!isValidEmail(email))
{
failed = true;
validateEmail.textContent = "Please enter a valid email";
validateEmail.style.display = 'block';
validationMessages.push(validateEmail.id);
}
var nameRegex = /^[A-Za-z\s\-]+$/; // Regex to allow letters, spaces, and hyphens
var firstname = $('#account-modal #firstname').val();
var surname = $('#account-modal #surname').val();
var locationName = $('#account-modal #countrySelect option:selected').text();
var locationCode = $('#account-modal #countrySelect').val();
if(firstname.trim() == "" || !nameRegex.test(firstname.trim()))
{
failed = true;
//validateFirstName.textContent = "Please enter a valid email";
validateFirstName.style.display = 'block';
validationMessages.push(validateFirstName.id);
}
if(surname.trim() == "" || !nameRegex.test(surname.trim()))
{
failed = true;
//validateFirstName.textContent = "Please enter a valid email";
validateSurname.style.display = 'block';
validationMessages.push(validateSurname.id);
}
if(locationName.trim() == "" || locationCode.trim() == "" )
{
failed = true;
validateLocation.style.display = 'block';
validationMessages.push(validateLocation.id);
}
if(!failed)
{
// disable the buttons until complete
$("#accountActionButton").prop("disabled", true);
$("#accountSaveChangesButton").prop("disabled", true);
$("#deleteAccount").prop("disabled", true);
$('#account-modal #modal-spinner').show();
var accountInfo = {};
accountInfo["firstname"] = firstname;
accountInfo["surname"] = surname;
accountInfo["location"] = {"locationName": locationName, "locationCode": locationCode};
accountInfo["email"] = email;
var accountType = localStorage.getItem("paidAccount");
switch(accountType)
{
case "true":
accountInfo["accountType"] = "full";
break;
case "false":
accountInfo["accountType"] = "lite";
break;
}
var memberID = localStorage.getItem("memberID");
var authToken = localStorage.getItem("auth_token");
accountInfo["referralCode"] = memberID;
// show spinner
$('#account-modal #modal-spinner').show();
// updatefield on server
UpdateDBField(memberID, authToken, "accountInfo", JSON.stringify(accountInfo))
.then(message => {
// re-enable
$("#accountActionButton").prop("disabled", false);
$("#accountSaveChangesButton").prop("disabled", false);
$("#deleteAccount").prop("disabled", false);
switch(message)
{
case "FieldUpdate Complete":
ConsoleLog("account updated");
$('#account-modal #modal-spinner').hide();
$('#account-message').show().text("Your changes were successfully saved.");
localStorage.setItem("accountInfo", JSON.stringify(accountInfo));
break;
case "FieldUpdate Failed":
case "Error updating account information":
case "Error updating account information":
ConsoleLog("account update failed");
$('#account-modal #modal-spinner').hide();
$('#account-message').show().text("There was a problem updating your account information. Please try again.");
break;
}
})
.catch(error => console.error("Error calling UpdateDBField: ", error));
}
}
catch(err)
{
// re-enable
$("#accountActionButton").prop("disabled", false);
$("#accountSaveChangesButton").prop("disabled", false);
$("#deleteAccount").prop("disabled", false);
$('#account-modal #modal-spinner').hide();
}
}
// Function to get selected option's value and text
function getSelectedOption() {
var selectedValue = $('#countrySelect').val(); // Get selected option value
var selectedText = $('#countrySelect option:selected').text(); // Get selected option text
// Return both value and text
return { value: selectedValue, text: selectedText };
}
function validateCountrySelect() {
// find what is visible
var accountModalVisible = $('#account-modal').is(':visible');
var leadModalVisible = $('#lead-modal').is(':visible');
var container = document;
if(accountModalVisible)
{
container = document.querySelector('#account-modal');
}
if(leadModalVisible)
{
container = document.querySelector('#lead-modal');
}
var countrySelect = container.querySelector('#countrySelect');
var errorDiv = container.querySelector('#validateCountrySelect');
if (window.location.href.toLowerCase().includes('/agency'))
{
errorDiv = container.querySelector('#validateAgentLocation');
}
if (countrySelect.value) {
// If a country is selected, hide the error message
errorDiv.style.display = 'none';
return true;
} else {
// If no country is selected, show the error message
errorDiv.style.display = 'block';
return false;
}
}
function validateAndShowNext(nextPageId) {
// Validate the country select dropdown
if (validateCountrySelect()) {
// If validation passes, proceed to the next page
showNext(nextPageId);
}
// If validation fails, it will not proceed and show the error message
}
/* app modal */
function OpenAppModal(item, containerID)
{
// reset fields - do this at end
setData('#' + containerID, item);
$('#' + containerID + ' #modal-spinner').hide();
$('#app-modal #modal-title').hide();
// animate and show
//$('#' + containerID).animate({ opacity: 1 }).show();
$('#app-modal').animate({ opacity: 1 }).show();
}
function CloseCategoryModal()
{
$('#category-modal').animate({ opacity: 0 }).hide();
unLockScroll();
}
function CloseLeadModal()
{
$('#lead-modal').animate({ opacity: 0 }).hide();
unLockScroll();
}
function CloseAppModal()
{
$('#app-modal').animate({ opacity: 0 }).hide();
unLockScroll();
}
function CloseFavouritesModal()
{
$('#favourites-modal').animate({ opacity: 0 }).hide();
unLockScroll();
}
function CloseAccountModal()
{
$('#account-modal').animate({ opacity: 0 }).hide();
unLockScroll();
}
function CloseOnboardModal()
{
// show myaccount and my apps
$('#btnFavourites').show();
$('#btnMyAccount').show();
$('#onboard-modal').animate({ opacity: 0 }).hide();
unLockScroll();
}
function CloseDeleteModal()
{
$('#delete-account-modal').animate({ opacity: 0 }).hide();
unLockScroll();
}
function CloseCalendarModal()
{
$('#calendar-holder-modal').animate({ opacity: 0 }).hide();
unLockScroll();
}
function bringModalToFront(modalId) {
const elements = document.querySelectorAll('*');
let highestZIndex = 0;
for (const element of elements) {
const zIndex = parseInt(element.style.zIndex || 0);
if (zIndex > highestZIndex) {
highestZIndex = zIndex;
}
}
const modal = document.getElementById(modalId);
modal.style.zIndex = highestZIndex + 1;
}
function goBack(questionId)
{
// Hide all questions
var questions = document.getElementsByClassName('question');
for (var i = 0; i < questions.length; i++) {
questions[i].style.display = 'none';
}
// Show the specified question
document.getElementById(questionId).style.display = 'block';
}
function showNext(questionId)
{
var goToNext = false;
var submitForm = false;
var questionnaireAnswers = {};
switch(questionId)
{
case "q1":
// Hide spinner
$('#contact-spinner-flex').hide();
$('#btnSubmitContact').show();
$('#contact-message').hide();
$('#contact-message').val('');
// Hide all questions
var questions = document.getElementsByClassName('question');
for (var i = 0; i < questions.length; i++) {
questions[i].style.display = 'none';
}
goToNext = true;
break;
// question 1
case "q2":
var checkboxes = document.querySelectorAll('#q1 .w-checkbox-input');
var isAnyCheckboxChecked = Array.from(checkboxes).some(checkbox => checkbox.checked);
var isOtherChecked = document.getElementById('other').checked;
var otherText = document.getElementById('interest_specify_other').value;
var errorMessage = '';
// Check if at least one checkbox is checked
if (!isAnyCheckboxChecked) {
errorMessage = 'Please select at least one option.';
}
// Check if "Other" is selected and textarea has less than 20 characters
else if (isOtherChecked && otherText.length < 20) {
errorMessage = 'Please enter at least 20 characters in the text area.';
}
// Show or hide error message
var errorDiv = document.getElementById('validateInterest');
if (errorMessage)
{
errorDiv.textContent = errorMessage;
errorDiv.style.display = 'block';
}
else
{
errorDiv.style.display = 'none';
goToNext = true;
}
// Show or hide textarea based on the "Other" checkbox
document.getElementById('interest_specify_other').style.display = isOtherChecked ? 'block' : 'none';
break;
// question 2
case "q3":
document.getElementById('locationPreference').addEventListener('change', function() {
var value = this.value;
var regionSelect = document.getElementById('regionSelect');
if (value === 'specificRegion') {
regionSelect.style.display = 'block';
} else {
regionSelect.style.display = 'none';
}
});
if (validateCountrySelect())
{
// If validation passes, proceed to the next page
goToNext = true;
}
break;
// question 3
case "q4":
goToNext = true;
break;
// question 4
case "q5":
goToNext = true;
break;
// question 5
case "q6":
var checkboxes = document.querySelectorAll('#q5 .w-checkbox-input');
var isAnyCheckboxChecked = Array.from(checkboxes).some(checkbox => checkbox.checked);
var errorDiv = document.getElementById('validatePrimaryGoal');
if (!isAnyCheckboxChecked) {
// If no checkbox is checked, show the error message
errorDiv.textContent = 'Please select at least one option.';
errorDiv.style.display = 'block';
} else {
// If any checkbox is checked, hide the error message and proceed
errorDiv.style.display = 'none';
goToNext = true;
}
break;
// question 6
case "q7":
var checkboxes = document.querySelectorAll('#q6 .w-checkbox-input');
var isAnyCheckboxChecked = Array.from(checkboxes).some(checkbox => checkbox.checked);
var errorDiv = document.getElementById('validateServiceChoice');
if (!isAnyCheckboxChecked) {
// If no checkbox is checked, show the error message
errorDiv.textContent = 'Please select at least one service option.';
errorDiv.style.display = 'block';
} else {
// If any checkbox is checked, hide the error message and proceed
errorDiv.style.display = 'none';
goToNext = true;
}
break;
// question 7
case "q8":
var textarea = document.getElementById('additionalDetails');
var errorDiv = document.getElementById('validateDescribe');
// better to be optional
/*if (textarea.value.length < 40) {
// If the textarea content is less than 40 characters, show the error message
errorDiv.textContent = 'Please provide more details (at least 40 characters).';
errorDiv.style.display = 'block';
} else {
// If the textarea content meets the requirement, hide the error message and proceed
errorDiv.style.display = 'none';
goToNext = true;
} */
goToNext = true;
break;
// question 8
case "END":
// validate fields on the contact form
var isValid = true;
// Validate First Name
var firstName = document.getElementById('txtFirstName');
var errorFirstName = document.getElementById('validateFirstName');
if (!firstName.value.trim()) {
errorFirstName.textContent = 'First Name is required.';
errorFirstName.style.display = 'block';
isValid = false;
} else {
errorFirstName.style.display = 'none';
}
// Validate Surname
var surname = document.getElementById('txtSurname');
var errorSurname = document.getElementById('validateSurname');
if (!surname.value.trim()) {
errorSurname.textContent = 'Surname is required.';
errorSurname.style.display = 'block';
isValid = false;
} else {
errorSurname.style.display = 'none';
}
// Validate Email
var email = document.getElementById('txtEmail');
var errorEmail = document.getElementById('validateEmail');
// Simple email validation check
var emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
if (!email.value.trim() || !emailRegex.test(email.value)) {
errorEmail.textContent = 'A valid Email is required.';
errorEmail.style.display = 'block';
isValid = false;
} else {
errorEmail.style.display = 'none';
}
// validate country code
var countryCode = document.getElementById('countryCode');
var errorCountryCode = document.getElementById('validateCountryCode');
var isValid = true; // Assuming you have this variable declared somewhere in your code
if (!countryCode.value.trim()) {
errorCountryCode.textContent = 'Country Code is required';
errorCountryCode.style.display = 'block';
isValid = false;
} else {
errorCountryCode.style.display = 'none';
}
// Validate Telephone
var telephone = document.getElementById('txtTelephone');
var errorTelephone = document.getElementById('validateTelephone');
if (!telephone.value.trim()) {
errorTelephone.textContent = 'Telephone is required.';
errorTelephone.style.display = 'block';
isValid = false;
} else if (countryCode.value.trim() === "+44" && telephone.value.trim().length < 11) {
errorTelephone.textContent = 'Telephone number must be at least 11 digits for +44 country code.';
errorTelephone.style.display = 'block';
isValid = false;
} else {
errorTelephone.style.display = 'none';
}
// Validate Terms and Conditions Checkbox
var termsCheckbox = document.getElementById('checkboxContactAgreeTerms');
var errorTerms = document.getElementById('validateContactAgreeTerms');
if (!termsCheckbox.checked) {
errorTerms.textContent = 'You must agree to the Terms and Conditions.';
errorTerms.style.display = 'block';
isValid = false;
} else {
errorTerms.style.display = 'none';
}
// Proceed if all validations pass
if (isValid) {
goToNext = false;
submitForm = true;
questionnaireAnswers = storeQuestionnaire();
}
break;
}
if(goToNext)
{
// Hide all questions
var questions = document.getElementsByClassName('question');
for (var i = 0; i < questions.length; i++) {
questions[i].style.display = 'none';
}
// Show the specified question
document.getElementById(questionId).style.display = 'block';
}
if(submitForm)
{
// show spinner
$('#contact-spinner-flex').show();
//$('#contact-spinner-flex').hide();
$('#contact-spinner').show();
$('#btnSubmitContact').hide();
// get user info from page
//var profile = JSON.parse($('#JobInfo').val());
var memberIDValue = localStorage.getItem("memberID");
// send request to store callback request
// Make an API call to API gateway
//var apiUrl = "https://v8flgw65bg.execute-api.eu-west-1.amazonaws.com/default/AIToolSearch";
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
var LeadData = {};
LeadData["UserId"] = memberIDValue; // get memberID from profile
LeadData["LeadValue"] = questionnaireAnswers; // store the lead object
LeadData["LeadCount"] = 0; // start count at 0. max 3
const requestData = {};
// initial search uses the long search query (this is the title of the step)
requestData["LeadData"] = LeadData;
/* var PaidUpdateData = {};
PaidUpdateData["promptDescription"] = "PaidUpdate";
// change this. get memberID from localstorage. set this
PaidUpdateData["memberID"] = GetParam("memberID");
PaidUpdateData["orderID"] = GetParam("orderId");
// https://mypeas.ai/?reset-password=yes&OTC=${OTC}&memberID=${memberIDValue}
const requestData = {};
requestData["PaidUpdateData"] = PaidUpdateData; */
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
// hide spinner
//$('#contact-spinner-flex').hide();
$('#contact-spinner').hide();
$('#btnSubmitContact').show();
ConsoleLog("Request Lead return: ",JSON.stringify(result));
var message = result["message"];
switch(message)
{
case "Lead Request Exists. Less Than Threshold":
$('#contact-message').show();
$('#contact-message').text('You have already made a request in the last 48 hours. It is being processed');
break;
case "Lead Request Updated.":
case "Lead Request Created.":
$('#contact-message').show();
$('#contact-message').text('Your request has been submitted.');
// close in 2 seconds
//setTimeout(CloseLeadModal, 2000);
// show success screen
showNext("leadSuccess");
break;
case "Internal Server Error":
case "LeadRegister Failed":
$('#contact-message').show();
$('#contact-message').text('Your request failed. Please try again later.');
break;
}
});
}
}
function storeQuestionnaire()
{
//document.getElementById('btnSubmitContact').addEventListener('click', function() {
var questionnaireAnswers = {
interest: [],
country: '',
locationPreference: '',
budget: 0,
primaryGoal: [],
servicesNeeded: [],
specificNeeds: '',
contactDetails: {
firstName: '',
surname: '',
email: '',
telephone: ''
},
agreeToTerms: false
};
// Collecting answers for the 'interest' checkboxes
document.querySelectorAll('#q1 .w-checkbox-input').forEach(function(checkbox) {
if (checkbox.checked) {
questionnaireAnswers.interest.push(checkbox.id);
}
});
// Country
var countrySelect = document.getElementById('countrySelect_holder').querySelector('select');
if (countrySelect) {
const selectedOption = countrySelect.options[countrySelect.selectedIndex]; // Get the selected option element
questionnaireAnswers.country = {
value: countrySelect.value,
text: selectedOption.textContent // Use the textContent of the selectedOption
};
}
// Location Preference
questionnaireAnswers.locationPreference = document.getElementById('locationPreference').value;
// Budget
questionnaireAnswers.budget = document.getElementById('budgetSlider').value;
// Primary Goal
/*document.querySelectorAll('#q5 .w-checkbox-input').forEach(function(checkbox) {
if (checkbox.checked) {
questionnaireAnswers.primaryGoal.push(checkbox.id);
}
});*/
document.querySelectorAll('#q5 .w-checkbox-input').forEach(function(checkbox) {
if (checkbox.checked) {
const checkboxId = checkbox.id;
// Find the label's span element associated with this checkbox
const labelSpan = document.querySelector(`span[for="${checkboxId}"]`);
// Get the text content of the span
const labelText = labelSpan ? labelSpan.textContent.trim() : '';
questionnaireAnswers.primaryGoal = { id: checkboxId, text: labelText };
}
});
// Services Needed
/*document.querySelectorAll('#q6 .w-checkbox-input').forEach(function(checkbox) {
if (checkbox.checked) {
questionnaireAnswers.servicesNeeded.push(checkbox.id);
}
});*/
document.querySelectorAll('#q6 .w-checkbox-input').forEach(function(checkbox) {
if (checkbox.checked) {
const checkboxId = checkbox.id;
// Find the label's span element associated with this checkbox
const labelSpan = document.querySelector(`span[for="${checkboxId}"]`);
// Get the text content of the span
const labelText = labelSpan ? labelSpan.textContent.trim() : '';
// Ensure the array is initialized before pushing (if not already done elsewhere)
//questionnaireAnswers.servicesNeeded = questionnaireAnswers.servicesNeeded || [];
questionnaireAnswers.servicesNeeded = { id: checkboxId, text: labelText };
}
});
// Specific Needs or Requirements
questionnaireAnswers.specificNeeds = document.getElementById('additionalDetails').value;
// Contact Details
questionnaireAnswers.contactDetails.firstName = document.getElementById('txtFirstName').value;
questionnaireAnswers.contactDetails.surname = document.getElementById('txtSurname').value;
questionnaireAnswers.contactDetails.email = document.getElementById('txtEmail').value;
questionnaireAnswers.contactDetails.telephone = document.getElementById('txtTelephone').value;
// Agree to Terms and Conditions
questionnaireAnswers.agreeToTerms = document.getElementById('checkboxContactAgreeTerms').checked;
ConsoleLog(questionnaireAnswers); // Logging the answers to the console. Replace this with your desired action.
return questionnaireAnswers;
// Add your logic here to handle the questionnaireAnswers object, like sending it to a server or storing it locally
//});
}
/* next */
function SubmitForgotPassword()
{
var email = document.getElementById('txtForgotPasswordEmail').value;
var failed = false;
var validateEmail = document.getElementById('validateForgotPasswordEmail');
var validationMessages = [];
// hide all validation messages
validateEmail.style.display = 'none';
validateEmail.style.color = 'red';
// validate loging fields
if(!isValidEmail(email))
{
failed = true;
validateEmail.textContent = "Please enter a valid email";
validateEmail.style.display = 'block';
validationMessages.push(validateEmail.id);
}
if(!failed)
{
// submit to server
var ForgotPasswordData = {};
ForgotPasswordData["promptDescription"] = "ForgotPassword";
ForgotPasswordData["email"] = email;
const requestData = {};
requestData["ForgotPasswordData"] = ForgotPasswordData;
// show check email message
$('#forgot-password-message').show();
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("ForgotPassword return: ",JSON.stringify(result));
var message = result["message"];
switch(message)
{
case "Forgot Password: password reset request made":
// hide
$('#forgot-password-modal').animate({ opacity: 0 }).hide();
// show message to check email
OpenModal("Email Sent", "Check your email inbox for a password reset link.", false, false);
break;
case "Forgot Password: User Not Found":
// hide
$('#forgot-password-modal').animate({ opacity: 0 }).hide();
// show message to check email
OpenModal("Problem", "Please try again", false, false);
break;
}
});
}
if(failed)
{
// scroll to first error
$('html, body').animate({
scrollTop: $('#' + validationMessages[0]).offset().top - 50
}, 500);
}
}
function SubmitForgotPassword_Agency()
{
var email = document.getElementById('txtForgotPasswordEmail').value;
var failed = false;
var validateEmail = document.getElementById('validateForgotPasswordEmail');
var validationMessages = [];
// hide all validation messages
validateEmail.style.display = 'none';
validateEmail.style.color = 'red';
// validate loging fields
if(!isValidEmail(email))
{
failed = true;
validateEmail.textContent = "Please enter a valid email";
validateEmail.style.display = 'block';
validationMessages.push(validateEmail.id);
}
if(!failed)
{
// submit to server
var ForgotPasswordData = {};
ForgotPasswordData["requestDescription"] = "ForgotPassword";
ForgotPasswordData["email"] = email;
const requestData = {};
requestData["MYPEAS_payload"] = {};
requestData["MYPEAS_payload"]["email"] = email;
requestData["MYPEAS_payload"]["requestDescription"] = "ForgotPassword";
requestData["MYPEAS_payload"]["ForgotPasswordData"] = ForgotPasswordData;
requestData["ForgotPasswordData"] = ForgotPasswordData;
// show check email message
$('#forgot-password-message').show();
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("ForgotPassword return: ",JSON.stringify(result));
var message = result["message"];
switch(message)
{
case "Forgot Password: password reset request made":
// hide
$('#forgot-password-modal').animate({ opacity: 0 }).hide();
// show message to check email
OpenModal("Email Sent", "Check your email inbox for a password reset link.", false, false);
break;
case "Forgot Password: User Not Found":
// hide
$('#forgot-password-modal').animate({ opacity: 0 }).hide();
// show message to check email
OpenModal("Problem", "Please try again", false, false);
break;
}
});
}
if(failed)
{
// scroll to first error
$('html, body').animate({
scrollTop: $('#' + validationMessages[0]).offset().top - 50
}, 500);
}
}
// this uses more concise newer browser(ES6 technologies)
function GetParam(querystringKey)
{
try
{
// 1. Get the query string from the URL:
const queryString = window.location.search;
// 2. Create a URLSearchParams object to parse the query string:
const urlParams = new URLSearchParams(queryString);
// 3. Access individual query parameters by key:
return urlParams.get(querystringKey);
/*const name = urlParams.get('name');
const age = urlParams.get('age');
const city = urlParams.get('city');*/
}
catch (err)
{
console.error(err);
return "";
}
}
function removeParam(querystringKey) {
try {
const currentUrl = new URL(window.location.href);
// Check if the key exists before deleting
if (currentUrl.searchParams.has(querystringKey)) {
currentUrl.searchParams.delete(querystringKey);
const newUrl = currentUrl.toString();
window.history.replaceState({}, document.title, newUrl);
} else {
console.warn(`Query parameter '${querystringKey}' not found.`);
}
} catch (error) {
console.error("Error removing query parameter:", error);
// Additional error handling if needed
}
}
function getUrlParameter(sParam) {
var sPageURL = window.location.search.substring(1),
sURLVariables = sPageURL.split('&'),
sParameterName,
i;
for (i = 0; i < sURLVariables.length; i++) {
sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] === sParam) {
return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]);
}
}
}
function ResetPassword()
{
// validate password
var newPassword = document.getElementById("txtNewPassword").value;
var repeatPassword = document.getElementById("txtNewPasswordRepeat").value;
var validateNewPassword = document.getElementById("validateNewPassword");
var validateRepeatPassword = document.getElementById("validateRepeatPassword");
// get querystring values
var memberIDValue = GetParam("memberID");
var otcValue = GetParam("OTC");
var validationMessages = [];
var failed = false;
if(!isValidPassword(newPassword))
{
failed = true;
validateNewPassword.textContent = "Minimum length of 8 characters, contains at least one uppercase letter, one lowercase letter, one number, and one special character";
validateNewPassword.style.display = 'block';
validationMessages.push(validateNewPassword.id);
}
// make sure both are the same
if(newPassword != repeatPassword)
{
failed = true;
validateRepeatPassword.textContent = "Passwords do not match. Please try again.";
validateRepeatPassword.style.display = 'block';
validationMessages.push(validateRepeatPassword.id);
}
// show spinner in place of submit
if(!failed)
{
// hide submit button
$('#btnResetPassword').hide();
// show loading spinner
$('#spinner-holder-flex-reset-password').show();
// submit to server
// submit to server
var ResetPasswordData = {};
ResetPasswordData["promptDescription"] = "ResetPassword";
ResetPasswordData["memberID"] = memberIDValue;
ResetPasswordData["OTC"] = otcValue;
ResetPasswordData["newPassword"] = newPassword;
const requestData = {};
requestData["ResetPasswordData"] = ResetPasswordData;
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("ResetPassword return: ",JSON.stringify(result));
var message = result["message"];
switch(message)
{
case "Reset Password: completed":
//https://www.mypeas.ai/agency?OTC=BcqpgwEmQk&memberID=2Loe82y7ca
removeParam("OTC");
removeParam("memberID");
// set the message
$('#password-reset-confirm').text("Your password is reset.");
// show password reset message (holding div)
$('#reset-confirm-message').show();
// hide the other fields
$('#reset-form').hide();
// redirect to login - open login dialog
setTimeout(function(){
OpenCloseResetPasswordModal("close");
OpenCloseLoginModal("open");
}, 1500);
break;
case "Reset Password: failed OTC":
removeParam("OTC");
removeParam("memberID");
// set the message
$('#password-reset-confirm').text("This password reset link has expired");
// show password reset message (holding div)
$('#reset-confirm-message').show();
// hide the other fields
$('#reset-form').hide();
break;
case "Reset Password: failed memberID not found":
removeParam("OTC");
removeParam("memberID");
// set the message
$('#password-reset-confirm').text("This password reset link is not valid");
// show password reset message (holding div)
$('#reset-confirm-message').show();
// hide the other fields
$('#reset-form').hide();
break;
}
});
}
if(failed)
{
// scroll to first error
$('html, body').animate({
scrollTop: $('#' + validationMessages[0]).offset().top - 50
}, 500);
}
}
function ResetPassword_Agency()
{
// validate password
var newPassword = document.getElementById("txtNewPassword").value;
var repeatPassword = document.getElementById("txtNewPasswordRepeat").value;
var validateNewPassword = document.getElementById("validateNewPassword").value;
var validateRepeatPassword = document.getElementById("validateRepeatPassword").value;
// get querystring values
var memberIDValue = GetParam("memberID");
var otcValue = GetParam("OTC");
var failed = false;
var validationMessages = [];
if(!isValidPassword(newPassword))
{
failed = true;
validateNewPassword.textContent = "Minimum length of 8 characters, contains at least one uppercase letter, one lowercase letter, one number, and one special character";
validateNewPassword.style.display = 'block';
validationMessages.push(validateNewPassword.id);
}
// make sure both are the same
if(newPassword != repeatPassword)
{
failed = true;
validateRepeatPassword.textContent = "Passwords do not match. Please try again.";
validateRepeatPassword.style.display = 'block';
validationMessages.push(validateRepeatPassword.id);
}
// show spinner in place of submit
if(!failed)
{
// hide submit button
$('#btnResetPassword').hide();
// show loading spinner
$('#spinner-holder-flex-reset-password').show();
// submit to server
// submit to server
var ResetPasswordData = {};
var MYPEAS_payload = {};
MYPEAS_payload["requestDescription"] = "ResetPassword";
MYPEAS_payload["memberID"] = memberIDValue;
MYPEAS_payload["OTC"] = otcValue;
MYPEAS_payload["newPassword"] = newPassword;
ResetPasswordData["requestDescription"] = "ResetPassword";
ResetPasswordData["memberID"] = memberIDValue;
ResetPasswordData["OTC"] = otcValue;
ResetPasswordData["newPassword"] = newPassword;
const requestData = {};
requestData["ResetPasswordData"] = ResetPasswordData;
requestData["MYPEAS_payload"] = MYPEAS_payload;
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("ResetPassword return: ",JSON.stringify(result));
var message = result["message"];
switch(message)
{
case "Reset Password: completed":
// set the message
$('#password-reset-confirm').text("Your password is reset.");
// show password reset message (holding div)
$('#reset-confirm-message').show();
// hide the other fields
$('#reset-form').hide();
// redirect to login - open login dialog
setTimeout(function(){
OpenCloseResetPasswordModal("close");
OpenCloseLoginModal("open");
}, 1500);
break;
case "Reset Password: failed OTC":
// set the message
$('#password-reset-confirm').text("This password reset link has expired");
// show password reset message (holding div)
$('#reset-confirm-message').show();
// hide the other fields
$('#reset-form').hide();
break;
case "Reset Password: failed memberID not found":
// set the message
$('#password-reset-confirm').text("This password reset link is not valid");
// show password reset message (holding div)
$('#reset-confirm-message').show();
// hide the other fields
$('#reset-form').hide();
break;
}
});
}
if(failed)
{
// scroll to first error
$('html, body').animate({
scrollTop: $('#' + validationMessages[0]).offset().top - 50
}, 500);
}
}
function ClearStorage()
{
var segmentList = document.getElementById('JobSegments');
// clear segments
segmentList.innerHTML = "";
// clear activities
var activitiesList = document.getElementById('JobActivities');
activitiesList.innerHTML = "";
// clear steps
// it is inside jobactivities
// clear howto
// it is the textarea in steps div
// clear local storage
localStorage.removeItem("profile");
// clear hidden field
var profileinfo = document.getElementById('profileinfo');
if(profileinfo)
{
profileinfo.value = "";
}
}
/**
* SearchJobEnable is a method that enables the Search button for users to start a jobtitle and job description search
*
* @param enable - boolean value that sets whether the search buttons are enabled or disabled
*/
function SearchJobEnable(enable)
{
var getJob = document.querySelector('#btnGetJob');
var txtJobTitle = document.getElementById('jobTitle');
var txtJobDescription = document.getElementById('jobDescription');
if(getJob)
{
switch(enable)
{
case true:
// re-enable these fields
getJob.classList.remove('loading', 'disabled');
txtJobTitle.disabled = false;
txtJobDescription.disabled = false;
break;
case false:
// disable fields
getJob.classList.add('loading', 'disabled');
txtJobTitle.disabled = true;
txtJobDescription.disabled = true;
break;
}
}
}
function findSegmentIndexById(JobSegments, SegmentId)
{
var foundIndex = JobSegments.findIndex(jobSegment => jobSegment.id === SegmentId);
return foundIndex;
}
// obselete - was a mismatch of activityif on activities and outputs objects
function findActivityIndexById(JobActivities, ActivityId)
{
var foundIndex = JobActivities.findIndex(jobActivity => jobActivity.id === ActivityId);
return foundIndex;
}
// findActivityIndexByOutputId is supposed to find the index of Activities array by matching output.activityid
function findActivityIndexByOutputId(JobActivities, OutputActivityId) {
var foundIndex = JobActivities.findIndex(jobActivity =>
jobActivity.Outputs && jobActivity.Outputs.some(output => output.ActivityOutputId === OutputActivityId)
);
return foundIndex;
}
// findActivityOutputIndexById is supposed to find index of Outputs array by matching output.activityid
function findActivityOutputIndexById(Outputs, ActivityId) {
var foundIndex = Outputs.findIndex(output => output.ActivityOutputId === ActivityId);
return foundIndex;
}
function findStepIndexById(Steps, StepId)
{
var foundIndex = Steps.findIndex(step => step.id === StepId);
return foundIndex;
}
function UpdateProfileOnServer (stringifiedProfile)
{
var saveBtn = document.getElementById('btnUpdateProfile');
if(saveBtn)
{
var profileInfo = document.getElementById('profileinfo');
profileInfo.value = stringifiedProfile;
// update profileinfo field with data in localprofile
// use form to submit to server
saveBtn.click();
}
}
function LoadExistingProfile(profile)
{
try
{
console.log('LoadExistingProfile Called');
// set to loading
$('#initLoading').val('loadingExisting');
var localStoredProfile = profile;
if (typeof profile === 'string') {
localStoredProfile = JSON.parse(profile);
}
let maxParseAttempts = 10; // Maximum allowed parsing attempts
while (typeof profile === 'string' && maxParseAttempts > 0)
{
try
{
profile = JSON.parse(profile);
} catch (error)
{
console.error("Error parsing profile:", error);
break; // Exit loop on parsing failure
}
maxParseAttempts--;
}
localStoredProfile = profile;
var jobObj = localStoredProfile;
var segmentsPresent = false;
var activitiesPresent = false;
var segmentsPresent = "JobSegments" in localStoredProfile;
OpenModal("Loading", "just one moment", true, false);
if(segmentsPresent)
{
// hide background video
$('.background-video').hide();
$('.background-video-agency').hide();
// create segments with LoadMethods from stored data
var jobSegmentIds = [];
// store in hidden field
$('#JobInfo').val(JSON.stringify(jobObj));
// store this value in hidden field
$('#JobDescriptionSummary').val(jobObj["JobDescriptionSummary"]);
var jobSegments = jobObj["JobSegments"];
jobSegmentIds = jobSegments.map(function(jobSegment) {
return jobSegment.id;
});
//createItemData(result);
CreateSegment(jobObj["JobTitle"], jobObj["JobSegments"], jobObj["JobDescriptionSummary"], jobSegmentIds, jobObj);
CloseModal();
ConsoleLog("close modal called in loadexisting");
// clear loading
$('#initLoading').val('');
}
// scroll top
$(window).scrollTop(0);
}
catch(err)
{
// clear value
$('#initLoading').val('');
}
}
function LoadAgencyAccount(accountInfo, profile)
{
try
{
// hide background video
$('.background-video').hide();
$('.background-video-agency').hide();
if (typeof accountInfo === 'string')
{
try
{
accountInfo = JSON.parse(accountInfo);
}
catch (error)
{
console.error("Error parsing JSON property:", error);
}
}
var ApprovedStatus = accountInfo["ApprovedStatus"];
switch(ApprovedStatus)
{
case "Approved":
case "approved":
CreateDashboard(accountInfo, profile);
CreateSetCalendar(accountInfo);
//OpenCalendarModal();
// show dashboard fields
$('.agency-account-info-holder').show();
break;
case "InviteSent":
ShowPreLoad();
ShowDashboardProcesssing(ApprovedStatus);
break;
case "AwaitingApproval":
case "processing":
case "rejected":
case "Rejected":
ShowDashboardProcesssing(ApprovedStatus);
break;
}
}
catch(err)
{
}
}
/*function CreateDashboard()
{
var dashboard = `
`;
$('#dashboard-info-container').append(dashboard);
}*/
function OpenFavourites()
{
// check favourites
var favourites = localStorage.getItem("favourites") || null;
if(favourites && favourites != "")
{
favourites = JSON.parse(favourites);
}
OpenFavourtiesModal(true, "Favourites", "");
favourites = normalizeKeys(favourites);
appendUnitsFavourites(favourites, $('#favourites-modal #favourites-content-holder'));
$('#favourites-modal #modal-spinner').hide();
}
// findStepIndexById
/* TO DO */
/**
* SaveProfile - this method will be used to update a profleObj with the activities as a user fills in their activity tree with generative AI derived information.
* This profile object reduces the time required for repeat searches or returning visitors
* @param label
* @param update
* @param otherParameter
* @param profileParameter
*/
function SaveProfile(label, update, otherParameter, profileParameter) {
/*
Example
{
"id": "12345",
"JobTitle": "Job Title entered by the user",
"JobDescription": "Job Description entered by the user",
"JobDescriptionSummary": "Summary returned by the first query",
"JobSegments": [
{
"Name": "JobSegmentName",
"Activities": [
// Array of objects with details of job activities.
These create the prompts
]
}
]
}
*/
var jobObj = {}; // Initialize jobObj outside the switch statement
switch (label) {
case "Start":
// receive an array of segment names
var JobTitle = document.getElementById('jobTitle').value;
var JobDescription = document.getElementById('jobDescription').value;
//var updateObj = tryParse(update);
var updateObj = update;
jobObj["id"] = generateRandomString(8);
jobObj["JobTitle"] = JobTitle;
jobObj["JobDescription"] = JobDescription;
jobObj["JobDescriptionSummary"] = updateObj["DescriptionSummary"];
jobObj["JobSegments"] = [];
var idStrings = profileParameter;
var jobSegments = updateObj["SegmentTitles"];
var idIndex = 0; // Initialize the index for idStrings
jobSegments.forEach(jobSegment => {
var jobSegmentObj = {};
jobSegmentObj["id"] = idStrings[idIndex];
jobSegmentObj["profileid"] = jobObj["id"];
jobSegmentObj["Name"] = jobSegment;
jobSegmentObj["Activities"] = [];
jobObj["JobSegments"].push(jobSegmentObj);
idIndex = (idIndex + 1) % idStrings.length; // Increment index and wrap around if needed
});
// store in hidden field
$('#JobInfo').val(JSON.stringify(jobObj));
// create profile
var stringifiedProfile = JSON.stringify(jobObj);
localStorage.setItem("profile", stringifiedProfile);
UpdateProfileOnServer(JSON.stringify(jobObj));
break;
case "TaskOutline":
// GetOutline(JobTitle, segment, counter, JobDescriptionSummary);
// get segmentId
var segmentId = profileParameter;
// get the stored profile
jobObj = JSON.parse($('#JobInfo').val());
// Find the index of the jobSegmentObj with the specified jobsegmentid
var foundIndex = jobObj["JobSegments"].findIndex(jobSegment => jobSegment.id === segmentId);
if (foundIndex !== -1) {
// Access the jobSegmentObj using the found index
var foundJobSegment = jobObj["JobSegments"][foundIndex];
// add LastOpenedSegement
jobObj["LastOpenedSegment"] = segmentId;
// add activities to the segment
var Activities = update;
var idStrings = otherParameter;
var idIndex = 0; // Initialize the index for idStrings
Activities.forEach(activity => {
var outputs = activity['Outputs'];
outputs.forEach(output => {
output["ActivityId"] = idStrings[idIndex];
idIndex = (idIndex + 1) % idStrings.length; // Increment index and wrap around if needed
});
});
jobObj["JobSegments"][foundIndex]["Activities"] = Activities;
/* Note
Each activity in activities has a title and description property.
Title = TaskTitle
Description = TaskSummary
*/
}
else
{
ConsoleLog("Job segment not found with the specified id.");
}
//SaveProfile("TaskOutline", jobActivities, "", SegmentId);
// store in hidden field
$('#JobInfo').val(JSON.stringify(jobObj));
// update profile
var stringifiedProfile = JSON.stringify(jobObj);
localStorage.setItem("profile", stringifiedProfile);
UpdateProfileOnServer(JSON.stringify(jobObj));
break;
case "RequestAdditionalInfo":
// RequestAdditionalInfo(JobTitle, jobDescriptionSummary, output['Title'], output['Description'], divOutput.id, JobSegmentTitle);
jobObj = JSON.parse($('#JobInfo').val());
// send all the parameters as an object
var taskInfo = profileParameter;
/*taskInfo["TaskTitle"] = TaskTitle;
taskInfo["TaskSummary"] = TaskSummary;
taskInfo["TagCategory"] = "";*/
// add tagCategory
// need segmentid
var SegmentIndex = findSegmentIndexById(jobObj["JobSegments"], taskInfo["SegmentId"]);
if(SegmentIndex !== -1)
{
var ActivityIndex = findActivityIndexByOutputId(jobObj["JobSegments"][SegmentIndex]["Activities"], taskInfo["ActivityId"]);
if(ActivityIndex !== -1)
{
jobObj["LastOpenedActivity"] = taskInfo["ActivityId"];
// update the activity with category
jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["TagCategory"] = taskInfo["TagCategory"];
// add request for additional info
jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["AdditionalContext"] = taskInfo["AdditionalContext"];
}
}
// need activitiesid
// add taskActivities["Tags"][0] as TagCategory
// store in hidden field
$('#JobInfo').val(JSON.stringify(jobObj));
// update profile
var stringifiedProfile = JSON.stringify(jobObj);
localStorage.setItem("profile", stringifiedProfile);
UpdateProfileOnServer(JSON.stringify(jobObj));
break;
/* hit 'GENERATE' - store the additional context provided by user */
case "CreateUISteps_Request":
// GetOutline(JobTitle, segment, counter, JobDescriptionSummary);
jobObj = JSON.parse($('#JobInfo').val());
// send all the parameters as an object
var AdditionalContextUser = profileParameter;
var taskInfo = update;
// need segmentid
var SegmentIndex = findSegmentIndexById(jobObj["JobSegments"], taskInfo["SegmentId"]);
if(SegmentIndex !== -1)
{
var ActivityIndex = findActivityIndexByOutputId(jobObj["JobSegments"][SegmentIndex]["Activities"], taskInfo["ActivityId"]);
if(ActivityIndex !== -1)
{
// add request for additional info
jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["AdditionalContextUser"] = AdditionalContextUser;
}
}
// need activitiesid
// add taskActivities["Tags"][0] as TagCategory
// store in hidden field
$('#JobInfo').val(JSON.stringify(jobObj));
// update profile
var stringifiedProfile = JSON.stringify(jobObj);
localStorage.setItem("profile", stringifiedProfile);
UpdateProfileOnServer(JSON.stringify(jobObj));
break;
/* received by request after 'GENERATE' prompt is returned */
case "CreateUISteps_Request_Response":
// CreateUserInterface(TaskActivities, ContainerID, JobInfo, TaskInfo, JobSegmentTitle)
jobObj = JSON.parse($('#JobInfo').val());
// send all the parameters as an object
var taskInfo = profileParameter;
var jobInfo = update;
// need segmentid
var SegmentIndex = findSegmentIndexById(jobObj["JobSegments"], taskInfo["SegmentId"]);
if(SegmentIndex !== -1)
{
var ActivityIndex = findActivityIndexByOutputId(jobObj["JobSegments"][SegmentIndex]["Activities"], taskInfo["ActivityId"]);
if(ActivityIndex !== -1)
{
var OutputIndex = findActivityOutputIndexById(jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"], taskInfo["ActivityId"]);
// add request for additional info
jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Steps"] = taskInfo["Steps"];
}
}
// store in hidden field
$('#JobInfo').val(JSON.stringify(jobObj));
// update profile
var stringifiedProfile = JSON.stringify(jobObj);
localStorage.setItem("profile", stringifiedProfile);
UpdateProfileOnServer(JSON.stringify(jobObj));
break;
case "CreateUIShowMeHow":
// CreateUIShowMeHow(JobInfo, TaskInfo, StepInfo, Container, TextArea, JobSegmentTitle)
jobObj = JSON.parse($('#JobInfo').val());
// send all the parameters as an object
var taskInfo = profileParameter;
var jobInfo = update;
var stepInfo = otherParameter;
// need segmentid
var SegmentIndex = findSegmentIndexById(jobObj["JobSegments"], taskInfo["SegmentId"]);
if(SegmentIndex !== -1)
{
var ActivityIndex = findActivityIndexByOutputId(jobObj["JobSegments"][SegmentIndex]["Activities"], taskInfo["ActivityId"]);
if(ActivityIndex !== -1)
{
var OutputIndex = findActivityOutputIndexById(jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"], taskInfo["ActivityId"]);
// add request for additional info
jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Steps"] = taskInfo["Steps"];
var StepIndex = findStepIndexById(jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Steps"], stepInfo["id"]);
if(StepIndex !== -1)
{
jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Steps"][StepIndex]["HowTo"] = stepInfo["HowTo"];
}
}
}
// store in hidden field
$('#JobInfo').val(JSON.stringify(jobObj));
// update profile
var stringifiedProfile = JSON.stringify(jobObj);
localStorage.setItem("profile", stringifiedProfile);
UpdateProfileOnServer(JSON.stringify(jobObj));
break;
}
// store in localstorage
// store on server
/* look at save-profile-peas.js */
}
/**
* generateRandomString method creates a random string with a defined length
* @param length
* @returns
*/
function generateRandomString(length) {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let randomString = '';
for (let i = 0; i < length; i++) {
const randomIndex = Math.floor(Math.random() * characters.length);
randomString += characters.charAt(randomIndex);
}
return randomString;
}
/* code for creating segments from json return 1 */
/**
* CreateSegment - this method takes the information returned after the data entered by the user (job title and description) and sent to the LLM and prompts job activities and creates the job activity segments
* This is the second stage. Users can then select the segment they want expanded job activities for.
* @param JobTitle
* @param jobSegments
* @param JobDescriptionSummary
* @param JobSegmentIds
*/
function CreateSegment(JobTitle, jobSegments, JobDescriptionSummary, JobSegmentIds, jobObj)
{
try
{
var isString = true;
if(jobSegments.every(element => typeof element === 'object'))
{
isString = false
var segmentsConverter = [];
jobSegments.forEach(jobSegment => {
segmentsConverter.push(jobSegment.Name);
});
jobSegments = segmentsConverter;
}
// this navigation bar div is where we will put dropdown for job segments, favourite icon AND my account avatar button (when logged in)
var navEmbed = document.getElementById('nav-embed');
/* This should always be fresh,
Clear all current UX: Segments, Activities, Steps ,HowTo UI
*/
/* remove this before deploy */
//var jobSegments = ["Sales", "Research", "Relationship Management", "Upselling", "Finance Advice"];
var segmentList = document.getElementById('JobSegments');
// clear segments
segmentList.innerHTML = "";
// clear activities
var activitiesList = document.getElementById('JobActivities');
activitiesList.innerHTML = "";
// clear steps
// it is inside jobactivities
// clear howto
// it is the textarea in steps div
// Create banner container
let bannerContainer = document.createElement('div');
bannerContainer.style.maxWidth = '1200px';
bannerContainer.style.margin = '0 auto 10px auto';
bannerContainer.style.display = 'flex';
bannerContainer.style.gap = '16px';
bannerContainer.style.flexWrap = 'wrap';
// Help banner
let helpBanner = document.createElement('div');
helpBanner.innerHTML = 'ⓘ
Click for more info
';
helpBanner.style.flex = '1';
helpBanner.style.minWidth = '280px';
helpBanner.style.padding = '4px 12px';
helpBanner.style.borderRadius = '12px';
helpBanner.style.display = 'flex';
helpBanner.style.alignItems = 'center';
helpBanner.style.justifyContent = 'center';
helpBanner.style.textAlign = 'center';
helpBanner.style.gap = '8px';
helpBanner.style.fontSize = '12px';
helpBanner.style.fontWeight = '500';
helpBanner.style.backgroundColor = 'rgb(193, 231, 193)';
helpBanner.style.color = '#2d5a2d';
helpBanner.style.border = '1px solid #4ade80';
helpBanner.style.cursor = 'pointer';
// Upgrade banner
let upgradeBanner = document.createElement('div');
upgradeBanner.innerHTML = 'Content requires upgrade
';
upgradeBanner.style.flex = '1';
upgradeBanner.style.minWidth = '280px';
upgradeBanner.style.padding = '4px 12px';
upgradeBanner.style.borderRadius = '12px';
upgradeBanner.style.display = 'flex';
upgradeBanner.style.alignItems = 'center';
upgradeBanner.style.justifyContent = 'center';
upgradeBanner.style.textAlign = 'center';
upgradeBanner.style.gap = '8px';
upgradeBanner.style.fontSize = '12px';
upgradeBanner.style.fontWeight = '500';
upgradeBanner.style.backgroundColor = 'rgb(225, 230, 225)';
upgradeBanner.style.color = '#374151';
upgradeBanner.style.border = '1px solid #9ca3af';
upgradeBanner.style.cursor = 'pointer';
// dont want banner image anymore
$('#hero-holder').hide();
// Add banners to container
bannerContainer.appendChild(helpBanner);
bannerContainer.appendChild(upgradeBanner);
// Append to your target element
segmentList.appendChild(bannerContainer);
// info
/*// Create the main div container
const quoteDiv = document.createElement('div');
quoteDiv.style.fontFamily = 'Arial, sans-serif';
quoteDiv.style.padding = '20px';
quoteDiv.style.borderLeft = '4px solid #0073b1';
quoteDiv.style.backgroundColor = '#f4f4f4';
quoteDiv.style.display = 'flex';
quoteDiv.style.alignItems = 'center';
// Create the inner content div
const contentDiv = document.createElement('div');
contentDiv.style.flex = '1';
// Create the quote paragraph
const quoteParagraph = document.createElement('p');
quoteParagraph.style.fontSize = '16px';
quoteParagraph.style.fontWeight = 'bold';
quoteParagraph.style.margin = '0';
quoteParagraph.textContent = '📌 “This breakdown reveals exactly where AI can be leveraged to optimize your team\'s performance. Navigate through each section to see how AI fits into your daily work and explore AI-powered tools to enhance efficiency.”';
// Create the author paragraph
const authorParagraph = document.createElement('p');
authorParagraph.style.fontSize = '14px';
authorParagraph.style.fontWeight = 'bold';
authorParagraph.style.marginTop = '10px';
authorParagraph.textContent = '– Ade Molajo ';
// Create the LinkedIn link
const linkedinLink = document.createElement('a');
linkedinLink.href = 'https://www.linkedin.com/in/ademolajo/';
linkedinLink.target = '_blank';
linkedinLink.style.textDecoration = 'none';
// Create the LinkedIn logo image
const linkedinLogo = document.createElement('img');
linkedinLogo.src = 'https://cdn.prod.website-files.com/6446c148837a8953093cbfeb/67c5ebe5dcee6a875ddafef1_LinkedIn_logo_initials.png';
linkedinLogo.alt = 'LinkedIn';
linkedinLogo.style.width = '16px';
linkedinLogo.style.height = '16px';
// Assemble the elements
linkedinLink.appendChild(linkedinLogo);
authorParagraph.appendChild(linkedinLink);
contentDiv.appendChild(quoteParagraph);
contentDiv.appendChild(authorParagraph);
quoteDiv.appendChild(contentDiv);
// Append the created div to the segmentList
segmentList.appendChild(quoteDiv); */
/* Title above segments */
let segmentTitle = document.createElement('h2');
segmentTitle.textContent = "Your Job";
segmentTitle.style.color = 'black';
segmentList.appendChild(segmentTitle);
// add hr
var rule = createThickRule();
segmentList.appendChild(rule);
/* FROM activities
let activityOuputId = 'jobActivity_' + JobSegmentNo + '_Activity_' + i + '_Output_' + j;
let output = activity['Outputs'][j];
let divOutput = document.createElement('div');
divOutput.className = 'segment-container';
divOutput.id = activityOuputId;
// Add a heading for the output
let outputHeading = document.createElement('h4');
outputHeading.textContent = output['Title'];
outputHeading.style.color = 'green';
divOutput.appendChild(outputHeading);
// Add description text below the heading
let outputDescription = document.createElement('p');
outputDescription.textContent = output['Description'];
divOutput.appendChild(outputDescription);
// add to parent div
div.appendChild(divOutput);
END */
/*
Add Job-Specific Tools Here
*/
// tools holder
var toolsHolder = document.createElement('div');
toolsHolder.id = "_tools_holder_";
/*var toolsSubheading = document.createElement('h4');
toolsSubheading.id = "toolsSubheading";
toolsSubheading.textContent = '';
toolsHolder.appendChild(toolsSubheading);
// add rule
var toolsRule = createThickRule();
toolsHolder.appendChild(toolsRule); */
// Add smaller heading for "Useful Tools"
var toolsHeading = document.createElement('h3');
toolsHeading.textContent = 'Job Specific AI Tools ';
toolsHeading.style.cursor = 'pointer';
toolsHeading.appendChild(CreateInfoSpan());
toolsHeading.onclick = function() {
OpenInfoModal("Tools");
};
toolsHolder.appendChild(toolsHeading);
// explain what the section is
let toolsParagraph = document.createElement('p');
toolsParagraph.textContent = "Explore a curated selection of AI-powered tools to enhance this job role.";
toolsHolder.appendChild(toolsParagraph);
// add subheading with the title from searchtools button
/* var toolsSubheading = document.createElement('p');
toolsSubheading.id = "toolsSubheading";
toolsSubheading.textContent = '';
toolsHolder.appendChild(toolsSubheading); */
// Create vertical boxes for AI tools
var toolsContainer = document.createElement('div');
toolsContainer.id = "gridContainerTools";
toolsHolder.appendChild(toolsContainer);
//segmentList.appendChild(toolsHolder);
// append tools
// create a false object for searchtools function to manipulate
// job title, industry
var jobDescriptionSummary = jobObj["JobDescriptionSummary"];
var searchItem = {};
searchItem.Breakdown = {
Output: JobTitle,
};
searchItem.Title = jobDescriptionSummary;
// add a h3 "job segments" title with thin rule
let jobSegmentsTitle = document.createElement('h2');
jobSegmentsTitle.textContent = "Job Segments ";
jobSegmentsTitle.style.cursor = 'pointer';
jobSegmentsTitle.style.color = 'black';
jobSegmentsTitle.appendChild(CreateInfoSpan());
jobSegmentsTitle.onclick = function() {
// name,
OpenInfoModal("Segments");
};
//segmentList.appendChild(jobSegmentsTitle);
// give it onclick
// add hr
/* var thinrule = document.createElement('hr');
segmentList.appendChild(thinrule); */
var rule = createThickRule();
//segmentList.appendChild(rule);
// add paragraph to segmentList
var segmentParagraph = document.createElement('p');
segmentParagraph.textContent = "Our AI identified the key areas of your role. These segments represent the core responsibilities where AI can create impact.";
//segmentList.appendChild(segmentParagraph);
// Create a dropdown element
var dropdown = document.createElement('select');
dropdown.id = "jobsegment-dropdown";
dropdown.classList.add('jobsegment-dropdown', 'big-dropdown'); // Add classes for styling
dropdown.style.textAlign = 'center';
dropdown.style.marginLeft = "10px";
dropdown.style.marginRight = "10px";
dropdown.style.borderColor = "black";
/*
Sales
*/
// Loop through jobSegments and create options
jobSegments.forEach((segment, index) => {
const option = document.createElement('option');
option.id = 'jobSegment-' + (index + 1);
option.value = index + 1; // Use index + 1 as value for consistency with previous logic
option.textContent = segment;
option.setAttribute('segmentId', JobSegmentIds[index]); // Add segmentId for later use
dropdown.appendChild(option);
});
// Add click/change event listener to the dropdown
//dropdown.addEventListener('click', handleSegmentClick);
dropdown.addEventListener('change', handleSegmentClick);
// Append the dropdown to the segmentList
//segmentList.appendChild(dropdown);
// new segments dropdown
populateJobSegmentDropdown(jobObj);
// hide
$('#btnTools').hide();
$('#btnFavourites').hide();
$('#btnMyAccount').hide();
$('#btnLogInOut').hide();
// show
$('#nav-embed').show();
// add revise activities link
// Create a new div element and assign it an ID 'revise-holder'
var reviseHolder = document.createElement('div');
reviseHolder.id = 'revise-holder';
reviseHolder.padding = '20px';
reviseHolder.style.marginTop = '10px';
// Create a new span element, assign it an ID 'revise-btn-link', and change the variable name to reviseBtn
var reviseBtn = document.createElement('span');
reviseBtn.id = 'revise-btn-link';
reviseBtn.style.textDecoration = 'underline';
reviseBtn.style.cursor = 'pointer';
reviseBtn.style.marginLeft = '10px';
reviseBtn.textContent = 'Revise my Job Description (requires Credits)';
// Adding an onclick event listener to the span
reviseBtn.onclick = function() {
// check the revisions/credits
var revisions = getRevisionCount(localStorage.getItem("revisions"));
ConsoleLog("revisions count: ",revisions);
if(revisions > 0)
{
OpenNewSearchDialog();
// clear data related to ai generated job description
if(jobData)
{
jobData = {};
/*if(!$('#new-search-holder #responsibilities').is(':empty'))
{
$('#new-search-holder #responsibilities').empty();
}*/
if(!$('#new-search-holder #ai-responsibilities').is(':empty'))
{
$('#new-search-holder #ai-responsibilities').empty();
}
/*if(selectedResponsibilities)
{
selectedResponsibilities = [];
}*/
}
}
else
{
OpenModal("Upgrade", "You have exceeded your account profile limit. Please purchase credit to perform more revisions.", false, true);
}
};
// Append the span element to the div element
reviseHolder.appendChild(reviseBtn);
segmentList.appendChild(reviseHolder);
// add 'add custom task'
// Create a new div element with an ID for the section
var customActivitySection = document.createElement('div');
customActivitySection.id = 'custom-activity-section';
customActivitySection.style.backgroundColor = '#E6F4EA'; // Light green background
customActivitySection.style.padding = '15px';
customActivitySection.style.borderRadius = '8px';
customActivitySection.style.marginTop = '20px';
customActivitySection.style.width = '100%';
customActivitySection.style.boxSizing = 'border-box';
// Create a heading for the section
var sectionHeading = document.createElement('h3');
sectionHeading.textContent = 'Need to add a custom task?';
sectionHeading.style.marginBottom = '5px';
// Create a paragraph for the explanation
var sectionText = document.createElement('p');
sectionText.textContent = 'If there\'s something specific you\'d like to track, add a custom activity to your job segment.';
sectionText.style.fontSize = 'small';
sectionText.style.margin = '0px';
// Create the button container
var buttonContainer = document.createElement('div');
buttonContainer.style.display = 'flex';
buttonContainer.style.alignItems = 'center';
buttonContainer.style.marginTop = '10px';
// Create the button
var addCustomBtn = document.createElement('button');
addCustomBtn.className = 'toolsAdvice';
addCustomBtn.id = 'add-custom-activity-button';
addCustomBtn.style.height = '40px';
addCustomBtn.style.borderRadius = '10px';
addCustomBtn.style.maxWidth = '300px';
addCustomBtn.style.padding = '0px 5px';
addCustomBtn.style.backgroundColor = 'white';
addCustomBtn.style.border = '1px solid darkgray';
addCustomBtn.style.display = 'flex';
addCustomBtn.style.alignItems = 'center';
addCustomBtn.style.justifyContent = 'center';
addCustomBtn.style.gap = '5px';
addCustomBtn.style.cursor = 'pointer';
// Create the button icon
var buttonIcon = document.createElement('img');
buttonIcon.src = 'https://flexluthor.s3.eu-west-2.amazonaws.com/images/sparkle.png';
buttonIcon.alt = 'Add Custom Activity';
buttonIcon.style.height = '20px';
// Create the button text
var buttonText = document.createElement('span');
buttonText.textContent = '+ Add Custom Activity';
// Add an onclick event to the button
addCustomBtn.onclick = function () {
console.log("Custom activity button clicked. Open your modal or trigger an event here.");
//add-custom-activity-button
$('#custom-task-modal').css('z-index', '10001').animate({ opacity: 1 }).show();
var holder = document.querySelector('#custom-task-modal');
const button = holder.querySelector("#generate-steps-button");
const buttonText = button.querySelector('#button-text');
const spinner = button.querySelector('#spinner');
var errorMsg = holder.querySelector('#custom-activity-error');
// add validators to the UI
// hide validators
$('#validateCustomName').hide();
$('#validateCustomDescription').hide();
$('#validateCustomOutput').hide();
};
// Append the icon and text to the button
addCustomBtn.appendChild(buttonIcon);
addCustomBtn.appendChild(buttonText);
// Append button to the container
buttonContainer.appendChild(addCustomBtn);
// Append all elements to the section
customActivitySection.appendChild(sectionHeading);
customActivitySection.appendChild(sectionText);
customActivitySection.appendChild(buttonContainer);
// Append the section to the body (or any other container in your DOM)
//document.body.appendChild(customActivitySection);
//segmentList.appendChild(customActivitySection);
// end
// Option 1: Using a flex container (recommended)
// Create container for heading and dropdown
let headerContainer = document.createElement('div');
headerContainer.style.display = 'flex';
headerContainer.style.justifyContent = 'space-between';
headerContainer.style.alignItems = 'center';
headerContainer.style.marginTop = '40px';
headerContainer.style.width = '100%';
// Create the heading
/* let headingJobActivities = document.createElement('h2');
headingJobActivities.textContent = "Your Activities";
headingJobActivities.style.cursor = 'pointer';
headingJobActivities.style.margin = '0'; // Remove default margin*/
let headingJobActivities = document.createElement('h2');
headingJobActivities.textContent = "Your Activities ";
headingJobActivities.style.marginTop = "40px";
headingJobActivities.style.cursor = 'pointer';
headingJobActivities.onclick = function() {
// name,
OpenInfoModal("Activities");
};
headingJobActivities.appendChild(CreateInfoSpan());
// Create the dropdown
var activitiesDropdown = document.createElement('select');
activitiesDropdown.className = 'jobsegment-dropdown nav-dropdown';
activitiesDropdown.id = 'activities-dropdown';
activitiesDropdown.style.padding = '8px 12px';
activitiesDropdown.style.fontSize = '14px';
activitiesDropdown.style.border = '1px solid #ccc';
activitiesDropdown.style.borderRadius = '4px';
activitiesDropdown.style.cursor = 'pointer';
// create method for onchange of the dropdown
// Append heading and dropdown to container
/*headerContainer.appendChild(headingJobActivities);
headerContainer.appendChild(activitiesDropdown);*/
//segmentList.appendChild(headingJobActivities);
segmentList.appendChild(headerContainer);
// add hr
var rule = createThickRule();
//segmentList.appendChild(rule);
var activitiesParagraph = document.createElement('p');
activitiesParagraph.textContent = "We broke down your role into essential tasks. These activities highlight where you spend time—and where AI can streamline processes.";
segmentList.appendChild(activitiesParagraph);
/* ACTIVITIES */
// START //
/*
jobSegments.forEach((segment, index) => {
const option = document.createElement('option');
option.id = `jobSegment-`,(index + 1);
option.value = index + 1; // Use index + 1 as value for consistency with previous logic
option.textContent = segment;
option.setAttribute('segmentId', JobSegmentIds[index]); // Add segmentId for later use
dropdown.appendChild(option);
});
//GetOutline(JobTitle, segmentTitle, segmentCounter, JobDescriptionSummary, SegmentId)
GetOutline(JobTitle, segmentName, selectedOption.value, JobDescriptionSummary, segmentId);
*/
jobSegments.forEach((jobSegment, index) => {
var segmentCounter = index + 1;
var segmentTitle = jobSegment;
var SegmentId = JobSegmentIds[index];
var segmentIndex = findSegmentIndexById(jobObj["JobSegments"], SegmentId);
// this does not work as they all by default have empty activities arrays
// also the segment counter is too high.
// check for activities in the dom
// if activities in the profile
var jobActivities = jobObj["JobSegments"][segmentIndex]["Activities"];
var ActivityIds = [];
ActivityIds = jobActivities.map(function(JobActivity) {
return JobActivity.id;
});
jobActivities.forEach(jobActivity => {
var id = generateRandomString(8);
jobActivity.id = id;
ActivityIds.push(id);
});
//setupActivitiesDropdown(jobObj, segmentIndex);
// set the first segments activities
if(segmentIndex == 0)
{
populateActivitiesDropdown(activitiesDropdown, jobObj, 0);
}
// if custom tasks exist
CreateJobActivities(jobActivities, segmentIndex, segmentTitle, JobTitle, JobDescriptionSummary, SegmentId, ActivityIds, jobObj);
// if no custom tasks just add the need custom task fields
/*if(segmentTitle == "Custom Tasks" && jobActivities.length == 0)
{
}*/
});
//SearchTools(toolsHolder, searchItem, 0);
// replace this with the new job specific ai tools recommender
//SearchTools_Weighted(toolsHolder, searchItem, 0);
// END //
}
catch (err)
{
ConsoleLog('error name: ' + err.name);
ConsoleLog('error message: ' + err.messsage);
ConsoleLog('error stacktrace: ' + err.stack);
// remove loading and disabled from segment buttons
// enable segment buttons
SegmentButtonsActive(true);
// clear all loading screens
LoaderView(false);
CancelSimulateGPT();
// enable searchjob
SearchJobEnable(true);
}
// Function to handle click/change events on the dropdown options
function handleSegmentClick() {
const selectedOption = this.options[this.selectedIndex];
const segmentName = selectedOption.textContent;
const segmentId = selectedOption.getAttribute('segmentId');
var JobSegmentNo = this.selectedIndex + 1;
// Call GetOutline with the selected segment details
//GetOutline(JobTitle, segmentTitle, segmentCounter, JobDescriptionSummary, SegmentId)
//GetOutline(JobTitle, segmentName, selectedOption.value, JobDescriptionSummary, segmentId);
/* TODO ADD OPEN ACTIVITIES */
// hide all other activities divs
/*for(var x = 0; x < this.options.length; x++)
{
var otherContainer = document.getElementById('JobActivities_' + (x + 1));
if(otherContainer)
{
otherContainer.style.display = 'none';
}
}*/
// Check if container div exists with id = 'JobActivities_' + JobSegementNo
let jobActivitiesContainer = document.getElementById('JobActivities');
let containerId = 'JobActivities_' + JobSegmentNo;
let container = document.getElementById(containerId);
container.style.display = 'block';
// open the first output in the segment
// removed as we do this on firstload
/*for(var x = 0; x < $('#jobsegment-dropdown option').length; + x++)
{
var activityID = "jobActivity_" + $('#jobsegment-dropdown option').eq(x).val() + "_Activity_0_Output_0";
// open first activity
$('#' + activityID).click();
}*/
/* HIDE */
// 1) hide all expanded - show show more
var totalSegments = $('#jobsegment-dropdown option').length;
for(var x = 1; x < (totalSegments +1); x++)
{
var parentElement = $('#JobActivities_' + x.toString());
/*if(x > 1)
{
// only show the first segment at load
parentElement.hide();
}*/
// Hide all but the first instance of children with the class name '.segment-container'
parentElement.find('.segment-container').not('.show-more').not(':first').hide();
// show all show more buttons
//parentElement.find('.show-more').show();
// we no longer want them
parentElement.find('.show-more').hide();
// Hide all but the first instance of children with the class name '.activity-steps'
parentElement.find('.activity-steps').not(':first').hide();
// hide subheadings
parentElement.find('.activity-subheading').not(':first').hide();
// this should make the first one visible for each segment
parentElement.find('.segment-container').first().click();
}
// 2) open show more segment-containers
var selectedValue = $('#jobsegment-dropdown').val();
// scroll to that segment
var selectedSegment = $('#JobActivities_' + selectedValue);
var position = selectedSegment.offset().top - 110;
window.scrollTo(0, position);
// hide show more for this one
}
}
function firstLoad()
{
// hide other segments - just show first
var optionsLength = $('#jobsegment-dropdown option').length;
/* for(var x = 1; x < optionsLength; x++)
{
var otherContainer = document.getElementById('JobActivities_' + (x + 1));
if(otherContainer)
{
otherContainer.style.display = 'none';
}
} */
// show
// open first activity
for(var x = 1; x < (optionsLength + 1); x++)
{
$('#jobActivity_' + x + '_Activity_0_Output_0').click();
}
// open first show me how
//$('#jobActivity_1_Activity_0_Output_0_steps button').eq(0).click();
}
/**
* SegmentButtonsActive - this method is used to disable the segment buttons created in CreateSegment so that the user cannot implement a further search before the previous completes or timesout. It will enable when complete or timedout.
* @param active - boolean value
*/
function SegmentButtonsActive(active)
{
switch(active)
{
case true:
$('.jobsegment').removeClass('disabled');
break;
case false:
$('.jobsegment').addClass('disabled');
break;
}
}
/* this still needs to exists
Use this to request the activities
*/
/* create outline prompt */
/* TO DO - remove the default prompt setting that has hard coded information */
/**
* CreatePrompt - this method (called by GetOutline) creates the prompt 2. Prompt 2 queries the LLM for the selected Job segment's activities (with descriptons)
* @param JobTitle
* @param JobDescriptionSummary
* @param SegmentTitle
* @returns the prompt - called by GetOutline
*/
function CreatePrompt(JobTitle, JobDescriptionSummary, SegmentTitle)
{
/* corrected by chatgpt */
/*var prompt = "Job Activity Breakdown: " + JobTitle + " (" + SegmentTitle + ")" + "Job Title: " + JobTitle + "\n" + "Job Description: " + JobDescriptionSummary + "\n" + "This object represents different types of work. Each type of work has a variety of tasks associated with it. {\"Administrative work\": [\"data entry\", \"scheduling\", \"calendar management\", \"answering phones\", \"email correspondence\"],\"Creative work\": [\"graphic design\", \"content creation\", \"copywriting\", \"multimedia production\"],\"Analytical work\": [\"data analysis\", \"financial analysis\", \"market research\", \"forecasting\"],\"Customer Service work\": [\"handling customer inquiries\", \"providing support\", \"resolving issues\", \"maintaining customer satisfaction\"],\"Sales work\": [\"lead generation\", \"prospect qualification\", \"product presentations\", \"negotiations\", \"closing deals\"],\"Management work\": [\"strategic planning\", \"team leadership\", \"resource allocation\", \"decision-making\"],\"Technology Implementation\": [\"implementing and integrating technology solutions\", \"software development\", \"system configuration\", \"deployment\", \"testing\", \"user training\"],\"Financial Analysis\": [\"financial statement analysis\", \"budgeting\", \"forecasting\", \"risk assessment\", \"investment evaluation\"],\"Legal Research and Advice\": [\"legal research\", \"contract review\", \"case analysis\", \"providing legal advice\"],\"Healthcare Provision\": [\"patient care\", \"diagnosis\", \"treatment planning\", \"medical procedures\", \"healthcare consultations\"]} Please create a breakdown of the job activity, focusing on sales and upselling tasks. Outline the specific tasks, outputs, and reports that an employee in this role would be expected to perform/produce. Return the breakdown as a JSON object. Example format: [{\"Section\": \"Sales\",\"Title\": \"Contact Customers\",\"TypeOfWork\": \"Sales work\",\"TaskHandler\": \"lead generation\",\"Outputs\": [{\"Title\": \"Prospect List\",\"Description\": \"Generate a list of potential customers\",\"Report\": \"Prospect list with contact details\"},{\"Title\": \"Sales Calls\",\"Description\": \"Make sales calls to prospects\",\"Report\": \"Call log with outcomes and follow-up actions\"}]},{\"Section\": \"Sales\",\"Title\": \"Product Presentations\",\"TypeOfWork\": \"Sales work\",\"TaskHandler\": \"product presentations\",\"Outputs\": [{\"Title\": \"Product Presentations\",\"Description\": \"Deliver engaging presentations to showcase products\",\"Report\": \"Feedback from customers and sales conversion rates\"},{\"Title\": \"Upselling Opportunities\",\"Description\": \"Identify upselling opportunities during presentations\",\"Report\": \"Upselling success rates and revenue generated\"}]}...] Please provide the breakdown of the job activity, including additional sections, tasks, outputs, and reports related to sales and upselling in the car dealership context.";*/
/* final version */
var prompt = "Job Activity Breakdown: " + JobTitle + " (in the context of " + SegmentTitle + ")" +
"\nJob Title: " + JobTitle +
"\nJob Description: " + JobDescriptionSummary +
"\nJob Category: " + SegmentTitle +
"\nThis TypeOfWork object represents different types of work. Each type of work has a variety of tasks associated with it. " +
"\n{\r\n \"Administrative work\": [\"data entry\", \"scheduling\", \"calendar management\", \"answering phones\", \"email correspondence\"],\r\n \"Creative work\": [\"graphic design\", \"content creation\", \"copywriting\", \"multimedia production\"],\r\n \"Analytical work\": [\"data analysis\", \"financial analysis\", \"market research\", \"forecasting\"],\r\n \"Customer Service work\": [\"handling customer inquiries\", \"providing support\", \"resolving issues\", \"maintaining customer satisfaction\"],\r\n \"Sales work\": [\"lead generation\", \"prospect qualification\", \"product presentations\", \"negotiations\", \"closing deals\"],\r\n \"Management work\": [\"strategic planning\", \"team leadership\", \"resource allocation\", \"decision-making\"],\r\n \"Technology Implementation\": [\"implementing and integrating technology solutions\", \"software development\", \"system configuration\", \"deployment\", \"testing\", \"user training\"],\r\n \"Financial Analysis\": [\"financial statement analysis\", \"budgeting\", \"forecasting\", \"risk assessment\", \"investment evaluation\"],\r\n \"Legal Research and Advice\": [\"legal research\", \"contract review\", \"case analysis\", \"providing legal advice\"],\r\n \"Healthcare Provision\": [\"patient care\", \"diagnosis\", \"treatment planning\", \"medical procedures\", \"healthcare consultations\"]\r\n}" +
"\nYou will create a breakdown of the job activity, focusing on " + SegmentTitle + "." +
"\nOutline the specific tasks, with a title and a description of the outputs/reports that an employee in this role would be expected to perform / produce. " +
"\nReturn this breakdown as an array of JSON objects. Each JSON object represents a task and will have the following properties." +
"\nProperties:" +
"\nSection is the exact Job Category stated above, " +
"\nTitle is Title of the task" +
"\nTypeOfWork is the key in the previously mentioned types of work object" +
"\nTaskHandler is the appropriate value in TypeOfWork property array" +
"\nOutputs is an array of objects that represent the subtasks involved in the parent task. Each output has a Title property (which is descriptive) and a Description property (Which describes what is being performed/output/reported) " +
"\nExample format: [{\r\n \"Section\": \"Sales\",\r\n \"Title\": \"Contact Customers\",\r\n \"TypeOfWork\": \"Sales work\",\r\n \"TaskHandler\": \"lead generation\",\r\n \"Outputs\": [{\r\n \"Title\": \"Prospect List\",\r\n \"Description\": \"Generate a list of potential customers\"\r\n }, {\r\n \"Title\": \"Sales Calls\",\r\n \"Description\": \"Make sales calls to prospects\"\r\n }]\r\n}, {\r\n \"Section\": \"Sales\",\r\n \"Title\": \"Product Presentations\",\r\n \"TypeOfWork\": \"Sales work\",\r\n \"TaskHandler\": \"product presentations\",\r\n \"Outputs\": [{\r\n \"Title\": \"Product Presentations\",\r\n \"Description\": \"Deliver engaging presentations to showcase products\"\r\n }, {\r\n \"Title\": \"Upselling Opportunities\",\r\n \"Description\": \"Identify upselling opportunities during presentations\"\r\n }]\r\n}...] " +
"\nPlease return the array of JSON objects.";
return prompt;
/*"Job Activity Breakdown: " + JobTitle + " (" + SegmentTitle + ")" +
"Job Title: " + JobTitle + "\n" +
"Job Description: " + JobDescriptionSummary + "\n" +
"This object represents different types of work. Each type of work has a variety of tasks associated with it." +
" {\r\n \"Administrative work\": [\"data entry\", \"scheduling\", \"calendar management\", \"answering phones\", \"email correspondence\"],\r\n \"Creative work\": [\"graphic design\", \"content creation\", \"copywriting\", \"multimedia production\"],\r\n \"Analytical work\": [\"data analysis\", \"financial analysis\", \"market research\", \"forecasting\"],\r\n \"Customer Service work\": [\"handling customer inquiries\", \"providing support\", \"resolving issues\", \"maintaining customer satisfaction\"],\r\n \"Sales work\": [\"lead generation\", \"prospect qualification\", \"product presentations\", \"negotiations\", \"closing deals\"],\r\n \"Management work\": [\"strategic planning\", \"team leadership\", \"resource allocation\", \"decision-making\"],\r\n \"Technology Implementation\": [\"implementing and integrating technology solutions\", \"software development\", \"system configuration\", \"deployment\", \"testing\", \"user training\"],\r\n \"Financial Analysis\": [\"financial statement analysis\", \"budgeting\", \"forecasting\", \"risk assessment\", \"investment evaluation\"],\r\n \"Legal Research and Advice\": [\"legal research\", \"contract review\", \"case analysis\", \"providing legal advice\"],\r\n \"Healthcare Provision\": [\"patient care\", \"diagnosis\", \"treatment planning\", \"medical procedures\", \"healthcare consultations\"]\r\n }"
+ "Please create a breakdown of the job activity, focusing on sales and upselling tasks. Outline the specific tasks, outputs, and reports that an employee in this role would be expected to perform/produce. Return the breakdown as a JSON object." +
"Example format: " +
"[\r\n {\r\n \"Section\": \"Sales\",\r\n \"Title\": \"Contact Customers\",\r\n \"TypeOfWork\": \"Sales work\",\r\n \"TaskHandler\": \"lead generation\",\r\n \"Outputs\": [\r\n {\r\n \"Title\": \"Prospect List\",\r\n \"Description\": \"Generate a list of potential customers\",\r\n \"Report\": \"Prospect list with contact details\"\r\n },\r\n {\r\n \"Title\": \"Sales Calls\",\r\n \"Description\": \"Make sales calls to prospects\",\r\n \"Report\": \"Call log with outcomes and follow-up actions\"\r\n }\r\n ]\r\n },\r\n {\r\n \"Section\": \"Sales\",\r\n \"Title\": \"Product Presentations\",\r\n \"TypeOfWork\": \"Sales work\",\r\n \"TaskHandler\": \"product presentations\",\r\n \"Outputs\": [\r\n {\r\n \"Title\": \"Product Presentations\",\r\n \"Description\": \"Deliver engaging presentations to showcase products\",\r\n \"Report\": \"Feedback from customers and sales conversion rates\"\r\n },\r\n {\r\n \"Title\": \"Upselling Opportunities\",\r\n \"Description\": \"Identify upselling opportunities during presentations\",\r\n \"Report\": \"Upselling success rates and revenue generated\"\r\n }\r\n ]\r\n },\r\n ...\r\n ]"
+ " Please provide the breakdown of the job activity, including additional sections, tasks, outputs, and reports related to sales and upselling in the car dealership context."*/
}
/**
* LoaderView - this method uses a switch statement to make loaderview visible or reverse. This also controls visibility of the initial video hero.
* @param visible - boolean value that determines if the loaderview is visible
*/
function LoaderView(visible)
{
switch(visible)
{
case true:
// hide background video
$('.background-video').hide();
$('.background-video-agency').hide();
$('.hcv-container').show();
$('#hero-holder').show();
$('#background-image-hero').show();
// show loader (without textbox)
$('#statement-component').show();
$('#statement-loader').show();
$('#statement-text').hide();
$('#cta-wrapper').hide();
break;
case false:
// show hero image
$('.hcv-container').show();
$('#hero-holder').show();
$('#background-image-hero').show();
// hide loader
$('#statement-component').hide();
break;
}
}
/**
* LoaderHeading - this method sets the header text in the loaderview
* @param message - the loaderview header text
*/
function LoaderHeading(message)
{
var loadingMessage = document.getElementById('statement-heading');
if(loadingMessage !== null)
{
loadingMessage.textContent = message;
}
}
/**
* removeBeforeOpeningBracketOrCurlyBracket - This method checks the returned json for any other information that is sent and removes it, this allows us to parse the object without it failing because of preceding messages
* @param str - the string returned by the API call
* @returns - returns the object without any preceding text
*/
function removeBeforeOpeningBracketOrCurlyBracket(str) {
const openingSquareBracketIndex = str.indexOf('[');
const openingCurlyBracketIndex = str.indexOf('{');
if (openingSquareBracketIndex !== -1 && openingCurlyBracketIndex !== -1) {
// If both brackets are found, extract the substring starting from the first occurrence
if (openingSquareBracketIndex < openingCurlyBracketIndex) {
return str.substring(openingSquareBracketIndex);
} else {
return str.substring(openingCurlyBracketIndex);
}
} else if (openingSquareBracketIndex !== -1) {
// Only opening square bracket is found, extract the substring from that position
return str.substring(openingSquareBracketIndex);
} else if (openingCurlyBracketIndex !== -1) {
// Only opening curly bracket is found, extract the substring from that position
return str.substring(openingCurlyBracketIndex);
}
return str; // Return the original string if no opening bracket is found
}
/* edited version - divs for each output */
function CreateJobActivities(jobActivities, JobSegmentNo, JobSegmentTitle, JobTitle, JobDescriptionSummary, SegmentId, ActivityIds, jobObj)
{
try
{
// check loading
var isLoading = false;
if($('#initLoading').val() == "loadingExisting")
{
isLoading = true;
}
// Check if container div exists with id = 'JobActivities_' + JobSegementNo
let jobActivitiesContainer = document.getElementById('JobActivities');
let containerId = 'JobActivities_' + JobSegmentNo;
let container = document.getElementById(containerId);
// If the container doesn't exist, create it
if (!container) {
container = document.createElement('div');
container.id = containerId;
container.classList.add('JobActivity');
//document.body.appendChild(container);
// add break before this title
// Add a heading to the container - moved to createJobsegment
/*let headingJobActivities = document.createElement('h2');
headingJobActivities.textContent = "Your Activities";
headingJobActivities.style.marginTop = "40px";
jobActivitiesContainer.appendChild(headingJobActivities); */
// add paragraph to jobActivitiesContainer
/*var activitiesParagraph = document.createElement('p');
activitiesParagraph.textContent = "Our AI analyzed your information and identified these as your Activities. These represent the key tasks or actions that fall under each Job Segment, helping break down your role into functional parts.";
jobActivitiesContainer.appendChild(activitiesParagraph); */
// Add a heading to the container
let heading = document.createElement('h3');
heading.textContent = JobSegmentTitle;
container.appendChild(heading);
// add rule beneath heading
let rule = document.createElement('hr');
container.appendChild(rule);
if(JobSegmentNo > 1)
{
container.style.display = 'none';
}
}
if(JobSegmentTitle == "Custom Tasks")
{
// add 'add custom task'
// Create a new div element with an ID for the section
var customActivitySection = document.createElement('div');
customActivitySection.id = 'custom-activity-section';
customActivitySection.style.backgroundColor = '#E6F4EA'; // Light green background
customActivitySection.style.padding = '15px';
customActivitySection.style.borderRadius = '8px';
customActivitySection.style.marginTop = '20px';
customActivitySection.style.width = '100%';
customActivitySection.style.boxSizing = 'border-box';
// Create a heading for the section
var sectionHeading = document.createElement('h3');
sectionHeading.textContent = 'Need to add a custom task?';
sectionHeading.style.marginBottom = '5px';
// Create a paragraph for the explanation
var sectionText = document.createElement('p');
sectionText.textContent = 'If there\'s something specific you\'d like to track, add a custom activity to your job segment.';
sectionText.style.fontSize = 'small';
sectionText.style.margin = '0px';
// Create the button container
var buttonContainer = document.createElement('div');
buttonContainer.style.display = 'flex';
buttonContainer.style.alignItems = 'center';
buttonContainer.style.marginTop = '10px';
// Create the button
var addCustomBtn = document.createElement('button');
addCustomBtn.className = 'toolsAdvice';
addCustomBtn.id = 'add-custom-activity-button';
addCustomBtn.style.height = '40px';
addCustomBtn.style.borderRadius = '10px';
addCustomBtn.style.maxWidth = '300px';
addCustomBtn.style.padding = '0px 5px';
addCustomBtn.style.backgroundColor = 'white';
addCustomBtn.style.border = '1px solid darkgray';
addCustomBtn.style.display = 'flex';
addCustomBtn.style.alignItems = 'center';
addCustomBtn.style.justifyContent = 'center';
addCustomBtn.style.gap = '5px';
addCustomBtn.style.cursor = 'pointer';
// Create the button icon
var buttonIcon = document.createElement('img');
buttonIcon.src = 'https://flexluthor.s3.eu-west-2.amazonaws.com/images/sparkle.png';
buttonIcon.alt = 'Add Custom Activity';
buttonIcon.style.height = '20px';
// Create the button text
var buttonText = document.createElement('span');
buttonText.textContent = '+ Add Custom Activity';
// Add an onclick event to the button
addCustomBtn.onclick = function () {
console.log("Custom activity button clicked. Open your modal or trigger an event here.");
//add-custom-activity-button
$('#custom-task-modal').css('z-index', '10001').animate({ opacity: 1 }).show();
var holder = document.querySelector('#custom-task-modal');
const button = holder.querySelector("#generate-steps-button");
const buttonText = button.querySelector('#button-text');
const spinner = button.querySelector('#spinner');
var errorMsg = holder.querySelector('#custom-activity-error');
// add validators to the UI
// hide validators
$('#validateCustomName').hide();
$('#validateCustomDescription').hide();
$('#validateCustomOutput').hide();
};
// Append the icon and text to the button
addCustomBtn.appendChild(buttonIcon);
addCustomBtn.appendChild(buttonText);
// Append button to the container
buttonContainer.appendChild(addCustomBtn);
// Append all elements to the section
customActivitySection.appendChild(sectionHeading);
customActivitySection.appendChild(sectionText);
customActivitySection.appendChild(buttonContainer);
// Append the section to the body (or any other container in your DOM)
// Add the output div to the container
container.appendChild(customActivitySection);
if(jobActivities.length == 0)
{
// add all to jobactivities
jobActivitiesContainer.appendChild(container);
jobActivitiesContainer.scrollIntoView({behavior: "smooth"});
}
}
// create tab container
// Create main tab container
const tabContainer = document.createElement('div');
tabContainer.className = 'tab-container';
// Create tab navigation
const tabNav = document.createElement('div');
tabNav.className = 'tab-nav';
// Create Tasks button
const tasksButton = document.createElement('button');
tasksButton.className = 'tab-button active';
tasksButton.textContent = 'Tasks';
tasksButton.onclick = () => {
var ActivitySegment = tasksButton.closest('[id^="JobActivities_"]');
switchTab(ActivitySegment, 'tasks');
};
// Create Workflows button
const workflowsButton = document.createElement('button');
workflowsButton.className = 'tab-button';
workflowsButton.textContent = 'Workflows';
/*workflowsButton.onclick = () => {
// call api to find workflows
// check if populated
// if not create search query
var jobTitle = jobObj["JobTitle"];
var industry = jobObj["Industry"];
var SegmentTitle = JobSegmentTitle;
// use loop to go through all activities and create these
var searchQuery = `user is ${jobTitle} in ${industry} working on ${SegmentTitle} to achieve ${ActivityDescription}. Work Type is ${TypeOfWork}. Under Handler ${TaskHandler}`;
// output array of queries
// use promise to do all at once
switchTab('workflows');
};*/
workflowsButton.onclick = async () => {
var ActivitySegment = tasksButton.closest('[id^="JobActivities_"]');
// Get the workflows content container
const workflowsContent = workflowsButton.closest("[id^='JobActivities_']").querySelector("[id^='workflows-content']");
// Check if already populated
const workflowsContainer = workflowsButton.closest("[id^='JobActivities_']").querySelector("[id^='workflows-container']");
if (workflowsContainer && workflowsContainer.children.length > 0) {
// Already populated, just switch tab
switchTab(ActivitySegment, 'workflows');
return;
}
// Get current job segment
const currentSegment = jobObj.JobSegments[JobSegmentNo];
const jobTitle = jobObj.JobTitle;
const industry = jobObj.Industry;
const segmentTitle = currentSegment.Name;
const activities = currentSegment.Activities;
// Switch to workflows tab first
switchTab(ActivitySegment, 'workflows');
// Show loading indicator
workflowsContent.innerHTML = `
Loading workflows for ${activities.length} activities...
`;
// Build search queries for each activity
const searchPromises = activities.map((activity, index) => {
const activityDescription = activity.Title;
const typeOfWork = activity.TypeOfWork;
const taskHandler = activity.TaskHandler;
const section = activity.Section;
const searchQuery = `user is ${jobTitle} in ${industry} working on ${segmentTitle} to achieve ${activityDescription}. Work Type is ${typeOfWork}. Under Handler ${taskHandler}`;
// Return promise with activity metadata
return searchWorkflows({
query: searchQuery,
maxResults: 5
}).then(result => ({
activity: activity,
activityIndex: index,
activityTitle: activityDescription,
section: section,
results: result.success ? result.data.results : [],
query: searchQuery
})).catch(error => {
console.error(`Error searching workflows for activity "${activityDescription}":`, error);
return {
activity: activity,
activityIndex: index,
activityTitle: activityDescription,
section: section,
results: [],
error: error.message,
query: searchQuery
};
});
});
try {
// Execute all searches in parallel
const allResults = await Promise.all(searchPromises);
// Clear loading indicator and create main container
workflowsContent.innerHTML = '';
// Create scrollable wrapper
const mainWrapper = document.createElement('div');
mainWrapper.style.padding = '20px';
mainWrapper.style.maxHeight = '100%';
mainWrapper.style.overflowY = 'auto';
// Add header
const header = document.createElement('div');
header.style.marginBottom = '30px';
header.innerHTML = `
Recommended Workflows
${segmentTitle} - ${activities.length} activities
`;
mainWrapper.appendChild(header);
// Create sections for each activity
allResults.forEach((result, index) => {
// Create section container
const sectionDiv = document.createElement('div');
sectionDiv.style.marginBottom = '40px';
sectionDiv.id = 'SectionDiv_' + index;
// Section header
const sectionHeader = document.createElement('div');
sectionHeader.style.marginBottom = '15px';
sectionHeader.style.paddingBottom = '10px';
sectionHeader.style.borderBottom = '2px solid #e5e7eb';
const activityTitle = document.createElement('h3');
activityTitle.style.margin = '0 0 5px 0';
activityTitle.style.color = '#374151';
activityTitle.style.fontSize = '18px';
activityTitle.style.fontWeight = '600';
activityTitle.textContent = result.activityTitle;
const activityMeta = document.createElement('p');
activityMeta.style.margin = '0';
activityMeta.style.color = '#9ca3af';
activityMeta.style.fontSize = '13px';
activityMeta.innerHTML = `
${result.activity.TypeOfWork}
${result.results.length} workflow${result.results.length !== 1 ? 's' : ''} found
`;
sectionHeader.appendChild(activityTitle);
sectionHeader.appendChild(activityMeta);
sectionDiv.appendChild(sectionHeader);
// Workflows container for this activity
const activityWorkflowsContainer = document.createElement('div');
activityWorkflowsContainer.id = `workflows-container-activity-${index}`;
sectionDiv.appendChild(activityWorkflowsContainer);
mainWrapper.appendChild(sectionDiv);
workflowsContent.appendChild(mainWrapper);
// Display workflows for this activity
if (result.results.length > 0) {
displayWorkflows(result.results, sectionDiv);
} else {
const emptyMessage = document.createElement('div');
emptyMessage.style.padding = '20px';
emptyMessage.style.textAlign = 'center';
emptyMessage.style.color = '#9ca3af';
emptyMessage.style.fontSize = '14px';
emptyMessage.style.fontStyle = 'italic';
emptyMessage.textContent = result.error
? `Error loading workflows: ${result.error}`
: 'No workflows found for this activity';
activityWorkflowsContainer.appendChild(emptyMessage);
}
});
// Log summary
const totalWorkflows = allResults.reduce((sum, r) => sum + r.results.length, 0);
console.log(`Loaded ${totalWorkflows} workflows across ${activities.length} activities`);
} catch (error) {
console.error('Error loading workflows:', error);
workflowsContent.innerHTML = `
⚠️ Error loading workflows
${error.message}
`;
}
};
// Append buttons to nav
tabNav.appendChild(tasksButton);
tabNav.appendChild(workflowsButton);
// append tab-nav
container.appendChild(tabNav);
// Create Tasks tab content
const tasksContent = document.createElement('div');
tasksContent.id = 'tasks-content';
tasksContent.className = 'tab-content active';
// Create Workflows tab content
const workflowsContent = document.createElement('div');
workflowsContent.id = 'workflows-content';
workflowsContent.className = 'tab-content';
// add tasks-content holder
// then add that to container
// everything after this point is added to tasks-content holder rather than container
// add workflows-content holder
// Loop through all job activities
for (let i = 0; i < jobActivities.length; i++) {
let activity = jobActivities[i];
let activityId = 'jobActivity_' + JobSegmentNo + '_Activity_' + i;
// Create a div for each activity
let div = document.createElement('div');
//div.className = 'segment-container';
div.id = activityId;
div.style.marginLeft = "10px";
div.style.marginRight = "10px";
div.segmentId = SegmentId;
div.activityId = ActivityIds[i];
//div.activityId = ActivityIds[i];
// Add a subheading for the activity
let subheading = document.createElement('h4');
subheading.className = "activity-subheading";
subheading.style.color = 'gray';
subheading.style.fontWeight = 'normal';
subheading.textContent = activity['Section'] + ' > ' + activity['Title'];
div.appendChild(subheading);
var segmentWrapper = document.createElement('div');
segmentWrapper.className = "segments-wrapper";
div.appendChild(segmentWrapper);
// Loop through all outputs of the activity
for (let j = 0; j < activity['Outputs'].length; j++)
{
let activityOuputId = 'jobActivity_' + JobSegmentNo + '_Activity_' + i + '_Output_' + j;
let output = activity['Outputs'][j];
let divOutput = document.createElement('div');
divOutput.classList.add('segment-container');
divOutput.id = activityOuputId;
divOutput.segmentId = SegmentId;
//divOutput.activityId = generateRandomString(8);
//divOutput.activityId = activity['Outputs'][j]["ActivityId"];
divOutput.activityId = activity['Outputs'][j]["ActivityOutputId"];
//divOutput.activityId = ActivityIds[i];
ConsoleLog('divOutputID: ' + divOutput.id);
divOutput.style.position = 'relative'; // Set position to relative here
// Inside your for loop after creating divOutput
/*const padlockLabel = document.createElement('div');
padlockLabel.className = 'padlock-label';
padlockLabel.innerHTML = '🔒';*/
// Define the SVG string with the requested changes:
// 1. Removed the 'class' attribute.
// 2. Replaced 'stroke="currentColor"' with 'stroke="#FFBF00"' (a shade of Amber Gold).
const padlockSVGString = `
`;
// 1. Create a container element (like the original 'div').
// We'll still use a 'div' or similar wrapper to hold the SVG content,
// mimicking the structure of your original 'padlockLabel' div.
const padlockLabel = document.createElement('div');
// 2. Set the className (if you still need the 'padlock-label' class on the wrapper).
padlockLabel.className = 'padlock-label';
// 3. Insert the modified SVG string directly into the wrapper element's content.
// This effectively replaces the 'innerHTML = "🔒"' step.
padlockLabel.innerHTML = padlockSVGString.trim();
divOutput.appendChild(padlockLabel); // Append padlock label to the divOutput
// if first in array hide padlock as its free
if(i == 0 && j == 0)
{
padlockLabel.style.display = 'none';
}
var isPaid = false;
// Check for and update or add the "paidAccount" property
if ("paidAccount" in jobObj || localStorage.getItem("paidAccount"))
{
if(jobObj.paidAccount == true || localStorage.getItem("paidAccount") == "true")
{
isPaid = true;
}
}
if(isPaid)
{
// hide all padlocks if paid account
padlockLabel.style.display = 'none';
}
// 1. Define the SVG string exactly as requested
const trendingUpSVGString = `
`;
// 2. Create a temporary container element (like a div)
const tempContainer = document.createElement('div');
// 3. Set the container's innerHTML to the SVG string
tempContainer.innerHTML = trendingUpSVGString.trim();
// 4. Extract the actual SVG element from the container
const trendingUpSVG = tempContainer.firstChild;
divOutput.appendChild(trendingUpSVG);
// Add a heading for the output
let outputHeading = document.createElement('h4');
outputHeading.textContent = output['Title'];
outputHeading.style.color = 'green';
divOutput.appendChild(outputHeading);
// Add description text below the heading
let outputDescription = document.createElement('p');
outputDescription.textContent = output['Description'];
divOutput.appendChild(outputDescription);
// add activity task level hitl to ui card
// Assuming you have the HITL score value
// need to create an average for all of the hitl steps in that task
//let hitlScore = output["Steps"][x]["HITLScore"]["overall_hitl_score"]; // or however you're getting the score
// Calculate average HITL score across all steps
let totalScore = 0;
let stepCount = 0;
for (let h = 0; h < output["Steps"].length; h++) {
if (output["Steps"][h]["HITLScore"] && output["Steps"][h]["HITLScore"]["overall_hitl_score"] !== undefined) {
totalScore += Number(output["Steps"][h]["HITLScore"]["overall_hitl_score"]);
stepCount++;
}
}
let hitlScore = stepCount > 0 ? (totalScore / stepCount).toFixed(1) : 0;
// Create HITL badge
let hitlBadge = document.createElement('span');
hitlBadge.style.display = 'inline-flex';
hitlBadge.style.alignItems = 'center';
hitlBadge.style.padding = '6px 12px';
hitlBadge.style.borderRadius = '20px';
hitlBadge.style.fontSize = '14px';
hitlBadge.style.fontWeight = '500';
hitlBadge.style.marginTop = '8px';
// Determine color based on score
let borderColor, textColor, bgColor, badgeContent;
if (hitlScore == 0 || isNaN(hitlScore))
{
// No score - Gray with padlock
borderColor = '#9ca3af';
textColor = '#9ca3af';
bgColor = '#f3f4f6';
let padlockSvg = ` `;
badgeContent = `${padlockSvg}HITL`;
} else if (hitlScore <= 1.5) {
// Low HITL - Green
borderColor = '#10b981';
textColor = '#10b981';
bgColor = '#ecfdf5';
let starSvg = ` `;
badgeContent = `${starSvg}HITL: ${hitlScore}`;
} else if (hitlScore <= 3.5) {
// Medium HITL - Amber
borderColor = '#f59e0b';
textColor = '#f59e0b';
bgColor = '#fffbeb';
let starSvg = ` `;
badgeContent = `${starSvg}HITL: ${hitlScore}`;
} else {
// High HITL - Red
borderColor = '#ef4444';
textColor = '#ef4444';
bgColor = '#fef2f2';
let starSvg = ` `;
badgeContent = `${starSvg}HITL: ${hitlScore}`;
}
hitlBadge.style.border = `2px solid ${borderColor}`;
hitlBadge.style.color = textColor;
hitlBadge.style.backgroundColor = bgColor;
hitlBadge.innerHTML = badgeContent;
divOutput.appendChild(hitlBadge);
hitlBadge.style.border = `2px solid ${borderColor}`;
hitlBadge.style.color = textColor;
hitlBadge.style.backgroundColor = bgColor;
divOutput.addEventListener('click', function() {
try
{
// open the steps for this output
var jobDescriptionSummary = JobDescriptionSummary;
/* check for stored properties in storedprofile */
var localStorageValue = localStorage.getItem("profile");
/* set default values */
var SegmentIndex = 0;
var ActivityIndex = 0;
var OutputIndex = 0;
var stepsPresent = false;
/*var localStoredProfile = JSON.parse(localStorage.getItem("profile"));
var jobObj = localStoredProfile; */
SegmentIndex = findSegmentIndexById(jobObj["JobSegments"], divOutput.segmentId);
ActivityIndex = findActivityIndexByOutputId(jobObj["JobSegments"][SegmentIndex]["Activities"], divOutput.activityId);
OutputIndex = findActivityOutputIndexById(jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"], divOutput.activityId);
//stepsPresent = "Steps" in jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex];
ConsoleLog("divoutput click test: ");
ConsoleLog('divOutputID: ' + divOutput.activityId);
ConsoleLog("SegmentIndex: " + SegmentIndex + "ActivityIndex: " + ActivityIndex + "OutputIndex: " + OutputIndex);
stepsPresent = !!(jobObj?.["JobSegments"]?.[SegmentIndex]?.["Activities"]?.[ActivityIndex]?.["Outputs"]?.[OutputIndex]?.["Steps"]?.length ?? false);
/*
Explanation:
Optional chaining (?.): As before, safely handles potential null or undefined values in the chain.
Nullish coalescing (??): Provides a default value if the optional chaining expression evaluates to null or undefined. In this case, it sets the value to false.
Coerce to boolean (!!): Still necessary to ensure stepsPresent is a boolean value, as ?? returns the provided default value directly.
With this approach:
If the "Steps" property exists and has elements, stepsPresent will be true.
If the "Steps" property exists but is empty, stepsPresent will be false.
If any part of the chain is null or undefined, stepsPresent will also be false.
*/
// go to createuisteps
if(stepsPresent)
{
// I THINK IF ALREADY PRESENT SHOULD JUST OPEN THEM
// find this specific set of steps for this activity
// if present use that to call createuisteps
/*resultText.value = result;*/
ConsoleLog('Step-By-Step Present: ');
var steps = jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Steps"];
var stepIds = [];
// create id for each
steps.forEach(step => {
stepIds.push(step.id);
});
var JobInfo = {};
JobInfo["JobTitle"] = JobTitle;
JobInfo["JobDescriptionSummary"] = JobDescriptionSummary;
var TaskInfo = {};
TaskInfo["Steps"] = steps;
TaskInfo["StepIds"] = stepIds;
TaskInfo["SegmentId"] = divOutput.segmentId;
TaskInfo["ActivityId"] = divOutput.activityId;
/* need to maintain parameter format so need a object that holds steps as a property */
var StepsObj = {};
StepsObj["Steps"] = steps;
// FIX: this should only get called if the steps havent already been set.
// this is the one we are seeing - the others are using activitycontainer... that does not exist
//$('#jobActivity_1_Activity_0_Output_0_steps.activity-steps .StepToolSearchSelector').length
//$(this).parent().find('#_steps_instructions_0').show();
var stepsContainerId = $(this).attr('id') + "_steps";
//$('#jobActivity_1_Activity_0_Output_0_steps .StepToolSearchSelector').length
if($('#' + stepsContainerId + ' .StepToolSearchSelector').length == 0)
{
CreateUISteps(StepsObj, TaskInfo, JobInfo, divOutput.id, JobSegmentTitle, jobObj);
}
$('#' + stepsContainerId + ' #btnShowMe').hide();
$('#' + stepsContainerId + ' #step-description').hide();
$('#' + stepsContainerId).show();
$('#' + stepsContainerId + ' #_steps_instructions_0').show();
// hide segments and activities
$('#JobSegments').hide();
$('#JobActivities').hide();
$('#nav-embed').hide();
$('#ExpandedView').show();
window.scrollTo(0, 0);
}
if(!stepsPresent)
{
// check for paid account
var isPaid = false;
// Check for and update or add the "paidAccount" property
if ("paidAccount" in jobObj || localStorage.getItem("paidAccount"))
{
if(jobObj.paidAccount == true || localStorage.getItem("paidAccount") == "true")
{
isPaid = true;
}
}
// if not paid then it is empty because it was removed.
// trigger the upsell
switch(isPaid)
{
case false:
// trigger upsell
// create a upsell modal that has all of the information about the paid account
//OpenModal("Unlock The Full Experience", "Need more help with your AI Strategy? Unlock it with a paid account", false, true);
OpenModal("Maximize Your AI Potential", "Need more help with your AI Strategy? Unlock it with a paid account", false, true);
break;
}
}
}
catch(errClick)
{
ConsoleLog('error name: ' + errClick.name);
ConsoleLog('error message: ' + errClick.messsage);
ConsoleLog('error stacktrace: ' + errClick.stack);
}
});
// add to parent div
//div.appendChild(divOutput);
segmentWrapper.appendChild(divOutput);
// Add the output div to the container
//container.appendChild(div);
tasksContent.appendChild(div);
// Create steps for each output
/* set default values */
var SegmentIndex = 0;
var ActivityIndex = 0;
var OutputIndex = 0;
var stepsPresent = false;
SegmentIndex = findSegmentIndexById(jobObj["JobSegments"], divOutput.segmentId);
ConsoleLog("SegmentIndex: ",SegmentIndex);
/*
function findActivityIndexByOutputId(JobActivities, OutputActivityId) {
var foundIndex = JobActivities.findIndex(jobActivity =>
jobActivity.Outputs && jobActivity.Outputs.some(output => output.ActivityId === OutputActivityId)
);
return foundIndex;
}
*/
ActivityIndex = findActivityIndexByOutputId(jobObj["JobSegments"][SegmentIndex]["Activities"], divOutput.activityId);
/*
function findActivityIndexByOutputId(JobActivities, OutputActivityId) {
var foundIndex = JobActivities.findIndex(jobActivity =>
jobActivity.Outputs && jobActivity.Outputs.some(output => output.ActivityOutputId === OutputActivityId)
);
return foundIndex;
}
*/
ConsoleLog("divOutput.activityId: ",divOutput.activityId);
ConsoleLog("ActivityIndex: ",ActivityIndex);
OutputIndex = findActivityOutputIndexById(jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"], divOutput.activityId);
//stepsPresent = "Steps" in jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex];
stepsPresent = !!(jobObj?.["JobSegments"]?.[SegmentIndex]?.["Activities"]?.[ActivityIndex]?.["Outputs"]?.[OutputIndex]?.["Steps"]?.length ?? false);
/*
Explanation:
Optional chaining (?.): As before, safely handles potential null or undefined values in the chain.
Nullish coalescing (??): Provides a default value if the optional chaining expression evaluates to null or undefined. In this case, it sets the value to false.
Coerce to boolean (!!): Still necessary to ensure stepsPresent is a boolean value, as ?? returns the provided default value directly.
With this approach:
If the "Steps" property exists and has elements, stepsPresent will be true.
If the "Steps" property exists but is empty, stepsPresent will be false.
If any part of the chain is null or undefined, stepsPresent will also be false.
*/
// go to createuisteps
// add all to jobactivities
container.appendChild(tasksContent);
container.appendChild(workflowsContent);
jobActivitiesContainer.appendChild(container);
jobActivitiesContainer.scrollIntoView({behavior: "smooth"});
if(stepsPresent)
{
// find this specific set of steps for this activity
// if present use that to call createuisteps
/*resultText.value = result;*/
ConsoleLog('Step-By-Step Present: ');
var steps = jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Steps"];
var stepIds = [];
// create id for each
steps.forEach(step => {
stepIds.push(step.id);
});
var JobInfo = {};
JobInfo["JobTitle"] = JobTitle;
JobInfo["JobDescriptionSummary"] = JobDescriptionSummary;
var TaskInfo = {};
TaskInfo["Steps"] = steps;
TaskInfo["StepIds"] = stepIds;
TaskInfo["SegmentId"] = divOutput.segmentId;
TaskInfo["ActivityId"] = divOutput.activityId;
/* need to maintain parameter format so need a object that holds steps as a property */
var StepsObj = {};
StepsObj["Steps"] = steps;
// this is the one we are seeing - the others are using activitycontainer... that does not exist
//CreateUISteps(data, TaskInfo, JobInfo, parentID, JobSegmentTitle)
//CreateUISteps(StepsObj, TaskInfo, JobInfo, activityOuputId, JobSegmentTitle, jobObj);
}
if(!stepsPresent)
{
// check for paid account
var isPaid = false;
// Check for and update or add the "paidAccount" property
if ("paidAccount" in jobObj || localStorage.getItem("paidAccount"))
{
if(jobObj.paidAccount == true || localStorage.getItem("paidAccount") == "true")
{
isPaid = true;
}
}
// if not paid then it is empty because it was removed.
// trigger the upsell
switch(isPaid)
{
case false:
// trigger upsell
// create a upsell modal that has all of the information about the paid account
//OpenModal("Unlock The Full Experience", "Need more help with your AI Strategy? Unlock it with a paid account", false, true);
OpenModal("Maximize Your AI Potential", "Need more help with your AI Strategy? Unlock it with a paid account", false, true);
break;
}
}
}
// Add the output div to the container
//container.appendChild(div);
tasksContent.appendChild(div);
}
/* SHOW MORE BUTTON */
// add show more button
/*let activityOuputId = 'jobActivity_' + JobSegmentNo + '_Show_More';
let divOutput = document.createElement('div');
divOutput.classList.add('segment-container');
divOutput.classList.add('show-more');
divOutput.id = activityOuputId;
divOutput.segmentId = SegmentId;
// Add a heading for the output
let outputHeading = document.createElement('h4');
outputHeading.textContent = "Show More";
outputHeading.style.textAlign = 'center'; // This line centers the text horizontally
outputHeading.style.color = 'black';
divOutput.appendChild(outputHeading);
// expand the segment to show all of the activities
divOutput.addEventListener('click', function() {
try
{
// SHOW
// show all but the first instance of each segment-container or activit-steps container
var parentElement = $(this).parent(); // Identifying the parent element
// show all '.segment-container'
parentElement.find('.segment-container').show();
// hide show more for this segment
$(this).hide();
// show just the first '.activity-steps' (hides all, then shows first)
parentElement.find('.activity-steps').hide().first().show();
// show all subheadings
parentElement.find('.activity-subheading').show();
}
catch(errClick)
{
ConsoleLog('error name: ' + errClick.name);
ConsoleLog('error message: ' + errClick.messsage);
ConsoleLog('error stacktrace: ' + errClick.stack);
}
});
// Add the show more button to the container
//container.appendChild(divOutput);
tasksContent.appendChild(divOutput);
// HIDE
// 1) hide all expanded - show show more
var totalSegments = $('#jobsegment-dropdown option').length;
for(var x = 1; x < (totalSegments + 1); x++)
{
//var parentElement = $('#JobActivities_' + JobSegmentNo);
var parentElement = $('#JobActivities_' + x);
// Hide all but the first instance of descendants with the class name '.segment-container', excluding '.show-more'
parentElement.find('.segment-container').not('.show-more').not(':first').hide();
// Show all '.show-more' buttons
parentElement.find('.show-more').show();
// Hide all but the first instance of descendants with the class name '.activity-steps'
parentElement.find('.activity-steps').not(':first').hide();
// hide subheadings
parentElement.find('.activity-subheading').not(':first').hide();
// This should make the first one visible for each segment
// Note: Be careful with triggering clicks in a loop - make sure it's the intended action
//parentElement.find('.segment-container').first().click();
}
// 2) open show more segment-containers
// scroll to that segment
var selectedSegment = $('#JobActivities_1');
var position = selectedSegment.offset().top - 110;
window.scrollTo(0, position); */
}
catch(err)
{
ConsoleLog('error name: ' + err.name);
ConsoleLog('error message: ' + err.messsage);
ConsoleLog('error stacktrace: ' + err.stack);
}
}
/**
* simulateChatGPT - This method populates the loaderview with a textbox that loads a context
* specific message word by word (similar to chatgpt). This is used to mask the loading
* time of generative AI.
*
* @param counter - integer value of the segment so we can use specific simulateText values for different searches
* @param mode -
*/
//function simulateChatGPT(text, imageSrc, counter)
function simulateChatGPT(counter, mode)
{
// scroll top of page
window.scrollTo(0, 0);
var simulateText = ["At our AI prompting consultancy, we understand the importance of turning a job description into a comprehensive job specification that sets clear objectives, outlines key activities, and establishes measurable key results. We recognize that this process can be time-consuming and challenging, which is why we leverage the power of artificial intelligence and large language models to streamline and enhance the entire process.\nUsing cutting-edge technology, we analyze the job description provided and extract the essential information. Our AI algorithms then generate a well-defined job specification that captures the core objectives of the role, breaks down the key activities required, and identifies measurable key results to assess performance\nBy utilizing AI and vast amounts of data, we can provide you with efficient prompts that optimize your workflow. These prompts serve as valuable tools to boost your productivity and confidence in achieving your objectives. They offer insights and suggestions that fill in any gaps you may not have even been aware of, empowering you to perform at your best.\nWith our AI-driven approach, you can expedite your work, gain a deeper understanding of your role, and excel in meeting and exceeding your goals. Let our expertise in AI-powered prompts help you unlock your true potential and drive success in your professional endeavors.\n",
"When considering the job segments relative to your current objectives and key results, it is crucial to align them with the focus of your department at that moment. Our AI prompting consultancy provides you with a multitude of prompts powered by state-of-the-art artificial intelligence, designed to assist you in this evaluation process.\nWhile our AI-generated prompts offer valuable insights and suggestions, it is important to exercise critical thinking and confirm the outputs by fact-checking them. While AI can provide efficient and innovative solutions, human judgment and expertise remain essential.\nConsider the prompts as tools to enhance your decision-making and productivity. Evaluate them in the context of your objectives, key results, and the department's current focus. Assess the relevance, feasibility, and alignment of the prompts with your goals.\nBy leveraging the power of AI, you can explore new perspectives, discover alternative approaches, and optimize your work processes. Embrace the prompts as a means to gain confidence, uncover hidden opportunities, and uncover potential blind spots.\nRemember, you are in control, and the prompts are there to support your decision-making. Utilize them as a resource, but always exercise discretion, verify information, and adapt the outputs to suit your specific needs and circumstances.\n",
"At our AI prompting consultancy, we understand that completing tasks effectively requires relevant and timely guidance. That's why we provide prompts for individual activities to assist you throughout the process. These prompts are designed to help you achieve your objectives by offering valuable insights and suggestions.\nDepending on the level of subscription you choose, you will have access to a varying number of prompts. Our subscription model ensures that you have the flexibility to select the level of support that best fits your needs.\nEach prompt is generated by our state-of-the-art AI technology, which has been trained on vast amounts of data. These prompts aim to provide you with actionable recommendations, alternative approaches, or additional information to improve the relevance and efficiency of your work.\nMoreover, we understand that your unique circumstances may require specific information or context. That's why we encourage you to state any additional information that could enhance the relevance of the prompts. By considering your specific needs, our AI algorithms can generate even more tailored and valuable prompts for you.\nWith our prompt subscription service, you gain access to a wealth of AI-generated assistance, empowering you to optimize your productivity and achieve your objectives effectively. Select the subscription level that suits you, and unlock the power of prompts tailored to your tasks.\n",
"At our AI prompting consultancy, we believe in providing prompts that generate fantastic, high-quality outputs for your individual activities. Our AI algorithms are designed to offer valuable insights and suggestions, empowering you to excel in your work. However, we also recognize that there are workflows that can be further enhanced by incorporating additional tools and resources.\nIn order to optimize your workflows, we go beyond prompts and leverage our expertise to recommend strong tools specifically targeted to your needs. By analyzing your core activities, we identify areas where supplementary tools can significantly enhance your productivity and outcomes.\nThese recommended tools are carefully selected to align with your specific workflows, ensuring seamless integration and maximum efficiency. Whether it's project management software, collaboration platforms, data analysis tools, or any other resource, we tailor our recommendations to empower you with the right tools for the job.\nBy combining our AI-generated prompts with these complementary tools, you can unlock even greater potential and achieve exceptional results. Our goal is to provide a comprehensive solution that leverages both AI-driven prompts and targeted tools, enabling you to optimize your workflows and reach new levels of success.\nLet us guide you not only with prompts but also with a curated selection of tools, tailored to your unique requirements. Together, we can transform your work processes and help you accomplish outstanding outcomes.\n",
"At our AI prompting consultancy, we take pride in offering strong and highly efficient AI-generated prompts that assist you in your tasks. These prompts are designed to provide valuable insights, suggestions, and recommendations, utilizing the power of artificial intelligence to optimize your workflow.\nHowever, it's important to note that the quality of the output generated by the prompts is dependent on the input provided. The more relevant and detailed the information you provide, the more tailored and accurate the prompts will be. It's essential to ensure that the input you provide is accurate, comprehensive, and aligned with your specific needs and goals.\nFor those seeking truly tailored prompting solutions, we offer access to expert prompt engineering consultation. Our team of experienced professionals can work closely with you to understand the unique requirements and challenges of your business. Through consultation, we can fine-tune the prompts to suit your specific workflows, objectives, and key results, providing you with highly personalized and effective guidance.\nContact us today to discuss the needs of your business and explore how our expert prompt engineering consultation can further enhance your AI prompting experience. Together, we can create a customized solution that empowers you to achieve outstanding results.\n"];
var simulateImg = ["https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/6485756ead4a2634df4f196a_hero_mypeas_narrow_0002_01-overview.png",
"https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/6485756e841d2b143a2e6caf_hero_mypeas_narrow_0003_02-jobs.png",
"https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/6485756fcdba2a48db8bc9b5_hero_mypeas_narrow_0004_03-activities.png",
"https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/6485756e841d2b143a2e6c87_hero_mypeas_narrow_0005_04-tools.png",
"https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/6485756ff8b87abd36fbcff7_hero_mypeas_narrow_0006_05-consultants.png"];
var arrayIndex = GetIndex(counter, simulateImg);
var text = simulateText[arrayIndex];
var imageSrc = simulateImg[arrayIndex];
switch(mode)
{
case "jobSearch":
text = "At our AI prompting consultancy, we utilize cutting-edge AI technology to generate a comprehensive and accurate list of your key responsibilities and activities, based on the interpretation of your job description. Our advanced algorithms analyze the text, extract relevant information, and organize it into a clear and concise format. By leveraging the power of AI, we save you time and effort in manually identifying and defining your responsibilities, ensuring that nothing gets overlooked. The generated list serves as a valuable reference that helps you stay focused and aligned with your role's expectations, enabling you to prioritize and execute tasks effectively. With our AI-generated list, you can confidently navigate your professional responsibilities and maximize your productivity.";
imageSrc = "https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/646f872bc76212af94a4761c_hero-mypeas-continue_1_50.png";
break;
// click acitivities div
case "ContextSearch":
text = "To fully harness the potential of AI-powered search and boost your productivity, context is key. Our advanced AI search engine seamlessly integrates with your objectives, providing instructions that optimize your work.Our AI algorithm analyzes various factors to understand your work context, aligning with your current objectives and key results. By tailoring instructions to your specific needs, our search engine offers valuable insights and guidance.While our AI search generates innovative solutions, it's important to engage your critical thinking and fact-check the outputs. AI streamlines processes, but human judgment is indispensable. Combine the strengths of AI and your discernment for optimal results.View the instructions from our AI search engine as resources to enhance decision-making and productivity. Evaluate them within your objectives, key results, and departmental focus. Assess their relevance, feasibility, and alignment with your goals.Leverage AI to explore new perspectives, discover alternative approaches, and optimize work processes. Embrace instructions to gain confidence, uncover opportunities, and address blind spots. Remember, you're in control, and instructions support your decision-making and capabilities.Utilize instructions as valuable resources, but exercise discretion, verify information, and adapt outputs to your needs. Our AI-powered search empowers you, maximizing your potential for remarkable professional results.";
break;
// click generate button
case "GenerateSteps":
text = "To unlock the full potential of AI-powered search and boost your productivity, understanding the context is crucial. Our advanced AI search engine seamlessly integrates with your objectives by providing step-by-step instructions and insightful advice tailored to optimize your work.Our AI algorithm analyzes a range of factors to grasp the context of your task, aligning it with your current objectives and key results. By tailoring instructions to your specific needs, our search engine offers valuable guidance and ensures a personalized approach.While our AI search generates innovative solutions, it is essential to engage your critical thinking and fact-check the outputs. AI excels at streamlining processes, but human judgment remains indispensable. Combining the strengths of AI and your own discernment enables you to achieve optimal results.Consider the instructions provided by our AI search engine as valuable resources to enhance your decision-making and boost productivity. Evaluate these instructions within the framework of your objectives, key results, and departmental focus. Assess their relevance, feasibility, and alignment with your goals to make informed choices.In addition to delivering step-by-step instructions, we leverage AI models to identify other AI tools that could further improve the productivity of your task. We explore automation opportunities and recommend suitable AI-powered tools that can expedite and streamline your work processes.By embracing AI, you gain access to new perspectives, alternative approaches, and innovative ways to optimize your work. Our instructions provide the confidence to uncover opportunities and address potential blind spots. Remember, you retain full control of the process, and our instructions are there to support your decision-making and enhance your capabilities.While utilizing the instructions as valuable resources, exercise discretion, verify information, and adapt the outputs to meet your specific needs. Our AI-powered search empowers you, maximizing your potential for remarkable professional results. By leveraging AI models, step-by-step instructions, and recommendations for AI tools and automation, we aim to revolutionize the way you work and amplify your productivity.";
break;
// click 'show me how' button
case "ShowMeHow":
text = "To unlock the full potential of AI-powered search and turbocharge your productivity, we go beyond providing basic instructions. Our advanced AI search engine seamlessly integrates with your objectives, offering detailed step-by-step guidance to optimize your work.Our AI algorithm goes the extra mile by leveraging AI models to expand on the selected step. It provides you with comprehensive instructions on how to execute the task effectively, taking into account your specific needs and circumstances. This detailed guidance helps you navigate through the process with clarity and confidence.But that's not all. We understand that utilizing the right tools is essential for enhancing productivity. Our AI-powered search identifies relevant AI tools that can complement your task. These recommendations are tailored to your objectives, giving you insights into which tools could be useful in achieving your desired outcomes.Furthermore, our AI algorithm explores automation opportunities. We understand that automating certain aspects of your work can significantly streamline your processes and save valuable time. By analyzing the task at hand, our search engine suggests potential automation options, empowering you to optimize your workflow efficiently.It's important to remember that while AI provides valuable insights, your critical thinking and judgment remain crucial. Engaging your own expertise ensures that the outputs align seamlessly with your specific needs and goals. The combination of AI-driven guidance and your discernment enables you to achieve remarkable results.View the instructions provided by our AI search engine as a comprehensive resource that not only outlines the steps but also expands on how to perform them effectively. Consider the AI tool recommendations and Automation Evaluation as valuable insights to boost your productivity further.As you utilize these instructions, exercise discretion, verify information, and adapt the outputs to suit your specific requirements. Our AI-powered search is designed to empower you, amplifying your capabilities and revolutionizing the way you work. By leveraging AI models, detailed step-by-step instructions, AI tool recommendations, and automation considerations, we aim to maximize your potential and drive outstanding professional outcomes.";
break;
}
// hide background video
$('.background-video').hide();
$('.background-video-agency').hide();
$('#hero-holder').show();
$('.hcv-container').show();
$('#background-image-hero').show();
// show holder
$('#statement-component').show();
$('#statement-text').hide();
$('#cta-wrapper').hide();
// hide the robot load animation
$('#statement-loader').hide();
// hide the output text box that was already there
$('#statement-text').hide();
// show simulator
$('#SimulateGPT-container').show();
var messageContainer = $('#statement-simulate-chatgpt');
var messageContainerContinue = $('#statement-simulate-chatgpt-continue');
var heroImage = document.getElementById('simulate-hero');
let currentText = '';
let continueText = '';
let currentIndex = 0;
const words = text.split(' '); // Split the text into individual words
const typingSpeed = 25000; // Adjust this value to control the typing speed for character-by-character typing
const fadeDuration = 1000; // Adjust this value to control the fade-in duration for the hero image
// Calculate the typing speed for word-by-word typing
const wordTypingSpeed = Math.floor(typingSpeed / words.length);
function typeText()
{
const currentWord = words[currentIndex];
currentText += currentWord + ' '; // Append the current word with a space
// Set the CSS properties for font, size, and line height
/*messageContainer.style.fontFamily = 'Arial, sans-serif';
messageContainer.style.fontSize = '17x';
messageContainer.style.lineHeight = '1.7';
messageContainer.style.maxWidth = '600px';*/
messageContainer.css({
'font-family': 'Arial, sans-serif',
'font-size': '17px',
'line-height': '1.7',
'max-width': '600px',
'max-height': '100px',
'overflow-y': 'scroll',
'paddingLeft': '10px',
'paddingRight': '10px',
'margin': '0 auto' // Add this line to center the div
});
messageContainer.text(currentText);
// Scroll the message container to the bottom
messageContainer.scrollTop(messageContainer[0].scrollHeight);
// need a cutoff point to introduce the fade-in image.
const cutoff = Math.floor(words.length / 2);
// check if visible.
if($('#SimulateGPT-container').is(':visible'))
{
/*if (currentIndex < cutoff) {
currentIndex++;
setTimeout(typeText, wordTypingSpeed); // Use the word typing speed here
}
else
{
setTimeout(() => {
fadeHeroImage(imageSrc);
}, fadeDuration);
}*/
/* removed the fade in image */
if (currentIndex < words.length-1) {
currentIndex++;
setTimeout(typeText, wordTypingSpeed); // Use the word typing speed here
}
else
{
// check if still loading, if so go to the robot lottie
if($('.jobsegment.loading').length > 0)
{
// show holder
$('#statement-component').show();
// show the robot (lottie) load animation
$('#statement-loader').show();
// hide simulator
$('#SimulateGPT-container').hide();
// empty BOTH message containers and clear the hero-image
CancelSimulateGPT();
SearchJobEnable(false);
}
else
{
// not loading. hide all
// empty BOTH message containers and clear the hero-image
// show holder
$('#statement-component').hide();
// show the robot (lottie) load animation
$('#statement-loader').hide();
// hide simulator
$('#SimulateGPT-container').hide();
// empty BOTH message containers and clear the hero-image
CancelSimulateGPT();
SearchJobEnable(true);
}
}
}
}
/*
Get the index for the simulateGPT arrays
*/
function GetIndex(counter, stringsArray)
{
// Array of strings
//const stringsArray = ['String 1', 'String 2', 'String 3', 'String 4', 'String 5'];
// Collection of divs
const divCollection = document.getElementsByClassName('your-div-class');
// Function to get string array index based on counter
function getSelectedString(divIndex) {
const maxIndex = stringsArray.length - 1;
const selectedStringIndex = divIndex > maxIndex ? divIndex % stringsArray.length : divIndex;
return selectedStringIndex;
}
const selectedIndex = getSelectedString(counter);
ConsoleLog('GetIndex: ' + selectedIndex);
return selectedIndex;
}
function fadeHeroImage(src) {
heroImage.src = src;
heroImage.style.opacity = 0;
heroImage.style.display = 'block';
heroImage.style.width = '100%';
heroImage.style.maxWidth = '600px';
heroImage.style.margin = '0 auto';
const fadeInInterval = setInterval(() => {
if (parseFloat(heroImage.style.opacity) < 1) {
heroImage.style.opacity = (parseFloat(heroImage.style.opacity) + 0.1).toFixed(1);
} else {
clearInterval(fadeInInterval);
continueTyping();
}
}, 200);
}
function continueTyping() {
const remainingText = words[currentIndex];
continueText += remainingText + ' '; // Append the current word with a space
/*messageContainerContinue.style.fontFamily = 'Arial, sans-serif';
messageContainerContinue.style.fontSize = '17x';
messageContainerContinue.style.lineHeight = '1.7';
messageContainer.style.maxWidth = '600px';*/
messageContainerContinue.css({
'font-family': 'Arial, sans-serif',
'font-size': '17px',
'line-height': '1.7',
'max-width': '600px',
'paddingLeft': '10px',
'paddingRight': '10px',
'margin': '0 auto' // Add this line to center the div
});
messageContainerContinue.text(continueText);
// Scroll the message container to the bottom
messageContainerContinue.scrollTop(messageContainer[0].scrollHeight);
if($('#SimulateGPT-container').is(':visible'))
{
if (currentIndex < words.length - 1) {
currentIndex++;
setTimeout(continueTyping, wordTypingSpeed); // Use the word typing speed here
}
else
{
// check if still loading, if so go to the robot lottie
if($('.jobsegment.loading').length > 0)
{
// show holder
$('#statement-component').show();
// show the robot (lottie) load animation
$('#statement-loader').show();
// hide simulator
$('#SimulateGPT-container').hide();
// empty BOTH message containers and clear the hero-image
CancelSimulateGPT();
SearchJobEnable(false);
}
else
{
// not loading. hide all
// empty BOTH message containers and clear the hero-image
// show holder
$('#statement-component').hide();
// show the robot (lottie) load animation
$('#statement-loader').hide();
// hide simulator
$('#SimulateGPT-container').hide();
// empty BOTH message containers and clear the hero-image
CancelSimulateGPT();
SearchJobEnable(true);
}
}
}
else
{
// check if still loading, if so go to the robot lottie
if($('.jobsegment.loading').length > 0)
{
// show holder
$('#statement-component').show();
// show the robot (lottie) load animation
$('#statement-loader').show();
// hide simulator
$('#SimulateGPT-container').hide();
// empty BOTH message containers and clear the hero-image
CancelSimulateGPT();
SearchJobEnable(false);
}
else
{
// not loading. hide all
// empty BOTH message containers and clear the hero-image
// show holder
$('#statement-component').hide();
// show the robot (lottie) load animation
$('#statement-loader').hide();
// hide simulator
$('#SimulateGPT-container').hide();
// empty BOTH message containers and clear the hero-image
CancelSimulateGPT();
SearchJobEnable(true);
}
}
}
if (window.location.href.toLowerCase().includes('/agency'))
{
typeText_Agency();
}
else
{
typeText();
}
}
/**
* CancelSimulateGPT - this method stops the simulateChatGPT method and hides its container
*/
function CancelSimulateGPT()
{
// clear both text boxes
$('#statement-simulate-chatgpt').val('');
$('#statement-simulate-chatgpt-continue').val('');
// clear the heroimage in the simulator
var heroImage = document.getElementById('simulate-hero');
heroImage.src = '';
// hide their container
// if simulateGPT is visible. if not. it will stop the timeouts
// hide simulator
$('#SimulateGPT-container').hide();
}
/**
* FooterView - this method determines the visibility and function of the footer (which contains search inputs and button)
* @param status - NewSearch (shows the footer in its original state), HideSearch (hides the default footer and displays a button to bring it back if user wants to start a new search)
*/
function FooterView(status)
{
switch(status)
{
case "NewSearch":
/* show jobtitle, job description and generate button */
$('#jobTitle').show();
$('#jobDescription').show();
$('#btnGetJob').show();
/* only show the divider on desktop */
if($('#Footer .divider').eq(0).hasClass('showMe'))
$('#Footer .divider').eq(0).show();
/* hide New Search button */
$('#NewSearch').hide();
break;
case "HideSearch":
/* hide jobtitle, job description and generate button */
$('#jobTitle').hide();
$('#jobDescription').hide();
$('#btnGetJob').hide();
/* only show the divider on desktop (its only visible on desktop) */
if($('#Footer .divider').eq(0).is(':visible'))
$('#Footer .divider').eq(0).hide().addClass('showMe');
/* show New Search button (is a link button so needs set to block to go full width) */
$('#NewSearch').css('width', '100%').css('display', 'block').show();
break;
}
}
/**
* typeHeading - This method applies to the video hero on the start page. this handles the simulated text
*/
/*function typeHeading()
{
var simulateText = ["My Job, with ChatGPT", "Enter Your Job Title", "GPT generates prompts tailored to you", "Enhance Your Productivity ..."];
var arrayIndex = 0;
for(var x = 0; x < simulateText.length; x++)
{
arrayIndex = x;
var text = simulateText[arrayIndex];
// hide the output text box that was already there
$('#statement-text').hide();
var messageContainer = $('#statement-simulate-chatgpt');
if(x == 0)
{
messageContainer = $('#statement-simulate-chatgpt');
}
let currentText = '';
let currentIndex = 0;
const words = text.split(' '); // Split the text into individual words
const typingSpeed = 25000; // Adjust this value to control the typing speed for character-by-character typing
const fadeDuration = 1000; // Adjust this value to control the fade-in duration for the hero image
// Calculate the typing speed for word-by-word typing
const wordTypingSpeed = Math.floor(typingSpeed / words.length);
function typeText()
{
const currentWord = words[currentIndex];
currentText += currentWord + ' '; // Append the current word with a space
// Set the CSS properties for font, size, and line height
messageContainer.css({
'font-family': 'Arial, sans-serif',
'font-size': '17px',
'line-height': '1.7',
'max-width': '600px',
'margin': '0 auto' // Add this line to center the div
});
messageContainer.text(currentText);
}
typeText();
}
}*/
function CheckStatus()
{
// check localstorage
var checkStatusEmail = localStorage.getItem("email");
var checkStatusStatus = localStorage.getItem("processStatus");
// check server for
var sentCheckRequest = false;
// check for localstorage is in processing
if(checkStatusEmail && checkStatusEmail !== "")
{
// if processStatus is processing/updating
if(checkStatusStatus && (checkStatusStatus == "processing/updating" || checkStatusStatus == "processing" || checkStatusStatus == "updating" || checkStatusStatus == "failed"))
{
sentCheckRequest = true;
}
// if contains processStatus=processing/updating -> call checkstatus
}
if(sentCheckRequest)
{
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = "";
MYPEAS_payload["JobDescription"] = "";
MYPEAS_payload["promptDescription"] = "CheckStatus";
MYPEAS_payload["registered"] = "true"; // should always be true now that user provides password at start page
MYPEAS_payload["email"] = checkStatusEmail;
MYPEAS_payload["password"] = "";
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
HidePreLoad();
result = JSON.parse(result);
var processStatus = result.processStatus;
switch(result.processStatus)
{
case "complete":
case "completed":
// stop timer if running
stopCheckStatusIntervals();
HideProcessing("loggedIn");
// check if profile is empty
var profile = result.profile;
if(profile && (profile !== "" && profile !== "\"\""))
{
// if completed and not empty - load profile in UI
profile = result["profile"];
var favourites = result["favourites"] || JSON.stringify([]);
var memberID = result["memberID"];
var authToken = result["auth_token"];
var auth_token_date_created = result["auth_token_date_created"];
var accountInfo = result["accountInfo"] || JSON.stringify({});
var orderHistory = result["orderHistory"] || JSON.stringify([]);
var StripeInvoices = result["StripeInvoices"] || JSON.stringify([]);
var revisions = result["revisions"] || "0";
var optIn = result["optIn"] !== undefined ? result["optIn"] : true;
var paidAccount = result["paidAccount"] !== undefined ? result["paidAccount"] : "false";
if(paidAccount !== undefined)
{
localStorage.setItem("paidAccount", paidAccount);
}
else
{
localStorage.setItem("paidAccount", "false");
}
if(optIn !== undefined)
{
// set optin in localstorage
localStorage.setItem("optIn", optIn);
}
else
{
localStorage.setItem("optIn", true);
}
if(accountInfo == "")
{
accountInfo = JSON.stringify({});
}
if(orderHistory == "")
{
orderHistory = JSON.stringify([]);
}
// set profile in localstorage
localStorage.setItem("profile", JSON.stringify(profile));
localStorage.setItem("favourites", favourites);
// set memberID
localStorage.setItem("memberID", memberID);
// set auth_token
localStorage.setItem("auth_token", authToken);
localStorage.setItem("auth_token_date_created", auth_token_date_created);
localStorage.setItem("processStatus", "complete");
localStorage.setItem("accountInfo", accountInfo);
localStorage.setItem("orderHistory", orderHistory);
localStorage.setItem("StripeInvoices", StripeInvoices);
localStorage.setItem("revisions", revisions);
// show the nav buttons
var btnMyAccount = document.getElementById('btnMyAccount');
var btnMyFavourites = document.getElementById("btnFavourites");
var btnTools = document.getElementById("btnTools");
var btnLogInOut = document.getElementById("btnLogInOut");
var btnAgency = document.getElementById("btnAgency");
var containerWaitList = document.getElementById('waitlist-container');
var skipContainer = document.getElementById('skipwaitlist-container');
$(btnMyAccount).show();
$(btnMyFavourites).show();
$(btnTools).show();
$(btnLogInOut).show();
$(btnAgency).hide();
$(btnLogInOut).text("Log Out");
$(containerWaitList).hide();
$(skipContainer).hide();
// remove any current profile from UX
ClearExistingProfile();
LoadExistingProfile(profile);
accountInfo = JSON.parse(accountInfo);
if(!checkAccountInfo(accountInfo))
{
/*OpenAccountModal();
// show red text saying enter missing information
$('#modal-message-account').text("** Complete Your Account Information **").show();*/
OpenOnboardModal();
}
firstLoad();
ProcessingRequestShowUX();
}
else
{
OpenCloseLoginModal("close");
NewSearch();
}
break;
case "failed":
// stop timer if running
stopCheckStatusIntervals();
var profile = result["profile"];
var favourites = result["favourites"] || JSON.stringify([]);
var memberID = result["memberID"];
var authToken = result["auth_token"];
var auth_token_date_created = result["auth_token_date_created"];
localStorage.setItem("profile", JSON.stringify(profile));
localStorage.setItem("favourites", favourites);
// set memberID
localStorage.setItem("memberID", memberID);
// set auth_token
localStorage.setItem("auth_token", authToken);
localStorage.setItem("auth_token_date_created", auth_token_date_created);
localStorage.setItem("processStatus", "failed");
var profile = result.profile;
if(profile && (profile !== "" && profile !== "\"\""))
{
// check if profile is empty
localStorage.setItem("profile", JSON.stringify(result.profile));
if(profile || (profile !== "" && profile !== "\"\""))
{
ShowProcessing(processStatus);
}
}
if(!profile || (profile == "" || profile == "\"\""))
{
/*HideProcessing("loggedIn");
NewSearch();*/
ShowProcessing(processStatus);
}
break;
case "updating":
case "processing":
case "processing/updating":
// update that it is STILL processing
var profile = result["profile"];
var favourites = result["favourites"] || JSON.stringify([]);
var memberID = result["memberID"];
var authToken = result["auth_token"];
var auth_token_date_created = result["auth_token_date_created"];
localStorage.setItem("profile", JSON.stringify(profile));
localStorage.setItem("favourites", favourites);
// set memberID
localStorage.setItem("memberID", memberID);
// set auth_token
localStorage.setItem("auth_token", authToken);
localStorage.setItem("auth_token_date_created", auth_token_date_created);
localStorage.setItem("processStatus", processStatus);
// if processing
ShowProcessing(processStatus);
break;
default:
break;
}
ConsoleLog("processStatus return: ",JSON.stringify(result));
});
}
// if not - check for querystring is in processing
if(!sentCheckRequest)
{
if(checkStatusEmail && checkStatusEmail !== "")
{
// check querystring
const queryString = window.location.search;
const keyValue = 'processStatus=processing'; // Replace with your actual key-value pair
var keyValues = ['processStatus=processing', 'processStatus=updating'];
for(var x = 0; x < keyValues.length; x++)
{
if (queryString.includes(keyValues[x])) {
ConsoleLog('Key-value pair exists in query string');
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = "";
MYPEAS_payload["JobDescription"] = "";
MYPEAS_payload["promptDescription"] = "CheckStatus";
MYPEAS_payload["registered"] = "true"; // should always be true now that user provides password at start page
MYPEAS_payload["email"] = checkStatusEmail;
MYPEAS_payload["password"] = "";
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
HidePreLoad();
result = JSON.parse(result);
ConsoleLog("processStatus return: ",JSON.stringify(result));
switch(result.processStatus)
{
case "complete":
case "completed":
// stop timer if running
stopCheckStatusIntervals();
HideProcessing("loggedIn");
// check if profile is empty
var profile = result.profile;
if(profile || (profile !== "" && profile !== "\"\""))
{
localStorage.setItem("profile", JSON.stringify(result.profile));
LoadExistingProfile(result.profile);
firstLoad();
}
else
{
OpenCloseLoginModal("close");
NewSearch();
}
break;
case "failed":
// stop timer if running
stopCheckStatusIntervals();
// show retry button
// hide check status button
HideProcessing("loggedIn");
var profile = result.profile;
if(profile || (profile !== "" && profile !== "\"\""))
{
var profile = result.profile;
localStorage.setItem("profile", JSON.stringify(result.profile));
LoadExistingProfile(result.profile);
firstLoad();
}
if(!profile || profile == "" || profile == "\"\"")
{
OpenCloseLoginModal("close");
NewSearch();
}
break;
case "updating":
case "processing":
case "processing/updating":
// update that it is STILL processing
ShowProcessing(processStatus);
break;
default:
break;
}
});
}
else {
ConsoleLog('Key-value pair does not exist in query string');
}
}
}
else
{
// redirect to login page
//window.location.href = window.location.pathname + '?redir=login';
// redirect to home page
location.href = '/?login=true';
}
}
}
function CheckStatus_Agency()
{
// check localstorage
var checkStatusEmail = localStorage.getItem("email");
var checkStatusStatus = localStorage.getItem("processStatus");
// check server for
var sentCheckRequest = false;
// check for localstorage is in processing
if(checkStatusEmail && checkStatusEmail !== "")
{
// if processStatus is processing/updating
if(checkStatusStatus && (checkStatusStatus == "processing/updating" || checkStatusStatus == "processing" || checkStatusStatus == "updating"))
{
sentCheckRequest = true;
}
// if contains processStatus=processing/updating -> call checkstatus
}
if(sentCheckRequest)
{
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = "";
MYPEAS_payload["JobDescription"] = "";
MYPEAS_payload["promptDescription"] = "CheckStatus";
MYPEAS_payload["registered"] = "true"; // should always be true now that user provides password at start page
MYPEAS_payload["email"] = checkStatusEmail;
MYPEAS_payload["password"] = "";
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
var processStatus = result.processStatus;
switch(result.processStatus)
{
case "complete":
case "completed":
HideProcessing("loggedIn");
// check if profile is empty
var profile = result.profile;
if(profile || (profile !== "" && profile !== "\"\""))
{
if(profile == "")
{
HideProcessing("loggedIn");
NewSearch();
}
if(profile != "")
{
// if completed and not empty - load profile in UI
profile = result["profile"];
var favourites = result["favourites"] || JSON.stringify([]);
var memberID = result["memberID"];
var authToken = result["auth_token"];
var auth_token_date_created = result["auth_token_date_created"];
HideProcessing("loggedIn");
// set profile in localstorage
localStorage.setItem("profile", JSON.stringify(profile));
localStorage.setItem("favourites", favourites);
// set memberID
localStorage.setItem("memberID", memberID);
// set auth_token
localStorage.setItem("auth_token", authToken);
localStorage.setItem("auth_token_date_created", auth_token_date_created);
localStorage.setItem("processStatus", "complete");
LoadExistingProfile(profile);
firstLoad();
}
}
else
{
OpenCloseLoginModal("close");
HideProcessing("loggedIn");
NewSearch();
}
break;
case "failed":
var profile = result["profile"];
var favourites = result["favourites"] || JSON.stringify([]);
var memberID = result["memberID"];
var authToken = result["auth_token"];
var auth_token_date_created = result["auth_token_date_created"];
localStorage.setItem("profile", JSON.stringify(profile));
localStorage.setItem("favourites", favourites);
// set memberID
localStorage.setItem("memberID", memberID);
// set auth_token
localStorage.setItem("auth_token", authToken);
localStorage.setItem("auth_token_date_created", auth_token_date_created);
localStorage.setItem("processStatus", "failed");
if(result.profile)
{
var profile = result.profile;
localStorage.setItem("profile", JSON.stringify(result.profile));
}
ShowProcessing(processStatus);
break;
case "updating":
case "processing":
case "processing/updating":
// update that it is STILL processing
var profile = result["profile"];
var favourites = result["favourites"] || JSON.stringify([]);
var memberID = result["memberID"];
var authToken = result["auth_token"];
var auth_token_date_created = result["auth_token_date_created"];
localStorage.setItem("profile", JSON.stringify(profile));
localStorage.setItem("favourites", favourites);
// set memberID
localStorage.setItem("memberID", memberID);
// set auth_token
localStorage.setItem("auth_token", authToken);
localStorage.setItem("auth_token_date_created", auth_token_date_created);
localStorage.setItem("processStatus", processStatus);
// if processing
ShowProcessing(processStatus);
break;
default:
break;
}
ConsoleLog("processStatus return: ",JSON.stringify(result));
});
}
// if not - check for querystring is in processing
if(!sentCheckRequest)
{
if(checkStatusEmail && checkStatusEmail !== "")
{
// check querystring
const queryString = window.location.search;
const keyValue = 'processStatus=processing'; // Replace with your actual key-value pair
var keyValues = ['processStatus=processing', 'processStatus=updating'];
for(var x = 0; x < keyValues.length; x++)
{
if (queryString.includes(keyValues[x])) {
ConsoleLog('Key-value pair exists in query string');
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = "";
MYPEAS_payload["JobDescription"] = "";
MYPEAS_payload["promptDescription"] = "CheckStatus";
MYPEAS_payload["registered"] = "true"; // should always be true now that user provides password at start page
MYPEAS_payload["email"] = checkStatusEmail;
MYPEAS_payload["password"] = "";
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// send request to checkstatus on website
// Make an API call to API gateway
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("processStatus return: ",JSON.stringify(result));
var processStatus = result.processStatus;
switch(result.processStatus)
{
case "complete":
case "completed":
HideProcessing("loggedIn");
// check if profile is empty
var profile = result.profile;
if(profile || (profile !== "" && profile !== "\"\""))
{
if(profile == "")
{
NewSearch();
}
if(profile != "")
{
localStorage.setItem("profile", JSON.stringify(result.profile));
LoadExistingProfile(result.profile);
firstLoad();
}
}
else
{
OpenCloseLoginModal("close");
NewSearch();
}
break;
case "failed":
// show retry button
// hide check status button
HideProcessing("loggedIn");
if(result.profile)
{
var profile = result.profile;
localStorage.setItem("profile", JSON.stringify(result.profile));
LoadExistingProfile(result.profile);
firstLoad();
}
if(!result.profile || result.profile == "")
{
NewSearch();
}
break;
case "updating":
case "processing":
case "processing/updating":
// update that it is STILL processing
ShowProcessing(processStatus);
break;
default:
break;
}
});
}
else {
ConsoleLog('Key-value pair does not exist in query string');
}
}
}
else
{
// redirect to login page
//window.location.href = window.location.pathname + '?redir=login';
// redirect to home page
location.href = '/?login=true';
}
}
}
function WhatIsMyPeas()
{
// test
var slowSpeed = 500;
var fastSpeed = 15;
var typingSpeed = 15; // Adjust the typing speed (in milliseconds)
var pauseDuration = 100; // Pause duration between strings (in milliseconds)
var index = 0;
var charIndex = 0;
var currentString = "";
var strings = [
".AI won’t replace you",
"Somebody Using .AI will",
"Don’t Get. . .",
"Left Behind!",
];
if (window.location.href.toLowerCase().includes('/agency'))
{
strings = [
"Businesses Everywhere . . .",
"Need Your . . .",
"Automation and. . .",
"AI skills . . .",
];
}
function typeText1(index)
{
var ids = ["VideoHeading", "VideoSubheading_0", "VideoSubheading_1", "VideoSubheading_2", "VideoSubheading_3", "VideoSubheading_4"];
var headingElement = document.getElementById(ids[index]);
// remove classes
removeAllClasses(headingElement);
// add
setMultipleClasses(headingElement, ["heading-video"]);
if(charIndex == 0 && (index == 0))
{
// clear all
for(x = 1; x < ids.length; x++)
{
var clearElement = document.getElementById(ids[x]);
while (clearElement.firstChild) {
clearElement.removeChild(clearElement.firstChild);
}
}
}
// clear content
if (charIndex < strings[index].length)
{
headingElement.innerHTML = "";
while (headingElement.firstChild) {
headingElement.removeChild(headingElement.firstChild);
}
}
var h1Element = document.createElement("h1");
h1Element.id = ids[index] + "_h1";
// add
setMultipleClasses(h1Element, ["videoheading", "highlighted-heading"]);
if (charIndex < strings[index].length)
{
headingElement.appendChild(h1Element);
currentString += strings[index][charIndex];
h1Element.innerHTML = currentString;
typingSpeed = fastSpeed;
charIndex++;
}
else
{
typingSpeed = slowSpeed;
index++;
charIndex = 0;
currentString = "";
}
if (index < 2)
//if (index < strings.length)
{
setTimeout(typeText1, typingSpeed, index);
}
else
{
setTimeout(typeText2, 1000, index);
}
}
function typeText2(index)
{
var ids = ["VideoHeading", "VideoSubheading_0", "VideoSubheading_1", "VideoSubheading_2", "VideoSubheading_3", "VideoSubheading_4"];
var headingElement = document.getElementById(ids[index - 2]);
// remove classes
removeAllClasses(headingElement);
// add
setMultipleClasses(headingElement, ["heading-video"]);
if(charIndex == 0 && (index - 2 == 0))
{
// clear all
var clearElement = document.getElementById(ids[0]);
clearElement.innerHTML = "";
while (clearElement.firstChild) {
clearElement.removeChild(clearElement.firstChild);
}
clearElement = document.getElementById(ids[1]);
clearElement.innerHTML = "";
while (clearElement.firstChild) {
clearElement.removeChild(clearElement.firstChild);
}
}
// clear content
if (charIndex < strings[index].length)
{
headingElement.innerHTML = "";
while (headingElement.firstChild) {
headingElement.removeChild(headingElement.firstChild);
}
}
var h1Element = document.createElement("h1");
h1Element.id = ids[index] + "_h1";
// add
setMultipleClasses(h1Element, ["videoheading", "highlighted-heading"]);
if (charIndex < strings[index].length)
{
headingElement.appendChild(h1Element);
currentString += strings[index][charIndex];
h1Element.innerHTML = currentString;
typingSpeed = fastSpeed;
charIndex++;
}
else
{
typingSpeed = fastSpeed;
index++;
charIndex = 0;
currentString = "";
}
if (index > 1 && index < 4)
//if (index < strings.length)
{
setTimeout(typeText2, typingSpeed, index);
}
else
{
index = 0;
if (window.location.href.toLowerCase().includes('/agency'))
{
setTimeout(typeText_Agency, 750, index);
}
else
{
setTimeout(typeText, 750, index);
}
}
}
/* function typeText() {
var finalStrings1 = [
"Your Job ", "+ ", " .AI"
];
strings = finalStrings1;
var ids = ["VideoHeading", "VideoSubheading_0", "VideoSubheading_1", "VideoSubheading_2", "VideoSubheading_3", "VideoSubheading_4"];
var headingElement = document.getElementById("VideoHeading");
// remove classes
removeAllClasses(headingElement);
// add
setMultipleClasses(headingElement, ["videoheading", "highlighted-heading"]);
if(charIndex == 0 && (index == 0))
{
// clear all
var clearElement = document.getElementById(ids[0]);
clearElement.innerHTML = "";
while (clearElement.firstChild) {
clearElement.removeChild(clearElement.firstChild);
}
clearElement = document.getElementById(ids[1]);
clearElement.innerHTML = "";
while (clearElement.firstChild) {
clearElement.removeChild(clearElement.firstChild);
}
}
// this is to add html rather than text
if (index === 1)
{
currentString += strings[index];
headingElement.innerHTML = currentString;
index++;
typingSpeed = fastSpeed;
}
else
{
if (charIndex < strings[index].length)
{
currentString += strings[index][charIndex];
headingElement.innerHTML = currentString;
charIndex++;
typingSpeed = fastSpeed;
}
else
{
typingSpeed = fastSpeed;
index++;
charIndex = 0;
//currentString = "";
}
}
if (index < strings.length)
{
setTimeout(typeText, typingSpeed, index);
}
else
{
index = 0;
currentString = "";
typingSpeed = slowSpeed;
setTimeout(typeTextHeading, slowSpeed, index);
}
}*/
function typeText() {
/*var finalStrings1 = [
"Your Job ", "+ ", " .AI"
];*/
var finalStrings1 = [
"Where Should You Use AI?"
];
if (window.location.href.toLowerCase().includes('/agency'))
{
finalStrings1 = [
"Dear ", ". AI", " Agencies "
];
}
strings = finalStrings1;
var ids = ["VideoHeading", "VideoSubheading_0", "VideoSubheading_1", "VideoSubheading_2", "VideoSubheading_3", "VideoSubheading_4"];
var headingElement = document.getElementById("VideoHeading");
// hide videosubheading_3
$('#VideoSubheading_3').hide()
// remove classes
removeAllClasses(headingElement);
// add
//setMultipleClasses(headingElement, ["videoheading", "highlighted-heading"]);
setMultipleClasses(headingElement, ["heading-video"]);
// clear all
if(charIndex == 0 && (index == 0))
{
var clearElement = document.getElementById(ids[0]);
clearElement.innerHTML = "";
while (clearElement.firstChild) {
clearElement.removeChild(clearElement.firstChild);
}
clearElement = document.getElementById(ids[1]);
clearElement.innerHTML = "";
while (clearElement.firstChild) {
clearElement.removeChild(clearElement.firstChild);
}
var h1Element = document.createElement("h1");
h1Element.id = ids[index] + "_h1";
headingElement.appendChild(h1Element);
}
var h1Element = document.getElementById("VideoHeading").querySelector("h1");
// add
setMultipleClasses(h1Element, ["videoheading", "highlighted-heading"]);
// this is to add html rather than text
/*if (index === 1)
{
currentString += strings[index];
//headingElement.innerHTML = currentString;
h1Element.innerHTML = currentString;
index++;
typingSpeed = fastSpeed;
}
else
{
if (charIndex < strings[index].length)
{
currentString += strings[index][charIndex];
h1Element.innerHTML = currentString;
typingSpeed = fastSpeed;
charIndex++;
}
else
{
typingSpeed = slowSpeed;
index++;
charIndex = 0;
//currentString = "";
}
}*/
// this is to add html rather than text
if (index === 1)
{
currentString += strings[index];
//headingElement.innerHTML = currentString;
h1Element.innerHTML = currentString;
index++;
typingSpeed = fastSpeed;
}
else
{
if (charIndex < strings[index].length)
{
currentString += strings[index][charIndex];
h1Element.innerHTML = currentString;
typingSpeed = fastSpeed;
charIndex++;
}
else
{
typingSpeed = slowSpeed;
index++;
charIndex = 0;
//currentString = "";
}
}
if (index < strings.length)
{
setTimeout(typeText, typingSpeed, index);
}
else
{
index = 0;
currentString = "";
typingSpeed = slowSpeed;
setTimeout(typeTextHeading, slowSpeed, index);
}
}
function typeText_Agency() {
var finalStrings1 = [
"Dear ", ". AI", " Agencies "
];
strings = finalStrings1;
var ids = ["VideoHeading", "VideoSubheading_0", "VideoSubheading_1", "VideoSubheading_2", "VideoSubheading_3", "VideoSubheading_4"];
var headingElement = document.getElementById("VideoHeading");
// remove classes
removeAllClasses(headingElement);
// add
//setMultipleClasses(headingElement, ["videoheading", "highlighted-heading"]);
setMultipleClasses(headingElement, ["heading-video"]);
// clear all
if(charIndex == 0 && (index == 0))
{
var clearElement = document.getElementById(ids[0]);
clearElement.innerHTML = "";
while (clearElement.firstChild) {
clearElement.removeChild(clearElement.firstChild);
}
clearElement = document.getElementById(ids[1]);
clearElement.innerHTML = "";
while (clearElement.firstChild) {
clearElement.removeChild(clearElement.firstChild);
}
var h1Element = document.createElement("h1");
h1Element.id = ids[index] + "_h1";
headingElement.appendChild(h1Element);
}
var h1Element = document.getElementById("VideoHeading").querySelector("h1");
// add
setMultipleClasses(h1Element, ["videoheading", "highlighted-heading"]);
// this is to add html rather than text
if (index === 1)
{
currentString += strings[index];
//headingElement.innerHTML = currentString;
h1Element.innerHTML = currentString;
index++;
typingSpeed = fastSpeed;
}
else
{
if (charIndex < strings[index].length)
{
currentString += strings[index][charIndex];
h1Element.innerHTML = currentString;
typingSpeed = fastSpeed;
charIndex++;
}
else
{
typingSpeed = slowSpeed;
index++;
charIndex = 0;
//currentString = "";
}
}
if (index < strings.length)
{
setTimeout(typeText_Agency, typingSpeed, index);
}
else
{
index = 0;
currentString = "";
typingSpeed = slowSpeed;
setTimeout(typeTextHeading_Agency, slowSpeed, index);
}
}
function typeTextHeading()
{
var ids = ["VideoHeading", "VideoSubheading_0", "VideoSubheading_1", "VideoSubheading_2", "VideoSubheading_3", "VideoSubheading_4"];
if(charIndex == 0 && (index == 0))
{
// clear all
for(x = 1; x < ids.length; x++)
{
var clearElement = document.getElementById(ids[x]);
clearElement.innerHTML = "";
while (clearElement.firstChild) {
clearElement.removeChild(clearElement.firstChild);
}
}
}
/*var finalStrings2 = [
"Enter Your Job Description . . .",
"Generate A Targeted .AI plan . . .",
"Match Your Workflows to Thousands of .AI tools . . .",
"Connect with .AI pros and boost productivity . . .",
]; */
var finalStrings2 = [
"Discover how AI fits into your role",
"Get a tailored AI workflow instantly",
"Unlock productivity & expert insights"
];
strings = finalStrings2;
var headingElement = document.getElementById("VideoSubheading_" + index);
// remove classes
removeAllClasses(headingElement);
// add
//setMultipleClasses(headingElement, ["heading-video"]);
setMultipleClasses(headingElement, ["videosubheading", "highlighted-heading"]);
if (charIndex < strings[index].length)
{
currentString += strings[index][charIndex];
headingElement.innerHTML = currentString;
charIndex++;
typingSpeed = fastSpeed;
setTimeout(typeTextHeading, typingSpeed, index);
}
else
{
var brElement = document.createElement('br');
headingElement.appendChild(brElement);
currentString = "";
index++;
charIndex = 0;
if (index < strings.length)
{
setTimeout(typeTextHeading, pauseDuration, index);
}
else
{
// show ticking cursor
setInterval(function(){if($('#VideoSubheading_4').is(':visible')){$('#VideoSubheading_4').hide()}else{$('#VideoSubheading_4').show()}}, 400);
}
// reveal buttons
}
}
function typeTextHeading_Agency()
{
var ids = ["VideoHeading", "VideoSubheading_0", "VideoSubheading_1", "VideoSubheading_2", "VideoSubheading_3", "VideoSubheading_4"];
if(charIndex == 0 && (index == 0))
{
// clear all
for(x = 1; x < ids.length; x++)
{
var clearElement = document.getElementById(ids[x]);
clearElement.innerHTML = "";
while (clearElement.firstChild) {
clearElement.removeChild(clearElement.firstChild);
}
}
}
var finalStrings2 = [
"Businesses Everywhere . . .",
"Need Your . . .",
"Automation and. . .",
"AI skills . . .",
];
strings = finalStrings2;
var headingElement = document.getElementById("VideoSubheading_" + index);
// remove classes
removeAllClasses(headingElement);
// add
//setMultipleClasses(headingElement, ["heading-video"]);
setMultipleClasses(headingElement, ["videosubheading", "highlighted-heading"]);
if (charIndex < strings[index].length)
{
currentString += strings[index][charIndex];
headingElement.innerHTML = currentString;
charIndex++;
typingSpeed = fastSpeed;
setTimeout(typeTextHeading_Agency, typingSpeed, index);
}
else
{
var brElement = document.createElement('br');
headingElement.appendChild(brElement);
currentString = "";
index++;
charIndex = 0;
if (index < strings.length)
{
setTimeout(typeTextHeading_Agency, pauseDuration, index);
}
else
{
// show ticking cursor
setInterval(function(){if($('#VideoSubheading_4').is(':visible')){$('#VideoSubheading_4').hide()}else{$('#VideoSubheading_4').show()}}, 400);
}
// reveal buttons
}
}
// Function to remove all classes from an element
function removeAllClasses(element) {
if(element)
{
const currentClasses = element.classList.toString().split(' ');
for (const className of currentClasses) {
element.classList.remove(className);
}
}
}
// Function to set multiple classes to an element
function setMultipleClasses(element, classes) {
if(element)
{
for (const className of classes) {
element.classList.add(className);
}
}
}
if (window.location.href.toLowerCase().includes('/agency'))
{
//typeTextHeading_Agency();
typeText_Agency();
}
else
{
//typeText1(index);
//typeTextHeading();
typeText();
}
}
/**
* WhatIsMyPeas - This method types Mypeas with the styling on the .
*/
function WhatIsMyPeas_Old() {
/*var strings = [
"What is ", ". ", "MYPEAS.AI?"
];*/
var strings = [
"Your Job ", "+ ", " .AI"
];
const typingSpeed = 15; // Adjust the typing speed (in milliseconds)
const pauseDuration = 100; // Pause duration between strings (in milliseconds)
let index = 0;
let charIndex = 0;
let currentString = "";
function typeText() {
var headingElement = document.getElementById("VideoHeading");
if (index === 1)
{
currentString += strings[index];
headingElement.innerHTML = currentString;
index++;
}
else
{
if (charIndex < strings[index].length)
{
currentString += strings[index][charIndex];
headingElement.innerHTML = currentString;
charIndex++;
}
else
{
index++;
charIndex = 0;
}
}
if (index < strings.length) {
setTimeout(typeText, typingSpeed);
} else {
setTimeout(TypingHeading, pauseDuration);
}
}
// Start the typing effect
typeText();
}
/**
* RequestAdditionalInfo - This method uses calls Prompt 3
* Prompt 3 uses the profile and task info to provide an interface for user to add additional context to improve the output of the task instructions
* @param JobTitle
* @param JobDescriptionSummary
* @param TaskTitle
* @param TaskSummary
* @param CurrentElement - Used to be CurrentID - this is the id of the div clicked to expand on the segment activity (replaced by CurrentElement which is a DOM element with id, segmentId and activityId properties)
*/
function RequestAdditionalInfo_OLD(JobTitle, JobDescriptionSummary, TaskTitle, TaskSummary, CurrentElement, JobSegmentTitle)
{
var resultWrap = document.querySelector('#statement-component');
var resultLoader = document.querySelector('#statement-loader');
var resultText = document.querySelector('#statement-text');
/*
this is CurrentElement
divOutput.id = activityOuputId;
divOutput.segmentId = SegmentId;
divOutput.activityId = ActivityIds[i];
*/
/* check for stored properties in storedprofile */
var localStoredProfile = JSON.parse(localStorage.getItem("profile"));
var jobObj = localStoredProfile;
var createNew = true;
var CurrentID = CurrentElement.id;
var activityContainer = document.getElementById(CurrentID + '_' + 'prompt');
if(activityContainer)
{
// do not create it
createUI = false;
if(activityContainer.is(':visible'))
{
// do nothing
}
else
{
// show it
activityContainer.show();
}
// scroll into view
// Calculate the top offset of the target div relative to its container (if any)
var offsetTop = activityContainer.offset().top - activityContainer.parent().offset().top;
/*
error stacktrace: TypeError: Cannot read properties of undefined (reading 'top')
at RequestAdditionalInfo (https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/64f06f7a8af9f6e69c1aa27b_mypeas.txt:2225:49)
at HTMLDivElement. (https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/64f06f7a8af9f6e69c1aa27b_mypeas.txt:1518:15)
*/
// Scroll the parent container to make the target div visible
activityContainer.parent().scrollTop(offsetTop);
var SegmentIndex = findSegmentIndexById(jobObj["JobSegments"], CurrentElement.segmentId);
//var ActivityIndex = findActivityIndexById(jobObj["JobSegments"][SegmentIndex]["Activities"], CurrentElement.activityId);
var ActivityIndex = findActivityIndexByOutputId(jobObj["JobSegments"][SegmentIndex]["Activities"], CurrentElement.activityId);
var OutputIndex = findActivityOutputIndexById(jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"], CurrentElement.activityId);
// check for additionalcontext
// determine if we need to fetch this information
var additionalContextPresent = "AdditionalContext" in jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex];
if(additionalContextPresent)
{
createNew = false;
}
if(!additionalContextPresent)
{
createNew = true;
}
}
/* store summary in hidden field */
/* Send jobdescriptionsummary */
/* send task summary */
/* Send prompt asking for more info from user - create input label */
// "Job title: " + JobTitle + "\nJob description: " + JobDescription + "\n
var prompt = "JobTitle: " + JobTitle + "\nJob description: " + JobDescriptionSummary + "\nTask: " + TaskTitle + " " + TaskSummary + ". \n" + "The aim is to produce a json object as our reponse. Example: {\"AdditionalContext\": \"\",\"Reports\": [],\"Tags\": []} AdditionalContext: This is a string. The user interface will contain a text area and a label that requests additional information for context to improve the output of the LLM prompt. AdditionalContext is the contents generated for this label. It should be concise but it should explicitly mention the information that needs to be entered by the user for the LLM to have enough context to create a step-by-step outline of how to complete the task.Reports:This is an array of strings. Based on what the task is, give us the best report/output type to produce for this task to provide the most value to the organization. if more than one is applicable add them in order of relevance. Tags: This is an array of strings. We have categorized tasks as these types: Administrative, Creative, Analytical,Customer Service, Sales, Management, Technology Implementation, Financial Analysis, Legal Research and Advice, Healthcare Provision. Using this framework assign a Tag to the task and add it to the array. if more than one is applicable add them in order of relevance. Now create and Return only the json object.";
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = JobTitle;
//MYPEAS_payload["JobDescription"] = JobDescription;
MYPEAS_payload["JobDescriptionSummary"] = JobDescriptionSummary;
//MYPEAS_payload["Title"] =
MYPEAS_payload["SegmentTitle"] = segmentTitle;
MYPEAS_payload["TaskTitle"] = taskInfo["TaskTitle"];
MYPEAS_payload["TaskSummary"] = taskInfo["TaskSummary"];
MYPEAS_payload["TagCategory"] = taskInfo["TagCategory"];
MYPEAS_payload["additionalInfo"] = "";
MYPEAS_payload["promptDescription"] = "prompt4";
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
ConsoleLog('Prompt: ' + prompt);
// check for additionalcontext
if(!createNew)
{
var taskActivities = {};
taskActivities["AdditionalContext"] = jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["AdditionalContext"];
var tags = [];
tags.push(jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["TagCategory"]);
taskActivities["Tags"] = tags;
/*
TaskActivities["AdditionalContext"]
jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["AdditionalContext"]
taskActivities["Tags"][0];
jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["TagCategory"]
*/
/* Craete an object to carry all of the job info */
var jobInfo = {};
jobInfo["JobTitle"] = JobTitle;
jobInfo["JobDescriptionSummary"] = JobDescriptionSummary;
var taskInfo = {};
taskInfo["TaskTitle"] = TaskTitle;
taskInfo["TaskSummary"] = TaskSummary;
taskInfo["TagCategory"] = "";
if(taskActivities["Tags"] && taskActivities["Tags"].length > 0)
{
taskInfo["TagCategory"] = taskActivities["Tags"][0];
}
// how to get these references
taskInfo["SegmentId"] = CurrentElement.segmentId;
taskInfo["ActivityId"] = CurrentElement.activityId;
taskInfo["AdditionalContext"] = taskActivities["AdditionalContext"];
// store profile
SaveProfile("RequestAdditionalInfo", taskInfo, "", taskInfo);
// why are we calling this again?
//CreateJobActivities(jobActivities, segmentCounter, segmentTitle);
CreateUserInterface(taskActivities, CurrentID, jobInfo, taskInfo, JobSegmentTitle);
// clear all loading screens
ActivitiesView(true);
LoaderView(false);
CancelSimulateGPT();
// re-enable the segment buttons
SegmentButtonsActive(true);
// enable search buttons
SearchJobEnable(true);
}
if(createNew)
{
/* show loading */
ActivitiesView(false);
LoaderView(true);
simulateChatGPT(0, "ShowMeHow");
// Make an API call to our Make cenario
fetch('https://hook.eu1.make.com/cvu294snzy8hh6fengvcln9y2j2qi7ne', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prompt: prompt,
max_tokens: 2900
})
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
// Get the first choice in the "choices" array.
const firstChoice = JSON.parse(result).choices[0];
// Get the "content" property of the "message" object.
const content = firstChoice.message.content;
/*resultText.value = result;*/
ConsoleLog('RequestAdditionalInfo: called after return');
if(resultLoader)
{
resultLoader.style.display = "none";
}
var resultChecked = removeBeforeOpeningBracketOrCurlyBracket(content);
ConsoleLog(resultChecked);
var taskActivities = tryParse(resultChecked);
/* Craete an object to carry all of the job info */
var jobInfo = {};
jobInfo["JobTitle"] = JobTitle;
jobInfo["JobDescriptionSummary"] = JobDescriptionSummary;
var taskInfo = {};
taskInfo["TaskTitle"] = TaskTitle;
taskInfo["TaskSummary"] = TaskSummary;
taskInfo["TagCategory"] = "";
if(taskActivities["Tags"] && taskActivities["Tags"].length > 0)
{
taskInfo["TagCategory"] = taskActivities["Tags"][0];
}
// how to get these references
taskInfo["SegmentId"] = CurrentElement.segmentId;
taskInfo["ActivityId"] = CurrentElement.activityId;
taskInfo["AdditionalContext"] = taskActivities["AdditionalContext"];
//TaskActivities = taskActivities;
// store profile
SaveProfile("RequestAdditionalInfo", taskInfo, "", taskInfo);
// why are we calling this again?
//CreateJobActivities(jobActivities, segmentCounter, segmentTitle);
CreateUserInterface(taskActivities, CurrentID, jobInfo, taskInfo, JobSegmentTitle);
// clear all loading screens
ActivitiesView(true);
LoaderView(false);
CancelSimulateGPT();
// re-enable the segment buttons
SegmentButtonsActive(true);
// enable search buttons
SearchJobEnable(true);
});
}
/* return */
/* context label */
/* tags and reports */
}
function RequestAdditionalInfo(JobTitle, JobDescriptionSummary, TaskTitle, TaskSummary, CurrentElement, JobSegmentTitle)
{
var resultWrap = document.querySelector('#statement-component');
var resultLoader = document.querySelector('#statement-loader');
var resultText = document.querySelector('#statement-text');
/*
this is CurrentElement
divOutput.id = activityOuputId;
divOutput.segmentId = SegmentId;
divOutput.activityId = ActivityIds[i];
*/
/* check for stored properties in storedprofile */
var localStoredProfile = JSON.parse(localStorage.getItem("profile"));
var jobObj = localStoredProfile;
var createNew = true;
var CurrentID = CurrentElement.id;
var activityContainer = document.getElementById(CurrentID + '_' + 'prompt');
if(activityContainer)
{
// do not create it
createUI = false;
if(activityContainer.is(':visible'))
{
// do nothing
}
else
{
// show it
activityContainer.show();
}
// scroll into view
// Calculate the top offset of the target div relative to its container (if any)
var offsetTop = activityContainer.offset().top - activityContainer.parent().offset().top;
/*
error stacktrace: TypeError: Cannot read properties of undefined (reading 'top')
at RequestAdditionalInfo (https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/64f06f7a8af9f6e69c1aa27b_mypeas.txt:2225:49)
at HTMLDivElement. (https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/64f06f7a8af9f6e69c1aa27b_mypeas.txt:1518:15)
*/
// Scroll the parent container to make the target div visible
activityContainer.parent().scrollTop(offsetTop);
var SegmentIndex = findSegmentIndexById(jobObj["JobSegments"], CurrentElement.segmentId);
//var ActivityIndex = findActivityIndexById(jobObj["JobSegments"][SegmentIndex]["Activities"], CurrentElement.activityId);
var ActivityIndex = findActivityIndexByOutputId(jobObj["JobSegments"][SegmentIndex]["Activities"], CurrentElement.activityId);
var OutputIndex = findActivityOutputIndexById(jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"], CurrentElement.activityId);
// check for additionalcontext
// determine if we need to fetch this information
var additionalContextPresent = "AdditionalContext" in jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex];
if(additionalContextPresent)
{
createNew = false;
}
if(!additionalContextPresent)
{
createNew = true;
}
}
// check for additionalcontext
if(!createNew)
{
var taskActivities = {};
taskActivities["AdditionalContext"] = jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["AdditionalContext"];
var tags = [];
tags.push(jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["TagCategory"]);
taskActivities["Tags"] = tags;
/*
TaskActivities["AdditionalContext"]
jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["AdditionalContext"]
taskActivities["Tags"][0];
jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["TagCategory"]
*/
/* Craete an object to carry all of the job info */
var jobInfo = {};
jobInfo["JobTitle"] = JobTitle;
jobInfo["JobDescriptionSummary"] = JobDescriptionSummary;
var taskInfo = {};
taskInfo["TaskTitle"] = TaskTitle;
taskInfo["TaskSummary"] = TaskSummary;
taskInfo["TagCategory"] = "";
if(taskActivities["Tags"] && taskActivities["Tags"].length > 0)
{
taskInfo["TagCategory"] = taskActivities["Tags"][0];
}
// how to get these references
taskInfo["SegmentId"] = CurrentElement.segmentId;
taskInfo["ActivityId"] = CurrentElement.activityId;
taskInfo["AdditionalContext"] = taskActivities["AdditionalContext"];
// store profile
SaveProfile("RequestAdditionalInfo", taskInfo, "", taskInfo);
// why are we calling this again?
//CreateJobActivities(jobActivities, segmentCounter, segmentTitle);
CreateUserInterface(taskActivities, CurrentID, jobInfo, taskInfo, JobSegmentTitle);
// clear all loading screens
ActivitiesView(true);
LoaderView(false);
CancelSimulateGPT();
// re-enable the segment buttons
SegmentButtonsActive(true);
// enable search buttons
SearchJobEnable(true);
}
if(createNew)
{
/* show loading */
ActivitiesView(false);
LoaderView(true);
simulateChatGPT(0, "ShowMeHow");
/*resultText.value = result;*/
ConsoleLog('RequestAdditionalInfo: called after return');
if(resultLoader)
{
resultLoader.style.display = "none";
}
var resultChecked = removeBeforeOpeningBracketOrCurlyBracket(result);
ConsoleLog(resultChecked);
var taskActivities = tryParse(resultChecked);
/* Craete an object to carry all of the job info */
var jobInfo = {};
jobInfo["JobTitle"] = JobTitle;
jobInfo["JobDescriptionSummary"] = JobDescriptionSummary;
var taskInfo = {};
taskInfo["TaskTitle"] = TaskTitle;
taskInfo["TaskSummary"] = TaskSummary;
taskInfo["TagCategory"] = "";
if(taskActivities["Tags"] && taskActivities["Tags"].length > 0)
{
taskInfo["TagCategory"] = taskActivities["Tags"][0];
}
// how to get these references
taskInfo["SegmentId"] = CurrentElement.segmentId;
taskInfo["ActivityId"] = CurrentElement.activityId;
taskInfo["AdditionalContext"] = taskActivities["AdditionalContext"];
//TaskActivities = taskActivities;
// store profile
SaveProfile("RequestAdditionalInfo", taskInfo, "", taskInfo);
// why are we calling this again?
//CreateJobActivities(jobActivities, segmentCounter, segmentTitle);
CreateUserInterface(taskActivities, CurrentID, jobInfo, taskInfo, JobSegmentTitle);
// clear all loading screens
ActivitiesView(true);
LoaderView(false);
CancelSimulateGPT();
// re-enable the segment buttons
SegmentButtonsActive(true);
// enable search buttons
SearchJobEnable(true);
}
}
/**
* CreateUserInterface - This method creates the interface below the segment activity div (see RequestAdditionalInfo)
* The div is created and added after its segment activity div. The id of this new div is the same as the segment activity + _prompt
* @param TaskActivities
* @param ContainerID
* @param JobInfo
* @param TaskInfo
*/
function CreateUserInterface(TaskActivities, ContainerID, JobInfo, TaskInfo, JobSegmentTitle)
{
/* check for stored properties in storedprofile */
var localStoredProfile = JSON.parse(localStorage.getItem("profile"));
var jobObj = localStoredProfile;
var activityContainer = document.getElementById(ContainerID + '_' + 'prompt');
if(activityContainer)
{
ConsoleLog('CreateUserInterface: activityContainer');
// make visible
activityContainer.style.display = 'block';
var CurrentElement = document.getElementById(ContainerId);
var SegmentIndex = findSegmentIndexById(jobObj["JobSegments"], CurrentElement.segmentId);
var ActivityIndex = findActivityIndexByOutputId(jobObj["JobSegments"][SegmentIndex]["Activities"], CurrentElement.activityId);
var OutputIndex = findActivityOutputIndexById(jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"], CurrentElement.activityId);
var stepsPresent = "Steps" in jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex];
var resultWrap = document.querySelector('#statement-component');
var resultLoader = document.querySelector('#statement-loader');
var resultText = document.querySelector('#statement-text');
// go to createuisteps
if(stepsPresent)
{
// find this specific set of steps for this activity
// if present use that to call createuisteps
/*resultText.value = result;*/
ConsoleLog('Step-By-Step Present: ');
var steps = jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Steps"];
var stepIds = [];
// create id for each
steps.forEach(step => {
stepIds.push(step.id);
});
TaskInfo["Steps"] = steps;
TaskInfo["StepIds"] = stepIds;
/* need to maintain parameter format so need a object that holds steps as a property */
var StepsObj = {};
StepsObj["Steps"] = steps;
//CreateUISteps(StepsObj, TaskInfo, JobInfo, activityContainer.id, JobSegmentTitle);
CreateUISteps(StepsObj, TaskInfo, JobInfo, ContainerID, JobSegmentTitle, jobObj);
// clear all loading screens
ActivitiesView(true);
LoaderView(false);
CancelSimulateGPT();
// store updated profile
SaveProfile("CreateUISteps_Request_Response", JobInfo, "", TaskInfo);
// reenable GENERATE button
// should no need this as it will be hidden during prompt query
// instead make it visible again (as update parameters button)
// re-enable the segment buttons
SegmentButtonsActive(true);
// enable search buttons
SearchJobEnable(true);
return;
}
// user has already supplied the additional context
var addContextAdded = "AdditionalContextUser" in jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex];
if(addContextAdded)
{
// add the text to the textarea and run the search
var contextTextArea = activitycontainer.querySelector('#AdditionalContext');
contextTextArea.value = jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["AdditionalContextUser"];
var generateBtn = activitycontainer.querySelector('#generateBtn');
generateBtn.click();
return;
}
// user has already requested the additional context from LLM
var addContextSuggested = "AdditionalContext" in jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex];
if(addContextSuggested)
{
// set the suggestion
var contextLabel = activitycontainer.querySelector('#contextLabel');
contextLabel.innerText = 'Add additional context e.g.' + TaskActivities["AdditionalContext"];
return;
}
}
if (!activityContainer)
{
ConsoleLog('CreateUserInterface: !activityContainer');
/*
taskInfo["TaskTitle"] = TaskTitle;
taskInfo["TaskSummary"] = TaskSummary;
taskInfo["TagCategory"]
*/
// Create the activity container if it doesn't exist
activityContainer = document.createElement('div');
activityContainer.id = ContainerID + '_' + 'prompt';
// Task Title (Heading)
var title = document.createElement('h1');
title.innerText = TaskInfo["TaskTitle"];
title.style.color = 'green';
activityContainer.appendChild(title);
// Task Summary (Paragraph)
var summary = document.createElement('p');
summary.innerText = TaskInfo["TaskSummary"];
activityContainer.appendChild(summary);
// Line break
activityContainer.appendChild(document.createElement('br'));
// Line break
activityContainer.appendChild(document.createElement('br'));
// Additional context label
var contextLabel = document.createElement('label');
contextLabel.id = "contextLabel";
contextLabel.innerText = 'Add additional context e.g.' + TaskActivities["AdditionalContext"];
// Additional context text area
var contextTextArea = document.createElement('textarea');
contextTextArea.id = "AdditionalContext";
contextTextArea.rows = 5;
// set placeholder
contextTextArea.placeholder = '(Optional)';
// Set the width of the textarea to 100%
contextTextArea.style.width = "100%";
activityContainer.appendChild(contextLabel);
activityContainer.appendChild(document.createElement('br'));
activityContainer.appendChild(contextTextArea);
// Generate button
var generateButton = document.createElement('input');
generateButton.id = 'generateBtn'
generateButton.type = 'button';
generateButton.value = 'GENERATE';
generateButton.style.backgroundColor = '#8cd190';
generateButton.style.color = 'white';
generateButton.onclick = function () {
try
{
// Handle the button click event
// Your code here...
var additionalInfo = $('#' + ContainerID + '_' + 'prompt' + ' #AdditionalContext').val();
// hide this search box
$('#' + ContainerID + '_' + 'prompt').hide();
/*var taskInfo = TaskInfo["TaskTitle"] + ". " + TaskInfo["TaskSummary"]; */
var prompt = CreateOutlinePrompt(JobInfo["JobTitle"], JobInfo["JobDescriptionSummary"], TaskInfo, TaskInfo["TagCategory"], additionalInfo);
// run this prompt and fetch the output from chatgpt
ActivitiesView(false);
LoaderView(true);
simulateChatGPT(0, "GenerateSteps");
// store profile
SaveProfile("CreateUISteps_Request", TaskInfo, "", additionalInfo);
/* NEW */
// check for steps for this activity in the storedprofile
// check for steps
/* check for stored properties in storedprofile */
var localStoredProfile = JSON.parse(localStorage.getItem("profile"));
var jobObj = localStoredProfile;
//var stepsPresent = "Steps" in localStoredProfile;
var SegmentIndex = findSegmentIndexById(jobObj["JobSegments"], TaskInfo["SegmentId"]);
var ActivityIndex = findActivityIndexByOutputId(jobObj["JobSegments"][SegmentIndex]["Activities"], TaskInfo["ActivityId"]);
var OutputIndex = findActivityOutputIndexById(jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"], TaskInfo["ActivityId"]);
var stepsPresent = "Steps" in jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex];
if(stepsPresent)
{
// find this specific set of steps for this activity
// if present use that to call createuisteps
/*resultText.value = result;*/
ConsoleLog('Step-By-Step Present: ');
var steps = jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Steps"];
var stepIds = [];
// create id for each
steps.forEach(step => {
stepIds.push(step.id);
});
TaskInfo["Steps"] = steps;
TaskInfo["StepIds"] = stepIds;
/* need to maintain parameter format so need a object that holds steps as a property */
var StepsObj = {};
StepsObj["Steps"] = steps;
CreateUISteps(StepsObj, TaskInfo, JobInfo, ContainerID, JobSegmentTitle, jobObj);
// clear all loading screens
ActivitiesView(true);
LoaderView(false);
CancelSimulateGPT();
// store updated profile
SaveProfile("CreateUISteps_Request_Response", JobInfo, "", TaskInfo);
// reenable GENERATE button
// should no need this as it will be hidden during prompt query
// instead make it visible again (as update parameters button)
// re-enable the segment buttons
SegmentButtonsActive(true);
// enable search buttons
SearchJobEnable(true);
}
else
{
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = JobInfo["JobTitle"];
MYPEAS_payload["JobDescriptionSummary"] = JobInfo["JobDescriptionSummary"];
MYPEAS_payload["TaskTitle"] = TaskInfo["TaskTitle"];
MYPEAS_payload["TaskSummary"] = TaskInfo["TaskSummary"];
MYPEAS_payload["TagCategory"] = TaskInfo["TagCategory"];
MYPEAS_payload["additionalInfo"] = "";
MYPEAS_payload["promptDescription"] = "prompt3";
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// else use fetch
// Make an API call to our Make scenario
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
// Get the first choice in the "choices" array.
const firstChoice = JSON.parse(result).choices[0];
// Get the "content" property of the "message" object.
const content = firstChoice.message.content;
/*resultText.value = result;*/
ConsoleLog('Generate Step-By-Step: called after return');
if(resultLoader)
{
resultLoader.style.display = "none";
}
var resultChecked = removeBeforeOpeningBracketOrCurlyBracket(content);
ConsoleLog(resultChecked);
var steps = tryParse(resultChecked);
if(!isEmptyObject(steps))
{
var stepIds = [];
// create id for each
steps.Steps.forEach(step => {
var id = generateRandomString(8);
step.id = id;
stepIds.push(id);
});
TaskInfo["Steps"] = steps.Steps;
TaskInfo["StepIds"] = stepIds;
CreateUISteps(steps, TaskInfo, JobInfo, ContainerID, JobSegmentTitle, jobObj);
// clear all loading screens
ActivitiesView(true);
LoaderView(false);
CancelSimulateGPT();
// store updated profile
SaveProfile("CreateUISteps_Request_Response", JobInfo, "", TaskInfo);
// reenable GENERATE button
// should no need this as it will be hidden during prompt query
// instead make it visible again (as update parameters button)
// re-enable the segment buttons
SegmentButtonsActive(true);
// enable search buttons
SearchJobEnable(true);
}
if(isEmptyObject(steps))
{
// show activitycontainer
$(activityContainer).show();
// clear all loading screens
ActivitiesView(true);
LoaderView(false);
CancelSimulateGPT();
}
});
}
/* END NEW */
}
catch(err)
{
ConsoleLog('error name: ' + err.name);
ConsoleLog('error message: ' + err.message);
ConsoleLog('error stacktrace: ' + err.stack);
// show activitycontainer
$(activityContainer).show();
// clear all loading screens
ActivitiesView(true);
LoaderView(false);
CancelSimulateGPT();
}
};
activityContainer.appendChild(document.createElement('br'));
activityContainer.appendChild(generateButton);
ConsoleLog('containerID: ' + ContainerID);
ConsoleLog('activitycontainerID: ' + activityContainer.id);
// Add the activityContainer to the DOM
// Your code here...
// Find the element to insert after
var insertAfterElement = document.getElementById(ContainerID);
if (insertAfterElement) {
// Insert the activityContainer after the specified element
insertAfterElement.insertAdjacentElement('afterend', activityContainer);
}
}
}
/**
* ActivitiesView - this method shows or hides the activities divs (container id="JobActivities") while searching or completed
* @param visible
*/
function ActivitiesView(visible)
{
switch(visible)
{
case true:
// hide background video
$('.background-video').hide();
$('.background-video-agency').hide();
$('#hero-holder').show();
$('.hcv-container').show();
$('#background-image-hero').show();
// show loader (without textbox)
$('#statement-component').show();
$('#statement-loader').show();
$('#statement-text').hide();
$('#cta-wrapper').hide();
// show activities container div
$('#JobActivities').show();
break;
case false:
// show hero image
$('#hero-holder').show();
$('.hcv-container').show();
$('#background-image-hero').show();
// hide loader
$('#statement-component').hide();
// hide activities container div
$('#JobActivities').hide();
break;
}
}
function CreateOutlinePrompt(JobTitle, JobDescriptionSummary, TaskInfo, tagCategory, additionalInfo)
{
/* Generate prompt */
/* Prompt 1: how to do */
/*var taskInfo = TaskInfo["TaskTitle"] + ". " + TaskInfo["TaskSummary"]; */
var prompt = "Act as an LLM prompt engineer. You are creating prompts for your organisation. At this stage" +
"\nJobTitle: " + JobTitle +
"\nJobDescription: " + JobDescriptionSummary +
"\nCurrentTask: " + TaskInfo["TaskTitle"] + ". " + TaskInfo["TaskSummary"] +
"\nIf there is additional information supplied below, Incorporate the additionalContext to make the instructions relevant and targeted to the profile of the person tasked with carrying them out." +
"\nAdditionalContext: " + additionalInfo +
"\nTags: " +
"\nThe task has already been classified as " + tagCategory +
"\nThis kind of work often involves: " + GetTagBreakDown(tagCategory) +
"\nThe aim is to create a step-by-step outline for how to perform and complete the task with industry best practices delivering useful outputs along the way." +
"\nreturn this information as per this example. " +
"\nExample:\r\n\r\n{\r\n \"Steps\": [\r\n\r\n {\r\n \"Outline\": \"What to do in this step\",\r\n \"Output\": \"What type of report, visualization is best practice and of most value\"\r\n },\r\n {\r\n \"Outline\": \"What to do in this step\",\r\n \"Output\": \"What type of report, visualization is best practice and of most value\"\r\n },\r\n etc.\r\n\r\n\r\n ]\r\n}" +
"\nSteps: This property represents an array of steps involved in a process or task." +
"\nWithin each step object:" +
"\nOutline: This property describes what needs to be done in the particular step. It provides an overview or summary of the actions to be taken." +
"\nOutput: This property specifies the desired outcome or result of the step. It indicates what type of report or visualization would be considered best practice and of most value for that particular step." +
"\nReturn only the json object";
return prompt;
}
function GetTagBreakDown(tagCategory)
{
var breakdown = "";
var tagCategories = {
"Administrative work": ["data entry", "scheduling", "calendar management", "answering phones", "email correspondence"],
"Creative work": ["graphic design", "content creation", "copywriting", "multimedia production"],
"Analytical work": ["data analysis", "financial analysis", "market research", "forecasting"],
"Customer Service work": ["handling customer inquiries", "providing support", "resolving issues", "maintaining customer satisfaction"],
"Sales work": ["lead generation", "prospect qualification", "product presentations", "negotiations", "closing deals"],
"Management work": ["strategic planning", "team leadership", "resource allocation", "decision-making"],
"Technology Implementation": ["implementing and integrating technology solutions", "software development", "system configuration", "deployment", "testing", "user training"],
"Financial Analysis": ["financial statement analysis", "budgeting", "forecasting", "risk assessment", "investment evaluation"],
"Legal Research and Advice": ["legal research", "contract review", "case analysis", "providing legal advice"],
"Healthcare Provision": ["patient care", "diagnosis", "treatment planning", "medical procedures", "healthcare consultations"]
};
if(tagCategories.hasOwnProperty(tagCategory))
{
breakdown = tagCategories[tagCategory].join(", ");
}
ConsoleLog(tagCategory + ": " + breakdown);
return breakdown;
}
/**
* CreateUISteps - this method is called by the onclick of the "Generate" button from CreateUserInterface function. It creates a div that contains the steps and buttons to get instructions
* @param data - this object contains the steps of each task
* @param TaskInfo - this object has the overriding task title and task description
* @param parentID - this string represents the id of the activity container. It is also used to create a new div for steps, this is then added to the activity container
*/
function CreateUISteps(data, TaskInfo, JobInfo, parentID, JobSegmentTitle, jobObj)
{
// check loading
var isLoading = false;
if($('#initLoading').val() == "loadingExisting")
{
isLoading = true;
}
var SegmentIndex = findSegmentIndexById(jobObj["JobSegments"], TaskInfo["SegmentId"]);
var ActivityIndex = findActivityIndexByOutputId(jobObj["JobSegments"][SegmentIndex]["Activities"], TaskInfo["ActivityId"]);
var OutputIndex = findActivityOutputIndexById(jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"], TaskInfo["ActivityId"]);
ConsoleLog("createuisteps test: ");
ConsoleLog('TaskInfo["ActivityId"]: ' + TaskInfo["ActivityId"]);
ConsoleLog("SegmentIndex: " + SegmentIndex + "ActivityIndex: " + ActivityIndex + "OutputIndex: " + OutputIndex);
var stepsPresent = !!(jobObj?.["JobSegments"]?.[SegmentIndex]?.["Activities"]?.[ActivityIndex]?.["Outputs"]?.[OutputIndex]?.["Steps"]?.length ?? false);
if(stepsPresent)
{
// find this specific set of steps for this activity
var steps = jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Steps"];
var parentElement = document.getElementById(parentID);
ConsoleLog("parentID: ", parentID);
var holderID = parentID.substring(0, parentID.lastIndexOf("_Output_"));
if(parentElement)
{
// close any open showmehow divs
var visibleStepsContainerID = "";
// need to show the job activities that are hidden
var visibleStepsElements = $("#" + holderID + " *:visible[id$='_steps']");
// Extract the preceding text in the ID before "_steps"
visibleStepsElements.each(function() {
var id = $(this).attr("id");
visibleStepsContainerID = id.substring(0, id.lastIndexOf("_steps"));
ConsoleLog("visibleStepsContainerID:", visibleStepsContainerID);
// hide the expanded output
$(this).hide();
// show the divoutput
$('#' + visibleStepsContainerID).show();
});
}
// Create container div
if($('#' + parentID + '_steps').length == 0)
{
var container = document.createElement('div');
container.id = parentID + "_steps";
container.className = "activity-steps";
container.style.marginBottom = '15px';
// Add heading with green text
var heading = document.createElement('h1');
heading.style.color = 'green';
heading.textContent = TaskInfo["TaskTitle"];
container.appendChild(heading);
// Create steps array for PreFormatTextAreaText
var stepsArray = data.Steps.map(function(step, index) {
return {
HowTo: step.HowTo,
index: index,
Title: step.Outline,
id: step.id,
Report: step.Outline,
Gain: step.Gain,
Breakdown: {
JobSegment: jobObj["JobSegments"][SegmentIndex]["Name"],
Activity: jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Title"],
Output: jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Description"]
}
};
});
// Create stepInfo object (removing HowTo from Breakdown)
var stepInfo = {};
stepInfo["Title"] = data.Steps[0].Outline; // Use first step's outline as title
stepInfo["id"] = data.Steps[0].id;
stepInfo["index"] = 0;
stepInfo["Report"] = data.Steps[0].Outline;
stepInfo["HITLScore"] = data?.Steps?.[0]?.HITLScore ?? null;
stepInfo["Gain"] = data.Steps[0].Gain;
stepInfo["Breakdown"] = {};
stepInfo["Breakdown"]["JobSegment"] = jobObj["JobSegments"][SegmentIndex]["Name"];
stepInfo["Breakdown"]["Activity"] = jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Title"];
stepInfo["Breakdown"]["Output"] = jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Description"];
// Create the instructions div
var instructionsDiv = document.createElement('div');
instructionsDiv.id = "_steps_instructions_0";
instructionsDiv.style.borderRadius = '10px';
instructionsDiv.style.border = '1px solid lightgray';
instructionsDiv.style.display = 'none';
instructionsDiv.style.marginTop = '10px';
instructionsDiv.style.padding = '10px';
instructionsDiv.style.marginBottom = '15px';
// Create the HITLData hidden input element
var hiddenHITLData = document.createElement("input");
hiddenHITLData.type = "hidden";
hiddenHITLData.id = "_steps_instructions_HITLData";
instructionsDiv.appendChild(hiddenHITLData);
// Create the close button
var closeButton = document.createElement('button');
closeButton.textContent = 'CLOSE';
closeButton.style.textTransform = 'uppercase';
closeButton.style.border = 'none';
closeButton.style.background = 'none';
closeButton.style.cursor = 'pointer';
closeButton.style.float = 'right';
closeButton.onclick = function() {
instructionsDiv.style.display = 'none';
$('#nav-embed').show();
$('#JobSegments').show();
$('#JobActivities').show();
$('#ExpandedView').hide();
};
// Create the Your Steps heading
var headingSteps = document.createElement('h2');
headingSteps.textContent = 'Your Steps ';
headingSteps.style.cursor = 'pointer';
headingSteps.appendChild(CreateInfoSpan());
headingSteps.onclick = function() {
OpenInfoModal("Steps");
};
var ruleSteps = createThickRule();
// add paragraph
var stepsParagraph = document.createElement('p');
stepsParagraph.textContent = "We mapped out the detailed steps that make up each task. This fine-grained view pinpoints exactly where AI tools can automate and enhance your workflow.";
// Create the Overview heading
var headingOverview = document.createElement('h3');
headingOverview.textContent = 'Overview';
// Create the textarea - REPLACE WITH DIV
var textarea = document.createElement('div');
textarea.id = "_steps_instructions_0_content";
// hidden index (this informs us which step is active)
var hiddenIndex = document.createElement('input');
hiddenIndex.type = 'hidden';
hiddenIndex.id = "_steps_index";
hiddenIndex.value = "0";
// report holder - START
var reportHolder = document.createElement('div');
reportHolder.id = '_report_holder_0';
reportHolder.style.margin = '10px';
reportHolder.style.padding = '20px';
reportHolder.style.borderRadius = '10px';
reportHolder.style.backgroundColor = 'white';
reportHolder.style.border = '2px solid lightgray';
var reportHeading = document.createElement('h3');
reportHeading.textContent = 'Suggested Report ';
reportHeading.style.cursor = 'pointer';
reportHeading.appendChild(CreateInfoSpan());
reportHeading.onclick = function() {
OpenInfoModal("Suggested");
};
reportHolder.appendChild(reportHeading);
var reportRule = createThickRule();
reportHolder.appendChild(reportRule);
// add subparagraph
var reportSubparagraph = document.createElement('p');
reportSubparagraph.textContent = 'Generate a structured framework to guide your analysis, reporting and decision-making process - to ensure consistent and effective communication of your findings.';
reportHolder.appendChild(reportSubparagraph);
// key deliverable text
var keyDeliverableElement = document.createElement('h3');
keyDeliverableElement.textContent = "Key Deliverable: ";
reportHolder.appendChild(keyDeliverableElement);
// add hr
var rule = document.createElement('hr');
reportHolder.appendChild(rule);
// Create h4 for the report text
var reportTextElement = document.createElement('h4');
reportTextElement.classList.add('report-text');
reportTextElement.id = "document-outline-title";
reportTextElement.textContent = stepInfo["Report"];
reportHolder.appendChild(reportTextElement);
// Create report container
var reportContainer = document.createElement('div');
reportContainer.classList.add('report-container');
reportContainer.style.display = 'flex';
reportContainer.style.alignItems = 'center';
// Create image container
var imgContainer = document.createElement('div');
imgContainer.classList.add('img-container');
imgContainer.style.flex = "0 0 auto";
imgContainer.style.marginRight = "20px";
var imgElement = document.createElement('img');
imgElement.id = 'document-img';
imgElement.src = 'https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/651d59729dbbab56a28ca0da_documentation.png';
imgElement.style.height = '150px';
imgElement.style.width = '150px';
imgContainer.appendChild(imgElement);
reportContainer.appendChild(imgContainer);
// Create text-button container
var textButtonContainer = document.createElement('div');
textButtonContainer.classList.add('text-button-container');
textButtonContainer.style.flex = "1";
// add caption above button
var generateDocumentOutlineParagraph = document.createElement('p');
generateDocumentOutlineParagraph.style.fontSize = 'small';
generateDocumentOutlineParagraph.textContent = 'Click to generate a report outline with built-in instructions for your AI assistant.';
textButtonContainer.appendChild(generateDocumentOutlineParagraph);
// Create generate document outline button
var generateDocumentOutlineButton = createButton('https://flexluthor.s3.eu-west-2.amazonaws.com/images/sparkle.png', ' Generate Document Outline');
generateDocumentOutlineButton.id = "generate-document-outline-button";
generateDocumentOutlineButton.style.marginTop = '10px';
generateDocumentOutlineButton.onclick = function() {
GenerateDocumentOutline(SegmentIndex, ActivityIndex, OutputIndex, 0);
};
textButtonContainer.appendChild(generateDocumentOutlineButton);
// create hidden field with stringified object of the parameters so we can access them later
// A simple object to hold your parameters
const params = {
segmentIndex: SegmentIndex,
activityIndex: ActivityIndex,
outputIndex: OutputIndex,
stepIndex: 0
};
// Create the hidden input field
const hiddenField = document.createElement('input');
hiddenField.type = 'hidden';
hiddenField.id = 'document-outline-params';
hiddenField.value = JSON.stringify(params);
// Append the field to the container
textButtonContainer.appendChild(hiddenField);
// Append containers
reportContainer.appendChild(textButtonContainer);
reportHolder.appendChild(reportContainer);
// tools holder
var toolsHolder = document.createElement('div');
toolsHolder.id = "_tools_holder_0";
var toolsSubheading = document.createElement('h4');
toolsSubheading.id = "toolsSubheading";
toolsSubheading.textContent = '';
toolsHolder.appendChild(toolsSubheading);
var toolsRule = document.createElement('hr');
toolsHolder.appendChild(toolsRule);
/*
If not - give user option to generate it
*/
// HITL Score section
var HITLHolder = document.createElement('div');
HITLHolder.id = '_hitl_holder_0';
HITLHolder.style.margin = '10px';
HITLHolder.style.padding = '20px';
HITLHolder.style.borderRadius = '10px';
HITLHolder.style.backgroundColor = 'white';
HITLHolder.style.border = '2px solid lightgray';
var HITLElement = document.createElement('h3');
HITLElement.textContent = "HITL Score ";
HITLElement.style.cursor = 'pointer';
HITLElement.appendChild(CreateInfoSpan());
HITLElement.onclick = function() {
OpenInfoModal("HITL");
};
HITLHolder.appendChild(HITLElement);
var rule = document.createElement('hr');
HITLHolder.appendChild(rule);
var HITLText = "Human-In-The-Loop Score: How essential is the human in this workflow, and what extent can AI take over?";
var HITLTextElement = document.createElement('p');
HITLTextElement.classList.add('hitl-text');
HITLTextElement.textContent = HITLText;
HITLHolder.appendChild(HITLTextElement);
// HITL Container
var HITLContainer = document.createElement('div');
HITLContainer.id = 'hitl-request';
HITLContainer.classList.add('hitl-request');
HITLContainer.style.display = 'flex';
HITLContainer.style.alignItems = 'center';
var HITLimgContainer = document.createElement('div');
HITLimgContainer.classList.add('img-container');
HITLimgContainer.style.flex = "0 0 auto";
HITLimgContainer.style.marginRight = "20px";
var imgElement = document.createElement('img');
imgElement.id = 'ranking-img';
imgElement.src = 'https://cdn.prod.website-files.com/6446c148837a8953093cbfeb/67fe6f858c1fed29509b520e_rank-icon.png';
imgElement.style.height = '150px';
imgElement.style.width = '150px';
HITLimgContainer.appendChild(imgElement);
HITLContainer.appendChild(HITLimgContainer);
var HITLButtonContainer = document.createElement('div');
HITLButtonContainer.classList.add('text-button-container');
HITLButtonContainer.style.flex = "1";
var generateHITLCaption = document.createElement('p');
generateHITLCaption.style.fontSize = 'small';
generateHITLCaption.textContent = 'Click to generate the HITL score';
HITLButtonContainer.appendChild(generateHITLCaption);
var generateHITLButton = createButton('https://flexluthor.s3.eu-west-2.amazonaws.com/images/sparkle.png', ' Generate HITL score');
generateHITLButton.id = "generate-hitl-button";
generateHITLButton.style.marginTop = '10px';
generateHITLButton.onclick = function() {
GenerateHITLScore(SegmentIndex, ActivityIndex, OutputIndex, HITLHolder, hiddenHITLData, hiddenIndex.value);
};
HITLButtonContainer.appendChild(generateHITLButton);
// HITL Result container
var HITLResult = document.createElement('div');
HITLResult.id = 'hitl-result';
HITLResult.classList.add('hitl-result');
HITLResult.style.display = 'none';
HITLResult.style.alignItems = 'center';
const scoreContainer = document.createElement('div');
scoreContainer.id = 'scoreContainer';
HITLResult.appendChild(scoreContainer);
HITLContainer.appendChild(HITLButtonContainer);
HITLHolder.appendChild(HITLContainer);
HITLHolder.appendChild(HITLResult);
/*
HITL option: check if HITLScore present
*/
if(stepInfo["HITLScore"])
{
// loop to get all hitl scores - plus add index property
const HITLScores = data?.Steps?.map((step, index) => ({
HITLScore: step?.HITLScore ?? null,
index: String(index)
})) ?? [];
// put the scores in a hidden field
hiddenHITLData.value = JSON.stringify(HITLScores);
//PopulateHITLData(HITLScores, 0, hiddenHITLData, HITLContainer);
PopulateHITLData(HITLScores, 0, hiddenHITLData, HITLHolder);
}
toolsHolder.appendChild(HITLHolder);
/*
Add Job-Specific Tools Here
*/
// tools holder
var jobToolsHolder = document.createElement('div');
jobToolsHolder.id = "_job_tools_holder_";
/*var jobToolsSubheading = document.createElement('h4');
jobToolsSubheading.id = "jobToolsSubheading";
jobToolsSubheading.textContent = '';
jobToolsHolder.appendChild(jobToolsSubheading);
// add rule
var jobToolsRule = createThickRule();
jobToolsHolder.appendChild(jobToolsRule); */
// Add smaller heading for "Useful Tools"
var jobToolsHeading = document.createElement('h3');
jobToolsHeading.textContent = 'Job Specific AI Tools ';
jobToolsHeading.style.cursor = 'pointer';
jobToolsHeading.appendChild(CreateInfoSpan());
jobToolsHeading.onclick = function() {
OpenInfoModal("Tools");
};
//jobToolsHolder.appendChild(jobToolsHeading);
toolsHolder.appendChild(jobToolsHeading);
// explain what the section is
let jobToolsParagraph = document.createElement('p');
jobToolsParagraph.textContent = "Explore a curated selection of AI-powered tools to enhance this job role.";
//jobToolsHolder.appendChild(jobToolsParagraph);
toolsHolder.appendChild(jobToolsParagraph);
// add subheading with the title from searchtools button
/* var jobToolsSubheading = document.createElement('p');
jobToolsSubheading.id = "jobToolsSubheading";
jobToolsSubheading.textContent = '';
jobToolsHolder.appendChild(jobToolsSubheading); */
// Create vertical boxes for AI tools
var jobToolsContainer = document.createElement('div');
jobToolsContainer.id = "gridContainerJobTools";
//jobToolsHolder.appendChild(jobToolsContainer);
toolsHolder.appendChild(jobToolsContainer);
// Useful Tools section
var toolsHeading = document.createElement('h3');
toolsHeading.textContent = 'Task Specific Tools ';
toolsHeading.style.cursor = 'pointer';
toolsHeading.appendChild(CreateInfoSpan());
toolsHeading.onclick = function() {
OpenInfoModal("Tools");
};
toolsHolder.appendChild(toolsHeading);
let toolsParagraph = document.createElement('p');
toolsParagraph.textContent = "Explore a curated selection of AI-powered tools to enhance this workflow.";
toolsHolder.appendChild(toolsParagraph);
var toolsContainer = document.createElement('div');
toolsContainer.id = "gridContainerTools";
toolsHolder.appendChild(toolsContainer);
// automations holder
var automationsHolder = document.createElement('div');
automationsHolder.id = "_automations_holder_0"; //
automationsHolder.className = 'visualization-container';
var automationsHeading = document.createElement('h3');
automationsHeading.textContent = 'Automation Evaluation ';
automationsHeading.style.cursor = 'pointer';
automationsHeading.appendChild(CreateInfoSpan());
automationsHeading.onclick = function() {
OpenInfoModal("Automation");
};
automationsHolder.appendChild(automationsHeading);
var ruleAutomations = createThickRule();
automationsHolder.appendChild(ruleAutomations);
var automationsSubheading = document.createElement('p');
automationsSubheading.textContent = 'Visualize the current workflow and discover how AI can improve the efficiency of the processes';
automationsHolder.appendChild(automationsSubheading);
var automationsContainer = document.createElement('div');
automationsContainer.id = "gridContainerAutomations";
// ROI panel
// Add the estimated cost savings container
const assumptions = {
salary: 100000,
timePercent: 20,
efficiency: parseInt(stepInfo["Gain"]["EfficiencyGain"])
};
const costSavingsCard = createEstimatedCostSavings(0, assumptions);
automationsHolder.appendChild(costSavingsCard);
automationsHolder.appendChild(automationsContainer);
// Add new container/holder for workflow results
// create tab container
// Create main tab container
const workflowsContainer = document.createElement('div');
workflowsContainer.className = 'workflows-container';
workflowsContainer.id = 'workflows-container'
// Create Workflows tab content
const workflowsContent = document.createElement('div');
workflowsContent.id = 'workflows-content';
workflowsContent.className = 'workflows-content';
workflowsContainer.appendChild(workflowsContent);
automationsHolder.appendChild(workflowsContainer);
var helpContainer = document.createElement('div');
helpContainer.id = 'helpAutomations';
helpContainer.innerHTML = ``;
automationsHolder.appendChild(helpContainer);
// Append elements in order
instructionsDiv.appendChild(closeButton);
instructionsDiv.appendChild(headingSteps);
instructionsDiv.appendChild(ruleSteps);
instructionsDiv.appendChild(stepsParagraph);
instructionsDiv.appendChild(headingOverview);
instructionsDiv.appendChild(textarea);
instructionsDiv.appendChild(hiddenIndex);
//instructionsDiv.appendChild(jobToolsHolder);
instructionsDiv.appendChild(toolsHolder);
instructionsDiv.appendChild(automationsHolder);
instructionsDiv.appendChild(reportHolder);
instructionsDiv.style.display = 'none';
// Show instructions div when button is clicked
var showInstructionsButton = document.createElement('button');
showInstructionsButton.id = 'btnShowMe';
showInstructionsButton.textContent = 'Show Me How';
showInstructionsButton.style.backgroundColor = '#8cd190';
showInstructionsButton.style.borderRadius = '10px';
showInstructionsButton.style.marginBottom = '15px';
showInstructionsButton.style.color = 'black';
showInstructionsButton.style.fontSize = 'large';
showInstructionsButton.style.padding = '5px';
showInstructionsButton.addEventListener('click', function() {
// close all other steps before displaying this one
var divs = document.querySelectorAll('#' + holderID + ' div[id^="_steps_instructions_"]');
for (var i = 0; i < divs.length; i++) {
divs[i].style.display = 'none';
}
instructionsDiv.style.display = 'block';
// Call PreFormatTextAreaText with the steps array
//PreFormatTextAreaText(stepsArray, textarea, container, stepInfo["Breakdown"]);
CreateUIShowMeHow(JobInfo, TaskInfo, stepInfo, container, textarea, JobSegmentTitle, jobObj);
});
container.appendChild(showInstructionsButton);
container.appendChild(instructionsDiv);
/*var insertAfterElement = document.getElementById(parentID);
if (insertAfterElement) {
insertAfterElement.insertAdjacentElement('afterend', container);
}*/
// instead add this to #ExpandedView
var ExpandedViewContainer = document.getElementById('ExpandedView');
ExpandedViewContainer.appendChild(container);
}
if($('#' + parentID + '_steps').length > 0)
{
$('#' + parentID + '_steps' + ' #btnShowMe').hide();
$('#' + parentID + '_steps' + ' #step-description').hide();
$('#' + parentID + '_steps' + ' #_steps_instructions_0').show();
$('#' + parentID + '_steps').show();
$('#' + parentID + '_steps' + ' button').eq(0).click();
}
}
if(!stepsPresent)
{
ConsoleLog("steps not present: SegmentIndex - ",SegmentIndex, " ActivitiesIndex - ",ActivityIndex, " OutputIndex - ", OutputIndex);
}
}
/**
* CreateUIShowMeHow - this method queries the LLM for how to do the step, it then returns the response and displays it in the instructionsDiv described in CreateUISteps
* @param JobTitle
* @param JobSummary
* @param TaskTitle
* @param TaskSummary
* @param AdditionalContext
* @param StepTitle
* @param parentID
* @param textAreaID
*/
//function CreateUIShowMeHow(JobTitle, JobSummary, TaskTitle, TaskSummary, AdditionalContext, StepTitle, Container, TextArea, JobSegmentTitle)
function CreateUIShowMeHow(JobInfo, TaskInfo, StepInfo, Container, TextArea, JobSegmentTitle, jobObj)
{
try
{
var resultWrap = document.querySelector('#statement-component');
var resultLoader = document.querySelector('#statement-loader');
var resultText = document.querySelector('#statement-text');
var JobTitle = JobInfo["JobTitle"];
var JobSummary = JobInfo["JobDecriptionSummary"];
var TaskTitle = TaskInfo["TaskTitle"];
var TaskSummary = TaskInfo["TaskSummary"];
var AdditionalContext = JobInfo["AdditionalContext"];
var StepTitle = StepInfo["Title"];
// FYI this is actually a div not a textarea
var textareaID = "_steps_instructions_" + StepInfo["index"] + "_content";
var createNew = true;
// Find the textarea element using vanilla JavaScript
var textarea = Container.querySelector("div[id='" + textareaID + "']");
//var stepsPresent = "Steps" in localStoredProfile;
// need to find the output -> then the steps in that output -> then the index of the correct step
var SegmentIndex = findSegmentIndexById(jobObj["JobSegments"], TaskInfo["SegmentId"]);
var ActivityIndex = findActivityIndexByOutputId(jobObj["JobSegments"][SegmentIndex]["Activities"], TaskInfo["ActivityId"]);
// in theory in order to be here you must have outputs and steps
var OutputIndex = findActivityOutputIndexById(jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"], TaskInfo["ActivityId"]);
var StepIndex = findStepIndexById(jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Steps"], StepInfo["id"]);
// Do something with the textarea element
if (textarea)
{
ConsoleLog('textArea: present');
var textArea = $(textarea);
// if this div has children then it is not new, therefore we can just show it
var preTags = textarea.querySelectorAll('pre');
var count = preTags.length;
ConsoleLog('pre tags: ' + count);
if(count > 0)
{
createNew = false;
}
}
else
{
ConsoleLog('The textarea element does not exist');
createNew = true;
}
if(!createNew)
{
// show the textarea
textarea.style.display = 'block';
// show instructionsDiv
var textArea = $(textarea);
textArea.parent().show();
}
if(createNew)
{
// check if HowTo exists for this step
var HowToPresent = "HowTo" in jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Steps"][StepIndex];
if(HowToPresent)
{
/*resultText.value = result;*/
ConsoleLog('HowToPresent: true');
if(resultLoader)
{
resultLoader.style.display = "none";
}
var data = jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex];
// Create steps array for PreFormatTextAreaText
var stepsArray = data.Steps.map(function(step, index) {
return {
HowTo: step.HowTo,
index: index,
Title: step.Outline,
id: step.id,
Report: step.Outline,
Gain: step.Gain,
Breakdown: {
JobSegment: jobObj["JobSegments"][SegmentIndex]["Name"],
Activity: jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Title"],
Output: jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Description"]
}
};
});
// Create stepInfo object (removing HowTo from Breakdown)
var stepInfo = {};
stepInfo["Title"] = data.Steps[0].Outline; // Use first step's outline as title
stepInfo["id"] = data.Steps[0].id;
stepInfo["index"] = 0;
stepInfo["Report"] = data.Steps[0].Outline;
stepInfo["Gain"] = data.Steps[0].Gain;
stepInfo["HowTo"] = data.Steps[0].HowTo;
stepInfo["HITLScore"] = data.Steps[0].HITLScore;
stepInfo["Breakdown"] = {};
stepInfo["Breakdown"]["JobSegment"] = jobObj["JobSegments"][SegmentIndex]["Name"];
stepInfo["Breakdown"]["Activity"] = jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Title"];
stepInfo["Breakdown"]["Output"] = jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Description"];
// add howto text to UI - convert this element to jquery element
var textArea = $(TextArea);
// maintain the formatting
/* TOOLS - they come from steps calling SearchTools */
PreFormatTextAreaText(stepsArray, textarea, Container, stepInfo["Breakdown"]);
//createNumberedList(howToItems, parentID);
// set title
$('#' + textArea.attr('id') + '_heading').text(stepInfo["Title"]);
// find parentID
let myElement = textArea;
let automationsHolder = myElement.nextAll('[id^="_automations_holder_"]').first();
//let jobToolsHolder = myElement.nextAll('[id^="_job_tools_holder_"]').first();
let jobToolsHolder = myElement.nextAll('[id^="_tools_holder_"]').first();
if (automationsHolder.length) {
// find automations container in side there
//var automationsContainer = $('#' + automationsHolder.attr('id') + ' #gridContainerAutomations');
var automationsContainer = automationsHolder.find('#gridContainerAutomations');
ConsoleLog('automationContainer: ' + automationsContainer.length);
// Element found, do something with it
ConsoleLog(automationsHolder);
// add automations
appendAutomations(automationsContainer, stepInfo);
} else {
// Element not found, handle the case
ConsoleLog("Automations holder not found.");
}
// show the textarea
textarea.style.display = 'block';
// show instructionsDiv
var textArea = $(textarea);
textArea.parent().show();
// trigger default searchtools
// StepToolSearchSelector
var toolSearchOptions = myElement.find('.StepToolSearchSelector');
if(toolSearchOptions.length)
{
// this preloads the first tools on open
toolSearchOptions.eq(0).click();
// NEXT
var jobDescriptionSummary = jobObj["JobDescriptionSummary"];
var jobTitle = jobObj["JobTitle"];
var searchItem = {};
searchItem.Breakdown = {
Output: jobTitle,
};
searchItem.Title = jobDescriptionSummary;
// find the holder - but note that it needs to target the new jobtools fields.
SearchTools_Weighted(jobToolsHolder, searchItem, 0);
}
else
{
ConsoleLog("search tools options empty");
}
}
if(!HowToPresent)
{
// trigger upsell
// perhaps show the holder but no instructions, no tools, a generic mermaid diagram etc.
// explain what you get and give button to upgrade to paid account
// create a upsell modal that has all of the information about the paid account
//Upgrade Now
//OpenModal("Unlock The Full Experience", "Need more help with your AI Strategy? Unlock it with a paid account", false, true);
OpenModal("Maximize Your AI Potential", "Need more help with your AI Strategy? Unlock it with a paid account", false, true);
}
}
// return and
}
catch(err)
{
ConsoleLog('error name: ' + err.name);
ConsoleLog('error message: ' + err.messsage);
ConsoleLog('error stacktrace: ' + err.stack);
// reset changes
// re-enable these fields
SearchJobEnable(true);
// clear all loading screens
LoaderView(false);
CancelSimulateGPT();
}
}
function sortResultsByRelevance(results) {
return results.sort((a, b) => {
const aMatchLevel = a.matchLevel;
const bMatchLevel = b.matchLevel;
if (aMatchLevel === "full" && bMatchLevel !== "full") {
return -1; // Prioritize "full" matches
} else if (aMatchLevel !== "full" && bMatchLevel === "full") {
return 1;
} else if (aMatchLevel === "partial" && bMatchLevel === "partial") {
return b.matchedWords.length - a.matchedWords.length; // More matched words first
} else if (aMatchLevel === "none" && bMatchLevel === "none") {
// Ignore further sorting when both are "none"
return 0;
}
});
}
function appendUnits(searchResults, container, breakdown, titleIndex) {
//function appendUnits(searchResults, container) {
var openSiteContainer = "app-holder";
// Create the main structure
const mainDiv = document.createElement('div');
mainDiv.className = "unitHolder";
/*mainDiv.style.display = 'grid';
mainDiv.style.gridTemplateColumns = '1fr 1fr 1fr';*/
// Create and append the header
/*const header = document.createElement('h2');
header.textContent = 'Useful Tools';
mainDiv.appendChild(header);*/
// Create and append the no tools message (hidden by default)
const noToolsMessage = document.createElement('div');
noToolsMessage.style.display = 'none';
noToolsMessage.textContent = 'No AI tools provided.';
mainDiv.appendChild(noToolsMessage);
// Create the grid wrapper
const gridWrapper = document.createElement('div');
gridWrapper.className = 'grid-wrapper';
gridWrapper.style.display = 'flex';
if (searchResults.length === 0) {
// If no search results, show the no tools message
noToolsMessage.style.display = 'block';
}
else
{
// Handle both formats of search results
let processedResults = [];
// Check if searchResults has specialized/universal structure
if (searchResults?.data?.specialized && searchResults?.data?.universal) {
// New format: combine specialized and universal arrays
//processedResults = [...searchResults.data.specialized, ...searchResults.data.universal];
processedResults = [...searchResults.data.universal, ...searchResults.data.specialized];
// Transform to match expected format (add metadata wrapper if needed)
processedResults = processedResults.map(item => {
let screenshot = item.screenshot || '';
// If no screenshot, check for s3_image_url
if (!screenshot) {
screenshot = item.s3_image_url || '';
}
// If still no image, use fallback based on source array
if (!screenshot) {
// Check if this item came from specialized array
const isSpecialized = searchResults.data.specialized.some(specializedItem =>
specializedItem.url === item.url || specializedItem.name === item.name
);
screenshot = isSpecialized
? "https://flexluthor.s3.eu-west-2.amazonaws.com/meta-images/tools-specialized.png"
: "https://flexluthor.s3.eu-west-2.amazonaws.com/meta-images/tools-universal.png";
}
return {
metadata: {
screenshot: screenshot,
name: item.name,
task: item.category, // or item.task if available
useCase: item.useCase,
siteUrl: item.url,
description: item.description
}
};
});
} else {
// Original format: use as-is
processedResults = searchResults;
}
// Now use processedResults in the forEach loop
processedResults.forEach(searchResult => {
var item = searchResult['metadata'];
const gridItem = document.createElement('div');
gridItem.className = 'grid-item';
// Add the badge
const badge = document.createElement('div');
badge.className = 'badge';
//badge.textContent = 'Sponsored';
badge.textContent = 'For You';
gridItem.appendChild(badge);
// Add the favorite button
const favoriteBtn = document.createElement('div');
favoriteBtn.className = 'favorite-btn';
favoriteBtn.innerHTML = '♥';
favoriteBtn.addEventListener('click', function() {
// used JQuery to add class
$(favoriteBtn).addClass("favorite");
// create favourite object
var favorite = {};
favorite["Screenshot"] = item.screenshot;
favorite["Name"] = item.name;
favorite["Task"] = item.task;
// short description
favorite["UseCase"] = item.useCase;
favorite["SiteUrl"] = item.siteUrl;
addFavorite(favorite);
});
gridItem.appendChild(favoriteBtn);
// Add the image
const img = document.createElement('img');
img.style.cursor = 'pointer';
var imgSrc = item.screenshot;
img.src = imgSrc;
img.alt = 'Screenshot';
const fallbackSrc = 'https://flexluthor.s3.eu-west-2.amazonaws.com/images/fallback_large.png';
img.onerror = function() {
if (this.src !== fallbackSrc) {
this.src = fallbackSrc;
}
this.onerror = null; // Remove the event handler after setting the fallback
};
img.style.borderBottom = '1px solid lightgray';
// Add click listener to image
img.addEventListener('click', function() {
openSite(item, openSiteContainer);
});
gridItem.appendChild(img);
// Add the content section
const content = document.createElement('div');
content.className = 'content';
const title = document.createElement('h4');
title.style.cursor = 'pointer';
title.textContent = item.name;
// Add click listener to title
title.addEventListener('click', function() {
openSite(item, openSiteContainer);
});
content.appendChild(title);
/*const description = document.createElement('p');
description.style.cursor = 'pointer';
description.innerHTML = item.Description;
content.appendChild(description);*/
const description = document.createElement('p');
description.style.cursor = 'pointer';
description.innerHTML = item.useCase;
// Add click listener to title
description.addEventListener('click', function() {
openSite(item, openSiteContainer);
});
content.appendChild(description);
/*const categoryTask = document.createElement('span');
categoryTask.style.cursor = 'pointer';
categoryTask.textContent = item.task;
// Applying CSS styles
categoryTask.style.backgroundColor = 'white';
categoryTask.style.color = 'green';
categoryTask.style.padding = '4px 8px';
categoryTask.style.borderStyle = 'solid';
categoryTask.style.borderColor = 'green';
categoryTask.style.borderRadius = '4px';
// if they search the category we will open a modal with all of the apps from that category
categoryTask.addEventListener('click', (event) => {
SearchCategory(categoryTask.textContent);
});
content.appendChild(categoryTask);*/
/* Add an onclick event here that triggers search */
gridItem.appendChild(content);
gridWrapper.appendChild(gridItem);
});
}
mainDiv.appendChild(gridWrapper);
// add the advice button first
// add spinner for advice loading
//var toolsAdviceSpinner = addSpinner_Advice();
//toolsAdviceSpinner.id = "_tools_holder_" + index + "_" + "spinner";
var toolsAdviceSpinnerHolder = document.createElement('div');
toolsAdviceSpinnerHolder.style.display = 'none';
toolsAdviceSpinnerHolder.style.maxHeight = '100px';
toolsAdviceSpinnerHolder.style.maxWidth = '100px';
var toolsAdviceSpinner = createLottiePlayer(
"https://cdn.prod.website-files.com/6446c148837a8953093cbfeb/657793c349c01f28349a98e0_spinner.json",
100,
100
);
toolsAdviceSpinner.id = "_tools_holder_advice_spinner";
//toolsAdviceSpinner.style.display = 'none';
// tools textArea div
var toolsTextarea = document.createElement('div');
toolsTextarea.id = "_tools_holder_advice_TextArea";
toolsTextarea.style.display = 'none';
// add caption under button
var giveMeAdviceParagraph = document.createElement('p');
giveMeAdviceParagraph.style.marginTop = '10px';
giveMeAdviceParagraph.style.fontSize = 'small';
giveMeAdviceParagraph.textContent = 'Use AI to analyse this selection of useful tools for advice on the best fit';
mainDiv.appendChild(giveMeAdviceParagraph);
// add advice button here
var toolsAdvice = createButton('https://flexluthor.s3.eu-west-2.amazonaws.com/images/sparkle.png', ' Give me Advice');
toolsAdvice.addEventListener('click', function() {
if(!$(toolsAdviceSpinnerHolder).is(':visible'))
{
// Re-initialize the copied animation
$(toolsAdviceSpinnerHolder).find("lottie-player").each(function() {
lottie.loadAnimation({
container: toolsAdviceSpinnerHolder,
renderer: "svg",
loop: true,
autoplay: true,
path: 'https://cdn.prod.website-files.com/6446c148837a8953093cbfeb/657793c349c01f28349a98e0_spinner.json'
});
});
$(toolsAdviceSpinnerHolder).show();
// use searchResults to create requestData
// jobTitle, jobDescriptionSummary, jobSegment, Activity, Description, StepTitle, Tools
var jobObj = JSON.parse(localStorage.getItem("profile"));
var jobTitle = jobObj["JobTitle"];
var jobDescriptionSummary = jobObj["JobDescriptionSummary"];
// uses empty strings if undefined (this is for the job specific tools)
var jobSegment = breakdown["JobSegment"] ?? "";
var jobActivity = breakdown["Activity"] ?? "";
var jobOutput = breakdown["Output"] ?? "";
var jobStepTitle = breakdown["Title"] ?? "";
var jobTools = CreateToolsInfo(searchResults);
var adviceData = {
jobTitle: jobTitle,
jobDescriptionSummary: jobDescriptionSummary,
jobSegment: jobSegment,
jobActivity: jobActivity,
jobOutput: jobOutput,
jobStepTitle: jobStepTitle,
jobTools: jobTools
};
var apiUrl = "https://v8flgw65bg.execute-api.eu-west-1.amazonaws.com/default/AIToolSearch";
const requestData = {};
// initial search uses the long search query (this is the title of the step)
requestData["requestDescription"] = "Advice";
requestData["adviceData"] = adviceData;
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
// Handle the API response here
//ConsoleLog("ShowMeHow return: " + data);
ConsoleLog('test result');
ConsoleLog(result);
result = JSON.parse(result);
//var searchResults = JSON.parse(result["body"]);
var message = result["message"];
switch(message)
{
case "success":
var advice = result["advice"];
PreFormatTextAreaText_advice(advice, toolsTextarea)
$(toolsTextarea).show();
break;
case "fail":
break;
}
//var advice = JSON.parse(result["choices"][0]["message"]["content"].replace(/`/g, '').replace(/json/g, ''));
$(toolsAdviceSpinnerHolder).hide();
})
.catch(error =>
{
console.error('Error calling Search API:', error);
$(toolsAdviceSpinnerHolder).hide();
});
}
});
mainDiv.appendChild(toolsAdvice);
toolsAdviceSpinnerHolder.appendChild(toolsAdviceSpinner);
mainDiv.appendChild(toolsAdviceSpinnerHolder);
mainDiv.appendChild(toolsTextarea);
container.append(mainDiv);
}
function addFavorite(newFavorite) {
try {
var memberID = localStorage.getItem("memberID");
var authToken = localStorage.getItem("auth_token");
var storedFavourites = JSON.parse(localStorage.getItem("favourites"));
if (storedFavourites) {
// Ensure favourites array exists
storedFavourites = storedFavourites || [];
// Check for existing favorite by Name
const alreadyExists = storedFavourites.some(
(storedFavourite) => storedFavourite.Name === newFavorite.Name
);
if (!alreadyExists) {
// Add new favorite to the array
storedFavourites.push(newFavorite);
// Update Local Storage with the modified profile
localStorage.setItem("favourites", JSON.stringify(storedFavourites));
// Handle server updates and any local references to profile (if applicable)
/*UpdateDBField(memberID, authToken, "favourites", JSON.stringify(storedFavourites))
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
var message = result["message"];
switch(message)
{
case "FieldUpdate Complete":
ConsoleLog("favourite saved");
break;
case "FieldUpdate Failed":
ConsoleLog("favourite failed");
break;
}
})
.catch(error => console.error("Error calling UpdateDBField: ", error));*/
UpdateDBField(memberID, authToken, "favourites", JSON.stringify(storedFavourites))
.then(response => { // First .then() for response resolution
// You don't need .text() here, as response is already parsed
//return JSON.parse(response); // Parse response as JSON
return response;
})
.then(result => { // Second .then() for JSON parsing
//const message = result["message"];
const message = result;
// Process the message here
switch(message)
{
case "FieldUpdate Complete":
ConsoleLog("favourite saved");
break;
case "FieldUpdate Failed":
ConsoleLog("favourite failed");
break;
}
})
.catch(error => console.error("Error updating database:", error));
}
}
} catch (error) {
// Handle any errors that may occur
console.error("Error in addFavorite:", error);
}
}
function appendUnitsCategory(searchResults, container) {
var siteHolder = "#category-modal #app-holder-category";
// Create the main structure
const mainDiv = document.createElement('div');
mainDiv.className = "unitHolder";
/*mainDiv.style.display = 'grid';
mainDiv.style.gridTemplateColumns = '1fr 1fr 1fr';*/
// Create and append the header
/*const header = document.createElement('h2');
header.textContent = 'Useful Tools';
mainDiv.appendChild(header);*/
// Create and append the no tools message (hidden by default)
const noToolsMessage = document.createElement('div');
noToolsMessage.style.display = 'none';
noToolsMessage.textContent = 'No AI tools provided.';
mainDiv.appendChild(noToolsMessage);
// Create the grid wrapper
const gridWrapper = document.createElement('div');
gridWrapper.className = 'grid-wrapper';
gridWrapper.style.display = 'flex';
if (searchResults.length === 0) {
// If no search results, show the no tools message
noToolsMessage.style.display = 'block';
} else {
// Append the search results to the grid wrapper
searchResults.forEach(item => {
const gridItem = document.createElement('div');
gridItem.className = 'grid-item';
// Add the badge
const badge = document.createElement('div');
badge.className = 'badge';
//badge.textContent = 'Sponsored';
badge.textContent = 'For You';
gridItem.appendChild(badge);
// Add the favorite button
const favoriteBtn = document.createElement('div');
favoriteBtn.className = 'favorite-btn';
favoriteBtn.innerHTML = '♥';
favoriteBtn.addEventListener('click', function() {
// used JQuery to add class
$(favoriteBtn).addClass("favorite");
// create favourite object
var favorite = {};
favorite["Screenshot"] = item.screenshot;
favorite["Name"] = item.name;
favorite["Category"] = item.task;
// short description
//favorite["Description"] = item.useCase;
favorite["UseCase"] = item.useCase;
favorite["SiteUrl"] = item.siteUrl;
addFavorite(favorite);
});
gridItem.appendChild(favoriteBtn);
// Add the image
const img = document.createElement('img');
img.style.cursor = 'pointer';
// create img src url (its just name in lower case, any space is a +)
var imgSrc = item.screenshot;
//img.src = item.Screenshot;
img.src = imgSrc;
img.alt = 'Screenshot';
const fallbackSrc = 'https://flexluthor.s3.eu-west-2.amazonaws.com/images/fallback_large.png';
img.onerror = function() {
if (this.src !== fallbackSrc) {
this.src = fallbackSrc;
}
this.onerror = null; // Remove the event handler after setting the fallback
};
// Add click listener to image
img.addEventListener('click', function() {
openSiteCategory(item, siteHolder);
});
img.style.borderBottom = '1px solid lightgray';
gridItem.appendChild(img);
// Add the content section
const content = document.createElement('div');
content.className = 'content';
const title = document.createElement('h4');
title.style.cursor = 'pointer';
title.textContent = item.name;
// Add click listener to title
title.addEventListener('click', function() {
openSiteCategory(item, siteHolder);
});
content.appendChild(title);
/*const description = document.createElement('p');
description.style.cursor = 'pointer';
description.innerHTML = item.Description;
content.appendChild(description);*/
const description = document.createElement('p');
description.style.cursor = 'pointer';
description.innerHTML = item.useCase;
// Add click listener to title
description.addEventListener('click', function() {
openSiteCategory(item, siteHolder);
});
content.appendChild(description);
/*const categoryTask = document.createElement('span');
categoryTask.style.cursor = 'pointer';
categoryTask.textContent = item.task;
// Applying CSS styles
categoryTask.style.backgroundColor = 'white';
categoryTask.style.color = 'green';
categoryTask.style.padding = '4px 8px';
categoryTask.style.borderStyle = 'solid';
categoryTask.style.borderColor = 'green';
categoryTask.style.borderRadius = '4px';
// if they search the category we will open a modal with all of the apps from that category
categoryTask.addEventListener('click', (event) => {
// no click for category in the category modal
});
content.appendChild(categoryTask);*/
/* Add an onclick event here that triggers search */
gridItem.appendChild(content);
gridWrapper.appendChild(gridItem);
});
}
mainDiv.appendChild(gridWrapper);
container.append(mainDiv);
// hide the app container in category modal
$('#category-modal #app-holder-category').hide();
}
function appendUnitsFavourites(searchResults, container) {
var siteHolder = "#favourites-modal #app-holder-category";
// Create the main structure
const mainDiv = document.createElement('div');
mainDiv.className = "unitHolder";
/*mainDiv.style.display = 'grid';
mainDiv.style.gridTemplateColumns = '1fr 1fr 1fr';*/
// Create and append the header
/*const header = document.createElement('h2');
header.textContent = 'Useful Tools';
mainDiv.appendChild(header);*/
// Create and append the no tools message (hidden by default)
const noToolsMessage = document.createElement('div');
noToolsMessage.style.display = 'none';
noToolsMessage.textContent = 'No AI tools provided.';
mainDiv.appendChild(noToolsMessage);
// Create the grid wrapper
const gridWrapper = document.createElement('div');
gridWrapper.className = 'grid-wrapper';
gridWrapper.style.display = 'flex';
if (searchResults.length === 0) {
// If no search results, show the no tools message
noToolsMessage.style.display = 'block';
} else {
// Append the search results to the grid wrapper
searchResults.forEach(item => {
const gridItem = document.createElement('div');
gridItem.className = 'grid-item';
// Add the badge
const badge = document.createElement('div');
badge.className = 'badge';
//badge.textContent = 'Sponsored';
badge.textContent = 'Saved';
gridItem.appendChild(badge);
// Add the image
const img = document.createElement('img');
img.style.cursor = 'pointer';
// create img src url (its just name in lower case, any space is a +)
var imgSrc = item.screenshot;
img.src = imgSrc;
img.alt = 'Screenshot';
const fallbackSrc = 'https://flexluthor.s3.eu-west-2.amazonaws.com/images/fallback_large.png';
img.onerror = function() {
if (this.src !== fallbackSrc) {
this.src = fallbackSrc;
}
this.onerror = null; // Remove the event handler after setting the fallback
};
// Add click listener to image
img.addEventListener('click', function() {
openSiteCategory(item, siteHolder);
});
img.style.borderBottom = '1px solid lightgray';
gridItem.appendChild(img);
// Add the content section
const content = document.createElement('div');
content.className = 'content';
const title = document.createElement('h4');
title.style.cursor = 'pointer';
title.textContent = item.name;
// Add click listener to title
title.addEventListener('click', function() {
openSiteCategory(item, siteHolder);
});
content.appendChild(title);
const description = document.createElement('p');
description.style.cursor = 'pointer';
description.innerHTML = item.useCase;
// Add click listener to title
description.addEventListener('click', function() {
openSiteCategory(item, siteHolder);
});
content.appendChild(description);
/*const categoryTask = document.createElement('span');
categoryTask.style.cursor = 'pointer';
categoryTask.textContent = item.task;
// Applying CSS styles
categoryTask.style.backgroundColor = 'white';
categoryTask.style.color = 'green';
categoryTask.style.padding = '4px 8px';
categoryTask.style.borderStyle = 'solid';
categoryTask.style.borderColor = 'green';
categoryTask.style.borderRadius = '4px';
// if they search the category we will open a modal with all of the apps from that category
categoryTask.addEventListener('click', (event) => {
// no click for category in the category modal
SearchCategory(categoryTask.textContent);
// hide favourites modal
$('#favourites-modal').animate({ opacity: 0 }).hide();
});
content.appendChild(categoryTask);*/
/* Add an onclick event here that triggers search */
gridItem.appendChild(content);
gridWrapper.appendChild(gridItem);
});
}
mainDiv.appendChild(gridWrapper);
container.append(mainDiv);
// hide the app container in category modal
$('#favourites-modal #app-holder-category').hide();
}
function SearchCategory(AttributeValue)
{
var apiUrl = "https://v8flgw65bg.execute-api.eu-west-1.amazonaws.com/default/AIToolSearch";
const requestData = {};
// initial search uses the long search query (this is the title of the step)
requestData["query"] = "Task";
requestData["AttributeValue"] = AttributeValue;
OpenCategoryModal(true, AttributeValue, "");
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
// Handle the API response here
//ConsoleLog("ShowMeHow return: " + data);
ConsoleLog(result);
result = JSON.parse(result);
//var searchResults = JSON.parse(result["body"]);
var searchResults = result;
// hide loading on category modal
$('#category-modal #modal-spinner').hide();
if (searchResults.length > 0)
{
ConsoleLog('test result');
ConsoleLog(result);
// create category results holder and populate
ConsoleLog(JSON.stringify(searchResults));
// use modal
searchResults = normalizeKeys(searchResults);
appendUnitsCategory(searchResults, $('#category-modal #category-content-holder'));
}
});
}
function createEncodedUrl(baseUrl, appname) {
// Handle spaces appropriately, using "%20" for consistency and clarity
const encodedAppname = encodeURIComponent(appname);
// Construct the URL using safeAppname, ensuring correct encoding
const url = baseUrl + "?appname=" + encodedAppname;
return url;
}
function SearchApp(AttributeName, AttributeValue)
{
var apiUrl = "https://v8flgw65bg.execute-api.eu-west-1.amazonaws.com/default/AIToolSearch";
const requestData = {};
// initial search uses the long search query (this is the title of the step)
requestData["query"] = AttributeName;
requestData["AttributeValue"] = AttributeValue;
// show loading on app page
OpenModal("Loading", "please wait", true, false);
//$('#loading-modal #modal-spinner').show();
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
// Handle the API response here
//ConsoleLog("ShowMeHow return: " + data);
ConsoleLog(result);
result = JSON.parse(result);
//var searchResults = JSON.parse(result["body"]);
var searchResults = result;
// hide loading on category modal
CloseModal();
if (searchResults.length > 0)
{
searchResults = normalizeKeys(searchResults);
setData("#app-holder", searchResults[0]);
ConsoleLog('test result');
ConsoleLog(result);
}
});
}
// pinecone has loewercase first letter for properties, so we need to change the object returned by algolia search
function normalizeKeys(dataArray) {
return dataArray.map(obj => {
const normalizedObj = {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// Convert the first letter of the key to lowercase
const normalizedKey = key.charAt(0).toLowerCase() + key.slice(1);
// Assign the value to the new key
normalizedObj[normalizedKey] = obj[key];
}
}
return normalizedObj;
});
}
function loadApp(result)
{
// load the details in ux
}
function openSite(item, containerID)
{
// open modal
OpenAppModal(item, containerID);
}
function openSiteCategory(item, containerID)
{
setData(containerID, item);
// show the app container in category modal
//$(containerID,' #app-holder-category').show();
//$('#category-modal #app-holder-category').show();
$(containerID).show();
}
// use global variables
let currentFavorite;
let currentSite;
async function setData(holder, data)
{
var heading = $(holder + ' ' + '#app-heading');
var subheading = $(holder + ' ' + '#app-subheading');
var category = $(holder + ' ' + '#category-button');
var currentUrl = window.location.href;
// if listing pages
if(currentUrl.toLowerCase().includes("/app-listing/listing") || currentUrl.toLowerCase().includes("/app-listing/my-tools"))
{
category = $(holder + ' ' + '#app-category');
}
var btn_title_visit = $(holder + ' ' + '#btn-title-visit');
var btn_title_share = $(holder + ' ' + '#btn-title-share');
var btn_title_save = $(holder + ' ' + '#btn-title-save');
var app_hero_img = $(holder + ' ' + '#app-hero-image');
var app_description = $(holder + ' ' + '#app-description');
var btn_visit = $(holder + ' ' + '#btn_visit');
var btn_save = $(holder + ' ' + '#btn_favourite');
var btn_share = $(holder + ' ' + '#btn_share');
/* check if app page */
// if app page
if (window.location.pathname.startsWith('/app'))
{
// hide login button and save buttons
$('#btnLogInOut').hide();
$('#btnAgency').hide();
btn_save.hide();
btn_title_save.hide();
}
var appData = data && (data.length > 0 ? data[0] : data);
if(appData)
{
// Change the meta title of the webpage
document.title = "MYPEAS.AI - " + appData.name;
heading.text(appData.name);
subheading.text(appData.useCase);
category.text(appData.task);
category.on('click', function(event) {
// no click for category in the category modal
SearchCategory(category.text());
// hide favourites modal
$('#favourites-modal').animate({ opacity: 0 }).hide();
// hide app modal
$('#app-modal').animate({ opacity: 0 }).hide();
});
// create favourite object
var favorite = {};
favorite["Screenshot"] = appData.screenshot;
favorite["Name"] = appData.name;
favorite["Task"] = appData.task;
// short description
favorite["UseCase"] = appData.useCase;
favorite["SiteUrl"] = appData.siteUrl;
currentFavorite = favorite;
// Parse the current appData.SiteUrl to check if it already has query parameters
const url = new URL(appData.siteUrl, window.location.origin); // Provide a base for relative URLs
const searchParams = new URLSearchParams(url.search);
// Add or update the 'referredby' parameter
searchParams.set('referredby', 'mypeas.ai');
// Reconstruct the URL with the updated query string
const finalUrl = url.origin + url.pathname + '?' + searchParams.toString();
//currentSite = finalUrl;
currentSite = appData.name;
btn_title_visit.attr('onclick', `window.open('${finalUrl}', '_blank')`);
//btn_title_share.attr('onclick', 'shareSite(window.location.href)');
/*btn_title_share.attr('onclick', `shareSite("${escapeHTMLAttribute(appData.name)}")`);
btn_title_save.attr('onclick', `addFavorite("${escapeHTMLAttribute(appData.name)}")`);*/
btn_title_share.attr('onclick', `shareSite(currentSite)`);
btn_title_save.attr('onclick', `addFavorite(currentFavorite)`);
app_hero_img.attr('src', appData.screenshot);
app_description.html(appData.description);
btn_visit.attr('onclick', `window.open('${finalUrl}', '_blank')`);
btn_save.attr('onclick', `addFavorite(currentFavorite)`);
btn_share.attr('onclick', `shareSite(currentSite)`);
/*btn_save.attr('onclick', `addFavorite("${escapeHTMLAttribute(appData.name)}")`);
btn_share.attr('onclick', `shareSite("${escapeHTMLAttribute(appData.name)}")`);*/
}
// if listing
var btnEditHeading = document.getElementById("edit-heading");
var btnEditSubheading = document.getElementById("edit-tagline");
var btnEditImage = document.getElementById("edit-hero-image");
var uploadButton = document.getElementById("upload-button");
var btnEditDescription = document.getElementById("edit-description");
var btnAddFAQ = document.getElementById("add-faq");
var btnEditUrl = document.getElementById("edit-url");
var btnOpenUrl = document.getElementById("visit-website");
var appURL = document.getElementById('app-URL');
var appId = document.getElementById('app-id');
// Code in here determines what happens on listing and mytools listing pages
if(appURL)
{
appURL.addEventListener("focus", () => {
appURL.style.border = "2px solid blue";
appURL.style.backgroundColor = "lightblue";
appURL.style.boxShadow = "0px 0px 5px rgba(0, 0, 0, 0.5)";
});
appURL.addEventListener("blur", () => {
appURL.style.border = "1px solid lightgray";
appURL.style.backgroundColor = "";
appURL.style.boxShadow = "";
});
if(appData)
{
// Parse the current appData.SiteUrl to check if it already has query parameters
const url = new URL(appData.siteUrl, window.location.origin); // Provide a base for relative URLs
const searchParams = new URLSearchParams(url.search);
// Add or update the 'referredby' parameter
searchParams.set('referredby', 'mypeas.ai');
// Reconstruct the URL with the updated query string
const finalUrl = url.origin + url.pathname + '?' + searchParams.toString();
appURL.textContent = (url.origin + url.pathname).toString();
}
btnOpenUrl.addEventListener('click', (event) => {
event.preventDefault();
var appLink = appURL.textContent;
if(appLink && appLink.trim() !== "")
{
window.open(appLink, '_blank', 'noopener');
}
});
btnEditUrl.addEventListener('click', (event) => {
event.preventDefault();
appURL.contentEditable = true;
appURL.focus();
});
var appHeading = document.getElementById("app-heading");
appHeading.addEventListener("focus", () => {
var placeholder = "Heading";
if(appHeading.textContent.trim() == placeholder)
{
appHeading.textContent = "";
// Set a minimum width when the content is empty
appHeading.style.minWidth = '200px'; // Adjust the value as needed
}
appHeading.style.border = "2px solid blue";
appHeading.style.backgroundColor = "lightblue";
appHeading.style.boxShadow = "0px 0px 5px rgba(0, 0, 0, 0.5)";
});
appHeading.addEventListener("blur", () => {
var placeholder = "Heading";
if(appHeading.textContent.trim() == "")
{
appHeading.textContent = placeholder;
}
appHeading.style.border = "";
appHeading.style.backgroundColor = "";
appHeading.style.boxShadow = "";
});
appHeading.addEventListener("paste", (event) => {
event.preventDefault(); // Prevent default paste behavior
// Get the plain text from the clipboard
const plainText = (event.clipboardData || window.clipboardData).getData('text');
// Insert the plain text at the current caret position
const selection = window.getSelection();
if (!selection.rangeCount) return;
// Get the current range and replace it with plain text
const range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(document.createTextNode(plainText));
});
btnEditHeading.addEventListener('click', (event) => {
// show forgotpassword
event.preventDefault();
/*$('#app-heading-update').show();
$('#app-heading').hide();*/
appHeading.contentEditable = true;
appHeading.focus();
});
var appSubheading = document.getElementById("app-subheading");
appSubheading.addEventListener("focus", () => {
var placeholder = "App tagline text";
if(appSubheading.textContent.trim() == placeholder)
{
appSubheading.textContent = "";
// Set a minimum width when the content is empty
appSubheading.style.minWidth = '200px'; // Adjust the value as needed
}
appSubheading.style.border = "2px solid blue";
appSubheading.style.backgroundColor = "lightblue";
appSubheading.style.boxShadow = "0px 0px 5px rgba(0, 0, 0, 0.5)";
});
appSubheading.addEventListener("blur", () => {
var placeholder = "App tagline text";
if(appSubheading.textContent.trim() == "")
{
appSubheading.textContent = placeholder;
}
appSubheading.style.border = "";
appSubheading.style.backgroundColor = "";
appSubheading.style.boxShadow = "";
});
appSubheading.addEventListener("paste", (event) => {
event.preventDefault(); // Prevent default paste behavior
// Get the plain text from the clipboard
const plainText = (event.clipboardData || window.clipboardData).getData('text');
// Insert the plain text at the current caret position
const selection = window.getSelection();
if (!selection.rangeCount) return;
// Get the current range and replace it with plain text
const range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(document.createTextNode(plainText));
});
btnEditSubheading.addEventListener('click', (event) => {
// show forgotpassword
event.preventDefault();
/*$('#app-subheading-update').show();
$('#app-subheading').hide(); */
appSubheading.contentEditable = true;
appSubheading.focus();
});
btnEditImage.addEventListener('click', (event) => {
// show forgotpassword
event.preventDefault();
$('#app-hero-image-update').show();
// file picker
$('#app-screenshot').show();
// update button
$('#upload-button').show();
});
if (uploadButton)
{
uploadButton.addEventListener('click', async (event) => {
event.preventDefault();
const screenshotInput = document.getElementById('app-screenshot'); // File input for new screenshot
if (screenshotInput.files.length > 0) {
const file = screenshotInput.files[0];
const folderName = 'images';
// Convert file to Base64 using FileReader
const fileBuffer = await fileToBase64(file); // Base64-encoded string
const payload = { folderName, fileBuffer };
const apiUrl = 'https://9halovn749.execute-api.eu-west-1.amazonaws.com/default/CreateListing';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify({ operation: 'generateScreenshotUploadUrl', payload }),
})
.then(response => response.json()) // Parse the response as JSON
.then(data => {
console.log("Upload response received:", data);
// Check if the response contains a valid imageUrl
if (data && typeof data === 'object' && data.imageUrl && typeof data.imageUrl === 'string' && data.imageUrl.startsWith('https://flexluthor.s3.eu-west-2.amazonaws.com/'))
{
console.log("Valid image URL detected:", data.imageUrl);
// Update the src of the image only if the URL is valid
const appHeroImg = document.getElementById('app-hero-image');
if (appHeroImg) {
appHeroImg.src = data.imageUrl;
} else {
console.warn('Element with id "app-hero-image" not found.');
}
// Clear the file selection
if (screenshotInput) {
screenshotInput.value = null;
} else {
console.warn('Element with id "screenshotInput" not found.');
}
}
else
{
console.warn("Response did not contain a valid image URL.", data);
}
})
.catch(error => {
console.error("Upload failed:", error);
});
}
});
}
var appDescription = document.getElementById('app-description');
appDescription.addEventListener("focus", () => {
var placeholder = "Description of Your AI solution";
if(appDescription.textContent.trim() == placeholder)
{
appDescription.textContent = "";
// Set a minimum width when the content is empty
appDescription.style.minWidth = '200px'; // Adjust the value as needed
}
appDescription.style.border = "2px solid blue";
appDescription.style.backgroundColor = "lightblue";
appDescription.style.boxShadow = "0px 0px 5px rgba(0, 0, 0, 0.5)";
appDescription.style.whiteSpace = 'pre-wrap';
appDescription.style.padding = '14px';
appDescription.style.wordWrap = 'break-word';
appDescription.style.overflowWrap = 'break-word';
appDescription.style.maxWidth = '100%';
appDescription.style.overflow = 'hidden';
appDescription.style.wordBreak = 'break-word';
//appDescription.style.outline = 'none';
});
appDescription.addEventListener("blur", () => {
var placeholder = "Description of Your AI solution";
if(appDescription.textContent.trim() == "")
{
appDescription.textContent = placeholder;
}
appDescription.style.whiteSpace = 'pre-wrap';
appDescription.style.padding = '14px';
appDescription.style.border = "1px solid lightgray";
appDescription.style.backgroundColor = "";
appDescription.style.boxShadow = "";
});
// Strip formatting when pasting
/*appDescription.addEventListener("paste", (event) => {
event.preventDefault(); // Prevent default paste behavior
const plainText = (event.clipboardData || window.clipboardData).getData('text'); // Get plain text
document.execCommand('insertText', false, plainText); // Insert text without formatting
});*/
appDescription.addEventListener("paste", (event) => {
event.preventDefault(); // Prevent default paste behavior
// Get the plain text from the clipboard
const plainText = (event.clipboardData || window.clipboardData).getData('text');
// Insert the plain text at the current caret position
const selection = window.getSelection();
if (!selection.rangeCount) return;
// Get the current range and replace it with plain text
const range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(document.createTextNode(plainText));
});
btnEditDescription.addEventListener('click', (event) => {
// show forgotpassword
event.preventDefault();
/*$('#app-description-update').show();
$('#app-description').hide();
var appDescription = document.getElementById("app-description");
const formattedText = appDescription.textContent.replace(/\n/g, " "); // Replace newlines with for HTML
// Get the textarea element
const textarea = document.getElementById('app-description-update');
// Set the textarea's value with the formatted text
textarea.value = formattedText;
// Create a temporary selection element (optional)
const selection = document.createRange();
selection.selectNodeContents(textarea);
try {
// Attempt to copy the selection (if supported)
const successful = document.execCommand('copy');
const msg = successful ? 'Formatted text copied!' : 'Browser may not support copying.';
alert(msg);
} catch (err) {
console.error('Copying failed:', err);
alert('Failed to copy text. Consider manual copy/paste.');
} finally {
// Cleanup the temporary selection (if created)
selection.detach();
}*/
appDescription.contentEditable = true;
appDescription.focus();
});
// add app category
var appCategory = document.getElementById('app-category');
appCategory.addEventListener("focus", () => {
appCategory.style.border = "2px solid blue";
appCategory.style.backgroundColor = "lightblue";
appCategory.style.boxShadow = "0px 0px 5px rgba(0, 0, 0, 0.5)";
appCategory.style.whiteSpace = 'pre-wrap';
appCategory.style.wordWrap = 'break-word';
appCategory.style.overflowWrap = 'break-word';
appCategory.style.maxWidth = '100%';
appCategory.style.overflow = 'hidden';
appCategory.style.wordBreak = 'break-word';
//appCategory.style.outline = 'none';
});
appCategory.addEventListener("blur", () => {
appCategory.style.border = "1px solid lightgray";
appCategory.style.backgroundColor = "";
appCategory.style.boxShadow = "";
});
appCategory.addEventListener("paste", (event) => {
event.preventDefault(); // Prevent default paste behavior
// Get the plain text from the clipboard
const plainText = (event.clipboardData || window.clipboardData).getData('text');
// Insert the plain text at the current caret position
const selection = window.getSelection();
if (!selection.rangeCount) return;
// Get the current range and replace it with plain text
const range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(document.createTextNode(plainText));
});
var btnEditCategory = document.getElementById('edit-category');
btnEditCategory.addEventListener('click', (event) => {
event.preventDefault();
appCategory.contentEditable = true;
appCategory.focus();
});
const faqList = document.getElementById('faq-list');
// Function to add a new FAQ input pair
/*function addFaqEntry(question, answer) {
const faqDiv = document.createElement('div');
faqDiv.style.marginBottom = "10px";
faqDiv.classList.add('faq-entry');
faqDiv.innerHTML = `
Remove
`;
faqList.appendChild(faqDiv);
const removeButton = faqDiv.querySelector('.remove-faq');
removeButton.addEventListener('click', () => {
faqDiv.remove();
});
}
// Add event listener to the "Add FAQ" button
btnAddFAQ.addEventListener('click', () => addFaqEntry());*/
// Function to ensure only one event listener is attached to btnAddFAQ
function setupFaqButtonListener() {
// If the handler hasn’t been set yet, define it
if (!handleAddFaqClick) {
handleAddFaqClick = function () {
addFaqEntry();
};
}
// Remove any existing listener before adding a new one
btnAddFAQ.removeEventListener('click', handleAddFaqClick);
btnAddFAQ.addEventListener('click', handleAddFaqClick);
}
// Function to add a new FAQ input pair
function addFaqEntry(question = '', answer = '') {
const faqDiv = document.createElement('div');
faqDiv.style.marginBottom = "10px";
faqDiv.classList.add('faq-entry');
faqDiv.innerHTML = `
Remove
`;
faqList.appendChild(faqDiv);
const removeButton = faqDiv.querySelector('.remove-faq');
removeButton.addEventListener('click', () => {
faqDiv.remove();
});
}
// Call this function whenever the event listener needs to be ensured
setupFaqButtonListener();
function populateFaqEntries(faqs) {
const existingFaqEntries = document.querySelectorAll('.faq-entry');
existingFaqEntries.forEach(entry => entry.remove());
faqs.forEach(faq => {
const { question, answer } = faq;
addFaqEntry(question, answer);
});
}
if (data && data.faqs) // && Array.isArray(data.faqs))
{
data.faqs = JSON.parse(data.faqs);
console.log('existing faqs exist');
populateFaqEntries(data.faqs);
}
// DETERMINE SUBMIT TYPE: buy listing OR update listing
var accountInfo = localStorage.getItem("accountInfo") || null;
if(accountInfo)
{
accountInfo = JSON.parse(accountInfo);
// create and populate
// get owned tools
var tools = accountInfo["tools"] || [];
// loop over tools and find appids
// Extracting AppId values
//const appIds = accountInfo.tools.map(tool => tool.AppId);
const appIds = tools.map(tool => tool.AppId);
// Output the result
console.log(appIds);
// compare current appId to the collection of AppId values
var appId = "";
if(appData)
{
appId = appData.objectID;
}
// Check if appId exists in appIds
if (appIds.includes(appId))
{
console.log("Match found for appId:", appId);
// Add any actions to execute when there's a match
// show update
$('#update-listing-holder').show();
$('#make-purchase-holder').hide();
}
else
{
console.log("No match found for appId:", appId);
// show purchase
$('#make-purchase-holder').show();
$('#update-listing-holder').hide();
}
}
// ** END ** DETERMINE SUBMIT TYPE: buy listing OR update listing
// use this to validate before go to purchase page
var submitButton = document.getElementById('submit-button');
if(submitButton)
{
setupSubmitButton(appData);
}
/*var submitButton_UpdateListing = docuement.getElementById('');
submitButton_UpdateListing.addEventListener('click', async () => {
});*/
// show update listing
// if loggedin and app owner. allow update without payment
var update_listing_button = document.getElementById('update-listing-button');
if(update_listing_button)
{
setupUpdateListingButton(appData);
}
}
}
let handleListingSubmit = async () => {
appData = CurrentContext;
var appHeading = document.getElementById("app-heading");
var appSubheading = document.getElementById("app-subheading");
var appHeroImg = document.getElementById('app-hero-image');
var appHeroImg = document.getElementById('app-hero-image');
var app_description = $(document.getElementById('app-description'));
var appURL = document.getElementById('app-URL');
var appCategory = document.getElementById('app-category');
var category = document.getElementById('app-category');
if(appData)
{
// if user has set any of these empty, we put them back
if(appHeading.textContent.trim() == "")
{
appHeading.textContent(appData.name);
}
if(appSubheading.textContent.trim() == "")
{
appSubheading.textContent(appData.useCase);
}
if(category.textContent.trim() == "")
{
if(appData.task)
{
category.textContent(appData.task);
}
}
if(app_description.text().trim() == "")
{
app_description.html(appData.description);
}
if(appURL.textContent.trim() == "")
{
// Parse the current appData.SiteUrl to check if it already has query parameters
const url = new URL(appData.siteUrl, window.location.origin); // Provide a base for relative URLs
const searchParams = new URLSearchParams(url.search);
// Add or update the 'referredby' parameter
searchParams.set('referredby', 'mypeas.ai');
// Reconstruct the URL with the updated query string
const finalUrl = url.origin + url.pathname + '?' + searchParams.toString();
appURL.textContent = (url.origin + url.pathname).toString();
}
}
var validListing = validateListing();
// we added email and password fields
var email = document.querySelector('#listing-email');
var validateEmail = document.querySelector('#validateEmail');
if(validateEmail)
{
validateEmail.style.display = 'none';
validateEmail.style.color = 'red';
}
var password = document.querySelector('#listing-password');
var validatePassword = document.querySelector('#validatePassword');
if(validatePassword)
{
validatePassword.style.display = 'none';
validatePassword.style.color = 'red';
}
var Credentials = {};
var isUserLoggedIn = checkLoggedIn();
/* START Set credentials for creating or accessing an account */
if(isUserLoggedIn)
{
Credentials.email = localStorage.getItem("email");
Credentials.loggedIn = 'true'
}
if(!isUserLoggedIn)
{
if(!isValidEmail(email.value))
{
failed = true;
validateEmail.textContent = "Please enter a valid email";
validateEmail.style.display = 'block';
validationMessages.push(validateEmail.id);
}
else
{
Credentials.email = email.value;
Credentials.loggedIn = 'false';
}
// validate them
// check if password field is visible
if($('#listing-password').is(':visible'))
{
if(!isValidPassword(password.value))
{
failed = true;
validatePassword.textContent = "Please enter a valid password";
validatePassword.style.display = 'block';
validationMessages.push(validatePassword.id);
}
else
{
Credentials.password = password.value;
}
}
}
/* END */
//const button = this;
const button = document.querySelector("#submit-button"); //document.getElementById("update-listing-button");
const buttonText = button.querySelector('#button-text'); //document.getElementById("button-text");
const spinner = button.querySelector('#spinner'); //document.getElementById("spinner");
if(validListing.isValid)
{
// Disable button and show spinner
button.disabled = true;
spinner.style.display = "inline-block";
// hide errors
var errorContainer = document.getElementById('validation-error-messages');
errorContainer.style.display = 'none';
const faqs = [];
const faqEntries = document.querySelectorAll('.faq-entry');
faqEntries.forEach((entry) => {
const question = entry.querySelector('.faq-question').value.trim();
const answer = entry.querySelector('.faq-answer').value.trim();
if (question && answer) {
faqs.push({ question, answer });
}
});
/*const payload = {
operation: 'createOrUpdateListing',
payload: {
UserId: 'example-user-id', // Replace with actual user ID
AppTitle: document.getElementById('app-title').value,
AppHeadline: document.getElementById('app-headline').value,
AppScreenshot: document.getElementById('app-screenshot').value,
AppDescription: document.getElementById('app-description').value,
WebsiteLink: document.getElementById('app-link').value,
FAQs: JSON.stringify(faqs),
Paid: false, // Default, can be updated as needed
DateOfPayment: null,
},
};*/
const DateOfPayment = new Date().toISOString();
var appId = "";
if(appData)
{
appId = appData.objectID;
}
else
{
// new listings require a unique objectID/appId
appId = generateRandomString(6);
}
var payload = {
operation: 'createOrUpdateListing',
payload: {
Credentials: Credentials,
AppId: appId,
AppTitle: document.getElementById('app-heading').textContent,
AppHeadline: document.getElementById('app-subheading').textContent,
AppScreenshot: document.getElementById('app-hero-image').src,
AppDescription: document.getElementById('app-description').textContent,
AppCategory: document.getElementById('app-category').textContent,
//AppCategory: appData.task,
WebsiteLink: document.getElementById('app-URL').textContent,
FAQs: JSON.stringify(faqs),
Paid: false, // Default, can be updated as needed
DateOfPayment: DateOfPayment,
},
};
// store in localStorage
localStorage.setItem("createOrUpdateListing", JSON.stringify(payload));
// go to purchase page
/*var btnBuyNow = document.getElementById('buy-now');
btnBuyNow.click();*/
// use the stripe checkout (not webflow)
// use a loading gif
//https://www.mypeas.ai/app-listing/listing?appname={{queryParam}}&list={{List}}&index={{Index}}
try
{
var paramList = getParameterByName("list", "");
if(!paramList)
{
paramList = "";
}
var paramIndex = getParameterByName("index", "");
if(!paramIndex)
{
paramIndex = "";
}
//var apiUrl = 'https://j8glspknjh.execute-api.eu-west-1.amazonaws.com/default/Checkout';
var apiUrl = 'https://j8glspknjh.execute-api.eu-west-1.amazonaws.com/Production/Checkout';
//https://j8glspknjh.execute-api.eu-west-1.amazonaws.com/Production/Checkout
var paramTest = getParameterByName("test", null);
var isTest = false;
if(paramTest)
{
isTest = true;
}
payload = payload.payload;
const currentOrigin = window.location.origin;
// check url
var currentUrl = window.location.href;
var urlDirectory = "/app-listing/listing";
if(currentUrl.toLowerCase().includes("/app-listing/listing"))
{
urlDirectory = "/app-listing/listing";
// determine which submit button is displayed
// if not logged in
if(!isUserLoggedIn)
{
localStorage.setItem("email", email);
// show purchase listing
}
if(isUserLoggedIn)
{
/*
why is this here?
*/
}
}
if(currentUrl.toLowerCase().includes("/app-listing/my-tools"))
{
urlDirectory = "/app-listing/my-tools";
}
/*var successUrl = `${currentOrigin}/app-listing/listing?appname=${encodeURIComponent(payload.AppTitle)}&success=true`;
var cancelUrl = `${currentOrigin}/app-listing/listing?appname=${encodeURIComponent(payload.AppTitle)}&cancel=true`;*/
var successUrl = `${currentOrigin}${urlDirectory}?appname=${encodeURIComponent(payload.AppTitle)}&success=true`;
var cancelUrl = `${currentOrigin}${urlDirectory}?appname=${encodeURIComponent(payload.AppTitle)}&cancel=true`;
const response = await fetch(apiUrl, {
method: 'POST',
body: JSON.stringify({
operation: 'create-checkout-session',
test: isTest,
priceId: 'price_1QUTOBH9xzzGAc7kRNc5uJZF', // Replace with your Stripe Price ID
successUrl: successUrl,
cancelUrl: cancelUrl,
userInfo: {userAction:"BuyListing", list: paramList, listindex: paramIndex, appId: payload.AppId, Credentials: Credentials},
listingData: payload
//userInfo: {userAction:"BuyListing", list: paramList, listindex: paramIndex, listing: payload}
})
});
const { url, sessionId } = await response.json();
if(sessionId && sessionId !== 'undefined')
{
console.log('sessionId: ', sessionId);
}
if(url && url !== 'undefined')
{
window.location.href = url; // Redirect to Stripe Checkout
console.log('redirect to: ', url);
}
else
{
console.log('problem: ', response);
}
// Hide spinner and enable button
spinner.style.display = "none";
button.disabled = false;
}
catch (error)
{
console.error('Error:', error);
// Hide spinner and enable button
spinner.style.display = "none";
button.disabled = false;
}
}
if(!validListing.isValid)
{
// Example usage:
/*var errors = [
'Name field cannot be empty.',
'Email address is invalid.',
'Password must be at least 8 characters long.'
];*/
var errors = validListing.errors;
displayValidationErrors(errors);
}
};
let CurrentContext;
function setupSubmitButton(context)
{
// Update the context dynamically
CurrentContext = context;
var submitButton = document.getElementById('submit-button');
if(submitButton)
{
// Remove the existing listener
submitButton.removeEventListener('click', handleListingSubmit);
// Add the listener with the persistent reference
submitButton.addEventListener('click', handleListingSubmit);
}
}
function setupUpdateListingButton(context)
{
// Update the context dynamically
CurrentContext = context;
var update_listing_button = document.getElementById('update-listing-button');
if(update_listing_button)
{
// Remove the existing listener
update_listing_button.removeEventListener('click', handleListingUpdate);
// Add the listener with the persistent reference
update_listing_button.addEventListener('click', handleListingUpdate);
}
}
let handleListingUpdate = async () =>
{
appData = CurrentContext;
var appHeading = document.getElementById("app-heading");
var appSubheading = document.getElementById("app-subheading");
var appHeroImg = document.getElementById('app-hero-image');
var app_description = $(document.getElementById('app-description'));
var appURL = document.getElementById('app-URL');
var appCategory = document.getElementById('app-category');
var category = document.getElementById('app-category');
if(appData)
{
// if user has set any of these empty, we put them back
if(appHeading.textContent.trim() == "")
{
appHeading.textContent(appData.name);
}
if(appSubheading.textContent.trim() == "")
{
appSubheading.textContent(appData.useCase);
}
if(category.textContent.trim() == "")
{
if(appData.task)
{
category.textContent(appData.task);
}
}
if(app_description.text().trim() == "")
{
app_description.html(appData.description);
}
if(appURL.textContent.trim() == "")
{
// Parse the current appData.SiteUrl to check if it already has query parameters
const url = new URL(appData.siteUrl, window.location.origin); // Provide a base for relative URLs
const searchParams = new URLSearchParams(url.search);
// Add or update the 'referredby' parameter
searchParams.set('referredby', 'mypeas.ai');
// Reconstruct the URL with the updated query string
const finalUrl = url.origin + url.pathname + '?' + searchParams.toString();
appURL.textContent = (url.origin + url.pathname).toString();
}
}
// THIS IS LISTING PAGE - CHECK EMAIL IS VALID
// ADD EMAIL TO PAGE
var validListing = validateListing();
var Credentials = {};
var isUserLoggedIn = checkLoggedIn();
var email = localStorage.getItem("email");
Credentials.email = email;
Credentials.loggedIn = 'true'
//const button = this;
const button = document.querySelector("#update-listing-button"); //document.getElementById("update-listing-button");
const buttonText = button.querySelector('#button-text'); //document.getElementById("button-text");
const spinner = button.querySelector('#spinner'); //document.getElementById("spinner");
if(validListing.isValid)
{
// Disable button and show spinner
button.disabled = true;
spinner.style.display = "inline-block";
// hide errors
var errorContainer = document.getElementById('validation-error-messages');
errorContainer.style.display = 'none';
const faqs = [];
const faqEntries = document.querySelectorAll('.faq-entry');
faqEntries.forEach((entry) => {
const question = entry.querySelector('.faq-question').value.trim();
const answer = entry.querySelector('.faq-answer').value.trim();
if (question && answer) {
faqs.push({ question, answer });
}
});
/*const payload = {
operation: 'createOrUpdateListing',
payload: {
UserId: 'example-user-id', // Replace with actual user ID
AppTitle: document.getElementById('app-title').value,
AppHeadline: document.getElementById('app-headline').value,
AppScreenshot: document.getElementById('app-screenshot').value,
AppDescription: document.getElementById('app-description').value,
WebsiteLink: document.getElementById('app-link').value,
FAQs: JSON.stringify(faqs),
Paid: false, // Default, can be updated as needed
DateOfPayment: null,
},
};*/
// use existing dateofpayment from server if present
const DateOfPayment = new Date().toISOString();
var appId = "";
var storedDateOfPayment = "";
if(appData)
{
appId = appData.objectID;
if(appData.DateOfPayment)
{
storedDateOfPayment = appData.DateOfPayment;
}
}
var payload = {
operation: 'createOrUpdateListing',
payload: {
Credentials: Credentials,
AppId: appId,
AppTitle: document.getElementById('app-heading').textContent,
AppHeadline: document.getElementById('app-subheading').textContent,
AppScreenshot: document.getElementById('app-hero-image').src,
AppDescription: document.getElementById('app-description').textContent,
AppCategory: document.getElementById('app-category').textContent,
//AppCategory: appData.task,
WebsiteLink: document.getElementById('app-URL').textContent,
FAQs: JSON.stringify(faqs),
Paid: true, // Default, can be updated as needed
DateOfPayment: storedDateOfPayment,
},
};
// store in localStorage
localStorage.setItem("createOrUpdateListing", JSON.stringify(payload));
// go to purchase page
/*var btnBuyNow = document.getElementById('buy-now');
btnBuyNow.click();*/
// use the stripe checkout (not webflow)
// use a loading gif
//https://www.mypeas.ai/app-listing/listing?appname={{queryParam}}&list={{List}}&index={{Index}}
try {
var paramList = getParameterByName("list", "");
if(!paramList)
{
paramList = "";
}
var paramIndex = getParameterByName("index", "");
if(!paramIndex)
{
paramIndex = "";
}
//var apiUrl = 'https://j8glspknjh.execute-api.eu-west-1.amazonaws.com/default/Checkout';
var apiUrl = 'https://j8glspknjh.execute-api.eu-west-1.amazonaws.com/Production/Checkout';
//https://j8glspknjh.execute-api.eu-west-1.amazonaws.com/Production/Checkout
var paramTest = getParameterByName("test", null);
var isTest = false;
if(paramTest)
{
isTest = true;
}
payload = payload.payload;
const currentOrigin = window.location.origin;
// check url
var currentUrl = window.location.href;
var urlDirectory = "/app-listing/listing";
if(currentUrl.toLowerCase().includes("/app-listing/listing"))
{
urlDirectory = "/app-listing/listing";
// determine which submit button is displayed
// if not logged in
if(!isUserLoggedIn)
{
localStorage.setItem("email", email);
// show purchase listing
}
if(isUserLoggedIn)
{
}
}
if(currentUrl.toLowerCase().includes("/app-listing/my-tools"))
{
urlDirectory = "/app-listing/my-tools";
}
/* SEND payload to server */
/*const response = await fetch(apiUrl, {
method: 'POST',
body: JSON.stringify({
operation: 'update-listing',
test: isTest,
userInfo: {userAction:"update-listing", list: paramList, listindex: paramIndex, appId: payload.AppId, Credentials: Credentials},
listingData: payload
//userInfo: {userAction:"BuyListing", list: paramList, listindex: paramIndex, listing: payload}
})
});*/
try {
const response = await fetch(apiUrl, {
method: 'POST',
body: JSON.stringify({
operation: 'update-listing',
test: isTest,
userInfo: {
userAction: "update-listing",
list: paramList,
listindex: paramIndex,
appId: payload.AppId,
Credentials: Credentials
},
listingData: payload
})
});
// Check if the response is OK
if (response.ok) {
const data = await response.json();
console.log('Success:', data.message);
// TODO: Handle success messaging
// redirect to paramsuccess
var successUrl = `${currentOrigin}${urlDirectory}?appname=${encodeURIComponent(payload.AppTitle)}&success=true`;
window.location = successUrl;
// Hide spinner and enable button
spinner.style.display = "none";
button.disabled = false;
} else {
// Handle server-side error responses
const errorData = await response.json();
console.error('Server Error:', response.status, response.statusText, errorData.error);
// TODO: Handle error messaging for non-2xx status codes (e.g., show error to the user)
var cancelUrl = `${currentOrigin}${urlDirectory}?appname=${encodeURIComponent(payload.AppTitle)}&cancel=true`;
window.location = cancelUrl;
// Hide spinner and enable button
spinner.style.display = "none";
button.disabled = false;
}
} catch (error) {
// Handle network or client-side errors
console.error('Network or client error:', error);
// TODO: Handle error messaging for network issues (e.g., show generic error message)
var cancelUrl = `${currentOrigin}${urlDirectory}?appname=${encodeURIComponent(payload.AppTitle)}&cancel=true`;
window.location = cancelUrl;
// Hide spinner and enable button
spinner.style.display = "none";
button.disabled = false;
}
} catch (error) {
console.error('Error:', error);
// Hide spinner and enable button
spinner.style.display = "none";
button.disabled = false;
}
}
if(!validListing.isValid)
{
// Example usage:
/*var errors = [
'Name field cannot be empty.',
'Email address is invalid.',
'Password must be at least 8 characters long.'
];*/
var errors = validListing.errors;
displayValidationErrors(errors);
}
};
/**
* Helper function to convert File/Blob to Base64
* @param {File} file - The file to convert
* @returns {Promise} - A promise that resolves to the Base64 encoded string
*/
function fileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file); // Convert file to Base64 using Data URL
reader.onload = () => resolve(reader.result.split(',')[1]); // Remove the "data:image/png;base64," prefix
reader.onerror = (error) => reject(error);
});
}
function validateListing()
{
var isValid = true;
var errors = [];
var appHeading = document.getElementById("app-heading");
var appSubheading = document.getElementById("app-subheading");
var appHeroImg = document.getElementById('app-hero-image');
var app_description = $(document.getElementById('app-description'));
var appURL = document.getElementById('app-URL');
var appCategory = document.getElementById('app-category');
var category = document.getElementById('app-category');
if(appHeading.textContent.trim() == "" || appHeading.textContent.trim() == "Product Title")
{
isValid = false;
errors.push("Enter Product Title");
}
if(appSubheading.textContent == "" || appSubheading.textContent == "Product Tagline")
{
isValid = false;
errors.push("Enter A Product Tagline");
/* // Check if the div is empty
if (div.textContent.trim() === '') {
div.classList.add('placeholder');
div.textContent = 'Enter your text here';
}
// Remove the placeholder when the user starts typing
div.addEventListener('input', () => {
div.classList.remove('placeholder');
});*/
}
// image
// if https://flexluthor.s3.eu-west-2.amazonaws.com/images/placeholder.png
// if
if(appHeroImg.src == "https://flexluthor.s3.eu-west-2.amazonaws.com/images/placeholder.png" || appHeroImg.src == "")
{
isValid = false;
errors.push("Upload a 1920x1080 screenshot (.png or .jpg) of your Product");
}
// description
if(app_description.html() == "")
{
isValid = false;
errors.push("Enter A Product Description");
}
// app category - check if empty and if it is in the categories list
if(appCategory.textContent.trim() == "" || (groupData && !groupData.includes(appCategory.textContent.trim())))
{
isValid = false;
errors.push("Enter a valid category");
}
if(!validateURL(appURL.textContent.trim()))
{
isValid = false;
errors.push("Enter a valid Product URL");
}
return { isValid: isValid, errors: errors};
}
function validateURL(url) {
const urlRegex = /^(https?:\/\/)?([\w.-]+)\.([a-z]{2,6})(\/[\w.-]*)*(\?[\w=&%.-]*)?(#[\w-]*)?$/i;
return urlRegex.test(url);
}
function displayValidationErrors(errors) {
const errorHolder = document.getElementById('validation-errors');
errorHolder.style.display = 'block';
// When you want to scroll to the error container:
// Select the container for error messages
const errorContainer = document.getElementById('validation-error-messages');
// Clear any existing errors
errorContainer.innerHTML = '';
// Loop through the errors array and create a for each error
errors.forEach((error) => {
const errorDiv = document.createElement('div');
errorDiv.textContent = `• ${error}`; // Add a bullet point and the error text
errorContainer.appendChild(errorDiv);
});
errorContainer.style.display = 'block';
// When you want to scroll to the error container:
errorContainer.scrollIntoView({ behavior: 'smooth' });
errorHolder.scrollIntoView({ behavior: 'smooth' });
}
function shareSite(siteName)
{
// btn_title_share.attr('onclick', 'shareSite(window.location.href)');
//peas-ai.webflow.io/app-listing/app
var shareAppTitle = siteName;
var shareAppUrl = createEncodedUrl("/app-listing/app", siteName);
var shareAppMessage = "🌟 Just found this amazing AI application on MYPEAS.AI. It's perfect for our needs. Check it out 👉";
//return shareAppUrl;
shareLink(shareAppTitle, shareAppMessage, shareAppUrl);
}
function shareLink(shareTitle, shareText, shareUrl)
{
// Ensure shareUrl is an absolute URL
if (!shareUrl.startsWith('http://') && !shareUrl.startsWith('https://')) {
// Construct the absolute URL if shareUrl is a relative path
const hostname = window.location.hostname;
const protocol = window.location.protocol;
shareUrl = `${protocol}//${hostname}${shareUrl.startsWith('/') ? '' : '/'}${shareUrl}`;
}
const shareData = {
title: shareTitle,
text: shareText,
url: shareUrl,
};
// Check if the Web Share API is supported && not desktop computer
if (navigator.share && !isDesktop())
{
// Use the Web Share API for mobile/tablet devices
navigator.share(shareData)
.then(() => ConsoleLog('Share was successful.'))
.catch((error) => ConsoleLog('Sharing failed', error));
}
else
{
// Fallback for desktop browsers
// Select the share link text
// Fallback for desktop browsers: Create a temporary textarea to copy the text
const tempInput = document.createElement('textarea');
// You might want to adjust the text format here to include the title or other details as needed
tempInput.value = "🌟 Just found this amazing AI application on MYPEAS.AI. It's perfect for our needs. Check it out 👉 " + shareUrl;
document.body.appendChild(tempInput);
tempInput.select();
tempInput.setSelectionRange(0, 99999); // For mobile devices
// Copy the text inside the text field
document.execCommand('copy');
// Clean up by removing the temporary element
document.body.removeChild(tempInput);
// Alert the copied text
alert('Copied to clipboard.');
}
}
function appendAutomations(parentDiv, data)
{
const container = parentDiv;
container.className = 'flex-container';
// clear old contents
container.empty();
if (data && data.Gain) {
// Create Visualization container - left
const visualizationContainer = document.createElement('div');
visualizationContainer.id = 'visualizationContainer';
visualizationContainer.className = 'visualizationContainer';
visualizationContainer.innerHTML = `
${data.Gain.EfficiencyGain} efficiency gain
${getEfficiencyLanguage(data.HITLScore.overall_hitl_score, data.Gain.EfficiencyGain)}
Reduced Labour Cost
Improved Accuracy
Increased Scalability
${data.Gain.Explanation}
`;
// Create Visualization container - right
const visualizationContainerRight = document.createElement('div');
visualizationContainerRight.id = 'visualizationContainerRight';
visualizationContainerRight.className = 'visualizationContainer';
appendN8Nbutton(parentDiv, visualizationContainerRight, data);
container.append(visualizationContainer);
container.append(visualizationContainerRight);
} else {
// Display message if data is empty or undefined
container.innerHTML = 'No Automations added';
}
}
function getEfficiencyLanguage(score, efficiencyPercent) {
if (score <= 2.0) {
return `Based on HITL analysis showing low implementation complexity, estimated efficiency gains of ${efficiencyPercent}% are highly achievable through full automation.`;
}
if (score <= 3.0) {
return `Based on HITL analysis showing moderate implementation complexity, estimated efficiency gains of ${efficiencyPercent}% are achievable with proper AI-assisted workflows.`;
}
if (score <= 4.0) {
return `Based on HITL analysis showing higher implementation complexity, estimated efficiency gains of ${efficiencyPercent}% are possible but require significant human oversight and structured AI collaboration.`;
}
return `Based on HITL analysis showing high implementation complexity, estimated efficiency gains of ${efficiencyPercent}% represent potential improvements to human workflows rather than automation replacements.`;
}
function appendN8Nbutton(parentDiv, visualizationContainer, data) {
if (data && data.Gain) {
//const n8nTaskTitle = data.Breakdown?.Output || "Automate This Task";
const n8nTaskTitle = data.Title || "Automate This Task";
// Create container div for the new UI
const n8nContainer = document.createElement('div');
n8nContainer.id = 'n8nContainer';
n8nContainer.style.marginTop = '20px';
n8nContainer.style.textAlign = 'left';
n8nContainer.style.backgroundColor = 'white';
n8nContainer.style.border = '2px solid lightgray';
n8nContainer.style.borderRadius = '1px';
n8nContainer.style.padding = '15px'; // optional: helps the content breathe inside the border
// Heading for the task
const heading = document.createElement('h4');
heading.id = "n8nTitle";
heading.textContent = n8nTaskTitle;
heading.style.marginBottom = '10px';
n8nContainer.appendChild(heading);
// Paragraph explaining what this does
const paragraph = document.createElement('p');
paragraph.style.marginBottom = '10px';
//paragraph.innerHTML = 'Generate an
n8n workflow template to automate this task in your own systems.';
paragraph.innerHTML = 'Browse AI-powered workflows designed for this type of task. Find pre-built automations you can customize for your needs.';
n8nContainer.appendChild(paragraph);
// Button element
const button = document.createElement('button');
button.id = 'generateN8Nbtn';
button.className = 'genN8Nbtn';
button.style.height = '40px';
button.style.borderRadius = '10px';
button.style.maxWidth = '300px';
button.style.padding = '0px 5px';
button.style.backgroundColor = 'white';
button.style.border = '1px solid darkgray';
// Button inner HTML
/*button.innerHTML = `
Generate n8n Workflow
`;*/
button.innerHTML = `
Find Relevant Workflows
`;
// Button click handler
button.addEventListener('click', async function () {
// show spinner
$(this).find('#n8nSpinner').show();
//GenerateN8N(data.Flow, data.Report); // Flow and Outline renamed accordingly
//GenerateN8N(data.HowTo, data.Title);
// When user clicks "Find Relevant Workflows"
//const taskTitle = "Implement KPI tracking and reporting mechanisms";
const taskTitle = $(button).parent().find('#n8nTitle').text();
try {
const response = await findWorkflowsForTask(taskTitle, 5);
ConsoleLog('Got workflows:', response);
// Now you can do whatever you want with the results
// Display them, navigate somewhere, update the UI, etc.
// response.data.results contains the workflows array
displayWorkflows(response, parentDiv);
// hide spinner
$(this).find('#n8nSpinner').hide();
} catch (error) {
console.error('Failed to load workflows:', error);
// Show user-friendly error message
}
});
n8nContainer.appendChild(button);
// Follow-up paragraph with interactive options
const infoParagraph = document.createElement('p');
infoParagraph.style.marginTop = '15px';
infoParagraph.innerHTML = `
What is n8n?
Get n8n
How to import
`;
n8nContainer.appendChild(infoParagraph);
// Append everything to the visualization container
visualizationContainer.appendChild(n8nContainer);
}
}
function openWhatIsN8NModal(mode)
{
// open modal
$('#n8n-info-modal').css('z-index', '10001').animate({ opacity: 1 }).show();
switch(mode)
{
case '1':
// show mode 1
showN8nSection('section-what-is-n8n');
break;
case '2':
showN8nSection('section-import-n8n');
break;
}
}
function showN8nSection(sectionId) {
document.getElementById('section-what-is-n8n').style.display = 'none';
document.getElementById('section-import-n8n').style.display = 'none';
document.getElementById(sectionId).style.display = 'block';
}
function GenerateN8N(HowTo, HowToTitle) {
// open modal
$('#n8n-modal').css('z-index', '10001').animate({ opacity: 1 }).show();
// set loading to 0
updateProgress(0, 'Preparing to generate your template...');
// show loading bar and message
$('#n8n-progress-container').show();
$('#n8n-generation-status').show();
// hide sections and download button
$('.n8n-download-btn').hide();
$('#n8n-blueprint-analysis-section').hide();
$('#n8n-blueprint-preview-section').hide();
$('#download-button-container').hide();
// hide consultant button
$('.connect-btn').hide();
$('.connect-text').hide();
// Format data for Lambda - keep your original format
/*const requestData = {
Outline: HowToTitle,
HowTo: HowTo // Your existing array of {Title: "..."} objects
};*/
const requestData = {
outline: HowToTitle, // lowercase
howToSteps: HowTo.map(h => h.Title) // extract just the titles
};
console.log('Sending request data:', requestData);
// Make an API call to API gateway
var apiUrl = 'https://waduwrgekj.execute-api.eu-west-1.amazonaws.com/default/generateN8Nstarter';
fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestData),
})
.then(response => response.json())
.then(result => {
console.log('API Response:', result);
if (result.success) {
// Job was accepted and queued
updateProgress(10, 'Job queued for processing...');
// Start polling for job completion
pollJobStatus(result.jobId);
} else {
// Handle error
updateProgress(0, 'Error: ' + (result.error || 'Unknown error occurred'));
console.error('Job creation failed:', result.error);
}
})
.catch(error => {
console.error('Request failed:', error);
updateProgress(0, 'Error: Failed to submit job');
});
}
/**
* Search for relevant workflows using semantic search and/or filters
*
* @param {Object} options - Search options
* @param {string} [options.query] - Semantic search query (e.g., task title/description)
* @param {string} [options.category] - Filter by workflow category
* @param {string} [options.subcategory] - Filter by workflow subcategory
* @param {number} [options.maxResults=10] - Maximum number of results to return (1-100)
* @returns {Promise
} Search results object
* @returns {boolean} return.success - Whether the search was successful
* @returns {Object} return.data - Search result data
* @returns {string} return.data.query - The query that was searched
* @returns {Object} return.data.filters - Filters that were applied
* @returns {Array} return.data.results - Array of matching workflows with metadata
* @returns {number} return.data.count - Number of results returned
* @returns {string} return.data.searchType - Type of search performed
*
* @throws {Error} If the API request fails
*
* @example
* // Semantic search for a task
* const results = await searchWorkflows({
* query: "Implement KPI tracking and reporting mechanisms",
* maxResults: 5
* });
*
* @example
* // Browse workflows by category
* const results = await searchWorkflows({
* category: "Customer Service",
* maxResults: 20
* });
*
* @example
* // Combined semantic search with category filter
* const results = await searchWorkflows({
* query: "automate email responses",
* category: "Marketing",
* maxResults: 10
* });
*/
async function searchWorkflows({
query = null,
category = null,
subcategory = null,
maxResults = 10
} = {}) {
// API endpoint
const API_ENDPOINT = 'https://670lpiwg7g.execute-api.eu-west-1.amazonaws.com/default/WorkoutRecommender';
// Validate maxResults
if (maxResults < 1 || maxResults > 100) {
throw new Error('maxResults must be between 1 and 100');
}
// Build query parameters
const params = new URLSearchParams();
if (query) {
params.append('query', query);
}
if (category) {
params.append('category', category);
}
if (subcategory) {
params.append('subcategory', subcategory);
}
params.append('maxResults', maxResults.toString());
// Construct full URL
const url = `${API_ENDPOINT}?${params.toString()}`;
try {
// Make the request
const response = await fetch(url, {
method: 'GET'
});
// Check if response is ok
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(
errorData.message ||
errorData.error ||
`API request failed with status ${response.status}`
);
}
// Parse and return the results
const data = await response.json();
return data;
} catch (error) {
// Re-throw with more context
console.error('Error searching workflows:', error);
throw new Error(`Failed to search workflows: ${error.message}`);
}
}
// Example usage functions you can use in your UI
/**
* Search workflows for a specific task
* @param {string} taskTitle - The task title to search for
* @param {number} [limit=5] - Number of workflows to return
* @returns {Promise} Array of matching workflows
*/
async function findWorkflowsForTask(taskTitle, limit = 5) {
try {
const result = await searchWorkflows({
query: taskTitle,
maxResults: limit
});
if (result.success) {
return result.data.results;
} else {
console.error('Search was not successful:', result);
return [];
}
} catch (error) {
console.error('Error finding workflows for task:', error);
return [];
}
}
/**
* Browse workflows by category
* @param {string} category - The category to browse
* @param {number} [limit=20] - Number of workflows to return
* @returns {Promise} Array of workflows in the category
*/
async function browseWorkflowsByCategory(category, limit = 20) {
try {
const result = await searchWorkflows({
category: category,
maxResults: limit
});
if (result.success) {
return result.data.results;
} else {
console.error('Browse was not successful:', result);
return [];
}
} catch (error) {
console.error('Error browsing workflows:', error);
return [];
}
}
// Export for use in modules (if needed)
// export { searchWorkflows, findWorkflowsForTask, browseWorkflowsByCategory };
function pollJobStatus(jobId) {
// You'll need a job status endpoint - this is a placeholder
//const statusUrl = `https://waduwrgekj.execute-api.eu-west-1.amazonaws.com/default/getJobStatus/${jobId}`;
const statusUrl = `https://jjiuw8ydh4.execute-api.eu-west-1.amazonaws.com/default/generateN8Nprogress/${jobId}`;
const checkStatus = () => {
fetch(statusUrl)
.then(response => response.json())
.then(result => {
console.log('Job status:', result);
if (result.status === 'completed') {
updateProgress(100, 'Generation complete!');
// Show download button with the generated workflow
if (result.workflow) {
console.log('result (workflow return): ',JSON.stringify(result));
//showDownloadButton(result.workflow, jobId);
showDownloadButton(result.workflow.workflow, result.jobId, result.workflow.analysis);
}
// Show consultant button
$('.connect-btn').show();
$('.connect-text').show();
} else if (result.status === 'failed') {
updateProgress(0, 'Generation failed: ' + (result.error || 'Unknown error'));
} else if (result.status === 'processing' || result.status === 'pending') {
// Use the actual progress from backend instead of hardcoded values
const progressValue = result.progress || 0;
const progressMessage = result.progressMessage || 'Processing...';
updateProgress(progressValue, progressMessage);
// Continue polling
setTimeout(checkStatus, 1000); // Faster polling - every 1 second
} else {
// Still pending with no progress yet
updateProgress(10, 'Waiting for processing to start...');
setTimeout(checkStatus, 2000);
}
})
.catch(error => {
console.error('Status check failed:', error);
updateProgress(0, 'Error checking job status');
});
};
// Start checking status
checkStatus();
}
function showDownloadButton_OLD(workflowData, jobId) {
// Create download functionality
const downloadBtn = $('.n8n-download-btn');
downloadBtn.off('click').on('click', function() {
const blob = new Blob([JSON.stringify(workflowData, null, 2)], {
type: 'application/json'
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `n8n-workflow-${jobId}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
});
downloadBtn.prop('disabled', false);
document.getElementById('n8n-generation-status').textContent = 'Template is ready!';
downloadBtn.show();
}
function updateProgress(percent, message) {
document.getElementById('n8n-generation-progress').style.width = percent + '%';
document.getElementById('n8n-generation-status').textContent = message;
}
/*
New n8n generation functions
*/
// Enhanced showDownloadButton function
function showDownloadButton(workflowData, jobId, analysisData) {
// Create download functionality
const downloadBtn = $('#n8n-download-n8n-btn');
downloadBtn.off('click').on('click', function() {
const blob = new Blob([JSON.stringify(workflowData, null, 2)], {
type: 'application/json'
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `n8n-workflow-${jobId}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
});
// Show all blueprint sections
document.querySelectorAll('.n8n-blueprint-section').forEach(section => {
section.style.display = 'block';
});
//$('#download-button-container').show();
// hide loading bar and message
$('#n8n-progress-container').hide();
$('#n8n-generation-status').hide();
// show sections and download button
//$('.n8n-download-btn').show();
$('#n8n-blueprint-analysis-section').show();
$('#n8n-blueprint-preview-section').show();
$('#download-button-container').show();
// Update status
document.getElementById('n8n-generation-status').textContent = 'Template is ready!';
// Populate blueprint analysis with actual data
populateBlueprintAnalysis(workflowData, analysisData);
// Populate template preview with actual nodes
populateTemplatePreview(workflowData, analysisData);
// Setup download functionality
window.currentWorkflowData = workflowData;
window.currentAnalysisData = analysisData;
window.currentJobId = jobId;
}
// using the click event instead.
function downloadWorkflow() {
if (window.currentWorkflowData && window.currentJobId) {
const blob = new Blob([JSON.stringify(window.currentWorkflowData, null, 2)], {
type: 'application/json'
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `n8n-workflow-blueprint-${window.currentJobId}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
}
function viewSetupGuide() {
// You can implement this to show a modal or navigate to a guide page
alert('Setup guide feature - implement based on your needs');
}
function populateBlueprintAnalysis(workflowData, analysisData) {
const nodes = workflowData.nodes || [];
// Extract node types from actual workflow
const nodeTypes = [...new Set(nodes.map(node => {
const type = node.type.replace('n8n-nodes-base.', '');
return type.charAt(0).toUpperCase() + type.slice(1);
}))];
// Update node types section
const nodeTypesContainer = document.getElementById('n8n-blueprint-node-types');
nodeTypesContainer.innerHTML = nodeTypes.map(type =>
`${type} `
).join('');
// Populate data sources from functionality needs
if (analysisData && analysisData.functionalityNeeds) {
const dataSources = analysisData.functionalityNeeds
.filter(need => need.category === 'data' || need.category === 'integration')
.map(need => need.keyword);
const dataSourcesContainer = document.getElementById('n8n-blueprint-data-sources');
dataSourcesContainer.innerHTML = dataSources.map(source =>
`${source} `
).join('');
}
// Populate outputs from output needs
if (analysisData && analysisData.outputNeeds) {
const outputs = analysisData.outputNeeds.map(output =>
output.type.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase())
);
const outputsContainer = document.getElementById('n8n-blueprint-outputs');
outputsContainer.innerHTML = outputs.map(output =>
`${output} `
).join('');
}
}
function populateTemplatePreview(workflowData) {
const nodes = workflowData.nodes || [];
const previewContainer = document.getElementById('n8n-blueprint-preview-content');
// Show first 3-4 key nodes
// const keyNodes = nodes.slice(0, 4);
const keyNodes = nodes; // Shows all nodes
previewContainer.innerHTML = keyNodes.map(node => `
${node.name}
${node.type}
${node.notes || 'Configure: Review and customize parameters'}
`).join('');
}
// Demo: Show the enhanced UI immediately
/*setTimeout(() => {
showDownloadButton({
nodes: [
{ name: "Schedule Trigger", type: "n8n-nodes-base.scheduleTrigger" },
{ name: "Get Market Data", type: "n8n-nodes-base.httpRequest" },
{ name: "Process Data", type: "n8n-nodes-base.code" },
{ name: "Save Results", type: "n8n-nodes-base.googleSheets" },
{ name: "Send Notification", type: "n8n-nodes-base.emailSend" }
]
}, "demo-123");
}, 1000);*/
/**
* PreFormatTextAreaText - this method formats the textArea so that we can maintain line breaks and lists using html, it works with FormatText method
* @param response - text returned by the LLM
* @param textArea - textarea element
*/
function PreFormatTextAreaText_OLD(response, textArea, Container, breakdown)
{
// Assume 'response' variable holds the API response
// response is the howto property
// we need a collection of titles
// create title array
//const titlesArray = exampleObject.map(item => item.Title);
const htmlElements = response.map(item => {
// create more contextual search
//var SearchTerm = item.Title + " > " + breakdown.Output + " > " + breakdown.Activity + " > " + breakdown.JobSegment;
//var SearchTerm = item.Title + " > " + breakdown.Output; // Output here is actually Description property
var SearchTerm = breakdown.Output + " > " + item.Title; // Output here is actually Description property
//var SearchTerm = item.Title + " > " + breakdown.Activity + " > " + breakdown.JobSegment;
return `${escapeHTMLAttribute(item.Title)}
`;
}).join('');
// Escape special characters for HTML display
//const escapedResponse = FormatText(response)
//const escapedResponse = FormatText(htmlElements)
// Set the formatted response as the textarea value using jQuery
//textArea.html('' + escapedResponse + ' ');
//textArea.html(escapedResponse);
textArea.html(htmlElements);
}
function PreFormatTextAreaText(response, textArea, Container, breakdown) {
// Generate HTML elements with click listeners for each item in the response
//response = breakdown.HowTo;
/*const htmlElements = */
// this counts where you are up to in the howto array
var titleIndex = 0;
response.map((item, index) => {
// Construct the search term using breakdown.Output and item.Title
const SearchTerm = item.Breakdown.Output + " > " + item.Title;
// Create the element
const p = document.createElement("p");
p.style.cursor = "pointer";
p.style.textDecoration = "underline";
p.style.padding = "5px";
p.style.margin = "5px";
p.style.borderRadius = "5px";
p.className = "StepToolSearchSelector";
p.textContent = item.Title;
// Add the click event listener
// also set the index of the step in the hiddenIndex field
var hiddenIndex = Container.querySelector('#_steps_index');
//.id = "_steps_index";
p.addEventListener("click", () => {
// UPDATE TOOLS
SearchTools(p, item, index);
hiddenIndex.value = index;
// UPDATE HITL
// check for hitlscore data stored
var parent = Container;
var hitlDataStore = parent.querySelector("#_steps_instructions_HITLData");
var hitlScore = 0;
if(hitlDataStore.value != "")
{
// need to find the hitl_holder and use that as the container in this parameter
//var parent = Container;
var hitlHolder = parent.querySelector('[id^="_hitl_holder_"]');
if (hitlHolder) {
// You've found the element! You can now work with hitlHolder
console.log("Found HITL Holder:", hitlHolder);
var hitlData = JSON.parse(hitlDataStore.value);
var hitlScoreObj = findObjectByStep(hitlData, index);
const overallScore = hitlScoreObj?.HITLScore?.overall_hitl_score;
const bucket = hitlScoreObj?.HITLScore?.bucket;
hitlScore = overallScore;
PopulateHITLData(hitlData, index, hitlDataStore, hitlHolder);
}
else
{
console.log("HITL Holder not found in the parent.");
}
}
else
{
// show generate hitl score fields
}
// UPDATE ROI panel
// find container so we know where this ROI panel is
// now needs to draw on the details in that output
// use this to determine id of this ROI panel
//const id = `_cost_savings_${index}`;
const id = `_cost_savings_0`;
// parse assumptions
var currentROIpanel = Container.querySelector('#' + id);
// Assume currentROIpanel, salaryLi, timeSpentLi, and efficiencyGainLi
// already exist in the DOM with their respective text content.
// --- Extract Salary ---
// Select the existing salaryLi element
const salaryli = currentROIpanel.querySelector('#salaryLi');
// Get its text content
const salaryTextContent = salaryli.textContent;
// Regular expression to find digits, commas, and dots after '$'
const salaryMatch = salaryTextContent.match(/\$(\d[,\d]*)/);
let extractedSalary = null;
if (salaryMatch && salaryMatch[1]) {
const salaryString = salaryMatch[1];
// Remove commas (and potentially dots if they are used as thousands separators in some locales)
extractedSalary = parseInt(salaryString.replace(/[,.]/g, ''), 10);
}
// --- Extract Time Spent Percentage ---
// Select the existing timeSpentLi element
const timeSpentli = currentROIpanel.querySelector('#timeSpentLi');
// Get its text content
const timeSpentTextContent = timeSpentli.textContent;
// Regex to capture digits before '%'
const timeSpentMatch = timeSpentTextContent.match(/(\d+)%/);
let extractedTimePercent = null;
if (timeSpentMatch && timeSpentMatch[1]) {
extractedTimePercent = parseInt(timeSpentMatch[1], 10);
}
// --- Extract Efficiency Gain Percentage ---
// Select the existing efficiencyGainLi element
const efficiencyGainLi = currentROIpanel.querySelector('#efficiencyGainLi');
// Get its text content
const efficiencyGainTextContent = efficiencyGainLi.textContent;
// Regex to capture digits before '%'
const efficiencyGainMatch = efficiencyGainTextContent.match(/(\d+)%/);
let extractedEfficiency = null;
var targetStepGain = item.Gain;
if (efficiencyGainMatch && efficiencyGainMatch[1]) {
//extractedEfficiency = parseInt(efficiencyGainMatch[1], 10);
extractedEfficiency = parseInt(targetStepGain.EfficiencyGain);
}
// --- Store them in an assumptions object ---
const assumptions = {
salary: extractedSalary,
timePercent: extractedTimePercent,
efficiency: extractedEfficiency
};
console.log('Extracted Salary:', assumptions.salary);
console.log('Extracted Time Percent:', assumptions.timePercent);
console.log('Extracted Efficiency:', assumptions.efficiency);
var newROIpanel = createEstimatedCostSavings(0, assumptions)
// call replaceWith
currentROIpanel.replaceWith(newROIpanel);
// update the automation evaluation
// Assume visualizationContainer already exists and has the new HTML content with IDs.
// Assume stepsArray is already populated as per your example.
// --- 1. Get a reference to the visualizationContainer (if you don't have it already) ---
const visualizationContainer = Container.querySelector('.visualization-container'); // Adjust selector if needed
// --- 2. Select the specific step's Gain data you want to use for the update ---
// For this example, we'll use the Gain data from the first step in stepsArray.
// You'll need to adapt this `stepsArray[0]` to whatever logic determines the current step.
//var targetStepGain = item.Gain; // Ensure stepsArray[0] and its 'Gain' property exist
// --- 3. Update the elements within visualizationContainer using their new IDs ---
// Update Efficiency Gain Text
const efficiencyGainDiv = visualizationContainer.querySelector('#efficiencyGainText');
if (efficiencyGainDiv) {
efficiencyGainDiv.textContent = `${targetStepGain.EfficiencyGain} efficiency gain`;
// update the efficiencyLanguage
const efficiencyLanguageText = textArea.parentNode.querySelector('[id^="efficiencyLanguageText"]');
var updateEfficiencyLanguageText = getEfficiencyLanguage(hitlScore, parseInt(targetStepGain.EfficiencyGain));
efficiencyLanguageText.textContent = updateEfficiencyLanguageText;
}
// Update Reduced Labour Cost Checkbox
const reducedLabourCostCheckbox = visualizationContainer.querySelector('#reducedLabourCostCheckbox');
if (reducedLabourCostCheckbox) {
reducedLabourCostCheckbox.checked = targetStepGain.ReducedLabourCost;
}
// Update Improved Accuracy Checkbox
const improvedAccuracyCheckbox = visualizationContainer.querySelector('#improvedAccuracyCheckbox');
if (improvedAccuracyCheckbox) {
improvedAccuracyCheckbox.checked = targetStepGain.ImprovedAccuracy;
}
// Update Increased Scalability Checkbox
const increasedScalabilityCheckbox = visualizationContainer.querySelector('#increasedScalabilityCheckbox');
if (increasedScalabilityCheckbox) {
increasedScalabilityCheckbox.checked = targetStepGain.IncreasedScalability;
}
// Update Explanation Text
const explanationDiv = visualizationContainer.querySelector('#explanationText');
if (explanationDiv) {
explanationDiv.textContent = targetStepGain.Explanation;
}
console.log('Visualization container updated successfully!');
// You can inspect the DOM to confirm changes, or add more console logs for the updated values.
// UPDATE n8n generator+
var originalN8NButton = Container.querySelector('#generateN8Nbtn');
// Button element
const button = document.createElement('button');
button.id = 'generateN8Nbtn';
button.className = 'genN8Nbtn';
button.style.height = '40px';
button.style.borderRadius = '10px';
button.style.maxWidth = '300px';
button.style.padding = '0px 5px';
button.style.backgroundColor = 'white';
button.style.border = '1px solid darkgray';
// Button inner HTML
/*button.innerHTML = `
Generate n8n Workflow
`;*/
button.innerHTML = `
Find Relevant Workflows
`;
// Button click handler
/*button.addEventListener('click', function () {
GenerateN8N(item.HowTo, item.Title);
});
*/
// Button click handler
button.addEventListener('click', async function () {
// show spinner
$(this).find('#n8nSpinner').show();
//GenerateN8N(data.Flow, data.Report); // Flow and Outline renamed accordingly
//GenerateN8N(data.HowTo, data.Title);
// When user clicks "Find Relevant Workflows"
//const taskTitle = "Implement KPI tracking and reporting mechanisms";
const taskTitle = $(button).parent().find('#n8nTitle').text();
try {
const response = await findWorkflowsForTask(taskTitle, 5);
ConsoleLog('Got workflows:', response);
// Now you can do whatever you want with the results
// Display them, navigate somewhere, update the UI, etc.
var parentDiv = button.closest("[id^='_automations_holder_']");
// response.data.results contains the workflows array
displayWorkflows(response, parentDiv);
// hide spinner
$(this).find('#n8nSpinner').hide();
} catch (error) {
console.error('Failed to load workflows:', error);
// Show user-friendly error message
}
});
originalN8NButton.replaceWith(button);
var hiddenField = Container.querySelector('#document-outline-params');
var params = JSON.parse(hiddenField.value);
var SegmentIndex = params.segmentIndex;
var ActivityIndex = params.activityIndex;
var OutputIndex = params.outputIndex;
var StepIndex = params.stepIndex;
// update the generateDocumentOutline title text
var reportTitle = Container.querySelector('#document-outline-title');
// stepInfo["Report"] = data.Steps[0].Outline;
var jobObj = JSON.parse(localStorage.getItem("profile"));
reportTitle.textContent = jobObj["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Steps"][index]["Outline"]
// update the generateDocumentOutlineButton onclick
var generateDocumentOutlineButton = Container.querySelector('#generate-document-outline-button');
generateDocumentOutlineButton.onclick = function() {
GenerateDocumentOutline(params.segmentIndex, params.activityIndex, params.outputIndex, index);
};
});
/*
return p.outerHTML; // Generate HTML string for each
element
}).join('');*/
// Set the formatted response as the div's inner HTML
//textArea.innerHTML = htmlElements;
//textArea.html(htmlElements);
textArea.append(p);
titleIndex++;
});
}
function escapeHTMLAttribute(value) {
return String(value)
.replace(/&/g, '&') // First replace & to avoid double escaping
.replace(/'/g, ''') // Escape single quotes
.replace(/"/g, '"') // Escape double quotes, if necessary
.replace(//g, '>'); // Escape greater than
}
function addSpinner()
{
// Select the original animation container
var originalAnimation = $("#modal-spinner");
// Clone the animation element and its internal structure
var clonedAnimation = originalAnimation.clone(true, true);
// If necessary to avoid ID conflicts:
clonedAnimation.attr("id", "main-spinner");
/*clonedAnimation.find("*").attr("id", function() {
return $(this).attr("id") + "-new";
});*/
return clonedAnimation;
}
function SearchTools(callingElement, item, titleIndex)
{
var breakdown = item.Breakdown;
breakdown.Title = item.Title; // for appendunits
var searchValue = breakdown.Output + " > " + item.Title;
var Title = item.Title;
var searchElement = $(callingElement);
var mode = "mainPage";
ConsoleLog(searchElement);
var parentId = $(this).closest('div[id^="_steps_instructions_"]').attr('id');
var toolsHolder = searchElement.parent().nextAll('div[id^="_tools_holder_"]').first();
if (searchElement.closest('#JobSegments').length) {
// This code will run if searchElement is a descendant of the element with the ID 'JobSegments'
toolsHolder = searchElement.parent().find('div[id^="_tools_holder_"]').first();
// Do something with toolsHolder here
} else {
// This code will run if searchElement is NOT a descendant of the element with the ID 'JobSegments'
toolsHolder = searchElement.parent().nextAll('div[id^="_tools_holder_"]').first();
// Do something with toolsHolder here
}
ConsoleLog(toolsHolder);
ConsoleLog('toolsHolder: ' + toolsHolder.length);
var gridContainer = toolsHolder.find('#gridContainerTools');
var toolsSubheading = toolsHolder.find('#toolsSubheading');
toolsSubheading.text(searchElement.text());
var automationsHolder = searchElement.parent().nextAll('div[id^="_automations_holder_"]').first();
if (searchElement.closest('#JobSegments').length) {
// This code will run if searchElement is a descendant of the element with the ID 'JobSegments'
automationsHolder = searchElement.parent().find('div[id^="_automations_holder_"]').first();
// Do something with toolsHolder here
} else {
// This code will run if searchElement is NOT a descendant of the element with the ID 'JobSegments'
automationsHolder = searchElement.parent().nextAll('div[id^="_automations_holder_"]').first();
// Do something with toolsHolder here
}
var n8nTitle = automationsHolder.find('#n8nTitle');
n8nTitle.text(searchElement.text());
ConsoleLog(gridContainer);
ConsoleLog('gridContainer: ' + gridContainer.length);
gridContainer.empty();
// spinner holder
var spinnerHolder = document.createElement('div');
spinnerHolder.style.display = 'none';
spinnerHolder.style.maxHeight = '100px';
spinnerHolder.style.maxWidth = '100px';
// create spinner
//var spinner = addSpinner();
var spinner = createLottiePlayer(
"https://cdn.prod.website-files.com/6446c148837a8953093cbfeb/657793c349c01f28349a98e0_spinner.json",
100,
100
);
spinner.id = "_tools_holder_spinner";
spinnerHolder.appendChild(spinner);
// Append the cloned animation to the target container
gridContainer.append(spinnerHolder);
// Ensure Lottie library is included in your project
// Re-initialize the copied animation
// Re-initialize the copied animation
$(spinnerHolder).find("lottie-player").each(function() {
lottie.loadAnimation({
container: spinnerHolder,
renderer: "svg",
loop: true,
autoplay: true,
path: 'https://cdn.prod.website-files.com/6446c148837a8953093cbfeb/657793c349c01f28349a98e0_spinner.json'
});
});
$(spinnerHolder).show();
var apiUrl = "https://v8flgw65bg.execute-api.eu-west-1.amazonaws.com/default/AIToolSearch";
const requestData = {};
// initial search uses the long search query (this is the title of the step)
requestData["query"] = searchValue;
requestData["QueryValue"] = Title;
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
// Handle the API response here
//ConsoleLog("ShowMeHow return: " + data);
ConsoleLog('test result');
ConsoleLog(result);
result = JSON.parse(result);
//var searchResults = JSON.parse(result["body"]);
var searchResults = result;
if (searchResults.length === 0)
{
// if this does not return results we should show "No tools found"
// send empty array and it will handle it
appendUnits(searchResults, gridContainer, breakdown, titleIndex);
}
if (searchResults.length > 0)
{
appendUnits(searchResults, gridContainer, breakdown, titleIndex);
}
$(spinnerHolder).hide();
})
.catch(error =>
{
console.error('Error calling Search API:', error);
$(spinnerHolder).hide();
});
}
function safeParseProfile() {
try {
var profileData = localStorage.getItem("profile");
if (!profileData) {
console.warn("No profile data found in localStorage");
return null;
}
ConsoleLog("Raw profile data:", profileData);
ConsoleLog("Type of raw data:", typeof profileData);
var parsedData = profileData;
var parseAttempts = 0;
var maxAttempts = 5; // Prevent infinite loops
// Keep parsing until we get an object or reach max attempts
while (typeof parsedData === 'string' && parseAttempts < maxAttempts) {
ConsoleLog(`Parse attempt ${parseAttempts + 1}:`, parsedData.substring(0, 100) + "...");
parsedData = JSON.parse(parsedData);
parseAttempts++;
ConsoleLog(`After parse attempt ${parseAttempts}, type is:`, typeof parsedData);
}
if (typeof parsedData === 'object' && parsedData !== null) {
ConsoleLog("Successfully parsed profile after", parseAttempts, "attempts");
ConsoleLog("Final parsed object keys:", Object.keys(parsedData));
return parsedData;
} else {
console.error("Failed to parse profile to object after", maxAttempts, "attempts");
return null;
}
} catch (error) {
console.error("Error parsing profile:", error);
return null;
}
}
function getWorkCategoriesFromProfile() {
try {
// Get the stored job profile with safe parsing
var jobObj = safeParseProfile();
if (!jobObj || !jobObj.JobSegments) {
console.warn("No job profile or job segments found");
return [];
}
var workCategories = [];
// Debug: log the full profile structure
ConsoleLog("Full profile for debugging:", jobObj);
// Iterate through all job segments
jobObj.JobSegments.forEach(function(segment) {
if (segment.Activities && Array.isArray(segment.Activities)) {
// Iterate through all activities in each segment
segment.Activities.forEach(function(activity) {
ConsoleLog("Processing activity:", activity);
// Make sure we're getting TypeOfWork, not other fields
if (activity.TypeOfWork && activity.TypeOfWork.trim() !== "") {
var typeOfWork = activity.TypeOfWork.trim();
// Add to array if it's not already included (case-insensitive check)
var alreadyExists = workCategories.some(function(category) {
return category.toLowerCase() === typeOfWork.toLowerCase();
});
if (!alreadyExists) {
workCategories.push(typeOfWork);
ConsoleLog("Added work category:", typeOfWork);
}
} else {
ConsoleLog("No TypeOfWork found in activity:", Object.keys(activity));
}
});
}
});
ConsoleLog("Final work categories:", workCategories);
return workCategories;
} catch (error) {
console.error("Error extracting work categories from profile:", error);
return [];
}
}
// Updated SearchTools function using the new work categories extraction
function SearchTools_Weighted(callingElement, item, titleIndex) {
var breakdown = item.Breakdown;
breakdown.Title = item.Title; // for appendunits
var searchValue = breakdown.Output + " > " + item.Title;
var Title = item.Title;
var searchElement = $(callingElement);
var mode = "mainPage";
ConsoleLog(searchElement);
var toolsHolder = callingElement;
/*var toolsHolder = searchElement.parent().find('div[id^="_tools_holder_"]').first();
if (searchElement.closest('#JobSegments').length) {
// 1. Run this if '#JobSegments' is a close ancestor.
toolsHolder = searchElement.parent().find('div[id^="_tools_holder_"]').first();
if (!toolsHolder.length) {
toolsHolder = searchElement.parent().find('div[id^="_job_tools_holder_"]').first();
}
} else {
// 2. Otherwise (if condition 1 is false), try this first assignment.
toolsHolder = searchElement.parent().nextAll('div[id^="_tools_holder_"]').first();
// 3. ONLY if the second assignment failed (toolsHolder is empty/has a length of 0),
// then run the final assignment.
if (!toolsHolder.length) {
toolsHolder = searchElement.parent().find('div[id^="_job_tools_holder_"]').first();
}
}*/
ConsoleLog(toolsHolder);
ConsoleLog('toolsHolder: ' + toolsHolder.length);
//var gridContainer = toolsHolder.find('#gridContainerTools');
var gridContainer = toolsHolder.find('#gridContainerJobTools');
ConsoleLog(gridContainer);
ConsoleLog('gridContainer: ' + gridContainer.length);
gridContainer.empty();
// spinner holder
var spinnerHolder = document.createElement('div');
spinnerHolder.style.display = 'none';
spinnerHolder.style.maxHeight = '100px';
spinnerHolder.style.maxWidth = '100px';
// create spinner
var spinner = createLottiePlayer(
"https://cdn.prod.website-files.com/6446c148837a8953093cbfeb/657793c349c01f28349a98e0_spinner.json",
100,
100
);
spinner.id = "_tools_holder_spinner";
spinnerHolder.appendChild(spinner);
// Append the cloned animation to the target container
gridContainer.append(spinnerHolder);
// Re-initialize the copied animation
$(spinnerHolder).find("lottie-player").each(function() {
lottie.loadAnimation({
container: spinnerHolder,
renderer: "svg",
loop: true,
autoplay: true,
path: 'https://cdn.prod.website-files.com/6446c148837a8953093cbfeb/657793c349c01f28349a98e0_spinner.json'
});
});
$(spinnerHolder).show();
// Get job profile data for new API structure
var jobObj = safeParseProfile();
var jobTitle = jobObj["JobTitle"];
var industryTitle = jobObj["Industry"] || jobObj["IndustryTitle"] || "";
// Extract work categories from the profile using the new function
var workCategories = getWorkCategoriesFromProfile();
// If no work categories found, fall back to using breakdown data
if (workCategories.length === 0) {
workCategories = [];
if (breakdown.Output) {
workCategories.push(breakdown.Output);
}
if (item.Title && item.Title !== breakdown.Output) {
workCategories.push(item.Title);
}
if (workCategories.length === 0) {
workCategories.push(searchValue);
}
}
var apiUrl = "https://ylmsn1rch3.execute-api.eu-west-1.amazonaws.com/default/AIRecommender";
const requestData = {
jobTitle: jobTitle,
industry: industryTitle,
workCategories: workCategories,
maxResults: {
universal: 5,
specialized: 10
}
};
ConsoleLog("Request data for new API:", requestData);
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
.then(response => response.text())
.then(result => {
ConsoleLog('test result');
ConsoleLog(result);
result = JSON.parse(result);
var searchResults = result;
if (searchResults.length === 0) {
appendUnits(searchResults, gridContainer, breakdown, titleIndex);
} else {
appendUnits(searchResults, gridContainer, breakdown, titleIndex);
}
$(spinnerHolder).hide();
})
.catch(error => {
console.error('Error calling Search API:', error);
$(spinnerHolder).hide();
});
}
/**
* FormatText - this method formats the text that is used by PreFormatTextAreaText. It replaces text formatting with html encoding
* @param textToFormat
* @returns
*/
function FormatText(textToFormat)
{
// Process the formatted text
const formattedContent = textToFormat
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/\n\n/g, ' ') // Preserve double line breaks as paragraphs
.replace(/\n(-|\d+\.) /g, ' • ') // Convert bullet lists
.replace(/\n(\d+\.) /g, ' # ') // Convert numbered lists
return formattedContent;
}
function tryParse(str)
{
try {
var returnObj = JSON.parse(str);
return returnObj;
}
catch (error)
{
ConsoleLog(error.message);
return {};
}
return {};
}
function MYPEASCallback(response) {
// Handle successful reCAPTCHA response
ConsoleLog("response: ",JSON.stringify(response));
// set hidden field to response
document.getElementById('hcv').value = response;
ConsoleLog("reCAPTCHA verified successfully");
// Optionally, you can disable the submit button here
const recaptchaStatusElement = document.getElementById('recaptcha-accessible-status');
const recaptchaStatusText = recaptchaStatusElement.textContent;
ConsoleLog(recaptchaStatusText); // Output: You are verified
function clearInput() {
document.getElementById('hcv').value = '';
}
setTimeout(clearInput, 55 * 1000);
}
function GenerateDocumentOutline(SegmentIndex, ActivityIndex, OutputIndex, StepIndex)
{
// NOTES
// 1)
// 2) StepIndex is to show which step in the overall Output/Task we are on. Each Step has several parts (seen in HowTo property) - we're calling them tasks now
// show generate document outline modal
OpenDocumentOutlineModal();
// create a fetch to request the document outine
var profile = localStorage.getItem("profile");
var maxParseAttempts = 10; // Maximum allowed parsing attempts
while (typeof profile === 'string' && maxParseAttempts > 0)
{
try
{
profile = JSON.parse(profile);
} catch (error)
{
console.error("Error parsing profile:", error);
break; // Exit loop on parsing failure
}
maxParseAttempts--;
}
//profile = JSON.parse(profile);
var MYPEAS_payload = {};
MYPEAS_payload["OutlineData"] = {};
MYPEAS_payload["JobTitle"] = profile["JobTitle"]; // use profile
MYPEAS_payload["JobDescriptionSummary"] = profile["JobDescriptionSummary"];// use profile
MYPEAS_payload["Title"] = profile["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Title"];
MYPEAS_payload["SegmentTitle"] = profile["JobSegments"][SegmentIndex]["Name"] || "";
MYPEAS_payload["Activity"] = profile["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Title"] + ": " + profile["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Description"] || "";
MYPEAS_payload["CurrentTask"] = profile["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Outline"]
// MYPEAS_payload["TaskSummary"];
var tasks = profile["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Steps"][StepIndex]["HowTo"];
var numberedList = "";
if(tasks)
{
tasks.forEach(function(task, index) {
numberedList += (index + 1) + ". " + task.Title + "\n";
});
}
MYPEAS_payload["ListOfSteps"] = numberedList;
ConsoleLog("ListOfSteps: " + numberedList);
//MYPEAS_payload["Report"] = profile["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Steps"][StepIndex]["Output"] + ": " + profile["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Steps"][StepIndex]["Outline"] || "";
MYPEAS_payload["Report"] = profile["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Steps"][StepIndex]["Outline"] || "";
ConsoleLog("Report: " + MYPEAS_payload["Report"]);
MYPEAS_payload["promptDescription"] = "CreateDocumentOutline";
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// switch to processing UI
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("result (object): ", result); // result (object): {"message":"processing"}
ConsoleLog("result (stringified): ", JSON.stringify(result)); // "{\"message\":\"processing\"}"
var message = result["message"];
var generatedDocument = "";
// show copy text
$('#copy-document-outline').show();
switch(message)
{
case "Completed: Generated Document Outline":
generatedDocument = result["document"];
// change title - hide this title when the content has generated
$('#generate-document-outline-modal #modal-title').hide();
// store document outline in hidden field
$('#generatedDocumentStore').val(generatedDocument);
interpretAndDisplayFormattedText(generatedDocument, 'document-outline');
// hide loading
$('#document-outline-loading').hide();
// show text area
$('#document-outline').show();
break;
case "Failed":
// change title - hide this title when the content has generated
$('#generate-document-outline-modal #modal-title').hide();
// show fail message
var failMessage = "Unfortunately there was a problem generating your document outline. Please try again later.";
// store document outline in hidden field
$('#generatedDocumentStore').val(failMessage);
interpretAndDisplayFormattedText(failMessage, 'document-outline');
// hide loading
$('#document-outline-loading').hide();
// show text area
$('#document-outline').show();
break;
}
})
.catch(error => console.error("Error calling generating document outline ", error));
}
function copyHiddenFieldValue(id) {
const hiddenField = document.getElementById(id);
// Create temporary textarea
const tempTextArea = document.createElement('textarea');
tempTextArea.value = hiddenField.value;
document.body.appendChild(tempTextArea);
// Select and copy
tempTextArea.select();
tempTextArea.setSelectionRange(0, 99999); // For large text
navigator.clipboard.writeText(tempTextArea.value)
.then(() => {
alert('Value copied to clipboard!');
})
.catch(err => {
console.error('Error copying value: ', err);
});
// Cleanup
document.body.removeChild(tempTextArea);
}
function interpretAndDisplayFormattedText(text, outputElementId) {
const lines = text.split("\n");
const outputElement = document.getElementById(outputElementId);
outputElement.innerHTML = ""; // Clear existing content
lines.forEach(line => {
if (line.startsWith("#")) {
// Heading
const level = line.indexOf(" ");
const headingTag = "h" + level;
const headingText = line.substring(level + 1);
const headingElement = document.createElement(headingTag);
headingElement.textContent = headingText;
outputElement.appendChild(headingElement);
} else if (line.startsWith("##")) {
// Subheading
const level = line.indexOf(" ");
const subheadingTag = "h" + (level + 1);
const subheadingText = line.substring(level + 1);
const subheadingElement = document.createElement(subheadingTag);
subheadingElement.textContent = subheadingText;
outputElement.appendChild(subheadingElement);
} else {
// Paragraph
const paragraphElement = document.createElement("p");
paragraphElement.textContent = line;
outputElement.appendChild(paragraphElement);
}
});
}
function OpenDocumentOutlineModal()
{
// hide copy text until generated
$('#copy-document-outline').hide();
// change title
$('#generate-document-outline-modal #modal-title').text('Generating').show();
// show loading
$('#document-outline-loading').show();
// hide text area
$('#document-outline').hide();
// animate and show
$('#generate-document-outline-modal').animate({ opacity: 1 }).show();
}
function CloseDocumentOutlineModal()
{
$('#generate-document-outline-modal').animate({ opacity: 0 }).hide();
unLockScroll();
}
// testing data
function fetchJobDataByDropdown() {
const dropdown = document.getElementById('industryDropdown'); // Assuming a dropdown for file selection
const selectedFile = dropdown.value;
// Build the file path (adjust if needed)
/*
https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/66380fed89e302cbe0625885_job_descriptions_Technology.txt
https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/66380fedfe9c515569526d3f_job_descriptions_Finance.txt
https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/66380feda3042435a77d2bcc_job_descriptions_Professional_Services.txt
https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/66380fec2dbc956063f40c7d_job_descriptions_healthcare.txt
*/
var filePath = 'data/' + selectedFile + '.txt';
//https://www.mypeas.ai/data/job_descriptions_healthcare.txt.txt
switch(selectedFile)
{
case "job_descriptions_Technology.txt":
filePath = "https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/66380fed89e302cbe0625885_job_descriptions_Technology.txt";
break;
case "job_descriptions_Finance.txt":
filePath = "https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/66380fedfe9c515569526d3f_job_descriptions_Finance.txt";
break;
case "job_descriptions_Professional_Services.txt":
filePath = "https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/66380feda3042435a77d2bcc_job_descriptions_Professional_Services.txt";
break;
case "job_descriptions_healthcare.txt":
filePath = "https://uploads-ssl.webflow.com/6446c148837a8953093cbfeb/66380fec2dbc956063f40c7d_job_descriptions_healthcare.txt";
break;
}
fetch(filePath)
.then(response => response.text())
.then(data => processData(data))
.catch(error => console.error('Error fetching data:', error));
}
function processData(data) {
// Clean up formatting (remove newlines etc.)
const cleanedData = data.replace(/\n/g, ' '); // Replace newlines with spaces
// Parse the JSON array
const jobArray = JSON.parse(cleanedData);
// Make the job data accessible globally (modify if needed)
window.jobData = jobArray;
// Now it's ready to populate your dropdown
populateDropdown();
}
function populateDropdown() {
const dropdown = document.getElementById('jobDropdown');
// Clear existing options
dropdown.innerHTML = '';
// Add the "Select Job" option first
const defaultOption = document.createElement('option');
defaultOption.value = ''; // Empty value for default option
defaultOption.text = 'Select Job';
dropdown.appendChild(defaultOption);
// Add new options
for (const job of window.jobData) {
const option = document.createElement('option');
option.value = job.jobTitle;
option.text = job.jobTitle;
dropdown.appendChild(option);
}
dropdown.addEventListener('change', () => {
updateTextFields();
});
}
function updateTextFields() {
const selectedJobTitle = document.getElementById('jobDropdown').value;
const selectedJob = window.jobData.find(job => job.jobTitle === selectedJobTitle);
var formContainer = document.getElementById('Form-container');
//ConsoleLog(JSON.stringify(selectedJob));
//ConsoleLog(JSON.stringify(selectedJob.jobDescription));
formContainer.querySelector('#jobTitle').value = selectedJob.jobTitle;
formContainer.querySelector('#jobDescription').value = selectedJob.jobDescription;
}
function isTestModeEnabled() {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get('testmode') === 'true';
}
function isWaitModeEnabled() {
// Check query string first
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('waitmode') === 'true') {
return true;
}
// Check localStorage if query string doesn't have it
if (localStorage.getItem('waitmode')) { // Assumes any value in localStorage means enabled
return true;
}
// If neither query string nor localStorage have it
return false;
}
function showUnlocked()
{
if (localStorage.getItem('waitmode'))
{
// Assumes any value in localStorage means enabled
// hide
$('#btnJoinWaitlist').hide();
$('#join-waitlist-bottom').hide();
$('#waitlist-container').hide();
$('#invite-launcher').hide();
$('#skipwaitlist-container').hide();
// show
$('#btnGetStarted').show().css('display', 'block');
$('#get-started-free').show().css('display', 'block');
$('#Form-container').show();
}
}
function UploadBookingRequests()
{
const transformedBookingRequests = [
{
interest: ['Technology', 'Design'],
country: 'USA',
locationPreference: 'New York City',
budget: '20003000',
primaryGoal: ['Website Redesign'],
servicesNeeded: ['Web Development', 'UX Design'],
specificNeeds: 'Need a modern and responsive design',
contactDetails: {
firstName: 'John',
surname: 'Doe',
email: 'john.doe@example.com',
telephone: '+1234567890'
},
agreeToTerms: true
},
{
interest: ['Marketing', 'Branding'],
country: 'USA',
locationPreference: 'Los Angeles',
budget: '5000',
primaryGoal: ['Branding and Marketing'],
servicesNeeded: ['Graphic Design', 'Social Media Strategy'],
specificNeeds: 'Focus on social media presence',
contactDetails: {
firstName: 'Jane',
surname: 'Smith',
email: 'jane.smith@example.com',
telephone: '+1234567891'
},
agreeToTerms: true
},
{
interest: ['E-commerce', 'Technology'],
country: 'France',
locationPreference: 'Paris, France',
budget: '30005000',
primaryGoal: ['E-commerce Website'],
servicesNeeded: ['Web Development', 'Payment Integration'],
specificNeeds: 'Multi-language support needed',
contactDetails: {
firstName: 'Pierre',
surname: 'Dupont',
email: 'pierre.dupont@example.com',
telephone: '+33123456789'
},
agreeToTerms: true
},
{
interest: ['Mobile Development', 'User Experience'],
country: 'Germany',
locationPreference: 'Berlin, Germany',
budget: '4000',
primaryGoal: ['Mobile App Development'],
servicesNeeded: ['iOS Development', 'Android Development', 'UI/UX'],
specificNeeds: 'Seamless user experience required',
contactDetails: {
firstName: 'Hans',
surname: 'Müller',
email: 'hans.muller@example.com',
telephone: '+491234567890'
},
agreeToTerms: true
},
{
interest: ['Video Production', 'Marketing'],
country: 'Italy',
locationPreference: 'Rome, Italy',
budget: '25004000',
primaryGoal: ['Promotional Video'],
servicesNeeded: ['Videography', 'Editing', 'Motion Graphics'],
specificNeeds: 'High-quality promotional video',
contactDetails: {
firstName: 'Luca',
surname: 'Rossi',
email: 'luca.rossi@example.com',
telephone: '+390123456789'
},
agreeToTerms: true
}
];
const apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
transformedBookingRequests.forEach(profile => {
const LeadData = {
UserId: profile.contactDetails.email, // Using email as memberID
LeadValue: profile, // Using the profile object as lead value
LeadCount: 0 // Start count at 0, max 3
};
const requestData = {
LeadData: LeadData
};
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData)
})
.then(response => response.json())
.then(result => {
ConsoleLog("Request Lead return: ", JSON.stringify(result));
})
.catch(error => {
console.error("Error: ", error);
});
});
}
/*
User has requested new search from current profile but server has determined insufficient credit
Restore dashboard/profile
*/
function ProcessingRequestShowUX()
{
// undo hide main profile content
$('#segments-and-activities').show();
// hide processing containter
$('#processing-container').hide();
$('#hero-holder').show();
$('.hcv-container').show();
$('#background-image-hero').show();
}
function ClearExistingProfile()
{
// $('#segments-and-activities')
$('#JobSegments').empty();
$('#JobActivities').empty();
$('#ExpandedView').empty();
}
function RejectHomepageSearch()
{
// hide formcontainer
$('#Form-container').show();
// hide waitlistcontainer
$('#waitlist-container').show();
// hide learn more
$('#learn-more-container').show();
// hide invite launcher
$('#invite-launcher').show();
// show processing containter
// add email to processing email field
$('#CheckStatusAddress').text("");
$('#processing-container').hide();
// hide background video
$('.background-video').show();
$('.background-video-agency').show();
// hide buttons
$('#button-box').show();
}
function getRevisionCount(revisions) {
if (typeof revisions === 'string' && revisions.trim() !== '') {
// Safely parse the string; if invalid, return 0
const parsedRevisions = parseInt(revisions, 10);
return isNaN(parsedRevisions) ? 0 : parsedRevisions;
} else {
// Handle cases where revisions is not a string or is empty
return 0;
}
}
var checkStatusIntervalId; // Global variable to hold the interval ID
var attempts = 0; // Global variable to track attempts
var timeoutId; // Global variable to hold the timeout ID
function startCheckStatusIntervals() {
// Initial delay of 2 minutes
timeoutId = setTimeout(function() {
ConsoleLog("timeout called " + (attempts + 1) + " times");
CheckStatus();
attempts++;
// Set up interval to call every 1 minute
checkStatusIntervalId = setInterval(function() {
CheckStatus();
attempts++;
// Check if we've reached the maximum attempts
if (attempts >= 5) {
stopCheckStatusIntervals(); // Stop calling the function after 5 times
}
}, 60 * 1000); // 60 seconds * 1000 milliseconds
}, 2 * 60 * 1000); // 2 minutes * 60 seconds * 1000 milliseconds
ConsoleLog("called startCheckStatusIntervals - timeoutID");
}
function stopCheckStatusIntervals() {
if (checkStatusIntervalId) {
clearInterval(checkStatusIntervalId);
checkStatusIntervalId = null; // Reset the interval ID
}
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = null; // Reset the timeout ID
}
}
// Function to pick a random element from an array
function getRandomUrl(urlOptions) {
// Use Math.random() to generate a random index between 0 and array length - 1
const randomIndex = Math.floor(Math.random() * urlOptions.length);
// Return the URL at the randomly chosen index
return urlOptions[randomIndex];
}
function goToLinkedIn(event) {
event.preventDefault();
if(!$('#linkedin-modal').is(':visible'))
{
$('#linkedin-modal').animate({ opacity: 100 }).show();
}
// Replace with your desired LinkedIn URL
//window.location.href = "https://www.linkedin.com";
// Define your URL options
var urlOptions = ["https://www.linkedin.com/feed/update/urn:li:activity:7238607025440452611/", "https://www.linkedin.com/feed/update/urn:li:activity:7238607031237050368/", "https://www.linkedin.com/feed/update/urn:li:activity:7238607028020023296/", "https://www.linkedin.com/feed/update/urn:li:activity:7238607022810681344/", "https://www.linkedin.com/feed/update/urn:li:activity:7238846154975686657", "https://www.linkedin.com/feed/update/urn:li:activity:7238846427592814592"];
// Get a random URL from the array
const randomUrl = getRandomUrl(urlOptions);
// Open the randomly chosen URL in a new tab
window.open(randomUrl, '_blank');
// add to localstorage
localStorage.setItem("requestedAccess", true);
// call getAccess if accessCode not visible
if(!$('#accessCode').is(':visible'))
{
getAccess();
}
}
function redeemMode(mode)
{
switch(mode)
{
case "linkedin":
// change the link buttom
$('#linkLinkedIn').hide();
$('#linkWaitlist').show();
// hide the email field and label
$('#labelRedeemEmail').hide();
$('#txtRedeemEmail').hide();
// open redeem-invitation-modal
$('#invite-launcher').click();
break;
case "waitlist":
$('#linkWaitlist').hide();
$('#linkLinkedIn').show();
// show the email field and label
$('#labelRedeemEmail').show();
$('#txtRedeemEmail').show();
// open redeem-invitation-modal
$('#invite-launcher').click();
break;
}
}
function getAccess()
{
// access-spinner
var showSpinner = function(){
$('#linkedin-modal #access-spinner').show();
var showCode = function(){
$('#linkedin-modal #access-spinner').hide();
// set the value
var accessCode = generateRandomString(8);
$('#linkedin-modal #accessCode').val(accessCode);
$('#skipwaitlist-container #accessCode').val(accessCode);
$('#linkedin-modal #accessCodeHolder').show();
localStorage.setItem("accessCode", accessCode);
// hide linkedin button
$('#linkedin-modal #goToLinkedinHolder').hide();
// hide 'i have an access code'
$('#linkedin-modal #launch-invite-moda-access').hide();
// hide already added
$('#linkedin-modal #already-commented-link').hide();
// hide waitlist advice text
$('#list-counter-popup').hide();
$('#linkedin-message').hide();
};
setTimeout(showCode, 2000);
};
// show in 3 seconds
setTimeout(showSpinner, 5000);
}
function UseCode(event)
{
event.preventDefault();
// store in localstorage
localStorage.setItem("waitmode", "unlocked");
// turn off joinwaitilist
if (isWaitModeEnabled())
{
// show
// hide
$('#btnJoinWaitlist').hide();
$('#join-waitlist-bottom').hide();
$('#waitlist-container').hide();
$('#invite-launcher').hide();
$('#skipwaitlist-container').hide();
// show
$('#btnGetStarted').show().css('display', 'block');
$('#get-started-free').show().css('display', 'block');
$('#Form-container').show();
}
// close modal
$('#redeem-invitation-modal').animate({ opacity: 0 }).hide();
$('#linkedin-modal').animate({ opacity: 0 }).hide();
unLockScroll();
// scroll to start of form
/*$('html, body').animate({
scrollTop: $('#wf-form-chatgptForm').offset().top - 95
}, 500);*/
$('html, body').animate({
scrollTop: $('#Form-container').offset().top - 95
}, 500);
}
function alreadyCommented()
{
// hide linkedin button
$('#goToLinkedinHolder').hide();
// hide 'i have an access code'
$('#launch-invite-moda-access').hide();
}
function identifyInAppBrowser() {
const userAgent = navigator.userAgent.toLowerCase();
if (userAgent.includes('fban/')) {
return 'Facebook';
} else if (userAgent.includes('instagram')) {
return 'Instagram';
} else if (userAgent.includes('twitter')) {
return 'Twitter';
} else if (userAgent.includes('whatsapp')) {
return 'WhatsApp';
} else if (userAgent.includes('tiktok')) {
return 'TikTok';
} else if (userAgent.includes('linkedin')) {
return 'LinkedIn';
} else if (userAgent.includes('chrome/') && !userAgent.includes('crios/')) {
return 'Chrome (in-app)';
} else if (userAgent.includes('pinterest')) {
return 'Pinterest';
} else if (userAgent.includes('reddit')) {
return 'Reddit';
} else {
return 'Unknown or other browser';
}
}
/*const inAppBrowser = identifyInAppBrowser();
console.log(inAppBrowser);*/
/* Admin Page code */
function isAdminPage()
{
if(window.location.href.toLowerCase().includes('/admin'))
{
return true;
}
return false;
}
function generateAccessCodeURL() {
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let accessCode = "";
const length = 16; // Adjust this for desired access code length
for (let i = 0; i < length; i++) {
accessCode += characters.charAt(Math.floor(Math.random() * characters.length));
}
const urlToShare = 'https://mypeas.ai?access=' + accessCode;
var replyOptions = ["Thanks for your interest in MYPEAS! Here's your personal access link: [URL].","Appreciate your comment. Check out MYPEAS here: [URL].","Welcome to the MYPEAS community! Your personal access link is: [URL]. Let us know if you have any questions.","Glad you're interested in MYPEAS. Explore the product with this link: [URL]. Enjoy!","Hey there, thanks for reaching out! Your personalized access link for MYPEAS is: [URL]. ","Hey there! We're excited to have you join us. Your access link for MYPEAS is: [URL].","Excited you're interested in MYPEAS. Your personal access link is: [URL].","Thanks for your comment. Let's get you started with MYPEAS. Your link: [URL].","Welcome to the world of MYPEAS! Your personal access link is: [URL]. Explore and enjoy.","Ready to experience MYPEAS? Your personal access link is: [URL]. Start now.","Hey there! We're thrilled you're interested in MYPEAS. Your link is: [URL].","Welcome to the MYPEAS family! Your personal access link is: [URL]. Let's create something amazing together."];
// Select a random reply option
const randomIndex = Math.floor(Math.random() * replyOptions.length);
const messageReply = replyOptions[randomIndex];
// Replace [URL] with urlToShare
const finalMessage = messageReply.replace("[URL]", urlToShare);
// Assuming "accessCode" element exists in your HTML
document.getElementById("accessCode").value = finalMessage;
}
function copyToClipboard_Access() {
const accessCode = document.getElementById("accessCode").value;
navigator.clipboard.writeText(accessCode)
.then(() => {
alert("Copied to clipboard!");
})
.catch(() => {
alert("Failed to copy to clipboard!");
});
}
function submitAdminEmails()
{
const sendButton = document.getElementById('sendButton');
const emailInput = document.getElementById('emails');
const adminEmailsHolder = document.getElementById('admin-account-send-email');
const adminEmailMessage = adminEmailsHolder.querySelector('#modal-message');
const emailString = emailInput.value;
// Regular expression to validate email addresses
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
// Split the email string into individual addresses
const emailArray = emailString.split(',');
// Validate each email address
//const isValid = emailArray.every(email => emailRegex.test(email));
var invalidEmails = [];
var validEmails = [];
// Validate each email address and create an array of invalid emails
emailArray.every(email => {
if (emailRegex.test(email)) {
validEmails.push(email); // Add valid email to the validEmails array
} else {
invalidEmails.push(email); // Add invalid email to the invalidEmails array
}
});
// Output a string with invalid and valid emails
console.log("Invalid emails: ", JSON.stringify(invalidEmails));
console.log("Valid emails: ", JSON.stringify(validEmails));
if(invalidEmails.length > 0)
{
$(adminEmailMessage).text('Invalid email addresses: ',JSON.stringify(invalidEmails));
}
else
{
if(validEmails.length > 0)
{
// send to server
$(adminEmailMessage).text('');
var MYPEAS_payload = {};
MYPEAS_payload["requestDescription"]= "RecruitAgency";
MYPEAS_payload["emails"] = JSON.stringify(validEmails);
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://v2tu3f9o1e.execute-api.eu-west-1.amazonaws.com/AgencyStage/Agency';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
var message = result["message"];
switch(message)
{
// user is validated
case "Sent emails":
$(adminEmailMessage).text("Emails Sent Successfully");
break;
case "Failed":
$(adminEmailMessage).text(result["errorMsg"]);
break;
}
});
}
else
{
$(adminEmailMessage).text('Enter a valid email address');
}
}
}
function MetaTrackEvent(EventName)
{
try
{
//MetaTrackEvent("CompleteRegistration");
fbq('track', EventName);
}
catch(error)
{
console.error('Error tracking CompleteRegistration event:', error);
}
}
function createButton(imageSrc, label) {
const button = document.createElement('button');
button.classList.add('toolsAdvice');
// Create an image element
const image = document.createElement('img');
image.src = imageSrc;
image.alt = label; // Provide an appropriate alt text for accessibility
image.style.height = '20px'; // Set the image height to 10px
// Create a text node for the label
const textNode = document.createTextNode(label);
//
// spinner
var spinner = document.createElement('span');
spinner.classList.add('spinner-black');
spinner.id = "spinner";
spinner.style.display = 'none';
// Append the image and text node to the button
button.appendChild(image);
button.appendChild(textNode);
button.appendChild(spinner);
// Apply styles to the button
button.style.height = '40px';
button.style.borderRadius = '10px';
button.style.maxWidth = '300px';
button.style.padding = '0 5px';
button.style.backgroundColor = 'white';
button.style.border = '1px solid darkgray';
return button;
}
function addSpinner_Advice()
{
// Select the original animation container
const originalAnimation = document.getElementById('modal-spinner');
// Clone the animation element
const clonedAnimation = originalAnimation.cloneNode(true);
return clonedAnimation;
}
function CreateToolsInfo(searchResults) {
var toolsCollection = [];
// Handle both formats of search results
let processedResults = [];
// Check if searchResults has specialized/universal structure
if (searchResults?.data?.specialized && searchResults?.data?.universal) {
// New format: combine specialized and universal arrays
//processedResults = [...searchResults.data.specialized, ...searchResults.data.universal];
processedResults = [...searchResults.data.universal, ...searchResults.data.specialized];
// Transform to match expected format (add metadata wrapper if needed)
processedResults = processedResults.map(item => {
let screenshot = item.screenshot || '';
// If no screenshot, check for s3_image_url
if (!screenshot) {
screenshot = item.s3_image_url || '';
}
// If still no image, use fallback based on source array
if (!screenshot) {
// Check if this item came from specialized array
const isSpecialized = searchResults.data.specialized.some(specializedItem =>
specializedItem.url === item.url || specializedItem.name === item.name
);
screenshot = isSpecialized
? "https://flexluthor.s3.eu-west-2.amazonaws.com/meta-images/tools-specialized.png"
: "https://flexluthor.s3.eu-west-2.amazonaws.com/meta-images/tools-universal.png";
}
return {
metadata: {
screenshot: screenshot,
name: item.name,
task: item.category, // or item.task if available
useCase: item.useCase,
siteUrl: item.url,
description: item.description
}
};
});
} else {
// Original format: use as-is
processedResults = searchResults;
}
processedResults.forEach((searchResult, index) => {
//searchResults.forEach((searchResult, index) => {
var item = searchResult['metadata'];
let tool = {};
tool["description"] = item["description"];
tool["name"] = item["name"];
tool["group"] = item["group"];
tool["useCase"] = item["useCase"];
tool["index"] = index; // Use the index from the forEach loop
toolsCollection.push(tool);
});
return toolsCollection;
}
function PreFormatTextAreaText_advice(adviceText, textArea)
{
textArea.innerHTML = "";
adviceText.map((item, index) => {
// title
var adviceTitle = document.createElement("p");
adviceTitle.style.cursor = "pointer";
adviceTitle.style.textDecoration = "underline";
adviceTitle.style.padding = "5px";
adviceTitle.style.margin = "5px";
adviceTitle.style.borderRadius = "5px";
adviceTitle.className = "tools_advice_title_" + index;
adviceTitle.textContent = item.name;
// Add the click event listener
adviceTitle.addEventListener("click", () => {
// launch appmodal
//$(textArea) find next instance of a div with class grid-wrapper. then find the collection of elements in that with class grid-item
let gridindex = parseInt(item.index);
$(textArea).prevAll('div.grid-wrapper').first().find('.grid-item').eq(gridindex).find('h4').eq(0).click();
});
// Construct the advice text
// Create the
element
const p = document.createElement("p");
p.style.cursor = "pointer";
//p.style.textDecoration = "underline";
p.style.padding = "5px";
p.style.margin = "5px";
p.style.borderRadius = "5px";
p.className = "tools_advice_" + index;
p.textContent = item.reason;
textArea.append(adviceTitle);
textArea.append(p);
});
}
function createLottiePlayer(src, width, height, loop = true, autoplay = true) {
// Create the Lottie player element
const player = document.createElement('lottie-player');
// Set attributes
player.setAttribute('src', src);
player.setAttribute('background', 'transparent');
player.setAttribute('speed', 1);
player.style.width = width + 'px';
player.style.height = height + 'px';
// Set loop and autoplay options
player.loop = loop;
player.autoplay = autoplay;
// Append the player to the body (you can change this to append to a specific element)
//document.body.appendChild(player);
return player;
}
function createThickRule()
{
var hr = document.createElement('hr');
// Style the HR element
hr.style.borderTop = '2px solid #ccc'; // Adjust color as needed
hr.style.borderBottom = 'none';
hr.style.margin = '10px 0'; // Adjust margin as needed
return hr;
}
function showUpgradeTable() {
document.getElementById('free-table').style.display = 'none';
document.getElementById('upgrade-table').style.display = 'block';
}
function showFreeTable() {
document.getElementById('free-table').style.display = 'block';
document.getElementById('upgrade-table').style.display = 'none';
}
// section-button code
// Function to handle button selection
function selectButton(selectedId) {
const buttons = document.querySelectorAll('.section-button');
// Loop through each button to update styles
buttons.forEach(button => {
if (button.id === selectedId) {
button.classList.add('active');
button.classList.remove('inactive');
} else {
button.classList.remove('active');
button.classList.add('inactive');
}
});
// change displayed card elements
switch(selectedId)
{
case "btnJobSegments":
// title
$('#gif_Span_Segments').show();
$('#gif_Span_Activities').hide();
$('#gif_Span_Steps').hide();
// subheading
$('#gif_subheading_segments').show();
$('#gif_subheading_activities').hide();
$('#gif_subheading_steps').hide();
// subheading 2
$('#gif_subheading_activities_2').hide();
$('#gif_subheading_steps_2').hide();
// gif + pics
$('#gif_segments').show();
$('#gif_activities').hide();
$('#gif_steps').hide();
// gif + pics 2
$('#gif_activities_2').hide();
$('#gif_steps_2').hide();
break;
case "btnJobActivities":
// title
$('#gif_Span_Segments').hide();
$('#gif_Span_Activities').show();
$('#gif_Span_Steps').hide();
// subheading
$('#gif_subheading_segments').hide();
$('#gif_subheading_activities').show();
$('#gif_subheading_steps').hide();
// subheading 2
$('#gif_subheading_activities_2').show();
$('#gif_subheading_steps_2').hide();
// gif + pics
$('#gif_segments').hide();
$('#gif_activities').show();
$('#gif_steps').hide();
// gif + pics 2
$('#gif_activities_2').show();
$('#gif_steps_2').hide();
break;
case "btnJobSteps":
// title
$('#gif_Span_Segments').hide();
$('#gif_Span_Activities').hide();
$('#gif_Span_Steps').show();
// subheading
$('#gif_subheading_segments').hide();
$('#gif_subheading_activities').hide();
$('#gif_subheading_steps').show();
// subheading 2
$('#gif_subheading_activities_2').hide();
$('#gif_subheading_steps_2').show();
// gif + pics
$('#gif_segments').hide();
$('#gif_activities').hide();
$('#gif_steps').show();
// gif + pics 2
$('#gif_activities_2').hide();
$('#gif_steps_2').show();
break;
}
}
function OpenInfoModal(sectionName)
{
CreateInfoModal();
// hide all images
// hide all images 2
$('#info-modal .legend-image').hide();
// hide all content headings
$('#info-modal .info-content-heading').hide();
// hide all subheading 2
$('#info-modal .info-content-subheading').hide();
switch(sectionName)
{
case "Segments":
// set title
$('#info-modal #infoHeading').text("Job Segments");
// set subheading
$('#info-modal #infoSubheading').text("Segments represent the main components of your job role, giving you a high-level view of how your responsibilities are organized. Each segment outlines a key area in which you might apply AI, from project management to data analysis, helping you quickly identify where AI can assist. By understanding these segments, you can better prioritize your efforts and focus on areas where AI tools may have the greatest impact.");
// show relevant content
$('#info-modal #gif_Span_Segments').show();
$('#info-modal #gif_subheading_segments').show();
$('#info-modal #gif_segments').show();
break;
case "Activities":
// set title
$('#info-modal #infoHeading').text("Your Activities");
$('#info-modal #infoSubheading').text("Activities break down each segment into specific tasks that you handle regularly, providing more detail about the processes within your role. By seeing your job divided into distinct activities, you can pinpoint the parts of your workflow that could benefit most from AI. This clarity helps you make targeted decisions about where automation or AI could save you time and effort on repetitive tasks or boost accuracy in complex operations.");
// show relevant content
$('#info-modal #gif_Span_Activities').show();
$('#info-modal #gif_subheading_activities').show();
$('#info-modal #gif_activities').show();
$('#info-modal #gif_subheading_activities_2').show();
$('#info-modal #gif_activities_2').show();
break;
case "Steps":
// set title
$('#info-modal #infoHeading').text("Your Steps");
$('#info-modal #infoSubheading').text("Steps are the individual actions you take within each activity, offering a detailed view of your workflow. Understanding these steps is crucial because it’s often the smaller, repetitive tasks where AI can offer quick wins. With a clear breakdown of these steps, you can see exactly how AI might support each stage of your tasks, reducing manual work and allowing you to focus on higher-level goals.");
$('#info-modal #gif_Span_Steps').show();
$('#info-modal #gif_subheading_steps').show();
$('#info-modal #gif_steps').show();
$('#info-modal #gif_subheading_steps_2').show();
$('#info-modal #gif_steps_2').show();
break;
case "Tools":
// set title
$('#info-modal #infoHeading').text("Useful Tools");
$('#info-modal #infoSubheading').text("The Useful Tools section highlights specific AI applications and software suited to your job’s needs, curated to align with your segments, activities, and steps. These tools have been selected from a vast database to provide you with the best fit for your tasks, whether you’re looking for ways to automate repetitive tasks, analyze data more efficiently, or enhance productivity. This tailored selection ensures that you’re only shown tools relevant to your role, making the adoption of AI much smoother. \n\nThe 'Give Me Advice' button uses our AI to recommend the most relevant solutions from the 'Useful Tools'.");
$('#info-modal #gif_Span_Tools').show();
$('#info-modal #gif_subheading_tools').show();
$('#info-modal #gif_tools').show();
$('#info-modal #gif_subheading_tools_2').show();
$('#info-modal #gif_tools_2').show();
break;
case "Suggested":
// set title
$('#info-modal #infoHeading').text("Suggested Report");
//$('#info-modal #infoSubheading').text("The Suggested Report section is designed to help you outline a structured deliverable based on your work within this activity. This section suggests an output—such as a report or presentation—that would communicate the insights or results you've gathered. By clicking the \"Generate Document Outline\" button, you'll receive a tailored framework to kickstart your report, helping you organize key findings, insights, and recommendations effectively. This outline serves as a foundation, enabling you to create impactful deliverables with greater ease and consistency.");
$('#info-modal #infoSubheading').html(
"This feature creates a dynamic, structured outline for the kind of report or deliverable typically produced from this activity. But it goes further. " +
"Alongside each section, you’ll get embedded AI instructions —designed as LLM-ready prompts —that guide a tool like ChatGPT or your preferred assistant to generate content, analyze data, or expand ideas for each part of the document. " +
"Think of it as a starter framework for deep research or writing—pre-formatted, task-aware, and ready to hand off to an AI for first-draft generation, expansion, or even co-pilot collaboration. " +
"Whether you're producing a report, presentation, or recommendation summary, this outline gives you:" +
"
" +
"A structured skeleton tailored to your work " +
"Pre-written guidance to unlock useful outputs from AI tools " +
"A fast way to move from task to tangible deliverable " +
" " +
"Use it as a launchpad to brief your AI assistant—and let the heavy lifting begin."
);
$('#info-modal #gif_Span_Suggested').show();
$('#info-modal #gif_subheading_suggested').show();
$('#info-modal #gif_suggested').show();
break;
case "Automation":
// set title
$('#info-modal #infoHeading').text("Automation Evaluation");
$('#info-modal #infoSubheading').text("Automation Evaulation provides insight into the potential time or resource savings you could achieve by automating certain parts of your job. This estimation is based on industry data and our AI analysis, giving you a realistic view of what you can expect. Understanding these potential gains helps you make informed decisions about where to invest in AI, prioritizing areas where the returns on automation are likely to be highest.");
$('#info-modal #gif_Span_Automation').show();
$('#info-modal #gif_subheading_automation').show();
$('#info-modal #gif_automation').show();
break;
case "HITL":
// set title
$('#info-modal #infoHeading').text("HITL Score");
$('#info-modal #infoSubheading').text("HITL (Human-in-the-Loop) measures how essential human input is for a task. It helps you identify where AI can assist, automate, or where human judgment is still critical—guiding smarter, safer AI integration in your workflow.");
$('#info-modal #gif_Span_HITL').show();
$('#info-modal #gif_subheading_HITL').show();
$('#info-modal #gif_HITL').show();
break;
case "Contact":
// set title
$('#info-modal #infoHeading').text("Need Help?");
$('#info-modal #infoSubheading').text("Our Need Help section is designed to connect you with an AI professional if you’re looking for personalized guidance or support with implementing AI in your workflows. Booking a consultation allows you to discuss your unique challenges and explore tailored solutions that can drive meaningful improvements in your role. AI consultants can offer valuable insights, helping you maximize the benefits of automation and stay ahead in an AI-powered workplace.");
$('#info-modal #gif_Span_Contact').show();
$('#info-modal #gif_subheading_contact').show();
$('#info-modal #gif_contact').show();
break;
}
// animate and show
lockScroll();
$('#info-modal ').animate({ opacity: 1 }).show();
}
function CreateInfoModal()
{
if($('#info-modal #infoHeading').length == 0)
{
var infoFields = `
Title Of Help
Information
.
Segments
Activities
Steps
Suggested Report
Tools
Automation Evaluation
HITL
Need Help?
The main components or responsibilities that make up a job role.
The potential tasks or actions performed within each job segment.
The detailed, sequential actions needed to complete each activity.
Create a report outline to kick-start your report and organise findings and insights
A selection of useful AI-powered tools suited to your current action
Estimate AI and automation efficiency gains for the current workflow
The HITL score shows how much a task relies on human input versus what AI can realistically handle.
Find AI and Automation professionals to assist with implementation
Score Range
Interpretation
1.0–2.0
Fully Automatable
2.1–3.0
AI-Assist Viable
3.1–4.0
Human-in-the-Loop
4.1–5.0
Human-Essential
The main components or responsibilities that make up a job role.
Explore suggested reports for your activities and generate document outlines for the deliverables.
Evaluate the potential efficiency gains from automating or applying AI solutions to the steps
Let our AI analyse the tools for the best fit for the current task
`;
$('#info-modal #infoContainer').append(infoFields);
}
}
function CloseInfoModal()
{
$('#info-modal').animate({ opacity: 0 }).hide();
unLockScroll();
}
function CreateInfoSpan()
{
const infoSpan = document.createElement('span');
infoSpan.textContent = 'ⓘ';
infoSpan.style.color = 'green'; // Set the color to green
return infoSpan;
}
function TriggerConfetti()
{
const jsConfetti = new JSConfetti();
// async/await
/*await jsConfetti.addConfetti().then(() => jsConfetti.clearCanvas() );
console.log('Confetti animation completed!')*/
// Promise.then
jsConfetti.addConfetti()
.then(() => jsConfetti.clearCanvas() );
}
function isDesktop() {
const userAgent = navigator.userAgent.toLowerCase();
return userAgent.indexOf('win') !== -1 || userAgent.indexOf('mac') !== -1 || userAgent.indexOf('linux') !== -1;
}
function handleFileSelection(event) {
const fileInput = event.target;
const uploadButton = document.getElementById("upload-button");
const spinner = document.getElementById("loading-spinner");
if (fileInput.files.length > 0) {
uploadButton.style.display = "inline-flex"; // Show upload button
spinner.style.display = "none"; // Hide spinner initially
} else {
uploadButton.style.display = "none"; // Hide upload button
}
}
function displayTools(tools) {
const toolsList = document.getElementById('tools-list');
toolsList.innerHTML = ''; // Clear existing content
tools.forEach(tool => {
// Create a container for each tool
const toolContainer = document.createElement('div');
toolContainer.style.display = 'flex';
toolContainer.style.flexDirection = 'column';
toolContainer.style.gap = '8px';
// Create a link element for the tool
const toolLink = document.createElement('a');
toolLink.href = tool.Url;
toolLink.textContent = tool.Title; // Updated to use "Title"
toolLink.style.textDecoration = 'underline';
toolLink.style.color = '#2563eb'; // Tailwind blue-600 equivalent
toolLink.target = '_self'; // Open in the same window
// Append the link to the container
toolContainer.appendChild(toolLink);
// Append the container to the tools list
toolsList.appendChild(toolContainer);
});
}
/*
document.getElementById('show-submit-form').addEventListener('click', () => {
document.getElementById('submit-new-tool-holder').style.display = 'block';
});
*/
/*displayTools(myTools);*/
function createInvoiceTable()
{
invoices = JSON.parse(localStorage.getItem("StripeInvoices")) || [];
const invoicesList = document.getElementById('invoices-list');
invoicesList.innerHTML = ''; // Clear existing content
const table = document.createElement('table');
table.style.width = '100%';
table.style.borderCollapse = 'collapse';
const headerRow = table.insertRow();
const dateHeader = headerRow.insertCell();
dateHeader.innerHTML = 'Date';
dateHeader.style.fontWeight = 'bold';
dateHeader.style.padding = '8px';
dateHeader.style.border = '1px solid #ddd';
const invoiceHeader = headerRow.insertCell();
invoiceHeader.innerHTML = 'Stripe Invoice';
invoiceHeader.style.fontWeight = 'bold';
invoiceHeader.style.padding = '8px';
invoiceHeader.style.border = '1px solid #ddd';
invoices.forEach(invoice => {
const row = table.insertRow();
const dateCell = row.insertCell();
dateCell.innerHTML = invoice.invoiceDate;
dateCell.style.padding = '8px';
dateCell.style.border = '1px solid #ddd';
const invoiceCell = row.insertCell();
const link = document.createElement('a');
link.href = invoice.invoiceUrl;
link.target = '_blank';
link.textContent = `[${invoice.invoiceType}]`;
invoiceCell.appendChild(link);
invoiceCell.style.padding = '8px';
invoiceCell.style.border = '1px solid #ddd';
});
invoicesList.appendChild(table);
if(invoices.length > 0)
{
// show invoices holder
}
}
// Example usage:
/*const stripeInvoices = [
{ invoiceUrl: 'https://example.com/invoice1', invoiceType: 'Open', invoiceDate: '2024-07-05' },
{ invoiceUrl: 'https://example.com/invoice2', invoiceType: 'Paid', invoiceDate: '2024-07-04' },
];*/
async function fetchGroups() {
try {
const response = await fetch(jsonUrl);
groupData = await response.json();
document.getElementById("app-category").addEventListener("input", (event) => {
const inputText = event.target.textContent.trim();
categoryIsValid = groupData.includes(inputText); // Validate input against dropdown list
filterDropdown(inputText);
});
/*document.getElementById("dropdown").addEventListener("change", (event) => {
const selectedValue = event.target.value;
const appCategoryDiv = document.getElementById("app-category");
appCategoryDiv.textContent = selectedValue;
document.getElementById("dropdown").style.display = "none";
});*/
document.getElementById("dropdown").addEventListener("change", (event) => {
const selectedValue = event.target.value;
setCategory(selectedValue);
});
document.getElementById("dropdown").addEventListener("click", (event) => {
const selectedValue = event.target.value;
setCategory(selectedValue);
});
// Hide dropdown on blur
document.getElementById("app-category").addEventListener("blur", () => {
setTimeout(() => document.getElementById("dropdown").style.display = "none", 100);
});
// Show dropdown when editable div is focused
document.getElementById("app-category").addEventListener("focus", (event) => {
const inputText = event.target.textContent.trim();
filterDropdown(inputText);
});
} catch (error) {
console.error("Error fetching JSON:", error);
}
}
function setCategory(value) {
const appCategoryDiv = document.getElementById("app-category");
appCategoryDiv.textContent = value;
categoryIsValid = true; // Set validity when a match is selected
document.getElementById("dropdown").style.display = "none";
}
function filterDropdown(input) {
const dropdown = document.getElementById("dropdown");
dropdown.innerHTML = ""; // Clear existing options
if (!input) {
dropdown.style.display = "none";
return; // If input is empty, hide dropdown
}
const filteredGroups = groupData.filter(group =>
group.toLowerCase().includes(input.toLowerCase())
);
if (filteredGroups.length === 0) {
dropdown.style.display = "none";
return;
}
dropdown.style.display = "block";
filteredGroups.forEach(group => {
const option = document.createElement("option");
option.value = group;
option.textContent = group;
dropdown.appendChild(option);
});
}
function GenerateResponsibilities()
{
try
{
// check which is visible
var holder;
if($('#new-search-holder').is(':visible'))
{
holder = document.querySelector('#new-search-holder');
}
if($('#wizard-modal').is(':visible'))
{
holder = document.querySelector('#wizard-modal');
}
var holderID = holder.id;
const button = holder.querySelector("#btn-generate-responsibilities");
const buttonText = button.querySelector('#button-text');
const spinner = button.querySelector('#spinner');
// hide jobdescription text area
$('#' + holderID + ' #jobDescriptionWizard').hide();
// only search if the ai responsibilities div is empty
var AI_responsibilitiesContainter = holder.querySelector('#ai-responsibilities');
var isEmpty = false;
if(AI_responsibilitiesContainter)
{
isEmpty = AI_responsibilitiesContainter.childNodes.length === 0 && AI_responsibilitiesContainter.textContent.trim() === '';
}
if(isEmpty)
{
// Disable button and show spinner
button.disabled = true;
spinner.style.display = "inline-block";
var MYPEAS_payload = {};
MYPEAS_payload["ResponsibilityRequestData"] = {};
MYPEAS_payload["JobTitle"] = $('#' + holderID + ' #step1 #jobTitle').val();
if($('#new-search-holder').is(':visible'))
{
MYPEAS_payload["Industry"] = $('#wizard_industry_new option:selected').text();
}
if($('#wizard-modal').is(':visible'))
{
MYPEAS_payload["Industry"] = $('#wizard_industry option:selected').text();
}
MYPEAS_payload["promptDescription"] = "GenerateResponsibilityData";
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// switch to processing UI
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
// Hide spinner and enable button
spinner.style.display = "none";
button.disabled = false;
result = JSON.parse(result);
ConsoleLog("result (object): ", result); // result (object): {"message":"processing"}
ConsoleLog("result (stringified): ", JSON.stringify(result)); // "{\"message\":\"processing\"}"
var message = result["message"];
var generatedDocument = "";
switch(message)
{
case "Completed: Generated Responsibilities":
generatedDocument = cleanOpenAIResponse(result["output"]);
// cancel loading spinner on button
// store document outline in hidden field
$('#generatedDocumentStore').val(generatedDocument);
try {
renderAIResponsibilities(JSON.parse(generatedDocument));
} catch (error) {
console.error("Error parsing AIResponsibilities response:", error);
}
break;
}
})
.catch(error => {
console.error("Error calling generating document outline ", error);
// Hide spinner and enable button
spinner.style.display = "none";
button.disabled = false;
});
}
}
catch (error)
{
console.error('Error:', error);
// Hide spinner and enable button
spinner.style.display = "none";
button.disabled = false;
}
}
function cleanOpenAIResponse(response) {
// Trim leading/trailing whitespace
response = response.trim();
// Check if response starts and ends with triple backticks
if (response.startsWith("```json") && response.endsWith("```")) {
// Extract only the JSON content
response = response.split("\n").slice(1, -1).join("\n").trim();
}
return response;
}
function nextStep(step) {
/*document.querySelectorAll('.wizard-step').forEach(el => el.classList.add('hidden'));
document.getElementById('step' + step).classList.remove('hidden');*/
console.log('clicked next: ',step);
}
function prevStep(step) {
/*document.querySelectorAll('.wizard-step').forEach(el => el.classList.add('hidden'));
document.getElementById('step' + step).classList.remove('hidden');*/
console.log('clicked back: ',step);
}
function useAISuggestions() {
alert('AI suggestions coming soon!');
}
// Keeps track of selected responsibilities
var selectedResponsibilities = [];
// Function to render AI-generated responsibilities as selectable bubbles
function renderAIResponsibilities(aiGeneratedResponsibilities) {
//const container = document.getElementById('ai-responsibilities');
//const ai_container = document.getElementById('ai-responsibilities');
// check which is visible
var holder;
if($('#new-search-holder').is(':visible'))
{
holder = document.querySelector('#new-search-holder');
}
if($('#wizard-modal').is(':visible'))
{
holder = document.querySelector('#wizard-modal');
}
var holderID = holder.id;
const ai_container = holder.querySelector('#ai-responsibilities');
ai_container.innerHTML = 'Select from the suggested Job Responsibilities below.
'; // Clear existing items
aiGeneratedResponsibilities.forEach(responsibility => {
const button = document.createElement('button');
button.className = 'bubble';
button.innerText = responsibility.RT;
button.onclick = () => addAIResponsibility(responsibility);
ai_container.appendChild(button);
});
}
// Function to add a responsibility from AI selection
function addAIResponsibility(responsibility) {
// check which is visible
var holder;
if($('#new-search-holder').is(':visible'))
{
holder = document.querySelector('#new-search-holder');
}
if($('#wizard-modal').is(':visible'))
{
holder = document.querySelector('#wizard-modal');
}
var holderID = holder.id;
// hide job description textarea
$('#' + holderID + ' #jobDescriptionWizard').hide();
if (selectedResponsibilities.length >= 6) {
alert("You can only add up to 6 responsibilities.");
return;
}
// Prevent duplicate entries
if (selectedResponsibilities.some(r => r.RT === responsibility.RT)) {
alert("This responsibility is already added.");
return;
}
selectedResponsibilities.push(responsibility);
updateResponsibilityList();
}
// Function to manually add a responsibility (text input)
function addManualResponsibility() {
// check which is visible
var holder;
if($('#new-search-holder').is(':visible'))
{
holder = document.querySelector('#new-search-holder');
}
if($('#wizard-modal').is(':visible'))
{
holder = document.querySelector('#wizard-modal');
}
var holderID = holder.id;
// hide jobdescription text area
$('#' + holderID + ' #jobDescriptionWizard').hide();
//const container = document.getElementById('responsibilities');
const container = holder.querySelector('#add-repsonsibilities-container');
if (selectedResponsibilities.length >= 10) {
alert("You can only add up to 10 responsibilities.");
return;
}
// Create a wrapper div to hold the input and button
const inputWrapper = document.createElement('div');
inputWrapper.style.display = 'flex';
inputWrapper.style.alignItems = 'center';
inputWrapper.style.gap = '8px';
inputWrapper.style.marginBottom = '8px';
// Create the input field
const input = document.createElement('input');
input.type = 'text';
input.className = 'responsibility';
input.placeholder = 'Enter a key responsibility';
input.style.flex = '1';
input.style.padding = '8px';
input.style.border = '1px solid #d1d5db';
input.style.borderRadius = '6px';
// Create the save button
const saveButton = document.createElement('button');
saveButton.innerHTML = `
`;
saveButton.style.display = 'inline-flex';
saveButton.style.alignItems = 'center';
saveButton.style.justifyContent = 'center';
saveButton.style.gap = '8px';
saveButton.style.whiteSpace = 'nowrap';
saveButton.style.fontSize = '14px';
saveButton.style.fontWeight = '500';
saveButton.style.color = '#374151';
saveButton.style.backgroundColor = '#ffffff';
saveButton.style.border = '1px solid #d1d5db';
saveButton.style.borderRadius = '6px';
saveButton.style.padding = '6px 12px';
saveButton.style.cursor = 'pointer';
saveButton.style.transition = 'all 0.2s ease';
saveButton.onmouseover = function () {
saveButton.style.backgroundColor = '#f3f4f6';
saveButton.style.borderColor = '#9ca3af';
};
saveButton.onmouseout = function () {
saveButton.style.backgroundColor = '#ffffff';
saveButton.style.borderColor = '#d1d5db';
};
// When button is clicked, trigger blur on input
saveButton.onclick = function () {
$('#' + holderID + ' #jobDescriptionWizard').hide();
input.blur();
};
// Handle input blur event
input.onblur = function () {
if (input.value.trim() !== "") {
selectedResponsibilities.push({ RT: input.value.trim(), RD: "Custom responsibility added by user." });
updateResponsibilityList();
inputWrapper.remove(); // Remove input field and button after entering
}
};
// Append elements
inputWrapper.appendChild(input);
inputWrapper.appendChild(saveButton);
container.appendChild(inputWrapper);
// Focus on the input field
input.focus();
}
// Function to update the displayed responsibility list
function updateResponsibilityList() {
// check which is visible
var holder;
if($('#new-search-holder').is(':visible'))
{
holder = document.querySelector('#new-search-holder');
}
if($('#wizard-modal').is(':visible'))
{
holder = document.querySelector('#wizard-modal');
}
var holderID = holder.id;
//$('#' + holderID + '
const ai_container = holder.querySelector('#ai-responsibilities');
const container = holder.querySelector('#responsibilities');
container.innerHTML = '';
selectedResponsibilities.forEach(responsibility => {
const div = document.createElement('div');
div.className = 'selected-bubble';
div.innerText = responsibility.RT;
const removeBtn = document.createElement('span');
removeBtn.innerText = '❌';
removeBtn.className = 'remove-btn';
removeBtn.onclick = () => removeResponsibility(responsibility.RT);
div.appendChild(removeBtn);
container.appendChild(div);
});
}
// Function to remove a responsibility
function removeResponsibility(rt) {
const index = selectedResponsibilities.findIndex(r => r.RT === rt);
if (index !== -1) {
selectedResponsibilities.splice(index, 1);
updateResponsibilityList();
}
}
// Function to export the final selected responsibilities as JSON
function exportResponsibilities() {
const jsonOutput = JSON.stringify(selectedResponsibilities, null, 2);
console.log("Final JSON Output:", jsonOutput);
alert("Responsibilities exported! Check console for output.");
}
function generatedJobDescription(jobData) {
if (!jobData || !jobData.title || !jobData.industry || !Array.isArray(jobData.responsibilities)) {
console.error("Invalid jobData format.");
return "";
}
let jobDescription = `**${jobData.title}**\nIndustry: ${jobData.industry}\n\n**Key Responsibilities:**\n`;
jobData.responsibilities.forEach(responsibility => {
let { RT, RD } = responsibility;
jobDescription += `\n- ${RT}`;
if (RD && RD !== "No description provided.") {
jobDescription += `: ${RD}`;
}
});
return jobDescription;
}
function NewSearchSubmit()
{
try
{
// Get the values of the form fields
//var holder = document.querySelector('#new-search-holder');
const JobTitle = document.getElementById('jobTitle-new').value;
const JobDescription = document.getElementById('jobDescription-new').value;
const IndustryTitle = $('#wizard_industry').text();
const IndustryId = $('#wizard_industry').val();
var email = localStorage.getItem("email");
var memberID = localStorage.getItem("memberID");
var auth_token = localStorage.getItem("auth_token");
var honeypot = document.getElementById('consent_check_new');
var MYPEAS_payload = {};
MYPEAS_payload["JobTitle"] = JobTitle;
MYPEAS_payload["Industry"] = IndustryTitle;
MYPEAS_payload["IndustryId"] = IndustryId;
MYPEAS_payload["JobDescription"] = JobDescription;
MYPEAS_payload["promptDescription"] = "NewSearch";
MYPEAS_payload["registered"] = "true"; // should always be true now that user provides password at start page
MYPEAS_payload["email"] = email;
MYPEAS_payload["memberID"] = memberID;
MYPEAS_payload["auth_token"] = auth_token;
// Get the client's time zone
const clientTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
MYPEAS_payload["timeZone"] = clientTimeZone;
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// validate fields
var failed = false;
var validationMessages = [];
if(JobTitle.length < 3)
{
failed = true;
}
if(JobDescription.length < 100 && (JobDescription.trim() !== 'Generated by AI' && jobData))
{
failed = true;
}
if(JobDescription.trim() == 'Generated by AI' && jobData)
{
var GeneratedJobDescription = generatedJobDescription(jobData);
// use jobData to create a jobdescription
MYPEAS_payload["JobDescription"] = GeneratedJobDescription;
}
if (honeypot && honeypot.checked)
{
failed = true;
}
if(!failed)
{
// switch to processing UI
// hide formcontainer
//$('#Form-container').hide();
// hide waitlistcontainer
$('#waitlist-container').hide();
// hide invite launcher
$('#invite-launcher').hide();
// hide learn more
$('#learn-more-container').hide();
$('#segments-and-activities').hide();
// show processing containter
// add email to processing email field
$('#CheckStatusAddress').text(email);
$('#processing-container').show();
// hide background video
$('.background-video').hide();
$('.background-video-agency').hide();
$('#hero-holder').show();
$('.hcv-container').show();
$('#background-image-hero').show();
// hide buttons
$('#button-box').hide();
// close new search modal
OpenCloseNewSearchModal("close");
ShowProcessing("processing");
// trigger timer
attempts = 0;
startCheckStatusIntervals();
localStorage.setItem("processStatus", "processing/updating");
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
ConsoleLog("result (object): ", result); // result (object): {"message":"processing"}
ConsoleLog("result (stringified): ", JSON.stringify(result)); // "{\"message\":\"processing\"}"
var message = result["message"];
switch(message)
{
case "processing":
case "updating":
// hide loading and show message to check back
// can't do this
break;
/* Signup */
case "You have a profile currently processing.":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "You have a profile currently processing.", "promptDescription": promptDescription}),
};
*/
OpenModal("Please Note", "You have a profile currently processing. Until that is complete you cannot request another on this account.", false, false);
break;
case "You have exceeded your free account profile limit":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "You have exceeded your free account profile limit", "promptDescription": promptDescription}),
};
*/
ProcessingRequestShowUX();
OpenModal("Upgrade", "You have exceeded your free account profile limit. Please purchase credit to perform more revisions.", false, true);
break;
case "You have exceeded your paid account profile limit":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "You have exceeded your paid account profile limit", "promptDescription": promptDescription}),
};
*/
ProcessingRequestShowUX();
OpenModal("Upgrade", "You have exceeded your paid account profile limit. Please purchase credit to perform more revisions.", false, true);
break;
// tell user to log in
case "Account Exists. Wrong Password Entered":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Account Exists. Wrong Password Entered", "promptDescription": promptDescription}),
}; */
OpenModal("Problem", "Please check your login details", false, false);
break;
/* Login */
// user is validated
case "User Validated":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "User Validated", "promptDescription": promptDescription, "profile": checkUserObj["profile"], "processStatus": checkUserObj["processStatus"]}),
}; */
// add useful info to localstorage
/*
const user = {
memberID: items.length > 0 && items[0].hasOwnProperty('memberID') ? items[0].memberID : null,
profile: items.length > 0 && items[0].hasOwnProperty('profile') ? items[0].profile : null,
processStatus: items.length > 0 && items[0].hasOwnProperty('processStatus') ? items[0].profile : null,
registered: items.length > 0 && items[0].hasOwnProperty('registered') ? items[0].registered : null,
passwordHash: items.length > 0 && items[0].hasOwnProperty('passwordHash') ? items[0].passwordHash : null,
paidAccount: items.length > 0 && items[0].hasOwnProperty('paidAccount') ? items[0].paidAccount : null,
revisions: items.length > 0 && items[0].hasOwnProperty('revisions') ? items[0].revisions : 0,
mypeasPayload: items.length > 0 && items[0].hasOwnProperty('mypeasPayload') ? items[0].mypeasPayload : null,
userExists: items.length > 0,
};
*/
localStorage.setItem("memberID", result["memberID"]);
localStorage.setItem("auth_token", result["auth_token"]);
localStorage.setItem("auth_token_date_created", result["auth_token_date_created"]);
break;
// tell user to log in
// failed to validate user
case "Account Exists. Wrong Password Entered":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Account Exists. Wrong Password Entered", "promptDescription": promptDescription}),
};
*/
OpenModal("Problem", "Please check your login details", false, false);
break;
/* ForgotPassword */
case "Password Changed":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "Password Changed", "promptDescription": promptDescription}),
};
*/
// update user interface and close loading
// clear local storage and cookies
localStorage.clear();
// can't delete the cookies, so set their values to expired. so we force UX to require new login
// redirect to home page
location.href = '/?login=true';
break;
/* CheckStatus */
case "ProcessStatus returned":
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "ProcessStatus returned", "promptDescription": promptDescription, "processStatus": returnProcessStatus}),
};
*/
// update processing page
var processStatus = result["processStatus"];
switch(processStatus)
{
case "updating":
case "processing":
// uses the default content
$('#UpdateStatusTextH1').text("AI Profile is still " + processStatus);
$('#UpdateStatusTextP1').text("Estimated time: 3 minutes");
$('#UpdateStatusTextP2').text("We will email you when it is ready at " + email);
$('#CheckStatusAddress').text(email);
// show check status button
// hide retry button
$('#btnCheckStatus').show();
$('#btnRetry').hide();
// hide cancel button
$('#btnCancel').hide();
break;
case "complete":
case "completed":
// display message and use try again button
$('#UpdateStatusTextH1').text("AI Profile is Ready");
// hide retry and check status buttons
$('#btnCheckStatus').hide();
$('#btnRetry').hide();
/*
return {
statusCode: 200,
body: JSON.stringify({"message": "complete", "promptDescription": promptDescription, "processStatus": returnProcessStatus}),
};
*/
// redirect to profile
// load profile in UI - look into making this all work cleanly
setTimeout(function()
{ LoadExistingProfile(result["profile"]);
}, 2000);
break;
case "failed":
// show retry button
// hide check status button
$('#btnCheckStatus').hide();
$('#btnRetry').show();
// use profile that was returned by failed - if present
var profileStored = localStorage.getItem("profile");
if(profileStored && profileStored != "")
{
// also show cancel button if there is a profile to fall back on
$('#btnCancel').show();
var btnRetry = document.getElementById("btnRetry");
btnRetry.addEventListener('click', (event) => {
try
{
// send email back to server to do retry
// NEXT: where do i get email from
var email = localStorage.getItem("email");
// replace with memberID delivered by checkstatus
var memberID = localStorage.getItem("memberID");
var auth_token = localStorage.getItem("auth_token");
// make sure it sends to login if these arent present
var MYPEAS_payload = {};
MYPEAS_payload["promptDescription"] = "retry";
MYPEAS_payload["memberID"] = memberID;
MYPEAS_payload["auth_token"] = auth_token;
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
requestData["RetryObj"] = {};
//requestData["RetryObj"]["email"] = email;
requestData["RetryObj"]["memberID"] = memberID;
requestData["RetryObj"]["auth_token"] = auth_token;
localStorage.setItem("processStatus", "processing/updating");
// set page to show processing or updating UI
// uses the default content
$('#UpdateStatusTextH1').text("AI Profile is still " + processStatus);
$('#UpdateStatusTextP1').text("Estimated time: 3 minutes");
$('#UpdateStatusTextP2').text("We will email you when it is ready at " + email);
$('#CheckStatusAddress').text(email);
// show check status button
// hide retry button
$('#btnCheckStatus').show();
$('#btnRetry').hide();
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
result = JSON.parse(result);
// we won't wait for this
});
}
catch(err)
{
console.error('Error:', err.message);
console.error('Stacktrace:', err.stack);
}
});
var btnCancel = document.getElementById("btnCancel");
btnCancel.removeEventListener('click', Cancel);
btnCancel.addEventListener('click', Cancel);
}
// display message and use try again button
$('#UpdateStatusTextH1').text("AI Profile " + processStatus);
$('#UpdateStatusTextP1').text("Your profile encountered a problem and did not complete.");
$('#UpdateStatusTextP2').text("Would you like to try again?");
$('#CheckStatusAddress').text("");
// update localstorage
break;
}
break;
}
var resultObj = tryParse(result);
});
}
if(failed)
{
// scroll to first error
$('html, body').animate({
scrollTop: $('#' + validationMessages[0]).offset().top - 50
}, 500);
}
}
catch(errNewSearch)
{
ConsoleLog('error name: ' + errNewSearch.name);
ConsoleLog('error message: ' + errNewSearch.messsage);
ConsoleLog('error stacktrace: ' + errNewSearch.stack);
}
}
function GenerateHITLScore(SegmentIndex, ActivityIndex, OutputIndex, container, HITLDataStore, indexValue)
{
try
{
// show spinner on button
var button = container.querySelector('#generate-hitl-button');
var spinner = container.querySelector('#spinner');
// Disable button and show spinner
button.disabled = true;
spinner.style.display = "inline-block";
// create a fetch to request the document outine
var profile = localStorage.getItem("profile");
var maxParseAttempts = 10; // Maximum allowed parsing attempts
while (typeof profile === 'string' && maxParseAttempts > 0)
{
try
{
profile = JSON.parse(profile);
} catch (error)
{
console.error("Error parsing profile:", error);
break; // Exit loop on parsing failure
}
maxParseAttempts--;
}
//profile = JSON.parse(profile);
var MYPEAS_payload = {};
MYPEAS_payload["HITLData"] = {};
MYPEAS_payload["JobTitle"] = profile["JobTitle"]; // use profile
//MYPEAS_payload["JobDescriptionSummary"] = profile["JobDescriptionSummary"];
MYPEAS_payload["Title"] = profile["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Title"];
MYPEAS_payload["SegmentTitle"] = profile["JobSegments"][SegmentIndex]["Name"] || "";
MYPEAS_payload["Activity"] = profile["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Title"];
MYPEAS_payload["CurrentTask"] = profile["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Title"] + ": " + profile["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Description"] || "";
var steps = MYPEAS_payload["CurrentTask"] = profile["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Steps"];
var stepsArray = steps.map(function(step, index)
{
return {
HowTo: step.HowTo,
index: index,
Title: step.Outline,
id: step.id
};
});
MYPEAS_payload["StepsArray"] = stepsArray;
// MYPEAS_payload["TaskSummary"];
/*var steps = profile["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Steps"][0]["HowTo"];
var stepsArray = profile.Steps.map(function(step, index) {
return {
HowTo: step.HowTo,
index: index,
Title: step.Outline,
id: step.id,
Report: step.Outline,
Gain: step.Gain,
Flow: step.Flow,
Breakdown: {
JobSegment: profile["JobSegments"][SegmentIndex]["Name"],
Activity: profile["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Title"],
Output: profile["JobSegments"][SegmentIndex]["Activities"][ActivityIndex]["Outputs"][OutputIndex]["Description"]
}
};
}); */
var numberedList = "";
if(stepsArray)
{
stepsArray.forEach(function(step, index) {
numberedList += (index + 1) + ". " + step.Title + "\n";
});
}
MYPEAS_payload["ListOfSteps"] = numberedList;
ConsoleLog("ListOfSteps: " + numberedList);
MYPEAS_payload["promptDescription"] = "CreateHITLScore";
const requestData = {};
requestData["MYPEAS_payload"] = MYPEAS_payload;
// switch to processing UI
// Make an API call to API gateway - return will just indicate that it is processing
var apiUrl = 'https://lt8psnfy4f.execute-api.eu-west-1.amazonaws.com/Production/MYPEASGPT';
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestData),
})
// Then get the API response object, convert it to text and display it
.then(response => response.text())
.then(result => {
// Hide spinner and enable button
spinner.style.display = "none";
button.disabled = false;
result = JSON.parse(result);
ConsoleLog("result (object): ", result); // result (object): {"message":"processing"}
ConsoleLog("result (stringified): ", JSON.stringify(result)); // "{\"message\":\"processing\"}"
var message = result["message"];
var HITLScores = [];
switch(message)
{
case "HITL Scores Returned":
HITLScores = result["HITLScores"];
// put the scores in a hidden field
HITLDataStore.value = JSON.stringify(HITLScores);
// use the steps to parse the hitl in future clicks to populate hitl
// What index are we on???
PopulateHITLData(HITLScores, indexValue, HITLDataStore, container);
// populate modal when required
break;
case "HITL Scores Failed":
// show fail message
var failMessage = "Unfortunately there was a problem generating the HITL score. Please try again later.";
alert(failMessage);
break;
}
})
.catch(error => {
console.error("Error calling GenerateHITLScore ", error);
// Hide spinner and enable button
spinner.style.display = "none";
button.disabled = false;
});
}
catch(error)
{
console.error('Error:', error);
// Hide spinner and enable button
spinner.style.display = "none";
button.disabled = false;
}
}
/*
JavaScript function that takes a specific index value as input and returns the object from the array whose step property matches that index value (as a string).
*/
function findObjectByStep(array, index) {
const stepToFind = parseInt(index); // Convert the input index to a string for comparison
return array.find(obj => obj.index.toString() === stepToFind.toString());
}
function PopulateHITLData(HITLScores, index, HITLDataStore, container)
{
// get the correct index
// get the correct hitlscore
var hitlScoreObj = findObjectByStep(HITLScores, index);
// normalise hitlobj
// Safe version with optional chaining
const cognitiveComplexity = hitlScoreObj?.HITLScore?.cognitive_complexity || hitlScoreObj?.scores?.cognitive_complexity;
const decisionMaking = hitlScoreObj?.HITLScore?.decision_making || hitlScoreObj?.scores?.decision_making;
const contextualDependence = hitlScoreObj?.HITLScore?.contextual_dependence || hitlScoreObj?.scores?.contextual_dependence;
const interactivityCollaboration = hitlScoreObj?.HITLScore?.interactivity_collaboration || hitlScoreObj?.scores?.interactivity_collaboration;
const dataAmbiguity = hitlScoreObj?.HITLScore?.data_ambiguity || hitlScoreObj?.scores?.data_ambiguity;
const aiMaturity = hitlScoreObj?.HITLScore?.ai_maturity || hitlScoreObj?.scores?.ai_maturity;
// Shared fields (also safer with optional chaining)
const overallScore = hitlScoreObj?.HITLScore?.overall_hitl_score;
const bucket = hitlScoreObj?.HITLScore?.bucket;
const reasoning = hitlScoreObj?.HITLScore?.reasoning_summary;
// Rebuild in standardized format
hitlScoreObj = {
"index": hitlScoreObj?.index || index, // Use existing index or fallback to your index parameter
"step": hitlScoreObj?.step || hitlScoreObj?.Outline || "", // Use step or fallback to Outline from prompt1
"scores": {
"cognitive_complexity": cognitiveComplexity,
"decision_making": decisionMaking,
"contextual_dependence": contextualDependence,
"interactivity_collaboration": interactivityCollaboration,
"data_ambiguity": dataAmbiguity,
"ai_maturity": aiMaturity
},
"overall_hitl_score": overallScore,
"bucket": bucket,
"reasoning_summary": reasoning
};
// populate the fields in the hitl container
var scoreContainer = container.querySelector('#scoreContainer');
scoreContainer.innerHTML = `
Score: ${parseFloat(hitlScoreObj.overall_hitl_score).toFixed(2)}
${hitlScoreObj.bucket}
${hitlScoreObj.reasoning_summary}
[Explain My HITL Score]
`;
// hide
//container is hitl-result
var hitl_result = container.querySelector('#hitl-result');
var hitl_request = container.querySelector('#hitl-request');
hitl_result.style.display = 'flex';
hitl_request.style.display = 'none';
/*var parent = container.parentNode;
var hitl_request = parent.querySelector('#hitl-request');
hitl_request.display = 'none';*/
//$('#modal-hitl-score').val()
}
function OpenHITLModal(hitlScoreObj)
{
// set values
//var hitlScoreObj = JSON.parse(hitlScoreObj);
// hitl title score
$('#HITL-modal #modal-hitl-score').text((parseFloat(hitlScoreObj["overall_hitl_score"])).toFixed(2));
// criterion
$('#HITL-modal #cognitive_complexity').text(hitlScoreObj["scores"]["cognitive_complexity"]);
$('#HITL-modal #contextual_dependence').text(hitlScoreObj["scores"]["contextual_dependence"]);
$('#HITL-modal #decision_making').text(hitlScoreObj["scores"]["decision_making"]);
$('#HITL-modal #data_ambiguity').text(hitlScoreObj["scores"]["data_ambiguity"]);
$('#HITL-modal #interactivity_collaboration').text(hitlScoreObj["scores"]["interactivity_collaboration"]);
$('#HITL-modal #ai_maturity').text(hitlScoreObj["scores"]["ai_maturity"]);
$('#HITL-modal #HITL_bucket').text("Conclusion: " + hitlScoreObj["bucket"]);
$('#HITL-modal #HITL_commentary').text(hitlScoreObj["reasoning_summary"]);
$('#HITL-modal').animate({ opacity: 1 }).show();
}
// estimated cost savings
function createEstimatedCostSavings(index, assumptions) {
const {
salary = 100000,
timePercent = 20,
efficiency = 30
} = assumptions;
// Calculate values
const hoursPerMonth = ((timePercent / 100) * 160) * (efficiency / 100); // Number of hours SAVED per month by AI/automation [160 is 40hrs per week X 4]
const annualCostSavings = salary * (timePercent / 100) * (efficiency / 100);
const fteEquivalent = (annualCostSavings / salary).toFixed(1); // Full-Time Equivalent (FTE) savings — that is, how many full-time employees' worth of salary you're saving due to AI efficiency.
const id = `_cost_savings_${index}`;
const container = document.createElement('div');
container.id = id;
container.style.margin = '10px';
container.style.padding = '20px';
container.style.borderRadius = '10px';
container.style.backgroundColor = 'white';
container.style.border = '2px solid lightgray';
const heading = document.createElement('h3');
heading.textContent = '💲 Estimated Cost Savings';
container.appendChild(heading);
const subtitle = document.createElement('p');
subtitle.textContent = "Based on your role and workflow time spent, here's what automating this process could save your organization.";
subtitle.style.marginTop = '0px';
container.appendChild(subtitle);
// Metrics section
const metrics = document.createElement('div');
metrics.style.display = 'flex';
metrics.style.justifyContent = 'space-between';
metrics.style.margin = '20px 0';
function createMetric(title, value) {
const metricBox = document.createElement('div');
metricBox.style.textAlign = 'center';
metricBox.style.flex = '1';
const val = document.createElement('div');
val.id = 'metricValue';
val.textContent = value;
val.style.fontSize = '1.5em';
val.style.fontWeight = 'bold';
const label = document.createElement('div');
label.id = 'metricLabel';
label.textContent = title;
label.style.fontSize = '0.9em';
label.style.color = 'gray';
metricBox.appendChild(val);
metricBox.appendChild(label);
return metricBox;
}
var metric_TimeSaving = createMetric("Time Savings", `≈ ${hoursPerMonth.toFixed(1)} hours/month`);
metric_TimeSaving.id = 'metricTimeSaving';
var metricCostSaving = createMetric("Annual Cost Savings", `≈ $${annualCostSavings.toLocaleString()}`);
metricCostSaving.id = 'metricCostSaving';
var metricFTE = createMetric("Equivalent Productivity", `≈ ${fteEquivalent} Full-Time Employee (FTE)`);
metricFTE.id = 'metricFTE';
/*metrics.appendChild(createMetric("Time Savings", `≈ ${hoursPerMonth.toFixed(1)} hours/month`));
metrics.appendChild(createMetric("Annual Cost Savings", `≈ $${annualCostSavings.toLocaleString()}`));
metrics.appendChild(createMetric("Equivalent Productivity", `≈ ${fteEquivalent} Full-Time Employee (FTE)`));*/
metrics.appendChild(metric_TimeSaving);
metrics.appendChild(metricCostSaving);
metrics.appendChild(metricFTE);
container.appendChild(metrics);
// Assumptions section
const assumptionsBox = document.createElement('div');
assumptionsBox.style.borderTop = '1px solid #ddd';
assumptionsBox.style.paddingTop = '10px';
const assumptionsHeading = document.createElement('strong');
assumptionsHeading.textContent = 'Assumptions Used:';
assumptionsBox.appendChild(assumptionsHeading);
const assumptionList = document.createElement('ul');
assumptionList.style.paddingLeft = '20px';
assumptionList.style.marginTop = '5px';
const assumptionItems = [
`Estimated salary: $${salary.toLocaleString()}/year`,
`Time spent on this workflow: ${timePercent}% of role`,
`Efficiency gain: ${efficiency}%`
];
/*assumptionItems.forEach(text => {
const li = document.createElement('li');
li.textContent = text;
assumptionList.appendChild(li);
});*/
/*
const salaryLi = SavingsCard.querySelector('#salaryLi');
const timeSpentLi = SavingsCard.querySelector('#timeSpentLi');
const efficiencyGainLi = SavingsCard.querySelector('#efficiencyGainLi');
*/
const salaryli = document.createElement('li');
salaryli.id = 'salaryLi';
salaryli.textContent = `Estimated salary: $${salary.toLocaleString()}/year`;
assumptionList.appendChild(salaryli);
const timeSpentli = document.createElement('li');
timeSpentli.id = 'timeSpentLi';
timeSpentli.textContent = `Time spent on this workflow: ${timePercent}% of role`;
assumptionList.appendChild(timeSpentli);
const efficiencyGainLi = document.createElement('li');
efficiencyGainLi.id = 'efficiencyGainLi';
efficiencyGainLi.textContent = `Efficiency gain: ${efficiency}%`;
assumptionList.appendChild(efficiencyGainLi);
assumptionsBox.appendChild(assumptionList);
// Edit Assumptions Button
const editButton = document.createElement('button');
editButton.textContent = 'Edit Assumptions';
editButton.style.marginTop = '10px';
editButton.style.border = '1px solid gray';
editButton.style.borderRadius = '8px';
editButton.style.padding = '5px 10px';
editButton.style.cursor = 'pointer';
editButton.onclick = function () {
//alert("This would open the assumptions editor.");
OpenEditAssumptionsModal(container);
};
assumptionsBox.appendChild(editButton);
container.appendChild(assumptionsBox);
// Disclaimer
const disclaimer = document.createElement('p');
disclaimer.textContent = '⚠️ This is an estimate. For full ROI analysis, book a consultation.';
disclaimer.style.fontSize = '0.8em';
disclaimer.style.color = '#888';
disclaimer.style.marginTop = '10px';
container.appendChild(disclaimer);
// hidden assumption items fields
var hiddenSalary = document.createElement('input');
hiddenSalary.id = 'hiddenSalary';
hiddenSalary.type = 'hidden';
hiddenSalary.value = salary;
var hiddenWorkPercent = document.createElement('input');
hiddenWorkPercent.id = 'hiddenPercent';
hiddenWorkPercent.type = 'hidden';
hiddenWorkPercent.value = timePercent;
var hiddenHoursPerWeek = document.createElement('input');
hiddenHoursPerWeek.id = 'hiddenHoursPerWeek';
hiddenHoursPerWeek.type = 'hidden';
hiddenHoursPerWeek.value = '40';
var hiddenEfficiencyGain = document.createElement('input');
hiddenEfficiencyGain.id = 'hiddenEfficiencyGain';
hiddenEfficiencyGain.type = 'hidden';
hiddenEfficiencyGain.value = efficiency;
container.appendChild(hiddenSalary);
container.appendChild(hiddenWorkPercent);
container.appendChild(hiddenHoursPerWeek);
container.appendChild(hiddenEfficiencyGain);
return container;
}
function OpenEditAssumptionsModal(SavingsCard)
{
// Access elements within the specific container
const salaryLi = SavingsCard.querySelector('#salaryLi');
const timeSpentLi = SavingsCard.querySelector('#timeSpentLi');
const efficiencyGainLi = SavingsCard.querySelector('#efficiencyGainLi');
// Extract current values (you might want to parse these further)
const currentSalary = salaryLi.textContent.split(': ')[1];
const currentTimeSpent = timeSpentLi.textContent.split(': ')[1];
const currentEfficiencyGain = efficiencyGainLi.textContent.split(': ')[1];
// For demonstration purposes, let's just log the values
console.log("Current Assumptions:");
console.log("Salary:", currentSalary);
console.log("Time Spent:", currentTimeSpent);
console.log("Efficiency Gain:", currentEfficiencyGain);
// modal fields
var assumptionsModal = document.getElementById('assumptions-modal');
const labelSalary = assumptionsModal.querySelector('#salaryValue');
const inputSalary = assumptionsModal.querySelector('#salary');
const labelWorkflowTime = assumptionsModal.querySelector('#timeValue');
const inputWorkflowTime = assumptionsModal.querySelector('#timePercent');
const labelHoursWorkPerWeek = assumptionsModal.querySelector('#hoursPerWeek');
const inputHoursWorkPerWeek = assumptionsModal.querySelector('#hoursValue');
// set the field values
var salary = SavingsCard.querySelector('#hiddenSalary').value;
labelSalary.textContent = '$' + Number((salary.toString().replace(',', ''))).toLocaleString();
inputSalary.value = salary;
$(inputSalary).trigger('input');
var workflowTimePercent = SavingsCard.querySelector('#hiddenPercent').value;
labelWorkflowTime.textContent = workflowTimePercent + '%';
inputWorkflowTime.value = workflowTimePercent;
$(inputWorkflowTime).trigger('input');
var hoursPerWeek = SavingsCard.querySelector('#hiddenHoursPerWeek').value;
labelHoursWorkPerWeek.value = hoursPerWeek;
inputHoursWorkPerWeek.textContent = hoursPerWeek;
$(inputHoursWorkPerWeek).trigger('input');
// change button
/*
Update Assumptions
*/
// change the click event
// Remove any existing click listeners to avoid duplicates
$('#assumptions-modal #updateAssumptionsBtn').off('click');
// Attach a new click listener that has access to containerDiv via closure
$('#assumptions-modal #updateAssumptionsBtn').on('click', function() {
// get modal values
// use modal values to update the savings card
UpdateAssumptions(SavingsCard);
});
// open the modal
$('#assumptions-modal').css('z-index', '10001').animate({ opacity: 1 }).show();
}
// add parameter of container
function UpdateAssumptions(SavingsCard)
{
// for speed, dont update across the site
// salary - this is common for all
// time spent
//
// Calculate values
var salary = parseInt($('#assumptions-modal #salary').val()) || 0;
var hoursPerWeek = parseInt($('#assumptions-modal #hoursPerWeek').val()) || 0;
var timePercent = parseInt($('#assumptions-modal #timePercent').val()) || 0;
const efficiencyGainLi = SavingsCard.querySelector('#efficiencyGainLi');
const currentEfficiencyGain = efficiencyGainLi.textContent.split(': ')[1];
var efficiency = parseInt(currentEfficiencyGain) || 0;
const hoursPerMonth = ((timePercent / 100) * (hoursPerWeek * 4)) * (efficiency / 100); // Number of hours SAVED per month by AI/automation [160 is 40hrs per week X 4]
const annualCostSavings = salary * (timePercent / 100) * (efficiency / 100);
const fteEquivalent = (annualCostSavings / salary).toFixed(1); // Full-Time Equivalent (FTE) savings — that is, how many full-time employees' worth of salary you're saving due to AI efficiency.
// Assumptions section
const assumptionsBox = document.createElement('div');
assumptionsBox.style.borderTop = '1px solid #ddd';
assumptionsBox.style.paddingTop = '10px';
const assumptionsHeading = document.createElement('strong');
assumptionsHeading.textContent = 'Assumptions Used:';
assumptionsBox.appendChild(assumptionsHeading);
const assumptionList = document.createElement('ul');
assumptionList.style.paddingLeft = '20px';
assumptionList.style.marginTop = '5px';
const assumptionItems = [
`Estimated salary: $${salary.toLocaleString()}/year`,
`Time spent on this workflow: ${timePercent}% of role`,
`Efficiency gain: ${efficiency}%`
];
var salaryli = SavingsCard.querySelector('#salaryLi');
salaryli.textContent = `Estimated salary: $${salary.toLocaleString()}/year`;
var timeSpentli = SavingsCard.querySelector('#timeSpentLi');
timeSpentli.textContent = `Time spent on this workflow: ${timePercent}% of role`;
efficiencyGainLi.textContent = `Efficiency gain: ${efficiency}%`;
// hidden assumption items fields
var hiddenSalary = SavingsCard.querySelector('#hiddenSalary');
hiddenSalary.value = salary;
var hiddenWorkPercent = SavingsCard.querySelector('#hiddenPercent');
hiddenWorkPercent.value = timePercent;
var hiddenHoursPerWeek = SavingsCard.querySelector('#hiddenHoursPerWeek');
hiddenHoursPerWeek.value = hoursPerWeek;
var hiddenEfficiencyGain = SavingsCard.querySelector('#hiddenEfficiencyGain');
hiddenEfficiencyGain.value = efficiency;
// update the savings card healdine figures
var metricValueTimeSaving = SavingsCard.querySelector('#metricTimeSaving #metricValue');
//var metricLabelTimeSaving = SavingsCard.querySelector('#metricTimeSaving #metricLabel');
metricValueTimeSaving.textContent = `≈ ${hoursPerMonth.toFixed(1)} hours/month`;
var metricValueCostSaving = SavingsCard.querySelector('#metricCostSaving #metricValue');
metricValueCostSaving.textContent = `≈ $${annualCostSavings.toLocaleString()}`;
var metricFTE = SavingsCard.querySelector('#metricFTE #metricValue');
metricFTE.textContent = `≈ ${fteEquivalent} Full-Time Employee (FTE)`;
$('#assumptions-modal').animate({ opacity: 0 }).hide();
}
function UpdateAssumptionsUX()
{
}
// agency purchase credits code
async function purchaseProduct(productType, productName) {
const button = event.target;
const originalText = button.textContent;
// Disable button and show loading state
button.disabled = true;
button.textContent = 'Processing...';
button.classList.add('loading');
try {
// Get user info from localStorage
const userInfo = {
memberID: localStorage.getItem("memberID"),
authToken: localStorage.getItem("auth_token")
};
// Validate user is logged in
if (!userInfo.memberID || !userInfo.authToken) {
alert("Please log in before purchasing");
hideLoadingState();
return;
}
var currentProtocol = window.location.protocol;
var currentHostname = window.location.hostname;
var currentPath = window.location.pathname;
var successUrl = `${currentProtocol}//${currentHostname}${currentPath}?success=true`;
var cancelUrl = `${currentProtocol}//${currentHostname}${currentPath}?cancel=true`;
// Call your Lambda to create Stripe checkout session
const response = await fetch('https://j8glspknjh.execute-api.eu-west-1.amazonaws.com/Production/Checkout', {
method: 'POST',
body: JSON.stringify({
operation: 'create-agency-checkout-session',
productType: productType,
successUrl: successUrl,
cancelUrl: cancelUrl,
userInfo: userInfo
})
});
const result = await response.json();
if (result.url) {
// Redirect to Stripe checkout
window.location.href = result.url;
} else {
throw new Error('Failed to create checkout session');
}
} catch (error) {
console.error('Error creating checkout session:', error);
alert('Sorry, there was an error processing your request. Please try again.');
} finally {
// Re-enable button
button.disabled = false;
button.textContent = originalText;
button.classList.remove('loading');
}
}
// new dropdown methods
// activities dropdown
function populateActivitiesDropdown(dropdown, jobObj, jobSegmentIndex) {
// Clear existing options
dropdown.innerHTML = '';
// Add default option
let defaultOption = document.createElement('option');
defaultOption.value = '';
defaultOption.textContent = 'Select Activity...';
defaultOption.disabled = true;
defaultOption.selected = true;
dropdown.appendChild(defaultOption);
// Get the current job segment
const currentJobSegment = jobObj["JobSegments"][jobSegmentIndex];
// Check if activities exist
if (!currentJobSegment || !currentJobSegment["Activities"]) {
console.warn('No activities found for job segment index:', jobSegmentIndex);
return;
}
// Iterate through activities and create options
currentJobSegment["Activities"].forEach((activity, activityIndex) => {
let option = document.createElement('option');
option.value = `${jobSegmentIndex}_${activityIndex}`;
option.textContent = activity["Title"];
option.dataset.jobSegmentIndex = jobSegmentIndex;
option.dataset.activityIndex = activityIndex;
dropdown.appendChild(option);
});
// Add change event listener to handle selection
dropdown.addEventListener('change', function(e) {
const selectedOption = e.target.selectedOptions[0];
if (selectedOption && selectedOption.value !== '') {
const jobSegmentIndex = selectedOption.dataset.jobSegmentIndex;
const activityIndex = selectedOption.dataset.activityIndex;
showActivityDiv(jobSegmentIndex, activityIndex);
}
});
}
function showActivityDiv(jobSegmentIndex, activityIndex) {
// Hide all activity divs for this job segment
hideAllActivityDivs(jobSegmentIndex);
// Show the selected activity div
const targetDivId = `jobActivity_${jobSegmentIndex}_Activity_${activityIndex}`;
const targetDiv = document.getElementById(targetDivId);
if (targetDiv) {
// Show the div
targetDiv.style.display = 'block';
// Scroll to the div
targetDiv.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
console.log(`Showing activity div: ${targetDivId}`);
} else {
console.warn(`Activity div not found: ${targetDivId}`);
}
}
function hideAllActivityDivs(jobSegmentIndex) {
// Find all divs that match the pattern for this job segment
const activityDivs = document.querySelectorAll(`[id^="jobActivity_${jobSegmentIndex}_Activity_"]`);
activityDivs.forEach(div => {
div.style.display = 'none';
});
console.log(`Hidden ${activityDivs.length} activity divs for job segment ${jobSegmentIndex}`);
}
// Alternative function if you want to hide ALL activity divs across all job segments
function hideAllActivityDivsGlobal() {
const activityDivs = document.querySelectorAll('[id^="jobActivity_"]');
activityDivs.forEach(div => {
div.style.display = 'none';
});
console.log(`Hidden ${activityDivs.length} activity divs globally`);
}
// Usage example:
// Assuming you have your jobObj and know the current jobSegmentIndex
function setupActivitiesDropdown(jobObj, jobSegmentIndex, dropdown) {
// Populate the dropdown with activities
populateActivitiesDropdown(dropdown, jobObj, jobSegmentIndex);
return headerWithDropdown;
}
// Example of how to use this with your job object:
/*
// Assuming you have:
// - jobObj: your job object with JobSegments
// - currentJobSegmentIndex: the index of the current job segment you want to display
const jobSegmentIndex = 0; // or whatever index you're currently viewing
const headerContainer = setupActivitiesDropdown(jobObj, jobSegmentIndex);
document.body.appendChild(headerContainer);
*/
function populateJobSegmentDropdown(jobObj) {
// Find the dropdown element
const dropdown = document.getElementById('jobsegment-dropdown-top');
if (!dropdown) {
console.error('Dropdown with id "jobsegment-dropdown-top" not found');
return;
}
// Clear existing options
dropdown.innerHTML = '';
// Add default option
let defaultOption = document.createElement('option');
defaultOption.value = '';
defaultOption.textContent = 'Select Job Segment...';
defaultOption.disabled = true;
defaultOption.selected = true;
dropdown.appendChild(defaultOption);
// Check if JobSegments exist
if (!jobObj || !jobObj["JobSegments"]) {
console.warn('No JobSegments found in jobObj');
return;
}
// Iterate through JobSegments and create options
jobObj["JobSegments"].forEach((jobSegment, index) => {
let option = document.createElement('option');
option.value = index;
option.textContent = jobSegment["Name"];
option.dataset.jobSegmentIndex = index;
dropdown.appendChild(option);
});
// Add change event listener to handle selection
dropdown.addEventListener('change', function(e) {
const selectedOption = e.target.selectedOptions[0];
if (selectedOption && selectedOption.value !== '') {
const jobSegmentIndex = selectedOption.dataset.jobSegmentIndex;
//showJobActivitiesDiv(parseInt(jobSegmentIndex )+1);
showJobActivitiesDiv(parseInt(jobSegmentIndex));
}
});
}
function showJobActivitiesDiv(jobSegmentIndex) {
// Hide all JobActivities divs
hideAllJobActivitiesDivs();
// Show the selected JobActivities div
const targetDivId = `JobActivities_${jobSegmentIndex}`;
const targetDiv = document.getElementById(targetDivId);
if (targetDiv) {
// Show the div
targetDiv.style.display = 'block';
// Scroll to the div
targetDiv.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
console.log(`Showing JobActivities div: ${targetDivId}`);
} else {
console.warn(`JobActivities div not found: ${targetDivId}`);
}
}
function hideAllJobActivitiesDivs() {
// Find all divs that match the JobActivities pattern
const jobActivitiesDivs = document.querySelectorAll('[id^="JobActivities_"]');
jobActivitiesDivs.forEach(div => {
div.style.display = 'none';
});
console.log(`Hidden ${jobActivitiesDivs.length} JobActivities divs`);
}
// Function to get the currently selected job segment index
function getCurrentJobSegmentIndex() {
const dropdown = document.getElementById('jobsegment-dropdown-top');
if (dropdown && dropdown.value !== '') {
return parseInt(dropdown.value);
}
return null;
}
// switchTab('tasks');
// switchTab('workflows');
function switchTab(ActivityElement, tabName) {
// Hide all tab contents
const tabContents = ActivityElement.querySelectorAll('.tab-content');
tabContents.forEach(content => {
content.classList.remove('active');
});
// Remove active class from all tab buttons
const tabButtons = ActivityElement.querySelectorAll('.tab-button');
tabButtons.forEach(button => {
button.classList.remove('active');
});
// Show selected tab content
ActivityElement.querySelector('#' + tabName + '-content').classList.add('active');
// Add active class to clicked button
event.target.classList.add('active');
}
// Function to programmatically select a job segment
function selectJobSegment(jobSegmentIndex) {
const dropdown = document.getElementById('jobsegment-dropdown-top');
if (dropdown) {
dropdown.value = jobSegmentIndex;
// Trigger the change event to show the corresponding div
const event = new Event('change');
dropdown.dispatchEvent(event);
}
}
// Usage example and initialization
function initializeJobSegmentDropdown(jobObj) {
// Populate the dropdown with job segment names
populateJobSegmentDropdown(jobObj);
// Optionally, you can set a default selection
// selectJobSegment(0); // This would select the first job segment
}
// Example of how to use this:
/*
// Call this when your page loads or when jobObj is available
initializeJobSegmentDropdown(jobObj);
// You can also manually trigger selections:
// selectJobSegment(1); // Select the second job segment
// getCurrentJobSegmentIndex(); // Get the currently selected index
*/
/**
* Display workflow cards in a specified container
*
* @param {Array} workflows - Array of workflow objects from the API
* @param {string} containerId - ID of the container element to render cards into
* @returns {void}
*
* @example
* // Display in the Workflows tab
* displayWorkflows(workflows, 'workflows-content');
*
* @example
* // Display in a task-specific results container
* displayWorkflows(workflows, 'task-results-123');
*/
function displayWorkflows(workflows, parentDiv) {
var parentDivId = parentDiv?.id ?? $(parentDiv).attr('id');
//var container = document.querySelector('#' + parentDivId + ' #workflows-container');
var container = parentDiv.querySelector("[id^='workflows-container']");
//workflows-container-activity-
if (!container) {
console.error(`Container with ID "${containerId}" not found`);
return;
}
// Clear existing content
container.innerHTML = '';
// Create wrapper for cards
const cardsWrapper = document.createElement('div');
cardsWrapper.className = 'workflows-grid';
cardsWrapper.style.display = 'grid';
cardsWrapper.style.gridTemplateColumns = 'repeat(auto-fill, minmax(350px, 1fr))';
cardsWrapper.style.gap = '20px';
cardsWrapper.style.padding = '20px';
// Handle empty results
if (!workflows || workflows.length === 0) {
const emptyMessage = document.createElement('div');
emptyMessage.style.textAlign = 'center';
emptyMessage.style.padding = '40px';
emptyMessage.style.color = '#6b7280';
emptyMessage.innerHTML = 'No workflows found matching your search.
';
container.appendChild(emptyMessage);
return;
}
// Create a card for each workflow
workflows.forEach((workflow, index) => {
const card = createWorkflowCard(workflow, index);
cardsWrapper.appendChild(card);
});
container.appendChild(cardsWrapper);
}
/**
* Create a single workflow card element
*
* @param {Object} workflow - Workflow object from API
* @param {number} index - Index in the workflows array
* @returns {HTMLElement} The card element
*/
function createWorkflowCard(workflow, index) {
const { metadata, score } = workflow;
// Main card container
const card = document.createElement('div');
card.className = 'workflow-card';
card.style.border = '1px solid #e5e7eb';
card.style.borderRadius = '8px';
card.style.padding = '20px';
card.style.backgroundColor = '#ffffff';
card.style.cursor = 'pointer';
card.style.transition = 'all 0.2s';
card.style.position = 'relative';
// Hover effect
card.addEventListener('mouseenter', function() {
this.style.boxShadow = '0 4px 6px -1px rgba(0, 0, 0, 0.1)';
this.style.borderColor = '#3b82f6';
});
card.addEventListener('mouseleave', function() {
this.style.boxShadow = 'none';
this.style.borderColor = '#e5e7eb';
});
// Title
const title = document.createElement('h3');
title.textContent = metadata.templateName;
title.style.fontSize = '16px';
title.style.fontWeight = '600';
title.style.color = '#111827';
title.style.marginBottom = '16px';
title.style.lineHeight = '1.5';
card.appendChild(title);
// Badges container
const badgesContainer = document.createElement('div');
badgesContainer.style.display = 'flex';
badgesContainer.style.flexWrap = 'wrap';
badgesContainer.style.gap = '8px';
badgesContainer.style.marginBottom = '16px';
// Complexity badge
const complexityBadge = createComplexityBadge(metadata.complexity);
badgesContainer.appendChild(complexityBadge);
// Node count badge
const nodeCountBadge = createNodeCountBadge(metadata.nodeCount);
badgesContainer.appendChild(nodeCountBadge);
// Setup time badge
const setupTimeBadge = createSetupTimeBadge(metadata.complexity);
badgesContainer.appendChild(setupTimeBadge);
// Relevance score badge
if (score !== undefined && score !== null) {
const scoreBadge = createScoreBadge(score);
badgesContainer.appendChild(scoreBadge);
}
card.appendChild(badgesContainer);
// Category info
const categoryInfo = document.createElement('div');
categoryInfo.style.fontSize = '13px';
categoryInfo.style.color = '#6b7280';
categoryInfo.style.marginBottom = '16px';
categoryInfo.textContent = `${metadata.category}${metadata.subcategory ? ' • ' + metadata.subcategory : ''}`;
card.appendChild(categoryInfo);
// Buttons container
const buttonsContainer = document.createElement('div');
buttonsContainer.style.display = 'flex';
buttonsContainer.style.gap = '8px';
buttonsContainer.style.marginTop = '16px';
// Get Template button
const getTemplateBtn = document.createElement('button');
getTemplateBtn.className = 'btn-get-template';
getTemplateBtn.innerHTML = `
Get Template
`;
getTemplateBtn.style.display = 'inline-flex';
getTemplateBtn.style.alignItems = 'center';
getTemplateBtn.style.padding = '8px 16px';
getTemplateBtn.style.backgroundColor = '#3b82f6';
getTemplateBtn.style.color = '#ffffff';
getTemplateBtn.style.border = 'none';
getTemplateBtn.style.borderRadius = '6px';
getTemplateBtn.style.fontSize = '14px';
getTemplateBtn.style.fontWeight = '500';
getTemplateBtn.style.cursor = 'pointer';
getTemplateBtn.style.transition = 'background-color 0.2s';
getTemplateBtn.addEventListener('mouseenter', function() {
this.style.backgroundColor = '#2563eb';
});
getTemplateBtn.addEventListener('mouseleave', function() {
this.style.backgroundColor = '#3b82f6';
});
getTemplateBtn.addEventListener('click', function(e) {
e.stopPropagation();
window.open(metadata.url, '_blank');
});
buttonsContainer.appendChild(getTemplateBtn);
// More Info button
const moreInfoBtn = document.createElement('button');
moreInfoBtn.className = 'btn-more-info';
moreInfoBtn.innerHTML = `
More Info
`;
moreInfoBtn.style.display = 'inline-flex';
moreInfoBtn.style.alignItems = 'center';
moreInfoBtn.style.padding = '8px 16px';
moreInfoBtn.style.backgroundColor = '#f3f4f6';
moreInfoBtn.style.color = '#374151';
moreInfoBtn.style.border = '1px solid #d1d5db';
moreInfoBtn.style.borderRadius = '6px';
moreInfoBtn.style.fontSize = '14px';
moreInfoBtn.style.fontWeight = '500';
moreInfoBtn.style.cursor = 'pointer';
moreInfoBtn.style.transition = 'background-color 0.2s';
moreInfoBtn.addEventListener('mouseenter', function() {
this.style.backgroundColor = '#e5e7eb';
});
moreInfoBtn.addEventListener('mouseleave', function() {
this.style.backgroundColor = '#f3f4f6';
});
moreInfoBtn.addEventListener('click', function(e) {
e.stopPropagation();
// TODO: Implement expanded view functionality
console.log('Show expanded view for workflow:', workflow);
alert('Expanded view coming soon!');
});
buttonsContainer.appendChild(moreInfoBtn);
card.appendChild(buttonsContainer);
// Card click handler (for expanded view)
card.addEventListener('click', function() {
// TODO: Implement expanded view functionality
console.log('Card clicked:', workflow);
alert('Expanded view coming soon!');
});
return card;
}
/**
* Create complexity badge element
*
* @param {string} complexity - Complexity level (simple, medium, complex)
* @returns {HTMLElement} Badge element
*/
function createComplexityBadge(complexity) {
const badge = document.createElement('span');
badge.style.display = 'inline-flex';
badge.style.alignItems = 'center';
badge.style.padding = '4px 10px';
badge.style.borderRadius = '12px';
badge.style.fontSize = '12px';
badge.style.fontWeight = '500';
let label, bgColor, textColor;
switch(complexity?.toLowerCase()) {
case 'simple':
label = 'Beginner';
bgColor = '#dcfce7';
textColor = '#166534';
break;
case 'medium':
label = 'Intermediate';
bgColor = '#fef3c7';
textColor = '#92400e';
break;
case 'complex':
label = 'Advanced';
bgColor = '#fee2e2';
textColor = '#991b1b';
break;
default:
label = 'Unknown';
bgColor = '#f3f4f6';
textColor = '#6b7280';
}
badge.style.backgroundColor = bgColor;
badge.style.color = textColor;
badge.textContent = label;
return badge;
}
/**
* Create node count badge element
*
* @param {number} nodeCount - Number of nodes in workflow
* @returns {HTMLElement} Badge element
*/
function createNodeCountBadge(nodeCount) {
const badge = document.createElement('span');
badge.style.display = 'inline-flex';
badge.style.alignItems = 'center';
badge.style.padding = '4px 10px';
badge.style.borderRadius = '12px';
badge.style.fontSize = '12px';
badge.style.fontWeight = '500';
badge.style.backgroundColor = '#eff6ff';
badge.style.color = '#1e40af';
badge.innerHTML = `
${nodeCount} nodes
`;
return badge;
}
/**
* Create setup time badge based on complexity
*
* @param {string} complexity - Complexity level
* @returns {HTMLElement} Badge element
*/
function createSetupTimeBadge(complexity) {
const badge = document.createElement('span');
badge.style.display = 'inline-flex';
badge.style.alignItems = 'center';
badge.style.padding = '4px 10px';
badge.style.borderRadius = '12px';
badge.style.fontSize = '12px';
badge.style.fontWeight = '500';
badge.style.backgroundColor = '#f5f3ff';
badge.style.color = '#6b21a8';
let setupTime;
switch(complexity?.toLowerCase()) {
case 'simple':
setupTime = '15min';
break;
case 'medium':
setupTime = '30min';
break;
case 'complex':
setupTime = '60min';
break;
default:
setupTime = '30min';
}
badge.innerHTML = `
${setupTime} setup
`;
return badge;
}
/**
* Create relevance score badge
*
* @param {number} score - Relevance score (0-1)
* @returns {HTMLElement} Badge element
*/
function createScoreBadge(score) {
const badge = document.createElement('span');
badge.style.display = 'inline-flex';
badge.style.alignItems = 'center';
badge.style.padding = '4px 10px';
badge.style.borderRadius = '12px';
badge.style.fontSize = '12px';
badge.style.fontWeight = '500';
badge.style.backgroundColor = '#fef9c3';
badge.style.color = '#854d0e';
// Convert score to percentage
const percentage = Math.round(score * 100);
badge.innerHTML = `
${percentage}% match
`;
return badge;
}
// Export functions if using modules
// export { displayWorkflows, createWorkflowCard };