Add page-level save for scenarios

This commit is contained in:
akhisud3195 2025-02-19 13:11:54 +05:30
parent 68cf6d6fd1
commit 00bd476b76
2 changed files with 87 additions and 52 deletions

View file

@ -196,14 +196,9 @@ export default function SimulationApp() {
}
);
// Refresh scenarios list and update only the modified scenario
// Just refresh the scenarios list without setting selected scenario
const updatedScenarios = await getScenarios(projectId as string);
setScenarios(updatedScenarios);
const refreshedScenario = updatedScenarios.find(s => s._id === updatedScenario._id);
if (refreshedScenario) {
setSelectedScenario(refreshedScenario);
}
setIsEditing(false);
};

View file

@ -1,11 +1,10 @@
'use client';
import { useState, useEffect } from 'react';
import { useState, useEffect, useCallback, ChangeEvent } from 'react';
import { XMarkIcon } from '@heroicons/react/24/outline';
import { WithStringId } from '../../../../lib/types/types';
import { Scenario } from "../../../../lib/types/testing_types";
import { z } from 'zod';
import { EditableField } from '../../../../lib/components/editable-field';
type ScenarioType = WithStringId<z.infer<typeof Scenario>>;
@ -17,73 +16,114 @@ interface ScenarioViewerProps {
export function ScenarioViewer({ scenario, onSave, onClose }: ScenarioViewerProps) {
const [editedScenario, setEditedScenario] = useState<ScenarioType>(scenario);
const [isDirty, setIsDirty] = useState(false);
// Reset state when scenario changes
useEffect(() => {
setEditedScenario(scenario);
setIsDirty(false);
}, [scenario]);
const handleFieldChange = (field: keyof ScenarioType) => (value: string) => {
const updatedScenario = {
...editedScenario,
const handleChange = useCallback((field: keyof ScenarioType, event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
event.preventDefault();
const value = event.target.value;
setEditedScenario(prev => ({
...prev,
[field]: value,
};
setEditedScenario(updatedScenario);
onSave(updatedScenario);
};
}));
setIsDirty(true);
}, []);
const handleSave = useCallback(() => {
onSave(editedScenario);
onClose();
}, [editedScenario, onSave, onClose]);
const adjustTextareaHeight = useCallback((element: HTMLTextAreaElement) => {
element.style.height = 'auto';
element.style.height = `${element.scrollHeight}px`;
}, []);
return (
<div>
<div className="flex justify-between items-center mb-6">
<h1 className="text-2xl font-bold">Scenario Details</h1>
<button
onClick={onClose}
className="p-2 rounded-full hover:bg-gray-100"
title="Close"
>
<XMarkIcon className="h-5 w-5 text-gray-600" />
</button>
<div className="flex gap-2">
{isDirty && (
<button
onClick={handleSave}
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors"
>
Save
</button>
)}
<button
onClick={onClose}
className="p-2 rounded-full hover:bg-gray-100"
title="Close"
>
<XMarkIcon className="h-5 w-5 text-gray-600" />
</button>
</div>
</div>
<div className="flex flex-col gap-4">
<EditableField
label="NAME"
value={editedScenario.name}
onChange={handleFieldChange('name')}
placeholder="Enter scenario name..."
/>
<div className="flex flex-col">
<div className="text-sm font-medium text-gray-500 uppercase tracking-wider mb-4">NAME</div>
<input
type="text"
value={editedScenario.name}
onChange={(e) => handleChange('name', e)}
className="text-base border border-gray-200 rounded px-2 py-1 hover:border-gray-300 focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
autoComplete="off"
spellCheck="false"
/>
</div>
<div className="border-t border-gray-200 my-4"></div>
<EditableField
label="DESCRIPTION"
value={editedScenario.description}
onChange={handleFieldChange('description')}
placeholder="Enter scenario description..."
multiline
markdown
/>
<div className="flex flex-col">
<div className="text-sm font-medium text-gray-500 uppercase tracking-wider mb-4">DESCRIPTION</div>
<textarea
value={editedScenario.description}
onChange={(e) => handleChange('description', e)}
onInput={(e) => adjustTextareaHeight(e.target as HTMLTextAreaElement)}
className="text-base border border-gray-200 rounded px-2 py-1 hover:border-gray-300 focus:border-blue-500 focus:ring-1 focus:ring-blue-500 min-h-[24px] resize-none"
style={{ height: 'auto', minHeight: '24px' }}
autoComplete="off"
spellCheck="false"
/>
</div>
<div className="border-t border-gray-200 my-4"></div>
<EditableField
label="CRITERIA"
value={editedScenario.criteria}
onChange={handleFieldChange('criteria')}
placeholder="Enter success criteria..."
multiline
markdown
/>
<div className="flex flex-col">
<div className="text-sm font-medium text-gray-500 uppercase tracking-wider mb-4">CRITERIA</div>
<textarea
value={editedScenario.criteria}
onChange={(e) => handleChange('criteria', e)}
onInput={(e) => adjustTextareaHeight(e.target as HTMLTextAreaElement)}
className="text-base border border-gray-200 rounded px-2 py-1 hover:border-gray-300 focus:border-blue-500 focus:ring-1 focus:ring-blue-500 min-h-[24px] resize-none"
style={{ height: 'auto', minHeight: '24px' }}
autoComplete="off"
spellCheck="false"
/>
</div>
<div className="border-t border-gray-200 my-4"></div>
<EditableField
label="CONTEXT"
value={editedScenario.context}
onChange={handleFieldChange('context')}
placeholder="Enter scenario context..."
multiline
markdown
/>
<div className="flex flex-col">
<div className="text-sm font-medium text-gray-500 uppercase tracking-wider mb-4">CONTEXT</div>
<textarea
value={editedScenario.context}
onChange={(e) => handleChange('context', e)}
onInput={(e) => adjustTextareaHeight(e.target as HTMLTextAreaElement)}
className="text-base border border-gray-200 rounded px-2 py-1 hover:border-gray-300 focus:border-blue-500 focus:ring-1 focus:ring-blue-500 min-h-[24px] resize-none"
style={{ height: 'auto', minHeight: '24px' }}
autoComplete="off"
spellCheck="false"
/>
</div>
</div>
</div>
);