How to rerender fields selected by a dropdown? - reactjs

im create a form using react-hook-from, and one of the fields that ive created is dynamic dropdown.
whenever im choosing one of the options im rendering some other text fields, depends on the the dropdown selection.
the problem is that when im submitting, im getting the fields of the other dropdown selection,
here is my code:
<FormGroup>
<Label>Automation Team</Label>
<Controller
name="team"
control={control}
as={Select}
options={ teams.map((team, index) => (
{ value: team.name, label: team.name}
)) }
defaultValue="Select component"
rules={{required: "Role is required" }}
isClearable
/>
</FormGroup>
<Row form>
{
getFields(teamComponent).map((field,index) => (
<Col key={index} md={4}>
<Label for={field}>{field}</Label>
<Input name={field} placeholder="with a placeholder" innerRef={register({required: true})}/>
{errors?.field?.types?.required &&
<small className="text-danger">Database name required</small>}
</Col>
) )
}
</Row>

so the problem was that I didnt used useEffect and didnt unregister from
last fields that was rendered.
Not the cleanest code bit it works for me :) .
so I refactored my code to look like this:
function TicketForm () {
const { register, unregister, handleSubmit, reset, formState: {isSubmitSuccessful, errors}, control, watch } = useForm({
mode: "onBlur",
criteriaMode: "all"
});
const teamComponent = watch("team")
const {isAuthenticated} = useAuthentication();
const [teams, setTeams] = useState([])
const [fields, setFields] = useState(0);
useEffect( () => {
if (isAuthenticated === true) {
getConfigurations(async response => {
setTeams(response.data.teams.Teams)
})
}
if (teamComponent )
onTeamChange(teamComponent)
}, [teamComponent])
const handleRegistration = async data => {
console.log(data)
}
const onTeamChange = c => {
if (!c) {
setFields([])
return
}
if (fields) {
fields.map((field,index) => {
unregister(field)
})
}
const result = teams.filter((team, index) => {
if(team.name === c.value) {
return team
}
})
if (result) {
setFields(result[0].Fields)
console.log(fields)
}
}
return (
<Form onSubmit={handleSubmit(handleRegistration)}>
<FormGroup>
<Label>Summary</Label>
<Input name="summary" innerRef={register({required: true})} />
{errors?.summary?.types?.required && <small className="text-danger">summary required</small>}
</FormGroup>
<FormGroup>
<Label>Description</Label>
<Input
type="textarea"
name="description"
innerRef={register({required: true})}
/>
{errors?.description?.types?.required && <small className="text-danger">description required</small>}
</FormGroup>
<FormGroup>
<Label for='team'>Automation Team</Label>
<Controller
control={control}
name="team"
innerRef={register({required: true})}
as={Select}
options={ teams.map((team, index) => (
{ value: team.name, label: team.name}
)) }
defaultValue=""
isClearable
/>
</FormGroup>
<Row form>
{
fields && fields.map((field,index) => {
//const fieldName = `field[${index}]`;
return (
<fieldset name={field} key={index}>
<Label for={field}>{field}</Label>
<Input name={field} placeholder="" innerRef={register({required: true})}/>
</fieldset>
)
}/*(
<Col key={index} md={4}>
<Label for={field}>{field}</Label>
<Input name={field} placeholder="with a placeholder" innerRef={register({required: true})}/>
{errors?.field?.types?.required &&
<small className="text-danger">Database name required</small>}
</Col>
)*/ )
}
</Row>
<Button type='submit' color="primary">Submit</Button>
</Form>
);}export default TicketForm;

Related

React Formik Field strange behavior with autofocus

I have a simple Formik Form and one from my field is custom field named MySpecialField which i try to implement but there is issue with autofocus behavior. I can only type by one character in my MySpecialField and then autofocus is gone.
I'm new with Formik and can not understand why it happens and how it could be solved?
const formik = useFormik<UserGroupInterface>({
initialValues: {
firstName: "",
groupName: "",
},
validate: (data: UserGroupInterface) => {
let errors: Record<string, string> = {};
if (!data.groupName) {
errors.groupName = "* required";
}
if (!data.firstName) {
errors.firstName = "* required";
}
return errors;
},
onSubmit: (data): void => {
console.log("submit", data);
},
});
const formikTouched: any = formik.touched;
const formikErrors: any = formik.errors;
const isFormFieldValid = (name: any) =>
!!(formikTouched[name] && formikErrors[name]);
const getFormErrorMessage = (name: any) => {
return (
isFormFieldValid(name) && (
<small className="p-error">{formikErrors[name]}</small>
)
);
};
//#ts-ignore
const MySpecialField = ({ field, props }) => {
return <InputText {...field} {...props} />;
};
<FormikProvider value={formik}>
<form
onSubmit={formik.handleSubmit}
className="p-fluid grid formgrid my-5"
>
<div className="field col-12 md:col-4">
<span className="p-float-label">
<Field
name="firstName"
id="firstName"
component={MySpecialField}
className={classNames({
"p-invalid": isFormFieldValid("firstName"),
})}
autoFocus // This is do not work as expected, only by one character
value={formik.values.firstName}
onChange={formik.handleChange}
/>
<label
htmlFor="firstName"
className={classNames({
"p-error": isFormFieldValid("firstName"),
})}
>
Group 1
</label>
</span>
{getFormErrorMessage("firstName")}
</div>
<div>
<span className="p-float-label">
<InputText
id="groupName"
name="groupName"
value={formik.values.groupName}
onChange={formik.handleChange}
autoFocus
className={classNames({
"p-invalid": isFormFieldValid("groupName"),
})}
/>
<label
htmlFor="name"
className={classNames({
"p-error": isFormFieldValid("groupName"),
})}
>
Group 2
</label>
</span>
{getFormErrorMessage("groupName")}
</div>

React onSubmit are not triggered with some Form.Check checkboxes

I have written modal window with dynamic fields. Text input, date and radio boxes works fine, but when I`m trying to use checkbox inputs it falls.
handleSubmit does not work and not goes into method body
AnswerQuestion:
function AnswerQuestion(props) {
const {questionStore} = useContext(Context);
const dispatch = useNotification();
const question = questionStore.getActiveAnswer();
const show = props.show;
const handleClose = props.handleClose;
const handleUpdate = props.handleUpdate;
const [checkedState, setCheckedState] = useState(question.id && question.answerEntity.answerType === "CHECKBOX"
? Array(question.answerEntity.options.length).fill(false)
: []
)
useEffect(() => {
if(question.id && question.answerEntity.answerType === "CHECKBOX") {
const newCheckedState = question.answerEntity.options.map((option) => question.answerEntity.answer.includes(option));
setCheckedState(newCheckedState);
}
}, [])
const setInitialValues = () => {
if (question.id) {
return {
author: question.author.username,
question: question.question,
answerType: question.answerEntity.answerType,
options: question.answerEntity.options,
date: question.answerEntity.answerType === "DATE" && question.answerEntity.answer ? new Date(question.answerEntity.answer) : new Date(),
answer: question.answerEntity.answer ? question.answerEntity.answer : "",
};
} else {
return {
author: "",
question: "",
answerType: "",
options: "",
date: new Date(),
answer: "",
};
}
};
const schema = yup.object().shape({
author: yup.string().required(),
question: yup.string().required(),
answer: yup.string(),
answerCheckBox: yup.array(),
date: yup.date(),
});
const submit = (values) => {
questionStore
.answerActiveQuestion(question.answerEntity.answerType, values.answer, values.date)
.then(() => handleUpdate());
handleClose();
dispatch({
type: "SUCCESS",
message: "Your answer was saved.",
title: "Success"
})
}
return (
<Formik
enableReinitialize
render={(props) => {
return (
<AnswerQuestionForm
{...props}
show={show}
handleClose={handleClose}
checkedState={checkedState}
></AnswerQuestionForm>
);
}}
initialValues={setInitialValues()}
validationSchema={schema}
onSubmit={submit}
>
</Formik>
)
}
And AnswerQuestionForm:
function AnswerQuestionForm(props) {
const {
values,
errors,
touched,
handleSubmit,
handleChange,
handleClose,
setFieldValue,
setFieldTouched,
show,
checkedState,
} = props;
function insertAnswerModule() {
switch (values.answerType) {
case "DATE":
return (
<Col sm={9}>
<DatePicker
name="date"
value={Date.parse(values.date)}
selected={values.date}
className="form-control"
onChange={(e) => {
setFieldValue('date', e);
setFieldTouched('date');
}}
/>
</Col>
)
case "SINGLE_LINE_TEXT":
return (
<Col sm={9}>
<Form.Control
type="text"
name="answer"
value={values.answer}
onChange={handleChange}
isValid={touched.question && !errors.question}
isInvalid={!!errors.question}
/>
<Form.Control.Feedback type="invalid">
{errors.question}
</Form.Control.Feedback>
</Col>
)
case "MULTILINE_TEXT":
return (
<Col sm={9}>
<Form.Control as="textarea" rows={3}
type="text"
name="answer"
value={values.answer}
onChange={handleChange}
isValid={touched.question && !errors.question}
isInvalid={!!errors.question}
/>
<Form.Control.Feedback type="invalid">
{errors.question}
</Form.Control.Feedback>
</Col>
)
case "CHECKBOX":
return (
<Col sm={9}>
{values.options.map((option, id) => (
<Form.Check
id={id}
type="checkbox"
name="answerCheckBox"
label={option}
value={option}
defaultChecked={checkedState[id]}
onChange={handleChange}
/>
))}
</Col>
)
case "RADIO_BUTTON":
return (
<Col sm={9}>
{values.options.map((option) => (
<Form.Check
type="radio"
name="answer"
label={option}
value={option}
checked={option === values.answer}
onChange={handleChange}
/>
))}
</Col>
)
}
}
return (
<Modal show={show} onHide={handleClose} centered backdrop="static">
<Modal.Header closeButton>
<Modal.Title>Answer the question</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Row className="me-3 md-3 justify-content-between">
<Form.Group as={Row}>
<Form.Label column sm={3}>
From user
</Form.Label>
<Col sm={9}>
<Form.Control
type="text"
name="author"
value={values.author}
readOnly
disabled
></Form.Control>
</Col>
</Form.Group>
</Row>
<Row className="me-3 mt-3 md-3 justify-content-between">
<Form.Group as={Row}>
<Form.Label column sm={3}>
Question
</Form.Label>
<Col sm={9}>
<Form.Control
type="text"
name="question"
value={values.question}
readOnly
disabled
></Form.Control>
</Col>
</Form.Group>
</Row>
<Row className="me-3 mt-3 md-3 justify-content-between">
<Form.Group as={Row}>
<Form.Label column sm={3}></Form.Label>
{insertAnswerModule()}
</Form.Group>
</Row>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="primary" onClick={handleSubmit}>
SAVE
</Button>
</Modal.Footer>
</Modal>
)
}
I would be glad to know where is error and how to solve it.
SOLUTION:
I passed answer as string[] if answerType is "CHECKBOX". It`s not allowed in HTML and i changed answer type to string and it begins to work.

React keep focus on re-rendering input

I am building an e-commerce web app, and have run into a problem making an array of inputs. Inside DescHTML I am trying to handle onChange event, but on each update the focus on the element is lost, making it very annoying to type. Does anyone have any solution or different aproach to this whole problem? Thanks in advance.
import {useState} from 'react'
export default function UploadForm() {
const [name, setName] = useState('')
const [category, setCategory] = useState('')
const [film, setFilm] = useState('')
const [price, setPrice] = useState('')
const [descArr, setDescArr] = useState([''])
function DescHTML() {
return (
<div>
{ descArr.map((item, i) =>
<input type="text" placeholder="TEST" key={i} value={item} onChange={(e) => {
e.preventDefault()
const newArr = [...descArr]
newArr[i] = e.target.value
setDescArr(newArr)
} } /> )}
</div>
)
}
console.log(descArr)
return (
<div>
<form method="POST" action="http://localhost:3500/api/upload" encType='multipart/form-data'>
<input type="file" name="image" />
<input type="text" value={name} name="name" onChange={(e) => setName(e.target.value)} placeholder="Product name" />
<input type="text" value={category} name="category" onChange={(e) => setCategory(e.target.value)} placeholder="Category" />
<input type="text" value={film} name="film" onChange={(e) => setFilm(e.target.value)} placeholder="Film" />
<input type="text" value={price} name="price" onChange={(e) => setPrice(e.target.value)} placeholder="Price" />
<DescHTML />
<hr />
{/*<input type="submit" value="Submit" />*/}
</form>
<button onClick={() => setDescArr([...descArr, ''])}>+</button>
</div>
)
}
Move your descArr and button inside DescHTML check below code you can check more info here.
function DescHTML() {
const [descArr, setDescArr] = useState([""]);
return (
<div>
{descArr.map((item, i) => (
<input
key={i}
type="text"
placeholder="TEST"
value={item}
onChange={(e) => {
e.preventDefault();
const newArr = [...descArr];
newArr[i] = e.target.value;
setDescArr(newArr);
}}
/>
))}
<br />
<button onClick={() => setDescArr([...descArr, ""])}>+</button>
</div>
);
}
First of all - move DescHTML out of UploadForm:
function DescHTML({descArr, setDescArr}) {
return (
<div>
{descArr.map((item, i) =>
<input type="text" placeholder="TEST" key={i} value={item} onChange={(e) => {
e.preventDefault()
const newArr = [...descArr]
newArr[i] = e.target.value
setDescArr(newArr)
}}/>)}
</div>
)
}
and use it in <UploadForm> like this
<DescHTML descArr={descArr} setDescArr={setDescArr}/>
The other problem is the + button which steals the focus on click. Adding onMouseDown handler will fix this.
<button onMouseDown={(e) => e.preventDefault()} onClick={() => setDescArr([...descArr, ''])}>+</button>

Why getting too many re-renders?

I have a Calculator component for calculating the exponent of a given base.
My code is as follows:
//Exponential Calculator (Power/Squre-Root/Cube-Root)
const Exponents=()=>{
const [result,setResult]=useState(null);
const [choice,setChoice]=useState("Power");
const [x,setX]=useState(null);
const [n,setN]=useState(null);
useEffect(()=>{
},[choice,x,n,result]);
const calcResult=()=>{
let res=1;
if(choice=="Power")
{
for(var i=1;i<=n;i++)
res*=x;
}
else if(choice=="SquareRoot")
res=Math.sqrt(x);
else
res=Math.cbrt(x);
setResult(res);
}
const handleChange=(e)=>{
reset();
setChoice(e.target.value);
}
function reset(){
setResult(null);
setX(null);
setN(null);
}
const choiceData=()=>{
if(choice==="Power"){
return {
name:"Power",
quantities:["Base","Exponent"],
disabled:false
}
}
else if(choice==="SquareRoot")
{
setN(0.50);
return{
name:"Square-Root",
quantities:["Base","Exponent"],
disabled:true
}
}
else if(choice==="CubeRoot")
{
setN(0.34);
return{
name:"Cube-Root",
quantities:["Base","Exponent"],
disabled:true
}
}
}
return(
<>
<Form>
<Form.Group className="mb-4" controlId="choice">
<Form.Label>Select the type of calculation</Form.Label>
<Form.Control
as="select"
className="select-custom-res"
onChange={(e) => handleChange(e)}
>
<option value="Power">Power</option>
<option value="SquareRoot">Square Root</option>
<option value="CubeRoot">Cube Root</option>
</Form.Control>
</Form.Group>
<Form.Group className="mb-4" controlId="text">
<Form.Text className="text">
<strong>
To find the {choiceData().name}, Enter the following values
</strong>
<br />
</Form.Text>
</Form.Group>
<Form.Group className="mb-4">
<Form.Label>{choiceData().quantities[0]}</Form.Label>
<Form.Control
onChange={(e) => setX(e.target.value)}
type="number"
placeholder={"Enter the Base"}
value={x === null ? "" : x}
/>
</Form.Group>
<Form.Group className="mb-4">
<Form.Label>{choiceData().quantities[1]}</Form.Label>
<Form.Control
onChange={(e) => setN(e.target.value)}
type="number"
placeholder={"Enter the Exponent"}
value={n === null ? "" : n}
disabled={choiceData().disabled}
/>
</Form.Group>
<Form.Group className="mb-4">
<Form.Control
readOnly
type="number"
placeholder={result === null ? "Result" : result + " "}
/>
</Form.Group>
</Form>
<div className="button-custom-grp">
<Button variant="primary" onClick={calcResult}>
Calculate
</Button>
<Button variant="dark" onClick={() => reset()} type="reset">
Reset
</Button>
</div>
</>
)
}
On changing the choice from Power to SquareRoot I get an error:Too many rerenders. Interestingly, when I remove the setState line in the choiceData function,the error vanishes. Although I have used useEffect to prevent re-renders, it's not working.
Issue
You call choiceData in the render return, which should be free of side-effects, like enqueueing state updates. When you call setN in the choiceData function it triggers a rerender, which calls choiceData again, which triggers a rerender... repeat ad nauseam.
Solution
I suggest converting choiceData into a chunk of state, and use an useEffect hook to update it and the n state depending on the choice state. In the render return, instead of calling a function to get a value, i.e. choiceData().quantities[0], you instead just access a property of the new choiceData state, i.e. choiceData.quantities[0].
const Exponents = () => {
const [result, setResult] = useState(null);
const [choice, setChoice] = useState("Power");
const [choiceData, setChoiceData] = useState({});
const [x, setX] = useState(null);
const [n, setN] = useState(null);
useEffect(() => {
if (choice === "Power") {
setChoiceData({
name: "Power",
quantities: ["Base", "Exponent"],
disabled: false
});
} else if (choice === "SquareRoot") {
setN(0.5);
setChoiceData({
name: "Square-Root",
quantities: ["Base", "Exponent"],
disabled: true
});
} else if (choice === "CubeRoot") {
setN(0.34);
setChoiceData({
name: "Cube-Root",
quantities: ["Base", "Exponent"],
disabled: true
});
}
}, [choice]);
useEffect(() => {
// is this effect used for anything?
}, [choice, x, n, result]);
const calcResult = () => {
let res = 1;
if (choice == "Power") {
for (var i = 1; i <= n; i++) res *= x;
} else if (choice == "SquareRoot") res = Math.sqrt(x);
else res = Math.cbrt(x);
setResult(res);
};
const handleChange = (e) => {
reset();
setChoice(e.target.value);
};
function reset() {
setResult(null);
setX(null);
setN(null);
}
return (
<>
<Form>
<Form.Group className="mb-4" controlId="choice">
<Form.Label>Select the type of calculation</Form.Label>
<Form.Control
as="select"
className="select-custom-res"
onChange={(e) => handleChange(e)}
>
<option value="Power">Power</option>
<option value="SquareRoot">Square Root</option>
<option value="CubeRoot">Cube Root</option>
</Form.Control>
</Form.Group>
<Form.Group className="mb-4" controlId="text">
<Form.Text className="text">
<strong>
To find the {choiceData.name}, Enter the following values
</strong>
<br />
</Form.Text>
</Form.Group>
<Form.Group className="mb-4">
<Form.Label>{choiceData.quantities[0]}</Form.Label>
<Form.Control
onChange={(e) => setX(e.target.value)}
type="number"
placeholder={"Enter the Base"}
value={x === null ? "" : x}
/>
</Form.Group>
<Form.Group className="mb-4">
<Form.Label>{choiceData.quantities[1]}</Form.Label>
<Form.Control
onChange={(e) => setN(e.target.value)}
type="number"
placeholder={"Enter the Exponent"}
value={n === null ? "" : n}
disabled={choiceData.disabled}
/>
</Form.Group>
<Form.Group className="mb-4">
<Form.Control
readOnly
type="number"
placeholder={result === null ? "Result" : result + " "}
/>
</Form.Group>
</Form>
<div className="button-custom-grp">
<Button variant="primary" onClick={calcResult}>
Calculate
</Button>
<Button variant="dark" onClick={() => reset()} type="reset">
Reset
</Button>
</div>
</>
);
};

How to show/hide a select input according to a value chosen in a previous select input reactjs?

I am new to reactjs, and here I have a form, and in that form I have an input select with two value options.
And the first value option should allow me to bring up a second input select with these value options, and the second nothing at all.
I made my form and for the first input select I manage to do an onChange method, to retrieve the chosen value, but now how to do a test on the chosen value, to display or not the second input select ?
And how to show or hide this second input select ?
My Form
// methode that retrieve the chosen value in input select
const handleOptionChange = (event: any) => {
console.log(event);
};
const FormContent = (props: any) => {
const { control, handleSubmit, errors } = useForm();
const { Option } = Select;
const onSubmit = handleSubmit((data) => {
console.log(data);
});
return (
<form onSubmit={onSubmit}>
<Row gutter={8}>
<Col md={12} lg={12} sm={24}>
<div className="ant-form-item">
<label className="label">Nom Utilisateur <span className="text-danger">*</span></label>
<Controller
// as={inputField("Nom Utilisateur")}
name="username"
control={control}
defaultValue={""}
rules={{ required: true }}
render={props => (<><Input name={props.name} defaultValue={props.value} className="ant-form-item-control" placeholder="Nom Utilisateur" /></>)}
/>
{errors.username && "First name is required"}
</div>
</Col>
<Col md={12} lg={12} sm={24}>
<div className="ant-form-item">
<label className="label">Mot de passe <span className="text-danger">*</span></label>
<Controller
// as={inputPassField()}
name="password"
control={control}
defaultValue={""}
rules={{ required: true }}
render={props => (<Input.Password placeholder="Mot de passe" />)}
/>
{errors.password && "First name is required"}
</div>
</Col>
</Row>
<Row gutter={8}>
<Col md={12} lg={12} sm={24}>
<div className="ant-form-item">
<label className="label">Profile<span className="text-danger">*</span></label>
<Controller
name="profile"
control={control}
defaultValue={""}
rules={{ required: true }}
render={({ onChange, value, name }) => (
<Select
showSearch
placeholder="Select a person"
onChange={(event) => {
onChange(event)
handleOptionChange(event)
}}
value={value ? value : ""}
// name={name}
optionFilterProp="children"
filterOption={(input, option: any) =>
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}>
<option key="b2b_user" value="B2B_CLIENT">B2B_USER</option>
<option key="app_user" value="APPLICATION_USER">USER_SIMPLE</option>
</Select>)}
/>
{errors.profile && "Profile is required"}
</div>
</Col>
</Row>
<Row gutter={8}>
<Col md={12} lg={12} sm={24}>
<Flex alignItems="center" justifyContent="center">
<Button onClick={() => props.onClose()} icon={<CloseOutlined />} size="small" className="mr-3" type="text">Annuler</Button>
<Button icon={<CheckCircleOutlined />} type='primary' htmlType='submit'>
Valider
</Button>
</Flex>
</Col>
</Row>
</form>);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Second input to show/hide
export const SelectCompanyField = () => {
const [page, setPage] = useState(1);
const [perPage, setPerPage] = useState(10);
const { data, error } = useSWR<ServerResponse, any>(companyUrls.base + `?page:${page}&perPage:${perPage}`, url => getDataByParams(companyUrls.base, { page: '' + page, perPage: '' + perPage }));
console.log("Data", data, "Error", error);
console.log(data?.entities);
return (
<Select
showSearch
placeholder="Choisir une compagnie"
optionFilterProp="children"
filterOption={(input, option: any) =>
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
{data?.entities.map(d => (
<option value={d.index} key={d.id} >
{d.name}
</option>
))}
</Select>
);
};
// the second input select to show/hide
<Col md={24} lg={24} sm={24}>
<div className="ant-form-item">
<label className="label">Compagnie <span className="text-danger">*</span></label>
<Controller
as={SelectCompanyField()}
name="company"
control={control}
defaultValue={""}
rules={{ required: false }}
/>
{errors.company && "Company is required"}
</div>
</Col>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Thanks
Something like...
const [firstOptionValue, setFirstOptionValue] = useState(null)
const handleOptionChange = (event: any) => {
setFirstOptionValue(event.target.value)
};
Then when you want to conditionally render the second select...
{firstOptionValue && <SecondSelectContainer/>}
So whatever is in SecondSelectContainer will only render if firstOptionValue is not falsey.

Resources