feat(DEV-15902): Allow Line Items negative price#802
feat(DEV-15902): Allow Line Items negative price#802dinis-monite wants to merge 3 commits intomainfrom
Conversation
🦋 Changeset detectedLatest commit: b231791 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
WalkthroughEnables negative line-item prices by removing the non-negative validation constraint. Refactors payable forms to use RHFTextField instead of Controller+TextField for several inputs. Applies minor type/format updates (e.g., MoniteCurrency generic, enum typing). Adds a patch changeset entry; no exported API changes. Changes
Possibly related PRs
✨ Finishing Touches
🧪 Generate unit tests
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
.changeset/rare-singers-sniff.md (1)
5-5: Consider enriching the changeset summaryThe title is clear, but adding context—e.g., the Jira ticket
DEV-15902or phrasing the entry in imperative mood (“Allow line-item prices to be negative (DEV-15902)”)—makes the changelog more informative when scanning release notes.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
.changeset/rare-singers-sniff.md(1 hunks)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx(0 hunks)
💤 Files with no reviewable changes (1)
- packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
PR: team-monite/monite-sdk#0
File: packages/sdk-react/.cursor/rules/api-calls.mdc:0-0
Timestamp: 2025-07-21T08:11:13.444Z
Learning: Applies to packages/sdk-react/**/*.{tsx} : Use optimistic updates in React Query mutations when updating Monite API resources to improve perceived performance
Learnt from: CR
PR: team-monite/monite-sdk#0
File: packages/sdk-react/.cursor/rules/api-calls.mdc:0-0
Timestamp: 2025-07-21T08:11:13.444Z
Learning: Applies to packages/sdk-react/**/*.{ts,tsx} : Use custom TypeScript types (e.g., Invoice, CreateInvoiceInput) imported from '@/types/api' for Monite API data structures
Learnt from: CR
PR: team-monite/monite-sdk#0
File: packages/sdk-react/.cursor/rules/api-calls.mdc:0-0
Timestamp: 2025-07-21T08:11:13.444Z
Learning: Applies to packages/sdk-react/**/*.{tsx} : Implement proper error boundaries and handle errors gracefully in React components using Monite API
📚 Learning: applies to packages/sdk-react/**/*.{tsx} : use optimistic updates in react query mutations when upda...
Learnt from: CR
PR: team-monite/monite-sdk#0
File: packages/sdk-react/.cursor/rules/api-calls.mdc:0-0
Timestamp: 2025-07-21T08:11:13.444Z
Learning: Applies to packages/sdk-react/**/*.{tsx} : Use optimistic updates in React Query mutations when updating Monite API resources to improve perceived performance
Applied to files:
.changeset/rare-singers-sniff.md
📚 Learning: applies to packages/sdk-react/**/*.{tsx} : implement proper error boundaries and handle errors grace...
Learnt from: CR
PR: team-monite/monite-sdk#0
File: packages/sdk-react/.cursor/rules/api-calls.mdc:0-0
Timestamp: 2025-07-21T08:11:13.444Z
Learning: Applies to packages/sdk-react/**/*.{tsx} : Implement proper error boundaries and handle errors gracefully in React components using Monite API
Applied to files:
.changeset/rare-singers-sniff.md
📚 Learning: applies to packages/sdk-react/**/*.{ts,tsx} : use custom typescript types (e.g., invoice, createinvo...
Learnt from: CR
PR: team-monite/monite-sdk#0
File: packages/sdk-react/.cursor/rules/api-calls.mdc:0-0
Timestamp: 2025-07-21T08:11:13.444Z
Learning: Applies to packages/sdk-react/**/*.{ts,tsx} : Use custom TypeScript types (e.g., Invoice, CreateInvoiceInput) imported from '@/types/api' for Monite API data structures
Applied to files:
.changeset/rare-singers-sniff.md
📚 Learning: applies to packages/sdk-react/**/*.{tsx} : use query keys consistently in react query hooks for moni...
Learnt from: CR
PR: team-monite/monite-sdk#0
File: packages/sdk-react/.cursor/rules/api-calls.mdc:0-0
Timestamp: 2025-07-21T08:11:13.444Z
Learning: Applies to packages/sdk-react/**/*.{tsx} : Use query keys consistently in React Query hooks for Monite API calls to ensure correct cache management
Applied to files:
.changeset/rare-singers-sniff.md
📚 Learning: applies to packages/sdk-react/**/*.{tsx} : use `api...usemutation` for post, pu...
Learnt from: CR
PR: team-monite/monite-sdk#0
File: packages/sdk-react/.cursor/rules/api-calls.mdc:0-0
Timestamp: 2025-07-21T08:11:13.444Z
Learning: Applies to packages/sdk-react/**/*.{tsx} : Use `api.<resource>.<operation>.useMutation` for POST, PUT, PATCH, and DELETE requests to Monite API endpoints
Applied to files:
.changeset/rare-singers-sniff.md
📚 Learning: applies to packages/sdk-react/**/*.{tsx} : handle global and mutation-specific errors in monite api ...
Learnt from: CR
PR: team-monite/monite-sdk#0
File: packages/sdk-react/.cursor/rules/api-calls.mdc:0-0
Timestamp: 2025-07-21T08:11:13.444Z
Learning: Applies to packages/sdk-react/**/*.{tsx} : Handle global and mutation-specific errors in Monite API calls using the `onError` callback in React Query hooks
Applied to files:
.changeset/rare-singers-sniff.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Build
- GitHub Check: Analyze (javascript)
|
🚀 Preview URLs are now available! 🚀 |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (11)
packages/sdk-demo/src/locales/en/messages.ts (2)
1-1: Avoid blanket ESLint disable; not needed here.This suppresses all rules repository-wide for this file. Since the only flagged issue is the duplicate import, remove the directive.
-/*eslint-disable*/
5-7: Optional: prefer a typed object (or imported JSON) overJSON.parse+ cast.Using a literal (or importing a JSON file) validated with
satisfies Messagesgives compile-time checks on keys and values.Example pattern (illustrative):
export const messages = { // ...catalog... } as const satisfies Messages;packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsx (1)
17-20: Avoid id collision with useFieldArray; set keyName and use it for React keys.Your items also have an
idfield; RHF usesidinternally. Use a custom keyName to prevent confusion.- const { fields, append, remove } = useFieldArray({ - control, - name: 'lineItems', - }); + const { fields, append, remove } = useFieldArray({ + control, + name: 'lineItems', + keyName: 'key', + });- key={item.id} + key={item.key}Also applies to: 31-31
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/validation.ts (1)
41-46: Reflect negative-price support in examples/meta.Schema allows negatives now; update examples to set expectations.
- price: z.number().meta({ + price: z.number().meta({ title: t(i18n)`Item price`, description: t(i18n)`Price per unit`, - examples: [10.99, 25.5, 100.0], + examples: [10.99, 25.5, 100.0, -5.0], }),packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx (5)
100-116: Invoice-only gating: OK; minor i18n nitGating looks good. Drop the unnecessary interpolation to keep the translation static.
- description={t( - i18n - )`You can not create receivable with a type other than “${'invoice'}”`} + description={t(i18n)`You can not create receivable with a type other than “invoice”`}
252-253: Load state not considered for contacts; may block reminder validationCounterpart contacts may still be loading at submit time and trigger a false “no email” error. Capture isLoading and guard submit/disable CTA until ready.
- const { data: counterpartContacts } = - useCounterpartContactList(counterpartId); + const { data: counterpartContacts, isLoading: areContactsLoading } = + useCounterpartContactList(counterpartId);Outside this hunk, also disable the submit button until contacts are loaded:
// In the Save button disabled={createReceivable.isPending || areContactsLoading}
314-319: Boolean intent: coerce to booleans for clarityPrevent string/undefined leakage into later conditionals.
- const customerHasRemindersEnabled = - counterpart && counterpart?.reminders_enabled; - const customerHasDefaultEmail = - counterpart && - counterpartContacts?.find((contact) => contact.is_default)?.email; + const customerHasRemindersEnabled = Boolean( + counterpart?.reminders_enabled + ); + const customerHasDefaultEmail = Boolean( + counterpartContacts?.find((contact) => contact.is_default)?.email + );
338-378: Deduplicate reminder validation branchesThree nearly identical blocks can be consolidated for readability and maintenance.
- if ( - !customerHasRemindersEnabled && - customerHasDefaultEmail && - (values.payment_reminder_id || values.overdue_reminder_id) - ) { - showErrorToast( - new Error( - 'Payment reminders are disabled for this customer. Please enable them in the customer details or turn them off.' - ) - ); - return; - } - - if ( - !customerHasDefaultEmail && - customerHasRemindersEnabled && - (values.payment_reminder_id || values.overdue_reminder_id) - ) { - showErrorToast( - new Error( - 'No email address is added for the selected customer. Please add it to the customer details or turn off the reminders.' - ) - ); - return; - } - - if ( - !customerHasRemindersEnabled && - !customerHasDefaultEmail && - (values.payment_reminder_id || values.overdue_reminder_id) - ) { - showErrorToast( - new Error( - 'Reminders are disabled for this customer, and no email address has been added for it. Please update the details or turn off reminders.' - ) - ); - return; - } + const remindersSelected = Boolean( + values.payment_reminder_id || values.overdue_reminder_id + ); + if (remindersSelected) { + if (!customerHasRemindersEnabled && !customerHasDefaultEmail) { + showErrorToast( + new Error( + 'Reminders are disabled for this customer, and no email address has been added for it. Please update the details or turn off reminders.' + ) + ); + return; + } + if (!customerHasRemindersEnabled) { + showErrorToast( + new Error( + 'Payment reminders are disabled for this customer. Please enable them in the customer details or turn them off.' + ) + ); + return; + } + if (!customerHasDefaultEmail) { + showErrorToast( + new Error( + 'No email address is added for the selected customer. Please add it to the customer details or turn off the reminders.' + ) + ); + return; + } + }
1107-1111: Avoid Math.random in render: unstable IDs can cause unnecessary re-mountsGenerate stable IDs; index-based fallback is fine for a non-editable preview.
- line_items: (lineItems || []).map((item) => ({ + line_items: (lineItems || []).map((item, idx) => ({ ...item, - id: item.id || `temp-${Math.random().toString(36).substr(2, 9)}`, + id: item.id || `temp-${idx}`, })) as CreateReceivablesFormBeforeValidationLineItemProps[],packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/sections/components/InvoicePreview.utils.ts (2)
58-71: Fallback label “item” may be misleadingConsider “unit” or an empty string to avoid confusing users when measure unit is unknown.
- return t(i18n)`item`; + return t(i18n)`unit`;
128-132: Country code normalizationIf getCountries uses upper-case ISO codes, normalize input to reduce fallbacks.
-export const getCountryName = (i18n: I18n, countryCode?: string) => { +export const getCountryName = (i18n: I18n, countryCode?: string) => { if (!countryCode) return ''; - - return getCountries(i18n)[countryCode] ?? countryCode; + const code = countryCode.toUpperCase(); + return getCountries(i18n)[code] ?? code; };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (19)
packages/sdk-demo/public/config.json(1 hunks)packages/sdk-demo/src/locales/en/messages.ts(1 hunks)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx(4 hunks)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/helpers.ts(1 hunks)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/validation.ts(1 hunks)packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsx(3 hunks)packages/sdk-react/src/components/payables/PayableDetails/usePayableDetails.tsx(2 hunks)packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx(10 hunks)packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/sections/components/InvoicePreview.types.ts(1 hunks)packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/sections/components/InvoicePreview.utils.ts(5 hunks)packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/sections/components/InvoicePreviewMonite.module.css(2 hunks)packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/sections/components/Items/ItemSelector.tsx(3 hunks)packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/validation.ts(1 hunks)packages/sdk-react/src/hooks/useA4Dimensions.ts(3 hunks)packages/sdk-react/src/hooks/useAdaptiveScale.ts(5 hunks)packages/sdk-react/src/hooks/useResizeObserver.ts(3 hunks)packages/sdk-react/src/hooks/useWindowResize.ts(3 hunks)packages/sdk-react/src/ui/components/aspect-ratio.tsx(1 hunks)packages/sdk-react/src/utils/dimensions.ts(4 hunks)
✅ Files skipped from review due to trivial changes (12)
- packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/sections/components/InvoicePreview.types.ts
- packages/sdk-react/src/components/payables/PayableDetails/usePayableDetails.tsx
- packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/sections/components/Items/ItemSelector.tsx
- packages/sdk-react/src/hooks/useWindowResize.ts
- packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/validation.ts
- packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/helpers.ts
- packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/sections/components/InvoicePreviewMonite.module.css
- packages/sdk-react/src/utils/dimensions.ts
- packages/sdk-react/src/hooks/useA4Dimensions.ts
- packages/sdk-demo/public/config.json
- packages/sdk-react/src/ui/components/aspect-ratio.tsx
- packages/sdk-react/src/hooks/useResizeObserver.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx
🧰 Additional context used
📓 Path-based instructions (2)
packages/sdk-react/**/*.{ts,tsx}
📄 CodeRabbit inference engine (packages/sdk-react/.cursor/rules/api-calls.mdc)
packages/sdk-react/**/*.{ts,tsx}: Use proper TypeScript types for API data and leverage type inference from the OpenAPI schema
Use custom TypeScript types (e.g., Invoice, CreateInvoiceInput) imported from '@/types/api' for Monite API data structures
Files:
packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsxpackages/sdk-react/src/hooks/useAdaptiveScale.tspackages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/sections/components/InvoicePreview.utils.tspackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/validation.tspackages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx
packages/sdk-react/**/*.tsx
📄 CodeRabbit inference engine (packages/sdk-react/.cursor/rules/ui-components.mdc)
packages/sdk-react/**/*.tsx: Always use shadcn/ui components when creating new UI elements
Import components from '@/ui/components/*' when using shadcn/ui components
All Tailwind classes should have the prefix 'mtw' (e.g., 'mtw:w-full')
Use Tailwind CSS utility classes for all styling
Avoid inline styles or styled-components
Follow Tailwind's mobile-first responsive design approach
Use Tailwind's color palette and spacing scale
Do NOT use Material UI for new components
When modifying files with Material UI: only update to shadcn/ui if the component needs significant changes; otherwise, maintain existing MUI implementation; add TODO comments when MUI components should be migrated
Always prefer shadcn/ui components such as Button, Input, Card, Dialog, etc., from '@/ui/components/[component]'
Use React Hook Form with shadcn/ui form components
Use 'lucide-react' for icons and import icons like 'import { Search, Menu, X } from "lucide-react"'
Always use named imports from the specific ui component file
Use the variant prop for different styles (e.g., variant="outline" for buttons)
Use the size prop when available (e.g., size="sm" for smaller buttons)
Extend components with className prop using Tailwind utilities
When updating Material UI components to shadcn/ui: map MUI component to shadcn/ui equivalent, convert sx props and makeStyles to Tailwind classes, update event handlers if API differs, test thoroughly, remove MUI imports only after confirming all usages are replaced
Use TypeScript for all new components
Leverage component prop types for better IntelliSense
Files:
packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsxpackages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx
🧠 Learnings (10)
📚 Learning: 2025-09-04T16:18:44.198Z
Learnt from: costa-monite
PR: team-monite/monite-sdk#785
File: packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsx:6-6
Timestamp: 2025-09-04T16:18:44.198Z
Learning: For forms in monite-sdk, prefer lib-agnostic TypeScript types (e.g., PayableDetailsFormFields) for component generics and contracts; avoid coupling components to Zod-inferred types. Use Zod only at the validation layer (e.g., zodResolver with a schema typed as ZodType<FormValues>).
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/validation.ts
📚 Learning: 2025-09-08T09:09:14.252Z
Learnt from: costa-monite
PR: team-monite/monite-sdk#785
File: packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/sections/components/InvoicePreviewMonite.tsx:320-336
Timestamp: 2025-09-08T09:09:14.252Z
Learning: In InvoicePreviewMonite component at packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/sections/components/InvoicePreviewMonite.tsx, the price values from item.product.price.value are already in minor units (as defined in the PriceFloat API schema), so they can be passed directly to formatCurrencyToDisplay without conversion.
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsxpackages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/sections/components/InvoicePreview.utils.tspackages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx
📚 Learning: 2025-07-21T08:10:47.057Z
Learnt from: CR
PR: team-monite/monite-sdk#0
File: examples/with-nextjs-and-clerk-auth/.cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-07-21T08:10:47.057Z
Learning: Applies to examples/with-nextjs-and-clerk-auth/src/components/**/*.tsx : Use React Hook Form with shadcn/ui form components for form handling
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsxpackages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx
📚 Learning: 2025-07-21T08:11:43.801Z
Learnt from: CR
PR: team-monite/monite-sdk#0
File: packages/sdk-react/.cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-07-21T08:11:43.801Z
Learning: Applies to packages/sdk-react/**/*.tsx : Use React Hook Form with shadcn/ui form components
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsxpackages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx
📚 Learning: 2025-09-05T11:02:00.698Z
Learnt from: costa-monite
PR: team-monite/monite-sdk#785
File: packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/sections/components/InvoicePreview.tsx:34-39
Timestamp: 2025-09-05T11:02:00.698Z
Learning: In the InvoicePreview component at packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/sections/components/InvoicePreview.tsx, the minScale: 1 setting in useAdaptiveScale is intentionally set to prevent downscaling below 100% to maintain invoice readability and quality, even if it requires scrolling on smaller viewports.
Applied to files:
packages/sdk-react/src/hooks/useAdaptiveScale.tspackages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx
📚 Learning: 2025-07-21T08:11:43.801Z
Learnt from: CR
PR: team-monite/monite-sdk#0
File: packages/sdk-react/.cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-07-21T08:11:43.801Z
Learning: Applies to packages/sdk-react/**/*.tsx : When updating Material UI components to shadcn/ui: map MUI component to shadcn/ui equivalent, convert sx props and makeStyles to Tailwind classes, update event handlers if API differs, test thoroughly, remove MUI imports only after confirming all usages are replaced
Applied to files:
packages/sdk-react/src/hooks/useAdaptiveScale.ts
📚 Learning: 2025-07-21T08:11:43.801Z
Learnt from: CR
PR: team-monite/monite-sdk#0
File: packages/sdk-react/.cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-07-21T08:11:43.801Z
Learning: Applies to packages/sdk-react/**/*.tsx : Use Tailwind's color palette and spacing scale
Applied to files:
packages/sdk-react/src/hooks/useAdaptiveScale.ts
📚 Learning: 2025-07-21T08:11:43.801Z
Learnt from: CR
PR: team-monite/monite-sdk#0
File: packages/sdk-react/.cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-07-21T08:11:43.801Z
Learning: Applies to packages/sdk-react/**/*.tsx : When modifying files with Material UI: only update to shadcn/ui if the component needs significant changes; otherwise, maintain existing MUI implementation; add TODO comments when MUI components should be migrated
Applied to files:
packages/sdk-react/src/hooks/useAdaptiveScale.ts
📚 Learning: 2025-07-21T08:11:43.801Z
Learnt from: CR
PR: team-monite/monite-sdk#0
File: packages/sdk-react/.cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-07-21T08:11:43.801Z
Learning: Applies to packages/sdk-react/**/*.tsx : Use the size prop when available (e.g., size="sm" for smaller buttons)
Applied to files:
packages/sdk-react/src/hooks/useAdaptiveScale.ts
📚 Learning: 2025-07-21T08:10:12.113Z
Learnt from: CR
PR: team-monite/monite-sdk#0
File: examples/with-nextjs-and-clerk-auth/.cursor/rules/api-calls.mdc:0-0
Timestamp: 2025-07-21T08:10:12.113Z
Learning: Applies to examples/with-nextjs-and-clerk-auth/**/*.tsx : Use React Query hooks (useQuery, useMutation) provided by the API.
Applied to files:
packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx
🧬 Code graph analysis (2)
packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsx (1)
packages/sdk-react/src/ui/RHF/RHFTextField/RHFTextField.tsx (1)
RHFTextField(8-78)
packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx (1)
packages/sdk-react/src/core/queries/useCounterpart.ts (1)
useCounterpartContactList(342-422)
🪛 Biome (2.1.2)
packages/sdk-demo/src/locales/en/messages.ts
[error] 4-4: Shouldn't redeclare 'Messages'. Consider to delete it or rename it.
'Messages' is defined here:
(lint/suspicious/noRedeclare)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Build and Push sdk-playground
- GitHub Check: Build and Push sdk-demo-with-nextjs-and-clerk-auth
- GitHub Check: Build and Push sdk-drop-in
- GitHub Check: Build
🔇 Additional comments (15)
packages/sdk-react/src/hooks/useAdaptiveScale.ts (5)
1-1: Import of useA4Dimensions looks goodMatches the hook’s intent to base defaults on A4 dimensions. No issues.
5-5: Import reordering/readabilityPurely stylistic; no functional impact.
39-43: A4-based min dimensions — OKUsing
useAdaptiveDimensions ? a4Dimensions : 794x1123is consistent with the A4 default. This aligns with the prior decision to keepminScale >= 1for readability.
59-65: Defensive guards — OKEarly-returning to
minScaleon non-positive dimensions is sensible and matches the “never downscale below 1” requirement.
120-120: No-op changeTrailing newline/brace formatting only.
packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsx (2)
36-41: LGTM on migrating to RHFTextField for name.Keeps validation/error UI consistent with the new abstraction.
93-103: LGTM on VAT constraints.0–100% bounds are enforced at the schema and UI layer.
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/validation.ts (3)
14-21: LGTM on whitespace-safe requiredString.Prevents “all-spaces” values from slipping through.
31-39: LGTM on quantity and tax constraints.Whole-number quantity > 0 and tax within 0–100 are appropriate.
Also applies to: 47-55
83-90: Verify API contract for optionalcounterpart_bank_account_id. EmptycounterpartBankAccountis mapped toundefinedin the request payload and validation/refine logic already handles required cases.packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/sections/components/InvoicePreview.utils.ts (5)
1-7: Imports: OKNew utils are properly sourced and typed.
16-30: Payment terms discount: OKPriority order and minor→major conversion are correct.
35-42: Measure unit lookup: OKStraightforward and typed; null fallback is sensible.
77-86: Rate value resolution: OKDelegation to getRateValueForDisplay with sensible defaults.
117-126: Counterpart phone extraction: confirm both schema variants includephoneEnsure in the
CounterpartResponsetype that both theorganizationandindividualshapes always (or optionally) includephone; adjust your code to handle cases where either variant may omitphone.
...k-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsx
Show resolved
Hide resolved
...k-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsx
Show resolved
Hide resolved
...s/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx
Outdated
Show resolved
Hide resolved
0b49670 to
d4fc251
Compare
…Form and PayableLineItemsForm for improved input number handling
d4fc251 to
b231791
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (3)
packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsx (3)
86-89: Use InputAdornment and avoid inline watch; add step='any' for decimals.- type="number" - fullWidth - InputProps={{ - endAdornment: getSymbolFromCurrency(watch('currency')), - }} + type="number" + inputProps={{ step: 'any' }} + fullWidth + InputProps={{ + endAdornment: ( + <InputAdornment position="end"> + {getSymbolFromCurrency(currentCurrency)} + </InputAdornment> + ), + }}Also update imports per comment on Lines 9-10.
44-51: Numeric-input interim state issue applies here too (quantity).Once RHFTextField is fixed, typing transitions (e.g., clearing then retyping) will behave correctly across all numeric fields.
80-89: Negative prices still impossible due to RHFTextField number coercion (blocks "-" typing).RHFTextField coerces every keystroke via Number(...), so typing "-" or "1." becomes NaN. This prevents entering negatives, defeating DEV-15902.
Apply the RHFTextField fix below (cross-file) and the adornment/step tweaks from the next comment.
🧹 Nitpick comments (9)
.changeset/rare-singers-sniff.md (1)
5-5: Clarify the note to set expectations (discounts remain ≥ 0).Consider explicitly stating that only line-item price can be negative while discounts remain non-negative, to avoid confusion in the release notes.
- Allow Line Items with negative price values + Allow line items with negative price values (discounts remain non-negative)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/validation.ts (3)
31-39: Quantity constraints are appropriate.Optional: add a sane upper bound to prevent accidental huge values (e.g., max(1_000_000) with a localized message).
- quantity: z - .number() + quantity: z + .number() .int(t(i18n)`Item quantity must be a whole number`) .positive(t(i18n)`Item quantity must be greater than 0`) + .max(1_000_000, t(i18n)`Item quantity is too large`)
159-169: Ensure the date is valid, not just a Date instance.
new Date('')is an invalid Date but still an instance. Guard against it.- if (isFieldRequiredByValidations('issued_at', payablesValidations)) { - return data.invoiceDate instanceof Date; + if (isFieldRequiredByValidations('issued_at', payablesValidations)) { + return ( + data.invoiceDate instanceof Date && + !isNaN(data.invoiceDate.getTime()) + ); }
127-142: Refine splits are clearer and field-scoped – nice.Optional: add a cross-field refine to ensure
dueDate >= invoiceDatewhen both are present.Also applies to: 172-182
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx (1)
185-191: Decouple form generics from Zod-inferred types.Per prior guidance, prefer lib-agnostic form value types. Use
PayableDetailsFormFieldsas the generic foruseFormand component props; keep Zod purely for validation.- const methods = useForm<PayableDetailsValidationFields>({ + const methods = useForm<PayableDetailsFormFields>({ resolver: zodResolver( getPayableDetailsValidationSchema(i18n, payablesValidations) ),Follow-ups:
- Also update downstream generics (
MoniteCurrency,CounterpartAutocomplete, etc.) toPayableDetailsFormFields.packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsx (4)
92-102: Wrap '%' in InputAdornment; consider allowing fractional VAT via step='any'.- inputProps={{ min: 0, max: 100 }} + inputProps={{ min: 0, max: 100, step: 'any' }} fullWidth - InputProps={{ - endAdornment: '%', - }} + InputProps={{ + endAdornment: ( + <InputAdornment position="end">%</InputAdornment> + ), + }}
9-10: Import InputAdornment and useWatch.-import { Button, Grid, IconButton, Typography } from '@mui/material'; -import { useFieldArray, useFormContext } from 'react-hook-form'; +import { Button, Grid, IconButton, Typography, InputAdornment } from '@mui/material'; +import { useFieldArray, useFormContext, useWatch } from 'react-hook-form';
16-23: Prefer useWatch for currency/lineItems to reduce unnecessary re-renders.- const { control, watch } = useFormContext<PayableDetailsFormFields>(); + const { control } = useFormContext<PayableDetailsFormFields>(); const { fields, append, remove } = useFieldArray({ control, name: 'lineItems', }); - const currentCurrency = watch('currency'); - const currentLineItems = watch('lineItems'); + const currentCurrency = useWatch({ control, name: 'currency' }); + const currentLineItems = useWatch({ control, name: 'lineItems' });
127-135: Default appended item OK; consider using org default VAT if available.Happy to wire this to a settings-derived default if you have one.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
.changeset/rare-singers-sniff.md(1 hunks)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx(4 hunks)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/validation.ts(1 hunks)packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsx(3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
packages/sdk-react/**/*.{ts,tsx}
📄 CodeRabbit inference engine (packages/sdk-react/.cursor/rules/api-calls.mdc)
packages/sdk-react/**/*.{ts,tsx}: Use proper TypeScript types for API data and leverage type inference from the OpenAPI schema
Use custom TypeScript types (e.g., Invoice, CreateInvoiceInput) imported from '@/types/api' for Monite API data structures
Files:
packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/validation.ts
packages/sdk-react/**/*.tsx
📄 CodeRabbit inference engine (packages/sdk-react/.cursor/rules/ui-components.mdc)
packages/sdk-react/**/*.tsx: Always use shadcn/ui components when creating new UI elements
Import components from '@/ui/components/*' when using shadcn/ui components
All Tailwind classes should have the prefix 'mtw' (e.g., 'mtw:w-full')
Use Tailwind CSS utility classes for all styling
Avoid inline styles or styled-components
Follow Tailwind's mobile-first responsive design approach
Use Tailwind's color palette and spacing scale
Do NOT use Material UI for new components
When modifying files with Material UI: only update to shadcn/ui if the component needs significant changes; otherwise, maintain existing MUI implementation; add TODO comments when MUI components should be migrated
Always prefer shadcn/ui components such as Button, Input, Card, Dialog, etc., from '@/ui/components/[component]'
Use React Hook Form with shadcn/ui form components
Use 'lucide-react' for icons and import icons like 'import { Search, Menu, X } from "lucide-react"'
Always use named imports from the specific ui component file
Use the variant prop for different styles (e.g., variant="outline" for buttons)
Use the size prop when available (e.g., size="sm" for smaller buttons)
Extend components with className prop using Tailwind utilities
When updating Material UI components to shadcn/ui: map MUI component to shadcn/ui equivalent, convert sx props and makeStyles to Tailwind classes, update event handlers if API differs, test thoroughly, remove MUI imports only after confirming all usages are replaced
Use TypeScript for all new components
Leverage component prop types for better IntelliSense
Files:
packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx
🧠 Learnings (4)
📚 Learning: 2025-07-21T08:10:47.057Z
Learnt from: CR
PR: team-monite/monite-sdk#0
File: examples/with-nextjs-and-clerk-auth/.cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-07-21T08:10:47.057Z
Learning: Applies to examples/with-nextjs-and-clerk-auth/src/components/**/*.tsx : Use React Hook Form with shadcn/ui form components for form handling
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx
📚 Learning: 2025-07-21T08:11:43.801Z
Learnt from: CR
PR: team-monite/monite-sdk#0
File: packages/sdk-react/.cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-07-21T08:11:43.801Z
Learning: Applies to packages/sdk-react/**/*.tsx : Use React Hook Form with shadcn/ui form components
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx
📚 Learning: 2025-09-08T09:09:14.252Z
Learnt from: costa-monite
PR: team-monite/monite-sdk#785
File: packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/sections/components/InvoicePreviewMonite.tsx:320-336
Timestamp: 2025-09-08T09:09:14.252Z
Learning: In InvoicePreviewMonite component at packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/sections/components/InvoicePreviewMonite.tsx, the price values from item.product.price.value are already in minor units (as defined in the PriceFloat API schema), so they can be passed directly to formatCurrencyToDisplay without conversion.
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/validation.ts
📚 Learning: 2025-09-04T16:18:44.198Z
Learnt from: costa-monite
PR: team-monite/monite-sdk#785
File: packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsx:6-6
Timestamp: 2025-09-04T16:18:44.198Z
Learning: For forms in monite-sdk, prefer lib-agnostic TypeScript types (e.g., PayableDetailsFormFields) for component generics and contracts; avoid coupling components to Zod-inferred types. Use Zod only at the validation layer (e.g., zodResolver with a schema typed as ZodType<FormValues>).
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/validation.ts
🧬 Code graph analysis (2)
packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsx (1)
packages/sdk-react/src/ui/RHF/RHFTextField/RHFTextField.tsx (1)
RHFTextField(8-78)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx (3)
packages/sdk-react/src/ui/Currency/MoniteCurrency.tsx (1)
MoniteCurrency(57-173)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/validation.ts (1)
PayableDetailsValidationFields(185-187)packages/sdk-react/src/ui/RHF/RHFTextField/RHFTextField.tsx (1)
RHFTextField(8-78)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Build and Push sdk-demo-with-nextjs-and-clerk-auth
- GitHub Check: Build and Push sdk-drop-in
- GitHub Check: Build and Push sdk-playground
- GitHub Check: Build
🔇 Additional comments (10)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/validation.ts (2)
14-21: Trim-aware required string helper looks good.
47-55: Tax constraints look correct.packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx (6)
5-5: Type-only import re-ordering is fine.
44-44: RHFTextField import looks good.
583-587: Currency field generic: OK after switching the form generic.If you adopt the form-generic change above, also update this to:
- <MoniteCurrency<PayableDetailsValidationFields, 'currency'>> + <MoniteCurrency<PayableDetailsFormFields, 'currency'>>
682-692: Discount field constraints: consistent with schema.
min: 0and the schema’smin(0)align; end adornment usage is fine.
650-658: formatToMinorUnits handles negative amounts as expected
formatToMinorUnits returnsNumber(amount) * 10^minor_units, so negative inputs yield negative minor-unit values without sign loss or clamping.
621-623: Price input field has nomin: 0; UI already permits negatives.packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsx (2)
36-41: LGTM: name field migration to RHFTextField looks good.
106-123: Confirm unit expectations in total calculation with negatives.Verify calculateTotalPriceForLineItem + formatToMinorUnits handle negative prices and taxes as intended (e.g., discounts). Ensure the displayed sign matches business rules.
Scope
Allow Line Items negative price values.
Jira ticket: https://monite.atlassian.net/browse/DEV-15902
Implementation
minvalidation from field lineItems.price in PayableDetailsForm.Steps to test
Summary by CodeRabbit
New Features
Improvements
Chores