After obtaining a data, I take a photo of the user from the users table with the user's ids, I can access all the data without any problem and I can see all of them with console.log. But it doesn't render.
How can i solve this problem ? Thank you.
export default function MentionInput(props) {
const [state, dispatch] = useContext(UsePeopleModuleContext);
const [decisionUserRole, setDecisionUserRole] = useContext(
UseDecisionUserRoleContext
);
const { isConsulted, isResponsible, isApprover, isCreator } =
decisionUserRole;
const { currentUser } = useAuth();
const { users, currentWorkspace, activeDecision, setActiveDecision } =
useWorkspace();
const [value, setValue] = useState([]);
const [loading, setLoading] = useState(true);
const userMentionData = users.map((myUser) => ({
id: myUser.userId,
value: myUser.userId,
displayName: `${myUser.displayName}`,
label: `${myUser.displayName}`,
}));
const propsData = props;
useEffect(async () => {
setLoading(true);
const people = await usersModule.getPeople(
currentWorkspace,
activeDecision.id
);
const datas = [];
if (propsData.field === 'consulted') {
people.consulted.map((consulted) => {
console.log('CONSULTED =>', consulted);
userdb.getUser(consulted.id).then((user) => {
const photoURL = user.photoURL;
datas.push({
id: consulted.id,
value: consulted.id,
displayName: `${user.displayName}`,
label: `${user.displayName}`,
photoURL: photoURL !== undefined ? photoURL : '',
});
});
});
console.log('DATAS =>', datas);
setValue(datas);
setLoading(false);
} else if (propsData.field === 'approver') {
const user = await userdb.getUser(people.approver.id);
const photoURL = user.photoURL;
setValue([{ ...people.approver, photoURL: photoURL }]);
setLoading(false);
} else if (propsData.field === 'responsible') {
//await userdb.getUser
const user = await userdb.getUser(people.responsible.id);
const photoURL = user.photoURL;
setValue([{ ...people.responsible, photoURL: photoURL }]);
setLoading(false);
}
}, []);
return (
!loading &&
(isCreator || !isResponsible ? (
<Box w="100%">
<Select
isMulti={
props.field === 'consulted'
? true
: props.field === 'approver'
? false
: props.field === 'responsible'
? false
: true
}
name=""
options={userMentionData}
placeholder="Assign people"
closeMenuOnSelect={false}
size="sm"
onChange={handleChange}
value={value}
/>
</Box>
) : (
<Box w="100%" ml="10px">
<Wrap>
{value?.map((item, index) =>
item !== undefined ? (
<WrapItem key={index}>
<Tag
size="md"
borderRadius="lg"
ml={index === 0 ? 0 : 2}
colorScheme="gray"
>
<Avatar
size="xs"
name={
item?.displayName !== undefined &&
item?.displayName.toLowerCase()
}
ml={-3}
mr={2}
src={item.photoURL}
/>
<TagLabel>{item?.displayName}</TagLabel>
</Tag>
</WrapItem>
) : null
)}
</Wrap>
</Box>
))
);
}
userdb.getUser: it works beautifully.
getUser: async (userId) => {
const q = query(doc(db, 'user', userId));
const getData = await getDoc(q);
if (getData.exists()) {
return getData.data();
}
},
As you can see from the screenshots, the data comes out fine, but the component does not render.
i update my setState function , the question solved.
if (propsData.field === 'consulted') {
const datas = [];
people.consulted.map((consulted) => {
userdb.getUser(consulted.id).then((user) => {
const photoURL = user.photoURL;
setValue((value) => [
...value,
{
id: consulted.id,
value: consulted.id,
displayName: `${user.displayName}`,
label: `${user.displayName}`,
photoURL: photoURL !== undefined ? photoURL : '',
},
]);
});
});
setLoading(false);
}
Related
I have a dropdown based on which different fields gets rendered. Initially I have initialized selected option of dropdown in useEffect hook, corresponding fields gets rendered and are working fine.
But when different option or even same option is chosen from dropdown fields gets rendered but when I type something in it it gets cleared. I have used useRef to store values for field at index i in fields array.
export default function CreateEntry({ navigation }) {
const { user, setLoading, setLoadingMsg } = useAuthContext();
const [name, setName] = useState("");
const [selectedCategory, setSelectedCategory] = useState("");
const [categoriesList, setCategoriesList] = useState([]);
const [primary, setPrimary] = useState("");
const [primaryValue, setPrimaryValue] = useState("");
const [fields, setFields] = useState([
{
name: "Email",
value: "",
type: "string",
encrypt: false,
},
{
name: "Password",
value: "",
type: "string",
encrypt: true,
},
]);
const refInputs = useRef([]);
useEffect(() => {
firestore()
.collection("categories")
.doc(user.uid)
.get()
.then((documentSnapshot) => {
setCategoriesList(documentSnapshot.data().category);
setSelectedCategory(documentSnapshot.data().category[0].name);
setFields(documentSnapshot.data().category[0].fields);
fields.map((field) => {
refInputs.current.push("");
});
})
.catch((error) => {
console.log(error);
});
}, []);
const addInput = () => {
refInputs.current.push("");
setFields([
...fields,
{ name: "First", value: "", type: "string", encrypt: false },
]);
};
const removeInput = (i) => {
refInputs.current[i] = "";
setFields((fields) =>
fields.map((field, index) => {
if (index === i) {
return null;
}
return field;
})
);
};
const setInputValue = (index, value) => {
refInputs.current[index] = value;
};
const inputs = [];
fields.forEach((field, i) => {
if (field !== null) {
inputs.push(
<View
key={i}
>
<TextInput
onChangeText={(value) => setInputValue(i, value)}
value={refInputs.current[i]}
/>
<TouchableOpacity
onPress={() => removeInput(i)}
>
<Ionicons name="close" style={[tw``]} size={22} color="#ddd" />
</TouchableOpacity>
</View>
);
}
});
const addEntry = () => {
//
};
return (
<ScrollView style={styles.container}>
<Dropdown
data={categoriesList}
value={selectedCategory}
onChange={(item) => {
refInputs.current = [];
setSelectedCategory(item.name);
setFields(item.fields);
item.fields.map((field) => {
refInputs.current.push("");
});
}}
/>
<Input
onChangeText={setName}
value={name}
placeholder="Name"
/>
{inputs}
<Pressable onPress={addInput}>
<Text}>+ Add a new input</Text>
</Pressable>
<MainButton onPress={addEntry}>Add</MainButton>
</ScrollView>
);
}
I am creating a cart where the client has multiple checkboxes, I can update the cart when the checkbox is checked and update it when is unchecked, so far so good, but the problem is when the client wants to create another order, I think the reducer is bringing me the old order.
This is my reducer
if (action.type === ADD_ITEM_TO_CART_DETAILS) {
return {
...state,
cart: [...state.cart, action.payload]
}
}
This is my action
export function addItemDetail(value){
return {
type : ADD_ITEM_TO_CART_DETAILS,
payload: value
}
}
and this is the JS:
export default function DetailProduct() {
const dispatch = useDispatch();
const { id } = useParams();
const history = useHistory();
useEffect(() => {
dispatch(getDetail(id));
}, [dispatch, id]);
const detail = useSelector((state) => state.detail); // details of the products
const { options, setOptions } = useContext(OrderContext);
const BackToProducts = () => {
if (options.salsa.length) {
dispatch(addItemDetail(options));
} else {
history.push("/productos");
}
};
const seeCart = () => {
if (options.salsa.length) {
dispatch(addItemDetail(options));
} else {
history.push("/carrito");
}
};
const handleComments = (e) => {
setOptions((prev) => ({
...prev,
Comments: e.target.value,
}));
};
const handleSalsa = (e) => {
const { name, checked } = e.target;
if (options.salsa.length <= 2) {
e.target.checked = false;
} else if (checked === true) {
setOptions((prev) => ({
...prev,
salsa: [...prev.salsa, name],
picture_url: detail.picture_url,
id: uuidv4(),
price: detail.price,
title: detail.title,
}));
}
if (checked === false) {
setOptions((prev) => ({
...prev,
salsa: prev.salsa.filter((p) => p !== name),
}));
}
};
const handleToppings = async (e) => {
const { name, checked } = e.target;
if (checked === true) {
setOptions({ ...options, toppings: [...options.toppings, name] });
}
if (checked === false) {
setOptions((prev) => ({
...prev,
toppings: prev.toppings.filter((p) => p !== name),
}));
}
};
useEffect(() => {
// useEffect to update the total amount
const productPrice = options.price; // price of the single product
const toppingPrice = options.priceTopping; // price of the topping
const total = toppingPrice ? productPrice + toppingPrice : productPrice;
setOptions((prev) => ({ ...prev, unit_price: total })); // set total amount product plus toppings
}, [options.price, options.priceTopping, setOptions]);
useEffect(() => {
// useEffect to update total amount of the toppings
const numberOfToppings = options.toppings.length;
const totalPriceTopping = numberOfToppings !== 0 ? numberOfToppings * 119 : 0;
setOptions((prev) => ({ ...prev, priceTopping: totalPriceTopping }));
}, [options.toppings, setOptions]);
return (
<MainContainer>
{detail.picture_url ? <PhotoProduct src={`https://hit-pasta.herokuapp.com/${detail.picture_url}`} /> : <Loading />}
<Like
onClick={() => {
history.push("/productos");
}}
/>
<ContainerOption>
{detail &&
detail?.salsas?.map((p, index) => {
return (
<ContainerOptionChild key={index}>
<div>
<Drop />
<LabelProductName>{p.sauce}</LabelProductName>
</div>
<InputOptions type="checkbox" checked={options.salsa.index} key={index} name={p.sauce} value={p.sauce} onChange={handleSalsa} />
<Description>{p.description}</Description>
</ContainerOptionChild>
);
})}
</ContainerOption>
<MainBoxComments>
<h3>Comentarios</h3>
<BoxComentario type="text" value={options.Comments} onChange={handleComments} placeholder="Agrega instrucciones o comentarios a tu orden" />
</MainBoxComments>
<MainBoxBtns>
<Okay onClick={seeCart}>
OKAY <CartIcon />
</Okay>
<BtnArmarOtroHit onClick={BackToProducts}>ARMAR OTRO HIT</BtnArmarOtroHit>
</MainBoxBtns>{" "}
</MainContainer>
);
}
I am having issues trying to focus on a previous input once I delete out of the input that I am in. I have 6 inputs, all with a maxLength of 1. When I press the backspace key I would like to delete the value and move to the previous input. I have tried a variety of things but nothing seems to work how I need.
Here is my code
This is the Auth component which is passing props to verify (the page with the inputs)
const Auth = ({ sub }) => {
let params = useParams();
const navigate = useNavigate();
const [rec, setRec] = useState({
accept: false,
email: '',
phone: '',
pin: ['', '', '', '', '', '']
})
const onPaste = (event) => {
event.preventDefault()
const pasted = event.clipboardData.getData("text/plain")
setRec({ ...rec, pin: pasted.split("").slice(0, rec.pin.length) })
// target event last sibling
event.target.parentNode.lastChild.focus()
}
function update(event, index) {
event.preventDefault()
setRec({
...rec, pin: [
...rec.pin.slice(0, index),
event.target.value,
...rec.pin.slice(index + 1)
]
})
}
const handleFocus = (event) => {
if (event.target.nextSibling)
event.target.nextSibling.focus();
// if value is deleted, focus previous sibling
// if all siblings are empty, focus first sibling
if (event.target.value === '' && event.target.previousSibling === null)
event.target.parentNode.firstChild.focus()
}
const onKeyPress = (event) => {
// if backspace is clicked, go to previous input
if (event.key === 'Backspace' && event.target.value === '') {
event.target.previousSibling.focus()
}
}
const handleChange = (name, value) => {
if (name === 'mobile') name = 'phone'
const recState = {
...rec,
[name]: value,
}
setRec(recState)
}
const toggleAccept = () => {
if (!rec.accept) {
setRec({
...rec,
accept: true
});
} else {
setRec({
...rec,
accept: false
});
}
}
const handleSubmit = async () => {
const { accept, email, phone } = rec
if (params.method === 'email' && !email) return app.actions.setError('Enter an email')
else if (params.method !== 'email' && !phone) return app.actions.setError('Enter a phone number')
const send = params.method === 'email' ? { email } : { phone }
if (!accept) return app.actions.setError('Please accept the terms & conditions')
try {
await app.actions.setLoading(true)
// if there is already a user, just login, else create user first
await user.actions.login(send)
await app.actions.setLoading(false)
navigate(`/auth/verify/login/${params.method || 'phone'}`)
} catch (e) {
if (e.response && e.response.status === 404) {
// try join
await user.actions.join(send)
await app.actions.setLoading(false)
return navigate(`/auth/verify/join/${params.method || 'phone'}`)
}
await app.actions.setLoading(false)
await app.actions.setError(e)
}
}
const handleVerify = async ({ context, method }) => {
const { email, phone, pin } = rec
const joinPin = pin.join('');
if (method === 'email' && !email) return app.actions.setError('Enter an email')
else if (method !== 'email' && !phone) return app.actions.setError('Enter a phone number')
const send = method === 'email' ? { email } : { phone }
await app.actions.setError(null)
try {
await app.actions.setLoading(true)
if (context === 'login') {
await user.actions.loginVerify({
...send,
pin: joinPin,
})
} else {
await user.actions.verify({
...send,
pin: joinPin,
})
}
await app.actions.init()
await app.actions.setLoading(false)
navigate('/')
} catch (e) {
await app.actions.setLoading(false)
await app.actions.setError(e)
}
}
return (
<>
{sub ?
<Verify
context={params.context}
handleChange={handleChange}
handleFocus={handleFocus}
handleSubmit={() => handleVerify({ context: params.context, method: params.method })}
onKeyPress={onKeyPress}
method={params.method}
paste={onPaste}
update={update}
rec={rec} />
:
<Jogin
handleChange={handleChange}
handleSubmit={handleSubmit}
method={params.method}
toggleAccept={toggleAccept}
rec={rec} />
}
</>
)
}
export default Auth
and here is the verify component
import React from 'react'
import { onFormSubmit } from '../../utility/form'
import { Navigate, useNavigate } from 'react-router-dom'
import user from '../../model/user'
import app from '../../model/app'
const Verify = ({ handleSubmit, method, rec, paste, update, handleFocus, onKeyPress }) => {
const navigate = useNavigate();
const { email, phone } = rec
const send = method === 'email' ? { email: email } : { phone: phone }
const resendPin = async () => {
try {
await app.actions.setLoading(true)
// if there is already a user, just login, else create user first
await user.actions.login(send)
await app.actions.setLoading(false)
navigate(`/auth/verify/login/${method || 'phone'}`)
} catch (e) {
if (e.response && e.response.status === 404) {
// try join
await user.actions.join(send)
await app.actions.setLoading(false)
return navigate(`/auth/verify/join/${method || 'phone'}`)
}
await app.actions.setLoading(false)
await app.actions.setError(e)
}
}
const renderContent = () => {
const methodLabel = method === 'email' ? 'email address' : 'phone number'
return (
<>
<div id="back-grad" />
<div className="col-md-8">
<div className='verify-text-section'>
<p className="verify-text pb-5">
Enter the PIN number we just sent to your {methodLabel}.
</p>
</div>
<div className="flex">
{rec.pin.map((s, key) => (
<input key={key} className='code-input mr-2' value={s} maxLength='1' onPaste={(e) => paste(e)} onKeyDown={e => onKeyPress(e)} onInput={(e) => update(e, key)} onChange={(e) => handleFocus(e)} inputMode='numeric' autoFocus={key === 0} />
))}
</div>
<div className="verify-resend mt-3" onClick={resendPin}>Resend Code</div>
<div className="flex margin-set text-center">
<button className="btn btn-block text-white verify-btn">
<p className="verify-btn-text">VERIFY</p>
</button>
</div>
</div>
</>
)
}
return (
<>
{rec.email.length < 1 && rec.phone.length < 1 ? <Navigate to={'/auth'} />
:
<div className="d-flex align-items-center h-full">
<form className="container" onSubmit={e => onFormSubmit(e, handleSubmit)}>
<div className="row justify-content-center">
{renderContent()}
</div>
</form>
</div>
}
</>
)
}
export default Verify
any help is appreciated!
I have a reusable drop down menu component and i render it twice with two different lists and it should update the state with the id of the first element.
the first drop down of the layout update the state without any issue but the second one does not(i switched the order and it always seems the first one updates the state the second doesn't).
please see code
dashbord
const initializeData = {
actionStatuses: [],
actionCategories: [],
actionGroups: [],
actionEvents: [],
actionEventsWithFilter: [],
selectedFilters: {actionStatusId: "", actionCategoryId:""},
};
const Dashboard = ({ selectedPracticeAndFy }) => {
const [data, setData] = useState(initializeData);
const getSelectedStatus = ({ key }) => {
const actionStatusId = key;
const selectedFilters = { ...data.selectedFilters, actionStatusId };
setData((prevState) => {
return { ...prevState, selectedFilters }
});
};
const getSelectedCategory = ({ key }) => {
const actionCategoryId = key;
const selectedFilters = { ...data.selectedFilters, actionCategoryId };
setData((prevState) => {
return { ...prevState, selectedFilters }
});
};
}
result filter:
const ResultFilter = ({actionStatuses, actionCategories, getSelectedStatus, getSelectedCategory}) => {
return (
<Grid
justify="flex-start"
container
>
<Grid item >
<Typography component="div" style={{padding:"3px 9px 0px 0px"}}>
<Box fontWeight="fontWeightBold" m={1}>
Result Filter:
</Box>
</Typography>
</Grid>
<Grid >
<DropdownList payload={actionCategories} onChange={getSelectedCategory} widthSize= {dropdownStyle.medium}/>
<DropdownList payload={actionStatuses} onChange={getSelectedStatus} widthSize= {dropdownStyle.medium}/>
</Grid>
</Grid>
);
}
DropdownList:
const DropdownList = ({ label, payload, onChange, widthSize, heightSize, withBorders, initialData }) => {
const { selectedData, setSelectedData, handelInputChange } = useForm(
payload
);
useEffect(() => {
if (Object.entries(selectedData).length === 0 && payload.length !== 0) {
setSelectedData(payload[0]);
}
}, [payload]);
useEffect(() => {
if (Object.entries(selectedData).length !== 0) {
onChange(selectedData);
}
}, [selectedData]);
return (
<div style={widthSize}>
<div className="ct-select-group ct-js-select-group" style={heightSize}>
<select
className="ct-select ct-js-select"
id={label}
value={JSON.stringify(selectedData)}
onChange={handelInputChange}
style={withBorders}
>
{label && <option value={JSON.stringify({key: "", value: ""})}>{label}</option>}
{payload.map((item, i) => (
<option key={i} value={JSON.stringify(item)} title={item.value}>
{item.value}
</option>
))}
</select>
</div>
</div>
);
};
It may be a stale closure issue, could you try the following:
const getSelectedStatus = ({ key }) => {
setData((data) => {
const actionStatusId = key;
const selectedFilters = {
...data.selectedFilters,
actionStatusId,
};
return { ...data, selectedFilters };
});
};
const getSelectedCategory = ({ key }) => {
setData((data) => {
const actionCategoryId = key;
const selectedFilters = {
...data.selectedFilters,
actionCategoryId,
};
return { ...data, selectedFilters };
});
};
I'm using hooks and Context when after login my URL refreshing sometimes and get this Error Maximum update depth exceeded and my page not loading when refresh page everything is Ok!
this code my Login Page :
function LoginView(props) {
const classes = useStyles()
const [Username, setUsername] = useState('');
const [Password, setPassword] = useState('');
const { getUserLogin, isLogin } = useContext(UserContext)
const handelSubmit = (e) => {
console.log(Username, Password)
if (Username.length < 1) {
alert("لطفا نام کاربری را وارد نمایید")
if (Password.length < 1) {
alert("لطفا رمز عبور را واردنمایید")
}
}
let uuid = uuidv1()
console.log(uuid)
localStorage.setItem('myUUID', uuid)
let xml = 'exampel xlm (srver is SOAP)';
console.log(xml)
getUserLogin(xml)
}
useEffect(() => {
if (isLogin) {
props.history.push("/MainPage")
}
})
return (
<div style={{ direction: 'rtl', }}>
<MyLogo />
<div className={classes.root} >
<div className='textfiled'>
<TextField
className={classes.txt}
name='username'
inputProps={{ style: { textAlign: 'center' } }}
onChange={(e) => setUsername(e.target.value)}
placeholder='نام کاربری' ></TextField>
</div>
<div >
<TextField
className={classes.txt}
inputProps={{ style: { textAlign: 'center' } }}
name='password'
type='password'
onChange={(e) => setPassword(e.target.value)}
placeholder='رمز عبور' ></TextField>
</div>
<div>
<Button color={'inherit'} className={classes.btn} onClick={() => handelSubmit()} > ورود</Button>
</div>
</div>
</div>
)
}
export default withRouter(LoginView);
after submitting my cod get some error in console google I read this post
Maximum update depth exceeded
and change my onclick function but steel error Maximum update depth exceeded
and this is my Context :
export const UserContext = createContext()
export const UserContextDispacher = createContext();
const UserProvider = (props) => {
const [user, setUser] = useState({ username: '', password: '', })
const [isLogin, setisLogin] = useState(false)
const getUserLogin = (value) => {
axios.post('https://exampel.com/myexampel.asmx', value, { headers: { 'Content-Type': 'text/xml;charset=UTF-8' } }).then(function (response) {
// console.log(response)
var options = {
attributeNamePrefix: "#_",
attrNodeName: "attr", //default is 'false'
textNodeName: "#text",
ignoreAttributes: true,
ignoreNameSpace: false,
allowBooleanAttributes: false,
parseNodeValue: true,
parseAttributeValue: false,
trimValues: true,
cdataTagName: "__cdata", //default is 'false'
cdataPositionChar: "\\c",
localeRange: "", //To support non english character in tag/attribute values.
parseTrueNumberOnly: false,
attrValueProcessor: a => he.decode(a, { isAttributeValue: true }),//default is a=>a
tagValueProcessor: a => he.decode(a) //default is a=>a
};
// Intermediate obj
var tObj = parser.getTraversalObj(response.data, options);
var jsonObj = parser.convertToJson(tObj, options);
//set Token
var token = jsonObj["soap:Envelope"]["soap:Body"].AuthenticateUserResponse.Token
var authResult = jsonObj["soap:Envelope"]["soap:Body"].AuthenticateUserResponse.AuthenticateUserResult
if (authResult != false) {
localStorage.setItem('mytoken', token)
localStorage.setItem('myisLogin', authResult)
setisLogin(true)
} else {
localStorage.setItem('myisLogin', authResult)
setisLogin(false)
}
return authResult
}).catch(function (error) {
// console.log("erorr in send to login : " + error)
})
}
return (
<UserContext.Provider value={{ user, getUserLogin, isLogin }}>
<UserContextDispacher.Provider>
{props.children}
</UserContextDispacher.Provider>
</UserContext.Provider>
)
}
export default withRouter(UserProvider);
how to fix it this error?
thank for helping me
UPDATE
if (authResult != false) {
localStorage.setItem('mytoken', token)
localStorage.setItem('myisLogin', authResult)
setisLogin(true)
props.history.push("/MainPage");
}
and delete useEffect from loginview.js
useEffect runs every time a change occurs so useEffect is getting triggered infinitely many times so the error.
Solution : Use isLogin as dependency for useEffect.
useEffect(() => {
if (isLogin) {
props.history.push("/MainPage")
}
},[isLogin])