Files
TheGame/packages/web/components/Guild/GuildForm.tsx
δυς f5295c3242 Reading and Writing Profile Info From Ceramic (#943)
This is being merged for further testing so as to not block the progress of `develop` & not require more rebases.
2022-01-25 16:51:53 -05:00

368 lines
11 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
Box,
HStack,
Input,
LoadingState,
MetaButton,
MultiSelect,
Select,
Textarea,
VStack,
} from '@metafam/ds';
import { SelectOption } from '@metafam/ds/src/MultiSelect';
import { Field } from 'components/Forms/Field';
import {
DiscordRole,
GuildFragmentFragment,
GuildType_Enum,
Maybe,
useGetGuildMetadataQuery,
} from 'graphql/autogen/types';
import { useRouter } from 'next/router';
import React, { useEffect, useMemo } from 'react';
import { Controller, useForm } from 'react-hook-form';
const validations = {
guildname: {
required: true,
minLength: 3,
maxLength: 50,
},
name: {
required: true,
minLength: 4,
},
type: {
required: true,
},
discordAdminRoles: {
validate: (roles: SelectOption[]) => roles != null && roles.length > 0,
},
discordMembershipRoles: {
validate: (roles: SelectOption[]) => roles != null && roles.length > 0,
},
};
export interface EditGuildFormInputs {
guildname: string;
name: string;
description?: Maybe<string>;
discordInviteUrl?: Maybe<string>;
joinUrl?: Maybe<string>;
logoUrl?: Maybe<string>;
websiteUrl?: Maybe<string>;
twitterUrl?: Maybe<string>;
githubUrl?: Maybe<string>;
daoAddress?: Maybe<string>;
type: GuildType_Enum;
discordAdminRoles: SelectOption[];
discordMembershipRoles: SelectOption[];
}
const getDefaultFormValues = (
guild: GuildFragmentFragment,
metadata: GuildMetadata | undefined,
roleOptions: SelectOption[],
): EditGuildFormInputs => {
const discordAdminRoleIds = metadata?.discord_metadata.administratorRoleIds;
const discordAdminRoleOptions =
metadata == null || discordAdminRoleIds == null
? []
: roleOptions.filter((r) => discordAdminRoleIds.includes(r.value));
const discordMembershipRoleIds = metadata?.discord_metadata.membershipRoleIds;
const discordMembershipRoleOptions =
metadata == null || discordMembershipRoleIds == null
? []
: roleOptions.filter((r) => discordMembershipRoleIds.includes(r.value));
return {
guildname: guild.guildname,
name: guild.name,
description: guild.description || '',
discordInviteUrl: guild.discord_invite_url || '',
joinUrl: guild.join_button_url || '',
logoUrl: guild.logo || '',
websiteUrl: guild.website_url || '',
twitterUrl: guild.twitter_url || '',
githubUrl: guild.github_url || '',
daoAddress: guild.moloch_address || '',
type: guild.type,
discordAdminRoles: discordAdminRoleOptions,
discordMembershipRoles: discordMembershipRoleOptions,
};
};
type Props = {
workingGuild: GuildFragmentFragment;
onSubmit: (data: EditGuildFormInputs) => void;
success?: boolean;
submitting?: boolean;
};
type GuildMetadata = {
discordRoles: DiscordRole[];
discord_metadata: {
membershipRoleIds: string[];
administratorRoleIds: string[];
};
};
export const GuildForm: React.FC<Props> = ({
workingGuild,
onSubmit,
success,
submitting,
}) => {
const router = useRouter();
const [getGuildMetadataResponse, getGuildMetadata] = useGetGuildMetadataQuery(
{
variables: { id: workingGuild.id },
},
);
const fetchingRoles =
getGuildMetadataResponse == null || getGuildMetadataResponse.fetching;
const guildMetadata = getGuildMetadataResponse.data
?.guild_metadata[0] as GuildMetadata;
const loadGuildMetadata = () => {
getGuildMetadata({ requestPolicy: 'network-only' });
};
const roleOptions = useMemo(() => {
const allDiscordRoles = guildMetadata?.discordRoles || [];
return allDiscordRoles.map((role) => ({
label: role.name,
value: role.id,
}));
}, [guildMetadata]);
const {
register,
formState: { errors },
handleSubmit,
reset,
control,
} = useForm<EditGuildFormInputs>({
mode: 'onTouched',
});
useEffect(() => {
const values = getDefaultFormValues(
workingGuild,
guildMetadata,
roleOptions,
);
// https://react-hook-form.com/v6/api#useForm
reset(values);
}, [workingGuild, guildMetadata, roleOptions, reset]);
return (
<Box w="100%" maxW="40rem">
<VStack>
<Field label="Guildname" error={errors.guildname}>
<Input
{...register('guildname', {
required: {
value: true,
message: 'This is a required field.',
},
minLength: {
value: validations.guildname.minLength,
message: `Must be at least ${validations.guildname.minLength} characters.`,
},
maxLength: {
value: validations.guildname.maxLength,
message: `Must be no more than ${validations.guildname.maxLength} characters.`,
},
})}
isInvalid={!!errors.guildname}
background="dark"
/>
<span>A unique identifier for your guild, like a username.</span>
</Field>
<Field label="Name" error={errors.name}>
<Input
{...register('name', {
required: {
value: true,
message: 'This is a required field.',
},
minLength: {
value: validations.guildname.minLength,
message: `Must be at least ${validations.guildname.minLength} characters.`,
},
})}
isInvalid={!!errors.name}
background="dark"
/>
<span>
Your guild&apos;s name. This is what will show throughout MetaGame.
</span>
</Field>
<Field label="Description" error={errors.description}>
<Textarea
placeholder="Whats your guild all about?"
{...register('description')}
background="dark"
/>
</Field>
<Field label="Logo URL" error={errors.logoUrl}>
<Input {...register('logoUrl')} background="dark" />
<span>
Logos should be square (same width and height) and reasonably
high-resolution.
</span>
</Field>
<Field label="Website URL" error={errors.websiteUrl}>
<Input {...register('websiteUrl')} background="dark" />
<span>Your guild&apos;s main website.</span>
</Field>
<Field label="Discord Invite URL" error={errors.discordInviteUrl}>
<Input
placeholder="https://discord.gg/fHvx7gu"
{...register('discordInviteUrl')}
background="dark"
/>
<span>A public invite URL for your Discord server.</span>
</Field>
<Field label="Join URL" error={errors.joinUrl}>
<Input {...register('joinUrl')} background="dark" />
<span>
The URL that the <q>JOIN</q> button will point to.
</span>
</Field>
<Field label="Twitter URL" error={errors.twitterUrl}>
<Input
placeholder="https://twitter.com/…"
{...register('twitterUrl')}
background="dark"
/>
<span>Your guild&apos;s home on Twitter.</span>
</Field>
<Field label="GitHub URL" error={errors.githubUrl}>
<Input
placeholder="https://github.com/…"
{...register('githubUrl')}
background="dark"
/>
<span>Your guild&apos;s home on GitHub.</span>
</Field>
<Field label="DAO Address" error={errors.daoAddress}>
<Input
placeholder="0x…"
{...register('daoAddress')}
background="dark"
/>
<span>If your guild has a DAO, enter its address here.</span>
</Field>
<Field label="Type" error={errors.type}>
<Select
{...register('type', {
required: {
value: true,
message: 'This is a required field.',
},
})}
isInvalid={!!errors.type}
background="dark"
color="white"
>
{Object.entries(GuildType_Enum).map(([key, value]) => (
<option key={value} value={value}>
{key}
</option>
))}
</Select>
</Field>
<Box py={5}>
{fetchingRoles ? (
<Box>
Fetching roles from Discord
<LoadingState />
</Box>
) : (
<>
<Field
label="Administrator Roles"
error={
errors.discordAdminRoles != null
? {
type: 'validate',
message: 'Required',
}
: undefined
}
>
<Controller
name="discordAdminRoles"
{...{ control }}
rules={validations.discordAdminRoles}
render={(props) => (
<MultiSelect isMulti options={roleOptions} {...props} />
)}
/>
<span>
Members of your Discord server with these roles will have
administration privileges.
</span>
</Field>
<Field
label="Membership Roles"
error={
errors.discordMembershipRoles != null
? {
type: 'validate',
message: 'Required',
}
: undefined
}
>
<Controller
name="discordMembershipRoles"
{...{ control }}
rules={validations.discordMembershipRoles}
render={(props) => (
<MultiSelect isMulti options={roleOptions} {...props} />
)}
/>
<span>
Members of your Discord server with these roles will be
considered members of this guild.
</span>
</Field>
</>
)}
</Box>
<HStack justify="space-between" mt={10} w="100%">
<MetaButton
isLoading={submitting}
loadingText="Submitting information…"
onClick={handleSubmit(onSubmit)}
isDisabled={success}
bg="purple.500"
>
Submit Guild Information
</MetaButton>
<MetaButton
fontSize="xs"
bg="purple.300"
colorScheme="facebook"
isDisabled={fetchingRoles}
onClick={loadGuildMetadata}
>
Reload Roles
</MetaButton>
<MetaButton
onClick={() => router.push('/')}
isDisabled={submitting || success}
>
Cancel
</MetaButton>
</HStack>
</VStack>
</Box>
);
};