From a83d5454538fd62fe077f96b02705e9e410eb990 Mon Sep 17 00:00:00 2001 From: jipstavenuiter Date: Thu, 2 Nov 2023 12:52:34 +0100 Subject: [PATCH 1/4] update hyperboard fetching to new data structure --- components/ftc-board.tsx | 8 +- hooks/registry.ts | 151 ++++++++++++++++++++++---------------- pages/board/[boardId].tsx | 2 +- pages/index.tsx | 2 +- types/Hyperboard.ts | 8 +- 5 files changed, 97 insertions(+), 74 deletions(-) diff --git a/components/ftc-board.tsx b/components/ftc-board.tsx index a479f45..82aea15 100644 --- a/components/ftc-board.tsx +++ b/components/ftc-board.tsx @@ -2,14 +2,14 @@ import { useEffect, useRef, useState } from "react"; import { useSize } from "@chakra-ui/react-use-size"; import { registryContentItemToHyperboardEntry, - useRegistryContents, + useHyperboardContents, } from "@/hooks/registry"; import { Center, Flex, Spinner } from "@chakra-ui/react"; import { Hyperboard } from "@/components/hyperboard"; import * as React from "react"; import Head from "next/head"; -export const FtcBoard = ({ registryId }: { registryId: string }) => { +export const FtcBoard = ({ hyperboardId }: { hyperboardId: string }) => { const containerRef = useRef(null); const dimensions = useSize(containerRef); @@ -17,7 +17,7 @@ export const FtcBoard = ({ registryId }: { registryId: string }) => { "sponsors" | "speakers" | "all" >("all"); - const { data: results, isLoading } = useRegistryContents(registryId); + const { data: results, isLoading } = useHyperboardContents(hyperboardId); const data = results?.content || {}; @@ -54,7 +54,7 @@ export const FtcBoard = ({ registryId }: { registryId: string }) => { return ( <> - Hyperboards - {results?.registry.name || "Loading"} + Hyperboards - {results?.hyperboard?.name || "Loading"}
{ ); }; -export const useRegistryContents = (registryId: string) => { +export const useHyperboardContents = (hyperboardId: string) => { + const toast = useToast(); const client = useHypercertClient(); return useQuery( - ["registry", registryId], + ["hyperboard-contents", hyperboardId], async () => { - return getRegistryWithClaims(registryId).then(async (registry) => { - if (!registry?.data) { - return null; - } - - if (!client) { - return null; - } - - // Create one big list of all fractions, for all hypercerts in registry - const allFractions = await Promise.all( - registry.data["claims"].map((claim) => { - return client.indexer.fractionsByClaim(claim.hypercert_id); - }), - ); - const fractions = _.chain(allFractions) - .flatMap((res) => res.claimTokens) - .value(); - - // Get display data for all owners and convert to dictionary - const ownerAddresses = _.uniq( - fractions.map((x) => x.owner), - ) as string[]; - const claimDisplayDataResponse = - await getEntryDisplayData(ownerAddresses); - const claimDisplayData = _.keyBy( - claimDisplayDataResponse?.data || [], - (x) => x.address.toLowerCase(), - ); - - // Group by owner, merge with display data and calculate total value of all fractions per owner - const content = _.chain(fractions) - .groupBy((fraction) => fraction.owner) - .mapValues((fractionsPerOwner, owner) => { - return { - fractions: fractionsPerOwner, - displayData: claimDisplayData[owner], - totalValue: _.sum( - fractionsPerOwner.map((x) => parseInt(x.units, 10)), - ), - }; - }) - .value(); - - return { - registry: registry.data, - content, - }; - }); + if (!client) { + toast({ + title: "Error", + description: "No client found", + status: "error", + duration: 9000, + isClosable: true, + }); + return null; + } + + const { data: hyperboardData, error: hyperboardContentsError } = + await supabase + .from("hyperboards") + .select( + "*, hyperboard_registries ( *, registries ( *, claims ( * ) ) )", + ) + .eq("id", hyperboardId) + .single(); + + if (hyperboardContentsError) { + toast({ + title: "Error", + description: hyperboardContentsError.message, + status: "error", + duration: 9000, + isClosable: true, + }); + } + + // Create one big list of all fractions, for all hypercerts in registry + const claimIds = _.flatMap( + hyperboardData?.hyperboard_registries, + (x) => x.registries?.claims.map((y) => y.hypercert_id), + ).filter((x) => !!x) as string[]; + + // Get display data for all owners and convert to dictionary + const allFractions = await Promise.all( + claimIds.map((claimId) => { + return client.indexer.fractionsByClaim(claimId); + }), + ); + + const fractions = _.chain(allFractions) + .flatMap((res) => res.claimTokens) + .value(); + const ownerAddresses = _.uniq(fractions.map((x) => x.owner)) as string[]; + console.log("ownerAddresses", ownerAddresses); + const claimDisplayDataResponse = + await getEntryDisplayData(ownerAddresses); + const claimDisplayData = _.keyBy( + claimDisplayDataResponse?.data || [], + (x) => x.address.toLowerCase(), + ); + + console.log("claimDisplayData", claimDisplayData); + + // Group by owner, merge with display data and calculate total value of all fractions per owner + const content = _.chain(fractions) + .groupBy((fraction) => fraction.owner) + .mapValues((fractionsPerOwner, owner) => { + return { + fractions: fractionsPerOwner, + displayData: claimDisplayData[owner], + totalValue: _.sum( + fractionsPerOwner.map((x) => parseInt(x.units, 10)), + ), + }; + }) + .value(); + + return { + content, + hyperboard: hyperboardData, + }; }, { - enabled: !!registryId && !!client, + enabled: !!hyperboardId && !!client, }, ); }; -const getRegistryWithClaims = async (registryId: string) => - supabase - .from("registries") - .select("*, claims ( * )") - .eq("id", registryId) - .single(); - const getEntryDisplayData = async (addresses: string[]) => { return supabase - .from("sponsor_metadata") - .select<"*", EntryDisplayData>("*") + .from("default_sponsor_metadata") + .select("*") .in("address", addresses); }; -export const registryContentItemToHyperboardEntry = ( - item: RegistryContentItem, -): HyperboardEntry => { +export const registryContentItemToHyperboardEntry = (item: { + displayData: DefaultSponsorMetadataEntity; + totalValue: number; +}): HyperboardEntry => { return { type: item.displayData.type, companyName: item.displayData.companyName, diff --git a/pages/board/[boardId].tsx b/pages/board/[boardId].tsx index b3f5dd7..d036f70 100644 --- a/pages/board/[boardId].tsx +++ b/pages/board/[boardId].tsx @@ -10,7 +10,7 @@ const BoardDetailPage = () => { return
Invalid uri
; } - return ; + return ; }; export default BoardDetailPage; diff --git a/pages/index.tsx b/pages/index.tsx index 46ced66..cf36367 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -8,7 +8,7 @@ function Index() { Hyperboards - FTC - + ); } diff --git a/types/Hyperboard.ts b/types/Hyperboard.ts index 5113e46..7e49cad 100644 --- a/types/Hyperboard.ts +++ b/types/Hyperboard.ts @@ -1,9 +1,9 @@ export interface HyperboardEntry { - type: "speaker" | "company" | "person"; + type: string; id: string; - companyName?: string; - firstName: string; - lastName: string; + companyName: string | null; + firstName: string | null; + lastName: string | null; image: string; value: number; } From c94b4d051318e71c971e9d04df37cabb1e408dc8 Mon Sep 17 00:00:00 2001 From: jipstavenuiter Date: Fri, 3 Nov 2023 12:38:19 +0100 Subject: [PATCH 2/4] use dynamic hyperboards from supabase --- components/ftc-board.tsx | 109 +++++-------- components/hyperboard/index.tsx | 2 +- hooks/registry.ts | 146 +++++++++++------- ...554_add_label_to_hyperboard_registries.sql | 1 + types/database.ts | 6 + 5 files changed, 134 insertions(+), 130 deletions(-) create mode 100644 supabase/migrations/20231103113554_add_label_to_hyperboard_registries.sql diff --git a/components/ftc-board.tsx b/components/ftc-board.tsx index 82aea15..4289bfc 100644 --- a/components/ftc-board.tsx +++ b/components/ftc-board.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from "react"; +import { useRef, useState } from "react"; import { useSize } from "@chakra-ui/react-use-size"; import { registryContentItemToHyperboardEntry, @@ -13,48 +13,30 @@ export const FtcBoard = ({ hyperboardId }: { hyperboardId: string }) => { const containerRef = useRef(null); const dimensions = useSize(containerRef); - const [displayBoards, setDisplayBoards] = useState< - "sponsors" | "speakers" | "all" - >("all"); + const [selectedRegistry, setSelectedRegistry] = useState(); - const { data: results, isLoading } = useHyperboardContents(hyperboardId); - - const data = results?.content || {}; - - const sponsors = Object.values(data).filter( - (x) => - x.displayData?.type === "person" || x.displayData?.type === "company", - ); - const speakers = Object.values(data || {}).filter( - (x) => x.displayData?.type === "speaker", - ); + const { data, isLoading } = useHyperboardContents(hyperboardId); + const results = data?.results; + const hyperboard = data?.hyperboard; const height = ((dimensions?.width || 1) / 16) * 9; + const widthPerBoard = `${100 / (results?.length || 1)}%`; - const [speakerWidth, setSpeakerWidth] = useState("50%"); - const [sponsorWidth, setSponsorWidth] = useState("50%"); - - useEffect(() => { - if (displayBoards === "all") { - setSpeakerWidth("50%"); - setSponsorWidth("50%"); - } - - if (displayBoards === "sponsors") { - setSpeakerWidth("0%"); - setSponsorWidth("100%"); + const getWidth = (registryId: string) => { + if (selectedRegistry === registryId) { + return "100%"; } - if (displayBoards === "speakers") { - setSpeakerWidth("100%"); - setSponsorWidth("0%"); + if (selectedRegistry && selectedRegistry !== registryId) { + return "0%"; } - }, [displayBoards]); + return widthPerBoard; + }; return ( <> - Hyperboards - {results?.hyperboard?.name || "Loading"} + Hyperboards - {hyperboard?.name || "Loading"}
{
) : ( <> - - - setDisplayBoards((val) => - val === "all" ? "sponsors" : "all", - ) - } - label="Sponsors" - height={height} - data={sponsors.map((x) => - registryContentItemToHyperboardEntry(x), - )} - /> - - - - setDisplayBoards((val) => - val === "all" ? "speakers" : "all", - ) - } - label="Speakers" - height={height} - data={speakers.map((x) => - registryContentItemToHyperboardEntry(x), - )} - /> - + {results?.map((x) => ( + + + setSelectedRegistry((currentId) => + currentId === x.registry.id ? undefined : x.registry.id, + ) + } + label={x.label || "Unlabelled"} + height={height} + data={ + (Object.values(x.content) || {}) + .filter((x) => x.displayData) + .map((x) => registryContentItemToHyperboardEntry(x)) || + [] + } + /> + + ))} )}
diff --git a/components/hyperboard/index.tsx b/components/hyperboard/index.tsx index d47cbd2..cafd36b 100644 --- a/components/hyperboard/index.tsx +++ b/components/hyperboard/index.tsx @@ -9,7 +9,7 @@ export interface HyperboardProps { data: HyperboardEntry[]; height: number; label: string; - onClickLabel: () => void; + onClickLabel: (registryId: string) => void; } type Leaf = { diff --git a/hooks/registry.ts b/hooks/registry.ts index 108bb29..b211c14 100644 --- a/hooks/registry.ts +++ b/hooks/registry.ts @@ -1,31 +1,35 @@ import { useQuery } from "@tanstack/react-query"; import { supabase } from "@/lib/supabase"; -import { ClaimToken } from "@hypercerts-org/sdk"; +import { HypercertClient } from "@hypercerts-org/sdk"; import _ from "lodash"; import { HyperboardEntry } from "@/types/Hyperboard"; import { useHypercertClient } from "@/components/providers"; import { useToast } from "@chakra-ui/react"; -import { DefaultSponsorMetadataEntity } from "@/types/database-entities"; - -interface EntryDisplayData { - image: string; - address: string; - type: "person" | "company" | "speaker"; - companyName?: string; - firstName: string; - lastName: string; - name: string; -} - -interface RegistryContentItem { - fractions: Pick< - ClaimToken, - "id" | "chainName" | "owner" | "tokenID" | "units" - >[]; - displayData: EntryDisplayData; - totalValue: number; -} +import { + ClaimEntity, + DefaultSponsorMetadataEntity, + RegistryEntity, +} from "@/types/database-entities"; + +// interface EntryDisplayData { +// image: string; +// address: string; +// type: "person" | "company" | "speaker"; +// companyName?: string; +// firstName: string; +// lastName: string; +// name: string; +// } + +// interface RegistryContentItem { +// fractions: Pick< +// ClaimToken, +// "id" | "chainName" | "owner" | "tokenID" | "units" +// >[]; +// displayData: EntryDisplayData; +// totalValue: number; +// } export const useListRegistries = () => { return useQuery(["list-registries"], async () => @@ -33,6 +37,46 @@ export const useListRegistries = () => { ); }; +const processRegistryForDisplay = async ( + registry: RegistryEntity & { claims: ClaimEntity[] }, + label: string | null, + client: HypercertClient, +) => { + const claims = registry.claims; + const fractionsResults = await Promise.all( + claims.map((claim) => { + return client.indexer.fractionsByClaim(claim.hypercert_id); + }), + ); + + const fractions = _.flatMap(fractionsResults, (x) => x.claimTokens); + const ownerAddresses = _.uniq(fractions.map((x) => x.owner)) as string[]; + + console.log("ownerAddresses", ownerAddresses); + const claimDisplayDataResponse = await getEntryDisplayData(ownerAddresses); + const claimDisplayData = _.keyBy(claimDisplayDataResponse?.data || [], (x) => + x.address.toLowerCase(), + ); + + // Group by owner, merge with display data and calculate total value of all fractions per owner + const content = _.chain(fractions) + .groupBy((fraction) => fraction.owner) + .mapValues((fractionsPerOwner, owner) => { + return { + fractions: fractionsPerOwner, + displayData: claimDisplayData[owner], + totalValue: _.sum(fractionsPerOwner.map((x) => parseInt(x.units, 10))), + }; + }) + .value(); + + return { + content, + registry, + label, + }; +}; + export const useHyperboardContents = (hyperboardId: string) => { const toast = useToast(); const client = useHypercertClient(); @@ -70,50 +114,23 @@ export const useHyperboardContents = (hyperboardId: string) => { }); } - // Create one big list of all fractions, for all hypercerts in registry - const claimIds = _.flatMap( - hyperboardData?.hyperboard_registries, - (x) => x.registries?.claims.map((y) => y.hypercert_id), - ).filter((x) => !!x) as string[]; + if (!hyperboardData?.hyperboard_registries) { + return null; + } - // Get display data for all owners and convert to dictionary - const allFractions = await Promise.all( - claimIds.map((claimId) => { - return client.indexer.fractionsByClaim(claimId); + const results = await Promise.all( + hyperboardData.hyperboard_registries.map(async (registry) => { + return await processRegistryForDisplay( + registry.registries!, + registry.label, + client, + ); }), ); - const fractions = _.chain(allFractions) - .flatMap((res) => res.claimTokens) - .value(); - const ownerAddresses = _.uniq(fractions.map((x) => x.owner)) as string[]; - console.log("ownerAddresses", ownerAddresses); - const claimDisplayDataResponse = - await getEntryDisplayData(ownerAddresses); - const claimDisplayData = _.keyBy( - claimDisplayDataResponse?.data || [], - (x) => x.address.toLowerCase(), - ); - - console.log("claimDisplayData", claimDisplayData); - - // Group by owner, merge with display data and calculate total value of all fractions per owner - const content = _.chain(fractions) - .groupBy((fraction) => fraction.owner) - .mapValues((fractionsPerOwner, owner) => { - return { - fractions: fractionsPerOwner, - displayData: claimDisplayData[owner], - totalValue: _.sum( - fractionsPerOwner.map((x) => parseInt(x.units, 10)), - ), - }; - }) - .value(); - return { - content, hyperboard: hyperboardData, + results, }; }, { @@ -133,6 +150,17 @@ export const registryContentItemToHyperboardEntry = (item: { displayData: DefaultSponsorMetadataEntity; totalValue: number; }): HyperboardEntry => { + if (!item.displayData) { + return { + type: "person", + companyName: null, + lastName: null, + firstName: null, + image: "", + value: item.totalValue, + id: "", + }; + } return { type: item.displayData.type, companyName: item.displayData.companyName, diff --git a/supabase/migrations/20231103113554_add_label_to_hyperboard_registries.sql b/supabase/migrations/20231103113554_add_label_to_hyperboard_registries.sql new file mode 100644 index 0000000..3d495d0 --- /dev/null +++ b/supabase/migrations/20231103113554_add_label_to_hyperboard_registries.sql @@ -0,0 +1 @@ +alter table "public"."hyperboard_registries" add column "label" text; diff --git a/types/database.ts b/types/database.ts index 2303917..c2133b0 100644 --- a/types/database.ts +++ b/types/database.ts @@ -117,6 +117,7 @@ export interface Database { companyName: string | null created_at: string firstName: string | null + id: string image: string lastName: string | null type: string @@ -126,6 +127,7 @@ export interface Database { companyName?: string | null created_at?: string firstName?: string | null + id?: string image: string lastName?: string | null type: string @@ -135,6 +137,7 @@ export interface Database { companyName?: string | null created_at?: string firstName?: string | null + id?: string image?: string lastName?: string | null type?: string @@ -145,16 +148,19 @@ export interface Database { Row: { created_at: string | null hyperboard_id: string + label: string | null registry_id: string } Insert: { created_at?: string | null hyperboard_id: string + label?: string | null registry_id: string } Update: { created_at?: string | null hyperboard_id?: string + label?: string | null registry_id?: string } Relationships: [ From 9106fe017c6098387ee4c4e2ffa2ea7c7f0a3843 Mon Sep 17 00:00:00 2001 From: jipstavenuiter Date: Fri, 3 Nov 2023 13:51:56 +0100 Subject: [PATCH 3/4] add update hyperboard-registry functionality --- ...te-or-update-hyperboard-registry-modal.tsx | 22 +++ .../admin/edit-hyperboard-registry-button.tsx | 33 ++++ components/admin/hyperboards-admin.tsx | 45 +++-- ...ate-or-update-hyperboard-registry-form.tsx | 167 ++++++++++++++++++ hooks/useFetchHyperboardRegistryById.ts | 17 ++ hooks/useMyHyperboards.ts | 2 +- 6 files changed, 271 insertions(+), 15 deletions(-) create mode 100644 components/admin/create-or-update-hyperboard-registry-modal.tsx create mode 100644 components/admin/edit-hyperboard-registry-button.tsx create mode 100644 components/forms/create-or-update-hyperboard-registry-form.tsx create mode 100644 hooks/useFetchHyperboardRegistryById.ts diff --git a/components/admin/create-or-update-hyperboard-registry-modal.tsx b/components/admin/create-or-update-hyperboard-registry-modal.tsx new file mode 100644 index 0000000..f5cb482 --- /dev/null +++ b/components/admin/create-or-update-hyperboard-registry-modal.tsx @@ -0,0 +1,22 @@ +import { ModalProps } from "@chakra-ui/modal"; +import { GenericModal } from "@/components/GenericModal"; +import { CreateOrUpdateHyperboardRegistryForm } from "@/components/forms/create-or-update-hyperboard-registry-form"; + +export const CreateOrUpdateHyperboardRegistryModal = ({ + hyperboardId, + registryId, + ...modalProps +}: { + registryId?: string; + hyperboardId: string; +} & Omit) => { + return ( + + + + ); +}; diff --git a/components/admin/edit-hyperboard-registry-button.tsx b/components/admin/edit-hyperboard-registry-button.tsx new file mode 100644 index 0000000..963fbfe --- /dev/null +++ b/components/admin/edit-hyperboard-registry-button.tsx @@ -0,0 +1,33 @@ +import { IconButton, useDisclosure } from "@chakra-ui/react"; +import { AiFillEdit } from "react-icons/ai"; +import { CreateOrUpdateHyperboardRegistryModal } from "@/components/admin/create-or-update-hyperboard-registry-modal"; + +export const EditHyperboardRegistryButton = ({ + hyperboardId, + registryId, + size, +}: { + hyperboardId: string; + registryId?: string; + size?: string; +}) => { + const { onClose, onOpen, isOpen } = useDisclosure(); + + return ( + <> + } + colorScheme="blue" + onClick={onOpen} + size={size} + /> + + + ); +}; diff --git a/components/admin/hyperboards-admin.tsx b/components/admin/hyperboards-admin.tsx index 4a671da..9f0a5e9 100644 --- a/components/admin/hyperboards-admin.tsx +++ b/components/admin/hyperboards-admin.tsx @@ -3,6 +3,7 @@ import { Card, Flex, Heading, + HStack, Table, TableContainer, Tbody, @@ -18,6 +19,7 @@ import { useMyHyperboards } from "@/hooks/useMyHyperboards"; import { DeleteHyperboardButton } from "@/components/admin/delete-hyperboard-button"; import { RemoveRegistryFromHyperboardButton } from "@/components/admin/remove-registry-from-hyperboard-button"; import { headerHeight } from "@/components/Layout"; +import { EditHyperboardRegistryButton } from "@/components/admin/edit-hyperboard-registry-button"; export const HyperboardsAdmin = () => { const { @@ -49,29 +51,44 @@ export const HyperboardsAdmin = () => { {hyperboard.name} - {!!hyperboard.registries.length && ( + {!!hyperboard.hyperboard_registries.length && ( + - {hyperboard.registries.map((registry) => ( - - - - - - ))} + {hyperboard.hyperboard_registries.map( + (hyperboardRegistry) => { + if (!hyperboardRegistry.registries) return null; + const registry = hyperboardRegistry.registries; + return ( + + + + + + + ); + }, + )}
NameLabel Chain ID
{registry.name}{registry.chain_id} - -
{registry.name}{hyperboardRegistry.label}{registry.chain_id} + + + + +
diff --git a/components/forms/create-or-update-hyperboard-registry-form.tsx b/components/forms/create-or-update-hyperboard-registry-form.tsx new file mode 100644 index 0000000..9877a66 --- /dev/null +++ b/components/forms/create-or-update-hyperboard-registry-form.tsx @@ -0,0 +1,167 @@ +import { Controller, useForm } from "react-hook-form"; +import { + Button, + FormControl, + FormErrorMessage, + FormLabel, + Input, + useToast, + VStack, +} from "@chakra-ui/react"; +import { useHypercertClient } from "@/components/providers"; +import { SingleRegistrySelector } from "@/components/admin/registry-selector"; +import { useFetchRegistryById } from "@/hooks/useFetchRegistryById"; +import { useEffect } from "react"; +import { useFetchHyperboardRegistryById } from "@/hooks/useFetchHyperboardRegistryById"; +import { useGetAuthenticatedClient } from "@/hooks/useGetAuthenticatedClient"; +import { useMyHyperboards } from "@/hooks/useMyHyperboards"; + +export interface CreateOrUpdateHyperboardRegistryFormValues { + label: string; + registry: { + value: string; + label: string; + }; +} + +export const CreateOrUpdateHyperboardRegistryForm = ({ + hyperboardId, + registryId, + initialValues = {}, + onComplete, +}: { + hyperboardId: string; + registryId?: string; + initialValues?: Partial; + onComplete?: () => void; +}) => { + const { refetch } = useMyHyperboards(); + const { data: registryData } = useFetchRegistryById(registryId); + const { data: hyperboardRegistryData } = useFetchHyperboardRegistryById( + hyperboardId, + registryId, + ); + + const { + control, + register, + setValue, + formState: { errors, isSubmitting }, + handleSubmit, + } = useForm({ + reValidateMode: "onBlur", + defaultValues: initialValues, + }); + + useEffect(() => { + if (registryData?.data) { + setValue("registry", { + value: registryData.data.id, + label: registryData.data.name, + }); + } + }, [registryData?.data, setValue]); + + useEffect(() => { + if (hyperboardRegistryData?.data?.label) { + setValue("label", hyperboardRegistryData.data.label); + } + }, [hyperboardRegistryData?.data, setValue]); + + const toast = useToast(); + const client = useHypercertClient(); + + const getClient = useGetAuthenticatedClient(); + const isEdit = !!registryId; + + const onSubmit = async ( + values: CreateOrUpdateHyperboardRegistryFormValues, + ) => { + const supabase = await getClient(); + + if (!client) { + toast({ + title: "Client is not initialized", + status: "error", + }); + return; + } + + if (!supabase) { + toast({ + title: "Supabase is not initialized", + status: "error", + }); + return; + } + + if (!hyperboardId) { + toast({ + title: "Hyperboard ID is required", + status: "error", + }); + return; + } + + const upsertValue = { + label: values.label, + registry_id: values.registry.value, + hyperboard_id: hyperboardId, + }; + + try { + await supabase.from("hyperboard_registries").upsert(upsertValue); + } catch (e) { + console.error(e); + toast({ + title: "Error", + description: "Could not create or update hyperboard registry", + status: "error", + duration: 9000, + isClosable: true, + }); + return; + } + + await refetch(); + onComplete?.(); + }; + + return ( +
+ + + Registry ID + ( + + )} + name={"registry"} + /> + {errors.registry?.message} + + + Label + + {errors.label?.message} + + + +
+ ); +}; diff --git a/hooks/useFetchHyperboardRegistryById.ts b/hooks/useFetchHyperboardRegistryById.ts new file mode 100644 index 0000000..458da40 --- /dev/null +++ b/hooks/useFetchHyperboardRegistryById.ts @@ -0,0 +1,17 @@ +import { useQuery } from "@tanstack/react-query"; +import { supabase } from "@/lib/supabase"; + +export const useFetchHyperboardRegistryById = ( + hyperboardId: string, + registryId?: string, +) => { + return useQuery(["hyperboard-registry", registryId], async () => { + if (!registryId) return null; + return supabase + .from("hyperboard_registries") + .select("*") + .eq("hyperboard_id", hyperboardId) + .eq("registry_id", registryId) + .single(); + }); +}; diff --git a/hooks/useMyHyperboards.ts b/hooks/useMyHyperboards.ts index 554478e..7fc5de4 100644 --- a/hooks/useMyHyperboards.ts +++ b/hooks/useMyHyperboards.ts @@ -13,7 +13,7 @@ export const useMyHyperboards = () => { } return supabase .from("hyperboards") - .select("*, registries!hyperboard_registries (*)") + .select("*, hyperboard_registries (*, registries (*))") .eq("admin_id", address); }, { From 3f008b3a50939beed0faa3f70585f0126fea7cff Mon Sep 17 00:00:00 2001 From: jipstavenuiter Date: Fri, 3 Nov 2023 14:31:59 +0100 Subject: [PATCH 4/4] add create hyperboard-registry functionality --- .../admin/add-hyperboard-registry-button.tsx | 33 +++++++++++++++++++ components/admin/hyperboards-admin.tsx | 5 +++ components/hyperboard/index.tsx | 4 +-- hooks/registry.ts | 1 - 4 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 components/admin/add-hyperboard-registry-button.tsx diff --git a/components/admin/add-hyperboard-registry-button.tsx b/components/admin/add-hyperboard-registry-button.tsx new file mode 100644 index 0000000..b5cab46 --- /dev/null +++ b/components/admin/add-hyperboard-registry-button.tsx @@ -0,0 +1,33 @@ +import { Button, useDisclosure } from "@chakra-ui/react"; +import { CreateOrUpdateHyperboardRegistryModal } from "@/components/admin/create-or-update-hyperboard-registry-modal"; + +export const AddHyperboardRegistryButton = ({ + hyperboardId, + registryId, + size, +}: { + hyperboardId: string; + registryId?: string; + size?: string; +}) => { + const { onClose, onOpen, isOpen } = useDisclosure(); + + return ( + <> + + + + ); +}; diff --git a/components/admin/hyperboards-admin.tsx b/components/admin/hyperboards-admin.tsx index 9f0a5e9..a4aeae9 100644 --- a/components/admin/hyperboards-admin.tsx +++ b/components/admin/hyperboards-admin.tsx @@ -1,6 +1,7 @@ import { Button, Card, + Center, Flex, Heading, HStack, @@ -20,6 +21,7 @@ import { DeleteHyperboardButton } from "@/components/admin/delete-hyperboard-but import { RemoveRegistryFromHyperboardButton } from "@/components/admin/remove-registry-from-hyperboard-button"; import { headerHeight } from "@/components/Layout"; import { EditHyperboardRegistryButton } from "@/components/admin/edit-hyperboard-registry-button"; +import { AddHyperboardRegistryButton } from "@/components/admin/add-hyperboard-registry-button"; export const HyperboardsAdmin = () => { const { @@ -93,6 +95,9 @@ export const HyperboardsAdmin = () => { )} +
+ +
))} diff --git a/components/hyperboard/index.tsx b/components/hyperboard/index.tsx index cafd36b..e9deba7 100644 --- a/components/hyperboard/index.tsx +++ b/components/hyperboard/index.tsx @@ -9,7 +9,7 @@ export interface HyperboardProps { data: HyperboardEntry[]; height: number; label: string; - onClickLabel: (registryId: string) => void; + onClickLabel: () => void; } type Leaf = { @@ -98,7 +98,7 @@ export const Hyperboard = (props: HyperboardProps) => { props.onClickLabel()} cursor={"pointer"} textTransform={"uppercase"} color={"white"} diff --git a/hooks/registry.ts b/hooks/registry.ts index b211c14..84b78bc 100644 --- a/hooks/registry.ts +++ b/hooks/registry.ts @@ -52,7 +52,6 @@ const processRegistryForDisplay = async ( const fractions = _.flatMap(fractionsResults, (x) => x.claimTokens); const ownerAddresses = _.uniq(fractions.map((x) => x.owner)) as string[]; - console.log("ownerAddresses", ownerAddresses); const claimDisplayDataResponse = await getEntryDisplayData(ownerAddresses); const claimDisplayData = _.keyBy(claimDisplayDataResponse?.data || [], (x) => x.address.toLowerCase(),