score:0

Accepted answer

based on the answers above i came up with the following code.

the hook:

const usecheckpayment = ({initialvalues, sendurl, successurl, description, sum, downloadpdf}) => {
  const [paid, setpaid] = usestate(false);
  const [loading, setloading] = usestate(false);
  const [submitting, setsubmitting] = usestate(false);
  const [data, setdata] = usestate(initialvalues);

  const checkorder = usecallback(
    async () => {
      let search = new urlsearchparams(window.location.search);
      let success = search.get('success');
      if (success) {
        try {
          const data = await getorder(search);
          setdata(data);
          checkpayment(search);
        } catch (err) {
          alert(err.message);
        }
      }
    }, [checkpayment]
  );

  const checkpayment = usecallback(
    async (search) => {
      try {
        const paid = await getpaymentstate(search);
        setpaid(paid);
        document.getelementbyid('myform').dispatchevent(new event('submit', { cancelable: true }))
      } catch (err) {
        alert(err.message);
      }
    }, []
  );

  const neworder = usecallback(
    async (values) => {
      setsubmitting(true);
      const order = await createorder(values, description, sum);
      const paymenturl = await initpayment(order, description, sum, successurl);
      setsubmitting(false);
      window.location.assign(paymenturl);
    }, [description, sum, successurl]
  );

  const downloadpdf = async (values, downloaddata) => {
    setloading(true);
    const response = await downloadfile(downloaddata, sendurl);
    setloading(false);
    window.location.assign(response.pdf);
  };

  const onsubmit = usecallback(
    async ({ values, downloaddata }) => {
      if (paid) {
        try {
          downloadpdf(values, downloaddata);
        } catch (err) {
          console.log(err);
        }
      } else {
        try {
          neworder(values);
        } catch (err) {
          alert(err.message);
        }
      }
    },
    [paid, downloadpdf, neworder]
  );

  useeffect(() => {
    checkorder();
  }, [checkorder]);

  return { onsubmit, submitting };
};

the component:

const sendurl = 'https://app.example.com/send'
const successurl = 'https://example.com/success'
const description = 'download pdf file'
const sum = '100'

const form = () => {

  const handlesubmit = (values) => {
    const downloaddata = {
      email: values.email,
      phone: values.phone
    }
    onsubmit({ downloaddata, values })
  }

  const { onsubmit, submitting } = usecheckpayment(
    {sendurl, successurl, description, sum}
  );

  return (
    <form
      onsubmit={handlesubmit}
      render={({ handlesubmit }) => (
        <form onsubmit={handlesubmit}></form>
      )}
    />
  )
}

score:1

i made a quick refactor of the code and put it in a custom hook, it looks like search param is the key for when the effect needs to run.

const usecheckpayment = (search) => {
  const [paid, setpaid] = usestate(false);
  const [submitting, setsubmitting] = usestate(false);
  const [loading, setloading] = usestate(false);
  const [data, setdata] = usestate({});

  const checkorder = usecallback(async () => {
    let paramsearch = new urlsearchparams(search);
    let success = paramsearch.get('success');
    if (success) {
      try {
        //why not just pass it, makes getorder a little less impure
        const data = await getorder(paramsearch);
        setdata(data);
        checkpayment(data);
      } catch (err) {
        alert(err.message);
      }
    }
  }, [checkpayment, search]);

  const checkpayment = usecallback(async (values) => {
    try {
      const paid = await getpaymentstate();
      setpaid(paid);
      downloadpdf(values);
    } catch (err) {
      alert(err.message);
    }
  }, []);

  const downloadpdf = async (values) => {
    setloading(true);
    const response = await downloadfile();
    setloading(false);
    window.location.assign(response.pdf);
  };

  const neworder = async (values) => {
    setsubmitting(true);
    const order = await createorder();
    const paymenturl = await initpayment(order);
    setsubmitting(false);
    window.location.assign(paymenturl);
  };
  const onsubmit = usecallback(
    async (values) => {
      if (paid) {
        try {
          downloadpdf(data);
        } catch (err) {
          console.log(err);
        }
      } else {
        try {
          neworder(values);
        } catch (err) {
          alert(err.message);
        }
      }
    },
    [data, paid]
  );
  useeffect(() => {
    checkorder();
  }, [checkorder]); //checkorder will change when search changes and effect is called again
  return { onsubmit, submitting, loading };
};


const form = () => {
  const { onsubmit, submitting, loading } = usecheckpayment(
    window.location.search
  );

  return '';
};

score:1

you can extract out all the generic things from within the form component into a custom hook and return the required values from this hook

the values which are dependencies and will vary according to the component this is being called from can be passed as arguments to the hook. also the hook can return a onsubmit function to which you can pass on the downloaddata

const useorderhook = ({returnurl, sendurl, }) => {
  const [paid, setpaid] = usestate(false);
  const [submitting, setsubmitting] = usestate(false);
  const [loading, setloading] = usestate(false);
  const [data, setdata] = usestate({});

  const checkorder = async () => {
    let search = new urlsearchparams(window.location.search);
    let success = search.get("success");
    if (success) {
      try {
        const data = await getorder();
        setdata(data);
        checkpayment(data);
      } catch (err) {
        alert(err.message)
      }
    }
  };

  const checkpayment = async values => {
    try {
      const paid = await getpaymentstate();
      setpaid(paid);
      downloadpdf(values);
    } catch (err) {
      alert(err.message)
    }
  };

  const downloadpdf = async values => {
    setloading(true);
    let downloaddata = {
      email: values.email,
      phone: values.phone
    }
    const response = await downloadfile(downloaddata, sendurl);
    setloading(false);
    window.location.assign(response.pdf);
  }

  const neworder = async (values, description, sum) => {
    setsubmitting(true);
    const order = await createorder(values, description, sum);
    const paymenturl = await initpayment(order, description, sum, returnurl);
    setsubmitting(false);
    window.location.assign(paymenturl);
  }

  const onsubmit = async ({values, downloaddata: data, description, sum}) => {
    if (paid) {
      try {
        downloadpdf(data);
      } catch (err) {
        console.log(err);
      }
    } else {
      try {
        neworder(values, description, sum)
      } catch (err) {
        alert(err.message)
      }
    }
  };

  useeffect(() => {
    checkorder();
  }, []);

  return {onsubmit, loading, submitting, paid, data };
}

now you can use this hook in component like form as follows

const form = () => {
    const {onsubmit, neworder, loading, submitting, paid, data } = useorderhook({returnurl: 'someurl', sendurl: 'some send url'})

    const handlesubmit = (values) => {
        // since this function is called, you can get the values from its closure.
        const data = {email: values.email, phone: values.phone}
        onsubmit({ data, values, description, sum})// pass in the required values for onsubmit here. you can do the same when you actually call neworder from somewhere
    }
    // this is how you pass on handlesubmit to react-final-form
    return <form
      onsubmit={handlesubmit }
      render={({ handlesubmit }) => {
        return <form onsubmit={handlesubmit}>...fields go here...</form>
      }}
    />
}

Related Query

More Query from same tag