♻️ refactor(components): restructure RedemptionsTable to modular architecture

Refactor the monolithic RedemptionsTable component (614 lines) into a clean,
modular structure following the established tokens component pattern.

### Changes Made:

**New Components:**
- `RedemptionsColumnDefs.js` - Extract table column definitions and render logic
- `RedemptionsActions.jsx` - Extract action buttons (add, batch copy, clear invalid)
- `RedemptionsFilters.jsx` - Extract search and filter form components
- `RedemptionsDescription.jsx` - Extract description area component
- `redemptions/index.jsx` - Main container component managing state and composition

**New Hook:**
- `useRedemptionsData.js` - Extract all data management, CRUD operations, and business logic

**New Constants:**
- `redemption.constants.js` - Extract redemption status, actions, and form constants

**Architecture Changes:**
- Transform RedemptionsTable.jsx into pure table rendering component
- Move state management and component composition to index.jsx
- Implement consistent prop drilling pattern matching tokens module
- Add memoization for performance optimization
- Centralize translation function distribution

### Benefits:
- **Maintainability**: Each component has single responsibility
- **Reusability**: Components and hooks can be used elsewhere
- **Testability**: Individual modules can be unit tested
- **Team Collaboration**: Multiple developers can work on different modules
- **Consistency**: Follows established architectural patterns

### File Structure:
```
redemptions/
├── index.jsx                    # Main container (state + composition)
├── RedemptionsTable.jsx        # Pure table component
├── RedemptionsActions.jsx      # Action buttons
├── RedemptionsFilters.jsx      # Search/filter form
├── RedemptionsDescription.jsx  # Description area
└── RedemptionsColumnDefs.js    # Column definitions
This commit is contained in:
t0ng7u
2025-07-19 00:12:04 +08:00
parent 42a26f076a
commit c05d6f7cdf
19 changed files with 1117 additions and 730 deletions

View File

@@ -0,0 +1,119 @@
import React, { useMemo, useState } from 'react';
import { Table, Empty } from '@douyinfe/semi-ui';
import {
IllustrationNoResult,
IllustrationNoResultDark
} from '@douyinfe/semi-illustrations';
import { getRedemptionsColumns, isExpired } from './RedemptionsColumnDefs';
import DeleteRedemptionModal from './modals/DeleteRedemptionModal';
const RedemptionsTable = (redemptionsData) => {
const {
redemptions,
loading,
activePage,
pageSize,
tokenCount,
compactMode,
handlePageChange,
rowSelection,
handleRow,
manageRedemption,
copyText,
setEditingRedemption,
setShowEdit,
refresh,
t,
} = redemptionsData;
// Modal states
const [showDeleteModal, setShowDeleteModal] = useState(false);
const [deletingRecord, setDeletingRecord] = useState(null);
// Handle show delete modal
const showDeleteRedemptionModal = (record) => {
setDeletingRecord(record);
setShowDeleteModal(true);
};
// Get all columns
const columns = useMemo(() => {
return getRedemptionsColumns({
t,
manageRedemption,
copyText,
setEditingRedemption,
setShowEdit,
refresh,
redemptions,
activePage,
showDeleteRedemptionModal
});
}, [
t,
manageRedemption,
copyText,
setEditingRedemption,
setShowEdit,
refresh,
redemptions,
activePage,
showDeleteRedemptionModal,
]);
// Handle compact mode by removing fixed positioning
const tableColumns = useMemo(() => {
return compactMode ? columns.map(col => {
if (col.dataIndex === 'operate') {
const { fixed, ...rest } = col;
return rest;
}
return col;
}) : columns;
}, [compactMode, columns]);
return (
<>
<Table
columns={tableColumns}
dataSource={redemptions}
scroll={compactMode ? undefined : { x: 'max-content' }}
pagination={{
currentPage: activePage,
pageSize: pageSize,
total: tokenCount,
showSizeChanger: true,
pageSizeOptions: [10, 20, 50, 100],
onPageSizeChange: redemptionsData.handlePageSizeChange,
onPageChange: handlePageChange,
}}
loading={loading}
rowSelection={rowSelection}
onRow={handleRow}
empty={
<Empty
image={<IllustrationNoResult style={{ width: 150, height: 150 }} />}
darkModeImage={<IllustrationNoResultDark style={{ width: 150, height: 150 }} />}
description={t('搜索无结果')}
style={{ padding: 30 }}
/>
}
className="rounded-xl overflow-hidden"
size="middle"
/>
<DeleteRedemptionModal
visible={showDeleteModal}
onCancel={() => setShowDeleteModal(false)}
record={deletingRecord}
manageRedemption={manageRedemption}
refresh={refresh}
redemptions={redemptions}
activePage={activePage}
t={t}
/>
</>
);
};
export default RedemptionsTable;