All files / layers / L2R / slots Crud.tsx

60% Statements 42/70
38.98% Branches 23/59
80% Functions 8/10
60.6% Lines 40/66

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97          52x   52x 52x   868x 868x 868x 868x 2854x 2854x 868x 868x 868x 868x                                                   868x 3x 3x 3x 3x 3x 3x 3x 1x 1x 1x         2x 2x                                             868x                        
import { useCallback } from 'react'
import { useNavigate } from 'react-router-dom'
import { CrudSurface } from '../surfaces/CrudSurface'
import { useEntityCoordinator } from '../../L2W/coordinatorResolver'
import { useRouteContext } from '../../L2W/routes/routeContextStore'
import type { CrudConfig, CrudFieldConfig, CrudVisualOverrides } from '../../interfaces'
 
export interface CrudProps {
  config: CrudConfig
}
 
const FALLBACK_CONTEXT = { page: 'collection' } as const
 
export function Crud({ config }: CrudProps) {
  const navigate = useNavigate()
  const rawContext = useRouteContext()
  const routeContext = rawContext ?? FALLBACK_CONTEXT
  const fieldNames = config.fieldSet.map(f => f.field)
  const fieldConfigMap = Object.fromEntries(
    config.fieldSet.map(fc => [fc.field, fc]),
  ) as Record<string, CrudFieldConfig>

  const { snapshot, updateField, cancel } =
    useEntityCoordinator(config.entityPath, fieldNames, routeContext, config.entitySelectSources)

  const { cancelTarget, onCancel, successTarget, onSuccess } = config

  const titleOverride = config.title ? { labels: { title: config.title } } : undefined

  const handleClose = useCallback(() => {
    if (cancelTarget) {
      if (snapshot.activeCrud?.mode === 'edit' && routeContext.page === 'detail') {
        navigate(cancelTarget.replace(':id', routeContext.id), { replace: true })
      } else {
        navigate(cancelTarget, { replace: true })
      }
      return
    }
    if (onCancel) {
      onCancel()
      return
    }
    if (routeContext.page === 'detail' && routeContext.id) {
      navigate('/' + config.entityPath + '/' + routeContext.id, { replace: true })
    } else {
      navigate(-1)
  E  }
  }, [cancelTarget, onCancel, navigate, snapshot.activeCrud, routeContext, config.entityPath])
 
  const handleSuccess = useCallback(() => {
    if (successTarget) {
      const result = snapshot.lastMutationData as Record<string, unknown> | null
      const resultId = typeof result?.id === 'string' ? result.id : undefined
    E  const routeId = routeContext.page === 'detail' ? routeContext.id : undefined
      const resolvedId =
        snapshot.activeCrud?.mode === 'edit' ? (routeId ?? resultId) : resultId
      const needsId = successTarget.includes(':id')
      if (needsId && !resolvedId) {
        if (cancelTarget) {
          navigate(cancelTarget, { replace: true })
          return
        }
        navigate('/' + config.entityPath, { replace: true })
        return
      }
      navigate(successTarget.replace(':id', resolvedId ?? ''), { replace: true })
      return
    }
    if (onSuccess) {
      onSuccess()
      return
    }
    const mutationResult = snapshot.lastMutationData as Record<string, unknown> | null
    const mutationResultId = typeof mutationResult?.id === 'string' ? mutationResult.id : undefined
    if (snapshot.activeCrud?.mode === 'add' && mutationResultId) {
      navigate('/' + config.entityPath + '/' + mutationResultId, { replace: true })
    } else if (snapshot.activeCrud?.mode === 'edit' && routeContext.page === 'detail' && routeContext.id) {
      navigate('/' + config.entityPath + '/' + routeContext.id, { replace: true })
    }
  }, [successTarget, cancelTarget, onSuccess, navigate, snapshot.lastMutationData, snapshot.activeCrud, routeContext, config.entityPath])
 
  return (
    <CrudSurface
      coordinatorSnapshot={snapshot}
      routeContext={routeContext}
      onClose={handleClose}
      onSuccess={handleSuccess}
      updateField={updateField}
      cancel={cancel}
      fieldTypes={config.fieldTypes}
      fieldConfigs={fieldConfigMap}
      entitySelectData={snapshot.entitySelectData}
      overrides={titleOverride as CrudVisualOverrides | undefined}
    />
  )
}