UNPKG

leumas-universal-crud-react

Version:

Leumas Universal CRUD to a dynamic Endpoint, Setup your own Dynamic Endpoint and Use Leumas API to send to your MONGO clusters

246 lines (212 loc) 10.4 kB
import { useEffect, useState } from 'react'; import {LeumasBaseStyle} from "../../styles/baseStyles" import {excludedSchemas} from "./ExcludedSchemas" import {schemaToCardMapping} from "./SchemaMapping" import { getAllPublicItems, getItemsByOwner } from '../UniversalCrud/UniversalCrudHelpers'; import useAuthUser from 'react-auth-kit/hooks/useAuthUser'; // import AceEditorWrapper from '../../../components/Editors/ACE/AceEditor'; import MultiPageForm from '../../Forms/MultiPageForm'; import ErrorBoundary from '../../errorBoundary'; import { FaSave, FaTrash, FaEdit } from 'react-icons/fa'; import { fetchSchemas } from './Helpers/fetchSchemas'; function SchemaSelector({ onSchemaSelect , setMode , itemToParent , onCrudSelect , passToParentAgain , hideCreateButton = false}) { const [schemas, setSchemas] = useState([]); const [selectedSchema, setSelectedSchema] = useState(''); const auth = useAuthUser() const [fetchedItems, setFetchedItems] = useState([]); const [selectedItem, setSelectedItem] = useState(null); const [CardComponent, setCardComponent] = useState(null); const [cardSide , setCardSide] = useState(true) useEffect(() => { fetchSchemas( (fetchedSchemas) => { setSchemas(fetchedSchemas); console.log(fetchedSchemas); }, (error) => console.error("Error fetching schemas:", error), import.meta.env.VITE_REACT_APP_LEUMAS_API_ENDPOINT, excludedSchemas ); }, []); const passToParent = (data) => { console.log("Schema Selector receiving from MultiPage form" , data) if(passToParentAgain){ passToParentAgain(data) } // Now we pass this into the parent for SchemaSelector } const handleSchemaChange = async (e) => { const schema = e.target.value || e; console.log("Searching for schema:", schema, "\nSelected CRUD Type:", selectedCrudType); try { let items = []; // Determine action based on selected CRUD type switch (selectedCrudType) { case "owned": case "edit": case "delete": case "histories": // Fetch items owned by the user items = await getItemsByOwner(`${schema}`, auth?.id, "LeumasAPI", auth?.token); break; case "public": // Fetch public items (assuming getPublicItems is a function you have) items = await getAllPublicItems(`${schema}` , "LeumasAPI" , auth?.token); break; case "create": // For creating new items, use the form component from schemaToCardMapping console.log("Creating an item") break; default: console.log("Invalid CRUD type selected"); } console.log("Fetched items:", items); setSelectedSchema(schema); setSelectedItem(null); setFetchedItems(items); // Set the fetched items onSchemaSelect(schema, schemaToCardMapping[schema], items); } catch (error) { console.error("Error fetching items:", error); } }; const handleItemChange = (e) => { const itemId = e.target.value; const foundItem = fetchedItems.find(item => item._id === itemId); // Ensure this matches the item ID key if (foundItem) { setSelectedItem(foundItem); // Set the selected item } if(itemToParent){ itemToParent(foundItem) } }; const [selectedCrudType , setSelectedCrudType] = useState("owned") const handleCrudChange = (e) => { const crudType = e.target.value; console.log("Crud Type Changed" , crudType); setSelectedCrudType(crudType); setFetchedItems([]) handleSchemaChange(selectedSchema) if(onCrudSelect){ onCrudSelect(crudType) } } return ( <div className='w-full'> <div className='w-full flex items-center justify-start'> <select className={`${LeumasBaseStyle} w-full`} value={selectedSchema} onChange={handleSchemaChange} > <option className={`bg-blue-400 text-white`} value="" disabled>Select a schema</option> {schemas.map(schema => ( <option className={`bg-blue-400 text-white`} key={schema} value={schema}> {schema} </option> ))} </select> <select value={selectedCrudType} onChange={handleCrudChange} className={`${LeumasBaseStyle}`}> {/* Owned means to getAllByOwner */} <option className='bg-blue-400 text-white' value={"owned"}>Owned</option> {/* Public Means we want to get all Public for our Model */} <option className='bg-blue-400 text-white' value={"public"}>Public</option> {/* */} <option className='bg-blue-400 text-white' value="create">Create</option> <option className='bg-blue-400 text-white' value={"edit"}>Edit</option> <option className='bg-blue-400 text-white' value={"delete"}>Delete</option> <option className='bg-blue-400 text-white' value={"histories"}>Histories</option> </select> </div> {/* The selectedCrudType we have will determine the content below that gets rendered */} {(selectedCrudType === "owned" || selectedCrudType === "public" || selectedCrudType === "histories" || selectedCrudType === "edit" || selectedCrudType === "delete") && <> {/* if viewing owned, we need to be able to see the fetchedItems in the select, and the card component below, this is also the same for public, */} {/* <p className='flex items-center justify-start gap-2'> {selectedSchema }{` (s)`} {fetchedItems.length} </p> */} {/* Item select */} {selectedSchema && ( <select className={`${LeumasBaseStyle} w-full mt-4`} onChange={handleItemChange}> <option className={`bg-blue-400 text-white`} value="" disabled>Select an item</option> {fetchedItems.map((item, index) => ( <option className={`bg-blue-400 text-white`} key={item._id || index} value={item._id}> {item.name || item?.title || `Unitled ${selectedSchema} ${index} `} {/* Adjust the property if needed */} </option> ))} </select> )} {/* Render CardComponent only if selectedItem is not null */} {selectedItem && ( <div className={`border-2 w-full max-h-[300px] overflow-auto`} onClick={() => setCardSide(!cardSide)}> {cardSide && CardComponent ? ( <> <CardComponent model={selectedItem} /> <div className="flex justify-around items-center mt-2"> <button onClick={(e) => { e.stopPropagation(); // Prevent event bubbling setCardSide(!cardSide); }} className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-2 rounded text-xs"> Show JSON </button> {/* Additional Utility Buttons Here */} </div> </> ) : ( <div className='h-full min-h-[300px]'> {/* Remove max-height and set full height */} {/* <div className='max-h-[250px] overflow-y-scroll'> <AceEditorWrapper mode="json" content={JSON.stringify(selectedItem, null, 2)} readOnly={true} // Set Ace Editor height to 90% /> </div> */} <div className="flex justify-around items-center mt-2 h-[10%] overflow-x-scroll text-[8px] relative top-0"> {/* Utility bar with 10% height and overflow-x-scroll */} <button onClick={() => setCardSide(!cardSide)} className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-2 rounded"> Show Card </button> {/* Additional utility buttons with icons and text */} <button className="bg-green-500 hover:bg-green-700 text-white font-bold py-1 px-2 rounded flex items-center"> <FaSave className="mr-1"/> Save </button> <button className="bg-yellow-500 hover:bg-yellow-700 text-white font-bold py-1 px-2 rounded flex items-center"> <FaEdit className="mr-1"/> Edit </button> <button className="bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-2 rounded flex items-center"> <FaTrash className="mr-1"/> Delete </button> </div> </div> )} </div> )} </> } {(selectedCrudType === "create") && selectedSchema && schemaToCardMapping[selectedSchema] && ( <> {schemaToCardMapping[selectedSchema].tool === null ? ( <ErrorBoundary> <MultiPageForm hideCreateButton={hideCreateButton} passToParent={passToParent} pages={schemaToCardMapping[selectedSchema].form} /> </ErrorBoundary> ) : ( <div> <p>Sorry, we cannot build complex schema types with a form.</p> <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" onClick={() => setMode(schemaToCardMapping[selectedSchema].tool)} > Open Tool </button> </div> )} </> )} </div> ); } export default SchemaSelector;