// Product query params (no category filter) function product_query_params(p) { return { limit: p.limit, sort: p.sort, order: p.order, offset: p.offset, search: p.search }; } // Category wise filter query params for promoted products function category_query_params(p) { return { category_id: $('#category_filter').val(), limit: p.limit, sort: p.sort, order: p.order, offset: p.offset, search: p.search }; } $(document).on('change', '#category_filter', function () { $('#products_table').bootstrapTable('refresh'); }); function wallet_transaction_queryParams(p) { return { transaction_type: $('#transaction_type_filter').val(), payment_type: $('#transaction_type').val(), limit: p.limit, sort: p.sort, order: p.order, offset: p.offset, search: p.search }; } $(document).on('change', '#transaction_type_filter, #transaction_type', function () { $('#affiliate_wallet_transaction_table').bootstrapTable('refresh'); }); $(document).on('click', '.copy-affiliate-link-btn', function () { const btn = $(this); const productId = btn.data('product_id'); const productSlug = btn.data('slug'); const userId = btn.data('user_id'); const productName = btn.data('name'); const categoryId = btn.data('category_id'); const affiliateCommission = btn.data('affiliate_commission'); // Get CSRF values // Disable button btn.prop('disabled', true).html('<i class="ti ti-loader-2 spinner me-2"></i> Generating...'); $.ajax({ url: base_url + 'affiliate/product/get_or_generate_token', type: 'POST', dataType: 'json', data: { product_id: productId, product_name: productName, user_id: userId, category_id: categoryId, affiliate_commission: affiliateCommission, [csrfName]: csrfHash // Dynamic key }, success: function (res) { // Update CSRF hash for next request csrfHash = res.csrfHash; if (!res.error && res.token) { const url = `${base_url}products/details/${productSlug}?ref=${res.token}`; navigator.clipboard.writeText(url).then(() => { showToast('Affiliate link copied!', 'success'); btn.html('<i class="ti ti-check me-2"></i> Copied!'); setTimeout(() => resetButton(btn), 2000); }).catch(() => { fallbackCopy(url, btn); }); } else { showToast(res.message || 'Failed to generate link.', 'error'); resetButton(btn); } }, error: function (xhr) { console.error('AJAX Error:', xhr.responseText); showToast('Request failed. Please try again.', 'error'); resetButton(btn); } }); }); // Fallback copy function fallbackCopy(text, btn) { const textarea = document.createElement('textarea'); textarea.value = text; textarea.style.position = 'fixed'; document.body.appendChild(textarea); textarea.select(); try { document.execCommand('copy'); showToast('Copied (fallback)!', 'success'); } catch (e) { showToast('Copy failed. URL: ' + text, 'warning'); } document.body.removeChild(textarea); resetButton(btn); } function resetButton(btn) { btn.html('<i class="ti ti-copy me-2"></i> Copy Affiliate Link').prop('disabled', false); } function resetButton(btn) { btn.html('<i class="ti ti-copy me-2"></i> Copy Affiliate Link').prop('disabled', false); } // Fallback for older browsers or permission issues function fallbackCopy(text, btn) { const tempInput = document.createElement('textarea'); tempInput.style.position = 'absolute'; tempInput.style.left = '-9999px'; tempInput.value = text; document.body.appendChild(tempInput); tempInput.select(); try { document.execCommand('copy'); showToast('Link copied (fallback)!', 'success'); } catch (err) { showToast('Copy failed. Please copy manually: ' + text, 'warning'); } document.body.removeChild(tempInput); resetButton(btn); } function resetButton(btn) { btn.html('<i class="ti ti-copy me-2"></i> Copy Affiliate Link').prop('disabled', false); } $(document).ready(function () { if (window.location.href.indexOf('affiliate') > -1 && window.location.href.indexOf('admin/affiliate') === -1) { var fetch_sales_url = base_url + "affiliate/home/fetch_sales" var most_selling_affiliate_categories_url = base_url + "affiliate/home/most_selling_affiliate_categories" // Function to fetch sales data and render the charts function fetchAndRenderAffiliateCharts() { // Check if the chart container exists if (!document.querySelector(".affiliate-chart-container")) { console.error("Chart container '.affiliate-chart-container' not found!"); return; } $.ajax({ url: fetch_sales_url, type: "GET", dataType: "json", success: function (response) { // Assuming response data structure as you provided let monthlyData = response[0]; let weeklyData = response[1]; let dailyData = response[2]; const data = { Monthly: { series: [{ name: 'Monthly Earning', data: monthlyData.total_sale || [] }], categories: monthlyData.month_name || [], colors: ['#1E90FF'] }, Weekly: { series: [{ name: 'Weekly Earning', data: weeklyData.total_sale || [] }], categories: weeklyData.week || [], colors: ['#32CD32'] }, Daily: { series: [{ name: 'Daily Earning', data: dailyData.total_sale || [] }], categories: dailyData.day || [], colors: ['#990099'] } }; let chartData = data['Monthly']; const options = { chart: { type: 'bar', height: 350 }, plotOptions: { bar: { horizontal: false, columnWidth: '55%', endingShape: 'rounded' }, }, series: chartData.series, dataLabels: { enabled: false }, stroke: { show: true, width: 2, colors: ['transparent'] }, xaxis: { categories: chartData.categories }, yaxis: { labels: { formatter: function (value) { if (value >= 1000) { return (value / 1000).toFixed(1) + 'k'; } return value.toFixed(0); } } }, fill: { opacity: 1, }, tooltip: { y: { formatter: function (val) { return val.toFixed(2); } } } }; const chart = new ApexCharts(document.querySelector(".affiliate-chart-container"), options); chart.render(); $(".sales-tab a").on("click", function (e) { e.preventDefault(); // Prevent default anchor behavior // Remove active class from all tabs $(".sales-tab a").removeClass('active'); // Add active to clicked tab $(this).addClass('active'); // Get the period from href (#Monthly, #Weekly, #Daily) let period = $(this).attr("href").replace('#', ''); // Update chart data chartData = data[period]; chart.updateOptions({ series: chartData.series, xaxis: { categories: chartData.categories } }); }); }, error: function (xhr, status, error) { console.error("Error fetching sales data:"); console.error("Status:", status); console.error("Error:", error); console.error("Response:", xhr.responseText); } }); } // Function to fetch sales data and render the charts function fetchAndRenderCategoryCharts() { $.ajax({ url: most_selling_affiliate_categories_url, type: "GET", dataType: "json", success: function (response) { // Assuming response data structure as you provided console.log('AJAX Success:', response); var options = { series: response.sales.map(Number), chart: { type: 'donut', height: '100%', width: '100%', toolbar: { show: false }, redrawOnWindowResize: true, redrawOnParentResize: true }, plotOptions: { pie: { startAngle: -90, endAngle: 270, donut: { size: '75%' // better fit } } }, fill: { type: 'gradient' }, labels: response.category, legend: { position: 'bottom', fontSize: '13px', labels: { colors: '#333' } }, responsive: [ { breakpoint: 992, options: { chart: { height: 260 }, legend: { position: 'bottom' } } }, { breakpoint: 576, options: { chart: { height: 240 }, plotOptions: { pie: { donut: { size: '70%' } } } } } ] }; var chartCategory = new ApexCharts(document.querySelector("#piechart_3d_affiliate"), options); chartCategory.render(); $(".chart-height li a").on("click", function () { $(".chart-height li a").removeClass('active'); $(this).addClass('active'); }); }, error: function (error) { console.error("Error fetching data: ", error); } }); } // Initial chart rendering fetchAndRenderAffiliateCharts(); fetchAndRenderCategoryCharts(); } }); $(document).ready(function () { $('#add_user_form').on('submit', function (e) { e.preventDefault(); // stop form submit initially const website = $('#my_website').val().trim(); const app = $('#my_app').val().trim(); // URL validation regex const urlPattern = /^(https?:\/\/)[\w.-]+(\.[\w\.-]+)+[\/#?]?.*$/; // check validity if (!urlPattern.test(website)) { showToast('Please enter a valid Website URL starting with http:// or https://', 'error'); return false; } if (!urlPattern.test(app)) { showToast('Please enter a valid App URL starting with http:// or https://', 'error'); return false; } // if valid → continue with form submission (AJAX or normal) this.submit(); }); });