| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- import { zodResolver } from '@hookform/resolvers/zod'
- import { useEffect, useRef, useState, type Dispatch } from 'react'
- import { useForm, useWatch, type DefaultValues, type UseFormReturn } from 'react-hook-form'
- import { SupportFormSchema, type SupportFormValues } from './SupportForm.schema'
- import type { SupportFormActions } from './SupportForm.state'
- import {
- loadSupportFormInitialParams,
- loadSupportFormInitialParamsFromObject,
- NO_ORG_MARKER,
- NO_PROJECT_MARKER,
- selectInitialOrgAndProject,
- type SupportFormUrlKeys,
- } from './SupportForm.utils'
- // End of third-party imports
- import { useOrganizationsQuery } from '@/data/organizations/organizations-query'
- const supportFormDefaultValues: DefaultValues<SupportFormValues> = {
- organizationSlug: NO_ORG_MARKER,
- projectRef: NO_PROJECT_MARKER,
- severity: 'Low',
- category: undefined,
- library: '',
- subject: '',
- message: '',
- affectedServices: '',
- allowSupportAccess: true,
- attachDashboardLogs: true,
- dashboardSentryIssueId: '',
- }
- interface UseSupportFormResult {
- form: UseFormReturn<SupportFormValues>
- initialError: string | null
- projectRef: string | null
- orgSlug: string | null
- }
- export function useSupportForm(
- dispatch: Dispatch<SupportFormActions>,
- initialParams?: Partial<SupportFormUrlKeys>
- ): UseSupportFormResult {
- const form = useForm<SupportFormValues>({
- mode: 'onBlur',
- reValidateMode: 'onBlur',
- resolver: zodResolver(SupportFormSchema as any),
- defaultValues: supportFormDefaultValues,
- })
- const urlParamsRef = useRef<SupportFormUrlKeys | null>(null)
- const providedInitialParamsRef = useRef(initialParams)
- const [initialError, setInitialError] = useState<string | null>(null)
- // Load initial values from URL params after mount so SSR/SSG render with
- // bare defaults (no `window` access) and the client hydrates against the
- // same HTML. URL-derived values are applied here, post-hydration.
- useEffect(() => {
- const params =
- providedInitialParamsRef.current !== undefined
- ? loadSupportFormInitialParamsFromObject(providedInitialParamsRef.current)
- : loadSupportFormInitialParams(window.location.search)
- urlParamsRef.current = params
- setInitialError(params.error ?? null)
- if (params.category && !form.getFieldState('category').isDirty) {
- form.setValue('category', params.category, { shouldDirty: false })
- }
- if (typeof params.subject === 'string' && !form.getFieldState('subject').isDirty) {
- form.setValue('subject', params.subject, { shouldDirty: false })
- }
- if (typeof params.message === 'string' && !form.getFieldState('message').isDirty) {
- form.setValue('message', params.message, { shouldDirty: false })
- }
- if (params.sid && !form.getFieldState('dashboardSentryIssueId').isDirty) {
- form.setValue('dashboardSentryIssueId', params.sid, {
- shouldDirty: false,
- })
- }
- }, [form])
- const hasAppliedOrgProjectRef = useRef(false)
- const { data: organizations, isPending: organizationsLoading } = useOrganizationsQuery()
- // Organization slug and project ref need to be validated after loading from
- // URL params
- useEffect(() => {
- if (hasAppliedOrgProjectRef.current) return
- if (!urlParamsRef.current) return
- if (organizationsLoading) return
- hasAppliedOrgProjectRef.current = true
- const orgSlugFromUrl =
- urlParamsRef.current.orgSlug && urlParamsRef.current.orgSlug !== NO_ORG_MARKER
- ? urlParamsRef.current.orgSlug
- : null
- const projectRefFromUrl = urlParamsRef.current.projectRef ?? null
- selectInitialOrgAndProject({
- projectRef: projectRefFromUrl,
- orgSlug: orgSlugFromUrl,
- orgs: organizations ?? [],
- })
- .then(({ orgSlug, projectRef }) => {
- if (!form.getFieldState('organizationSlug').isDirty) {
- form.setValue('organizationSlug', orgSlug ?? NO_ORG_MARKER, {
- shouldDirty: false,
- })
- }
- if (!form.getFieldState('projectRef').isDirty) {
- form.setValue('projectRef', projectRef ?? NO_PROJECT_MARKER, {
- shouldDirty: false,
- })
- }
- })
- .catch(() => {
- // Ignored: fall back to defaults when lookup fails
- })
- .finally(() => {
- dispatch({ type: 'INITIALIZE', debugSource: 'useSupportForm' })
- })
- }, [organizations, organizationsLoading, form, dispatch])
- const watchedProjectRef = useWatch({
- control: form.control,
- name: 'projectRef',
- })
- const watchedOrgSlug = useWatch({
- control: form.control,
- name: 'organizationSlug',
- })
- const projectRef =
- watchedProjectRef && watchedProjectRef !== NO_PROJECT_MARKER ? watchedProjectRef : null
- const orgSlug = watchedOrgSlug && watchedOrgSlug !== NO_ORG_MARKER ? watchedOrgSlug : null
- return {
- form,
- initialError,
- projectRef,
- orgSlug,
- }
- }
|