import axiosInstance from '@/plugins/axios-plugin'; import { mountStoreDevtool } from 'simple-zustand-devtools'; import { toast } from 'sonner'; import { route } from 'ziggy-js'; import { create } from 'zustand'; import { devtools } from 'zustand/middleware'; const useMediaStore = create( devtools((set, get) => ({ currentTab: 'memes', memes: [], backgrounds: [], isFetchingMemes: false, isFetchingBackgrounds: false, // Selected items selectedMeme: null, selectedBackground: null, currentCaption: 'I am chicken rice', watermarked: true, // Initial values state hasInitialMeme: false, hasInitialBackground: false, hasInitialText: false, keywords: [], isLoadingAIHints: false, isGeneratingMeme: false, setCurrentTab: (tab) => { set({ currentTab: tab }); }, // Selection actions selectMeme: async (meme) => { set({ selectedMeme: meme }); try { await axiosInstance.post(route('api.app.select.meme'), { meme_ids: meme.ids, }); } catch (error) { console.error('Error meme selection:', error); } }, selectBackground: async (background) => { set({ selectedBackground: background }); try { await axiosInstance.post(route('api.app.select.background'), { background_ids: background.ids, }); } catch (error) { console.error('Error background selection:', error); } }, // Update current caption when user edits text updateCurrentCaption: (caption) => { set({ currentCaption: caption }); }, // Set initial values from props setInitialMeme: (meme) => { set({ selectedMeme: meme, hasInitialMeme: true }); }, setInitialBackground: (background) => { set({ selectedBackground: background, hasInitialBackground: true }); }, setInitialText: (text) => { set({ currentCaption: text, hasInitialText: true }); }, // Clear initial state to allow fresh initialization clearInitialState: () => { set({ hasInitialMeme: false, hasInitialBackground: false, hasInitialText: false }); }, // Clear selections clearSelectedMeme: () => { set({ selectedMeme: null }); }, clearSelectedBackground: () => { set({ selectedBackground: null }); }, // Save meme action saveMeme: async (captionTexts, isPremiumExport = false) => { try { const { selectedMeme, selectedBackground } = get(); await axiosInstance.post(route('api.app.save.meme'), { meme_media_ids: selectedMeme?.ids || null, background_media_ids: selectedBackground?.ids || null, caption_texts: captionTexts, is_premium_export: isPremiumExport, }); } catch (error) { console.error('Error saving meme:', error); // Silently ignore save tracking errors } }, // Fetch AI hints fetchAIHints: async () => { set({ isLoadingAIHints: true }); try { const response = await axiosInstance.post(route('api.ai_hints')); set({ keywords: response.data.success?.data?.keywords || [], }); return response.data; } catch (error) { console.error(route('api.ai_hints')); console.error('Error fetching AI hints:', error); toast.error('Failed to fetch AI hints'); } finally { set({ isLoadingAIHints: false }); } }, // Clear keywords clearKeywords: () => { set({ keywords: [] }); }, init: async (skipCache = false) => { const state = get(); // Skip API call completely if ALL initial values were set via props if (state.hasInitialMeme && state.hasInitialBackground && state.hasInitialText) { return; } try { const params = {}; if (skipCache) { params.sc = '1'; } const response = await axiosInstance.post(route('api.app.init'), params); if (response?.data?.success?.data?.init) { const updates = {}; // Only update values that weren't set via props if (!state.hasInitialText) { updates.currentCaption = response.data.success.data.init.caption; } if (!state.hasInitialMeme) { updates.selectedMeme = response.data.success.data.init.meme; } if (!state.hasInitialBackground) { updates.selectedBackground = response.data.success.data.init.background; } set(updates); } else { throw 'Invalid API response'; } } catch (error) { console.error('Error fetching init:', error); throw error; } }, generateMeme: async (prompt) => { set({ isGeneratingMeme: true }); try { const response = await axiosInstance.post(route('api.user.generate_meme'), { prompt: prompt }); if (response?.data?.success?.data?.job_id) { return response.data; } else { throw 'Invalid API response'; } } catch (error) { console.error('Error generating meme:', error); toast.error('Failed to generate meme'); set({ isGeneratingMeme: false }); throw error; } }, checkMemeJobStatus: async (jobId) => { try { const response = await axiosInstance.post(route('api.user.check_meme_job_status'), { job_id: jobId }); return response.data; } catch (error) { console.error('Error checking job status:', error); throw error; } }, checkActiveJob: async () => { try { const response = await axiosInstance.post(route('api.user.get_active_job')); return response.data; } catch (error) { console.error('Error checking active job:', error); throw error; } }, getMemeHistory: async () => { try { const response = await axiosInstance.post(route('api.user.get_meme_history')); return response.data; } catch (error) { console.error('Error getting meme history:', error); throw error; } }, updateMemeResult: (result) => { set({ currentCaption: result.generate.caption, selectedMeme: result.generate.meme, selectedBackground: result.generate.background, isGeneratingMeme: false, }); }, setGeneratingMeme: (isGenerating) => { set({ isGeneratingMeme: isGenerating }); }, // Fetch memes (overlays) fetchMemes: async () => { set({ isFetchingMemes: true }); try { const response = await axiosInstance.post(route('api.app.memes')); if (response?.data?.success?.data?.memes) { set({ memes: response.data.success.data.memes, isFetchingMemes: false, }); return response.data.success.data.memes; } else { throw 'Invalid API response'; } } catch (error) { console.error('Error fetching memes:', error); set({ isFetchingMemes: false }); if (error?.response?.data?.error?.message?.length > 0) { toast.error(error.response.data.error.message); } throw error; } }, // Fetch backgrounds fetchBackgrounds: async () => { set({ isFetchingBackgrounds: true }); try { const response = await axiosInstance.post(route('api.app.background')); if (response?.data?.success?.data?.backgrounds) { set({ backgrounds: response.data.success.data.backgrounds, isFetchingBackgrounds: false, }); return response.data.success.data.backgrounds; } else { throw 'Invalid API response'; } } catch (error) { console.error('Error fetching backgrounds:', error); set({ isFetchingBackgrounds: false }); if (error?.response?.data?.error?.message?.length > 0) { toast.error(error.response.data.error.message); } throw error; } }, // Search memes searchMemes: async (query = '') => { set({ isFetchingMemes: true }); try { const response = await axiosInstance.post(route('api.app.search.memes'), { query }); if (response?.data?.success?.data?.memes) { set({ memes: response.data.success.data.memes, isFetchingMemes: false, }); return response.data.success.data.memes; } else { throw 'Invalid API response'; } } catch (error) { console.error('Error searching memes:', error); set({ isFetchingMemes: false }); if (error?.response?.data?.error?.message?.length > 0) { toast.error(error.response.data.error.message); } throw error; } }, // Search backgrounds searchBackgrounds: async (query = '') => { set({ isFetchingBackgrounds: true }); try { const response = await axiosInstance.post(route('api.app.search.background'), { query }); if (response?.data?.success?.data?.backgrounds) { set({ backgrounds: response.data.success.data.backgrounds, isFetchingBackgrounds: false, }); return response.data.success.data.backgrounds; } else { throw 'Invalid API response'; } } catch (error) { console.error('Error searching backgrounds:', error); set({ isFetchingBackgrounds: false }); if (error?.response?.data?.error?.message?.length > 0) { toast.error(error.response.data.error.message); } throw error; } }, // Reset store to default state restoreMemeStateToDefault: () => { console.log('restoreMemeStateToDefault'); set({ memes: [], backgrounds: [], isFetchingMemes: false, isFetchingBackgrounds: false, selectedMeme: null, selectedBackground: null, isGeneratingMeme: false, }); }, })), { name: 'MemeStore', store: 'MemeStore', }, ); if (import.meta.env.APP_ENV === 'local') { mountStoreDevtool('MediaStore', useMediaStore); } export default useMediaStore;