leumas-private-shared
Version:
Private React JSX Package For Leumas Shared Components, Headers, Footers, Asides, Login Pages, API Key Manager and much more. Styles and everything reusable to avoid DRY code across all of our subdomains
246 lines (212 loc) • 10.4 kB
JSX
import React, { 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;