Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Plik: firebase.js
- const FAKE_EMAIL_DOMAIN = '@br-timer.fan';
- let isSaving = false;
- let currentUserNick = null;
- window.currentUser = null;
- window.activeGroupId = null; // null oznacza "Moje Lokalne Timery"
- let unsubscribeGroupTimersListener = null;
- let unsubscribeUserGroupsListener = null;
- let isProcessingGroupAction = false; // Flaga zapobiegająca wielokrotnym operacjom
- // --- OBSŁUGA STANU LOGOWANIA ---
- auth.onAuthStateChanged(user => {
- console.log("AUTH_STATE_CHANGED: User status:", user ? user.email : 'Logged out');
- const loginButton = document.getElementById('loginButton');
- const userMenuContainer = document.getElementById('userMenuContainer');
- const userButton = document.getElementById('userButton');
- const groupManagementContainer = document.getElementById('groupManagementContainer');
- const userGroupsListSection = document.getElementById('userGroupsListSection');
- const activeGroupSelectorContainer = document.getElementById('activeGroupSelectorContainer');
- const currentTimerContextUI = document.getElementById('currentTimerContext');
- if (user) {
- window.currentUser = user;
- if (loginButton) loginButton.style.display = 'none';
- if (userMenuContainer) userMenuContainer.style.display = 'block';
- if (userButton) userButton.textContent = `👤 ${user.email.split('@')[0]}`;
- if (activeGroupSelectorContainer) activeGroupSelectorContainer.style.display = 'block';
- if (userGroupsListSection) userGroupsListSection.style.display = 'block';
- if (currentTimerContextUI) currentTimerContextUI.textContent = "Lokalne";
- loadUserGroupsAndHandleActive(); // Kluczowe wywołanie po zalogowaniu
- loadUserSettingsFromFirebase();
- if (groupManagementContainer) groupManagementContainer.style.display = 'none';
- document.querySelectorAll('.tab-content').forEach(el => el.style.display = 'none');
- } else { // Użytkownik wylogowany
- console.log("AUTH_STATE_CHANGED: User logged out. Cleaning up listeners and state.");
- window.currentUser = null;
- const oldActiveGroupId = window.activeGroupId;
- window.activeGroupId = null;
- if (unsubscribeGroupTimersListener) {
- unsubscribeGroupTimersListener();
- unsubscribeGroupTimersListener = null;
- console.log("AUTH_STATE_CHANGED: Unsubscribed group timers listener for old group:", oldActiveGroupId);
- }
- if (unsubscribeUserGroupsListener) {
- unsubscribeUserGroupsListener();
- unsubscribeUserGroupsListener = null;
- console.log("AUTH_STATE_CHANGED: Unsubscribed user groups listener.");
- }
- if (loginButton) loginButton.style.display = 'inline-flex';
- if (userMenuContainer) userMenuContainer.style.display = 'none';
- if (activeGroupSelectorContainer) activeGroupSelectorContainer.style.display = 'none';
- if (userGroupsListSection) userGroupsListSection.style.display = 'none';
- if (groupManagementContainer) groupManagementContainer.style.display = 'none';
- document.querySelectorAll('.tab-content').forEach(el => el.style.display = 'none');
- if (currentTimerContextUI) currentTimerContextUI.textContent = "Lokalne";
- if (typeof window.clearLocalTimers === 'function') window.clearLocalTimers();
- if (typeof window.loadTimers === 'function') window.loadTimers();
- if (typeof window.loadSavedBackground === 'function') window.loadSavedBackground();
- if (typeof window.loadNotificationSound === 'function') window.loadNotificationSound();
- }
- });
- // --- FUNKCJE UI (MODALE, ZAKŁADKI, MENU) ---
- function toRoman(num) {
- const roman = {M: 1000, CM: 900, D: 500, CD: 400, C: 100, XC: 90, L: 50, XL: 40, X: 10, IX: 9, V: 5, IV: 4, I: 1};
- let str = '';
- for (let i of Object.keys(roman)) {
- let q = Math.floor(num / roman[i]);
- num -= q * roman[i];
- str += i.repeat(q);
- }
- return str;
- }
- function capitalizeFirstLetter(string) {
- if (!string) return string;
- return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
- }
- function toggleLoginModal() {
- const modal = document.getElementById('loginModal');
- if (modal) modal.style.display = modal.style.display === 'block' ? 'none' : 'block';
- }
- function showTab(tabId) {
- console.log("UI_ACTION: showTab called for:", tabId);
- const groupManagementContainer = document.getElementById('groupManagementContainer');
- if(groupManagementContainer) groupManagementContainer.style.display = 'block';
- document.querySelectorAll('.tab-content').forEach(el => el.style.display = 'none');
- const tabToShow = document.getElementById(tabId);
- if (tabToShow) tabToShow.style.display = 'block';
- const userDropdown = document.getElementById('userDropdown');
- if (userDropdown) userDropdown.style.display = 'none';
- }
- document.addEventListener('DOMContentLoaded', () => {
- const userButton = document.getElementById('userButton');
- const userDropdown = document.getElementById('userDropdown');
- if (userButton && userDropdown) {
- userButton.addEventListener('click', (event) => {
- event.stopPropagation();
- userDropdown.style.display = userDropdown.style.display === 'block' ? 'none' : 'block';
- });
- document.addEventListener('click', (event) => {
- if (userDropdown.style.display === 'block' && !userButton.contains(event.target) && !userDropdown.contains(event.target)) {
- userDropdown.style.display = 'none';
- }
- });
- }
- const groupSwitcherSelect = document.getElementById('groupSwitcherSelect');
- if(groupSwitcherSelect) {
- groupSwitcherSelect.addEventListener('change', (e) => {
- const newSelectedGroupId = e.target.value || null;
- console.log("UI_ACTION: groupSwitcherSelect - Value changed to:", newSelectedGroupId, "Current activeGroupId:", window.activeGroupId);
- if (newSelectedGroupId !== window.activeGroupId) { // Wywołaj tylko jeśli faktycznie jest zmiana
- console.log("UI_ACTION: groupSwitcherSelect - Calling setActiveGroupForTimers with:", newSelectedGroupId);
- setActiveGroupForTimers(newSelectedGroupId);
- } else {
- console.log("UI_ACTION: groupSwitcherSelect - Value unchanged or already active. No call to setActiveGroupForTimers.");
- }
- });
- }
- });
- // --- FUNKCJE AUTENTYKACJI ---
- function loginUser() {
- const nickInput = document.getElementById('loginNick');
- const pinInput = document.getElementById('loginPin');
- if (!nickInput || !pinInput) return;
- // Formatujemy nick przed próbą logowania
- const nick = nickInput.value.trim();
- const capitalizedNick = capitalizeFirstLetter(nick); // <-- Użycie naszej nowej funkcji
- const pin = pinInput.value.trim();
- if (!capitalizedNick || !pin) return alert("Proszę wypełnić oba pola.");
- const fakeEmail = capitalizedNick + FAKE_EMAIL_DOMAIN;
- auth.signInWithEmailAndPassword(fakeEmail, pin)
- .then(() => {
- toggleLoginModal();
- })
- .catch(error => {
- if (error.code === 'auth/user-not-found' || error.code === 'auth/wrong-password') {
- alert("Nieprawidłowy nick lub PIN.");
- } else {
- window.api.showErrorDialog('Błąd Logowania', error.message);
- }
- });
- }
- function registerUser() {
- const nickInput = document.getElementById('loginNick');
- const pinInput = document.getElementById('loginPin');
- if (!nickInput || !pinInput) return;
- // Pobieramy nick i od razu go formatujemy
- const nick = nickInput.value.trim();
- const capitalizedNick = capitalizeFirstLetter(nick); // <-- Użycie naszej nowej funkcji
- const pin = pinInput.value.trim();
- if (!capitalizedNick) return alert("Nick nie może być pusty.");
- if (!/^\d{6}$/.test(pin)) return alert("PIN musi składać się z dokładnie 6 cyfr.");
- const fakeEmail = capitalizedNick + FAKE_EMAIL_DOMAIN; // Tworzymy e-mail z poprawnie sformatowanego nicku
- auth.createUserWithEmailAndPassword(fakeEmail, pin)
- .then(() => {
- alert(`Rejestracja pomyślna! Witaj, ${capitalizedNick}!`); // Wyświetlamy sformatowany nick
- toggleLoginModal();
- })
- .catch(error => {
- if (error.code === 'auth/email-already-in-use') {
- alert("Ten nick jest już zajęty. Proszę wybrać inny.");
- } else {
- window.api.showErrorDialog('Błąd Rejestracji', error.message);
- }
- });
- }
- function logoutUser() {
- console.log("ACTION: logoutUser - START");
- if (unsubscribeGroupTimersListener) {
- unsubscribeGroupTimersListener();
- unsubscribeGroupTimersListener = null;
- console.log("ACTION: logoutUser - Unsubscribed group timers listener.");
- }
- if (unsubscribeUserGroupsListener) {
- unsubscribeUserGroupsListener();
- unsubscribeUserGroupsListener = null;
- console.log("ACTION: logoutUser - Unsubscribed user groups listener.");
- }
- window.activeGroupId = null;
- console.log("ACTION: logoutUser - activeGroupId set to null.");
- auth.signOut().then(() => {
- console.log("ACTION: logoutUser - Signed out from Firebase successfully.");
- alert("Zostałeś wylogowany.");
- }).catch(error => {
- console.error("ACTION: logoutUser - Firebase sign out error:", error);
- alert(`Błąd wylogowania: ${error.message}`);
- });
- }
- async function loadUserNick(uid) {
- try {
- const userDoc = await db.collection('users').doc(uid).get();
- if (userDoc.exists) {
- currentUserNick = userDoc.data().nick;
- // Aktualizujemy od razu przycisk z nazwą użytkownika
- const userButton = document.getElementById('userButton');
- const nickFromEmail = user.email.split('@')[0];
- if (userButton) userButton.textContent = `👤 ${capitalizeFirstLetter(nickFromEmail)}`;
- } else {
- // Zabezpieczenie, jeśli ktoś ma konto, ale nie ma profilu w bazie
- currentUserNick = window.currentUser.email.split('@')[0];
- }
- } catch (error) {
- console.error("Błąd pobierania nicku użytkownika:", error);
- // W razie błędu, użyj nazwy z emaila
- currentUserNick = window.currentUser.email.split('@')[0];
- }
- }
- // --- FUNKCJE ZARZĄDZANIA GRUPAMI ---
- /*
- function generateRandomCode(length = 6) { ... bez zmian ... }
- */
- // W pliku: firebase.js
- window.saveCurrentTimers = function() {
- // Sprawdzenie, czy bieżący użytkownik jest zalogowany i ma aktywną grupę
- if (window.currentUser && window.activeGroupId) {
- // Ustawienie flagi blokującej, aby uniknąć problemów z odświeżaniem
- isSaving = true;
- console.log("Blokada zapisu włączona.");
- const groupTimersRef = db.collection("groups").doc(window.activeGroupId);
- // Przygotowanie danych do zapisu
- const timersToSaveForGroup = timers.map(t => ({
- name: t.name,
- minRespawnTime: new Date(t.minRespawnTime).toISOString(),
- maxRespawnTime: new Date(t.maxRespawnTime).toISOString(),
- alertPlayed: t.alertPlayed,
- addedBy: window.currentUser.uid,
- addedByName: window.currentUser.email.split('@')[0]
- }));
- // Aktualizacja dokumentu w Firestore
- groupTimersRef.update({ activeTimers: timersToSaveForGroup })
- .catch(error => {
- // Ta linia wyświetli błąd, jeśli uprawnienia nadal będą nieprawidłowe
- console.error("Błąd zapisu timerów grupy:", error);
- })
- .finally(() => {
- // Odblokuj odświeżanie z małym opóźnieniem, aby serwer zdążył przetworzyć zmianę
- setTimeout(() => {
- isSaving = false;
- console.log("Blokada zapisu zwolniona.");
- }, 500);
- });
- }
- // Jeśli użytkownik nie jest w grupie, zapisz dane lokalnie
- else {
- const timersToSaveLocal = timers.map(t => ({
- name: t.name,
- minRespawnTime: new Date(t.minRespawnTime).toISOString(),
- maxRespawnTime: new Date(t.maxRespawnTime).toISOString(),
- alertPlayed: t.alertPlayed
- }));
- localStorage.setItem("timers", JSON.stringify(timersToSaveLocal));
- }
- }
- function generateRandomCode(length = 6) { const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
- let result = '';
- for (let i = 0; i < length; i++) {
- const randomIndex = Math.floor(Math.random() * characters.length);
- result += characters[randomIndex];
- }
- return result;
- }
- async function createGroup() {
- if (isProcessingGroupAction) {
- console.warn("Operacja tworzenia grupy jest już w toku.");
- return;
- }
- isProcessingGroupAction = true;
- if (!window.currentUser) {
- alert("Musisz być zalogowany, aby stworzyć grupę.");
- isProcessingGroupAction = false;
- return;
- }
- const groupNameInput = document.getElementById('groupNameInput');
- const groupName = groupNameInput.value.trim();
- if (!groupName) {
- alert("Proszę podać nazwę dla nowej grupy.");
- isProcessingGroupAction = false;
- return;
- }
- try {
- const inviteCode = generateRandomCode();
- // Tworzymy obiekt grupy, używając tylko danych email, tak jak chcieliśmy
- const groupData = {
- name: groupName,
- adminId: window.currentUser.uid,
- adminEmail: window.currentUser.email.split('@')[0],
- members: [{ id: window.currentUser.uid, email: window.currentUser.email.split('@')[0] }],
- memberIds: [window.currentUser.uid],
- inviteCode: inviteCode,
- createdAt: firebase.firestore.FieldValue.serverTimestamp(),
- activeTimers: []
- };
- // Zapisujemy grupę w bazie danych (tylko raz)
- await db.collection("groups").doc(inviteCode).set(groupData);
- // Informujemy o sukcesie
- alert(`Grupa "${groupName}" została pomyślnie stworzona!`);
- // Czyścimy interfejs użytkownika
- if (document.getElementById('groupManagementContainer')) {
- document.getElementById('groupManagementContainer').style.display = 'none';
- }
- if (groupNameInput) {
- groupNameInput.value = '';
- }
- } catch (error) {
- console.error("Błąd podczas tworzenia grupy:", error);
- alert(`Wystąpił błąd: ${error.message}`);
- } finally {
- // Niezależnie od wyniku, odblokowujemy możliwość ponownej akcji
- isProcessingGroupAction = false;
- }
- }
- async function joinGroup() {
- if (isProcessingGroupAction) { return; }
- isProcessingGroupAction = true;
- if (!window.currentUser) { alert("Musisz być zalogowany."); isProcessingGroupAction = false; return; }
- const groupCodeInput = document.getElementById('groupCodeInput');
- const inviteCode = groupCodeInput.value.trim().toUpperCase();
- if (!inviteCode) { alert("Proszę podać kod zaproszenia."); isProcessingGroupAction = false; return; }
- const groupRef = db.collection("groups").doc(inviteCode);
- try {
- // Pobieramy nick dołączającego użytkownika
- const userDoc = await db.collection('users').doc(window.currentUser.uid).get();
- const userNick = userDoc.exists ? userDoc.data().nick : window.currentUser.email.split('@')[0];
- const groupName = await db.runTransaction(async transaction => {
- const doc = await transaction.get(groupRef);
- if (!doc.exists) throw "Grupa o podanym kodzie nie istnieje.";
- const groupData = doc.data();
- if (groupData.members.some(member => member.id === window.currentUser.uid)) throw "Już jesteś członkiem tej grupy.";
- transaction.update(groupRef, {
- members: firebase.firestore.FieldValue.arrayUnion({ id: window.currentUser.uid, email: currentUser.email.split('@')[0] }), // Wracamy do emaila
- memberIds: firebase.firestore.FieldValue.arrayUnion(window.currentUser.uid)
- });
- return groupData.name;
- });
- alert(`Pomyślnie dołączyłeś do grupy: "${groupName}"!`);
- if (groupCodeInput) groupCodeInput.value = '';
- } catch (error) {
- alert(`Błąd dołączania do grupy: ${error.toString()}`);
- } finally {
- isProcessingGroupAction = false;
- }
- }
- async function leaveGroup(groupId) {
- if (isProcessingGroupAction) { console.warn(`ACTION: leaveGroup (${groupId}) - Action already in progress.`); return; }
- isProcessingGroupAction = true;
- if (!window.currentUser) { alert("Brak zalogowanego użytkownika."); isProcessingGroupAction = false; return; }
- if (!confirm("Czy na pewno chcesz opuścić tę grupę?")) { isProcessingGroupAction = false; console.log(`ACTION: leaveGroup (${groupId}) - Cancelled by user.`); return; }
- console.log(`ACTION: leaveGroup - START - User ${window.currentUser.email.split('@')[0]} leaving group ${groupId}`);
- const groupRef = db.collection("groups").doc(groupId);
- try {
- const message = await db.runTransaction(async (transaction) => {
- console.log(`ACTION: leaveGroup - Transaction START for group ${groupId}`);
- const groupDoc = await transaction.get(groupRef);
- if (!groupDoc.exists) {
- console.error(`ACTION: leaveGroup - Transaction - Group ${groupId} does not exist.`);
- throw "Grupa nie istnieje.";
- }
- let groupData = groupDoc.data();
- console.log(`ACTION: leaveGroup - Transaction - Group data:`, JSON.parse(JSON.stringify(groupData)));
- let currentMembers = groupData.members;
- const memberIndex = currentMembers.findIndex(member => member.id === window.currentUser.uid);
- if (memberIndex === -1) {
- console.warn(`ACTION: leaveGroup - Transaction - User ${window.currentUser.email.split('@')[0]} is not a member of group ${groupId}.`);
- throw "Nie jesteś członkiem tej grupy.";
- }
- const remainingMembers = currentMembers.filter(member => member.id !== window.currentUser.uid);
- console.log(`ACTION: leaveGroup - Transaction - Remaining members: ${remainingMembers.length}`);
- if (remainingMembers.length === 0) {
- console.log(`ACTION: leaveGroup - Transaction - Last member leaving, deleting group ${groupId}.`);
- transaction.delete(groupRef);
- return "Opuściłeś grupę. Grupa została usunięta, ponieważ była pusta.";
- } else {
- let newAdminId = groupData.adminId;
- let newAdminEmail = groupData.adminEmail;
- if (groupData.adminId === window.currentUser.uid) { // If admin is leaving
- newAdminId = remainingMembers[0].id;
- newAdminEmail = remainingMembers[0].email;
- console.log(`ACTION: leaveGroup - Transaction - Admin ${groupData.adminEmail} is leaving. New admin: ${newAdminEmail}`);
- }
- console.log(`ACTION: leaveGroup - Transaction - Updating members and admin (if changed) for group ${groupId}.`);
- transaction.update(groupRef, {
- members: remainingMembers,
- adminId: newAdminId,
- adminEmail: newAdminEmail
- });
- return groupData.adminId === window.currentUser.uid && newAdminId !== window.currentUser.uid ?
- `Opuściłeś grupę. ${newAdminEmail} jest teraz nowym administratorem.` :
- "Opuściłeś grupę.";
- }
- });
- console.log(`ACTION: leaveGroup - Transaction COMPLETED SUCCESSFULLY for group ${groupId}. Message: ${message}`);
- alert(message); // Pokaż wiadomość zwróconą z transakcji
- if (window.activeGroupId === groupId) {
- console.log(`ACTION: leaveGroup - Left active group ${groupId}. Switching to local timers.`);
- setActiveGroupForTimers(null);
- }
- // onSnapshot in loadUserGroupsAndHandleActive should refresh the groups list.
- } catch (error) {
- console.error(`ACTION: leaveGroup - ERROR - ${error.toString()} for group ${groupId}`, error);
- alert(`Nie udało się opuścić grupy: ${error.toString()}`);
- } finally {
- isProcessingGroupAction = false;
- console.log(`ACTION: leaveGroup - END for group ${groupId}`);
- }
- }
- async function deleteGroup(groupId) {
- // To bardzo ważny krok - operacja usunięcia jest nieodwracalna.
- if (!confirm("Czy na pewno chcesz TRWALE USUNĄĆ całą grupę? Tej operacji nie można cofnąć!")) {
- return;
- }
- if (isProcessingGroupAction) { return; }
- isProcessingGroupAction = true;
- if (!window.currentUser) {
- window.api.showErrorDialog('Błąd', 'Musisz być zalogowany, aby usunąć grupę.');
- isProcessingGroupAction = false;
- return;
- }
- const groupRef = db.collection('groups').doc(groupId);
- try {
- // Wykonujemy operację usunięcia.
- // Reguły Bezpieczeństwa na serwerze sprawdzą, czy użytkownik jest adminem.
- await groupRef.delete();
- alert("Grupa została pomyślnie usunięta.");
- // Jeśli użytkownik usunął grupę, którą aktualnie przeglądał,
- // przełączamy go z powrotem na timery lokalne.
- if (window.activeGroupId === groupId) {
- setActiveGroupForTimers(null);
- }
- // Listener `onSnapshot` w funkcji `loadUserGroupsAndHandleActive` automatycznie
- // wykryje, że grupa zniknęła i odświeży listę.
- } catch (error) {
- // Wyświetlamy natywny dialog błędu w razie problemów
- window.api.showErrorDialog('Błąd usuwania grupy', error.message);
- } finally {
- isProcessingGroupAction = false;
- }
- }
- async function removeMemberFromGroup(groupId, memberIdToRemove, memberEmailToRemove, event) {
- if (isProcessingGroupAction) {
- console.warn(`ACTION: removeMember (${groupId}) - Action already in progress.`);
- return;
- }
- isProcessingGroupAction = true;
- const clickedButton = event ? event.target.closest('button') : null;
- if (clickedButton) clickedButton.disabled = true;
- try {
- console.log(`ACTION: removeMemberFromGroup - START for group ${groupId}, removing member ${memberIdToRemove} (${memberEmailToRemove})`);
- // Pobierz aktualny dokument grupy
- const groupRef = db.collection('groups').doc(groupId);
- const groupDoc = await groupRef.get();
- if (!groupDoc.exists) {
- console.error(`GROUP NOT FOUND: Group with ID ${groupId} does not exist.`);
- throw new Error(`Group with ID ${groupId} does not exist.`);
- }
- const groupData = groupDoc.data();
- // Sprawdź czy użytkownik jest członkiem grupy
- if (!groupData.members || !Array.isArray(groupData.members)) {
- console.error(`INVALID GROUP DATA: Members array not found or invalid in group ${groupId}.`);
- throw new Error(`Invalid group data structure for group ${groupId}.`);
- }
- const memberIndex = groupData.members.findIndex(member => member.id === memberIdToRemove);
- if (memberIndex === -1) {
- console.warn(`MEMBER NOT FOUND: Member ${memberIdToRemove} not found in group ${groupId}.`);
- throw new Error(`Member ${memberIdToRemove} is not a member of group ${groupId}.`);
- }
- // Usuń członka z tablicy
- const updatedMembers = [
- ...groupData.members.slice(0, memberIndex),
- ...groupData.members.slice(memberIndex + 1)
- ];
- // Wykonaj transakcję aktualizacji grupy
- await db.runTransaction(async (transaction) => {
- const freshGroupRef = db.collection('groups').doc(groupId);
- const freshGroupDoc = await transaction.get(freshGroupRef);
- if (!freshGroupDoc.exists) {
- throw new Error(`Group ${groupId} disappeared during transaction.`);
- }
- const freshGroupData = freshGroupDoc.data();
- if (!freshGroupData.members || !Array.isArray(freshGroupData.members)) {
- throw new Error(`Invalid group data structure in transaction for group ${groupId}.`);
- }
- const freshMemberIndex = freshGroupData.members.findIndex(member => member.id === memberIdToRemove);
- if (freshMemberIndex === -1) {
- throw new Error(`Member ${memberIdToRemove} disappeared from group ${groupId} during transaction.`);
- }
- const freshUpdatedMembers = [
- ...freshGroupData.members.slice(0, freshMemberIndex),
- ...freshGroupData.members.slice(freshMemberIndex + 1)
- ];
- transaction.update(freshGroupRef, {
- members: freshUpdatedMembers,
- updatedAt: firebase.firestore.FieldValue.serverTimestamp()
- });
- });
- console.log(`SUCCESS: Member ${memberIdToRemove} (${memberEmailToRemove}) removed from group ${groupId}`);
- // Odświeżenie interfejsu użytkownika po usunięciu członka
- // Możesz dodać tutaj kod do aktualizacji listy członków w UI
- // np. odświeżenie listy członków lub usunięcie elementu z listy
- } catch (error) {
- console.error(`ERROR: removeMemberFromGroup - Failed to remove member ${memberIdToRemove} from group ${groupId}`, error);
- // Wyświetlenie komunikatu o błędzie dla użytkownika
- if (clickedButton) {
- // Możesz dodać tutaj kod do wyświetlenia komunikatu błędu blisko przycisku
- // np. dodanie elementu z komunikatem błędu
- } else {
- alert(`Nie udało się usunąć użytkownika ${memberEmailToRemove} z grupy. Błąd: ${error.message}`);
- }
- } finally {
- if (clickedButton) clickedButton.disabled = false;
- isProcessingGroupAction = false;
- console.log(`ACTION: removeMemberFromGroup - END for group ${groupId}`);
- }
- }
- function loadUserGroupsAndHandleActive() {
- if (!window.currentUser) {
- const groupListContainer = document.getElementById('groupListContainer');
- if(groupListContainer) groupListContainer.innerHTML = '<p>Zaloguj się, aby zobaczyć swoje grupy.</p>';
- const groupSwitcherSelect = document.getElementById('groupSwitcherSelect');
- if(groupSwitcherSelect) groupSwitcherSelect.innerHTML = '<option value="">-- Moje Lokalne Timery --</option>';
- if (window.activeGroupId !== null) { // Jeśli była jakaś aktywna grupa, przełącz na lokalne
- console.log("loadUserGroupsAndHandleActive: No user, switching to local timers (was active).");
- setActiveGroupForTimers(null);
- } else {
- console.log("loadUserGroupsAndHandleActive: No user, local timers already active or no change needed.");
- }
- return;
- }
- if (unsubscribeUserGroupsListener) {
- unsubscribeUserGroupsListener();
- console.log("loadUserGroupsAndHandleActive: Old user groups listener unsubscribed.");
- }
- console.log("loadUserGroupsAndHandleActive: Subscribing user groups listener for:", window.currentUser.email.split('@')[0]);
- unsubscribeUserGroupsListener = db.collection("groups")
- .where("members", "array-contains", { id: window.currentUser.uid, email: window.currentUser.email.split('@')[0] })
- // .orderBy("createdAt", "desc") // REMEMBER INDEX IF YOU UNCOMMENT!
- .onSnapshot(snapshot => {
- console.log("loadUserGroupsAndHandleActive (onSnapshot): Received user groups snapshot, docs:", snapshot.size);
- const groups = [];
- snapshot.forEach(doc => groups.push({ id: doc.id, ...doc.data() }));
- displayUserGroupsList(groups);
- populateGroupSwitcher(groups);
- const previouslyActiveGroupId = window.activeGroupId;
- let newCandidateActiveGroupId = null;
- if (previouslyActiveGroupId && groups.some(g => g.id === previouslyActiveGroupId)) {
- newCandidateActiveGroupId = previouslyActiveGroupId;
- } else if (groups.length > 0) {
- newCandidateActiveGroupId = groups[0].id;
- }
- // If no groups, newCandidateActiveGroupId remains null (local timers)
- console.log(`loadUserGroupsAndHandleActive (onSnapshot): Prev active: ${previouslyActiveGroupId}, New candidate: ${newCandidateActiveGroupId}, Current active: ${window.activeGroupId}`);
- if (window.activeGroupId !== newCandidateActiveGroupId) {
- console.log(`loadUserGroupsAndHandleActive (onSnapshot): Active group WILL CHANGE. Calling setActiveGroupForTimers with ${newCandidateActiveGroupId}`);
- setActiveGroupForTimers(newCandidateActiveGroupId);
- } else {
- console.log("loadUserGroupsAndHandleActive (onSnapshot): Active group for timers remains unchanged. No call to setActiveGroupForTimers.");
- // Refresh UI for the current active group if its data (e.g., name) might have changed
- const activeGroupData = groups.find(g => g.id === window.activeGroupId);
- const activeGroupNameDisplay = document.getElementById('activeGroupNameDisplay');
- const currentTimerContextUI = document.getElementById('currentTimerContext');
- if (activeGroupData && activeGroupNameDisplay && currentTimerContextUI) {
- if (activeGroupNameDisplay.textContent !== activeGroupData.name) activeGroupNameDisplay.textContent = activeGroupData.name;
- if (currentTimerContextUI.textContent !== activeGroupData.name) currentTimerContextUI.textContent = activeGroupData.name;
- } else if (!activeGroupData && window.activeGroupId !== null) {
- // This case means the active group was deleted/left, and it wasn't the first one in the new list.
- // We should switch to local or the new first group.
- console.log("loadUserGroupsAndHandleActive (onSnapshot): Previously active group no longer exists. Switching.");
- setActiveGroupForTimers(groups.length > 0 ? groups[0].id : null);
- }
- }
- }, error => {
- console.error("loadUserGroupsAndHandleActive (onSnapshot): Error loading user groups: ", error);
- const groupListContainer = document.getElementById('groupListContainer');
- if(groupListContainer) groupListContainer.innerHTML = '<p>Błąd ładowania grup. Sprawdź konsolę (F12).</p>';
- });
- }
- /* wersja work
- function populateGroupSwitcher(groups) {
- const groupSwitcherSelect = document.getElementById('groupSwitcherSelect');
- if (!groupSwitcherSelect) return;
- const valueToRestore = window.activeGroupId || "";
- groupSwitcherSelect.innerHTML = '<option value="">-- Moje Lokalne Timery --</option>';
- groups.forEach(group => {
- const option = document.createElement('option');
- option.value = group.id;
- option.textContent = group.name;
- groupSwitcherSelect.appendChild(option);
- });
- groupSwitcherSelect.value = valueToRestore;
- console.log("populateGroupSwitcher: Select updated, value set to:", groupSwitcherSelect.value);
- }
- */
- function populateGroupSwitcher(groups) {
- const tabsContainer = document.getElementById('group-switcher-tabs');
- if (!tabsContainer) return;
- tabsContainer.innerHTML = ''; // Wyczyść stare zakładki
- // 1. Stwórz zakładkę dla timerów lokalnych
- const localTab = document.createElement('div');
- localTab.className = 'group-tab-scarf';
- localTab.textContent = 'Lokalne';
- localTab.title = 'Moje Lokalne Timery';
- localTab.dataset.groupId = 'null'; // Używamy stringa 'null' do identyfikacji
- localTab.addEventListener('click', () => {
- setActiveGroupForTimers(null); // Przełącz na timery lokalne
- });
- tabsContainer.appendChild(localTab);
- // 2. Stwórz zakładki dla każdej grupy z bazy danych
- groups.forEach((group, index) => {
- const tabElement = document.createElement('div');
- tabElement.className = 'group-tab-scarf';
- tabElement.textContent = toRoman(index + 1); // Używamy cyfr rzymskich
- tabElement.title = group.name; // Nazwa grupy w podpowiedzi
- tabElement.dataset.groupId = group.id;
- tabElement.addEventListener('click', () => {
- setActiveGroupForTimers(group.id); // Przełącz na wybraną grupę
- });
- tabsContainer.appendChild(tabElement);
- });
- // 3. Ustaw klasę 'active' na aktualnie wybranej zakładce
- updateActiveSwitcherTab();
- }
- // 4. Dodaj nową funkcję pomocniczą do aktualizacji aktywnej zakładki
- function updateActiveSwitcherTab() {
- const tabsContainer = document.getElementById('group-switcher-tabs');
- if (!tabsContainer) return;
- const currentActiveId = activeGroupId === null ? 'null' : activeGroupId;
- tabsContainer.querySelectorAll('.group-tab-scarf').forEach(tab => {
- tab.classList.remove('active');
- if (tab.dataset.groupId === currentActiveId) {
- tab.classList.add('active');
- }
- });
- }
- function setActiveGroupForTimers(newGroupId) {
- if (window.activeGroupId === newGroupId) {
- console.log(`setActiveGroupForTimers: Group ${newGroupId || 'Lokalne'} is already active. No changes needed.`);
- return;
- }
- console.log(`setActiveGroupForTimers: Attempting to switch from ${window.activeGroupId || 'Lokalne'} to ${newGroupId || 'Lokalne'}`);
- const oldListener = unsubscribeGroupTimersListener;
- unsubscribeGroupTimersListener = null; // Clear global handle first
- if (oldListener) {
- oldListener();
- console.log("setActiveGroupForTimers: Unsubscribed old group timers listener for:", window.activeGroupId);
- }
- window.activeGroupId = newGroupId; // Update global state IMMEDIATELY
- const activeGroupNameDisplay = document.getElementById('activeGroupNameDisplay');
- const currentTimerContextUI = document.getElementById('currentTimerContext');
- const groupSwitcherSelect = document.getElementById('groupSwitcherSelect');
- if (typeof window.clearLocalTimers === 'function') window.clearLocalTimers();
- if (newGroupId) {
- const groupDocRef = db.collection("groups").doc(newGroupId);
- // Get group data once to set UI immediately, then attach listener
- groupDocRef.get().then(doc => {
- if(doc.exists) {
- const groupName = doc.data().name;
- if(activeGroupNameDisplay) activeGroupNameDisplay.textContent = groupName;
- if(currentTimerContextUI) currentTimerContextUI.textContent = groupName;
- console.log("setActiveGroupForTimers: Subscribing new timers listener for group:", newGroupId, `(${groupName})`);
- unsubscribeGroupTimersListener = groupDocRef.onSnapshot(groupSnapshot => {
- // ⬇️ DODAJ TEN WARUNEK NA SAMEJ GÓRZE LISTENER'A ⬇️
- if (groupSnapshot.metadata.hasPendingWrites) {
- console.log("Snapshot zignorowany: zmiana lokalna w trakcie zapisu.");
- return; // Nie rób nic, to tylko "echo" naszej własnej zmiany.
- }
- if (window.activeGroupId !== newGroupId) { // Check if group changed again before snapshot arrives
- console.log(`setActiveGroupForTimers (onSnapshot for ${newGroupId}): Active group changed to ${window.activeGroupId}. This listener is now stale. Unsubscribing.`);
- // This specific listener instance should unsubscribe itself
- const thisListenerUnsubscribe = unsubscribeGroupTimersListener; // Capture current listener
- if (thisListenerUnsubscribe) { // Check if it's still the one we think it is
- thisListenerUnsubscribe();
- if(unsubscribeGroupTimersListener === thisListenerUnsubscribe) unsubscribeGroupTimersListener = null; // Clear global if it was this one
- }
- return;
- }
- if (groupSnapshot.exists) {
- const groupData = groupSnapshot.data();
- console.log(`setActiveGroupForTimers (onSnapshot for ${newGroupId}): Received timer data, count:`, groupData.activeTimers ? groupData.activeTimers.length : 0);
- if (typeof window.loadTimersFromArray === 'function') {
- window.loadTimersFromArray(groupData.activeTimers || []);
- }
- } else {
- console.warn(`setActiveGroupForTimers (onSnapshot for ${newGroupId}): Active group document no longer exists. Switching to local.`);
- if (window.activeGroupId === newGroupId) setActiveGroupForTimers(null);
- }
- }, error => {
- console.error(`setActiveGroupForTimers (onSnapshot for ${newGroupId}): Error listening to group timers:`, error);
- if (window.activeGroupId === newGroupId) setActiveGroupForTimers(null);
- });
- } else {
- console.warn(`setActiveGroupForTimers: Group ${newGroupId} does not exist (after get). Switching to local.`);
- setActiveGroupForTimers(null); // This will correctly set UI to local and load local timers
- }
- }).catch(error => {
- console.error(`setActiveGroupForTimers: Error fetching group ${newGroupId} details:`, error);
- setActiveGroupForTimers(null); // Fallback to local
- });
- } else { // newGroupId is null (local timers)
- console.log("setActiveGroupForTimers: Switched to local timers.");
- if(activeGroupNameDisplay) activeGroupNameDisplay.textContent = "Lokalne";
- if(currentTimerContextUI) currentTimerContextUI.textContent = "Lokalne";
- if (typeof window.loadTimers === 'function') window.loadTimers();
- }
- if(groupSwitcherSelect) groupSwitcherSelect.value = newGroupId || ""; // Update switcher to reflect current state
- updateActiveSwitcherTab();
- console.log("setActiveGroupForTimers: FINISHED. Active group is now:", window.activeGroupId);
- }
- function displayUserGroupsList(groups) {
- const container = document.getElementById('groupListContainer');
- if (!container) return;
- container.innerHTML = '';
- if (groups.length === 0) {
- container.innerHTML = '<p>Nie należysz do żadnej grupy. Stwórz nową lub dołącz do istniejącej!</p>';
- return;
- }
- groups.forEach(group => {
- // Główny kontener dla całej zwijanej grupy
- const groupDiv = document.createElement('div');
- groupDiv.className = 'timer-item group-item collapsible';
- // 1. Tworzymy nagłówek, który będzie zawsze widoczny i klikalny
- const header = document.createElement('div');
- header.className = 'collapsible-header';
- const groupNameSpan = document.createElement('span');
- groupNameSpan.className = 'group-name-display';
- groupNameSpan.textContent = group.name;
- header.appendChild(groupNameSpan);
- const controlsDiv = document.createElement('div');
- controlsDiv.className = 'header-controls';
- // Opcjonalna ikonka "i" z kodem zaproszenia dla admina
- if (group.adminId === window.currentUser.uid) {
- const inviteInfoSpan = document.createElement('span');
- inviteInfoSpan.className = 'group-invite-info';
- inviteInfoSpan.innerHTML = `
- <img src="https://api.iconify.design/solar/info-circle-bold-duotone.svg?color=%23e9d8a6" alt="info">
- <span class="tooltip-text">Kod: ${group.inviteCode}</span>
- `;
- inviteInfoSpan.addEventListener('click', e => e.stopPropagation());
- controlsDiv.appendChild(inviteInfoSpan);
- }
- const toggleBtn = document.createElement('button');
- toggleBtn.className = 'toggle-collapse-btn';
- toggleBtn.innerHTML = '▼'; // Strzałka w dół
- controlsDiv.appendChild(toggleBtn);
- header.appendChild(controlsDiv);
- // 2. Tworzymy kontener na treść, która będzie zwijana
- const content = document.createElement('div');
- content.className = 'collapsible-content';
- const membersSectionDiv = document.createElement('div');
- membersSectionDiv.className = 'group-members-section';
- const membersListUl = document.createElement('ul');
- membersListUl.className = 'group-members-list';
- group.members.forEach(member => {
- const memberLi = document.createElement('li');
- memberLi.textContent = member.email;
- if (member.id === group.adminId) {
- const adminBadge = document.createElement('span');
- adminBadge.textContent = ' (Admin)';
- adminBadge.style.fontWeight = 'bold';
- adminBadge.style.color = '#e9d8a6';
- memberLi.appendChild(adminBadge);
- }
- if (group.adminId === window.currentUser.uid && member.id !== window.currentUser.uid) {
- const removeBtn = document.createElement('button');
- removeBtn.textContent = 'X';
- removeBtn.className = 'remove-member-btn';
- removeBtn.title = `Wyrzuć ${member.email}`;
- removeBtn.onclick = (e) => {
- e.stopPropagation();
- removeMemberFromGroup(group.id, member.id, member.email);
- }
- memberLi.appendChild(removeBtn);
- }
- membersListUl.appendChild(memberLi);
- });
- membersSectionDiv.appendChild(membersListUl);
- content.appendChild(membersSectionDiv);
- const actionsDiv = document.createElement('div');
- actionsDiv.className = 'button-center group-actions';
- const leaveBtn = document.createElement('button');
- leaveBtn.textContent = 'Opuść grupę';
- leaveBtn.onclick = (e) => {
- e.stopPropagation();
- leaveGroup(group.id);
- };
- actionsDiv.appendChild(leaveBtn);
- if (group.adminId === window.currentUser.uid) {
- const deleteGroupBtn = document.createElement('button');
- deleteGroupBtn.textContent = 'Usuń grupę';
- deleteGroupBtn.onclick = (e) => {
- e.stopPropagation();
- deleteGroup(group.id); // Potrzebujesz takiej funkcji
- };
- actionsDiv.appendChild(deleteGroupBtn);
- }
- content.appendChild(actionsDiv);
- // 3. Składamy wszystko w całość
- groupDiv.appendChild(header);
- groupDiv.appendChild(content);
- container.appendChild(groupDiv);
- // 4. Dodajemy obsługę kliknięcia do nagłówka
- header.addEventListener('click', () => {
- groupDiv.classList.toggle('expanded');
- });
- });
- }
- // --- FUNKCJE ZAPISU/ODCZYTU USTAWIEŃ UŻYTKOWNIKA (TŁO, DŹWIĘK) ---
- const userPrivateSettingsRef = () => db.collection('user_settings').doc(window.currentUser.uid);
- async function saveUserSetting(key, value) {
- if (!window.currentUser) return;
- try {
- await userPrivateSettingsRef().set({ [key]: value }, { merge: true });
- } catch (error) {
- console.error(`Błąd zapisu ustawienia ${key}:`, error);
- }
- }
- async function loadUserSettingsFromFirebase() {
- if (!window.currentUser) return;
- try {
- const doc = await userPrivateSettingsRef().get();
- if (doc.exists) {
- const settings = doc.data();
- if (settings.background && typeof window.applyBackground === 'function') {
- window.applyBackground(settings.background);
- const bgOption = document.querySelector(`.background-thumbnail[data-path="${settings.background}"]`);
- if(bgOption) {
- document.querySelectorAll('.background-thumbnail.selected').forEach(s => s.classList.remove('selected'));
- bgOption.classList.add('selected');
- }
- } else if (typeof window.loadSavedBackground === 'function') window.loadSavedBackground();
- if (settings.sound && typeof window.respawnSound !== 'undefined' && document.getElementById('soundSelect')) {
- window.respawnSound.src = settings.sound;
- document.getElementById('soundSelect').value = settings.sound.startsWith('data:') ? 'custom' : settings.sound;
- const customSoundContainer = document.getElementById('customSoundContainer');
- if(document.getElementById('soundSelect').value === 'custom' && customSoundContainer) {
- customSoundContainer.style.display = 'block';
- }
- } else if (typeof window.loadNotificationSound === 'function') window.loadNotificationSound();
- } else {
- if (typeof window.loadSavedBackground === 'function') window.loadSavedBackground();
- if (typeof window.loadNotificationSound === 'function') window.loadNotificationSound();
- }
- } catch (error) {
- console.error("Błąd ładowania ustawień użytkownika:", error);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement