152 lines
3.2 KiB
TypeScript
152 lines
3.2 KiB
TypeScript
import type { FC } from "react";
|
|
|
|
import {
|
|
Alert,
|
|
Button,
|
|
Modal,
|
|
PasswordInput,
|
|
Stack,
|
|
Text,
|
|
} from "@mantine/core";
|
|
|
|
import { ApiErrorCode, isApiErrorCode } from "@/shared/api";
|
|
|
|
import { type TbankConnectionStatus } from "../../model/connection-boundary";
|
|
import { useTbankConnectionSectionLoadedVm } from "./TbankConnectionSectionLoaded.vm";
|
|
|
|
type TbankConnectionSectionLoadedProps = {
|
|
refreshError: boolean;
|
|
refreshing: boolean;
|
|
retry: () => void;
|
|
status: TbankConnectionStatus;
|
|
};
|
|
|
|
const TbankConnectionSectionLoaded: FC<TbankConnectionSectionLoadedProps> = (
|
|
props,
|
|
) => {
|
|
const {
|
|
errors,
|
|
isConnected,
|
|
isDeleteOpened,
|
|
isPending,
|
|
onCloseDisconnect,
|
|
onConfirmDisconnect,
|
|
onOpenDisconnect,
|
|
onSubmit,
|
|
register,
|
|
removalButtonRef,
|
|
remove,
|
|
requestError,
|
|
status,
|
|
t,
|
|
unavailableMessage,
|
|
update,
|
|
} = useTbankConnectionSectionLoadedVm(props);
|
|
|
|
return (
|
|
<Stack mt="xl">
|
|
<Text fw={600}>{t("tbank.title")}</Text>
|
|
|
|
<Text size="sm">
|
|
{isConnected
|
|
? t("tbank.connected", {
|
|
date: new Date(status.connectedAt ?? "").toLocaleDateString(
|
|
"ru-RU",
|
|
),
|
|
})
|
|
: t("tbank.disconnected")}
|
|
</Text>
|
|
|
|
<Text c="dimmed" size="sm">
|
|
{t("tbank.hint")}
|
|
</Text>
|
|
|
|
{props.refreshing && (
|
|
<Text c="dimmed" role="status" size="sm">
|
|
{t("tbank.refreshing")}
|
|
</Text>
|
|
)}
|
|
|
|
{props.refreshError && (
|
|
<Alert aria-live="polite" color="orange" role="status">
|
|
<Stack gap="sm">
|
|
<Text>{t("tbank.refreshError")}</Text>
|
|
|
|
<Button
|
|
disabled={props.refreshing || isPending}
|
|
onClick={props.retry}
|
|
variant="default"
|
|
>
|
|
{t("tbank.retry")}
|
|
</Button>
|
|
</Stack>
|
|
</Alert>
|
|
)}
|
|
|
|
<form onSubmit={onSubmit}>
|
|
<fieldset disabled={isPending}>
|
|
<Stack>
|
|
<PasswordInput
|
|
label={t("tbank.token")}
|
|
{...register("token", { required: t("tbank.tokenRequired") })}
|
|
error={errors.token?.message}
|
|
/>
|
|
|
|
{requestError && (
|
|
<Alert color="red">
|
|
{t(
|
|
isApiErrorCode(requestError, ApiErrorCode.InvalidTbankToken)
|
|
? "tbank.invalidToken"
|
|
: unavailableMessage,
|
|
)}
|
|
</Alert>
|
|
)}
|
|
|
|
<Button loading={update.isPending} type="submit">
|
|
{t(isConnected ? "tbank.replace" : "tbank.connect")}
|
|
</Button>
|
|
|
|
{isConnected && (
|
|
<Button color="red" onClick={onOpenDisconnect} variant="outline">
|
|
{t("tbank.delete")}
|
|
</Button>
|
|
)}
|
|
</Stack>
|
|
</fieldset>
|
|
</form>
|
|
|
|
<Modal
|
|
closeButtonProps={{
|
|
"aria-label": t("tbank.close"),
|
|
"disabled": isPending,
|
|
}}
|
|
closeOnClickOutside={!isPending}
|
|
closeOnEscape={!isPending}
|
|
onClose={onCloseDisconnect}
|
|
opened={isDeleteOpened}
|
|
title={t("tbank.deleteTitle")}
|
|
>
|
|
<Stack>
|
|
<Text>{t("tbank.deleteText")}</Text>
|
|
|
|
{remove.isError && (
|
|
<Alert color="red">{t("tbank.requestError")}</Alert>
|
|
)}
|
|
|
|
<Button
|
|
color="red"
|
|
disabled={isPending}
|
|
loading={remove.isPending}
|
|
onClick={onConfirmDisconnect}
|
|
ref={removalButtonRef}
|
|
>
|
|
{t("tbank.deleteConfirm")}
|
|
</Button>
|
|
</Stack>
|
|
</Modal>
|
|
</Stack>
|
|
);
|
|
};
|
|
|
|
export { TbankConnectionSectionLoaded };
|