delete and login

Signed-off-by: ale <ale@manalejandro.com>
Este commit está contenido en:
ale
2025-09-30 00:04:27 +02:00
padre 0888baa32f
commit e40154708a
Se han modificado 8 ficheros con 144 adiciones y 26 borrados

Ver fichero

@@ -137,8 +137,8 @@ function App() {
<Route path="/" element={ <Route path="/" element={
user ? <HomePage user={user} /> : <Navigate to="/login" replace /> user ? <HomePage user={user} /> : <Navigate to="/login" replace />
} /> } />
<Route path="/public" element={<PublicTimelinePage />} /> <Route path="/public" element={<PublicTimelinePage currentUser={user} />} />
<Route path="/local" element={<LocalTimelinePage />} /> <Route path="/local" element={<LocalTimelinePage currentUser={user} />} />
<Route path="/notifications" element={ <Route path="/notifications" element={
user ? <NotificationsPage user={user} /> : <Navigate to="/login" replace /> user ? <NotificationsPage user={user} /> : <Navigate to="/login" replace />
} /> } />

Ver fichero

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { FaHeart, FaRetweet, FaReply, FaShare, FaClock, FaGlobeAmericas, FaLock, FaUsers, FaEnvelope } from 'react-icons/fa'; import { FaHeart, FaRetweet, FaReply, FaShare, FaClock, FaGlobeAmericas, FaLock, FaUsers, FaEnvelope, FaTrash } from 'react-icons/fa';
const PostContainer = styled.article` const PostContainer = styled.article`
background: white; background: white;
@@ -158,7 +158,7 @@ const ReblogInfo = styled.div`
} }
`; `;
const Post = ({ post, onFavorite, onReblog, onReply, currentUser }) => { const Post = ({ post, onFavorite, onReblog, onReply, onDelete, currentUser }) => {
const isReblog = post.reblog; const isReblog = post.reblog;
const actualPost = isReblog ? post.reblog : post; const actualPost = isReblog ? post.reblog : post;
const originalPoster = isReblog ? post.account : null; const originalPoster = isReblog ? post.account : null;
@@ -281,6 +281,12 @@ const Post = ({ post, onFavorite, onReblog, onReply, currentUser }) => {
<span>{actualPost.favourites_count || 0}</span> <span>{actualPost.favourites_count || 0}</span>
</ActionButton> </ActionButton>
{currentUser && String(currentUser.id) === String(actualPost.account.id) && (
<ActionButton onClick={() => onDelete?.(actualPost)}>
<FaTrash />
</ActionButton>
)}
<ActionButton onClick={() => navigator.share?.({ url: actualPost.url })}> <ActionButton onClick={() => navigator.share?.({ url: actualPost.url })}>
<FaShare /> <FaShare />
</ActionButton> </ActionButton>

Ver fichero

@@ -152,6 +152,20 @@ const HomePage = ({ user }) => {
} }
}; };
const handleDelete = async (post) => {
if (!window.confirm('¿Estás seguro de que quieres eliminar este post? Esta acción no se puede deshacer.')) {
return;
}
try {
await api.deleteStatus(post.id);
setPosts(prev => prev.filter(p => p.id !== post.id));
} catch (err) {
console.error('Error deleting post:', err);
// Could show a toast or error message here
}
};
const handleLoadMore = () => { const handleLoadMore = () => {
if (posts.length > 0 && hasMore && !loadingMore) { if (posts.length > 0 && hasMore && !loadingMore) {
setLoadingMore(true); setLoadingMore(true);
@@ -215,6 +229,7 @@ const HomePage = ({ user }) => {
currentUser={user} currentUser={user}
onFavorite={handleFavorite} onFavorite={handleFavorite}
onReblog={handleReblog} onReblog={handleReblog}
onDelete={handleDelete}
onReply={(post) => console.log('Reply to:', post)} onReply={(post) => console.log('Reply to:', post)}
/> />
))} ))}

Ver fichero

@@ -90,7 +90,7 @@ const EmptyState = styled.div`
} }
`; `;
const LocalTimelinePage = () => { const LocalTimelinePage = ({ currentUser }) => {
const [posts, setPosts] = useState([]); const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState(null); const [error, setError] = useState(null);
@@ -171,6 +171,20 @@ const LocalTimelinePage = () => {
} }
}; };
const handleDelete = async (post) => {
if (!window.confirm('¿Estás seguro de que quieres eliminar este post? Esta acción no se puede deshacer.')) {
return;
}
try {
await api.deleteStatus(post.id);
setPosts(prev => prev.filter(p => p.id !== post.id));
} catch (err) {
console.error('Error deleting post:', err);
// Could show a toast or error message here
}
};
const handleLoadMore = () => { const handleLoadMore = () => {
if (posts.length > 0 && hasMore && !loadingMore) { if (posts.length > 0 && hasMore && !loadingMore) {
setLoadingMore(true); setLoadingMore(true);
@@ -234,8 +248,10 @@ const LocalTimelinePage = () => {
<Post <Post
key={post.id} key={post.id}
post={post} post={post}
currentUser={currentUser}
onFavorite={handleFavorite} onFavorite={handleFavorite}
onReblog={handleReblog} onReblog={handleReblog}
onDelete={handleDelete}
onReply={(post) => console.log('Reply to:', post)} onReply={(post) => console.log('Reply to:', post)}
/> />
))} ))}

Ver fichero

@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState, useRef } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import styled from 'styled-components'; import styled from 'styled-components';
import { FaExclamationTriangle } from 'react-icons/fa'; import { FaExclamationTriangle } from 'react-icons/fa';
@@ -80,10 +80,18 @@ const OAuthCallbackPage = ({ onLoginSuccess }) => {
} }
}, [hasCode, hasState]); }, [hasCode, hasState]);
const processedRef = useRef(false);
useEffect(() => { useEffect(() => {
if (processedRef.current) return;
processedRef.current = true;
console.log('OAuth callback: useEffect executed');
const processCallback = async () => { const processCallback = async () => {
try { try {
console.log('OAuth callback: Starting processCallback');
const { code, state, error: oauthError, error_description } = oauthService.getOAuthCallbackParams(); const { code, state, error: oauthError, error_description } = oauthService.getOAuthCallbackParams();
console.log('OAuth callback: Got params', { code: !!code, state: !!state, oauthError, error_description });
if (oauthError) { if (oauthError) {
throw new Error(error_description || `OAuth error: ${oauthError}`); throw new Error(error_description || `OAuth error: ${oauthError}`);
@@ -94,14 +102,23 @@ const OAuthCallbackPage = ({ onLoginSuccess }) => {
} }
setStatus('processing'); setStatus('processing');
console.log('OAuth callback: Status set to processing');
console.log('OAuth callback: Calling exchangeCodeForToken');
const tokenData = await oauthService.exchangeCodeForToken(code, state); const tokenData = await oauthService.exchangeCodeForToken(code, state);
api.setAuth(tokenData.access_token, tokenData.instance_url, tokenData.refresh_token); console.log('OAuth callback: Token exchange successful', { access_token: !!tokenData.access_token, instance_url: tokenData.instance_url });
api.setAuth(tokenData.access_token, tokenData.instance_url, tokenData.refresh_token);
console.log('OAuth callback: API auth set');
console.log('OAuth callback: Calling verifyCredentials');
const userData = await api.verifyCredentials(); const userData = await api.verifyCredentials();
console.log('OAuth callback: Credentials verified', { username: userData.username });
localStorage.setItem('current_user', JSON.stringify(userData)); localStorage.setItem('current_user', JSON.stringify(userData));
setStatus('success'); setStatus('success');
console.log('OAuth callback: Status set to success');
if (onLoginSuccess) { if (onLoginSuccess) {
onLoginSuccess(userData); onLoginSuccess(userData);
@@ -113,25 +130,15 @@ const OAuthCallbackPage = ({ onLoginSuccess }) => {
}, 2000); }, 2000);
} catch (err) { } catch (err) {
console.error('OAuth callback error:', err);
setError(err.message || 'Authentication failed'); setError(err.message || 'Authentication failed');
setStatus('error'); setStatus('error');
} }
}; };
const processTimer = setTimeout(processCallback, 100); // Call immediately instead of with setTimeout
processCallback();
const emergencyTimer = setTimeout(() => { }, [navigate, onLoginSuccess]);
if (status === 'processing') {
setError('Authentication is taking too long. Please try again or check your connection.');
setStatus('error');
}
}, 30000);
return () => {
clearTimeout(processTimer);
clearTimeout(emergencyTimer);
};
}, [navigate, onLoginSuccess, status]);

Ver fichero

@@ -209,19 +209,37 @@ const ProfilePage = ({ currentUser }) => {
setLoading(true); setLoading(true);
setError(null); setError(null);
console.log('Loading profile for username:', username);
// First, search for the user by username // First, search for the user by username
const searchResults = await api.search(username, { type: 'accounts', limit: 5 }); const searchResults = await api.search(username, { type: 'accounts', limit: 20, resolve: true });
let userAccount = null; let userAccount = null;
// Look for exact username match // Look for exact username match (try multiple variations)
if (searchResults.accounts) { if (searchResults.accounts && searchResults.accounts.length > 0) {
// First try exact username match
userAccount = searchResults.accounts.find(account => userAccount = searchResults.accounts.find(account =>
account.username === username || account.acct === username account.username === username
);
// If not found, try with acct field (which includes domain)
if (!userAccount) {
userAccount = searchResults.accounts.find(account =>
account.acct === username || account.acct === `${username}@${new URL(api.instanceUrl).host}`
); );
} }
// If still not found, try case-insensitive match
if (!userAccount) { if (!userAccount) {
userAccount = searchResults.accounts.find(account =>
account.username.toLowerCase() === username.toLowerCase()
);
}
}
if (!userAccount) {
console.log('User not found in search results. Available accounts:', searchResults.accounts?.map(acc => ({ username: acc.username, acct: acc.acct })));
throw new Error('User not found'); throw new Error('User not found');
} }
@@ -265,6 +283,20 @@ const ProfilePage = ({ currentUser }) => {
loadProfile(); loadProfile();
}, [loadProfile]); }, [loadProfile]);
const handleDelete = async (post) => {
if (!window.confirm('¿Estás seguro de que quieres eliminar este post? Esta acción no se puede deshacer.')) {
return;
}
try {
await api.deleteStatus(post.id);
setPosts(prev => prev.filter(p => p.id !== post.id));
} catch (err) {
console.error('Error deleting post:', err);
// Could show a toast or error message here
}
};
const handleFollow = async () => { const handleFollow = async () => {
if (!currentUser || !profile) return; if (!currentUser || !profile) return;
@@ -426,6 +458,7 @@ const ProfilePage = ({ currentUser }) => {
currentUser={currentUser} currentUser={currentUser}
onFavorite={() => {}} onFavorite={() => {}}
onReblog={() => {}} onReblog={() => {}}
onDelete={handleDelete}
onReply={() => {}} onReply={() => {}}
/> />
)) ))

Ver fichero

@@ -90,7 +90,7 @@ const EmptyState = styled.div`
} }
`; `;
const PublicTimelinePage = () => { const PublicTimelinePage = ({ currentUser }) => {
const [posts, setPosts] = useState([]); const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState(null); const [error, setError] = useState(null);
@@ -171,6 +171,20 @@ const PublicTimelinePage = () => {
} }
}; };
const handleDelete = async (post) => {
if (!window.confirm('¿Estás seguro de que quieres eliminar este post? Esta acción no se puede deshacer.')) {
return;
}
try {
await api.deleteStatus(post.id);
setPosts(prev => prev.filter(p => p.id !== post.id));
} catch (err) {
console.error('Error deleting post:', err);
// Could show a toast or error message here
}
};
const handleLoadMore = () => { const handleLoadMore = () => {
if (posts.length > 0 && hasMore && !loadingMore) { if (posts.length > 0 && hasMore && !loadingMore) {
setLoadingMore(true); setLoadingMore(true);
@@ -234,8 +248,10 @@ const PublicTimelinePage = () => {
<Post <Post
key={post.id} key={post.id}
post={post} post={post}
currentUser={currentUser}
onFavorite={handleFavorite} onFavorite={handleFavorite}
onReblog={handleReblog} onReblog={handleReblog}
onDelete={handleDelete}
onReply={(post) => console.log('Reply to:', post)} onReply={(post) => console.log('Reply to:', post)}
/> />
))} ))}

Ver fichero

@@ -158,6 +158,28 @@ const StatusPage = ({ currentUser }) => {
} }
}; };
const handleDelete = async (post) => {
if (!window.confirm('¿Estás seguro de que quieres eliminar este post? Esta acción no se puede deshacer.')) {
return;
}
try {
await api.deleteStatus(post.id);
if (post.id === status.id) {
// If deleting the main post, redirect to home
window.location.href = '/';
} else {
// Remove from context
setContext(prev => ({
ancestors: prev.ancestors.filter(p => p.id !== post.id),
descendants: prev.descendants.filter(p => p.id !== post.id)
}));
}
} catch (err) {
console.error('Error deleting post:', err);
}
};
// Build reply tree structure // Build reply tree structure
const buildReplyTree = (posts, parentId = null, depth = 0) => { const buildReplyTree = (posts, parentId = null, depth = 0) => {
return posts return posts
@@ -178,6 +200,7 @@ const StatusPage = ({ currentUser }) => {
currentUser={currentUser} currentUser={currentUser}
onFavorite={handleFavorite} onFavorite={handleFavorite}
onReblog={handleReblog} onReblog={handleReblog}
onDelete={handleDelete}
onReply={() => {}} onReply={() => {}}
compact={depth > 0} compact={depth > 0}
/> />
@@ -233,6 +256,7 @@ const StatusPage = ({ currentUser }) => {
currentUser={currentUser} currentUser={currentUser}
onFavorite={handleFavorite} onFavorite={handleFavorite}
onReblog={handleReblog} onReblog={handleReblog}
onDelete={handleDelete}
onReply={() => {}} onReply={() => {}}
/> />
</Reply> </Reply>
@@ -246,6 +270,7 @@ const StatusPage = ({ currentUser }) => {
currentUser={currentUser} currentUser={currentUser}
onFavorite={handleFavorite} onFavorite={handleFavorite}
onReblog={handleReblog} onReblog={handleReblog}
onDelete={handleDelete}
onReply={() => {}} onReply={() => {}}
showFullContent={true} showFullContent={true}
/> />