Загрузка данных


import { useDeviceRepository } from '@/domains/equipment/repositories/device.repository';
import { normalizeSipUriForPayload } from '@/domains/equipment/repositories/helpers/normalizeSipUriForPayload';
import { useNetInterfaceRepository } from '@/domains/equipment/repositories/netInterface.repository';
import { Helpers } from '@/shared/lib';
import { useDeviceActions } from '@/shared/store/сontrollers/device.actions';
import { yupResolver } from '@hookform/resolvers/yup';
import { QueryStatus } from '@reduxjs/toolkit/dist/query';
import { DrawerProps } from '@sber-friend/flamingo-core';
import {
  DeviceModel,
  Ieee8021X,
  InterfaceType,
  useGetApiV1SecondaryInterfaceValueOwnerByOwnerIdQuery,
  useGetDeviceByIdQuery,
} from '@shared/api/controller/client';
import { Button, Drawer } from '@shared/components';
import { useCloseDrawer } from '@shared/hooks/drawer/useCloseDrawer';
import { useSelectDrawerType } from '@shared/hooks/drawer/useSelectDrawerType';
import {
  EventActionTypes,
  useSendClickStreamEvent,
} from '@shared/hooks/useSendClickStreamEvent';
import { DrawerTypes } from '@shared/model/drawer/drawer.types';
import { useSelectActiveDeviceId } from '@shared/store/сontrollers/сontrollers.selectors';
import { useSyncControlPage } from '@widgets/Monitoring/hooks';
import { memo, useEffect, useState } from 'react';
import {
  FormProvider,
  Resolver,
  SubmitHandler,
  useForm,
} from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { UpdateDeviceForm } from './UpdateDeviceForm/UpdateDeviceForm';
import { OTHER_VALUES } from './model/formNames';
import { UpdateDeviceFormData } from './model/types';
import { updateDeviceSchema } from './validation/validator';

export const UpdateDeviceDrawer = memo(() => {
  const { t } = useTranslation('common');
  const { sendEvent } = useSendClickStreamEvent(EventActionTypes.updateDevice);

  const closeDrawer = useCloseDrawer();
  const { setActiveDeviceId } = useDeviceActions();
  const drawerType = useSelectDrawerType();
  const open = drawerType[DrawerTypes.updateDevice];
  const activeDeviceId = useSelectActiveDeviceId();

  const { updateDevice, updateDeviceStatus, isUpdateDeviceLoading } =
    useDeviceRepository();

  const { isSuccess: isDeviceSuccess, currentData: device } =
    useGetDeviceByIdQuery(
      { deviceId: activeDeviceId! },
      {
        skip: !activeDeviceId,
        refetchOnMountOrArgChange: true,
        refetchOnReconnect: true,
      },
    );

  const id = device?.id;

  const {
    data: secondaryInterfaceData,
    isSuccess: isSecondaryInterfaceSuccess,
  } = useGetApiV1SecondaryInterfaceValueOwnerByOwnerIdQuery(
    { ownerId: id! },
    { skip: !id },
  );

  const defaultValues: UpdateDeviceFormData = {
    name: device?.name,
    description: device?.description,
    ip: device?.ip || '',
    controlPage: device?.controlPage ?? '',
    hardwareId: device?.hardwareId,
    type:
      (device?.interface?.type?.toLowerCase().trim() as InterfaceType) ?? '',
    bidirectional: Boolean(device?.bidirectional),
    mac: device?.mac ?? '',
    manufacturerName: device?.model?.manufacturer?.name,
    typeName: device?.model?.type?.name,
    sipUri: device?.sipUri ?? '',
    hasSipUri: device?.model?.type?.hasSipUri ?? null,
    modelId: device?.model?.id,
    firmware: device?.firmware,
    serialNumber: device?.serialNumber,
    inventoryNumber: device?.inventoryNumber,
    protocolIp: device?.interface?.protocolIp,
    ipAvLan: device?.interface?.ipAvLan ?? '',
    port: device?.interface?.port,
    // TODO Саша будет присылать null либо не будет присылать поле вовсе
    ieee8021x:
      device?.interface?.ieee8021x === ('' as Ieee8021X)
        ? undefined
        : device?.interface?.ieee8021x,
    netInterface: !!secondaryInterfaceData?.length,
    netInterfaceInfo: secondaryInterfaceData?.map((secondaryInterface) => {
      return {
        gateway: secondaryInterface.gateway,
        mac: secondaryInterface.mac,
        ip: secondaryInterface.ip,
        subnetMask: secondaryInterface.subnetMask,
        nameId: secondaryInterface.name?.id,
        id: secondaryInterface.id,
      };
    }),
    disableMonitoring: device?.disableMonitoring ?? false,
  };

  useEffect(() => {
    if (isSecondaryInterfaceSuccess && secondaryInterfaceData) {
      methods.setValue(
        OTHER_VALUES.netInterface,
        !!secondaryInterfaceData?.length,
      );
      methods.setValue(
        OTHER_VALUES.netInterfaceInfo,
        secondaryInterfaceData?.map((secondaryInterface) => {
          return {
            gateway: secondaryInterface.gateway,
            mac: secondaryInterface.mac,
            ip: secondaryInterface.ip,
            subnetMask: secondaryInterface.subnetMask,
            nameId: secondaryInterface.name?.id,
            id: secondaryInterface.id,
          };
        }),
      );
    }
  }, [isSecondaryInterfaceSuccess, secondaryInterfaceData]);

  const methods = useForm<UpdateDeviceFormData>({
    mode: 'onBlur',
    reValidateMode: 'onChange',
    defaultValues,
    resolver: yupResolver(updateDeviceSchema) as Resolver<UpdateDeviceFormData>,
  });

  const netInterfaceInfo = methods.watch(OTHER_VALUES.netInterfaceInfo);
  const netInterface = methods.watch(OTHER_VALUES.netInterface);

  const { deleteNetInterfaces } = useNetInterfaceRepository();

  const [model, setModel] = useState<DeviceModel | null>(null);

  useEffect(() => {
    if (device?.model) {
      setModel(device.model);
    }
  }, [device]);

  const handleClearModel = () => {
    methods.setValue('modelId', '');
    methods.setValue('manufacturerName', '');
    methods.setValue('typeName', '');
    methods.setValue('hasSipUri', null);
  };

  useEffect(() => {
    if (model) {
      methods.setValue('manufacturerName', model?.manufacturer?.name);
      methods.setValue('typeName', model?.type?.name);
      methods.setValue('hasSipUri', model.type?.hasSipUri);
    }
  }, [model]);

  useEffect(() => {
    (async () => {
      if (
        !netInterface &&
        isSecondaryInterfaceSuccess &&
        netInterfaceInfo &&
        !!netInterfaceInfo.length
      ) {
        await deleteNetInterfaces(
          netInterfaceInfo?.map((netInterface) => netInterface.id),
        );

        methods.setValue(OTHER_VALUES.netInterfaceInfo, []);
      }
    })();
  }, [netInterface, netInterfaceInfo, isSecondaryInterfaceSuccess]);

  useSyncControlPage(device?.ip, methods);

  useEffect(() => {
    if (updateDeviceStatus === QueryStatus.fulfilled) {
      closeDrawer(DrawerTypes.updateDevice);
      sendEvent();
    }
  }, [updateDeviceStatus]);

  const submitHandler: SubmitHandler<UpdateDeviceFormData> = async (values) => {
    if (device?.id) {
      await updateDevice(normalizeSipUriForPayload(values), device.id);
    }
  };

  useEffect(() => {
    if (isDeviceSuccess && device && open && id) {
      methods.reset(defaultValues);
    }
  }, [device, open, isDeviceSuccess, id]);

  const { isValid, dirtyFields } = methods.formState;
  const isDirtyFields = !Helpers.isEmpty(dirtyFields);
  const isSaveButtonDisabled = !isDirtyFields || !isValid;

  const actions = {
    actionPrimary: (
      <Button
        onClick={methods.handleSubmit(submitHandler)}
        loading={isUpdateDeviceLoading}
        disabled={isSaveButtonDisabled}
      >
        {t('buttons.save')}
      </Button>
    ),
  };

  const handleClose: DrawerProps['onClose'] = () => {
    methods.reset(defaultValues);
    setModel(null);
  };

  if (!device) {
    return null;
  }

  return (
    <FormProvider {...methods}>
      <Drawer
        type={DrawerTypes.updateDevice}
        actions={actions}
        title={t('drawerTitle.updateDevice')}
        onClose={handleClose}
      >
        <UpdateDeviceForm
          initialModel={device?.model}
          setModel={setModel}
          handleClearModel={handleClearModel}
        />
      </Drawer>
    </FormProvider>
  );
});