[web] Deduplicate buttons (#3622)

And some fixes / tweaks to the recently added fav overlay.
This commit is contained in:
Manav Rathi
2024-10-08 13:21:38 +05:30
committed by GitHub
24 changed files with 167 additions and 272 deletions

View File

@@ -1,9 +1,9 @@
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
import log from "@/base/log";
import type { TwoFactorAuthorizationResponse } from "@/base/types/credentials";
import { ensure } from "@/utils/ensure";
import { nullToUndefined } from "@/utils/transform";
import { VerticallyCentered } from "@ente/shared/components/Container";
import EnteButton from "@ente/shared/components/EnteButton";
import EnteSpinner from "@ente/shared/components/EnteSpinner";
import InfoIcon from "@mui/icons-material/Info";
import KeyIcon from "@mui/icons-material/Key";
@@ -366,15 +366,9 @@ const Verify: React.FC<VerifyProps> = ({ onVerify }) => {
{t("passkey_verify_description")}
</Typography>
<ButtonStack>
<EnteButton
onClick={onVerify}
fullWidth
color="accent"
type="button"
variant="contained"
>
<FocusVisibleButton onClick={onVerify} fullWidth color="accent">
{t("VERIFY")}
</EnteButton>
</FocusVisibleButton>
</ButtonStack>
</Content>
);
@@ -416,25 +410,22 @@ const RetriableFailed: React.FC<RetriableFailedProps> = ({
: t("passkey_login_generic_error")}
</Typography>
<ButtonStack>
<EnteButton
<FocusVisibleButton
onClick={onRetry}
fullWidth
color="secondary"
type="button"
variant="contained"
>
{t("try_again")}
</EnteButton>
</FocusVisibleButton>
{onRecover && (
<EnteButton
<FocusVisibleButton
onClick={onRecover}
fullWidth
color="primary"
type="button"
variant="text"
>
{t("RECOVER_TWO_FACTOR")}
</EnteButton>
</FocusVisibleButton>
)}
</ButtonStack>
</Content>
@@ -504,15 +495,14 @@ const RedirectingApp: React.FC<RedirectingAppProps> = ({ onRetry }) => {
{t("redirect_close_instructions")}
</Typography>
<ButtonStack>
<EnteButton
<FocusVisibleButton
onClick={onRetry}
fullWidth
color="primary"
type="button"
variant="text"
>
{t("redirect_again")}
</EnteButton>
</FocusVisibleButton>
</ButtonStack>
</Content>
);

View File

@@ -3,11 +3,12 @@ import {
MenuItemGroup,
MenuSectionTitle,
} from "@/base/components/Menu";
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
import { LoadingButton } from "@/base/components/mui/LoadingButton";
import { FlexWrapper } from "@ente/shared/components/Container";
import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem";
import SubmitButton from "@ente/shared/components/SubmitButton";
import DoneIcon from "@mui/icons-material/Done";
import { Button, FormHelperText, Stack } from "@mui/material";
import { FormHelperText, Stack } from "@mui/material";
import TextField from "@mui/material/TextField";
import Avatar from "components/pages/gallery/Avatar";
import { Formik, type FormikHelpers } from "formik";
@@ -204,7 +205,7 @@ export default function AddParticipantForm(props: AddParticipantFormProps) {
>
<Stack direction={"column"} px={"8px"} width={"100%"}>
{props.secondaryButtonAction && (
<Button
<FocusVisibleButton
onClick={props.secondaryButtonAction}
size="large"
color="secondary"
@@ -219,20 +220,20 @@ export default function AddParticipantForm(props: AddParticipantFormProps) {
{...restSubmitButtonProps}
>
{t("cancel")}
</Button>
</FocusVisibleButton>
)}
<SubmitButton
sx={{
"&&&": {
mt: 2,
...buttonSx,
},
}}
<LoadingButton
type="submit"
color="accent"
fullWidth
buttonText={props.buttonText}
loading={loading}
sx={{ mt: 2, mb: 4 }}
{...restSubmitButtonProps}
/>
>
{props.buttonText}
</LoadingButton>
</Stack>
</FlexWrapper>
</form>

View File

@@ -1,8 +1,9 @@
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
import { LoadingButton } from "@/base/components/mui/LoadingButton";
import log from "@/base/log";
import { initiateEmail } from "@/new/photos/utils/web";
import DialogBoxV2 from "@ente/shared/components/DialogBoxV2";
import EnteButton from "@ente/shared/components/EnteButton";
import { Button, Link, Stack, useMediaQuery } from "@mui/material";
import { Link, Stack, useMediaQuery } from "@mui/material";
import { Formik, type FormikHelpers } from "formik";
import { t } from "i18next";
import { AppContext } from "pages/_app";
@@ -200,7 +201,7 @@ const DeleteAccountModal = ({ open, onClose }: Iprops) => {
)}
/>
<Stack spacing={"8px"}>
<EnteButton
<LoadingButton
type="submit"
size="large"
color="critical"
@@ -208,14 +209,14 @@ const DeleteAccountModal = ({ open, onClose }: Iprops) => {
loading={loading}
>
{t("delete_account_confirm")}
</EnteButton>
<Button
</LoadingButton>
<FocusVisibleButton
size="large"
color={"secondary"}
onClick={onClose}
>
{t("cancel")}
</Button>
</FocusVisibleButton>
</Stack>
</Stack>
</form>

View File

@@ -323,7 +323,7 @@ const PhotoFrame = ({
}
activeCollectionID={activeCollectionID}
showPlaceholder={isScrolling}
isFav={favItemIds.has(item.id)}
isFav={favItemIds?.has(item.id)}
/>
);

View File

@@ -13,7 +13,6 @@ import {
CenteredFlex,
HorizontalFlex,
} from "@ente/shared/components/Container";
import EnteButton from "@ente/shared/components/EnteButton";
import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem";
import { downloadUsingAnchor } from "@ente/shared/utils";
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
@@ -26,6 +25,7 @@ import MenuIcon from "@mui/icons-material/Menu";
import {
Backdrop,
Box,
Button,
CircularProgress,
IconButton,
Tab,
@@ -493,6 +493,30 @@ const ImageEditorOverlay = (props: IProps) => {
log.error("Error saving copy to ente", e);
}
};
const applyCrop = () => {
if (!cropBoxRef.current || !canvasRef.current) return;
const { x1, x2, y1, y2 } = getCropRegionArgs(
cropBoxRef.current,
canvasRef.current,
);
setCanvasLoading(true);
setTransformationPerformed(true);
cropRegionOfCanvas(canvasRef.current, x1, y1, x2, y2);
cropRegionOfCanvas(
originalSizeCanvasRef.current,
x1 / previewCanvasScale,
y1 / previewCanvasScale,
x2 / previewCanvasScale,
y2 / previewCanvasScale,
);
resetCropBox();
setCanvasLoading(false);
setCurrentTab("transform");
};
return (
<>
<Backdrop
@@ -540,7 +564,7 @@ const ImageEditorOverlay = (props: IProps) => {
}}
>
<Box
height="90%"
height="88%"
width="100%"
ref={parentRef}
display="flex"
@@ -580,45 +604,13 @@ const ImageEditorOverlay = (props: IProps) => {
</Box>
{currentTab === "crop" && (
<CenteredFlex marginTop="1rem">
<EnteButton
<Button
color="accent"
startIcon={<CropIcon />}
onClick={() => {
if (
!cropBoxRef.current ||
!canvasRef.current
)
return;
const { x1, x2, y1, y2 } =
getCropRegionArgs(
cropBoxRef.current,
canvasRef.current,
);
setCanvasLoading(true);
setTransformationPerformed(true);
cropRegionOfCanvas(
canvasRef.current,
x1,
y1,
x2,
y2,
);
cropRegionOfCanvas(
originalSizeCanvasRef.current,
x1 / previewCanvasScale,
y1 / previewCanvasScale,
x2 / previewCanvasScale,
y2 / previewCanvasScale,
);
resetCropBox();
setCanvasLoading(false);
setCurrentTab("transform");
}}
onClick={applyCrop}
>
{t("APPLY_CROP")}
</EnteButton>
</Button>
</CenteredFlex>
)}
</Box>

View File

@@ -1,7 +1,7 @@
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
import { useIsTouchscreen } from "@/base/hooks";
import { SpaceBetweenFlex } from "@/new/photos/components/mui";
import { DialogCloseIconButton } from "@/new/photos/components/mui/Dialog";
import { FocusVisibleButton } from "@/new/photos/components/mui/FocusVisibleButton";
import DialogTitleWithCloseButton, {
dialogCloseHandler,
} from "@ente/shared/components/DialogBox/TitleWithCloseButton";

View File

@@ -14,6 +14,7 @@ import { Overlay } from "@ente/shared/components/Container";
import { CustomError } from "@ente/shared/error";
import useLongPress from "@ente/shared/hooks/useLongPress";
import AlbumOutlined from "@mui/icons-material/AlbumOutlined";
import Favorite from "@mui/icons-material/FavoriteRounded";
import PlayCircleOutlineOutlinedIcon from "@mui/icons-material/PlayCircleOutlineOutlined";
import { Tooltip, styled } from "@mui/material";
import i18n from "i18next";
@@ -23,7 +24,6 @@ import React, { useContext, useEffect, useRef, useState } from "react";
import { TRASH_SECTION } from "utils/collection";
import { shouldShowAvatar } from "utils/file";
import Avatar from "./Avatar";
import Favorite from "@mui/icons-material/FavoriteRounded";
interface IProps {
file: EnteFile;
@@ -129,6 +129,7 @@ export const FavOverlay = styled(Overlay)`
align-items: flex-end;
padding-left: 5px;
padding-bottom: 5px;
opacity: 0.9;
`;
export const InSelectRangeOverLay = styled("div")<{ $active: boolean }>`
@@ -363,7 +364,7 @@ export default function PreviewCard(props: IProps) {
)}
{props.isFav && (
<FavOverlay>
<Favorite/>
<Favorite />
</FavOverlay>
)}

View File

@@ -1,6 +1,6 @@
import { isWeakPassword } from "@/accounts/utils";
import { LoadingButton } from "@/base/components/mui/LoadingButton";
import ShowHidePassword from "@ente/shared/components/Form/ShowHidePassword";
import SubmitButton from "@ente/shared/components/SubmitButton";
import { Box, Input, TextField, Typography } from "@mui/material";
import { Formik } from "formik";
import { t } from "i18next";
@@ -137,12 +137,15 @@ function SetPasswordForm(props: SetPasswordFormProps) {
</Typography>
<Box my={4}>
<SubmitButton
sx={{ my: 0 }}
<LoadingButton
fullWidth
color="accent"
type="submit"
loading={loading}
buttonText={props.buttonText}
disabled={isWeakPassword(values.passphrase)}
/>
>
{props.buttonText}
</LoadingButton>
{loading && (
<Typography
textAlign="center"

View File

@@ -3,6 +3,7 @@ import { PasswordStrengthHint } from "@/accounts/components/PasswordStrength";
import { PAGES } from "@/accounts/constants/pages";
import { isWeakPassword } from "@/accounts/utils";
import { generateKeyAndSRPAttributes } from "@/accounts/utils/srp";
import { LoadingButton } from "@/base/components/mui/LoadingButton";
import log from "@/base/log";
import { LS_KEYS, setLSUser } from "@ente/shared//storage/localStorage";
import { VerticallyCentered } from "@ente/shared/components/Container";
@@ -10,7 +11,6 @@ import FormPaperFooter from "@ente/shared/components/Form/FormPaper/Footer";
import FormPaperTitle from "@ente/shared/components/Form/FormPaper/Title";
import ShowHidePassword from "@ente/shared/components/Form/ShowHidePassword";
import LinkButton from "@ente/shared/components/LinkButton";
import SubmitButton from "@ente/shared/components/SubmitButton";
import {
generateAndSaveIntermediateKeyAttributes,
saveKeyInSessionStore,
@@ -289,15 +289,18 @@ export const SignUp: React.FC<SignUpProps> = ({ router, login, host }) => {
</FormGroup>
</VerticallyCentered>
<Box mb={4}>
<SubmitButton
sx={{ my: 0 }}
buttonText={t("CREATE_ACCOUNT")}
<LoadingButton
fullWidth
color="accent"
type="submit"
loading={loading}
disabled={
!acceptTerms ||
isWeakPassword(values.passphrase)
}
/>
>
{t("CREATE_ACCOUNT")}
</LoadingButton>
{loading && (
<Typography
mt={1}

View File

@@ -1,10 +1,9 @@
import InvalidInputMessage from "@/accounts/components/two-factor/InvalidInputMessage";
import { wait } from "@/utils/promise";
import { LoadingButton } from "@/base/components/mui/LoadingButton";
import {
CenteredFlex,
VerticallyCentered,
} from "@ente/shared/components/Container";
import SubmitButton from "@ente/shared/components/SubmitButton";
import { Box, Typography } from "@mui/material";
import { Formik, type FormikHelpers } from "formik";
import { t } from "i18next";
@@ -27,12 +26,9 @@ export type VerifyTwoFactorCallback = (
export default function VerifyTwoFactor(props: Props) {
const [waiting, setWaiting] = useState(false);
const otpInputRef = useRef<OtpInput>(null);
const [success, setSuccess] = useState(false);
const markSuccessful = async () => {
setWaiting(false);
setSuccess(true);
await wait(1000);
};
const submitForm = async (
@@ -95,12 +91,16 @@ export default function VerifyTwoFactor(props: Props) {
</CenteredFlex>
)}
</Box>
<SubmitButton
buttonText={props.buttonText}
<LoadingButton
type="submit"
color="accent"
fullWidth
sx={{ my: 4 }}
loading={waiting}
success={success}
disabled={values.otp.length < 6}
/>
>
{props.buttonText}
</LoadingButton>
</form>
</VerticallyCentered>
)}

View File

@@ -1,12 +1,11 @@
import { changeEmail, sendOTTForEmailChange } from "@/accounts/api/user";
import { LoadingButton } from "@/base/components/mui/LoadingButton";
import { ensure } from "@/utils/ensure";
import { wait } from "@/utils/promise";
import { VerticallyCentered } from "@ente/shared/components/Container";
import FormPaper from "@ente/shared/components/Form/FormPaper";
import FormPaperFooter from "@ente/shared/components/Form/FormPaper/Footer";
import FormPaperTitle from "@ente/shared/components/Form/FormPaper/Title";
import LinkButton from "@ente/shared/components/LinkButton";
import SubmitButton from "@ente/shared/components/SubmitButton";
import { LS_KEYS, getData, setLSUser } from "@ente/shared/storage/localStorage";
import { Alert, Box, TextField } from "@mui/material";
import { Formik, type FormikHelpers } from "formik";
@@ -50,7 +49,6 @@ const ChangeEmailForm: React.FC = () => {
const [ottInputVisible, setShowOttInputVisibility] = useState(false);
const [email, setEmail] = useState<string | null>(null);
const [showMessage, setShowMessage] = useState(false);
const [success, setSuccess] = useState(false);
const router = useRouter();
@@ -84,8 +82,6 @@ const ChangeEmailForm: React.FC = () => {
await changeEmail(email, ensure(ott));
await setLSUser({ ...getData(LS_KEYS.USER), email });
setLoading(false);
setSuccess(true);
await wait(1000);
goToApp();
} catch (e) {
setLoading(false);
@@ -165,16 +161,15 @@ const ChangeEmailForm: React.FC = () => {
disabled={loading}
/>
)}
<SubmitButton
success={success}
sx={{ mt: 2 }}
<LoadingButton
fullWidth
color="accent"
type="submit"
sx={{ mt: 2, mb: 4 }}
loading={loading}
buttonText={
!ottInputVisible
? t("SEND_OTT")
: t("VERIFY")
}
/>
>
{!ottInputVisible ? t("SEND_OTT") : t("VERIFY")}
</LoadingButton>
</VerticallyCentered>
</form>

View File

@@ -0,0 +1,38 @@
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
import { CircularProgress, type ButtonProps } from "@mui/material";
import React from "react";
/**
* A button that shows a indeterminate progress indicator if the {@link loading}
* prop is set.
*
* The button is also disabled when in the loading state.
*/
export const LoadingButton: React.FC<ButtonProps & { loading?: boolean }> = ({
loading,
disabled,
color,
sx,
children,
...rest
}) =>
loading ? (
<FocusVisibleButton
{...{ color }}
disabled
sx={{
"&.Mui-disabled": {
backgroundColor: `${color}.main`,
color: `${color}.contrastText`,
},
...sx,
}}
{...rest}
>
<CircularProgress size={20} />
</FocusVisibleButton>
) : (
<FocusVisibleButton {...{ color, disabled, sx }} {...rest}>
{children}
</FocusVisibleButton>
);

View File

@@ -1,3 +1,4 @@
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
import type { CollectionMapping } from "@/base/types/ipc";
import FolderIcon from "@mui/icons-material/Folder";
import FolderCopyIcon from "@mui/icons-material/FolderCopy";
@@ -15,7 +16,6 @@ import {
DialogCloseIconButton,
type DialogVisibilityProps,
} from "./mui/Dialog";
import { FocusVisibleButton } from "./mui/FocusVisibleButton";
type CollectionMappingChoiceModalProps = DialogVisibilityProps & {
didSelect: (mapping: CollectionMapping) => void;

View File

@@ -1,3 +1,4 @@
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
import { useIsMobileWidth } from "@/base/hooks";
import { ensureOk } from "@/base/http";
import { getKVS, removeKV, setKV } from "@/base/kv";
@@ -18,7 +19,6 @@ import { useFormik } from "formik";
import { t } from "i18next";
import React, { useEffect, useState } from "react";
import { z } from "zod";
import { FocusVisibleButton } from "./mui/FocusVisibleButton";
import { SlideUpTransition } from "./mui/SlideUpTransition";
interface DevSettingsProps {

View File

@@ -1,3 +1,5 @@
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
import { LoadingButton } from "@/base/components/mui/LoadingButton";
import log from "@/base/log";
import { wait } from "@/utils/promise";
import {
@@ -12,8 +14,6 @@ import { useFormik } from "formik";
import { t } from "i18next";
import React from "react";
import type { DialogVisibilityProps } from "./mui/Dialog";
import { FocusVisibleButton } from "./mui/FocusVisibleButton";
import { LoadingButton } from "./mui/LoadingButton";
type SingleInputFormProps = Pick<
TextFieldProps,

View File

@@ -1,3 +1,4 @@
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
import { ensureElectron } from "@/base/electron";
import { useIsMobileWidth } from "@/base/hooks";
import { ut } from "@/base/i18n";
@@ -14,7 +15,6 @@ import {
} from "@mui/material";
import React, { useEffect } from "react";
import { didShowWhatsNew } from "../services/changelog";
import { FocusVisibleButton } from "./mui/FocusVisibleButton";
import { SlideUpTransition } from "./mui/SlideUpTransition";
interface WhatsNewProps {

View File

@@ -1,37 +0,0 @@
import { CircularProgress, type ButtonProps } from "@mui/material";
import React from "react";
import { FocusVisibleButton } from "./FocusVisibleButton";
/**
* A button that shows a indeterminate progress indicator if the {@link loading}
* prop is set.
*
* The button is also disabled when in the loading state.
*
* TODO: This duplicates the existing SubmitButton and EnteButton. Merge these
* three gradually (didn't want to break existing layouts, so will do it
* piecewise).
*/
export const LoadingButton: React.FC<ButtonProps & { loading?: boolean }> = ({
loading,
disabled,
color,
sx,
children,
...rest
}) => (
<FocusVisibleButton
{...{ color }}
disabled={loading ?? disabled}
sx={{
"&.Mui-disabled": {
backgroundColor: `${color}.main`,
color: `${color}.contrastText`,
},
...sx,
}}
{...rest}
>
{loading ? <CircularProgress size={20} /> : children}
</FocusVisibleButton>
);

View File

@@ -1,4 +1,4 @@
import { FocusVisibleButton } from "@/new/photos/components/mui/FocusVisibleButton";
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
import {
Breakpoint,
DialogActions,

View File

@@ -1,8 +1,8 @@
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
import { LoadingButton } from "@/base/components/mui/LoadingButton";
import { dialogCloseHandler } from "@ente/shared/components/DialogBox/TitleWithCloseButton";
import EnteButton from "@ente/shared/components/EnteButton";
import {
Box,
Button,
Dialog,
Stack,
Typography,
@@ -91,7 +91,7 @@ export default function DialogBoxV2({
flex={1}
>
{attributes.proceed && (
<EnteButton
<LoadingButton
loading={loading}
size="large"
color={attributes.proceed?.variant}
@@ -105,10 +105,10 @@ export default function DialogBoxV2({
disabled={attributes.proceed.disabled}
>
{attributes.proceed.text}
</EnteButton>
</LoadingButton>
)}
{attributes.close && (
<Button
<FocusVisibleButton
size="large"
color={attributes.close?.variant ?? "secondary"}
onClick={() => {
@@ -118,11 +118,11 @@ export default function DialogBoxV2({
}}
>
{attributes.close?.text ?? t("ok")}
</Button>
</FocusVisibleButton>
)}
{attributes.buttons &&
attributes.buttons.map((b) => (
<Button
<FocusVisibleButton
size="large"
key={b.text}
color={b.variant}
@@ -133,7 +133,7 @@ export default function DialogBoxV2({
disabled={b.disabled}
>
{b.text}
</Button>
</FocusVisibleButton>
))}
</Stack>
)}

View File

@@ -1,43 +0,0 @@
import { ensure } from "@/utils/ensure";
import Done from "@mui/icons-material/Done";
import { Button, CircularProgress, type ButtonProps } from "@mui/material";
interface Iprops extends ButtonProps {
loading?: boolean;
success?: boolean;
}
export default function EnteButton({
children,
loading,
success,
disabled,
sx,
...props
}: Iprops) {
return (
<Button
disabled={disabled}
sx={{
...sx,
...((loading || success) && {
"&.Mui-disabled": (theme) => ({
// TODO: Refactor to not need this ensure.
backgroundColor:
theme.palette[ensure(props.color)].main,
color: theme.palette[ensure(props.color)].contrastText,
}),
}),
}}
{...props}
>
{loading ? (
<CircularProgress size={20} sx={{ color: "inherit" }} />
) : success ? (
<Done sx={{ fontSize: 20 }} />
) : (
children
)}
</Button>
);
}

View File

@@ -3,9 +3,9 @@ import {
passkeySessionExpiredErrorMessage,
saveCredentialsAndNavigateTo,
} from "@/accounts/services/passkey";
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
import log from "@/base/log";
import { customAPIHost } from "@/base/origins";
import EnteButton from "@ente/shared/components/EnteButton";
import { CircularProgress, Stack, Typography, styled } from "@mui/material";
import { t } from "i18next";
import { useRouter } from "next/router";
@@ -140,23 +140,21 @@ export const VerifyingPasskey: React.FC<VerifyingPasskeyProps> = ({
</VerifyingPasskeyStatus>
<ButtonStack>
<EnteButton
<FocusVisibleButton
onClick={handleRetry}
fullWidth
color="secondary"
type="button"
>
{t("try_again")}
</EnteButton>
</FocusVisibleButton>
<EnteButton
<FocusVisibleButton
onClick={handleCheckStatus}
fullWidth
color="accent"
type="button"
>
{t("check_status")}
</EnteButton>
</FocusVisibleButton>
</ButtonStack>
</VerifyingPasskeyMiddle>

View File

@@ -1,12 +1,13 @@
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
import { LoadingButton } from "@/base/components/mui/LoadingButton";
import { FlexWrapper } from "@ente/shared/components/Container";
import ShowHidePassword from "@ente/shared/components/Form/ShowHidePassword";
import { Button, FormHelperText } from "@mui/material";
import { FormHelperText } from "@mui/material";
import TextField from "@mui/material/TextField";
import { Formik, type FormikHelpers, type FormikState } from "formik";
import { t } from "i18next";
import React, { useMemo, useState } from "react";
import * as Yup from "yup";
import SubmitButton from "./SubmitButton";
interface formValues {
inputValue: string;
@@ -170,7 +171,7 @@ export default function SingleInputForm(props: SingleInputFormProps) {
flexWrap={props.blockButton ? "wrap-reverse" : "nowrap"}
>
{props.secondaryButtonAction && (
<Button
<FocusVisibleButton
onClick={props.secondaryButtonAction}
size="large"
color="secondary"
@@ -185,19 +186,24 @@ export default function SingleInputForm(props: SingleInputFormProps) {
{...restSubmitButtonProps}
>
{t("cancel")}
</Button>
</FocusVisibleButton>
)}
<SubmitButton
<LoadingButton
sx={{
"&&&": {
mt: 2,
...buttonSx,
},
}}
buttonText={props.buttonText}
size="large"
variant="contained"
color="accent"
type="submit"
loading={loading}
{...restSubmitButtonProps}
/>
>
{props.buttonText}
</LoadingButton>
</FlexWrapper>
</form>
)}

View File

@@ -1,53 +0,0 @@
import Done from "@mui/icons-material/Done";
import { Button, CircularProgress, type ButtonProps } from "@mui/material";
import React from "react";
export interface SubmitButtonProps {
loading: boolean;
buttonText: string;
disabled?: boolean;
success?: boolean;
}
const SubmitButton: React.FC<ButtonProps<"button", SubmitButtonProps>> = ({
loading,
buttonText,
disabled,
success,
sx,
...props
}) => {
return (
<Button
size="large"
variant="contained"
color="accent"
type="submit"
disabled={disabled || loading || success}
sx={{
my: 4,
...(loading
? {
"&.Mui-disabled": {
backgroundColor: (theme) =>
theme.colors.accent.A500,
color: (theme) => theme.colors.text.base,
},
}
: {}),
...sx,
}}
{...props}
>
{loading ? (
<CircularProgress size={20} />
) : success ? (
<Done sx={{ fontSize: 20 }} />
) : (
buttonText
)}
</Button>
);
};
export default SubmitButton;