React recaptcha is displayed - reactjs

I have this code, I would like to make recaptcha hidden,
how to do it, my recaptcha show general conditions with icon in the right lower corner.
Do I need to clean recaptcha?
window['recaptchaVerifier'].clear()
I won't to show this icon, recaptcha logo. I need it
to make 2FA authentication sms + email. It should work
without showing some elements, or is problem that I have
this div?
<div ref={recaptchaWrapperRef}>
<div id="recaptcha-container"></div>
</div>
import { Button } from '#material-ui/core'
import React, { useEffect, useRef } from 'react'
import { auth, provider } from '../firebase/firebase'
import useDeviceDetect from '../utils/useDeviceDetect'
import './Login.scss'
declare global {
interface Window { recaptchaVerifier: any; }
}
function Login(props: any) {
const val = useRef()
const recaptchaWrapperRef = useRef(null);
useEffect(() => {
initialiseRecaptcha()
}, [])
const { isMobile } = useDeviceDetect();
const initialiseRecaptcha = () => {
setTimeout(() => {
if (!window['recaptchaVerifier']) {
window['recaptchaVerifier'] = new auth.RecaptchaVerifier(
"recaptcha-container",
{
'size': "invisible"
}
);
}
}, 2000)
}
const TwoFactorAuthentication = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
smsVerification()
signIn(e)
}
const signIn = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
e.preventDefault()
auth().signInWithPopup(provider)
.then(result => {
localStorage.setItem('user', JSON.stringify(result.user));
window.location.href = '/'
}).catch(error => {
alert(error.message)
})
}
const smsVerification = () => {
if (window['recaptchaVerifier'] != null) {
new auth.PhoneAuthProvider().verifyPhoneNumber("+421944777170", window['recaptchaVerifier'])
.then(function (verificationId) {
var verificationCode = window.prompt('Please enter the verification code' +
', that was sent on mobile device')
if (verificationCode != null) {
return auth.PhoneAuthProvider.credential(verificationId, verificationCode)
}
})
.then(function (phoneCredential) {
if (phoneCredential != null) {
console.log(phoneCredential)
return auth().signInWithCredential(phoneCredential)
}
})
.catch(function (error) {
})
}
}
return (<>
<div className="login">
<div className="login__logo">
<img
src="https://i.pinimg.com/originals/c6/f2/cd/c6f2cd5e0ebf33ff1ae0b01d0407224c.png"
alt="" />
<img
src="https://svgshare.com/i/PTv.svg"
alt="" />
</div>
<Button id="sign-in-button" type="submit" onClick={TwoFactorAuthentication}>
Signin
</Button>
<div ref={recaptchaWrapperRef}>
<div id="recaptcha-container"></div>
</div>
</div>
</>
)
}
export default Login
EDIT:
I have found that I need set visibility:hidden on css of grecaptcha div, but it always rerender and disable my setting.
const hiddenGRecaptcha = () => {
var head = document.getElementsByClassName('grecaptcha-badge')[0] as HTMLElement
if (head !== undefined) {
head.style.visibility = "hidden"
console.log(head)
}
}
this is my new function in typescript to hide recaptcha badge but css are always overwritten don't know where to put it or how to make it persistent.

Related

In react - once I change the value of the data in my API - how can I then re-render my component with the new data?

I've tried to fix this with the useState hook but it still won't work - if I click the checkbox the first time the div will turn green, but when I untick it, it still stays green.
Here is my new code - please help
import React, { useState } from 'react'
import './item.css'
import axios from 'axios';
const Item = ({ todo }) => {
const [tryThis, setTryThis] = useState(todo.complete)
const eventHandle = async () => {
try {
if(todo.complete == false) {
const res = await axios.put(`todo/${todo._id}`, {
complete: true,
})
// window.location.reload();
setTryThis(true)
console.log(res)
} else {
const res = await axios.put(`todo/${todo._id}`, {
complete: false,
})
// window.location.reload();
setTryThis(false)
console.log(res)
}
} catch(err) {
console.log(err)
}
}
const deleteTodo = () => {
axios.delete(`todo/${todo._id}`)
window.location.reload();
}
return (
<li>
<div className={!tryThis ? 'item' : 'item itemComplete'} >
<div className='itemText'>
<p>{todo.desc}</p>
</div>
<div className='itemInput'>
<input type='checkbox' defaultChecked={todo.complete} onClick={() => eventHandle()} />
</div>
<div className='itemButton'>
<button className='actualButton' onClick={() => deleteTodo()} >Delete</button>
</div>
</div>
</li>
)
}
export default Item
import React, { useState } from 'react'
import './item.css'
import axios from 'axios';
const Item = ({ todo }) => {
const eventHandle = async () => {
try {
if(todo.complete == false) {
const res = await axios.put(`todo/${todo._id}`, {
complete: true,
})
window.location.reload();
console.log(res)
} else {
const res = await axios.put(`todo/${todo._id}`, {
complete: false,
})
window.location.reload();
console.log(res)
}
} catch(err) {
console.log(err)
}
}
const deleteTodo = () => {
axios.delete(`todo/${todo._id}`)
window.location.reload();
}
return (
<li>
<div className={!todo.complete ? 'item' : 'item itemComplete'} >
<div className='itemText'>
<p>{todo.desc}</p>
</div>
<div className='itemInput'>
<input type='checkbox' defaultChecked={todo.complete} onClick={() => eventHandle()} />
</div>
<div className='itemButton'>
<button className='actualButton' onClick={() => deleteTodo()} >Delete</button>
</div>
</div>
</li>
)
}
export default Item
I am new to programming and have been trying to build a todo app using the MERN stack.
It's working fine except for one function. When a task is complete I want to tick the checkbox which then turns the parent div background green.
In order to make my changes happen instantly I'm using -
window.location.reload();
Without this the background doesn't go green until I manually hit refresh.
This code works for the moment but I'm worried that this isn't a good practice as every time I do anything the console clears as the whole page is reloaded.
Is there some way of just refreshing that particular component and not the entire page?
Thanks

Stripe : Could not find Elements context error in nextjs

I am using stripe following package in nextjs 12
import { loadStripe } from "#stripe/stripe-js";
import { Elements } from "#stripe/react-stripe-js";
It is working well in developement mode but while production build it is throwing this error
Error: Could not find Elements context; You need to wrap the part of your app that calls useStripe() in an <Elements> provider.
I am using Elements as a parent container and Checkoutform inside Elements as a child
import React from 'react'
import { useAppContext } from '#/context/AppContext';
import { loadStripe } from "#stripe/stripe-js";
import { Elements } from "#stripe/react-stripe-js";
import Checkoutform from './Checkoutform';
import AppLoader from '#/components/common/Loader';
const Payment = () => {
const { state } = useAppContext();
const { user, planType } = state;
const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_KEY);
const options = {
clientSecret: planType.orderData.client_secret,
appearance: {
theme: 'stripe',
}
};
return (
options.clientSecret && options.clientSecret.length > 0 ? (
<Elements stripe={stripePromise} options={options} >
<Checkoutform userData={user} planType={planType} />
</Elements >
) : (
<AppLoader />
)
)
}
export default Payment
Checkoutform.js
import React, { useEffect, useState } from "react";
import {
PaymentElement,
useStripe,
useElements
} from "#stripe/react-stripe-js";
import AppLoader from "#/components/common/Loader";
import { toast } from "react-toastify";
import { baseURL } from "#/constants/utils/universal";
export default function Checkoutform(props) {
const { userData, planType } = props;
const stripe = useStripe();
const elements = useElements();
const [message, setMessage] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const [isInitialized, setIsInitialized] = useState(true);
const redirectUrl = baseURL + "/pricing/payment/success";
useEffect(() => {
if (typeof window === "undefined" && !stripe) {
return;
}
const clientSecret = new URLSearchParams(window.location.search).get(
"payment_intent_client_secret"
);
if (!clientSecret) {
return;
}
stripe.retrievePaymentIntent(clientSecret).then(({ paymentIntent }) => {
switch (paymentIntent.status) {
case "succeeded":
toast.success("Thankyou!, Payment Successful, please check your email for your receipt");
setMessage("Payment succeeded!");
break;
case "processing":
setMessage("Your payment is processing.");
break;
case "requires_payment_method":
setMessage("Your payment was not successful, please try again.");
break;
default:
setMessage("Something went wrong.");
break;
}
});
}, [stripe]);
useEffect(() => {
setTimeout(() => {
if (typeof window !== "undefined") {
setIsInitialized(false);
}
}, 1000);
}, [])
const handleSubmit = async (e) => {
e.preventDefault();
if (!stripe || !elements) {
return;
}
setIsLoading(true);
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: redirectUrl,
},
});
if (error.type === "card_error" || error.type === "validation_error") {
toast.error("Oops! some error occurred, please try again");
setMessage(error.message);
} else {
toast.error("Oops! some error occurred, please try again");
setMessage("An unexpected error occured.");
}
setIsLoading(false);
};
return (
<div className='container my-5 pt-5'>
<div className='row'>
<div className='col-md-6 col-12 mx-auto'>
<div className='card shadow-sm p-5'>
{
!isInitialized ?
<form id="payment-form" onSubmit={handleSubmit}>
<PaymentElement id="payment-element" className="mb-5" />
<div className="mt-3 d-grid">
<button disabled={isLoading || !stripe || !elements} id="submit" className="btn app-cta">
<span id="button-text">
{isLoading ? "processing please wait..." : "Pay now"}
</span>
</button>
</div>
{/* Show any error or success messages */}
{message && <div id="payment-message" className='my-2 small fw-light text-danger'>{message}</div>}
</form>
:
<AppLoader />
}
</div>
</div>
</div>
</div>
);
}
please help me what i am doing wrong or what i have to add for production build
Jonathan Steele is right if you are using checkoutform.js as a component then make sure you kept it inside components folder which should be outside pages folder. Because if it is inside pages folder then during build nextjs will trying to pre-render it by considering it as a page which will give you this error

[React-testing-library][FireEvent] Screen doesn't update after firing click event

I'm trying to simulate the 'see more' functionality to a blog.
It works as expected on the browser but when I simulate the behavior on react testing library it doesn't.
describe('when 12 blogs', () => {
describe('fetch more blogs', () => {
beforeEach(() => {
const twelveBlogs = generateBlogs(12);
const twoBlogs = generateBlogs(10);
Api.query.mockReturnValueOnce(twelveBlogs);
Api.query.mockReturnValueOnce(twoBlogs);
});
test('should fetch more blog posts when clicking on "See More" button', async () => {
render(
<MemoryRouter>
<Blog />
</MemoryRouter>
);
const seeMoreButton = await screen.findByRole('button', {
name: /See More/i,
});
fireEvent.click(seeMoreButton);
await waitFor(() => expect(Api.query).toHaveBeenCalledTimes(2));
await waitFor(
() =>
expect(screen.getAllByText(/NaN de undefined de NaN/)).toHaveLength(
15
)
);
});
});
});
And the implementation
import React from 'react';
import { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import Api from '../../api/api';
import BlogPreview from '../../components/BlogPreview/BlogPreview';
import './Blog.css';
function Blog() {
const [blogPosts, setBlogPosts] = useState([]);
const pageSize = 12;
const category = ['document.type', 'blog'];
const orderings = '[my.blog.data desc]';
const [apiPage, setApiPage] = useState(1);
const [shouldFetchMoreBlogs, setShouldFetchMoreBlogs] = useState(true);
useEffect(() => {
async function fetchApi(options) {
return Api.query(category, options);
}
const options = { pageSize, page: apiPage, orderings };
fetchApi(options).then((response) => {
if (response?.length > 0) {
if (blogPosts.length !== 0) {
setBlogPosts([...blogPosts, response]);
} else {
setBlogPosts(response);
}
} else {
setShouldFetchMoreBlogs(false);
}
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [apiPage]);
async function handleSeeMoreClick() {
setApiPage(apiPage + 1);
}
function renderBlogPosts() {
if (blogPosts.length > 0) {
return blogPosts.map((blog, index) => (
<Link to={{ pathname: `/blog/${blog.uid}`, ...blog }} key={index}>
<BlogPreview key={index} {...blog} />
</Link>
));
}
}
function renderSeeMoreButton() {
debugger;
if (blogPosts.length > 0) {
if (blogPosts?.length % 12 === 0 && shouldFetchMoreBlogs) {
return (
<div className="see-more-container">
<button className="see-more-button" onClick={handleSeeMoreClick}>
Veja Mais
</button>
</div>
);
}
}
}
return (
<section className="content blog">
<h1>BLOG</h1>
<div className="blog-posts">{renderBlogPosts()}</div>
{renderSeeMoreButton()}
</section>
);
}
export default Blog;
It fails 'cause it only finds the initial 12 blog posts, even though it shows that the api was called twice.
There's obviously some async issue here.
I've tried switching from fireEvent to userEvent, from waitFor to find*, but it still doesn't work.
Thanks

How to create infinite scroll in React and Redux?

import React, {useState, useEffect} from 'react';
import {connect} from 'react-redux';
import {
fetchRecipes
} from '../../store/actions';
import './BeerRecipes.css';
const BeerRecipes = ({recipesData, fetchRecipes}) => {
const [page, setPage] = useState(1);
const [recipes, setRecipes] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchRecipes();
}, [])
return (
<div className='beer_recipes_block'>
<div className='title_wrapper'>
<h2 className='title'>Beer recipes</h2>
</div>
<div className='beer_recipes'>
<ul className='beer_recipes_items'>
{
recipesData && recipesData.recipes && recipesData.recipes.map(recipe =>
<li className='beer_recipes_item' id={recipe.id}>{recipe.name}</li>
)
}
</ul>
</div>
</div>
);
};
const mapStateToProps = state => {
return {
recipesData: state.recipes
}
}
const mapDispatchToProps = dispatch => {
return {
fetchRecipes: () => dispatch(fetchRecipes())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(BeerRecipes);
this is my component where I would like to create infinite scroll and below is my redux-action with axios:
import axios from "axios";
import * as actionTypes from "./actionTypes";
export const fetchRecipesRequest = () => {
return {
type: actionTypes.FETCH_RECIPES_REQUEST
}
}
export const fetchRecipesSuccess = recipes => {
return {
type: actionTypes.FETCH_RECIPES_SUCCESS,
payload: recipes
}
}
export const fetchRecipesFailure = error => {
return {
type: actionTypes.FETCH_RECIPES_FAILURE,
payload: error
}
}
export const fetchRecipes = (page) => {
return (dispatch) => {
dispatch(fetchRecipesRequest)
axios
.get('https://api.punkapi.com/v2/beers?page=1')
.then(response => {
const recipes = response.data;
dispatch(fetchRecipesSuccess(recipes));
})
.catch(error => {
const errorMsg = error.message;
dispatch(fetchRecipesFailure(errorMsg));
})
}
}
I want to create a scroll. I need, firstly, to display first 10 elements and then to add 5 elements with every loading. I have 25 elements altogether and when the list is done it should start from the first five again.
Assuming you already have everything ready to load your next page. You can probably simplify the entire process by using a package like react-in-viewport so you don't have to deal with all the scroll listeners.
then you use it like this way.
import handleViewport from 'react-in-viewport';
const Block = (props: { inViewport: boolean }) => {
const { inViewport, forwardedRef } = props;
const color = inViewport ? '#217ac0' : '#ff9800';
const text = inViewport ? 'In viewport' : 'Not in viewport';
return (
<div className="viewport-block" ref={forwardedRef}>
<h3>{ text }</h3>
<div style={{ width: '400px', height: '300px', background: color }} />
</div>
);
};
const ViewportBlock = handleViewport(Block, /** options: {}, config: {} **/);
const Component = (props) => (
<div>
<div style={{ height: '100vh' }}>
<h2>Scroll down to make component in viewport</h2>
</div>
<ViewportBlock
onEnterViewport={() => console.log('This is the bottom of the content, lets dispatch to load more post ')}
onLeaveViewport={() => console.log('We can choose not to use this.')} />
</div>
))
What happen here is, it creates a 'div' which is outside the viewport, once it comes into the view port ( it means user already scrolled to the bottom ), you can call a function to load more post.
To Note: Remember to add some kind of throttle to your fetch function.

StencilJS emit event to React

I have a nested set of StencilJS components. I would like to attach a function to my nested component so that my React app, which hosts the parent component, can read.
Example
<pw-actionbar
actions={getActions}
/>
In this actionbar component, I have another nested button component. It looks like this
return (
<Host>
<div class="container">
{
// iterate through array
this.actions.map((action) => {
// take object.icon and make an icon
const XmlIcon = `${action.icon}`;
==> I WANT A FUNCTION ON PW-BUTTON THAT PASSES 'action' which my react app reads
return <pw-button-side-menu
// shade the selected pages button
isselected={action.onpage ? 'selected' : 'notselected'}
class="displace"
>
<span slot="label">{action.name}</span>
<i slot="icon">
<XmlIcon
class="icon-position"
fillcolor={this.iconfillcolor}
strokecolor={this.iconstrokecolor}/>
</i>
</pw-button-side-menu>
})
}
</div>
</Host>
);
}
My react app has some component
functionEmittedFromPwButton(action) {
console.log(action) <=== I WANT THIS TO WORK IN MY REACT APP WHICH IS EMITTED FROM THE PW-BUTTON COMPONENT NESTED IN THE PW-ACTIONBAR COMPONENT
}
return (
<MyComponent>
<pw-actionbar actions={getActions}/> <=== that takes an array of objects. I want to capture the 'action' object emitted by the pw-button nested in this component in my react app
</MyComponent>
)
I have tried all sorts of different methods like this one to try to emit the object from stencil to react
On the stenciljs side
import { Component, h, Host, Prop, Event, EventEmitter } from "#stencil/core";
#Component({
tag: "pw-actionbar",
styleUrl: "pw-actionbar.scss",
shadow: true,
})
export class PwActionbar {
#Prop() actions: any = [];
#Prop() iconfillcolor: "white" | "black" = "white";
#Prop() iconstrokecolor: "white" | "black" = "white";
#Event() emitAction: EventEmitter;
render() {
const handleClick = (action) => {
this.emitAction.emit(action);
};
return (
<Host>
<div class="container">
{
// iterate through array
this.actions.map((action) => {
// take object.icon and make an icon
const XmlIcon = `${action.icon}`;
// cast the button
return (
<pw-button-side-menu
// shade the selected pages button
isselected={action.onpage ? "selected" : "notselected"}
class="displace button-lines"
onClick={() => handleClick(action)}
>
<span slot="label">{action.name}</span>
<i slot="icon">
<XmlIcon
class="icon-position"
fillcolor={this.iconfillcolor}
strokecolor={this.iconstrokecolor}
/>
</i>
</pw-button-side-menu>
);
})
}
</div>
</Host>
);
}
}
On the react side
const handleAction = async (action, history, i18n) => {
Metrics.track("Changed Page", { action });
if ("sign-out" === action) {
await authActions.logout();
history.push(`/${i18n.locale}`);
} else if ("help-desk" === action) {
history.push(`/${i18n.locale}/zendesk`);
} else if ("advisors" === action) {
pageActionsObjAdmin[0].onpage = true;
history.push(`/${i18n.locale}/admin/advisors`);
} else if ("users" === action) {
pageActionsObjAdmin[1].onpage = true;
history.push(`/${i18n.locale}/admin/users`);
} else if ("forecast" === action) {
pageActionsObjAdmin[3].onpage = true;
history.push(`/${i18n.locale}/admin/forecast`);
} else if ("stats" === action) {
pageActionsObjAdmin[4].onpage = true;
history.push(`/${i18n.locale}/admin/stats`);
}
};
const Layout = ({ children }) => {
const { i18n } = useLingui();
const [, setContext] = useContext(StripeErrorContext);
const history = useHistory();
useEffect(() => {
const listener = (e) => {
// set page button to be "Active"
pageActionsObjAdmin.forEach((element) => {
element.onpage = false;
});
handleAction(e.detail.page, history, i18n, setContext);
};
// listen for events emitted form the action bar
document.body.addEventListener("emitAction", listener);
return () => {
document.body.removeEventListener("emitAction", listener);
};
}, []); // eslint-disable-line
// refs for the actionbar
const elementRef = useRef(null);
useEffect(() => {
if (elementRef.current !== null) {
elementRef.current.actions = pageActionsObjAdmin;
}
}, [elementRef]);
return (
<Wrapper>
<Header />
<BodyLayout>
<pw-actionbar
ref={(el) => (elementRef.current = el)}
style={{ paddingTop: "56px", zIndex: "99" }}
class="action-bar"
/>
<div className="main-layout" style={{ width: "100%" }}>
{children}
</div>
</BodyLayout>
</Wrapper>
);
};
export default Layout;

Resources