diff --git a/generated/graphql.tsx b/generated/graphql.tsx index 06c0fd658..32db21319 100644 --- a/generated/graphql.tsx +++ b/generated/graphql.tsx @@ -43,6 +43,38 @@ export type QueryGetUserByIdentifierArgs = { identifier: Scalars['String']; }; +export type UpdateUserProfileInput = { + twitterName?: Maybe; + customUrlPath?: Maybe; + twitchName?: Maybe; + youtubeId?: Maybe; + country?: Maybe; + bio?: Maybe; + sensStick?: Maybe; + sensMotion?: Maybe; + weaponPool?: Maybe>; +}; + +export type Mutation = { + __typename?: 'Mutation'; + updateUserProfile: Scalars['Boolean']; +}; + + +export type MutationUpdateUserProfileArgs = { + profile?: Maybe; +}; + +export type UpdateUserProfileMutationVariables = Exact<{ + profile: UpdateUserProfileInput; +}>; + + +export type UpdateUserProfileMutation = ( + { __typename?: 'Mutation' } + & Pick +); + export type GetUserByIdentifierQueryVariables = Exact<{ identifier: Scalars['String']; }>; @@ -61,6 +93,36 @@ export type GetUserByIdentifierQuery = ( ); +export const UpdateUserProfileDocument = gql` + mutation UpdateUserProfile($profile: UpdateUserProfileInput!) { + updateUserProfile(profile: $profile) +} + `; +export type UpdateUserProfileMutationFn = Apollo.MutationFunction; + +/** + * __useUpdateUserProfileMutation__ + * + * To run a mutation, you first call `useUpdateUserProfileMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useUpdateUserProfileMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [updateUserProfileMutation, { data, loading, error }] = useUpdateUserProfileMutation({ + * variables: { + * profile: // value for 'profile' + * }, + * }); + */ +export function useUpdateUserProfileMutation(baseOptions?: Apollo.MutationHookOptions) { + return Apollo.useMutation(UpdateUserProfileDocument, baseOptions); + } +export type UpdateUserProfileMutationHookResult = ReturnType; +export type UpdateUserProfileMutationResult = Apollo.MutationResult; +export type UpdateUserProfileMutationOptions = Apollo.BaseMutationOptions; export const GetUserByIdentifierDocument = gql` query GetUserByIdentifier($identifier: String!) { getUserByIdentifier(identifier: $identifier) { diff --git a/graphql/schema/index.ts b/graphql/schema/index.ts index 9132756bc..14cfe600d 100644 --- a/graphql/schema/index.ts +++ b/graphql/schema/index.ts @@ -13,7 +13,7 @@ export const schema = makeSchema({ typegen: path.join(process.cwd(), "nexus-typegen.ts"), }, nonNullDefaults: { - input: true, + input: false, output: true, }, typegenAutoConfig: { diff --git a/graphql/schema/user.ts b/graphql/schema/user.ts index 56081cf5f..39d08bca2 100644 --- a/graphql/schema/user.ts +++ b/graphql/schema/user.ts @@ -100,7 +100,7 @@ export const UpdateUserProfileInput = inputObjectType({ export const Mutation = mutationType({ definition(t) { t.field("updateUserProfile", { - type: Profile, + type: "Boolean", nullable: false, args: { profile: UpdateUserProfileInput, @@ -113,12 +113,14 @@ export const Mutation = mutationType({ console.log({ session }); // FIXME: set custom url to lowerCase - return await ctx.prisma.profile.upsert({ + await ctx.prisma.profile.upsert({ create: { user: { connect: { id: 4 } }, ...args.profile }, // FIXME: doing it like this makes removing values impossible? update: args.profile, where: { userId: 4 }, }); + + return true; }, }); }, diff --git a/nexus-typegen.ts b/nexus-typegen.ts index 59d3440fe..0b5bd43bc 100644 --- a/nexus-typegen.ts +++ b/nexus-typegen.ts @@ -21,15 +21,15 @@ declare global { export interface NexusGenInputs { UpdateUserProfileInput: { // input type - bio: string; // String! - country: string; // String! - customUrlPath: string; // String! - sensMotion: number; // Float! - sensStick: number; // Float! - twitchName: string; // String! - twitterName: string; // String! - weaponPool: string[]; // [String!]! - youtubeId: string; // String! + bio?: string | null; // String + country?: string | null; // String + customUrlPath?: string | null; // String + sensMotion?: number | null; // Float + sensStick?: number | null; // Float + twitchName?: string | null; // String + twitterName?: string | null; // String + weaponPool?: string[] | null; // [String!] + youtubeId?: string | null; // String } } @@ -62,7 +62,7 @@ export interface NexusGenAllTypes extends NexusGenRootTypes { export interface NexusGenFieldTypes { Mutation: { // field return type - updateUserProfile: NexusGenRootTypes['Profile']; // Profile! + updateUserProfile: boolean; // Boolean! } Profile: { // field return type bio: string | null; // String @@ -90,7 +90,7 @@ export interface NexusGenFieldTypes { export interface NexusGenArgTypes { Mutation: { updateUserProfile: { // args - profile: NexusGenInputs['UpdateUserProfileInput']; // UpdateUserProfileInput! + profile?: NexusGenInputs['UpdateUserProfileInput'] | null; // UpdateUserProfileInput } } Query: { diff --git a/pages/_app.tsx b/pages/_app.tsx index 2bf6a94d2..6d5724512 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -18,18 +18,17 @@ const extendedTheme = extendTheme({ }, }), }, + // FIXME: + // 1) round iconButton + // 2) table-like lime green input addons + // 3) input styling + // 4) focus color components: { Button: { defaultProps: { - colorScheme: "lime", - color: "black", + colorScheme: "theme", }, }, - // IconButton: { - // defaultProps: { - // isRound: true, - // }, - // }, Modal: { baseStyle: (props) => ({ content: { @@ -42,7 +41,7 @@ const extendedTheme = extendTheme({ }, }, colors: { - lime: { + theme: { 50: "#e4ffdf", 100: "#bbffb0", 200: "#92ff7f", diff --git a/scenes/Profile/components/AvatarWithInfo.tsx b/scenes/Profile/components/AvatarWithInfo.tsx index e778d2901..98f4b2f9d 100644 --- a/scenes/Profile/components/AvatarWithInfo.tsx +++ b/scenes/Profile/components/AvatarWithInfo.tsx @@ -91,7 +91,7 @@ const AvatarWithInfo: React.FC = ({ user }) => { /> )} - {user.profile?.weaponPool.length && ( + {user.profile?.weaponPool && user.profile?.weaponPool.length > 0 && ( = ({ isOpen, onClose }) => { const { t } = useTranslation(); - const { handleSubmit, errors, register } = useForm({ + + const { handleSubmit, errors, register } = useForm({ resolver: zodResolver(ProfileSchema), }); + const [updateUserProfile] = useUpdateUserProfileMutation(); - const onSubmit = (data) => { + const onSubmit = async (data: UpdateUserProfileInput) => { Object.keys(data).forEach((key) => { - if (data[key] === "") { - data[key] = null; + const typedKey = key as keyof typeof data; + if (data[typedKey] === "") { + data[typedKey] = null; } }); + await updateUserProfile({ variables: { profile: data } }); console.log(data); }; diff --git a/scenes/Profile/mutations/UpdateUserProfile.graphql b/scenes/Profile/mutations/UpdateUserProfile.graphql new file mode 100644 index 000000000..d585553d8 --- /dev/null +++ b/scenes/Profile/mutations/UpdateUserProfile.graphql @@ -0,0 +1,3 @@ +mutation UpdateUserProfile($profile: UpdateUserProfileInput!) { + updateUserProfile(profile: $profile) +} diff --git a/schema.graphql b/schema.graphql index 2d0843bd5..0b66ba278 100644 --- a/schema.graphql +++ b/schema.graphql @@ -3,7 +3,7 @@ type Mutation { - updateUserProfile(profile: UpdateUserProfileInput!): Profile! + updateUserProfile(profile: UpdateUserProfileInput): Boolean! } type Profile { @@ -23,15 +23,15 @@ type Query { } input UpdateUserProfileInput { - bio: String! - country: String! - customUrlPath: String! - sensMotion: Float! - sensStick: Float! - twitchName: String! - twitterName: String! - weaponPool: [String!]! - youtubeId: String! + bio: String + country: String + customUrlPath: String + sensMotion: Float + sensStick: Float + twitchName: String + twitterName: String + weaponPool: [String!] + youtubeId: String } type User { diff --git a/validators/Profile.ts b/validators/Profile.ts index e21642f67..0baf8ed60 100644 --- a/validators/Profile.ts +++ b/validators/Profile.ts @@ -1,173 +1,37 @@ //import isISO31661Alpha2 from "validator/es/lib/isISO31661Alpha2"; +import { weaponsWithHero } from "lib/lists/weaponsWithHero"; import * as z from "zod"; export const ProfileSchema = z.object({ - bio: z.string().max(10000).optional(), + bio: z.string().max(10000).optional().nullable(), country: z .string() //.refine((val) => isISO31661Alpha2(val)) - .optional(), - customUrlPath: z.string().max(32).optional(), + .optional() + .nullable(), + customUrlPath: z.string().max(32).optional().nullable(), sensMotion: z .number() .min(5) .max(5) .refine((val) => (val * 10) % 5 === 0) - .optional(), + .optional() + .nullable(), sensStick: z .number() .min(5) .max(5) .refine((val) => (val * 10) % 5 === 0) - .optional(), - twitchName: z.string().max(25).optional(), - twitterName: z.string().max(15).optional(), - youtubeId: z.string().optional(), + .optional() + .nullable(), + twitchName: z.string().max(25).optional().nullable(), + twitterName: z.string().max(15).optional().nullable(), + youtubeId: z.string().optional().nullable(), // weaponsWithHero weaponPool: z - .array( - z.enum([ - "Sploosh-o-matic", - "Neo Sploosh-o-matic", - "Sploosh-o-matic 7", - "Splattershot Jr.", - "Custom Splattershot Jr.", - "Kensa Splattershot Jr.", - "Splash-o-matic", - "Neo Splash-o-matic", - "Aerospray MG", - "Aerospray RG", - "Aerospray PG", - "Splattershot", - "Hero Shot Replica", - "Tentatek Splattershot", - "Octo Shot Replica", - "Kensa Splattershot", - ".52 Gal", - ".52 Gal Deco", - "Kensa .52 Gal", - "N-ZAP '85", - "N-ZAP '89", - "N-ZAP '83", - "Splattershot Pro", - "Forge Splattershot Pro", - "Kensa Splattershot Pro", - ".96 Gal", - ".96 Gal Deco", - "Jet Squelcher", - "Custom Jet Squelcher", - "L-3 Nozzlenose", - "L-3 Nozzlenose D", - "Kensa L-3 Nozzlenose", - "H-3 Nozzlenose", - "H-3 Nozzlenose D", - "Cherry H-3 Nozzlenose", - "Squeezer", - "Foil Squeezer", - "Luna Blaster", - "Luna Blaster Neo", - "Kensa Luna Blaster", - "Blaster", - "Hero Blaster Replica", - "Custom Blaster", - "Range Blaster", - "Custom Range Blaster", - "Grim Range Blaster", - "Rapid Blaster", - "Rapid Blaster Deco", - "Kensa Rapid Blaster", - "Rapid Blaster Pro", - "Rapid Blaster Pro Deco", - "Clash Blaster", - "Clash Blaster Neo", - "Carbon Roller", - "Carbon Roller Deco", - "Splat Roller", - "Hero Roller Replica", - "Krak-On Splat Roller", - "Kensa Splat Roller", - "Dynamo Roller", - "Gold Dynamo Roller", - "Kensa Dynamo Roller", - "Flingza Roller", - "Foil Flingza Roller", - "Inkbrush", - "Inkbrush Nouveau", - "Permanent Inkbrush", - "Octobrush", - "Herobrush Replica", - "Octobrush Nouveau", - "Kensa Octobrush", - "Classic Squiffer", - "New Squiffer", - "Fresh Squiffer", - "Splat Charger", - "Hero Charger Replica", - "Firefin Splat Charger", - "Kensa Charger", - "Splatterscope", - "Firefin Splatterscope", - "Kensa Splatterscope", - "E-liter 4K", - "Custom E-liter 4K", - "E-liter 4K Scope", - "Custom E-liter 4K Scope", - "Bamboozler 14 Mk I", - "Bamboozler 14 Mk II", - "Bamboozler 14 Mk III", - "Goo Tuber", - "Custom Goo Tuber", - "Slosher", - "Hero Slosher Replica", - "Slosher Deco", - "Soda Slosher", - "Tri-Slosher", - "Tri-Slosher Nouveau", - "Sloshing Machine", - "Sloshing Machine Neo", - "Kensa Sloshing Machine", - "Bloblobber", - "Bloblobber Deco", - "Explosher", - "Custom Explosher", - "Mini Splatling", - "Zink Mini Splatling", - "Kensa Mini Splatling", - "Heavy Splatling", - "Hero Splatling Replica", - "Heavy Splatling Deco", - "Heavy Splatling Remix", - "Hydra Splatling", - "Custom Hydra Splatling", - "Ballpoint Splatling", - "Ballpoint Splatling Nouveau", - "Nautilus 47", - "Nautilus 79", - "Dapple Dualies", - "Dapple Dualies Nouveau", - "Clear Dapple Dualies", - "Splat Dualies", - "Hero Dualie Replicas", - "Enperry Splat Dualies", - "Kensa Splat Dualies", - "Glooga Dualies", - "Glooga Dualies Deco", - "Kensa Glooga Dualies", - "Dualie Squelchers", - "Custom Dualie Squelchers", - "Dark Tetra Dualies", - "Light Tetra Dualies", - "Splat Brella", - "Hero Brella Replica", - "Sorella Brella", - "Tenta Brella", - "Tenta Sorella Brella", - "Tenta Camo Brella", - "Undercover Brella", - "Undercover Sorella Brella", - "Kensa Undercover Brella", - ]) - ) + .array(z.string()) .max(5) - .optional(), + .refine((arr) => arr.every((val) => weaponsWithHero.includes(val as any))) + .optional() + .nullable(), });