Skip to content

Commit 77dc4d0

Browse files
authored
Merge pull request #66 from FSDSTR0225/dev
Dev
2 parents c6d4286 + 1edad90 commit 77dc4d0

File tree

16 files changed

+1047
-555
lines changed

16 files changed

+1047
-555
lines changed

src/components/home/NumbersSection.jsx

Lines changed: 30 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { useState, useEffect } from "react";
2+
import { useCounter } from "../../hooks/useCounter";
23
import { getOffers } from "../../services/offersServices";
34
import { getAllDevelopers } from "../../services/devService";
45
import { getAllRecruiters } from "../../services/profileService";
@@ -7,82 +8,74 @@ export const NumbersSection = () => {
78
const [offers, setOffers] = useState([]);
89
const [devs, setDevs] = useState([]);
910
const [companies, setCompanies] = useState([]);
11+
const [acceptedApplications, setAcceptedApplications] = useState(0);
12+
13+
const devsCount = useCounter(devs.length * 100);
14+
const companiesCount = useCounter(companies.length * 100);
15+
const offersCount = useCounter(offers.length * 100);
16+
const hiresCount = useCounter(acceptedApplications * 100);
1017

1118
useEffect(() => {
12-
const fetchOffers = async () => {
19+
const fetchData = async () => {
1320
try {
14-
const offersData = await getOffers();
15-
setOffers(offersData);
16-
} catch (error) {
17-
console.error("Error fetching offers:", error);
18-
}
19-
};
21+
const [offersData, devsData, companiesData] = await Promise.all([
22+
getOffers(),
23+
getAllDevelopers(),
24+
getAllRecruiters(),
25+
]);
2026

21-
const fetchDevs = async () => {
22-
try {
23-
const devsData = await getAllDevelopers();
27+
setOffers(offersData);
2428
setDevs(devsData);
25-
} catch (error) {
26-
console.error("Error fetching devs:", error);
27-
}
28-
};
29-
30-
const fetchCompany = async () => {
31-
try {
32-
const companiesData = await getAllRecruiters();
3329
setCompanies(companiesData);
30+
31+
let accepted = 0;
32+
offersData.forEach((offer) => {
33+
offer.applicants?.forEach((applicant) => {
34+
if (applicant.status === "accepted") {
35+
accepted++;
36+
}
37+
});
38+
});
39+
setAcceptedApplications(accepted);
3440
} catch (error) {
35-
console.error("Error fetching companies:", error);
41+
console.error("Error fetching data:", error);
3642
}
3743
};
3844

39-
fetchOffers();
40-
fetchDevs();
41-
fetchCompany();
45+
fetchData();
4246
}, []);
4347

44-
let acceptedApplications = 0;
45-
offers.map((offer) => {
46-
if (offer.applicants) {
47-
offer.applicants.map((applicant) => {
48-
if (applicant.status === "accepted") {
49-
acceptedApplications++;
50-
}
51-
});
52-
}
53-
});
54-
5548
return (
5649
<div className="flex justify-center items-center w-full mt-8 px-2">
5750
<div className="w-full max-w-6xl bg-neutral-80 border border-neutral-60 rounded-3xl py-8 px-2 sm:py-12 sm:px-6 md:py-16 md:px-16">
5851
<div className="grid grid-cols-2 lg:grid-cols-4 gap-6 md:gap-8 text-center">
5952
<div className="flex flex-col items-center">
6053
<span className="text-3xl sm:text-4xl md:text-5xl font-bold text-primary-50 mb-2 block">
61-
+{devs.length * 100}
54+
+{devsCount}
6255
</span>
6356
<span className="text-neutral-20 text-sm md:text-base block">
6457
Developers
6558
</span>
6659
</div>
6760
<div className="flex flex-col items-center">
6861
<span className="text-3xl sm:text-4xl md:text-5xl font-bold text-secondary-50 mb-2 block">
69-
+{companies.length * 100}
62+
+{companiesCount}
7063
</span>
7164
<span className="text-neutral-20 text-sm md:text-base block">
7265
Companies
7366
</span>
7467
</div>
7568
<div className="flex flex-col items-center">
7669
<span className="text-3xl sm:text-4xl md:text-5xl font-bold text-primary-50 mb-2 block">
77-
+{offers.length * 100}
70+
+{offersCount}
7871
</span>
7972
<span className="text-neutral-20 text-sm md:text-base block">
8073
Active Offers
8174
</span>
8275
</div>
8376
<div className="flex flex-col items-center">
8477
<span className="text-3xl sm:text-4xl md:text-5xl font-bold text-secondary-50 mb-2 block">
85-
+{acceptedApplications * 100}
78+
+{hiresCount}
8679
</span>
8780
<span className="text-neutral-20 text-sm md:text-base block">
8881
Total hires

src/features/auth/login.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export const Login = () => {
3333
if (!email) {
3434
setError("email", {
3535
type: "required",
36-
message: "Este campo es requerido",
36+
message: "This field is required",
3737
});
3838
hasEmpty = true;
3939
}

src/features/developer/components/NewProjectModal.jsx

Lines changed: 102 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import { useForm } from "react-hook-form";
2-
import { useState } from "react";
2+
import { useState, useEffect } from "react";
33
import { useNavigate } from "react-router";
44
import { PiTrash, PiImages, PiCodeBlock, PiFile } from "react-icons/pi";
55
import { CategorySelect } from "../components/CategorySelect";
66
import { TagsInputDev } from "../components/TagsInputDev";
7-
import { createProject } from "../../../services/projectService";
87
import { AvatarUpload } from "../components/AvatarUpload";
98

10-
export const NewProjectModal = ({ onClose }) => {
9+
export const NewProjectModal = ({
10+
project = null,
11+
onClose,
12+
onSubmitProject,
13+
}) => {
1114
const navigate = useNavigate();
1215

1316
const {
@@ -79,6 +82,34 @@ export const NewProjectModal = ({ onClose }) => {
7982
});
8083
};
8184

85+
useEffect(() => {
86+
if (project) {
87+
reset({
88+
title: project.title,
89+
year: project.year,
90+
professionalRole: project.professionalRole,
91+
duration: project.duration,
92+
projectSkills: project.projectSkills || [],
93+
category: project.category,
94+
description: project.description,
95+
liveLink: project.liveLink,
96+
githubLink: project.githubLink,
97+
});
98+
99+
setCodeSections(project.codeSections || []);
100+
setGallerySlots(
101+
(project.gallery || []).map((url) => ({
102+
avatarUrl: url,
103+
imageFile: null,
104+
}))
105+
);
106+
} else {
107+
reset(); // Limpia el formulario si no hay proyecto
108+
setCodeSections([]);
109+
setGallerySlots([{ avatarUrl: null, imageFile: null }]);
110+
}
111+
}, [project, reset]);
112+
82113
const onSubmit = async (data) => {
83114
setLoading(true);
84115
setError(null);
@@ -93,23 +124,23 @@ export const NewProjectModal = ({ onClose }) => {
93124
gallery: filteredGallery,
94125
};
95126

96-
const token = localStorage.getItem("token");
97-
if (!token) {
98-
setError("No authentication token found, please login");
127+
if (!onSubmitProject) {
128+
setError("No submit handler provided");
99129
setLoading(false);
100130
return;
101131
}
102132

103133
try {
104-
const project = await createProject(payload, token);
105-
console.log("ID del proyecto creado:", project.project._id);
134+
await onSubmitProject(payload);
106135

107136
reset();
108137
setCodeSections([]);
109138
setGallerySlots([{ avatarUrl: null, imageFile: null }]);
110139
onClose();
111140

112-
navigate(`/projects/${project.project._id}`);
141+
if (!project) {
142+
navigate(`/projects/${payload._id || ""}`);
143+
}
113144
} catch (err) {
114145
setError(err.message || "Unknown error");
115146
} finally {
@@ -165,9 +196,9 @@ export const NewProjectModal = ({ onClose }) => {
165196

166197
return (
167198
<dialog id="project_modal" className="modal modal-open">
168-
<div className="modal-box max-w-3xl bg-neutral-70 border border-neutral-60 text-neutral-0 shadow-md rounded-lg">
169-
<h2 className="space-y-4 pt-2 text-2xl font-bold mb-4">
170-
Create New Project
199+
<div className="modal-box max-w-3xl bg-neutral-70 border border-neutral-60 text-neutral-0 shadow-md rounded-lg xl:max-h-[850px]">
200+
<h2 className="text-2xl font-bold mb-4">
201+
{project ? "Edit Project" : "Create New Project"}
171202
</h2>
172203
<hr className="border-t border-neutral-55 pt-4 mt-3" />
173204

@@ -181,19 +212,38 @@ export const NewProjectModal = ({ onClose }) => {
181212
<h3>Project Details</h3>
182213
</header>
183214

184-
<label
185-
className="block text-sm text-neutral-20 mb-1"
186-
htmlFor="title"
187-
>
188-
Project Title
189-
</label>
190-
<input
191-
id="title"
192-
type="text"
193-
placeholder="Write your project title..."
194-
className="input input-bordered bg-neutral-90 text-neutral-0 border-neutral-60 w-full placeholder-neutral-40 placeholder:italic"
195-
{...register("title", { required: true })}
196-
/>
215+
<div className="grid grid-cols-[3fr_2fr] gap-4">
216+
<div>
217+
<label
218+
className="block text-sm text-neutral-20 mb-1"
219+
htmlFor="title"
220+
>
221+
Project Title
222+
</label>
223+
<input
224+
id="title"
225+
type="text"
226+
placeholder="Write your project title..."
227+
className="input input-bordered bg-neutral-90 text-neutral-0 border-neutral-60 w-full placeholder-neutral-40 placeholder:italic"
228+
{...register("title", { required: true })}
229+
/>
230+
</div>
231+
232+
<div>
233+
<label
234+
className="block text-sm text-neutral-20 mb-1"
235+
htmlFor="category-select"
236+
>
237+
Category
238+
</label>
239+
<CategorySelect
240+
id="category"
241+
register={register}
242+
error={errors.category}
243+
setValue={setValue}
244+
/>
245+
</div>
246+
</div>
197247

198248
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
199249
<div>
@@ -260,42 +310,25 @@ export const NewProjectModal = ({ onClose }) => {
260310
</div>
261311
</div>
262312

263-
<div className="grid grid-cols-2 gap-4">
264-
<div>
265-
<label
266-
className="block text-sm text-neutral-20 mb-1"
267-
htmlFor="projectSkills"
268-
>
269-
Skills
270-
</label>
271-
<TagsInputDev
272-
value={skills}
273-
onChange={(tags) =>
274-
setValue("projectSkills", tags, { shouldValidate: true })
275-
}
276-
placeholder="Add skill and press enter"
277-
/>
278-
{errors.projectSkills && (
279-
<p className="text-red-500 text-sm mt-1">
280-
{errors.projectSkills.message}
281-
</p>
282-
)}
283-
</div>
284-
285-
<div>
286-
<label
287-
className="block text-sm text-neutral-20 mb-1"
288-
htmlFor="category-select"
289-
>
290-
Category
291-
</label>
292-
<CategorySelect
293-
id="category"
294-
register={register}
295-
error={errors.category}
296-
setValue={setValue}
297-
/>
298-
</div>
313+
<div>
314+
<label
315+
className="block text-sm text-neutral-20 mb-1"
316+
htmlFor="projectSkills"
317+
>
318+
Skills
319+
</label>
320+
<TagsInputDev
321+
value={skills}
322+
onChange={(tags) =>
323+
setValue("projectSkills", tags, { shouldValidate: true })
324+
}
325+
placeholder="Add skill and press enter"
326+
/>
327+
{errors.projectSkills && (
328+
<p className="text-red-500 text-sm mt-1">
329+
{errors.projectSkills.message}
330+
</p>
331+
)}
299332
</div>
300333

301334
<label
@@ -417,17 +450,21 @@ export const NewProjectModal = ({ onClose }) => {
417450
</div>
418451

419452
{/* Buttons */}
420-
<div className="flex justify-end gap-4 pt-4">
453+
<div className="flex justify-end gap-4 pt-4 w-full">
421454
<button
422455
type="submit"
423456
disabled={loading}
424-
className="btn bg-primary-60 text-neutral-0 hover:bg-primary-70 w-full md:w-auto"
457+
className="btn bg-primary-60 hover:bg-primary-70"
425458
>
426-
{loading ? "Saving..." : "Publish Project"}
459+
{loading
460+
? "Saving..."
461+
: project
462+
? "Update Project"
463+
: "Publish Project"}
427464
</button>
428465
<button
429466
type="button"
430-
className="btn bg-neutral-70 text-neutral-10 hover:bg-neutral-60 border border-neutral-60 w-full md:w-auto"
467+
className="btn bg-neutral-70 text-neutral-10 hover:bg-neutral-60 border border-neutral-60 md:w-auto"
431468
onClick={onClose}
432469
disabled={loading}
433470
>

0 commit comments

Comments
 (0)