Skip to content

Commit 3d355e0

Browse files
committed
refactor: moved action form to a separate component
1 parent 2448621 commit 3d355e0

File tree

2 files changed

+103
-126
lines changed

2 files changed

+103
-126
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import React from 'react';
2+
import { Input } from '../ui/input';
3+
import { Button } from '../ui/button';
4+
import { Save, X } from 'lucide-react';
5+
6+
export interface ActionFormProps {
7+
initialText?: string;
8+
initialDueDate?: string;
9+
onSave: (data: { text: string; dueDate: string }) => void;
10+
onCancel: () => void;
11+
}
12+
13+
const ActionForm: React.FC<ActionFormProps> = ({
14+
initialText = '',
15+
initialDueDate = '',
16+
onSave,
17+
onCancel,
18+
}) => {
19+
const [text, setText] = React.useState(initialText);
20+
const [dueDate, setDueDate] = React.useState(initialDueDate);
21+
22+
const handleSave = () => {
23+
if (text && dueDate) {
24+
onSave({ text, dueDate });
25+
}
26+
};
27+
28+
return (
29+
<div className='flex items-center bg-gray-50 p-2 rounded space-x-2'>
30+
<Input
31+
placeholder='Action text'
32+
value={text}
33+
onChange={(e) => setText(e.target.value)}
34+
className='flex-1'
35+
/>
36+
<Input
37+
type='date'
38+
value={dueDate}
39+
onChange={(e) => setDueDate(e.target.value)}
40+
className='w-36'
41+
/>
42+
<Button
43+
variant='ghost'
44+
size='sm'
45+
onClick={handleSave}
46+
className='text-green-500 hover:text-green-700'
47+
>
48+
<Save size={16} />
49+
</Button>
50+
<Button
51+
variant='ghost'
52+
size='sm'
53+
onClick={onCancel}
54+
className='text-gray-500 hover:text-gray-700'
55+
>
56+
<X size={16} />
57+
</Button>
58+
</div>
59+
);
60+
};
61+
62+
export default ActionForm;

src/components/statements/ActionPreview.tsx

Lines changed: 41 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
import React from 'react';
2-
// import { format } from 'date-fns';
3-
import { MoreVertical, Edit2, Trash2, Save, X } from 'lucide-react';
4-
import { Button } from '../ui/button';
5-
import { Input } from '../ui/input';
2+
import { format, parse } from 'date-fns';
3+
import { MoreVertical, Edit2, Trash2 } from 'lucide-react';
64
import {
75
DropdownMenu,
86
DropdownMenuTrigger,
97
DropdownMenuContent,
108
DropdownMenuItem,
119
} from '../ui/dropdown-menu';
10+
import ActionForm from './ActionForm';
1211
import type { Action } from '../../../types/types';
13-
import { format, parse } from 'date-fns';
1412

1513
export interface ActionPreviewProps {
1614
actions: Action[];
@@ -28,84 +26,64 @@ const ActionPreview: React.FC<ActionPreviewProps> = ({
2826
onDeleteAction,
2927
onAddAction,
3028
}) => {
31-
// Add Action State
32-
const [isAddingNew, setIsAddingNew] = React.useState(false);
33-
const [newAction, setNewAction] = React.useState({ text: '', dueDate: '' });
34-
35-
// Edit Action State
29+
// State to track which action is being edited.
3630
const [editingActionId, setEditingActionId] = React.useState<string | null>(
3731
null
3832
);
39-
const [editForm, setEditForm] = React.useState({ text: '', dueDate: '' });
33+
// State to control whether we're adding a new action.
34+
const [isAddingNew, setIsAddingNew] = React.useState(false);
4035

41-
// ---------------------------
42-
// ADD ACTION LOGIC
43-
// ---------------------------
44-
const handleStartAdd = () => {
45-
setIsAddingNew(true);
46-
setNewAction({ text: '', dueDate: '' });
36+
// --- Handlers for Editing ---
37+
const handleStartEdit = (action: Action) => {
38+
setEditingActionId(action.id);
4739
};
4840

49-
const handleSaveNew = () => {
50-
if (!newAction.text || !newAction.dueDate) return;
51-
onAddAction(newAction);
52-
setIsAddingNew(false);
53-
setNewAction({ text: '', dueDate: '' });
41+
const handleSaveEdit = (
42+
actionId: string,
43+
data: { text: string; dueDate: string }
44+
) => {
45+
onEditAction(actionId, data);
46+
setEditingActionId(null);
5447
};
5548

56-
const handleCancelNew = () => {
57-
setIsAddingNew(false);
58-
setNewAction({ text: '', dueDate: '' });
49+
const handleCancelEdit = () => {
50+
setEditingActionId(null);
5951
};
6052

61-
// ---------------------------
62-
// EDIT ACTION LOGIC
63-
// ---------------------------
64-
const handleStartEdit = (action: Action) => {
65-
setEditingActionId(action.id);
66-
// Directly use the stored dueDate, which is assumed to be in "YYYY-MM-DD" format.
67-
setEditForm({
68-
text: action.text,
69-
dueDate: action.dueDate,
70-
});
53+
// --- Handlers for Adding New Action ---
54+
const handleStartAdd = () => {
55+
setIsAddingNew(true);
7156
};
7257

73-
const handleSaveEdit = (actionId: string) => {
74-
if (!editForm.text || !editForm.dueDate) return;
75-
onEditAction(actionId, { text: editForm.text, dueDate: editForm.dueDate });
76-
setEditingActionId(null);
77-
setEditForm({ text: '', dueDate: '' });
58+
const handleSaveNew = (data: { text: string; dueDate: string }) => {
59+
onAddAction(data);
60+
setIsAddingNew(false);
7861
};
7962

80-
const handleCancelEdit = () => {
81-
setEditingActionId(null);
82-
setEditForm({ text: '', dueDate: '' });
63+
const handleCancelNew = () => {
64+
setIsAddingNew(false);
8365
};
8466

8567
return (
8668
<div className='space-y-2'>
8769
{actions.map((action) => {
8870
const isEditing = editingActionId === action.id;
89-
9071
if (!isEditing) {
91-
// Normal (read-only) view
92-
// Since dueDate is already in "YYYY-MM-DD", we can display it directly or format it if needed.
72+
// Read-only view for an action.
73+
// Parse stored "yyyy-MM-dd" into a Date object, then format as "dd/MM/yyyy"
74+
const dueDateObj = parse(action.dueDate, 'yyyy-MM-dd', new Date());
75+
const dueDateText = !isNaN(dueDateObj.getTime())
76+
? format(dueDateObj, 'dd/MM/yyyy')
77+
: 'No due date';
9378
return (
9479
<div
9580
key={action.id}
9681
className='flex items-center justify-between bg-gray-50 p-2 rounded'
9782
>
9883
<span className='flex-1'>{action.text}</span>
9984
<span className='mx-4 text-sm text-gray-500'>
100-
Due:{' '}
101-
{action.dueDate
102-
? format(
103-
parse(action.dueDate, 'yyyy-MM-dd', new Date()),
104-
'dd/MM/yyyy'
105-
)
106-
: 'No due date'}
85+
Due: {dueDateText}
10786
</span>
108-
10987
<DropdownMenu>
11088
<DropdownMenuTrigger asChild>
11189
<button onClick={(e) => e.stopPropagation()}>
@@ -129,50 +107,20 @@ const ActionPreview: React.FC<ActionPreviewProps> = ({
129107
</div>
130108
);
131109
} else {
132-
// Editing this action
110+
// Editing mode: use the ActionForm prefilled with the action data.
133111
return (
134-
<div
112+
<ActionForm
135113
key={action.id}
136-
className='flex items-center bg-gray-50 p-2 rounded space-x-2'
137-
>
138-
<Input
139-
placeholder='Action text'
140-
value={editForm.text}
141-
onChange={(e) =>
142-
setEditForm({ ...editForm, text: e.target.value })
143-
}
144-
className='flex-1'
145-
/>
146-
<Input
147-
type='date'
148-
value={editForm.dueDate}
149-
onChange={(e) =>
150-
setEditForm({ ...editForm, dueDate: e.target.value })
151-
}
152-
className='w-36'
153-
/>
154-
<Button
155-
variant='ghost'
156-
size='sm'
157-
onClick={() => handleSaveEdit(action.id)}
158-
className='text-green-500 hover:text-green-700'
159-
>
160-
<Save size={16} />
161-
</Button>
162-
<Button
163-
variant='ghost'
164-
size='sm'
165-
onClick={handleCancelEdit}
166-
className='text-gray-500 hover:text-gray-700'
167-
>
168-
<X size={16} />
169-
</Button>
170-
</div>
114+
initialText={action.text}
115+
initialDueDate={action.dueDate}
116+
onSave={(data) => handleSaveEdit(action.id, data)}
117+
onCancel={handleCancelEdit}
118+
/>
171119
);
172120
}
173121
})}
174122

175-
{/* Add Action row or inline form */}
123+
{/* Add new action: either show the "+ Add Action" row or the inline form */}
176124
{!isAddingNew ? (
177125
<div
178126
className='flex items-center justify-between bg-gray-50 p-2 rounded cursor-pointer hover:bg-gray-100'
@@ -181,40 +129,7 @@ const ActionPreview: React.FC<ActionPreviewProps> = ({
181129
<span className='flex-1'>+ Add Action</span>
182130
</div>
183131
) : (
184-
<div className='flex items-center bg-gray-50 p-2 rounded space-x-2'>
185-
<Input
186-
placeholder='Action text'
187-
value={newAction.text}
188-
onChange={(e) =>
189-
setNewAction({ ...newAction, text: e.target.value })
190-
}
191-
className='flex-1'
192-
/>
193-
<Input
194-
type='date'
195-
value={newAction.dueDate}
196-
onChange={(e) =>
197-
setNewAction({ ...newAction, dueDate: e.target.value })
198-
}
199-
className='w-36'
200-
/>
201-
<Button
202-
variant='ghost'
203-
size='sm'
204-
onClick={handleSaveNew}
205-
className='text-green-500 hover:text-green-700'
206-
>
207-
<Save size={16} />
208-
</Button>
209-
<Button
210-
variant='ghost'
211-
size='sm'
212-
onClick={handleCancelNew}
213-
className='text-gray-500 hover:text-gray-700'
214-
>
215-
<X size={16} />
216-
</Button>
217-
</div>
132+
<ActionForm onSave={handleSaveNew} onCancel={handleCancelNew} />
218133
)}
219134
</div>
220135
);

0 commit comments

Comments
 (0)