Skip to content

Commit 9086be5

Browse files
committed
chore: final tweaks
1 parent 60f3415 commit 9086be5

5 files changed

Lines changed: 266 additions & 118 deletions

File tree

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,48 @@
1-
'use client'
1+
"use client";
22

3-
import {
4-
forwardRef,
5-
useEffect,
6-
useState,
7-
useImperativeHandle,
8-
} from 'react'
9-
import { Button } from '@/components/ui/button'
10-
import { Input } from '@/components/ui/input'
11-
import { X } from 'lucide-react'
3+
import { forwardRef, useEffect, useState, useImperativeHandle } from "react";
4+
import { Button } from "@/components/ui/button";
5+
import { Input } from "@/components/ui/input";
6+
import { X } from "lucide-react";
127

138
const Interest = forwardRef(({ onDataChange, formData }, ref) => {
14-
const [interests, setInterests] = useState(formData?.interests || [])
15-
const [newInterest, setNewInterest] = useState('')
16-
const [error, setError] = useState('')
9+
const [interests, setInterests] = useState(formData?.interests || []);
10+
const [newInterest, setNewInterest] = useState("");
11+
const [error, setError] = useState("");
1712

1813
useEffect(() => {
19-
onDataChange({ interests })
20-
}, [interests])
14+
onDataChange({ interests });
15+
}, [interests]);
2116

2217
const validate = () => {
2318
if (interests.length === 0) {
24-
setError('Please add at least one interest.')
25-
return false
19+
setError("Please add at least one interest.");
20+
return false;
2621
}
27-
setError('')
28-
return true
29-
}
22+
setError("");
23+
return true;
24+
};
3025

31-
useImperativeHandle(ref, () => ({ validate }))
26+
useImperativeHandle(ref, () => ({ validate }));
3227

3328
const handleAdd = () => {
34-
const trimmed = newInterest.trim()
29+
const trimmed = newInterest.trim();
3530
if (trimmed && !interests.includes(trimmed)) {
36-
setInterests([...interests, trimmed].sort())
37-
setNewInterest('')
38-
setError('')
31+
setInterests([...interests, trimmed].sort());
32+
setNewInterest("");
33+
setError("");
3934
}
40-
}
35+
};
4136

4237
const handleRemove = (interest) => {
43-
setInterests(interests.filter((i) => i !== interest))
44-
}
38+
setInterests(interests.filter((i) => i !== interest));
39+
};
4540

4641
return (
4742
<div className="space-y-4">
4843
<label className="text-sm font-medium">
49-
What categories are you most interested in? <span className="text-red-500">*</span>
44+
What categories/topics/hobbies are you most interested in?{" "}
45+
<span className="text-red-500">*</span>
5046
</label>
5147

5248
<div className="flex space-x-2">
@@ -55,9 +51,9 @@ const Interest = forwardRef(({ onDataChange, formData }, ref) => {
5551
onChange={(e) => setNewInterest(e.target.value)}
5652
placeholder="Type a category"
5753
onKeyDown={(e) => {
58-
if (e.key === 'Enter') {
59-
e.preventDefault()
60-
handleAdd()
54+
if (e.key === "Enter") {
55+
e.preventDefault();
56+
handleAdd();
6157
}
6258
}}
6359
/>
@@ -82,7 +78,7 @@ const Interest = forwardRef(({ onDataChange, formData }, ref) => {
8278
))}
8379
</div>
8480
</div>
85-
)
86-
})
81+
);
82+
});
8783

88-
export default Interest
84+
export default Interest;

frontend/bitmatch/src/components/project/EditProjectDialog.jsx

Lines changed: 167 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22
import axios from "axios";
3-
import { useState } from "react";
3+
import { useState, useEffect } from "react";
44
import { X, Plus, Edit2, Trash2 } from "lucide-react";
55
import { Button } from "@/components/ui/button";
66
import {
@@ -26,6 +26,12 @@ export function EditProjectDialog({ open, onOpenChange, projectData, onSave }) {
2626
const [newPosition, setNewPosition] = useState({ title: "" });
2727
const [editingIndex, setEditingIndex] = useState(-1);
2828
const [sliderImages, setSliderImages] = useState(projectData.images || []);
29+
const [interests, setInterests] = useState(projectData.interest_tags || []);
30+
const [skills, setSkills] = useState(projectData.skill_tags || []);
31+
const [newInterest, setNewInterest] = useState("");
32+
const [newSkill, setNewSkill] = useState("");
33+
const [interestError, setInterestError] = useState("");
34+
const [skillError, setSkillError] = useState("");
2935

3036
const handleImageUrlChange = (index, e) => {
3137
const newSliderImages = [...sliderImages];
@@ -37,6 +43,59 @@ export function EditProjectDialog({ open, onOpenChange, projectData, onSave }) {
3743
handleChange("images", filteredImages);
3844
};
3945

46+
// For Interests
47+
const handleInterestChange = (e) => {
48+
setNewInterest(e.target.value);
49+
setInterestError(""); // Reset error message
50+
};
51+
52+
const handleAddInterest = () => {
53+
if (newInterest.trim()) {
54+
setInterests((prev) => {
55+
const updatedInterests = [...prev, newInterest.trim()];
56+
handleChange("interest_tags", updatedInterests); // Call handleChange with updated interests
57+
return updatedInterests;
58+
});
59+
setNewInterest(""); // Clear input after adding
60+
} else {
61+
setInterestError("Interest can't be empty.");
62+
}
63+
};
64+
65+
const handleSkillChange = (e) => {
66+
setNewSkill(e.target.value);
67+
setSkillError("");
68+
};
69+
70+
const handleAddSkill = () => {
71+
if (newSkill.trim()) {
72+
setSkills((prev) => {
73+
const updatedSkills = [...prev, newSkill.trim()];
74+
handleChange("skill_tags", updatedSkills);
75+
return updatedSkills;
76+
});
77+
setNewSkill("");
78+
} else {
79+
setSkillError("Skill can't be empty.");
80+
}
81+
};
82+
83+
const handleRemoveInterest = (index) => {
84+
setInterests((prev) => {
85+
const updatedInterests = prev.filter((_, i) => i !== index);
86+
handleChange("interest_tags", updatedInterests);
87+
return updatedInterests;
88+
});
89+
};
90+
91+
const handleRemoveSkill = (index) => {
92+
setSkills((prev) => {
93+
const updatedSkills = prev.filter((_, i) => i !== index);
94+
handleChange("skill_tags", updatedSkills);
95+
return updatedSkills;
96+
});
97+
};
98+
4099
const handleChange = (field, value) => {
41100
setFormData((prev) => ({ ...prev, [field]: value }));
42101
};
@@ -95,6 +154,17 @@ export function EditProjectDialog({ open, onOpenChange, projectData, onSave }) {
95154
setEditingIndex(index);
96155
};
97156

157+
useEffect(() => {
158+
if (open) {
159+
document.body.style.overflow = "hidden";
160+
} else {
161+
document.body.style.overflow = "";
162+
}
163+
return () => {
164+
document.body.style.overflow = "";
165+
};
166+
}, [open]);
167+
98168
return (
99169
<Dialog
100170
className="flex-1 custom-scrollbar"
@@ -383,6 +453,102 @@ export function EditProjectDialog({ open, onOpenChange, projectData, onSave }) {
383453
</div>
384454
</div>
385455

456+
<div className="mt-6">
457+
<label className="block font-medium mb-2">
458+
Categories/Interests
459+
</label>
460+
<div className="flex items-center space-x-2 mb-2">
461+
<input
462+
type="text"
463+
value={newInterest}
464+
onChange={handleInterestChange}
465+
className="flex-grow border rounded-md p-2 focus:ring-blue-500 focus:border-blue-500"
466+
placeholder="e.g., Backend, Frontend, DevOps, AI"
467+
/>
468+
<button
469+
type="button"
470+
onClick={handleAddInterest}
471+
className="bg-black text-white px-4 py-2 rounded-md hover:bg-gray-800 transition-colors text-sm"
472+
>
473+
Add Interest
474+
</button>
475+
</div>
476+
{interestError && (
477+
<p className="text-red-500 text-sm mt-1">{interestError}</p>
478+
)}
479+
<div className="mt-3 border rounded-md overflow-hidden">
480+
{interests.length === 0 ? (
481+
<p className="text-sm text-gray-500 px-4 py-3">
482+
No interests added yet.
483+
</p>
484+
) : (
485+
interests.map((interest, index) => (
486+
<div
487+
key={index}
488+
className="flex items-center justify-between px-4 py-2 border-b last:border-b-0 bg-gray-50"
489+
>
490+
<span className="text-sm">{interest}</span>
491+
<button
492+
type="button"
493+
onClick={() => handleRemoveInterest(index)}
494+
className="text-red-500 hover:text-red-700 transition-colors font-bold"
495+
aria-label={`Remove interest: ${interest}`}
496+
>
497+
&#x2715;
498+
</button>
499+
</div>
500+
))
501+
)}
502+
</div>
503+
</div>
504+
505+
<div className="mt-6">
506+
<label className="block font-medium mb-2">Desired Skills</label>
507+
<div className="flex items-center space-x-2 mb-2">
508+
<input
509+
type="text"
510+
value={newSkill}
511+
onChange={handleSkillChange}
512+
className="flex-grow border rounded-md p-2 focus:ring-blue-500 focus:border-blue-500"
513+
placeholder="e.g., JavaScript, Figma, Django"
514+
/>
515+
<button
516+
type="button"
517+
onClick={handleAddSkill}
518+
className="bg-black text-white px-4 py-2 rounded-md hover:bg-gray-800 transition-colors text-sm"
519+
>
520+
Add Skill
521+
</button>
522+
</div>
523+
{skillError && (
524+
<p className="text-red-500 text-sm mt-1">{skillError}</p>
525+
)}
526+
<div className="mt-3 border rounded-md overflow-hidden">
527+
{skills.length === 0 ? (
528+
<p className="text-sm text-gray-500 px-4 py-3">
529+
No skills added yet.
530+
</p>
531+
) : (
532+
skills.map((skill, index) => (
533+
<div
534+
key={index}
535+
className="flex items-center justify-between px-4 py-2 border-b last:border-b-0 bg-gray-50"
536+
>
537+
<span className="text-sm">{skill}</span>
538+
<button
539+
type="button"
540+
onClick={() => handleRemoveSkill(index)}
541+
className="text-red-500 hover:text-red-700 transition-colors font-bold"
542+
aria-label={`Remove skill: ${skill}`}
543+
>
544+
&#x2715;
545+
</button>
546+
</div>
547+
))
548+
)}
549+
</div>
550+
</div>
551+
386552
<DialogFooter className="pt-2">
387553
<Button
388554
variant="outline"

frontend/bitmatch/src/components/project/ProjectCardLarge.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,11 @@ export default function ProjectCardLarge({ project, highlighted = false }) {
7878
{/* Followers & Likes */}
7979
<div className="flex items-center gap-4 text-sm text-gray-500 mt-2">
8080
<div className="flex items-center gap-1">
81-
<span className="text-gray-400">~</span>
81+
<span className="text-gray-400">-</span>
8282
<span>{formatNumber(project.followers_count)} Followers</span>
8383
</div>
8484
<div className="flex items-center gap-1">
85-
<span className="text-gray-400">~</span>
85+
<span className="text-gray-400">-</span>
8686
<span>{formatNumber(project.likes_count)} Likes</span>
8787
</div>
8888
</div>

0 commit comments

Comments
 (0)