React : Firing a custom alert from multiple components using an existing component having its own styles
Asked Answered
L

3

5

I am looking to make my alert() more user friendly. I have 3 components which fit together before an alert is trigger.

I have a form (dropdown and input) which on submit fires the following function:

// src/components/input.js
<Btn onClick={() => getData(this.state.dropdown, this.state.value)}>Generate</Btn>

getData() is the following function which is in a separate file ../utils/debugger

// src/utils/debugger
async function getData(filter, captureName) {
  if (captureName === '') {
    alert(<Alert color='red' type='warning' message='this is an error' />);
  } else {
    axios({
      method: 'GET',
      url: `http://xxx/debugger/${filter}/${captureName}/logs`,
    })
      .then((res) => {
        if (res.data.length === 0) {
          alert(<Alert color='red' type='warning' message='this is an error' />);
        } else {
          alert(<Alert color='green' type='success' message='this is an error' />);
          console.log(res.data);
          data = res.data;
        }

        return res.data;
      })
      .catch((err) => {
        console.log(err);
      });
  }
}

But I would like to use the alerts above to present my <Alert /> components in the following file:

// src/App.js
ReactDOM.render(
  <React.StrictMode>
    <script src='http://localhost:8097'></script>
    <div className='flex flex-col min-h-screen'>
      <header>
        <nav className='bg-gray-800'>
          <div className='mx-auto px-8'>
            <div className='flex items-center justify-between h-20'>
              <div>
                <span className='text-white font-bold'>Easy Debugger UI</span>
              </div>

              <div className=''>
                <Input /> // ../src/components/input.js
              </div>
            </div>
          </div>
        </nav>
      </header>

      <div className='container mx-auto'>
        <div className='my-2'>
          <Alert color='red' type='warning' message='waaaah' /> // display my alert here.
        </div>
        <main>
          <App />
        </main>
      </div>
      <footer className='mt-10'></footer>
    </div>
  </React.StrictMode>,
  document.getElementById('root')
);

I have tried to use the alert() but this just gives me the standard popup with [object object]

any ideas how i can get all these 3 files to talk to each to fire off the alerts when the conditionals are met in getData()

This is my Alert component...i want to keep this the way it is

import React from 'react';

export const Alert = ({ color, type, message }) => {
  const [showAlert, setShowAlert] = React.useState(true);

  function AlertType(props) {
    const alertType = props.alertType;

    if (alertType === 'success') {
      return (
        <span role='img' className='text-3xl'>
          πŸŽ‰
        </span>
      );
    }

    if (alertType === 'warning') {
      return (
        <span role='img' className='text-3xl'>
          😱
        </span>
      );
    }
  }

  return (
    <>
      {showAlert ? (
        <div
          className={
            'text-white px-6 py-4 border-0 rounded relative mb-4 bg-' + color + '-500 flex items-center'
          }>
          <span className='text-xl inline-block mr-5 align-middle'>
            <AlertType alertType={type} />
          </span>
          <span className='inline-block align-middle mr-8'>
            <b className='uppercase'>{type}! </b>
            <span className='capitalize'>{message}</span>
          </span>
          <button
            className='absolute bg-transparent text-2xl font-semibold leading-none right-0 top-0 mt-4 mr-6 outline-none focus:outline-none'
            onClick={() => setShowAlert(false)}>
            <span>Γ—</span>
          </button>
        </div>
      ) : null}
    </>
  );
};

export default Alert;
Loydloydie answered 5/7, 2021 at 16:15 Comment(0)
H
5

You can use the Alert component provided in question with minor modification using react-universal-flash as below

Just use it as a child of the Flasher Component

export const Alert = ({ content, type, deleteFlash}) => {
  const {color,inpType} = type;

  function AlertType(props) {
    const alertType = props.alertType;

    if (alertType === 'success') {
      return (
        <span role='img' className='text-3xl'>
          πŸŽ‰
        </span>
      );
    }

    if (alertType === 'warning') {
      return (
        <span role='img' className='text-3xl'>
          😱
        </span>
      );
    }
  }

  return (
        <div
          className={
            'text-white px-6 py-4 border-0 rounded relative mb-4 bg-' + color + '-500 flex items-center'
          }>
          <span className='text-xl inline-block mr-5 align-middle'>
            <AlertType alertType={inpType} />
          </span>
          <span className='inline-block align-middle mr-8'>
            <b className='uppercase'>{inpType}! </b>
            <span className='capitalize'>{content}</span>
          </span>
          <button
            className='absolute bg-transparent text-2xl font-semibold leading-none right-0 top-0 mt-4 mr-6 outline-none focus:outline-none'
            onClick={deleteFlash}>
            <span>Γ—</span>
          </button>
        </div>
  );
};

export default Alert;


//Import it and use it as child of Flasher from react-universal-flash


<Flasher>
<Alert>
</Flasher>

You can change the position prop of flasher to position it anywhere in page like "top_left","top_right" etc

While firing the messages you can import flash and pass parameters based on the custom type in your alert

// src/utils/debugger
async function getData(filter, captureName) {
  if (captureName === '') {
flash("this is an error",6000,{color:"red":inpType:"warning"})
  } else {
    axios({
      method: 'GET',
      url: `http://xxx/debugger/${filter}/${captureName}/logs`,
    })
      .then((res) => {
        if (res.data.length === 0) {
flash("this is an error",6000,{color:"red":inpType:"warning"})
        } else {

flash("this is an error",6000,{color:"green":inpType:"success"})
          console.log(res.data);
          data = res.data;
        }

        return res.data;
      })
      .catch((err) => {
        console.log(err);
      });
  }
}

Harquebusier answered 5/7, 2021 at 16:24 Comment(4)
Thanks...this kinda works but it doesnt allow me to place the error where i need. And styling the flash is a pain, with the way i have already designed my alert. I have updated my question with my alert component. – Loydloydie
You don't have to style the flash, you can use your existing alert. I have edited the answer based on it. Placing is fixed to all corners and center of the page, you can pass it as prop to flasher. Yeah if you need to position it somewhere else, then it might not be possible now, you will have to check other solution. – Harquebusier
perfect!! lovely thanks dude this was a great help – Loydloydie
np bro, let me know if any improvements has to be made to that library – Harquebusier
K
2

You can't pass a React component to alert(). alert() expects a string.

Koala answered 5/7, 2021 at 19:58 Comment(0)
R
0

You can use react tostify to show alerts!!

First, install it:

npm install --save react-toastify

In your app.js:

  import React from 'react';
  import { ToastContainer, toast } from 'react-toastify';

  import 'react-toastify/dist/ReactToastify.css';
  // minified version is also included
  // import 'react-toastify/dist/ReactToastify.min.css';

  function App(){
    const notify = () => toast("Wow so easy !");

    return (
      <div>
        <button onClick={notify}>Notify !</button>
        <ToastContainer />
      </div>
    );
  }

Remember to render the ToastContainer once in your application tree. If you can't figure out where to put it, rendering it in the application root would be the best bet.

After that you can import and call toast function where ever you want.

Read more on it here.

Rambo answered 5/7, 2021 at 21:8 Comment(0)

© 2022 - 2024 β€” McMap. All rights reserved.