I am trying to figure out how to access the object.id on the update mutation I have made in my app.
I have an object called IssueGroup. I have made create and delete mutations and for the most part, they work okay. I'm getting stuck with the update mutation because I can't seem to get it to recognise the id of the object I'm trying to update.
I have a form with:
import * as React from "react"
import { gql } from "@apollo/client"
import type { IssueGroupInput } from "lib/graphql"
import { QueryMode, Role, SortOrder, useAllIssueGroupsQuery, useDeleteIssueGroupMutation, useUpdateIssueGroupMutation } from "lib/graphql"
import { AdminCreateIssueGroupForm } from "components/AdminCreateIssueGroupForm"
import { AdminUpdateIssueGroupForm } from "components/AdminUpdateIssueGroupForm"
import { Modal } from "components/Modal"
const __ = gql`
query AllIssueGroups {
allIssueGroups {
id
title
description
}
}
mutation deleteIssueGroup($id: String!) {
deleteIssueGroup(id: $id) {
id
title
description
issues
}
}
`
export default function IssueGroups() {
const [selectedIssueGroups, setSelectedIssueGroups] = React.useState<string[]>([])
const modalProps = useDisclosure()
const modalPropsUpdate = useDisclosure()
const [deleteIssueGroup] = useDeleteIssueGroupMutation()
const [updateIssueGroup] = useUpdateIssueGroupMutation()
const { data: issueGroup, refetch: refetchAllIssueGroups } = useAllIssueGroupsQuery()
const { data, loading, refetch } = useAllIssueGroupsQuery()
const allIssueGroups = data?.allIssueGroups
const onDeleteIssueGroup = (id: string) => {
return (
deleteIssueGroup({ variables: { id } }).then(() => refetch())
)
}
return (
<Box>
<Wrap mb={4} spacing={2}>
<Button
onClick={modalProps.onOpen}
}}
>
Create issue group
</Button>
</Wrap>
<Modal {...modalProps} title="Create Issue Group">
<AdminCreateIssueGroupForm onClose={modalProps.onClose} />
</Modal>
<IconButton
onClick={modalPropsUpdate.onOpen}
/>
<Modal {...modalPropsUpdate} title="Update Issue Group">
<AdminUpdateIssueGroupForm onClose=
{modalPropsUpdate.onClose} />
</Modal>
<IconButton
onClick={() => onDeleteIssueGroup(issueGroup.id)}
/>
))}
)
}
Then, I have a modal that opens when the update button is clicked that has:
import * as React from "react"
import { gql } from "@apollo/client"
import { useRouter } from "next/router"
import { useAllIssueGroupsQuery, useUpdateIssueGroupMutation, IssueGroupInput } from "lib/graphql"
import { useForm } from "lib/hooks/useForm"
import Yup from "lib/yup"
const _ = gql`
query AllIssueGroups {
allIssueGroups {
id
title
description
issues
}
}
mutation updateIssueGroup($id: String!, $data: IssueGroupInput!) {
updateIssueGroup(id: $id, data: $data) {
id
title
description
issues
}
}
`
interface Props {
onClose: () => void
}
const IssueGroupSchema = Yup.object().shape({
title: Yup.string().required(),
description: Yup.string().required(),
})
export function AdminUpdateIssueGroupForm(props: Props) {
const router = useRouter()
const [updateIssueGroup] = useUpdateIssueGroupMutation()
const { data: issueGroups, refetch: refetchAllIssueGroups } = useAllIssueGroupsQuery()
const form = useForm({ schema: IssueGroupSchema })
const handleSubmit = async(data:IssueGroupInput) => {
console.log("made it to the handle submit before success handler")
return await form.handler(() => updateIssueGroup({
variables: {
id: issueGroup.id,
// I get an error that says Cannot find name 'issueGroup'. Did you mean 'issueGroups'.
// I know that's because I'm using the AllIssueGroups query to find many,
// but I don't know how to write the query to find the specific one I
// want to edit when I press the edit button in the form above
data: { ...data }
} }), {
onSuccess: (res, toast) => {
console.log("made it to the form handler success")
toast({ description: "Issue group updated" })
form.reset()
props.onClose()
},
})
}
return (
<Form {...form} onSubmit={handleSubmit}>
<Stack>
<Input name="title" label="Title" />
{/* <Input name="description" label="Description" /> */}
{/* <Text mb='8px' fontWeight="medium" fontSize="sm" > Description</Text> */}
<Textarea name="description" label="Describe" rows={4}/>
<Button onClick={props.onClose}>Cancel</Button>
type="submit"
>
Create
</Form>
)
}
My IssueGroup resolver has:
@Mutation(() => IssueGroup)
async updateIssueGroup(
@Arg("id") id: string,
@Arg("data") data: IssueGroupInput
) {
return await this.issueGroupService.updateIssueGroup(id, data)
}
@Query(() => IssueGroup)
async issueGroup(@Arg("id") id: string) {
return await this.issueGroupService.getIssueGroup(id)
}
The IssueGroup service has:
async updateIssueGroup(id: string, data: IssueGroupInput) {
const issueGroup = await prisma.issueGroup.findUnique({ where: { id } })
if (!issueGroup) {
throw new Error("Issue not found")
}
return await prisma.issueGroup.update({ where: { id }, data })
}
async getIssueGroup(id: string) {
return await prisma.issueGroup.findUnique({
where: {
id,
},
})
}
How can I tell the modal form for update what the specific issueGroup.id related to the button clicked to open the modal is?
The prisma schema has:
model IssueGroup {
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
title String
description String
issues Issue[]
createdAt DateTime @default(now()) @db.Timestamptz(6)
updatedAt DateTime @default(now()) @updatedAt @db.Timestamptz(6)
}
model Issue {
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
title String
description String
issueGroup IssueGroup? @relation(fields: [issueGroupId], references: [id], onDelete: SetNull, onUpdate: Cascade)
issueGroupId String? @db.Uuid
subscribers UserIssue[]
createdAt DateTime @default(now()) @db.Timestamptz(6)
updatedAt DateTime @default(now()) @updatedAt @db.Timestamptz(6)
}
NEXT ATTEMPT
I have made a further attempt, which tries to give the modal the issueGroup.id with the onClick handler, but I still can't get the form to recognise the id, and this version of this attempt generates an error message I don't know how to break down. It says:
Type '{ onClose: () => void; issueGroup: Omit<IssueGroup, "createdAt" | "updatedAt" | "issues"> | null; }' is not assignable to type 'IntrinsicAttributes & Props'. Property 'issueGroup' does not exist
on type 'IntrinsicAttributes & Props'.
This time:
I tried to set state:
import { QueryMode, Role, SortOrder, useAllIssueGroupsQuery, useDeleteIssueGroupMutation, useUpdateIssueGroupMutation, IssueGroup as IssueGroupGQLType } from "lib/graphql" const [selectedIssueGroup, setSelectedIssueGroup] = React.useState<Omit< IssueGroupGQLType, "createdAt" | "updatedAt" | "issues" > | null>(null)
the update button has:
<IconButton aria-label='Update Issue Group' // onClick={modalPropsUpdate.onOpen} onClick={() => { setSelectedIssueGroup(issueGroup) modalPropsUpdate.onOpen() <Modal {...modalPropsUpdate } title="Update Issue Group"> <AdminUpdateIssueGroupForm onClose={modalPropsUpdate.onClose} issueGroup ={selectedIssueGroup} /> </Modal>
Then, in the form, I tried to read issueGroup.id:
const _ = gql`
query AllIssueGroups {
allIssueGroups {
id
title
description
issues
}
}
mutation updateIssueGroup($id: String!, $data: IssueGroupInput!) {
updateIssueGroup(id: $id, data: $data) {
id
title
description
issues
}
}
`
interface Props {
onClose: () => void
issueGroup: selectedIssueGroup
}
const IssueGroupSchema = Yup.object().shape({
title: Yup.string().required(),
description: Yup.string().required(),
})
export function AdminUpdateIssueGroupForm(props: Props) {
const router = useRouter()
const [updateIssueGroup] = useUpdateIssueGroupMutation()
// const { data: issueGroups, refetch: refetchAllIssueGroups } = useAllIssueGroupsQuery()
const form = useForm({ schema: IssueGroupSchema })
const handleSubmit = async( data:IssueGroupInput) => {
// await form.triggerValidation()
console.log("made it to the handle submit before success handler")
The variables below don't know what issueGroup is
return await form.handler(() => updateIssueGroup({ variables: { id: issueGroup.id, data: { ...data } } }), {
onSuccess: (res, toast) => {
console.log("made it to the form handler success")
form.reset()
props.onClose()
},
})
}
return (
<Form {...form} onSubmit={handleSubmit}>
<Stack>
<Input name="title" label="Title" />
<Textarea name="description" label="Describe" rows={4}/>
<FormError />
<ButtonGroup>
<Button onClick={props.onClose}>Cancel</Button>
<Button
type="submit"
isLoading={form.formState.isSubmitting}
isDisabled={form.formState.isSubmitting}
>
Create
</Button>
</ButtonGroup>
</Stack>
</Form>
)
}
With this attempt, my form still doesnt know what selectedIssueGroup or IssueGroup mean.
I have seen this page of the react docs, and I think the bit I am missing is that I haven't wrapped my form in the equivalent of isActive. The problem is, I don't know where to put selectedIssueGroup. My definition of that state is in a different file to the file the form is is saved in.
In an attempt to apply the logic in this documentation, I tried changing the modal so that is wrapped inside the state, as follows:
{selectedIssueGroup &&
<Modal {...modalPropsUpdate } title="Update Issue Group">
<AdminUpdateIssueGroupForm onClose={modalPropsUpdate.onClose} issueGroup ={selectedIssueGroup} />
</Modal>
}
I don't get any new errors, but it also doesn't work. My form still doesn't know what the issueGroup is.
I can see that the update button knows what the issueGroup is and I can see that the Modal knows it too. I cant figure out how to give that value to the update form.
I have seen this tutorial, which shows how to use the create form to make an edit. The screen shot it uses displays the created information populated in the edit form, but it does not show how it found that data to use in that form. I can't find an example of how to do that.
NEXT ATTEMPT 21 DEC
In this most recent attempt, I have tried to add the issueGroup reference as a property on the Modal. Even if this worked, I think it would not be helpful for a reason explained below. However, i don't understand why it doesn't work.
<Modal {...modalPropsUpdate } issueGroup={selectedIssueGroup} title="Update Issue Group" >
When I try this, I get an error (VS code underlines the issueGroup in the above line). The error message says:
Type '{ children: (void | Element)[]; issueGroup: Omit<IssueGroup, "createdAt" | "updatedAt" | "issues"> | null; title: string; isOpen:
boolean; onOpen: () => void; ... 4 more ...; getDisclosureProps: (props?: any) => any; }' is not assignable to type 'IntrinsicAttributes & Props & { children?: ReactNode; }'. Property 'issueGroup' does not exist on type 'IntrinsicAttributes & Props & { children?: ReactNode; }'.
I don't know what this means. The console logs inside the update button, and above and below the modal all know what issueGroup is.
The reason I think it is not required is that I can log the value of the issue Group above the modal and above the component inside the modal that loads the form. Both logs show the value of the issueGroup that I want to use in the form.
I'm trying to do that as follows:
const CheckIfModalKnowsIssueGroupId = props => {
console.log("checking if modal knows the issue group", props.toLog);
return (
<div>
{props.children}
</div>
);
};
ALTERNATE for attempt to log inside the form component
<AdminUpdateIssueGroupForm
onClose={modalPropsUpdate.onClose}
issueGroup ={selectedIssueGroup}
>
<CheckIfModalKnowsIssueGroupId toLog={selectedIssueGroup} />
</AdminUpdateIssueGroupForm>
NEXT ATTEMPT - READ MODAL VALUES
In a further attempt to try and make the modal carry the value of IssueGroup, I am trying to do the following:
{selectedIssueGroup && modalPropsUpdate(isOpen:true) <Modal {...modalPropsUpdate } issueGroup={selectedIssueGroup} title="Update Issue Group" >
This attempt is wrong because I don't know how to engage with modalPropsUpdate. The above formulation generates an error in the isOpen test as follows:
const modalPropsUpdate: {
isOpen: boolean;
onOpen: () => void;
onClose: () => void;
onToggle: () => void;
isControlled: boolean;
getButtonProps: (props?: any) => any;
getDisclosureProps: (props?: any) => any;
}
This expression is not callable. Type '{ isOpen: boolean; onOpen: () => void; onClose: () => void; onToggle: () => void; isControlled: boolean; getButtonProps: (props?: any) => any; getDisclosureProps: (props?: any) => any; }' has no call signatures.
I can't find syntax that does not produce an error.
The objective of this attempt is to see if the modal is open, and still knows what the selectedIssueGroup is.
NEW OBSERVATION
I have seen this repo. I cannot find an example using the structure I have adopted to allow the id to be communicated to the form.
NEXT ATTEMPT 23 DEC
I tried to rule out the source of the problem as the selectedIssueGroup state handler being set in a different component to the form I was trying to use to update the object. So, I moved the form into the same file. It did not work. The udpate form handler still does not know what issueGroup.id or selectedIssueGroup mean.
import * as React from "react"
import { gql } from "@apollo/client"
import { useRouter } from "next/router"
import type { IssueGroupInput } from "lib/graphql"
import { QueryMode, Role, SortOrder, useAllIssueGroupsQuery, useDeleteIssueGroupMutation, useUpdateIssueGroupMutation, IssueGroup as IssueGroupGQLType } from "lib/graphql"
// ,
import { AdminCreateIssueGroupForm } from "components/AdminCreateIssueGroupForm"
import Yup from "lib/yup"
const __ = gql`
query AllIssueGroups {
allIssueGroups {
id
title
description
}
}
mutation updateIssueGroup($id: String!, $data: IssueGroupInput!) {
updateIssueGroup(id: $id, data: $data) {
id
title
description
issues
}
}
`
const CheckIfModalKnowsIssueGroupId = props => {
console.log("checking if modal knows the issue group", props.toLog);
return (
<div>
{props.children}
</div>
);
};
const IssueGroupSchema = Yup.object().shape({
title: Yup.string().required(),
description: Yup.string().required(),
})
const form = useForm({ schema: IssueGroupSchema })
export default function IssueGroups() {
const [selectedIssueGroups, setSelectedIssueGroups] = React.useState<string[]>([])
const modalProps = useDisclosure()
const modalPropsUpdate = useDisclosure()
const [deleteIssueGroup] = useDeleteIssueGroupMutation()
const { data: issueGroup, refetch: refetchAllIssueGroups } = useAllIssueGroupsQuery()
const [selectedIssueGroup, setSelectedIssueGroup] = React.useState<Omit<
IssueGroupGQLType,
"createdAt" | "updatedAt" | "issues"
> | null>(null)
interface Props {
onClose: () => void
issueGroup: typeof selectedIssueGroup
}
function AdminUpdateIssueGroupForm(props: Props) {
const router = useRouter()
const [updateIssueGroup] = useUpdateIssueGroupMutation()
const handleSubmitUpdate = async( data:IssueGroupInput) => {
// await form.triggerValidation()
console.log("made it to the handle submit before success handler")
return await form.handler(() => updateIssueGroup({ variables: { id: issueGroup.id, data: { ...data } } }), {
onSuccess: (res, toast) => {
console.log("made it to the form handler success")
toast({ description: "Issue group updated" })
form.reset()
props.onClose()
},
})
}
const { data, loading, refetch } = useAllIssueGroupsQuery(
)
const allIssueGroups = data?.allIssueGroups
const onDeleteIssueGroup = (id: string) => {
return (
deleteIssueGroup({ variables: { id } }).then(() => refetch())
)
}
return (
<Wrap mb={4} spacing={2}>
<Button
onClick={modalProps.onOpen}
>
Create issue group
</Button>
</Wrap>
<Modal {...modalProps} title="Create Issue Group">
<AdminCreateIssueGroupForm onClose={modalProps.onClose} />
</Modal>
{data?.allIssueGroups.map((issueGroup) => (
<Tr key={issueGroup.id}>
<Text textStyle="h6">{issueGroup.title}</Text>
<IconButton
onClick={() => {
setSelectedIssueGroup(issueGroup)
modalPropsUpdate.onOpen()
}}
/>
{ console.log("update knows what the issuegroup is", selectedIssueGroup)}
<Modal {...modalPropsUpdate } title="Update Issue Group" >
<Form {...form} onSubmit={handleSubmitUpdate} >
<Stack>
<Input name="title" label="Title" />
<ButtonGroup>
<Button onClick={props.onClose}>Cancel</Button>
<Button
type="submit"
>
Save changes
</Button>
</ButtonGroup>
</Stack>
</Form>
</Modal>
<IconButton
onClick={() => onDeleteIssueGroup(issueGroup.id)}
/>
</ButtonGroup>