We are attempting to use an embedded Persona flow on our NextJS app.
Code as follows:
export default function PersonaTest(props) {
const PersonaInquiry = dynamic(() => import('persona').then((mod) => mod.Inquiry), { ssr: false });
const RenderFrame = () => (
<PersonaInquiry
templateId="itmpl_Ygs16MKTkA6obnF8C3Rb17dm"
environment="sandbox
frameHeight="900"
frameWidth="500"
parent="root"
onLoad={() => {
console.log('Loaded inline');
}}
onComplete={({ inquiryId, status, fields }) => {
// Inquiry completed. Optionally tell your server about it.
console.log(`Sending finished inquiry ${inquiryId} to backend`);
}}
/>
);
return (
<>
<Grid container spacing={2} style={{ paddingTop: 400 }}>
<Grid item xs={12} sm={6}>
<div id="root" />
<RenderFrame />
</Grid>
</Grid>
</>
);
}
The Persona component renders and imbedded iframe to allow an idv flow.
The Persona widget is rendered but in a very small frame.
It seems the params frameHeight, frameWidth and parent are being ignored.
Why dynamic rendering is needed to allow the component to render the iframe (if not, it will throw 'self' type errors).
Persona support is unable to diagnose/help.
What am I doing wrong?
Thanks!
I have tried numerous options to set the frame height and width.
I had a similar issue and found this when I was troubleshooting - frameHeight and frameWidth only set the max height and width. Persona's docs recommend targeting the general iframe tag from a parent container and that ended up working for me. I wrapped my PersonaInquiry tag in a styled component and targeted child iframe tags from there. Hope that helps!
Related
I've seen a few questions similar to this on SO but none that quite matched my needs. I'm using React and Material-UI to make a dashboard. I'm using Material-UI's mini variant drawer as a sidebar, with links that should display routes when clicked. The sidebar can be opened by clicking a button, which updates a state variable and adjusts the CSS className of the sidebar. This causes the sidebar/drawer to "slide" open.
If I click a link on the sidebar, I can easily display a desired route. However, I can't get the route to also "slide" to the side when the sidebar/drawer opens. It will probably be easier to understand by looking at the code, so I've included a link to a codesandbox below:
https://codesandbox.io/s/appbar-with-react-router-bkogj?file=/src/App.js
I basically copy and pasted everything from the Material-UI website (using v4 I believe), then added the route myself. Would appreciate any feedback on how to solve this issue.
For this I think the MiniDrawer component needs to render the content since it necessarily is aware of the space the appbar and drawer components occupy.
MiniDrawer
Take and render a children prop.
export default function MiniDrawer({ children }) {
...
return (
<div className={classes.root}>
<CssBaseline />
<AppBar
...
>
...
</AppBar>
<Drawer
...
>
...
</Drawer>
<main className={classes.content}>{children}</main>
</div>
);
}
App
Render the Outlet as a child component.
export default function App() {
return (
<div className="App">
<AppBar>
<Outlet />
</AppBar>
</div>
);
}
RejectTable
Remove the excess margin so it fills the content area the parent component allows.
const useStyles = makeStyles((theme) => ({
content: {
flexGrow: 1,
padding: theme.spacing(3),
height: "100%",
// marginLeft: "4em" // <-- remove
}
}));
I am trying to add a tooltip to each star of the rating component on Material UI [v4] but I am not being able to.
Is there a way to achieve this without having to use another rating library?
These are the links for the components I am trying to implement:
https://material-ui.com/es/api/rating/
https://material-ui.com/es/api/tooltip/
Thanks in advance!
Provide a custom IconContainerComponent and create your own Tooltip inside.
<Rating
IconContainerComponent = {
function IconContainer(props) {
// trigger your custom tooltip here
const { value, ...other } = props;
return <span {...other} />;
}
}
/>
I tried using the solution of #hamidreza which was similar to the one posted here but it did not work for me.
I know I'm a bit late to this but here is my solution:
Enclosing the <Rating> component with <Box> or a div (due to multiple child errors from Tooltip) then placing it as a child of the <Tooltip> component.
const [value, setVal] = React.useState(2);
const [tipValue, setTipValue] = React.useState(2);
<Tooltip title={tipValue === -1 ? value : tipValue}>
<Box display="inline-block">
<Rating
value={value}
onChange={(event, newValue) => {
setVal(newValue);
}}
onChangeActive={(event, newHover) => {
setTipValue(newHover);
}}
/>
</Box>
</Tooltip>
Working Demo:
https://codesandbox.io/s/blue-haze-jlvbb8?file=/demo.tsx
Splitting the tipValue and the value for me was necessary. This is to change the Tooltip message on hovering on the Rating component.
I'm unable to make following code render grid items when props.data changes from the top component.
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Grid from '#material-ui/core/Grid';
import ProductCard from './ProductCard';
const useStyles = makeStyles((theme) => ({
grid: {
padding: "8px",
},
}));
export default function CenteredGrid(props) {
const classes = useStyles();
const visibleProductData = props.data === null ? {} : props.data;
return (
<Grid container >
{console.log("This is from the product card grid")}
{console.log(visibleProductData)}
{Object.entries(visibleProductData).map(productData => (
<Grid key={productData[0]} className={classes.grid} item md={3} sm={6} xs={12}>
<ProductCard data={productData[1]}/>
</Grid>
))}
</Grid>
);
}
When I run this, after the data updates, the console logs visibleProductData which is a dictionary consisting of three products, as expected. However these products are not visible, in fact when I inspect I see no children for Grid container. What is weird is that, even after small changes in code, when a fast refresh occurs products become visible. What might be the issue here ?
PS: I'm using nextjs along with material ui.
Edit / Update - Parent Component
const classes = useStyles();
const { buyer, categoryData, filterData, visibleProductData } = useContext(BuyerContext);
if (!buyer) {
return (
<AuthRequired/>
)} else {
return (
<>
<HeaderBar/>
<Grid className={classes.breadcrumb} container>
<Breadcrumb />
</Grid>
<Divider variant="middle" />
<main className={classes.main}>
<Grid container>
<Grid item xs={2}>
<Box display={{ xs: 'none', sm: 'block' }}>
<CategoryList data={categoryData}/>
</Box>
</Grid>
<Grid item sm={10} xs={12}>
<FilterGrid data={filterData}/>
<ProductCardGrid data={visibleProductData}/>
</Grid>
</Grid>
</main>
<Footer/>
</>
)
}
}
Try the following line,
const visibleProductData = props.data === null ? {} : {...props.data};
It might be because your visibleProductData variable is always getting the same reference object. You need to create a new reference object each time props.data changes. If the issue still persists, then we need to see your parent component. The issue might be there.
Writing const visibleProductData = props.data === null ? {} : props.data; in React functional component body is not the correct "React way". You should:
define a local state variable called, for example, visibleProductData:
const [visibleProductData, setVisibleProductData] = useState({});
use useEffect hook to "listen" new values comes from parent object. Something like:
useEffect(() => {
setVisibleProductData(props.data === null ? {} : {...props.data});
}, [props.data]);
In this way, every time props.data changes, useEffect will be fired and it will update local visibleProductData.
I could at last solve the problem, it was a small typo that gives no error and therefore hard to debug. Instead of putting another "(" within map like so, {array.map(element => (...))} I should have done without it like this {array.map(element => ...)}.
I am trying to create a Stateful class in which you can call methods such as createHeaderButton() where after calling it would update the state and re-render with these new updates in the component.
Im using Material-UI and so most of their styling utilizes Reacts hook API which of course classes cant use. Ive tried to get around this by using;
export default withStyles(useStyles)(HeaderBar)
Which exports the class separately with the Styles(withStyles(useStyles) useStyles as the defined styles) And the class(HeaderBar). Now the only issue is that i need to access the styles in my class. Ive found a JS example online that wont work for me because of the strong typed syntax of TS. Additionally When initializing my Class component in other places i try to get the ref=(ref:any)=>{} And with that call the create button methods when i get a response from my server, Which doesnt work because of this new way of exporting the class component!
Thanks for the help, Heres my component class: https://pastebin.pl/view/944070c7
And where i try to call it: https://pastebin.com/PVxhKFHJ
My personal opinion is that you should convert HeaderBar to a function component. The reason that it needs to be a class right now is so you can use a ref to call a class method to modify the buttons. But this is not a good design to begin with. Refs should be avoided in cases where you can use props instead. In this case, you can pass down the buttons as a prop. I think the cleanest way to pass them down is by using the special children prop.
Let's create a BarButton component to externalize the rendering of each button. This is basically your this.state.barButtons.forEach callback, but we are moving it outside of the HeaderBar component to keep our code flexible since the button doesn't depend on the HeaderBar (the header bar depends on the buttons).
What is a bar button and what does it need? It needs to have a label text and a callback function which we will call on click. I also allowed it to pass through any valid props of the material-ui Button component. Note that we could have used children instead of label and that's just down to personal preference.
You defined your ButtonState as a callback which takes the HTMLButtonElement as a prop, but none of the buttons shown here use this prop at all. But I did leave this be to keep your options open so that you have the possibility of using the button in the callback if you need it. Using e.currentTarget instead of e.target gets the right type for the element.
import Button, {ButtonProps as MaterialButtonProps} from "#material-ui/core/Button";
type ButtonState = (button: HTMLButtonElement) => void;
type BarButtonProps = {
label: string;
callback: ButtonState;
} & Omit<MaterialButtonProps, 'onClick'>
const BarButton = ({ label, callback, ...props }: BarButtonProps) => {
return (
<Button
color="inherit" // place first so it can be overwritten by props
onClick={(e) => callback(e.currentTarget)}
{...props}
>
{label}
</Button>
);
};
Our HeaderBar becomes a lot simpler. We need to render the home page button, and the rest of the buttons will come from props.childen. If we define the type of HeaderBar as FunctionComponent that includes children in the props (through a PropsWithChildren<T> type which you can also use directly).
Since it's now a function component, we can get the CSS classes from a material-ui hook.
const useStyles = makeStyles({
root: {
flexGrow: 1
},
menuButton: {
marginRight: 0
},
title: {
flexGrow: 1
}
});
const HeaderBar: FunctionComponent = ({ children }) => {
const classes = useStyles();
return (
<div className={classes.root}>
<AppBar position="static">
<Toolbar>
<HeaderMenu classes={classes} />
<Typography variant="h6" className={classes.title}>
<BarButton
callback={() => renderModule(<HomePage />)}
style={{ color: "white" }}
label="Sundt Memes"
/>
</Typography>
{children}
</Toolbar>
</AppBar>
</div>
);
};
Nothing up to this point has used state at all, BarButton and HeaderBar are purely for rendering. But we do need to determine whether to display "Log In" or "Log Out" based on the current login state.
I had said in my comment that the buttons would need to be stateful in the Layout component, but in fact we can just use state to store an isLoggedIn boolean flag which we get from the response of AuthVerifier (this could be made into its own hook). We decide which buttons to show based on this isLoggedIn state.
I don't know what this handle prop is all about, so I haven't optimized this at all. If this is tied to renderModule, we could use a state in Layout to store the contents, and pass down a setContents method to be called by the buttons instead of renderModule.
interface LayoutProp {
handle: ReactElement<any, any>;
}
export default function Layout(props: LayoutProp) {
// use a state to respond to an asynchronous response from AuthVerifier
// could start with a third state of null or undefined when we haven't gotten a response yet
const [isLoggedIn, setIsLoggedIn] = useState(false);
// You might want to put this inside a useEffect but I'm not sure when this
// needs to be re-run. On every re-render or just once?
AuthVerifier.verifySession((res) => setIsLoggedIn(res._isAuthenticated));
return (
<div>
<HeaderBar>
{isLoggedIn ? (
<BarButton
label="Log Out"
callback={() => new CookieManager("session").setCookie("")}
/>
) : (
<>
<BarButton
label="Log In"
callback={() => renderModule(<LogInPage />)}
/>
<BarButton
label="Sign Up"
callback={() => renderModule(<SignUpPage />)}
/>
</>
)}
</HeaderBar>
{props.handle}
</div>
);
}
I believe that this rewrite will allow you to use the material-ui styles that you want as well as improving code style, but I haven't actually been able to test it since it relies on so many other pieces of your app. So let me know if you have issues.
I'm creating a Landing page for a project and want to reduce my code by making a helper function to display my four different paper components. Everything seems to be working correctly except for displaying my Icon components that are within the papers.
When I console log Icon it is the correct text, yet the component doesn't appear on the page and I receive these two warnings for each component tag:
"Warning: The tag <CardTravelIcon> is unrecognized in this browser. If you
meant to render a React component, start its name with an uppercase letter."
and
"Warning: <CardTravelIcon /> is using uppercase HTML. Always use lowercase
HTML tags in React."
If I just hard code in CardTravelIcon or any of the other 3 component names in that exact format instead of using Icon from my map function, everything works as expected. Below is the code for my helper function:
class Landing extends Component {
renderPapers() {
const classes = this.props.classes;
return _.map(infoPapers, ({ description, Icon }) => {
return (
<Grid item xs={6} sm={3} key={Icon}>
<Paper className={classes.paper}>
<Icon className={classes.paperIcons} />
{description}
</Paper>
</Grid>
);
});
}
I'm at a loss and would appreciate any help. Thank you.
So you want to pass a component as a variable, right?
Let's say you have this minimal CardTravelIcon component:
const CardTravelIcon = ( props ) => (
<div className={ props.className }>Card Travel Icon</div>
);
And infoPapers data like this (Icon is a reference to the component):
const infoPapers = [
{
description: "Paper 1 description",
Icon : CardTravelIcon
}];
You didn't show us the infoPapers data, but I suspect you're trying to pass a string as the component, e.g. { Icon : "<CardTravelIcon />" } and expect it to work like setting innerHTML (rendering HTML from a string). This is not the case in React, the JSX code needs to be transpiled into calls to React.CreateElement first, and it isn't done by parsing strings.
If you pass references to components everything should be rendered just fine with the following render method (note: removed lodash in favor of native map method, for clarity):
class Landing extends React.Component {
render() {
return infoPapers.map(({ description, Icon }, idx) => {
return (
<div key={ idx }>
<Icon />
{description}
</div>
);
});
}
};
Here's a working example: https://jsfiddle.net/svygw338/