mirror of
https://github.com/lingble/twenty.git
synced 2025-10-30 20:27:55 +00:00
Verification popup can be activated multiple times (#6938)
Fixes https://github.com/twentyhq/twenty/issues/6912 By clicking Enter key over and over, user can repeat action Expected: When 'yes' is typed in popup and user clicks Enter key once, popup should disappear and correlated action should be performed only once Implementation: - Added loading state for buttons onClick and onEnter to disable the button when the "Delete Api Key" and "Regenerate Api Key" function is called. - Added a new function to handle modal close and logic handling on clicking enter key. --------- Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
export type ConfirmationModalProps = {
|
||||
isOpen: boolean;
|
||||
title: string;
|
||||
loading?: boolean;
|
||||
subtitle: ReactNode;
|
||||
setIsOpen: (val: boolean) => void;
|
||||
onConfirmClick: () => void;
|
||||
@@ -59,6 +60,7 @@ export const StyledConfirmationButton = styled(StyledCenteredButton)`
|
||||
export const ConfirmationModal = ({
|
||||
isOpen = false,
|
||||
title,
|
||||
loading,
|
||||
subtitle,
|
||||
setIsOpen,
|
||||
onConfirmClick,
|
||||
@@ -83,6 +85,18 @@ export const ConfirmationModal = ({
|
||||
250,
|
||||
);
|
||||
|
||||
const handleConfirmClick = () => {
|
||||
onConfirmClick();
|
||||
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
const handleEnter = () => {
|
||||
if (isValidValue) {
|
||||
handleConfirmClick();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<AnimatePresence mode="wait">
|
||||
<LayoutGroup>
|
||||
@@ -93,7 +107,7 @@ export const ConfirmationModal = ({
|
||||
setIsOpen(false);
|
||||
}
|
||||
}}
|
||||
onEnter={!isValidValue ? undefined : onConfirmClick}
|
||||
onEnter={handleEnter}
|
||||
isClosable={true}
|
||||
padding="large"
|
||||
>
|
||||
@@ -125,14 +139,11 @@ export const ConfirmationModal = ({
|
||||
fullWidth
|
||||
/>
|
||||
<StyledCenteredButton
|
||||
onClick={async () => {
|
||||
await onConfirmClick();
|
||||
setIsOpen(false);
|
||||
}}
|
||||
onClick={handleConfirmClick}
|
||||
variant="secondary"
|
||||
accent={confirmButtonAccent}
|
||||
title={deleteButtonText}
|
||||
disabled={!isValidValue}
|
||||
disabled={!isValidValue || loading}
|
||||
fullWidth
|
||||
dataTestId="confirmation-modal-confirm-button"
|
||||
/>
|
||||
|
||||
@@ -19,6 +19,8 @@ import { computeNewExpirationDate } from '@/settings/developers/utils/compute-ne
|
||||
import { formatExpiration } from '@/settings/developers/utils/format-expiration';
|
||||
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||
import { SettingsPath } from '@/types/SettingsPath';
|
||||
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { Button } from '@/ui/input/button/components/Button';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
||||
@@ -41,9 +43,11 @@ const StyledInputContainer = styled.div`
|
||||
`;
|
||||
|
||||
export const SettingsDevelopersApiKeyDetail = () => {
|
||||
const { enqueueSnackBar } = useSnackBar();
|
||||
const [isRegenerateKeyModalOpen, setIsRegenerateKeyModalOpen] =
|
||||
useState(false);
|
||||
const [isDeleteApiKeyModalOpen, setIsDeleteApiKeyModalOpen] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const navigate = useNavigate();
|
||||
const { apiKeyId = '' } = useParams();
|
||||
@@ -69,12 +73,22 @@ export const SettingsDevelopersApiKeyDetail = () => {
|
||||
const developerPath = getSettingsPagePath(SettingsPath.Developers);
|
||||
|
||||
const deleteIntegration = async (redirect = true) => {
|
||||
await updateApiKey?.({
|
||||
idToUpdate: apiKeyId,
|
||||
updateOneRecordInput: { revokedAt: DateTime.now().toString() },
|
||||
});
|
||||
if (redirect) {
|
||||
navigate(developerPath);
|
||||
setIsLoading(true);
|
||||
|
||||
try {
|
||||
await updateApiKey?.({
|
||||
idToUpdate: apiKeyId,
|
||||
updateOneRecordInput: { revokedAt: DateTime.now().toString() },
|
||||
});
|
||||
if (redirect) {
|
||||
navigate(developerPath);
|
||||
}
|
||||
} catch (err) {
|
||||
enqueueSnackBar(`Error deleting api key: ${err}`, {
|
||||
variant: SnackBarVariant.Error,
|
||||
});
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -102,20 +116,28 @@ export const SettingsDevelopersApiKeyDetail = () => {
|
||||
token: tokenData.data?.generateApiKeyToken.token,
|
||||
};
|
||||
};
|
||||
|
||||
const regenerateApiKey = async () => {
|
||||
if (isNonEmptyString(apiKeyData?.name)) {
|
||||
const newExpiresAt = computeNewExpirationDate(
|
||||
apiKeyData?.expiresAt,
|
||||
apiKeyData?.createdAt,
|
||||
);
|
||||
const apiKey = await createIntegration(apiKeyData?.name, newExpiresAt);
|
||||
await deleteIntegration(false);
|
||||
setIsLoading(true);
|
||||
try {
|
||||
if (isNonEmptyString(apiKeyData?.name)) {
|
||||
const newExpiresAt = computeNewExpirationDate(
|
||||
apiKeyData?.expiresAt,
|
||||
apiKeyData?.createdAt,
|
||||
);
|
||||
const apiKey = await createIntegration(apiKeyData?.name, newExpiresAt);
|
||||
await deleteIntegration(false);
|
||||
|
||||
if (isNonEmptyString(apiKey?.token)) {
|
||||
setApiKeyToken(apiKey.token);
|
||||
navigate(`/settings/developers/api-keys/${apiKey.id}`);
|
||||
if (isNonEmptyString(apiKey?.token)) {
|
||||
setApiKeyToken(apiKey.token);
|
||||
navigate(`/settings/developers/api-keys/${apiKey.id}`);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
enqueueSnackBar(`Error regenerating api key: ${err}`, {
|
||||
variant: SnackBarVariant.Error,
|
||||
});
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -225,6 +247,7 @@ export const SettingsDevelopersApiKeyDetail = () => {
|
||||
}
|
||||
onConfirmClick={deleteIntegration}
|
||||
deleteButtonText="Delete"
|
||||
loading={isLoading}
|
||||
/>
|
||||
<ConfirmationModal
|
||||
confirmationPlaceholder="yes"
|
||||
@@ -241,6 +264,7 @@ export const SettingsDevelopersApiKeyDetail = () => {
|
||||
}
|
||||
onConfirmClick={regenerateApiKey}
|
||||
deleteButtonText="Regenerate key"
|
||||
loading={isLoading}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user