REACT JS-How to randomly display the data from firestore? - reactjs

I already have database for my "questions" and its "choices" now i want to display randomly.
import "./startExam.scss"
import HomeSidebar from '../homeSidebar/HomeSidebar'
import HomeNavbar from '../homeNavbar/HomeNavbar'
// import * as React from 'react';
import Radio from '#mui/material/Radio';
import RadioGroup from '#mui/material/RadioGroup';
import FormControlLabel from '#mui/material/FormControlLabel';
import FormControl from '#mui/material/FormControl';
import FormLabel from '#mui/material/FormLabel';
import { useParams , useNavigate } from 'react-router-dom';
import { getDocs, collection , onSnapshot, deleteDoc, doc , updateDoc } from '#firebase/firestore'
import { db } from '../../firebase'
import React, { useEffect, useState,useRef } from 'react'
const StartExam = () => {
const [getDocs,setgetDocs] = useState([])
const [getTitle,setTitle] = useState([])
let {id}=useParams()
const isMounted = useRef()
const collectionRef = collection(db, "Exams",id,"qna")
let navigate = useNavigate();
const getData = () => {
onSnapshot(collectionRef, (data) => {
setgetDocs(data.docs.map((doc) => {
return {...doc.data(), id: doc.id}
}))
})
}
useEffect(() => {
if(isMounted.current){
return
}
isMounted.current = true;
getData()
}, []);
return (
<div className="startExam">
<HomeSidebar/>
<div className="startExamContainer">
<HomeNavbar/>
{getDocs.map((row) => {
<div className="titleContainer" key={row.id}>
return(
<div className="examTitle">{row.title}</div>
)
</div>
})}
{getDocs.map((rows)=>{
return(
<div className="questionContainer">
<FormControl>
<FormLabel id="demo-radio-buttons-group-label">{rows.question}</FormLabel>
<RadioGroup
aria-labelledby="demo-radio-buttons-group-label"
defaultValue="female"
name="radio-buttons-group">
<FormControlLabel value="database" control={<Radio />} label={rows.correctanswer} />
<FormControlLabel value="data" control={<Radio />} label="Java" />
<FormControlLabel value="databytes" control={<Radio />} label="C##" />
<FormControlLabel value="databoard" control={<Radio />} label="Html" />
</RadioGroup>
</FormControl>
</div>
)
})}
<div className="questionContainer">
<FormControl>
<FormLabel id="demo-radio-buttons-group-label">2. Which programming language is not included?</FormLabel>
</FormControl>
</div>
</div>
</div>
)
}
export default StartExam
here is the database structure and this is where all the question and choices MUST randomly display
<RadioGroup
aria-labelledby="demo-radio-buttons-group-label"
defaultValue="female"
name="radio-buttons-group">
<FormControlLabel value="database" control={<Radio />} label={rows.correctanswer} />
<FormControlLabel value="data" control={<Radio />} label="Java" />
<FormControlLabel value="databytes" control={<Radio />} label="C##" />
<FormControlLabel value="databoard" control={<Radio />} label="Html" />
</RadioGroup>
as you can see in this line i just manually add the "correctanswer" which is not correct because when i add more questions, the correctanswer must be in one place. I also want the questions to be randomly displayed. i hope you can help me.

Related

Check radio on button click or click on radio

Using mui to create a radio button within a button and it should be possible to click on either the radio button or the button, when clicking on either of them the radio has to be checked. Only one option can be chosen, either female or male.
I know I could use multiple use states for clicked, but isn't there some better way to do it?
import FormControl from '#mui/material/FormControl';
import FormLabel from '#mui/material/FormLabel';
import RadioGroup from '#mui/material/RadioGroup';
import FormControlLabel from '#mui/material/FormControlLabel';
import Button from '#mui/material/Button';
import Radio from '#mui/material/Radio';
export const radioButtonGroup = () => {
const [value, setValue] = React.useState('female');
const [clicked, setClicked] = useState(false);
return (
<FormControl>
<FormLabel>Gender</FormLabel>
<RadioGroup value={value}>
<Button
onClick={() => setClicked(true)}
variant="outlined">
<FormControlLabel
value="female"
control={<Radio checked={clicked} />}
label="Female" />
</Button>
<Button
onClick={() => setClicked(true)}
variant="outlined">
<FormControlLabel
value="male"
control={<Radio checked={clicked} />}
label="Male" />
</Button>
</RadioGroup>
</FormControl>
);
};
Looks like this:
export const radioButtonGroup = () => {
const [gender, setGender] = useState('');
return (
<FormControl>
<FormLabel>Gender</FormLabel>
<RadioGroup>
<Button
onClick={() => setGender('female')}
variant="outlined">
<FormControlLabel
control={<Radio checked={gender === 'female'} />}
label="Female" />
</Button>
<Button
onClick={() => setGender('male')}
variant="outlined">
<FormControlLabel
control={<Radio checked={gender === 'male'} />}
label="Male" />
</Button>
</RadioGroup>
</FormControl>
);
};

How can I use React Testing Library to simulate clicking on Material UI RadioGroup option?

How can I write a react testing library test script to validate clicking on a Material UI radio button? The below is a recreation of the issue I am having.
import React from 'react';
import Radio from '#material-ui/core/Radio';
import RadioGroup from '#material-ui/core/RadioGroup';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import FormControl from '#material-ui/core/FormControl';
import FormLabel from '#material-ui/core/FormLabel';
export default function RadioButtonsGroup() {
const [value, setValue] = React.useState('female');
const handleChange = (event) => {
setValue(event.target.value);
};
return (
<FormControl component="fieldset">
<FormLabel component="legend">Gender</FormLabel>
<RadioGroup aria-label="gender" name="gender1" value={value} onChange={handleChange}>
<FormControlLabel value="female" control={<Radio />} label="Female" />
<FormControlLabel value="male" control={<Radio />} label="Male" />
<FormControlLabel value="other" control={<Radio />} label="Other" />
<FormControlLabel value="disabled" disabled control={<Radio />} label="(Disabled option)" />
</RadioGroup>
</FormControl>
);
}
and the test
import { render, screen, fireEvent } from "#testing-library/react";
import RadioButtonsGroup from "./demo";
test("can click Male radio option", () => {
render(<RadioButtonsGroup />);
const maleLabel = screen.getByLabelText(/Male/);
fireEvent.click(maleLabel);
expect(maleLabel).toBeChecked();
});
Hey – get by role should help you here. Try:
const button = screen.getByRole("radio", { name: "Male" });
This should give you access to the radio button with the lable as Male.
Then you can do
const leftClick = { button: 0 };
userEvent.click(button, leftClick);
expect(button.checked).toBe(true);
One thing I've found though is that the .checked property doesn't play nice with Typescript so if you're writing typescript, you may get warnings about .checked being non-existent

react - tick logic for material-ui radio button

I have a minimalist function whereby I'm providing two choices in the form of radio inputs: "bull" or "bear".
Full code below:
import React, { useState } from 'react';
import RadioButton from 'material-ui/RadioButton';
const styles = {
rootRadio: {
//left:"37%",
//position:'absolute'
}
}
function RadioComp() {
const [riskP, setRiskP] = useState("bull")
const handleRisk = (e) => {
setRiskP(e.target.value)
}
return (
<React.Fragment>
<h2>Risk profile</h2>
<div>
<span>Bull</span>
<RadioButton
style={styles.rootRadio}
value='bull'
checked={riskP==='bull'}
onChange={handleRisk}
/>
</div>
<div>
<span>Bear</span>
<RadioButton
style={styles.rootRadio}
value='bear'
checked={riskP==='bear'}
onChange={handleRisk}
/>
</div>
</React.Fragment>
)
}
export default RadioComp;
As seen above, I have tried to configure this logic using useState():
const [riskP, setRiskP] = useState("bull")
const handleRisk = (e) => {
setRiskP(e.target.value)
}
However, in the view, clicking on "bear" doesn't do anything. It seems to be locked on "bull."
Question
You have to use RadioGroup with FormControl option.
import React from 'react';
import Radio from '#material-ui/core/Radio';
import RadioGroup from '#material-ui/core/RadioGroup';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import FormControl from '#material-ui/core/FormControl';
import FormLabel from '#material-ui/core/FormLabel';
export default function RadioButtonsGroup() {
const [value, setValue] = React.useState('female');
const handleChange = (event) => {
setValue(event.target.value);
};
return (
<FormControl component="fieldset">
<FormLabel component="legend">Gender</FormLabel>
<RadioGroup name="gender1" value={value} onChange={handleChange}>
<FormControlLabel value="female" control={<Radio />} label="Female" />
<FormControlLabel value="male" control={<Radio />} label="Male" />
<FormControlLabel value="other" control={<Radio />} label="Other" />
</RadioGroup>
</FormControl>
);
}

How to use custom radio component with react-final-form?

I am trying to use a custom Radio component with React-final-form but it is not acting as a radio button but as a checkbox, ie, all the buttons are open for selection.
The 3rd party Radio button has the following schema:
checked boolean
Whether or not radio is checked
onChange () => void
Called when the user attempts to change the checked state
name string
The input name, used to reference the element in JavaScript
I created a custom Component for using the Radio Component:
const CustomRadio = (props: any) => (
<Radio
{...props.input}
{...props.rest}
name={props.name}
onChange={() => props.input.onChange()}
/>
)
and I am using it as follows:
<Field name="food"
component={CustomRadio}
value="1"
/>
<Field name="food"
component={CustomRadio}
value="2"
/>
Being very new to RFF and new to React, I may be doing something very wrong, hence any help will be appreciated.
Basically, I want to use RFF with my 3rd party components. Though I have been successful to use my Input component with RFF as expected, Radio Button is the one creating problems.
Here is the correct implementation for Radio with react-final-form:-
https://codesandbox.io/s/vibrant-easley-5n1ek?file=/index.js
/* eslint-disable jsx-a11y/accessible-emoji */
import React from "react";
import { render } from "react-dom";
import Styles from "./Styles";
import { Form, Field } from "react-final-form";
import RadioGroup from "#material-ui/core/RadioGroup";
import FormControlLabel from "#material-ui/core/FormControlLabel";
import FormControl from "#material-ui/core/FormControl";
import Radio from "#material-ui/core/Radio";
import FormLabel from "#material-ui/core/FormLabel";
const RadioWrapper = (props) => {
const {
input: { checked, value, name, onChange, ...restInput },
} = props;
return (
<Radio
name={name}
inputProps={restInput}
onChange={onChange}
checked={checked}
value={value}
/>
);
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const onSubmit = async (values) => {
await sleep(300);
window.alert(JSON.stringify(values, 0, 2));
};
const App = () => {
return (
<Styles>
<h1>React Final Form - Simple Example</h1>
<a
href="https://final-form.org/react"
target="_blank"
rel="noopener noreferrer"
>
Read Docs
</a>
<Form
onSubmit={onSubmit}
initialValues={{
employed: false,
all_sub_tenants: "true"
}}
render={({ handleSubmit, form, submitting, pristine, values }) => (
<form onSubmit={handleSubmit}>
<FormControl component="fieldset">
<FormLabel component="legend">
Select Tenants
</FormLabel>
<RadioGroup aria-label="allSubTenants" name="allSubTenants">
<FormControlLabel
value="true"
control={
<Field
name="all_sub_tenants"
component={RadioWrapper}
type="radio"
value={"true"}
/>
}
label="All Sub-Tenants"
/>
<FormControlLabel
value="false"
control={
<Field
name="all_sub_tenants"
component={RadioWrapper}
type="radio"
value={"false"}
/>
}
label="Select Sub-Tenants"
/>
</RadioGroup>
</FormControl>
<div>
<label>Notes</label>
<Field name="notes" component="textarea" placeholder="Notes" />
</div>
<div className="buttons">
<button type="submit" disabled={submitting || pristine}>
Submit
</button>
<button
type="button"
onClick={form.reset}
disabled={submitting || pristine}
>
Reset
</button>
</div>
<pre>{JSON.stringify(values, 0, 2)}</pre>
</form>
)}
/>
</Styles>
);
};
render(<App />, document.getElementById("root"));

Uncheck Radio buttons with Material UI

I wish to be able to uncheck radio buttons, Idea is like this: if I click on some radio button, it is going to be checked, if I click on another field, this another field is going to be checked instead BUT if I click on field which is already checked, I wish to uncheck it so all fields are empty. I tried to catch the moment of being checked or unchecked but seems like opposite to checkboxes, Radio buttons don't have this field. does anyone has idea how to achieve that?
setTests = (key, e) => {
console.log(e.checked)
if (e.checked) {
// this.setState({[key]: null})
console.log('works')
}
}
RadioGroup
value={this.state.test_mode}
style={{ display: "block" }}
onChange={e => this.setTests({ "test_mode", e.target })}
>
<FormControlLabel value="before" control={<Radio color="primary"/>} label="before tests" />
<FormControlLabel value="progressing" control={<Radio color="primary"/>} label="progressing" />
<FormControlLabel value="done" control={<Radio color="primary"/>} label="done" />
</RadioGroup>
Below is an example of how to do this. Instead of using the onChange of the RadioGroup, you use the onClick event of the Radio. If the new value matches the current value in state, then set the value to empty string.
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import Radio from "#material-ui/core/Radio";
import RadioGroup from "#material-ui/core/RadioGroup";
import FormControlLabel from "#material-ui/core/FormControlLabel";
import FormControl from "#material-ui/core/FormControl";
import FormLabel from "#material-ui/core/FormLabel";
const useStyles = makeStyles(theme => ({
root: {
display: "flex"
},
formControl: {
margin: theme.spacing(3)
},
group: {
margin: theme.spacing(1, 0)
}
}));
export default function RadioButtonsGroup() {
const classes = useStyles();
const [value, setValue] = React.useState("female");
function handleClick(event) {
if (event.target.value === value) {
setValue("");
} else {
setValue(event.target.value);
}
}
return (
<div className={classes.root}>
<FormControl component="fieldset" className={classes.formControl}>
<FormLabel component="legend">Gender</FormLabel>
<RadioGroup
aria-label="gender"
name="gender1"
className={classes.group}
value={value}
>
<FormControlLabel
value="female"
control={<Radio onClick={handleClick} />}
label="Female"
/>
<FormControlLabel
value="male"
control={<Radio onClick={handleClick} />}
label="Male"
/>
<FormControlLabel
value="other"
control={<Radio onClick={handleClick} />}
label="Other"
/>
</RadioGroup>
</FormControl>
</div>
);
}

Resources