dynamic import next.js for implementing modal dialog - reactjs

I have created a modal dialog component with a function toggleModal() which toggles the dialog.
I need to import this component and trigger toggleModal() from the parent component.
Bellow the component code to be dynamically imported:
import { useState, useEffect, useContext } from 'react'
const Modal = (props) => {
const [IsModalOpen, setIsModalOpen] = useState(true)
const toggleModal = () => {
setIsModalOpen(!IsModalOpen)
}
return(
<div className="fixed z-10 inset-0 overflow-y-auto">
<div className="flex">
<span className="hidden"></span>​
<div ref={ref} className="inline-block" role="dialog" aria-modal="true" aria-labelledby="modal-headline">
<div className="mt-3">
<h3 className="text-lg leading-6 font-medium text-gray-900" id="modal-headline">
Deactivate account
</h3>
<div className="mt-2">
<p className="text-sm leading-5 text-gray-500">
Are you sure you want to deactivate your account? All of your data will be permanently removed. This action cannot be undone.
</p>
</div>
</div>
<div className="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<span className="flex w-full rounded-md shadow-sm sm:ml-3 sm:w-auto">
<button type="button" className="inline-flex justify-center w-full rounded-md border border-transparent px-4 py-2 bg-red-600 text-base leading-6 font-medium text-white shadow-sm hover:bg-red-500 focus:outline-none focus:border-red-700 focus:shadow-outline-red transition ease-in-out duration-150 sm:text-sm sm:leading-5">
Deactivate
</button>
</span>
<span className="mt-3 flex w-full rounded-md shadow-sm sm:mt-0 sm:w-auto">
<button onClick={() => toggleModal()} type="button" className="inline-flex justify-center w-full rounded-md border border-gray-300 px-4 py-2 bg-white text-base leading-6 font-medium text-gray-700 shadow-sm hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue transition ease-in-out duration-150 sm:text-sm sm:leading-5">
Cancel
</button>
</span>
</div>
</div>
</div>
</div>
)
}
export default Modal
Here I import the component:
import { useState, useEffect } from 'react'
import dynamic from 'next/dynamic'
const Event = (props) => {
const {eventKey} = props
const [eventData, setEventData] = useState(null)
const [showModal, setshowModal] = useState(false)
const Modal = dynamic(() => import('./Modal'))
const openModal = () => {
setshowModal(true)
}
return (
eventData &&
<div className="max-w-sm rounded overflow-hidden shadow-lg m-3 sm:m-3 md:m-4 lg:m-6 ">
<img className="w-full" src={eventData.img} alt="Sunset in the mountains" />
<div className="px-6 py-4">
<div className="font-bold text-xl mb-2">{eventData.title}</div>
<div className="font-medium text-xs mb-2 text-gray-500">De {eventData.start} a {eventData.end}</div>
<p className="text-gray-700 text-base">
{eventData.desc}
</p>
</div>
<div className="px-6 pt-4 pb-2">
<span className="inline-block bg-gray-200 rounded-full px-3 py-1 text-xs font-semibold text-gray-500 mr-2 mb-2">#Yoga</span>
<span className="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-500 mr-2 mb-2">#winter</span>
<button onClick={() => openModal()} className="bg-indigo-600 hover:bg-indigo-500 text-xs font-medium text-white py-1 px-2 rounded-full">Recordarme</button>
</div>
{showModal && <Modal />}
</div>
)
}
export default Event
How can I import the component and trigger toggleModal() to display the modal dialog?

Related

Passing function to modal in ReactJs

In an application in ReactJs, I am trying to use a modal to confirm the deletion of a user. Normally I have a delete function created in the users table that deletes a user from my database. Now I would like to pass this functionality to the modal. I am wondering how I can easily pass the delete function to the modal. That when I confirm the delete action in modal a user is deleted. I would be grateful for any guidance.
MyModal.js
import React from "react";
export default function MyModal() {
const [showModal, setShowModal] = React.useState(false);
return (
<>
<button
className="bg-red-600 text-white active:bg-pink-600 font-bold uppercase text-sm px-6 py-3 rounded shadow hover:shadow-lg outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150"
type="button"
onClick={() => setShowModal(true)}
>
Delete
</button>
{showModal ? (
<>
<div className="justify-center items-center flex overflow-x-hidden overflow-y-auto fixed inset-0 z-50 outline-none focus:outline-none">
<div className="relative w-auto my-6 mx-auto max-w-3xl">
{/*content*/}
<div className="border-0 rounded-lg shadow-lg relative flex flex-col w-full bg-white outline-none focus:outline-none">
{/*header*/}
<div className="flex items-start justify-between p-5 border-b border-solid border-slate-200 rounded-t">
<h3 className="text-3xl font-semibold">Modal Title</h3>
<button
className="p-1 ml-auto bg-transparent border-0 text-black opacity-5 float-right text-3xl leading-none font-semibold outline-none focus:outline-none"
onClick={() => setShowModal(false)}
>
<span className="bg-transparent text-black opacity-5 h-6 w-6 text-2xl block outline-none focus:outline-none">
×
</span>
</button>
</div>
{/*body*/}
<div className="relative p-6 flex-auto">
<p className="my-4 text-slate-500 text-lg leading-relaxed">
Are you sure you want to delete this user?
</p>
</div>
{/*footer*/}
<div className="flex items-center justify-end p-6 border-t border-solid border-slate-200 rounded-b">
<button
className="text-blue-600 background-transparent font-bold uppercase px-6 py-2 text-sm outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150"
type="button"
onClick={() => setShowModal(false)}
>
Close
</button>
<button
className="bg-red-600 text-white active:bg-emerald-600 font-bold uppercase text-sm px-6 py-3 rounded shadow hover:shadow-lg outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150"
type="button"
onClick={() => setShowModal(false)}
>
Delete
</button>
</div>
</div>
</div>
</div>
<div className="opacity-25 fixed inset-0 z-40 bg-black"></div>
</>
) : null}
</>
);
}
ManageUser.js
import { useEffect, useState } from "react";
import { useAuthContext } from "../hooks/useAuthContext";
import MyModal from "../components/MyModal"
import LoadingSpinner from "../components/LoadingSpinner";
function ManageUser() {
const [users, setUser] = useState([]);
const [loading, setLoading] = useState(false)
useEffect(() => {
getData();
}, []);
async function deleteOperation(_id) {
let result = await fetch(`/api/user/${_id}`, {
method: "DELETE",
});
result = await result.json();
console.warn(result);
getData();
}
async function getData() {
setLoading(true)
let result = await fetch("/api/user/users");
result = await result.json();
setUser(result);
setLoading(false)
}
return (
<div>
<h1 className="flex justify-center py-4 text-xl font-bold">Zarządzaj użytkownikami:</h1>
<div className="flex justify-center py-2">
<div className="flex justify-between items-center h-30 max-w-[1240px] mx-auto px-4">
{ loading ? (<div className="flex justify-center items-center "><LoadingSpinner/></div>) :
<div className=" overflow-x-auto relative shadow-md sm:rounded-lg">
<table className="w-full text-sm text-center text-white">
<thead className="text-xs text-white uppercase bg-rgba(6, 18, 36, 0.945)">
<tr>
<th scope="col" className="py-3 px-6">
Nazwa
</th>
<th scope="col" className="py-3 px-6 hidden sm:table-cell">
Email
</th>
<th scope="col" className="py-3 px-6">
Admin
</th>
<th scope="col" className="py-3 px-6">
</th>
</tr>
</thead>
<tbody>
{users.map((user) => (
<tr key={user._id} user={user} className="bg-rgba(6, 18, 36, 0.945) border-b border-[#00df9a] ">
<th scope="row" className="py-4 px-6 font-medium text-white whitespace-nowrap">
{user.name}
</th>
<td className="py-4 px-6 hidden sm:table-cell">
{user.email}
</td>
<td className="py-4 px-6">
{user.isAdmin ? "Tak" : "Nie"}
</td>
<td className="py-4 px-6 text-right">
<MyModal/><button className="bg-red-500 hover:bg-[#00df9a] text-white font-semibold py-2 px-4 border border-zinc-900 rounded shadow" onClick={() => deleteOperation(user._id)}>Delete</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
}
</div>
</div>
</div>
);
}
export default ManageUser;
Is there any quick way to pass the function that I use for deleting a user to this modal?
You could just pass a property to your model component, lets call it onSubmit
export default function MyModal( { onSubmit } ) {
Within your modal you can handle the submitting with a submitHandler like
const submitHandler = () => {
setShowModal(false);
onSubmit();
}
Your delete button in the MyModal can call this submitHandler like
<button onClick={submitHandler}>
Delete
</button>
and within your ManageUser component you could pass the deleteOperation as the onSubmit function like
<MyModal onSubmit={() => deleteOperation(user.id)}/>

how to obtain the value of the input?

I am trying to make a clinic locator that when you put where you are, you get as a result the nearby clinics, I can not enter data in the imput, not even let me write and I can not find the problem.
import React, { useState, useEffect } from 'react'
import { getClinic } from '../../api/drupalAPI'
import {Clinic} from '#icofcv/common';
import Spinner from '../spinner/Spinner';
interface Props {
showModalLocator: boolean,
closeModalLocator: () => void
}
export const ClinicLocator: React.FC<Props> = ({ children, showModalLocator, closeModalLocator }) => {
const [clinicList, setClinicList] = useState<Clinic[]>([]);
const [clinicListFiltered, setClinicListFiltered] = useState<Clinic[]>([]);
const [searchClinic, setSearchClinic] = useState("");
const handleChange= (e) => async () => {
getClinic().then((response)=>{
console.log(response)
setClinicList(response);
setClinicListFiltered(response)
}).catch ( (error) => {
console.error(error);
throw error;
});
setSearchClinic(e.target.value);
filter(e.target.value);
}
const filter=(termSearch)=>{
const resultSearch= clinicList.filter((element)=>{
if(element.address?.toString().toLowerCase().includes(termSearch.toLowerCase())
|| element.province?.toString().toLowerCase().includes(termSearch.toLowerCase())
|| element.town?.toString().toLowerCase().includes(termSearch.toLowerCase())
){
return element;
}
});
setClinicListFiltered(resultSearch);
}
return (
<>
<div>
{showModalLocator ? (
<>
<div className="justify-center items-center flex overflow-x-hidden overflow-y-auto fixed inset-0 z-50 outline-none focus:outline-none">
<div className="relative p-2 w-full max-w-3xl h-full md:h-auto">
{/*content*/}
<div className="relative bg-white rounded-lg shadow">
{/*header*/}
<div className="flex justify-between items-start px-4 py-3 rounded-t border-b">
<h3 className="text-lg font-medium">Localizador de clinicas</h3>
<button className="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center" onClick={closeModalLocator}>
<svg aria-hidden="true" className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path>
</svg>
</button>
</div>
{/*body*/}
<div className="relative px-3 py-3 flex-auto overflow-auto modal-body">
<h2 className="text-sm font-medium mb-2">¿Dónde te encuentras?</h2>
<input
value={searchClinic}
onChange={handleChange}
type="search"
className="w-100 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2"
placeholder="Introduce una ubicación"
/>
<div className="py-3 border-b flex flex-col md:flex-row items-start md:items-center md:justify-between justify-start gap-2">
<div className="flex items-center">
<label className="inline-flex relative items-center mr-5 cursor-pointer">
<input type="checkbox" className="sr-only peer" checked/>
<div className="w-11 h-6 bg-gray-200 rounded-full peer peer-focus:ring-teeal-600
peer-checked:after:translate-x-full peer-checked:after:border-white after:content-['']
after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-teal-600"></div>
<span className="ml-2 text-xs font-medium text-gray-900">Centro privado</span>
</label>
</div>
<div className="flex items-center">
<label className="inline-flex relative items-center mr-5 cursor-pointer">
<input type="checkbox" className="sr-only peer" readOnly/>
<div className="w-11 h-6 bg-gray-200 rounded-full peer peer-focus:ring-teeal-600
peer-checked:after:translate-x-full peer-checked:after:border-white after:content-['']
after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-teal-600"></div>
<span className="ml-2 text-xs font-medium text-gray-900">con Mútuas</span>
</label>
</div>
<div className="flex items-center">
<label className="inline-flex relative items-center mr-5 cursor-pointer">
<input type="checkbox" className="sr-only peer" readOnly/>
<div className="w-11 h-6 bg-gray-200 rounded-full peer peer-focus:ring-teeal-600
peer-checked:after:translate-x-full peer-checked:after:border-white after:content-['']
after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-teal-600"></div>
<span className="ml-2 text-xs font-medium text-gray-900">con Compañías de Salud</span>
</label>
</div>
</div>
<div>
<h2 className="text-sm font-medium my-3">Resultados</h2>
<div className="w-100">
<iframe className="w-100" src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2664.3238269926374!2d-0.3805919350162851!3d39.46959682083709!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0xd604f4bee0957f3%3A0x6686ff7d230b3965!2zQy4gZGUgU2FudC
BWaWNlbnQgTcOgcnRpciwgNjEsIHBpc28gMsK6LCBwdGEgMsKqLCA0NjAwMiBWYWzDqG5jaWEsIEVzcGHDsWE!5e0!3m2!1ses!2sus!4v1662388390673!5m2!1ses!2sus" loading="lazy"></iframe>
</div>
<div className="md:mt-4 overflow-auto relative py-2">
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
<div className="card bg-white px-2 py-3 h-36 md:h-32">
{!clinicListFiltered ? <Spinner /> :
clinicListFiltered.map((clinic) => (
<button key={clinic.id} type="button" className="text-left">
<div className="flex items-center gap-2 md:gap-4 md:gap-4">
<img className="h-24 w-2/5 min-w-40 object-cover object-center rounded-lg" src="../carousel-1.svg" alt="#"/>
<div className="w-3/5">
<div className="text-md font-medium leading-5 clinic-title uppercase">{clinic.title}</div>
<div className="flex items-center gap-2">
<div className="text-neutral-500 text-sm">{clinic.propsPhone}</div>
<div className="text-neutral-500 text-sm">{clinic.mobile}</div>
</div>
<div className="text-teal-600 text-sm underline clinic-mail">{clinic.email}</div>
<div className="text-neutral-500 text-sm">{clinic.registry}</div>
</div>
</div>
</button>
))
}
</div>
{/* <div className="card bg-white px-2 py-3 h-36 md:h-32">
<button type="button" className="text-left">
<div className="flex items-center gap-2 md:gap-4 md:gap-4">
<img className="h-24 w-2/5 min-w-40 object-cover object-center rounded-lg" src="../carousel-1.svg" alt="#"/>
<div className="w-3/5">
<div className="text-md font-medium leading-5 clinic-title uppercase">AlamedaVLC</div>
<div className="flex items-center gap-2">
<div className="text-neutral-500 text-sm">963255652</div>
<div className="text-neutral-500 text-sm">963255652</div>
</div>
<div className="text-teal-600 text-sm underline clinic-mail">fisioalamedavlc#gmail.com</div>
<div className="text-neutral-500 text-sm">9947</div>
</div>
</div>
</button>
</div> */}
</div>
</div>
</div>
</div>
{/*footer*/}
<div className="flex items-center justify-end px-4 py-2 border-t border-solid border-slate-200 rounded-b gap-2">
<button className="btn text-black text-sm background-transparent px-8 outline-none focus:outline-none focus:ring-teal-600 focus:border-teal-600" type="button" onClick={closeModalLocator}>Cancelar</button>
<button className="btn bg-teal-600 hover:bg-teal-700 text-white text-sm active:bg-teal-700 px-8 outline-none focus:outline-none" type="button" onClick={closeModalLocator}>Buscar</button>
</div>
</div>
</div>
</div>
<div className="opacity-25 fixed inset-0 z-40 bg-black"></div>
</>
) : null}
</div>
</>
)
}
Try to change the line
const handleChange= (e) => async () => {
to
const handleChange = (e) => {
You're currently returning a function, which means that it doesn't get called. There is also no need for async as you don't have any await in the function.
handleChange returns a function which is never executed; remove the currying as it is not needed:
const handleChange= (e) => {
getClinic().then((response)=>{
console.log(response)
setClinicList(response);
setClinicListFiltered(response)
}).catch ( (error) => {
console.error(error);
throw error;
});
setSearchClinic(e.target.value);
filter(e.target.value);
}
The reason you cannot input anything is that React treats the input field as controlled component, which means that it itself won't take care of updating the fields value since you passed an initial value (of ""). With controlled components, you as the developer are required to handle the state outside of the input field, i.e. update the value attribute of the input component. Since that failed due to the mistake outlined above, the value of the input field remains fixed at "", thus not allowing you to type in the field.
Further reading:
Controlled components
Uncontrolled components

Access JSX react variables in a button

I have mapped a list of responses from my backend mongodb to my frontend. For each response, I have also added a button. I want to add an voteResponse function for my vote button. How can I continue to have access to my {response.respondee} and {response.response} in my voteResponse function?
{responses.map((response) => (
<div
key={response._id}
className='py-8 px-12 mb-12 bg-gray-50 border-b border-gray-100 transform transition duration-300 ease-in-out hover:-translate-y-2'
>
<NextLink href={`/responses/${response.response}`} passHref>
<div>
<div className='inline-block text-gray-900 mb-4'></div>
<h3 className='text-lg leading-normal mb-2 font-semibold text-black'>
{response.response}
</h3>
<p className='text-gray-500'>
{response.respondee.slice(0, 5)}...
{response.respondee.slice(38)}
</p>
</div>
</NextLink>
<div>
<button
type='submit'
className='inline-flex justify-center mt-3 py-1 px-3 border border-transparent shadow text-base font-medium rounded-md text-white bg-cyan-600 hover:bg-cyan-700 focus:outline-none'
onClick={voteResponse}
>
Vote
</button>
</div>
</div>
))}
You can do this by 2 ways. First is by making a separate component which is being rendered in map function and pass response in it through props then each component will have access to it's response.response and response.respondee.
funtion Response({response}){
const voteResponse = () =>{
console.log(response.response, response.respondee)
}
return(
<div key={response._id} className='py-8 px-12 mb-12 bg-gray-50 border-b border-gray-100 transform transition duration-300 ease-in-out hover:-translate-y-2'>
<NextLink href={`/responses/${response.response}`} passHref>
<div>
<div className='inline-block text-gray-900 mb-4'></div>
<h3 className='text-lg leading-normal mb-2 font-semibold text-black'>
{response.response}
</h3>
<p className='text-gray-500'>
{response.respondee.slice(0, 5)}... {response.respondee.slice(38)}
</p>
</div>
</NextLink>
<div>
<button type='submit' className='inline-flex justify-center mt-3 py-1 px-3 border border-transparent shadow text-base font-medium rounded-md text-white bg-cyan-600 hover:bg-cyan-700 focus:outline-none' onClick={voteResponse}>
Vote
</button>
</div>
</div>
)
}
//use it like this
{responses.map((response) => (
<Response response={response} key={response._id} />
))}
Second way to pass the index in voteResponse function and then through that index you can access the those variables like responses[index].response and responses[index].respondee.
{responses.map((response, index) => (
<div key={response._id} className='py-8 px-12 mb-12 bg-gray-50 border-b border-gray-100 transform transition duration-300 ease-in-out hover:-translate-y-2'>
<NextLink href={`/responses/${response.response}`} passHref>
<div>
<div className='inline-block text-gray-900 mb-4'></div>
<h3 className='text-lg leading-normal mb-2 font-semibold text-black'>
{response.response}
</h3>
<p className='text-gray-500'>
{response.respondee.slice(0, 5)}... {response.respondee.slice(38)}
</p>
</div>
</NextLink>
<div>
<button type='submit' className='inline-flex justify-center mt-3 py-1 px-3 border border-transparent shadow text-base font-medium rounded-md text-white bg-cyan-600 hover:bg-cyan-700 focus:outline-none' onClick={voteResponse}>
Vote
</button>
</div>
</div>
))}
Pass value to onClick prop: onClick={() => voteResponse(response)} and use it as parameter of voteResponse function:
const voteResponse = (res) => {
console.log("response.respondee is: ", res.respondee) //<=== response.respondee value is res.respondee value
console.log("response.response is: ", res.response)
}
{responses.map((response) => (
<div
key={response._id}
className='py-8 px-12 mb-12 bg-gray-50 border-b border-gray-100 transform transition duration-300 ease-in-out hover:-translate-y-2'
>
<NextLink href={`/responses/${response.response}`} passHref>
<div>
<div className='inline-block text-gray-900 mb-4'></div>
<h3 className='text-lg leading-normal mb-2 font-semibold text-black'>
{response.response}
</h3>
<p className='text-gray-500'>
{response.respondee.slice(0, 5)}...
{response.respondee.slice(38)}
</p>
</div>
</NextLink>
<div>
<button
type='submit'
className='inline-flex justify-center mt-3 py-1 px-3 border border-transparent shadow text-base font-medium rounded-md text-white bg-cyan-600 hover:bg-cyan-700 focus:outline-none'
onClick={() => voteResponse(response)
>
Vote
</button>
</div>
</div>
))}

React/Tailwind CSS: Search bar filter moving when typed in/filtering data

Its been a while since I coded in react and I'm working on teaching myself again. Also this is the first time I've used Tailwind CSS. I'm working with a navbar component that has a search bar to filter data within a database. I have everything setup correctly for the most part. The issue is that when you type in the search bar, the user img, and buttons moved like the nav sections is being pushed down when the filter response shows up below the search bar.
Here is my code for the navbar with the search bar
import React, { useState } from "react";
import UserDropdown from "../../components/Dropdowns/UserDropdown.js";
import AccountDropdown from "../Dropdowns/AccountDropdown.js";
export default function Navbar({ data }) {
const [filteredData, setFilteredData] = useState([]);
const [wordEntered, setWordEntered] = useState("");
const handleFilter = (event) => {
const searchWord = event.target.value;
setWordEntered(searchWord);
const newFilter = data.filter((value) => {
return value.dealership.toLowerCase().includes(searchWord.toLowerCase());
});
if (searchWord === "") {
setFilteredData([]);
} else {
setFilteredData(newFilter);
}
};
return (
<>
{/* Navbar */}
<div className="relative bg-lightBlue-600 md:pt-32 pb-32 pt-12">
<nav className="absolute top-0 left-0 w-full z-10 bg-transparent md:flex-row md:flex-nowrap md:justify-start flex items-center p-4">
<div className="w-full mx-autp items-center flex justify-between md:flex-nowrap flex-wrap md:px-10 px-4">
{/* Brand */}
<a
className="text-white text-sm uppercase hidden lg:inline-block font-semibold"
href="#pablo"
onClick={(e) => e.preventDefault()}
>
Dashboard
</a>
<div className="md:flex flex-row flex-wrap items-center lg:ml-auto mr-3">
<AccountDropdown />
</div>
{/* Form */}
<form className="md:flex hidden flex-row flex-wrap items-center lg:ml-auto mr-3">
<div className="relative flex w-full flex-wrap items-stretch">
<span className="z-10 h-full leading-snug font-normal absolute text-center text-blueGray-300 absolute bg-transparent rounded text-base items-center justify-center w-8 pl-3 py-3">
<i className="fas fa-search"></i>
</span>
<input
type="text"
placeholder="Search here..."
className="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 relative bg-white bg-white rounded text-sm shadow outline-none focus:outline-none focus:ring w-full pl-10"
value={wordEntered}
onChange={handleFilter}
/>
</div>
{filteredData.length != 0 && (
<div className="dataResult">
{filteredData.slice(0, 15).map((value) => {
return (
<a className="dataItem" href="/admin/dashboard">
<p>{value.dealership}</p>
</a>
);
})}
</div>
)}
</form>
{/* User */}
<ul className="flex-col md:flex-row list-none items-center hidden md:flex">
<UserDropdown />
</ul>
</div>
</nav>
</div>
{/* End Navbar */}
</>
);
}
Here are a few pics of what it does.
I guess it is because of align-items property. When the data shows, the height of the component is changing so alignment should be flex-start in css. You can remove items-center because its default value is flex-start in css. Or you can replace with items-start.
You wrote
<nav className="absolute top-0 left-0 w-full z-10 bg-transparent md:flex-row md:flex-nowrap md:justify-start flex items-center p-4">
And I think it should be like this
<nav className="absolute top-0 left-0 w-full z-10 bg-transparent md:flex-row md:flex-nowrap md:justify-start flex items-start p-4">
Or this
<nav className="absolute top-0 left-0 w-full z-10 bg-transparent md:flex-row md:flex-nowrap md:justify-start flex p-4">

Conditionally render download button in react

I have a download button from which the user can download the assets. but I want only authenticated users can download. If the user is not authenticated and click on the download button I want to show them a modal with a login button on it. I have a modal component. I am using React.
Please help me.
Getting currently authenticated user from the firebase.
const {currentUser} = useAuth();
This is my code for the download button.
<a className="bg-secondary text-white font-bold py-3
px-5 rounded text-2xl focus:outline-none mt-3 block w-48" href="YOUR_URL">
<i className="animate-bounce fas fa-arrow-down mr-2"></i>
Download
</a>
Modal Code:
import React from "react";
import { useState } from "react";
export default function Modal() {
const [showModal, setShowModal] = useState(true);
console.log('modal');
return (
<>
{showModal ? (
<>
<div
className="justify-center items-center flex overflow-x-hidden overflow-y-auto fixed inset-0 z-50 outline-none focus:outline-none"
onClick={() => setShowModal(false)}
>
<div className="relative w-auto my-6 mx-auto max-w-3xl">
{/*content*/}
<div className="border-0 rounded-lg shadow-lg relative flex flex-col w-full bg-white outline-none focus:outline-none">
{/*header*/}
<div className="flex items-start justify-between p-5 border-b border-solid border-gray-300 rounded-t">
<h3 className="text-3xl font-semibold">
Modal Title
</h3>
<button
className="p-1 ml-auto bg-transparent border-0 text-black opacity-5 float-right text-3xl leading-none font-semibold outline-none focus:outline-none"
onClick={() => setShowModal(false)}
>
<span className="bg-transparent text-black opacity-5 h-6 w-6 text-2xl block outline-none focus:outline-none">
×
</span>
</button>
</div>
{/*body*/}
<div className="relative p-6 flex-auto">
<p className="my-4 text-gray-600 text-lg leading-relaxed">
I always felt like I could do anything. That’s the main
thing people are controlled by! Thoughts- their perception
of themselves! They're slowed down by their perception of
themselves. If you're taught you can’t do anything, you
won’t do anything. I was taught I could do everything.
</p>
</div>
{/*footer*/}
<div className="flex items-center justify-end p-6 border-t border-solid border-gray-300 rounded-b">
<button
className="text-red-500 background-transparent font-bold uppercase px-6 py-2 text-sm outline-none focus:outline-none mr-1 mb-1"
type="button"
style={{ transition: "all .15s ease" }}
onClick={() => setShowModal(false)}
>
Close
</button>
<button
className="bg-green-500 text-white active:bg-green-600 font-bold uppercase text-sm px-6 py-3 rounded shadow hover:shadow-lg outline-none focus:outline-none mr-1 mb-1"
type="button"
style={{ transition: "all .15s ease" }}
onClick={() => setShowModal(false)}
>
Save Changes
</button>
</div>
</div>
</div>
</div>
<div className="opacity-25 fixed inset-0 z-40 bg-black"></div>
</>
) : null}
</>
);
}
You could use button instead of a and use onClick to check if currentUser exists when you click button.
This is final code:
function x {
const {currentUser} = useAuth();
const downloadAssets = () => {
if(currentUser){
window.open("url assets here", '_blank', 'noopener,noreferrer')
}else{
// Open modal here
alert("User not authenticated");
}
}
return {
<>
...
<button onClick={downloadAssets}><i className="animate-bounce fas fa-arrow-down mr-2"></I>Download</button>
...
</>
}

Resources