Search code examples
reactjsantd

upload handle change list antd keep loading


i got a project from other team.the promblem is upload file and image using antd.everything working well but when come to upload pdf file the progress bar keep loading forever but when i click submit the pdf uploaded to the server so i think the handle change was the problem

here the pdf upload loading forever picture

and when i try to upload image the text turn red but submit working as well

here example of image upload the text get red like error but submit working

here the error message when i inspect element error from inspect element

here image edit code

import { useEffect, useState } from 'react';

import {
  Row,
  Col,
  Card,
  Space,
  Typography,
  Button,
  Tooltip,
  Avatar,
  Upload,
  message,
} from 'antd';

import { InfoOutlined, UploadOutlined } from '@ant-design/icons';

import CustomTitle from '@components/Title';

import { KAJIAN_DAN_KONSULTASI } from '@constants/urls';
import fetchRequest, { fetchFormData } from '@utils/fetcher';
import { useNavigate } from 'react-router';

const { Title } = Typography;

const EditMainPictureConsultation = () => {
  const [id, setId] = useState('');
  const [mediaUrl, setMediaUrl] = useState<any[]>([]);

  const navigate = useNavigate();

  const handleImageUpload = async (info: any) => {
    let fileList = [...info.fileList];
    fileList = fileList.slice(-1);

    fileList = fileList.map((file) => {
      if (file.response) {
        file.url = file.response.url;
      }
      return file;
    });

    setMediaUrl(fileList);
  };

  const handleSubmit = async () => {
    const formData = new FormData();

    if (mediaUrl) {
      formData.append('file', mediaUrl[0]?.originFileObj || mediaUrl[0]?.url);
    }

    try {
      await fetchFormData({
        method: 'POST',
        path: 'resource/service/study-and-consul/main-picture',
        data: formData,
      }).then((response) => {
        if (!response.error) {
          navigate(KAJIAN_DAN_KONSULTASI);
        } else {
          message.error(response.error.message);
        }
      });
    } catch (error) {
      message.error(error.message);
    }
  };

  const getPictureData = async (id: string) => {
    try {
      await fetchRequest({
        method: 'GET',
        path: 'resource?id=' + id,
      }).then((response) => {
        setMediaUrl([
          {
            uid: '-1',
            name: 'mainPictureConsultation.png',
            status: 'done',
            url: response.url,
          },
        ]);
      });
    } catch (error) {}
  };

  useEffect(() => {
    const isEdit =
      location.pathname.split('/').filter((pn) => pn === 'edit').length > 0;

    if (isEdit) {
      const path = location.pathname.split('/');
      const pictId = path[path.indexOf('edit') + 1];

      setId(pictId);
      getPictureData(pictId);
    }
  }, []);

  return (
    <Row>
      <Col span={12} offset={6}>
        <Card>
          <Space direction="vertical" style={{ width: '100%' }}>
            <Space align="baseline">
              <CustomTitle name="Gambar Konsultasi" url={KAJIAN_DAN_KONSULTASI} />
              <Tooltip title="Menerima jenis file: .jpg, .jpeg, .png. Untuk icon transparan gunakan .png">
                <Avatar
                  size={'small'}
                  icon={<InfoOutlined />}
                  style={{ backgroundColor: '#8C8C8C' }}
                ></Avatar>
              </Tooltip>
            </Space>
            <Title level={5}>Gambar</Title>
            <Upload
              listType="picture"
              maxCount={1}
              accept=".png, .jpg, .jpeg"
              fileList={mediaUrl}
              onChange={handleImageUpload}
            >
              <Button icon={<UploadOutlined />}>Unggah Icon</Button>
            </Upload>
            <Row justify="end">
              <Col>
                <Button type="primary" danger onClick={() => handleSubmit()}>
                  Simpan Perubahan
                </Button>
              </Col>
            </Row>
          </Space>
        </Card>
      </Col>
    </Row>
  );
};

export default EditMainPictureConsultation;

here's the edit pdf code

import { useState } from 'react';
import { useNavigate } from 'react-router';

import {
  Row,
  Col,
  Card,
  Space,
  Typography,
  Button,
  message,
  Avatar,
  Tooltip,
  Upload,
} from 'antd';

import { UploadOutlined, InfoOutlined } from '@ant-design/icons';

import CustomTitle from '@components/Title';

import { PELATIHAN } from '@constants/urls';

import { fetchFormData } from '@utils/fetcher';

const { Title } = Typography;

const EditCatalogTraining = () => {
  const [fileUrl, setFileUrl] = useState<any[]>([]);
  const navigate = useNavigate();

  const handleFileUpload = async (info: any) => {
    let fileList = [...info.fileList];
    fileList = fileList.slice(-1);

    fileList = fileList.map((file) => {
      if (file.response) {
        file.url = file.response.url;
      }
      return file;
    });

    setFileUrl(fileList);
  };

  const handleSubmit = async () => {
    const formData = new FormData();

    if (fileUrl) {
      formData.append('file', fileUrl[0]?.originFileObj || fileUrl[0]?.url);
    }

    try {
      await fetchFormData({
        method: 'POST',
        path: 'resource/service/training/catalog',
        data: formData,
      }).then((response) => {
        if (!response.error) {
          navigate(PELATIHAN);
        } else {
          if (Array.isArray(response.message)) {
            response.message.map((msg: string) => message.error(msg));
          } else {
            message.error(response.message);
          }
        }
      });
    } catch (error: any) {
      message.error(error.message);
    }
  };

  return (
    <Row>
      <Col span={12} offset={6}>
        <Card>
          <Space direction="vertical" style={{ width: '100%' }}>
            <Space align="baseline">
              <CustomTitle name="Katalog Layanan" url={PELATIHAN} />
              <Tooltip title="Menerima jenis file: .pdf. Unggah sertifikat dalam bentuk file .pdf maksimal 25mb.">
                <Avatar
                  size={'small'}
                  icon={<InfoOutlined />}
                  style={{ backgroundColor: '#8C8C8C' }}
                ></Avatar>
              </Tooltip>
            </Space>
            <Title level={5}>Katalog</Title>
            <Upload
              listType="picture"
              maxCount={1}
              accept=".pdf"
              fileList={fileUrl}
               onChange={handleFileUpload}
            >
              <Button icon={<UploadOutlined />}>Unggah Katalog</Button>
            </Upload>
            <Row justify="end">
              <Col>
                <Button type="primary" danger onClick={() => handleSubmit()}>
                  Simpan Perubahan
                </Button>
              </Col>
            </Row>
          </Space>
        </Card>
      </Col>
    </Row>
  );
};

export default EditCatalogTraining;

please help me with the handle change list how to turn to how its suppose to.submit work well the data upload to the server.


Solution

  • you can try the following script, When uploading, Antd will immediately execute the action function, you have to handle the action so that the return is always 200

     const props: UploadProps = {
        onRemove: (file) => {
          const index = fileList.indexOf(file);
          const newFileList = fileList.slice();
          newFileList.splice(index, 1);
          setFileList(newFileList);
        },
        beforeUpload: (file) => {
          setFileList([file]);
          const isJpgOrPng =
            file.type === "image/jpeg" ||
            file.type === "image/png" ||
            file.type === "image/jpg" ||
            file.type === "application/pdf";
          if (!isJpgOrPng) {
            message.error("You can only upload JPG/PNG file!");
            const index = fileList.indexOf(file);
            const newFileList = fileList.slice();
            newFileList.splice(index, 1);
            setFileList(newFileList);
          }
          const isLt2M = file.size / 1024 / 1024 < 2;
          if (!isLt2M) {
            message.error("Image must smaller than 2MB!");
            const index = fileList.indexOf(file);
            const newFileList = fileList.slice();
            newFileList.splice(index, 1);
            setFileList(newFileList);
          }
          return isJpgOrPng && isLt2M;
        },
        fileList,
        action: "/api",
        accept: "image/png, image/jpeg, image/jpg. application/pdf",
        maxCount: 1,
      };
    
    
    <Upload {...props}>
         <Button>Select File</Button>
     </Upload>
    

    for api you can custom url always return 200

    export async function POST(request: Request) {
      return new Response("noop", {
        status: 200,
      });
    }
    

    then you can still use the handleSubmit function