create form and modal components, update datatable persistant filtering

This commit is contained in:
Casey 2025-10-30 03:21:41 -05:00
parent b70e08026d
commit 8d9bb81fe2
23 changed files with 3502 additions and 74 deletions

View file

@ -0,0 +1,90 @@
import { defineStore } from "pinia";
import { FilterMatchMode } from "@primevue/core";
export const useFiltersStore = defineStore("filters", {
state: () => ({
// Store filters by table/component name
tableFilters: {
clients: {
fullName: { value: null, matchMode: FilterMatchMode.CONTAINS },
},
jobs: {
customer: { value: null, matchMode: FilterMatchMode.CONTAINS },
jobId: { value: null, matchMode: FilterMatchMode.CONTAINS },
},
timesheets: {
employee: { value: null, matchMode: FilterMatchMode.CONTAINS },
customer: { value: null, matchMode: FilterMatchMode.CONTAINS },
},
warranties: {
customer: { value: null, matchMode: FilterMatchMode.CONTAINS },
warrantyId: { value: null, matchMode: FilterMatchMode.CONTAINS },
address: { value: null, matchMode: FilterMatchMode.CONTAINS },
assignedTechnician: { value: null, matchMode: FilterMatchMode.CONTAINS },
},
routes: {
technician: { value: null, matchMode: FilterMatchMode.CONTAINS },
routeId: { value: null, matchMode: FilterMatchMode.CONTAINS },
}
}
}),
actions: {
// Generic method to get filters for a specific table
getTableFilters(tableName) {
return this.tableFilters[tableName] || {};
},
// Generic method to update a specific filter
updateTableFilter(tableName, fieldName, value, matchMode = null) {
if (!this.tableFilters[tableName]) {
this.tableFilters[tableName] = {};
}
if (!this.tableFilters[tableName][fieldName]) {
this.tableFilters[tableName][fieldName] = {
value: null,
matchMode: FilterMatchMode.CONTAINS
};
}
this.tableFilters[tableName][fieldName].value = value;
// Update match mode if provided
if (matchMode) {
this.tableFilters[tableName][fieldName].matchMode = matchMode;
}
},
// Method to clear all filters for a table
clearTableFilters(tableName) {
if (this.tableFilters[tableName]) {
Object.keys(this.tableFilters[tableName]).forEach(key => {
this.tableFilters[tableName][key].value = null;
});
}
},
// Method to initialize filters for a table if they don't exist
initializeTableFilters(tableName, columns) {
if (!this.tableFilters[tableName]) {
this.tableFilters[tableName] = {};
}
columns.forEach(column => {
if (column.filterable && !this.tableFilters[tableName][column.fieldName]) {
this.tableFilters[tableName][column.fieldName] = {
value: null,
matchMode: FilterMatchMode.CONTAINS
};
}
});
},
// Legacy method for backward compatibility
setClientNameFilter(filterValue) {
this.updateTableFilter('clients', 'fullName', filterValue);
},
// Getter for legacy compatibility
get clientNameFilter() {
return this.tableFilters?.clients?.fullName?.value || "";
}
},
});

View file

@ -1,36 +1,232 @@
import { defineStore } from "pinia";
export const useModalsStore = defineStore("modals", {
export const useModalStore = defineStore("modal", {
state: () => ({
isCreateClientOpen: false,
isCreateInvoiceOpen: false,
isCreateJobOpen: false,
isCreateEstimateOpen: false,
// Dynamic modal registry - can handle any number of modals
modals: {},
// Stack for modal layering (optional)
modalStack: [],
// Component registry for dynamic modals
registeredComponents: {},
// Global modal configuration
globalConfig: {
closeOnEscape: true,
closeOnOutsideClick: true,
preventBodyScroll: true
}
}),
actions: {
openCreateClient() {
this.isCreateClientOpen = true;
getters: {
// Check if any modal is open
hasOpenModal: (state) => {
return Object.values(state.modals).some(modal => modal.isOpen);
},
closeCreateClient() {
this.isCreateClientOpen = false;
// Get modal by ID
getModal: (state) => (modalId) => {
return state.modals[modalId] || null;
},
openCreateInvoice() {
this.isCreateInvoiceOpen = true;
// Check if specific modal is open
isModalOpen: (state) => (modalId) => {
return state.modals[modalId]?.isOpen || false;
},
closeCreateInvoice() {
this.isCreateInvoiceOpen = false;
},
openCreateJob() {
this.isCreateJobOpen = true;
},
closeCreateJob() {
this.isCreateJobOpen = false;
},
openCreateEstimate() {
this.isCreateEstimateOpen = true;
},
closeCreateEstimate() {
this.isCreateEstimateOpen = false;
// Get modal data
getModalData: (state) => (modalId) => {
return state.modals[modalId]?.data || null;
},
// Get the topmost modal in stack
getTopModal: (state) => {
if (state.modalStack.length === 0) return null;
const topModalId = state.modalStack[state.modalStack.length - 1];
return state.modals[topModalId];
}
},
actions: {
// Register a modal component for dynamic loading
registerModalComponent(modalId, component) {
this.registeredComponents[modalId] = component;
},
// Initialize a modal (register it in the store)
initializeModal(modalId, config = {}) {
if (!this.modals[modalId]) {
this.modals[modalId] = {
id: modalId,
isOpen: false,
data: null,
config: {
...this.globalConfig,
...config
},
history: []
};
}
},
// Open a modal with optional data
openModal(modalId, data = null, config = {}) {
// Initialize modal if it doesn't exist
this.initializeModal(modalId, config);
// Close other modals if exclusive mode (default behavior)
if (config.exclusive !== false) {
this.closeAllModals();
}
// Set modal state
this.modals[modalId].isOpen = true;
this.modals[modalId].data = data;
this.modals[modalId].config = {
...this.modals[modalId].config,
...config
};
// Add to stack
if (!this.modalStack.includes(modalId)) {
this.modalStack.push(modalId);
}
// Track opening in history
this.modals[modalId].history.push({
action: 'opened',
timestamp: new Date(),
data: data
});
},
// Close a specific modal
closeModal(modalId) {
if (this.modals[modalId]) {
this.modals[modalId].isOpen = false;
this.modals[modalId].data = null;
// Remove from stack
const index = this.modalStack.indexOf(modalId);
if (index > -1) {
this.modalStack.splice(index, 1);
}
// Track closing in history
this.modals[modalId].history.push({
action: 'closed',
timestamp: new Date()
});
}
},
// Toggle a modal
toggleModal(modalId, data = null, config = {}) {
if (this.isModalOpen(modalId)) {
this.closeModal(modalId);
} else {
this.openModal(modalId, data, config);
}
},
// Close all modals
closeAllModals() {
Object.keys(this.modals).forEach(modalId => {
if (this.modals[modalId].isOpen) {
this.closeModal(modalId);
}
});
this.modalStack = [];
},
// Close the topmost modal
closeTopModal() {
if (this.modalStack.length > 0) {
const topModalId = this.modalStack[this.modalStack.length - 1];
this.closeModal(topModalId);
}
},
// Update modal data without opening/closing
updateModalData(modalId, data) {
if (this.modals[modalId]) {
this.modals[modalId].data = data;
}
},
// Update modal configuration
updateModalConfig(modalId, config) {
if (this.modals[modalId]) {
this.modals[modalId].config = {
...this.modals[modalId].config,
...config
};
}
},
// Remove a modal from the store (cleanup)
removeModal(modalId) {
if (this.modals[modalId]) {
this.closeModal(modalId);
delete this.modals[modalId];
}
},
// Convenience methods for common modals
// Add your specific modal methods here
// Example: Edit User Modal
openEditUser(userData = null) {
this.openModal('editUser', userData, {
closeOnEscape: true,
closeOnOutsideClick: false
});
},
closeEditUser() {
this.closeModal('editUser');
},
// Example: Confirmation Modal
openConfirmation(message, onConfirm, onCancel = null) {
this.openModal('confirmation', {
message,
onConfirm,
onCancel
}, {
closeOnEscape: false,
closeOnOutsideClick: false
});
},
closeConfirmation() {
this.closeModal('confirmation');
},
// Example: Image Gallery Modal
openImageGallery(images, currentIndex = 0) {
this.openModal('imageGallery', {
images,
currentIndex
}, {
closeOnEscape: true,
exclusive: true
});
},
closeImageGallery() {
this.closeModal('imageGallery');
},
// Create Client Modal
openCreateClient(clientData = null) {
this.openModal('createClient', clientData, {
closeOnEscape: true,
closeOnOutsideClick: true,
exclusive: true
});
},
closeCreateClient() {
this.closeModal('createClient');
}
}
});

View file

@ -1,16 +0,0 @@
import { defineStore } from "pinia";
export const useUserStore = defineStore("user", {
state: () => ({
username: "",
roles: [],
}),
actions: {
check_permission(role) {
if (this.roles.includes(role)) {
return true;
}
return false;
},
},
});