diff --git a/frontend/src/hooks/useStickerWall.js b/frontend/src/hooks/useStickerWall.js new file mode 100644 index 0000000..b3bcc68 --- /dev/null +++ b/frontend/src/hooks/useStickerWall.js @@ -0,0 +1,76 @@ +import { useState, useEffect, useRef, useCallback } from 'react'; +import api from '../api/axios'; + +export function useStickerWall(sessionId) { + const [imageUrl, setImageUrl] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(false); + const urlRef = useRef(null); + + const revokeUrl = useCallback(() => { + if (urlRef.current) { + URL.revokeObjectURL(urlRef.current); + urlRef.current = null; + } + }, []); + + const setBlobUrl = useCallback((blob) => { + revokeUrl(); + const url = URL.createObjectURL(blob); + urlRef.current = url; + setImageUrl(url); + }, [revokeUrl]); + + const fetchWall = useCallback(async (id) => { + setLoading(true); + setError(false); + try { + const res = await api.get(`/stickerwalls/${id}`, { responseType: 'blob' }); + setBlobUrl(res.data); + } catch (err) { + if (err.response?.status === 404) { + try { + const renderRes = await api.post(`/stickerwalls/${id}/render`, null, { responseType: 'blob' }); + setBlobUrl(renderRes.data); + } catch (renderErr) { + revokeUrl(); + setImageUrl(null); + setError(true); + } + } else { + revokeUrl(); + setImageUrl(null); + setError(true); + } + } finally { + setLoading(false); + } + }, [setBlobUrl, revokeUrl]); + + const refresh = useCallback(async () => { + if (!sessionId) return; + setLoading(true); + setError(false); + try { + const res = await api.post(`/stickerwalls/${sessionId}/render`, null, { responseType: 'blob' }); + setBlobUrl(res.data); + } catch { + setError(true); + } finally { + setLoading(false); + } + }, [sessionId, setBlobUrl]); + + useEffect(() => { + if (sessionId) { + fetchWall(sessionId); + } else { + revokeUrl(); + setImageUrl(null); + setError(false); + } + return revokeUrl; + }, [sessionId, fetchWall, revokeUrl]); + + return { imageUrl, loading, error, refresh }; +}