From d23a182650bbbf611367c078b76efd48a6d30ca3 Mon Sep 17 00:00:00 2001 From: Dave Date: Tue, 24 Mar 2026 10:54:42 -0400 Subject: [PATCH] IO-3624 Refresh shop config list rows and color UX --- .../form-fields-changed-alert.component.jsx | 2 +- .../phone-form-item.component.jsx | 85 +- .../form-list-item-title.utils.js | 30 + .../layout-form-row.component.jsx | 26 +- .../layout-form-row.styles.scss | 23 + .../parts-order-modal.component.jsx | 57 +- .../parts-receive-modal.component.jsx | 54 +- .../parts-email-presets.component.jsx | 66 +- .../parts-locations.component.jsx | 70 +- .../parts-order-comments.component.jsx | 99 +- .../shop-employees-form.component.jsx | 122 +- .../shop-info/shop-info.color.utils.js | 304 ++++ .../shop-info/shop-info.color.utils.test.js | 52 + .../shop-info/shop-info.general.component.jsx | 1396 ++++++++++------- .../shop-info/shop-info.intake.component.jsx | 429 ++--- .../shop-info.laborrates.component.jsx | 47 +- .../shop-info/shop-info.parts-scan.jsx | 280 ++-- ...p-info.responsibilitycenters.component.jsx | 840 ++++++---- .../shop-info.rostatus.component.jsx | 142 +- .../shop-info.scheduling.component.jsx | 337 ++-- .../shop-info.speedprint.component.jsx | 134 +- .../shop-info.task-presets.component.jsx | 314 ++-- 22 files changed, 3100 insertions(+), 1809 deletions(-) create mode 100644 client/src/components/form-list-move-arrows/form-list-item-title.utils.js create mode 100644 client/src/components/shop-info/shop-info.color.utils.js create mode 100644 client/src/components/shop-info/shop-info.color.utils.test.js diff --git a/client/src/components/form-fields-changed-alert/form-fields-changed-alert.component.jsx b/client/src/components/form-fields-changed-alert/form-fields-changed-alert.component.jsx index 0f265d7db..3254c9f74 100644 --- a/client/src/components/form-fields-changed-alert/form-fields-changed-alert.component.jsx +++ b/client/src/components/form-fields-changed-alert/form-fields-changed-alert.component.jsx @@ -17,7 +17,7 @@ export default function FormsFieldChanged({ form, skipPrompt }) { const errors = form.getFieldsError().filter((e) => e.errors.length > 0); if (form.isFieldsTouched()) return ( - + ; -} +/** + * Formats a phone number for display purposes. If the input value is a valid phone number, it will be formatted in a + * national format (e.g., (123) 456-7890 for US/CA). If the input is not a valid phone number, it will be returned as-is. + * @param value + * @returns {*} + */ +const formatPhoneDisplayValue = (value) => { + if (!value) return value; + + try { + const parsedPhone = parsePhoneNumber(value, "CA"); + return parsedPhone?.isValid() ? parsedPhone.formatNational() : value; + } catch { + return value; + } +}; + +/** + * Generates a "tel:" URL for a phone number if it's valid. If the input value is a valid phone number, it will return a + * URL in the format "tel:+1234567890". If the input is not a valid phone number, it will attempt to trim whitespace and + * return a "tel:" URL with the raw value, or null if the trimmed value is empty. + * @param value + * @returns {string|null} + */ +const getPhoneActionHref = (value) => { + if (!value) return null; + + try { + const parsedPhone = parsePhoneNumber(value, "CA"); + if (parsedPhone?.isValid()) return `tel:${parsedPhone.number}`; + } catch { + // Fall back to the raw value below. + } + + const trimmedValue = String(value).trim(); + return trimmedValue ? `tel:${trimmedValue}` : null; +}; + +const FormItemPhone = forwardRef(function FormItemPhone( + { formatDisplayOnly = false, showPhoneAction = false, value, onBlur, onFocus, ...props }, + ref +) { + const [isFocused, setIsFocused] = useState(false); + const displayValue = useMemo(() => { + if (!formatDisplayOnly || isFocused) return value; + return formatPhoneDisplayValue(value); + }, [formatDisplayOnly, isFocused, value]); + const phoneActionHref = useMemo(() => (showPhoneAction ? getPhoneActionHref(value) : null), [showPhoneAction, value]); + + const input = ( + { + setIsFocused(true); + onFocus?.(event); + }} + onBlur={(event) => { + setIsFocused(false); + onBlur?.(event); + }} + /> + ); + + if (!showPhoneAction) return input; + + return ( + + {input} + {phoneActionHref ? ( +