Files
frontend/src/features/tbank-connection/ui/TbankConnectionSection/TbankConnectionSectionLoaded.tsx
T
ksv741 ca0ad4f824
Frontend verify / commits (pull_request) Successful in 28s
Frontend verify / security (pull_request) Successful in 10s
Frontend verify / verify (pull_request) Successful in 8m19s
refactor: enforce frontend view model boundaries
2026-09-28 18:48:23 +03:00

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 };