notificacoes

This commit is contained in:
2026-05-04 22:28:44 +01:00
parent daaecd97d2
commit 54a7ce0e8e
2 changed files with 78 additions and 15 deletions

View File

@@ -1794,35 +1794,88 @@ export default function App() {
{showNotificationsModal && ( {showNotificationsModal && (
<div className="fixed inset-0 z-[200] flex items-center justify-center bg-black/60 backdrop-blur-sm p-6" onClick={() => setShowNotificationsModal(false)}> <div className="fixed inset-0 z-[200] flex items-center justify-center bg-black/60 backdrop-blur-sm p-6" onClick={() => setShowNotificationsModal(false)}>
<Card className="w-full max-w-md p-8 animate-in zoom-in-95 flex flex-col max-h-[80vh]" darkMode={darkMode} onClick={e => e.stopPropagation()}> <Card className="w-full max-w-md p-8 animate-in zoom-in-95 flex flex-col max-h-[80vh]" darkMode={darkMode} onClick={e => e.stopPropagation()}>
<div className="flex items-center justify-between mb-8"> {/* Header */}
<h3 className="text-2xl font-black text-inherit flex items-center gap-3"><Bell size={24} className="text-primary-600" /> {t('notificationsModal')}</h3> <div className="flex items-center justify-between mb-6">
<button onClick={() => setShowNotificationsModal(false)} className="p-2 bg-gray-100 dark:bg-gray-800 rounded-full hover:scale-110 transition-all text-inherit"><X size={20} /></button> <div>
<h3 className="text-2xl font-black text-inherit flex items-center gap-3">
<Bell size={24} className="text-primary-600" /> {t('notificationsModal')}
</h3>
{notifications.filter(n => !n.read).length > 0 && (
<p className="text-[10px] font-black uppercase tracking-widest text-primary-600 mt-1">
{notifications.filter(n => !n.read).length} {language === 'PT' ? 'nova(s)' : language === 'EN' ? 'new' : language === 'ES' ? 'nueva(s)' : language === 'FR' ? 'nouvelle(s)' : 'neue'}
</p>
)}
</div>
<div className="flex items-center gap-2">
{notifications.filter(n => !n.read).length > 0 && (
<button
onClick={async () => {
const batch = writeBatch(db);
notifications.filter(n => !n.read).forEach(n => {
const ref = doc(db, 'artifacts', appId, 'users', user.uid, 'notifications', n.id);
batch.update(ref, { read: true });
});
await batch.commit();
}}
className="text-[9px] font-black uppercase tracking-widest text-primary-600 hover:underline px-3 py-2 hover:bg-primary-50 dark:hover:bg-primary-900/20 rounded-xl transition-all"
>
{t('markAllRead')}
</button>
)}
<button onClick={() => setShowNotificationsModal(false)} className="p-2 bg-gray-100 dark:bg-gray-800 rounded-full hover:scale-110 transition-all text-inherit"><X size={20} /></button>
</div>
</div> </div>
<div className="flex-1 overflow-y-auto space-y-4 custom-scrollbar">
{/* Lista */}
<div className="flex-1 overflow-y-auto space-y-3 custom-scrollbar">
{notifications.length === 0 ? ( {notifications.length === 0 ? (
<div className="py-12 text-center opacity-30 font-black uppercase tracking-[0.3em] text-sm">{t('noNotifications')}</div> <div className="py-16 text-center flex flex-col items-center gap-4 opacity-30">
<Bell size={40} />
<span className="font-black uppercase tracking-[0.3em] text-sm">{t('noNotifications')}</span>
</div>
) : notifications.map(notif => ( ) : notifications.map(notif => (
<div key={notif.id} className={`p-4 rounded-2xl flex items-start gap-4 ${!notif.read ? 'bg-primary-50 dark:bg-primary-900/20' : 'bg-gray-50 dark:bg-gray-800'}`}> <div
<div className={`p-3 rounded-full ${!notif.read ? 'bg-primary-100 text-primary-600 dark:bg-primary-900/40 dark:text-primary-400' : 'bg-gray-200 text-gray-500 dark:bg-gray-700'}`}> key={notif.id}
<Bell size={20} /> className={`p-4 rounded-2xl flex items-start gap-4 transition-all ${
!notif.read
? 'bg-primary-50 dark:bg-primary-900/20 border border-primary-100 dark:border-primary-800/40'
: (darkMode ? 'bg-gray-800/60' : 'bg-gray-50')
}`}
>
{/* Ícone da Notificação */}
<div className={`shrink-0 w-12 h-12 flex items-center justify-center rounded-2xl text-xl shadow-sm ${
!notif.read
? 'bg-primary-100 dark:bg-primary-900/50'
: (darkMode ? 'bg-gray-700' : 'bg-gray-200')
}`}>
{notif.type === 'look_copied' ? '✂️' : <Bell size={20} />}
</div> </div>
<div className="flex-1">
<p className="font-bold text-sm text-inherit"> {/* Conteúdo */}
<div className="flex-1 min-w-0">
<p className="font-bold text-sm leading-snug text-inherit">
{notif.type === 'look_copied' && ( {notif.type === 'look_copied' && (
<>O utilizador <span className="text-primary-600">{notif.copiedByEmail}</span> guardou o seu look "{notif.lookName}" {t('inTheirCloset')}</> <>
<span className="text-primary-600 font-black">{notif.copiedByEmail}</span>
{' '}{t('lookCopiedBy')}{' '}
<span className="italic">"{notif.lookName}"</span>
</>
)} )}
</p> </p>
<p className="text-[10px] uppercase font-black tracking-widest opacity-40 mt-2"> <p className="text-[10px] uppercase font-black tracking-widest opacity-40 mt-1.5">
{new Date(notif.createdAt).toLocaleDateString()} às {new Date(notif.createdAt).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})} {new Date(notif.createdAt).toLocaleDateString()} às {new Date(notif.createdAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
</p> </p>
</div> </div>
{/* Botão marcar como lida */}
{!notif.read && ( {!notif.read && (
<button <button
onClick={async () => { onClick={async () => {
const docRef = doc(db, 'artifacts', appId, 'users', user.uid, 'notifications', notif.id); const docRef = doc(db, 'artifacts', appId, 'users', user.uid, 'notifications', notif.id);
await updateDoc(docRef, { read: true }); await updateDoc(docRef, { read: true });
}} }}
className="p-2 text-primary-600 hover:bg-primary-100 dark:hover:bg-primary-900/40 rounded-xl" className="shrink-0 p-2 text-primary-600 hover:bg-primary-100 dark:hover:bg-primary-900/40 rounded-xl transition-all"
title="Marcar como lida"
> >
<Check size={16} /> <Check size={16} />
</button> </button>

View File

@@ -149,6 +149,8 @@ export const translations = {
sendMessage: "Enviar Mensagem", sendMessage: "Enviar Mensagem",
notificationsModal: "Notificações", notificationsModal: "Notificações",
noNotifications: "Sem Notificações", noNotifications: "Sem Notificações",
markAllRead: "Marcar todas como lidas",
lookCopiedBy: "copiou o seu look",
userSavedLook: "guardou o seu look", userSavedLook: "guardou o seu look",
inTheirCloset: "no armário dele!", inTheirCloset: "no armário dele!",
sharedLookTitle: "Look Partilhado", sharedLookTitle: "Look Partilhado",
@@ -321,6 +323,8 @@ export const translations = {
sendMessage: "Send Message", sendMessage: "Send Message",
notificationsModal: "Notifications", notificationsModal: "Notifications",
noNotifications: "No Notifications", noNotifications: "No Notifications",
markAllRead: "Mark all as read",
lookCopiedBy: "copied your look",
userSavedLook: "saved your look", userSavedLook: "saved your look",
inTheirCloset: "in their closet!", inTheirCloset: "in their closet!",
sharedLookTitle: "Shared Look", sharedLookTitle: "Shared Look",
@@ -493,6 +497,8 @@ export const translations = {
sendMessage: "Enviar Mensaje", sendMessage: "Enviar Mensaje",
notificationsModal: "Notificaciones", notificationsModal: "Notificaciones",
noNotifications: "Sin Notificaciones", noNotifications: "Sin Notificaciones",
markAllRead: "Marcar todas como leídas",
lookCopiedBy: "copió tu look",
userSavedLook: "guardó tu look", userSavedLook: "guardó tu look",
inTheirCloset: "en su armario!", inTheirCloset: "en su armario!",
sharedLookTitle: "Look Compartido", sharedLookTitle: "Look Compartido",
@@ -665,6 +671,8 @@ export const translations = {
sendMessage: "Envoyer le Message", sendMessage: "Envoyer le Message",
notificationsModal: "Notifications", notificationsModal: "Notifications",
noNotifications: "Aucune Notification", noNotifications: "Aucune Notification",
markAllRead: "Tout marquer comme lu",
lookCopiedBy: "a copié votre look",
userSavedLook: "a sauvegardé votre look", userSavedLook: "a sauvegardé votre look",
inTheirCloset: "dans son placard !", inTheirCloset: "dans son placard !",
sharedLookTitle: "Look Partagé", sharedLookTitle: "Look Partagé",
@@ -837,6 +845,8 @@ export const translations = {
sendMessage: "Nachricht Senden", sendMessage: "Nachricht Senden",
notificationsModal: "Benachrichtigungen", notificationsModal: "Benachrichtigungen",
noNotifications: "Keine Benachrichtigungen", noNotifications: "Keine Benachrichtigungen",
markAllRead: "Alle als gelesen markieren",
lookCopiedBy: "hat deinen Look kopiert",
userSavedLook: "hat deinen Look gespeichert", userSavedLook: "hat deinen Look gespeichert",
inTheirCloset: "in seinem Schrank!", inTheirCloset: "in seinem Schrank!",
sharedLookTitle: "Geteilter Look", sharedLookTitle: "Geteilter Look",