I'm having a problem when I input a new url in the project's custom url.
So this url input can be edited, now when it can be edited I enter a new url behind "https://www.kutanya.com/share/", then I save and a notification "custom url is exist" appears.
my API =
export const setCustomUrl = (args, surveyId) => {
return new Promise((resolve, reject) => {
axios
.put(process.env.NEXT_PUBLIC_API_URL + `/v1/smart-survey/${surveyId}/custom-url`, args, {
headers: { Authorization: `Bearer ${token()}` },
})
.then((response) => {
resolve(response.data.data);
})
.catch((error) => {
console.log(error.response);
reject(error?.response?.data?.message || "Network error.");
});
});
};
file .jsx =
const ShareKey = ({ customUrl, surveyId, shareKey = "", setShareKey, updateUrl, refProps }) => {
const [isLoading, setIsLoading] = useState(false);
const [customInput, setCustomInput] = useState(process.env.NEXT_PUBLIC_SHARE_URL + "/");
const [active, setActive] = useState(false);
const [show, setShow] = useState(false);
const router = useRouter();
const getLink = () => {
setShareKey("");
setIsLoading(true);
automaticApproval({ surveyId })
.then((resolve) => {
console.log(resolve);
setShareKey(resolve.key);
})
.catch((reject) => {
console.log(reject);
toast.error(reject);
})
.finally(() => {
setIsLoading(false);
});
};
const toggleFunction = () => {
setActive(!active);
setShow(!show);
};
const SaveFunction = () => {
setCustomUrl({ customUrl }, router.query.surveyId)
.then((resolve) => {
console.log(resolve);
updateUrl({
customUrl
});
setShareKey(resolve.key);
toast.info("Berhasil ubah link");
})
.catch((reject) => {
console.log(reject);
toast.error(reject);
})
.finally(() => {
setIsLoading(false);
});
};
return (
<section>
<button onClick={getLink} disabled={isLoading} className={styles.link_button}>
{`GENERATE ${shareKey && "NEW "}LINK`}
</button>
{shareKey && (
<div className={styles.link_container}>
<label>Share link</label>
<div className={styles.link}>
<input
value={active ? customInput : process.env.NEXT_PUBLIC_SHARE_URL + "/" + shareKey}
onChange={(e) => {
setCustomInput(e.target.value);
}}
disabled={!active}
ref={refProps}
/>
{!show && (
<button
onClick={() => {
if (typeof navigator !== "undefined") {
navigator.clipboard.writeText(refProps.current.value);
toast.info("Copied to clipboard");
}
}}
>
copy
</button>
)}
</div>
{active ? (
<div className={styles.custom2}>
<button style={{ color: "red", marginTop: "6px" }} onClick={toggleFunction}>
Cancel
</button>
<button style={{ color: "blue", marginTop: "6px" }} onClick={SaveFunction}>
Save
</button>
</div>
) : (
<div className={styles.custom} onClick={toggleFunction}>
Create Custom URL
</div>
)}
</div>
)}
</section>
);
};
The question is, is there something wrong in my coding so that the output is 400 in the console and the notification appears?
Related
This error is shown in the browser console when Dialog (modal) is open:
Warning: Failed prop type: The prop onSubmit is marked as required
in ProjectWizardForm, but its value is undefined.
Code:
const UstHomeToolbar = ({ destroyProjectWizardForm, handleOpenAddPattern }) => {
const [open, setOpen] = useState(false);
const [openUploadForm, setOpenUploadForm] = useState(false);
const [projectWizardModalTitle, setProjectWizardModalTitle] = useState("");
const classes = useStyles();
const [selectedFile, setSelectedFile] = useState();
const [isFilePicked, setIsFilePicked] = useState(false);
const [statusText, setStatusText] = useState({
type: null,
msg: null,
});
const [userData, setUserData] = useState({});
useEffect(() => {
const userDataForPermissions = localStorage.getItem(LOGGED_IN_USER);
setUserData(JSON.parse(userDataForPermissions));
}, []);
const handleProjectDialogClickOpen = () => {
setOpen(true);
};
const handleProjectDialogClose = async () => {
setOpen(false);
};
const changeUploadHandler = (event) => {
setSelectedFile(event.target.files[0]);
setIsFilePicked(true);
};
const clearUploadHandler = (event) => {
setSelectedFile(null);
setIsFilePicked(false);
};
const handleUploadSubmission = () => {
const formData = new FormData();
formData.append("excel", selectedFile);
axios
.post("/project/excel", formData, {
headers: { "Content-Type": "multipart/form-data" },
})
.then((res) => {
clearUploadHandler();
setStatusText({
type: "success",
msg: "Excel file is uploaded successfully and taking you to the design....",
});
const design = res.data;
window.location.href = `/project/${design.project_id}/design/${design.id}`;
})
.catch((err) => {
console.error("Error:", err?.response?.data?.message);
clearUploadHandler();
setStatusText({
type: "error",
msg: err?.response?.data?.message,
});
});
};
const handleProjectDialogExited = () => {
destroyProjectWizardForm();
};
const handleProjectWizardModalTitle = (newModalTitle) =>
setProjectWizardModalTitle(newModalTitle);
return (
<Toolbar className={classes.toolbarHome}>
<Grid container justify="space-between">
<Grid item>
<Box className={classes.projectTitleStyle}>Projects</Box>
<Box className={classes.projectTitleDetailsStyle}>
List of ongoing and finished projects
</Box>
</Grid>
<Grid item>
<div className={classes.addProjectButtonStyle}>
<IxButton
onClick={() => setOpenUploadForm(true)}
handleClose={() => setOpenUploadForm(false)}
customClassName={TOOLBAR_BUTTON}
text="UPLOAD EXCEL"
inline={true}
disabled={!getPermission(userData, PROJECT).can_edit}
/>
<IxButton
onClick={handleProjectDialogClickOpen}
customClassName={TOOLBAR_BUTTON}
text="ADD PROJECT"
inline={true}
disabled={!getPermission(userData, PROJECT).can_edit}
/>
</div>
</Grid>
</Grid>
<IxDialog
handleClose={() => setOpenUploadForm(false)}
open={openUploadForm}
modalTitle={"Upload Design Excel"}
>
<div style={{ minHeight: "50px" }}>
Select an excel (*.xls) file:
<input
type="file"
onChange={changeUploadHandler}
accept=".xls"
style={{ marginLeft: "10px" }}
/>
</div>
<div style={{ marginBottom: "5px" }}>
{statusText.type && (
<Alert className={classes.statusText} severity={statusText.type}>
{statusText.msg}{" "}
</Alert>
)}
</div>
<div>
<Button
variant="contained"
component="label"
onClick={handleUploadSubmission}
disabled={!isFilePicked}
>
Upload File
</Button>
</div>
</IxDialog>
<IxDialog
handleClose={handleProjectDialogClose}
onExited={handleProjectDialogExited}
open={open}
modalTitle={projectWizardModalTitle}
>
<ProjectWizardForm
handleOpenAddPattern={handleOpenAddPattern}
handleClose={handleProjectDialogClose}
handleProjectWizardModalTitle={handleProjectWizardModalTitle}
/>
</IxDialog>
</Toolbar>
);
};
export default UstHomeToolbar;
ProjectWizardForm component:
const ProjectWizardForm = props => {
const [page, setPage] = useState(1);
const [touchedOnLoad, setTouchedOnLoad] = useState(false);
const history = useHistory();
const {
handleClose,
dispatch,
handleOpenAddPattern,
handleProjectWizardModalTitle
} = props;
useEffect(() => {
switch (page) {
case 1:
handleProjectWizardModalTitle('Add project');
break;
case 2:
handleProjectWizardModalTitle('Add target specs');
break;
case 3:
handleProjectWizardModalTitle('Add version details');
break;
default:
return;
}
}, [page, handleProjectWizardModalTitle]);
const saveData = values => {
const { submitButtonType } = values;
var errors = ProjectValidate(values);
if (Object.entries(errors).length > 0) {
if (errors?.number || errors?.drawn_date) {
setTouchedOnLoad(true);
setPage(1);
return;
} else if (errors.mandrel_id) {
setTouchedOnLoad(true);
setPage(3);
return;
}
}
const openAddPatternForm = newProject => {
const openAddPatternForm = true;
handleOpenAddPattern(openAddPatternForm, newProject);
};
dispatch(
addDesign(
formatProjectWizardSubmittedValue(values),
(err, newProject) => {
if (!err) {
dispatch(fetchProjects());
submitButtonType === ADD_PATTERN_NEXT_SUBMIT_BUTTON_TYPE
? openAddPatternForm(newProject)
: history.push(
`/project/${newProject.project_id}/details/${newProject.id}`
);
} else {
dispatch(setError(getFormatError(err)));
}
}
)
);
handleClose();
};
return (
<div>
{page === 1 && (
<UstProjectDetailForm
getDialogActionButtons={getAddProjectDetailsDialogActionButtons}
{...props}
touchedOnLoad={touchedOnLoad}
onSubmit={saveData}
nextPage={() => setPage(page + 1)}
/>
)}
{page === 2 && (
<UstProjectTargetSpecForm
{...props}
getDialogActionButtons={getAddTargetSpecDialogActionButtons}
onSubmit={saveData}
previousPage={() => setPage(page - 1)}
nextPage={() => setPage(page + 1)}
/>
)}
{page === 3 && (
<UstDesignDetailForm
{...props}
getDialogActionButtons={getAddDesignDetailsDialogActionButtons}
touchedOnLoad={touchedOnLoad}
onSubmit={saveData}
previousPage={() => setPage(page - 1)}
nextPage={() => setPage(page + 1)}
/>
)}
</div>
);
};
ProjectWizardForm.propTypes = {
onSubmit: PropTypes.func.isRequired
};
How can I fix this issue?
here I have a case where when I click a link "create custom url" it will change to "cancel" and "save".
for example like this :
When I click "create custom url"
Turned into like this
Want it like that.
However, when I try to make it this is the result
Cancel and save together, cancel and save should have its own function.
This is my code:
const ShareKey = ({ surveyId, shareKey = "", setShareKey, refProps }) => {
const [isLoading, setIsLoading] = useState(false);
const [customInput, setCustomInput] = useState(process.env.NEXT_PUBLIC_SHARE_URL + "/");
const [active, setActive] = useState(false);
const [show, setShow] = useState(false);
const getLink = () => {
setShareKey("");
setIsLoading(true);
automaticApproval({ surveyId })
.then((resolve) => {
console.log(resolve);
setShareKey(resolve.key);
})
.catch((reject) => {
console.log(reject);
toast.error(reject);
})
.finally(() => {
setIsLoading(false);
});
};
return (
<section>
<button onClick={getLink} disabled={isLoading} className={styles.link_button}>
{`GENERATE ${shareKey && "NEW "}LINK`}
</button>
{shareKey && (
<div className={styles.link_container}>
<label>Share link</label>
<div className={styles.link}>
<input
value={active ? customInput : process.env.NEXT_PUBLIC_SHARE_URL + "/" + shareKey}
onChange={(e) => {
setCustomInput(e.target.value);
}}
disabled={!active}
ref={refProps}
/>
{!show &&
<button
onClick={() => {
if (typeof navigator !== "undefined") {
navigator.clipboard.writeText(refProps.current.value);
toast.info("Copied to clipboard");
}
}}
>
copy
</button>
}
</div>
<p className={styles.custom} onClick={() => {setActive(!active); setShow(!show);}}>
{active ? "Cancel " + " Save" : "Create Custom URL"}
</p>
</div>
)}
</section>
);
};
Is there something wrong in my code? Please help. Thank you
This is how you gonna do it.
Also I changed your <p> to <div>. You can't nest anything inside of it.
You can change the container <div> to React Fragment if you don't want have some additional div.
You also have to fix the style.
const ShareKey = ({ surveyId, shareKey = "", setShareKey, refProps }) => {
const [isLoading, setIsLoading] = useState(false);
const [customInput, setCustomInput] = useState(
process.env.NEXT_PUBLIC_SHARE_URL + "/"
);
const [active, setActive] = useState(false);
const [show, setShow] = useState(false);
const getLink = () => {
setShareKey("");
setIsLoading(true);
automaticApproval({ surveyId })
.then((resolve) => {
console.log(resolve);
setShareKey(resolve.key);
})
.catch((reject) => {
console.log(reject);
toast.error(reject);
})
.finally(() => {
setIsLoading(false);
});
};
const toggleFunction = () => {
setActive(!active);
setShow(!show);
};
return (
<section>
<button
onClick={getLink}
disabled={isLoading}
className={styles.link_button}
>
{`GENERATE ${shareKey && "NEW "}LINK`}
</button>
{shareKey && (
<div className={styles.link_container}>
<label>Share link</label>
<div className={styles.link}>
<input
value={
active
? customInput
: process.env.NEXT_PUBLIC_SHARE_URL + "/" + shareKey
}
onChange={(e) => {
setCustomInput(e.target.value);
}}
disabled={!active}
ref={refProps}
/>
{!show && (
<button
onClick={() => {
if (typeof navigator !== "undefined") {
navigator.clipboard.writeText(refProps.current.value);
toast.info("Copied to clipboard");
}
}}
>
copy
</button>
)}
</div>
{active ? (
<div>
<button onClick={toggleFunction}>Cancel</button>
<button onClick={yourSaveFunction}>Save</button>
</div>
) : (
<div className={styles.custom} onClick={toggleFunction}>
Create Custom URL
</div>
)}
</div>
)}
</section>
);
};
I would like to upload a image-file to storage of the firebase and put {title , content, createDate etc} in firestore.
but it seems that state.upload file prevents putting it in firestore.
this.setState({ uploadfile: "" })
The error says
FirebaseError: Function addDoc() called with invalid data. Unsupported field value: a custom File object (found in field uploadfile in document projects/c0hQXdRAgIe1lIzq1vTy)
class CreateProject extends Component {
state = {
title:'',
content:'',
uploadfile:'',
setImageUrl:'',
}
handleChange = (e) =>{
this.setState({
[e.target.id]: e.target.value
})
}
handleSubmit = (e) =>{
e.preventDefault();
this.setState({ uploadfile: "" })
this.props.createProject(this.state)
this.props.history.push('/')
}
onDrop = acceptedFiles => {
if (acceptedFiles.length > 0) {
this.setState({ uploadfile: acceptedFiles[0] })
}
}
handleSubmitImg = (e) =>{
e.preventDefault()
//this.props.sampleteFunction()
};
parseFile = (file) =>{
const updatedFile = new Blob([file], { type: file.type });
updatedFile.name = file.name;
return updatedFile;
}
onSubmit = (event) => {
event.preventDefault();
var updatedFile = this.state.uploadfile;
if (updatedFile === "") {
}
console.log("aaaaaaaaaaaa"+updatedFile)
const uploadTask = storage.ref(`/images/${updatedFile.name}`).put(updatedFile);
uploadTask.on(
firebase.storage.TaskEvent.STATE_CHANGED,
this.next,
this.error,
this.complete
);
};
next = snapshot => {
const percent = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
};
error = error => {
console.log(error);
};
complete = () => {
var updatedFile = this.state.uploadfile
storage
.ref("images")
.child(updatedFile.name)
.getDownloadURL()
.then(fireBaseUrl => {
this.setState({ setImageUrl: fireBaseUrl })
//this.state.setImageUrl(fireBaseUrl);
});
};
render() {
const maxSize = 3 * 1024 * 1024;
const dropzoneStyle = {
width: "100%",
height: "auto",
borderWidth: 2,
borderColor: "rgb(102, 102, 102)",
borderStyle: "dashed",
borderRadius: 5,
}
const {auth} = this.props
console.log("UP"+this.state.uploadfile );
if(!auth.uid) return <Redirect to="/signin" />
return (
<Dropzone
onDrop={this.onDrop}
accept="image/png,image/jpeg,image/gif,image/jpg"
inputContent={(files, extra) => (extra.reject ? 'Image files only' : 'Drag Files')}
styles={dropzoneStyle}
minSize={1}
maxSize={maxSize}
>
{({ getRootProps, getInputProps }) => (
<div className="container">
<form onSubmit={this.handleSubmit} className="white">
<h5 className="grey-text text-darken-3">
Create Project
</h5>
<div className="input-field">
<label htmlFor="title">Title</label>
<input type="text" id="title" onChange={this.handleChange}/>
</div>
<div className="input-field">
<label htmlFor="content">Project Content</label>
<textarea id="content" className="materialize-textarea" onChange={this.handleChange}></textarea>
</div>
<div className="input-field">
<button className="btn pink lighten-1 z-depth-0">Create</button>
</div>
</form>
<div {...getRootProps()}>
<input {...getInputProps()} />
<p>File Drag</p>
{this.state.uploadfile ? <p>Selected file: {this.state.uploadfile.name}</p> : null}
{this.state.uploadfile ? (<Thumb key={0} file={this.state.uploadfile } />) :null}
</div>
<form onSubmit={this.onSubmit}>
<button>Upload</button>
</form>
</div>
)}
</Dropzone>
)
}
}
const matchStateToProps = (state) => {
return{
auth: state.firebase.auth
}
}
const mapDispatchToProps = (dispatch) => {
return{
createProject: (project) => dispatch(createProject(project))
}
}
export default connect(matchStateToProps, mapDispatchToProps)(CreateProject)
Action
export const createProject = (project) => {
return (dispatch, getState, { getFirebase, getFirestore }) => {
// make async call to database
const firestore = getFirestore();
const profile = getState().firebase.profile;
const authorId = getState().firebase.auth.uid;
firestore.collection('projects').add({
...project,
authorUserName: profile.userName,
authorId: authorId,
createdAt: new Date()
}).then(() => {
dispatch({ type: 'CREATE_PROJECT', project})
}).catch((err) => {
dispatch({ type: 'CREATE_PROJECT_ERROR', err })
})
}
};
How Should I solve this problem?
After uploading an image by react state, this state seems to prevents putting props"project" in Action in Redux.
this.setState({ uploadfile: "" })
The error says
FirebaseError: Function addDoc() called with invalid data. Unsupported field value: a custom File object (found in field uploadfile in document projects/c0hQXdRAgIe1lIzq1vTy)
class CreateProject extends Component {
state = {
title:'',
content:'',
uploadfile:'',
setImageUrl:'',
}
handleChange = (e) =>{
this.setState({
[e.target.id]: e.target.value
})
}
handleSubmit = (e) =>{
e.preventDefault();
this.setState({ uploadfile: "" })
this.props.createProject(this.state)
this.props.history.push('/')
}
onDrop = acceptedFiles => {
if (acceptedFiles.length > 0) {
this.setState({ uploadfile: acceptedFiles[0] })
}
}
handleSubmitImg = (e) =>{
e.preventDefault()
//this.props.sampleteFunction()
};
parseFile = (file) =>{
const updatedFile = new Blob([file], { type: file.type });
updatedFile.name = file.name;
return updatedFile;
}
onSubmit = (event) => {
event.preventDefault();
var updatedFile = this.state.uploadfile;
if (updatedFile === "") {
}
console.log("aaaaaaaaaaaa"+updatedFile)
const uploadTask = storage.ref(`/images/${updatedFile.name}`).put(updatedFile);
uploadTask.on(
firebase.storage.TaskEvent.STATE_CHANGED,
this.next,
this.error,
this.complete
);
};
next = snapshot => {
const percent = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
};
error = error => {
console.log(error);
};
complete = () => {
var updatedFile = this.state.uploadfile
storage
.ref("images")
.child(updatedFile.name)
.getDownloadURL()
.then(fireBaseUrl => {
this.setState({ setImageUrl: fireBaseUrl })
//this.state.setImageUrl(fireBaseUrl);
});
};
render() {
const maxSize = 3 * 1024 * 1024;
const dropzoneStyle = {
width: "100%",
height: "auto",
borderWidth: 2,
borderColor: "rgb(102, 102, 102)",
borderStyle: "dashed",
borderRadius: 5,
}
const {auth} = this.props
console.log("UP"+this.state.uploadfile );
if(!auth.uid) return <Redirect to="/signin" />
return (
<Dropzone
onDrop={this.onDrop}
accept="image/png,image/jpeg,image/gif,image/jpg"
inputContent={(files, extra) => (extra.reject ? 'Image files only' : 'Drag Files')}
styles={dropzoneStyle}
minSize={1}
maxSize={maxSize}
>
{({ getRootProps, getInputProps }) => (
<div className="container">
<form onSubmit={this.handleSubmit} className="white">
<h5 className="grey-text text-darken-3">
Create Project
</h5>
<div className="input-field">
<label htmlFor="title">Title</label>
<input type="text" id="title" onChange={this.handleChange}/>
</div>
<div className="input-field">
<label htmlFor="content">Project Content</label>
<textarea id="content" className="materialize-textarea" onChange={this.handleChange}></textarea>
</div>
<div className="input-field">
<button className="btn pink lighten-1 z-depth-0">Create</button>
</div>
</form>
<div {...getRootProps()}>
<input {...getInputProps()} />
<p>File Drag</p>
{this.state.uploadfile ? <p>Selected file: {this.state.uploadfile.name}</p> : null}
{this.state.uploadfile ? (<Thumb key={0} file={this.state.uploadfile } />) :null}
</div>
<form onSubmit={this.onSubmit}>
<button>Upload</button>
</form>
</div>
)}
</Dropzone>
)
}
}
const matchStateToProps = (state) => {
return{
auth: state.firebase.auth
}
}
const mapDispatchToProps = (dispatch) => {
return{
createProject: (project) => dispatch(createProject(project))
}
}
export default connect(matchStateToProps, mapDispatchToProps)(CreateProject)
Action
export const createProject = (project) => {
return (dispatch, getState, { getFirebase, getFirestore }) => {
// make async call to database
const firestore = getFirestore();
const profile = getState().firebase.profile;
const authorId = getState().firebase.auth.uid;
firestore.collection('projects').add({
...project,
authorUserName: profile.userName,
authorId: authorId,
createdAt: new Date()
}).then(() => {
dispatch({ type: 'CREATE_PROJECT', project})
}).catch((err) => {
dispatch({ type: 'CREATE_PROJECT_ERROR', err })
})
}
};
I am making unit test for the component and also trying to make a test for hook but I can't seem to get it working. This is my hook. What do I need to change or do to fix this test?
import { useState } from 'react';
function UseToggleState (initialValue = false) {
const [state, setState] = useState(initialValue);
const toggle = () => setState(!state);
return [state, toggle];
};
export default UseToggleState
And this is the component I am using it.
export function Todo({ id, task, completed }) {
const classes = useStyles();
const dispatch = useContext(DispatchContext);
const [isEditing, toggle] = useToggleState(false);
if (isEditing) {
return (
<li
className={classes.Todo}
style={{ overflowY: "hidden" }}
onClick={() => toggle()}
>
<EditForm id={id} task={task} toggleEditForm={toggle} />
</li>
);
}
return (
<li
className={classes.Todo}
onClick={() => dispatch({ type: TOGGLE_TODO, id })}
>
<span
style={{
textDecoration: completed ? "line-through" : "",
color: completed ? "#A9ABAE" : "#34495e",
}}
>
{task}
</span>
<div className={classes.icons}>
<FontAwesomeIcon
icon={faPen}
size="1x"
onClick={(e) => {
e.stopPropagation();
toggle();
}}
/>{" "}
<FontAwesomeIcon
icon={faTrash}
size="1x"
color={"#c0392b"}
onClick={(e) => {
e.stopPropagation();
dispatch({ type: REMOVE_TODO, id });
}}
/>
</div>
</li>
);
}
And the test file is as follows. It keeps saying that toggle is not a function and I am not quite sure why it is doing that. Is there something I need to change differently to make it work?
describe("useToggleState", () => {
it("Initial toggle is true", () => {
const { result } = renderHook(() => UseToggleState(true))
act(() => {
result.current.toggle
})
expect(result.current.state).toBeTruthy()
})
it("Toggle is false", () => {
const { result } = renderHook(() => UseToggleState(false))
act(() => {
result.current.toggle
})
expect(result.current.state).toBeFalsy()
})
})
You test is supposed to be:
describe("useToggleState", () => {
it("Initial toggle is false", () => {
const { result } = renderHook(() => UseToggleState(true))
act(() => {
result.current[1]()
})
expect(result.current[0]).toBe(false)
})
it("Toggle is true", () => {
const { result } = renderHook(() => UseToggleState())
act(() => {
result.current[1]()
})
expect(result.current[0]).toBe(true)
})
})