From 197a2e326d6fa168a61f478f35f27a791e34a1b1 Mon Sep 17 00:00:00 2001
From: 230419 <230419@epvc.pt>
Date: Wed, 6 May 2026 11:46:48 +0100
Subject: [PATCH] att, pronto para apresentar!
---
src/App.jsx | 89 ++++++++++++++++++++++++++++++++++++++++++-------
src/lib/i18n.js | 5 +++
2 files changed, 82 insertions(+), 12 deletions(-)
diff --git a/src/App.jsx b/src/App.jsx
index 74be53f..404167f 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -44,6 +44,7 @@ export default function App() {
const [categoryFilter, setCategoryFilter] = useState('Todos');
const [colorFilter, setColorFilter] = useState('');
const [ageFilter, setAgeFilter] = useState('any');
+ const [favoriteFilter, setFavoriteFilter] = useState(false);
const [showClosetFilters, setShowClosetFilters] = useState(false);
// Estado para criação de Looks
@@ -315,9 +316,20 @@ export default function App() {
return () => { unsubClothes(); unsubLooks(); unsubSections(); unsubProfile(); unsubNotif(); unsubPlans(); };
}, [user]);
+ const getWeatherEmoji = (code) => {
+ if (code === 0) return '☀️';
+ if ([1, 2, 3].includes(code)) return '⛅';
+ if ([45, 48].includes(code)) return '🌫️';
+ if ([51, 53, 55, 56, 57, 61, 63, 65, 66, 67].includes(code)) return '🌧️';
+ if ([71, 73, 75, 77, 85, 86].includes(code)) return '❄️';
+ if ([80, 81, 82].includes(code)) return '🌦️';
+ if ([95, 96, 99].includes(code)) return '⛈️';
+ return '☀️';
+ };
+
// Fetch Weather Data
useEffect(() => {
- if (view !== 'dashboard') return;
+ if (!user) return;
const fetchWeather = async () => {
try {
const locName = userProfile?.location || 'Lisboa, Portugal';
@@ -326,16 +338,24 @@ export default function App() {
if (geoData.results && geoData.results.length > 0) {
const { latitude, longitude, name, country } = geoData.results[0];
- const weatherRes = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t_weather=true&daily=temperature_2m_max,temperature_2m_min&timezone=auto`);
+ const weatherRes = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t_weather=true&daily=temperature_2m_max,temperature_2m_min,weathercode&timezone=auto`);
const weatherRaw = await weatherRes.json();
if (weatherRaw.current_weather && weatherRaw.daily) {
+ const dailyForecast = weatherRaw.daily.time.map((dateStr, idx) => ({
+ date: dateStr,
+ min: Math.round(weatherRaw.daily.temperature_2m_min[idx]),
+ max: Math.round(weatherRaw.daily.temperature_2m_max[idx]),
+ weathercode: weatherRaw.daily.weathercode[idx]
+ }));
+
setWeatherData({
name: `${name}, ${country || ''}`.replace(/,\s*$/, ''),
currentTemp: Math.round(weatherRaw.current_weather.temperature),
minTemp: Math.round(weatherRaw.daily.temperature_2m_min[0]),
maxTemp: Math.round(weatherRaw.daily.temperature_2m_max[0]),
- avgTemp: Math.round((weatherRaw.daily.temperature_2m_min[0] + weatherRaw.daily.temperature_2m_max[0]) / 2)
+ avgTemp: Math.round((weatherRaw.daily.temperature_2m_min[0] + weatherRaw.daily.temperature_2m_max[0]) / 2),
+ forecast: dailyForecast
});
}
}
@@ -344,7 +364,7 @@ export default function App() {
}
};
fetchWeather();
- }, [userProfile?.location, view]);
+ }, [userProfile?.location, user]);
// --- Lógicas de Negócio ---
@@ -491,9 +511,11 @@ export default function App() {
else if (ageFilter === 'older') matchesAge = days > 365;
}
- return matchesSearch && matchesCategory && matchesColor && matchesAge && matchesSection;
+ const matchesFavorite = !favoriteFilter || c.favorite;
+
+ return matchesSearch && matchesCategory && matchesColor && matchesAge && matchesSection && matchesFavorite;
});
- }, [baseClothes, searchTerm, categoryFilter, colorFilter, ageFilter, t, activeSectionFilter]);
+ }, [baseClothes, searchTerm, categoryFilter, colorFilter, ageFilter, t, activeSectionFilter, favoriteFilter]);
// Ações de Itens
const handleItemAction = async (action, item) => {
@@ -510,6 +532,15 @@ export default function App() {
}
};
+ const handleLookAction = async (action, look) => {
+ if (!user) return;
+ const docRef = doc(db, 'artifacts', appId, 'users', user.uid, 'looks', look.id || look);
+
+ switch (action) {
+ case 'favorite': await updateDoc(docRef, { favorite: !look.favorite }); break;
+ }
+ };
+
const saveItem = async (e) => {
e.preventDefault();
if (!user) return;
@@ -1103,12 +1134,11 @@ export default function App() {
{/* DASHBOARD */}
{view === 'dashboard' && (
-
+
{[
{ label: t('readyClothes'), val: activeClothes.length, icon: Shirt, col: 'primary' },
{ label: t('inLaundry'), val: laundryClothes.length, icon: Droplets, col: 'blue' },
{ label: t('myLooks'), val: looks.length, icon: Sparkles, col: 'purple' },
- { label: t('favorites'), val: activeClothes.filter(c => c.favorite).length, icon: Heart, col: 'rose' },
].map((s, i) => (
@@ -1190,7 +1220,7 @@ export default function App() {
className="flex items-center gap-3 px-8 py-4 bg-primary-600 text-white rounded-[2rem] font-black uppercase text-[10px] tracking-widest shadow-xl shadow-primary-600/30 hover:scale-105 transition-all"
>
{t('advancedFilters')}
- {(colorFilter || ageFilter !== 'any' || (categoryFilter !== 'Todos' && categoryFilter !== t('all'))) && (
+ {(colorFilter || favoriteFilter || ageFilter !== 'any' || (categoryFilter !== 'Todos' && categoryFilter !== t('all'))) && (
)}
@@ -1478,7 +1508,8 @@ export default function App() {
return item && item.color && item.color.includes(colorFilter);
});
}
- return matchesSection && matchesColor;
+ const matchesFavorite = !favoriteFilter || look.favorite;
+ return matchesSection && matchesColor && matchesFavorite;
});
const availableLooks = filteredBySectionLooks.filter(look =>
@@ -1517,6 +1548,13 @@ export default function App() {
{copiedLookId === look.id ? t('linkCopied') : t('share')}
+
@@ -1668,6 +1706,12 @@ export default function App() {
const dayLooks = getLooksForDayGlobal(ds);
const isToday = ds === todayStrGlobal;
const isWeek = plannerMode === 'week';
+
+ let dayWeather = null;
+ if (weatherAlerts && weatherData && weatherData.forecast) {
+ dayWeather = weatherData.forecast.find(f => f.date === ds);
+ }
+
return (
{ setPlannerPickerDate(ds); setShowPlannerPicker(true); }}
@@ -1675,7 +1719,14 @@ export default function App() {
style={{ minHeight: isWeek ? '180px' : '100px' }}
>
-
{date.getDate()}
+
+ {date.getDate()}
+ {dayWeather && (
+
+ {getWeatherEmoji(dayWeather.weathercode)}
+
+ )}
+
{isToday &&
{t('today')}}
{dayLooks.length > 0 ? (
@@ -2412,10 +2463,24 @@ export default function App() {
{availableColors.map(c =>
)}
+
+
+
+
+
-
+
diff --git a/src/lib/i18n.js b/src/lib/i18n.js
index a2ba7e3..5b41459 100644
--- a/src/lib/i18n.js
+++ b/src/lib/i18n.js
@@ -21,6 +21,7 @@ export const translations = {
dailyOutfit: "Outfit Diário",
noOutfitPlanned: "Nenhum Outfit Planeado",
goToPlanning: "Vá ao planeamento para adicionar",
+ onlyFavorites: "Apenas Favoritos",
logout: "Sair",
overview: "Visão Geral",
myCloset: "O Meu Armário",
@@ -223,6 +224,7 @@ export const translations = {
dailyOutfit: "Daily Outfit",
noOutfitPlanned: "No Outfit Planned",
goToPlanning: "Go to planning to add one",
+ onlyFavorites: "Favorites Only",
logout: "Logout",
overview: "Overview",
myCloset: "My Closet",
@@ -425,6 +427,7 @@ export const translations = {
dailyOutfit: "Outfit Diario",
noOutfitPlanned: "Sin Outfit Planeado",
goToPlanning: "Ve a planificación para añadir",
+ onlyFavorites: "Solo Favoritos",
logout: "Cerrar Sesión",
overview: "Visión General",
myCloset: "Mi Armario",
@@ -627,6 +630,7 @@ export const translations = {
dailyOutfit: "Tenue du Jour",
noOutfitPlanned: "Aucune Tenue Prévue",
goToPlanning: "Allez dans planification pour ajouter",
+ onlyFavorites: "Favoris Uniquement",
logout: "Déconnexion",
overview: "Vue d'ensemble",
myCloset: "Mon Placard",
@@ -829,6 +833,7 @@ export const translations = {
dailyOutfit: "Tägliches Outfit",
noOutfitPlanned: "Kein Outfit Geplant",
goToPlanning: "Gehen Sie zur Planung, um eins hinzuzufügen",
+ onlyFavorites: "Nur Favoriten",
logout: "Abmelden",
overview: "Übersicht",
myCloset: "Mein Schrank",