Allmine API

Superlike entegrasyonu

~10 dkMobil / WebKararlı

Superlike mobil ve API kullanımı

Superlike Özelliği - React Native Entegrasyon Dokümantasyonu

Migration rehberi

Yapılandırma sırası için Migration şablonu. Yeni düzenlemelerde Amaç → Önkoşullar → Endpoint → Request/Response → Hata kodları → Client adımları → İlgili sayfalar bölümlerini tercih edin.

Bu dokümantasyon, React Native uygulamasında superlike özelliğinin nasıl kullanılacağını açıklar.

İçindekiler

  1. Genel Bakış
  2. API Endpoint'leri
  3. Socket Event'leri
  4. React Native Implementasyonu
  5. Hata Yönetimi
  6. Örnek Kullanım Senaryoları

Genel Bakış

Superlike özelliği, kullanıcıların canlı yayınlara özel bir beğeni göndermesini sağlar. Bu özellik:

  • Ücretli bir özelliktir: Her superlike için kullanıcının credit balance'ından belirli bir miktar düşülür
  • Fiyat: getAppConfig endpoint'inden alınan superLikePrice değeri kullanılır (varsayılan: 10 kredi)
  • Broadcast: Superlike gönderildiğinde, yayındaki tüm kullanıcılara socket üzerinden bildirim gönderilir
  • Timeseries: Tüm superlike'lar MongoDB timeseries collection'ında saklanır

API Endpoint'leri

1. App Config - Superlike Fiyatını Öğrenme

Superlike fiyatını öğrenmek için app config endpoint'ini kullanın.

Endpoint: GET /v1/app-config

Authentication: Gerekmez (Public endpoint)

Response:

{
  superLikePrice: number;  // Örnek: 10
}

Örnek Request:

const response = await fetch('https://api.allmine.win/v1/app-config');
const config = await response.json();
const superLikePrice = config.superLikePrice; // 10

2. Superlike Gönderme

Canlı yayına superlike göndermek için REST API endpoint'ini kullanın.

Endpoint: POST /v1/live-stream/:streamId/chat/superlike

Authentication: JWT Bearer token gerekli

Path Parameters:

  • streamId (string, required): Canlı yayın ID'si (MongoDB ObjectId)

Request Body: Yok (body gerekmez)

Response (201 Created):

{
  streamId: string;                    // Yayın ID'si
  senderId: string;                    // Gönderen kullanıcı ID'si
  senderSnapshot: {                    // Gönderen kullanıcı bilgisi snapshot'ı
    _id: string;
    username: string | null;
    name: string | null;
    surname: string | null;
    profilePhoto: {
      _id: string;
      url: string;
      thumbnailUrl?: string;
    } | null;
  };
  price: number;                       // Ödenen superlike fiyatı
  timestamp: Date;                      // Superlike zamanı
}

Hata Durumları:

Status CodeAçıklama
400Yetersiz kredi bakiyesi, geçersiz stream ID, stream aktif değil
401Authentication gerekli
403Kullanıcı bu yayında superlike gönderme yetkisine sahip değil (ban)
404Stream veya kullanıcı bulunamadı

Örnek Request:

const sendSuperlike = async (streamId: string, accessToken: string) => {
  try {
    const response = await fetch(
      `https://api.allmine.win/v1/live-stream/${streamId}/chat/superlike`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${accessToken}`,
          'Content-Type': 'application/json',
        },
      }
    );

    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.message || 'Superlike gönderilemedi');
    }

    const superlike = await response.json();
    return superlike;
  } catch (error) {
    console.error('Superlike gönderme hatası:', error);
    throw error;
  }
};

Socket Event'leri

Namespace: /stream-chat

Superlike'lar socket üzerinden broadcast edilir. Önce yayın chat'ine katılmanız gerekir.

1. Chat'e Katılma

Superlike broadcast'lerini almak için önce chat namespace'ine katılın:

import io from 'socket.io-client';

const socket = io('https://api.allmine.win/stream-chat', {
  transports: ['websocket', 'polling'],
  auth: {
    token: accessToken, // JWT access token
  },
});

// Yayın chat'ine katıl
socket.emit('joinStream', {
  streamId: '507f1f77bcf86cd799439011',
  token: accessToken,
});

socket.on('joinStreamSuccess', (data) => {
  console.log('Chat\'e katıldınız:', data);
});

2. Superlike Broadcast Event'i

Birisi superlike gönderdiğinde, yayındaki tüm kullanıcılara newSuperlike event'i gönderilir.

Event: newSuperlike

Payload:

{
  streamId: string;                    // Yayın ID'si
  senderId: string;                    // Gönderen kullanıcı ID'si
  senderSnapshot: {                    // Gönderen kullanıcı bilgisi
    _id: string;
    username: string | null;
    name: string | null;
    surname: string | null;
    profilePhoto: {
      _id: string;
      url: string;
      thumbnailUrl?: string;
    } | null;
  };
  price: number;                       // Ödenen superlike fiyatı
  timestamp: Date;                     // Superlike zamanı (ISO string)
}

Örnek Listener:

socket.on('newSuperlike', (superlike) => {
  console.log('Yeni superlike:', superlike);
  console.log('Gönderen:', superlike.senderSnapshot.username);
  console.log('Fiyat:', superlike.price);
  
  // UI'da superlike animasyonu göster
  showSuperlikeAnimation(superlike);
});

React Native Implementasyonu

1. Superlike Service Oluşturma

// services/superlike.service.ts
import { API_BASE_URL } from '../config';

export interface SuperlikeResponse {
  streamId: string;
  senderId: string;
  senderSnapshot: {
    _id: string;
    username: string | null;
    name: string | null;
    surname: string | null;
    profilePhoto: {
      _id: string;
      url: string;
      thumbnailUrl?: string;
    } | null;
  };
  price: number;
  timestamp: string;
}

export interface AppConfig {
  superLikePrice: number;
}

class SuperlikeService {
  private baseUrl = API_BASE_URL;

  /**
   * App config'den superlike fiyatını alır
   */
  async getSuperlikePrice(): Promise<number> {
    try {
      const response = await fetch(`${this.baseUrl}/v1/app-config`);
      const config: AppConfig = await response.json();
      return config.superLikePrice;
    } catch (error) {
      console.error('Superlike fiyatı alınamadı:', error);
      return 10; // Varsayılan değer
    }
  }

  /**
   * Canlı yayına superlike gönderir
   */
  async sendSuperlike(
    streamId: string,
    accessToken: string
  ): Promise<SuperlikeResponse> {
    const response = await fetch(
      `${this.baseUrl}/v1/live-stream/${streamId}/chat/superlike`,
      {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${accessToken}`,
          'Content-Type': 'application/json',
        },
      }
    );

    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.message || 'Superlike gönderilemedi');
    }

    return response.json();
  }
}

export const superlikeService = new SuperlikeService();

2. Socket Manager ile Superlike Broadcast Dinleme

// services/socket.service.ts
import io, { Socket } from 'socket.io-client';
import { SuperlikeResponse } from './superlike.service';

class SocketService {
  private socket: Socket | null = null;
  private superlikeListeners: Array<(superlike: SuperlikeResponse) => void> = [];

  /**
   * Stream chat namespace'ine bağlanır
   */
  connectToStreamChat(accessToken: string) {
    this.socket = io(`${API_BASE_URL}/stream-chat`, {
      transports: ['websocket', 'polling'],
      auth: {
        token: accessToken,
      },
    });

    // Superlike broadcast'ini dinle
    this.socket.on('newSuperlike', (superlike: SuperlikeResponse) => {
      this.superlikeListeners.forEach((listener) => listener(superlike));
    });

    this.socket.on('connect', () => {
      console.log('Stream chat socket bağlandı');
    });

    this.socket.on('disconnect', () => {
      console.log('Stream chat socket bağlantısı kesildi');
    });
  }

  /**
   * Yayın chat'ine katılır
   */
  joinStreamChat(streamId: string, accessToken: string) {
    if (!this.socket) {
      throw new Error('Socket bağlantısı yok');
    }

    this.socket.emit('joinStream', {
      streamId,
      token: accessToken,
    });
  }

  /**
   * Superlike event'ini dinlemek için listener ekler
   */
  onSuperlike(callback: (superlike: SuperlikeResponse) => void) {
    this.superlikeListeners.push(callback);
  }

  /**
   * Superlike listener'ı kaldırır
   */
  offSuperlike(callback: (superlike: SuperlikeResponse) => void) {
    this.superlikeListeners = this.superlikeListeners.filter(
      (listener) => listener !== callback
    );
  }

  /**
   * Socket bağlantısını kapatır
   */
  disconnect() {
    if (this.socket) {
      this.socket.disconnect();
      this.socket = null;
    }
    this.superlikeListeners = [];
  }
}

export const socketService = new SocketService();

3. React Native Component Örneği

// components/LiveStreamScreen.tsx
import React, { useEffect, useState } from 'react';
import { View, Text, TouchableOpacity, Alert } from 'react-native';
import { superlikeService, SuperlikeResponse } from '../services/superlike.service';
import { socketService } from '../services/socket.service';
import { useAuth } from '../hooks/useAuth';

interface Props {
  streamId: string;
}

export const LiveStreamScreen: React.FC<Props> = ({ streamId }) => {
  const { accessToken, user } = useAuth();
  const [superlikePrice, setSuperlikePrice] = useState<number>(10);
  const [creditBalance, setCreditBalance] = useState<number>(0);
  const [isSending, setIsSending] = useState(false);

  useEffect(() => {
    // Superlike fiyatını al
    loadSuperlikePrice();

    // Socket bağlantısını kur ve chat'e katıl
    if (accessToken) {
      socketService.connectToStreamChat(accessToken);
      socketService.joinStreamChat(streamId, accessToken);

      // Superlike broadcast'ini dinle
      const handleSuperlike = (superlike: SuperlikeResponse) => {
        console.log('Yeni superlike:', superlike);
        // UI'da animasyon göster
        showSuperlikeAnimation(superlike);
      };

      socketService.onSuperlike(handleSuperlike);

      return () => {
        socketService.offSuperlike(handleSuperlike);
        socketService.disconnect();
      };
    }
  }, [streamId, accessToken]);

  const loadSuperlikePrice = async () => {
    try {
      const price = await superlikeService.getSuperlikePrice();
      setSuperlikePrice(price);
    } catch (error) {
      console.error('Fiyat yüklenemedi:', error);
    }
  };

  const handleSendSuperlike = async () => {
    // Kredi kontrolü
    if (creditBalance < superlikePrice) {
      Alert.alert(
        'Yetersiz Bakiye',
        `Superlike göndermek için en az ${superlikePrice} kredi gereklidir. Mevcut bakiyeniz: ${creditBalance}`,
        [{ text: 'Tamam' }]
      );
      return;
    }

    // Onay al
    Alert.alert(
      'Superlike Gönder',
      `${superlikePrice} kredi ile superlike göndermek istediğinize emin misiniz?`,
      [
        { text: 'İptal', style: 'cancel' },
        {
          text: 'Gönder',
          onPress: async () => {
            setIsSending(true);
            try {
              const superlike = await superlikeService.sendSuperlike(
                streamId,
                accessToken!
              );
              
              // Başarılı - credit balance güncelle (kullanıcı bilgilerini yeniden yükle)
              setCreditBalance((prev) => prev - superlikePrice);
              
              Alert.alert('Başarılı', 'Superlike gönderildi!');
            } catch (error: any) {
              Alert.alert(
                'Hata',
                error.message || 'Superlike gönderilemedi'
              );
            } finally {
              setIsSending(false);
            }
          },
        },
      ]
    );
  };

  const showSuperlikeAnimation = (superlike: SuperlikeResponse) => {
    // Superlike animasyonu göster
    // Örnek: Lottie animasyonu, toast mesajı, vb.
    console.log('Superlike animasyonu göster:', superlike);
  };

  return (
    <View>
      {/* Superlike butonu */}
      <TouchableOpacity
        onPress={handleSendSuperlike}
        disabled={isSending || creditBalance < superlikePrice}
        style={{
          opacity: creditBalance < superlikePrice ? 0.5 : 1,
        }}
      >
        <Text>⭐ Superlike ({superlikePrice} kredi)</Text>
      </TouchableOpacity>

      {/* Kredi bakiyesi */}
      <Text>Kredi Bakiyesi: {creditBalance}</Text>
    </View>
  );
};

4. Superlike Animasyonu Gösterme

// components/SuperlikeAnimation.tsx
import React, { useEffect } from 'react';
import { View, Text, Animated, StyleSheet } from 'react-native';
import { SuperlikeResponse } from '../services/superlike.service';

interface Props {
  superlike: SuperlikeResponse;
  onComplete: () => void;
}

export const SuperlikeAnimation: React.FC<Props> = ({ superlike, onComplete }) => {
  const fadeAnim = new Animated.Value(0);
  const scaleAnim = new Animated.Value(0.5);
  const translateY = new Animated.Value(0);

  useEffect(() => {
    // Animasyon başlat
    Animated.parallel([
      Animated.timing(fadeAnim, {
        toValue: 1,
        duration: 300,
        useNativeDriver: true,
      }),
      Animated.spring(scaleAnim, {
        toValue: 1,
        friction: 4,
        useNativeDriver: true,
      }),
      Animated.timing(translateY, {
        toValue: -100,
        duration: 2000,
        useNativeDriver: true,
      }),
      Animated.timing(fadeAnim, {
        toValue: 0,
        duration: 500,
        delay: 1500,
        useNativeDriver: true,
      }),
    ]).start(() => {
      onComplete();
    });
  }, []);

  return (
    <Animated.View
      style={[
        styles.container,
        {
          opacity: fadeAnim,
          transform: [
            { scale: scaleAnim },
            { translateY: translateY },
          ],
        },
      ]}
    >
      <Text style={styles.emoji}>⭐</Text>
      <Text style={styles.username}>
        {superlike.senderSnapshot.username || 'Kullanıcı'}
      </Text>
      <Text style={styles.text}>Superlike gönderdi!</Text>
    </Animated.View>
  );
};

const styles = StyleSheet.create({
  container: {
    position: 'absolute',
    top: '50%',
    alignSelf: 'center',
    alignItems: 'center',
    backgroundColor: 'rgba(0, 0, 0, 0.7)',
    padding: 20,
    borderRadius: 10,
  },
  emoji: {
    fontSize: 48,
  },
  username: {
    color: 'white',
    fontSize: 16,
    fontWeight: 'bold',
    marginTop: 8,
  },
  text: {
    color: 'white',
    fontSize: 14,
    marginTop: 4,
  },
});

Hata Yönetimi

Hata Kodları ve Mesajları

DurumHTTP StatusMesajAçıklama
Yetersiz bakiye400"Yetersiz kredi bakiyesi"Kullanıcının credit balance'ı superlike fiyatından az
Geçersiz stream ID400"Geçersiz canlı yayın kimliği"Stream ID formatı hatalı
Stream aktif değil400"Canlı yayın aktif değil"Stream durumu ACTIVE değil
Ban durumu403"Bu yayında superlike gönderme yetkiniz yok"Kullanıcı bu yayında banlı
Stream bulunamadı404"Canlı yayın bulunamadı"Stream ID'si veritabanında yok
Kullanıcı bulunamadı404"Kullanıcı bulunamadı"JWT token'daki kullanıcı bulunamadı
Authentication401"Unauthorized"JWT token geçersiz veya eksik

Hata Yönetimi Örneği

const handleSuperlikeError = (error: any) => {
  if (error.message.includes('Yetersiz kredi bakiyesi')) {
    Alert.alert(
      'Yetersiz Bakiye',
      'Superlike göndermek için yeterli krediniz yok. Lütfen kredi paketi satın alın.',
      [
        { text: 'İptal' },
        { text: 'Kredi Satın Al', onPress: () => navigateToCreditPackages() },
      ]
    );
  } else if (error.message.includes('superlike gönderme yetkiniz yok')) {
    Alert.alert('Yetki Yok', 'Bu yayında superlike gönderme yetkiniz bulunmamaktadır.');
  } else if (error.message.includes('aktif değil')) {
    Alert.alert('Yayın Aktif Değil', 'Bu yayın artık aktif değil.');
  } else {
    Alert.alert('Hata', 'Superlike gönderilirken bir hata oluştu. Lütfen tekrar deneyin.');
  }
};

Örnek Kullanım Senaryoları

Senaryo 1: Superlike Gönderme ve Broadcast Dinleme

// 1. App config'den fiyatı al
const price = await superlikeService.getSuperlikePrice();

// 2. Socket bağlantısı kur ve chat'e katıl
socketService.connectToStreamChat(accessToken);
socketService.joinStreamChat(streamId, accessToken);

// 3. Superlike broadcast'ini dinle
socketService.onSuperlike((superlike) => {
  // UI'da animasyon göster
  showSuperlikeAnimation(superlike);
});

// 4. Superlike gönder
await superlikeService.sendSuperlike(streamId, accessToken);
// Not: Broadcast otomatik olarak socket üzerinden gönderilir

Senaryo 2: Kredi Kontrolü ve Onay

const handleSuperlikeWithConfirmation = async () => {
  // Kredi kontrolü
  const price = await superlikeService.getSuperlikePrice();
  const userBalance = await getUserCreditBalance();

  if (userBalance < price) {
    // Yetersiz bakiye - kredi satın alma sayfasına yönlendir
    navigateToCreditPackages();
    return;
  }

  // Onay al
  const confirmed = await showConfirmationDialog(
    'Superlike Gönder',
    `${price} kredi ile superlike göndermek istediğinize emin misiniz?`
  );

  if (confirmed) {
    try {
      await superlikeService.sendSuperlike(streamId, accessToken);
      // Başarılı
    } catch (error) {
      // Hata yönetimi
      handleSuperlikeError(error);
    }
  }
};

Senaryo 3: Superlike Listesi Gösterme

Superlike'lar timeseries collection'ında saklandığı için, geçmiş superlike'ları sorgulamak için ayrı bir endpoint gerekebilir. Şu an için sadece real-time broadcast mevcuttur.


Önemli Notlar

  1. Credit Balance Güncelleme: Superlike gönderildikten sonra, kullanıcının credit balance'ı otomatik olarak düşer. UI'da kullanıcı bilgilerini yeniden yükleyerek güncel bakiyeyi gösterebilirsiniz.

  2. Socket Bağlantısı: Superlike broadcast'lerini almak için mutlaka /stream-chat namespace'ine bağlanıp joinStream event'i ile yayın chat'ine katılmanız gerekir.

  3. Authentication: Hem REST API hem de socket bağlantısı için geçerli bir JWT access token gereklidir.

  4. Fiyat Değişikliği: Superlike fiyatı getAppConfig endpoint'inden dinamik olarak alınır. Uygulama başlangıcında veya periyodik olarak bu değeri güncelleyin.

  5. Timeseries Storage: Tüm superlike'lar MongoDB timeseries collection'ında saklanır. Bu, performanslı sorgulama ve analiz için optimize edilmiştir.

  6. Ban Kontrolü: Kullanıcı yayında banlıysa (CHAT_ONLY veya BLOCK), superlike gönderemez.


Test Senaryoları

1. Başarılı Superlike Gönderme

// Kredi bakiyesi yeterli, stream aktif, kullanıcı banlı değil
const result = await superlikeService.sendSuperlike(streamId, accessToken);
// ✅ Başarılı - result döner, socket'te newSuperlike event'i gelir

2. Yetersiz Bakiye

// Kredi bakiyesi superlike fiyatından az
try {
  await superlikeService.sendSuperlike(streamId, accessToken);
} catch (error) {
  // ✅ 400 Bad Request - "Yetersiz kredi bakiyesi"
}

3. Stream Aktif Değil

// Stream durumu ACTIVE değil
try {
  await superlikeService.sendSuperlike(streamId, accessToken);
} catch (error) {
  // ✅ 400 Bad Request - "Canlı yayın aktif değil"
}

4. Broadcast Dinleme

// Socket bağlantısı kuruldu, joinStream yapıldı
socketService.onSuperlike((superlike) => {
  // ✅ newSuperlike event'i geldiğinde bu callback çalışır
});

API Base URL'leri

  • Local: http://localhost:3000
  • Development: https://dev.allmine.win
  • Staging: https://staging.allmine.win
  • Production: https://api.allmine.win

Socket URL'leri için ws:// veya wss:// protokolünü kullanın.


Destek

Sorularınız için backend ekibi ile iletişime geçin.

On this page