import {
isSeamHttpInvalidInputError,
type SeamHttpApiError,
} from '@seamapi/http/connect'
import type { AccessCode, Device } from '@seamapi/types/connect'
import { useState } from 'react'
import { shake } from 'lib/object.js'
import { useCreateAccessCode } from 'lib/seam/access-codes/use-create-access-code.js'
import {
type CommonProps,
withRequiredCommonProps,
} from 'lib/seam/components/common-props.js'
import { useDevice } from 'lib/seam/devices/use-device.js'
import { useComponentTelemetry } from 'lib/telemetry/index.js'
import {
AccessCodeForm,
type AccessCodeFormSubmitData,
type ResponseErrors,
} from 'lib/ui/AccessCodeForm/AccessCodeForm.js'
export interface CreateAccessCodeFormProps extends CommonProps {
deviceId: string
onSuccess?: (accessCodeId: string) => void
}
export const NestedCreateAccessCodeForm =
withRequiredCommonProps(CreateAccessCodeForm)
export function CreateAccessCodeForm({
className,
onBack,
deviceId,
onSuccess,
}: CreateAccessCodeFormProps): JSX.Element | null {
useComponentTelemetry('CreateAccessCodeForm')
const { device } = useDevice({
device_id: deviceId,
})
if (device == null) {
return null
}
return (
)
}
function Content({
device,
className,
onBack,
onSuccess,
}: Omit & {
device: Device
}): JSX.Element {
const { submit, isSubmitting, responseErrors } = useSubmitCreateAccessCode({
onSuccess: (accessCode: AccessCode) => {
if (onSuccess != null) {
onSuccess(accessCode.access_code_id)
}
if (onBack != null) {
onBack()
}
},
})
return (
)
}
function useSubmitCreateAccessCode(params: {
onSuccess: (accessCode: AccessCode) => void
}): {
submit: (data: AccessCodeFormSubmitData) => void
isSubmitting: boolean
responseErrors: ResponseErrors | null
} {
const { onSuccess } = params
const { mutate, isPending: isSubmitting } = useCreateAccessCode()
const { responseErrors, handleResponseError, resetResponseErrors } =
useResponseErrors()
const submit = (data: AccessCodeFormSubmitData): void => {
resetResponseErrors()
const { name, code, type, device, startDate, endDate } = data
if (name === '') {
return
}
if (isSubmitting) {
return
}
if (type === 'time_bound') {
mutate(
{
name,
code,
device_id: device.device_id,
starts_at: startDate,
ends_at: endDate,
},
{
onSuccess,
onError: handleResponseError,
}
)
return
}
mutate(
{
name,
code,
device_id: device.device_id,
},
{
onSuccess,
onError: handleResponseError,
}
)
}
return { submit, isSubmitting, responseErrors }
}
export function useResponseErrors(): {
responseErrors: ResponseErrors | null
handleResponseError: (error: SeamHttpApiError | Error) => void
resetResponseErrors: () => void
} {
const [responseErrors, setResponseErrors] = useState | null>(null)
const handleResponseError = (error: SeamHttpApiError | Error): void => {
if (isSeamHttpInvalidInputError(error)) {
const errors = shake({
code: error.getValidationErrorMessages('code')[0],
name: error.getValidationErrorMessages('name')[0],
})
if (Object.keys(errors).length === 0) {
setResponseErrors({
unknown: error.message,
})
}
}
setResponseErrors({
unknown: t.genericResponseError,
})
}
const resetResponseErrors = (): void => {
setResponseErrors(null)
}
return {
responseErrors,
handleResponseError,
resetResponseErrors,
}
}
const t = {
genericResponseError: 'The code could not be saved. Please try again.',
}