This commit is contained in:
2026-05-11 14:59:20 +01:00
parent 95bb34b46d
commit 90dec0d963
7 changed files with 3622 additions and 3382 deletions

3324
dist/assets/index-0fNqCu5T.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
dist/assets/index-D1z9PPLp.css vendored Normal file

File diff suppressed because one or more lines are too long

4
dist/index.html vendored
View File

@@ -4,8 +4,8 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>MyCloset</title> <title>MyCloset</title>
<script type="module" crossorigin src="/assets/index-D-Q7LD7U.js"></script> <script type="module" crossorigin src="/assets/index-0fNqCu5T.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CvAWiRXE.css"> <link rel="stylesheet" crossorigin href="/assets/index-D1z9PPLp.css">
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

View File

@@ -7,7 +7,7 @@ import {
PanelLeftClose, PanelLeftOpen, Sparkles, CloudSun, PanelLeftClose, PanelLeftOpen, Sparkles, CloudSun,
ArrowRight, Droplets, CheckCircle2, PieChart, History, ArrowRight, Droplets, CheckCircle2, PieChart, History,
X, Download, Bell, Globe, Filter, ShoppingBag, Share2, X, Download, Bell, Globe, Filter, ShoppingBag, Share2,
FolderOpen, Tag, Link, Calendar, ChevronLeft, ChevronRight FolderOpen, Tag, Link, Calendar, ChevronLeft, ChevronRight, Users
} from 'lucide-react'; } from 'lucide-react';
import { import {
@@ -16,7 +16,7 @@ import {
} from 'firebase/auth'; } from 'firebase/auth';
import { import {
collection, doc, onSnapshot, addDoc, updateDoc, collection, doc, onSnapshot, addDoc, updateDoc,
deleteDoc, writeBatch, setDoc, getDoc, query, where deleteDoc, writeBatch, setDoc, getDoc, query, where, getDocs, collectionGroup
} from 'firebase/firestore'; } from 'firebase/firestore';
import { auth, db, appId } from './lib/firebase'; import { auth, db, appId } from './lib/firebase';
@@ -64,6 +64,15 @@ export default function App() {
const [cardSize, setCardSize] = useState('large'); const [cardSize, setCardSize] = useState('large');
const [defaultPage, setDefaultPage] = useState('dashboard'); const [defaultPage, setDefaultPage] = useState('dashboard');
const [weatherData, setWeatherData] = useState(null); const [weatherData, setWeatherData] = useState(null);
const [isPrivate, setIsPrivate] = useState(false);
const [userStatus, setUserStatus] = useState('online');
// Estado da Comunidade
const [communitySearchTerm, setCommunitySearchTerm] = useState('');
const [communityUsers, setCommunityUsers] = useState([]);
const [selectedCommunityUser, setSelectedCommunityUser] = useState(null);
const [selectedUserClothes, setSelectedUserClothes] = useState([]);
const [selectedUserLooks, setSelectedUserLooks] = useState([]);
// Estado para Partilha de Looks // Estado para Partilha de Looks
const sharedLookRef = useRef(''); const sharedLookRef = useRef('');
@@ -127,6 +136,11 @@ export default function App() {
await setDoc(profileDoc, { await setDoc(profileDoc, {
settings: { [key]: value } settings: { [key]: value }
}, { merge: true }); }, { merge: true });
if (key === 'isPrivate') {
const publicProfileDoc = doc(db, 'artifacts', appId, 'publicProfiles', user.uid);
await setDoc(publicProfileDoc, { isPrivate: value, uid: user.uid }, { merge: true });
}
} catch (err) { } catch (err) {
console.error('Error saving setting:', err); console.error('Error saving setting:', err);
} }
@@ -168,6 +182,21 @@ export default function App() {
saveUserSetting('defaultPage', newVal); saveUserSetting('defaultPage', newVal);
}; };
const handlePrivacyToggle = (newVal) => {
setIsPrivate(newVal);
saveUserSetting('isPrivate', newVal);
};
const toggleStatus = (e) => {
e.stopPropagation();
e.preventDefault();
const statuses = ['online', 'away', 'offline'];
const currentIndex = statuses.indexOf(userStatus);
const nextStatus = statuses[(currentIndex + 1) % statuses.length];
setUserStatus(nextStatus);
saveUserSetting('status', nextStatus);
};
// Buscar o look partilhado pelo link // Buscar o look partilhado pelo link
const fetchSharedLook = async (lookId) => { const fetchSharedLook = async (lookId) => {
if (!lookId) return; if (!lookId) return;
@@ -328,6 +357,8 @@ export default function App() {
if (data.settings.defaultPage !== undefined) { if (data.settings.defaultPage !== undefined) {
setDefaultPage(data.settings.defaultPage === 'planning' ? 'planner' : data.settings.defaultPage); setDefaultPage(data.settings.defaultPage === 'planning' ? 'planner' : data.settings.defaultPage);
} }
if (data.settings.isPrivate !== undefined) setIsPrivate(data.settings.isPrivate);
if (data.settings.status !== undefined) setUserStatus(data.settings.status);
} }
} }
else setUserProfile({}); else setUserProfile({});
@@ -393,6 +424,68 @@ export default function App() {
fetchWeather(); fetchWeather();
}, [userProfile?.location, user]); }, [userProfile?.location, user]);
// Sync do perfil público para a Comunidade
useEffect(() => {
if (user && userProfile) {
const publicProfileDoc = doc(db, 'artifacts', appId, 'publicProfiles', user.uid);
setDoc(publicProfileDoc, {
uid: user.uid,
username: userProfile.username || '',
fullName: userProfile.fullName || '',
avatar: userProfile.avatar || null,
isPrivate: userProfile.settings?.isPrivate || false
}, { merge: true }).catch(console.error);
}
}, [user, userProfile?.username, userProfile?.fullName, userProfile?.avatar, userProfile?.settings?.isPrivate]);
// Fetch utilizadores da comunidade
useEffect(() => {
if (view !== 'community') return;
const fetchUsers = async () => {
try {
const profilesRef = collection(db, 'artifacts', appId, 'publicProfiles');
const snap = await getDocs(profilesRef);
const users = snap.docs.map(d => d.data()).filter(u => u.uid !== user?.uid);
if (communitySearchTerm.trim()) {
let term = communitySearchTerm.toLowerCase();
if (term.startsWith('@')) term = term.substring(1);
setCommunityUsers(users.filter(u =>
u.username && u.username.toLowerCase().includes(term)
));
} else {
setCommunityUsers(users);
}
} catch (err) {
console.error("Erro ao buscar comunidade", err);
}
};
fetchUsers();
}, [view, communitySearchTerm, user?.uid]);
const viewCommunityUser = async (targetUser) => {
setSelectedCommunityUser(targetUser);
if (targetUser.isPrivate) {
setSelectedUserClothes([]);
setSelectedUserLooks([]);
return;
}
try {
// Roupas
const clothesCol = collection(db, 'artifacts', appId, 'users', targetUser.uid, 'clothes');
const snapClothes = await getDocs(clothesCol);
setSelectedUserClothes(snapClothes.docs.map(d => ({id: d.id, ...d.data()})).filter(c => c.status !== 'trash'));
// Looks
const looksCol = collection(db, 'artifacts', appId, 'users', targetUser.uid, 'looks');
const snapLooks = await getDocs(looksCol);
setSelectedUserLooks(snapLooks.docs.map(d => ({id: d.id, ...d.data()})));
} catch (err) {
console.error("Erro ao carregar perfil do utilizador", err);
}
};
// --- Lógicas de Negócio --- // --- Lógicas de Negócio ---
const activeClothes = useMemo(() => clothes.filter(c => c.status === 'active'), [clothes]); const activeClothes = useMemo(() => clothes.filter(c => c.status === 'active'), [clothes]);
@@ -961,6 +1054,23 @@ export default function App() {
const fd = new FormData(e.target); const fd = new FormData(e.target);
try { try {
let usernameInput = (fd.get('username') || '').trim();
if (usernameInput.startsWith('@')) usernameInput = usernameInput.substring(1);
if (usernameInput) {
// Verificar se o nome de utilizador já existe
const publicProfilesRef = collection(db, 'artifacts', appId, 'publicProfiles');
const q = query(publicProfilesRef, where('username', '==', usernameInput));
const snap = await getDocs(q);
const isTaken = snap.docs.some(doc => doc.data().uid !== user.uid);
if (isTaken) {
alert(t('usernameTaken') || 'Este nome de utilizador já está em uso.');
setSavingProfile(false);
return;
}
}
const profileDoc = doc(db, 'artifacts', appId, 'users', user.uid, 'profile', 'data'); const profileDoc = doc(db, 'artifacts', appId, 'users', user.uid, 'profile', 'data');
const dobDay = fd.get('dobDay'); const dobDay = fd.get('dobDay');
const dobMonth = fd.get('dobMonth'); const dobMonth = fd.get('dobMonth');
@@ -972,7 +1082,7 @@ export default function App() {
// Perform optimistc setDoc without blocking the UI // Perform optimistc setDoc without blocking the UI
setDoc(profileDoc, { setDoc(profileDoc, {
username: fd.get('username') || '', username: usernameInput,
fullName: fd.get('fullName') || '', fullName: fd.get('fullName') || '',
dob: dob, dob: dob,
bio: fd.get('bio') || '', bio: fd.get('bio') || '',
@@ -1098,6 +1208,7 @@ export default function App() {
{ id: 'laundry', label: t('laundry'), icon: Droplets }, { id: 'laundry', label: t('laundry'), icon: Droplets },
{ id: 'outfits', label: t('outfits'), icon: Sparkles }, { id: 'outfits', label: t('outfits'), icon: Sparkles },
{ id: 'planner', label: t('planning'), icon: Calendar }, { id: 'planner', label: t('planning'), icon: Calendar },
{ id: 'community', label: t('community'), icon: Users },
{ id: 'settings', label: t('settings'), icon: Settings }, { id: 'settings', label: t('settings'), icon: Settings },
].map(item => ( ].map(item => (
<button <button
@@ -1112,7 +1223,7 @@ export default function App() {
</nav> </nav>
<div className="mt-auto pt-10 border-t border-inherit"> <div className="mt-auto pt-10 border-t border-inherit">
<button onClick={() => setView('profile')} className="w-full flex items-center gap-4 mb-8 px-2 text-left hover:bg-gray-100 dark:hover:bg-gray-800 py-3 rounded-2xl transition-all cursor-pointer"> <div onClick={() => setView('profile')} className="w-full flex items-center gap-4 mb-8 px-2 text-left hover:bg-gray-100 dark:hover:bg-gray-800 py-3 rounded-2xl transition-all cursor-pointer">
<div className={`w-12 h-12 rounded-2xl shrink-0 flex items-center justify-center font-black text-white shadow-xl overflow-hidden ${darkMode ? 'bg-primary-500' : 'bg-primary-600'}`}> <div className={`w-12 h-12 rounded-2xl shrink-0 flex items-center justify-center font-black text-white shadow-xl overflow-hidden ${darkMode ? 'bg-primary-500' : 'bg-primary-600'}`}>
{userProfile?.avatar ? ( {userProfile?.avatar ? (
<img src={userProfile.avatar} className="w-full h-full object-cover" alt="Avatar" /> <img src={userProfile.avatar} className="w-full h-full object-cover" alt="Avatar" />
@@ -1120,11 +1231,15 @@ export default function App() {
(userProfile?.fullName?.[0] || userProfile?.username?.[0] || user?.email?.[0] || 'U').toUpperCase() (userProfile?.fullName?.[0] || userProfile?.username?.[0] || user?.email?.[0] || 'U').toUpperCase()
)} )}
</div> </div>
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0 text-left">
<p className="text-sm font-black truncate">{userProfile?.username || userProfile?.fullName || user?.email?.split('@')[0] || t('userTitle')}</p> <p className="text-sm font-black truncate text-inherit">@{userProfile?.username || user?.email?.split('@')[0] || t('userTitle')}</p>
<Badge variant="success">{t('online')}</Badge> <div onClick={toggleStatus} className="inline-block mt-1 cursor-pointer hover:opacity-80 transition-opacity" title="Mudar estado">
<Badge variant={userStatus === 'online' ? 'success' : (userStatus === 'away' ? 'warning' : 'default')}>
{t(userStatus)}
</Badge>
</div>
</div>
</div> </div>
</button>
<button onClick={() => { <button onClick={() => {
// Limpar dados locais antes de fazer logout // Limpar dados locais antes de fazer logout
if (user?.uid) localStorage.removeItem(`app-theme-${user.uid}`); if (user?.uid) localStorage.removeItem(`app-theme-${user.uid}`);
@@ -1152,6 +1267,7 @@ export default function App() {
{view === 'laundry' && t('laundry')} {view === 'laundry' && t('laundry')}
{view === 'outfits' && t('outfitsAndStyle')} {view === 'outfits' && t('outfitsAndStyle')}
{view === 'planner' && t('planning')} {view === 'planner' && t('planning')}
{view === 'community' && t('community')}
{view === 'settings' && t('settings')} {view === 'settings' && t('settings')}
{view === 'profile' && t('profileInfo')} {view === 'profile' && t('profileInfo')}
</h2> </h2>
@@ -2011,7 +2127,13 @@ export default function App() {
<h3 className="text-xl font-black mb-6 flex items-center gap-3 text-inherit"><UserCircle className="text-primary-600" /> {t('profileInfo')}</h3> <h3 className="text-xl font-black mb-6 flex items-center gap-3 text-inherit"><UserCircle className="text-primary-600" /> {t('profileInfo')}</h3>
<form key={`${userProfile?.username}-${userProfile?.fullName}-${userProfile?.dob}-${userProfile?.bio}-${userProfile?.location}`} onSubmit={saveProfile} className="space-y-6"> <form key={`${userProfile?.username}-${userProfile?.fullName}-${userProfile?.dob}-${userProfile?.bio}-${userProfile?.location}`} onSubmit={saveProfile} className="space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6"> <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<Input label={t('username')} name="username" defaultValue={userProfile?.username || ''} placeholder="Ex: amari" /> <div className="space-y-2 relative">
<label className="text-[10px] font-black uppercase opacity-40 tracking-widest ml-1 text-inherit">{t('username')}</label>
<div className="relative">
<span className="absolute left-4 top-1/2 -translate-y-1/2 opacity-40 font-black">@</span>
<input name="username" defaultValue={userProfile?.username || ''} placeholder="amari" className={`w-full p-4 pl-10 rounded-xl border-none outline-none focus:ring-2 focus:ring-primary-500 font-bold ${darkMode ? 'bg-gray-800 text-white' : 'bg-gray-50'}`} />
</div>
</div>
<Input label={t('fullName')} name="fullName" defaultValue={userProfile?.fullName || ''} placeholder="Ex: Amari Rodriguez" /> <Input label={t('fullName')} name="fullName" defaultValue={userProfile?.fullName || ''} placeholder="Ex: Amari Rodriguez" />
<div className="space-y-2"> <div className="space-y-2">
<label className="text-[10px] font-black uppercase opacity-40 tracking-widest ml-1 text-inherit">{t('dob')} {t('optional')}</label> <label className="text-[10px] font-black uppercase opacity-40 tracking-widest ml-1 text-inherit">{t('dob')} {t('optional')}</label>
@@ -2041,6 +2163,101 @@ export default function App() {
</div> </div>
)} )}
{/* COMUNIDADE */}
{view === 'community' && (
<div className="max-w-7xl mx-auto space-y-12 animate-in fade-in duration-700 pb-20">
{!selectedCommunityUser ? (
<>
<div className="relative mb-8">
<Search className="absolute left-6 top-1/2 -translate-y-1/2 opacity-40 text-inherit" size={24} />
<input
type="text"
placeholder={t('searchUsers')}
value={communitySearchTerm}
onChange={(e) => setCommunitySearchTerm(e.target.value)}
className={`w-full p-6 pl-16 rounded-3xl font-black text-lg outline-none focus:ring-4 focus:ring-primary-500/20 transition-all shadow-xl shadow-black/5 text-inherit ${darkMode ? 'bg-gray-800' : 'bg-white'}`}
/>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{communityUsers.length === 0 ? (
<div className="col-span-full text-center py-12 opacity-50 text-inherit font-black text-xl">
{t('noUsersFound')}
</div>
) : (
communityUsers.map(u => (
<Card key={u.uid} className="p-6 cursor-pointer hover:scale-105 transition-transform" darkMode={darkMode} onClick={() => viewCommunityUser(u)}>
<div className="flex items-center gap-4 text-inherit">
<div className="w-16 h-16 rounded-2xl bg-primary-600 text-white flex items-center justify-center font-black text-2xl overflow-hidden">
{u.avatar ? <img src={u.avatar} className="w-full h-full object-cover" alt="Avatar"/> : <span>{(u.fullName?.[0] || u.username?.[0] || 'U').toUpperCase()}</span>}
</div>
<div>
<h3 className="font-black text-lg">{u.fullName || t('userTitle')}</h3>
<p className="text-sm opacity-60 font-bold">@{u.username || 'user'}</p>
</div>
</div>
</Card>
))
)}
</div>
</>
) : (
<div className="space-y-8">
<button onClick={() => setSelectedCommunityUser(null)} className="flex items-center gap-2 opacity-60 hover:opacity-100 transition-opacity font-black text-inherit uppercase text-xs tracking-widest">
<ChevronLeft size={16} /> Voltar
</button>
<Card className="p-8 border-primary-100 relative overflow-hidden" darkMode={darkMode}>
<div className="flex items-center gap-8 relative z-10 text-inherit">
<div className="w-24 h-24 rounded-[2.5rem] bg-primary-600 text-white flex items-center justify-center font-black text-4xl overflow-hidden">
{selectedCommunityUser.avatar ? <img src={selectedCommunityUser.avatar} className="w-full h-full object-cover" alt="Avatar"/> : <span>{(selectedCommunityUser.fullName?.[0] || selectedCommunityUser.username?.[0] || 'U').toUpperCase()}</span>}
</div>
<div>
<h3 className="text-3xl font-black tracking-tighter">{selectedCommunityUser.fullName || t('userTitle')}</h3>
<p className="opacity-60 font-bold text-sm">@{selectedCommunityUser.username || 'user'}</p>
</div>
</div>
</Card>
{selectedCommunityUser.isPrivate ? (
<div className="text-center py-20 opacity-50 font-black text-2xl text-inherit">
<ShieldAlert className="w-16 h-16 mx-auto mb-4 opacity-50" />
{t('isPrivateUser')}
</div>
) : (
<div className="space-y-12 text-inherit">
<div>
<h3 className="text-xl font-black mb-6 uppercase tracking-widest text-[11px] opacity-50">{t('userOutfits')} ({selectedUserLooks.length})</h3>
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-6">
{selectedUserLooks.map(look => (
<div key={look.id} className="group relative aspect-[3/4] rounded-[2rem] overflow-hidden bg-gray-100 dark:bg-gray-800 cursor-pointer shadow-lg">
{look.items && look.items[0] && selectedUserClothes.find(c => c.id === look.items[0]) && (
<img src={selectedUserClothes.find(c => c.id === look.items[0]).imageUrl} className="w-full h-full object-cover group-hover:scale-110 transition-transform duration-700" alt="Look" />
)}
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent flex items-end p-6">
<span className="text-white font-black text-sm">{look.name}</span>
</div>
</div>
))}
</div>
</div>
<div>
<h3 className="text-xl font-black mb-6 uppercase tracking-widest text-[11px] opacity-50">{t('userCloset')} ({selectedUserClothes.length})</h3>
<div className="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-5 lg:grid-cols-6 gap-4">
{selectedUserClothes.map(item => (
<div key={item.id} className="aspect-square rounded-2xl overflow-hidden bg-gray-100 dark:bg-gray-800 shadow-md">
<img src={item.imageUrl} className="w-full h-full object-cover" alt="Item" />
</div>
))}
</div>
</div>
</div>
)}
</div>
)}
</div>
)}
{/* DEFINIÇÕES */} {/* DEFINIÇÕES */}
{view === 'settings' && ( {view === 'settings' && (
<div className="max-w-4xl mx-auto space-y-12 animate-in fade-in duration-700 pb-20"> <div className="max-w-4xl mx-auto space-y-12 animate-in fade-in duration-700 pb-20">
@@ -2101,6 +2318,15 @@ export default function App() {
<div className={`w-6 h-6 rounded-full bg-white absolute top-1 transition-all ${weatherAlerts ? 'left-7' : 'left-1'}`}></div> <div className={`w-6 h-6 rounded-full bg-white absolute top-1 transition-all ${weatherAlerts ? 'left-7' : 'left-1'}`}></div>
</button> </button>
</div> </div>
<div className="flex items-center justify-between">
<div>
<p className="font-bold text-inherit flex items-center gap-2">{t('privateProfile')}</p>
<p className="text-[10px] uppercase tracking-widest opacity-50 text-inherit">{t('privateProfileDesc')}</p>
</div>
<button onClick={() => handlePrivacyToggle(!isPrivate)} className={`w-14 h-8 rounded-full transition-colors relative ${isPrivate ? 'bg-primary-600' : 'bg-gray-200'}`}>
<div className={`w-6 h-6 rounded-full bg-white absolute top-1 transition-all ${isPrivate ? 'left-7' : 'left-1'}`}></div>
</button>
</div>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<p className="font-bold text-inherit">{t('cardSize') || 'Tamanho do Card'}</p> <p className="font-bold text-inherit">{t('cardSize') || 'Tamanho do Card'}</p>

View File

@@ -18,6 +18,8 @@ export const translations = {
outfits: "Outfits", outfits: "Outfits",
settings: "Definições", settings: "Definições",
online: "Online", online: "Online",
away: "Ausente",
offline: "Offline",
dailyOutfit: "Outfit Diário", dailyOutfit: "Outfit Diário",
noOutfitPlanned: "Nenhum Outfit Planeado", noOutfitPlanned: "Nenhum Outfit Planeado",
goToPlanning: "Vá ao planeamento para adicionar", goToPlanning: "Vá ao planeamento para adicionar",
@@ -203,6 +205,16 @@ export const translations = {
large: "Grande", large: "Grande",
defaultPage: "Página Inicial", defaultPage: "Página Inicial",
defaultPageDesc: "Página que aparece após o login", defaultPageDesc: "Página que aparece após o login",
community: "Comunidade",
searchUsers: "Procurar por @username...",
privateProfile: "Perfil Privado",
privateProfileDesc: "Ocultar armário de outros utilizadores",
viewProfile: "Ver Perfil",
noUsersFound: "Nenhum utilizador encontrado",
isPrivateUser: "Este perfil é privado.",
userOutfits: "Outfits do Utilizador",
userCloset: "Armário",
usernameTaken: "Este nome de utilizador já está em uso.",
}, },
EN: { EN: {
loginModeIntro: "The Future of Your Style", loginModeIntro: "The Future of Your Style",
@@ -223,6 +235,8 @@ export const translations = {
outfits: "Outfits", outfits: "Outfits",
settings: "Settings", settings: "Settings",
online: "Online", online: "Online",
away: "Away",
offline: "Offline",
dailyOutfit: "Daily Outfit", dailyOutfit: "Daily Outfit",
noOutfitPlanned: "No Outfit Planned", noOutfitPlanned: "No Outfit Planned",
goToPlanning: "Go to planning to add one", goToPlanning: "Go to planning to add one",
@@ -408,6 +422,16 @@ export const translations = {
large: "Large", large: "Large",
defaultPage: "Home Page", defaultPage: "Home Page",
defaultPageDesc: "Page that appears after login", defaultPageDesc: "Page that appears after login",
community: "Community",
searchUsers: "Search by @username...",
privateProfile: "Private Profile",
privateProfileDesc: "Hide closet from other users",
viewProfile: "View Profile",
noUsersFound: "No users found",
isPrivateUser: "This profile is private.",
userOutfits: "User's Outfits",
userCloset: "Closet",
usernameTaken: "This username is already taken.",
}, },
ES: { ES: {
loginModeIntro: "El Futuro de Tu Estilo", loginModeIntro: "El Futuro de Tu Estilo",
@@ -428,6 +452,8 @@ export const translations = {
outfits: "Outfits", outfits: "Outfits",
settings: "Ajustes", settings: "Ajustes",
online: "En línea", online: "En línea",
away: "Ausente",
offline: "Desconectado",
dailyOutfit: "Outfit Diario", dailyOutfit: "Outfit Diario",
noOutfitPlanned: "Sin Outfit Planeado", noOutfitPlanned: "Sin Outfit Planeado",
goToPlanning: "Ve a planificación para añadir", goToPlanning: "Ve a planificación para añadir",
@@ -613,6 +639,16 @@ export const translations = {
large: "Grande", large: "Grande",
defaultPage: "Página de Inicio", defaultPage: "Página de Inicio",
defaultPageDesc: "Página que aparece después de iniciar sesión", defaultPageDesc: "Página que aparece después de iniciar sesión",
community: "Comunidad",
searchUsers: "Buscar por @username...",
privateProfile: "Perfil Privado",
privateProfileDesc: "Ocultar armario de otros usuarios",
viewProfile: "Ver Perfil",
noUsersFound: "Ningún usuario encontrado",
isPrivateUser: "Este perfil es privado.",
userOutfits: "Outfits del Usuario",
userCloset: "Armario",
usernameTaken: "Este nombre de usuario ya está en uso.",
}, },
FR: { FR: {
loginModeIntro: "Le Futur de Ton Style", loginModeIntro: "Le Futur de Ton Style",
@@ -633,6 +669,8 @@ export const translations = {
outfits: "Tenues", outfits: "Tenues",
settings: "Paramètres", settings: "Paramètres",
online: "En ligne", online: "En ligne",
away: "Absent",
offline: "Hors ligne",
dailyOutfit: "Tenue du Jour", dailyOutfit: "Tenue du Jour",
noOutfitPlanned: "Aucune Tenue Prévue", noOutfitPlanned: "Aucune Tenue Prévue",
goToPlanning: "Allez dans planification pour ajouter", goToPlanning: "Allez dans planification pour ajouter",
@@ -818,6 +856,16 @@ export const translations = {
large: "Grand", large: "Grand",
defaultPage: "Page d'Accueil", defaultPage: "Page d'Accueil",
defaultPageDesc: "Page qui apparaît après la connexion", defaultPageDesc: "Page qui apparaît après la connexion",
community: "Communauté",
searchUsers: "Rechercher par @username...",
privateProfile: "Profil Privé",
privateProfileDesc: "Cacher le placard aux autres utilisateurs",
viewProfile: "Voir le Profil",
noUsersFound: "Aucun utilisateur trouvé",
isPrivateUser: "Ce profil est privé.",
userOutfits: "Outfits de l'Utilisateur",
userCloset: "Placard",
usernameTaken: "Ce nom d'utilisateur est déjà utilisé.",
}, },
DE: { DE: {
loginModeIntro: "Die Zukunft deines Stils", loginModeIntro: "Die Zukunft deines Stils",
@@ -838,6 +886,8 @@ export const translations = {
outfits: "Outfits", outfits: "Outfits",
settings: "Einstellungen", settings: "Einstellungen",
online: "Online", online: "Online",
away: "Abwesend",
offline: "Offline",
dailyOutfit: "Tägliches Outfit", dailyOutfit: "Tägliches Outfit",
noOutfitPlanned: "Kein Outfit Geplant", noOutfitPlanned: "Kein Outfit Geplant",
goToPlanning: "Gehen Sie zur Planung, um eins hinzuzufügen", goToPlanning: "Gehen Sie zur Planung, um eins hinzuzufügen",
@@ -1023,5 +1073,15 @@ export const translations = {
large: "Groß", large: "Groß",
defaultPage: "Startseite", defaultPage: "Startseite",
defaultPageDesc: "Seite, die nach der Anmeldung angezeigt wird", defaultPageDesc: "Seite, die nach der Anmeldung angezeigt wird",
community: "Gemeinschaft",
searchUsers: "Nach @username suchen...",
privateProfile: "Privates Profil",
privateProfileDesc: "Kleiderschrank vor anderen Benutzern verbergen",
viewProfile: "Profil anzeigen",
noUsersFound: "Keine Benutzer gefunden",
isPrivateUser: "Dieses Profil ist privat.",
userOutfits: "Outfits des Benutzers",
userCloset: "Kleiderschrank",
usernameTaken: "Dieser Benutzername ist bereits vergeben.",
} }
}; };