After successful testing on my local environment, I encountered strange behavior when the code was pushed to the main branch and deployed on Vercel with a Postgres DB. While creating projects and skills worked without any issues, deleting items resulted in inconsistencies. Despite being deleted from the database, the site failed to update properly, causing additional projects to disappear even though they still existed in the DB.
skill-view-card.tsx
'use client'
import { deleteSkill, createProject, deleteProject } from '@/app/lib/actions';
import { Button } from '@nextui-org/react';
import { TrashIcon } from '@heroicons/react/20/solid';
export default function SkillViewCard({ skills, projects }: { skills: string; projects: string }) { // after performing certain actions, outdated data is fetched
const skillsParsed = JSON.parse(skills); // refetching required
const projectsParsed = JSON.parse(projects);
function toTitleCase(str: string) {
return str.replace(/\w\S*/g, (text: string) => text.charAt(0).toUpperCase() + text.substring(1).toLowerCase());
}
return (
<div className="p-8 border w-full h-full shadow-lg rounded-md bg-white">
<div className="columns-2">
<div className="text-left text-xl font-bold">
{toTitleCase(skillsParsed?.description) || 'No description available'}
</div>
<Button onClick={() => { deleteSkill(skillsParsed.id);}}>
<TrashIcon className="h-4 w-4 content-right" />
</Button>
</div>
<div className="columns-1">
<fieldset>
{projectsParsed && projectsParsed.length > 0 ? (
projectsParsed
.filter((project: { skill_id: string }) => project.skill_id === skillsParsed?.id)
.map((project: { title: string, id: number }) => (
<div key={project.id}>
<div>{project.title}</div>
<Button onClick={() => { deleteProject(project.id);}}>
<p>Delete</p>
</Button>
</div>
))
) : (
<p className="text-gray-500">No projects available</p>
)}
</fieldset>
</div>
<div className="columns-2"></div>
<input
type="text"
placeholder="Enter project title"
className="border rounded-md p-2 w-half"
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
const formData = new FormData();
formData.append('title', e.currentTarget.value);
formData.append('skill_id', skillsParsed.id);
createProject(formData);
e.currentTarget.value = '';
}
}}
/>
</div>
);
}
@/app/lib/actions
'use server';
import { sql } from '@vercel/postgres';
import { redirect } from 'next/navigation';
export async function createSkill(formData: FormData) {
const skillDescription = formData.get('skill') as string | null;
await sql`
INSERT INTO skills (description)
VALUES (${skillDescription || ''})
`;
redirect('/test-page?refetch=true'); // data needs to be refetched
}
export async function deleteSkill(id: number) {
await sql`
DELETE FROM skills WHERE id = ${id}
`;
redirect('/test-page?refetch=true');
}
export async function createProject(formData: FormData) {
const projectTitle = formData.get('title') as string | null;
const skillId = formData.get('skill_id') ? parseInt(formData.get('skill_id') as string, 10) : null;
await sql`
INSERT INTO projects (title, skill_id)
VALUES (${projectTitle || ''}, ${skillId || ''})
`;
redirect('/test-page?refetch=true');
}
export async function deleteProject(id: number) {
await sql`
DELETE FROM projects WHERE id = ${id}
`;
redirect('/test-page?refetch=true');
}