Skip to content

Feat/coderabbit#3

Open
nicksonthc wants to merge 3 commits into
mainfrom
feat/coderabbit
Open

Feat/coderabbit#3
nicksonthc wants to merge 3 commits into
mainfrom
feat/coderabbit

Conversation

@nicksonthc
Copy link
Copy Markdown
Owner

@nicksonthc nicksonthc commented Sep 26, 2025

Summary by CodeRabbit

  • New Features

    • Added an Income Tax Calculator: enter income and reliefs to compute taxable income, total tax, net income, and effective/marginal rates.
    • Optional detailed tax bracket breakdown and current brackets reference.
    • New navigation link and route for quick access; responsive, polished UI with cards, tables, and clear action buttons.
  • Chores

    • Added automated code-review configuration for quality rules, reviewer assignment, auto-labels, notifications, and learning aids.

nicksonthc and others added 2 commits September 26, 2025 14:23
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 26, 2025

Walkthrough

Adds a CodeRabbit review configuration and a new Income Tax Calculator feature (React component + CSS), integrates it with app routing and the navbar, and provides UI for income/relief inputs, bracketed tax computation, results, and a detailed breakdown (Malaysia 2025).

Changes

Cohort / File(s) Summary
Review automation config
.github/coderabbit.yml
Adds a comprehensive CodeRabbit configuration defining review scope, quality/security rules, commenting strategy, project detection, GitHub integrations, notifications, and learning aids.
App routing integration
src/App.js
Imports IncomeTaxCalculator and registers a new /income-tax route rendering the component.
Income Tax feature (logic + UI)
src/components/IncomeTax/IncomeTaxCalculator.js, src/components/IncomeTax/IncomeTaxCalculator.css
Adds a new React component implementing stateful income/relief inputs, multi-bracket tax calculation, totals/rates/breakdown rendering, reset behavior, and responsive CSS for the UI.
Navbar update
src/components/Navbar.js
Adds a navigation link pointing to the new Income Tax route.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Navbar
  participant Router as App Router
  participant Calc as IncomeTaxCalculator
  participant Logic as Tax Logic
  participant UI as Results View

  User->>Navbar: Click "Income Tax"
  Navbar->>Router: Navigate /income-tax
  Router-->>Calc: Mount component
  User->>Calc: Enter income and reliefs
  User->>Calc: Click "Calculate Tax"
  Calc->>Logic: Compute totals, rates, bracket breakdown
  Logic-->>Calc: Results (tax, net, effective/marginal)
  Calc->>UI: Render results & breakdown
  User->>Calc: Click "Reset"
  Calc->>UI: Clear inputs and results
Loading
sequenceDiagram
  participant App as App
  participant Routes as Routes
  participant Calc as IncomeTaxCalculator

  App->>Routes: Define route "income-tax"
  Routes-->>Calc: Render on match
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~55 minutes

Poem

I nibble numbers, hop through brackets bright,
With carrots of credits, I lighten your byte.
From gross to net I bound and track,
Effective tails wag—no secrets I pack.
Click, compute—thump! Results in view,
A cozy burrow of taxes—yours anew.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Feat/coderabbit" does reference the addition of the CodeRabbit configuration file but does not clearly summarise the other significant changes in the pull request, such as the new IncomeTaxCalculator component and related UI updates. It is concise yet too narrow and branch-like to convey the full scope of the changeset.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/coderabbit

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a094b2e and eadb0c7.

📒 Files selected for processing (1)
  • .github/coderabbit.yml (1 hunks)
🔇 Additional comments (2)
.github/coderabbit.yml (2)

173-179: Broaden the calculator rule glob so it actually matches the new component

The current pattern only targets files sitting inside folders whose name ends with Calculator, so IncomeTaxCalculator.js in the root of the feature directory slips past the rule.

   - name: "calculator_accuracy"
     description: "Ensure calculator components have proper validation"
-    pattern: "src/components/*Calculator/**/*.js"
+    pattern: "src/components/**/*Calculator*.js"

142-147: Fix auto_assign_reviewers to use the supported boolean flag

Per CodeRabbit’s configuration schema, reviews.auto_assign_reviewers only accepts a boolean. Supplying a map leaves the option ignored, so no reviewers will ever be auto-assigned for those paths.

   github:
     # PR title suggestions
     suggest_pr_titles: true
-    
-    # Auto-assign reviewers based on file changes
-    auto_assign_reviewers:
-      - "src/components/GameTheory/**": ["@game-theory-expert"]
-      - "src/components/Pathfinding/**": ["@algorithms-expert"]
-      - "src/components/IncomeTax/**": ["@finance-expert"]
-      - "**/*.css": ["@ui-ux-expert"]
+    auto_assign_reviewers: true

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

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🧹 Nitpick comments (7)
.github/coderabbit.yml (1)

47-53: Remove stray CLAUDE.md from manual-approval list (if unused).

If this file doesn’t exist in the repo, it adds noise.

Apply this diff:

   require_manual_approval:
     - "src/App.js"
     - ".github/**"
     - "public/index.html"
-    - "CLAUDE.md"
src/components/Navbar.js (1)

8-21: Prefer NavLink for active state.

NavLink simplifies active class management and avoids manual pathname checks.

Apply this diff:

-import { Link, useLocation } from 'react-router-dom';
+import { NavLink } from 'react-router-dom';
 ...
-const location = useLocation();
-const isActive = (path) => location.pathname === path ? 'active' : '';
 ...
-<Link to="/income-tax" className={`nav-link ${isActive('/income-tax')}`}>Income Tax</Link>
+<NavLink to="/income-tax" className={({ isActive }) => `nav-link ${isActive ? 'active' : ''}`}>Income Tax</NavLink>

Repeat similarly for other links if desired.

src/App.js (1)

1-21: Consider lazy-loading the calculator route.

Reduces initial bundle size; the calculator is non-critical on first paint.

Example:

-import IncomeTaxCalculator from "./components/IncomeTax/IncomeTaxCalculator";
+import React, { Suspense } from 'react';
+const IncomeTaxCalculator = React.lazy(() => import("./components/IncomeTax/IncomeTaxCalculator"));
 ...
-  <Route path="income-tax" element={<IncomeTaxCalculator />} />
+  <Route path="income-tax" element={
+    <Suspense fallback={<div>Loading…</div>}>
+      <IncomeTaxCalculator />
+    </Suspense>
+  } />
src/components/IncomeTax/IncomeTaxCalculator.js (2)

106-149: Add constraints to relief fields and children count; improve label associations.

  • Add min/step to prevent negatives.
  • For accessibility, associate labels and inputs via id/htmlFor.

Apply this diff (pattern shown; replicate for each input):

-              <div className="input-group">
-                <label>Personal Relief (RM)</label>
-                <input
-                  type="number"
-                  value={personalRelief}
-                  onChange={(e) => setPersonalRelief(parseFloat(e.target.value) || 0)}
-                  placeholder="9000"
-                />
-              </div>
+              <div className="input-group">
+                <label htmlFor="personalRelief">Personal Relief (RM)</label>
+                <input
+                  id="personalRelief"
+                  type="number"
+                  min="0"
+                  step="1"
+                  value={personalRelief}
+                  onChange={(e) => setPersonalRelief(parseFloat(e.target.value) || 0)}
+                  placeholder="9000"
+                />
+              </div>

-              <div className="input-group">
-                <label>Spouse Relief (RM)</label>
+              <div className="input-group">
+                <label htmlFor="spouseRelief">Spouse Relief (RM)</label>
                 <input
+                  id="spouseRelief"
                   type="number"
+                  min="0"
+                  step="1"
                   value={spouseRelief}
                   onChange={(e) => setSpouseRelief(parseFloat(e.target.value) || 0)}
                   placeholder="4000"
                 />
               </div>
-              <div className="input-group">
-                <label>Number of Children</label>
+              <div className="input-group">
+                <label htmlFor="childrenCount">Number of Children</label>
                 <input
+                  id="childrenCount"
                   type="number"
+                  min="0"
+                  step="1"
                   value={childRelief}
                   onChange={(e) => setChildRelief(parseInt(e.target.value) || 0)}
                   placeholder="0"
                 />
               </div>

Optional: rename state childRelief to childrenCount for clarity.


226-242: Update brackets display to match threshold model.

Reflect the new lower/upper thresholds.

Apply this diff:

-              {taxBrackets.map((bracket, index) => (
+              {taxBrackets.reduce((rows, bracket, idx) => {
+                const lower = idx === 0 ? 0 : taxBrackets[idx - 1].upTo;
+                rows.push({ lower, upper: bracket.upTo, rate: bracket.rate });
+                return rows;
+              }, []).map((b, index) => (
                 <div key={index} className="brackets-row">
                   <span>
-                    {bracket.min === 0 ? '0' : bracket.min.toLocaleString()} - {' '}
-                    {bracket.max === Infinity ? '2,000,000+' : bracket.max.toLocaleString()}
+                    {b.lower === 0 ? '0' : b.lower.toLocaleString()} - {' '}
+                    {b.upper === Infinity ? '2,000,000+' : b.upper.toLocaleString()}
                   </span>
-                  <span>{bracket.rate}%</span>
+                  <span>{b.rate}%</span>
                 </div>
               ))}
src/components/IncomeTax/IncomeTaxCalculator.css (2)

112-145: Add visible keyboard focus states for buttons.

Improve accessibility by styling :focus-visible (don’t rely on default outlines).

Apply this diff:

 .calculate-btn, .reset-btn {
   padding: 1rem 2rem;
   border: none;
   border-radius: 8px;
   font-size: 1rem;
   font-weight: 600;
   cursor: pointer;
   transition: all 0.3s ease;
   text-transform: uppercase;
   letter-spacing: 0.5px;
 }
+
+.calculate-btn:focus-visible,
+.reset-btn:focus-visible {
+  outline: 3px solid rgba(102, 126, 234, 0.6);
+  outline-offset: 2px;
+}

344-376: Respect reduced motion preferences.

Avoid hover transforms for users preferring reduced motion.

Apply this diff:

 @media (max-width: 768px) {
 ...
 }
+
+@media (prefers-reduced-motion: reduce) {
+  .calculate-btn:hover,
+  .reset-btn:hover {
+    transform: none;
+    transition: none;
+  }
+}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a120de3 and a094b2e.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (5)
  • .github/coderabbit.yml (1 hunks)
  • src/App.js (2 hunks)
  • src/components/IncomeTax/IncomeTaxCalculator.css (1 hunks)
  • src/components/IncomeTax/IncomeTaxCalculator.js (1 hunks)
  • src/components/Navbar.js (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/App.js (1)
src/components/IncomeTax/IncomeTaxCalculator.js (1)
  • IncomeTaxCalculator (4-248)
🔇 Additional comments (4)
src/components/Navbar.js (1)

21-21: LGTM: new Income Tax nav link.

Correct path and active-class handling align with the new route.

src/App.js (1)

7-7: LGTM: route wiring for IncomeTaxCalculator.

Import and route are correct and consistent with Navbar.

Also applies to: 19-19

src/components/IncomeTax/IncomeTaxCalculator.js (2)

1-2: Ignore default React import suggestion – the project uses React 18 with CRA v5’s automatic JSX runtime; an explicit import React isn’t required.

Likely an incorrect or invalid review comment.


1-247: Tax brackets match LHDN YA2025 All defined thresholds and marginal rates align with the Inland Revenue Board’s published resident individual table for Assessment Year 2025.

Comment thread .github/coderabbit.yml
Comment thread .github/coderabbit.yml
Comment on lines +142 to +148
# Auto-assign reviewers based on file changes
auto_assign_reviewers:
- "src/components/GameTheory/**": ["@game-theory-expert"]
- "src/components/Pathfinding/**": ["@algorithms-expert"]
- "src/components/IncomeTax/**": ["@finance-expert"]
- "**/*.css": ["@ui-ux-expert"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify auto_assign_reviewers format.

YAML is valid, but confirm CodeRabbit expects a mapping vs list-of-single-key maps for this field.

Run a web check:


🌐 Web query:

Show the correct schema and example for `auto_assign_reviewers` in CodeRabbit's `.coderabbit.yml` / `.github/coderabbit.yml` configuration.

💡 Result:

Schema (field path + type + default)

  • reviews.auto_assign_reviewers: boolean — default: false. [1][2]

Minimal examples

.coderabbit.yml or .github/coderabbit.yml

# enable suggested reviewers and auto-assign them
reviews:
  suggested_reviewers: true
  auto_assign_reviewers: true

Fuller context example

reviews:
  profile: "chill"
  suggested_reviewers: true
  auto_assign_reviewers: true
  auto_apply_labels: false
  auto_review:
    enabled: true
    drafts: false

Sources

  • Configuration reference (reviews section). [1]
  • YAML template / examples. [2]

Configure reviews.auto_assign_reviewers as a boolean
Replace the mapping in .github/coderabbit.yml lines 142–148 with:

reviews:
  suggested_reviewers: true
  auto_assign_reviewers: true

CodeRabbit only supports auto_assign_reviewers as a boolean flag, not a file‐pattern map.

🤖 Prompt for AI Agents
In .github/coderabbit.yml around lines 142 to 148, the current
auto_assign_reviewers mapping using file patterns is invalid; CodeRabbit expects
a boolean flag. Replace the pattern map with a reviews block that sets
suggested_reviewers: true and auto_assign_reviewers: true, removing the
file-pattern entries entirely so the config uses the supported boolean flag.

Comment thread .github/coderabbit.yml
Comment on lines +162 to +181
# Custom rules for this project
custom_rules:
# Educational project specific rules
- name: "educational_clarity"
description: "Ensure code is educational and well-documented"
pattern: "src/components/**/*.js"
checks:
- has_component_description: warn
- has_prop_types: suggest
- has_usage_examples: suggest

# Calculator specific rules
- name: "calculator_accuracy"
description: "Ensure calculator components have proper validation"
pattern: "src/components/*Calculator/**/*.js"
checks:
- has_input_validation: error
- has_error_handling: error
- has_boundary_testing: warn

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Fix custom_rules pattern so it matches IncomeTaxCalculator.js.

Pattern "src/components/Calculator/**/.js" targets folders ending with "Calculator", not files like IncomeTaxCalculator.js. As a result, accuracy/validation checks won’t run on this component.

Apply this diff:

   - name: "calculator_accuracy"
     description: "Ensure calculator components have proper validation"
-    pattern: "src/components/*Calculator/**/*.js"
+    pattern: "src/components/**/*Calculator*.js"
     checks:
       - has_input_validation: error
       - has_error_handling: error
       - has_boundary_testing: warn
📝 Committable suggestion

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

Suggested change
# Custom rules for this project
custom_rules:
# Educational project specific rules
- name: "educational_clarity"
description: "Ensure code is educational and well-documented"
pattern: "src/components/**/*.js"
checks:
- has_component_description: warn
- has_prop_types: suggest
- has_usage_examples: suggest
# Calculator specific rules
- name: "calculator_accuracy"
description: "Ensure calculator components have proper validation"
pattern: "src/components/*Calculator/**/*.js"
checks:
- has_input_validation: error
- has_error_handling: error
- has_boundary_testing: warn
# Custom rules for this project
custom_rules:
# Educational project specific rules
- name: "educational_clarity"
description: "Ensure code is educational and well-documented"
pattern: "src/components/**/*.js"
checks:
- has_component_description: warn
- has_prop_types: suggest
- has_usage_examples: suggest
# Calculator specific rules
- name: "calculator_accuracy"
description: "Ensure calculator components have proper validation"
pattern: "src/components/**/*Calculator*.js"
checks:
- has_input_validation: error
- has_error_handling: error
- has_boundary_testing: warn
🤖 Prompt for AI Agents
.github/coderabbit.yml around lines 162 to 181: the glob pattern
"src/components/*Calculator/**/*.js" only matches directories whose name ends
with "Calculator" and nested files, so it misses files named like
IncomeTaxCalculator.js; update the pattern to match files with "Calculator" in
their filename (for example use "src/components/**/*Calculator.js" or
"src/components/**/*Calculator*.js") so the calculator_accuracy checks will run
against IncomeTaxCalculator.js (apply the chosen glob to replace the existing
pattern).

Comment on lines +13 to +24
const taxBrackets = [
{ min: 0, max: 5000, rate: 0 },
{ min: 5001, max: 20000, rate: 1 },
{ min: 20001, max: 35000, rate: 3 },
{ min: 35001, max: 50000, rate: 6 },
{ min: 50001, max: 70000, rate: 11 },
{ min: 70001, max: 100000, rate: 19 },
{ min: 100001, max: 400000, rate: 25 },
{ min: 400001, max: 600000, rate: 26 },
{ min: 600001, max: 2000000, rate: 28 },
{ min: 2000001, max: Infinity, rate: 30 }
];
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Bracket definitions are off-by-one and model discrete RM units; switch to threshold-based brackets.

Current min/max with 5001 starts and +1 math imply inclusive ranges and integer steps, which mis-taxes amounts (e.g., first bracket taxes 5001 instead of 5000) and fails for decimals.

Apply this diff to use thresholds:

-  const taxBrackets = [
-    { min: 0, max: 5000, rate: 0 },
-    { min: 5001, max: 20000, rate: 1 },
-    { min: 20001, max: 35000, rate: 3 },
-    { min: 35001, max: 50000, rate: 6 },
-    { min: 50001, max: 70000, rate: 11 },
-    { min: 70001, max: 100000, rate: 19 },
-    { min: 100001, max: 400000, rate: 25 },
-    { min: 400001, max: 600000, rate: 26 },
-    { min: 600001, max: 2000000, rate: 28 },
-    { min: 2000001, max: Infinity, rate: 30 }
-  ];
+  const taxBrackets = [
+    { upTo: 5000, rate: 0 },
+    { upTo: 20000, rate: 1 },
+    { upTo: 35000, rate: 3 },
+    { upTo: 50000, rate: 6 },
+    { upTo: 70000, rate: 11 },
+    { upTo: 100000, rate: 19 },
+    { upTo: 400000, rate: 25 },
+    { upTo: 600000, rate: 26 },
+    { upTo: 2000000, rate: 28 },
+    { upTo: Infinity, rate: 30 }
+  ];
📝 Committable suggestion

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

Suggested change
const taxBrackets = [
{ min: 0, max: 5000, rate: 0 },
{ min: 5001, max: 20000, rate: 1 },
{ min: 20001, max: 35000, rate: 3 },
{ min: 35001, max: 50000, rate: 6 },
{ min: 50001, max: 70000, rate: 11 },
{ min: 70001, max: 100000, rate: 19 },
{ min: 100001, max: 400000, rate: 25 },
{ min: 400001, max: 600000, rate: 26 },
{ min: 600001, max: 2000000, rate: 28 },
{ min: 2000001, max: Infinity, rate: 30 }
];
const taxBrackets = [
{ upTo: 5000, rate: 0 },
{ upTo: 20000, rate: 1 },
{ upTo: 35000, rate: 3 },
{ upTo: 50000, rate: 6 },
{ upTo: 70000, rate: 11 },
{ upTo: 100000, rate: 19 },
{ upTo: 400000, rate: 25 },
{ upTo: 600000, rate: 26 },
{ upTo: 2000000, rate: 28 },
{ upTo: Infinity, rate: 30 }
];

Comment on lines +26 to +33
const calculateTax = () => {
const grossIncome = parseFloat(income) || 0;
const totalRelief = personalRelief + spouseRelief + (childRelief * 2000) + educationRelief + epfRelief;
const taxableIncome = Math.max(0, grossIncome - totalRelief);

let tax = 0;
let breakdownData = [];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Clamp negatives and sanitize inputs before computing.

Ensure non-negative values and avoid NaN propagation.

Apply this diff:

-    const grossIncome = parseFloat(income) || 0;
-    const totalRelief = personalRelief + spouseRelief + (childRelief * 2000) + educationRelief + epfRelief;
+    const grossIncome = Math.max(0, parseFloat(income) || 0);
+    const p = Math.max(0, Number(personalRelief) || 0);
+    const s = Math.max(0, Number(spouseRelief) || 0);
+    const c = Math.max(0, Math.floor(Number(childRelief) || 0));
+    const edu = Math.max(0, Number(educationRelief) || 0);
+    const epf = Math.max(0, Number(epfRelief) || 0);
+    const totalRelief = p + s + (c * 2000) + edu + epf;
📝 Committable suggestion

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

Suggested change
const calculateTax = () => {
const grossIncome = parseFloat(income) || 0;
const totalRelief = personalRelief + spouseRelief + (childRelief * 2000) + educationRelief + epfRelief;
const taxableIncome = Math.max(0, grossIncome - totalRelief);
let tax = 0;
let breakdownData = [];
const calculateTax = () => {
const grossIncome = Math.max(0, parseFloat(income) || 0);
const p = Math.max(0, Number(personalRelief) || 0);
const s = Math.max(0, Number(spouseRelief) || 0);
const c = Math.max(0, Math.floor(Number(childRelief) || 0));
const edu = Math.max(0, Number(educationRelief) || 0);
const epf = Math.max(0, Number(epfRelief) || 0);
const totalRelief = p + s + (c * 2000) + edu + epf;
const taxableIncome = Math.max(0, grossIncome - totalRelief);
let tax = 0;
let breakdownData = [];
🤖 Prompt for AI Agents
In src/components/IncomeTax/IncomeTaxCalculator.js around lines 26 to 33, the
inputs are used directly which can produce NaN or negative reliefs; sanitize
each input by coercing to numbers (e.g., Number(...) or parseFloat(...)) and
defaulting to 0 for NaN, then clamp any relief values and grossIncome to a
minimum of 0 (Math.max(0, value)) before computing totalRelief and
taxableIncome; compute childRelief contribution using the sanitized childRelief
value and ensure taxableIncome = Math.max(0, grossIncome - totalRelief) so
negatives never propagate.

Comment on lines +34 to +49
for (const bracket of taxBrackets) {
if (taxableIncome > bracket.min - 1) {
const taxableInBracket = Math.min(taxableIncome, bracket.max) - bracket.min + 1;
const taxInBracket = (taxableInBracket * bracket.rate) / 100;

if (taxInBracket > 0) {
tax += taxInBracket;
breakdownData.push({
range: bracket.max === Infinity ? `RM ${bracket.min.toLocaleString()}+` : `RM ${bracket.min.toLocaleString()} - RM ${bracket.max.toLocaleString()}`,
rate: bracket.rate,
taxableAmount: taxableInBracket,
taxAmount: taxInBracket
});
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Correct bracket tax computation (remove +1 and off-by-one).

Use progressive spans between thresholds.

Apply this diff:

-    for (const bracket of taxBrackets) {
-      if (taxableIncome > bracket.min - 1) {
-        const taxableInBracket = Math.min(taxableIncome, bracket.max) - bracket.min + 1;
-        const taxInBracket = (taxableInBracket * bracket.rate) / 100;
-        
-        if (taxInBracket > 0) {
-          tax += taxInBracket;
-          breakdownData.push({
-            range: bracket.max === Infinity ? `RM ${bracket.min.toLocaleString()}+` : `RM ${bracket.min.toLocaleString()} - RM ${bracket.max.toLocaleString()}`,
-            rate: bracket.rate,
-            taxableAmount: taxableInBracket,
-            taxAmount: taxInBracket
-          });
-        }
-      }
-    }
+    let lower = 0;
+    let remaining = taxableIncome;
+    for (const bracket of taxBrackets) {
+      if (remaining <= 0) break;
+      const upper = bracket.upTo;
+      const span = Math.max(0, Math.min(remaining, upper - lower));
+      if (span > 0) {
+        const taxInBracket = span * (bracket.rate / 100);
+        tax += taxInBracket;
+        breakdownData.push({
+          range: upper === Infinity ? `RM ${lower.toLocaleString()}+` : `RM ${lower.toLocaleString()} - RM ${upper.toLocaleString()}`,
+          rate: bracket.rate,
+          taxableAmount: span,
+          taxAmount: taxInBracket
+        });
+        remaining -= span;
+      }
+      lower = upper;
+    }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +51 to +55
const netIncome = grossIncome - tax;
const effectiveRate = grossIncome > 0 ? (tax / grossIncome) * 100 : 0;
const marginalRate = taxBrackets.find(bracket =>
taxableIncome >= bracket.min - 1 && taxableIncome <= bracket.max
)?.rate || 0;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix marginal rate selection.

Use the current threshold band, not min-1.

Apply this diff:

-    const marginalRate = taxBrackets.find(bracket => 
-      taxableIncome >= bracket.min - 1 && taxableIncome <= bracket.max
-    )?.rate || 0;
+    const marginalRate = taxBrackets.find(bracket => taxableIncome <= bracket.upTo)?.rate || 0;

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/components/IncomeTax/IncomeTaxCalculator.js around lines 51 to 55, the
marginal rate lookup uses bracket.min - 1 which incorrectly shifts the lower
bound; change the comparison to use the actual threshold band by using
taxableIncome >= bracket.min && taxableIncome <= bracket.max (or equivalent) so
the current bracket is selected correctly and fallback to 0 if none match.

Comment on lines +91 to +99
<label>Annual Gross Income (RM)</label>
<input
type="number"
value={income}
onChange={(e) => setIncome(e.target.value)}
placeholder="Enter your annual income"
className="income-input"
/>
</div>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add basic input constraints to income field.

Prevent negative inputs and allow cents.

Apply this diff:

               <input
                 type="number"
                 value={income}
                 onChange={(e) => setIncome(e.target.value)}
                 placeholder="Enter your annual income"
                 className="income-input"
+                min="0"
+                step="0.01"
               />
📝 Committable suggestion

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

Suggested change
<label>Annual Gross Income (RM)</label>
<input
type="number"
value={income}
onChange={(e) => setIncome(e.target.value)}
placeholder="Enter your annual income"
className="income-input"
/>
</div>
<label>Annual Gross Income (RM)</label>
<input
type="number"
value={income}
onChange={(e) => setIncome(e.target.value)}
placeholder="Enter your annual income"
className="income-input"
min="0"
step="0.01"
/>
</div>
🤖 Prompt for AI Agents
In src/components/IncomeTax/IncomeTaxCalculator.js around lines 91 to 99, the
income input currently allows negative values and non-decimal handling; add
basic input constraints by setting min="0" and step="0.01" on the input to
prevent negatives and allow cents, and update the onChange handler to parse the
input as a numeric value (e.g., parseFloat) and clamp negative values to 0
before calling setIncome so the state always holds a valid non-negative number
with cents support.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 26, 2025

Note

Unit test generation is an Early Access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 26, 2025

UTG Post-Process Complete

No new issues were detected in the generated code and all check runs have completed. The unit test generation process has completed successfully.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 26, 2025

Creating a PR to put the unit tests in...

The changes have been created in this pull request: View PR

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant