Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"@emotion/styled": "^11.11.0",
"@fuels/connectors": "^0.36.0",
"@fuels/react": "^0.36.0",
"@guildxyz/types": "^1.10.40",
"@guildxyz/types": "1.10.41",
"@hcaptcha/react-hcaptcha": "^1.4.4",
"@hookform/resolvers": "^3.3.4",
"@lexical/code": "^0.12.0",
Expand Down
Binary file added public/requirementLogos/verax.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const RequirementButton = forwardRef(

interface LinkProps extends Omit<AnchorProps, "variant"> {
label: string
imageUrl: string
imageUrl?: string
variant?: Omit<ButtonProps["variant"], "unstyled"> | "link"
}

Expand Down Expand Up @@ -65,7 +65,7 @@ const RequirementLink = ({
)}
{...anchorProps}
>
<img src={imageUrl} alt="Link image" className="size-3" />
{imageUrl && <img src={imageUrl} alt="Link image" className="size-3" />}
<span>{label}</span>
<ArrowSquareOut weight="bold" />
</Anchor>
Expand Down
41 changes: 41 additions & 0 deletions src/requirements/Verax/VeraxAttest.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {
FormErrorMessage,
FormField,
FormItem,
FormLabel,
} from "@/components/ui/Form"
import { Input } from "@/components/ui/Input"
import { useFormContext } from "react-hook-form"
import { RequirementFormProps } from "requirements/types"
import { ADDRESS_REGEX } from "utils/guildCheckout/constants"
import { VeraxCommonFields } from "./VeraxCommonFields"

export const VeraxAttest = ({ baseFieldPath }: RequirementFormProps) => {
const { control } = useFormContext()

return (
<>
<VeraxCommonFields baseFieldPath={baseFieldPath} />

<FormField
control={control}
name={`${baseFieldPath}.data.subject`}
rules={{
required: "This field is required.",
pattern: {
value: ADDRESS_REGEX,
message:
"Please input a 42 characters long, 0x-prefixed hexadecimal address.",
},
}}
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Subject</FormLabel>
<Input {...field} />
<FormErrorMessage />
</FormItem>
)}
/>
</>
)
}
41 changes: 41 additions & 0 deletions src/requirements/Verax/VeraxAttestedBy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {
FormErrorMessage,
FormField,
FormItem,
FormLabel,
} from "@/components/ui/Form"
import { Input } from "@/components/ui/Input"
import { useFormContext } from "react-hook-form"
import { RequirementFormProps } from "requirements/types"
import { ADDRESS_REGEX } from "utils/guildCheckout/constants"
import { VeraxCommonFields } from "./VeraxCommonFields"

export const VeraxAttestedBy = ({ baseFieldPath }: RequirementFormProps) => {
const { control } = useFormContext()

return (
<>
<VeraxCommonFields baseFieldPath={baseFieldPath} />

<FormField
control={control}
name={`${baseFieldPath}.data.attester`}
rules={{
required: "This field is required.",
pattern: {
value: ADDRESS_REGEX,
message:
"Please input a 42 characters long, 0x-prefixed hexadecimal address.",
},
}}
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Attester</FormLabel>
<Input {...field} />
<FormErrorMessage />
</FormItem>
)}
/>
</>
)
}
61 changes: 61 additions & 0 deletions src/requirements/Verax/VeraxCommonFields.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {
FormErrorMessage,
FormField,
FormItem,
FormLabel,
} from "@/components/ui/Form"
import { Input } from "@/components/ui/Input"
import { useFormContext } from "react-hook-form"
import { RequirementFormProps } from "requirements/types"
import { HEX_STRING_REGEX } from "./constants"

export const VeraxCommonFields = ({ baseFieldPath }: RequirementFormProps) => {
const { control } = useFormContext()

return (
<>
<FormField
control={control}
name={`${baseFieldPath}.data.schemaId`}
rules={{
required: "This field is required.",
pattern: {
value: HEX_STRING_REGEX,
message: "Please input a 0x-prefixed hexadecimal schema id.",
},
}}
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Schema ID</FormLabel>
<Input {...field} />
<FormErrorMessage />
</FormItem>
)}
/>

<FormField
control={control}
name={`${baseFieldPath}.data.key`}
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Key</FormLabel>
<Input {...field} />
<FormErrorMessage />
</FormItem>
)}
/>

<FormField
control={control}
name={`${baseFieldPath}.data.val`}
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Value</FormLabel>
<Input {...field} />
<FormErrorMessage />
</FormItem>
)}
/>
</>
)
}
93 changes: 93 additions & 0 deletions src/requirements/Verax/VeraxForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { FormControl, FormField, FormItem, FormLabel } from "@/components/ui/Form"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/Select"
import { Separator } from "@/components/ui/Separator"
import { ComponentType } from "react"
import { useFormContext, useWatch } from "react-hook-form"
import { RequirementFormProps, RequirementType } from "requirements/types"
import { VeraxAttest } from "./VeraxAttest"
import { VeraxAttestedBy } from "./VeraxAttestedBy"

const typeOptions = [
{
value: "VERAX_ATTEST",
label: "Attest",
VeraxComponent: VeraxAttest,
},
{
value: "VERAX_ATTESTED_BY",
label: "Be attested by",
VeraxComponent: VeraxAttestedBy,
},
] as const satisfies {
value: Extract<RequirementType, `VERAX_${string}`>
label: string
VeraxComponent: ComponentType<RequirementFormProps>
}[]

const VeraxForm = ({ baseFieldPath, field }: RequirementFormProps) => {
const isEditMode = !!field?.id
const { control, resetField } = useFormContext()

const type = useWatch({ name: `${baseFieldPath}.type` })

const selected = typeOptions.find((reqType) => reqType.value === type)

const resetForm = () => {
resetField(`${baseFieldPath}.data.attester`, { defaultValue: "" })
resetField(`${baseFieldPath}.data.subject`, { defaultValue: "" })
resetField(`${baseFieldPath}.data.schemaId`, { defaultValue: "" })
resetField(`${baseFieldPath}.data.key`, { defaultValue: "" })
resetField(`${baseFieldPath}.data.val`, { defaultValue: "" })
}

return (
<div className="flex flex-col items-start gap-4">
<FormField
control={control}
name={`${baseFieldPath}.type`}
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Verification level</FormLabel>
<Select
onValueChange={(e) => {
resetForm()
field.onChange(e)
}}
defaultValue={field.value}
value={field.value}
disabled={isEditMode}
>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Select one..." />
</SelectTrigger>
</FormControl>
<SelectContent>
{typeOptions.map(({ value, label }) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectContent>
</Select>
</FormItem>
)}
/>

{!!selected && (
<>
<Separator />
<selected.VeraxComponent baseFieldPath={baseFieldPath} field={field} />
</>
)}
</div>
)
}

export default VeraxForm
95 changes: 95 additions & 0 deletions src/requirements/Verax/VeraxRequirement.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { anchorVariants } from "@/components/ui/Anchor"
import { Button } from "@/components/ui/Button"
import {
Popover,
PopoverContent,
PopoverPortal,
PopoverTrigger,
} from "@/components/ui/Popover"
import { ArrowSquareOut } from "@phosphor-icons/react/dist/ssr"
import {
Requirement,
RequirementProps,
} from "components/[guild]/Requirements/components/Requirement"
import { useRequirementContext } from "components/[guild]/Requirements/components/RequirementContext"
import { DataBlock } from "components/common/DataBlock"
import { DataBlockWithCopy } from "components/common/DataBlockWithCopy"
import shortenHex from "utils/shortenHex"
import { VeraxRequirementFooter } from "./VeraxRequirementFooter"

const formatValue = (val: string) => {
let value = val
try {
value = JSON.stringify(JSON.parse(val), undefined, 2)
} catch {
// If we can't format it, we just return the original value
}

return value
}

const VeraxRequirement = (props: RequirementProps): JSX.Element => {
const { type, data } = useRequirementContext<
"VERAX_ATTEST" | "VERAX_ATTESTED_BY"
>()

return (
<Requirement
image="/requirementLogos/verax.png"
footer={<VeraxRequirementFooter />}
{...props}
>
{type === "VERAX_ATTEST" ? (
<>
<span>{"Attest "}</span>
<DataBlockWithCopy text={data.subject}>
{shortenHex(data.subject ?? "", 3)}
</DataBlockWithCopy>
<span>{" according to schema "}</span>
</>
) : (
<>
<span>{"Be attested by "}</span>
<DataBlockWithCopy text={data.attester}>
{shortenHex(data.attester ?? "", 3)}
</DataBlockWithCopy>
<span>{" according to schema "}</span>
</>
)}
<DataBlockWithCopy text={data.schemaId}>
{shortenHex(data.schemaId, 3)}
</DataBlockWithCopy>
{data.key && (
<>
<span>{" with key "}</span>
<DataBlock>{data.key}</DataBlock>
{data.val && (
<>
<span>{" and "}</span>
<Popover>
<PopoverTrigger asChild>
<Button
variant="unstyled"
className={anchorVariants({
className: "h-auto p-0",
})}
rightIcon={<ArrowSquareOut weight="bold" />}
>
a specific value
</Button>
</PopoverTrigger>
<PopoverPortal>
<PopoverContent side="bottom" className="w-max max-w-[100vw]">
<pre className="text-xs">{formatValue(data.val)}</pre>
</PopoverContent>
</PopoverPortal>
</Popover>
</>
)}
</>
)}
</Requirement>
)
}

export default VeraxRequirement
Loading