looood / src /contexts /chat-utils-context.tsx
looda3131's picture
Clean push without any binary history
cc276cc
"use client";
import React, { createContext, useContext, useState, useCallback } from 'react';
import { ref, update, remove, set } from "firebase/database";
import { storageService } from '@/lib/storage-service';
import type { User, ReplyTo, PrivacySettings, DataMode, ChatRecipient } from '@/lib/types';
import { useAuth } from '@/contexts/auth-context';
import { useFirebase } from '@/contexts/firebase-context';
import { useSettings } from '@/contexts/settings-context';
import { Capacitor } from '@capacitor/core';
export const useChatUtilsCore = () => {
const { currentUser } = useAuth();
const { rtdb } = useFirebase();
const { addToast, t, dataMode, privacySettings } = useSettings();
const clearChatHistory = useCallback(async (chatId: string) => {
try {
await storageService.clearMessages(chatId);
addToast(t('historyCleared'));
window.dispatchEvent(new CustomEvent('localDataChange', { detail: { chatId } }));
} catch (error) {
console.error("Error clearing local chat history:", error);
addToast(t('historyClearError'), { variant: "destructive" });
}
}, [addToast, t]);
const deleteMessage = useCallback(async (chatId: string, messageId: string) => {
if (!currentUser) return;
try {
const messageRef = ref(rtdb, `chats/${chatId}/messages/${messageId}`);
const updatePayload = {
text: null,
encryptedText: null,
isDeleted: true,
audioKey: null,
imageKey: null,
videoKey: null,
replyTo: null,
transcription: null,
urlPreviewData: null,
compressedText: null,
reactions: null,
};
await update(messageRef, updatePayload);
await storageService.updateMessage(chatId, messageId, { ...updatePayload, isDeleted: true });
window.dispatchEvent(new CustomEvent('localDataChange', { detail: { chatId } }));
} catch (error) {
console.error("Error deleting message:", error);
addToast(t('deleteMessageError'), { variant: "destructive" });
}
}, [currentUser, addToast, rtdb, t]);
const setUserTyping = useCallback((chatId: string, isTyping: boolean) => {
if (!currentUser || dataMode === 'ultra' || !privacySettings.showTyping) return;
const typingRef = ref(rtdb, `typing/${chatId}/${currentUser.uid}`);
if (isTyping) {
set(typingRef, currentUser.displayName);
} else {
remove(typingRef);
}
}, [currentUser, dataMode, rtdb, privacySettings.showTyping]);
const uploadFile = useCallback(async (file: File, onProgress: (progress: number) => void) => {
const formData = new FormData();
formData.append('file', file);
return new Promise<{ fileKey: string }>((resolve, reject) => {
const xhr = new XMLHttpRequest();
const isNative = Capacitor.isNativePlatform();
const baseUrl = isNative ? process.env.NEXT_PUBLIC_API_BASE_URL : '';
const uploadUrl = `${baseUrl}/api/media`;
xhr.open('POST', uploadUrl, true);
xhr.upload.onprogress = (event) => {
if (event.lengthComputable) {
const progress = (event.loaded / event.total) * 100;
onProgress(progress);
}
};
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
try {
const response = JSON.parse(xhr.responseText);
resolve({ fileKey: response.fileKey });
} catch (e) {
reject(new Error('Invalid JSON response from server.'));
}
} else {
reject(new Error(`Upload failed: ${xhr.statusText}`));
}
};
xhr.onerror = () => {
reject(new Error('Upload failed due to a network error.'));
};
xhr.send(formData);
});
}, []);
const transcribeAndSet = useCallback(async (messageId: string, audioFile: File, recipient: ChatRecipient) => {
if (!currentUser) return;
const chatId = recipient.isGroup
? recipient.uid
: (currentUser.uid < recipient.uid
? `private_'''${currentUser.uid}'''_'''${recipient.uid}'''`
: `private_'''${recipient.uid}'''_'''${currentUser.uid}'''`);
if (!chatId) return;
try {
// Disabled
} catch (error) {
console.warn("Could not transcribe audio:", error);
}
}, [currentUser, rtdb]);
return {
clearChatHistory,
deleteMessage,
setUserTyping,
uploadFile,
transcribeAndSet,
};
};
type ChatUtilsContextType = ReturnType<typeof useChatUtilsCore>;
const ChatUtilsContext = createContext<ChatUtilsContextType | null>(null);
export const useChatUtils = () => {
const context = useContext(ChatUtilsContext);
if (!context) {
throw new Error('useChatUtils must be used within a ChatUtilsProvider');
}
return context;
};
export const ChatUtilsProvider = ({ children }: { children: React.ReactNode }) => {
const chatUtilsData = useChatUtilsCore();
return (
<ChatUtilsContext.Provider value={chatUtilsData}>
{children}
</ChatUtilsContext.Provider>
);
};