вот мой фронт. я возвращаю с бэкэнда данные изделий модели ItemRead. при редактировании изделия, мне нужно вывести картинки из projections в ComplexItemPane


class ItemBase(BaseModel):
    name: str
    type: str
    thumbnail: Optional[bytes] = None

class ItemCreate(ItemBase):
    projections: List[ProjectionCreate] = Field(..., min_length=6, max_length=6)

    model_config = ConfigDict(from_attributes=True)

class ItemUpdate(BaseModel): # Для частичного обновления
    name: Optional[str] = None
    type: Optional[str] = None
    thumbnail: Optional[bytes] = None
    delete_mark: Optional[bool] = None

class ItemRead(ItemBase):
    id: int
    delete_mark: bool
    insert_time: datetime

    model_config = ConfigDict(from_attributes=True)

    projections: List[ProjectionRead] = []
    # defects: List[DefectRead] = []


class ProjectionBase(BaseModel):
    number: int
    image: bytes
    grid_resolution_x: int
    grid_resolution_y: int
    image_offset_x: int
    image_offset_y: int

class ProjectionCreate(ProjectionBase):
    pass

class ProjectionUpdate(BaseModel):
    number: Optional[int] = None
    image: Optional[bytes] = None
    grid_resolution_x: Optional[int] = None
    grid_resolution_y: Optional[int] = None
    image_offset_x: Optional[int] = None
    image_offset_y: Optional[int] = None

class ProjectionRead(ProjectionBase):
    id: int
    item_id: int
    insert_time: datetime

    model_config = ConfigDict(from_attributes=True)



import React, { useRef } from 'react';
import {
  Button,
  LoadIndicator,
  TextBox,
  DataGrid,
  Autocomplete,
  TabPanel,
  ScrollView,
  FileUploader,
  CheckBox,
  SelectBox,
} from 'devextreme-react';
import {
  Column,
  Paging,
  Pager,
  Editing,
  RequiredRule,
  Lookup,
  Button as DataGridButton,
} from 'devextreme-react/data-grid';
import { Item } from 'devextreme-react/tab-panel';
import Popup, { ToolbarItem } from 'devextreme-react/popup';
import { useCallback, useEffect, useState } from 'react';
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';
import DataSource from 'devextreme/data/data_source';
import CustomStore from 'devextreme/data/custom_store';
import { useFetching } from './useFetching';
import ADAPIAuth from './api';
import { confirm } from 'devextreme/ui/dialog';
import { ComplexItemPane } from 'arm-ui';

const RECENT_LOGINS_KEY = 'recentLogins';
const MAX_RECENT_LOGINS = 5;

function App() {
  const [token, setToken] = useState(() =>
    window.localStorage.getItem('token')
  );
  const [message, setMessage] = useState('');
  const [error, setError] = useState(null);
  const [statusData, setStatusData] = useState(null);
  const [usersDataSource, setUsersDataSource] = useState(null);
  const [banListDataSource, setBanListDataSource] = useState(null);
  const [productsDataSource, setProductsDataSource] = useState(null);
  const [typesDataSource, setTypesDataSource] = useState(null); // Добавлено для видов
  const [roles, setRoles] = useState([]);
  const [types, setTypes] = useState([]); // Добавлено для хранения видов
  const [showAdminPanel, setShowAdminPanel] = useState(false);
  const [productPopupVisible, setProductPopupVisible] = useState(false);
  const [currentProduct, setCurrentProduct] = useState(null);
  const [productProjections, setProductProjections] = useState([]);
  const [selectedTabIndex, setSelectedTabIndex] = useState(0);

  const [recentLogins, setRecentLogins] = useState(() => {
    try {
      const savedLogins = window.localStorage.getItem(RECENT_LOGINS_KEY);
      return savedLogins ? JSON.parse(savedLogins) : [];
    } catch {
      return [];
    }
  });

  const loginAutocompleteRef = useRef(null);
  const passwdRef = useRef(null);
  const dataGridRef = useRef(null);
  const banListGridRef = useRef(null);
  const productsGridRef = useRef(null);
  const typesGridRef = useRef(null); // Добавлено для grid видов

  const [performLogin, isLoginLoading] = useFetching(
    async (login, password) => {
      try {
        const response = await ADAPIAuth.postLogin(login, password);
        const accessToken = response.data.token.access_token;
        setToken(accessToken);
        setMessage('Вы успешно вошли в систему!');

        const updatedLogins = recentLogins.filter((l) => l !== login);
        updatedLogins.unshift(login);
        const trimmedLogins = updatedLogins.slice(0, MAX_RECENT_LOGINS);

        setRecentLogins(trimmedLogins);
        window.localStorage.setItem(
          RECENT_LOGINS_KEY,
          JSON.stringify(trimmedLogins)
        );
      } catch (e) {
        setError(e);
        setToken(null);
      }
    }
  );

  const [performCheckStatus, isStatusLoading] = useFetching(async () => {
    if (!token) return;
    try {
      const response = await ADAPIAuth.getTokenInfo(token);
      setStatusData(response.data);
      setMessage('Токен действителен. Статус пользователя получен.');
    } catch (e) {
      setError(e);
      setStatusData(null);
      if (e.response?.status === 401 || e.response?.status === 403) {
        setToken(null);
        setMessage('Сессия истекла. Пожалуйста, войдите снова.');
      }
    }
  });

  const [performLogout, isLogoutLoading] = useFetching(async () => {
    if (!token) return;
    try {
      await ADAPIAuth.logout(token);
    } catch (e) {
      console.error('Ошибка при выходе на бэкенде:', e);
    } finally {
      setToken(null);
      setMessage('Вы успешно вышли из системы.');
    }
  });

  const [performEndUserSession, isEndUserSessionLoading] = useFetching(
    async (userId) => {
      if (!token) return;
      try {
        await ADAPIAuth.endUserSession(token, userId);
        setMessage(`Сессия пользователя с ID ${userId} успешно завершена.`);

        if (dataGridRef.current) {
          dataGridRef.current.instance().refresh();
        }
      } catch (e) {
        setError(e);
        throw e;
      }
    }
  );

  const [performFetchRoles, areRolesLoading] = useFetching(async () => {
    if (!token) return;
    try {
      const response = await ADAPIAuth.getRoles(token);
      setRoles(response.data);
    } catch (e) {
      console.error('Не удалось загрузить роли:', e);
      setError(e);
    }
  });

  // Добавлено для загрузки видов
  const [performFetchTypes, areTypesLoading] = useFetching(async () => {
    if (!token) return;
    try {
      const response = await ADAPIAuth.getTypes(token);
      setTypes(response.data);
    } catch (e) {
      console.error('Не удалось загрузить виды:', e);
      setError(e);
    }
  });

function fileToBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => {
      const base64str = reader.result.split(',')[1]; // без префикса data:image/...base64,
      resolve(base64str);
    };
    reader.onerror = error => reject(error);
    reader.readAsDataURL(file);
  });
}

  const prepareProjectionsForSend = async (projectionsObj) => {
  const arr = Object.values(projectionsObj);

  const prepared = await Promise.all(arr.map(async (proj, index) => {
    // Конвертация файла в base64
    let imageBase64 = null;
    if (proj.file instanceof File) {
      imageBase64 = await fileToBase64(proj.file);
    } else if (typeof proj.file === 'string') {
      // Если уже base64 строка
      imageBase64 = proj.file;
    } else {
      throw new Error(`Проекция ${index + 1} не содержит корректное поле file.`);
    }

    return {
      number: index + 1,  // или по вашему assignment, важно чтобы совпадал с backend
      image: imageBase64, // base64 строка без префикса, будет десериализована как bytes на backend
      grid_resolution_x: proj.gridWidth,
      grid_resolution_y: proj.gridHeight,
      image_offset_x: proj.imageOffsetX || 0,
      image_offset_y: proj.imageOffsetY || 0,
    };
  }));

  return prepared;
};

const createItem = async () => {
  try {
    if (!currentProduct) {
      setError(new Error('Нет данных изделия для создания'));
      return;
    }

    if (!productProjections) {
      setError(new Error('Нет данных проекций'));
      return;
    }

    const projectionsArray = await prepareProjectionsForSend(productProjections);

    if (projectionsArray.length !== 6) {
      setError(new Error('Должно быть ровно 6 проекций'));
      return;
    }

    const newItemData = {
      ...currentProduct,
      projections: projectionsArray,
      delete_mark: false,
    };

    await ADAPIAuth.createItem(token, newItemData);

    if (productsGridRef.current) {
      await productsGridRef.current.instance().refresh();
    }

    setMessage('Изделие успешно создано.');
    setProductPopupVisible(false);
    setCurrentProduct(null);
    setProductProjections([]);
  } catch (e) {
    setError(e);
  }
};

  const clearUiState = () => {
    setMessage('');
    setError(null);
  };

  const handleLogin = useCallback(() => {
    clearUiState();
    performLogin(
      loginAutocompleteRef.current.instance().option('value'),
      passwdRef.current.instance().option('value')
    );
  }, [performLogin, recentLogins]);

  const handleCheckStatus = useCallback(() => {
    clearUiState();
    performCheckStatus();
  }, [performCheckStatus]);

  const handleLogout = useCallback(() => {
    clearUiState();
    performLogout();
  }, [performLogout]);

  const handleOpenAdminPanel = useCallback(() => {
    clearUiState();
    setShowAdminPanel(true);

    // Загружаем пользователей
    setUsersDataSource(
      new DataSource({
        store: new CustomStore({
          key: 'id',
          load: async () => {
            try {
              const response = await ADAPIAuth.getAllUsers(token);
              return response.data;
            } catch (e) {
              setError(e);
              throw e;
            }
          },
          update: async (key, values) => {
            if (values.password === undefined || values.password === '') {
              delete values.password;
            }
            try {
              await ADAPIAuth.updateUser(token, key, values);
              setMessage(`Пользователь с ID ${key} успешно обновлен.`);
            } catch (e) {
              setError(e);
              throw e;
            }
          },
          insert: async (values) => {
            try {
              await ADAPIAuth.createUser(token, values);
              setMessage('Пользователь успешно создан.');
            } catch (e) {
              setError(e);
              throw e;
            }
          },
        }),
      })
    );

    // Загружаем бан-лист
    setBanListDataSource(
      new DataSource({
        store: new CustomStore({
          key: 'ip',
          load: async () => {
            try {
              const response = await ADAPIAuth.getBanList(token);
              return response.data;
            } catch (e) {
              setError(e);
              throw e;
            }
          },
          remove: async (key) => {
            try {
              await ADAPIAuth.removeBan(token, key);
              setMessage(`IP адрес ${key} успешно удален из бан-листа.`);
            } catch (e) {
              setError(e);
              throw e;
            }
          },
        }),
      })
    );

    // Загружаем изделия
    setProductsDataSource(
      new DataSource({
        store: new CustomStore({
          key: 'id',
          load: async () => {
            try {
              const response = await ADAPIAuth.getAllItems(token);
              return response.data;
            } catch (e) {
              setError(e);
              throw e;
            }
          },
          update: async (key, values) => {
            try {
              await ADAPIAuth.updateProduct(token, key, values);
              setMessage(`Изделие с ID ${key} успешно обновлено.`);
            } catch (e) {
              setError(e);
              throw e;
            }
          },
          insert: async (values) => {
            try {
              await ADAPIAuth.createProduct(token, values);
              setMessage('Изделие успешно создано.');
            } catch (e) {
              setError(e);
              throw e;
            }
          },
          remove: async (key) => {
            try {
              await ADAPIAuth.deleteProduct(token, key);
              setMessage(`Изделие с ID ${key} успешно удалено.`);
            } catch (e) {
              setError(e);
              throw e;
            }
          },
        }),
      })
    );

    // Загружаем виды
    setTypesDataSource(
      new DataSource({
        store: new CustomStore({
          key: 'id',
          load: async () => {
            try {
              const response = await ADAPIAuth.getTypes(token);
              setTypes(response.data); // Обновляем и локальный state
              return response.data;
            } catch (e) {
              setError(e);
              throw e;
            }
          },
          insert: async (values) => {
            try {
              await ADAPIAuth.createType(token, values);
              setMessage('Вид успешно создан.');
              // Обновляем список видов после создания
              performFetchTypes();
            } catch (e) {
              setError(e);
              throw e;
            }
          },
          update: async (key, values) => {
            try {
              await ADAPIAuth.updateType(token, key, values);
              setMessage(`Вид с ID ${key} успешно обновлен.`);
              // Обновляем список видов после обновления
              performFetchTypes();
            } catch (e) {
              setError(e);
              throw e;
            }
          },
          remove: async (key) => {
            try {
              await ADAPIAuth.deleteType(token, key);
              setMessage(`Вид с ID ${key} успешно удален.`);
              // Обновляем список видов после удаления
              performFetchTypes();
            } catch (e) {
              setError(e);
              throw e;
            }
          },
        }),
      })
    );

    // Загружаем роли и виды
    performFetchRoles();
    performFetchTypes();
  }, [token, performFetchRoles, performFetchTypes]);

  const handleEndUserSession = useCallback(
    (userData) => {
      clearUiState();

      if (statusData && statusData.id === userData.id) {
        alert('Вы не можете завершить собственный сеанс.');
        return;
      }

      const result = confirm(
        `Вы уверены, что хотите завершить все сеансы для пользователя <b>${userData.username}</b>?`,
        'Подтверждение действия'
      );
      result.then((dialogResult) => {
        if (dialogResult) {
          performEndUserSession(userData.id);
        }
      });
    },
    [performEndUserSession, statusData]
  );

  const handleAddProduct = () => {
    setCurrentProduct({
      id: null,
      name: '',
      type: '',
      delete_mark: false,
      projections: [],
    });
    setProductProjections([]);
    setProductPopupVisible(true);
  };

  const handleEditProduct = (productData) => {
    setCurrentProduct(productData);
    setProductProjections(productData.projections || []);
    setProductPopupVisible(true);
  };

  const handleDeleteProduct = (productId) => {
    const result = confirm(
      'Вы уверены, что хотите удалить это изделие?',
      'Подтверждение удаления'
    );
    result.then((dialogResult) => {
      if (dialogResult) {
        productsDataSource
          .store()
          .remove(productId)
          .then(() => {
            productsGridRef.current.instance().refresh();
          });
      }
    });
  };

  const handleSaveProduct = async () => {
    try {
      const productData = {
        ...currentProduct,
        projections: productProjections,
      };

      if (currentProduct.id) {
        await productsDataSource.store().update(currentProduct.id, productData);
      } else {
        await productsDataSource.store().insert(productData);
      }

      setProductPopupVisible(false);
      productsGridRef.current.instance().refresh();
    } catch (e) {
      setError(e);
    }
  };

  const imageReady = useCallback((images) => {
    // Обработка новых изображений проекций
    setProductProjections(images);
    console.log('Новые изображения проекций:', images);
  }, []);

  useEffect(() => {
    if (token) {
      window.localStorage.setItem('token', token);
    } else {
      window.localStorage.removeItem('token');
      setStatusData(null);
      setUsersDataSource(null);
      setBanListDataSource(null);
      setProductsDataSource(null);
      setTypesDataSource(null);
      setRoles([]);
      setTypes([]);
      setShowAdminPanel(false);
      if (loginAutocompleteRef.current && passwdRef.current) {
        passwdRef.current.instance().reset();
      }
    }
  }, [token]);

  const isAdmin = statusData?.role === 'Администратор';

  const onEditorPreparing = (e) => {
    if (e.parentType !== 'dataRow') {
      return;
    }
    if (e.dataField === 'login') {
      e.editorOptions.disabled = !e.row.isNewRow;
    }
    if (e.dataField === 'password') {
      e.editorName = 'dxTextBox';
      e.editorOptions.mode = 'password';
      e.editorOptions.placeholder = e.row.isNewRow
        ? ''
        : 'Введите для смены...';
    }
    if (e.dataField === 'delete_mark' && e.row.isNewRow) {
      e.cancel = true;
    }
    if (e.dataField === 'role') {
      e.editorOptions.acceptCustomValue = false;
      e.editorOptions.searchEnabled = false;
    }
  };

  const onInitNewRow = (e) => {
    if (roles.includes('Контролер')) {
      e.data.role = 'Контролер';
    }
  };

  const handleLoginFocus = () => {
    if (loginAutocompleteRef.current) {
      loginAutocompleteRef.current.instance().open();
    }
  };

  const isLoading =
    isLoginLoading ||
    isStatusLoading ||
    isLogoutLoading ||
    isEndUserSessionLoading ||
    areRolesLoading ||
    areTypesLoading;

  const renderButtonX = useCallback(
    ({ data }) => {
      const canEndSession = data.session_exists && !isLoading;

      return (
        <div style={{ display: 'flex', justifyContent: 'center' }}>
          <Button
            icon="runner"
            hint="Завершить сеанс"
            onClick={() => handleEndUserSession(data)}
            disabled={!canEndSession}
            stylingMode="contained"
            type="danger"
          />
        </div>
      );
    },
    [isLoading, handleEndUserSession]
  );

  const renderUsersTab = () => (
    <div style={{ marginTop: '20px' }}>
      <DataGrid
        ref={dataGridRef}
        dataSource={usersDataSource}
        showBorders={true}
        wordWrapEnabled={true}
        keyExpr="id"
        onSaving={() => {
          setMessage('');
          setError(null);
        }}
        onEditorPreparing={onEditorPreparing}
        onInitNewRow={onInitNewRow}
      >
        <Editing
          mode="row"
          allowUpdating={true}
          allowAdding={true}
          allowDeleting={false}
          useIcons={true}
        />
        <Paging defaultPageSize={10} />
        <Pager
          showPageSizeSelector={true}
          allowedPageSizes={[5, 10, 20]}
          showInfo={true}
        />

        <Column dataField="id" caption="ID" width={40} allowEditing={false} />
        <Column dataField="login" caption="Логин">
          <RequiredRule message="Логин обязателен" />
        </Column>
        <Column dataField="username" caption="Имя пользователя">
          <RequiredRule message="Имя пользователя обязательно" />
        </Column>
        <Column dataField="password" caption="Пароль" />
        <Column dataField="role" caption="Роль">
          <RequiredRule message="Роль обязательна" />
          <Lookup dataSource={roles} />
        </Column>
        <Column
          dataField="insert_time"
          caption="Время создания"
          allowEditing={false}
          dataType="datetime"
          format="dd.MM.yyyy HH:mm"
          width={120}
        />
        <Column
          dataField="delete_mark"
          caption="Пометка удаления"
          dataType="boolean"
          width={80}
        />

        <Column type="buttons" width={80}>
          <Button name="edit" />
        </Column>
        <Column width={60} cellRender={renderButtonX} />
      </DataGrid>
    </div>
  );

  const renderBanListTab = () => (
    <div style={{ marginTop: '20px' }}>
      <DataGrid
        ref={banListGridRef}
        dataSource={banListDataSource}
        showBorders={true}
        wordWrapEnabled={true}
        keyExpr="ip"
      >
        <Editing
          mode="row"
          allowUpdating={false}
          allowAdding={false}
          allowDeleting={true}
          useIcons={true}
        />
        <Paging defaultPageSize={10} />
        <Pager
          showPageSizeSelector={true}
          allowedPageSizes={[5, 10, 20]}
          showInfo={true}
        />

        <Column dataField="ip" caption="IP адрес" />
        <Column
          dataField="insert_time"
          caption="Время блокировки"
          dataType="datetime"
          format="dd.MM.yyyy HH:mm:ss"
        />

        <Column type="buttons" width={80}>
          <Button name="delete" />
        </Column>
      </DataGrid>
    </div>
  );

  const renderProductsTab = () => (
    <div style={{ marginTop: '20px' }}>
      <div style={{ marginBottom: '10px' }}>
        <Button
          text="Добавить изделие"
          icon="plus"
          type="success"
          onClick={handleAddProduct}
        />
      </div>
      <DataGrid
        ref={productsGridRef}
        dataSource={productsDataSource}
        showBorders={true}
        wordWrapEnabled={true}
        keyExpr="id"
      >
        <Paging defaultPageSize={10} />
        <Pager
          showPageSizeSelector={true}
          allowedPageSizes={[5, 10, 20]}
          showInfo={true}
        />
        <Column dataField="id" caption="ID" width={60} />
        <Column dataField="name" caption="Имя" />
        <Column dataField="type" caption="Вид" width={150} />
        <Column
          dataField="delete_mark"
          caption="Пометка удаления"
          dataType="boolean"
          width={120}
        />
        <Column
          dataField="insert_time"
          caption="Время создания"
          dataType="datetime"
          format="dd.MM.yyyy HH:mm"
          width={150}
        />
        <Column
          type="buttons"
          width={110}
          cellRender={({ data }) => (
            <div style={{ display: 'flex', gap: '5px' }}>
              <Button
                icon="edit"
                hint="Редактировать"
                onClick={() => handleEditProduct(data)}
              />
              <Button
                icon="trash"
                hint="Удалить"
                onClick={() => handleDeleteProduct(data.id)}
                type="danger"
              />
            </div>
          )}
        />
      </DataGrid>
      <Popup
        visible={productPopupVisible}
        onHiding={() => setProductPopupVisible(false)}
        dragEnabled={true}
        closeOnOutsideClick={false}
        showTitle={true}
        title={
          currentProduct?.id ? 'Редактировать изделие' : 'Добавить изделие'
        }
        width={700}
        height={700}
        toolbarItems={[
  {
    widget: 'dxButton',
    toolbar: 'bottom',
    location: 'after',
    options: {
      text: currentProduct?.id ? 'Сохранить' : 'Создать',
      type: 'success',
      icon: currentProduct?.id ? 'save' : 'add',
      onClick: createItem
    },
  },
  {
    widget: 'dxButton',
    toolbar: 'bottom',
    location: 'after',
    options: {
      text: 'Отмена',
      onClick: () => {
        setProductPopupVisible(false); 
      },
    },
  },
]}
        contentRender={() => {
          return (
           <>

              <ScrollView width="100%" height="100%">
                <div style={{ padding: '20px' }}>
                  <div style={{ marginBottom: '15px' }}>
                    <label>Имя:</label>
                    <TextBox
                      value={currentProduct?.name || ''}
                      onValueChanged={(e) =>
                        setCurrentProduct({ ...currentProduct, name: e.value })
                      }
                      placeholder="Введите имя изделия"
                    />
                  </div>
                  <div style={{ marginBottom: '15px' }}>
                    <label>Вид:</label>
                    <SelectBox
                      value={currentProduct?.type || ''}
                      onValueChanged={(e) =>
                        setCurrentProduct({ ...currentProduct, type: e.value })
                      }
                      placeholder="Выберите вид"
                      dataSource={types}
                      displayExpr="name"
                      valueExpr="name"
                      searchEnabled={true}
                    />
                  </div>
                  <div style={{ marginBottom: '15px' }}>
                    <label>Проекции:</label>
                    <div style={{ marginTop: '10px' }}>
                      <ComplexItemPane
                        componentHeight={400}
                        componentWidth={500}
                        dragAndDropEnabled={true}
                        onNewImagesReady={imageReady}
                        //onProjectionResize={imageReady}
                        projectionImagesOffsets={{
                          p1: 10,
                          p2: 10,
                          p3: 20,
                          p4: 10,
                          p5: 10,
                          p6: 20,
                        }}
                      />
                    </div>
                  </div>
                </div>
              </ScrollView>
            </>
          );
        }}
      />
    </div>
  );

  // Добавлено для отображения настроек видов
  const renderSettingsTab = () => (
    <div style={{ marginTop: '20px' }}>
      <h3>Управление видами изделий</h3>
      <DataGrid
        ref={typesGridRef}
        dataSource={typesDataSource}
        showBorders={true}
        wordWrapEnabled={true}
        keyExpr="id"
        onSaving={() => {
          setMessage('');
          setError(null);
        }}
      >
        <Editing
          mode="row"
          allowUpdating={true}
          allowAdding={true}
          allowDeleting={true}
          useIcons={true}
        />
        <Paging defaultPageSize={10} />
        <Pager
          showPageSizeSelector={true}
          allowedPageSizes={[5, 10, 20]}
          showInfo={true}
        />

        <Column dataField="id" caption="ID" width={60} allowEditing={false} />
        <Column dataField="name" caption="Название вида">
          <RequiredRule message="Название вида обязательно" />
        </Column>
        <Column dataField="description" caption="Описание" />
        <Column
          dataField="insert_time"
          caption="Время создания"
          allowEditing={false}
          dataType="datetime"
          format="dd.MM.yyyy HH:mm"
          width={150}
        />

        <Column type="buttons" width={100}>
          <Button name="edit" />
          <Button name="delete" />
        </Column>
      </DataGrid>
    </div>
  );

  return (
    <div
      style={{
        padding: '20px',
        maxWidth: '1200px',
        margin: 'auto',
        fontFamily: 'sans-serif',
      }}
    >
      <h1>Демонстрация</h1>

      {!token ? (
        <div
          style={{
            padding: '15px',
            border: '1px solid #ccc',
            borderRadius: '5px',
          }}
        >
          <h2>Вход в систему</h2>
          <div style={{ marginBottom: '10px' }}>
            <Autocomplete
              ref={loginAutocompleteRef}
              dataSource={recentLogins}
              placeholder="Логин"
              width="100%"
              openOnFocus={true}
              showClearButton={true}
              showDropDownButton={true}
              minSearchLength={0}
              onFocus={handleLoginFocus}
            />
          </div>
          <div style={{ marginBottom: '15px' }}>
            <TextBox
              ref={passwdRef}
              placeholder="Пароль"
              mode="password"
              width="100%"
            />
          </div>
          <Button
            text="Войти"
            type="default"
            onClick={handleLogin}
            disabled={isLoading}
          />
        </div>
      ) : (
        <div>
          <div
            style={{
              padding: '15px',
              border: '1px solid #ccc',
              borderRadius: '5px',
            }}
          >
            <h2>Добро пожаловать!</h2>
            <p>
              Вы вошли в систему. Нажмите "Проверить статус", чтобы получить
              информацию о себе.
            </p>
            <div style={{ display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
              <Button
                text="1. Проверить статус"
                type="success"
                onClick={handleCheckStatus}
                disabled={isLoading}
              />
              <Button
                text="2. Выйти"
                type="danger"
                onClick={handleLogout}
                disabled={isLoading}
              />
            </div>
          </div>

          {isAdmin && (
            <div
              style={{
                marginTop: '20px',
                padding: '15px',
                border: '1px solid #e0b4b4',
                background: '#fff5f5',
                borderRadius: '5px',
              }}
            >
              <h3>Панель администратора</h3>
              <Button
                text="Открыть панель администратора"
                icon="preferences"
                onClick={handleOpenAdminPanel}
                disabled={isLoading}
              />
            </div>
          )}
        </div>
      )}

      <div
        style={{
          marginTop: '20px',
          padding: '15px',
          background: '#f5f5f5',
          borderRadius: '5px',
          minHeight: '100px',
        }}
      >
        <h2>Статус операции</h2>
        {isLoading && <LoadIndicator visible={true} />}
        {message && (
          <p style={{ color: 'green', fontWeight: 'bold' }}>{message}</p>
        )}
        {error && (
          <div style={{ color: 'red' }}>
            <strong>Ошибка:</strong> {error.message}
            <pre
              style={{
                background: '#ffebeb',
                padding: '10px',
                borderRadius: '3px',
                whiteSpace: 'pre-wrap',
                wordBreak: 'break-all',
              }}
            >
              {JSON.stringify(error.response?.data || error, null, 2)}
            </pre>
          </div>
        )}
        {statusData && !showAdminPanel && (
          <div>
            <strong>Данные из /token_info:</strong>
            <pre
              style={{
                background: '#e6f7ff',
                padding: '10px',
                borderRadius: '3px',
              }}
            >
              {JSON.stringify(statusData, null, 2)}
            </pre>
          </div>
        )}

        {showAdminPanel && (
          <div style={{ marginTop: '20px' }}>
            <TabPanel
              height={600}
              selectedIndex={selectedTabIndex}
              onSelectionChanged={(e) => setSelectedTabIndex(e.component.option('selectedIndex'))}
              animationEnabled={true}
              swipeEnabled={false}
            >
              <Item title="Пользователи" icon="group">
                {renderUsersTab()}
              </Item>
              <Item title="Бан-лист" icon="remove">
                {renderBanListTab()}
              </Item>
              <Item title="Изделия" icon="product">
                {renderProductsTab()}
              </Item>
              <Item title="Настройки" icon="preferences">
                {renderSettingsTab()}
              </Item>
            </TabPanel>
          </div>
        )}
      </div>
    </div>
  );
}

export default App;