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
31 changes: 5 additions & 26 deletions frontend/src/graphql/mutations.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { gql, type TypedDocumentNode } from '@apollo/client'
import type { UfoSighting } from '../types/ufo-sighting'
import { SIGHTING_FIELDS } from './queries'

/** Matches `CreateSightingInput` in backend/src/schema.ts. */
export interface CreateSightingInput {
Expand All @@ -14,22 +16,8 @@ export interface CreateSightingInput {
longitude: number
}

export interface CreatedSighting {
id: string
datetime: string | null
city: string | null
state: string | null
country: string | null
shape: string | null
durationSeconds: number | null
comments: string | null
datePosted: string | null
latitude: number | null
longitude: number | null
}

interface CreateSightingData {
createSighting: CreatedSighting
createSighting: UfoSighting
}

interface CreateSightingVariables {
Expand All @@ -52,17 +40,8 @@ export const CREATE_SIGHTING_MUTATION: TypedDocumentNode<
> = gql`
mutation CreateSighting($input: CreateSightingInput!) {
createSighting(input: $input) {
id
datetime
city
state
country
shape
durationSeconds
comments
datePosted
latitude
longitude
...SightingFields
}
}
${SIGHTING_FIELDS}
`
46 changes: 24 additions & 22 deletions frontend/src/graphql/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,26 @@ export const HEALTH_QUERY: TypedDocumentNode<HealthQueryData> = gql`
}
`

/**
* The fields of a `UfoSighting`. Every query and mutation that returns a
* sighting spreads this, so they all fetch, and cache, the same fields.
*/
export const SIGHTING_FIELDS = gql`
fragment SightingFields on Sighting {
id
datetime
city
state
country
shape
durationSeconds
comments
datePosted
latitude
longitude
}
`

export interface SightingsQueryData {
sightings: {
edges: { cursor: string; node: UfoSighting }[]
Expand Down Expand Up @@ -50,17 +70,7 @@ export const SIGHTINGS_QUERY: TypedDocumentNode<
edges {
cursor
node {
id
datetime
city
state
country
shape
durationSeconds
comments
datePosted
latitude
longitude
...SightingFields
}
}
pageInfo {
Expand All @@ -70,6 +80,7 @@ export const SIGHTINGS_QUERY: TypedDocumentNode<
totalCount
}
}
${SIGHTING_FIELDS}
`

interface SightingQueryData {
Expand All @@ -84,17 +95,8 @@ export const SIGHTING_QUERY: TypedDocumentNode<
> = gql`
query Sighting($id: ID!) {
sighting(id: $id) {
id
datetime
city
state
country
shape
durationSeconds
comments
datePosted
latitude
longitude
...SightingFields
}
}
${SIGHTING_FIELDS}
`
9 changes: 2 additions & 7 deletions frontend/src/hooks/use-sighting-search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
sightingSortEnum,
type SightingSortOption,
} from '../types/ufo-sighting'
import { createRetry } from '../utils/create-retry'
import { useDebouncedValue } from './use-debounced-value'

const SEARCH_DEBOUNCE_MS = 300
Expand Down Expand Up @@ -73,12 +74,6 @@ export function useSightingSearch() {
[shownData],
)

// A failed refetch is shown through `error`, so the rejected promise
// needs no handling of its own.
const retry = () => {
refetch().catch(() => {})
}

// `loading` is also true while "load more" runs. Telling the two apart
// keeps the list from dimming when only a page is being added.
const loadingMore = networkStatus === NetworkStatus.fetchMore
Expand Down Expand Up @@ -107,7 +102,7 @@ export function useSightingSearch() {
totalCount: shownData?.sightings.totalCount ?? 0,
loading: loading && !loadingMore,
error,
retry,
retry: createRetry(refetch),
hasNextPage: pageInfo?.hasNextPage ?? false,
loadMore,
loadingMore,
Expand Down
12 changes: 6 additions & 6 deletions frontend/src/hooks/use-sighting.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useQuery } from '@apollo/client/react'
import { SIGHTING_QUERY } from '../graphql/queries'
import { createRetry } from '../utils/create-retry'

/**
* Fetches one sighting. `sighting` is null once the load has finished and
Expand All @@ -10,11 +11,10 @@ export function useSighting(id: string) {
variables: { id },
})

// A failed refetch is shown through `error`, so the rejected promise
// needs no handling of its own.
const retry = () => {
refetch().catch(() => {})
return {
sighting: data?.sighting ?? null,
loading,
error,
retry: createRetry(refetch),
}

return { sighting: data?.sighting ?? null, loading, error, retry }
}
10 changes: 10 additions & 0 deletions frontend/src/utils/create-retry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Turns a query's `refetch` into a retry callback for an error message's
* button. A failed refetch is shown through the query's `error`, so the
* rejected promise needs no handling of its own.
*/
export function createRetry(refetch: () => Promise<unknown>) {
return () => {
refetch().catch(() => {})
}
}