Skip to content

Commit

Permalink
Improve edit modals
Browse files Browse the repository at this point in the history
  • Loading branch information
danielsobrado committed Oct 26, 2024
1 parent 1d40f52 commit 6e3b85b
Show file tree
Hide file tree
Showing 4 changed files with 362 additions and 120 deletions.
4 changes: 2 additions & 2 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import {
ReadCustomInstructionsFile,
WriteCustomInstructionsFile,
} from '../wailsjs/go/main/App';
import { TaskTypeEditModal } from './components/TaskTypeEditModal';
import { CustomInstructionsEditModal } from './components/CustomInstructionsEditModal';
import TaskTypeEditModal from './components/TaskTypeEditModal';
import CustomInstructionsEditModal from './components/CustomInstructionsEditModal';
import { TaskTypeOption, CustomInstructionOption } from './types';
import { v4 as uuidv4 } from 'uuid';
import { CheckedState } from '@radix-ui/react-checkbox';
Expand Down
211 changes: 150 additions & 61 deletions frontend/src/components/CustomInstructionsEditModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
// CustomInstructionsEditModal.tsx

import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import {
Dialog,
DialogContent,
Expand All @@ -11,8 +9,13 @@ import {
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
import { CustomInstructionOption } from '../types';
import { v4 as uuidv4 } from 'uuid';
import { Select, SelectTrigger, SelectContent, SelectItem, SelectValue } from '@/components/ui/select';

interface CustomInstructionOption {
id: string;
label: string;
description: string;
}

interface CustomInstructionsEditModalProps {
isOpen: boolean;
Expand All @@ -21,86 +24,172 @@ interface CustomInstructionsEditModalProps {
onSave: (options: CustomInstructionOption[]) => void;
}

export function CustomInstructionsEditModal({
export default function CustomInstructionsEditModal({
isOpen,
onClose,
options,
onSave,
}: CustomInstructionsEditModalProps) {
const [localOptions, setLocalOptions] = useState<CustomInstructionOption[]>(options);

const handleAddOption = () => {
const newOption: CustomInstructionOption = {
id: uuidv4(),
label: '',
description: '',
};
setLocalOptions([...localOptions, newOption]);
};
// State management
const [localOptions, setLocalOptions] = useState<CustomInstructionOption[]>([]);
const [selectedItemId, setSelectedItemId] = useState<string>('new');
const [label, setLabel] = useState<string>('');
const [description, setDescription] = useState<string>('');
const [error, setError] = useState<string>('');

// Initialize local options when modal opens
useEffect(() => {
setLocalOptions(options);
}, [options]);

// Handle selection changes
useEffect(() => {
setError('');
if (selectedItemId === 'new') {
setLabel('');
setDescription('');
} else {
const selectedItem = localOptions.find((option) => option.id === selectedItemId);
if (selectedItem) {
setLabel(selectedItem.label);
setDescription(selectedItem.description);
}
}
}, [selectedItemId, localOptions]);

const handleSave = () => {
if (label.trim() === '') {
setError('Label is required');
return;
}

if (description.trim() === '') {
setError('Description is required');
return;
}

setError('');

const handleOptionChange = (
id: string,
field: keyof CustomInstructionOption,
value: string
) => {
setLocalOptions((prevOptions) =>
prevOptions.map((option) =>
option.id === id ? { ...option, [field]: value } : option
)
);
if (selectedItemId === 'new') {
// Add new item
const newOption: CustomInstructionOption = {
id: crypto.randomUUID(),
label: label.trim(),
description: description.trim(),
};
setLocalOptions((prev) => [...prev, newOption]);
} else {
// Update existing item
setLocalOptions((prev) =>
prev.map((option) =>
option.id === selectedItemId
? { ...option, label: label.trim(), description: description.trim() }
: option
)
);
}

// Reset form
setSelectedItemId('new');
setLabel('');
setDescription('');
};

const handleDeleteOption = (id: string) => {
setLocalOptions((prevOptions) => prevOptions.filter((option) => option.id !== id));
const handleDelete = () => {
if (selectedItemId !== 'new') {
setLocalOptions((prev) => prev.filter((option) => option.id !== selectedItemId));
setSelectedItemId('new');
setLabel('');
setDescription('');
}
};

const handleSave = () => {
const handleModalSave = () => {
onSave(localOptions);
onClose();
};

return (
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent>
<DialogContent className="sm:max-w-[600px]">
<DialogHeader>
<DialogTitle>Edit Custom Instructions</DialogTitle>
<DialogTitle className="text-xl font-semibold">Edit Custom Instructions</DialogTitle>
</DialogHeader>
<div className="space-y-4 mt-4">
{localOptions.map((option) => (
<div key={option.id} className="space-y-2 border-b pb-4">
<div className="flex items-center space-x-2">
<Input
placeholder="Label"
value={option.label}
onChange={(e) =>
handleOptionChange(option.id, 'label', e.target.value)
}
/>
<Button
variant="destructive"
onClick={() => handleDeleteOption(option.id)}
>
Delete
</Button>
</div>
<Textarea
placeholder="Description"
value={option.description}
onChange={(e) =>
handleOptionChange(option.id, 'description', e.target.value)
}
/>

<div className="space-y-6 py-4">
{error && (
<div className="rounded-lg border border-red-500 p-4 text-red-500 text-sm">
{error}
</div>
))}
<Button onClick={handleAddOption}>Add Custom Instruction</Button>
)}

<div className="space-y-2">
<div className="text-sm font-medium">Select Instruction</div>
<Select
value={selectedItemId}
onValueChange={setSelectedItemId}
>
<SelectTrigger className="w-full">
<SelectValue placeholder="Select or create new instruction" />
</SelectTrigger>
<SelectContent>
<SelectItem value="new">Create New Custom Instruction</SelectItem>
{localOptions.map((option) => (
<SelectItem key={option.id} value={option.id}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>

<div className="space-y-2">
<div className="text-sm font-medium">Label</div>
<Input
placeholder="Enter instruction label"
value={label}
onChange={(e) => setLabel(e.target.value)}
/>
</div>

<div className="space-y-2">
<div className="text-sm font-medium">Description</div>
<Textarea
placeholder="Enter instruction description"
value={description}
onChange={(e) => setDescription(e.target.value)}
className="min-h-[100px]"
/>
</div>

<div className="flex space-x-2">
<Button
onClick={handleSave}
className="flex-1"
>
{selectedItemId === 'new' ? 'Add Custom Instruction' : 'Update Instruction'}
</Button>
{selectedItemId !== 'new' && (
<Button
variant="destructive"
onClick={handleDelete}
className="flex-1"
>
Delete Instruction
</Button>
)}
</div>
</div>
<DialogFooter>

<DialogFooter className="gap-2 sm:gap-0">
<Button variant="outline" onClick={onClose}>
Cancel
</Button>
<Button onClick={handleSave}>Save</Button>
<Button onClick={handleModalSave}>
Save All Changes
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
}
Loading

0 comments on commit 6e3b85b

Please sign in to comment.