Add Buy Me A Coffee Widget to React application

Viewed 2650

I am trying to create a component that renders the Buy Me A Coffee widget in some routes of my react single page application. This is my component so far:

class BuyMeACoffee extends React.Component {
    componentDidMount () {
         const script = document.createElement("script",);
         script.setAttribute('data-name','BMC-Widget')
         script.src = "https://cdnjs.buymeacoffee.com/1.0.0/widget.prod.min.js"
         script.setAttribute('data-id', 'boulderproblems');
         script.setAttribute('data-description', 'Thank you for your support!');
         script.setAttribute('data-message', 'This web is free to use. Do you want to help supporting it?');
         script.setAttribute('data-color',"#FF5F5F")
         script.setAttribute('data-position','right')
         script.setAttribute('data-x_margin','18')
         script.setAttribute('data-y-margin','18')
         script.async = true
         document.head.appendChild(script)
    }

    render(){
         return(null)
    }
}

When I inspect the page with the developer tools, the tag is at the end of the head section and everything seems correct but the widget doesn't show in the page.

Note: If I copy the script code in the head section of the index.html page:

<script data-name="BMC-Widget" src="https://cdnjs.buymeacoffee.com/1.0.0/widget.prod.min.js" data-id="boulderproblems" data-description="Thank you for your support!" data-message="This web is free to use. Do you want to help supporting it?" data-color="#FF5F5F" data-position="right" data-x_margin="18" data-y-margin="18"></script>

then it works perfectly. The problem is that in this case, the widget is shown for all routes. I have also tried react-helmet without success.

5 Answers

I finnally got it working. I post my solution here in case it is useful for someone. Not sure if it is the most elegant but it works. I slightly modified the original component so the script and widget is removed when the component is unmounted. Here is the component now:

class BuyMeACoffe extends React.Component {
    constructor(props){
        super(props)
        let script = document.createElement("script");
        script.setAttribute('data-name','BMC-Widget')
        script.src = "https://cdnjs.buymeacoffee.com/1.0.0/widget.prod.min.js"
        script.setAttribute('data-id', 'boulderproblems');
        script.setAttribute('data-description', 'Thank you for your support!');
        script.setAttribute('data-message', 'This web is free to use. Do you want to help supporting it?');
        script.setAttribute('data-color',"#FF5F5F")
        script.setAttribute('data-position','right')
        script.setAttribute('data-x_margin','18')
        script.setAttribute('data-y-margin','18')
        script.async = true
        //Call window on load to show the image
        script.onload=function(){
            var evt = document.createEvent('Event');  
            evt.initEvent('DOMContentLoaded', false, false);  
            window.dispatchEvent(evt);
        }
        this.script=script
    }

    componentDidMount () {    
        document.head.appendChild(this.script)
    }

    componentWillUnmount(){
        document.head.removeChild(this.script);
        document.body.removeChild(document.getElementById("bmc-wbtn"))
     }

    render(){
        return(null)
    }
}

Basically, after reading the buymeacoffee script I realized that they load the widget when the window is DOMContentLoaded event is fired. What I do is to fire this event manually after I insert the script.

Note: After doing this, I had to add a couple of styles because the widget was showing out of the screen. Maybe it was because of my layout. Anyway, here they are in case they you need them:

#bmc-wbtn{
    bottom: 15px;
}

#bmc-wbtn + div{
    bottom:15px;
}

You can simply add the copied code provided by buymecoffee.com into head tag of your index.html of your React project. It will load automatically onLoad of your React App. You can customize the properties inside it if required, But I think you don't need to create a separate component to make it work. You can find your index.html inside the public folder.

project-name > public > index.html

<!DOCTYPE html>
<html lang="en">
  <head>

    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>

    <script
      data-name="BMC-Widget"
      data-cfasync="false"
      src="https://cdnjs.buymeacoffee.com/1.0.0/widget.prod.min.js"
      data-id="codesim"
      data-description="Support me on Buy me a coffee!"
      data-message=""
      data-color=""
      data-position="Right"
      data-x_margin="18"
      data-y_margin="18"
    ></script>

  </head>

  <body>
    <div id="root"></div>
  </body>
</html>

A simpler way.
You can create a react component like this.

Coffee.js

function Coffee() {
return (
<a
  className="buyButton"
  target="_blank"
  href="https://www.buymeacoffee.com/theshubhagrwl"
>
  <img
    className="coffeeImage"
    src="https://cdn.buymeacoffee.com/buttons/bmc-new-btn-logo.svg"
    alt="Buy me a coffee"
  />
  <span className="coffeeButtonText">Buy me a coffee</span>
</a>
 );
}

Styles.css

.buyButton {
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  color: #ffffff;
  background-color: #ff813f;
  border-radius: 5px;
  border: 1px solid transparent;
  padding: 0.5rem;
  font-size: 1rem;
  letter-spacing: 0.6px;
  box-shadow: 0px 1px 2px rgba(190, 190, 190, 0.5);
  font-family: cursive;
}
.buyButton:hover,
.buyButton:active,
.buyButton:focus {
  text-decoration: underline;
  box-shadow: 0px 1px 2px 2px rgba(190, 190, 190, 0.5);
  opacity: 0.85;
  color: #ffffff;
}

.coffeeImage {
  height: 2vh;
  box-shadow: none;
  border: none;
  vertical-align: middle;
}

.coffeeButtonText {
  margin-left: 15px;
  font-size: 0.8rem;
  vertical-align: middle;
}

This will give you easy customization.

For Widget you can embed that in iframe

const BuyMeACoffeeWidget = () => {
  const path = "https://www.buymeacoffee.com/widget/page/PskV9Rt?description=Support%20me%20on%20Buy%20me%20a%20coffee!&color=%235F7FFF";

  return (
    <iframe className="bmc" src={path} />
  );
};
export default BuyMeACoffeeWidget;

Add custom styling

.bmc{
  height: 100%;    
  border: antiquewhite;
  border-radius: 1px;
}

And use in your repo where required

<BuyMeACoffeeWidget />

Also in case if you wanna add the redirection Image to your application, just put the image in Public/image folder and use the path in imag source tag in code.

enter image description here

I took a snip it of the image, put this in image folder and used this in code like

const BuyMeACoffeeSupport = () => {
    return (
       
      <a href="https://www.buymeacoffee.com/PskV9Rt">
        <img src="img/bmc.PNG" />
      </a>
       
    );
}
export default BuyMeACoffeeSupport;

And use in your repo where required

<BuyMeACoffeeSupport/>

this solution is for functional component

import React, { useEffect } from "react";

export default function Buymeacoffee() {
  // const
  useEffect(() => {
    const script = document.createElement("script");
    const div = document.getElementById("supportByBMC");
    script.setAttribute(
      "src",
      "https://cdnjs.buymeacoffee.com/1.0.0/widget.prod.min.js"
    );
    script.setAttribute("data-name", "BMC-Widget");
    script.setAttribute("data-cfasync", "false");
    script.setAttribute("data-id", "algorithammer");
    script.setAttribute("data-description", "Support me on Buy me a coffee!");
    script.setAttribute(
      "data-message",
      "Buying a single coffee for me is 1000 times worth than a Thankyou "
    );
    script.setAttribute("data-color", "#5F7FFF");
    script.setAttribute("data-position", "Right");
    script.setAttribute("data-x_margin", "18");
    script.setAttribute("data-y_margin", "18");

    script.onload = function () {
      var evt = document.createEvent("Event");
      evt.initEvent("DOMContentLoaded", false, false);
      window.dispatchEvent(evt);
    };

    div.appendChild(script);
  }, []);

  return <div id="supportByBMC"></div>;
}


.supportFromHome {
  bottom: 15px;
}

output :is at the bottom of the page:
enter image description here

Related