Conditionally render download button in react - reactjs

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>
...
</>
}

Related

HTTP 302 Redirect when using OAuth nextjs

i'm trying to put OAuth in my project but after i log in with my gmail the default redirect page will show up and say's that i have to
Try signing in with a different account.
here's my code
import Image from "next/image"
import { signIn } from "next-auth/react"
export default function Login({ provider }) {
return (
<div className="flex flex-col items-center space-y-20 pt-48">
<Image
src="/image/pictures/twitter-icon-svg-28.jpg"
width={150}
height={150}
objectFit="contain"
className="bg-transparent"
/>
{Object.values(provider).map(provider => {
return (
<div key={provider.name} className="flex flex-col items-center space-y-20 pt-48">
<button onClick={() => signIn(provider.id, { callbackUrl: "/" })}>
<a href="#_" className="relative inline-flex items-center justify-center px-6 py-3 text-lg font-medium tracking-tighter text-white bg-gray-800 rounded-md group">
<span className="absolute inset-0 w-full h-full mt-1 ml-1 transition-all duration-300 ease-in-out bg-blue-600 rounded-md group-hover:mt-0 group-hover:ml-0"></span>
<span className="absolute inset-0 w-full h-full bg-white rounded-md "></span>
<span className="absolute inset-0 w-full h-full transition-all duration-200 ease-in-out delay-100 bg-blue-600 rounded-md opacity-0 group-hover:opacity-100 "></span>
<span className="relative text-blue-600 transition-colors duration-200 ease-in-out delay-100 group-hover:text-white">
Signin With {provider.name}
</span>
</a>
</button>
</div>
)
})}
</div>
)
}
i set everything needed for google credential and nextauth_URL in env.local file but i don't know why am i getting 302 redirect error and cant log in into my website

ReactJS: Button Enable disable with change color

here I have a problem related to making the disable and enable button logic functions.
So, when the user selects the menu in the select option, the button that was originally disabled becomes enable and the color of the button changes too.
how to create such a function? Thanks.
before choosing, the button is disabled.
User selects menu.
The user after selecting the menu, the button changes to enable and the button color also changes.
My Code =
const ButtonModal = () => {
const [openModal, setOpenModal] = useState(false);
const [selectedOption, setSelectedOption] = useState(null);
const handleModal = () => setOpenModal(!openModal);
return (
<>
<button
onClick={handleModal}
className="bg-merah text-white font-bold text-sm rounded-2xl w-48 h-10 py-2 mb-6"
>
Perbarui Kompetitor
</button>
<Modal
center
open={openModal}
onClose={handleModal}
showCloseIcon={false}
>
<section className="grid justify-items-end">
<AiOutlineClose
size={20}
onClick={handleModal}
className="cursor-pointer"
/>
</section>
<div className="flex items-center justify-center mb-4">
<section className="inline-flex gap-2">
<p className="font-bold text-center">Pembaruan Data Kompetitor</p>
</section>
</div>
<p>
Tambah data dengan memilih nama kompetitor yang tersedia atau masukkan
data baru.
</p>
<p className="font-bold mt-6">Nama Kompetitor</p>
<div class="flex justify-center">
<div class="mb-3 w-600 mr-6 mt-2">
<select
onChange={(e) => setSelectedOption(e.target.value)}
class="form-select appearance-none
block
w-full
px-3
py-1.5
mb-1
text-base
font-normal
text-gray-700
bg-white bg-clip-padding bg-no-repeat
border border-solid border-gray-300
rounded
transition
ease-in-out
m-0
focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none"
aria-label="Default select example"
>
<option selected>Pilih nama kompetitor</option>
<option value="biznet">Biznet</option>
<option value="cbn">CBN</option>
<option value="first_media">First Media</option>
<option value="iconet">Iconet</option>
<option value="oxygen">Oxygen</option>
<option value="my_republik">My Republik</option>
<option value="other">Lainnya</option>
</select>
</div>
</div>
{selectedOption === "other" && (
<div class="mb-6">
<input
class="w-[37.5rem] 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.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
placeholder="Masukan nama kompetitor..."
required
/>
</div>
)}
<div className="flex items-center justify-center">
<button
onClick={handleModal}
type="button"
class="inline-block px-6 py-2 border-2 border-red-600 text-red-600 font-medium text-xs leading-tight rounded hover:bg-black hover:bg-opacity-5 focus:outline-none focus:ring-0 transition duration-150 ease-in-out"
>
Kembali
</button>
<button
type="button"
class="inline-block ml-6 px-6 py-2.5 bg-gray-200 text-gray-700 font-medium text-xs leading-tight rounded shadow-md hover:bg-gray-300 hover:shadow-lg focus:bg-gray-300 focus:shadow-lg focus:outline-none focus:ring-0 active:bg-gray-400 active:shadow-lg transition duration-150 ease-in-out"
disabled
>
Lanjutkan
</button>
</div>
</Modal>
</>
);
};
Bind the button's disabled attribute to the selectedOption state - is this what you're after?
And do the same for changing colour, using a ternary to set the value.
<button
onClick={handleModal}
disabled={!selectedOption}
style={{ background: selectedOption ? 'red': 'transparent' }}
className="bg-merah text-white font-bold text-sm rounded-2xl w-48 h-10 py-2 mb-6"
/>
EDIT: I think I saw you mention in a comment that it's the other button. Just set them on the other button then.
Also edited to bind to the more appropriate state selectedOption.
disabled={!selectedOption}
style={{ background: selectedOption ? 'red': 'transparent' }}

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>
))}

How can I get a modal to be larger on desktop?

I am trying to get the modal on the site I'm working on to open larger on a desktop and to change to a vertical view in mobile, like these examples which I designed in Figma:
.
Any help with what I could change in the code to reflect these images would be amazing.
{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 grid grid-cols-2 ">
{/* which grid? number one */}
<div className="border-0 rounded-lg shadow-lg relative flex flex-col w-full bg-white outline-none focus:outline-none">
<Image
src={ImageLink}
alt="Work?"
width="600"
height="600"
layout="responsive"
onClick={() => setShowModal(true)}
/>
</div>
{/*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">
{Name} </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">
{Description}
</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)}
>
Contact
</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)}
>
Make an Offer </button>
</div>
</div>
</div>
</div>
<div className="opacity-25 fixed inset-0 z-40 bg-black"></div>
</>
) : null}
</>
);
}
I'm just stuck on tailwind documentation - trying to use the grid system, it just doesn't want to work and would love to understand where i'm going wrong.
Here is a link to the current site to see how it looks currently
https://greenr-two.vercel.app/example
thanks in advance,
It's a simple change.
On mobile, grid-cols-1 with col-span-1 will give 100% to image and div.
On Desktop, md:grid-cols-3 with image as col-span-2 will consume 66% (2/3 * 100) . Whereas div with col-span-1 will consume 33% (1/3 * 100).
<div class="grid grid-cols-1 md:grid-cols-3">
<image class="col-span-1 md:col-span-2" />
<div class="col-span-1"></div>
</div>

dynamic import next.js for implementing modal dialog

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?

Resources