Skip to content

Commit d255e26

Browse files
committed
feat(tags): implement tags dropdown in Add/Edit Task dialogs
- Replace text input with Select dropdown for tag selection - Add "Create new tag" option in dropdown - Display selected tags as removable badges - Add uniqueTags, isCreatingNewTag, setIsCreatingNewTag props - Add data-testid to Priority, Tags, Recur SelectTriggers Tests: - Update Select component mocks for testing - Rewrite tag tests to use dropdown selection - Add tests for dropdown selection and tag removal Fixes: #210
1 parent 8213c94 commit d255e26

9 files changed

Lines changed: 362 additions & 194 deletions

File tree

frontend/src/components/HomeComponents/Tasks/AddTaskDialog.tsx

Lines changed: 80 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
} from '@/components/ui/select';
2525
import { AddTaskDialogProps } from '@/components/utils/types';
2626
import { format } from 'date-fns';
27+
import { processTagInput } from './tasks-utils';
2728

2829
export const AddTaskdialog = ({
2930
isOpen,
@@ -36,6 +37,9 @@ export const AddTaskdialog = ({
3637
isCreatingNewProject,
3738
setIsCreatingNewProject,
3839
uniqueProjects = [],
40+
isCreatingNewTag,
41+
setIsCreatingNewTag,
42+
uniqueTags = [],
3943
allTasks = [],
4044
}: AddTaskDialogProps) => {
4145
const [annotationInput, setAnnotationInput] = useState('');
@@ -102,13 +106,6 @@ export const AddTaskdialog = ({
102106
});
103107
};
104108

105-
const handleAddTag = () => {
106-
if (tagInput && !newTask.tags.includes(tagInput, 0)) {
107-
setNewTask({ ...newTask, tags: [...newTask.tags, tagInput] });
108-
setTagInput('');
109-
}
110-
};
111-
112109
const handleRemoveTag = (tagToRemove: string) => {
113110
setNewTask({
114111
...newTask,
@@ -194,6 +191,7 @@ export const AddTaskdialog = ({
194191
</Label>
195192
<div className="col-span-3 space-y-2">
196193
<Select
194+
data-testid="project-select"
197195
value={
198196
isCreatingNewProject ? '__CREATE_NEW__' : newTask.project
199197
}
@@ -207,7 +205,7 @@ export const AddTaskdialog = ({
207205
}
208206
}}
209207
>
210-
<SelectTrigger id="project" data-testid="project-select">
208+
<SelectTrigger id="project">
211209
<SelectValue
212210
placeholder={
213211
uniqueProjects.length
@@ -373,24 +371,84 @@ export const AddTaskdialog = ({
373371
</select>
374372
</div>
375373
</div>
376-
<div className="grid grid-cols-8 items-center gap-4">
377-
<Label htmlFor="tags" className="text-right col-span-2">
374+
<div className="grid grid-cols-4 items-center gap-4">
375+
<Label htmlFor="tags" className="text-right">
378376
Tags
379377
</Label>
380-
<div className="col-span-6">
381-
<Input
382-
id="tags"
383-
name="tags"
384-
placeholder="Add a tag"
385-
value={tagInput}
386-
onChange={(e) => setTagInput(e.target.value)}
387-
onKeyDown={(e) => e.key === 'Enter' && handleAddTag()}
388-
required
389-
className="col-span-6"
390-
/>
378+
<div className="col-span-3 space-y-2">
379+
<Select
380+
data-testid="tags-select"
381+
value={isCreatingNewTag ? '__CREATE_NEW__' : '__SELECT__'}
382+
onValueChange={(value) => {
383+
if (value === '__CREATE_NEW__') {
384+
setIsCreatingNewTag(true);
385+
} else if (value !== '__SELECT__') {
386+
if (!newTask.tags.includes(value)) {
387+
setNewTask({
388+
...newTask,
389+
tags: [...newTask.tags, value],
390+
});
391+
}
392+
}
393+
}}
394+
>
395+
<SelectTrigger id="tags">
396+
<SelectValue
397+
placeholder={
398+
uniqueTags.length ? 'Select a tag' : 'No tags yet'
399+
}
400+
>
401+
{isCreatingNewTag
402+
? tagInput
403+
? `New Tag: ${tagInput}`
404+
: '+ Create new tag…'
405+
: 'Select a tag'}
406+
</SelectValue>
407+
</SelectTrigger>
408+
<SelectContent
409+
onWheel={(e) => e.stopPropagation()}
410+
onKeyDown={(e) => e.stopPropagation()}
411+
className="max-h-60 overflow-y-auto"
412+
>
413+
<SelectItem value="__CREATE_NEW__">
414+
+ Create new tag…
415+
</SelectItem>
416+
{uniqueTags.map((tag: string) => {
417+
const isSelected = newTask.tags.includes(tag);
418+
return (
419+
<SelectItem key={tag} value={tag} disabled={isSelected}>
420+
{tag}
421+
</SelectItem>
422+
);
423+
})}
424+
</SelectContent>
425+
</Select>
426+
{isCreatingNewTag && (
427+
<Input
428+
id="tag-name"
429+
placeholder="New tag name"
430+
value={tagInput}
431+
autoFocus
432+
onChange={(e) => setTagInput(e.target.value)}
433+
onKeyDown={(e) => {
434+
const newTag = processTagInput(
435+
e.key,
436+
tagInput,
437+
newTask.tags
438+
);
439+
if (newTag) {
440+
setNewTask({
441+
...newTask,
442+
tags: [...newTask.tags, newTag],
443+
});
444+
setTagInput('');
445+
setIsCreatingNewTag(false);
446+
}
447+
}}
448+
/>
449+
)}
391450
</div>
392451
</div>
393-
394452
<div className="mt-2">
395453
{newTask.tags.length > 0 && (
396454
<div className="grid grid-cols-4 items-center">

0 commit comments

Comments
 (0)