From 91d5cbfcff4b459d7a407b02c083bdae306afe1c Mon Sep 17 00:00:00 2001 From: 230419 <230419@epvc.pt> Date: Fri, 24 Apr 2026 14:06:24 +0100 Subject: [PATCH] share look good --- src/App.jsx | 189 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 186 insertions(+), 3 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 26059c4..86991c7 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useMemo } from 'react'; +import React, { useState, useEffect, useMemo, useRef } from 'react'; import { Plus, Search, LayoutDashboard, Shirt, LogOut, Trash2, Heart, Loader2, AlertCircle, @@ -6,7 +6,7 @@ import { Edit2, Image as ImageIcon, Check, RotateCcw, Trash, PanelLeftClose, PanelLeftOpen, Sparkles, CloudSun, ArrowRight, Droplets, CheckCircle2, PieChart, History, - X, Download, Bell, Globe, Filter, ShoppingBag + X, Download, Bell, Globe, Filter, ShoppingBag, Share2 } from 'lucide-react'; import { @@ -15,7 +15,7 @@ import { } from 'firebase/auth'; import { collection, doc, onSnapshot, addDoc, updateDoc, - deleteDoc, writeBatch, setDoc + deleteDoc, writeBatch, setDoc, getDoc } from 'firebase/firestore'; import { auth, db, appId } from './lib/firebase'; @@ -59,6 +59,13 @@ export default function App() { const [theme, setTheme] = useState('theme-indigo'); const [weatherData, setWeatherData] = useState(null); + // Estado para Partilha de Looks + const sharedLookRef = useRef(''); + const [sharedLookData, setSharedLookData] = useState(null); + const [showSharedLookModal, setShowSharedLookModal] = useState(false); + const [sharedLookCopying, setSharedLookCopying] = useState(false); + const [copiedLookId, setCopiedLookId] = useState(null); + const t = (key) => translations[language]?.[key] || translations['PT'][key] || key; // Mapeamento de nomes de cor (PT) para valores CSS @@ -121,6 +128,23 @@ export default function App() { saveUserSetting('weatherAlerts', newVal); }; + // Buscar o look partilhado pelo link + const fetchSharedLook = async (lookId) => { + if (!lookId) return; + try { + const lookDoc = doc(db, 'artifacts', appId, 'sharedLooks', lookId); + const snap = await getDoc(lookDoc); + if (snap.exists()) { + setSharedLookData({ id: snap.id, ...snap.data() }); + setShowSharedLookModal(true); + // Limpar o parâmetro do URL sem recarregar a página + window.history.replaceState({}, '', window.location.pathname); + } + } catch (err) { + console.error('Erro ao buscar look partilhado:', err); + } + }; + useEffect(() => { if (editingItem && editingItem.color) { setItemColors(editingItem.color.split(',').map(c => c.trim()).filter(Boolean)); @@ -169,6 +193,10 @@ export default function App() { setTheme(savedTheme); setUser(currentUser); setView('dashboard'); + // Verificar se há um look partilhado no URL + const sharedId = sharedLookRef.current || new URLSearchParams(window.location.search).get('shared'); + sharedLookRef.current = ''; + if (sharedId) fetchSharedLook(sharedId); } setLoading(false); }); @@ -397,6 +425,77 @@ export default function App() { await deleteDoc(docRef); }; + // Gerar link de partilha e copiar para clipboard + const shareLook = async (look) => { + if (!user) return; + try { + const lookItems = look.items.map(itemId => { + const item = clothes.find(c => c.id === itemId); + return item ? { + name: item.name, + category: item.category, + color: item.color, + imageUrl: item.imageUrl, + } : null; + }).filter(Boolean); + + const sharedCol = collection(db, 'artifacts', appId, 'sharedLooks'); + const docRef = await addDoc(sharedCol, { + lookName: look.name, + ownerUid: user.uid, + ownerEmail: user.email || '', + items: lookItems, + createdAt: new Date().getTime(), + }); + + const shareUrl = `${window.location.origin}${window.location.pathname}?shared=${docRef.id}`; + await navigator.clipboard.writeText(shareUrl); + setCopiedLookId(look.id); + setTimeout(() => setCopiedLookId(null), 3000); + } catch (err) { + console.error('Erro ao partilhar look:', err); + alert('Erro ao gerar link de partilha.'); + } + }; + + // Copiar o look partilhado para o armário do utilizador atual + const copySharedLook = async () => { + if (!user || !sharedLookData) return; + setSharedLookCopying(true); + try { + const newItemIds = []; + for (const item of sharedLookData.items) { + const clothesCol = collection(db, 'artifacts', appId, 'users', user.uid, 'clothes'); + const newItemRef = await addDoc(clothesCol, { + name: item.name, + category: item.category, + color: item.color, + imageUrl: item.imageUrl, + status: 'active', + favorite: false, + createdAt: new Date().getTime(), + updatedAt: new Date().getTime(), + }); + newItemIds.push(newItemRef.id); + } + const looksCol = collection(db, 'artifacts', appId, 'users', user.uid, 'looks'); + await addDoc(looksCol, { + name: sharedLookData.lookName, + items: newItemIds, + createdAt: new Date().getTime(), + updatedAt: new Date().getTime(), + }); + setShowSharedLookModal(false); + setSharedLookData(null); + setView('outfits'); + } catch (err) { + console.error('Erro ao copiar look:', err); + alert('Erro ao copiar look.'); + } finally { + setSharedLookCopying(false); + } + }; + const sendLookToLaundry = async (look) => { if (!window.confirm(t('confirmSendLookToLaundry') || 'Enviar todas as peças deste look para a lavandaria?')) return; setLoading(true); @@ -914,6 +1013,16 @@ export default function App() {
{look.items.length} {t('pieces')} • {new Date(look.createdAt).toLocaleDateString()}
{sharedLookData.items.length} peça{sharedLookData.items.length !== 1 ? 's' : ''} • Partilhado por {sharedLookData.ownerEmail?.split('@')[0] || 'alguém'}
+Peças incluídas
+