Accessing onAccept() function in react cookie consent from custom button - reactjs

I have a gatsby-react application which uses gatsby-plugin-gdpr-cookies and react-cookie-consent packages to enable and disable cookies and implement cookie consent bar. Here is the part of the component:
import CookieConsent from "react-cookie-consent";
import ReactGA from "react-ga";
import styled from "styled-components";
import { Button, Grid, Link, NoSsr, Typography } from "#material-ui/core";
import { initializeAndTrack } from 'gatsby-plugin-gdpr-cookies';
<CookieConsent
location="none"
cookieName="gatsby-gdpr-google-analytics"
disableStyles = {true}
onAccept={() => {
console.log("cookies accepted");
ReactGA.initialize("UA-XXXXXXXX-XX");
}}
>
<StyledBanner container justify="center" alignItems="center">
<Grid item container direction="column" lg={9} xs={12}>
<StyledText>
This website uses cookies.
</StyledText>
</Grid>
<Grid
container
item
justify="center"
alignItems="center"
lg={3}
xs={12}
wrap={"nowrap"}
>
<Button
variant="outlined"
*onClick={this.onAccept}*
>
I Disagree
</Button>
<Button
variant="outlined"
*onClick={this.onAccept}*
>
I Agree
</Button>
</Grid>
</StyledBanner>
</CookieConsent>
I would really like to trigger the onAccept function in CookieConsent so that my cookies can be enabled. The reason I would like use a custom button is so that the color scheme and theme of my app is constant without having to redesign within the default CookieConsent buttons.
If this is not possible I would also like to explore the customButtonProps prop within CookieConsent option but I having a very difficult time in making that work.
I wanted to know if one of these two options are possible and take a look at small implementation.

Related

Components overlapping in React using #material-ui/core

I am new to React and I am watching a tutorial on youtube. The guy is using some styling from #material-ui/core and his project looks like this https://www.youtube.com/watch?v=ngc9gnGgUdA&t=2209s at min 36:50 while mine looks as the following picture.
This is the code
import {Container, AppBar, Typography, Grow, Grid} from '#material-ui/core'
<Container maxWidth='lg'>
<AppBar positin="static" color='inherit'>
<Typography variant='h2' align='center'>Memories</Typography>
<img src={memories} alt='memories' height={60}/>
</AppBar>
<Grow in>
<Container>
<Grid container justifyContent='space-between' alignItems='stretch' spacing={3}>
<Grid item xs={12} sm={7}>
<Posts />
</Grid>
<Grid item xs={12} sm={4}>
<Form/>
</Grid>
</Grid>
</Container>
</Grow>
</Container>
And another thing is that the <AppBar> and <Grow> components start from the top of the page and overlap with each other. If I remove the <AppBar> the page looks like this.
As you can see there is POSTS, POST and FORM hiding behind the other <AppBar>.
I am using the exact same code and don't understand why there are so many differences. The styling part might be fixable if I play with it, but I don't understand why the overlapping happens and how to fix it.

Responsive and split layout

I started a project with react-splitter-layout and material ui library.
I would like to find a way to create responsive components, with material ui Grid or Box component
I encounter a problem with responsive, I would like my left panel to be responsive (use of xs / md / lg) with Grid component based on the size of the container (not window size), as you can see in the example below , this is not the case. It's use the viewport size. (I know it's normal because of media queries).
Here the code sample : https://codesandbox.io/s/material-demo-i04rr?file=/demo.js (recommended to open the rendering in a new tab to see the problem)
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import Paper from "#material-ui/core/Paper";
import Grid from "#material-ui/core/Grid";
import SplitterLayout from "react-splitter-layout";
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1
},
paper: {
padding: theme.spacing(2),
textAlign: "center",
color: theme.palette.text.secondary
}
}));
export default function CenteredGrid() {
const classes = useStyles();
return (
<SplitterLayout>
<div className={classes.root}>
<Grid container spacing={3}>
<Grid item xs={4} md={6} lg={8}>
<Paper className={classes.paper}>xs=3</Paper>
</Grid>
<Grid item xs={4} md={4} lg={2}>
<Paper className={classes.paper}>xs=3</Paper>
</Grid>
<Grid item xs={4} md={2} lg={2}>
<Paper className={classes.paper}>xs=3</Paper>
</Grid>
</Grid>
</div>
<div>Panel 2</div>
</SplitterLayout>
);
}
Anyone have a solution to this problem ?
Best regards,
EDIT
I also posted in material ui github https://github.com/mui-org/material-ui/issues/25189
This is one of my question when I started using material-UI or any CSS framework.
Material-UI currently supports almost cases you need especially for responsive, and I never use any other library/framework for responsive. First, you know that all xs, sm, md are based on screen size, not on their container.
Then, the problem here is how did you called a "container"? When you work with material-UI, you should layout everything based on screen size instead of a specific container. Because your "container" you are think about doesn't have any meaning in responsive. It just help you solve the layout problem.
To be honest, just change your mind, thinking in the way of Material-UI, and everything about responsive become easily.

Form validation and error messages not working

I'm currently working on several forms for an app and chose to use Material UI and React Hook Forms to build them. The basic functions are working, which means I can only proceed when all required inputs are filled and I'm getting the desired data.
Unfortunately I'm not able to use the form validation or display of error messages that comes with React Hook Form. It is still using the Material UI validation, even though I followed along to the documentation as close as possible.
Here's what I want to be able to do:
define the min and max length of an input
enter RegEx patterns for password inputs
show the neat looking error messages of React Hook Form
Some of the logic is working, some is not. Can you help me figure out why? Thank you in advance!
import React from 'react';
import { useForm, Controller } from 'react-hook-form';
import { Link } from 'react-router-dom';
// COMPONENTS
import Button from '../01-atoms/inputs/Button';
import Textfield from '../01-atoms/inputs/Textfield';
// MATERIAL UI - CORE
import Fade from '#material-ui/core/Fade';
import Grid from '#material-ui/core/Grid';
import InputAdornment from '#material-ui/core/InputAdornment';
import Typography from '#material-ui/core/Typography';
import Paper from '#material-ui/core/Paper';
// MATERIAL UI - ICONS
import LockSharpIcon from '#material-ui/icons/LockSharp';
import PersonAddSharpIcon from '#material-ui/icons/PersonAddSharp';
export default function SignUp({ i18n, submitSignUpData }) {
const { register, handleSubmit, control, errors } = useForm();
return (
<Grid item xs={12} sm={6} md={3}>
<Fade in>
<Paper elevation={3}>
<Typography align='center' gutterBottom variant='h5'>
{i18n.sign_up.page_title}
</Typography>
<form onSubmit={handleSubmit(submitSignUpData)}>
<Grid container spacing={1}>
<Grid item xs={12}>
<Controller
// This is not working:
rules={register({
required: true,
minLength: 8,
})}
// But this is:
required
as={Textfield}
name='newPassword'
control={control}
defaultValue=''
fullWidth
label={i18n.login.password_placeholder}
variant='outlined'
type='password'
InputProps={{
endAdornment: (
<InputAdornment position='end'>
<LockSharpIcon />
</InputAdornment>
),
}}
/>
{errors.newPassword && 'Your input is required!'}
</Grid>
<Grid item xs={12}>
<Button
fullWidth
content={i18n.sign_up.get_started_button}
variant='contained'
color='secondary'
type='submit'
endIcon={<PersonAddSharpIcon />}
/>
</Grid>
</Grid>
</form>
<Link to='/log-in'>
<Typography>{i18n.login.login_button}</Typography>
</Link>
</Paper>
</Fade>
</Grid>
);
}
Instead of using controller why don't you use TextField of Material UI. I have something like this in my code.
<TextField
name="newPassword"
label="Password"
inputRef={register({ required: true, minLength: 8 })}
defaultValue=''
/>
{
errors.newPassword &&
<ErrorText>
{errors.newPassword.type === "required" ?
'Password is required.' :
`Min character limit for Password is 8.`}
</ErrorText>
}

React Material UI Button component with hookrouter

I am trying to migrate a class component React app to functional components with hooks.
When using class components I use to pass a Link component to a Button component since I was using react-router-dom library.
But now I am trying to use Paratron/hookrouter library for routing but I get an error when passing an A component to the Button:
TypeError: props.href is undefined
My code now looks like this:
import React, { Fragment } from 'react';
import { Grid, Button } from '#material-ui/core';
import { A } from 'hookrouter';
import './styles.css';
const Home = props => {
return (
<Fragment>
<Grid container spacing={24} className="landing">
<Grid item xs={6}>
<Button
variant="contained"
color="primary"
size="large"
component={A}
to="/login"
>Login</Button>
</Grid>
<Grid item xs={6}>
<Button
variant="contained"
color="secondary"
size="large"
component={A}
to="/contact"
>Contact us</Button>
</Grid>
</Grid>
</Fragment>
);
}
export default Home;
I guess this A component does not contain an href property. Not sure how to proceed. Any comments will be appreciated.
You need to provide 'href' prop, not 'to' prop.
<Fragment>
<Grid container spacing={24} className="landing">
<Grid item xs={6}>
<Button
variant="contained"
color="primary"
size="large"
component={A}
href="/login" //href
>Login</Button>
</Grid>
<Grid item xs={6}>
<Button
variant="contained"
color="secondary"
size="large"
component={A}
href="/contact" //href
>Contact us</Button>
</Grid>
</Grid>
</Fragment>
I also had to wrap A with class component, since A is probably function component, and they can't hold a ref (which is required by button component prop)
You can refer to this working CodeSandbox demo

Material UI button rendered with span that is not clickable

I am building a site using material-UI and have run into a bit of a snag. It seems that the button is being rendered with a span element around the button's text. This makes it so the click event only fires when you click outside the span element.
As you can imagine it's not the greatest UI to have users click buttons that don't do anything. I am sure that I am not the first one to go through this, is there a way that I can propagate the event down to the child element programmatically? Below is my component snipit:
import withRoot from '../onepirate/modules/withRoot';
// --- Post bootstrap -----
import React from 'react';
import { useState, useStyles } from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Grid from '#material-ui/core/Grid';
import Link from '#material-ui/core/Link';
import Typography from '../onepirate/modules/components/Typography';
import AppFooter from '../onepirate/modules/views/AppFooter';
import AppForm from '../onepirate/modules/views/AppForm';
import Button from '#material-ui/core/Button';
import MuiTextField from '#material-ui/core/TextField';
import List from '#material-ui/core/List';
import ListItem from '#material-ui/core/ListItem';
import ListItemText from '#material-ui/core/ListItemText';
import ListItemAvatar from '#material-ui/core/ListItemAvatar';
import Avatar from '#material-ui/core/Avatar';
import AddCircleIcon from '#material-ui/icons/AddCircle';
import WorkIcon from '#material-ui/icons/Work';
import BeachAccessIcon from '#material-ui/icons/BeachAccess';
import Divider from '#material-ui/core/Divider';
const Tickets = props => {
const useStyles = makeStyles(theme => ({
button: {
margin: theme.spacing(1),
backgroundColor: "#ff3366",
color: "#000000"
},
input: {
display: 'none',
},
ListItemText: {
marginLeft: 105,
}
}));
const classes = useStyles();
return (
<React.Fragment>
<AppForm>
<React.Fragment>
<Typography variant="h3" gutterBottom marked="center" align="center">
Order Tickets
</Typography>
<Typography variant="body2" align="center">
<Link href="/premium-themes/onepirate/sign-in/" underline="always">
Already have an account?
</Link>
</Typography>
</React.Fragment>
<Grid container spacing={2}>
<Grid item xs={12} sm={12}>
<List className={classes.root}>
<ListItem>
<Button
variant="contained"
className={classes.button}
onClick={props.quantity}
id="basic">
Add
</Button>
<ListItemText
primary="Basic"
secondary="$450"
className={classes.ListItemText}/>
{props.init.basic}
</ListItem>
<Divider variant="inset" component="li" />
<ListItem>
<Button
variant="contained"
className={classes.button}
onClick={props.quantity}
id="exec" >
Add
</Button>
<ListItemText
primary="Executive"
secondary="$550"
className={classes.ListItemText}/>
{props.init.exec}
</ListItem>
<Divider variant="inset" component="li" />
<ListItem>
<Button
variant="contained"
className={classes.button}
onClick={props.quantity}
id="vip">
Add
</Button>
<ListItemText
primary="VIP"
secondary="$750"
className={classes.ListItemText}/>
{props.init.vip}
</ListItem>
</List>
<Typography variant="h2">
{`Total: $ ${(props.init.basic * 450) + (props.init.exec * 550) + (props.init.vip * 750)}`}
</Typography>
<Button
className={classes.button}
size="large"
color="secondary"
fullWidth
onClick={props.price}
id=""
>
{'Proceed to Checkout'}
</Button>
</Grid>
</Grid>
</AppForm>
<AppFooter />
</React.Fragment>
);
}
export default withRoot(Tickets);
And the rendered HTML output of one of the buttons:
<button class="MuiButtonBase-root-307 MuiButton-root-290 makeStyles-button-87 MuiButton-contained-298"
tabindex="0"
type="button"
id="exec">
<span class="MuiButton-label-291">Add</span>
<span class="MuiTouchRipple-root-391"></span>
</button>
It seems that Material UI v4 accepts both e.target.value and e.currentTarget.value.
However, if you use e.target.value to deliver buttons' value, and click on the span node (nested inside of button), the value won't be taken from the button node that you assigned it to, but the span HTML element that does not have the value property and so the value is undefined.
To remedy the above, use e.currentTarget.value as it seems to pick up the value property from the button, even if you click on the span node.
Below sandbox should show you the difference in using e.target.value and e.currentTarget.value with material UI buttons.
https://codesandbox.io/s/elated-glitter-wqtt3?file=/src/App.js
Open up the console and click interchangeably on span and button elements and observe logs when you do that.
I have not tested the latest v5 from Material UI, it could be that they changed (improved?) this behaviour.
try wrapping span and button inside a div or other wrapper component and call onClick on that

Resources