Skip to content

New reverse withdrawal react#2970

Merged
MdAsifHossainNadim merged 17 commits intodevelopfrom
new-reverse-withdrawal-react
Nov 24, 2025
Merged

New reverse withdrawal react#2970
MdAsifHossainNadim merged 17 commits intodevelopfrom
new-reverse-withdrawal-react

Conversation

@akzmoudud
Copy link
Contributor

@akzmoudud akzmoudud commented Nov 8, 2025

All Submissions:

  • My code follow the WordPress' coding standards
  • My code satisfies feature requirements
  • My code is tested
  • My code passes the PHPCS tests
  • My code has proper inline documentation
  • I've included related pull request(s) (optional)
  • I've included developer documentation (optional)
  • I've added proper labels to this pull request

Changes proposed in this Pull Request:

Related Pull Request(s)

  • Full PR Link

Closes

How to test the changes in this Pull Request:

  • Steps or issue link

Changelog entry

Title

Detailed Description of the pull request. What was previous behaviour
and what will be changed in this PR.

Before Changes

Describe the issue before changes with screenshots(s).

After Changes

Describe the issue after changes with screenshot(s).

Feature Video (optional)

Link of detailed video if this PR is for a feature.

PR Self Review Checklist:

  • Code is not following code style guidelines
  • Bad naming: make sure you would understand your code if you read it a few months from now.
  • KISS: Keep it simple, Sweetie (not stupid!).
  • DRY: Don't Repeat Yourself.
  • Code that is not readable: too many nested 'if's are a bad sign.
  • Performance issues
  • Complicated constructions that need refactoring or comments: code should almost always be self-explanatory.
  • Grammar errors.

FOR PR REVIEWER ONLY:

As a reviewer, your feedback should be focused on the idea, not the person. Seek to understand, be respectful, and focus on constructive dialog.

As a contributor, your responsibility is to learn from suggestions and iterate your pull request should it be needed based on feedback. Seek to collaborate and produce the best possible contribution to the greater whole.

  • Correct — Does the change do what it’s supposed to? ie: code 100% fulfilling the requirements?
  • Secure — Would a nefarious party find some way to exploit this change? ie: everything is sanitized/escaped appropriately for any SQL or XSS injection possibilities?
  • Readable — Will your future self be able to understand this change months down the road?
  • Elegant — Does the change fit aesthetically within the overall style and architecture?

Summary by CodeRabbit

  • New Features

    • Reverse Withdrawal admin area: KPIs, store list view, per-store transactions page, new admin routes, and an "Add New" modal for creating reverse withdrawal transactions (vendor/product/order selection, debit/credit, amount, notes).
  • Filters

    • Vendor/store selector and date-range filtering with apply/clear behavior; per-store transaction viewing.
  • Bug Fixes

    • Transactions API accepts optional date range and falls back to a default window when none provided.
  • Style

    • UI tweaks to data view layout and tab/button appearance; header support added above dataview tabs.
  • Other

    • Panel switcher recognizes the new admin panel key; modal confirm can be programmatically disabled.

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

@akzmoudud akzmoudud self-assigned this Nov 8, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 8, 2025

Walkthrough

Adds a Reverse Withdrawal admin feature: new PHP page class and service registration, makes REST trn_date optional with a default, introduces React routes/pages (list + transaction), add-modal, DataView header support, SCSS tweaks, panel-switcher key, and a modal prop for confirm disabling.

Changes

Cohort / File(s) Summary
PHP Page & Provider
\includes/Admin/Dashboard/Pages/ReverseWithdrawal.php`, `includes/DependencyManagement/Providers/AdminDashboardServiceProvider.php``
New ReverseWithdrawal page class (get_id, menu, settings, scripts, styles, register). Service provider imports and registers ReverseWithdrawal::class.
REST Controller
\includes/REST/ReverseWithdrawalController.php``
get_store_transactions supplies a default trn_date when absent; trn_date route param changed to 'required' => false.
Dashboard Routes
\src/admin/dashboard/components/Dashboard.tsx``
Added admin routes: reverse-withdrawal and reverse-withdrawal/store/:id wired to new pages.
Reverse Withdrawal Page
\src/admin/dashboard/pages/reverse-withdrawal/index.tsx``
New ReverseWithdrawalPage: KPI cards (from response headers), vendor/date filters, server fetch for stores balance, paginated DataView grid, integrated add-modal.
Transaction Page
\src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx``
New ReverseWithdrawalTransactionPage with vendor transactions, stats, date-range filtering, pagination and formatted renders.
Add Reverse Withdraw Modal
\src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx``
New modal to create reverse withdrawals: vendor/product/order async selects, trn_type, debit/credit handling, client validation, POST to dokan/v1/reverse-withdrawal/transactions.
Panel Switcher
\src/admin/panel-switcher/PanelSwitch.tsx``
Added 'reverse-withdrawal' to supported panel switch keys.
DataView Table
\src/components/dataviews/AdminDataViewTable.tsx``
Optional header block rendered above tabs when filteredProps.header provided.
Modal API
\src/components/modals/DokanModal.tsx``
Added confirmButtonDisabled?: boolean prop and included it in confirm button disabled logic.
Styles
\src/admin/dashboard/style.scss``
SCSS tweaks for #reverse-withdrawal-data-view and #reverse-withdrawal-transactions (column width, tab button border).

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor Admin
    participant UI as ReverseWithdrawalPage
    participant Modal as AddReverseWithdrawModal
    participant API as dokan/v1 API

    rect rgba(0,128,96,0.06)
    Admin->>UI: Open /reverse-withdrawal
    UI->>API: GET /reverse-withdrawal/stores-balance?filters...
    API-->>UI: 200 OK (body + KPI headers)
    UI->>Admin: Render KPIs, filters, grid
    end

    rect rgba(0,96,160,0.06)
    Admin->>UI: Click "Add New"
    UI->>Modal: Open modal
    Admin->>Modal: Submit form (vendor, trn_type, trn_id, debit/credit, note)
    Modal->>API: POST /reverse-withdrawal/transactions (payload)
    API-->>Modal: 200 OK
    Modal->>UI: Emit refresh
    UI->>API: Re-fetch /stores-balance
    API-->>UI: Updated data + KPI headers
    UI->>Admin: Update view
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Focus areas:
    • src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx — validation, debit vs credit payload, async selects.
    • src/admin/dashboard/pages/reverse-withdrawal/index.tsx — query assembly, KPI header parsing, pagination/DataView fields.
    • includes/REST/ReverseWithdrawalController.php — default trn_date behavior and route param change.
    • Integration points: AdminDashboardServiceProvider and Dashboard route wiring.

Possibly related PRs

Suggested reviewers

  • mrabbani
  • shohag121

Poem

🐇 I hopped through code, a carrot in hand,
Pages and modals sprung up on the land.
Vendors and KPIs dance in a row,
Transactions aligned in tidy flow.
The rabbit grins: "Merge — watch it grow!"

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description uses the template structure but lacks critical details: 'Changes proposed' section is empty, 'How to test' is incomplete, 'Changelog entry' lacks implementation details, and 'Before/After Changes' sections have no content or screenshots. Complete the required template sections with specific implementation details, clear testing steps, detailed changelog entry explaining behavior changes, and before/after context where applicable.
Title check ❓ Inconclusive The title 'New reverse withdrawal react' is vague and generic, using non-descriptive phrasing that doesn't convey meaningful information about the specific changes beyond mentioning 'reverse withdrawal' and 'react'. Use a more descriptive title that clearly summarizes the main change, such as 'Add reverse withdrawal admin dashboard page' or 'Implement reverse withdrawal React components and routing'.
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch new-reverse-withdrawal-react

📜 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 3883362 and 3a6fbd5.

📒 Files selected for processing (1)
  • src/admin/panel-switcher/PanelSwitch.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/admin/panel-switcher/PanelSwitch.tsx
⏰ 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: e2e tests (3, 3)
  • GitHub Check: e2e tests (1, 3)
  • GitHub Check: e2e tests (2, 3)
  • GitHub Check: api tests (1, 1)

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
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fe7b12b and 87f4064.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (5)
  • includes/Admin/Dashboard/Pages/ReverseWithdrawal.php (1 hunks)
  • includes/DependencyManagement/Providers/AdminDashboardServiceProvider.php (2 hunks)
  • src/admin/dashboard/components/Dashboard.tsx (2 hunks)
  • src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (1 hunks)
  • src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
includes/DependencyManagement/Providers/AdminDashboardServiceProvider.php (2)
includes/Admin/Dashboard/Dashboard.php (1)
  • Dashboard (14-658)
includes/Admin/Dashboard/Pages/ReverseWithdrawal.php (1)
  • ReverseWithdrawal (5-66)
src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (1)
types/externals.d.ts (1)
  • DokanModal (65-65)
src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1)
types/externals.d.ts (2)
  • Filter (60-60)
  • DataViews (59-59)
includes/Admin/Dashboard/Pages/ReverseWithdrawal.php (2)
includes/Admin/Dashboard/Pages/AbstractPage.php (1)
  • AbstractPage (8-59)
includes/DependencyManagement/Providers/AdminDashboardServiceProvider.php (1)
  • register (51-58)
⏰ 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: e2e tests (3, 3)
  • GitHub Check: e2e tests (2, 3)
  • GitHub Check: e2e tests (1, 3)
  • GitHub Check: api tests (1, 1)

@akzmoudud akzmoudud force-pushed the new-reverse-withdrawal-react branch from 87f4064 to 49eb668 Compare November 8, 2025 07:01
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

♻️ Duplicate comments (2)
src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (1)

8-20: Missing onSave callback to refresh parent data.

The component signature doesn't accept an onSave prop, so the parent's callback is dropped and the page data won't refresh after a successful save. This issue was already flagged in a previous review.

src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1)

174-180: Modal integration issue already flagged.

The handleModalSave callback is defined here but AddReverseWithdrawModal doesn't accept an onSave prop, so this callback is never invoked. This was already flagged in the previous review of the modal component.

🧹 Nitpick comments (4)
includes/DependencyManagement/Providers/AdminDashboardServiceProvider.php (2)

15-15: Consider alphabetical ordering of imports.

The import is correct, but for consistency and maintainability, consider placing it in alphabetical order with the other page imports (between ProFeatures and SetupGuide).


43-43: Remove redundant inline comment.

The inline comment is self-explanatory from the code itself and inconsistent with other entries in the array.

Apply this diff:

-        ReverseWithdrawal::class, // Added ReverseWithdrawal page service
+        ReverseWithdrawal::class,
src/admin/dashboard/pages/reverse-withdrawal/index.tsx (2)

183-189: Remove unnecessary memoization wrapper.

The memoizedSetFilterArgs callback doesn't provide any real benefit since setFilterArgs from useState is already stable, and React's setState natively handles both function and value forms. This adds unnecessary complexity.

-    // Memoize setFilterArgs to prevent unnecessary re-renders of StoreFilter
-    const memoizedSetFilterArgs = useCallback((newArgs) => {
-        if (typeof newArgs === 'function') {
-            setFilterArgs(newArgs);
-        } else {
-            setFilterArgs(newArgs);
-        }
-    }, []);
-
     // Move DateFilter outside or memoize it
     const DateFilter = useCallback(() => {

Then update line 272:

-        <StoreFilter key="store_filter" filterArgs={filterArgs} setFilterArgs={memoizedSetFilterArgs} />,
+        <StoreFilter key="store_filter" filterArgs={filterArgs} setFilterArgs={setFilterArgs} />,

227-227: Add space after if keyword.

Minor style inconsistency.

-            if(tempAfter && tempBefore) {
+            if (tempAfter && tempBefore) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 87f4064 and cce4699.

📒 Files selected for processing (5)
  • includes/Admin/Dashboard/Pages/ReverseWithdrawal.php (1 hunks)
  • includes/DependencyManagement/Providers/AdminDashboardServiceProvider.php (2 hunks)
  • src/admin/dashboard/components/Dashboard.tsx (2 hunks)
  • src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (1 hunks)
  • src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/admin/dashboard/components/Dashboard.tsx
  • includes/Admin/Dashboard/Pages/ReverseWithdrawal.php
🧰 Additional context used
🧬 Code graph analysis (3)
includes/DependencyManagement/Providers/AdminDashboardServiceProvider.php (2)
includes/Admin/Dashboard/Dashboard.php (1)
  • Dashboard (14-658)
includes/Admin/Dashboard/Pages/ReverseWithdrawal.php (1)
  • ReverseWithdrawal (5-66)
src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1)
types/externals.d.ts (2)
  • Filter (60-60)
  • DataViews (59-59)
src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (1)
types/externals.d.ts (1)
  • DokanModal (65-65)
⏰ 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: e2e tests (3, 3)
  • GitHub Check: api tests (1, 1)
  • GitHub Check: e2e tests (1, 3)
  • GitHub Check: e2e tests (2, 3)
🔇 Additional comments (2)
src/admin/dashboard/pages/reverse-withdrawal/index.tsx (2)

17-58: Well-structured memoized component.

The StoreFilter component properly uses memo, useCallback, and useMemo to optimize re-renders. Good practice setting displayName for debugging.


276-345: Main page structure looks good.

The component structure, KPI cards, filters, and data grid are well-organized and follow good practices for layout and user interaction.

Comment on lines 161 to 188
{transectionType === 'manual_product' && (
<div>
<h3 className="text-base font-medium mb-3">
{__('Select Product', 'dokan-lite')}
</h3>
<ProductAsyncSelect
value={selectedProduct}
onChange={setSelectedProduct}
placeholder={__('Search', 'dokan-lite')}
isClearable
prefetch
extraQuery={{
...(vendorsData?.value ? { id: vendorsData.value } : {}),
post_status: 'publish',
}}
noOptionsMessage={() =>
!vendorsData
? __('Please select a vendor first', 'dokan-lite')
: __('No products found', 'dokan-lite')
}
/>
{errors.trId && (
<span className="text-red-500 text-sm mt-1 block">
{__('Please select a product', 'dokan-lite')}
</span>
)}
</div>
)}
Copy link
Contributor

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 the id parameter for vendor filtering.

The extraQuery passes id: vendorsData.value to filter products by vendor. Please verify that the API endpoint expects id as the vendor filter parameter (rather than vendor_id or seller_id).


🏁 Script executed:

#!/bin/bash
# Search for ProductAsyncSelect component definition and usage patterns
ast-grep --pattern 'ProductAsyncSelect'

# Search for product endpoint query parameter handling
rg -nP --type=ts --type=js -C3 'extraQuery.*vendor|extraQuery.*seller' -g '!node_modules'

Length of output: 562



---

🏁 Script executed:

```shell
#!/bin/bash
# Get the ProductAsyncSelect component implementation to understand its parameters
cat src/components/ProductAsyncSelect.tsx

Length of output: 10695


🏁 Script executed:

#!/bin/bash
# Get more context around the ProductAsyncSelect usage in AddReverseWithdrawModal
sed -n '160,190p' src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx

Length of output: 1334


🏁 Script executed:

#!/bin/bash
# Search for product API endpoint definitions to understand query parameters
rg -nP --type=ts --type=js -C2 'dokan.*product|endpoint.*product' -g '!node_modules' | head -50

Length of output: 3787


🏁 Script executed:

#!/bin/bash
# Search for where the product endpoint is called to see what parameters are expected
rg -nP --type=ts --type=js 'dokan/v1/products' -g '!node_modules' -C3

Length of output: 13014



---

🏁 Script executed:

```shell
#!/bin/bash
# Search for other usages of ProductAsyncSelect to see what extraQuery parameters they use
rg -nP --type=ts --type=js 'ProductAsyncSelect' -A 15 -g '!node_modules' | grep -A 15 'extraQuery'

Length of output: 5700


🏁 Script executed:

#!/bin/bash
# Search for REST API patterns with 'id' parameter used for vendor/seller filtering
rg -nP --type=ts --type=js '[\?&]id=' -C 2 -g '!node_modules' | head -60

Length of output: 486


🏁 Script executed:

#!/bin/bash
# Search for WordPress Dokan product query examples in backend or documentation
rg -nP --type=php --type=json 'seller_id|vendor_id' -C 2 -g '!node_modules' | head -40

Length of output: 3448


🏁 Script executed:

#!/bin/bash
# Search for how OrderAsyncSelect is called to see the extraQuery pattern for orders
rg -nP --type=ts --type=js 'OrderAsyncSelect' -A 15 -g '!node_modules' | grep -B 2 -A 10 'extraQuery'

Length of output: 5552


Change id to seller_id in ProductAsyncSelect extraQuery to match API expectations.

The extraQuery uses id: vendorsData.value to filter products by vendor, but the orders component on the same page correctly uses seller_id: vendorsData.value. The product API elsewhere in the codebase also filters by seller_id (see src/stores/vendors/resolvers.ts:46). This inconsistency will likely cause the product filtering to fail.

extraQuery={{
-   ...(vendorsData?.value ? { id: vendorsData.value } : {}),
+   ...(vendorsData?.value ? { seller_id: vendorsData.value } : {}),
    post_status: 'publish',
}}
📝 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
{transectionType === 'manual_product' && (
<div>
<h3 className="text-base font-medium mb-3">
{__('Select Product', 'dokan-lite')}
</h3>
<ProductAsyncSelect
value={selectedProduct}
onChange={setSelectedProduct}
placeholder={__('Search', 'dokan-lite')}
isClearable
prefetch
extraQuery={{
...(vendorsData?.value ? { id: vendorsData.value } : {}),
post_status: 'publish',
}}
noOptionsMessage={() =>
!vendorsData
? __('Please select a vendor first', 'dokan-lite')
: __('No products found', 'dokan-lite')
}
/>
{errors.trId && (
<span className="text-red-500 text-sm mt-1 block">
{__('Please select a product', 'dokan-lite')}
</span>
)}
</div>
)}
{transectionType === 'manual_product' && (
<div>
<h3 className="text-base font-medium mb-3">
{__('Select Product', 'dokan-lite')}
</h3>
<ProductAsyncSelect
value={selectedProduct}
onChange={setSelectedProduct}
placeholder={__('Search', 'dokan-lite')}
isClearable
prefetch
extraQuery={{
...(vendorsData?.value ? { seller_id: vendorsData.value } : {}),
post_status: 'publish',
}}
noOptionsMessage={() =>
!vendorsData
? __('Please select a vendor first', 'dokan-lite')
: __('No products found', 'dokan-lite')
}
/>
{errors.trId && (
<span className="text-red-500 text-sm mt-1 block">
{__('Please select a product', 'dokan-lite')}
</span>
)}
</div>
)}
🤖 Prompt for AI Agents
In src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx
around lines 161 to 188, the ProductAsyncSelect extraQuery uses id:
vendorsData.value which is inconsistent with the API and other components;
change the key from id to seller_id (i.e., use seller_id: vendorsData.value when
vendorsData?.value exists) so the products are correctly filtered by vendor,
leaving the rest of the extraQuery (post_status: 'publish') unchanged and
keeping the conditional presence check for vendorsData.

@akzmoudud akzmoudud force-pushed the new-reverse-withdrawal-react branch from cce4699 to 3228751 Compare November 8, 2025 07:22
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (7)
src/admin/dashboard/pages/reverse-withdrawal/index.tsx (2)

131-168: Update useCallback dependencies to include date parameters.

The fetchData function uses dateAfter and dateBefore from its closure (default parameter values on line 131) but doesn't include them in the dependency array on line 168. This causes stale closure issues where the callback won't update when the date values change.

Apply this diff:

-    }, [view.page, view.perPage, filterArgs]);
+    }, [view.page, view.perPage, filterArgs, dateAfter, dateBefore]);

192-268: Extract DateFilter as a separate component to avoid reconciliation issues.

Defining a component inside another component (even with useCallback) is an anti-pattern. When the parent re-renders and dependencies change, React creates a new component function, causing unmounts/remounts that lose internal state and break user interactions.

Move DateFilter outside ReverseWithdrawalPage as a standalone memoized component:

+const DateFilter = memo(({ dateAfter, dateAfterText, dateBefore, dateBeforeText, focusedInput, setDateAfter, setDateAfterText, setDateBefore, setDateBeforeText, setFocusedInput, fetchData }) => {
+    const [tempAfter, setTempAfter] = useState(dateAfter);
+    const [tempAfterText, setTempAfterText] = useState(dateAfterText);
+    const [tempBefore, setTempBefore] = useState(dateBefore);
+    const [tempBeforeText, setTempBeforeText] = useState(dateBeforeText);
+    const [tempFocused, setTempFocused] = useState(focusedInput);
+    
+    // ... rest of the component logic
+});
+
+DateFilter.displayName = 'DateFilter';
+
 const ReverseWithdrawalPage = () => {
     // ...
-    const DateFilter = useCallback(() => {
-        // ...
-    }, [dateAfter, dateAfterText, dateBefore, dateBeforeText, focusedInput, fetchData]);

Then pass props explicitly:

-        <DateFilter key="date_filter" />,
+        <DateFilter 
+            key="date_filter" 
+            dateAfter={dateAfter}
+            dateAfterText={dateAfterText}
+            dateBefore={dateBefore}
+            dateBeforeText={dateBeforeText}
+            focusedInput={focusedInput}
+            setDateAfter={setDateAfter}
+            setDateAfterText={setDateAfterText}
+            setDateBefore={setDateBefore}
+            setDateBeforeText={setDateBeforeText}
+            setFocusedInput={setFocusedInput}
+            fetchData={fetchData}
+        />,
src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (5)

8-8: Add missing onSave prop to enable page refresh.

The component only destructures open and onClose, dropping the onSave callback passed from the parent page. Without this, successful submissions don't trigger a data refresh, leaving the dashboard stale.

Apply this diff:

-const AddReverseWithdrawModal = ({ open, onClose }) => {
+const AddReverseWithdrawModal = ({ open, onClose, onSave }) => {

Then update the success handler (see comment on lines 69-86).


9-11: Fix typo: "transectionType" → "transactionType".

The state variable is consistently misspelled as "transectionType" instead of "transactionType" throughout the file.

Apply a global find-and-replace:

-    const [transectionType, setTransectionType] = useState<
+    const [transactionType, setTransactionType] = useState<
         'manual_product' | 'manual_order' | 'other'
     >('manual_product');

(Apply to all 12 occurrences in the file)


69-86: Improve error handling and remove debug code.

Multiple issues in this block:

  1. Missing onSave call: After successful POST, the callback isn't invoked, so the parent page never refreshes.
  2. Console.log in production: Debug logging should be removed (line 79).
  3. Silent error handling: Errors are re-thrown without user feedback, leaving the modal open with no indication of what failed.

Apply these fixes:

         try {
             const response = await apiFetch({
                 path: 'dokan/v1/reverse-withdrawal/transactions',
                 method: 'POST',
                 data: payload,
             });
 
             resetForm();
-            onClose();
-            console.log('Reverse withdrawal created successfully:', response);
+            onSave?.(response);
+            onClose();
         } catch (error) {
-            console.error('Error saving reverse withdrawal:', error);
-            throw error;
+            setErrors({ submit: __('Failed to create reverse withdrawal. Please try again.', 'dokan-lite') });
         } finally {
             setLoading(false);
         }

161-188: Change id to seller_id in ProductAsyncSelect extraQuery.

The ProductAsyncSelect uses id: vendorsData.value to filter products by vendor (line 173), but this is inconsistent with the OrderAsyncSelect on line 204 which correctly uses seller_id: vendorsData.value. The product API expects seller_id for vendor filtering.

Apply this diff:

 extraQuery={{
-    ...(vendorsData?.value ? { id: vendorsData.value } : {}),
+    ...(vendorsData?.value ? { seller_id: vendorsData.value } : {}),
     post_status: 'publish',
 }}

305-320: Fix dynamic height class for Tailwind JIT compatibility.

The template literal in the className on line 311 (h-[${transectionType === 'other' ? '718px' : '818px'}]) won't work with Tailwind JIT mode because the complete class names must be statically detectable at build time.

Apply this diff:

-            className={`w-full sm:w-[620px] max-w-[95%] h-[${transectionType === 'other' ? '718px' : '818px'}] max-h-[96vh] flex flex-col`}
+            className={`w-full sm:w-[620px] max-w-[95%] ${transectionType === 'other' ? 'h-[718px]' : 'h-[818px]'} max-h-[96vh] flex flex-col`}
🧹 Nitpick comments (1)
src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1)

182-189: Simplify memoizedSetFilterArgs or remove it.

The memoizedSetFilterArgs wrapper is unnecessary because setFilterArgs (from useState) is already stable. Additionally, both branches of the conditional execute identical code, making the condition redundant.

You can either:

  1. Remove the wrapper and pass setFilterArgs directly to StoreFilter
  2. Or simplify to just pass through the argument:
 const memoizedSetFilterArgs = useCallback((newArgs) => {
-    if (typeof newArgs === 'function') {
-        setFilterArgs(newArgs);
-    } else {
-        setFilterArgs(newArgs);
-    }
+    setFilterArgs(newArgs);
 }, []);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cce4699 and 3228751.

📒 Files selected for processing (5)
  • includes/Admin/Dashboard/Pages/ReverseWithdrawal.php (1 hunks)
  • includes/DependencyManagement/Providers/AdminDashboardServiceProvider.php (2 hunks)
  • src/admin/dashboard/components/Dashboard.tsx (2 hunks)
  • src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (1 hunks)
  • src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/admin/dashboard/components/Dashboard.tsx
  • includes/Admin/Dashboard/Pages/ReverseWithdrawal.php
🧰 Additional context used
🧬 Code graph analysis (3)
includes/DependencyManagement/Providers/AdminDashboardServiceProvider.php (2)
includes/Admin/Dashboard/Dashboard.php (1)
  • Dashboard (14-658)
includes/Admin/Dashboard/Pages/ReverseWithdrawal.php (1)
  • ReverseWithdrawal (5-66)
src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1)
types/externals.d.ts (2)
  • Filter (60-60)
  • DataViews (59-59)
src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (1)
types/externals.d.ts (1)
  • DokanModal (65-65)
⏰ 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: e2e tests (1, 3)
  • GitHub Check: api tests (1, 1)
  • GitHub Check: e2e tests (3, 3)
  • GitHub Check: e2e tests (2, 3)
🔇 Additional comments (14)
includes/DependencyManagement/Providers/AdminDashboardServiceProvider.php (2)

15-15: LGTM! Import follows the established pattern.

The import statement correctly references the new ReverseWithdrawal page class and follows the same pattern as other dashboard page imports.


43-43: LGTM! Service registration is correct.

The ReverseWithdrawal page is properly registered in the services array, allowing the Dashboard class to discover and integrate it into the admin dashboard menu and routing.

src/admin/dashboard/pages/reverse-withdrawal/index.tsx (6)

1-13: LGTM! Imports are appropriate.

All imports are properly used throughout the component and include necessary dependencies for the reverse withdrawal page functionality.


14-58: LGTM! Helper function and StoreFilter are well-structured.

The price helper is concise, and StoreFilter is properly extracted as a memoized component with appropriate use of useCallback and useMemo to prevent unnecessary re-renders.


60-89: LGTM! State management is comprehensive.

The state structure appropriately covers all aspects of the page including statistics, data grid state, filters, and modal visibility.


91-129: LGTM! Field definitions are properly memoized.

The field configurations are well-structured with custom renderers, and the date field includes appropriate validation before formatting.


170-180: LGTM! Effect and modal handler are properly structured.

The useEffect correctly triggers initial data fetch, and handleModalSave appropriately refreshes data after successful submission.


276-345: LGTM! Component render structure is well-organized.

The JSX layout effectively presents the page header, KPI cards, filter controls, data grid, and modal integration with appropriate conditional rendering.

src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (6)

1-6: LGTM! Imports are appropriate.

All necessary dependencies are imported for the modal functionality.


21-48: LGTM! Validation logic is comprehensive.

The validation covers all required fields with appropriate conditional checks based on transaction type.


50-67: LGTM! Payload construction is correct.

The payload properly maps form state to API requirements, including conditional trn_id and appropriate debit/credit formatting.


88-118: LGTM! Form handlers are well-structured.

Reset and change handlers appropriately manage form state, including clearing dependent selections when vendors or transaction types change.


120-136: LGTM! Vendor selection UI is properly configured.

The vendor selector includes appropriate prefetch, clearable options, and error feedback.


225-302: LGTM! Form fields are well-structured.

The withdrawal type selector, amount input, and notes textarea include appropriate validation feedback and user-friendly UI elements like the currency prefix and info tooltips.

This was referenced Nov 13, 2025
* enhance: update admin data-table ui.

* enhance: update reverse withdrawal's code.

* enhance: update reverse withdrawal modal UI styles.

* enhance: improve reverse withdrawal UI and functionality with updated styles and layout.

* enhance: add support for reverse withdrawal, update texts, and clean up unused code
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1)

160-161: Consider logging fetch errors for debugging.

The empty catch block silently suppresses errors. While setting empty data is a reasonable fallback, logging would help diagnose API issues.

-        } catch {
+        } catch (error) {
+            console.error('Failed to fetch reverse withdrawal data:', error);
             setData( [] );
         } finally {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3228751 and 0c02723.

📒 Files selected for processing (6)
  • includes/Admin/Dashboard/Pages/ReverseWithdrawal.php (1 hunks)
  • src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (1 hunks)
  • src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1 hunks)
  • src/admin/dashboard/style.scss (1 hunks)
  • src/admin/panel-switcher/PanelSwitch.tsx (1 hunks)
  • src/components/dataviews/AdminDataViewTable.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • includes/Admin/Dashboard/Pages/ReverseWithdrawal.php
🧰 Additional context used
🧬 Code graph analysis (2)
src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (1)
types/externals.d.ts (1)
  • DokanModal (65-65)
src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1)
types/externals.d.ts (1)
  • DataViews (59-59)
⏰ 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: e2e tests (3, 3)
  • GitHub Check: api tests (1, 1)
  • GitHub Check: e2e tests (2, 3)
  • GitHub Check: e2e tests (1, 3)
🔇 Additional comments (4)
src/components/dataviews/AdminDataViewTable.tsx (1)

216-220: LGTM!

The conditional header rendering is clean and properly guarded with a null check. The placement above the tabs is logical for presenting page-level context.

src/admin/panel-switcher/PanelSwitch.tsx (1)

17-24: LGTM!

Adding 'reverse-withdrawal' to the supported keys aligns with the new admin page being introduced. The change follows the established pattern.

src/admin/dashboard/style.scss (1)

72-88: LGTM!

The styling adjustments for the reverse withdrawal data view are isolated and appropriate. The 75% width allocation for the first column and border removal for the first tab button are reasonable layout choices.

src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1)

94-104: Empty string in fields array may not be ideal but behavior is unclear without library verification.

The pattern you've flagged exists consistently across multiple pages (reverse-withdrawal, withdraw, and RequestList), not just this file. However, vendors.tsx uses a different approach with a static array that doesn't include the titleField at all.

The empty string approach may be silently handled by the WordPress DataViews library or could potentially cause issues. Since the DataViews component is from an external library (@wordpress/dataviews/wp), its behavior with empty strings cannot be verified from the codebase alone.

The cleaner approach would match vendors.tsx—using filter() instead of mapping to empty strings—but this requires confirmation that it won't break existing functionality.

Please verify:

  1. Test if empty strings in the fields array cause any rendering or data issues in the current implementation
  2. If no issues exist, the pattern is acceptable but inconsistent with vendors.tsx; consider documenting why this page uses dynamic mapping vs. static arrays
  3. If issues exist, align with the vendors.tsx pattern using filter() instead

@akzmoudud akzmoudud added Needs: Testing This requires further testing Needs: Dev Review It requires a developer review and approval labels Nov 14, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (4)
src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (4)

15-15: Hook modal success so the page refreshes.

The component signature still doesn't accept an onSave callback, so after a successful POST the parent page cannot refresh its data. This was flagged in previous reviews.


16-18: Fix typo: "transectionType" → "transactionType".

The state variable remains misspelled throughout the file. This was flagged in previous reviews.


93-95: Improve error handling for better UX.

The catch block re-throws the error without providing user feedback, leaving the modal open with no indication of what went wrong. This was flagged in previous reviews.


232-237: Change id to seller_id in ProductAsyncSelect extraQuery.

Line 234 uses id: vendorsData.value while the OrderAsyncSelect correctly uses seller_id: vendorsData.value on line 271. This inconsistency was flagged in previous reviews.

🧹 Nitpick comments (1)
src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (1)

47-49: Consider validating amount is a positive number.

The validation only checks if withdrawalAmount is truthy, but doesn't verify it's a valid positive number. This could allow invalid values like negative numbers or non-numeric strings to be submitted.

Apply this diff to add number validation:

     if ( ! withdrawalAmount ) {
         newErrors.withdrawalAmount = true;
+    } else if ( isNaN( Number( withdrawalAmount ) ) || Number( withdrawalAmount ) <= 0 ) {
+        newErrors.withdrawalAmount = true;
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0c02723 and fa5cba6.

📒 Files selected for processing (2)
  • src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (1 hunks)
  • src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/admin/dashboard/pages/reverse-withdrawal/index.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-19T06:19:41.376Z
Learnt from: mrabbani
Repo: getdokan/dokan PR: 2891
File: src/admin/dashboard/pages/vendors-single/InformationTabs/WithdrawTab.tsx:58-59
Timestamp: 2025-09-19T06:19:41.376Z
Learning: The Dokan codebase uses 'dokan-lite' as the text domain for WordPress internationalization (__() function calls).

Applied to files:

  • src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx
🧬 Code graph analysis (1)
src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (1)
types/externals.d.ts (1)
  • DokanModal (65-65)
⏰ 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: api tests (1, 1)
  • GitHub Check: e2e tests (3, 3)
  • GitHub Check: e2e tests (1, 3)
  • GitHub Check: e2e tests (2, 3)
🔇 Additional comments (1)
src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (1)

423-437: LGTM! Modal setup is correct.

The DokanModal is properly configured with all necessary props, and the className concatenation is handled correctly.

@mrabbani mrabbani added Dev Review Done and removed Needs: Dev Review It requires a developer review and approval labels Nov 17, 2025
@shohan0120
Copy link
Contributor

shohan0120 commented Nov 19, 2025

Please Check these bugs:
Bug 1
Bug 2

CC: @getdokan/product-plugin-team , @mrabbani vai

@shohan0120 shohan0120 removed Needs: Testing This requires further testing QA In Progress labels Nov 19, 2025
@shohan0120 shohan0120 added the Needs: Testing This requires further testing label Nov 19, 2025
* feat: Add new Reverse Withdrawal Transaction page with filters, stats, and routing integration

* refactor: Move reverse withdrawal creation logic to AddReverseWithdrawModal component
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (2)
src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (2)

26-28: Rename transectionTypetransactionType for clarity

The state and related handlers are consistently misspelled as transectionType. This hurts readability and can be confusing long‑term.

A simple find‑and‑replace to transactionType / setTransactionType would clarify intent.

Also applies to: 141-147, 217-238


41-68: Handle API errors in the modal instead of just logging and re‑throwing

On failure, the catch block only logs to the console and re‑throws. The modal stays open but the user receives no feedback and the thrown error may bubble in unexpected ways.

Recommend:

  • Remove the console.log (no console.* in production code).
  • Capture the error into component state (e.g., errors.submit) or trigger a global toast/notice so the user sees a clear message.
  • Do not re‑throw from here; rely on the UI error path instead.

Also applies to: 86-115

🧹 Nitpick comments (6)
src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (3)

153-161: Debounced amount state can be stale at submit time

DokanPriceInput’s onChange feeds a 500 ms‑debounced debouncedWithdrawAmount, and both the displayed value and the payload (withdrawalAmountRaw) come from that debounced state. If an admin edits the amount and immediately clicks “Add New”, you may post the previous amount.

Consider keeping a non‑debounced state for the actual submitted value (and optionally debounce only any heavy side‑effects), or drop the debounce if it isn’t needed.

Also applies to: 382-417


382-417: Avoid hard‑coded $ currency symbol

The amount input overlays a literal $ prefix while also using DokanPriceInput, which is already currency‑aware. This can:

  • Show the wrong symbol in non‑USD stores.
  • Potentially duplicate the symbol if DokanPriceInput renders one.

Prefer pulling the symbol from the store settings (or letting DokanPriceInput handle it) instead of hard‑coding $.

If DokanPriceInput already renders the store currency symbol, remove the manual $ span to avoid duplication.


39-40: Strongly type errors for better safety

errors is initialized as a bare {} and later accessed with properties like errors.vendorId, errors.trId, etc. Without an explicit type, this bypasses TypeScript’s safety and can hide typos in error keys.

Defining an interface, e.g.:

type FormErrors = {
    vendorId?: boolean;
    trId?: boolean;
    withdrawalAmount?: boolean;
    withdrawalNote?: boolean;
    submit?: string;
};

const [ errors, setErrors ] = useState<FormErrors>( {} );

would make access and updates much safer.

Also applies to: 118-128

src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx (1)

171-180: Consider server‑side pagination instead of per_page: -1

The transactions fetch uses per_page: -1 and then sets paginationInfo={{ totalItems, totalPages: 1 }}. For vendors with many transactions, this can become a heavy request and slow UI.

If the API supports it, consider:

  • Using per_page: view.perPage and a real totalPages from headers or data length.
  • Wiring view.page into queryArgs and paginationInfo.

This would keep the UI responsive on large datasets.

Also applies to: 487-488

src/admin/dashboard/pages/reverse-withdrawal/index.tsx (2)

201-332: Optional: actually memoize filterFields to avoid recreating inline components

filterFields is re‑declared on every render, and each field contains inline JSX with closures over component state. The comment says “Memoize filter fields,” but no useMemo is used.

This is not a correctness bug, but you could wrap it in useMemo with appropriate deps (date/vender/filter state) to reduce unnecessary recalculations and avoid potential re‑mounts if the DataViews implementation compares fields by reference.


430-438: Confirm that closing the modal only on success matches desired UX

onCreated both closes the modal and triggers fetchData, while onClose simply hides it. If the POST fails inside the modal, onCreated is never called and the modal remains open (which is good), but combined with the current modal error handling (no user‑visible error from the child), admins may not realize something went wrong.

Once AddReverseWithdrawModal surfaces a clear error, this pattern is fine; otherwise, consider also showing a toast here when onCreated is not invoked due to failure.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fa5cba6 and a1f60b8.

📒 Files selected for processing (5)
  • src/admin/dashboard/components/Dashboard.tsx (2 hunks)
  • src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (1 hunks)
  • src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx (1 hunks)
  • src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1 hunks)
  • src/admin/dashboard/style.scss (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/admin/dashboard/style.scss
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-19T06:19:41.376Z
Learnt from: mrabbani
Repo: getdokan/dokan PR: 2891
File: src/admin/dashboard/pages/vendors-single/InformationTabs/WithdrawTab.tsx:58-59
Timestamp: 2025-09-19T06:19:41.376Z
Learning: The Dokan codebase uses 'dokan-lite' as the text domain for WordPress internationalization (__() function calls).

Applied to files:

  • src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx
🧬 Code graph analysis (3)
src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (1)
types/externals.d.ts (1)
  • DokanModal (65-65)
src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx (1)
types/externals.d.ts (1)
  • DataViews (59-59)
src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1)
types/externals.d.ts (1)
  • DataViews (59-59)
🪛 Biome (2.1.2)
src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx

[error] 248-248: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 250-250: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 254-254: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 255-255: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

⏰ 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: e2e tests (2, 3)
  • GitHub Check: e2e tests (3, 3)
  • GitHub Check: e2e tests (1, 3)
  • GitHub Check: api tests (1, 1)
🔇 Additional comments (1)
src/admin/dashboard/components/Dashboard.tsx (1)

13-15: The review comment is incorrect—the import path is valid and will resolve properly.

The 'admin' alias is configured in tsconfig.json as "admin/*": ["./src/admin/*"], and the file ./src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx exists at the exact location the alias resolves to. While the import style is inconsistent with the relative path on the line above, it is functionally correct and will not fail.

No changes are required.

Likely an incorrect or invalid review comment.

Comment on lines +17 to +25
const AddReverseWithdrawModal = ( {
open,
onClose,
onCreated,
}: {
open: boolean;
onClose: () => void;
onCreated?: ( args?: any ) => void;
} ) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Guard optional onCreated before calling

onCreated is typed as optional but is invoked unconditionally in handleConfirm. If this modal is ever used without an onCreated prop, it will throw at runtime.

Consider guarding the call:

-            onCreated( { payload } );
+            onCreated?.( { payload } );

Also applies to: 104-106

🤖 Prompt for AI Agents
In src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx
around lines 17-25 (and also apply to the call sites at lines 104-106), the prop
onCreated is declared optional but is invoked unconditionally; update the
implementation to guard the call by checking the existence of onCreated before
invoking it (e.g., use if (onCreated) onCreated(...) or onCreated?.(...)) at
each call site so the modal does not throw when onCreated is not supplied.

Comment on lines +248 to +267
{ transectionType === 'manual_product' && (
<div className="space-y-2.5">
{ /* eslint-disable-next-line jsx-a11y/label-has-associated-control */ }
<label className="text-[#25252D] font-medium text-sm">
{ __( 'Select Product', 'dokan-lite' ) }
</label>
<ProductAsyncSelect
value={ selectedProduct }
onChange={ setSelectedProduct }
placeholder={ __( 'Search', 'dokan-lite' ) }
isClearable
prefetch
extraQuery={ {
...( vendorsData?.value && {
author: vendorsData.value,
} ),
post_status: 'publish',
} }
disabled={ ! vendorsData }
className={ '!rounded-lg' }
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Verify correct vendor filter key for ProductAsyncSelect (author vs seller_id)

The product selector sends extraQuery={{ ...(vendorsData?.value && { author: vendorsData.value }), post_status: 'publish' }}. Other reverse‑withdrawal endpoints use vendor_id / seller_id (e.g., the order selector just below uses seller_id).

Please confirm that the products endpoint actually expects author here; if it instead expects something like seller_id or vendor_id, product filtering by vendor will silently fail.

Would you run a quick search in this repo for other ProductAsyncSelect usages and for the dokan/v1/products endpoint to confirm which query key is used for vendor filtering?



---

🏁 Script executed:

```shell
#!/bin/bash
# Search for all ProductAsyncSelect usages to see which query parameters are used
rg -n "ProductAsyncSelect" --type=tsx --type=ts -A 10 | head -100

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Search for the dokan products endpoint handler
rg -n "dokan/v1/products" --type=php --type=ts --type=tsx -B 2 -A 5 | head -100

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Search for "seller_id" to see how it's used in similar contexts
rg -n "seller_id" --type=tsx --type=ts -B 2 -A 2 | head -80

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Search for the order selector in the same file to see how it filters
rg -n "OrderAsyncSelect\|seller_id.*post_status" src/admin/dashboard/pages/reverse-withdrawal/ --type=tsx -B 3 -A 3

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Look for ProductAsyncSelect component definition
fd "ProductAsyncSelect" --type=tsx --type=ts --exec cat {} \;

Length of output: 170



---

🏁 Script executed:

```shell
#!/bin/bash
# Search for ProductAsyncSelect usage without strict type filter
rg -n "ProductAsyncSelect" -A 12 src/ 2>/dev/null | head -120

Length of output: 7369


🏁 Script executed:

#!/bin/bash
# Search for seller_id usage in src directory
rg -n "seller_id" -B 2 -A 2 src/ 2>/dev/null | head -100

Length of output: 3565


🏁 Script executed:

#!/bin/bash
# Find all files with ProductAsyncSelect in src
fd -e js -e ts -e jsx -e tsx "^ProductAsyncSelect" src/ 2>/dev/null

Length of output: 37


🏁 Script executed:

#!/bin/bash
# Look for the AddReverseWithdrawModal file directly and check context
cat src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx 2>/dev/null | head -300

Length of output: 11375


🏁 Script executed:

#!/bin/bash
# Search for dokan products endpoint references
rg -n "products.*endpoint\|dokan.*products\|extraQuery" src/ 2>/dev/null | head -80

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for OrderAsyncSelect to compare filter patterns
rg -n "OrderAsyncSelect" -A 8 src/ 2>/dev/null

Length of output: 5209



---

🏁 Script executed:

```shell
#!/bin/bash
# Look at ProductAsyncSelect.tsx to see how queries are constructed
cat src/components/ProductAsyncSelect.tsx

Length of output: 10760


🏁 Script executed:

#!/bin/bash
# Get the complete AddReverseWithdrawModal.tsx to see OrderAsyncSelect full config
cat src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx | tail -150

Length of output: 7042


🏁 Script executed:

#!/bin/bash
# Search for any dokan/v2/products references or products endpoint handlers
rg -n "dokan/v2/products\|/products.*extraQuery\|author.*product" src/ 2>/dev/null | head -50

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for WordPress REST API product query parameter handling
rg -n "author.*query\|WP_Query.*author" --type=php 2>/dev/null | head -30

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search in entire codebase for "author" usage in extraQuery contexts
rg -n "extraQuery.*author\|author.*extraQuery" 2>/dev/null

Length of output: 0



---

🏁 Script executed:

```shell
#!/bin/bash
# Search for backend/PHP files that might define products endpoint
fd -e php --max-depth 5 "routes\|products" . 2>/dev/null | head -20

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for any dokan routes or API handler files
find . -name "*.php" -path "*routes*" -o -name "*.php" -path "*api*" 2>/dev/null | head -20

Length of output: 33


🏁 Script executed:

#!/bin/bash
# Check if there are test files showing correct parameters
rg -l "seller_id.*product\|product.*seller_id" --type=php 2>/dev/null | head -10

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for all places where the /dokan/v2/products endpoint is referenced or tested
rg -n "v2/products\|v1/products" . 2>/dev/null | head -40

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check for README or documentation about API parameters
fd -e md -e txt "README\|CHANGELOG\|API\|api" . 2>/dev/null | xargs grep -l "seller_id\|author" 2>/dev/null | head -10

Length of output: 0


Fix ProductAsyncSelect vendor filter parameter from author to seller_id

Line 262 uses incorrect parameter name: author: vendorsData.value should be seller_id: vendorsData.value. The OrderAsyncSelect immediately below (line 302) correctly uses seller_id, and other product endpoint calls in the codebase (e.g., src/stores/vendors/resolvers.ts:46) also use seller_id. Using author will silently fail to filter products by vendor.

🤖 Prompt for AI Agents
In src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx
around lines 248 to 267, the ProductAsyncSelect extraQuery uses the wrong vendor
filter key (`author: vendorsData.value`) which fails to filter products; change
that key to `seller_id: vendorsData.value` to match the OrderAsyncSelect and
other product endpoint usages, ensuring the vendor filter is applied when
vendorsData is present.

Comment on lines +118 to +129
const fetchData = useCallback( async () => {
setData( [] );
setTotalItems( 0 );
setIsLoading( true );
try {
const queryArgs = {
per_page: view.perPage,
page: view.page,
orderby: ( view as any )?.sort?.field || 'added',
order: ( view as any )?.sort?.direction || 'desc',
...filterArgs,
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Update fetchData dependencies so sort changes trigger refetch

fetchData builds orderby and order from view.sort, but the dependency array only includes view.page, view.perPage, and filterArgs. If the user changes sort without changing page/perPage, the closure will still use the old sort and useEffect won’t re‑run.

Consider:

-    }, [ view.page, view.perPage, filterArgs ] );
+    }, [ view, filterArgs ] );

(or add view.sort explicitly) so any sort change results in a new request and consistent data.

Also applies to: 164-168, 399-413

🤖 Prompt for AI Agents
In src/admin/dashboard/pages/reverse-withdrawal/index.tsx around lines 118-129
(and similarly at 164-168 and 399-413), fetchData reads orderby/order from
view.sort but the effect/dependencies omit view.sort so sort changes don’t
trigger a refetch; update the dependency arrays (or the useCallback
dependencies) to include view.sort (or view.sort.field and view.sort.direction)
so changes to sort cause fetchData to be recreated and the useEffect to re-run,
ensuring the request uses the current sort values.

Comment on lines 161 to 181
const fetchTransactions = useCallback( async () => {
if ( ! vendorId ) {
return;
}

// Don't fetch until initialization is complete
if ( ! isInitialized ) {
return;
}

setIsLoading( true );
setData( [] );
try {
const queryArgs: any = {
orderby: ( view as any )?.sort?.field || 'added',
order: ( view as any )?.sort?.direction || 'desc',
vendor_id: vendorId,
per_page: -1,
...filterArgs,
};

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Include view sort in fetchTransactions dependencies so sorting works correctly

fetchTransactions reads view.sort.field and view.sort.direction from closure, but the hook’s dependency array only includes view.page, view.perPage, filterArgs, and isInitialized. If the user changes sort without changing page/perPage, the callback won’t update and the API will still use the previous sort.

Safer to depend on the full view object (or at least view.sort) so sort changes trigger a new fetch:

-    }, [ vendorId, view.page, view.perPage, filterArgs, isInitialized ] );
+    }, [ vendorId, view, filterArgs, isInitialized ] );

(or add view.sort explicitly if you want to be more granular).

Also applies to: 211-241, 481-515

Comment on lines 243 to 267
const clearSingleFilter = ( filterId ) => {
const args = { ...filterArgs };
switch ( filterId ) {
case 'date-range':
// Reset to default 30 days window like Vue
const end = new Date();
end.setHours( 23, 59, 59, 0 );
const start = new Date();
start.setDate( start.getDate() - 29 );
start.setHours( 0, 0, 0, 0 );

const from = dateI18n( 'Y-m-d H:i:s', start );
const to = dateI18n( 'Y-m-d H:i:s', end );

setDateAfter( start );
setDateAfterText( from );
setDateBefore( end );
setDateBeforeText( to );
args.trn_date = { from, to };
break;
default:
break;
}
setFilterArgs( args );
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Wrap case 'date-range' declarations in a block to fix noSwitchDeclarations lint error

The case 'date-range' branch declares const end, const start, const from, and const to directly in the switch. Biome flags this (noSwitchDeclarations) because those bindings are in scope for all subsequent cases.

Wrap the case body in a block:

-        switch ( filterId ) {
-            case 'date-range':
-                // Reset to default 30 days window like Vue
-                const end = new Date();
-                end.setHours( 23, 59, 59, 0 );
-                const start = new Date();
-                start.setDate( start.getDate() - 29 );
-                start.setHours( 0, 0, 0, 0 );
-
-                const from = dateI18n( 'Y-m-d H:i:s', start );
-                const to = dateI18n( 'Y-m-d H:i:s', end );
-
-                setDateAfter( start );
-                setDateAfterText( from );
-                setDateBefore( end );
-                setDateBeforeText( to );
-                args.trn_date = { from, to };
-                break;
+        switch ( filterId ) {
+            case 'date-range': {
+                // Reset to default 30 days window like Vue
+                const end = new Date();
+                end.setHours( 23, 59, 59, 0 );
+                const start = new Date();
+                start.setDate( start.getDate() - 29 );
+                start.setHours( 0, 0, 0, 0 );
+
+                const from = dateI18n( 'Y-m-d H:i:s', start );
+                const to = dateI18n( 'Y-m-d H:i:s', end );
+
+                setDateAfter( start );
+                setDateAfterText( from );
+                setDateBefore( end );
+                setDateBeforeText( to );
+                args.trn_date = { from, to };
+                break;
+            }
             default:
                 break;
         }
📝 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 clearSingleFilter = ( filterId ) => {
const args = { ...filterArgs };
switch ( filterId ) {
case 'date-range':
// Reset to default 30 days window like Vue
const end = new Date();
end.setHours( 23, 59, 59, 0 );
const start = new Date();
start.setDate( start.getDate() - 29 );
start.setHours( 0, 0, 0, 0 );
const from = dateI18n( 'Y-m-d H:i:s', start );
const to = dateI18n( 'Y-m-d H:i:s', end );
setDateAfter( start );
setDateAfterText( from );
setDateBefore( end );
setDateBeforeText( to );
args.trn_date = { from, to };
break;
default:
break;
}
setFilterArgs( args );
};
const clearSingleFilter = ( filterId ) => {
const args = { ...filterArgs };
switch ( filterId ) {
case 'date-range': {
// Reset to default 30 days window like Vue
const end = new Date();
end.setHours( 23, 59, 59, 0 );
const start = new Date();
start.setDate( start.getDate() - 29 );
start.setHours( 0, 0, 0, 0 );
const from = dateI18n( 'Y-m-d H:i:s', start );
const to = dateI18n( 'Y-m-d H:i:s', end );
setDateAfter( start );
setDateAfterText( from );
setDateBefore( end );
setDateBeforeText( to );
args.trn_date = { from, to };
break;
}
default:
break;
}
setFilterArgs( args );
};
🧰 Tools
🪛 Biome (2.1.2)

[error] 248-248: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 250-250: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 254-254: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 255-255: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

🤖 Prompt for AI Agents
In src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx
around lines 243 to 267, the declarations inside the case 'date-range' (const
end, start, from, to) are made directly in the switch and trigger the
noSwitchDeclarations lint error; wrap the entire case 'date-range' body in its
own block ({ ... }) so those const bindings are scoped to that case only,
leaving the rest of the switch unchanged and keeping the setFilterArgs(args)
call after the switch.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx (1)

180-225: Include full view (or at least view.sort) in fetchTransactions dependencies so sorting works correctly

fetchTransactions builds orderby/order from view.sort:

const queryArgs: any = {
    orderby: ( view as any )?.sort?.field || 'added',
    order: ( view as any )?.sort?.direction || 'desc',
    vendor_id: vendorId,
    per_page: -1,
    ...filterArgs,
};

but the hook dependencies only include view.page, view.perPage, and filterArgs. If the user changes sort without changing page/perPage, the closure keeps using the old sort and the effect won’t re‑run, so the table doesn’t actually resort on the server.

Updating the deps to include the sort state fixes this:

-    }, [ vendorId, view.page, view.perPage, filterArgs ] );
+    }, [ vendorId, view, filterArgs ] );

(or depend specifically on view.sort if you want to be more granular).

src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1)

117-167: Update fetchData dependencies so sort changes (and other view changes) trigger a refetch

fetchData constructs query args using view.sort.field/view.sort.direction:

const queryArgs = {
    per_page: view.perPage,
    page: view.page,
    orderby: ( view as any )?.sort?.field || 'added',
    order: ( view as any )?.sort?.direction || 'desc',
    ...filterArgs,
};

but the useCallback only depends on view.page, view.perPage, and filterArgs. If the user adjusts sorting without changing page/perPage, the request will still use the previous sort and the effect watching fetchData won’t fire.

Safer to depend on the full view object (or at least view.sort) so any sort or layout change is reflected:

-    }, [ view.page, view.perPage, filterArgs ] );
+    }, [ view, filterArgs ] );

This keeps the backend data consistent with the current table view.

🧹 Nitpick comments (1)
includes/REST/ReverseWithdrawalController.php (1)

230-246: Verify new trn_date defaulting semantics and avoid surprising changes for partial ranges

Controller now always normalizes trn_date:

$default_transaction_date = Helper::get_default_transaction_date();
$request_params           = $request->get_params();
// ...
$request_params['trn_date'] = [
    'from' => $request_params['trn_date']['from'] ?? $default_transaction_date['from'],
    'to'   => $request_params['trn_date']['to'] ?? $default_transaction_date['to'],
];

and the route schema marks trn_date as optional with nested defaults.

This is good for the new UI (it can omit trn_date entirely and still get a sane last‑X‑days window), but it also subtly changes API behavior for callers that previously sent only a from or only a to date – those now get the default on the missing side instead of an open‑ended range.

If open‑ended ranges should remain supported for API consumers, consider only applying the defaults when trn_date is absent or both from and to are empty, e.g.:

-        // Set default trn_date if not set.
-        $request_params['trn_date'] = [
-            'from' => $request_params['trn_date']['from'] ?? $default_transaction_date['from'],
-            'to'   => $request_params['trn_date']['to'] ?? $default_transaction_date['to'],
-        ];
+        // Set default trn_date only when no bounds are provided.
+        if (
+            empty( $request_params['trn_date']['from'] )
+            && empty( $request_params['trn_date']['to'] )
+        ) {
+            $request_params['trn_date'] = $default_transaction_date;
+        }

If the intent is to always clamp to a bounded range for this endpoint, then this change looks fine but should be called out explicitly in API/feature docs so consumers know open‑ended ranges are no longer possible.

Also applies to: 633-671

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a1f60b8 and f1bb86d.

📒 Files selected for processing (3)
  • includes/REST/ReverseWithdrawalController.php (2 hunks)
  • src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx (1 hunks)
  • src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1)
types/externals.d.ts (1)
  • DataViews (59-59)
src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx (1)
types/externals.d.ts (1)
  • DataViews (59-59)
includes/REST/ReverseWithdrawalController.php (3)
includes/ReverseWithdrawal/Helper.php (2)
  • Helper (18-778)
  • get_default_transaction_date (344-349)
includes/ReverseWithdrawal/Manager.php (1)
  • Manager (20-789)
includes/functions.php (1)
  • dokan_get_current_user_id (48-61)
⏰ 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: e2e tests (2, 3)
  • GitHub Check: api tests (1, 1)
  • GitHub Check: e2e tests (1, 3)
  • GitHub Check: e2e tests (3, 3)

@shohan0120
Copy link
Contributor

Please Check this Bug
@MdAsifHossainNadim vai
CC: @getdokan/product-plugin-team , @mrabbani vai

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1)

118-168: Ensure sort changes trigger data refetch in fetchData

fetchData builds orderby/order from view.sort, but the hook’s dependency array only includes view.page, view.perPage, and filterArgs. Changing sort alone won’t recreate fetchData or re-run the effect, so the API keeps using stale sort values.

Consider depending on the full view (or at least view.sort) so sort changes refetch data:

-    }, [ view.page, view.perPage, filterArgs ] );
+    }, [ view, filterArgs ] );

This keeps behaviour for page/perPage while making sort reactive.

src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx (1)

181-226: Include view sort in fetchTransactions dependencies to avoid stale sorting

fetchTransactions reads view.sort.field / view.sort.direction but the dependency array only includes vendorId, view.page, view.perPage, and filterArgs. Sort changes won’t recreate the callback or trigger the effect, so the API keeps using the previous sort.

Update dependencies so sort changes refetch:

-    }, [ vendorId, view.page, view.perPage, filterArgs ] );
+    }, [ vendorId, view, filterArgs ] );

This also removes unused deps (view.page/view.perPage aren’t used in the query).

🧹 Nitpick comments (2)
src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1)

210-323: Align filterFields implementation with the “memoize” intent

The comment says “Memoize filter fields to prevent recreation”, but filterFields is a plain array literal, so it’s rebuilt on every render (including the inline VendorAsyncSelect and DateRangePicker elements).

Either remove/adjust the comment, or actually memoize:

-import DateRangePicker from '@src/components/DateRangePicker';
+import DateRangePicker from '@src/components/DateRangePicker';
@@
-    // Memoize filter fields to prevent recreation
-    const filterFields = [
+    // Memoize filter fields to avoid unnecessary re-renders
+    const filterFields = useMemo(
+        () => [
         {
             id: 'vendor',
@@
         {
             id: 'date-range',
@@
-        },
-    ];
+        },
+    ], [
+        vendorFilter,
+        filterArgs,
+        dateAfter,
+        dateAfterText,
+        dateBefore,
+        dateBeforeText,
+        focusedInput,
+    ] );

(You’d also need to import useMemo from @wordpress/element.)

src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx (1)

302-400: Consider extracting a shared date‑range filter abstraction

The DateRangePicker + SimpleInput + trn_date wiring here is almost identical to the date‑range filter in reverse-withdrawal/index.tsx. Duplicating this logic in two pages makes future fixes (formatting, default ranges, edge cases) harder.

Consider extracting a small shared helper (component or hook) that encapsulates:

  • Local date state mapping (after/before, text, focusedInput)
  • Building/clearing trn_date inside filterArgs
  • Display formatting via displayDateRange

Then use it in both pages to keep behaviour consistent.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f1bb86d and 795c9ef.

📒 Files selected for processing (4)
  • src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx (1 hunks)
  • src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx (1 hunks)
  • src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1 hunks)
  • src/components/modals/DokanModal.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/admin/dashboard/pages/reverse-withdrawal/AddReverseWithdrawModal.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx (1)
types/externals.d.ts (1)
  • DataViews (59-59)
src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1)
types/externals.d.ts (1)
  • DataViews (59-59)
⏰ 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: api tests (1, 1)
  • GitHub Check: e2e tests (3, 3)
  • GitHub Check: e2e tests (2, 3)
  • GitHub Check: e2e tests (1, 3)
🔇 Additional comments (3)
src/components/modals/DokanModal.tsx (1)

35-36: Confirm button disable flag is correctly integrated

confirmButtonDisabled is added to the props, defaulted to false, and correctly combined with isSubmitting/loading in the confirm button’s disabled and loading behaviour. No functional or API regression concerns from this change.

Also applies to: 61-62, 225-229

src/admin/dashboard/pages/reverse-withdrawal/index.tsx (1)

348-419: Overall DataViews wiring looks consistent

Header, stats cards, and DataViews configuration (namespace, pagination, filters, tabs, and onChangeView) are wired coherently and match the rest of the page state shape. No blocking issues spotted in this section.

src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx (1)

260-465: Transactions page layout and DataViews integration look solid

Header/back button, info cards, and DataViews setup (namespace, fields, filters, tabs, pagination) form a coherent transactions view and align with the reverse‑withdrawal list page patterns. No additional functional issues spotted here beyond the fetchTransactions dependency concern already noted.

@shohan0120
Copy link
Contributor

Please Check this Bug
@MdAsifHossainNadim vai
CC: @getdokan/product-plugin-team , @mrabbani vai

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx (1)

181-226: Include view.sort in dependencies to ensure sorting works correctly.

This is a continuation of the previous review comment. The fetchTransactions callback reads view.sort.field and view.sort.direction (lines 190-191) but only depends on [vendorId, view.page, view.perPage, filterArgs]. When the user changes sort order without changing page or perPage, the callback won't update and will continue using stale sort values.

-    }, [ vendorId, view.page, view.perPage, filterArgs ] );
+    }, [ vendorId, view.page, view.perPage, view.sort, filterArgs ] );

Alternatively, depend on the entire view object if you prefer:

-    }, [ vendorId, view.page, view.perPage, filterArgs ] );
+    }, [ vendorId, view, filterArgs ] );

Additional concern: Lines 189-191 use type assertions (as any) that bypass TypeScript's type checking. Consider defining a proper type for the view state or using the correct type from the DataViews library.

🧹 Nitpick comments (2)
src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx (2)

86-137: Extract common monetary value rendering logic to reduce duplication.

The render functions for debit, credit, and balance fields share nearly identical logic (empty check, parseFloat, NaN check, negative value handling). This duplication increases maintenance burden and risk of inconsistency.

Consider extracting a shared helper:

+const renderMonetaryValue = ( value ) => {
+    if ( value === '' ) {
+        return <span>--</span>;
+    }
+    const amt = parseFloat( value );
+    if ( isNaN( amt ) ) {
+        return <span>--</span>;
+    }
+    return amt < 0 ? (
+        <div className="flex">( { price( Math.abs( amt ) ) } )</div>
+    ) : (
+        <div className="flex">{ price( amt ) }</div>
+    );
+};
+
 const fields = [
     // ... other fields
     {
         id: 'debit',
         label: __( 'Debit', 'dokan-lite' ),
-        render: ( { item } ) => {
-            if ( item.debit === '' ) {
-                return <span>--</span>;
-            }
-            const amt = parseFloat( item.debit );
-            if ( isNaN( amt ) ) {
-                return <span>--</span>;
-            }
-            return amt < 0 ? (
-                <div className="flex">( { price( Math.abs( amt ) ) } )</div>
-            ) : (
-                <div className="flex">{ price( amt ) }</div>
-            );
-        },
+        render: ( { item } ) => renderMonetaryValue( item.debit ),
     },
     {
         id: 'credit',
         label: __( 'Credit', 'dokan-lite' ),
-        render: ( { item } ) => {
-            if ( item.credit === '' ) {
-                return <span>--</span>;
-            }
-            const amt = parseFloat( item.credit );
-            if ( isNaN( amt ) ) {
-                return <span>--</span>;
-            }
-            return amt < 0 ? (
-                <div className="flex">( { price( Math.abs( amt ) ) } )</div>
-            ) : (
-                <div className="flex">{ price( amt ) }</div>
-            );
-        },
+        render: ( { item } ) => renderMonetaryValue( item.credit ),
     },
     {
         id: 'balance',
         label: __( 'Balance', 'dokan-lite' ),
-        render: ( { item } ) => {
-            if ( item.balance === '' ) {
-                return <span>--</span>;
-            }
-            const amt = parseFloat( item.balance );
-            if ( isNaN( amt ) ) {
-                return <span>--</span>;
-            }
-            return amt < 0 ? (
-                <div className="flex">( { price( Math.abs( amt ) ) } )</div>
-            ) : (
-                <div className="flex">{ price( amt ) }</div>
-            );
-        },
+        render: ( { item } ) => renderMonetaryValue( item.balance ),
     },
 ];

141-148: Initialize sort property in view state for consistency and type safety.

The fetchTransactions callback (lines 190-191) accesses view.sort.field and view.sort.direction, but the initial view state doesn't include a sort property. While the code safely falls back using optional chaining and defaults, explicitly initializing sort improves clarity and type safety.

 const [ view, setView ] = useState( {
     perPage: 100,
     page: 1,
     search: '',
     type: 'table',
     layout: { density: 'comfortable' },
     fields: fields.map( ( f ) => f.id ),
+    sort: {
+        field: 'trn_date',
+        direction: 'desc',
+    },
 } );
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 78ede77 and 3883362.

📒 Files selected for processing (1)
  • src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/admin/dashboard/pages/reverse-withdrawal/ReverseWithdrawalTransaction.tsx (1)
types/externals.d.ts (1)
  • DataViews (59-59)
⏰ 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: e2e tests (1, 3)
  • GitHub Check: e2e tests (3, 3)
  • GitHub Check: e2e tests (2, 3)
  • GitHub Check: api tests (1, 1)

@shohan0120 shohan0120 added 🎉 QA Approved This PR is approved by the QA team and removed Type: Bug Needs: Testing This requires further testing QA In Progress labels Nov 20, 2025
@MdAsifHossainNadim MdAsifHossainNadim merged commit 9bcb9fc into develop Nov 24, 2025
1 of 5 checks passed
@MdAsifHossainNadim MdAsifHossainNadim deleted the new-reverse-withdrawal-react branch November 24, 2025 08:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Dev Review Done 🎉 QA Approved This PR is approved by the QA team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants