I want to create a form that creates a card that I can edit. Whenever I try to click on the edit button to update the card, the information that was made doesn't transfer over into the new screen. When I try to edit it anyway, I get a 400 message saying
Failed to load resource: the server responded with a status of 400 (Bad Request)
I tried changing the dates to integers and Floats, but nothing. When I try to change the ID to experienceID in the Experience page variable under UseParams, I get more error messages. I have checked and double-checked my mutations, resolvers, typeDefs, etc., but I still can't seem to get it working. I also tried using AI to fix the problem, and it suggested that I change all of my dates from strings to integers, but that didn't help with my 'update a form' problem..
I got a correction request to state what I want (always have been on the first line), show the shortest amount of code (I did that), and state the problem (I did).
ExperiencePage.js
import { useMutation, useQuery } from "@apollo/client";
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { GET_EXPERIENCE } from "../graphql/queries/experience.query.js";
import { UPDATE_EXPERIENCE } from "../graphql/mutations/experience.mutations.js";
import toast from "react-hot-toast";
const ExperiencePage = () => {
const { id } = useParams();
const { loading, data} = useQuery(GET_EXPERIENCE, {
variables: { id: id },
});
console.log("UseQuery:", data)
const [updateExperience] = useMutation(UPDATE_EXPERIENCE);
const [formData, setFormData] = useState({
description: data?.experience?.description || "",
title: data?.experience?.title || "",
type: data?.experience?.type || "",
startDate: data?.experience?.startDate || "",
endDate: data?.experience?.endDate || "",
});
const handleSubmit = async (e) => {
e.preventDefault();
try {
await updateExperience({
variables: {
input: {
...formData,
experienceID: id,
startDate: formData.startDate ? new Date(formData.startDate).getTime() : null,
endDate: formData.endDate ? new Date(formData.endDate).getTime() : null,
},
},
});
toast.success("Experience updated successfully");
} catch (error) {
toast.error(error.message || "Update failed");
}
};
const handleInputChange = (e) => {
const { name, value } = e.target;
setFormData((prevFormData) => ({
...prevFormData,
[name]: value,
}));
console.log(formData)
};
useEffect(() => {
if (data && data.experience) {
setFormData({
description: data.experience.description || "",
title: data.experience.title || "",
type: data.experience.type || "",
startDate: data.experience.startDate
? new Date(Number(data.experience.startDate)).toISOString().slice(0, 10)
: "",
endDate: data.experience.endDate
? new Date(Number(data.experience.endDate)).toISOString().slice(0, 10)
: "",
});
}
}, [data]);
if (loading) return <p>Loading...</p>
return (
<div>
{/* */}
<form className="w-full max-w-lg flex flex-col gap-5 px-3" onSubmit={handleSubmit}>
<div className="space-y-12">
<div className="border-b border-gray-900/10 pb-12">
<h2 className="text-base/7 font-semibold text-gray-900">Update Experience Form</h2>
<div className="mt-10 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div className="sm:col-span-4">
<label htmlFor="title" className="block text-sm/6 font-medium text-gray-900">
Title
</label>
<div className="mt-2">
<div className="flex items-center rounded-md bg-white pl-3 outline-1 -outline-offset-1 outline-gray-300 focus-within:outline-2 focus-within:-outline-offset-2 focus-within:outline-indigo-600">
<input
className="block min-w-0 grow py-2 pr-3 pl-1 text-base text-gray-900 placeholder:text-gray-400 focus:outline-none sm:text-sm/6"
id="title"
name="title"
type="text"
placeholder="Title"
value={formData.title}
onChange={handleInputChange}
/>
</div>
</div>
</div>
<div className="col-span-full">
<label htmlFor="description" className="block text-sm/6 font-medium text-gray-900">
Description
</label>
<div className="mt-2">
<textarea
id="description"
name="description"
rows={3}
className="block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6"
placeholder="Write a description of your experience: Awards, goals achieved, lessons learned, etc. Make sure to use keywords you want to be analyzed."
value={formData.description}
onChange={handleInputChange}
/>
</div>
<div className="sm:col-span-3">
<label htmlFor="type" className="block text-sm/6 font-medium text-gray-900">
Type
</label>
<div className="mt-2 grid grid-cols-1">
<select
className="col-start-1 row-start-1 w-full appearance-none rounded-md bg-white py-1.5 pr-8 pl-3 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6"
id="type"
name="type"
onChange={handleInputChange}
value={formData.type}
>
<option value="">Type</option>
<option value="education">Education</option>
<option value="employment">Employment</option>
<option value="internship">Internship</option>
<option value="volunteer">Volunteer</option>
</select>
</div>
</div>
<div className="w-full flex-1">
<label className="block text-sm/6 font-medium text-gray-900" htmlFor="startDate">
Start Date
</label>
<input
type="date"
name="startDate"
id="startDate"
className="block min-w-0 grow py-1.5 pr-3 pl-1 text-base text-gray-900 placeholder:text-gray-400 focus:outline-none sm:text-sm/6"
placeholder="Select start date"
value={formData.startDate}
onChange={handleInputChange}
/>
<label className="block text-sm/6 font-medium text-gray-900" htmlFor="endDate">
End Date
</label>
<input
type="date"
name="endDate"
id="endDate"
className="block min-w-0 grow py-1.5 pr-3 pl-1 text-base text-gray-900 placeholder:text-gray-400 focus:outline-none sm:text-sm/6"
placeholder="Select end date"
value={formData.endDate}
onChange={handleInputChange}
/>
</div>
<button
className="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm/6 font-semibold text-white shadow-xs hover:bg-indigo-500 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
type="submit"
>
Update Experience
</button>
<button type="button" className="text-sm/6 font-semibold text-gray-900">
Cancel
</button>
</div>
</div>
</div>
</div>
</form>
</div>
);
};
export default ExperiencePage;
Query, Mutation, Resolve, TypeDef
Query:
export const GET_EXPERIENCE = gql`
query GetExperience($id: ID!) {
experience(experienceID: $id) {
_id
title
type
description
startDate
endDate
}
user {
email
}
}
`;
Mutation:
export const UPDATE_EXPERIENCE = gql`
mutation UpdateExperience($input: UpdateExperienceInput!) {
updateExperience(input: $input) {
experienceID
title
type
description
startDate
endDate
}
}
`;
Resolvers:
updateExperience: async (_, { input }) => {
try {
const updatedExperience = await Experience.findByIdAndUpdate(input.experienceID, input, {
new: true,
});
return updatedExperience;
} catch (err) {
console.error("Error updating Experience:", err);
throw new Error("Error updating Experience");
}
},
TypeDef:
type Experience {
_id: ID!
userId: ID!
description: String!,
title: String!,
type: String,
startDate: Date,
endDate: Float,
}
type Query {
experiences: [Experience!]
experience(experienceID: ID!): Experience
}
type Mutation {
addExperience(input: AddExperienceInput!): Experience!
updateExperience(input: UpdateExperienceInput!): Experience!
deleteExperience(experienceID: ID!): Experience!
}
input AddExperienceInput {
description: String!,
title: String!,
type: String,
startDate: Date,
endDate: Date,
}
input UpdateExperienceInput {
experienceID: ID!
description: String,
title: String,
type: String,
startDate: Date,
endDate: Date,
}