> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thunderphone.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Headless Hook

> useThunderPhone React hook'u ile tamamen özel bir ses arayüzü oluşturun

`useThunderPhone` hook'u, ThunderPhone ses oturumunu, ses yönlendirmesini ve bağlantı durumunu yönetirken kullanıcı arayüzü üzerinde tam denetim sağlar. ThunderPhone arka planda her şeyi yönetirken kendi düğmeleriniz, düzenleriniz, animasyonlarınız ve markalamanızla tamamen özel bir kullanıcı arayüzü istediğinizde kullanın.

## Arayüzsüz Hook Ne Zaman Kullanılmalı

Hazır `ThunderPhoneWidget` bileşeni çoğu kullanım durumunu kapsar, ancak aşağıdakilere ihtiyacınız olduğunda arayüzsüz hook'u kullanın:

* Uygulamanızın tasarım sistemine uyan tamamen özel bir arama kullanıcı arayüzü
* Gerçek zamanlı ses seviyelerine dayalı, sese duyarlı görselleştirmeler (dalga formları, küreler, titreşimli göstergeler)
* Arama öncesi formlar, arama sonrası anketler veya sesin yanında satır içi sohbet gibi özel arama akışları
* Mevcut bir bileşen kitaplığıyla entegrasyon (Material UI, Chakra, Radix vb.)

***

## Kurulum

```bash theme={null}
npm install @thunderphone/widget
```

<Note>
  Kendi kullanıcı arayüzünüzü sağladığınız için arayüzsüz hook, `@thunderphone/widget/style.css` içe aktarımını **gerektirmez**. Ancak yine de aynı `@thunderphone/widget` paketini yüklemelisiniz.
</Note>

***

## Temel Kullanım

```tsx theme={null}
import { useThunderPhone } from '@thunderphone/widget'

function CustomCallButton() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })

  const handleClick = () => {
    if (phone.state === 'connected') {
      phone.disconnect()
    } else {
      phone.connect()
    }
  }

  return (
    <>
      <button onClick={handleClick} disabled={phone.state === 'connecting'}>
        {phone.state === 'connecting'
          ? 'Connecting...'
          : phone.state === 'connected'
            ? 'End call'
            : 'Start call'}
      </button>
      {phone.audio}
    </>
  )
}
```

<Warning>
  **Bileşen ağacınızda bir yerde `phone.audio` öğesini oluşturmalısınız.** Bu, temel ses bağlantısını yöneten görünmez bir React öğesidir. Atlarsanız ses oynatılmaz ve oturum çalışmaz.
</Warning>

***

## Seçenekler

Bu seçenekleri `UseThunderPhoneOptions` aracılığıyla `useThunderPhone` için iletin:

| Seçenek          | Tür                 | Zorunlu | Varsayılan                          | Açıklama                                                                                                                                                              |
| ---------------- | ------------------- | ------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `publishableKey` | `string`            | Evet    | --                                  | Yayınlanabilir API anahtarı (`pk_live_...`). Yapay zeka ajanı, anahtarın widget yapılandırmasından otomatik olarak belirlenir.                                        |
| `apiBase`        | `string`            | Hayır   | `'https://api.thunderphone.com/v1'` | API temel URL'sini geçersiz kılma.                                                                                                                                    |
| `language`       | `string`            | Hayır   | --                                  | Oturum başına dil geçersiz kılma -- `en`, `es` veya `fr-FR` gibi bir dil kodu ya da yerel ayar. Ayarlanmadığında, yapay zeka ajanının yapılandırılmış dili uygulanır. |
| `voice`          | `string`            | Hayır   | --                                  | Oturum başına ses geçersiz kılma -- `maria` gibi bir ses adı. Ayarlanmadığında, yapay zeka ajanının yapılandırılmış sesi uygulanır.                                   |
| `context`        | `string`            | Hayır   | --                                  | Yapay zeka ajanına iletilen, oturum başına olgusal sayfa veya site bağlamı. Sunucu tarafında 12.000 karaktere kadar kısaltılır.                                       |
| `onConnect`      | `() => void`        | Hayır   | --                                  | Ses oturumu bağlandığında çağrılır.                                                                                                                                   |
| `onDisconnect`   | `() => void`        | Hayır   | --                                  | Oturum sona erdiğinde çağrılır.                                                                                                                                       |
| `onError`        | `(error) => void`   | Hayır   | --                                  | Hatalarda çağrılır. Hata, `error` (kod) ve `message` alanlarına sahiptir.                                                                                             |
| `ringtone`       | `boolean \| string` | Hayır   | `false`                             | Bağlanırken zil sesi çalar. Varsayılan zil sesi için `true`, özel ses için ise bir URL dizesi kullanın.                                                               |

<Note>
  Hook arayüzsüzdür: `ThunderPhoneWidget` görünüm prop'larını (`theme`, `primaryColor`, `title`, `position`, `className`) **kabul etmez**. Bunları iletmek bir TypeScript hatasıdır -- sunumu tamamen siz oluşturursunuz.
</Note>

***

## Dönüş Değeri

Hook, bir `UseThunderPhoneReturn` nesnesi döndürür:

| Özellik         | Tür                                                                  | Açıklama                                                                                                                                                                                                                                                                                                                                                                                                         |
| --------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `state`         | `'idle' \| 'connecting' \| 'connected' \| 'disconnected' \| 'error'` | Geçerli bağlantı durumu.                                                                                                                                                                                                                                                                                                                                                                                         |
| `connect`       | `() => void`                                                         | Sesli oturumu başlatın.                                                                                                                                                                                                                                                                                                                                                                                          |
| `disconnect`    | `() => void`                                                         | Geçerli oturumu sonlandırın.                                                                                                                                                                                                                                                                                                                                                                                     |
| `toggleMute`    | `() => void`                                                         | Mikrofon sessize alma durumunu açıp kapatın.                                                                                                                                                                                                                                                                                                                                                                     |
| `isMuted`       | `boolean`                                                            | Mikrofonun şu anda sessize alınıp alınmadığı.                                                                                                                                                                                                                                                                                                                                                                    |
| `error`         | `string \| undefined`                                                | Durum `'error'` olduğunda hata mesajı.                                                                                                                                                                                                                                                                                                                                                                           |
| `agentName`     | `string \| undefined`                                                | Bağlı ajanın görünen adı.                                                                                                                                                                                                                                                                                                                                                                                        |
| `audioLevel`    | `number`                                                             | **Kullanımdan kaldırıldı -- her zaman `0`.** Geriye dönük uyumluluk için korunan statik bir yer tutucudur; hiçbir zaman güncellenmez. Bunun yerine `audioLevelRef.current` okuyun.                                                                                                                                                                                                                               |
| `audioLevelRef` | `React.RefObject<number>`                                            | Gerçek zamanlı ses seviyesini (0--1) içeren değiştirilebilir bir ref -- ajanın sesi ile ziyaretçinin mikrofonundan hangisi daha yüksekse o -- her animasyon karesinde React'in işleme döngüsü dışında güncellenir. Akıcı, takılmasız animasyonlar için `requestAnimationFrame` döngülerinde `audioLevelRef.current` okuyun veya React durumunda değere ihtiyaç duyduğunuzda bunu belirli aralıklarla örnekleyin. |
| `audio`         | `ReactNode`                                                          | Ses bağlantısını yöneten görünmez öğe -- **işlenmelidir**.                                                                                                                                                                                                                                                                                                                                                       |

***

## Sese Duyarlı UI

`audioLevelRef` ref'i, React yeniden oluşturmalarını tetiklemeden kare hızı düzeyinde ses seviyeleri sunar; bu da onu akıcı dalga biçimi görselleştirmeleri, titreşen küreler veya konuşmaya bağlı herhangi bir animasyonu çalıştırmak için ideal kılar. Seviye, yapay zeka ajanının sesi ya da ziyaretçinin mikrofonundan hangisi daha yüksekse onu yansıtır.

### Dalga Biçimi Örneği

```tsx theme={null}
import { useRef, useEffect } from 'react'
import { useThunderPhone } from '@thunderphone/widget'

function WaveformCall() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })
  const canvasRef = useRef<HTMLCanvasElement>(null)

  useEffect(() => {
    if (phone.state !== 'connected') return
    const canvas = canvasRef.current
    if (!canvas) return
    const ctx = canvas.getContext('2d')!

    let animId: number
    const draw = () => {
      const level = phone.audioLevelRef.current ?? 0
      ctx.clearRect(0, 0, canvas.width, canvas.height)

      // Draw bars that react to audio level
      const barCount = 24
      const barWidth = canvas.width / barCount
      for (let i = 0; i < barCount; i++) {
        const distance = Math.abs(i - barCount / 2) / (barCount / 2)
        const height = level * canvas.height * (1 - distance * 0.6)
        const y = (canvas.height - height) / 2
        ctx.fillStyle = '#0ea5e9'
        ctx.fillRect(i * barWidth + 1, y, barWidth - 2, height)
      }

      animId = requestAnimationFrame(draw)
    }
    animId = requestAnimationFrame(draw)
    return () => cancelAnimationFrame(animId)
  }, [phone.state, phone.audioLevelRef])

  return (
    <div>
      {phone.state === 'connected' && (
        <canvas ref={canvasRef} width={240} height={80} />
      )}
      <button
        onClick={phone.state === 'connected' ? phone.disconnect : phone.connect}
        disabled={phone.state === 'connecting'}
      >
        {phone.state === 'connected' ? 'End call' : 'Start call'}
      </button>
      {phone.audio}
    </div>
  )
}
```

### Titreşen Küre Örneği

```tsx theme={null}
import { useRef, useEffect } from 'react'
import { useThunderPhone } from '@thunderphone/widget'

function PulsingOrb() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })
  const orbRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    if (phone.state !== 'connected') return
    let animId: number
    const animate = () => {
      const level = phone.audioLevelRef.current ?? 0
      if (orbRef.current) {
        const scale = 1 + level * 0.5
        orbRef.current.style.transform = `scale(${scale})`
        orbRef.current.style.opacity = `${0.6 + level * 0.4}`
      }
      animId = requestAnimationFrame(animate)
    }
    animId = requestAnimationFrame(animate)
    return () => cancelAnimationFrame(animId)
  }, [phone.state, phone.audioLevelRef])

  return (
    <div style={{ textAlign: 'center' }}>
      <div
        ref={orbRef}
        style={{
          width: 80,
          height: 80,
          borderRadius: '50%',
          background: '#0ea5e9',
          margin: '20px auto',
          transition: 'transform 0.05s ease-out',
        }}
      />
      <button
        onClick={phone.state === 'connected' ? phone.disconnect : phone.connect}
        disabled={phone.state === 'connecting'}
      >
        {phone.state === 'connected' ? 'End call' : 'Call'}
      </button>
      {phone.audio}
    </div>
  )
}
```

### Konuşma Göstergesi Örneği

Ses düzeyiyle değişen React ile işlenen bir kullanıcı arayüzü için -- eşik tabanlı bir "konuşuyor" rozeti gibi -- `audioLevelRef.current` değerini düzenli aralıklarla örnekleyin ve sonucu durumda saklayın:

```tsx theme={null}
import { useEffect, useState } from 'react'
import { useThunderPhone } from '@thunderphone/widget'

function SpeakingBadge() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })
  const [speaking, setSpeaking] = useState(false)

  useEffect(() => {
    if (phone.state !== 'connected') {
      setSpeaking(false)
      return
    }
    const interval = setInterval(() => {
      setSpeaking((phone.audioLevelRef.current ?? 0) > 0.1)
    }, 100)
    return () => clearInterval(interval)
  }, [phone.state, phone.audioLevelRef])

  return (
    <div>
      {phone.state === 'connected' && (
        <span>{speaking ? 'Speaking' : 'Listening'}</span>
      )}
      <button onClick={phone.state === 'connected' ? phone.disconnect : phone.connect}>
        {phone.state === 'connected' ? 'End call' : 'Start call'}
      </button>
      {phone.audio}
    </div>
  )
}
```

<Warning>
  Seviyeleri her zaman `audioLevelRef.current` üzerinden okuyun. Dönüş nesnesindeki `audioLevel` sayısı **kullanımdan kaldırılmıştır ve her zaman `0` değerindedir** -- buna dayalı tüm mantık sessizce sıfır değerini okur.
</Warning>

***

## Durum Makinesi

`state` özelliği şu yaşam döngüsünü izler:

```
idle --> connecting --> connected --> disconnected --> idle (after 1.5s)
                  \
                   --> error (stays until connect() is called again)
```

| Durum          | Açıklama                                                                                                                                                                                |
| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `idle`         | Etkin oturum yok. `connect()` çağrılmaya hazır.                                                                                                                                         |
| `connecting`   | Oturum kuruluyor. Bu durum sırasında arama düğmesini devre dışı bırakın.                                                                                                                |
| `connected`    | Sesli oturum etkin. Kullanıcı ajanla konuşuyor.                                                                                                                                         |
| `disconnected` | Oturum sorunsuz şekilde sona erdi. 1,5 saniye sonra otomatik olarak `idle` durumuna geçer.                                                                                              |
| `error`        | Bir sorun oluştu. Mesaj için `phone.error` değerini kontrol edin. Durum kendiliğinden temizlenmez -- `connect()` işlevini yeniden çağırmak yeni bir deneme başlatır ve hatayı sıfırlar. |

***

## Örnekler

### Sessize Alma Denetimi ile

```tsx theme={null}
import { useThunderPhone } from '@thunderphone/widget'

function CallWithMute() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })

  return (
    <div>
      {phone.state === 'connected' && (
        <div>
          <p>Talking to {phone.agentName ?? 'Agent'}</p>
          <button onClick={phone.toggleMute}>
            {phone.isMuted ? 'Unmute' : 'Mute'}
          </button>
          <button onClick={phone.disconnect}>End call</button>
        </div>
      )}

      {phone.state !== 'connected' && (
        <button
          onClick={phone.connect}
          disabled={phone.state === 'connecting'}
        >
          {phone.state === 'connecting' ? 'Connecting...' : 'Call support'}
        </button>
      )}

      {phone.state === 'error' && (
        <p style={{ color: 'red' }}>{phone.error}</p>
      )}

      {phone.audio}
    </div>
  )
}
```

### Zil Sesi ile

Telefon aramasını simüle etmek için bağlanırken bir zil sesi çalın:

```tsx theme={null}
import { useThunderPhone } from '@thunderphone/widget'

function PhoneCallButton() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
    ringtone: true, // or a custom URL: 'https://example.com/ringtone.mp3'
  })

  return (
    <>
      <button
        onClick={phone.state === 'connected' ? phone.disconnect : phone.connect}
        disabled={phone.state === 'connecting'}
      >
        {phone.state === 'connecting'
          ? 'Ringing...'
          : phone.state === 'connected'
            ? 'Hang up'
            : 'Call'}
      </button>
      {phone.audio}
    </>
  )
}
```

Zil sesi, `connecting` durumu sırasında döngü halinde çalar ve ajan bağlandığında kademeli olarak azalır. Yerleşik varsayılan zil sesi için `true`, kendi ses dosyanızı kullanmak için ise bir URL dizesi iletin.

### Olay Geri Çağrıları ile

```tsx theme={null}
import { useThunderPhone } from '@thunderphone/widget'

function TrackedCallButton() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
    onConnect: () => {
      analytics.track('call_started')
    },
    onDisconnect: () => {
      analytics.track('call_ended')
    },
    onError: (error) => {
      analytics.track('call_error', { code: error.error, message: error.message })
    },
  })

  return (
    <>
      <button
        onClick={phone.state === 'connected' ? phone.disconnect : phone.connect}
        disabled={phone.state === 'connecting'}
      >
        {phone.state === 'connected' ? 'Hang up' : 'Talk to AI'}
      </button>
      {phone.audio}
    </>
  )
}
```

### Tam Özel Arayüz

```tsx theme={null}
import { useThunderPhone } from '@thunderphone/widget'

function FullCustomUI() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })

  return (
    <div className="call-panel">
      <div className="call-status">
        {phone.state === 'idle' && <span>Ready</span>}
        {phone.state === 'connecting' && <span className="pulse">Connecting...</span>}
        {phone.state === 'connected' && (
          <span>On call with {phone.agentName}</span>
        )}
        {phone.state === 'error' && <span className="error">{phone.error}</span>}
      </div>

      <div className="call-controls">
        {phone.state === 'connected' ? (
          <>
            <button className="mute-btn" onClick={phone.toggleMute}>
              {phone.isMuted ? 'Unmute' : 'Mute'}
            </button>
            <button className="end-btn" onClick={phone.disconnect}>
              End
            </button>
          </>
        ) : (
          <button
            className="start-btn"
            onClick={phone.connect}
            disabled={phone.state === 'connecting'}
          >
            Start call
          </button>
        )}
      </div>

      {/* Required -- handles audio under the hood */}
      {phone.audio}
    </div>
  )
}
```

***

## İpuçları

<AccordionGroup>
  <Accordion title="phone.audio'yu her zaman render edin">
    `phone.audio` öğesi görünmez ancak gereklidir. JSX'inizde herhangi bir yere yerleştirin -- görünür bir DOM render etmez, ancak WebRTC ses bağlantısını dahili olarak yönetir.
  </Accordion>

  <Accordion title="Bağlanırken düğmeyi devre dışı bırakın">
    `connecting` durumu 1-3 saniye sürebilir. Yinelenen bağlantı denemelerini önlemek için bu durum sırasında arama düğmesini devre dışı bırakın.
  </Accordion>

  <Accordion title="Hata durumunu sorunsuz şekilde yönetin">
    Durum `error` olduğunda, kullanıcıya `phone.error` değerini gösterin ve arama düğmenizi etkin tutun. Hook, `error` durumundan kendiliğinden çıkmaz -- `connect()` işlevini yeniden çağırmak yeni bir deneme başlatır ve önceki hatayı temizler.
  </Accordion>

  <Accordion title="Yan etkiler için geri çağrıları kullanın">
    `onConnect`, `onDisconnect` ve `onError` geri çağrıları; durumu yoklamadan analitik, günlük kaydı veya diğer uygulama mantıklarını tetiklemek için idealdir.
  </Accordion>

  <Accordion title="Ses seviyelerini audioLevelRef'ten okuyun">
    `audioLevelRef`, tek canlı ses seviyesi kaynağıdır. Dalga formları gibi akıcı animasyonlar için `audioLevelRef.current` değerini `requestAnimationFrame` içinde okuyun (bir ref'i okumak yeniden render işlemine neden olmaz) veya bunu belirli aralıklarla örnekleyip sonucu React tarafından render edilen kullanıcı arayüzü için durumda saklayın. `audioLevel` sayısı kullanımdan kaldırılmıştır ve her zaman `0` değerindedir -- bunun üzerine mantık oluşturmayın.
  </Accordion>
</AccordionGroup>
