Фикс скрола
This commit is contained in:
@@ -115,7 +115,6 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal
|
|||||||
}
|
}
|
||||||
const firstUnreadId = activeChat === sessionUnreadRef.current.chatId ? sessionUnreadRef.current.msgId : null;
|
const firstUnreadId = activeChat === sessionUnreadRef.current.chatId ? sessionUnreadRef.current.msgId : null;
|
||||||
const lastObservedMessageIdRef = useRef<string | null>(null);
|
const lastObservedMessageIdRef = useRef<string | null>(null);
|
||||||
const prevScrollHeightRef = useRef<number>(0);
|
|
||||||
const initialScrollChatId = useRef<string | null>(null);
|
const initialScrollChatId = useRef<string | null>(null);
|
||||||
|
|
||||||
// Load muted state
|
// Load muted state
|
||||||
@@ -209,15 +208,6 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal
|
|||||||
}
|
}
|
||||||
}, [activeChat, isLoadingMessages]);
|
}, [activeChat, isLoadingMessages]);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
if (prevScrollHeightRef.current > 0 && messagesContainerRef.current) {
|
|
||||||
const container = messagesContainerRef.current;
|
|
||||||
const diff = container.scrollHeight - prevScrollHeightRef.current;
|
|
||||||
container.scrollTop += diff;
|
|
||||||
prevScrollHeightRef.current = 0;
|
|
||||||
}
|
|
||||||
}, [chatMessages.length]);
|
|
||||||
|
|
||||||
// Scroll on new message arrivals
|
// Scroll on new message arrivals
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (chatMessages.length > 0) {
|
if (chatMessages.length > 0) {
|
||||||
@@ -337,7 +327,6 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal
|
|||||||
|
|
||||||
const container = messagesContainerRef.current;
|
const container = messagesContainerRef.current;
|
||||||
if (container && container.scrollTop < 100 && activeChat && hasMoreMessages[activeChat] && !isLoadingMessages) {
|
if (container && container.scrollTop < 100 && activeChat && hasMoreMessages[activeChat] && !isLoadingMessages) {
|
||||||
prevScrollHeightRef.current = container.scrollHeight;
|
|
||||||
useChatStore.getState().loadMessages(activeChat, false, true);
|
useChatStore.getState().loadMessages(activeChat, false, true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -130,6 +130,9 @@ const translations = {
|
|||||||
klipySuccess: 'Klipy connection successful!',
|
klipySuccess: 'Klipy connection successful!',
|
||||||
klipyFailed: 'Klipy Test Failed: ',
|
klipyFailed: 'Klipy Test Failed: ',
|
||||||
apiRequired: 'API Key is required',
|
apiRequired: 'API Key is required',
|
||||||
|
customerIdRequired: 'Customer ID is required',
|
||||||
|
turnGatherFailed: 'Failed to gather candidates. Check credentials or network.',
|
||||||
|
turnTimeout: 'Timeout gathering candidates.',
|
||||||
},
|
},
|
||||||
ru: {
|
ru: {
|
||||||
loginTitle: 'Вход администратора',
|
loginTitle: 'Вход администратора',
|
||||||
@@ -215,6 +218,9 @@ const translations = {
|
|||||||
klipySuccess: 'Успешное подключение к Klipy!',
|
klipySuccess: 'Успешное подключение к Klipy!',
|
||||||
klipyFailed: 'Ошибка Klipy: ',
|
klipyFailed: 'Ошибка Klipy: ',
|
||||||
apiRequired: 'API ключ обязателен',
|
apiRequired: 'API ключ обязателен',
|
||||||
|
customerIdRequired: 'Customer ID обязателен',
|
||||||
|
turnGatherFailed: 'Сбор кандидатов не удался. Проверьте данные или сеть.',
|
||||||
|
turnTimeout: 'Таймаут при сборе кандидатов.',
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -333,12 +339,23 @@ export default function AdminPage() {
|
|||||||
let resolved = false;
|
let resolved = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const pc = new RTCPeerConnection({
|
const turnUrl = `turn:${config.turnHost}:${config.turnPort}`;
|
||||||
iceServers: [{
|
const stunUrl = `stun:${config.turnHost}:${config.turnPort}`;
|
||||||
urls: `turn:${config.turnHost}:${config.turnPort}`,
|
|
||||||
|
const servers: RTCIceServer[] = [
|
||||||
|
{ urls: stunUrl }
|
||||||
|
];
|
||||||
|
|
||||||
|
if (config.turnUser) {
|
||||||
|
servers.push({
|
||||||
|
urls: [turnUrl, turnUrl + "?transport=tcp"],
|
||||||
username: config.turnUser,
|
username: config.turnUser,
|
||||||
credential: config.turnSecret
|
credential: config.turnSecret || config.turnUser
|
||||||
}]
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const pc = new RTCPeerConnection({
|
||||||
|
iceServers: servers
|
||||||
});
|
});
|
||||||
|
|
||||||
pc.addTransceiver('audio');
|
pc.addTransceiver('audio');
|
||||||
@@ -349,7 +366,7 @@ export default function AdminPage() {
|
|||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
if (!resolved) {
|
if (!resolved) {
|
||||||
resolved = true;
|
resolved = true;
|
||||||
reject(new Error("Timeout gathering relay candidates"));
|
reject(new Error(t.turnTimeout || "Timeout"));
|
||||||
}
|
}
|
||||||
}, 10000);
|
}, 10000);
|
||||||
|
|
||||||
@@ -365,7 +382,7 @@ export default function AdminPage() {
|
|||||||
if (!resolved) {
|
if (!resolved) {
|
||||||
resolved = true;
|
resolved = true;
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
reject(new Error("Failed to gather candidates. Check credentials or network."));
|
reject(new Error(t.turnGatherFailed || "Failed to gather candidates."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -385,6 +402,10 @@ export default function AdminPage() {
|
|||||||
showToast(t.apiRequired, 'error');
|
showToast(t.apiRequired, 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!config.klipyCustomerId) {
|
||||||
|
showToast(t.customerIdRequired || "Customer ID required", 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setIsTestingKlipy(true);
|
setIsTestingKlipy(true);
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user