feat(DEV-15658): Payables remove automatic calculation of totals and allow manual edit#822
feat(DEV-15658): Payables remove automatic calculation of totals and allow manual edit#822dinis-monite wants to merge 21 commits into
Conversation
… into reusable components
…ailsFormFields interface
…according to isCalculateTotalsEnabled flag
… input number handling
…s in PayableDetailsForm
…s conditionally on disableAutoCalculateTotals flag
…ables `componentSettings`. When set to `true`, this allows users to manually edit the totals values of a Payable; no automatic calculation will be performed on the client side.
🦋 Changeset detectedLatest commit: fb64a56 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 |
WalkthroughAdds a payables feature flag Changes
Possibly related PRs
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. 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 |
|
🚀 Preview URLs are now available! 🚀 |
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
packages/sdk-react/src/core/componentSettings/index.ts (1)
319-466: Remove temporary isDisableAutoCalculateTotals logic
Occurrences of the hard-codedisDisableAutoCalculateTotalsremain inpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx(lines 189–192, 200, 202, 387) and must be reverted or removed.packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsx (1)
17-21: Avoid RHF key collision with reserved iduseFieldArray reserves item.id; your data model also uses id. Set keyName to prevent collisions and use the custom key for React keys.
- const { fields, append, remove } = useFieldArray({ - control, - name: 'lineItems', - }); + const { fields, append, remove } = useFieldArray({ + control, + name: 'lineItems', + keyName: '_key', + }); ... - {fields.map((item, index) => ( + {fields.map((item, index) => ( <Grid item container gap={2} - key={item.id} + key={item._key}Also applies to: 26-36
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/helpers.ts (1)
49-57: Critical: helpers default to manual-totals mode when flag is omitted (breaks back-compat).
isCalculateTotalsEnabledis optional, soundefinedis treated as falsy and triggers the manual-totals path by default. This changes existing behavior: new/edit forms will initialize totals as user-editable (zeros) and include totals in submit payloads unless the caller explicitly opts in. Set a safe default oftrue.Apply this diff:
export const prepareDefaultValues = ( formatFromMinorUnits: ( amount: number, currency: CurrencyEnum | string ) => number | null, payable?: components['schemas']['PayableResponseSchema'], lineItems?: components['schemas']['LineItemResponse'][], - isCalculateTotalsEnabled?: boolean + isCalculateTotalsEnabled: boolean = true ): PayableDetailsFormFields => { @@ export const prepareSubmit = ( { invoiceNumber, @@ total_amount, }: SubmitPayload, - formatToMinorUnits: (amount: number, currency: string) => number | null, - isCalculateTotalsEnabled?: boolean + formatToMinorUnits: (amount: number, currency: string) => number | null, + isCalculateTotalsEnabled: boolean = true ): components['schemas']['PayableUpdateSchema'] => {Also applies to: 159-161, 79-87, 128-141, 175-184
🧹 Nitpick comments (14)
.changeset/shaggy-eels-pretend.md (1)
5-5: Expand the changeset with public API notes and ops caveats
- Mention that PayableDetailsInfo now publicly re-exports DisplayPayableLineItems and DisplayPayableTotals (minor surface growth).
- Add a brief note on required partner settings interplay (payable.enable_line_items vs manual totals) and units (totals in minor units on API, major units in form), to reduce integration surprises.
packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsx (2)
96-101: Use InputAdornment for endAdornment and reuse currentCurrencyMinor MUI correctness/readability: use InputAdornment and the already watched currentCurrency.
+import InputAdornment from '@mui/material/InputAdornment'; ... - InputProps={{ - endAdornment: getSymbolFromCurrency(watch('currency')), - }} + InputProps={{ + endAdornment: ( + <InputAdornment position="end"> + {getSymbolFromCurrency(currentCurrency) ?? ''} + </InputAdornment> + ), + }}- InputProps={{ - endAdornment: '%', - }} + InputProps={{ + endAdornment: <InputAdornment position="end">%</InputAdornment>, + }}Also applies to: 102-112
71-77: Improve a11y label for delete actionMake the intent explicit for screen readers.
- <IconButton - aria-label="delete" + <IconButton + aria-label={t(i18n)`Delete line item ${index + 1}`} onClick={() => remove(index)} disabled={fields.length === 1} >packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/types.ts (1)
20-23: Document major/minor unit conversions and consider camelCase
- Add JSDoc to PayableDetailsFormFields (
subtotal,tax_amount,total_amount) clarifying these are main-currency (major-unit) values, converted to minor units in prepareSubmit and back in prepareDefaultValues.- prepareDefaultValues uses
formatFromMinorUnits(...)and prepareSubmit usesformatToMinorUnits(...), so unit conversions are already correctly applied.- Optional: rename
tax_amount/total_amounttotaxAmount/totalAmountin the form interface and map to API snake_case in the helpers for consistent field naming.packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableLineItems.tsx (2)
33-34: Header wording mismatch with contentHeader says “Total, tax” but body shows subtotal “excl. Tax”. Make the header explicit.
- <TableCell align="right">{t(i18n)`Total, tax`}</TableCell> + <TableCell align="right">{t(i18n)`Total (excl. tax)`}</TableCell>
52-55: Styling: replace MUI sx with Tailwind or theme tokens (post-migration)When migrating to shadcn/ui, replace sx with Tailwind (e.g., mtw-text-muted-foreground).
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableTotals.tsx (1)
34-41: Display discount row for zero or negative values
Replace the truthy check with an explicit null check so that a discount of 0 or any negative value still renders the row:- {payable.discount && payable.discount > 0 ? ( + {payable.discount != null ? ( <TableRow> <TableCell>{t(i18n)`Discount`}</TableCell> <TableCell align="right"> {formatCurrencyToDisplay(payable.discount, currency)} </TableCell> </TableRow> ) : null}packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx (2)
323-348: Consider simplifying the dirty field detection logic.The current implementation correctly identifies changes in line items and totals. However, the nested logic could be simplified for better readability.
Consider this more concise approach:
- // Check if Line Items values have changed - const areLineItemsValuesChanged = (() => { - if (!dirtyFields.lineItems) return false; - const hasLengthChanged = - dirtyFields.lineItems.length !== (lineItems?.length || 0); - const hasRelevantFieldsChanged = dirtyFields.lineItems.some( - (lineItemDirtyFields) => { - if (!lineItemDirtyFields) return false; - return !!( - lineItemDirtyFields.quantity || - lineItemDirtyFields.price || - lineItemDirtyFields.tax - ); - } - ); - return hasLengthChanged || hasRelevantFieldsChanged; - })(); + // Check if Line Items values have changed + const areLineItemsValuesChanged = useMemo(() => { + if (!dirtyFields.lineItems) return false; + + // Check if number of items changed + if (dirtyFields.lineItems.length !== (lineItems?.length || 0)) { + return true; + } + + // Check if any relevant fields changed + return dirtyFields.lineItems.some(item => + item && (item.quantity || item.price || item.tax) + ); + }, [dirtyFields.lineItems, lineItems?.length]);
684-692: Include alert for line-item changes even when totals are locked
At PayableDetailsForm.tsx:684-692 the warning is gated byisTotalsEditable && showAlertChangedValues, butshowAlertChangedValuesis true for line-item diffs as well. Remove theisTotalsEditablecheck or add a separate branch so that any line-item change always triggers the alert.packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/helpers.ts (5)
79-87: Creation defaults: prefer nulls over 0 for manual totals.Using
0makes the UI look “valid” before the user acts and can mask validation. Usingnullbetter signals “unset”.Apply this diff:
- if (!isCalculateTotalsEnabled) { - return { - ...defaultValuesCreating, - subtotal: 0, - tax_amount: 0, - total_amount: 0, - }; - } + if (!isCalculateTotalsEnabled) { + return { + ...defaultValuesCreating, + subtotal: null, + tax_amount: null, + total_amount: null, + }; + }
128-141: Normalize formatter nulls to numbers for edit defaults.Guard against
formatFromMinorUnitsreturningnullso form fields don’t getnullunexpectedly.Apply this diff:
- subtotal: - subtotal && currency ? formatFromMinorUnits(subtotal, currency) : 0, - tax_amount: - tax_amount && currency ? formatFromMinorUnits(tax_amount, currency) : 0, - total_amount: - total_amount && currency - ? formatFromMinorUnits(total_amount, currency) - : 0, + subtotal: + subtotal && currency + ? (formatFromMinorUnits(subtotal, currency) ?? 0) + : 0, + tax_amount: + tax_amount && currency + ? (formatFromMinorUnits(tax_amount, currency) ?? 0) + : 0, + total_amount: + total_amount && currency + ? (formatFromMinorUnits(total_amount, currency) ?? 0) + : 0,
49-57: Naming consistency: align flag semantics.Here we use
isCalculateTotalsEnabled, while the public prop isdisableAutoCalculateTotals. Consider a single positive boolean (isAutoTotalsEnabledormanualTotalsEnabled) to reduce double-negation across call sites.
321-327: Public API addition looks good; add JSDoc and default.Add a short JSDoc and ensure default is
falseat the consumer boundary (e.g., theme hook) for predictable behavior.
162-174: Guard discount in payload
Only spreaddiscountwhen non-null to prevent unintentionally sending0and clearing existing server-side values.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
.changeset/shaggy-eels-pretend.md(1 hunks)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx(13 hunks)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/helpers.ts(7 hunks)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/types.ts(1 hunks)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/validation.ts(1 hunks)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableLineItems.tsx(1 hunks)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableTotals.tsx(1 hunks)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/PayableDetailsInfo.tsx(2 hunks)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/index.tsx(1 hunks)packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsx(3 hunks)packages/sdk-react/src/components/payables/hooks/usePayableDetailsThemeProps.ts(1 hunks)packages/sdk-react/src/core/componentSettings/index.ts(1 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/PayableDetailsInfo/index.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableTotals.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableLineItems.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/types.tspackages/sdk-react/src/components/payables/hooks/usePayableDetailsThemeProps.tspackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/PayableDetailsInfo.tsxpackages/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/helpers.tspackages/sdk-react/src/core/componentSettings/index.tspackages/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/PayableDetailsInfo/index.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableTotals.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableLineItems.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/PayableDetailsInfo.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx
🧠 Learnings (9)
📓 Common learnings
Learnt from: costa-monite
PR: team-monite/monite-sdk#785
File: packages/sdk-react/src/core/i18n/locales/en/messages.po:8470-8473
Timestamp: 2025-09-04T15:54:24.944Z
Learning: For PRs focused on the invoice preview template (feat/DEV-15554), costa-monite prefers to exclude out-of-scope tweaks like minor i18n spacing changes (e.g., "Subtotal{0}" → "Subtotal {0}") and handle them in a separate follow-up.
📚 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/PayableDetailsInfo/DisplayPayableTotals.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableLineItems.tsxpackages/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/helpers.ts
📚 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-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/helpers.tspackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/validation.ts
📚 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 lucide-react for icons and import icons like: import { Search, Menu, X } from 'lucide-react'
Applied to files:
packages/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 'lucide-react' for icons and import icons like 'import { Search, Menu, X } from "lucide-react"'
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.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 : Always prefer shadcn/ui components such as Button, Input, Card, Dialog, Select, Checkbox, RadioGroup, Switch, Textarea, Label, Alert, Badge, Toast, Tabs, Table, Form, DropdownMenu, Sheet, Skeleton, Separator
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.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 : Always use shadcn/ui components when creating new UI elements
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx
🧬 Code graph analysis (6)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableTotals.tsx (1)
packages/sdk-react/src/core/hooks/useCurrencies.ts (1)
useCurrencies(15-170)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableLineItems.tsx (1)
packages/sdk-react/src/core/hooks/useCurrencies.ts (1)
useCurrencies(15-170)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/PayableDetailsInfo.tsx (2)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableLineItems.tsx (1)
DisplayPayableLineItems(15-67)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableTotals.tsx (1)
DisplayPayableTotals(14-62)
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 (7)
packages/sdk-react/src/components/payables/hooks/usePayableDetailsThemeProps.ts (1)
usePayableDetailsThemeProps(4-24)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/helpers.ts (1)
prepareDefaultValues(49-142)packages/sdk-react/src/ui/Currency/MoniteCurrency.tsx (1)
MoniteCurrency(57-173)packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsx (1)
PayableLineItemsForm(12-148)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableLineItems.tsx (1)
DisplayPayableLineItems(15-67)packages/sdk-react/src/ui/components/alert.tsx (1)
Alert(98-98)packages/sdk-react/src/ui/RHF/RHFTextField/RHFTextField.tsx (1)
RHFTextField(8-78)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/helpers.ts (1)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/types.ts (1)
PayableDetailsFormFields(10-23)
⏰ 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). (7)
- GitHub Check: Build and Push sdk-playground
- GitHub Check: Build and Push sdk-drop-in
- 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 and Push sdk-demo-with-nextjs-and-clerk-auth
- GitHub Check: Build
🔇 Additional comments (13)
packages/sdk-react/src/core/componentSettings/index.ts (2)
350-377: LGTM on defaults and wiringGood defaulting pattern (nullish coalescing) and placement alongside other payables flags.
367-369: disableAutoCalculateTotals is declared on MonitePayableDetailsInfoProps
Verified as an optional boolean in packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/helpers.ts (line 326).packages/sdk-react/src/components/payables/hooks/usePayableDetailsThemeProps.ts (1)
20-23: Flag wiring matches componentSettingsCorrect precedence (inProps over componentSettings). No further action.
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableLineItems.tsx (1)
47-59: Confirm tax units & handle zero subtotal
- Replace the truthy check with
item.subtotal != nullso a subtotal of 0 renders correctly.- Verify whether
item.taxon LineItemResponse is expressed as a percentage (0–100) or in basis points (e.g. 1900) and adjust the display logic accordingly.packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableTotals.tsx (1)
29-56: LGTM on currency formatting and fallbacksUsing formatCurrencyToDisplay with minor-unit inputs is correct and consistent.
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/PayableDetailsInfo.tsx (1)
7-8: LGTM! Clean refactoring to use the new display components.The extraction of line items and totals display logic into separate components improves code organization and reusability. The components receive appropriate props with sensible defaults for currency.
Also applies to: 475-479, 482-486
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx (3)
719-742: Good implementation of conditional editing for totals fields.The switch between editable
RHFTextFieldcomponents and read-only display based onisTotalsEditableis well implemented. The numeric input constraints and currency symbol display are correctly configured.Also applies to: 789-812, 828-852
765-775: LGTM! Proper migration from Controller to RHFTextField.The discount field has been correctly migrated to use
RHFTextFieldwith appropriate numeric constraints and currency display.
631-634: Good TypeScript practice with explicit generic parameters.The explicit type parameters for
MoniteCurrencyimprove type safety and code clarity.packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/validation.ts (2)
123-139: Validation for new totals fields looks good.The new optional fields
subtotal,tax_amount, andtotal_amountare properly validated with non-negative constraints and appropriate error messages.
14-21: Formatting improvements enhance readability.The multi-line chaining style for the validation schema improves code readability while maintaining the same functionality.
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/helpers.ts (2)
1-1: Type-only import LGTM.Using
import typekeeps bundles clean.
175-184: API supports manual totals fields
Propertiessubtotal,tax_amount, andtotal_amountare defined (and optional) in PayableUpdateSchema in schema.json, so you can safely include them in the patch payload.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (6)
packages/sdk-react/src/core/i18n/locales/en/messages.po (6)
499-501: Casing: “Add Discount” vs existing “Add discount”UI copy style is inconsistent with the existing “Add discount” (lowercase “d”). Recommend unifying.
-msgid "Add Discount" -msgstr "Add Discount" +msgid "Add discount" +msgstr "Add discount"Note: update the corresponding usages in PayableDetailsForm to match the new msgid.
1262-1270: Duplicate strings differ only by capitalization (“Bank account” vs “Bank Account”)Having both forces extra translations and risks drift. Prefer a single canonical form (“Bank account”) and reuse it.
- msgid "Bank Account" - msgstr "Bank Account" + msgid "Bank account" + msgstr "Bank account"Also align the component label to reuse the same msgid.
4024-4027: Fix label casing: “excl. Tax” → “Excl. tax”Current casing is inconsistent with “Incl. tax”. Suggest Title-case first word only.
-msgid "excl. Tax" -msgstr "excl. Tax" +msgid "Excl. tax" +msgstr "Excl. tax"Remember to update the DisplayPayableLineItems usage.
9482-9485: Clarify “Total, tax” column header“Total, tax” is ambiguous. Align with existing patterns (“Incl. tax” / “Excl. tax”) or use “Total incl. tax”.
-msgid "Total, tax" -msgstr "Total, tax" +msgid "Total incl. tax" +msgstr "Total incl. tax"If you actually need the generic “Incl. tax”, consider reusing the existing msgid instead of adding a near-duplicate.
10086-10093: Unify “VAT total” vs “VAT Total”Two variants exist across Payables: “VAT total” (form) and “VAT Total” (display). Pick one (recommend “VAT total” to match “Subtotal”, “Total tax”).
- msgid "VAT Total" - msgstr "VAT Total" + msgid "VAT total" + msgstr "VAT total"
6160-6175: Add context/explicit IDs for generic terms (Name, Price, Quantity, Subtotal, Total, Discount)These high-frequency msgids are reused across many screens. To avoid translation collisions in some locales, add msgctxt or explicit IDs for the Payables context (e.g., “PayablesLineItems-Name”, “PayablesTotals-Subtotal”).
Example (PO):
- msgid "Name" + msgctxt "PayablesLineItems" + msgid "Name"Or switch these to js-lingui explicit IDs in code and PO.
Also applies to: 7455-7463, 7620-7624, 8739-8747, 9430-9435, 3213-3217
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/sdk-react/src/core/i18n/locales/en/messages.po(53 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: costa-monite
PR: team-monite/monite-sdk#785
File: packages/sdk-react/src/core/i18n/locales/en/messages.po:8470-8473
Timestamp: 2025-09-04T15:54:24.944Z
Learning: For PRs focused on the invoice preview template (feat/DEV-15554), costa-monite prefers to exclude out-of-scope tweaks like minor i18n spacing changes (e.g., "Subtotal{0}" → "Subtotal {0}") and handle them in a separate follow-up.
📚 Learning: 2025-09-04T15:54:24.944Z
Learnt from: costa-monite
PR: team-monite/monite-sdk#785
File: packages/sdk-react/src/core/i18n/locales/en/messages.po:8470-8473
Timestamp: 2025-09-04T15:54:24.944Z
Learning: For PRs focused on the invoice preview template (feat/DEV-15554), costa-monite prefers to exclude out-of-scope tweaks like minor i18n spacing changes (e.g., "Subtotal{0}" → "Subtotal {0}") and handle them in a separate follow-up.
Applied to files:
packages/sdk-react/src/core/i18n/locales/en/messages.po
⏰ 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 (2)
packages/sdk-react/src/core/i18n/locales/en/messages.po (2)
221-228: Validation copy LGTMThe new validation and helper texts read well and match the new manual-totals workflow.
Also applies to: 2757-2765, 2855-2858, 3222-3225, 8748-8751, 8893-8896, 9455-9457, 8965-8971
9080-9083: Confirm alert trigger conditions for “amounts modified”Ensure this warning is shown only when totals or line items were changed while auto-calc is disabled, and it doesn’t appear on pristine loads.
If helpful, I can scan the PR for guard conditions and emit a small e2e/checklist.
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/sdk-react/src/components/receivables/components/EntityProfileModal.tsx (2)
50-64: Avoid possible runtime crash: guard optional address fields.
entity.addressmay be absent; direct property access can throw.- vat_country: vatId?.country || entity.address.country || undefined, - address_line_1: entity.address.line1 || undefined, - address_line_2: entity.address.line2 || undefined, - city: entity.address.city || undefined, - postal_code: entity.address.postal_code || undefined, - state: entity.address.state || undefined, - country: entity.address.country || undefined, + vat_country: vatId?.country || entity.address?.country || undefined, + address_line_1: entity.address?.line1 || undefined, + address_line_2: entity.address?.line2 || undefined, + city: entity.address?.city || undefined, + postal_code: entity.address?.postal_code || undefined, + state: entity.address?.state || undefined, + country: entity.address?.country || undefined,
118-136: Include country when patching address.If users edit the country, it’s currently ignored.
address: { line1: values.address_line_1 || null, line2: values.address_line_2 || null, city: values.city || null, postal_code: values.postal_code || null, state: values.state || null, + country: values.country || null, },
🧹 Nitpick comments (37)
packages/sdk-react/src/core/i18n/locales/en/messages.po (6)
4064-4066: Unify “incl./excl. tax” capitalizationElsewhere we use “Incl. tax”. Suggest “Excl. tax” (capitalize Excl., lowercase tax) for consistency.
Apply this diff:
-msgstr "excl. Tax" +msgstr "Excl. tax"
9592-9594: Column label reads awkwardly (“Total, tax”)Consider “Total incl. tax” to match the “Incl./Excl. tax” pattern used elsewhere.
-msgstr "Total, tax" +msgstr "Total incl. tax"
10194-10200: Inconsistent “VAT total/Total” casingTwo variants exist (“VAT total”, “VAT Total”). Pick one; recommend sentence case for field labels.
-#: src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableTotals.tsx:43 -msgid "VAT Total" -msgstr "VAT Total" +#: src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableTotals.tsx:43 +msgid "VAT Total" +msgstr "VAT total"
2415-2417: Avoid exposing “ID” in user-facing labels“Counterpart bank account ID” and “ID of counterpart's bank account” feel internal. Prefer “Counterpart bank account” in UI and error labels.
- msgid "Counterpart bank account ID" - msgstr "Counterpart bank account ID" + msgid "Counterpart bank account ID" + msgstr "Counterpart bank account"- msgid "ID of counterpart's bank account" - msgstr "ID of counterpart's bank account" + msgid "ID of counterpart's bank account" + msgstr "Counterpart bank account"Also applies to: 4924-4927
2773-2780: Duplicate currency labels; prefer one canonical copyWe have:
- “Currency for the invoice amount” (likely used as a label placeholder in required errors),
- “Invoice currency”,
- “Currency is required”.
To keep messages consistent, translate “Currency for the invoice amount” as “Invoice currency” so generic errors read well (“Invoice currency is required”).
- msgid "Currency for the invoice amount" - msgstr "Currency for the invoice amount" + msgid "Currency for the invoice amount" + msgstr "Invoice currency"Also applies to: 5140-5142, 2777-2780
4502-4508: Rename misspelled file: FullfillmentSummary.tsx → FulfillmentSummary.tsxpackages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/sections/components/Billing/FullfillmentSummary.tsx — rename to FulfillmentSummary.tsx and update all imports/usages to match the "Fulfillment" spelling used elsewhere.
packages/sdk-react/src/ui/components/calendar.tsx (2)
215-218: z-index token may not exist — use arbitrary value syntaxz-1300 requires a custom theme scale. To avoid depending on theme tokens and ensure correctness, use z-[1300].
- '... mtw:group-data-[focused=true]/day:z-1300 ...', + '... mtw:group-data-[focused=true]/day:z-[1300] ...',
37-41: Locale handling for month dropdowntoLocaleString('default') can vary between SSR and client locales. Consider sourcing the locale from DayPicker props (if provided) or your i18n context to avoid mismatches.
- formatMonthDropdown: (date) => - date.toLocaleString('default', { month: 'short' }), + formatMonthDropdown: (date) => { + const locale = props.locale ?? undefined; // or from your i18n context + return new Intl.DateTimeFormat(locale, { month: 'short' }).format(date); +},packages/sdk-react/src/components/receivables/components/InvoiceRecurrenceIterationStatusChip.stories.tsx (2)
44-47: Replace inline styles with Tailwind classes (mtw‑ prefix).Stories live in packages/sdk-react and should avoid inline styles per guidelines. Suggest:
- <div style={{ height: 500, padding: 20 }}> + <div className="mtw:h-[500px] mtw:p-5"> ... - <div style={{ height: 500, padding: 20 }}> + <div className="mtw:h-[500px] mtw:p-5"> - <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}> + <div className="mtw:flex mtw:flex-col mtw:gap-3"> ... - <div style={{ height: 500, padding: 20 }}> + <div className="mtw:h-[500px] mtw:p-5">Also applies to: 53-55, 73-76
50-61: De-duplicate AllStatuses rendering.Use a small array map for maintainability.
- <InvoiceRecurrenceIterationStatusChipComponent status="pending" /> - <InvoiceRecurrenceIterationStatusChipComponent status="skipped" /> - <InvoiceRecurrenceIterationStatusChipComponent status="canceled" /> - <InvoiceRecurrenceIterationStatusChipComponent status="issue_failed" /> - <InvoiceRecurrenceIterationStatusChipComponent status="send_failed" /> - <InvoiceRecurrenceIterationStatusChipComponent status="completed" /> + {['pending','skipped','canceled','issue_failed','send_failed','completed'].map((s) => ( + <InvoiceRecurrenceIterationStatusChipComponent key={s} status={s as any} /> + ))}packages/sdk-react/src/components/receivables/components/RecurrenceCancelModal.tsx (2)
25-29: Guard actions when recurrence_id is missing.
recurrence_idmay be empty; calling cancel with''will 400. Hide modal or no-op confirm when missing.- open={open && Boolean(invoice.id)} + open={open && Boolean(invoice.id) && Boolean(recurrence_id)} ... - onConfirm={() => - cancelRecurrence(undefined, { - onSuccess: onClose, - }) - } + onConfirm={() => { + if (!recurrence_id) return; + cancelRecurrence(undefined, { onSuccess: onClose }); + }}Also applies to: 58-66
32-38: Minor readability nit: extract chosen “source” for pending iterations.Helps comprehension and avoids nested ternary.
- const totalPendingInvoices = - (previousRecurrence?.status === 'active' && - recurrence?.status === 'canceled' - ? previousRecurrence - : recurrence - )?.iterations?.filter(({ status }) => status === 'pending')?.length ?? 0; + const source = previousRecurrence?.status === 'active' && recurrence?.status === 'canceled' + ? previousRecurrence + : recurrence; + const totalPendingInvoices = source?.iterations?.filter(({ status }) => status === 'pending')?.length ?? 0;packages/sdk-react/src/components/receivables/components/EntityProfileModal.tsx (2)
169-169: Tailwind class likely invalid: use arbitrary value for max-h.
mtw:max-h-4/5isn’t a standard Tailwind utility. Prefer:- <DialogContent className="mtw:max-h-4/5 mtw:overflow-y-auto"> + <DialogContent className="mtw:max-h-[80vh] mtw:overflow-y-auto">
187-193: Optional: prevent double submits while mutations are in flight.Wire
isPendingflags frompatchEntity,createEntityVatId, andpatchEntityVatto disable the Save button during requests.packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/validation.ts (3)
61-64: Zod v4: userequired_errorfor numbers;messageis ignored.Ensure proper required error for
tax_rate_value.- tax_rate_value: z - .number({ - message: t(i18n)`Tax is a required field`, - }) + tax_rate_value: z + .number({ + required_error: t(i18n)`Tax is a required field`, + invalid_type_error: t(i18n)`Tax must be a number`, + }) .min(0, t(i18n)`Tax rate must be 0 or greater`) .max(100, t(i18n)`Tax rate must be 100 or less`),
165-174: Zod v4: misuse ofz.date().min(1, ...)and error message.
min(1)compares against 1970-01-01; it doesn’t express “required”. Userequired_erroronz.date().- recurrence_start_date: isRecurrenceEnabled - ? z.date().min(1, t(i18n)`Recurrence start date is a required field`) + recurrence_start_date: isRecurrenceEnabled + ? z.date({ required_error: t(i18n)`Recurrence start date is a required field` }) : z.string().optional(), - recurrence_end_date: isRecurrenceEnabled - ? z.date().min(1, t(i18n)`Recurrence end date is a required field`) + recurrence_end_date: isRecurrenceEnabled + ? z.date({ required_error: t(i18n)`Recurrence end date is a required field` }) : z.string().optional(),
70-75: Also update VAT field errors to Zod v4 option keys.
errorisn’t a recognized key. Userequired_error/invalid_type_error.- vat_rate_value: z - .number({ error: t(i18n)`VAT is a required field` }) + vat_rate_value: z + .number({ required_error: t(i18n)`VAT is a required field`, invalid_type_error: t(i18n)`VAT must be a number` }) .min(0), - vat_rate_id: z - .string({ error: t(i18n)`VAT is a required field` }) + vat_rate_id: z + .string({ required_error: t(i18n)`VAT is a required field`, invalid_type_error: t(i18n)`VAT is a required field` }) .min(1, t(i18n)`VAT is a required field`),packages/sdk-react/src/components/receivables/Receivables.tsx (1)
17-19: Unify AccessRestriction import path across files.This file uses '@/ui/accessRestriction' while CreateReceivables.tsx uses '@/ui/accessRestriction/AccessRestriction'. Prefer one path (ideally the barrel if available) to avoid duplicate bundles and confusion.
- import { AccessRestriction } from '@/ui/accessRestriction'; + import { AccessRestriction } from '@/ui/accessRestriction/AccessRestriction';packages/sdk-react/src/components/receivables/components/RecurrenceSection.tsx (1)
24-31: Fix Switch aria-label to match control purpose.Currently says “Payment reminders”, but this toggle is for “Make recurring”.
- aria-label={t(i18n)`Payment reminders`} + aria-label={t(i18n)`Make recurring`}Add a TODO to migrate MUI Switch to shadcn/ui when this section gets a larger refactor, per repo guidelines.
packages/sdk-react/src/components/receivables/components/InvoiceDetailsTabOverview.tsx (2)
197-205: Simplify count check for Badge rendering.Double-checking length is redundant.
- {creditNoteQuery?.data?.length && - creditNoteQuery?.data?.length > 0 && ( + {creditNoteQuery?.data?.length ? ( <Badge variant="secondary" className="mtw:h-5 mtw:min-w-5 mtw:rounded-full mtw:px-1 mtw:tabular-nums"> {creditNoteQuery?.data?.length} </Badge> - )} + ) : null}
50-57: Guard empty dates to avoid formatting “Invalid Date”.issueDate may resolve to ''. Provide a fallback.
- {t(i18n)`${status === 'draft' ? 'Created' : 'Issued'}`} {i18n.date(issueDate, locale.dateFormat)} + {t(i18n)`${status === 'draft' ? 'Created' : 'Issued'}`} {issueDate ? i18n.date(issueDate, locale.dateFormat) : '-'}Also applies to: 211-218
packages/sdk-react/src/components/receivables/components/InvoiceDetailsTabScheduledInvoices.tsx (2)
112-118: Use a stable, non-i18n key.Keys should be deterministic and not localized. Prefer issued_invoice_id or iteration index as a last resort.
- key={t(i18n)`iteration-${iteration?.iteration}-${index}`} + key={iteration?.issued_invoice_id ?? `iter-${iteration?.iteration ?? index}`}
28-33: Avoid N+1 receivable fetches. Batch by id__in.Fetching each issued invoice per row will not scale. Prefetch all issued IDs once and pass the map to IterationInvoice.
// Parent component (before return): const issuedIds = (recurrence?.iterations ?? []) .map((it) => it.issued_invoice_id) .filter(Boolean) as string[]; const { data: issuedQuery } = useGetReceivables({ id__in: issuedIds }, issuedIds.length > 0); const issuedMap = new Map(issuedQuery?.data?.map((r) => [r.id, r]) ?? []); // Pass down: <IterationInvoice ... issuedInvoice={issuedMap.get(iteration.issued_invoice_id ?? '')} /> // Child: drop useGetReceivableById and use prop instead.Also applies to: 88-90
packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx (4)
1297-1300: Use functional state update for toggle to avoid stale closure.- toggleRecurrence={() => - setIsRecurrenceEnabled(!isRecurrenceEnabled) - } + toggleRecurrence={() => setIsRecurrenceEnabled((v) => !v)}
157-159: Guard settings query on entityId availability.If entityId can be undefined initially, add enabled to avoid a bad request.
- const { data: settings, isLoading: isSettingsLoading } = - api.entities.getEntitiesIdSettings.useQuery({ - path: { entity_id: entityId }, - }); + const { data: settings, isLoading: isSettingsLoading } = + api.entities.getEntitiesIdSettings.useQuery( + { path: { entity_id: entityId } }, + { enabled: Boolean(entityId) } + );
1321-1323: Prefer collision-resistant temp IDs.Math.random-based IDs collide in large lists. Use crypto.randomUUID() when available.
- id: item.id || `temp-${Math.random().toString(36).substr(2, 9)}`, + id: item.id || (typeof crypto !== 'undefined' && 'randomUUID' in crypto + ? crypto.randomUUID() + : `temp-${Date.now()}-${Math.round(Math.random()*1e6)}`),
48-49: Align AccessRestriction import path with the rest of the app.Receivables.tsx imports from '@/ui/accessRestriction'; prefer a single source to avoid duplication.
- import { AccessRestriction } from '@/ui/accessRestriction/AccessRestriction'; + import { AccessRestriction } from '@/ui/accessRestriction';packages/sdk-react/src/components/receivables/components/InvoiceDetails.tsx (2)
208-213: Remove defaultValue on controlled Tabs to avoid controlled/uncontrolled ambiguityTabs is controlled via
value={selectedTab}. DropdefaultValueto prevent confusion.- <Tabs - defaultValue={Tab.Overview} - className="mtw:gap-8" - value={selectedTab} + <Tabs + className="mtw:gap-8" + value={selectedTab} onValueChange={handleTabChange} >
294-295: Align API typings with repo guidelineCasting to
components['schemas']['InvoiceResponsePayload']works, but guidelines prefer custom API types (e.g.,Invoice) from@/types/apifor better IntelliSense and decoupling from OpenAPI internals.Would you like me to generate a small refactor patch switching these props to the canonical
@/types/apitype?packages/sdk-react/src/components/receivables/components/InvoiceDetailsActions.tsx (4)
98-104: Prevent reverse‑tabnabbing when opening PDFAdd
noopener,noreferrertowindow.open.- if (pdfLink.data?.file_url) { - window.open(pdfLink.data.file_url, '_blank'); - } + if (pdfLink.data?.file_url) { + window.open(pdfLink.data.file_url, '_blank', 'noopener,noreferrer'); + }
286-299: Dropdown labels mismatch for non‑draft invoicesWhen
hideSendAndPdfButtonsis true on non‑draft invoices, labels show “Send draft” / “Download draft”. Use dynamic labels and disable while downloading.- {(isDraft || hideSendAndPdfButtons) && ( + {(isDraft || hideSendAndPdfButtons) && ( <> - <DropdownMenuItem - onClick={() => - handleButtonClick(actions.onIssueAndSendButtonClick) - } - > - {t(i18n)`Send draft`} - </DropdownMenuItem> - <DropdownMenuItem onClick={handleDownloadPdf}> - {t(i18n)`Download draft`} - </DropdownMenuItem> + <DropdownMenuItem + onClick={() => + handleButtonClick(actions.onIssueAndSendButtonClick) + } + > + {isDraft ? t(i18n)`Send draft` : t(i18n)`Send`} + </DropdownMenuItem> + <DropdownMenuItem onClick={handleDownloadPdf} disabled={isDownloadingPdf}> + {isDraft ? t(i18n)`Download draft` : t(i18n)`Download PDF`} + </DropdownMenuItem> </> )}
301-304: Gate “Edit template settings” behind permissions for consistencyAll other mutating actions are permission‑gated; this one should be too.
- <DropdownMenuItem onClick={actions.onTemplateSettingsButtonClick}> + <DropdownMenuItem + onClick={() => handleButtonClick(actions.onTemplateSettingsButtonClick)} + disabled={isUpdateAllowedLoading} + > {t(i18n)`Edit template settings`} </DropdownMenuItem>
240-248: Disable Duplicate button while permissions are loadingMinor UX polish: mirror other buttons’ disabled state while
isUpdateAllowedLoading.- {isRecurring && ( + {isRecurring && ( <Button type="button" variant="outline" size="sm" + disabled={isUpdateAllowedLoading} onClick={() => handleButtonClick(handleDuplicateInvoice)} > <Copy /> {t(i18n)`Duplicate`} </Button> )}packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/helpers.ts (4)
49-81: Extracted defaults helper: avoid hard-coded currency/tax.Nice extraction; this addresses the prior feedback about encapsulating defaults. To reduce coupling to EU-specific defaults, accept overridable defaults (currency, tax) instead of hard-coding 'EUR' and 19%.
Apply:
-const getDefaultValuesForCreating = ( - isCalculateTotalsEnabled?: boolean -): PayableDetailsFormFields => { +const getDefaultValuesForCreating = ( + isCalculateTotalsEnabled?: boolean, + defaultCurrency: CurrencyEnum = 'EUR' as CurrencyEnum, + defaultTaxRate = 0 +): PayableDetailsFormFields => { const defaultValuesCreating = { invoiceNumber: '', counterpart: '', counterpartBankAccount: '', invoiceDate: undefined, dueDate: undefined, - currency: 'EUR' as CurrencyEnum, + currency: defaultCurrency, tags: [], discount: null, lineItems: [ { id: '', name: '', quantity: 1, price: 0, - tax: 19, + tax: defaultTaxRate, }, ], };Call sites keep working due to defaults; pass entity defaults later if available. Also confirm whether 19% was intentional for payables; many entities default to 0% on input.
110-133: Discount 0 becomes null in editing defaults.Using truthiness drops legitimate 0 discounts. Switch to nullish check.
Apply:
- discount: - discount && currency ? formatFromMinorUnits(discount, currency) : null, + discount: + discount != null && currency + ? formatFromMinorUnits(discount, currency) + : null,
150-191: Manual totals + discount: avoid double application.When manual totals are submitted (!isCalculateTotalsEnabled), also sending discount may cause the backend to apply discount in addition to your provided totals. Gate discount behind the flag; keep totals as the source of truth. Also narrow the currency type in the formatter signature.
Apply:
- formatToMinorUnits: (amount: number, currency: string) => number | null, + formatToMinorUnits: (amount: number, currency: CurrencyEnum | string) => number | null, isCalculateTotalsEnabled?: boolean ): components['schemas']['PayableUpdateSchema'] => { const submitPayload = { document_id: invoiceNumber, counterpart_id: counterpart || undefined, counterpart_bank_account_id: counterpartBankAccount || undefined, issued_at: invoiceDate instanceof Date ? dateToString(invoiceDate) : undefined, due_date: dueDate instanceof Date ? dateToString(dueDate) : undefined, currency: currency as CurrencyEnum, tag_ids: tags.map((tag) => tag.id), counterpart_address_id: counterpartAddressId, - discount: formatToMinorUnits(discount ?? 0, currency) ?? 0, + discount: isCalculateTotalsEnabled + ? formatToMinorUnits(discount ?? 0, currency) ?? 0 + : undefined, };Please confirm API behavior: if subtotal/tax/total are provided, should discount be omitted? If discount is informational, we can still send it but the backend must ignore it when totals are present.
327-333: Public prop naming consistency.Props elsewhere often use is* for booleans (e.g., isTagsDisabled). Consider isAutoCalculateTotalsDisabled for symmetry, or at least add a JSDoc explaining polarity to avoid misuse.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (34)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx(13 hunks)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/helpers.ts(6 hunks)packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx(17 hunks)packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/validation.ts(5 hunks)packages/sdk-react/src/components/receivables/InvoiceDetails/ExistingInvoiceDetails/components/EditInvoiceDetails.tsx(3 hunks)packages/sdk-react/src/components/receivables/InvoiceDetails/InvoiceDetails.tsx(2 hunks)packages/sdk-react/src/components/receivables/Receivables.tsx(1 hunks)packages/sdk-react/src/components/receivables/components/CustomerSection.tsx(2 hunks)packages/sdk-react/src/components/receivables/components/EntityProfileModal.tsx(3 hunks)packages/sdk-react/src/components/receivables/components/InvoiceDetails.tsx(11 hunks)packages/sdk-react/src/components/receivables/components/InvoiceDetailsActions.tsx(9 hunks)packages/sdk-react/src/components/receivables/components/InvoiceDetailsInfoBlock.tsx(1 hunks)packages/sdk-react/src/components/receivables/components/InvoiceDetailsOverviewRecurrenceSection.tsx(2 hunks)packages/sdk-react/src/components/receivables/components/InvoiceDetailsTabDetails.tsx(2 hunks)packages/sdk-react/src/components/receivables/components/InvoiceDetailsTabOverview.tsx(3 hunks)packages/sdk-react/src/components/receivables/components/InvoiceDetailsTabScheduledInvoices.tsx(1 hunks)packages/sdk-react/src/components/receivables/components/InvoiceRecurrenceIterationStatusChip.stories.tsx(1 hunks)packages/sdk-react/src/components/receivables/components/InvoiceRecurrenceIterationStatusChip.tsx(1 hunks)packages/sdk-react/src/components/receivables/components/InvoiceRecurrenceStatusChip.stories.tsx(1 hunks)packages/sdk-react/src/components/receivables/components/InvoiceRecurrenceStatusChip.tsx(1 hunks)packages/sdk-react/src/components/receivables/components/RecurrenceCancelModal.tsx(4 hunks)packages/sdk-react/src/components/receivables/components/RecurrenceFormContent.tsx(1 hunks)packages/sdk-react/src/components/receivables/components/RecurrenceSection.tsx(2 hunks)packages/sdk-react/src/components/receivables/components/index.ts(1 hunks)packages/sdk-react/src/components/receivables/hooks/useCancelRecurrence.ts(1 hunks)packages/sdk-react/src/components/receivables/hooks/useCreateReceivable.ts(1 hunks)packages/sdk-react/src/components/receivables/hooks/useCreateRecurrence.ts(1 hunks)packages/sdk-react/src/components/receivables/hooks/useGetInvoiceRequiredFields.ts(1 hunks)packages/sdk-react/src/components/receivables/hooks/useUpdateRecurrenceById.ts(1 hunks)packages/sdk-react/src/components/receivables/utils/index.ts(1 hunks)packages/sdk-react/src/components/receivables/utils/invoiceStatus.ts(1 hunks)packages/sdk-react/src/core/i18n/locales/en/messages.po(143 hunks)packages/sdk-react/src/ui/DatePicker.tsx(2 hunks)packages/sdk-react/src/ui/components/calendar.tsx(5 hunks)
✅ Files skipped from review due to trivial changes (14)
- packages/sdk-react/src/components/receivables/components/CustomerSection.tsx
- packages/sdk-react/src/components/receivables/InvoiceDetails/InvoiceDetails.tsx
- packages/sdk-react/src/components/receivables/hooks/useCreateReceivable.ts
- packages/sdk-react/src/components/receivables/hooks/useGetInvoiceRequiredFields.ts
- packages/sdk-react/src/components/receivables/hooks/useCancelRecurrence.ts
- packages/sdk-react/src/components/receivables/utils/index.ts
- packages/sdk-react/src/components/receivables/components/InvoiceRecurrenceStatusChip.stories.tsx
- packages/sdk-react/src/components/receivables/components/index.ts
- packages/sdk-react/src/components/receivables/hooks/useCreateRecurrence.ts
- packages/sdk-react/src/components/receivables/utils/invoiceStatus.ts
- packages/sdk-react/src/components/receivables/components/InvoiceDetailsTabDetails.tsx
- packages/sdk-react/src/components/receivables/components/InvoiceRecurrenceIterationStatusChip.tsx
- packages/sdk-react/src/ui/DatePicker.tsx
- packages/sdk-react/src/components/receivables/components/InvoiceDetailsInfoBlock.tsx
🚧 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/receivables/components/InvoiceRecurrenceIterationStatusChip.stories.tsxpackages/sdk-react/src/components/receivables/components/RecurrenceSection.tsxpackages/sdk-react/src/components/receivables/components/InvoiceRecurrenceStatusChip.tsxpackages/sdk-react/src/components/receivables/Receivables.tsxpackages/sdk-react/src/components/receivables/components/InvoiceDetails.tsxpackages/sdk-react/src/components/receivables/InvoiceDetails/ExistingInvoiceDetails/components/EditInvoiceDetails.tsxpackages/sdk-react/src/components/receivables/hooks/useUpdateRecurrenceById.tspackages/sdk-react/src/components/receivables/components/EntityProfileModal.tsxpackages/sdk-react/src/components/receivables/components/RecurrenceCancelModal.tsxpackages/sdk-react/src/components/receivables/components/InvoiceDetailsTabScheduledInvoices.tsxpackages/sdk-react/src/components/receivables/components/InvoiceDetailsTabOverview.tsxpackages/sdk-react/src/components/receivables/components/RecurrenceFormContent.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/helpers.tspackages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsxpackages/sdk-react/src/components/receivables/components/InvoiceDetailsOverviewRecurrenceSection.tsxpackages/sdk-react/src/ui/components/calendar.tsxpackages/sdk-react/src/components/receivables/components/InvoiceDetailsActions.tsxpackages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/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/receivables/components/InvoiceRecurrenceIterationStatusChip.stories.tsxpackages/sdk-react/src/components/receivables/components/RecurrenceSection.tsxpackages/sdk-react/src/components/receivables/components/InvoiceRecurrenceStatusChip.tsxpackages/sdk-react/src/components/receivables/Receivables.tsxpackages/sdk-react/src/components/receivables/components/InvoiceDetails.tsxpackages/sdk-react/src/components/receivables/InvoiceDetails/ExistingInvoiceDetails/components/EditInvoiceDetails.tsxpackages/sdk-react/src/components/receivables/components/EntityProfileModal.tsxpackages/sdk-react/src/components/receivables/components/RecurrenceCancelModal.tsxpackages/sdk-react/src/components/receivables/components/InvoiceDetailsTabScheduledInvoices.tsxpackages/sdk-react/src/components/receivables/components/InvoiceDetailsTabOverview.tsxpackages/sdk-react/src/components/receivables/components/RecurrenceFormContent.tsxpackages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsxpackages/sdk-react/src/components/receivables/components/InvoiceDetailsOverviewRecurrenceSection.tsxpackages/sdk-react/src/ui/components/calendar.tsxpackages/sdk-react/src/components/receivables/components/InvoiceDetailsActions.tsx
🧠 Learnings (18)
📓 Common learnings
Learnt from: costa-monite
PR: team-monite/monite-sdk#785
File: packages/sdk-react/src/core/i18n/locales/en/messages.po:8470-8473
Timestamp: 2025-09-04T15:54:24.944Z
Learning: For PRs focused on the invoice preview template (feat/DEV-15554), costa-monite prefers to exclude out-of-scope tweaks like minor i18n spacing changes (e.g., "Subtotal{0}" → "Subtotal {0}") and handle them in a separate follow-up.
📚 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/components/receivables/Receivables.tsxpackages/sdk-react/src/ui/components/calendar.tsx
📚 Learning: 2025-07-21T08:11:13.444Z
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:
packages/sdk-react/src/components/receivables/Receivables.tsx
📚 Learning: 2025-09-05T11:02:00.731Z
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.731Z
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/components/receivables/components/InvoiceDetails.tsxpackages/sdk-react/src/components/receivables/components/InvoiceDetailsTabOverview.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 : Import components from '@/ui/components/*' when using shadcn/ui components
Applied to files:
packages/sdk-react/src/components/receivables/components/InvoiceDetails.tsx
📚 Learning: 2025-09-08T09:09:14.289Z
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.289Z
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/receivables/InvoiceDetails/ExistingInvoiceDetails/components/EditInvoiceDetails.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/helpers.tspackages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx
📚 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 : Always destructure `api` and `entityId` from useMoniteContext.
Applied to files:
packages/sdk-react/src/components/receivables/InvoiceDetails/ExistingInvoiceDetails/components/EditInvoiceDetails.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/receivables/components/EntityProfileModal.tsxpackages/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/receivables/components/EntityProfileModal.tsxpackages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx
📚 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/receivables/components/EntityProfileModal.tsxpackages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/helpers.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/components/receivables/components/RecurrenceFormContent.tsxpackages/sdk-react/src/ui/components/calendar.tsx
📚 Learning: 2025-09-04T15:54:24.944Z
Learnt from: costa-monite
PR: team-monite/monite-sdk#785
File: packages/sdk-react/src/core/i18n/locales/en/messages.po:8470-8473
Timestamp: 2025-09-04T15:54:24.944Z
Learning: For PRs focused on the invoice preview template (feat/DEV-15554), costa-monite prefers to exclude out-of-scope tweaks like minor i18n spacing changes (e.g., "Subtotal{0}" → "Subtotal {0}") and handle them in a separate follow-up.
Applied to files:
packages/sdk-react/src/core/i18n/locales/en/messages.po
📚 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 : Always prefer shadcn/ui components such as Button, Input, Card, Dialog, Select, Checkbox, RadioGroup, Switch, Textarea, Label, Alert, Badge, Toast, Tabs, Table, Form, DropdownMenu, Sheet, Skeleton, Separator
Applied to files:
packages/sdk-react/src/core/i18n/locales/en/messages.popackages/sdk-react/src/ui/components/calendar.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 the variant prop for different styles (e.g., variant="outline" for buttons)
Applied to files:
packages/sdk-react/src/ui/components/calendar.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 the variant prop for different styles (e.g., variant="outline" for buttons)
Applied to files:
packages/sdk-react/src/ui/components/calendar.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 : Always prefer shadcn/ui components such as Button, Input, Card, Dialog, etc., from '@/ui/components/[component]'
Applied to files:
packages/sdk-react/src/ui/components/calendar.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 lucide-react for icons and import icons like: import { Search, Menu, X } from 'lucide-react'
Applied to files:
packages/sdk-react/src/components/receivables/components/InvoiceDetailsActions.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 'lucide-react' for icons and import icons like 'import { Search, Menu, X } from "lucide-react"'
Applied to files:
packages/sdk-react/src/components/receivables/components/InvoiceDetailsActions.tsx
🧬 Code graph analysis (12)
packages/sdk-react/src/components/receivables/components/RecurrenceSection.tsx (1)
packages/sdk-react/src/components/receivables/components/RecurrenceFormContent.tsx (1)
RecurrenceFormContent(21-142)
packages/sdk-react/src/components/receivables/components/InvoiceDetails.tsx (4)
packages/sdk-react/src/components/receivables/hooks/useGetRecurrenceById.ts (1)
useGetRecurrenceById(3-10)packages/sdk-react/src/core/queries/usePermissions.ts (1)
useIsActionAllowed(106-126)packages/sdk-react/src/components/receivables/components/InvoiceDetailsTabOverview.tsx (1)
InvoiceDetailsTabOverview(74-243)packages/sdk-react/src/components/receivables/components/InvoiceDetailsTabScheduledInvoices.tsx (1)
InvoiceDetailsTabScheduledInvoices(84-124)
packages/sdk-react/src/components/receivables/InvoiceDetails/ExistingInvoiceDetails/components/EditInvoiceDetails.tsx (2)
packages/sdk-react/src/core/queries/useMe.ts (1)
useMyEntity(31-68)packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/validation.ts (2)
UpdateReceivablesFormProps(159-161)getUpdateInvoiceValidationSchema(148-157)
packages/sdk-react/src/components/receivables/hooks/useUpdateRecurrenceById.ts (1)
packages/sdk-react/src/core/utils/getAPIErrorMessage.ts (1)
getAPIErrorMessage(5-22)
packages/sdk-react/src/components/receivables/components/RecurrenceCancelModal.tsx (2)
packages/sdk-react/src/components/receivables/hooks/useCancelRecurrence.ts (1)
useCancelRecurrence(7-36)packages/sdk-react/src/components/receivables/hooks/useGetRecurrenceById.ts (1)
useGetRecurrenceById(3-10)
packages/sdk-react/src/components/receivables/components/InvoiceDetailsTabScheduledInvoices.tsx (4)
packages/sdk-react/src/core/hooks/useCurrencies.ts (1)
useCurrencies(15-170)packages/sdk-react/src/core/queries/useGetReceivableById.ts (1)
useGetReceivableById(8-24)packages/sdk-react/src/components/receivables/consts.ts (1)
INVOICE_DOCUMENT_AUTO_ID(60-60)packages/sdk-react/src/components/receivables/components/InvoiceRecurrenceIterationStatusChip.tsx (1)
InvoiceRecurrenceIterationStatusChip(28-46)
packages/sdk-react/src/components/receivables/components/InvoiceDetailsTabOverview.tsx (2)
packages/sdk-react/src/components/receivables/components/InvoiceDetailsOverviewRecurrenceSection.tsx (1)
InvoiceDetailsOverviewRecurrenceSection(35-218)packages/sdk-react/src/components/receivables/components/index.ts (1)
InvoiceDetailsOverviewRecurrenceSection(52-52)
packages/sdk-react/src/components/receivables/components/RecurrenceFormContent.tsx (2)
packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/validation.ts (1)
CreateRecurrenceFormProps(204-206)packages/sdk-react/src/ui/DatePicker.tsx (1)
DatePicker(19-54)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/helpers.ts (1)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/types.ts (1)
PayableDetailsFormFields(10-23)
packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx (4)
packages/sdk-react/src/core/queries/useCounterpart.ts (1)
useCounterpartContactList(342-422)packages/sdk-react/src/components/receivables/hooks/useCreateReceivable.ts (1)
useCreateReceivable(7-29)packages/sdk-react/src/components/receivables/hooks/useCreateRecurrence.ts (1)
useCreateRecurrence(7-20)packages/sdk-react/src/components/receivables/hooks/useGetInvoiceRequiredFields.ts (1)
useGetInvoiceRequiredFields(13-41)
packages/sdk-react/src/components/receivables/components/InvoiceDetailsOverviewRecurrenceSection.tsx (5)
packages/sdk-react/src/components/receivables/hooks/useUpdateRecurrenceById.ts (1)
useUpdateRecurrenceById(7-48)packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/validation.ts (2)
CreateRecurrenceFormProps(204-206)getCreateRecurrenceValidationSchema(177-202)packages/sdk-react/src/components/receivables/components/RecurrenceFormContent.tsx (1)
RecurrenceFormContent(21-142)packages/sdk-react/src/components/receivables/components/InvoiceRecurrenceStatusChip.tsx (1)
InvoiceRecurrenceStatusChip(26-44)packages/sdk-react/src/components/receivables/components/InvoiceDetailsInfoBlock.tsx (1)
InvoiceDetailsInfoBlock(14-47)
packages/sdk-react/src/components/receivables/components/InvoiceDetailsActions.tsx (3)
packages/sdk-react/src/core/queries/usePermissions.ts (1)
useIsActionAllowed(106-126)packages/sdk-react/src/components/receivables/hooks/useIssueReceivableById.ts (1)
useIssueReceivableById(12-52)packages/sdk-react/src/components/receivables/components/RecordManualPaymentModal.tsx (1)
RecordManualPaymentModal(41-175)
⏰ 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-drop-in
- GitHub Check: Build and Push sdk-demo-with-nextjs-and-clerk-auth
- GitHub Check: Build
🔇 Additional comments (22)
packages/sdk-react/src/core/i18n/locales/en/messages.po (2)
9188-9191: Alert copy for manual totals — LGTMClear and action‑oriented. No changes needed.
8856-8859: Validation messages for negative amounts — LGTMThese cover the new manual-entry fields appropriately.
Also applies to: 9001-9004, 9563-9566
packages/sdk-react/src/ui/components/calendar.tsx (3)
11-13: Public API + sensible defaults LGTMType for buttonVariant is correctly inferred from Button, and defaults for captionLayout and buttonVariant are reasonable.
Also applies to: 19-21
43-66: Component overrides and classNames merging LGTMGood use of getDefaultClassNames() and non-destructive overrides; Chevron/WeekNumber/DayButton customizations are clean and consistent with shadcn/ui.
Also applies to: 132-168, 170-178, 186-194, 199-221
31-35: Confirm Tailwind config, prefix ("mtw"), and variant plugins (RTL & data-variants) are present
- packages/sdk-react/src/ui/components/calendar.tsx uses Tailwind v4-style arbitrary values and advanced variants (size-(--cell-size), h-(--cell-size), rtl:**, group-data, data-[...]).
- Tailwind v4 is present in packages/sdk-playground/package.json (~4.1.11) and packages/rollup-config/package.json (~4.0.17), but repository search did not find a tailwind.config.* file or a configured prefix: 'mtw' — add/verify a workspace tailwind.config.(js|cjs|ts) that sets prefix: 'mtw'.
- Ensure RTL and data-* variant plugins (or equivalent Tailwind v4 configuration) are enabled so rtl:** and group-data[...] selectors compile.
Files to check: packages/sdk-react/src/ui/components/calendar.tsx, packages/sdk-playground/package.json, packages/rollup-config/package.json
packages/sdk-react/src/components/receivables/InvoiceDetails/ExistingInvoiceDetails/components/EditInvoiceDetails.tsx (6)
10-14: Reminders components barrel import — LGTM.Import consolidation is tidy and matches usages below.
17-19: New hooks imports are correctly wired.All three hooks are used and contribute to loading state and submit flow.
86-86: DestructuringisLoadingasisEntityLoading— good call.It’s correctly included in the combined
isLoading.
157-158: Dependency array includesisNonVatSupported— correct.Keeps defaults in sync when entity VAT support changes.
23-23: Guard against missing vat_rate and confirm conversion semantics.File: packages/sdk-react/src/components/receivables/InvoiceDetails/ExistingInvoiceDetails/components/EditInvoiceDetails.tsx — lines 23 (also applies to lines 138–143).
Accessing lineItem.product.vat_rate.value can throw if vat_rate is absent; use optional chaining + null check and verify whether rateMinorToMajor returns a percentage (e.g. 19) or a fraction (e.g. 0.19) to avoid UI/server unit mismatches.
- tax_rate_value: isNonVatSupported - ? lineItem.product.vat_rate.value !== undefined - ? rateMinorToMajor(lineItem.product.vat_rate.value) - : undefined - : undefined, + // Guard against missing vat_rate and avoid hard failure in non-VAT flows + tax_rate_value: + isNonVatSupported && lineItem.product.vat_rate?.value != null + ? rateMinorToMajor(lineItem.product.vat_rate.value) + : undefined,
162-163: Validation schema conditional on isNonVatSupported is correct — no change required.getBaseInvoiceSchema selects nonVatLineItemSchema when isNonVatSupported (tax_rate_value required) and vatLineItemSchema otherwise (vat_rate_id/vat_rate_value required); getUpdateInvoiceValidationSchema simply extends that base.
packages/sdk-react/src/components/receivables/components/InvoiceRecurrenceIterationStatusChip.stories.tsx (1)
1-1: Import reordering looks good.No behavioral change; fine to keep.
packages/sdk-react/src/components/receivables/hooks/useUpdateRecurrenceById.ts (1)
34-45: LGTM overall.Invalidations and toasts are consistent with the rest of the hooks.
packages/sdk-react/src/components/receivables/Receivables.tsx (1)
5-5: LGTM on import reorder and hooks placement.No behavioral changes introduced.
Also applies to: 22-22
packages/sdk-react/src/components/receivables/components/RecurrenceSection.tsx (1)
11-14: Signature/style changes only.No runtime impact.
packages/sdk-react/src/components/receivables/components/InvoiceDetailsTabOverview.tsx (1)
1-9: Recurrence and linked-docs wiring looks good.Imports and the new Recurrence section integration are correct; props passed align with the section’s API.
Also applies to: 172-179
packages/sdk-react/src/components/receivables/components/RecurrenceFormContent.tsx (1)
31-48: General refactor/readability improvements look fine.Date disabling logic and DatePicker wiring remain behaviorally consistent.
Also applies to: 50-141
packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx (1)
446-452: Reminder validation gates are solid.Good user guidance and early returns to prevent invalid submissions.
Also applies to: 532-569
packages/sdk-react/src/components/receivables/components/InvoiceRecurrenceStatusChip.tsx (1)
15-24: Don't add a "cancelled" alias — API enum uses "canceled"; add a safe default variant.Schema (packages/sdk-react/src/api/schema.json) defines RecurrenceStatus = ["active","paused","canceled","completed"], so adding "cancelled" is unnecessary. Instead add a safe default to the cva call in packages/sdk-react/src/components/receivables/components/InvoiceRecurrenceStatusChip.tsx — e.g. include defaultVariants: { variant: 'active' } to avoid silent style omission for unexpected values.
Likely an incorrect or invalid review comment.
packages/sdk-react/src/components/receivables/components/InvoiceDetails.tsx (1)
320-321: Confirm custom z-index utility or switch to Tailwind arbitrary value
mtw:xl:z-1299relies on a custom scale. If not configured, usemtw:xl:z-[1299].- className="mtw:w-full mtw:flex-row mtw:xl:max-w-[1200px] mtw:xl:z-1299" + className="mtw:w-full mtw:flex-row mtw:xl:max-w-[1200px] mtw:xl:z-[1299]"packages/sdk-react/src/components/receivables/components/InvoiceDetailsActions.tsx (1)
66-71: Verify permission used for gating fits each actionYou’re gating many actions with
receivable:update. Some actions may require different scopes (e.g., duplicate = create, send/email = send permission). Risk: unnecessary denials.Would you like me to map actions → permissions and wire separate checks (e.g.,
create,send,delete)?packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/helpers.ts (1)
1-1: Type-only imports and form types: good.Using lib-agnostic form types (PayableDetailsFormFields) aligns with our forms guidance.
… include auto-calculation toggle
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (11)
packages/sdk-react/src/core/i18n/locales/en/messages.po (7)
505-508: Standardize action casing: “Add Discount” → “Add discount”.UI copy elsewhere uses sentence case for actions (“Add discount”, “Add item”, “Add new bank account”). Suggest aligning.
Apply if you also update call sites using this msgid:
-msgid "Add Discount" -msgstr "Add Discount" +msgid "Add discount" +msgstr "Add discount"
1269-1277: Unify capitalization: “Bank account” vs “Bank Account”.Two variants appear back‑to‑back; pick one (suggest sentence case).
If you choose sentence case:
- msgid "Bank Account" - msgstr "Bank Account" + msgid "Bank account" + msgstr "Bank account"Note: update components that reference the old msgid.
4064-4067: Fix style: “excl. Tax” → “Excl. tax” (or reuse “Excluding tax”).
- Current casing is inconsistent with “Incl. tax”.
- If you want to avoid abbreviations, prefer existing “Excluding tax”.
Option A (match “Incl. tax”):
-msgid "excl. Tax" -msgstr "excl. Tax" +msgid "Excl. tax" +msgstr "Excl. tax"Option B (spell out; re‑use existing key if possible):
-msgid "excl. Tax" -msgstr "excl. Tax" +msgid "Excluding tax" +msgstr "Excluding tax"
9591-9594: Wording nit: “Total, tax” reads awkwardly.Consider “Total incl. tax” to mirror “Incl. tax”.
-msgid "Total, tax" -msgstr "Total, tax" +msgid "Total incl. tax" +msgstr "Total incl. tax"
10194-10200: Duplicate/inconsistent: “VAT total” vs “VAT Total”.Please pick a single casing (suggest sentence case: “VAT total”) and de‑duplicate. If both are needed, add context or explicit ids to avoid drift.
- msgid "VAT Total" - msgstr "VAT Total" + msgid "VAT total" + msgstr "VAT total"Ensure all call sites are updated or switch these to explicit ids to prevent regressions.
2870-2873: Terminology check: “invoice” vs “bill” in Payables.These strings (“Date when the invoice was issued”, “Invoice currency”, “Invoice issue date”) surface in Payables. If your UX guidelines prefer “bill” in Payables, consider aligning; if “invoice” is intentional (vendor’s invoice), ignore.
Also applies to: 5139-5142, 5177-5179
394-397: Scope reminder: avoid drive‑by i18n tweaks.Given the PR focuses on manual totals, keep unrelated copy changes out (per costa‑monite’s preference). If any of these weren’t required for the feature, move to a follow‑up.
Also applies to: 432-435, 446-448, 509-513, 514-519, 579-582, 583-587, 655-662, 697-704, 777-783, 846-854
packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx (4)
108-118: Access gating LGTM; minor copy fix ("cannot").Message reads better as “You cannot…”.
- )`You can not create receivable with a type other than “${'invoice'}”`} + )`You cannot create receivable with a type other than “${'invoice'}”`}Also applies to: 112-115
260-262: Reminder gating logic: good; localize toast error strings.All user-facing errors should be wrapped with
t(i18n). Keep the logic; only localize strings.- showErrorToast(new Error("Set your entity's Tax ID to issue invoice")); + showErrorToast(new Error(t(i18n)`Set your entity's Tax ID to issue invoice`)); - showErrorToast(new Error("Set your entity's VAT ID to issue invoice")); + showErrorToast(new Error(t(i18n)`Set your entity's VAT ID to issue invoice`)); - showErrorToast( - new Error("Set your entity's VAT ID and Tax ID to issue invoice") - ); + showErrorToast( + new Error(t(i18n)`Set your entity's VAT ID and Tax ID to issue invoice`) + ); - showErrorToast( - new Error('Set a Tax ID for this customer to issue invoice') - ); + showErrorToast( + new Error(t(i18n)`Set a Tax ID for this customer to issue invoice`) + ); - showErrorToast( - new Error('Set a VAT ID for this customer to issue invoice') - ); + showErrorToast( + new Error(t(i18n)`Set a VAT ID for this customer to issue invoice`) + ); - showErrorToast( - new Error('Set a VAT ID and Tax ID for this customer to issue invoice') - ); + showErrorToast( + new Error(t(i18n)`Set a VAT ID and Tax ID for this customer to issue invoice`) + ); - showErrorToast( - new Error( - 'Payment reminders are disabled for this customer. Please enable them in the customer details or turn them off.' - ) - ); + showErrorToast( + new Error( + t(i18n)`Payment reminders are disabled for this customer. Please enable them in the customer details or turn them off.` + ) + ); - showErrorToast( - new Error( - 'No email address is added for the selected customer. Please add it to the customer details or turn off the reminders.' - ) - ); + showErrorToast( + new Error( + t(i18n)`No email address is added for the selected customer. Please add it to the customer details or turn off the reminders.` + ) + ); - 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.' - ) - ); + showErrorToast( + new Error( + t(i18n)`Reminders are disabled for this customer, and no email address has been added for it. Please update the details or turn off reminders.` + ) + );Also applies to: 446-452, 458-486, 488-520, 532-569
1320-1323: Avoidsubstr; preferslice(and consider stronger IDs).
substris non-standard. Also,Math.random()IDs can collide. At minimum, switch toslice. Optionally usecrypto.randomUUID()when available.- id: item.id || `temp-${Math.random().toString(36).substr(2, 9)}`, + id: item.id || `temp-${Math.random().toString(36).slice(2, 11)}`,Optional:
- id: item.id || `temp-${Math.random().toString(36).slice(2, 11)}`, + id: item.id || `temp-${(typeof crypto !== 'undefined' && 'randomUUID' in crypto) + ? (crypto as any).randomUUID() + : Math.random().toString(36).slice(2)}`,
849-851: Currency modal: saving without selection sets currency toundefined.If the user opens the modal and hits Save without choosing a currency,
tempCurrencystaysundefined, and you setactualCurrencytoundefined.- <DropdownMenuItem - onClick={() => setIsCurrencyModalOpen(true)} - > + <DropdownMenuItem + onClick={() => { + setTempCurrency(actualCurrency); + setIsCurrencyModalOpen(true); + }} + >- const handleCurrencySubmit = () => { - if (tempCurrency !== actualCurrency) { + const handleCurrencySubmit = () => { + if (tempCurrency && tempCurrency !== actualCurrency) { const validLineItems = lineItems.filter((item) => { return item.product?.name?.trim() !== ''; }); // ... - setActualCurrency(tempCurrency); + setActualCurrency(tempCurrency);Also applies to: 721-723
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx(17 hunks)packages/sdk-react/src/components/receivables/components/InvoiceDetailsTabOverview.tsx(3 hunks)packages/sdk-react/src/core/i18n/locales/en/messages.po(143 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/sdk-react/src/components/receivables/components/InvoiceDetailsTabOverview.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/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/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx
🧠 Learnings (6)
📓 Common learnings
Learnt from: costa-monite
PR: team-monite/monite-sdk#785
File: packages/sdk-react/src/core/i18n/locales/en/messages.po:8470-8473
Timestamp: 2025-09-04T15:54:24.944Z
Learning: For PRs focused on the invoice preview template (feat/DEV-15554), costa-monite prefers to exclude out-of-scope tweaks like minor i18n spacing changes (e.g., "Subtotal{0}" → "Subtotal {0}") and handle them in a separate follow-up.
📚 Learning: 2025-09-04T15:54:24.944Z
Learnt from: costa-monite
PR: team-monite/monite-sdk#785
File: packages/sdk-react/src/core/i18n/locales/en/messages.po:8470-8473
Timestamp: 2025-09-04T15:54:24.944Z
Learning: For PRs focused on the invoice preview template (feat/DEV-15554), costa-monite prefers to exclude out-of-scope tweaks like minor i18n spacing changes (e.g., "Subtotal{0}" → "Subtotal {0}") and handle them in a separate follow-up.
Applied to files:
packages/sdk-react/src/core/i18n/locales/en/messages.po
📚 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 : Always prefer shadcn/ui components such as Button, Input, Card, Dialog, Select, Checkbox, RadioGroup, Switch, Textarea, Label, Alert, Badge, Toast, Tabs, Table, Form, DropdownMenu, Sheet, Skeleton, Separator
Applied to files:
packages/sdk-react/src/core/i18n/locales/en/messages.po
📚 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/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/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx
📚 Learning: 2025-09-08T09:09:14.289Z
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.289Z
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/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx
🧬 Code graph analysis (1)
packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx (4)
packages/sdk-react/src/core/queries/useCounterpart.ts (1)
useCounterpartContactList(342-422)packages/sdk-react/src/components/receivables/hooks/useCreateReceivable.ts (1)
useCreateReceivable(7-29)packages/sdk-react/src/components/receivables/hooks/useCreateRecurrence.ts (1)
useCreateRecurrence(7-20)packages/sdk-react/src/components/receivables/hooks/useGetInvoiceRequiredFields.ts (1)
useGetInvoiceRequiredFields(13-41)
⏰ 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 (8)
packages/sdk-react/src/core/i18n/locales/en/messages.po (2)
9188-9191: Good safety copy for manual-totals mode.“The amounts have been modified...” is clear and action‑oriented. No changes needed.
8856-8860: Validation messages read well and are consistent.“cannot be negative” matches other Payables validations (e.g., tax rate). Ship as is.
Also applies to: 9001-9004, 9563-9566
packages/sdk-react/src/components/receivables/InvoiceDetails/CreateReceivable/CreateReceivables.tsx (6)
1246-1249: Double-check VAT flag semantics passed to ItemsSection.
isNonVatSupported || !isLineItemVatRateIdRequiredchanges behavior. Confirm ItemsSection interprets this as intended (i.e., hide/disable VAT rate when not required).
272-276: Create mutations wiring LGTM.Using
mutateAsyncfor receivable andmutatefor recurrence is appropriate given subsequent flow control.
279-292: Required-fields query inputs LGTM.Good defensive checks to avoid stale IDs/country. Matches
useGetInvoiceRequiredFieldsexpectations.
888-891: CTA label toggle LGTM.Clear UX: “Activate” when recurrence is enabled, otherwise “Save and continue”.
1-6: Imports and small plumbing changes LGTM.Additions are cohesive and correctly scoped.
Also applies to: 24-26, 29-30, 48-48, 220-223, 260-262
649-671: Wire recurrence payload from form values — don't hard-codeschema.json's CreateRecurrencePayload exposes frequency (day/week/month/quarter/year; default 'month'), interval and automation_level — source these from RecurrenceSection / RHF values and confirm AutomationLevel accepts 'issue' before defaulting to it.
- body: { - invoice_id: receivableId, - frequency: 'month', - interval: 1, + body: { + invoice_id: receivableId, + // TODO: wire these from RecurrenceSection/RHF values if available + frequency: values.recurrence_frequency ?? 'month', + interval: values.recurrence_interval ?? 1, start_date: values.recurrence_start_date ? format(new Date(values.recurrence_start_date), 'yyyy-MM-dd') : undefined, end_date: values.recurrence_end_date ? format(new Date(values.recurrence_end_date), 'yyyy-MM-dd') : undefined, - automation_level: 'issue', + automation_level: values.recurrence_automation_level ?? 'issue', + // If supported by API: + // issue_mode: values.recurrence_issue_mode, },
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx (2)
179-184: Wire through disableAutoCalculateTotals (currently commented).This prevents the feature flag from working and cascades into the debug override below.
Apply this diff:
const { ocrRequiredFields, optionalFields, isTagsDisabled, - // disableAutoCalculateTotals, // TODO: commented for debugging (DEV-15658) + disableAutoCalculateTotals, } = usePayableDetailsThemeProps(inProps);
189-193: Remove debug override; use the incoming prop.Hardcoding disables the feature and diverges from componentSettings.
Apply this diff:
- // const isDisableAutoCalculateTotals = disableAutoCalculateTotals || false; // TODO: commented for debugging (DEV-15658) - const isDisableAutoCalculateTotals = false; // TODO: for debugging (DEV-15658) + const isDisableAutoCalculateTotals = !!disableAutoCalculateTotals; const isLineItemsEditable = isDisableAutoCalculateTotals || !payable; const isTotalsEditable = isDisableAutoCalculateTotals;
🧹 Nitpick comments (5)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx (5)
270-285: Deduplicate reset logic by reusing memoized defaultValues.Avoids recalculating prepareDefaultValues and keeps sources in one place.
Apply this diff:
- useEffect(() => { - reset( - prepareDefaultValues( - formatFromMinorUnits, - payable, - lineItems, - !isDisableAutoCalculateTotals - ) - ); - }, [ - payable, - formatFromMinorUnits, - reset, - lineItems, - isDisableAutoCalculateTotals, - ]); + useEffect(() => { + reset(defaultValues); + }, [defaultValues, reset]);
748-771: Show 0 currency amounts correctly; avoid falsy checks and use nullish coalescing.Current truthy checks render “—” for legitimate 0 values, and
|| 0masks 0.Apply this diff:
- {isTotalsEditable ? ( + {isTotalsEditable ? ( <RHFTextField name="subtotal" control={control} size="small" type="number" - inputProps={{ min: 0 }} + inputProps={{ min: 0, step: 0.01 }} sx={{ width: 150 }} InputProps={{ endAdornment: getSymbolFromCurrency(currentCurrency), }} /> - ) : totals.subtotal && currentCurrency ? ( + ) : currentCurrency && totals.subtotal != null ? ( formatCurrencyToDisplay( - formatToMinorUnits( - totals.subtotal, - currentCurrency - ) || 0, + formatToMinorUnits( + totals.subtotal, + currentCurrency + ) ?? 0, currentCurrency ) ) : ( '—' )}
812-842: Same 0-handling fix for VAT total; add decimal step.Apply this diff:
- {isTotalsEditable ? ( + {isTotalsEditable ? ( <RHFTextField name="tax_amount" control={control} type="number" - inputProps={{ min: 0 }} + inputProps={{ min: 0, step: 0.01 }} sx={{ width: 150 }} InputProps={{ endAdornment: getSymbolFromCurrency(currentCurrency), }} /> - ) : totals.taxes && currentCurrency ? ( + ) : currentCurrency && totals.taxes != null ? ( formatCurrencyToDisplay( - formatToMinorUnits( - totals.taxes, - currentCurrency - ) || 0, + formatToMinorUnits( + totals.taxes, + currentCurrency + ) ?? 0, currentCurrency ) ) : ( '—' )}
851-882: Same 0-handling fix for Total; add decimal step.Apply this diff:
- {isTotalsEditable ? ( + {isTotalsEditable ? ( <RHFTextField name="total_amount" control={control} type="number" - inputProps={{ min: 0 }} + inputProps={{ min: 0, step: 0.01 }} sx={{ width: 150 }} InputProps={{ endAdornment: getSymbolFromCurrency(currentCurrency), }} /> ) : ( <Typography variant="subtitle1"> - {totals.total && currentCurrency + {currentCurrency && totals.total != null ? formatCurrencyToDisplay( - formatToMinorUnits( - totals.total, - currentCurrency - ) || 0, + formatToMinorUnits( + totals.total, + currentCurrency + ) ?? 0, currentCurrency ) : '—'} </Typography> )}
736-747: Prefer lucide-react icons for new UI per repo guidelines.Use Plus/Trash2 from lucide-react for newly added controls; add TODO if deferring broader migration.
Apply these diffs within the shown ranges:
- <Button - startIcon={<AddIcon />} + <Button + startIcon={<Plus size={16} />}- <IconButton + <IconButton aria-label="delete" onClick={() => { const setValue = methods.setValue; setValue('discount', null); }} > - <DeleteIcon /> + <Trash2 size={18} /> </IconButton>Add imports:
// at the icons import section import { Plus, Trash2 } from 'lucide-react';Also applies to: 785-793
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx(14 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/PayableDetailsForm/PayableDetailsForm.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/PayableDetailsForm/PayableDetailsForm.tsx
🧠 Learnings (10)
📓 Common learnings
Learnt from: costa-monite
PR: team-monite/monite-sdk#785
File: packages/sdk-react/src/core/i18n/locales/en/messages.po:8470-8473
Timestamp: 2025-09-04T15:54:24.944Z
Learning: For PRs focused on the invoice preview template (feat/DEV-15554), costa-monite prefers to exclude out-of-scope tweaks like minor i18n spacing changes (e.g., "Subtotal{0}" → "Subtotal {0}") and handle them in a separate follow-up.
📚 Learning: 2025-09-17T07:36:02.844Z
Learnt from: costa-monite
PR: team-monite/monite-sdk#828
File: packages/sdk-react/src/components/payables/PayableDetails/PayableDetails.tsx:54-54
Timestamp: 2025-09-17T07:36:02.844Z
Learning: All payables components (Payables, PayableDetails, PayableDetailsForm, PayableDetailsInfo, PayableLineItemsForm) consistently default enableGLCodes to false, not true. The JSDoc in Payables.tsx correctly documents default false.
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx
📚 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.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/PayableDetailsForm/PayableDetailsForm.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 lucide-react for icons and import icons like: import { Search, Menu, X } from 'lucide-react'
Applied to files:
packages/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 'lucide-react' for icons and import icons like 'import { Search, Menu, X } from "lucide-react"'
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.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 : Always prefer shadcn/ui components such as Button, Input, Card, Dialog, Select, Checkbox, RadioGroup, Switch, Textarea, Label, Alert, Badge, Toast, Tabs, Table, Form, DropdownMenu, Sheet, Skeleton, Separator
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.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 : Always use shadcn/ui components when creating new UI elements
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.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/PayableDetailsForm/PayableDetailsForm.tsx
📚 Learning: 2025-09-08T09:09:14.289Z
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.289Z
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/PayableDetailsForm/PayableDetailsForm.tsx
🧬 Code graph analysis (1)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx (5)
packages/sdk-react/src/components/payables/hooks/usePayableDetailsThemeProps.ts (1)
usePayableDetailsThemeProps(4-24)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/helpers.ts (1)
prepareDefaultValues(83-148)packages/sdk-react/src/components/payables/PayableDetails/PayableLineItemsForm/PayableLineItemsForm.tsx (1)
PayableLineItemsForm(12-148)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsInfo/DisplayPayableLineItems.tsx (1)
DisplayPayableLineItems(15-67)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-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 (5)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx (5)
194-203: Default-values memoization looks good.
335-352: Validate dirty detection for line items.dirtyFields.lineItems can be non-array in some RHF cases (e.g., full-array changes). Please verify this logic with add/remove/edit flows.
If needed, guard with Array.isArray(dirtyFields.lineItems) before .length/.some checks.
353-379: Change‑alert gating looks solid.
690-711: Items edit/read-only switch LGTM.
660-675: MoniteCurrency generic usage is correct.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx (1)
74-74: Fix lucide-react import/usage (build blocker).lucide-react exports AlertCircle (no "Icon" suffix). Importing AlertCircleIcon will fail.
- import { AlertCircleIcon } from 'lucide-react'; + import { AlertCircle } from 'lucide-react';- <Alert variant="warning" icon={<AlertCircleIcon />}> + <Alert variant="warning" icon={<AlertCircle />}>Also applies to: 699-706
🧹 Nitpick comments (3)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx (3)
733-746: Use MUI InputAdornment for currency suffix and set decimal input options.Passing a raw string to InputProps.endAdornment isn’t the intended MUI API and may render incorrectly. Also, add step/inputMode for consistent decimal input.
@@ TableRow, TextField, Typography, } from '@mui/material'; +import InputAdornment from '@mui/material/InputAdornment'; @@ - {isDisableAutoCalculateTotals ? ( + {isDisableAutoCalculateTotals ? ( <RHFTextField name="subtotal" control={control} size="small" - type="number" - inputProps={{ min: 0 }} + type="number" + inputProps={{ min: 0, step: 0.01, inputMode: 'decimal' }} sx={{ width: 150 }} InputProps={{ - endAdornment: - getSymbolFromCurrency(currentCurrency), + endAdornment: ( + <InputAdornment position="end"> + {getSymbolFromCurrency(currentCurrency)} + </InputAdornment> + ), }} /> ) : totals.subtotal && currentCurrency ? ( @@ <RHFTextField name="discount" control={control} - type="number" - inputProps={{ min: 0, step: 0.01 }} + type="number" + inputProps={{ min: 0, step: 0.01, inputMode: 'decimal' }} sx={{ width: 150 }} InputProps={{ - endAdornment: - getSymbolFromCurrency(currentCurrency), + endAdornment: ( + <InputAdornment position="end"> + {getSymbolFromCurrency(currentCurrency)} + </InputAdornment> + ), }} /> @@ - {isDisableAutoCalculateTotals ? ( + {isDisableAutoCalculateTotals ? ( <RHFTextField name="tax_amount" control={control} - type="number" - inputProps={{ min: 0 }} + type="number" + inputProps={{ min: 0, step: 0.01, inputMode: 'decimal' }} sx={{ width: 150 }} InputProps={{ - endAdornment: - getSymbolFromCurrency(currentCurrency), + endAdornment: ( + <InputAdornment position="end"> + {getSymbolFromCurrency(currentCurrency)} + </InputAdornment> + ), }} /> @@ - {isDisableAutoCalculateTotals ? ( + {isDisableAutoCalculateTotals ? ( <RHFTextField name="total_amount" control={control} - type="number" - inputProps={{ min: 0 }} + type="number" + inputProps={{ min: 0, step: 0.01, inputMode: 'decimal' }} sx={{ width: 150 }} InputProps={{ - endAdornment: - getSymbolFromCurrency(currentCurrency), + endAdornment: ( + <InputAdornment position="end"> + {getSymbolFromCurrency(currentCurrency)} + </InputAdornment> + ), }} />Also applies to: 779-789, 803-815, 843-853, 55-72
6-6: Remove unused import.DisplayPayableLineItems is imported but not used in this file.
-import { DisplayPayableLineItems } from '../PayableDetailsInfo';
189-199: Avoid double‑negatives; consider a positively named flag.isDisableAutoCalculateTotals forces repeated negation. A local const like isCalculateTotalsEnabled = !disableAutoCalculateTotals would improve readability across prepareDefaultValues/prepareSubmit/UI checks.
Also applies to: 268-282, 410-414, 698-706, 733-757, 803-867
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx(14 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/PayableDetailsForm/PayableDetailsForm.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/PayableDetailsForm/PayableDetailsForm.tsx
🧠 Learnings (10)
📓 Common learnings
Learnt from: costa-monite
PR: team-monite/monite-sdk#785
File: packages/sdk-react/src/core/i18n/locales/en/messages.po:8470-8473
Timestamp: 2025-09-04T15:54:24.944Z
Learning: For PRs focused on the invoice preview template (feat/DEV-15554), costa-monite prefers to exclude out-of-scope tweaks like minor i18n spacing changes (e.g., "Subtotal{0}" → "Subtotal {0}") and handle them in a separate follow-up.
📚 Learning: 2025-09-17T07:36:02.844Z
Learnt from: costa-monite
PR: team-monite/monite-sdk#828
File: packages/sdk-react/src/components/payables/PayableDetails/PayableDetails.tsx:54-54
Timestamp: 2025-09-17T07:36:02.844Z
Learning: All payables components (Payables, PayableDetails, PayableDetailsForm, PayableDetailsInfo, PayableLineItemsForm) consistently default enableGLCodes to false, not true. The JSDoc in Payables.tsx correctly documents default false.
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx
📚 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.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 'lucide-react' for icons and import icons like 'import { Search, Menu, X } from "lucide-react"'
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.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 lucide-react for icons and import icons like: import { Search, Menu, X } from 'lucide-react'
Applied to files:
packages/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/PayableDetailsForm/PayableDetailsForm.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 : Always prefer shadcn/ui components such as Button, Input, Card, Dialog, Select, Checkbox, RadioGroup, Switch, Textarea, Label, Alert, Badge, Toast, Tabs, Table, Form, DropdownMenu, Sheet, Skeleton, Separator
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.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 : Always use shadcn/ui components when creating new UI elements
Applied to files:
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.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/PayableDetailsForm/PayableDetailsForm.tsx
📚 Learning: 2025-09-08T09:09:14.289Z
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.289Z
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/PayableDetailsForm/PayableDetailsForm.tsx
🧬 Code graph analysis (1)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx (3)
packages/sdk-react/src/components/payables/hooks/usePayableDetailsThemeProps.ts (1)
usePayableDetailsThemeProps(4-24)packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/helpers.ts (1)
prepareDefaultValues(83-148)packages/sdk-react/src/ui/RHF/RHFTextField/RHFTextField.tsx (1)
RHFTextField(8-78)
🔇 Additional comments (2)
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx (2)
179-184: Flag wiring looks correct.disableAutoCalculateTotals is now properly sourced from theme props and used to drive behavior. Thanks for removing the hardcoded debug override.
If partners pass disableAutoCalculateTotals via componentSettings, verify it reaches this component:
- componentSettings.payables.disableAutoCalculateTotals is set
- usePayableDetailsThemeProps returns it
- This file toggles manual totals accordingly
Also applies to: 189-199
699-706: Confirmed — Alert supports variant="warning" and icon prop.packages/sdk-react/src/ui/components/alert.tsx defines a 'warning' variant in alertVariants and AlertProps includes icon?: React.ReactNode which is rendered when provided.
| ) : totals.subtotal && currentCurrency ? ( | ||
| formatCurrencyToDisplay( | ||
| formatToMinorUnits( | ||
| totals.subtotal, | ||
| currentCurrency | ||
| ) | ||
| : '—'} | ||
| ) || 0, | ||
| currentCurrency | ||
| ) | ||
| ) : ( | ||
| '—' | ||
| )} |
There was a problem hiding this comment.
Zero values render as em dash — should render 0.00.
Truthiness checks treat 0 as falsy, so subtotal/taxes/total display “—” when they are 0.
- ) : totals.subtotal && currentCurrency ? (
+ ) : (totals.subtotal !== null && totals.subtotal !== undefined) && currentCurrency ? (
@@
- ) : totals.taxes && currentCurrency ? (
+ ) : (totals.taxes !== null && totals.taxes !== undefined) && currentCurrency ? (
@@
- {totals.total && currentCurrency
+ {(totals.total !== null && totals.total !== undefined) && currentCurrencyAlso applies to: 815-825, 855-866
🤖 Prompt for AI Agents
In
packages/sdk-react/src/components/payables/PayableDetails/PayableDetailsForm/PayableDetailsForm.tsx
around lines 746-756 (and similarly at 815-825 and 855-866), the render logic
uses truthiness checks like "totals.subtotal && currentCurrency" which treats 0
as falsy causing zeros to render as '—'; change the condition to explicitly test
for null/undefined (e.g., totals.subtotal != null && currentCurrency != null or
Number.isFinite(totals.subtotal) && currentCurrency) so zero values pass, then
keep the existing formatting call; apply the same null/undefined check pattern
to taxes and total blocks and only render the em dash when value or currency is
actually missing.
Scope
Added a new
disableAutoCalculateTotalsflag in PayablescomponentSettings. When set totrue, this allows users to manually edit the totals values of a Payable; no automatic calculation will be performed on the client side.Jira ticket: https://monite.atlassian.net/browse/DEV-15658
Implementation
disableAutoCalculateTotalsseting to Payables componentSettings.subtotal,tax_amount, andtotal_amountfields to PayableDetailsFormFields interface.AlertinPayableDetailsFormif values of Line Items or Totals have been changed.PayableDetailsFormto use it to display Alert for changed values and also to avoid unnecessary updates of line items if not changed.Also:
PayableDetailsInfointo reusable components.Remarks
The value of
isDisableAutoCalculateTotalsis hardcoded as true to simulate the setting of componentSettings with disableAutoCalculateTotals=true. This will be removed before merging.The newly extracted PayableLineItems and Totals reusable components were used in a previous working version of this branch, but are no longer necessary. Decided to keep them, as the code separation can facilitate eventual refactors. I'm ok to revert this if you don't agree.
Steps to test
For testing purposes, it is simulated the setting of componentSettings with disableAutoCalculateTotals=true.
Change your partner settings to have
payable.enable_line_items: false(that will be the new default). With the partner settingpayable.enable_line_items: true, the saving of the payable should fail with API message.Creating new payable, from manual input
Editing Payable (either OCR or not)
And again
Summary by CodeRabbit
New Features
Refactor
Chores