- Redesign dashboard as daily briefing format with action-first layout - Consolidate sidebar menu structure (Dashboard as single link) - Fix CRM form styling to use consistent UI patterns - Add PWA icons and push notification groundwork - Update SuiteMenuResolver for cleaner navigation
135 lines
5.0 KiB
JavaScript
135 lines
5.0 KiB
JavaScript
import './bootstrap';
|
|
import './push-notifications';
|
|
|
|
import Alpine from 'alpinejs';
|
|
import Precognition from 'laravel-precognition-alpine';
|
|
import persist from '@alpinejs/persist';
|
|
import morph from '@alpinejs/morph';
|
|
import intersect from '@alpinejs/intersect';
|
|
import collapse from '@alpinejs/collapse';
|
|
import Sortable from 'sortablejs';
|
|
import Choices from 'choices.js';
|
|
import 'choices.js/public/assets/styles/choices.min.css';
|
|
import ApexCharts from 'apexcharts';
|
|
import { animate } from 'animejs';
|
|
import CalHeatmap from 'cal-heatmap';
|
|
import 'cal-heatmap/cal-heatmap.css';
|
|
import Quill from 'quill';
|
|
import 'quill/dist/quill.snow.css';
|
|
|
|
window.Alpine = Alpine;
|
|
window.Sortable = Sortable;
|
|
window.Choices = Choices;
|
|
window.ApexCharts = ApexCharts;
|
|
window.anime = animate; // Anime.js v4 renamed anime() to animate()
|
|
window.CalHeatmap = CalHeatmap;
|
|
window.Quill = Quill;
|
|
|
|
// Register Alpine.js plugins
|
|
Alpine.plugin(persist);
|
|
Alpine.plugin(Precognition);
|
|
Alpine.plugin(morph);
|
|
Alpine.plugin(intersect);
|
|
Alpine.plugin(collapse);
|
|
|
|
// Import Password Meter component
|
|
import './components/password-meter.js';
|
|
|
|
// Import Phone Formatter component
|
|
import './components/phone-formatter.js';
|
|
|
|
// Import Search Select component
|
|
import './components/search-select.js';
|
|
|
|
// Route helper function for JavaScript
|
|
window.route = function(name, params = {}) {
|
|
// Simple route helper - in a real app you might use Laravel Ziggy
|
|
const routes = {
|
|
'business.setup': '/business/setup',
|
|
'business.setup.create': '/business/setup',
|
|
'dashboard': '/dashboard',
|
|
'profile.edit': '/profile',
|
|
};
|
|
|
|
return routes[name] || '#';
|
|
};
|
|
|
|
// Currency formatter for consistent display across the app
|
|
window.formatCurrency = function(amount) {
|
|
// Handle null, undefined, or NaN values
|
|
if (amount == null || isNaN(amount)) {
|
|
return '$0.00';
|
|
}
|
|
// Convert to number, format with 2 decimals, and add thousand separators
|
|
return '$' + Number(amount).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
|
};
|
|
|
|
Alpine.start();
|
|
|
|
// FilePond integration
|
|
import * as FilePond from 'filepond';
|
|
import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type';
|
|
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
|
|
import 'filepond/dist/filepond.min.css';
|
|
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css';
|
|
|
|
import "cally";
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
FilePond.registerPlugin(FilePondPluginFileValidateType, FilePondPluginImagePreview);
|
|
document.querySelectorAll('form').forEach(form => {
|
|
form.addEventListener('submit', function(e) {
|
|
// Prevent submission if any FilePond instance is still uploading
|
|
const ponds = Array.from(form.querySelectorAll('input[type="file"].filepond')).map(el => el._pond).filter(Boolean);
|
|
if (ponds.some(pond => pond && pond.status !== 5)) { // 5 = FilePond.Status.IDLE
|
|
e.preventDefault();
|
|
// Optionally show a message to the user
|
|
alert('Please wait for all uploads to finish before submitting.');
|
|
}
|
|
});
|
|
});
|
|
document.querySelectorAll('input[type="file"].filepond').forEach(el => {
|
|
const hidden = document.getElementById(el.name + '_path');
|
|
let files = [];
|
|
if (hidden && hidden.value) {
|
|
files.push({ source: hidden.value, options: { type: 'local' } });
|
|
}
|
|
try {
|
|
const pond = FilePond.create(el, {
|
|
files,
|
|
maxFileSize: '5MB',
|
|
acceptedFileTypes: ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'application/pdf'],
|
|
server: {
|
|
url: '/filepond',
|
|
process: {
|
|
headers: {
|
|
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
|
|
}
|
|
}
|
|
},
|
|
onprocessfile: (error, file) => {
|
|
if (!error && hidden) {
|
|
hidden.value = file.serverId;
|
|
// Also update filename and size
|
|
const nameInput = document.getElementById(el.name + '_name');
|
|
const sizeInput = document.getElementById(el.name + '_size');
|
|
if (nameInput) nameInput.value = file.file.name;
|
|
if (sizeInput) sizeInput.value = file.file.size;
|
|
} else if (error) {
|
|
console.error('FilePond upload error:', error, file);
|
|
}
|
|
},
|
|
onremovefile: () => {
|
|
if (hidden) {
|
|
hidden.value = '';
|
|
}
|
|
},
|
|
});
|
|
// Attach the pond instance to the input for form-level checks
|
|
el._pond = pond;
|
|
} catch (e) {
|
|
console.error('FilePond failed to initialize:', e, el);
|
|
}
|
|
});
|
|
});
|
|
|