Home / Function/ Feedback() — supabase Function Reference

Feedback() — supabase Function Reference

Architecture documentation for the Feedback() function in Feedback.tsx from the supabase codebase.

Entity Profile

Dependency Diagram

graph TD
  db81693d_9a17_bf20_5e49_ea669c5037e3["Feedback()"]
  4b70e582_d1b2_fa26_b397_618941837a63["useSendTelemetryEvent()"]
  db81693d_9a17_bf20_5e49_ea669c5037e3 -->|calls| 4b70e582_d1b2_fa26_b397_618941837a63
  28b182b0_b6eb_ea43_788c_54be8711896a["useSendFeedbackMutation()"]
  db81693d_9a17_bf20_5e49_ea669c5037e3 -->|calls| 28b182b0_b6eb_ea43_788c_54be8711896a
  4581944a_42ce_7bd1_a836_adcac492f56d["getSanitizedTabParams()"]
  db81693d_9a17_bf20_5e49_ea669c5037e3 -->|calls| 4581944a_42ce_7bd1_a836_adcac492f56d
  06021ec0_94f4_72a6_9fd8_c3841210a444["getLinearTeam()"]
  db81693d_9a17_bf20_5e49_ea669c5037e3 -->|calls| 06021ec0_94f4_72a6_9fd8_c3841210a444
  style db81693d_9a17_bf20_5e49_ea669c5037e3 fill:#6366f1,stroke:#818cf8,color:#fff

Relationship Graph

Source Code

apps/docs/components/Feedback/Feedback.tsx lines 75–236

function Feedback({ className }: { className?: string }) {
  const [state, dispatch] = useReducer(reducer, initialState)
  const [modalOpen, setModalOpen] = useState(false)
  const feedbackButtonRef = useRef<HTMLButtonElement>(null)

  const pathname = usePathname() ?? ''
  const sendTelemetryEvent = useSendTelemetryEvent()
  const { mutate: sendFeedbackComment } = useSendFeedbackMutation()
  const supabase = useConstant(() =>
    IS_PLATFORM
      ? createClient<Database>(
          process.env.NEXT_PUBLIC_SUPABASE_URL!,
          process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
        )
      : undefined
  )

  const unanswered = state.type === 'unanswered'
  const isYes = 'response' in state && state.response === 'yes'
  const isNo = 'response' in state && state.response === 'no'
  const showYes = unanswered || isYes
  const showNo = unanswered || isNo

  async function sendFeedbackVote(response: Response) {
    if (!supabase) return

    const { error } = await supabase.from('feedback').insert({
      vote: response,
      page: pathname,
      metadata: {
        query: getSanitizedTabParams(),
      },
    })
    if (error) console.error(error)
  }

  function handleVote(response: Response) {
    sendTelemetryEvent({
      action: 'docs_feedback_clicked',
      properties: { response },
    })
    sendFeedbackVote(response)
    dispatch({ event: 'VOTED', response })
    // Focus so screen reader users are aware of the new element
    setTimeout(() => {
      feedbackButtonRef.current?.focus()
      // Wait for element to show up first
    }, 700)
  }

  function refocusButton() {
    setTimeout(() => {
      feedbackButtonRef.current?.focus()
      // Wait for modal to disappear and button to become focusable again
    }, 100)
  }

  async function handleSubmit({ page, comment, title }: FeedbackFields) {
    sendFeedbackComment({
      message: comment,
      pathname: page,
      title,
      // @ts-expect-error -- can't click this button without having a state.response
      isHelpful: state.response === 'yes',
      team: getLinearTeam(pathname),
    })
    setModalOpen(false)
    refocusButton()
  }

  return (
    <section className={cn('@container', className)} aria-labelledby="feedback-title">
      <h3 id="feedback-title" className="block font-mono text-xs text-foreground-light mb-3">
        Is this helpful?
      </h3>
      <div className="relative flex flex-col gap-2 @[12rem]:gap-4 @[12rem]:flex-row @[12rem]:items-center">
        <div
          style={{ '--container-flex-gap': '0.5rem' } as CSSProperties}
          className="relative flex gap-2 items-center"
        >
          <Button
            type="outline"
            rounded
            className={cn(
              'px-1 w-7 h-7',
              'text-foreground-light',
              '[transition-property:opacity,transform,color] [transition-duration:150ms,250ms,250ms]',
              'motion-reduce:[transition-duration:150ms,1ms,300ms]',
              '[transition-timing-function:cubic-bezier(.76,0,.23,1)]',
              !isNo && 'hover:text-warning hover:border-warning-500',
              isNo && `bg-warning text-warning-200 !border-warning disabled:opacity-100`,
              !showNo && 'opacity-0 invisible'
            )}
            onClick={() => handleVote('no')}
            disabled={state.type === StateType.Followup}
          >
            <X size={14} strokeWidth={2} className="text-current" />
            <span className="sr-only">No</span>
          </Button>
          <Button
            type="outline"
            rounded
            className={cn(
              'px-1 w-7 h-7',
              'text-foreground-light',
              '[transition-property:opacity,transform,color] [transition-duration:150ms,250ms,250ms]',
              'motion-reduce:[transition-duration:150ms,1ms,300ms]',
              '[transition-timing-function:cubic-bezier(.76,0,.23,1)]',
              !isYes && 'hover:text-brand-600 hover:border-brand-500',
              isYes &&
                'bg-brand text-brand-200 !border-brand disabled:opacity-100 -translate-x-[calc(100%+var(--container-inline-flex-gap,0.5rem))]',
              !showYes && 'opacity-0 invisible'
            )}
            onClick={() => handleVote('yes')}
            disabled={state.type === StateType.Followup}
          >
            <Check size={14} strokeWidth={2} />
            <span className="sr-only">Yes</span>
          </Button>
        </div>
        <div
          className={cn(
            'flex flex-col gap-0.5',
            '@[12rem]:absolute @[12rem]:left-9',
            'text-xs',
            'opacity-0 invisible',
            'text-left',
            '-translate-x-2',
            '[transition-property:opacity,transform]',
            '[transition-duration:450ms,300ms]',
            '[transition-delay:200ms,0ms]',
            '[transition-timing-function:cubic-bezier(.76,0,.23,1)]',
            'motion-reduce:[transition-duration:150ms,1ms]',
            '!ease-out',
            state.type === StateType.Followup && 'opacity-100 visible -translate-x-0'
          )}
        >
          {state.type === StateType.Followup && (
            <>
              <span className="text-foreground-light">Thanks for your feedback!</span>
              <FeedbackButton
                ref={feedbackButtonRef}
                onClick={() => setModalOpen(true)}
                isYes={isYes}
                visible={true}
              />
            </>
          )}
        </div>
      </div>
      <FeedbackModal
        visible={modalOpen}
        page={pathname}
        onCancel={() => {
          setModalOpen(false)
          refocusButton()
        }}
        onSubmit={handleSubmit}
      />
    </section>
  )
}

Subdomains

Frequently Asked Questions

What does Feedback() do?
Feedback() is a function in the supabase codebase.
What does Feedback() call?
Feedback() calls 4 function(s): getLinearTeam, getSanitizedTabParams, useSendFeedbackMutation, useSendTelemetryEvent.

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free