Skip to content

Refactor/lint react compiler#22

Merged
kilbot merged 3 commits intomainfrom
refactor/lint-react-compiler
Jan 30, 2026
Merged

Refactor/lint react compiler#22
kilbot merged 3 commits intomainfrom
refactor/lint-react-compiler

Conversation

@kilbot
Copy link
Copy Markdown
Contributor

@kilbot kilbot commented Jan 29, 2026

Summary by CodeRabbit

  • Bug Fixes

    • Fixed HTML entity escaping in error display messages for improved consistency
  • Refactor

    • Cleaned up unused imports and type declarations across components
    • Simplified component initialization and structure
    • Optimized import statements and consolidated dependencies
    • Adjusted search algorithm scoring mechanism
    • Enhanced React lifecycle practices by moving state mutations to appropriate hooks

✏️ Tip: You can customize this high-level summary in your review settings.

Safe, no-behavior-change fixes across the monorepo:
- Remove 75+ unused imports, variables, and type declarations
- Fix no-undef errors by adding eslint-env node to Node.js scripts
- Fix react/no-unescaped-entities by escaping apostrophes in JSX
- Remove unused catch parameters
- Add missing displayName to forwardRef components
- Fix missing key props in iterators
- Replace empty interfaces with type aliases

Packages affected:
- @wcpos/core: 82 → 36 problems
- @wcpos/components: 43 → 25 problems
- @wcpos/web-bundle: 2 → 2 problems (all fixed, remaining are no-undef)
- @wcpos/main: 4 → 2 problems
- @wcpos/utils: 4 → 3 problems

Total reduction: 213 → 138 problems (~35% reduction)
Fixes for hooks dependency issues:
- Add eslint-disable comments for intentional patterns (cache busters, identity keys)
- Remove unnecessary dependencies where safe
- Add txInstance to translations context dependencies
- Fix stable ref patterns in collapsible primitives
- Remove unused type declarations and imports from query hooks

Query hooks cleaned:
- categories.tsx, customers.tsx, orders.tsx, products.ts
- tags.tsx, tax-rates.tsx, variations.ts

Packages affected:
- @wcpos/query: 33 → 15 problems
- @wcpos/components: Added eslint-disable for intentional patterns

Total reduction: 138 → 116 problems
Fixed mutation-during-render issues in UI settings forms:
- Moved ref mutations to useEffect (customers, orders, logs, reports, pos-cart, pos-products, products)
- Added eslint-disable comments for intentional ref mutations from useObservableRef

Fixed mutation issues in:
- pos/cart/cells/actions.tsx - moved newRowUUIDs update to useEffect
- use-date-format.tsx - suppress warning for intentional visibleRef mutation
- pos/products/index.tsx - suppress for expandedRef mutations in table config
- products/products.tsx - same expandedRef pattern

Note: Some react-compiler "skipped optimizing" warnings remain as an acceptable
trade-off for maintaining the ref mutation patterns required by the architecture.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jan 29, 2026

📝 Walkthrough

Walkthrough

This pull request performs extensive codebase cleanup and refactoring, including removing unused imports and type declarations, consolidating import statements, moving render-time mutations to useEffect hooks, and adding ESLint suppress comments. No functional behavior changes; improvements to code quality and React rule compliance.

Changes

Cohort / File(s) Summary
Unused Import Removals - React Native & Utilities
packages/components/src/loader/index.tsx, packages/components/src/logo/logo.tsx, packages/components/src/label/index.tsx, packages/core/src/screens/main/pos/cart/cells/edit-shipping-line/form.tsx, packages/core/src/screens/main/pos/cart/index.tsx, packages/core/src/screens/main/reports/orders/index.tsx, packages/core/src/hooks/use-*
Removed unused imports like Platform, StyleProp, ViewProps, toString, lodash utilities, and router references; no impact on functionality.
Unused Import Removals - Hooks & Operators
packages/core/src/screens/main/hooks/use-collection.ts, packages/core/src/screens/main/components/product/filter-bar/index.tsx, packages/core/src/screens/main/components/customer-select.tsx, packages/core/src/hooks/barcodes/use-barcode-detection.ts, packages/core/src/screens/main/hooks/use-base-tax-location.ts
Removed unused RxJS operators (tap, startWith), React imports, and context hooks; improves tree-shaking.
Type Declaration Removals - Query Hooks
packages/query/src/hooks/categories.tsx, packages/query/src/hooks/customers.tsx, packages/query/src/hooks/orders.tsx, packages/query/src/hooks/products.ts, packages/query/src/hooks/tags.tsx, packages/query/src/hooks/tax-rates.tsx, packages/query/src/hooks/variations.ts
Removed unused type aliases (ProductDocument, CustomerDocument, OrderDocument) and APIQueryParams interfaces; function logic unchanged.
Type Alias Removals - Component & Module Types
packages/core/src/screens/main/pos/cart/customer.tsx, packages/core/src/screens/main/pos/cart/tabs.tsx, packages/core/src/screens/main/pos/hooks/use-add-product.ts, packages/core/src/screens/main/pos/hooks/use-add-variation.ts, packages/core/src/screens/main/pos/cart/rows/fee-line.tsx, packages/core/src/screens/main/pos/cart/rows/line-item.tsx, packages/core/src/screens/main/pos/cart/rows/shipping-line.tsx, packages/core/src/screens/main/pos/hooks/use-cart-lines.ts, packages/core/src/screens/main/pos/contexts/current-order/use-new-order.ts
Removed local type aliases for OrderDocument, LineItem, ShippingLine, and RenderItem; eliminates unused internal types without affecting behavior.
Render-Time Mutation to useEffect Refactoring
packages/core/src/screens/main/customers/ui-settings-form.tsx, packages/core/src/screens/main/logs/ui-settings-form.tsx, packages/core/src/screens/main/orders/ui-settings-form.tsx, packages/core/src/screens/main/pos/cart/ui-settings-form.tsx, packages/core/src/screens/main/pos/products/ui-settings-form.tsx, packages/core/src/screens/main/products/ui-settings-form.tsx, packages/core/src/screens/main/reports/ui-settings-form.tsx
Moved buttonPressHandlerRef.current assignment from render to useEffect to comply with React rules; preserves observable behavior while ensuring mutations occur post-render.
Ref Mutation and Callback Refactoring
packages/core/src/screens/main/pos/cart/cells/actions.tsx
Moved isNew pulse logic to useEffect with dependencies [isNew, uuid, table.options.meta]; now queues row state mutations through effect rather than inline during render.
ESLint Disable Comments - Hook Dependencies
packages/core/src/screens/main/hooks/use-date-format.tsx, packages/query/src/use-query.ts, packages/query/src/use-relational-query.ts, packages/core/src/screens/main/pos/products/index.tsx, packages/core/src/screens/main/products/products.tsx
Added react-hooks/exhaustive-deps suppress comments for intentional dependency array patterns; no functional changes.
ESLint Disable Comments - React Compiler
packages/core/src/screens/main/pos/products/index.tsx, packages/core/src/screens/main/products/products.tsx
Added react-compiler disable/enable comments around computed property destructuring to bypass minification issues; no runtime changes.
Import Statement Consolidations
packages/components/src/data-table/index.tsx, packages/components/src/input/index.tsx
Consolidated multi-line React Native and reanimated imports to single-line format; imports functionality preserved.
Import Style Changes
packages/components/src/format-number/format-number.tsx, packages/components/src/command/index.tsx, packages/components/src/combobox/utils/fuzzy-search.ts, packages/components/src/select/index.tsx, packages/components/src/tooltip/index.web.tsx, packages/components/src/virtualized-list/virtualized-list.tsx
Changed default imports to named exports (Text) or removed redundant named imports (FadeIn/FadeOut, TooltipTriggerProps, ItemProps); maintains intended usage.
Unused Import Removals - Components
packages/components/src/data-table/row.tsx, packages/components/src/data-table/index.web.tsx, packages/components/src/print/text.tsx, packages/core/src/contexts/translations/cache.ts
Removed unused isRxDocument, LayoutChangeEvent, cn utility, and TextUnderline type alias; reduces unused dependency declarations.
Hook Dependency and Linting Updates
packages/components/src/collapsible/primitives.web.tsx, packages/core/src/contexts/translations/index.tsx, packages/query/src/use-replication-state.ts
Added exhaustive-deps suppression comments in useLayoutEffect/useMemo; extended txInstance to TranslationProvider effect dependencies; added cache-buster comments in useMemo.
Bare Catch Clause Simplifications
packages/components/src/webview/index.tsx, packages/core/src/lib/url/parse-link-header.ts, packages/utils/src/logger/index.ts
Simplified catch clauses from catch (e) to bare catch; removes unused error variable without changing error-handling behavior.
String Escaping & Component Metadata
apps/main/app/+not-found.tsx, apps/main/components/root-error.tsx, apps/main/app/(app)/(drawer)/(pos)/(modals)/cart/add-misc-product.tsx, packages/components/src/pressable/index.tsx, packages/components/src/numpad/index.tsx
Escaped apostrophes in error messages; added displayName for Pressable and Numpad; simplified AddMiscProductForm wrapper; improves debugging and message rendering.
Store Lookup Optimization
packages/core/src/utils/merge-stores.ts
Replaced Map-based store lookup (currentStoreMap) with Set-based existence checking (remoteStoreIds); maintains same upsert/removal behavior with leaner data structure.
Unused Imports - Components
packages/core/src/screens/main/pos/cart/add-cart-item-buttons.tsx, packages/core/src/screens/main/products/cells/actions.tsx, packages/core/src/screens/main/pos/products/scanner-button.tsx, packages/core/src/screens/main/pos/cart/table.tsx, packages/core/src/modules/versions/versions.stories.tsx
Removed useRouter, Link, disconnect handler from scanner hook, and unused table utilities; no functional impact.
Scoring Constants Tuning
packages/components/src/combobox/utils/fuzzy-search.ts
Removed PENALTY_DISTANCE_FROM_START scoring constant; reduces penalty for near-start matches in fuzzy search.
Type Simplifications
packages/components/src/command/index.tsx, packages/components/src/format/list.tsx
Changed CommandSeparatorProps from interface to type alias; added React key prop to FormatList string items.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~28 minutes

Possibly related PRs

Poem

🐰 Hop hop, refactor we go,
Unused imports: out they flow,
Refs to effects, mutations freed,
Clean code growing, that's what we need!
Lints suppressed and types refined—
A cleaner warren, well-designed!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective of the PR: refactoring and linting related to the React compiler, which is reflected in the numerous import cleanups, lint directives, and code structure adjustments throughout.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (12)
packages/components/src/format-number/format-number.tsx (2)

132-139: Undefined variable index will cause a runtime error.

The getMaskAtIndex callback references index on line 138, but this variable is never defined within the function scope or received as a parameter. This will throw a ReferenceError at runtime.

🐛 Proposed fix to accept index as a parameter
-	const getMaskAtIndex = React.useCallback(() => {
+	const getMaskAtIndex = React.useCallback((index: number) => {
 		const { mask = ' ' } = props;
 		if (typeof mask === 'string') {
 			return mask;
 		}

 		return mask[index] || ' ';
-	}, [props]);
+	}, [props.mask]);

172-173: Type mismatch: format function expects number but receives string.

The format prop is typed as (value: number) => string on line 28, but formattedValue is a string. Either update the type signature or convert the value appropriately.

🔧 Option 1: Update type to accept string
-	format?: string | ((value: number) => string);
+	format?: string | ((value: string) => string);
🔧 Option 2: Parse the string to number before calling
 		} else if (typeof format === 'function') {
-			formattedValue = format(formattedValue);
+			formattedValue = format(parseFloat(formattedValue));
packages/core/src/screens/main/pos/cart/table.tsx (1)

208-209: Replace console.log with logger and avoid any type.

Two guideline violations:

  1. Line 208: Uses any type—should use a strict type or generic
  2. Line 209: Uses console.log—should use the logger library

As per coding guidelines: "Use the logger library exclusively for logging; DO NOT use console.log" and "Do not use 'any' type; use strict types and generics instead."

Proposed fix
+import log from '@wcpos/utils/logger';
 meta: {
-  onChange: (data: any) => {
-    console.log('onChange called without handler', data);
+  onChange: (data: unknown) => {
+    log.warn('onChange called without handler', data);
   },
packages/components/src/format/list.tsx (1)

5-7: Fix the array type definition.

The type array?: [] is an empty tuple type, meaning it can only accept an empty array. This should be a proper array type to allow actual items.

🐛 Proposed fix
 export interface FormatListProps {
-	array?: [];
+	array?: (string | React.ReactNode)[];
 }
packages/core/src/screens/main/products/cells/actions.tsx (1)

1-30: Fix import ordering: move @tanstack/react-table with external deps.

@tanstack/react-table is an external dependency and should be grouped with other externals right after React imports, before @wcpos/* and local imports.

🔧 Suggested reorder
 import * as React from 'react';

 import { useRouter } from 'expo-router';
+import type { CellContext } from '@tanstack/react-table';

 import {
 	AlertDialog,
 	AlertDialogAction,
 	AlertDialogCancel,
@@
 import { Text } from '@wcpos/components/text';

 import { useT } from '../../../../contexts/translations';
 import useDeleteDocument from '../../contexts/use-delete-document';
 import usePullDocument from '../../contexts/use-pull-document';

-import type { CellContext } from '@tanstack/react-table';
-
 type ProductDocument = import('@wcpos/database').ProductDocument;

As per coding guidelines: Enforce import ordering in TypeScript/JavaScript files: React first, then external dependencies, then @wcpos/* internal imports.

packages/core/src/utils/merge-stores.ts (1)

32-121: Add unit tests for this utility function.

This utility handles critical business logic with multiple code paths (store removal, upsert, error handling) and data transformations. Per coding guidelines, utility functions with data transformations and business logic require colocated unit tests in a merge-stores.test.ts file.

packages/core/src/screens/main/products/products.tsx (1)

201-237: Mutable ref pattern violates React Compiler rules; refactor instead of narrowing suppression scope.

The block suppression of react-compiler/react-compiler correctly identifies a violation, but narrowing the scope alone doesn't resolve it. React Compiler bails out of optimization when ESLint suppressions are present, even if narrowed. The deeper issue is that expandedRef is both mutated (lines 205, 207, 218) and used in the meta object passed to JSX (line 222), which violates React Compiler's requirement to avoid reading/writing mutable refs during render.

The comment mentions a TanStack minification bug with computed property destructuring, not a React Compiler limitation. Rather than suppressing the rule, consider:

  1. Keeping the ref fully internal without passing it to JSX meta objects, or
  2. Converting expandedRef to React state if its value affects rendering, or
  3. Using a stable callback wrapper pattern that avoids exposing the mutable ref in dependencies.

Simply adding a // eslint-disable-next-line comment (as shown in the previous suggestion) will still cause the compiler to bail, and the issue will remain unresolved.

packages/utils/src/logger/index.ts (1)

82-105: Replace any with unknown in the safeStringify parameter.

The function safely handles any input type through JSON.stringify and try-catch, making unknown the appropriate choice for type safety.

Proposed change
-function safeStringify(obj: any, maxLength = 10000): string {
+function safeStringify(obj: unknown, maxLength = 10000): string {
packages/core/src/screens/main/components/header/user-menu.tsx (1)

87-89: Replace console.log with logger.

Per coding guidelines, use the logger library exclusively for logging. This console.log should use uiLogger which is already imported.

Proposed fix
 			onChange: (data: any) => {
-				console.log('onChange called without handler', data);
+				uiLogger.warn('onChange called without handler', data);
 			},

As per coding guidelines: "Use the logger library exclusively for logging; DO NOT use console.log."

packages/components/src/data-table/index.web.tsx (2)

87-89: Replace console.log with logger.

Per coding guidelines, use the logger library exclusively. Consider importing the logger and replacing this debug statement.

Proposed fix

Add import at the top of the file:

import { getLogger } from '@wcpos/utils/logger';

const tableLogger = getLogger(['wcpos', 'components', 'data-table']);

Then update the handler:

 			onChange: (data: any) => {
-				console.log('onChange called without handler', data);
+				tableLogger.warn('onChange called without handler', data);
 			},

As per coding guidelines: "Use the logger library exclusively for logging; DO NOT use console.log."


66-66: Remove unused extraData prop.

The extraData prop is declared in the interface (line 36) and destructured (line 66), but it is not used anywhere in the component. Remove it from both the DataTableProps interface and the destructuring statement.

packages/components/src/data-table/index.tsx (1)

98-100: Replace console.log with logger and avoid any type.

This code violates the coding guidelines:

  1. Uses console.log instead of the logger library
  2. Uses any type for the data parameter
Proposed fix
+import { getLogger } from '@wcpos/utils/logger';
+
+const logger = getLogger(['wcpos', 'components', 'data-table']);
+
 meta: {
   expanded$,
   expandedRef,
-  onChange: (data: any) => {
-    console.log('onChange called without handler', data);
+  onChange: (data: unknown) => {
+    logger.warn('onChange called without handler', { context: { data } });
   },

As per coding guidelines: "Use the logger library exclusively for logging; DO NOT use console.log" and "Do not use 'any' type; use strict types and generics instead".

🤖 Fix all issues with AI agents
In `@packages/components/src/format/list.tsx`:
- Around line 12-17: The map callback in array?.map returns string items with a
key but returns non-string items (returned as item) without ensuring a key,
which can trigger React key warnings; update the map so non-string React
elements also get a key — e.g., wrap returned non-string items in a keyed
React.Fragment or use React.cloneElement to add key when the map callback
(array?.map) returns item, ensuring the key uses the index or a stable
identifier (index in this code) so every branch (the typeof item === 'string'
branch and the else branch that returns item) supplies a key.

In `@packages/core/src/screens/main/pos/cart/cells/actions.tsx`:
- Around line 35-52: Add an explicit explanatory comment above the
React.useEffect block (the one referencing isNew, table.options.meta, uuid)
stating that useEffect is required because rowRef.pulseAdd(...) is asynchronous
(runs its callback after the ~800ms animation) so cleanup of
table.options.meta.newRowUUIDs must occur when the animation completes, and
therefore cannot be performed in the row-add event handler which has no hook for
post-animation timing; keep the existing eslint-disable comment about
table.options.meta being safe to update in the effect.
🧹 Nitpick comments (7)
packages/core/src/screens/main/components/customer-select.tsx (1)

21-21: Use a type-only import for CustomerDocument.

It’s only used as a type (Line 137), so make this a type-only import to avoid unnecessary runtime dependency.

Proposed change
-import { CustomerDocument } from '@wcpos/database';
+import type { CustomerDocument } from '@wcpos/database';
packages/core/src/screens/main/pos/products/index.tsx (1)

174-206: Narrow the eslint-disable scope to only the offending line.

The disable currently spans the table config too, but the justification references setRowExpanded. Prefer eslint-disable-next-line (or a tightly scoped block) to minimize rule suppression.

♻️ Suggested change
-	/* eslint-disable react-compiler/react-compiler -- expandedRef is a mutable ref from useObservableRef */
-	const setRowExpanded = React.useCallback(
+	/* eslint-disable-next-line react-compiler/react-compiler -- expandedRef is a mutable ref from useObservableRef */
+	const setRowExpanded = React.useCallback(
 		(rowId: string, expanded: boolean) => {
 			if (expanded) {
 				expandedRef.current = { ...expandedRef.current, [rowId]: true };
 			} else {
 				expandedRef.current = omit(expandedRef.current, rowId);
 			}
 		},
 		[expandedRef]
 	);
@@
-	/* eslint-enable react-compiler/react-compiler */

As per coding guidelines: “Enforce React Compiler rules in TypeScript/JavaScript files.”

packages/components/src/format-number/format-number.tsx (1)

186-188: Implicit any type on val parameter.

The val parameter lacks a type annotation, resulting in an implicit any type. As per coding guidelines, explicit types should be used instead of any.

♻️ Proposed fix to add explicit type
-	const formatInput = React.useCallback((val) => {
+	const formatInput = React.useCallback((val: string) => {
 		return val;
 	}, []);
packages/components/src/select/index.tsx (1)

92-96: FIXME comments indicate pending animation issues.

There are two related FIXME comments here: the flash on unmount (lines 93-95) and the content rendering prematurely (lines 84-86). These appear to be interconnected—the early render workaround at line 87 (if (!open) return null) may be conflicting with Reanimated's exit animations.

Would you like me to open an issue to track investigating these animation issues? A potential approach would be to use useAnimatedStyle with opacity transitions instead of entering/exiting props, or explore @rn-primitives/select's built-in presence handling.

packages/core/src/utils/merge-stores.ts (1)

41-41: Avoid using any type in the remoteStores parameter.

The [key: string]: any index signature violates the coding guidelines. Consider defining a proper type for the remote store response shape or using a generic type parameter.

♻️ Suggested refactor
+// Define at the top of the file or in a shared types module
+interface RemoteStore {
+	id: number;
+	name?: string;
+	// Add other known properties from the API response
+	[key: string]: unknown; // Use 'unknown' if additional properties are expected
+}
+
 export async function mergeStoresWithResponse({
 	userDB,
 	wpUser,
 	remoteStores,
 	user,
 	siteID,
 }: {
 	userDB: UserDatabase;
 	wpUser: WPCredentialsDocument;
-	remoteStores: { id: number; [key: string]: any }[];
+	remoteStores: RemoteStore[];
 	user: { uuid: string };
 	siteID: string;
 }) {

As per coding guidelines: "Do not use 'any' type; use strict types and generics instead".

packages/components/src/command/index.tsx (1)

107-109: Prefer semantic color classes + className for theme compatibility.

Inline styles with hardcoded #e5e7eb can break theme switching; use semantic classes instead.

♻️ Suggested change
-const CommandSeparator = React.forwardRef<View, CommandSeparatorProps>((props, ref) => (
-	<View ref={ref} style={[{ height: 1, backgroundColor: '#e5e7eb' }]} {...props} />
-));
+const CommandSeparator = React.forwardRef<View, CommandSeparatorProps>((props, ref) => (
+	<View ref={ref} className="h-px bg-muted" {...props} />
+));

As per coding guidelines, “Always prefer semantic color classes (bg-background, bg-card, bg-sidebar, bg-muted, bg-table-header) over hardcoded colors” and “Prefer className over inline styles to ensure proper theme switching.”

packages/query/src/use-relational-query.ts (1)

103-104: Minor: The comment could mention both identity keys.

The comment references only parentIdentityKey, but childIdentityKey is also involved through the registerQueries callback dependency. Consider updating the comment for completeness:

-// eslint-disable-next-line react-hooks/exhaustive-deps -- parentIdentityKey triggers re-registration when query identity changes
+// eslint-disable-next-line react-hooks/exhaustive-deps -- identity keys trigger re-registration via registerQueries when query identity changes

Comment on lines 12 to 17
{array?.map((item, index) => {
if (typeof item === 'string') {
return <Text>{item}, </Text>;
return <Text key={index}>{item}, </Text>;
}
return item;
})}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Non-string items returned without a key will trigger React warnings.

Line 14 correctly adds a key for string items, but line 16 returns non-string items (potentially React elements) without ensuring they have keys. If item is a React element without a key, React will warn about missing keys in the list.

🔧 Proposed fix using React.Fragment with key
 {array?.map((item, index) => {
 	if (typeof item === 'string') {
 		return <Text key={index}>{item}, </Text>;
 	}
-	return item;
+	return <React.Fragment key={index}>{item}</React.Fragment>;
 })}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{array?.map((item, index) => {
if (typeof item === 'string') {
return <Text>{item}, </Text>;
return <Text key={index}>{item}, </Text>;
}
return item;
})}
{array?.map((item, index) => {
if (typeof item === 'string') {
return <Text key={index}>{item}, </Text>;
}
return <React.Fragment key={index}>{item}</React.Fragment>;
})}
🤖 Prompt for AI Agents
In `@packages/components/src/format/list.tsx` around lines 12 - 17, The map
callback in array?.map returns string items with a key but returns non-string
items (returned as item) without ensuring a key, which can trigger React key
warnings; update the map so non-string React elements also get a key — e.g.,
wrap returned non-string items in a keyed React.Fragment or use
React.cloneElement to add key when the map callback (array?.map) returns item,
ensuring the key uses the index or a stable identifier (index in this code) so
every branch (the typeof item === 'string' branch and the else branch that
returns item) supplies a key.

Comment on lines 35 to +52
* Use pulse effect for new rows
* Move to effect to avoid mutating props during render
*/
const isNew = table.options.meta.newRowUUIDs.includes(uuid);
if (isNew) {
const rowRef = table.options.meta.rowRefs.current.get(uuid);
if (rowRef && rowRef?.pulseAdd) {
rowRef.pulseAdd(() => {
table.options.meta.newRowUUIDs = table.options.meta.newRowUUIDs.filter((id) => id !== uuid);
});

// eslint-disable-next-line react-compiler/react-compiler -- table.options.meta is table config, safe to update in effect
React.useEffect(() => {
if (isNew) {
const rowRef = table.options.meta.rowRefs.current.get(uuid);
if (rowRef && rowRef?.pulseAdd) {
rowRef.pulseAdd(() => {
// Create new array instead of mutating
const currentUUIDs = table.options.meta.newRowUUIDs;
table.options.meta.newRowUUIDs = currentUUIDs.filter((id) => id !== uuid);
});
}
}
}
}, [isNew, table.options.meta, uuid]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n packages/core/src/screens/main/pos/cart/cells/actions.tsx | head -60

Repository: wcpos/monorepo

Length of output: 2198


🏁 Script executed:

rg -n "newRowUUIDs" packages/core/src/screens/main/pos/cart/cells/actions.tsx -B 5 -A 5

Repository: wcpos/monorepo

Length of output: 818


🏁 Script executed:

# Find where newRowUUIDs is set/updated across the codebase
rg -n "newRowUUIDs\s*=" -C 3

Repository: wcpos/monorepo

Length of output: 1274


🏁 Script executed:

# Get more context about where newRowUUIDs is computed and updated
cat -n packages/core/src/screens/main/pos/cart/table.tsx | sed -n '120,150p'

Repository: wcpos/monorepo

Length of output: 1075


🏁 Script executed:

# Search for where rows are added to understand the control flow
rg -n "newRowUUIDs|addRow" packages/core/src/screens/main/pos/cart/ -C 2

Repository: wcpos/monorepo

Length of output: 2006


🏁 Script executed:

# Check if there are any event handlers that add rows
rg -n "handleAdd|onCreate|onAdd" packages/core/src/screens/main/pos/cart/ -C 3

Repository: wcpos/monorepo

Length of output: 5742


🏁 Script executed:

# Find pulseAdd definition to understand if it's async
rg -n "pulseAdd" packages/core/src/screens/main/pos/cart/ -C 3

Repository: wcpos/monorepo

Length of output: 897


🏁 Script executed:

# Look for rowRefs definition and pulseAdd implementation
rg -n "pulseAdd|pulseRemove" packages/core/src/ -C 2 | head -50

Repository: wcpos/monorepo

Length of output: 1266


🏁 Script executed:

# Check if there's a row component that manages pulseAdd animation
fd -e tsx -e ts . packages/core/src/screens/main/pos/cart/ | xargs grep -l "pulseAdd\|pulseRemove" 2>/dev/null

Repository: wcpos/monorepo

Length of output: 115


🏁 Script executed:

# Find the row component and its pulseAdd/pulseRemove implementation
rg -n "class.*Row|const.*Row" packages/core/src/screens/main/pos/cart/ -C 2 | grep -i "row\|tsx"

Repository: wcpos/monorepo

Length of output: 2756


🏁 Script executed:

# Search for row component that might define pulseAdd
fd -name "*row*.tsx" packages/core/src/screens/main/pos/cart/

Repository: wcpos/monorepo

Length of output: 288


🏁 Script executed:

# Look at the cart table structure to find row component
cat -n packages/core/src/screens/main/pos/cart/table.tsx | sed -n '1,50p'

Repository: wcpos/monorepo

Length of output: 2305


🏁 Script executed:

# Find PulseTableRow component
fd "PulseTableRow\|pulse-table-row" packages/

Repository: wcpos/monorepo

Length of output: 40


🏁 Script executed:

# Search for PulseTableRow and its implementation
rg -n "PulseTableRow|pulseAdd" packages/components -C 3 | head -80

Repository: wcpos/monorepo

Length of output: 3563


🏁 Script executed:

# Look at the table component file to understand pulseAdd
rg -n "pulseAdd\|export.*Pulse" packages/components/src/table/ -C 3

Repository: wcpos/monorepo

Length of output: 40


🏁 Script executed:

# Get more context on pulseAdd implementation
cat -n packages/components/src/table/pulse-row.tsx | sed -n '60,100p'

Repository: wcpos/monorepo

Length of output: 1400


Add a comment explaining why useEffect is necessary here instead of moving cleanup to the event handler.

The useEffect is justified because pulseAdd() is asynchronous—the callback only executes after the 800ms animation completes. You cannot move this cleanup to the row-add event handler since there's no event mechanism to trigger cleanup after animation finishes. However, per coding guidelines, add a comment explaining WHY useEffect is necessary here, rather than just relying on the React Compiler disable comment.

Current code (lines 40-52)
	// eslint-disable-next-line react-compiler/react-compiler -- table.options.meta is table config, safe to update in effect
	React.useEffect(() => {
		if (isNew) {
			const rowRef = table.options.meta.rowRefs.current.get(uuid);
			if (rowRef && rowRef?.pulseAdd) {
				rowRef.pulseAdd(() => {
					// Create new array instead of mutating
					const currentUUIDs = table.options.meta.newRowUUIDs;
					table.options.meta.newRowUUIDs = currentUUIDs.filter((id) => id !== uuid);
				});
			}
		}
	}, [isNew, table.options.meta, uuid]);

Suggested update:

	// useEffect needed: pulseAdd animation is async (800ms), callback runs after animation completes.
	// Cannot be in event handler since animation timing is not synchronous with row addition.
	// eslint-disable-next-line react-compiler/react-compiler -- table.options.meta is table config, safe to update in effect
	React.useEffect(() => {
		if (isNew) {
			const rowRef = table.options.meta.rowRefs.current.get(uuid);
			if (rowRef && rowRef?.pulseAdd) {
				rowRef.pulseAdd(() => {
					// Create new array instead of mutating
					const currentUUIDs = table.options.meta.newRowUUIDs;
					table.options.meta.newRowUUIDs = currentUUIDs.filter((id) => id !== uuid);
				});
			}
		}
	}, [isNew, table.options.meta, uuid]);
🤖 Prompt for AI Agents
In `@packages/core/src/screens/main/pos/cart/cells/actions.tsx` around lines 35 -
52, Add an explicit explanatory comment above the React.useEffect block (the one
referencing isNew, table.options.meta, uuid) stating that useEffect is required
because rowRef.pulseAdd(...) is asynchronous (runs its callback after the ~800ms
animation) so cleanup of table.options.meta.newRowUUIDs must occur when the
animation completes, and therefore cannot be performed in the row-add event
handler which has no hook for post-animation timing; keep the existing
eslint-disable comment about table.options.meta being safe to update in the
effect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant