notifica
This commit is contained in:
84
src/App.jsx
84
src/App.jsx
@@ -57,6 +57,9 @@ export default function App() {
|
|||||||
|
|
||||||
// Estado para Definições
|
// Estado para Definições
|
||||||
const [notificationsEnabled, setNotificationsEnabled] = useState(true);
|
const [notificationsEnabled, setNotificationsEnabled] = useState(true);
|
||||||
|
const [dailyOutfitTime, setDailyOutfitTime] = useState('08:00');
|
||||||
|
const [dailyOutfitNotifEnabled, setDailyOutfitNotifEnabled] = useState(false);
|
||||||
|
const [lastNotifiedDate, setLastNotifiedDate] = useState('');
|
||||||
const [weatherAlerts, setWeatherAlerts] = useState(true);
|
const [weatherAlerts, setWeatherAlerts] = useState(true);
|
||||||
const [language, setLanguage] = useState('PT');
|
const [language, setLanguage] = useState('PT');
|
||||||
const [showLangModal, setShowLangModal] = useState(false);
|
const [showLangModal, setShowLangModal] = useState(false);
|
||||||
@@ -172,6 +175,23 @@ export default function App() {
|
|||||||
saveUserSetting('notificationsEnabled', newVal);
|
saveUserSetting('notificationsEnabled', newVal);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDailyOutfitNotifToggle = async (newVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
if ('Notification' in window) {
|
||||||
|
const permission = await Notification.requestPermission();
|
||||||
|
if (permission !== 'granted') {
|
||||||
|
alert('Permissão recusada. Ative as notificações no browser para usar esta funcionalidade.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert('O seu browser não suporta notificações.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setDailyOutfitNotifEnabled(newVal);
|
||||||
|
saveUserSetting('dailyOutfitNotifEnabled', newVal);
|
||||||
|
};
|
||||||
|
|
||||||
const handleWeatherAlertsToggle = (newVal) => {
|
const handleWeatherAlertsToggle = (newVal) => {
|
||||||
setWeatherAlerts(newVal);
|
setWeatherAlerts(newVal);
|
||||||
saveUserSetting('weatherAlerts', newVal);
|
saveUserSetting('weatherAlerts', newVal);
|
||||||
@@ -370,6 +390,9 @@ export default function App() {
|
|||||||
if (data.settings.darkMode !== undefined) setDarkMode(data.settings.darkMode);
|
if (data.settings.darkMode !== undefined) setDarkMode(data.settings.darkMode);
|
||||||
if (data.settings.theme !== undefined) setTheme(data.settings.theme);
|
if (data.settings.theme !== undefined) setTheme(data.settings.theme);
|
||||||
if (data.settings.notificationsEnabled !== undefined) setNotificationsEnabled(data.settings.notificationsEnabled);
|
if (data.settings.notificationsEnabled !== undefined) setNotificationsEnabled(data.settings.notificationsEnabled);
|
||||||
|
if (data.settings.dailyOutfitTime !== undefined) setDailyOutfitTime(data.settings.dailyOutfitTime);
|
||||||
|
if (data.settings.dailyOutfitNotifEnabled !== undefined) setDailyOutfitNotifEnabled(data.settings.dailyOutfitNotifEnabled);
|
||||||
|
if (data.settings.lastNotifiedDate !== undefined) setLastNotifiedDate(data.settings.lastNotifiedDate);
|
||||||
if (data.settings.weatherAlerts !== undefined) setWeatherAlerts(data.settings.weatherAlerts);
|
if (data.settings.weatherAlerts !== undefined) setWeatherAlerts(data.settings.weatherAlerts);
|
||||||
if (data.settings.cardSize !== undefined) setCardSize(data.settings.cardSize);
|
if (data.settings.cardSize !== undefined) setCardSize(data.settings.cardSize);
|
||||||
if (data.settings.defaultPage !== undefined) {
|
if (data.settings.defaultPage !== undefined) {
|
||||||
@@ -630,6 +653,45 @@ export default function App() {
|
|||||||
};
|
};
|
||||||
const dailyLooks = getLooksForDayGlobal(todayStrGlobal);
|
const dailyLooks = getLooksForDayGlobal(todayStrGlobal);
|
||||||
|
|
||||||
|
// Efeito para notificação diária
|
||||||
|
useEffect(() => {
|
||||||
|
if (!user || !dailyOutfitNotifEnabled || !dailyOutfitTime) return;
|
||||||
|
|
||||||
|
const intervalId = setInterval(() => {
|
||||||
|
const now = new Date();
|
||||||
|
const currentHour = String(now.getHours()).padStart(2, '0');
|
||||||
|
const currentMinute = String(now.getMinutes()).padStart(2, '0');
|
||||||
|
const currentTime = `${currentHour}:${currentMinute}`;
|
||||||
|
|
||||||
|
const todayStr = `${now.getFullYear()}-${String(now.getMonth()+1).padStart(2,'0')}-${String(now.getDate()).padStart(2,'0')}`;
|
||||||
|
|
||||||
|
if (currentTime === dailyOutfitTime && lastNotifiedDate !== todayStr) {
|
||||||
|
const todaysLooks = getLooksForDayGlobal(todayStr);
|
||||||
|
if (todaysLooks.length > 0) {
|
||||||
|
const mainLook = todaysLooks[0];
|
||||||
|
if ('Notification' in window && Notification.permission === 'granted') {
|
||||||
|
navigator.serviceWorker?.getRegistration().then(reg => {
|
||||||
|
const title = 'MyCloset - Outfit Diário';
|
||||||
|
const options = {
|
||||||
|
body: `O seu outfit planeado "${mainLook.name}" está pronto para hoje!`,
|
||||||
|
icon: '/favicon.ico'
|
||||||
|
};
|
||||||
|
if (reg) {
|
||||||
|
reg.showNotification(title, options);
|
||||||
|
} else {
|
||||||
|
new Notification(title, options);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setLastNotifiedDate(todayStr);
|
||||||
|
saveUserSetting('lastNotifiedDate', todayStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 30000); // Verifica a cada 30 segundos
|
||||||
|
|
||||||
|
return () => clearInterval(intervalId);
|
||||||
|
}, [user, dailyOutfitNotifEnabled, dailyOutfitTime, lastNotifiedDate, outfitPlans, looks]);
|
||||||
|
|
||||||
const baseClothes = view === 'wishlist' ? wishlistClothes : activeClothes;
|
const baseClothes = view === 'wishlist' ? wishlistClothes : activeClothes;
|
||||||
|
|
||||||
const availableColors = useMemo(() => {
|
const availableColors = useMemo(() => {
|
||||||
@@ -2566,6 +2628,28 @@ export default function App() {
|
|||||||
<div className={`w-6 h-6 rounded-full bg-white absolute top-1 transition-all ${notificationsEnabled ? 'left-7' : 'left-1'}`}></div>
|
<div className={`w-6 h-6 rounded-full bg-white absolute top-1 transition-all ${notificationsEnabled ? 'left-7' : 'left-1'}`}></div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4">
|
||||||
|
<div>
|
||||||
|
<p className="font-bold text-inherit flex items-center gap-2">Notificação do Outfit Diário</p>
|
||||||
|
<p className="text-[10px] uppercase tracking-widest opacity-50 text-inherit">Receber notificação com o outfit planeado à hora marcada</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-4 w-full sm:w-auto justify-between sm:justify-end">
|
||||||
|
{dailyOutfitNotifEnabled && (
|
||||||
|
<input
|
||||||
|
type="time"
|
||||||
|
value={dailyOutfitTime}
|
||||||
|
onChange={(e) => {
|
||||||
|
setDailyOutfitTime(e.target.value);
|
||||||
|
saveUserSetting('dailyOutfitTime', e.target.value);
|
||||||
|
}}
|
||||||
|
className={`px-3 py-1.5 rounded-xl text-sm outline-none border font-bold ${darkMode ? 'bg-gray-800 border-gray-700 text-white' : 'bg-white border-gray-200 text-gray-900'}`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<button onClick={() => handleDailyOutfitNotifToggle(!dailyOutfitNotifEnabled)} className={`w-14 h-8 rounded-full transition-colors relative shrink-0 ${dailyOutfitNotifEnabled ? 'bg-primary-600' : 'bg-gray-200'}`}>
|
||||||
|
<div className={`w-6 h-6 rounded-full bg-white absolute top-1 transition-all ${dailyOutfitNotifEnabled ? 'left-7' : 'left-1'}`}></div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="font-bold text-inherit flex items-center gap-2">{t('weatherAlerts')}</p>
|
<p className="font-bold text-inherit flex items-center gap-2">{t('weatherAlerts')}</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user