|
|
import { useEffect, useState } from 'react'; import ReactQuill from 'react-quill'; import 'react-quill/dist/quill.snow.css'; import CodeMirror from '@uiw/react-codemirror'; import { html } from '@codemirror/lang-html'; import { javascript } from '@codemirror/lang-javascript'; import { php } from '@codemirror/lang-php'; import 'codemirror/lib/codemirror.css'; import 'codemirror/theme/material.css'; import PrimaryButton from '@/Components/PrimaryButton'; import { Code, Download, Minus, MinusCircle, Plus } from 'react-feather'; import FormGroup from '@/Components/FormGroup'; import InputLabel from '@/Components/InputLabel'; import TextInput from '@/Components/TextInput'; import AddFrameworkModal from '../AppFramework/AddModal'; import axios from 'axios';
interface InstructionsProps { instruction_id: number; onDelete: (instruction_id: number) => void; onUpdate: (instruction_id: number, steps: any[], frameworkID: string) => void; }
interface Framework { id: number; framework_name: string; version: string; }
export default function Instructions({ instruction_id, onDelete, onUpdate }: InstructionsProps) {
const [frameworkID, setFrameworkID] = useState('');
const [frameworks, setFrameworks] = useState<Framework[]>([]); const fetchFrameworks = async () => { try { const response = await axios.get<Framework[]>(route('frameworks.index')); setFrameworks(response.data); } catch (error) { console.error('Failed to fetch frameworks', error); } };
useEffect(() => { fetchFrameworks(); }, []);
const [isAddFrameworkModalOpen, setIsAddFrameworkModalOpen] = useState(false); const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => { const selectedValue = e.target.value; setFrameworkID(selectedValue); if (selectedValue === "0") { setIsAddFrameworkModalOpen(true); } }
const [steps, setSteps] = useState<Array<{ title: string, content: string, code: string }>>([]);
const handleAddStep = () => { setSteps([...steps, { title: '', content: '', code: '' }]); };
const handleRemoveStep = (step_id: number) => { setSteps(prevSteps => prevSteps.filter((_, index) => index !== step_id)); };
const handleTitleChange = (step_id: number, title: string) => { const newSteps = [...steps]; newSteps[step_id].title = title; setSteps(newSteps); onUpdate(instruction_id, newSteps, frameworkID); };
const handleContentChange = (step_id: number, content: string) => { const newSteps = [...steps]; newSteps[step_id].content = content; setSteps(newSteps); onUpdate(instruction_id, newSteps, frameworkID); };
const handleCodeChange = (step_id: number, code: string) => { const newSteps = [...steps]; newSteps[step_id].code = code; setSteps(newSteps); onUpdate(instruction_id, newSteps, frameworkID); };
return ( <div className="h-full w-full bg-neutral-10 shadow-md my-4 p-6 rounded-lg flex flex-col items-start"> <div className='flex w-full justify-between items-center'> <h1 className="font-bold text-lg text-secondary-main flex items-center my-2">Instructions Editor</h1> <button className="btn btn-link text-error-main p-0 no-underline" onClick={() => onDelete(instruction_id)}> <Minus size={20} /> Remove Instruction </button> </div> <div className='w-full'> <FormGroup> <InputLabel htmlFor="frameworkID"><Code className='stroke-neutral-10' /></InputLabel> <label htmlFor="frameworkID" className="ml-2 w-1/4">Application Framework:</label> <select name="frameworkID" id="frameworkID" value={frameworkID} onChange={handleChange} className='px-2 py-0 flex-grow w-full h-[30px] bg-primary-background border border-primary-hover focus:outline-none focus:bg-neutral-10 focus:border focus:border-primary-hover'> <option value="" selected disabled></option> {frameworks.map(framework => ( <option key={framework.id} value={framework.id}> {framework.framework_name} </option> ))} <option value="0" className="text-secondary-main font-semibold">Add new framework</option> </select> </FormGroup> </div>
<div className='w-full my-4'> {steps.map((step, step_id) => ( <div key={step_id}> <div className='flex justify-between items-center'> <div className='flex w-full items-center'> <h3 className='font-semibold text-lg w-1/7'>Step {step_id + 1}</h3> <TextInput id='stepTitle' name='stepTitle' value={step.title} placeholder='Step Title' autoComplete='off' required onChange={(e) => handleTitleChange(step_id, e.target.value)} className='w-1/4 mx-4' /> </div> <button type="button" className="btn btn-link text-error-main p-0 no-underline" onClick={() => handleRemoveStep(step_id)}> <Minus size={20} /> Remove Step </button> </div> <p>Textual Instruction:</p> <ReactQuill value={step.content} onChange={(content) => handleContentChange(step_id, content)} className="h-1/2" modules={{ toolbar: [ ['bold', 'italic', 'underline'], [{'list': 'ordered'}, {'list': 'bullet'}], ['link', 'image', 'video'] ] }} /> <p className='mt-2'>Code Snippet:</p> <CodeMirror value={step.code} extensions={[php(), javascript(), html()]} onChange={(value) => handleCodeChange(step_id, value)} /> <div className="divider divider-neutral-20"></div> </div> ))} </div> <PrimaryButton type="button" onClick={handleAddStep} className='w-full'> <Plus className='stroke-neutral-10' /> Add Steps </PrimaryButton>
<AddFrameworkModal show={isAddFrameworkModalOpen} onClose={() => setIsAddFrameworkModalOpen(false)} onFrameworkAdded={fetchFrameworks} /> </div> ); };
|