Path: blob/main/extensions/copilot/test/simulation/fixtures/edit/issue-7487/EditForm.tsx
13513 views
'use client';12import { Edit } from '@/database';3import { useRouter } from 'next/navigation';4import { useEffect, useState } from 'react';56interface EditFormProps {7storyUid: string;8edit?: Edit;9}1011const EditForm: React.FC<EditFormProps> = ({ storyUid, edit: initialEdit }) => {12const [prompt, setPrompt] = useState('');13const [edit, setEdit] = useState<Edit | null>(initialEdit || null);14const [isLoading, setIsLoading] = useState(false);15const [isAccepting, setIsAccepting] = useState(false);16const [isDiscarding, setIsDiscarding] = useState(false);17const router = useRouter();1819useEffect(() => {20if (edit) {21setPrompt(edit.prompt);22}23}, [edit]);2425const handleSubmit = async (e: React.FormEvent) => {26e.preventDefault();27setIsLoading(true);28const response = await fetch(`/api/updateStory`, {29method: 'POST',30headers: {31'Content-Type': 'application/json',32},33body: JSON.stringify({ storyUid, prompt }),34});3536if (!response.ok) {37console.error('Failed to fetch suggestions');38setIsLoading(false);39return;40}4142const data = await response.json().catch(() => null);43if (data) {44setEdit(data);45} else {46console.error('Failed to parse JSON response');47}48setIsLoading(false);49};5051const handleAcceptEdits = async () => {52if (!edit || !edit.operations.length) {53console.error('No edits to accept');54return;55}5657setIsAccepting(true);58await fetch(`/api/acceptEdits`, {59method: 'POST',60headers: {61'Content-Type': 'application/json',62},63body: JSON.stringify({ storyUid }),64});65setEdit(null);66setIsAccepting(false);67router.refresh();68};6970const handleDiscardEdits = async () => {71setIsDiscarding(true);72await fetch(`/api/discardEdits`, {73method: 'POST',74headers: {75'Content-Type': 'application/json',76},77body: JSON.stringify({ storyUid }),78});79setEdit(null);80setIsDiscarding(false);81router.refresh();82};8384const handleFollowupClick = (followup: string) => {85setPrompt((prevPrompt) => `${prevPrompt.trim()}\n${followup.trim()}`);86};8788return (89<div className="fixed top-0 right-0 w-1/3 p-4 bg-white shadow-lg h-full overflow-y-auto">90<form onSubmit={handleSubmit}>91<textarea92value={prompt}93onChange={(e) => setPrompt(e.target.value)}94className="w-full h-20 p-2 border border-gray-300 rounded"95placeholder="Enter your prompt here..."96disabled={isLoading}97/>98<button type="submit" className={`mt-2 p-2 text-white rounded ${isLoading ? 'bg-gray-400' : 'bg-blue-500'}`} disabled={isLoading}>99{isLoading ? 'Submitting...' : 'Submit'}100</button>101</form>102{edit && (103<div>104<div className="flex justify-between items-baseline mt-4">105<h2 className="text-xl font-bold">Suggestions</h2>106<div className="flex space-x-2">107<button onClick={handleAcceptEdits} className={`px-2 text-white rounded ${isAccepting ? 'bg-gray-400' : 'bg-green-500'}`} disabled={isAccepting}>108{isAccepting ? 'Accepting...' : 'Accept'}109</button>110<button onClick={handleDiscardEdits} className={`px-2 text-white rounded ${isDiscarding ? 'bg-gray-400' : 'bg-red-500'}`} disabled={isDiscarding}>111{isDiscarding ? 'Discarding...' : 'Discard'}112</button>113</div>114</div>115<div className="bg-gray-100 p-4 rounded">116<ul className="list-disc ml-4">117{edit.operations.map((suggestion, idx) => (118<li key={idx} className="mt-1">119<a href={`#edit-${idx}`} onMouseOver={() => {120const element = document.querySelector(`[name=edit-${idx}]`);121console.log(element);122123element?.classList.add('bg-red-100');124element?.scrollIntoView({ behavior: 'smooth', block: 'center' });125}}126onMouseOut={() => {127document.querySelector(`[name=edit-${idx}]`)?.classList.remove('bg-red-100');128}}129className="font-medium">{suggestion.type}</a> at line {suggestion.line + 1}130{suggestion.text && (131<span>: {suggestion.text}</span>132)}133</li>134))}135</ul>136<h3 className="mt-4 text-lg font-bold">Follow-up Suggestions</h3>137<ul className="ml-4">138{edit.followup.map((followup, idx) => (139<li key={idx} className="mt-1">140<button141onClick={() => handleFollowupClick(followup)}142className="text-white text-sm rounded-full"143>144{followup}145</button>146</li>147))}148</ul>149</div>150</div>151)}152</div>153);154};155156export default EditForm;157158159