From 48dd1a14cac0670c8292cf3a4ab22f8bdfc4d783 Mon Sep 17 00:00:00 2001 From: Shukla213 Date: Wed, 24 Jun 2026 13:21:25 +0530 Subject: [PATCH] feat: add drag and drop resume section reordering --- package-lock.json | 127 +++++++++++++++++- package.json | 3 + .../components/ResumeForm/SortableForm.tsx | 46 +++++++ src/app/components/ResumeForm/index.tsx | 94 +++++++++++-- src/app/lib/redux/hooks.tsx | 2 +- src/app/lib/redux/settingsSlice.ts | 9 ++ 6 files changed, 269 insertions(+), 12 deletions(-) create mode 100644 src/app/components/ResumeForm/SortableForm.tsx diff --git a/package-lock.json b/package-lock.json index 4cb0ec1..56f27b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "open-resume", "version": "0.1.0", "dependencies": { + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", "@heroicons/react": "^2.0.18", "@react-pdf/renderer": "^3.1.10", "@reduxjs/toolkit": "^1.9.5", @@ -96,6 +99,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.1.tgz", "integrity": "sha512-Hkqu7J4ynysSXxmAahpN1jjRwVJ+NdpraFLIWflgjpVob3KNyK3/tIUc7Q7szed8WMp0JNa7Qtd1E9Oo22F9gA==", "dev": true, + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.21.4", @@ -694,6 +698,60 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@dnd-kit/accessibility": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz", + "integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/core": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", + "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@dnd-kit/accessibility": "^3.1.1", + "@dnd-kit/utilities": "^3.2.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/sortable": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-10.0.0.tgz", + "integrity": "sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==", + "license": "MIT", + "dependencies": { + "@dnd-kit/utilities": "^3.2.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@dnd-kit/core": "^6.3.0", + "react": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/utilities": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz", + "integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -1639,6 +1697,7 @@ "version": "1.9.5", "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.5.tgz", "integrity": "sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ==", + "peer": true, "dependencies": { "immer": "^9.0.21", "redux": "^4.2.1", @@ -1984,6 +2043,7 @@ "version": "18.2.4", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.4.tgz", "integrity": "sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==", + "peer": true, "dependencies": { "@types/react": "*" } @@ -2156,6 +2216,7 @@ "version": "8.8.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2670,6 +2731,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001489", "electron-to-chromium": "^1.4.411", @@ -3630,6 +3692,7 @@ "version": "8.41.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz", "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", @@ -3806,6 +3869,7 @@ "version": "2.27.5", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "peer": true, "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", @@ -7403,6 +7467,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -7594,6 +7659,7 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "peer": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -7667,6 +7733,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -7690,6 +7757,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" @@ -7717,6 +7785,7 @@ "version": "8.0.7", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.7.tgz", "integrity": "sha512-1vRQuCQI5Y2uNmrMXg81RXKiBHY3jBzvCvNmZF437O/Z9/pZ+ba2uYHbemYXb3g8rjsacBGo+/wmfrQKzMhJsg==", + "peer": true, "dependencies": { "@babel/runtime": "^7.12.1", "@types/hoist-non-react-statics": "^3.3.1", @@ -7809,6 +7878,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "peer": true, "dependencies": { "@babel/runtime": "^7.9.2" } @@ -8595,6 +8665,7 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz", "integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==", + "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -8841,6 +8912,7 @@ "version": "5.0.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9329,6 +9401,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.1.tgz", "integrity": "sha512-Hkqu7J4ynysSXxmAahpN1jjRwVJ+NdpraFLIWflgjpVob3KNyK3/tIUc7Q7szed8WMp0JNa7Qtd1E9Oo22F9gA==", "dev": true, + "peer": true, "requires": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.21.4", @@ -9781,6 +9854,42 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@dnd-kit/accessibility": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz", + "integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==", + "requires": { + "tslib": "^2.0.0" + } + }, + "@dnd-kit/core": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", + "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", + "peer": true, + "requires": { + "@dnd-kit/accessibility": "^3.1.1", + "@dnd-kit/utilities": "^3.2.2", + "tslib": "^2.0.0" + } + }, + "@dnd-kit/sortable": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-10.0.0.tgz", + "integrity": "sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==", + "requires": { + "@dnd-kit/utilities": "^3.2.2", + "tslib": "^2.0.0" + } + }, + "@dnd-kit/utilities": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz", + "integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==", + "requires": { + "tslib": "^2.0.0" + } + }, "@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -10501,6 +10610,7 @@ "version": "1.9.5", "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.5.tgz", "integrity": "sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ==", + "peer": true, "requires": { "immer": "^9.0.21", "redux": "^4.2.1", @@ -10808,6 +10918,7 @@ "version": "18.2.4", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.4.tgz", "integrity": "sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==", + "peer": true, "requires": { "@types/react": "*" } @@ -10931,7 +11042,8 @@ "acorn": { "version": "8.8.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==" + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "peer": true }, "acorn-globals": { "version": "7.0.1", @@ -11290,6 +11402,7 @@ "version": "4.21.7", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.7.tgz", "integrity": "sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==", + "peer": true, "requires": { "caniuse-lite": "^1.0.30001489", "electron-to-chromium": "^1.4.411", @@ -12008,6 +12121,7 @@ "version": "8.41.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz", "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==", + "peer": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", @@ -12142,6 +12256,7 @@ "version": "2.27.5", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "peer": true, "requires": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", @@ -14725,6 +14840,7 @@ "version": "8.4.24", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", + "peer": true, "requires": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -14838,6 +14954,7 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "peer": true, "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -14884,6 +15001,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, "requires": { "loose-envify": "^1.1.0" } @@ -14901,6 +15019,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "peer": true, "requires": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" @@ -14921,6 +15040,7 @@ "version": "8.0.7", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.7.tgz", "integrity": "sha512-1vRQuCQI5Y2uNmrMXg81RXKiBHY3jBzvCvNmZF437O/Z9/pZ+ba2uYHbemYXb3g8rjsacBGo+/wmfrQKzMhJsg==", + "peer": true, "requires": { "@babel/runtime": "^7.12.1", "@types/hoist-non-react-statics": "^3.3.1", @@ -14977,6 +15097,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "peer": true, "requires": { "@babel/runtime": "^7.9.2" } @@ -15522,6 +15643,7 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz", "integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==", + "peer": true, "requires": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -15714,7 +15836,8 @@ "typescript": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==" + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "peer": true }, "unbox-primitive": { "version": "1.0.2", diff --git a/package.json b/package.json index 49258b9..80c4372 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,9 @@ "test:ci": "jest --ci" }, "dependencies": { + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", "@heroicons/react": "^2.0.18", "@react-pdf/renderer": "^3.1.10", "@reduxjs/toolkit": "^1.9.5", diff --git a/src/app/components/ResumeForm/SortableForm.tsx b/src/app/components/ResumeForm/SortableForm.tsx new file mode 100644 index 0000000..76bfb5f --- /dev/null +++ b/src/app/components/ResumeForm/SortableForm.tsx @@ -0,0 +1,46 @@ +"use client"; + +import { ReactNode } from "react"; +import { useSortable } from "@dnd-kit/sortable"; +import { CSS } from "@dnd-kit/utilities"; + +interface SortableFormProps { + id: string; + children: ReactNode; +} + +export const SortableForm = ({ + id, + children, +}: SortableFormProps) => { + const { + attributes, + listeners, + setNodeRef, + transform, + transition, + } = useSortable({ id }); + + const style = { + transform: CSS.Transform.toString(transform), + transition, + }; + + return ( +
+
+ ☰ Drag +
+ + {children} +
+ ); +}; \ No newline at end of file diff --git a/src/app/components/ResumeForm/index.tsx b/src/app/components/ResumeForm/index.tsx index 2f0d8c7..203e975 100644 --- a/src/app/components/ResumeForm/index.tsx +++ b/src/app/components/ResumeForm/index.tsx @@ -1,11 +1,20 @@ "use client"; + import { useState } from "react"; + import { useAppSelector, + useAppDispatch, useSaveStateToLocalStorageOnChange, useSetInitialStore, } from "lib/redux/hooks"; -import { ShowForm, selectFormsOrder } from "lib/redux/settingsSlice"; + +import { + ShowForm, + selectFormsOrder, + setFormsOrder, +} from "lib/redux/settingsSlice"; + import { ProfileForm } from "components/ResumeForm/ProfileForm"; import { WorkExperiencesForm } from "components/ResumeForm/WorkExperiencesForm"; import { EducationsForm } from "components/ResumeForm/EducationsForm"; @@ -13,10 +22,26 @@ import { ProjectsForm } from "components/ResumeForm/ProjectsForm"; import { SkillsForm } from "components/ResumeForm/SkillsForm"; import { ThemeForm } from "components/ResumeForm/ThemeForm"; import { CustomForm } from "components/ResumeForm/CustomForm"; +import { SortableForm } from "components/ResumeForm/SortableForm"; + import { FlexboxSpacer } from "components/FlexboxSpacer"; import { cx } from "lib/cx"; -const formTypeToComponent: { [type in ShowForm]: () => JSX.Element } = { +import { + DndContext, + closestCenter, + DragEndEvent, +} from "@dnd-kit/core"; + +import { + SortableContext, + verticalListSortingStrategy, + arrayMove, +} from "@dnd-kit/sortable"; + +const formTypeToComponent: { + [type in ShowForm]: () => JSX.Element; +} = { workExperiences: WorkExperiencesForm, educations: EducationsForm, projects: ProjectsForm, @@ -28,28 +53,79 @@ export const ResumeForm = () => { useSetInitialStore(); useSaveStateToLocalStorageOnChange(); + const dispatch = useAppDispatch(); const formsOrder = useAppSelector(selectFormsOrder); + const [isHover, setIsHover] = useState(false); + const handleDragEnd = (event: DragEndEvent) => { + const { active, over } = event; + + if (!over) return; + + if (active.id !== over.id) { + const oldIndex = formsOrder.indexOf( + active.id as ShowForm + ); + + const newIndex = formsOrder.indexOf( + over.id as ShowForm + ); + + dispatch( + setFormsOrder( + arrayMove(formsOrder, oldIndex, newIndex) + ) + ); + } + }; + return (
setIsHover(true)} onMouseLeave={() => setIsHover(false)} >
- {formsOrder.map((form) => { - const Component = formTypeToComponent[form]; - return ; - })} + + + + {formsOrder.map((form) => { + const Component = + formTypeToComponent[form]; + + return ( + + + + ); + })} + + +
- + +
); -}; +}; \ No newline at end of file diff --git a/src/app/lib/redux/hooks.tsx b/src/app/lib/redux/hooks.tsx index 74803d6..e669437 100644 --- a/src/app/lib/redux/hooks.tsx +++ b/src/app/lib/redux/hooks.tsx @@ -55,5 +55,5 @@ export const useSetInitialStore = () => { ) as Settings; dispatch(setSettings(mergedSettingsState)); } - }, []); + }, [dispatch]); }; diff --git a/src/app/lib/redux/settingsSlice.ts b/src/app/lib/redux/settingsSlice.ts index 7e8fa83..f574871 100644 --- a/src/app/lib/redux/settingsSlice.ts +++ b/src/app/lib/redux/settingsSlice.ts @@ -111,6 +111,14 @@ export const settingsSlice = createSlice({ swapFormOrder(pos, newPos); } }, + + setFormsOrder: ( + draft, + action: PayloadAction +) => { + draft.formsOrder = action.payload; +}, + changeShowBulletPoints: ( draft, action: PayloadAction<{ @@ -132,6 +140,7 @@ export const { changeShowForm, changeFormHeading, changeFormOrder, + setFormsOrder, changeShowBulletPoints, setSettings, } = settingsSlice.actions;