From 157aea0418a898204076e42cd6a130ec363f6fb5 Mon Sep 17 00:00:00 2001 From: jipstavenuiter Date: Tue, 31 Oct 2023 11:01:31 +0100 Subject: [PATCH] create single migration file and add support for hyperboard sponsor metadata --- ...-update-default-sponsor-metadata-modal.tsx | 13 + .../admin/default-sponsor-metadata-admin.tsx | 88 +++++ ...r-update-default-sponsor-metadata-form.tsx | 125 +++++++ hooks/useCreateDefaultSponsorMetadata.ts | 29 ++ hooks/useFetchDefaultSponsorMetadata.tsx | 8 + pages/admin/[page].tsx | 7 + supabase/migrations/20231027150411_init.sql | 307 ++++++++++++++++++ .../20231017122116_init.sql | 0 .../20231017140135_rename_registries.sql | 0 .../20231018084759_nested_registries.sql | 0 .../20231018133039_add_authentication.sql | 0 .../20231019083311_enable_rls.sql | 0 .../20231019083656_rename_tables.sql | 0 .../20231019185743_add_registry_policies.sql | 0 ...20090638_add_zuzalu_donations_registry.sql | 0 ...20231024065840_add_delete_claim_policy.sql | 0 ...4351_add_rls_for_hyperboard_registries.sql | 0 ...20231024120828_add_rls_for_hyperboards.sql | 0 ...0231025103020_add_claim_id_to_registry.sql | 0 .../20231025134411_add_blueprints_table.sql | 0 .../20231027104055_add_owner_to_claim.sql | 0 types/database-entities.ts | 5 + types/database.ts | 63 ++-- 23 files changed, 612 insertions(+), 33 deletions(-) create mode 100644 components/admin/create-or-update-default-sponsor-metadata-modal.tsx create mode 100644 components/admin/default-sponsor-metadata-admin.tsx create mode 100644 components/forms/create-or-update-default-sponsor-metadata-form.tsx create mode 100644 hooks/useCreateDefaultSponsorMetadata.ts create mode 100644 hooks/useFetchDefaultSponsorMetadata.tsx create mode 100644 supabase/migrations/20231027150411_init.sql rename supabase/{migrations => old_migrations}/20231017122116_init.sql (100%) rename supabase/{migrations => old_migrations}/20231017140135_rename_registries.sql (100%) rename supabase/{migrations => old_migrations}/20231018084759_nested_registries.sql (100%) rename supabase/{migrations => old_migrations}/20231018133039_add_authentication.sql (100%) rename supabase/{migrations => old_migrations}/20231019083311_enable_rls.sql (100%) rename supabase/{migrations => old_migrations}/20231019083656_rename_tables.sql (100%) rename supabase/{migrations => old_migrations}/20231019185743_add_registry_policies.sql (100%) rename supabase/{migrations => old_migrations}/20231020090638_add_zuzalu_donations_registry.sql (100%) rename supabase/{migrations => old_migrations}/20231024065840_add_delete_claim_policy.sql (100%) rename supabase/{migrations => old_migrations}/20231024084351_add_rls_for_hyperboard_registries.sql (100%) rename supabase/{migrations => old_migrations}/20231024120828_add_rls_for_hyperboards.sql (100%) rename supabase/{migrations => old_migrations}/20231025103020_add_claim_id_to_registry.sql (100%) rename supabase/{migrations => old_migrations}/20231025134411_add_blueprints_table.sql (100%) rename supabase/{migrations => old_migrations}/20231027104055_add_owner_to_claim.sql (100%) diff --git a/components/admin/create-or-update-default-sponsor-metadata-modal.tsx b/components/admin/create-or-update-default-sponsor-metadata-modal.tsx new file mode 100644 index 0000000..0ebca25 --- /dev/null +++ b/components/admin/create-or-update-default-sponsor-metadata-modal.tsx @@ -0,0 +1,13 @@ +import { GenericModal } from "@/components/GenericModal"; +import { ModalProps } from "@chakra-ui/modal"; +import { CreateOrUpdateDefaultSponsorMetadataForm } from "@/components/forms/create-or-update-default-sponsor-metadata-form"; + +export const CreateOrUpdateDefaultSponsorMetadataModal = ({ + ...modalProps +}: Omit) => { + return ( + + + + ); +}; diff --git a/components/admin/default-sponsor-metadata-admin.tsx b/components/admin/default-sponsor-metadata-admin.tsx new file mode 100644 index 0000000..0e5aeb7 --- /dev/null +++ b/components/admin/default-sponsor-metadata-admin.tsx @@ -0,0 +1,88 @@ +import { useFetchDefaultSponsorMetadata } from "@/hooks/useFetchDefaultSponsorMetadata"; +import { + Button, + Card, + Center, + Flex, + Heading, + Spinner, + Table, + TableContainer, + Tbody, + Td, + Th, + Thead, + Tr, + useDisclosure, + VStack, +} from "@chakra-ui/react"; +import { formatAddress } from "@/utils/formatting"; +import { CreateOrUpdateDefaultSponsorMetadataModal } from "@/components/admin/create-or-update-default-sponsor-metadata-modal"; + +export const DefaultSponsorMetadataAdmin = () => { + const { data, isLoading } = useFetchDefaultSponsorMetadata(); + const { + isOpen: isOpenCreate, + onClose: onCloseCreate, + onOpen: onOpenCreate, + } = useDisclosure(); + + if (isLoading) { + return ; + } + + return ( + + + + + {data?.data?.length ? ( + + + + + + + + + + + + + + {data.data.map((defaultSponsorMetadata) => ( + + + + + + + + + ))} + +
AddressTypeCompany nameFirst nameLast nameImage
{formatAddress(defaultSponsorMetadata.address)}{defaultSponsorMetadata.type}{defaultSponsorMetadata.companyName}{defaultSponsorMetadata.firstName}{defaultSponsorMetadata.lastName} + + {defaultSponsorMetadata.image} + +
+
+ ) : ( +
+ No default sponsor metadata found +
+ )} +
+
+ +
+ ); +}; diff --git a/components/forms/create-or-update-default-sponsor-metadata-form.tsx b/components/forms/create-or-update-default-sponsor-metadata-form.tsx new file mode 100644 index 0000000..72ac239 --- /dev/null +++ b/components/forms/create-or-update-default-sponsor-metadata-form.tsx @@ -0,0 +1,125 @@ +import { useForm } from "react-hook-form"; +import { + Button, + FormControl, + FormErrorMessage, + FormLabel, + Input, + useToast, + VStack, +} from "@chakra-ui/react"; +import { useCreateDefaultSponsorMetadata } from "@/hooks/useCreateDefaultSponsorMetadata"; + +interface CreateOrUpdateDefaultSponsorMetadataFormValues { + address: string; + type: string; + companyName: string; + firstName: string; + lastName: string; + image: string; +} +export const CreateOrUpdateDefaultSponsorMetadataForm = ({ + initialValues, + onCompleted, +}: { + initialValues?: CreateOrUpdateDefaultSponsorMetadataFormValues; + onCompleted?: () => void; +}) => { + const { + handleSubmit, + register, + formState: { errors }, + } = useForm({ + defaultValues: initialValues, + }); + + const { mutateAsync: createDefaultSponsorMetadata } = + useCreateDefaultSponsorMetadata(); + const toast = useToast(); + + const onSubmitted = async ( + values: CreateOrUpdateDefaultSponsorMetadataFormValues, + ) => { + try { + await createDefaultSponsorMetadata({ data: values }); + toast({ + title: "Success", + description: "Default sponsor metadata created", + status: "success", + duration: 9000, + isClosable: true, + }); + onCompleted?.(); + } catch (e) { + console.log(e); + } + }; + + return ( +
+ + + Address + + {errors.address?.message} + + + Type + + {errors.type?.message} + + + Company name + + {errors.companyName?.message} + + + First name + + {errors.firstName?.message} + + + Last name + + {errors.lastName?.message} + + + Image + + {errors.image?.message} + + + +
+ ); +}; diff --git a/hooks/useCreateDefaultSponsorMetadata.ts b/hooks/useCreateDefaultSponsorMetadata.ts new file mode 100644 index 0000000..4e3bd08 --- /dev/null +++ b/hooks/useCreateDefaultSponsorMetadata.ts @@ -0,0 +1,29 @@ +import { useGetAuthenticatedClient } from "@/hooks/useGetAuthenticatedClient"; +import { useMutation } from "wagmi"; +import { useToast } from "@chakra-ui/react"; +import { DefaultSponsorMetadataInsert } from "@/types/database-entities"; + +export const useCreateDefaultSponsorMetadata = () => { + const getClient = useGetAuthenticatedClient(); + const toast = useToast(); + + return useMutation( + async ({ data }: { data: DefaultSponsorMetadataInsert }) => { + const client = await getClient(); + + if (!client) { + toast({ + title: "Error", + description: + "You must be logged in to create default sponsor metadata", + status: "error", + duration: 5000, + isClosable: true, + }); + return null; + } + + return client.from("sponsor_metadata").insert([data]); + }, + ); +}; diff --git a/hooks/useFetchDefaultSponsorMetadata.tsx b/hooks/useFetchDefaultSponsorMetadata.tsx new file mode 100644 index 0000000..a023cd8 --- /dev/null +++ b/hooks/useFetchDefaultSponsorMetadata.tsx @@ -0,0 +1,8 @@ +import { useQuery } from "@tanstack/react-query"; +import { supabase } from "@/lib/supabase"; + +export const useFetchDefaultSponsorMetadata = () => { + return useQuery(["default-sponsor-metadata"], async () => { + return supabase.from("default_sponsor_metadata").select("*"); + }); +}; diff --git a/pages/admin/[page].tsx b/pages/admin/[page].tsx index 20b79c2..f6ea022 100644 --- a/pages/admin/[page].tsx +++ b/pages/admin/[page].tsx @@ -7,12 +7,18 @@ import { RegistriesAdmin } from "@/components/admin/registries-admin"; import { headerHeight } from "@/components/Layout"; import { MyBlueprintsAdmin } from "@/components/admin/my-blueprints-admin"; import { MyClaimsAdmin } from "@/components/admin/my-claims-admin"; +import { DefaultSponsorMetadataAdmin } from "@/components/admin/default-sponsor-metadata-admin"; const SIDEBAR_ITEMS = [ { name: "Hyperboards", icon: FiHome, href: "/admin/hyperboards/" }, { name: "Registries", icon: FiTrendingUp, href: "/admin/registries/" }, { name: "My claims", icon: FiCompass, href: "/admin/my-claims/" }, { name: "My blueprints", icon: FiCompass, href: "/admin/my-blueprints/" }, + { + name: "Default metadata", + icon: FiCompass, + href: "/admin/default-sponsor-metadata/", + }, ]; const Admin = () => { @@ -28,6 +34,7 @@ const Admin = () => { {page === "registries" && } {page === "my-claims" && } {page === "my-blueprints" && } + {page === "default-sponsor-metadata" && } ); diff --git a/supabase/migrations/20231027150411_init.sql b/supabase/migrations/20231027150411_init.sql new file mode 100644 index 0000000..13c9149 --- /dev/null +++ b/supabase/migrations/20231027150411_init.sql @@ -0,0 +1,307 @@ +create extension if not exists citext + with + schema extensions; + + +create table + public.users +( + id uuid null, + created_at timestamp with time zone not null default now(), + auth json not null default '{}'::json, + email text null, + address text not null, + constraint users_pkey primary key (address) +) tablespace pg_default; + + + + +create table + public.hyperboards +( + id uuid not null default gen_random_uuid(), + created_at timestamp with time zone null default now(), + name text not null, + admin_id text not null, + chain_id integer not null, + constraint hyperboards_pkey primary key (id) +) tablespace pg_default; + + + +create table + public.registries +( + id uuid not null default gen_random_uuid(), + created_at timestamp with time zone not null default now(), + name text not null, + description text not null, + admin_id text not null, + hidden boolean not null default false, + chain_id integer not null, + constraint registries_optimism_pkey primary key (id) +) tablespace pg_default; + +create table + public.hyperboard_registries +( + created_at timestamp with time zone null default now(), + hyperboard_id uuid not null, + registry_id uuid not null, + constraint hyperboard_registries_pkey primary key (hyperboard_id, registry_id), + constraint hyperboard_registries_hyperboard_id_fkey foreign key (hyperboard_id) references hyperboards (id), + constraint hyperboard_registries_registry_id_fkey foreign key (registry_id) references registries (id) +) tablespace pg_default; + +create table + public.blueprints +( + id bigint generated by default as identity, + created_at timestamp with time zone not null default now(), + admin_id extensions.citext not null, + form_values json not null, + minter_address extensions.citext not null, + registry_id uuid not null, + constraint blueprints_pkey primary key (id), + constraint blueprints_admin_id_fkey foreign key (admin_id) references users (address), + constraint blueprints_registry_id_fkey foreign key (registry_id) references registries (id) on delete cascade +) tablespace pg_default; + +create table + public.claims +( + id uuid not null default gen_random_uuid(), + created_at timestamp with time zone not null default now(), + registry_id uuid not null, + hypercert_id text not null, + chain_id integer not null, + admin_id extensions.citext not null, + owner_id extensions.citext not null, + constraint hyperboard_claims_pkey primary key (id), + constraint claims_registry_id_fkey foreign key (registry_id) references registries (id) on delete cascade +) tablespace pg_default; + + + +create table + public.default_sponsor_metadata +( + id uuid not null default gen_random_uuid(), + created_at timestamp with time zone not null default now(), + type text not null, + "companyName" text null, + "firstName" text null, + "lastName" text null, + image text not null, + address extensions.citext not null, + constraint hyperboard_sponsor_metadata_pkey primary key (id) +) tablespace pg_default; + + +create table + public.zuzalu_donations +( + id bigint generated by default as identity, + created_at timestamp with time zone not null default now(), + address text not null, + email text not null, + amount text null, + constraint zuzalu_donations_pkey primary key (id) +) tablespace pg_default; + +alter table "public"."hyperboard_registries" + enable row level security; + +alter table "public"."hyperboards" + enable row level security; + + +alter table "public"."hyperboard_registries" + validate constraint "hyperboard_registries_hyperboard_id_fkey"; + +alter table "public"."hyperboard_registries" + add constraint "hyperboard_registries_registries_id_fkey" FOREIGN KEY (registry_id) REFERENCES registries (id) not valid; + +alter table "public"."hyperboard_registries" + validate constraint "hyperboard_registries_registries_id_fkey"; + +alter table "public"."users" + enable row level security; + + +create policy "Enable insert for authenticated users only" + on "public"."hyperboards" + as permissive + for insert + to authenticated + with check (true); + + +create policy "Enable read access for all users" + on "public"."hyperboards" + as permissive + for select + to public + using (true); + + +create policy "Enable update for users based on address" + on "public"."hyperboards" + as permissive + for update + to public + using (((auth.jwt() ->> 'address'::text) = admin_id)) + with check (((auth.jwt() ->> 'address'::text) = admin_id)); + +alter table "public"."claims" + enable row level security; + +alter table "public"."default_sponsor_metadata" + enable row level security; + +alter table "public"."registries" + enable row level security; + +create policy "Enable read access for all users" + on "public"."claims" + as permissive + for select + to public + using (true); + + +create policy "Enable read access for all users" + on "public"."hyperboard_registries" + as permissive + for select + to public + using (true); + + +create policy "Enable read access for all users" + on "public"."default_sponsor_metadata" + as permissive + for select + to public + using (true); + + +create policy "Enable read access for all users" + on "public"."registries" + as permissive + for select + to public + using (true); + +alter table "public"."claims" + drop constraint "claims_registry_id_fkey"; + +alter table "public"."claims" + add constraint "claims_registry_id_fkey" FOREIGN KEY (registry_id) REFERENCES registries (id) ON DELETE CASCADE not valid; + +alter table "public"."claims" + validate constraint "claims_registry_id_fkey"; + +create policy "Enable insert for authenticated users only" + on "public"."claims" + as permissive + for insert + to authenticated + with check (true); + + +create policy "Allow owners of registries to delete them based on address" + on "public"."registries" + as permissive + for delete + to public + using (((auth.jwt() ->> 'address'::text) = admin_id)); + + +create policy "Allow owners of registries to update based on address" + on "public"."registries" + as permissive + for update + to public + using (((auth.jwt() ->> 'address'::text) = admin_id)) + with check (((auth.jwt() ->> 'address'::text) = admin_id)); + + +create policy "Enable insert for authenticated users only" + on "public"."registries" + as permissive + for insert + to authenticated + with check (true); + + +alter table "public"."zuzalu_donations" + enable row level security; + +create policy "Allow insert for everybody" + on "public"."zuzalu_donations" + as permissive + for insert + to public + with check (true); + +create policy "Delete claims when you are the owner" + on "public"."claims" + as permissive + for delete + to public + using (((auth.jwt() ->> 'address'::text) = admin_id)); + + +create policy "Only allow for owner of the hyperboard" + on "public"."hyperboard_registries" + as permissive + for insert + to public + with check (((auth.jwt() ->> 'address'::text) IN (SELECT hyperboards.admin_id + FROM hyperboards + WHERE (hyperboard_registries.hyperboard_id = hyperboards.id)))); + +create policy "Only allow for owner of hyperboard" + on "public"."hyperboard_registries" + as permissive + for delete + to public + using (((auth.jwt() ->> 'address'::text) IN (SELECT hyperboards.admin_id + FROM hyperboards + WHERE (hyperboard_registries.hyperboard_id = hyperboards.id)))); + + +create policy "Enable delete for users based on address" + on "public"."hyperboards" + as permissive + for delete + to public + using (((auth.jwt() ->> 'address'::text) = admin_id)); + +alter table "public"."blueprints" enable row level security; + +create policy "Enable read access for all users" + on "public"."blueprints" + as permissive + for select + to public + using (true); + + +create policy "Only owners of registry can add a blueprint to it" + on "public"."blueprints" + as permissive + for insert + to public + with check (((auth.jwt() ->> 'address'::text) IN (SELECT registries.admin_id + FROM registries + WHERE (registries.id = blueprints.registry_id)))); + +create policy "Owners of blueprint or minters of blueprint can delete" + on "public"."blueprints" + as permissive + for delete + to public + using ((((auth.jwt() ->> 'address'::text) = admin_id) OR ((auth.jwt() ->> 'address'::text) = minter_address))); diff --git a/supabase/migrations/20231017122116_init.sql b/supabase/old_migrations/20231017122116_init.sql similarity index 100% rename from supabase/migrations/20231017122116_init.sql rename to supabase/old_migrations/20231017122116_init.sql diff --git a/supabase/migrations/20231017140135_rename_registries.sql b/supabase/old_migrations/20231017140135_rename_registries.sql similarity index 100% rename from supabase/migrations/20231017140135_rename_registries.sql rename to supabase/old_migrations/20231017140135_rename_registries.sql diff --git a/supabase/migrations/20231018084759_nested_registries.sql b/supabase/old_migrations/20231018084759_nested_registries.sql similarity index 100% rename from supabase/migrations/20231018084759_nested_registries.sql rename to supabase/old_migrations/20231018084759_nested_registries.sql diff --git a/supabase/migrations/20231018133039_add_authentication.sql b/supabase/old_migrations/20231018133039_add_authentication.sql similarity index 100% rename from supabase/migrations/20231018133039_add_authentication.sql rename to supabase/old_migrations/20231018133039_add_authentication.sql diff --git a/supabase/migrations/20231019083311_enable_rls.sql b/supabase/old_migrations/20231019083311_enable_rls.sql similarity index 100% rename from supabase/migrations/20231019083311_enable_rls.sql rename to supabase/old_migrations/20231019083311_enable_rls.sql diff --git a/supabase/migrations/20231019083656_rename_tables.sql b/supabase/old_migrations/20231019083656_rename_tables.sql similarity index 100% rename from supabase/migrations/20231019083656_rename_tables.sql rename to supabase/old_migrations/20231019083656_rename_tables.sql diff --git a/supabase/migrations/20231019185743_add_registry_policies.sql b/supabase/old_migrations/20231019185743_add_registry_policies.sql similarity index 100% rename from supabase/migrations/20231019185743_add_registry_policies.sql rename to supabase/old_migrations/20231019185743_add_registry_policies.sql diff --git a/supabase/migrations/20231020090638_add_zuzalu_donations_registry.sql b/supabase/old_migrations/20231020090638_add_zuzalu_donations_registry.sql similarity index 100% rename from supabase/migrations/20231020090638_add_zuzalu_donations_registry.sql rename to supabase/old_migrations/20231020090638_add_zuzalu_donations_registry.sql diff --git a/supabase/migrations/20231024065840_add_delete_claim_policy.sql b/supabase/old_migrations/20231024065840_add_delete_claim_policy.sql similarity index 100% rename from supabase/migrations/20231024065840_add_delete_claim_policy.sql rename to supabase/old_migrations/20231024065840_add_delete_claim_policy.sql diff --git a/supabase/migrations/20231024084351_add_rls_for_hyperboard_registries.sql b/supabase/old_migrations/20231024084351_add_rls_for_hyperboard_registries.sql similarity index 100% rename from supabase/migrations/20231024084351_add_rls_for_hyperboard_registries.sql rename to supabase/old_migrations/20231024084351_add_rls_for_hyperboard_registries.sql diff --git a/supabase/migrations/20231024120828_add_rls_for_hyperboards.sql b/supabase/old_migrations/20231024120828_add_rls_for_hyperboards.sql similarity index 100% rename from supabase/migrations/20231024120828_add_rls_for_hyperboards.sql rename to supabase/old_migrations/20231024120828_add_rls_for_hyperboards.sql diff --git a/supabase/migrations/20231025103020_add_claim_id_to_registry.sql b/supabase/old_migrations/20231025103020_add_claim_id_to_registry.sql similarity index 100% rename from supabase/migrations/20231025103020_add_claim_id_to_registry.sql rename to supabase/old_migrations/20231025103020_add_claim_id_to_registry.sql diff --git a/supabase/migrations/20231025134411_add_blueprints_table.sql b/supabase/old_migrations/20231025134411_add_blueprints_table.sql similarity index 100% rename from supabase/migrations/20231025134411_add_blueprints_table.sql rename to supabase/old_migrations/20231025134411_add_blueprints_table.sql diff --git a/supabase/migrations/20231027104055_add_owner_to_claim.sql b/supabase/old_migrations/20231027104055_add_owner_to_claim.sql similarity index 100% rename from supabase/migrations/20231027104055_add_owner_to_claim.sql rename to supabase/old_migrations/20231027104055_add_owner_to_claim.sql diff --git a/types/database-entities.ts b/types/database-entities.ts index 94586e4..8d1590c 100644 --- a/types/database-entities.ts +++ b/types/database-entities.ts @@ -16,3 +16,8 @@ export type HyperboardRegistryEntity = Database["public"]["Tables"]["hyperboard_registries"]["Row"]; export type HyperboardRegistryInsert = Database["public"]["Tables"]["hyperboard_registries"]["Insert"]; + +export type DefaultSponsorMetadataEntity = + Database["public"]["Tables"]["default_sponsor_metadata"]["Row"]; +export type DefaultSponsorMetadataInsert = + Database["public"]["Tables"]["default_sponsor_metadata"]["Insert"]; diff --git a/types/database.ts b/types/database.ts index b872c74..2303917 100644 --- a/types/database.ts +++ b/types/database.ts @@ -111,6 +111,36 @@ export interface Database { } ] } + default_sponsor_metadata: { + Row: { + address: string + companyName: string | null + created_at: string + firstName: string | null + image: string + lastName: string | null + type: string + } + Insert: { + address: string + companyName?: string | null + created_at?: string + firstName?: string | null + image: string + lastName?: string | null + type: string + } + Update: { + address?: string + companyName?: string | null + created_at?: string + firstName?: string | null + image?: string + lastName?: string | null + type?: string + } + Relationships: [] + } hyperboard_registries: { Row: { created_at: string | null @@ -196,39 +226,6 @@ export interface Database { } Relationships: [] } - sponsor_metadata: { - Row: { - address: string - companyName: string | null - created_at: string - firstName: string | null - id: string - image: string - lastName: string | null - type: string - } - Insert: { - address: string - companyName?: string | null - created_at?: string - firstName?: string | null - id?: string - image: string - lastName?: string | null - type: string - } - Update: { - address?: string - companyName?: string | null - created_at?: string - firstName?: string | null - id?: string - image?: string - lastName?: string | null - type?: string - } - Relationships: [] - } users: { Row: { address: string