Skip to content

Commit

Permalink
fix: query creation, update and viewing
Browse files Browse the repository at this point in the history
  • Loading branch information
sajald77 committed Aug 13, 2024
1 parent 3577129 commit b27774a
Show file tree
Hide file tree
Showing 7 changed files with 237 additions and 252 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
"react-dropzone": "^14.2.3",
"react-easy-crop": "^5.0.4",
"react-helmet": "^6.1.0",
"react-hook-form": "^7.43.9",
"react-hook-form": "^7.52.2",
"react-i18next": "^13.0.0",
"react-icons": "^5.2.1",
"react-jss": "^10.9.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const PostView = () => {

handleEntryQuery()
}
}, [postId, toast])
}, [postId])

const entry = data?.entry

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
import { LazyQueryHookOptions } from '@apollo/client'
import { yupResolver } from '@hookform/resolvers/yup'
import { useCallback, useState } from 'react'
import { useForm } from 'react-hook-form'
import * as yup from 'yup'

import { useProjectEntriesAPI } from '@/modules/project/API/useProjectEntriesAPI'

import { useUnsavedAlert } from '../../../../../../../shared/hooks/useUnsavedAlert'
import {
CreateEntryInput,
EntryType,
ProjectEntryQuery,
ProjectEntryQueryVariables,
ProjectEntryViewFragment,
UpdateEntryInput,
useProjectEntryQuery,
} from '../../../../../../../types'
import { toInt, useNotification } from '../../../../../../../utils'

type EntryFormType = Pick<ProjectEntryViewFragment, 'id' | 'title' | 'description' | 'image' | 'content' | 'status'>

const schema = yup.object({
title: yup.string().required('This is a required field'),
})

export const useEntryForm = (
projectId: number,
entryId?: number | string,
options?: LazyQueryHookOptions<ProjectEntryQuery, ProjectEntryQueryVariables>,
entryTemplate: ProjectEntryViewFragment = {} as ProjectEntryViewFragment,
) => {
const toast = useNotification()

const [loading, setLoading] = useState(true)

const { createEntry, updateEntry, publishEntry } = useProjectEntriesAPI()

const { formState, setValue, watch, getValues, reset } = useForm<EntryFormType>({
defaultValues: {
content: entryTemplate.content || '',
description: entryTemplate.description || '',
image: entryTemplate.image || '',
title: entryTemplate.title || '',
},
resolver: yupResolver(schema),
})
const { isDirty } = formState

const resetForm = (entry: ProjectEntryViewFragment) => {
reset({
id: entry.id,
status: entry.status,
content: entry.content,
description: entry.description,
image: entry.image,
title: entry.title,
})
}

useProjectEntryQuery({
variables: {
entryId: toInt(entryId),
},
skip: !entryId,
fetchPolicy: 'network-only',
...options,
onError(error) {
if (options?.onError) {
options?.onError(error)
}

setLoading(false)
},
onCompleted(data) {
if (data.entry) {
resetForm(data.entry)
}

setLoading(false)
},
})

useUnsavedAlert(isDirty)

const saveEntry = useCallback(async () => {
if (!isDirty) {
return
}

const entry = getValues()

if (entryId || Boolean(entry?.id)) {
const input: UpdateEntryInput = {
content: entry.content,
description: entry.description,
entryId: entryId || toInt(entry?.id),
image: entry.image,
title: entry.title,
}
await updateEntry.execute({
variables: { input },
onError() {
toast.error({
title: 'Entry update failed',
description: 'Please try again later',
})
},
onCompleted(data) {
resetForm(data.updateEntry)
},
})
} else {
const input: CreateEntryInput = {
projectId: toInt(projectId),
content: entry.content,
description: entry.description || '',
image: entry.image,
title: entry.title || '',
type: EntryType.Article,
}
await createEntry.execute({
variables: { input },
onError() {
toast.error({
title: 'Entry creation failed',
description: 'Please try again later',
})
},
onCompleted(data) {
resetForm(data.createEntry)
},
})
}
/** Don't add apollo query or mutation to useEffect dependency */
}, [entryId, projectId, toast, resetForm, getValues, isDirty])

const publishEntryAfterValidation = useCallback(
async ({ onCompleted }: { onCompleted?: Function }) => {
const entry = getValues()
if (!entry.id) {
toast.info({
title: 'Cannot publish',
description: 'Please edit your content before publish',
})
return
}

try {
if (isDirty) {
await saveEntry()
}

const entryId = toInt(entry.id)
if (entryId) {
publishEntry.execute({
variables: { id: entryId },
onCompleted(data) {
resetForm(data.publishEntry)
if (onCompleted) {
onCompleted()
}

toast.success({
title: 'Entry published',
description: 'Your entry is now live',
})
},
onError() {
toast.error({
title: 'Entry publish failed',
description: 'Please try again later',
})
},
})
}
} catch (error) {
toast.error({
title: 'Entry publish failed',
description: 'Please try again later',
})
}
},
/** Don't add apollo query or mutation to useEffect dependency */
[isDirty, saveEntry, getValues, resetForm, toast],
)

return {
loading,
saving: updateEntry.loading || createEntry.loading,
saveEntry,
publishEntry: publishEntryAfterValidation,
publishing: publishEntry.loading,
setValue,
isDirty,
watch,
}
}
Loading

0 comments on commit b27774a

Please sign in to comment.