mirror of https://gitee.com/answerdev/answer.git
feat(SchemaForm): Optimising the action feedback of the Button component
This commit is contained in:
parent
9f2607cf35
commit
c843dddf0b
|
@ -1,9 +1,10 @@
|
||||||
import React, { FC, useState } from 'react';
|
import React, { FC, useLayoutEffect, useState } from 'react';
|
||||||
import { Button, ButtonProps } from 'react-bootstrap';
|
import { Button, ButtonProps, Spinner } from 'react-bootstrap';
|
||||||
|
|
||||||
import { request } from '@/utils';
|
import { request } from '@/utils';
|
||||||
import type * as Type from '@/common/interface';
|
import type * as Type from '@/common/interface';
|
||||||
import type { UIAction } from '../index.d';
|
import type { UIAction } from '../types';
|
||||||
|
import { useToast } from '@/hooks';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
fieldName: string;
|
fieldName: string;
|
||||||
|
@ -24,17 +25,51 @@ const Index: FC<Props> = ({
|
||||||
variant = 'primary',
|
variant = 'primary',
|
||||||
size,
|
size,
|
||||||
}) => {
|
}) => {
|
||||||
|
const Toast = useToast();
|
||||||
const [isLoading, setLoading] = useState(false);
|
const [isLoading, setLoading] = useState(false);
|
||||||
const handleAction = async () => {
|
const handleNotify = (msg, type: 'success' | 'danger' = 'success') => {
|
||||||
|
const tm = action?.toastMessage;
|
||||||
|
if (tm === false || !msg) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Toast.onShow({
|
||||||
|
msg,
|
||||||
|
variant: type,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const handleAction = () => {
|
||||||
if (!action) {
|
if (!action) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const method = action.method || 'get';
|
request
|
||||||
await request[method](action.url);
|
.request({
|
||||||
|
method: action.method,
|
||||||
|
url: action.url,
|
||||||
|
timeout: 0,
|
||||||
|
})
|
||||||
|
.then((resp) => {
|
||||||
|
if ('message' in resp) {
|
||||||
|
handleNotify(resp.message, 'success');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((ex) => {
|
||||||
|
if (ex && 'msg' in ex) {
|
||||||
|
handleNotify(ex.msg, 'danger');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
if (action?.loading?.state === 'pending') {
|
||||||
|
setLoading(true);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
const loadingText = action?.loading?.text || text;
|
||||||
const disabled = isLoading || readOnly;
|
const disabled = isLoading || readOnly;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="d-flex">
|
<div className="d-flex">
|
||||||
<Button
|
<Button
|
||||||
|
@ -43,8 +78,19 @@ const Index: FC<Props> = ({
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
size={size}
|
size={size}
|
||||||
variant={variant}>
|
variant={variant}>
|
||||||
{text || fieldName}
|
{isLoading ? (
|
||||||
{isLoading ? '...' : ''}
|
<>
|
||||||
|
<Spinner
|
||||||
|
className="align-middle me-2"
|
||||||
|
animation="border"
|
||||||
|
size="sm"
|
||||||
|
variant={variant}
|
||||||
|
/>
|
||||||
|
{loadingText}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
text
|
||||||
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
export interface UIAction {
|
|
||||||
url: string;
|
|
||||||
method?: 'get' | 'post' | 'put' | 'delete';
|
|
||||||
event?: 'click' | 'change';
|
|
||||||
handler?: ({evt, formData, request}) => Promise<void>
|
|
||||||
}
|
|
|
@ -11,7 +11,7 @@ import classnames from 'classnames';
|
||||||
|
|
||||||
import type * as Type from '@/common/interface';
|
import type * as Type from '@/common/interface';
|
||||||
|
|
||||||
import type { UIAction } from './index.d';
|
import type { UIAction } from './types';
|
||||||
import {
|
import {
|
||||||
Legend,
|
Legend,
|
||||||
Select,
|
Select,
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
* A few notes on button control:
|
||||||
|
* - Mainly used to send a request and notify the result of the request, and to update the data as required
|
||||||
|
* - A scenario where a message notification is displayed directly after a click without sending a request, implementing a dedicated control
|
||||||
|
* - Scenarios where the page jumps directly after a click without sending a request, implementing a dedicated control
|
||||||
|
*
|
||||||
|
* @field url : Target address for sending requests
|
||||||
|
* @field method : Method for sending requests, default `get`
|
||||||
|
* @field callback: Button event handler function that will fully take over the button events when this field is configured
|
||||||
|
* *** Incomplete, DO NOT USE ***
|
||||||
|
* @field loading: Set button loading information
|
||||||
|
* @field notify: Configure how button action processing results are prompted
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO:
|
||||||
|
* - Refining the type of `notify.options`
|
||||||
|
*/
|
||||||
|
export interface UIAction {
|
||||||
|
url: string;
|
||||||
|
method?: 'get' | 'post' | 'put' | 'delete';
|
||||||
|
callback?: () => Promise<void>;
|
||||||
|
loading?: {
|
||||||
|
text: string;
|
||||||
|
state?: 'none' | 'pending' | 'completed';
|
||||||
|
}
|
||||||
|
toastMessage?: boolean;
|
||||||
|
}
|
Loading…
Reference in New Issue