Sifa professional network frontend (Next.js, React, TailwindCSS)
sifa.id/
1'use client';
2
3import { useState, useCallback } from 'react';
4import { X } from '@phosphor-icons/react';
5import { SkillCombobox } from '@/components/skill-combobox';
6import { Badge } from '@/components/ui/badge';
7import type { ProfileSkill } from '@/lib/types';
8
9interface PositionSkillEditorProps {
10 linkedSkills: ProfileSkill[];
11 /** All skills on the user's profile, for combobox suggestions. */
12 profileSkills?: ProfileSkill[];
13 onAdd: (skillName: string, category: string) => void;
14 onRemove: (rkey: string) => void;
15}
16
17export function PositionSkillEditor({
18 linkedSkills,
19 profileSkills,
20 onAdd,
21 onRemove,
22}: PositionSkillEditorProps) {
23 const [query, setQuery] = useState('');
24 const [category, setCategory] = useState('');
25
26 const handleChange = useCallback((skillName: string, cat: string) => {
27 setQuery(skillName);
28 setCategory(cat);
29 }, []);
30
31 const handleSelect = useCallback(
32 (skillName: string, cat: string) => {
33 if (skillName.trim().length < 2) return;
34 onAdd(skillName.trim(), cat);
35 setQuery('');
36 setCategory('');
37 },
38 [onAdd],
39 );
40
41 return (
42 <div>
43 <label htmlFor="position-skill-search" className="mb-1 block text-sm font-medium">
44 Skills used
45 </label>
46 {linkedSkills.length > 0 && (
47 <div className="mb-2 flex flex-wrap gap-1.5" role="list" aria-label="Linked skills">
48 {linkedSkills.map((skill) => (
49 <Badge key={skill.rkey} variant="secondary" className="gap-1" role="listitem">
50 {skill.name}
51 <button
52 type="button"
53 className="inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-destructive/20 hover:text-destructive"
54 onClick={() => onRemove(skill.rkey)}
55 aria-label={`Remove ${skill.name}`}
56 >
57 <X className="h-2.5 w-2.5" weight="bold" aria-hidden="true" />
58 </button>
59 </Badge>
60 ))}
61 </div>
62 )}
63 <SkillCombobox
64 id="position-skill-search"
65 value={query}
66 category={category}
67 onChange={handleChange}
68 onSelect={handleSelect}
69 profileSkills={profileSkills}
70 />
71 </div>
72 );
73}