diff --git a/backend/src/application/services/positionService.ts b/backend/src/application/services/positionService.ts index 1332491..576cc36 100644 --- a/backend/src/application/services/positionService.ts +++ b/backend/src/application/services/positionService.ts @@ -1,65 +1,70 @@ import { PrismaClient } from '@prisma/client'; -import { Position } from '../../domain/models/Position'; const prisma = new PrismaClient(); const calculateAverageScore = (interviews: any[]) => { - if (interviews.length === 0) return 0; - const totalScore = interviews.reduce((acc, interview) => acc + (interview.score || 0), 0); - return totalScore / interviews.length; + if (interviews.length === 0) return 0; + const totalScore = interviews.reduce( + (acc, interview) => acc + (interview.score || 0), + 0, + ); + return totalScore / interviews.length; }; export const getCandidatesByPositionService = async (positionId: number) => { - try { - const applications = await prisma.application.findMany({ - where: { positionId }, - include: { - candidate: true, - interviews: true, - interviewStep: true - } - }); + try { + const applications = await prisma.application.findMany({ + where: { positionId }, + include: { + candidate: true, + interviews: true, + interviewStep: true, + }, + }); - return applications.map(app => ({ - fullName: `${app.candidate.firstName} ${app.candidate.lastName}`, - currentInterviewStep: app.interviewStep.name, - averageScore: calculateAverageScore(app.interviews) - })); - } catch (error) { - console.error('Error retrieving candidates by position:', error); - throw new Error('Error retrieving candidates by position'); - } + return applications.map((app) => ({ + candidateId: app.candidateId, + applicationId: app.id, + fullName: `${app.candidate.firstName} ${app.candidate.lastName}`, + currentInterviewStep: app.interviewStep.name, + averageScore: calculateAverageScore(app.interviews), + })); + } catch (error) { + console.error('Error retrieving candidates by position:', error); + throw new Error('Error retrieving candidates by position'); + } }; export const getInterviewFlowByPositionService = async (positionId: number) => { - const positionWithInterviewFlow = await prisma.position.findUnique({ - where: { id: positionId }, + const positionWithInterviewFlow = await prisma.position.findUnique({ + where: { id: positionId }, + include: { + interviewFlow: { include: { - interviewFlow: { - include: { - interviewSteps: true - } - } - } - }); + interviewSteps: true, + }, + }, + }, + }); - if (!positionWithInterviewFlow) { - throw new Error('Position not found'); - } + if (!positionWithInterviewFlow) { + throw new Error('Position not found'); + } - // Formatear la respuesta para incluir el nombre de la posición y el flujo de entrevistas - return { - positionName: positionWithInterviewFlow.title, - interviewFlow: { - id: positionWithInterviewFlow.interviewFlow.id, - description: positionWithInterviewFlow.interviewFlow.description, - interviewSteps: positionWithInterviewFlow.interviewFlow.interviewSteps.map(step => ({ - id: step.id, - interviewFlowId: step.interviewFlowId, - interviewTypeId: step.interviewTypeId, - name: step.name, - orderIndex: step.orderIndex - })) - } - }; -}; \ No newline at end of file + // Formatear la respuesta para incluir el nombre de la posición y el flujo de entrevistas + return { + positionName: positionWithInterviewFlow.title, + interviewFlow: { + id: positionWithInterviewFlow.interviewFlow.id, + description: positionWithInterviewFlow.interviewFlow.description, + interviewSteps: + positionWithInterviewFlow.interviewFlow.interviewSteps.map((step) => ({ + id: step.id, + interviewFlowId: step.interviewFlowId, + interviewTypeId: step.interviewTypeId, + name: step.name, + orderIndex: step.orderIndex, + })), + }, + }; +}; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 75428c1..0b6351e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,6 +8,9 @@ "name": "frontend", "version": "0.1.0", "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.6.0", + "@fortawesome/free-solid-svg-icons": "^6.6.0", + "@fortawesome/react-fontawesome": "^0.2.2", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -21,6 +24,8 @@ "react-bootstrap": "^2.10.2", "react-bootstrap-icons": "^1.11.4", "react-datepicker": "^6.9.0", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", "react-dom": "^18.3.1", "react-router-dom": "^6.23.1", "react-scripts": "5.0.1", @@ -2684,6 +2689,48 @@ "integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==", "license": "MIT" }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.6.0.tgz", + "integrity": "sha512-xyX0X9mc0kyz9plIyryrRbl7ngsA9jz77mCZJsUkLl+ZKs0KWObgaEBoSgQiYWAsSmjz/yjl0F++Got0Mdp4Rw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.6.0.tgz", + "integrity": "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg==", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.6.0.tgz", + "integrity": "sha512-IYv/2skhEDFc2WGUcqvFJkeK39Q+HyPf5GHUrT/l2pKbtgEIv1al1TKd6qStR5OIwQdN1GZP54ci3y4mroJWjA==", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz", + "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.3" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -3339,6 +3386,21 @@ "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" } }, + "node_modules/@react-dnd/asap": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz", + "integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==" + }, + "node_modules/@react-dnd/invariant": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz", + "integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==" + }, + "node_modules/@react-dnd/shallowequal": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz", + "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==" + }, "node_modules/@remix-run/router": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.1.tgz", @@ -7092,6 +7154,16 @@ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "license": "MIT" }, + "node_modules/dnd-core": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz", + "integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==", + "dependencies": { + "@react-dnd/asap": "^5.0.1", + "@react-dnd/invariant": "^4.0.1", + "redux": "^4.2.0" + } + }, "node_modules/dns-packet": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", @@ -9275,6 +9347,19 @@ "he": "bin/he" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -14429,6 +14514,43 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/react-dnd": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz", + "integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==", + "dependencies": { + "@react-dnd/invariant": "^4.0.1", + "@react-dnd/shallowequal": "^4.0.1", + "dnd-core": "^16.0.1", + "fast-deep-equal": "^3.1.3", + "hoist-non-react-statics": "^3.3.2" + }, + "peerDependencies": { + "@types/hoist-non-react-statics": ">= 3.3.1", + "@types/node": ">= 12", + "@types/react": ">= 16", + "react": ">= 16.14" + }, + "peerDependenciesMeta": { + "@types/hoist-non-react-statics": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-dnd-html5-backend": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz", + "integrity": "sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==", + "dependencies": { + "dnd-core": "^16.0.1" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -14673,6 +14795,14 @@ "node": ">=8" } }, + "node_modules/redux": { + "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==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", @@ -16324,10 +16454,9 @@ "license": "MIT" }, "node_modules/tailwindcss": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", - "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==", - "license": "MIT", + "version": "3.4.14", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.14.tgz", + "integrity": "sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", diff --git a/frontend/package.json b/frontend/package.json index 3856c00..62731a5 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -3,6 +3,9 @@ "version": "0.1.0", "private": true, "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.6.0", + "@fortawesome/free-solid-svg-icons": "^6.6.0", + "@fortawesome/react-fontawesome": "^0.2.2", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -16,6 +19,8 @@ "react-bootstrap": "^2.10.2", "react-bootstrap-icons": "^1.11.4", "react-datepicker": "^6.9.0", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", "react-dom": "^18.3.1", "react-router-dom": "^6.23.1", "react-scripts": "5.0.1", diff --git a/frontend/src/App.js b/frontend/src/App.js index 3f27809..1a5c7a8 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,9 +1,10 @@ -import React from 'react'; import 'bootstrap/dist/css/bootstrap.min.css'; -import { BrowserRouter, Routes, Route } from 'react-router-dom'; +import React from 'react'; +import { BrowserRouter, Route, Routes } from 'react-router-dom'; +import AddCandidate from './components/AddCandidateForm'; +import InterviewProcess from './components/InterviewProcess/InterviewProcess'; +import Positions from './components/Positions'; import RecruiterDashboard from './components/RecruiterDashboard'; -import AddCandidate from './components/AddCandidateForm'; -import Positions from './components/Positions'; const App = () => { return ( @@ -12,9 +13,10 @@ const App = () => { } /> } /> {/* Agrega esta línea */} } /> + } /> ); }; -export default App; \ No newline at end of file +export default App; diff --git a/frontend/src/components/InterviewProcess/Candidate.tsx b/frontend/src/components/InterviewProcess/Candidate.tsx new file mode 100644 index 0000000..84a9c9d --- /dev/null +++ b/frontend/src/components/InterviewProcess/Candidate.tsx @@ -0,0 +1,51 @@ +/** + * This code was generated by Builder.io + */ +import React from "react"; +import { Card } from "react-bootstrap"; +import { useDrag } from "react-dnd"; + +export interface ICandidateProps { + candidateId: string; + applicationId: string; + fullName: string; + currentInterviewStep: string; + averageScore: number; +} + +const Candidate: React.FC = ({ + candidateId, + fullName, + averageScore, +}) => { + const [{ isDragging }, drag] = useDrag(() => ({ + type: "CANDIDATE", + item: { candidateId }, + collect: (monitor) => ({ + isDragging: !!monitor.isDragging(), + }), + })); + + return ( + + +

{fullName}

+
+ {[...Array(5)].map((_, index) => ( + + + + ); +}; + +export default Candidate; diff --git a/frontend/src/components/InterviewProcess/InterviewProcess.tsx b/frontend/src/components/InterviewProcess/InterviewProcess.tsx new file mode 100644 index 0000000..e0e3ebe --- /dev/null +++ b/frontend/src/components/InterviewProcess/InterviewProcess.tsx @@ -0,0 +1,123 @@ +/** + * This code was generated by Builder.io + */ +import { faArrowLeft } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import React, { useEffect, useState } from "react"; +import { Button, Col, Container, Row } from "react-bootstrap"; +import { DndProvider } from "react-dnd"; +import { HTML5Backend } from "react-dnd-html5-backend"; +import { useNavigate, useParams } from "react-router-dom"; +import { ICandidateProps } from "./Candidate"; +import InterviewStage from "./InterviewStage"; + +export interface IInterviewStep { + id: number; + interviewFlowId: number; + interviewTypeId: number; + name: string; + orderIndex: number; +} + +export interface IInterviewFlow { + id: number; + description: string; + interviewSteps: IInterviewStep[]; +} + +export interface IInterviewStage { + positionName: string; + interviewFlow: IInterviewFlow; +} + +const InterviewProcess: React.FC = () => { + const { id } = useParams<{ id: string }>(); + const navigate = useNavigate(); + const [interviewStages, setInterviewStages] = useState(); + const [candidates, setCandidates] = useState([]); + + useEffect(() => { + const fetchCandidates = async () => { + try { + const response = await fetch( + `http://localhost:3010/position/${id}/candidates` + ); + const data = await response.json(); + setCandidates(data); + } catch (error) { + console.error("Error fetching candidates:", error); + } + }; + + const fetchInterviewFlow = async () => { + try { + const response = await fetch( + `http://localhost:3010/position/${id}/interviewflow` + ); + const data = await response.json(); + setInterviewStages(data.interviewFlow); + } catch (error) { + console.error("Error fetching interview flow:", error); + } + }; + + fetchCandidates(); + fetchInterviewFlow(); + }, [id]); + + const handleDrop = async (candidateId: string, newStepId: number) => { + const candidate = candidates.find((c) => c.candidateId === candidateId); + + try { + await fetch(`http://localhost:3010/candidates/${candidateId}`, { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + applicationId: candidate?.applicationId, + currentInterviewStep: String(newStepId), + }), + }); + + // Fetch the updated candidates list + const response = await fetch( + `http://localhost:3010/position/${id}/candidates` + ); + const data = await response.json(); + setCandidates(data); + } catch (error) { + console.error("Error updating candidate:", error); + } + }; + + return ( + + + +

{interviewStages?.positionName}

+ + {interviewStages?.interviewFlow.interviewSteps.map((stage) => { + const stageCandidates = candidates.filter( + (candidate) => candidate.currentInterviewStep === stage.name + ); + return ( + + + + ); + })} + +
+
+ ); +}; + +export default InterviewProcess; diff --git a/frontend/src/components/InterviewProcess/InterviewStage.tsx b/frontend/src/components/InterviewProcess/InterviewStage.tsx new file mode 100644 index 0000000..fd9b6db --- /dev/null +++ b/frontend/src/components/InterviewProcess/InterviewStage.tsx @@ -0,0 +1,50 @@ +/** + * This code was generated by Builder.io + */ +import React from "react"; +import { Card } from "react-bootstrap"; +import { useDrop } from "react-dnd"; +import Candidate, { ICandidateProps } from "./Candidate"; + +export interface InterviewStageProps { + id: number; + title: string; + candidates: ICandidateProps[]; + onDrop?: (candidateId: string, newStepId: number) => void; +} + +const InterviewStage: React.FC = ({ + title, + id, + candidates, + onDrop, +}) => { + const [{ isOver }, drop] = useDrop(() => ({ + accept: "CANDIDATE", + drop: (item: { candidateId: string }) => { + return onDrop!(item.candidateId, id); + }, + collect: (monitor) => ({ + isOver: !!monitor.isOver(), + }), + })); + + return ( + + +

{title}

+
+ + {candidates.map((candidate) => ( + + ))} + +
+ ); +}; + +export default InterviewStage; diff --git a/frontend/src/components/Positions.tsx b/frontend/src/components/Positions.tsx index 822dccd..ef24a4b 100644 --- a/frontend/src/components/Positions.tsx +++ b/frontend/src/components/Positions.tsx @@ -1,72 +1,114 @@ -import React from 'react'; -import { Card, Container, Row, Col, Form, Button } from 'react-bootstrap'; +import React from "react"; +import { Button, Card, Col, Container, Form, Row } from "react-bootstrap"; +import { useNavigate } from "react-router-dom"; type Position = { - title: string; - manager: string; - deadline: string; - status: 'Abierto' | 'Contratado' | 'Cerrado' | 'Borrador'; + id: number; + title: string; + manager: string; + deadline: string; + status: "Abierto" | "Contratado" | "Cerrado" | "Borrador"; }; const mockPositions: Position[] = [ - { title: 'Senior Backend Engineer', manager: 'John Doe', deadline: '2024-12-31', status: 'Abierto' }, - { title: 'Junior Android Engineer', manager: 'Jane Smith', deadline: '2024-11-15', status: 'Contratado' }, - { title: 'Product Manager', manager: 'Alex Jones', deadline: '2024-07-31', status: 'Borrador' } + { + id: 1, + title: "Senior Backend Engineer", + manager: "John Doe", + deadline: "2024-12-31", + status: "Abierto", + }, + { + id: 2, + title: "Junior Android Engineer", + manager: "Jane Smith", + deadline: "2024-11-15", + status: "Contratado", + }, + { + id: 3, + title: "Product Manager", + manager: "Alex Jones", + deadline: "2024-07-31", + status: "Borrador", + }, ]; const Positions: React.FC = () => { - return ( - -

Posiciones

- - - - - - - - - - - - - - - - - - - - - - - - - - - {mockPositions.map((position, index) => ( - - - - {position.title} - - Manager: {position.manager}
- Deadline: {position.deadline} -
- - {position.status} - -
- - -
-
-
- - ))} -
-
- ); + const navigate = useNavigate(); + + const handleViewProcess = (id: number) => { + navigate(`/positions/${id}`); + }; + + return ( + +

Posiciones

+ + + + + + + + + + + + + + + + + + + + + + + + + + + {mockPositions.map((position, index) => ( + + + + {position.title} + + Manager: {position.manager} +
+ Deadline: {position.deadline} +
+ + {position.status} + +
+ + +
+
+
+ + ))} +
+
+ ); }; -export default Positions; \ No newline at end of file +export default Positions; diff --git a/prompts/prompts-JIM.md b/prompts/prompts-JIM.md new file mode 100644 index 0000000..3450733 --- /dev/null +++ b/prompts/prompts-JIM.md @@ -0,0 +1,61 @@ +## Figma -> Builder.io + +## Copilot + +# Prompt 1 + +Act as a Senior Frontend developer. I want to create an action link that when the user press over the button "Ver proceso" the page will navigate to a new URL positions/{positionID} where we need to show #file:InterviewStage.tsx page + +# Prompt 2 + +/fix Module '"react-router-dom"' has no exported member 'useHistory'. + +# Prompt 3 + +complete the InterviewProcessProp types with the following object + +``` +{ "positionName": "Senior Full-Stack Engineer", "interviewFlow": { "id": 1, "description": "Standard development interview process", "interviewSteps": [ { "id": 1, "interviewFlowId": 1, "interviewTypeId": 1, "name": "Initial Screening", "orderIndex": 1 }, { "id": 2, "interviewFlowId": 1, "interviewTypeId": 2, "name": "Technical Interview", "orderIndex": 2 }, { "id": 3, "interviewFlowId": 1, "interviewTypeId": 3, "name": "Manager Interview", "orderIndex": 2 } ] } } +``` + +and for Candidates with + +``` +{ "fullName": "John Doe", "currentInterviewStep": "Technical Interview", "averageScore": 5 } +``` + +# Prompt 4 + +I want to pass as a prop the candidates that correspond to each interviewStep, since each candidate as a prop where is located in the process + +# Prompt 5 + +Each candidate card should be placed in the corresponding phase and show their full name and average score. + +And should be dragable to another interviewStep + +# Prompt 6 + +after each drop I want to do a PUT /candidate/:id where the candidate should change the interview process. and after the put do a GET again to have a refresh window with all the changes + +# Prompt 7 + +and I need to send the applicationId + +# Prompt 8 + +the currentInterviewStep for the PUT needs to be the ID of the newStep + +# Prompt 9 + +Add an arrow to the left of the title to return to the list of positions. + +# Prompt 10 + +improve components to be mobile #file:InterviewProcess.tsx #file:InterviewStage.tsx #file:Candidate.tsx + +# Prompt 11 + +I want to use icons from fas fa-arrow-left + +# Several prompts with /fix from copilot.