Загрузка данных
dmitriev-aal@VDI-Dmitriev-A:~/Desktop/rshbintech/crft/ckof/ownfin/frontend/prd/autopayments-ui$ cat src/client/view/auto-payment-edit-page/index.tsx
import {
BasicAction,
NavigationBar,
useTemplateLayout,
} from "@rshbintech.ckof.ownfin/core-ui";
import { useEffect, useMemo, useRef } from "react";
import { useParams, useNavigate, generatePath } from "react-router-dom";
import { Icons } from "@rshbintech.ckof.ownfin/icons";
import { useAppSelector } from "src/hooks";
import { ToastNotificationContainer } from "src/client/shared/ui/toast-notification-container";
import {
getAutoPaymentsSelector,
getTemplateByIdSelector,
selectNewAdditionalAccount,
} from "src/client/model/get-auto-payments/selectors";
import { useScrollAnchor } from "src/client/view/auto-transfer-edit-page/use-scroll-anchor";
import { useNameInput } from "src/client/view/auto-transfer-edit-page/hooks/use-name-input";
import { AmountInputPage } from "src/client/view/auto-transfer-edit-page/components/amount-input-page";
import { useAmountInputPage } from "src/client/view/auto-transfer-edit-page/hooks/use-amount-input-page";
import { useEditFormState } from "src/client/view/auto-transfer-edit-page/hooks/use-edit-form-state";
import { useSaveEntityChanges } from "src/client/view/auto-transfer-edit-page/hooks/use-save-changes/use-save-changes";
import { useFormChanges } from "src/client/view/auto-transfer-edit-page/hooks/use-form-changes/use-form-changes";
import { FormChangesResultWithAdditional } from "src/client/view/auto-transfer-edit-page/hooks/use-form-changes/types";
import { EntityType } from "src/client/view/auto-transfer-edit-page/hooks/use-save-changes/types";
import { accountsSelector } from "src/client/model/accounts-payments/selectors";
import { ROUTES } from "src/constants";
import { PaymentRecurrentType } from "src/client/common/types";
import { EditForm } from "./components/edit-form";
import { usePaymentScheduleNavigation } from "./hooks/use-schedule-navigation/use-payment-schedule-navigation";
import { convertScheduleTypeToPayment, validateAmount } from "./utils";
import {
HEADER_TEXT,
DATA_TEST_ID_PAGE,
SAVE_CHANGES_BASIC_ACTION_TITLE,
} from "./constants";
import styles from "./styles.scss";
export const AutoPaymentEditPage = () => {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const autoPayment = useAppSelector(getTemplateByIdSelector);
const autoPaymentsData = useAppSelector(getAutoPaymentsSelector);
const templateById = (autoPaymentsData ?? []).find(
(template) => template.id === id
);
const screenRef = useRef<HTMLDivElement>(null);
const { withShadowBottom, scrollHandler } = useTemplateLayout({ screenRef });
const accounts = useAppSelector(accountsSelector);
const newAdditionalAccount = useAppSelector(selectNewAdditionalAccount);
const {
containerRef: formsContainerRef,
bottomRef,
bottomStyle,
scrollToBottom,
} = useScrollAnchor();
const formState = useEditFormState({
entity: autoPayment,
userProducts: accounts,
getAmount: (entity) => entity.amount?.toString() || "",
getProductId: (entity) => entity.accountId,
getUserProductId: (product) => product.id,
});
const nameInput = useNameInput("", scrollToBottom);
useEffect(() => {
const state = formState.locationState;
if (state?.nameValue !== undefined) {
nameInput.setNameValue(state.nameValue);
formState.setLocationState(null);
} else if (autoPayment?.name && !nameInput.nameValue) {
nameInput.setNameValue(autoPayment.name);
}
}, [autoPayment?.name, formState.locationState]);
const amountInputPage = useAmountInputPage({
entity: autoPayment,
amountValue: formState.amountValue,
setAmountValue: formState.setAmountValue,
onGoBackFromMain: () =>
navigate(
generatePath(ROUTES.AUTO_PAYMENT_DETAIL_PAGE, { id: autoPayment?.id })
),
});
const hasActualScheduleChanges = useMemo(() => {
if (!autoPayment || !formState.scheduleChanges) {
return false;
}
const newScheduleType = convertScheduleTypeToPayment(
formState.scheduleChanges.scheduleType
);
const initRecurrentType = autoPayment.recurrentType;
const sameScheduleTypes = newScheduleType === initRecurrentType;
const areArraysEqual = (
arr1: number[] | undefined,
arr2: number[] | undefined
) => {
if (arr1 === arr2) {
return true;
}
if (!arr1 || !arr2) {
return false;
}
if (arr1.length !== arr2.length) {
return false;
}
const sorted1 = [...arr1].sort((a, b) => a - b);
const sorted2 = [...arr2].sort((a, b) => a - b);
return sorted1.every((value, index) => value === sorted2[index]);
};
if (sameScheduleTypes) {
if (
newScheduleType === PaymentRecurrentType.DAILY &&
initRecurrentType === PaymentRecurrentType.DAILY
) {
return false;
}
if (
newScheduleType === PaymentRecurrentType.WEEKLY &&
initRecurrentType === PaymentRecurrentType.WEEKLY
) {
return !areArraysEqual(
formState.scheduleChanges.weekDays,
autoPayment.days
);
}
if (
newScheduleType === PaymentRecurrentType.MONTHLY &&
initRecurrentType === PaymentRecurrentType.MONTHLY
) {
return !areArraysEqual(
formState.scheduleChanges.monthDays,
autoPayment.days
);
}
}
return true;
}, [autoPayment, formState.scheduleChanges]);
const formChanges = useFormChanges({
amountValue: formState.amountValue,
nameValue: nameInput.nameValue,
activeProductIndex: formState.activeProductIndex,
initialProductIndex: formState.initialProductIndexRef.current,
scheduleChanges: formState.scheduleChanges,
hasScheduleChangesFlag: hasActualScheduleChanges,
entity: autoPayment,
userProducts: accounts,
additionalAccountId: newAdditionalAccount,
}) as FormChangesResultWithAdditional;
const saveChanges = useSaveEntityChanges({
id,
entityType: EntityType.PAYMENT,
autoPayment,
userProducts: accounts,
activeProductIndex: formState.activeProductIndex,
amountValue: formState.amountValue,
nameValue: nameInput.nameValue,
scheduleChanges: formState.scheduleChanges,
hasSumChanged: formChanges.hasSumChanged,
hasNameChanged: formChanges.hasNameChanged,
hasAccountChanged: formChanges.hasAccountChanged,
hasScheduleChanged: formChanges.hasScheduleChanged,
hasChanges: formChanges.hasChanges,
hasAdditionalAccountChanged: formChanges.hasAdditionalAccountChanged,
newAdditionalAccount,
});
const scheduleNavigation = usePaymentScheduleNavigation({
id,
autoPayment,
scheduleChanges: formState.scheduleChanges,
amountValue: formState.amountValue,
nameValue: nameInput.nameValue,
activeProductIndex: formState.activeProductIndex,
});
useEffect(() => {
if (id && !autoPayment) {
navigate(-1);
}
}, [id, autoPayment, navigate]);
const isAmountError = useMemo(
() => validateAmount(formState.amountValue),
[formState.amountValue]
);
if (!autoPayment || !accounts) {
return null;
}
return (
<div
className={styles["auto-payment-edit-page"]}
data-test-id={DATA_TEST_ID_PAGE}
ref={screenRef}
onScroll={scrollHandler}
>
<NavigationBar
title={HEADER_TEXT}
leftButton={<Icons.ArrowLeftBase />}
onLeftButtonClick={amountInputPage.handleGoBack}
background
safeTop
className={styles["nav-bar"]}
fixed
/>
<div className={styles["content-wrapper"]}>
{amountInputPage.isAmountInputPage ? (
<AmountInputPage
amountValue={formState.amountValue}
currency={templateById?.currency}
amountInputRef={amountInputPage.amountInputRef}
onAmountChange={formState.setAmountValue}
onGoBack={amountInputPage.handleGoBack}
isAmountInputPage={amountInputPage.isAmountInputPage}
onBackToForm={amountInputPage.backToForm}
onFocus={nameInput.handleNameInputFocus}
onBlur={nameInput.handleNameInputBlur}
/>
) : (
<>
<EditForm
autoPayment={autoPayment}
currency={templateById?.currency}
activeProductIndex={formState.activeProductIndex}
amountValue={formState.amountValue}
nameValue={nameInput.nameValue}
scheduleChanges={formState.scheduleChanges}
isAmountError={isAmountError}
nameInputRef={nameInput.nameInputRef}
formsContainerRef={formsContainerRef}
bottomRef={bottomRef}
bottomStyle={bottomStyle}
onProductChange={formState.setActiveProductIndex}
onAmountClick={amountInputPage.handleSumClick}
onNameChange={nameInput.handleNameValueChange}
onNameFocus={nameInput.handleNameInputFocus}
onNameBlur={nameInput.handleNameInputBlur}
onScheduleClick={scheduleNavigation.handleScheduleClick}
/>
<BasicAction
disablePrimaryButton={!formChanges.hasChanges}
onButtonClick={saveChanges.handleSaveChanges}
isLoadingPrimaryButton={saveChanges.isLoading}
fixed
safeBottom={!nameInput.isInputFocused}
shadow={withShadowBottom}
>
{SAVE_CHANGES_BASIC_ACTION_TITLE}
</BasicAction>
</>
)}
</div>
{saveChanges.fullScreenLoader}
<ToastNotificationContainer targetPage={DATA_TEST_ID_PAGE} />
</div>
);
};