Skip to content

Commit 528c99a

Browse files
committed
feat: create draft state for statement being modified
1 parent a0dd8fa commit 528c99a

File tree

7 files changed

+113
-101
lines changed

7 files changed

+113
-101
lines changed

src/components/statementWizard/VerbGrid.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const VerbGrid: React.FC<VerbGridProps> = ({
2424
<div className='grid grid-cols-3 sm:grid-cols-4 md:grid-cols-5 gap-4 p-4 overflow-auto'>
2525
{sortedVerbs.map((verb) => {
2626
const tileColor = getVerbColor(verb, rootCategory);
27-
console.log('Verb name:', verb.name, ' SelectedVerb:', selectedVerbId);
27+
2828
const isSelected = verb.id === selectedVerbId;
2929
return (
3030
<Button

src/components/statementWizard/selectors/SubjectSelector.tsx

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,6 @@ const SubjectSelector: React.FC<SubjectSelectorProps> = ({
7070
{/* Options List */}
7171
<ul className='max-h-60 overflow-y-auto'>
7272
{options.map((option) => {
73-
// Log each option's value, the current selected value, and the comparison result.
74-
console.log(
75-
'Rendering option:',
76-
option.value,
77-
'Current value:',
78-
value,
79-
'Selected:',
80-
option.value === value
81-
);
8273
return (
8374
<li key={option.value}>
8475
<button

src/components/statements/StatementItem.tsx

Lines changed: 63 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
RotateCcw,
1313
CheckCircle2,
1414
XCircle,
15-
// Mail,
1615
MailPlus,
1716
MailX,
1817
} from 'lucide-react';
@@ -35,12 +34,8 @@ export interface StatementItemProps {
3534
part: 'subject' | 'verb' | 'object',
3635
statementId: string
3736
) => void;
38-
onPartUpdate: (
39-
statementId: string,
40-
part: 'subject' | 'verb' | 'object',
41-
value: string
42-
) => void;
43-
onSave: (statementId: string) => void;
37+
// When the green save icon is clicked, the updated entry (draft) is passed back
38+
onLocalSave: (updatedEntry: Entry) => void;
4439
onDelete: (statementId: string) => void;
4540
onTogglePublic: (statementId: string) => void;
4641
onEditClick: (statementId: string) => void;
@@ -49,6 +44,7 @@ export interface StatementItemProps {
4944
actionId: string,
5045
updated: { text: string; dueDate?: string }
5146
) => void;
47+
onCancel?: (statementId: string) => void;
5248
onDeleteAction?: (statementId: string, actionId: string) => void;
5349
onAddAction?: (
5450
statementId: string,
@@ -64,11 +60,11 @@ const StatementItem: React.FC<StatementItemProps> = ({
6460
isEditing,
6561
editingPart,
6662
onPartClick,
67-
onPartUpdate,
68-
onSave,
63+
onLocalSave,
6964
onDelete,
7065
onTogglePublic,
7166
onEditClick,
67+
onCancel,
7268
onEditAction = () => {},
7369
onDeleteAction = () => {},
7470
onAddAction = () => {},
@@ -79,12 +75,31 @@ const StatementItem: React.FC<StatementItemProps> = ({
7975
const [isActionsExpanded, setIsActionsExpanded] = React.useState(false);
8076
const objectInputRef = useRef<HTMLInputElement>(null);
8177

78+
// Local "draft" state to hold unsaved modifications.
79+
const [draft, setDraft] = React.useState<Entry>(statement);
80+
81+
// Whenever the statement prop changes (or when not editing), re-sync the draft.
82+
useEffect(() => {
83+
setDraft(statement);
84+
}, [statement]);
85+
8286
useEffect(() => {
8387
if (editingPart === 'object' && objectInputRef.current) {
8488
objectInputRef.current.focus();
8589
}
8690
}, [editingPart]);
8791

92+
// Local function to update a specific part in the draft.
93+
const updatePart = (part: 'subject' | 'verb' | 'object', value: string) => {
94+
setDraft((prev) => ({
95+
...prev,
96+
atoms: {
97+
...prev.atoms,
98+
[part]: value,
99+
},
100+
}));
101+
};
102+
88103
if (isEditing) {
89104
return (
90105
<div className='flex items-center space-x-2 bg-gray-100 p-2 rounded'>
@@ -93,88 +108,101 @@ const StatementItem: React.FC<StatementItemProps> = ({
93108
variant='ghost'
94109
size='sm'
95110
onClick={() => {
96-
console.log('Privacy toggle clicked for statement:', statement.id);
97-
onTogglePublic(statement.id);
111+
console.log('Privacy toggle clicked for statement:', draft.id);
112+
onTogglePublic(draft.id);
98113
}}
99114
className={`rounded-md px-3 py-2 transition-colors ${
100-
statement.isPublic
115+
draft.isPublic
101116
? 'bg-green-100 text-green-700 hover:bg-green-200'
102117
: 'bg-red-100 text-red-700 hover:bg-red-200'
103118
}`}
104119
>
105-
{statement.isPublic ? <MailPlus size={16} /> : <MailX size={16} />}
120+
{draft.isPublic ? <MailPlus size={16} /> : <MailX size={16} />}
106121
</Button>
107122

108123
<div className='flex flex-1 items-center space-x-2'>
109124
{/* Subject */}
110125
<div
111-
onClick={() => onPartClick('subject', statement.id)}
126+
onClick={() => onPartClick('subject', draft.id)}
112127
className='cursor-pointer px-2 py-1 rounded bg-subjectSelector hover:bg-subjectSelectorHover'
113128
>
114129
{editingPart === 'subject' ? (
115130
<SubjectSelector
116-
value={statement.atoms.subject}
117-
onChange={(value) =>
118-
onPartUpdate(statement.id, 'subject', value)
119-
}
131+
value={draft.atoms.subject}
132+
onChange={(value) => updatePart('subject', value)}
120133
onAddDescriptor={() => {}}
121134
username={
122-
statement.atoms.subject.split("'s")[0] ||
123-
statement.atoms.subject
135+
draft.atoms.subject.split("'s")[0] || draft.atoms.subject
124136
}
125137
/>
126138
) : (
127-
statement.atoms.subject
139+
draft.atoms.subject
128140
)}
129141
</div>
130142
{/* Verb */}
131143
<div
132144
className='cursor-pointer px-2 py-1 rounded bg-verbSelector hover:bg-verbSelectorHover'
133-
onClick={() => onPartClick('verb', statement.id)}
145+
onClick={() => onPartClick('verb', draft.id)}
134146
>
135147
{editingPart === 'verb' ? (
136148
<VerbSelector
137-
onVerbSelect={(verb) =>
138-
onPartUpdate(statement.id, 'verb', verb.id)
139-
}
149+
onVerbSelect={(verb) => updatePart('verb', verb.id)}
140150
onClose={() => onPartClick('verb', '')}
141151
/>
142152
) : (
143-
<span>{getVerbName(statement.atoms.verb)}</span>
153+
<span>{getVerbName(draft.atoms.verb)}</span>
144154
)}
145155
</div>
146156
{/* Object */}
147157
<div
148-
onClick={() => onPartClick('object', statement.id)}
158+
onClick={() => onPartClick('object', draft.id)}
149159
className='cursor-pointer px-2 py-1 rounded bg-objectInput hover:bg-objectInputHover'
150160
>
151161
{editingPart === 'object' ? (
152162
<Input
153163
ref={objectInputRef}
154-
value={statement.atoms.object}
155-
onChange={(e) =>
156-
onPartUpdate(statement.id, 'object', e.target.value)
157-
}
164+
value={draft.atoms.object}
165+
onChange={(e) => updatePart('object', e.target.value)}
158166
className='w-full'
159167
/>
160168
) : (
161-
statement.atoms.object
169+
draft.atoms.object
162170
)}
163171
</div>
164172
</div>
165173
<div className='flex items-center space-x-2 ml-auto'>
174+
{/* Final Save button (green icon):
175+
This commits the local draft to the database via onLocalSave */}
166176
<Button
167177
variant='ghost'
168178
size='sm'
169-
onClick={() => onSave(statement.id)}
179+
onClick={() => {
180+
onLocalSave(draft);
181+
}}
170182
className='text-green-500 hover:text-green-700'
171183
>
172184
<Save size={16} />
173185
</Button>
186+
{/* Cancel button: resets draft and exits edit mode */}
187+
<Button
188+
variant='ghost'
189+
size='sm'
190+
onClick={() => {
191+
// Reset local draft to original statement passed from parent.
192+
setDraft(statement);
193+
// Call the onCancel prop if provided.
194+
if (onCancel) {
195+
onCancel(statement.id);
196+
}
197+
}}
198+
className='text-gray-500 hover:text-gray-700'
199+
>
200+
Cancel
201+
</Button>
174202
<Button
175203
variant='ghost'
176204
size='sm'
177-
onClick={() => onDelete(statement.id)}
205+
onClick={() => onDelete(draft.id)}
178206
className='text-red-500 hover:text-red-700'
179207
>
180208
<Trash2 size={16} />
@@ -184,7 +212,7 @@ const StatementItem: React.FC<StatementItemProps> = ({
184212
);
185213
}
186214

187-
// Static view when not in editing mode with grouped Edit and Delete
215+
// Static view when not in editing mode.
188216
return (
189217
<div
190218
className={`bg-white border rounded-md p-3 space-y-2 shadow-sm ${
@@ -202,7 +230,6 @@ const StatementItem: React.FC<StatementItemProps> = ({
202230
statement.isPublic ? 'text-green-500' : 'text-red-500'
203231
}`}
204232
>
205-
{/* {statement.isPublic ? <Eye size={16} /> : <EyeOff size={16} />} */}
206233
{statement.isPublic ? (
207234
<MailPlus size={16} />
208235
) : (
@@ -216,15 +243,13 @@ const StatementItem: React.FC<StatementItemProps> = ({
216243
: 'This statement is private'}
217244
</TooltipContent>
218245
</Tooltip>
219-
{/* Construct full sentence from atoms */}
220246
<span>{`${statement.atoms.subject} ${getVerbName(
221247
statement.atoms.verb
222248
)} ${statement.atoms.object}`}</span>
223249
</div>
224250

225251
{/* Right side: resolved icon, actions counter + dropdown */}
226252
<div className='flex items-center space-x-4'>
227-
{/* Resolved icon */}
228253
{statement.isResolved && (
229254
<Tooltip>
230255
<TooltipTrigger asChild>
@@ -237,7 +262,6 @@ const StatementItem: React.FC<StatementItemProps> = ({
237262
</TooltipContent>
238263
</Tooltip>
239264
)}
240-
{/* Actions counter */}
241265
<div
242266
onClick={() => setIsActionsExpanded((prev) => !prev)}
243267
className='cursor-pointer'
@@ -265,7 +289,6 @@ const StatementItem: React.FC<StatementItemProps> = ({
265289
<Trash2 className='mr-2 h-4 w-4' />
266290
Delete
267291
</DropdownMenuItem>
268-
{/* Toggle Resolved */}
269292
<DropdownMenuItem onClick={() => onToggleResolved(statement.id)}>
270293
{statement.isResolved ? (
271294
<>
@@ -279,7 +302,6 @@ const StatementItem: React.FC<StatementItemProps> = ({
279302
</>
280303
)}
281304
</DropdownMenuItem>
282-
{/* Reset option if provided */}
283305
{onReset && (
284306
<DropdownMenuItem onClick={() => onReset(statement.id)}>
285307
<RotateCcw className='mr-2 h-4 w-4' />
@@ -291,7 +313,6 @@ const StatementItem: React.FC<StatementItemProps> = ({
291313
</div>
292314
</div>
293315

294-
{/* Inline actions preview if expanded */}
295316
{isActionsExpanded && (
296317
<div className='mt-2'>
297318
<ActionLine

src/components/statements/StatementList.tsx

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -95,21 +95,35 @@ const StatementList: React.FC<{ username: string }> = ({ username }) => {
9595
updateEntry(updated);
9696
};
9797

98-
const handleSave = (statementId: string) => {
99-
// Find the statement from the entries
100-
const stmt = entries.find((s) => s.id === statementId);
101-
if (!stmt) return;
98+
// const handleSave = (statementId: string) => {
99+
// // Find the statement from the entries
100+
// const stmt = entries.find((s) => s.id === statementId);
101+
// if (!stmt) return;
102102

103-
// Call the API to persist the updated statement
104-
updateEntry(stmt)
105-
.then(() => {
106-
console.log(`Statement ${statementId} saved successfully.`);
107-
// Optionally, show a success message or update local state further.
108-
})
109-
.catch((error) => {
110-
console.error(`Error saving statement ${statementId}:`, error);
111-
});
112-
};
103+
// // Call the API to persist the updated statement
104+
// updateEntry(stmt)
105+
// .then(() => {
106+
// console.log(`Statement ${statementId} saved successfully.`);
107+
// // Optionally, show a success message or update local state further.
108+
// })
109+
// .catch((error) => {
110+
// console.error(`Error saving statement ${statementId}:`, error);
111+
// });
112+
// };
113+
// Handler for when a statement's local save button is clicked.
114+
async function handleLocalSave(updatedEntry: Entry) {
115+
try {
116+
// Call the backend API with the updated entry.
117+
await updateEntry(updatedEntry);
118+
// Update the context with the new entry.
119+
setData({ type: 'UPDATE_ENTRY', payload: updatedEntry });
120+
// Exit editing mode for this statement.
121+
setEditingStatementId(null);
122+
} catch (error) {
123+
console.error('Error saving statement to DB:', error);
124+
// Optionally display an error message to the user.
125+
}
126+
}
113127

114128
const handlePresetQuestionSelect = (presetQuestion: SetQuestion) => {
115129
setSelectedPresetQuestion(presetQuestion);
@@ -164,19 +178,19 @@ const StatementList: React.FC<{ username: string }> = ({ username }) => {
164178
}
165179
};
166180

167-
const handlePartUpdate = (
168-
statementId: string,
169-
part: 'subject' | 'verb' | 'object',
170-
value: string
171-
) => {
172-
const updatedEntries = entries.map((entry) =>
173-
entry.id === statementId
174-
? { ...entry, atoms: { ...entry.atoms, [part]: value } }
175-
: entry
176-
);
177-
// Update only context
178-
setData({ type: 'SET_ENTRIES', payload: updatedEntries });
179-
};
181+
// const handlePartUpdate = (
182+
// statementId: string,
183+
// part: 'subject' | 'verb' | 'object',
184+
// value: string
185+
// ) => {
186+
// const updatedEntries = entries.map((entry) =>
187+
// entry.id === statementId
188+
// ? { ...entry, atoms: { ...entry.atoms, [part]: value } }
189+
// : entry
190+
// );
191+
// // Update only context
192+
// setData({ type: 'SET_ENTRIES', payload: updatedEntries });
193+
// };
180194

181195
const handleResetClick = (statementId: string) => {
182196
const statementToReset = entries.find((s) => s.id === statementId);
@@ -271,8 +285,11 @@ const StatementList: React.FC<{ username: string }> = ({ username }) => {
271285
isEditing={statement.id === editingStatementId}
272286
editingPart={null}
273287
onPartClick={handlePartClick}
274-
onPartUpdate={handlePartUpdate}
275-
onSave={handleSave}
288+
onLocalSave={handleLocalSave}
289+
onCancel={() => {
290+
// Exit edit mode for this statement.
291+
setEditingStatementId(null);
292+
}}
276293
onDelete={handleDeleteClick}
277294
onTogglePublic={handleTogglePublic}
278295
onEditClick={handleEditClick}
@@ -336,7 +353,6 @@ const StatementList: React.FC<{ username: string }> = ({ username }) => {
336353
username={username}
337354
onUpdate={(updatedStatement) => {
338355
setData({ type: 'UPDATE_ENTRY', payload: updatedStatement });
339-
updateEntry(updatedStatement);
340356
}}
341357
onClose={() => setEditModalData(null)}
342358
/>

0 commit comments

Comments
 (0)