🚀 feat: Enhance table UX & fix reset actions across Users / Tokens / Redemptions
Users table (UsersColumnDefs.js) • Merged “Status” into the “Statistics” tag: unified text-color logic, removed duplicate renderStatus / renderOverallStatus helpers. • Switch now disabled for deleted users. • Replaced dropdown “More” menu with explicit action buttons (Edit / Promote / Demote / Delete) and set column width to 200 px. • Deleted unused Dropdown & IconMore imports and tidied redundant code. Users filters & hooks • UsersFilters.jsx – store formApi in a ref; reset button clears form then reloads data after 100 ms. • useUsersData.js – call setLoading(true) at the start of loadUsers so the Query button shows loading on reset / reload. TokensFilters.jsx & RedemptionsFilters.jsx • Same ref-based reset pattern with 100 ms debounce to restore working “Reset” buttons. Other clean-ups • Removed repeated status strings and unused helper functions. • Updated import lists to reflect component changes. Result – Reset buttons now reliably clear filters and reload data with proper loading feedback. – Users table shows concise status information and all operation buttons without extra clicks.
This commit is contained in:
@@ -128,13 +128,13 @@ const SiderBar = ({ onNavigate = () => { } }) => {
|
||||
const adminItems = useMemo(
|
||||
() => [
|
||||
{
|
||||
text: t('渠道'),
|
||||
text: t('渠道管理'),
|
||||
itemKey: 'channel',
|
||||
to: '/channel',
|
||||
className: isAdmin() ? '' : 'tableHiddle',
|
||||
},
|
||||
{
|
||||
text: t('兑换码'),
|
||||
text: t('兑换码管理'),
|
||||
itemKey: 'redemption',
|
||||
to: '/redemption',
|
||||
className: isAdmin() ? '' : 'tableHiddle',
|
||||
|
||||
@@ -17,7 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
For commercial licensing, please contact support@quantumnous.com
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useRef } from 'react';
|
||||
import { Form, Button } from '@douyinfe/semi-ui';
|
||||
import { IconSearch } from '@douyinfe/semi-icons';
|
||||
|
||||
@@ -31,20 +31,23 @@ const RedemptionsFilters = ({
|
||||
}) => {
|
||||
|
||||
// Handle form reset and immediate search
|
||||
const handleReset = (formApi) => {
|
||||
if (formApi) {
|
||||
formApi.reset();
|
||||
// Reset and search immediately
|
||||
setTimeout(() => {
|
||||
searchRedemptions();
|
||||
}, 100);
|
||||
}
|
||||
const formApiRef = useRef(null);
|
||||
|
||||
const handleReset = () => {
|
||||
if (!formApiRef.current) return;
|
||||
formApiRef.current.reset();
|
||||
setTimeout(() => {
|
||||
searchRedemptions();
|
||||
}, 100);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
initValues={formInitValues}
|
||||
getFormApi={(api) => setFormApi(api)}
|
||||
getFormApi={(api) => {
|
||||
setFormApi(api);
|
||||
formApiRef.current = api;
|
||||
}}
|
||||
onSubmit={searchRedemptions}
|
||||
allowEmpty={true}
|
||||
autoComplete="off"
|
||||
@@ -76,7 +79,7 @@ const RedemptionsFilters = ({
|
||||
</Button>
|
||||
<Button
|
||||
type="tertiary"
|
||||
onClick={(_, formApi) => handleReset(formApi)}
|
||||
onClick={handleReset}
|
||||
className="flex-1 md:flex-initial md:w-auto"
|
||||
size="small"
|
||||
>
|
||||
|
||||
@@ -17,7 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
For commercial licensing, please contact support@quantumnous.com
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useRef } from 'react';
|
||||
import { Form, Button } from '@douyinfe/semi-ui';
|
||||
import { IconSearch } from '@douyinfe/semi-icons';
|
||||
|
||||
@@ -30,20 +30,23 @@ const TokensFilters = ({
|
||||
t,
|
||||
}) => {
|
||||
// Handle form reset and immediate search
|
||||
const handleReset = (formApi) => {
|
||||
if (formApi) {
|
||||
formApi.reset();
|
||||
// Reset and search immediately
|
||||
setTimeout(() => {
|
||||
searchTokens();
|
||||
}, 100);
|
||||
}
|
||||
const formApiRef = useRef(null);
|
||||
|
||||
const handleReset = () => {
|
||||
if (!formApiRef.current) return;
|
||||
formApiRef.current.reset();
|
||||
setTimeout(() => {
|
||||
searchTokens();
|
||||
}, 100);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
initValues={formInitValues}
|
||||
getFormApi={(api) => setFormApi(api)}
|
||||
getFormApi={(api) => {
|
||||
setFormApi(api);
|
||||
formApiRef.current = api;
|
||||
}}
|
||||
onSubmit={searchTokens}
|
||||
allowEmpty={true}
|
||||
autoComplete="off"
|
||||
@@ -88,7 +91,7 @@ const TokensFilters = ({
|
||||
|
||||
<Button
|
||||
type='tertiary'
|
||||
onClick={(_, formApi) => handleReset(formApi)}
|
||||
onClick={handleReset}
|
||||
className="flex-1 md:flex-initial md:w-auto"
|
||||
size="small"
|
||||
>
|
||||
|
||||
@@ -17,7 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
For commercial licensing, please contact support@quantumnous.com
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useRef } from 'react';
|
||||
import { Form, Button } from '@douyinfe/semi-ui';
|
||||
import { IconSearch } from '@douyinfe/semi-icons';
|
||||
|
||||
@@ -34,21 +34,23 @@ const UsersFilters = ({
|
||||
t
|
||||
}) => {
|
||||
|
||||
// Handle form reset and immediate search
|
||||
const handleReset = (formApi) => {
|
||||
if (formApi) {
|
||||
formApi.reset();
|
||||
// Reset and search immediately
|
||||
setTimeout(() => {
|
||||
loadUsers(1, pageSize);
|
||||
}, 100);
|
||||
}
|
||||
const formApiRef = useRef(null);
|
||||
|
||||
const handleReset = () => {
|
||||
if (!formApiRef.current) return;
|
||||
formApiRef.current.reset();
|
||||
setTimeout(() => {
|
||||
loadUsers(1, pageSize);
|
||||
}, 100);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
initValues={formInitValues}
|
||||
getFormApi={(api) => setFormApi(api)}
|
||||
getFormApi={(api) => {
|
||||
setFormApi(api);
|
||||
formApiRef.current = api;
|
||||
}}
|
||||
onSubmit={() => {
|
||||
searchUsers(1, pageSize);
|
||||
}}
|
||||
@@ -99,7 +101,7 @@ const UsersFilters = ({
|
||||
</Button>
|
||||
<Button
|
||||
type='tertiary'
|
||||
onClick={(_, formApi) => handleReset(formApi)}
|
||||
onClick={handleReset}
|
||||
className="flex-1 md:flex-initial md:w-auto"
|
||||
size="small"
|
||||
>
|
||||
|
||||
@@ -71,6 +71,7 @@ export const useUsersData = () => {
|
||||
|
||||
// Load users data
|
||||
const loadUsers = async (startIdx, pageSize) => {
|
||||
setLoading(true);
|
||||
const res = await API.get(`/api/user/?p=${startIdx}&page_size=${pageSize}`);
|
||||
const { success, message, data } = res.data;
|
||||
if (success) {
|
||||
|
||||
@@ -165,7 +165,8 @@
|
||||
"操作失败,重定向至登录界面中...": "Operation failed, redirecting to login page...",
|
||||
"出现错误,第 ${count} 次重试中...": "Error occurred, retry attempt ${count}...",
|
||||
"首页": "Home",
|
||||
"渠道": "Channels",
|
||||
"渠道": "Channel",
|
||||
"渠道管理": "Channels",
|
||||
"令牌": "Tokens",
|
||||
"兑换": "Redeem",
|
||||
"充值": "Recharge",
|
||||
@@ -1487,7 +1488,7 @@
|
||||
"收益": "Earnings",
|
||||
"无邀请人": "No Inviter",
|
||||
"邀请人": "Inviter",
|
||||
"兑换码管理": "Redemption Code Management",
|
||||
"兑换码管理": "Redemption Code",
|
||||
"设置兑换码的基本信息": "Set redemption code basic information",
|
||||
"设置兑换码的额度和数量": "Set redemption code quota and quantity",
|
||||
"编辑用户": "Edit User",
|
||||
|
||||
Reference in New Issue
Block a user