Software: Apache. PHP/8.1.30 uname -a: Linux server1.tuhinhossain.com 5.15.0-163-generic #173-Ubuntu SMP Tue Oct 14 17:51:00 UTC uid=1002(picotech) gid=1003(picotech) groups=1003(picotech),0(root) Safe-mode: OFF (not secure) /home/picotech/domains/test.sms.picotech.app/public_html/public/js/ drwxr-xr-x | |
| Viewing file: Select action/file-type: /**
* PicoSMS Customer Panel Tour Guide
* Professional onboarding tour for new customers with page navigation
* Maintains tour progress across page redirects using sessionStorage
*/
(function () {
'use strict';
// Check if Shepherd is loaded
if (typeof Shepherd === 'undefined') {
console.error('Shepherd.js is not loaded. Please include it before this script.');
return;
}
// Storage keys
const TOUR_ACTIVE_KEY = 'picosms_customer_tour_active';
const TOUR_STEP_KEY = 'picosms_customer_tour_step';
// Helper function to navigate to a page
function navigateToPage(url, nextStepId) {
return new Promise((resolve) => {
if (window.location.pathname === url || window.location.href.includes(url)) {
// Already on the page
resolve();
} else {
// Save that we're in the middle of a tour
sessionStorage.setItem(TOUR_ACTIVE_KEY, 'true');
sessionStorage.setItem(TOUR_STEP_KEY, nextStepId);
// Navigate to the page
window.location.href = url;
// Don't resolve - page will reload
}
});
}
// Tour configuration
const tourConfig = {
useModalOverlay: true,
defaultStepOptions: {
classes: 'shepherd-theme-custom',
scrollTo: { behavior: 'smooth', block: 'center' },
cancelIcon: {
enabled: true
}
}
};
// Initialize tour
const customerTour = new Shepherd.Tour(tourConfig);
// Save current step whenever it changes
customerTour.on('show', function () {
const currentStep = customerTour.getCurrentStep();
if (currentStep) {
sessionStorage.setItem(TOUR_STEP_KEY, currentStep.id);
}
});
// Clear storage when tour completes or is cancelled
customerTour.on('complete', function () {
sessionStorage.removeItem(TOUR_ACTIVE_KEY);
sessionStorage.removeItem(TOUR_STEP_KEY);
});
customerTour.on('cancel', function () {
sessionStorage.removeItem(TOUR_ACTIVE_KEY);
sessionStorage.removeItem(TOUR_STEP_KEY);
});
// Helper function to create buttons
function createButtons(showBack = true, showNext = true, isLast = false) {
const buttons = [];
if (showBack) {
buttons.push({
text: 'Back',
classes: 'shepherd-button-secondary',
action: customerTour.back
});
}
if (showNext && !isLast) {
buttons.push({
text: 'Next',
classes: 'shepherd-button-primary',
action: customerTour.next
});
}
if (isLast) {
buttons.push({
text: `Start Using ${window.appName || 'PicoSMS'}`,
classes: 'shepherd-button-primary',
action: function () {
completeTour();
customerTour.complete();
}
});
}
return buttons;
}
// Step 1: Welcome
customerTour.addStep({
id: 'welcome',
title: 'Welcome to Your SMS Portal!',
text: `
<div class="shepherd-welcome-modal">
<p>Welcome to ${window.appName || 'PicoSMS'}! This quick tour will show you how to send SMS campaigns, manage contacts, check coverage, and track your results.</p>
<p>You can skip this tour at any time and restart it later from the help menu.</p>
</div>
`,
classes: 'shepherd-welcome-modal',
buttons: [
{
text: 'Skip Tour',
classes: 'shepherd-button-skip',
action: function () {
completeTour();
customerTour.cancel();
}
},
{
text: 'Get Started',
classes: 'shepherd-button-primary',
action: customerTour.next
}
]
});
// Step 2: Dashboard Overview
customerTour.addStep({
id: 'dashboard-overview',
title: 'Your SMS Statistics',
text: `
<div class="shepherd-step-counter">Step 1 of 10</div>
<p>Your dashboard shows important metrics about your SMS activity. Monitor your daily sent messages, delivery rates, response rates, and expenses. These numbers update in real-time to help you track your campaign performance.</p>
`,
beforeShowPromise: function () {
return navigateToPage('/dashboard', 'dashboard-overview');
},
attachTo: {
element: '#counters',
on: 'bottom'
},
buttons: createButtons(true, true)
});
// Step 3: Coverage Check
customerTour.addStep({
id: 'coverage-check',
title: 'Check Service Coverage',
text: `
<div class="shepherd-step-counter">Step 2 of 10</div>
<p>Before sending messages, check if we provide coverage for your target countries or regions. You can view pricing, delivery rates, and available features for each coverage area. This helps you plan your campaigns effectively.</p>
<p><strong>Click on the "See Coverage" link to view the coverage details.</strong></p>
`,
beforeShowPromise: function () {
return navigateToPage('/billing', 'coverage-check');
},
attachTo: {
element: '.plan-coverage',
on: 'left'
},
buttons: createButtons(true, true)
});
// Step 4: Contacts Management
customerTour.addStep({
id: 'contacts-management',
title: 'Organize Your Contacts',
text: `
<div class="shepherd-step-counter">Step 3 of 10</div>
<p>Import and manage your contact lists here. You can upload contacts from CSV files, create groups, add custom fields, and segment your audience. Well-organized contacts make your campaigns more targeted and effective.</p>
<p><strong>Click on the "Phonebook" for details</strong></p>
`,
beforeShowPromise: function () {
// return navigateToPage('/contacts', 'contacts-management');
},
attachTo: {
element: '#contacts-management',
on: 'left'
},
buttons: createButtons(true, true)
});
// Step 5: Phone Number Management
customerTour.addStep({
id: 'phone-number',
title: 'Purchase Phone Number',
text: `
<div class="shepherd-step-counter">Step 4 of 10</div>
<p>Purchase phone numbers to send SMS messages. You can choose from different types of phone numbers, such as local, toll-free, or vanity numbers. These numbers help you build trust with your audience and improve your brand's reputation.</p>
<p><strong>Click on the "Phone Number" for details</strong></p>
`,
beforeShowPromise: function () {
return navigateToPage('phone-numbers', 'phone-number');
},
attachTo: {
element: '#sending-config',
on: 'left'
},
buttons: createButtons(true, true)
});
// Step 6: Message Templates
customerTour.addStep({
id: 'templates',
title: 'Save Time with Templates',
text: `
<div class="shepherd-step-counter">Step 5 of 10</div>
<p>Create reusable message templates for your common communications. Templates save time and ensure consistency in your messaging. You can use placeholders to personalize messages with contact-specific information.</p>
<p><strong>Click on the "SMS Templates" for details</strong></p>
`,
beforeShowPromise: function () {
return navigateToPage('/sms-template', 'templates');
},
attachTo: {
element: '#sms-template',
on: 'left'
},
buttons: createButtons(true, true)
});
// Step 7: SMS Campaigns
customerTour.addStep({
id: 'sms-campaigns',
title: 'Create SMS Campaigns',
text: `
<div class="shepherd-step-counter">Step 6 of 10</div>
<p>Send SMS messages to your contacts. You can create one-time campaigns, schedule messages for later, or set up automated campaigns. Track delivery status, responses, and engagement for each campaign you send.</p>
<p><strong>Click on the "Regular Campaigns" for details</strong></p>
`,
beforeShowPromise: function () {
return navigateToPage('/campaign', 'sms-campaigns');
},
attachTo: {
element: '#campaign-management',
on: 'left'
},
buttons: createButtons(true, true)
});
// Step 8: Reports & Analytics
customerTour.addStep({
id: 'reports',
title: 'Track Your Results',
text: `
<div class="shepherd-step-counter">Step 7 of 10</div>
<p>View detailed reports about your SMS campaigns. See delivery rates, failed messages, response rates, and engagement metrics. Use these insights to optimize your messaging strategy and improve results.</p>
<p><strong>Click on the "Reports" for details</strong></p>
`,
beforeShowPromise: function () {
return navigateToPage('/message/reports', 'reports');
},
attachTo: {
element: '#report-sidebar',
on: 'left'
},
buttons: createButtons(true, true)
});
// Step 9: Billing & Credits
customerTour.addStep({
id: 'billing',
title: 'Manage Your Account Balance',
text: `
<div class="shepherd-step-counter">Step 8 of 10</div>
<p>Check your current balance, view invoices, and top up your account. You can see your spending history, download invoices for accounting, and set up auto-recharge to ensure you never run out of credits.</p>
<p><strong>Click on the "Billing" for details</strong></p>
`,
beforeShowPromise: function () {
return navigateToPage('/billing', 'billing');
},
attachTo: {
element: '#billing-sidebar',
on: 'left'
},
buttons: createButtons(true, true)
});
// Step 10: Account Settings
customerTour.addStep({
id: 'settings',
title: 'Manage Your Account',
text: `
<div class="shepherd-step-counter">Step 9 of 10</div>
<p>Configure your account settings across multiple areas:</p>
<ul style="margin-left: 20px; margin-top: 10px;">
<li><strong>Account:</strong> Update your profile information, name, email, and profile picture</li>
<li><strong>Security:</strong> Change your password and configure OTP (one-time password) settings for enhanced security</li>
<li><strong>Communication:</strong> Configure inbound SMS settings</li>
<li><strong>Integration:</strong> Set up webhooks for real-time notifications and configure notification preferences</li>
</ul>
<p><strong>Click on the "Settings" for details</strong></p>
`,
beforeShowPromise: function () {
return navigateToPage('/settings/index', 'settings');
},
attachTo: {
element: '#settings',
on: 'left'
},
buttons: createButtons(true, true)
});
// Step 11: Completion
customerTour.addStep({
id: 'completion',
title: 'Ready to Send Messages!',
text: `
<div class="shepherd-completion-modal">
<p>Great! You now know how to use all the key features of ${window.appName || 'PicoSMS'}. Start by checking coverage for your target area, importing your contacts, and creating your first campaign.</p>
<p>Need help? Visit our help center or contact support anytime.</p>
</div>
`,
classes: 'shepherd-completion-modal',
buttons: createButtons(false, false, true)
});
// Function to mark tour as completed
function completeTour() {
// Get CSRF token from meta tag or hidden input
let csrfToken = null;
const metaTag = document.querySelector('meta[name="csrf-token"]');
if (metaTag) {
csrfToken = metaTag.getAttribute('content');
} else {
const hiddenInput = document.querySelector('input[name="_token"]');
if (hiddenInput) {
csrfToken = hiddenInput.value;
}
}
if (!csrfToken) {
console.error('CSRF token not found');
return;
}
fetch('/tour/complete', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
}
}).then(response => response.json())
.then(data => {
console.log('Tour completed:', data);
})
.catch(error => {
console.error('Error marking tour as completed:', error);
});
}
// Function to start the tour
window.startCustomerTour = function () {
sessionStorage.setItem(TOUR_ACTIVE_KEY, 'true');
customerTour.start();
};
// Function to reset the tour
window.resetCustomerTour = function () {
// Get CSRF token from meta tag or hidden input
let csrfToken = null;
const metaTag = document.querySelector('meta[name="csrf-token"]');
if (metaTag) {
csrfToken = metaTag.getAttribute('content');
} else {
const hiddenInput = document.querySelector('input[name="_token"]');
if (hiddenInput) {
csrfToken = hiddenInput.value;
}
}
if (!csrfToken) {
console.error('CSRF token not found');
return;
}
fetch('/tour/reset', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
}
}).then(response => response.json())
.then(data => {
console.log('Tour reset:', data);
sessionStorage.removeItem(TOUR_ACTIVE_KEY);
sessionStorage.removeItem(TOUR_STEP_KEY);
window.startCustomerTour();
})
.catch(error => {
console.error('Error resetting tour:', error);
});
};
// Check if we should resume the tour
const isTourActive = sessionStorage.getItem(TOUR_ACTIVE_KEY) === 'true';
const savedStepId = sessionStorage.getItem(TOUR_STEP_KEY);
if (isTourActive && savedStepId) {
// Resume tour from saved step
setTimeout(function () {
customerTour.show(savedStepId);
}, 500);
} else if (window.tourEnabled && typeof window.customerTourCompleted !== 'undefined' && !window.customerTourCompleted) {
// Auto-start tour for new users only if tour is enabled
setTimeout(function () {
customerTour.start();
}, 1000);
}
})();
|
:: Command execute :: | |
--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0086 ]-- |