Advertisement
Mashtii

firebase.js

Jun 28th, 2025 (edited)
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Plik: firebase.js
  2. const FAKE_EMAIL_DOMAIN = '@br-timer.fan';
  3.  
  4. let isSaving = false;
  5. let currentUserNick = null;
  6.  
  7. window.currentUser = null;
  8. window.activeGroupId = null; // null oznacza "Moje Lokalne Timery"
  9. let unsubscribeGroupTimersListener = null;
  10. let unsubscribeUserGroupsListener = null;
  11. let isProcessingGroupAction = false; // Flaga zapobiegająca wielokrotnym operacjom
  12.  
  13. // --- OBSŁUGA STANU LOGOWANIA ---
  14. auth.onAuthStateChanged(user => {
  15.     console.log("AUTH_STATE_CHANGED: User status:", user ? user.email : 'Logged out');
  16.     const loginButton = document.getElementById('loginButton');
  17.     const userMenuContainer = document.getElementById('userMenuContainer');
  18.     const userButton = document.getElementById('userButton');
  19.     const groupManagementContainer = document.getElementById('groupManagementContainer');
  20.     const userGroupsListSection = document.getElementById('userGroupsListSection');
  21.     const activeGroupSelectorContainer = document.getElementById('activeGroupSelectorContainer');
  22.     const currentTimerContextUI = document.getElementById('currentTimerContext');
  23.  
  24.     if (user) {
  25.         window.currentUser = user;
  26.         if (loginButton) loginButton.style.display = 'none';
  27.         if (userMenuContainer) userMenuContainer.style.display = 'block';
  28.         if (userButton) userButton.textContent = `👤 ${user.email.split('@')[0]}`;
  29.                        
  30.        
  31.         if (activeGroupSelectorContainer) activeGroupSelectorContainer.style.display = 'block';
  32.         if (userGroupsListSection) userGroupsListSection.style.display = 'block';
  33.         if (currentTimerContextUI) currentTimerContextUI.textContent = "Lokalne";
  34.  
  35.         loadUserGroupsAndHandleActive(); // Kluczowe wywołanie po zalogowaniu
  36.         loadUserSettingsFromFirebase();
  37.         if (groupManagementContainer) groupManagementContainer.style.display = 'none';
  38.         document.querySelectorAll('.tab-content').forEach(el => el.style.display = 'none');
  39.  
  40.     } else { // Użytkownik wylogowany
  41.         console.log("AUTH_STATE_CHANGED: User logged out. Cleaning up listeners and state.");
  42.         window.currentUser = null;
  43.    
  44.         const oldActiveGroupId = window.activeGroupId;
  45.         window.activeGroupId = null;
  46.  
  47.         if (unsubscribeGroupTimersListener) {
  48.             unsubscribeGroupTimersListener();
  49.             unsubscribeGroupTimersListener = null;
  50.             console.log("AUTH_STATE_CHANGED: Unsubscribed group timers listener for old group:", oldActiveGroupId);
  51.         }
  52.         if (unsubscribeUserGroupsListener) {
  53.             unsubscribeUserGroupsListener();
  54.             unsubscribeUserGroupsListener = null;
  55.             console.log("AUTH_STATE_CHANGED: Unsubscribed user groups listener.");
  56.         }
  57.        
  58.         if (loginButton) loginButton.style.display = 'inline-flex';
  59.         if (userMenuContainer) userMenuContainer.style.display = 'none';
  60.         if (activeGroupSelectorContainer) activeGroupSelectorContainer.style.display = 'none';
  61.         if (userGroupsListSection) userGroupsListSection.style.display = 'none';
  62.         if (groupManagementContainer) groupManagementContainer.style.display = 'none';
  63.         document.querySelectorAll('.tab-content').forEach(el => el.style.display = 'none');
  64.         if (currentTimerContextUI) currentTimerContextUI.textContent = "Lokalne";
  65.  
  66.         if (typeof window.clearLocalTimers === 'function') window.clearLocalTimers();
  67.         if (typeof window.loadTimers === 'function') window.loadTimers();
  68.         if (typeof window.loadSavedBackground === 'function') window.loadSavedBackground();
  69.         if (typeof window.loadNotificationSound === 'function') window.loadNotificationSound();
  70.     }
  71. });
  72.  
  73. // --- FUNKCJE UI (MODALE, ZAKŁADKI, MENU) ---
  74. function toRoman(num) {
  75.     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};
  76.     let str = '';
  77.     for (let i of Object.keys(roman)) {
  78.         let q = Math.floor(num / roman[i]);
  79.         num -= q * roman[i];
  80.         str += i.repeat(q);
  81.     }
  82.     return str;
  83. }
  84. function capitalizeFirstLetter(string) {
  85.     if (!string) return string;
  86.     return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
  87. }
  88. function toggleLoginModal() {
  89.     const modal = document.getElementById('loginModal');
  90.     if (modal) modal.style.display = modal.style.display === 'block' ? 'none' : 'block';
  91. }
  92.  
  93. function showTab(tabId) {
  94.     console.log("UI_ACTION: showTab called for:", tabId);
  95.     const groupManagementContainer = document.getElementById('groupManagementContainer');
  96.     if(groupManagementContainer) groupManagementContainer.style.display = 'block';
  97.     document.querySelectorAll('.tab-content').forEach(el => el.style.display = 'none');
  98.     const tabToShow = document.getElementById(tabId);
  99.     if (tabToShow) tabToShow.style.display = 'block';
  100.  
  101.     const userDropdown = document.getElementById('userDropdown');
  102.     if (userDropdown) userDropdown.style.display = 'none';
  103. }
  104.  
  105. document.addEventListener('DOMContentLoaded', () => {
  106.     const userButton = document.getElementById('userButton');
  107.     const userDropdown = document.getElementById('userDropdown');
  108.     if (userButton && userDropdown) {
  109.         userButton.addEventListener('click', (event) => {
  110.             event.stopPropagation();
  111.             userDropdown.style.display = userDropdown.style.display === 'block' ? 'none' : 'block';
  112.         });
  113.         document.addEventListener('click', (event) => {
  114.             if (userDropdown.style.display === 'block' && !userButton.contains(event.target) && !userDropdown.contains(event.target)) {
  115.                 userDropdown.style.display = 'none';
  116.             }
  117.         });
  118.     }
  119.     const groupSwitcherSelect = document.getElementById('groupSwitcherSelect');
  120.     if(groupSwitcherSelect) {
  121.         groupSwitcherSelect.addEventListener('change', (e) => {
  122.             const newSelectedGroupId = e.target.value || null;
  123.             console.log("UI_ACTION: groupSwitcherSelect - Value changed to:", newSelectedGroupId, "Current activeGroupId:", window.activeGroupId);
  124.             if (newSelectedGroupId !== window.activeGroupId) { // Wywołaj tylko jeśli faktycznie jest zmiana
  125.                 console.log("UI_ACTION: groupSwitcherSelect - Calling setActiveGroupForTimers with:", newSelectedGroupId);
  126.                 setActiveGroupForTimers(newSelectedGroupId);
  127.             } else {
  128.                 console.log("UI_ACTION: groupSwitcherSelect - Value unchanged or already active. No call to setActiveGroupForTimers.");
  129.             }
  130.         });
  131.     }
  132. });
  133.  
  134. // --- FUNKCJE AUTENTYKACJI ---
  135. function loginUser() {
  136.     const nickInput = document.getElementById('loginNick');
  137.     const pinInput = document.getElementById('loginPin');
  138.     if (!nickInput || !pinInput) return;
  139.  
  140.     // Formatujemy nick przed próbą logowania
  141.     const nick = nickInput.value.trim();
  142.     const capitalizedNick = capitalizeFirstLetter(nick); // <-- Użycie naszej nowej funkcji
  143.  
  144.     const pin = pinInput.value.trim();
  145.  
  146.     if (!capitalizedNick || !pin) return alert("Proszę wypełnić oba pola.");
  147.  
  148.     const fakeEmail = capitalizedNick + FAKE_EMAIL_DOMAIN;
  149.  
  150.     auth.signInWithEmailAndPassword(fakeEmail, pin)
  151.         .then(() => {
  152.             toggleLoginModal();
  153.         })
  154.         .catch(error => {
  155.             if (error.code === 'auth/user-not-found' || error.code === 'auth/wrong-password') {
  156.                 alert("Nieprawidłowy nick lub PIN.");
  157.             } else {
  158.                 window.api.showErrorDialog('Błąd Logowania', error.message);
  159.             }
  160.         });
  161. }
  162. function registerUser() {
  163.     const nickInput = document.getElementById('loginNick');
  164.     const pinInput = document.getElementById('loginPin');
  165.     if (!nickInput || !pinInput) return;
  166.  
  167.     // Pobieramy nick i od razu go formatujemy
  168.     const nick = nickInput.value.trim();
  169.     const capitalizedNick = capitalizeFirstLetter(nick); // <-- Użycie naszej nowej funkcji
  170.    
  171.     const pin = pinInput.value.trim();
  172.  
  173.     if (!capitalizedNick) return alert("Nick nie może być pusty.");
  174.     if (!/^\d{6}$/.test(pin)) return alert("PIN musi składać się z dokładnie 6 cyfr.");
  175.  
  176.     const fakeEmail = capitalizedNick + FAKE_EMAIL_DOMAIN; // Tworzymy e-mail z poprawnie sformatowanego nicku
  177.  
  178.     auth.createUserWithEmailAndPassword(fakeEmail, pin)
  179.         .then(() => {
  180.             alert(`Rejestracja pomyślna! Witaj, ${capitalizedNick}!`); // Wyświetlamy sformatowany nick
  181.             toggleLoginModal();
  182.         })
  183.         .catch(error => {
  184.             if (error.code === 'auth/email-already-in-use') {
  185.                 alert("Ten nick jest już zajęty. Proszę wybrać inny.");
  186.             } else {
  187.                 window.api.showErrorDialog('Błąd Rejestracji', error.message);
  188.             }
  189.         });
  190. }
  191.  
  192.   function logoutUser() {
  193.     console.log("ACTION: logoutUser - START");
  194.     if (unsubscribeGroupTimersListener) {
  195.         unsubscribeGroupTimersListener();
  196.         unsubscribeGroupTimersListener = null;
  197.         console.log("ACTION: logoutUser - Unsubscribed group timers listener.");
  198.     }
  199.     if (unsubscribeUserGroupsListener) {
  200.         unsubscribeUserGroupsListener();
  201.         unsubscribeUserGroupsListener = null;
  202.         console.log("ACTION: logoutUser - Unsubscribed user groups listener.");
  203.     }
  204.     window.activeGroupId = null;
  205.     console.log("ACTION: logoutUser - activeGroupId set to null.");
  206.  
  207.     auth.signOut().then(() => {
  208.         console.log("ACTION: logoutUser - Signed out from Firebase successfully.");
  209.         alert("Zostałeś wylogowany.");
  210.     }).catch(error => {
  211.         console.error("ACTION: logoutUser - Firebase sign out error:", error);
  212.         alert(`Błąd wylogowania: ${error.message}`);
  213.     });
  214. }
  215.  
  216. async function loadUserNick(uid) {
  217.     try {
  218.         const userDoc = await db.collection('users').doc(uid).get();
  219.         if (userDoc.exists) {
  220.             currentUserNick = userDoc.data().nick;
  221.             // Aktualizujemy od razu przycisk z nazwą użytkownika
  222.             const userButton = document.getElementById('userButton');
  223.             const nickFromEmail = user.email.split('@')[0];
  224.            if (userButton) userButton.textContent = `👤 ${capitalizeFirstLetter(nickFromEmail)}`;
  225.         } else {
  226.             // Zabezpieczenie, jeśli ktoś ma konto, ale nie ma profilu w bazie
  227.             currentUserNick = window.currentUser.email.split('@')[0];
  228.         }
  229.     } catch (error) {
  230.         console.error("Błąd pobierania nicku użytkownika:", error);
  231.         // W razie błędu, użyj nazwy z emaila
  232.         currentUserNick = window.currentUser.email.split('@')[0];
  233.     }
  234. }
  235.  
  236. // --- FUNKCJE ZARZĄDZANIA GRUPAMI ---
  237.   /*
  238. function generateRandomCode(length = 6) { ... bez zmian ...  }
  239. */
  240.   // W pliku: firebase.js
  241.  
  242. window.saveCurrentTimers = function() {
  243.     // Sprawdzenie, czy bieżący użytkownik jest zalogowany i ma aktywną grupę
  244.     if (window.currentUser && window.activeGroupId) {
  245.         // Ustawienie flagi blokującej, aby uniknąć problemów z odświeżaniem
  246.         isSaving = true;
  247.         console.log("Blokada zapisu włączona.");
  248.  
  249.         const groupTimersRef = db.collection("groups").doc(window.activeGroupId);
  250.        
  251.         // Przygotowanie danych do zapisu
  252.         const timersToSaveForGroup = timers.map(t => ({
  253.             name: t.name,
  254.             minRespawnTime: new Date(t.minRespawnTime).toISOString(),
  255.             maxRespawnTime: new Date(t.maxRespawnTime).toISOString(),
  256.             alertPlayed: t.alertPlayed,
  257.             addedBy: window.currentUser.uid,
  258.             addedByName: window.currentUser.email.split('@')[0]
  259.         }));
  260.  
  261.         // Aktualizacja dokumentu w Firestore
  262.         groupTimersRef.update({ activeTimers: timersToSaveForGroup })
  263.             .catch(error => {
  264.                 // Ta linia wyświetli błąd, jeśli uprawnienia nadal będą nieprawidłowe
  265.                 console.error("Błąd zapisu timerów grupy:", error);
  266.             })
  267.             .finally(() => {
  268.                 // Odblokuj odświeżanie z małym opóźnieniem, aby serwer zdążył przetworzyć zmianę
  269.                 setTimeout(() => {
  270.                     isSaving = false;
  271.                     console.log("Blokada zapisu zwolniona.");
  272.                 }, 500);
  273.             });
  274.     }
  275.     // Jeśli użytkownik nie jest w grupie, zapisz dane lokalnie
  276.     else {
  277.         const timersToSaveLocal = timers.map(t => ({
  278.             name: t.name,
  279.             minRespawnTime: new Date(t.minRespawnTime).toISOString(),
  280.             maxRespawnTime: new Date(t.maxRespawnTime).toISOString(),
  281.             alertPlayed: t.alertPlayed
  282.         }));
  283.         localStorage.setItem("timers", JSON.stringify(timersToSaveLocal));
  284.     }
  285. }
  286.   function generateRandomCode(length = 6) {    const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  287.     let result = '';
  288.     for (let i = 0; i < length; i++) {
  289.         const randomIndex = Math.floor(Math.random() * characters.length);
  290.         result += characters[randomIndex];
  291.     }
  292.     return result;
  293. }
  294.  
  295. async function createGroup() {
  296.     if (isProcessingGroupAction) {
  297.         console.warn("Operacja tworzenia grupy jest już w toku.");
  298.         return;
  299.     }
  300.     isProcessingGroupAction = true;
  301.  
  302.     if (!window.currentUser) {
  303.         alert("Musisz być zalogowany, aby stworzyć grupę.");
  304.         isProcessingGroupAction = false;
  305.         return;
  306.     }
  307.    
  308.     const groupNameInput = document.getElementById('groupNameInput');
  309.     const groupName = groupNameInput.value.trim();
  310.     if (!groupName) {
  311.         alert("Proszę podać nazwę dla nowej grupy.");
  312.         isProcessingGroupAction = false;
  313.         return;
  314.     }
  315.  
  316.     try {
  317.         const inviteCode = generateRandomCode();
  318.        
  319.         // Tworzymy obiekt grupy, używając tylko danych email, tak jak chcieliśmy
  320.         const groupData = {
  321.             name: groupName,
  322.             adminId: window.currentUser.uid,
  323.             adminEmail: window.currentUser.email.split('@')[0],
  324.             members: [{ id: window.currentUser.uid, email: window.currentUser.email.split('@')[0] }],
  325.             memberIds: [window.currentUser.uid],
  326.             inviteCode: inviteCode,
  327.             createdAt: firebase.firestore.FieldValue.serverTimestamp(),
  328.             activeTimers: []
  329.         };
  330.  
  331.         // Zapisujemy grupę w bazie danych (tylko raz)
  332.         await db.collection("groups").doc(inviteCode).set(groupData);
  333.        
  334.         // Informujemy o sukcesie
  335.         alert(`Grupa "${groupName}" została pomyślnie stworzona!`);
  336.        
  337.         // Czyścimy interfejs użytkownika
  338.         if (document.getElementById('groupManagementContainer')) {
  339.             document.getElementById('groupManagementContainer').style.display = 'none';
  340.         }
  341.         if (groupNameInput) {
  342.             groupNameInput.value = '';
  343.         }
  344.  
  345.     } catch (error) {
  346.         console.error("Błąd podczas tworzenia grupy:", error);
  347.         alert(`Wystąpił błąd: ${error.message}`);
  348.     } finally {
  349.         // Niezależnie od wyniku, odblokowujemy możliwość ponownej akcji
  350.         isProcessingGroupAction = false;
  351.     }
  352. }
  353. async function joinGroup() {
  354.     if (isProcessingGroupAction) { return; }
  355.     isProcessingGroupAction = true;
  356.     if (!window.currentUser) { alert("Musisz być zalogowany."); isProcessingGroupAction = false; return; }
  357.     const groupCodeInput = document.getElementById('groupCodeInput');
  358.     const inviteCode = groupCodeInput.value.trim().toUpperCase();
  359.     if (!inviteCode) { alert("Proszę podać kod zaproszenia."); isProcessingGroupAction = false; return; }
  360.  
  361.     const groupRef = db.collection("groups").doc(inviteCode);
  362.     try {
  363.         // Pobieramy nick dołączającego użytkownika
  364.         const userDoc = await db.collection('users').doc(window.currentUser.uid).get();
  365.         const userNick = userDoc.exists ? userDoc.data().nick : window.currentUser.email.split('@')[0];
  366.  
  367.         const groupName = await db.runTransaction(async transaction => {
  368.             const doc = await transaction.get(groupRef);
  369.             if (!doc.exists) throw "Grupa o podanym kodzie nie istnieje.";
  370.             const groupData = doc.data();
  371.             if (groupData.members.some(member => member.id === window.currentUser.uid)) throw "Już jesteś członkiem tej grupy.";
  372.            
  373.             transaction.update(groupRef, {
  374.                 members: firebase.firestore.FieldValue.arrayUnion({ id: window.currentUser.uid, email: currentUser.email.split('@')[0] }), // Wracamy do emaila
  375.                 memberIds: firebase.firestore.FieldValue.arrayUnion(window.currentUser.uid)
  376.             });
  377.             return groupData.name;
  378.         });
  379.         alert(`Pomyślnie dołączyłeś do grupy: "${groupName}"!`);
  380.         if (groupCodeInput) groupCodeInput.value = '';
  381.     } catch (error) {
  382.         alert(`Błąd dołączania do grupy: ${error.toString()}`);
  383.     } finally {
  384.         isProcessingGroupAction = false;
  385.     }
  386. }
  387.  
  388. async function leaveGroup(groupId) {
  389.     if (isProcessingGroupAction) { console.warn(`ACTION: leaveGroup (${groupId}) - Action already in progress.`); return; }
  390.     isProcessingGroupAction = true;
  391.  
  392.     if (!window.currentUser) { alert("Brak zalogowanego użytkownika."); isProcessingGroupAction = false; return; }
  393.     if (!confirm("Czy na pewno chcesz opuścić tę grupę?")) { isProcessingGroupAction = false; console.log(`ACTION: leaveGroup (${groupId}) - Cancelled by user.`); return; }
  394.    
  395.     console.log(`ACTION: leaveGroup - START - User ${window.currentUser.email.split('@')[0]} leaving group ${groupId}`);
  396.     const groupRef = db.collection("groups").doc(groupId);
  397.  
  398.     try {
  399.         const message = await db.runTransaction(async (transaction) => {
  400.             console.log(`ACTION: leaveGroup - Transaction START for group ${groupId}`);
  401.             const groupDoc = await transaction.get(groupRef);
  402.             if (!groupDoc.exists) {
  403.                 console.error(`ACTION: leaveGroup - Transaction - Group ${groupId} does not exist.`);
  404.                 throw "Grupa nie istnieje.";
  405.             }
  406.  
  407.             let groupData = groupDoc.data();
  408.             console.log(`ACTION: leaveGroup - Transaction - Group data:`, JSON.parse(JSON.stringify(groupData)));
  409.             let currentMembers = groupData.members;
  410.            
  411.             const memberIndex = currentMembers.findIndex(member => member.id === window.currentUser.uid);
  412.             if (memberIndex === -1) {
  413.                 console.warn(`ACTION: leaveGroup - Transaction - User ${window.currentUser.email.split('@')[0]} is not a member of group ${groupId}.`);
  414.                 throw "Nie jesteś członkiem tej grupy.";
  415.             }
  416.  
  417.             const remainingMembers = currentMembers.filter(member => member.id !== window.currentUser.uid);
  418.             console.log(`ACTION: leaveGroup - Transaction - Remaining members: ${remainingMembers.length}`);
  419.  
  420.             if (remainingMembers.length === 0) {
  421.                 console.log(`ACTION: leaveGroup - Transaction - Last member leaving, deleting group ${groupId}.`);
  422.                 transaction.delete(groupRef);
  423.                 return "Opuściłeś grupę. Grupa została usunięta, ponieważ była pusta.";
  424.             } else {
  425.                 let newAdminId = groupData.adminId;
  426.                 let newAdminEmail = groupData.adminEmail;
  427.                 if (groupData.adminId === window.currentUser.uid) { // If admin is leaving
  428.                     newAdminId = remainingMembers[0].id;
  429.                     newAdminEmail = remainingMembers[0].email;
  430.                     console.log(`ACTION: leaveGroup - Transaction - Admin ${groupData.adminEmail} is leaving. New admin: ${newAdminEmail}`);
  431.                 }
  432.                 console.log(`ACTION: leaveGroup - Transaction - Updating members and admin (if changed) for group ${groupId}.`);
  433.                 transaction.update(groupRef, {
  434.                     members: remainingMembers,
  435.                     adminId: newAdminId,
  436.                     adminEmail: newAdminEmail
  437.                 });
  438.                 return groupData.adminId === window.currentUser.uid && newAdminId !== window.currentUser.uid ?
  439.                        `Opuściłeś grupę. ${newAdminEmail} jest teraz nowym administratorem.` :
  440.                        "Opuściłeś grupę.";
  441.             }
  442.         });
  443.        
  444.         console.log(`ACTION: leaveGroup - Transaction COMPLETED SUCCESSFULLY for group ${groupId}. Message: ${message}`);
  445.         alert(message); // Pokaż wiadomość zwróconą z transakcji
  446.        
  447.         if (window.activeGroupId === groupId) {
  448.             console.log(`ACTION: leaveGroup - Left active group ${groupId}. Switching to local timers.`);
  449.             setActiveGroupForTimers(null);
  450.         }
  451.         // onSnapshot in loadUserGroupsAndHandleActive should refresh the groups list.
  452.     } catch (error) {
  453.         console.error(`ACTION: leaveGroup - ERROR - ${error.toString()} for group ${groupId}`, error);
  454.         alert(`Nie udało się opuścić grupy: ${error.toString()}`);
  455.     } finally {
  456.         isProcessingGroupAction = false;
  457.         console.log(`ACTION: leaveGroup - END for group ${groupId}`);
  458.     }
  459. }
  460.  
  461.   async function deleteGroup(groupId) {
  462.     // To bardzo ważny krok - operacja usunięcia jest nieodwracalna.
  463.     if (!confirm("Czy na pewno chcesz TRWALE USUNĄĆ całą grupę? Tej operacji nie można cofnąć!")) {
  464.         return;
  465.     }
  466.  
  467.     if (isProcessingGroupAction) { return; }
  468.     isProcessingGroupAction = true;
  469.  
  470.     if (!window.currentUser) {
  471.         window.api.showErrorDialog('Błąd', 'Musisz być zalogowany, aby usunąć grupę.');
  472.         isProcessingGroupAction = false;
  473.         return;
  474.     }
  475.  
  476.     const groupRef = db.collection('groups').doc(groupId);
  477.  
  478.     try {
  479.         // Wykonujemy operację usunięcia.
  480.         // Reguły Bezpieczeństwa na serwerze sprawdzą, czy użytkownik jest adminem.
  481.         await groupRef.delete();
  482.  
  483.         alert("Grupa została pomyślnie usunięta.");
  484.  
  485.         // Jeśli użytkownik usunął grupę, którą aktualnie przeglądał,
  486.         // przełączamy go z powrotem na timery lokalne.
  487.         if (window.activeGroupId === groupId) {
  488.             setActiveGroupForTimers(null);
  489.         }
  490.         // Listener `onSnapshot` w funkcji `loadUserGroupsAndHandleActive` automatycznie
  491.         // wykryje, że grupa zniknęła i odświeży listę.
  492.  
  493.     } catch (error) {
  494.         // Wyświetlamy natywny dialog błędu w razie problemów
  495.         window.api.showErrorDialog('Błąd usuwania grupy', error.message);
  496.     } finally {
  497.         isProcessingGroupAction = false;
  498.     }
  499. }
  500.  
  501.  
  502. async function removeMemberFromGroup(groupId, memberIdToRemove, memberEmailToRemove, event) {
  503.     if (isProcessingGroupAction) {
  504.         console.warn(`ACTION: removeMember (${groupId}) - Action already in progress.`);
  505.         return;
  506.     }
  507.     isProcessingGroupAction = true;
  508.     const clickedButton = event ? event.target.closest('button') : null;
  509.     if (clickedButton) clickedButton.disabled = true;
  510.    
  511.     try {
  512.         console.log(`ACTION: removeMemberFromGroup - START for group ${groupId}, removing member ${memberIdToRemove} (${memberEmailToRemove})`);
  513.        
  514.         // Pobierz aktualny dokument grupy
  515.         const groupRef = db.collection('groups').doc(groupId);
  516.         const groupDoc = await groupRef.get();
  517.        
  518.         if (!groupDoc.exists) {
  519.             console.error(`GROUP NOT FOUND: Group with ID ${groupId} does not exist.`);
  520.             throw new Error(`Group with ID ${groupId} does not exist.`);
  521.         }
  522.        
  523.         const groupData = groupDoc.data();
  524.        
  525.         // Sprawdź czy użytkownik jest członkiem grupy
  526.         if (!groupData.members || !Array.isArray(groupData.members)) {
  527.             console.error(`INVALID GROUP DATA: Members array not found or invalid in group ${groupId}.`);
  528.             throw new Error(`Invalid group data structure for group ${groupId}.`);
  529.         }
  530.        
  531.         const memberIndex = groupData.members.findIndex(member => member.id === memberIdToRemove);
  532.         if (memberIndex === -1) {
  533.             console.warn(`MEMBER NOT FOUND: Member ${memberIdToRemove} not found in group ${groupId}.`);
  534.             throw new Error(`Member ${memberIdToRemove} is not a member of group ${groupId}.`);
  535.         }
  536.        
  537.         // Usuń członka z tablicy
  538.         const updatedMembers = [
  539.             ...groupData.members.slice(0, memberIndex),
  540.             ...groupData.members.slice(memberIndex + 1)
  541.         ];
  542.        
  543.         // Wykonaj transakcję aktualizacji grupy
  544.         await db.runTransaction(async (transaction) => {
  545.             const freshGroupRef = db.collection('groups').doc(groupId);
  546.             const freshGroupDoc = await transaction.get(freshGroupRef);
  547.            
  548.             if (!freshGroupDoc.exists) {
  549.                 throw new Error(`Group ${groupId} disappeared during transaction.`);
  550.             }
  551.            
  552.             const freshGroupData = freshGroupDoc.data();
  553.            
  554.             if (!freshGroupData.members || !Array.isArray(freshGroupData.members)) {
  555.                 throw new Error(`Invalid group data structure in transaction for group ${groupId}.`);
  556.             }
  557.            
  558.             const freshMemberIndex = freshGroupData.members.findIndex(member => member.id === memberIdToRemove);
  559.             if (freshMemberIndex === -1) {
  560.                 throw new Error(`Member ${memberIdToRemove} disappeared from group ${groupId} during transaction.`);
  561.             }
  562.            
  563.             const freshUpdatedMembers = [
  564.                 ...freshGroupData.members.slice(0, freshMemberIndex),
  565.                 ...freshGroupData.members.slice(freshMemberIndex + 1)
  566.             ];
  567.            
  568.             transaction.update(freshGroupRef, {
  569.                 members: freshUpdatedMembers,
  570.                 updatedAt: firebase.firestore.FieldValue.serverTimestamp()
  571.             });
  572.         });
  573.        
  574.         console.log(`SUCCESS: Member ${memberIdToRemove} (${memberEmailToRemove}) removed from group ${groupId}`);
  575.        
  576.         // Odświeżenie interfejsu użytkownika po usunięciu członka
  577.         // Możesz dodać tutaj kod do aktualizacji listy członków w UI
  578.         // np. odświeżenie listy członków lub usunięcie elementu z listy
  579.        
  580.     } catch (error) {
  581.         console.error(`ERROR: removeMemberFromGroup - Failed to remove member ${memberIdToRemove} from group ${groupId}`, error);
  582.         // Wyświetlenie komunikatu o błędzie dla użytkownika
  583.         if (clickedButton) {
  584.             // Możesz dodać tutaj kod do wyświetlenia komunikatu błędu blisko przycisku
  585.             // np. dodanie elementu z komunikatem błędu
  586.         } else {
  587.             alert(`Nie udało się usunąć użytkownika ${memberEmailToRemove} z grupy. Błąd: ${error.message}`);
  588.         }
  589.     } finally {
  590.         if (clickedButton) clickedButton.disabled = false;
  591.         isProcessingGroupAction = false;
  592.         console.log(`ACTION: removeMemberFromGroup - END for group ${groupId}`);
  593.     }
  594. }
  595.  
  596.  
  597. function loadUserGroupsAndHandleActive() {
  598.     if (!window.currentUser) {
  599.         const groupListContainer = document.getElementById('groupListContainer');
  600.         if(groupListContainer) groupListContainer.innerHTML = '<p>Zaloguj się, aby zobaczyć swoje grupy.</p>';
  601.         const groupSwitcherSelect = document.getElementById('groupSwitcherSelect');
  602.         if(groupSwitcherSelect) groupSwitcherSelect.innerHTML = '<option value="">-- Moje Lokalne Timery --</option>';
  603.         if (window.activeGroupId !== null) { // Jeśli była jakaś aktywna grupa, przełącz na lokalne
  604.             console.log("loadUserGroupsAndHandleActive: No user, switching to local timers (was active).");
  605.             setActiveGroupForTimers(null);
  606.         } else {
  607.             console.log("loadUserGroupsAndHandleActive: No user, local timers already active or no change needed.");
  608.         }
  609.         return;
  610.     }
  611.  
  612.     if (unsubscribeUserGroupsListener) {
  613.         unsubscribeUserGroupsListener();
  614.         console.log("loadUserGroupsAndHandleActive: Old user groups listener unsubscribed.");
  615.     }
  616.  
  617.     console.log("loadUserGroupsAndHandleActive: Subscribing user groups listener for:", window.currentUser.email.split('@')[0]);
  618.     unsubscribeUserGroupsListener = db.collection("groups")
  619.         .where("members", "array-contains", { id: window.currentUser.uid, email: window.currentUser.email.split('@')[0] })
  620.         // .orderBy("createdAt", "desc") // REMEMBER INDEX IF YOU UNCOMMENT!
  621.         .onSnapshot(snapshot => {
  622.             console.log("loadUserGroupsAndHandleActive (onSnapshot): Received user groups snapshot, docs:", snapshot.size);
  623.             const groups = [];
  624.             snapshot.forEach(doc => groups.push({ id: doc.id, ...doc.data() }));
  625.            
  626.             displayUserGroupsList(groups);
  627.             populateGroupSwitcher(groups);
  628.  
  629.             const previouslyActiveGroupId = window.activeGroupId;
  630.             let newCandidateActiveGroupId = null;
  631.  
  632.             if (previouslyActiveGroupId && groups.some(g => g.id === previouslyActiveGroupId)) {
  633.                 newCandidateActiveGroupId = previouslyActiveGroupId;
  634.             } else if (groups.length > 0) {
  635.                 newCandidateActiveGroupId = groups[0].id;
  636.             }
  637.             // If no groups, newCandidateActiveGroupId remains null (local timers)
  638.  
  639.             console.log(`loadUserGroupsAndHandleActive (onSnapshot): Prev active: ${previouslyActiveGroupId}, New candidate: ${newCandidateActiveGroupId}, Current active: ${window.activeGroupId}`);
  640.  
  641.             if (window.activeGroupId !== newCandidateActiveGroupId) {
  642.                 console.log(`loadUserGroupsAndHandleActive (onSnapshot): Active group WILL CHANGE. Calling setActiveGroupForTimers with ${newCandidateActiveGroupId}`);
  643.                 setActiveGroupForTimers(newCandidateActiveGroupId);
  644.             } else {
  645.                 console.log("loadUserGroupsAndHandleActive (onSnapshot): Active group for timers remains unchanged. No call to setActiveGroupForTimers.");
  646.                 // Refresh UI for the current active group if its data (e.g., name) might have changed
  647.                 const activeGroupData = groups.find(g => g.id === window.activeGroupId);
  648.                 const activeGroupNameDisplay = document.getElementById('activeGroupNameDisplay');
  649.                 const currentTimerContextUI = document.getElementById('currentTimerContext');
  650.                 if (activeGroupData && activeGroupNameDisplay && currentTimerContextUI) {
  651.                      if (activeGroupNameDisplay.textContent !== activeGroupData.name) activeGroupNameDisplay.textContent = activeGroupData.name;
  652.                      if (currentTimerContextUI.textContent !== activeGroupData.name) currentTimerContextUI.textContent = activeGroupData.name;
  653.                 } else if (!activeGroupData && window.activeGroupId !== null) {
  654.                     // This case means the active group was deleted/left, and it wasn't the first one in the new list.
  655.                     // We should switch to local or the new first group.
  656.                     console.log("loadUserGroupsAndHandleActive (onSnapshot): Previously active group no longer exists. Switching.");
  657.                     setActiveGroupForTimers(groups.length > 0 ? groups[0].id : null);
  658.                 }
  659.             }
  660.  
  661.         }, error => {
  662.             console.error("loadUserGroupsAndHandleActive (onSnapshot): Error loading user groups: ", error);
  663.             const groupListContainer = document.getElementById('groupListContainer');
  664.             if(groupListContainer) groupListContainer.innerHTML = '<p>Błąd ładowania grup. Sprawdź konsolę (F12).</p>';
  665.         });
  666. }
  667.  
  668.   /* wersja work        
  669. function populateGroupSwitcher(groups) {
  670.     const groupSwitcherSelect = document.getElementById('groupSwitcherSelect');
  671.     if (!groupSwitcherSelect) return;
  672.  
  673.     const valueToRestore = window.activeGroupId || "";
  674.    
  675.     groupSwitcherSelect.innerHTML = '<option value="">-- Moje Lokalne Timery --</option>';
  676.     groups.forEach(group => {
  677.         const option = document.createElement('option');
  678.         option.value = group.id;
  679.         option.textContent = group.name;
  680.         groupSwitcherSelect.appendChild(option);
  681.     });
  682.  
  683.     groupSwitcherSelect.value = valueToRestore;
  684.     console.log("populateGroupSwitcher: Select updated, value set to:", groupSwitcherSelect.value);
  685. }
  686. */
  687.          
  688.          
  689.          
  690.     function populateGroupSwitcher(groups) {
  691.     const tabsContainer = document.getElementById('group-switcher-tabs');
  692.     if (!tabsContainer) return;
  693.  
  694.     tabsContainer.innerHTML = ''; // Wyczyść stare zakładki
  695.  
  696.     // 1. Stwórz zakładkę dla timerów lokalnych
  697.     const localTab = document.createElement('div');
  698.     localTab.className = 'group-tab-scarf';
  699.     localTab.textContent = 'Lokalne';
  700.     localTab.title = 'Moje Lokalne Timery';
  701.     localTab.dataset.groupId = 'null'; // Używamy stringa 'null' do identyfikacji
  702.  
  703.     localTab.addEventListener('click', () => {
  704.         setActiveGroupForTimers(null); // Przełącz na timery lokalne
  705.     });
  706.     tabsContainer.appendChild(localTab);
  707.  
  708.     // 2. Stwórz zakładki dla każdej grupy z bazy danych
  709.     groups.forEach((group, index) => {
  710.         const tabElement = document.createElement('div');
  711.         tabElement.className = 'group-tab-scarf';
  712.         tabElement.textContent = toRoman(index + 1); // Używamy cyfr rzymskich
  713.         tabElement.title = group.name; // Nazwa grupy w podpowiedzi
  714.         tabElement.dataset.groupId = group.id;
  715.  
  716.         tabElement.addEventListener('click', () => {
  717.             setActiveGroupForTimers(group.id); // Przełącz na wybraną grupę
  718.         });
  719.         tabsContainer.appendChild(tabElement);
  720.     });
  721.  
  722.     // 3. Ustaw klasę 'active' na aktualnie wybranej zakładce
  723.     updateActiveSwitcherTab();
  724. }
  725.  
  726. // 4. Dodaj nową funkcję pomocniczą do aktualizacji aktywnej zakładki
  727. function updateActiveSwitcherTab() {
  728.     const tabsContainer = document.getElementById('group-switcher-tabs');
  729.     if (!tabsContainer) return;
  730.  
  731.     const currentActiveId = activeGroupId === null ? 'null' : activeGroupId;
  732.  
  733.     tabsContainer.querySelectorAll('.group-tab-scarf').forEach(tab => {
  734.         tab.classList.remove('active');
  735.         if (tab.dataset.groupId === currentActiveId) {
  736.             tab.classList.add('active');
  737.         }
  738.     });
  739. }      
  740.          
  741.          
  742.          
  743.          
  744. function setActiveGroupForTimers(newGroupId) {
  745.     if (window.activeGroupId === newGroupId) {
  746.         console.log(`setActiveGroupForTimers: Group ${newGroupId || 'Lokalne'} is already active. No changes needed.`);
  747.         return;
  748.     }
  749.     console.log(`setActiveGroupForTimers: Attempting to switch from ${window.activeGroupId || 'Lokalne'} to ${newGroupId || 'Lokalne'}`);
  750.  
  751.     const oldListener = unsubscribeGroupTimersListener;
  752.     unsubscribeGroupTimersListener = null; // Clear global handle first
  753.  
  754.     if (oldListener) {
  755.         oldListener();
  756.         console.log("setActiveGroupForTimers: Unsubscribed old group timers listener for:", window.activeGroupId);
  757.     }
  758.    
  759.     window.activeGroupId = newGroupId; // Update global state IMMEDIATELY
  760.  
  761.     const activeGroupNameDisplay = document.getElementById('activeGroupNameDisplay');
  762.     const currentTimerContextUI = document.getElementById('currentTimerContext');
  763.     const groupSwitcherSelect = document.getElementById('groupSwitcherSelect');
  764.  
  765.     if (typeof window.clearLocalTimers === 'function') window.clearLocalTimers();
  766.  
  767.     if (newGroupId) {
  768.         const groupDocRef = db.collection("groups").doc(newGroupId);
  769.         // Get group data once to set UI immediately, then attach listener
  770.         groupDocRef.get().then(doc => {
  771.             if(doc.exists) {
  772.                 const groupName = doc.data().name;
  773.                 if(activeGroupNameDisplay) activeGroupNameDisplay.textContent = groupName;
  774.                 if(currentTimerContextUI) currentTimerContextUI.textContent = groupName;
  775.                
  776.                 console.log("setActiveGroupForTimers: Subscribing new timers listener for group:", newGroupId, `(${groupName})`);
  777.                
  778. unsubscribeGroupTimersListener = groupDocRef.onSnapshot(groupSnapshot => {
  779.     // ⬇️ DODAJ TEN WARUNEK NA SAMEJ GÓRZE LISTENER'A ⬇️
  780.     if (groupSnapshot.metadata.hasPendingWrites) {
  781.         console.log("Snapshot zignorowany: zmiana lokalna w trakcie zapisu.");
  782.         return; // Nie rób nic, to tylko "echo" naszej własnej zmiany.
  783.     }
  784.                     if (window.activeGroupId !== newGroupId) { // Check if group changed again before snapshot arrives
  785.                         console.log(`setActiveGroupForTimers (onSnapshot for ${newGroupId}): Active group changed to ${window.activeGroupId}. This listener is now stale. Unsubscribing.`);
  786.                         // This specific listener instance should unsubscribe itself
  787.                         const thisListenerUnsubscribe = unsubscribeGroupTimersListener; // Capture current listener
  788.                         if (thisListenerUnsubscribe) { // Check if it's still the one we think it is
  789.                             thisListenerUnsubscribe();
  790.                             if(unsubscribeGroupTimersListener === thisListenerUnsubscribe) unsubscribeGroupTimersListener = null; // Clear global if it was this one
  791.                         }
  792.                         return;
  793.                     }
  794.                     if (groupSnapshot.exists) {
  795.                         const groupData = groupSnapshot.data();
  796.                         console.log(`setActiveGroupForTimers (onSnapshot for ${newGroupId}): Received timer data, count:`, groupData.activeTimers ? groupData.activeTimers.length : 0);
  797.                         if (typeof window.loadTimersFromArray === 'function') {
  798.                             window.loadTimersFromArray(groupData.activeTimers || []);
  799.                         }
  800.                     } else {
  801.                         console.warn(`setActiveGroupForTimers (onSnapshot for ${newGroupId}): Active group document no longer exists. Switching to local.`);
  802.                         if (window.activeGroupId === newGroupId) setActiveGroupForTimers(null);
  803.                     }
  804.                 }, error => {
  805.                     console.error(`setActiveGroupForTimers (onSnapshot for ${newGroupId}): Error listening to group timers:`, error);
  806.                     if (window.activeGroupId === newGroupId) setActiveGroupForTimers(null);
  807.                 });
  808.             } else {
  809.                 console.warn(`setActiveGroupForTimers: Group ${newGroupId} does not exist (after get). Switching to local.`);
  810.                 setActiveGroupForTimers(null); // This will correctly set UI to local and load local timers
  811.             }
  812.         }).catch(error => {
  813.             console.error(`setActiveGroupForTimers: Error fetching group ${newGroupId} details:`, error);
  814.             setActiveGroupForTimers(null); // Fallback to local
  815.         });
  816.     } else { // newGroupId is null (local timers)
  817.         console.log("setActiveGroupForTimers: Switched to local timers.");
  818.         if(activeGroupNameDisplay) activeGroupNameDisplay.textContent = "Lokalne";
  819.         if(currentTimerContextUI) currentTimerContextUI.textContent = "Lokalne";
  820.         if (typeof window.loadTimers === 'function') window.loadTimers();
  821.     }
  822.    
  823.     if(groupSwitcherSelect) groupSwitcherSelect.value = newGroupId || ""; // Update switcher to reflect current state
  824.   updateActiveSwitcherTab();
  825.     console.log("setActiveGroupForTimers: FINISHED. Active group is now:", window.activeGroupId);
  826. }
  827.  
  828.  
  829. function displayUserGroupsList(groups) {
  830.     const container = document.getElementById('groupListContainer');
  831.     if (!container) return;
  832.     container.innerHTML = '';
  833.  
  834.     if (groups.length === 0) {
  835.         container.innerHTML = '<p>Nie należysz do żadnej grupy. Stwórz nową lub dołącz do istniejącej!</p>';
  836.         return;
  837.     }
  838.  
  839.     groups.forEach(group => {
  840.         // Główny kontener dla całej zwijanej grupy
  841.         const groupDiv = document.createElement('div');
  842.         groupDiv.className = 'timer-item group-item collapsible';
  843.  
  844.         // 1. Tworzymy nagłówek, który będzie zawsze widoczny i klikalny
  845.         const header = document.createElement('div');
  846.         header.className = 'collapsible-header';
  847.  
  848.         const groupNameSpan = document.createElement('span');
  849.         groupNameSpan.className = 'group-name-display';
  850.         groupNameSpan.textContent = group.name;
  851.         header.appendChild(groupNameSpan);
  852.        
  853.         const controlsDiv = document.createElement('div');
  854.         controlsDiv.className = 'header-controls';
  855.  
  856.         // Opcjonalna ikonka "i" z kodem zaproszenia dla admina
  857.         if (group.adminId === window.currentUser.uid) {
  858.             const inviteInfoSpan = document.createElement('span');
  859.             inviteInfoSpan.className = 'group-invite-info';
  860.             inviteInfoSpan.innerHTML = `
  861.                 <img src="https://api.iconify.design/solar/info-circle-bold-duotone.svg?color=%23e9d8a6" alt="info">
  862.                 <span class="tooltip-text">Kod: ${group.inviteCode}</span>
  863.             `;
  864.             inviteInfoSpan.addEventListener('click', e => e.stopPropagation());
  865.             controlsDiv.appendChild(inviteInfoSpan);
  866.         }
  867.  
  868.         const toggleBtn = document.createElement('button');
  869.         toggleBtn.className = 'toggle-collapse-btn';
  870.         toggleBtn.innerHTML = '&#9660;'; // Strzałka w dół
  871.         controlsDiv.appendChild(toggleBtn);
  872.         header.appendChild(controlsDiv);
  873.  
  874.         // 2. Tworzymy kontener na treść, która będzie zwijana
  875.         const content = document.createElement('div');
  876.         content.className = 'collapsible-content';
  877.  
  878.         const membersSectionDiv = document.createElement('div');
  879.         membersSectionDiv.className = 'group-members-section';
  880.         const membersListUl = document.createElement('ul');
  881.         membersListUl.className = 'group-members-list';
  882.         group.members.forEach(member => {
  883.             const memberLi = document.createElement('li');
  884.             memberLi.textContent = member.email;
  885.             if (member.id === group.adminId) {
  886.                 const adminBadge = document.createElement('span');
  887.                 adminBadge.textContent = ' (Admin)';
  888.                 adminBadge.style.fontWeight = 'bold';
  889.                 adminBadge.style.color = '#e9d8a6';
  890.                 memberLi.appendChild(adminBadge);
  891.             }
  892.             if (group.adminId === window.currentUser.uid && member.id !== window.currentUser.uid) {
  893.                 const removeBtn = document.createElement('button');
  894.                 removeBtn.textContent = 'X';
  895.                 removeBtn.className = 'remove-member-btn';
  896.                 removeBtn.title = `Wyrzuć ${member.email}`;
  897.                 removeBtn.onclick = (e) => {
  898.                     e.stopPropagation();
  899.                     removeMemberFromGroup(group.id, member.id, member.email);
  900.                 }
  901.                 memberLi.appendChild(removeBtn);
  902.             }
  903.             membersListUl.appendChild(memberLi);
  904.         });
  905.         membersSectionDiv.appendChild(membersListUl);
  906.         content.appendChild(membersSectionDiv);
  907.  
  908.         const actionsDiv = document.createElement('div');
  909.         actionsDiv.className = 'button-center group-actions';
  910.         const leaveBtn = document.createElement('button');
  911.         leaveBtn.textContent = 'Opuść grupę';
  912.         leaveBtn.onclick = (e) => {
  913.             e.stopPropagation();
  914.             leaveGroup(group.id);
  915.         };
  916.         actionsDiv.appendChild(leaveBtn);
  917.         if (group.adminId === window.currentUser.uid) {
  918.             const deleteGroupBtn = document.createElement('button');
  919.             deleteGroupBtn.textContent = 'Usuń grupę';
  920.             deleteGroupBtn.onclick = (e) => {
  921.                 e.stopPropagation();
  922.                 deleteGroup(group.id); // Potrzebujesz takiej funkcji
  923.             };
  924.             actionsDiv.appendChild(deleteGroupBtn);
  925.         }
  926.         content.appendChild(actionsDiv);
  927.  
  928.         // 3. Składamy wszystko w całość
  929.         groupDiv.appendChild(header);
  930.         groupDiv.appendChild(content);
  931.         container.appendChild(groupDiv);
  932.  
  933.         // 4. Dodajemy obsługę kliknięcia do nagłówka
  934.         header.addEventListener('click', () => {
  935.             groupDiv.classList.toggle('expanded');
  936.         });
  937.     });
  938. }
  939. // --- FUNKCJE ZAPISU/ODCZYTU USTAWIEŃ UŻYTKOWNIKA (TŁO, DŹWIĘK) ---
  940. const userPrivateSettingsRef = () => db.collection('user_settings').doc(window.currentUser.uid);
  941.  
  942. async function saveUserSetting(key, value) {
  943.     if (!window.currentUser) return;
  944.     try {
  945.         await userPrivateSettingsRef().set({ [key]: value }, { merge: true });
  946.     } catch (error) {
  947.         console.error(`Błąd zapisu ustawienia ${key}:`, error);
  948.     }
  949. }
  950.  
  951. async function loadUserSettingsFromFirebase() {
  952.     if (!window.currentUser) return;
  953.     try {
  954.         const doc = await userPrivateSettingsRef().get();
  955.         if (doc.exists) {
  956.             const settings = doc.data();
  957.             if (settings.background && typeof window.applyBackground === 'function') {
  958.                 window.applyBackground(settings.background);
  959.                 const bgOption = document.querySelector(`.background-thumbnail[data-path="${settings.background}"]`);
  960.                 if(bgOption) {
  961.                     document.querySelectorAll('.background-thumbnail.selected').forEach(s => s.classList.remove('selected'));
  962.                     bgOption.classList.add('selected');
  963.                 }
  964.             } else if (typeof window.loadSavedBackground === 'function') window.loadSavedBackground();
  965.  
  966.             if (settings.sound && typeof window.respawnSound !== 'undefined' && document.getElementById('soundSelect')) {
  967.                 window.respawnSound.src = settings.sound;
  968.                 document.getElementById('soundSelect').value = settings.sound.startsWith('data:') ? 'custom' : settings.sound;
  969.                 const customSoundContainer = document.getElementById('customSoundContainer');
  970.                 if(document.getElementById('soundSelect').value === 'custom' && customSoundContainer) {
  971.                     customSoundContainer.style.display = 'block';
  972.                 }
  973.             } else if (typeof window.loadNotificationSound === 'function') window.loadNotificationSound();
  974.         } else {
  975.              if (typeof window.loadSavedBackground === 'function') window.loadSavedBackground();
  976.              if (typeof window.loadNotificationSound === 'function') window.loadNotificationSound();
  977.         }
  978.     } catch (error) {
  979.         console.error("Błąd ładowania ustawień użytkownika:", error);
  980.     }
  981. }
  982.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement