You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

285 lines
13 KiB

import FormGroup from "@/Components/FormGroup";
import InputError from "@/Components/InputError";
import InputLabel from "@/Components/InputLabel";
import TextInput from "@/Components/TextInput";
import Authenticated from "@/Layouts/AuthenticatedLayout";
import { PageProps } from "@/types";
import { Head, Link, useForm } from "@inertiajs/react";
import { Book, Box, CheckCircle, FileText, Paperclip, Plus, PlusCircle, XCircle, XOctagon } from "react-feather";
import 'codemirror/lib/codemirror.css';
import 'codemirror/mode/javascript/javascript';
import PrimaryButton from "@/Components/PrimaryButton";
import Instructions from "./InstructionsForm";
import Modal from "@/Components/Modal";
import ModalButton from "@/Components/ModalButton";
import { FormEventHandler, useEffect, useState } from "react";
import AddCategoryModal from "../SubjectCategory/AddModal";
import axios from "axios";
import SuccessButton from "@/Components/SuccessButton";
import ErrorButton from "@/Components/ErrorButton";
import dayjs from "dayjs";
interface Category {
id: number;
subject_title: string;
description?: string;
}
export default function Create({ auth }: PageProps) {
const thisUser = auth.user;
const { data, setData, processing, errors } = useForm({
pageTitle: '',
category: '',
introduction:'',
});
const [isAddCategoryModalOpen, setIsAddCategoryModalOpen] = useState(false);
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
const selectedValue = e.target.value;
setData('category', selectedValue);
if (selectedValue === "0") {
setIsAddCategoryModalOpen(true);
}
}
const [status, setStatus] = useState('');
const [feedback, setFeedback] = useState('');
const [isSuccessModalOpen, setIsSuccessModalOpen] = useState(false);
const [isErrorModalOpen, setIsErrorModalOpen] = useState(false);
const [categories, setCategories] = useState<Category[]>([]);
const fetchCategories = async () => {
try {
const response = await axios.get<Category[]>(route('categories.index'));
setCategories(response.data);
} catch (e) {
setStatus('Function Failure');
setFeedback('Failed to fetch categories');
setIsErrorModalOpen(true);
}
};
useEffect(() => {
if (thisUser.role_id !== 1) {
setStatus('Warning');
setFeedback('You are unauthorized to access this page');
setIsErrorModalOpen(true);
} else {
fetchCategories();
}
}, [thisUser.role_id]);
const handleCloseSuccessModal = () => {
setIsSuccessModalOpen(false);
window.location.href = '/dashboard';
}
const handleCloseErrorModal = () => {
setIsErrorModalOpen(false);
window.location.href = '/dashboard';
};
const [instructions, setInstructions] = useState<{ id: number; steps: any[]; frameworkID: string; }[]>([]);
const [nextId, setNextId] = useState<number>(0);
const handleAddInstruction = () => {
setInstructions([...instructions, { id: nextId, steps: [], frameworkID: '' }]);
setNextId(nextId + 1);
};
const handleRemoveInstruction = (id: number) => {
setInstructions(prevInstructions =>
prevInstructions.filter(instruction => instruction.id !== id)
);
};
const handleUpdateInstruction = (id: number, steps: any[], frameworkID: string) => {
setInstructions(prevInstructions =>
prevInstructions.map(instruction =>
instruction.id === id ? { ...instruction, steps, frameworkID } : instruction
)
);
};
const submit: FormEventHandler = async (e) => {
e.preventDefault();
if (data.category==="0" || data.category==="") {
alert('Please choose a valid category.')
return
}
try {
const response = await axios.post(route('page.add'), data);
const pageID = response.data.page.id;
await Promise.all(instructions.map(async (instruction) => {
if (instruction.frameworkID === "0" || instruction.frameworkID === "") {
alert('Please choose a valid framework for each instruction.');
return;
}
const timestamp = dayjs().format('YYYYMMDDHHmmss');
const jsonString = JSON.stringify({ steps: instruction.steps });
const blob = new Blob([jsonString], { type: 'application/json' });
const file = new File([blob], `${timestamp}.json`, { type: 'application/json' });
const formData = new FormData();
formData.append('file', file);
formData.append('frameworkID', instruction.frameworkID);
formData.append('pageID', pageID.toString());
await axios.post(route('instruction.add'), formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
}));
setStatus('Success');
setFeedback(response.data.message);
setIsSuccessModalOpen(true);
} catch (error) {
setStatus('Error')
if (axios.isAxiosError(error)) {
setFeedback(error.response?.data.message || 'An error occurred');
} else {
setFeedback('An unexpected error occurred');
}
setIsErrorModalOpen(true);
}
}
const renderIfAdmin = () => {
if (thisUser.role_id === 1) {
return (
<div>
<div className="breadcrumbs text-sm">
<ul>
<li><Link href="/dashboard">Home</Link></li>
<li><a>Repository Pages</a></li>
<li>Add New Repository Page</li>
</ul>
</div>
<h1 className="font-bold text-xl text-primary-main flex items-center my-2"><FileText className="stroke-primary-main mr-2" />Create Repository Page</h1>
<div className="divider"></div>
<form id="CreateRepositoryPageForm" onSubmit={submit}>
<div>
<FormGroup>
<InputLabel htmlFor="pageTitle"><Box className='stroke-neutral-10' /></InputLabel>
<label htmlFor="pageTitle" className="mx-2 font-semibold">Page Title:</label>
</FormGroup>
<TextInput
id='pageTitle'
name='pageTitle'
value={data.pageTitle}
autoComplete='off'
required
onChange={(e) => setData('pageTitle', e.target.value)}
/>
<InputError message={errors.pageTitle} className="mt-2" />
</div>
<div>
<FormGroup>
<InputLabel htmlFor="category"><Book className='stroke-neutral-10' /></InputLabel>
<label htmlFor="category" className="mx-2 font-semibold">Subject Category:</label>
</FormGroup>
<select name="category" id="category" value={data.category} 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>
{categories.map(category => (
<option key={category.id} value={category.id}>
{category.subject_title}
</option>
))}
<option value="0" className="text-secondary-main font-semibold">Add new framework</option>
</select>
</div>
<div>
<FormGroup>
<InputLabel htmlFor="description"><Paperclip className='stroke-neutral-10' /></InputLabel>
<label htmlFor="description" className="mx-2 font-semibold">Introduction:</label>
</FormGroup>
<textarea className='px-2 flex-grow w-full bg-primary-background border border-primary-hover focus:outline-none focus:bg-neutral-10 focus:border-2 focus:border-primary-hover '
onChange={(e) => setData('introduction', e.target.value)} />
</div>
{instructions.map((instruction) => (
<Instructions
key={instruction.id}
instruction_id={instruction.id}
onDelete={handleRemoveInstruction}
onUpdate={handleUpdateInstruction}
/>
))}
<PrimaryButton type='button' disabled={processing} onClick={handleAddInstruction} className="w-full">
<Plus className='stroke-neutral-10' />
Add Instruction
</PrimaryButton>
<div className="divider"></div>
<div className="flex">
<ErrorButton className="w-1/2" onClick={() => window.location.href = '/dashboard'}>
<XCircle className='stroke-neutral-10' />
Cancel
</ErrorButton>
<SuccessButton type="submit" className="w-1/2">
<PlusCircle className='stroke-neutral-10' />
Save Repository Page
</SuccessButton>
</div>
</form>
</div>
);
}
}
return (
<Authenticated user={thisUser}>
<Head title="Repository Page" />
<div id="CreateRepositoryPage" className="drawer lg:drawer-open">
<input id="my-drawer-2" type="checkbox" className="drawer-toggle" />
<div className="drawer-content flex flex-row justify-between p-6 bg-neutral-20">
<div className="h-full w-full bg-neutral-10 shadow-md p-6 rounded-lg">
{renderIfAdmin()}
</div>
</div>
<div className="drawer-side">
<label htmlFor="my-drawer-2" aria-label="close sidebar" className="drawer-overlay"></label>
<ul className="menu p-4 w-56 h-full bg-primary-background text-base-content">
{/* Sidebar content here */}
<li><a>Sidebar Item 1</a></li>
<li><a>Sidebar Item 2</a></li>
</ul>
</div>
</div>
<AddCategoryModal show={isAddCategoryModalOpen} onClose={() => setIsAddCategoryModalOpen(false)} onCategoryAdded={fetchCategories} />
<Modal show={isSuccessModalOpen} onClose={() => setIsSuccessModalOpen(false)} maxWidth="lg" styling='success'>
<div className="p-4 flex flex-col items-center">
<CheckCircle className='stroke-success-main' size={80} />
<h2 className="text-xl font-bold mt-2">{ status }</h2>
<p className="mt-4">{ feedback }</p>
<ModalButton onClick={handleCloseSuccessModal} className="bg-success-main text-white hover:bg-success-hover active:bg-success-pressed">
Close
</ModalButton>
</div>
</Modal>
<Modal show={isErrorModalOpen} onClose={() => setIsErrorModalOpen(false)} maxWidth="lg" styling='error'>
<div className="p-4 flex flex-col items-center">
<XOctagon className='stroke-error-main' size={80} />
<h2 className="text-xl font-bold mt-2">{ status }</h2>
<p className="mt-4">{ feedback }</p>
<ModalButton onClick={handleCloseErrorModal} className="bg-error-main text-white hover:bg-error-hover active:bg-error-pressed">
Close
</ModalButton>
</div>
</Modal>
</Authenticated>
);
}