| | 'use client'; |
| |
|
| | import { useState, useEffect } from 'react'; |
| | import { apiUrl } from '../constants'; |
| | import { appendTokenToUrl, withAdminTokenHeader } from '../adminAuth'; |
| |
|
| | interface SavedClipboard { |
| | roomCode: string; |
| | lastVisited: string; |
| | name?: string; |
| | isExpired?: boolean; |
| | isPasswordProtected?: boolean; |
| | lastChecked?: string; |
| | } |
| |
|
| | export function useSavedClipboards() { |
| | const [savedClipboards, setSavedClipboards] = useState<SavedClipboard[]>([]); |
| | const [isLoaded, setIsLoaded] = useState(false); |
| | const [isCheckingStatus, setIsCheckingStatus] = useState(false); |
| |
|
| | |
| | useEffect(() => { |
| | const loadSavedClipboards = () => { |
| | try { |
| | const saved = localStorage.getItem('savedClipboards'); |
| | if (saved) { |
| | setSavedClipboards(JSON.parse(saved)); |
| | } |
| | } catch (error) { |
| | console.error('Failed to load saved clipboards:', error); |
| | } finally { |
| | setIsLoaded(true); |
| | } |
| | }; |
| |
|
| | loadSavedClipboards(); |
| | }, []); |
| |
|
| | |
| | useEffect(() => { |
| | if (isLoaded) { |
| | localStorage.setItem('savedClipboards', JSON.stringify(savedClipboards)); |
| | } |
| | }, [savedClipboards, isLoaded]); |
| |
|
| | |
| | useEffect(() => { |
| | const checkClipboardStatus = async () => { |
| | if (!isLoaded || savedClipboards.length === 0 || isCheckingStatus) { |
| | return; |
| | } |
| |
|
| | setIsCheckingStatus(true); |
| | const now = new Date(); |
| | const ONE_HOUR = 60 * 60 * 1000; |
| | |
| | |
| | const updatedClipboards = [...savedClipboards]; |
| | let hasChanges = false; |
| |
|
| | |
| | for (let i = 0; i < updatedClipboards.length; i++) { |
| | const clipboard = updatedClipboards[i]; |
| | const lastChecked = clipboard.lastChecked ? new Date(clipboard.lastChecked) : null; |
| | |
| | |
| | if (lastChecked && (now.getTime() - lastChecked.getTime() < ONE_HOUR)) { |
| | continue; |
| | } |
| |
|
| | try { |
| | const response = await fetch( |
| | appendTokenToUrl(`${apiUrl}/clipboard/${clipboard.roomCode}/exists`), |
| | { |
| | headers: withAdminTokenHeader(), |
| | }, |
| | ); |
| | |
| | if (response.ok) { |
| | const data = await response.json(); |
| | |
| | |
| | if (clipboard.isExpired !== !data.exists || clipboard.isPasswordProtected !== data.hasPassword) { |
| | updatedClipboards[i] = { |
| | ...clipboard, |
| | isExpired: !data.exists, |
| | isPasswordProtected: data.hasPassword, |
| | lastChecked: now.toISOString() |
| | }; |
| | hasChanges = true; |
| | } else if (!clipboard.lastChecked) { |
| | |
| | updatedClipboards[i] = { |
| | ...clipboard, |
| | lastChecked: now.toISOString() |
| | }; |
| | hasChanges = true; |
| | } |
| | } |
| | } catch (error) { |
| | console.error(`Failed to check status for clipboard ${clipboard.roomCode}:`, error); |
| | |
| | } |
| | } |
| |
|
| | if (hasChanges) { |
| | setSavedClipboards(updatedClipboards); |
| | } |
| | |
| | setIsCheckingStatus(false); |
| | }; |
| |
|
| | checkClipboardStatus(); |
| | }, [isLoaded, savedClipboards]); |
| |
|
| | |
| | const addClipboard = (roomCode: string, name?: string) => { |
| | setSavedClipboards(prev => { |
| | |
| | const existingIndex = prev.findIndex(item => item.roomCode === roomCode); |
| | |
| | |
| | const newSavedClipboards = [...prev]; |
| | const now = new Date().toISOString(); |
| | |
| | if (existingIndex >= 0) { |
| | |
| | newSavedClipboards[existingIndex] = { |
| | ...newSavedClipboards[existingIndex], |
| | lastVisited: now, |
| | name: name || newSavedClipboards[existingIndex].name |
| | }; |
| | } else { |
| | |
| | newSavedClipboards.unshift({ |
| | roomCode, |
| | lastVisited: now, |
| | name |
| | }); |
| | } |
| | |
| | |
| | return newSavedClipboards.slice(0, 10); |
| | }); |
| | }; |
| |
|
| | |
| | const removeClipboard = (roomCode: string) => { |
| | setSavedClipboards(prev => |
| | prev.filter(item => item.roomCode !== roomCode) |
| | ); |
| | }; |
| |
|
| | |
| | const clearClipboards = () => { |
| | setSavedClipboards([]); |
| | }; |
| |
|
| | |
| | const renameClipboard = (roomCode: string, newName: string) => { |
| | setSavedClipboards(prev => |
| | prev.map(item => |
| | item.roomCode === roomCode |
| | ? { ...item, name: newName || undefined } |
| | : item |
| | ) |
| | ); |
| | }; |
| |
|
| | return { |
| | savedClipboards, |
| | addClipboard, |
| | removeClipboard, |
| | clearClipboards, |
| | renameClipboard, |
| | isLoaded, |
| | isCheckingStatus |
| | }; |
| | } |
| |
|