diff --git a/apps/frontend/components/builder/forms/projects-form.tsx b/apps/frontend/components/builder/forms/projects-form.tsx index 16ca653a..ff723537 100644 --- a/apps/frontend/components/builder/forms/projects-form.tsx +++ b/apps/frontend/components/builder/forms/projects-form.tsx @@ -8,6 +8,22 @@ import { RichTextEditor } from '@/components/ui/rich-text-editor'; import { Project } from '@/components/dashboard/resume-component'; import { Plus, Trash2, Github, Globe } from 'lucide-react'; import { useTranslations } from '@/lib/i18n'; +import { + DndContext, + closestCenter, + PointerSensor, + KeyboardSensor, + useSensor, + useSensors, + DragEndEvent, +} from '@dnd-kit/core'; +import { + arrayMove, + SortableContext, + sortableKeyboardCoordinates, + verticalListSortingStrategy, +} from '@dnd-kit/sortable'; +import { DraggableListItem } from '../draggable-list-item'; interface ProjectsFormProps { data: Project[]; @@ -17,6 +33,30 @@ interface ProjectsFormProps { export const ProjectsForm: React.FC = ({ data, onChange }) => { const { t } = useTranslations(); + // Configure drag-and-drop sensors + const sensors = useSensors( + useSensor(PointerSensor), + useSensor(KeyboardSensor, { + coordinateGetter: sortableKeyboardCoordinates, + }) + ); + + // Handler for drag end event + const handleDragEnd = (event: DragEndEvent) => { + const { active, over } = event; + + if (!over || active.id === over.id) return; + + const oldIndex = data.findIndex((item) => item.id === active.id); + const newIndex = data.findIndex((item) => item.id === over.id); + + if (oldIndex === -1 || newIndex === -1) return; + + // Reorder the array using arrayMove from @dnd-kit + const reordered = arrayMove(data, oldIndex, newIndex); + onChange(reordered); + }; + const handleAdd = () => { const newId = Math.max(...data.map((d) => d.id), 0) + 1; onChange([ @@ -98,121 +138,9 @@ export const ProjectsForm: React.FC = ({ data, onChange }) => -
- {data.map((item) => ( -
- - -
-
- - handleChange(item.id, 'name', e.target.value)} - placeholder={t('builder.forms.projects.placeholders.projectName')} - className="rounded-none border-black bg-white" - /> -
-
- - handleChange(item.id, 'role', e.target.value)} - placeholder={t('builder.forms.projects.placeholders.role')} - className="rounded-none border-black bg-white" - /> -
-
- - handleChange(item.id, 'years', e.target.value)} - placeholder={t('builder.forms.projects.placeholders.years')} - className="rounded-none border-black bg-white" - /> -
-
- - handleChange(item.id, 'github', e.target.value)} - placeholder={t('builder.forms.projects.placeholders.github')} - className="rounded-none border-black bg-white" - /> -
-
- - handleChange(item.id, 'website', e.target.value)} - placeholder={t('builder.forms.projects.placeholders.website')} - className="rounded-none border-black bg-white" - /> -
-
- -
-
- - -
- {item.description?.map((desc, idx) => ( -
-
- handleDescriptionChange(item.id, idx, html)} - placeholder={t('builder.forms.projects.placeholders.description')} - minHeight="60px" - /> -
- -
- ))} -
-
- ))} - - {data.length === 0 && ( -
-

+ {data.length === 0 ? ( +

+

{t('builder.genericItemForm.noEntries', { label: t('resume.sections.projects') })}

- )} -
+ ) : ( + + item.id)} + strategy={verticalListSortingStrategy} + > +
+ {data.map((item) => ( + +
+ + +
+
+ + handleChange(item.id, 'name', e.target.value)} + placeholder={t('builder.forms.projects.placeholders.projectName')} + className="rounded-none border-black bg-white" + /> +
+
+ + handleChange(item.id, 'role', e.target.value)} + placeholder={t('builder.forms.projects.placeholders.role')} + className="rounded-none border-black bg-white" + /> +
+
+ + handleChange(item.id, 'years', e.target.value)} + placeholder={t('builder.forms.projects.placeholders.years')} + className="rounded-none border-black bg-white" + /> +
+
+ + handleChange(item.id, 'github', e.target.value)} + placeholder={t('builder.forms.projects.placeholders.github')} + className="rounded-none border-black bg-white" + /> +
+
+ + handleChange(item.id, 'website', e.target.value)} + placeholder={t('builder.forms.projects.placeholders.website')} + className="rounded-none border-black bg-white" + /> +
+
+ +
+
+ + +
+ {item.description?.map((desc, idx) => ( +
+
+ handleDescriptionChange(item.id, idx, html)} + placeholder={t('builder.forms.projects.placeholders.description')} + minHeight="60px" + /> +
+ +
+ ))} +
+
+
+ ))} +
+
+
+ )}
); };