Bugfix for data parser and data formatter

This commit is contained in:
Jeremy Rangel
2025-01-26 17:26:55 -08:00
parent c9dedf6c8d
commit 3fe81a23ff
6 changed files with 173 additions and 29 deletions

View File

@ -48,22 +48,22 @@
{
"Department": "Sheriffs Office",
"Budget": "150",
"MeetAt": "12/12/2025",
"PreferredColor": "#e0e0e0",
"MeetAt": "2025-01-26T14:30:00Z",
"preferredColor": "red",
"PostContent": "<div> </div>"
},
{
"Department": "Assessor",
"Budget": "100",
"MeetAt": "12/12/2025",
"PreferredColor": "#e0e0e0",
"MeetAt": "2025-01-26T14:30:00Z",
"preferredColor": "#232323",
"PostContent": "<div> </div>"
},
{
"Department": "Treasurer",
"Budget": "50",
"MeetAt": "12/12/2025",
"PreferredColor": "#e0e0e0",
"MeetAt": "2025-01-26T14:30:00Z",
"preferredColor": "#E72323",
"PostContent": "<div> </div>"
}
]
@ -74,21 +74,21 @@
{
"State": "California",
"Coordinates": "150,000",
"MeetAt": "12/12/2025",
"MeetAt": "2025-01-26T14:30:00Z",
"PreferredColor": "#e0e0e0",
"PostContent": "<div> </div>"
},
{
"State": "Texas",
"Coordinates": "100,000",
"MeetAt": "12/12/2025",
"MeetAt": "2025-01-26T14:30:00Z",
"PreferredColor": "#e0e0e0",
"PostContent": "<div> </div>"
},
{
"State": "Florida",
"Coordinates": "50,000",
"MeetAt": "12/12/2025",
"MeetAt": "2025-01-26T14:30:00Z",
"PreferredColor": "#e0e0e0",
"PostContent": "<div> </div>"
}

View File

@ -1 +1 @@
<?php return array('dependencies' => array('react', 'react-dom', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => '0c512545db897b1c5c5e');
<?php return array('dependencies' => array('react', 'react-dom', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => '5afb8b4f337b11cc4837');

File diff suppressed because one or more lines are too long

View File

@ -46,17 +46,17 @@
"default": [{
"name": "Data",
"data": [
{ "Department": "Sheriffs Office", "Budget": "150", "MeetAt": "12/12/2025", "PreferredColor": "#e0e0e0", "PostContent": "<div> </div>" },
{ "Department": "Assessor", "Budget": "100", "MeetAt": "12/12/2025", "PreferredColor": "#e0e0e0", "PostContent": "<div> </div>" },
{ "Department": "Treasurer", "Budget": "50", "MeetAt": "12/12/2025", "PreferredColor": "#e0e0e0", "PostContent": "<div> </div>" }
{ "Department": "Sheriffs Office", "Budget": "150", "MeetAt": "2025-01-26T14:30:00Z", "preferredColor": "red", "PostContent": "<div> </div>" },
{ "Department": "Assessor", "Budget": "100", "MeetAt": "2025-01-26T14:30:00Z", "preferredColor": "#232323", "PostContent": "<div> </div>" },
{ "Department": "Treasurer", "Budget": "50", "MeetAt": "2025-01-26T14:30:00Z", "preferredColor": "#E72323", "PostContent": "<div> </div>" }
]
},
{
"name": "Locations",
"data": [
{ "State": "California", "Coordinates": "150,000", "MeetAt": "12/12/2025", "PreferredColor": "#e0e0e0", "PostContent": "<div> </div>" },
{ "State": "Texas", "Coordinates": "100,000", "MeetAt": "12/12/2025", "PreferredColor": "#e0e0e0", "PostContent": "<div> </div>" },
{ "State": "Florida", "Coordinates": "50,000", "MeetAt": "12/12/2025", "PreferredColor": "#e0e0e0", "PostContent": "<div> </div>" }
{ "State": "California", "Coordinates": "150,000", "MeetAt": "2025-01-26T14:30:00Z", "PreferredColor": "#e0e0e0", "PostContent": "<div> </div>" },
{ "State": "Texas", "Coordinates": "100,000", "MeetAt": "2025-01-26T14:30:00Z", "PreferredColor": "#e0e0e0", "PostContent": "<div> </div>" },
{ "State": "Florida", "Coordinates": "50,000", "MeetAt": "2025-01-26T14:30:00Z", "PreferredColor": "#e0e0e0", "PostContent": "<div> </div>" }
]
},
{

View File

@ -3,9 +3,27 @@ import { AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-alpine.css';
import LCPGridColorRender from './LCPGridColorRender';
const LCPDataGrid = ({dataset}) => {
// lcpCellRenderer to dynamically assign the right cellRenderer
function lcpCellRenderer(params) {
const value = params.value;
// First, check if the value is a Date object
if (value instanceof Date) {
return value.toLocaleString(); // Return a formatted string (you can format it however you want)
}
// Check if the value is a valid CSS color (this works for string values like '#232323' or 'red')
if (isValidCSSColor(value)) {
return <LCPGridColorRender value={value} />; // Use the color renderer
}
// Default rendering for other types of data (like text, number, etc.)
return value;
}
const [rowsToAdd, setRowsToAdd] = useState(1); // Number of rows the user wants to add
const [currentRowCount, setCurrentRowCount] = useState(dataset.length); // Track the current row count
@ -43,11 +61,85 @@ const LCPDataGrid = ({dataset}) => {
return 'text'; // Defaults to 'text' for strings and others
};
// Helper function to detect if a value is a valid CSS color
const isValidCSSColor = (value) => {
const cssColorRegex = /^(#([0-9a-fA-F]{3}){1,2}|[a-zA-Z]+|rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)|rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(0(\.\d+)?|1(\.0+)?)\)|hsl\((\d{1,3}),\s*(\d{1,3})%,\s*(\d{1,3})%\)|hsla\((\d{1,3}),\s*(\d{1,3})%,\s*(\d{1,3})%,\s*(0(\.\d+)?|1(\.0+)?)\))$/i;
return cssColorRegex.test(value);
};
// Helper function to detect if a value is a valid CSS color
const isValidCSSColor = (value) => {
// Ensure the value is a string before trimming
value = String(value).trim(); // Convert to string if it's not already
// Regex to match valid CSS color formats (hex, rgb, rgba, hsl, hsla, named colors)
const cssColorRegex = /^(#([0-9a-fA-F]{3}){1,2}|[a-zA-Z]+|rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)|rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(0(\.\d+)?|1(\.0+)?)\)|hsl\((\d{1,3}),\s*(\d{1,3})%,\s*(\d{1,3})%\)|hsla\((\d{1,3}),\s*(\d{1,3})%,\s*(\d{1,3})%,\s*(0(\.\d+)?|1(\.0+)?)\))$/i;
// First check if the value matches the general color regex
if (!cssColorRegex.test(value)) {
return false; // If it doesn't match any known color format, it's not valid
}
// Now, we'll do more detailed checks for RGB, RGBA, HSL, and HSLA formats
// Check if it's a valid RGB format (rgb(r, g, b))
const rgbMatch = /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/i.exec(value);
if (rgbMatch) {
const r = parseInt(rgbMatch[1], 10);
const g = parseInt(rgbMatch[2], 10);
const b = parseInt(rgbMatch[3], 10);
// RGB values should be in the range 0-255
return r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255;
}
// Check if it's a valid RGBA format (rgba(r, g, b, a))
const rgbaMatch = /^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(0(\.\d+)?|1(\.0+)?)\)$/i.exec(value);
if (rgbaMatch) {
const r = parseInt(rgbaMatch[1], 10);
const g = parseInt(rgbaMatch[2], 10);
const b = parseInt(rgbaMatch[3], 10);
const a = parseFloat(rgbaMatch[4]);
// RGBA values should be in the range 0-255 for RGB and 0-1 for alpha
return r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255 && a >= 0 && a <= 1;
}
// Check if it's a valid HSL format (hsl(h, s%, l%))
const hslMatch = /^hsl\((\d{1,3}),\s*(\d{1,3})%,\s*(\d{1,3})%\)$/i.exec(value);
if (hslMatch) {
const h = parseInt(hslMatch[1], 10);
const s = parseInt(hslMatch[2], 10);
const l = parseInt(hslMatch[3], 10);
// Hue should be 0-360, saturation and lightness should be 0-100
return h >= 0 && h <= 360 && s >= 0 && s <= 100 && l >= 0 && l <= 100;
}
// Check if it's a valid HSLA format (hsla(h, s%, l%, a))
const hslaMatch = /^hsla\((\d{1,3}),\s*(\d{1,3})%,\s*(\d{1,3})%,\s*(0(\.\d+)?|1(\.0+)?)\)$/i.exec(value);
if (hslaMatch) {
const h = parseInt(hslaMatch[1], 10);
const s = parseInt(hslaMatch[2], 10);
const l = parseInt(hslaMatch[3], 10);
const a = parseFloat(hslaMatch[4]);
// Hue should be 0-360, saturation and lightness should be 0-100, alpha should be 0-1
return h >= 0 && h <= 360 && s >= 0 && s <= 100 && l >= 0 && l <= 100 && a >= 0 && a <= 1;
}
// If it's a valid named color (like "red", "blue", etc.)
const namedColors = [
"red", "green", "blue", "yellow", "black", "white", "gray", "purple", "orange", "brown", "pink", "cyan", "magenta",
// Add more CSS named colors as necessary
];
if (namedColors.includes(value.toLowerCase())) {
return true; // It's a valid named color
}
// If it's a valid hex color (hex format should be valid)
const hexMatch = /^#([0-9a-fA-F]{3}){1,2}$/i.exec(value);
if (hexMatch) {
return true; // It's a valid hex color
}
// If it passed regex but didn't pass the detailed checks, it's invalid
return false;
};
// Helper function to detect if a value contains HTML tags
const isHTML = (value) => {
@ -115,7 +207,6 @@ const LCPDataGrid = ({dataset}) => {
return label;
};
// Data parser for Ag Grid based on detected data types
function lcpDataTypeParser(params) {
const columnName = params.colDef.field; // Get the column field name (e.g., 'Budget', 'MeetAt')
const dataType = gridDataTypes[columnName]; // Get the data type for this column from gridDataTypes
@ -130,11 +221,30 @@ const LCPDataGrid = ({dataset}) => {
// If it's a number, return the number or NaN
return Number(params.newValue);
case 'date':
// If it's a date, try to parse the value as a Date
const parsedDate = new Date(params.newValue);
return !isNaN(parsedDate.getTime()) ? parsedDate : params.newValue; // Return parsed date or original value if invalid
const dateStr = params.newValue;
// Check if the value is an empty string or undefined
if (!dateStr || dateStr.trim() === '') {
return null; // If empty, return null or any default value you prefer
}
let parsedDate;
// Check if the date is in the format "MM/DD/YYYY"
const isValidMMDDYYYY = /^\d{2}\/\d{2}\/\d{4}$/.test(dateStr);
if (isValidMMDDYYYY) {
const [month, day, year] = dateStr.split('/');
const isoDateStr = `${year}-${month}-${day}`;
parsedDate = new Date(isoDateStr);
} else {
// For other formats, try using the default Date parser
parsedDate = new Date(dateStr);
}
// Return parsed date if valid, otherwise return the original string
return !isNaN(parsedDate.getTime()) ? parsedDate : dateStr;
case 'color':
// If it's a color, we don't need to change the value (it's already a valid color)
// If it's a color, return the value as-is
return params.newValue;
case 'html':
// If it's HTML, we can either sanitize or leave the value as is (for now, leaving it as is)
@ -146,6 +256,9 @@ const LCPDataGrid = ({dataset}) => {
}
}
// Create columnDefs dynamically
const [columnDefs, setColumnDefs] = useState([]);
const [pinnedTopRowData, setPinnedTopRowData] = useState([]);
@ -161,6 +274,9 @@ const LCPDataGrid = ({dataset}) => {
headerName: getColumnLabel(index), // 'A', 'B', 'C', ...
field: key, // Field will match the key (Department2, Budget, etc.)
valueParser: lcpDataTypeParser,
cellRenderer: lcpCellRenderer, // Reference the custom cell renderer
};
});

View File

@ -0,0 +1,28 @@
import React, { useState, useEffect } from 'react';
// AG-Grid Cell Renderer Component
const LCPGridColorRender = (props) => {
const [color, setColor] = useState(props.value || ''); // Get the color value from the cell data
useEffect(() => {
// Update color if the value from AG-Grid changes
if (props.value !== color) {
setColor(props.value);
}
}, [props.value]); // Dependency on props.value so it updates when the cell value changes
return (
<div
style={{
width: '30px',
height: '30px',
backgroundColor: color,
border: '1px solid #000',
margin: '0 auto'
}}
/>
);
};
export default LCPGridColorRender;