Superlike entegrasyonu
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
- Genel Bakış
- API Endpoint'leri
- Socket Event'leri
- React Native Implementasyonu
- Hata Yönetimi
- Ö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:
getAppConfigendpoint'inden alınansuperLikePricedeğ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; // 102. 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 Code | Açıklama |
|---|---|
| 400 | Yetersiz kredi bakiyesi, geçersiz stream ID, stream aktif değil |
| 401 | Authentication gerekli |
| 403 | Kullanıcı bu yayında superlike gönderme yetkisine sahip değil (ban) |
| 404 | Stream 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ı
| Durum | HTTP Status | Mesaj | Açıklama |
|---|---|---|---|
| Yetersiz bakiye | 400 | "Yetersiz kredi bakiyesi" | Kullanıcının credit balance'ı superlike fiyatından az |
| Geçersiz stream ID | 400 | "Geçersiz canlı yayın kimliği" | Stream ID formatı hatalı |
| Stream aktif değil | 400 | "Canlı yayın aktif değil" | Stream durumu ACTIVE değil |
| Ban durumu | 403 | "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ı |
| Authentication | 401 | "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önderilirSenaryo 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
-
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.
-
Socket Bağlantısı: Superlike broadcast'lerini almak için mutlaka
/stream-chatnamespace'ine bağlanıpjoinStreamevent'i ile yayın chat'ine katılmanız gerekir. -
Authentication: Hem REST API hem de socket bağlantısı için geçerli bir JWT access token gereklidir.
-
Fiyat Değişikliği: Superlike fiyatı
getAppConfigendpoint'inden dinamik olarak alınır. Uygulama başlangıcında veya periyodik olarak bu değeri güncelleyin. -
Timeseries Storage: Tüm superlike'lar MongoDB timeseries collection'ında saklanır. Bu, performanslı sorgulama ve analiz için optimize edilmiştir.
-
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 gelir2. 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.