import React, { createContext, useContext, useState, useEffect } from "react"; import { developerKitService, } from "@/services/developerKit.service"; import { ApiEndpoint, ApiMigration, CreateUpdateCustomEntityDto, CustomEntity } from "@/proxy/developerKit/models"; export const FIELD_TYPE_OPTIONS = [ { label: "String", value: "string" }, { label: "Number", value: "number" }, { label: "Boolean", value: "boolean" }, { label: "Date", value: "date" }, { label: "Guid", value: "guid" }, { label: "Decimal", value: "decimal" }, ] as const; export type EntityFieldType = (typeof FIELD_TYPE_OPTIONS)[number]["value"]; interface EntityContextType { entities: CustomEntity[]; migrations: ApiMigration[]; generatedEndpoints: ApiEndpoint[]; loading: boolean; error: string | null; // Entity operations addEntity: (entity: CreateUpdateCustomEntityDto) => Promise; updateEntity: (id: string, entity: CreateUpdateCustomEntityDto) => Promise; deleteEntity: (id: string) => Promise; getEntity: (id: string) => CustomEntity | undefined; refreshEntities: () => Promise; toggleEntityActiveStatus: (id: string) => Promise; // Migration operations generateMigration: (entityId: string) => Promise; applyMigration: (migrationId: string) => Promise; getEntityMigrations: (entityId: string) => ApiMigration[]; deleteMigration: (id: string) => Promise; // Generated endpoint operations generateCrudEndpoints: (entityId: string) => Promise; toggleEndpoint: (endpointId: string) => Promise; getEntityEndpoints: (entityId: string) => ApiEndpoint[]; deleteGeneratedEndpoint: (id: string) => Promise; } const EntityContext = createContext(undefined); // eslint-disable-next-line react-refresh/only-export-components export const useEntities = () => { const context = useContext(EntityContext); if (context === undefined) { throw new Error("useEntities must be used within an EntityProvider"); } return context; }; export const EntityProvider: React.FC<{ children: React.ReactNode }> = ({ children, }) => { const [entities, setEntities] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [migrations, setMigrations] = useState([]); const [generatedEndpoints, setGeneratedEndpoints] = useState([]); const refreshEntities = async () => { try { setLoading(true); setError(null); const [entitiesData, migrationsData, generatedEndpointsData] = await Promise.all([ developerKitService.getCustomEntities(), developerKitService.getMigrations(), developerKitService.getGeneratedEndpoints(), ]); setEntities(entitiesData.items || []); setMigrations(migrationsData.items || []); setGeneratedEndpoints(generatedEndpointsData.items || []); } catch (err) { setError(err instanceof Error ? err.message : "Failed to fetch data"); console.error("Failed to fetch data:", err); } finally { setLoading(false); } }; useEffect(() => { refreshEntities(); }, []); const addEntity = async (entityData: CreateUpdateCustomEntityDto) => { try { setLoading(true); setError(null); const newEntity = await developerKitService.createCustomEntity(entityData); setEntities((prev) => [...prev, newEntity]); } catch (err) { setError(err instanceof Error ? err.message : "Failed to create entity"); throw err; } finally { setLoading(false); } }; const updateEntity = async ( id: string, entityData: CreateUpdateCustomEntityDto ) => { try { setLoading(true); setError(null); const updatedEntity = await developerKitService.updateCustomEntity(id, entityData); setEntities((prev) => prev.map((entity) => (entity.id === id ? updatedEntity : entity)) ); } catch (err) { setError(err instanceof Error ? err.message : "Failed to update entity"); throw err; } finally { setLoading(false); } }; const deleteEntity = async (id: string) => { try { setLoading(true); setError(null); await developerKitService.deleteCustomEntity(id); // Remove entity from state setEntities((prev) => prev.filter((entity) => entity.id !== id)); // Remove related migrations from state setMigrations((prev) => prev.filter((migration) => migration.entityId !== id)); // Remove related endpoints from state setGeneratedEndpoints((prev) => prev.filter((endpoint) => endpoint.entityId !== id)); } catch (err) { setError(err instanceof Error ? err.message : "Failed to delete entity"); throw err; } finally { setLoading(false); } }; const toggleEntityActiveStatus = async (id: string) => { try { setLoading(true); setError(null); await developerKitService.toggleCustomEntityActiveStatus(id); // Refresh entities to get updated status await refreshEntities(); } catch (err) { setError( err instanceof Error ? err.message : "Failed to toggle entity status" ); throw err; } finally { setLoading(false); } }; const getEntity = (id: string): CustomEntity | undefined => { return entities.find((entity) => entity.id === id); }; // Migration operations const generateMigration = async (entityId: string) => { try { setLoading(true); setError(null); const migration = await developerKitService.generateMigration(entityId); setMigrations((prev) => [...prev, migration]); // Refresh entities to get updated migration status await refreshEntities(); } catch (err) { setError(err instanceof Error ? err.message : "Failed to generate migration"); throw err; } finally { setLoading(false); } }; const applyMigration = async (migrationId: string) => { try { setLoading(true); setError(null); const appliedMigration = await developerKitService.applyMigration(migrationId); setMigrations((prev) => prev.map((m) => (m.id === migrationId ? appliedMigration : m)) ); // Refresh entities to get updated migration status await refreshEntities(); } catch (err) { setError(err instanceof Error ? err.message : "Failed to apply migration"); throw err; } finally { setLoading(false); } }; const getEntityMigrations = (entityId: string): ApiMigration[] => { return migrations.filter((migration) => migration.entityId === entityId); }; const deleteMigration = async (id: string) => { try { setLoading(true); setError(null); await developerKitService.deleteMigration(id); setMigrations((prev) => prev.filter((migration) => migration.id !== id)); } catch (err) { setError(err instanceof Error ? err.message : "Failed to delete migration"); throw err; } finally { setLoading(false); } }; // Generated endpoint operations const generateCrudEndpoints = async (entityId: string) => { try { setLoading(true); setError(null); const endpointsData = await developerKitService.generateCrudEndpoints(entityId); // Replace existing endpoints for this entity setGeneratedEndpoints((prev) => [ ...prev.filter((e) => e.entityId !== entityId), ...endpointsData.items || [], ]); // Refresh entities to get updated endpoint status await refreshEntities(); } catch (err) { setError(err instanceof Error ? err.message : "Failed to generate CRUD endpoints"); throw err; } finally { setLoading(false); } }; const toggleEndpoint = async (endpointId: string) => { try { setLoading(true); setError(null); const updatedEndpoint = await developerKitService.toggleGeneratedEndpoint(endpointId); setGeneratedEndpoints((prev) => prev.map((e) => (e.id === endpointId ? updatedEndpoint : e)) ); } catch (err) { setError(err instanceof Error ? err.message : "Failed to toggle endpoint"); throw err; } finally { setLoading(false); } }; const getEntityEndpoints = (entityId: string): ApiEndpoint[] => { return generatedEndpoints.filter((endpoint) => endpoint.entityId === entityId); }; const deleteGeneratedEndpoint = async (id: string) => { try { setLoading(true); setError(null); await developerKitService.deleteGeneratedEndpoint(id); setGeneratedEndpoints((prev) => prev.filter((endpoint) => endpoint.id !== id)); } catch (err) { setError(err instanceof Error ? err.message : "Failed to delete generated endpoint"); throw err; } finally { setLoading(false); } }; return ( {children} ); };