diff --git a/apps/events/src/components/playground.tsx b/apps/events/src/components/playground.tsx
index c324e450..084f2868 100644
--- a/apps/events/src/components/playground.tsx
+++ b/apps/events/src/components/playground.tsx
@@ -1,5 +1,5 @@
import { getSmartAccountWalletClient } from '@/lib/smart-account';
-import { _useDeleteEntityPublic, useQuery } from '@graphprotocol/hypergraph-react';
+import { _useCreateEntityPublic, _useDeleteEntityPublic, useQuery } from '@graphprotocol/hypergraph-react';
import { useState } from 'react';
import { Event } from '../schema';
import { Button } from './ui/button';
@@ -14,17 +14,46 @@ export const Playground = () => {
},
});
const [isDeleting, setIsDeleting] = useState(false);
+ const [isCreating, setIsCreating] = useState(false);
const deleteEntity = _useDeleteEntityPublic(Event, {
space: '1c954768-7e14-4f0f-9396-0fe9dcd55fe8',
});
+ const createEntity = _useCreateEntityPublic(Event, {
+ space: '1c954768-7e14-4f0f-9396-0fe9dcd55fe8',
+ });
+
console.log({ isLoading, isError, data });
return (
{isLoading &&
Loading...
}
{isError &&
Error
}
+
{data?.map((event) => (
{event.name}
diff --git a/packages/hypergraph-react/src/index.ts b/packages/hypergraph-react/src/index.ts
index 45767be2..a4d826ad 100644
--- a/packages/hypergraph-react/src/index.ts
+++ b/packages/hypergraph-react/src/index.ts
@@ -23,6 +23,7 @@ export {
useUpdateEntity,
} from './HypergraphSpaceContext.js';
export { generateDeleteOps as _generateDeleteOps } from './internal/generate-delete-ops.js';
+export { useCreateEntityPublic as _useCreateEntityPublic } from './internal/use-create-entity-public.js';
export { useDeleteEntityPublic as _useDeleteEntityPublic } from './internal/use-delete-entity-public.js';
export { useGenerateCreateOps as _useGenerateCreateOps } from './internal/use-generate-create-ops.js';
export { useQueryPublic as _useQueryPublic } from './internal/use-query-public.js';
diff --git a/packages/hypergraph-react/src/internal/use-create-entity-public.ts b/packages/hypergraph-react/src/internal/use-create-entity-public.ts
new file mode 100644
index 00000000..a2ef30a5
--- /dev/null
+++ b/packages/hypergraph-react/src/internal/use-create-entity-public.ts
@@ -0,0 +1,100 @@
+import { type GeoSmartAccount, Graph, Id, type PropertiesParam, type RelationsParam } from '@graphprotocol/grc-20';
+import type { Entity } from '@graphprotocol/hypergraph';
+import { Type, store } from '@graphprotocol/hypergraph';
+import { useQueryClient } from '@tanstack/react-query';
+import { useSelector } from '@xstate/store/react';
+import type * as Schema from 'effect/Schema';
+import { publishOps } from '../publish-ops.js';
+
+type CreateEntityPublicParams = {
+ space: string;
+};
+
+export function useCreateEntityPublic(
+ type: S,
+ { space }: CreateEntityPublicParams,
+) {
+ const mapping = useSelector(store, (state) => state.context.mapping);
+ const queryClient = useQueryClient();
+
+ return async (
+ data: Readonly>>,
+ { walletClient }: { walletClient: GeoSmartAccount },
+ // TODO: return the entity with this type: Promise>
+ ) => {
+ try {
+ // @ts-expect-error TODO should use the actual type instead of the name in the mapping
+ const typeName = type.name;
+ const mappingEntry = mapping?.[typeName];
+ if (!mappingEntry) {
+ throw new Error(`Mapping entry for ${typeName} not found`);
+ }
+
+ const fields = type.fields;
+ const values: PropertiesParam = [];
+ for (const [key, value] of Object.entries(mappingEntry.properties || {})) {
+ let serializedValue: string = data[key];
+ if (fields[key] === Type.Checkbox) {
+ serializedValue = Graph.serializeCheckbox(data[key]);
+ } else if (fields[key] === Type.Date) {
+ serializedValue = Graph.serializeDate(data[key]);
+ } else if (fields[key] === Type.Point) {
+ serializedValue = Graph.serializePoint(data[key]);
+ } else if (fields[key] === Type.Number) {
+ serializedValue = Graph.serializeNumber(data[key]);
+ }
+
+ values.push({
+ property: Id.Id(value),
+ value: serializedValue,
+ });
+ }
+
+ const relations: RelationsParam = {};
+ for (const [key, relationId] of Object.entries(mappingEntry.relations || {})) {
+ const toIds: { toEntity: Id.Id }[] = [];
+
+ if (data[key]) {
+ // @ts-expect-error - TODO: fix the types error
+ for (const entity of data[key]) {
+ if (typeof entity === 'string') {
+ toIds.push({ toEntity: Id.Id(entity) });
+ } else {
+ toIds.push({ toEntity: Id.Id(entity.id) });
+ }
+ }
+ relations[Id.Id(relationId)] = toIds;
+ }
+ }
+
+ const { ops } = Graph.createEntity({
+ types: mappingEntry.typeIds,
+ id: data.id,
+ values,
+ relations,
+ });
+
+ const { cid, txResult } = await publishOps({
+ ops,
+ space,
+ name: `Create entity ${data.id}`,
+ walletClient,
+ network: 'TESTNET',
+ });
+ // TODO: temporary fix until we get the information from the API when a transaction is confirmed
+ await new Promise((resolve) => setTimeout(resolve, 2000));
+ queryClient.invalidateQueries({
+ queryKey: [
+ 'hypergraph-public-entities',
+ // @ts-expect-error - TODO: find a better way to access the type.name
+ type.name,
+ space,
+ ],
+ });
+ return { success: true, cid, txResult };
+ } catch (error) {
+ console.error(error);
+ return { success: false, error: 'Failed to create entity' };
+ }
+ };
+}