У меня почему-то запросы не проходят, только preflight каждый раз, и всё. Почему? // CreateItemPage.jsx
import { useNavigate } from 'react-router-dom';
import { createItem } from '../api';
import { ItemForm } from '../components/ItemForm';

export const CreateItemPage = () => {
  const navigate = useNavigate();

  const handleSubmit = (data) => {
    console.log('Creating item with data:', data); // Логирование на клиенте
    createItem(data)
      .then((response) => {
        console.log('Item created:', response.data); // Логирование ответа
        navigate('/');
      })
      .catch((error) => {
        console.error('Error creating item:', error); // Обработка ошибок
      });
  };

  return (
    <div>
      <h1>Create Item</h1>
      <ItemForm
        onSubmit={handleSubmit}
        defaultValues={{
          name: '',
          category: '',
          quantity: 1,
          location: '',
          supplier: '',
          supplierLocation: '',
          showPriceDetails: 'no',
          priceType: '',
          price: '',
          endpoints: []
        }}
      />
      <button onClick={() => navigate('/')}>Back to List</button>
    </div>
  );
}; import { useForm, useFieldArray } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';
import { useEffect } from 'react';
const schema = yup.object({
  name: yup.string().required('Name is required').max(50, 'Max length is 50'),
  category: yup.string().required('Category is required'),
  quantity: yup
    .number()
    .typeError('Quantity must be a number')
    .required('Quantity is required')
    .min(1, 'Quantity must be at least 1'),
  location: yup.string().notRequired(),
  supplier: yup.string().notRequired(),
  supplierLocation: yup.string().notRequired(),
  showPriceDetails: yup
    .string()
    .oneOf(['yes', 'no'], 'Please select an option')
    .required('Please select an option'),

  priceType: yup
    .string()
    .when('showPriceDetails', {
      is: 'yes',
      then: schema => schema.required('Price Type is required'),
      otherwise: schema => schema.notRequired(),
    }),

  price: yup
    .number()
    .transform((value, originalValue) => (originalValue === '' ? undefined : value))
    .when('showPriceDetails', {
      is: 'yes',
      then: schema =>
        schema
          .required('Price is required')
          .typeError('Price must be a number')
          .min(1, 'Price must be at least 1'),
      otherwise: schema => schema.notRequired(),
    }),

  endpoints: yup.array().of(
    yup.object({
      endpoint: yup.string().required('Endpoint is required'),
      status: yup.string().required('Status is required'),
    })
  ),
});
export const ItemForm = ({ defaultValues, onSubmit }) => {
  const {
    register,
    handleSubmit,
    watch,
    control,
    formState: { errors },
    reset,
  } = useForm({
    defaultValues,
    resolver: yupResolver(schema),
  });

  const { fields, append, remove } = useFieldArray({
    control,
    name: 'endpoints',
  });

  const showPriceDetails = watch('showPriceDetails', 'no') === 'yes';

  useEffect(() => {
    reset(defaultValues);
  }, [defaultValues, reset]);

  const handleFormSubmit = (data) => {
    const changes = {};
    Object.keys(data).forEach((key) => {
      if (JSON.stringify(data[key]) !== JSON.stringify(defaultValues[key])) {
        changes[key] = data[key];
      }
    });
    console.log('Submitting changes:', changes);
    onSubmit(changes);
  };

  return (
    <div className="form-container">
      <form onSubmit={handleSubmit(handleFormSubmit)} className="form-wrapper">
        {/* Сетка для имени, категории и количества */}
        <div className="form-grid grid-3">
          <div className="form-group">
            <label>Name:</label>
            <input
              {...register('name')}
              className={errors.name ? 'input-error' : ''}
            />
            {errors.name && <p className="error-message">{errors.name.message}</p>}
          </div>

          <div className="form-group">
            <label>Category:</label>
            <select
              {...register('category')}
              className={errors.category ? 'input-error' : ''}
            >
              <option value="">Select category</option>
              <option value="Electronics">Electronics</option>
              <option value="Furniture">Furniture</option>
              <option value="Clothing">Clothing</option>
              <option value="Food">Food</option>
              <option value="Toys">Toys</option>
              <option value="Books">Books</option>
              <option value="Sports">Sports</option>
            </select>
            {errors.category && (
              <p className="error-message">{errors.category.message}</p>
            )}
          </div>

          <div className="form-group">
            <label>Quantity:</label>
            <input
              type="number"
              {...register('quantity')}
              className={errors.quantity ? 'input-error' : ''}
            />
            {errors.quantity && (
              <p className="error-message">{errors.quantity.message}</p>
            )}
          </div>
        </div>

        {/* Сетка для поставщика и его локации */}
        <div className="form-grid grid-2">
          <div className="form-group">
            <label>Supplier (Optional):</label>
            <input
              {...register('supplier')}
              className={errors.supplier ? 'input-error' : ''}
            />
            {errors.supplier && (
              <p className="error-message">{errors.supplier.message}</p>
            )}
          </div>

          <div className="form-group">
            <label>Supplier Location (Optional):</label>
            <input
              {...register('supplierLocation')}
              className={errors.supplierLocation ? 'input-error' : ''}
            />
            {errors.supplierLocation && (
              <p className="error-message">{errors.supplierLocation.message}</p>
            )}
          </div>
        </div>

        {/* Сетка для ценовых данных */}
        <div className="form-group">
          <label>Show Price Details?</label>
          <div className="radio-group">
            <label>
              <input
                type="radio"
                value="yes"
                {...register('showPriceDetails')}
                defaultChecked={defaultValues?.showPriceDetails === 'yes'}
              />
              Yes
            </label>
            <label>
              <input
                type="radio"
                value="no"
                {...register('showPriceDetails')}
                defaultChecked={defaultValues?.showPriceDetails !== 'yes'}
              />
              No
            </label>
          </div>
          {errors.showPriceDetails && (
            <p className="error-message">{errors.showPriceDetails.message}</p>
          )}
        </div>

        {showPriceDetails && (
          <div className="form-grid grid-2">
            <div className="form-group">
              <label>Type:</label>
              <select
                {...register('priceType')}
                className={errors.priceType ? 'input-error' : ''}
              >
                <option value="">Select type</option>
                <option value="For Sale">For Sale</option>
                <option value="For Buying">For Buying</option>
              </select>
              {errors.priceType && (
                <p className="error-message">{errors.priceType.message}</p>
              )}
            </div>

            <div className="form-group">
              <label>Price:</label>
              <input
                type="number"
                {...register('price')}
                className={errors.price ? 'input-error' : ''}
                placeholder="Enter price"
              />
              {errors.price && (
                <p className="error-message">{errors.price.message}</p>
              )}
            </div>
          </div>
        )}

        {/* Сетка для Endpoints */}
        <div className="form-group full-width">
          <h3>Endpoints</h3>
          {fields.map((endpoint, index) => (
            <div key={endpoint.id} className="form-grid grid-2">
              <div className="form-group">
                <label>Endpoint {index + 1}:</label>
                <input
                  {...register(endpoints.${index}.endpoint)}
                  placeholder={Endpoint ${index + 1}}
                  className={errors.endpoints?.[index]?.endpoint ? 'input-error' : ''}
                />
                {errors.endpoints?.[index]?.endpoint && (
                  <p className="error-message">
                    {errors.endpoints[index].endpoint.message}
                  </p>
                )}
              </div>

              <div className="form-group">
                <label>Status:</label>
                <select
                  {...register(endpoints.${index}.status)}
                  className={errors.endpoints?.[index]?.status ? 'input-error' : ''}
                >
                  <option value="">Select status</option>
                  <option value="Delivering">Delivering</option>
                  <option value="Delivered">Delivered</option>
                  <option value="Pending">Pending</option>
                  <option value="Delayed">Delayed</option>
                  <option value="Canceled">Canceled</option>
                </select>
                {errors.endpoints?.[index]?.status && (
                  <p className="error-message">
                    {errors.endpoints[index].status.message}
                  </p>
                )}
              </div>

              <button
                type="button"
                className="remove-endpoint-button"
                onClick={() => remove(index)}
              >
                Remove Endpoint
              </button>
            </div>
          ))}
          <button
            type="button"
            onClick={() => append({ endpoint: '', status: '' })}
            className="add-endpoint-button"
          >
            Add Endpoint
          </button>
        </div>

        <div className="form-actions">
          <button type="submit" className="action-button">Save</button>
          <button type="button" className="action-button">Back to List</button>
        </div>
      </form>
    </div>
  );
}; import { Link } from 'react-router-dom';

export const ItemTable = ({ items = [] }) => {
  return (
    <table>
      <thead>
        <tr>
          <th>Name</th>
          <th>Category</th>
          <th>Quantity</th>
          <th>Location</th>
          <th>Supplier</th>
          <th>Supplier Location</th>
          <th>Price Type</th>
          <th>Price</th>
          <th>Endpoints</th>
          <th>Actions</th>
        </tr>
      </thead>
      <tbody>
        {items.length > 0 ? (
          items.map((item) => (
            <tr key={item.id}>
              <td>{item.name}</td>
              <td>{item.category}</td>
              <td>{item.quantity}</td>
              <td>{item.location}</td>
              <td>{item.supplier || 'N/A'}</td>
              <td>{item.supplierLocation || 'N/A'}</td>
              <td>{item.showPriceDetails === 'yes' ? item.priceType : 'N/A'}</td>
              <td>
                {item.showPriceDetails === 'yes' && typeof item.price !== 'undefined'
                  ? item.price
                  : 'N/A'}
              </td>
              <td>
                {item.endpoints && item.endpoints.length > 0 ? (
                  <ul>
                    {item.endpoints.map((endpoint, index) => (
                      <li key={index}>{${endpoint.endpoint} - ${endpoint.status}}</li>
                    ))}
                  </ul>
                ) : (
                  <p>No endpoints available</p>
                )}
              </td>
              <td>
                <Link to={/edit/${item.id}}>Edit</Link>
              </td>
            </tr>
          ))
        ) : (
          <tr>
            <td colSpan="10">No items available</td>
          </tr>
        )}
      </tbody>
    </table>
  );
}; import { Link } from 'react-router-dom';

export const ItemTable = ({ items = [] }) => {
  return (
    <table>
      <thead>
        <tr>
          <th>Name</th>
          <th>Category</th>
          <th>Quantity</th>
          <th>Location</th>
          <th>Supplier</th>
          <th>Supplier Location</th>
          <th>Price Type</th>
          <th>Price</th>
          <th>Endpoints</th>
          <th>Actions</th>
        </tr>
      </thead>
      <tbody>
        {items.length > 0 ? (
          items.map((item) => (
            <tr key={item.id}>
              <td>{item.name}</td>
              <td>{item.category}</td>
              <td>{item.quantity}</td>
              <td>{item.location}</td>
              <td>{item.supplier || 'N/A'}</td>
              <td>{item.supplierLocation || 'N/A'}</td>
              <td>{item.showPriceDetails === 'yes' ? item.priceType : 'N/A'}</td>
              <td>
                {item.showPriceDetails === 'yes' && typeof item.price !== 'undefined'
                  ? item.price
                  : 'N/A'}
              </td>
              <td>
                {item.endpoints && item.endpoints.length > 0 ? (
                  <ul>
                    {item.endpoints.map((endpoint, index) => (
                      <li key={index}>{${endpoint.endpoint} - ${endpoint.status}}</li>
                    ))}
                  </ul>
                ) : (
                  <p>No endpoints available</p>
                )}
              </td>
              <td>
                <Link to={/edit/${item.id}}>Edit</Link>
              </td>
            </tr>
          ))
        ) : (
          <tr>
            <td colSpan="10">No items available</td>
          </tr>
        )}
      </tbody>
    </table>
  );
}; import axios from 'axios';

const API_BASE_URL = 'http://localhost:5000';

export const getItems = () => axios.get(${API_BASE_URL}/items);

export const createItem = (data) => axios.post(${API_BASE_URL}/items, data);

export const updateItem = (id, data) => axios.put(${API_BASE_URL}/items/${id}, data);