diff --git a/src/App.js b/src/App.js
index fda0ecf..ae65013 100644
--- a/src/App.js
+++ b/src/App.js
@@ -137,8 +137,8 @@ function App() {
:
} />
- } />
- } />
+ } />
+ } />
:
} />
diff --git a/src/components/Post/Post.js b/src/components/Post/Post.js
index 97908ac..0cf99d1 100644
--- a/src/components/Post/Post.js
+++ b/src/components/Post/Post.js
@@ -1,6 +1,6 @@
import React from 'react';
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`
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 actualPost = isReblog ? post.reblog : post;
const originalPoster = isReblog ? post.account : null;
@@ -281,6 +281,12 @@ const Post = ({ post, onFavorite, onReblog, onReply, currentUser }) => {
{actualPost.favourites_count || 0}
+ {currentUser && String(currentUser.id) === String(actualPost.account.id) && (
+ onDelete?.(actualPost)}>
+
+
+ )}
+
navigator.share?.({ url: actualPost.url })}>
diff --git a/src/pages/HomePage.js b/src/pages/HomePage.js
index 1986b13..510a1e1 100644
--- a/src/pages/HomePage.js
+++ b/src/pages/HomePage.js
@@ -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 = () => {
if (posts.length > 0 && hasMore && !loadingMore) {
setLoadingMore(true);
@@ -215,6 +229,7 @@ const HomePage = ({ user }) => {
currentUser={user}
onFavorite={handleFavorite}
onReblog={handleReblog}
+ onDelete={handleDelete}
onReply={(post) => console.log('Reply to:', post)}
/>
))}
diff --git a/src/pages/LocalTimelinePage.js b/src/pages/LocalTimelinePage.js
index b421e65..b793e22 100644
--- a/src/pages/LocalTimelinePage.js
+++ b/src/pages/LocalTimelinePage.js
@@ -90,7 +90,7 @@ const EmptyState = styled.div`
}
`;
-const LocalTimelinePage = () => {
+const LocalTimelinePage = ({ currentUser }) => {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
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 = () => {
if (posts.length > 0 && hasMore && !loadingMore) {
setLoadingMore(true);
@@ -234,8 +248,10 @@ const LocalTimelinePage = () => {
console.log('Reply to:', post)}
/>
))}
diff --git a/src/pages/OAuthCallbackPage.js b/src/pages/OAuthCallbackPage.js
index c1e49df..5f51659 100644
--- a/src/pages/OAuthCallbackPage.js
+++ b/src/pages/OAuthCallbackPage.js
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useState, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import styled from 'styled-components';
import { FaExclamationTriangle } from 'react-icons/fa';
@@ -80,10 +80,18 @@ const OAuthCallbackPage = ({ onLoginSuccess }) => {
}
}, [hasCode, hasState]);
+ const processedRef = useRef(false);
+
useEffect(() => {
+ if (processedRef.current) return;
+ processedRef.current = true;
+ console.log('OAuth callback: useEffect executed');
+
const processCallback = async () => {
try {
+ console.log('OAuth callback: Starting processCallback');
const { code, state, error: oauthError, error_description } = oauthService.getOAuthCallbackParams();
+ console.log('OAuth callback: Got params', { code: !!code, state: !!state, oauthError, error_description });
if (oauthError) {
throw new Error(error_description || `OAuth error: ${oauthError}`);
@@ -94,14 +102,23 @@ const OAuthCallbackPage = ({ onLoginSuccess }) => {
}
setStatus('processing');
+ console.log('OAuth callback: Status set to processing');
+ console.log('OAuth callback: Calling exchangeCodeForToken');
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();
+ console.log('OAuth callback: Credentials verified', { username: userData.username });
+
localStorage.setItem('current_user', JSON.stringify(userData));
setStatus('success');
+ console.log('OAuth callback: Status set to success');
if (onLoginSuccess) {
onLoginSuccess(userData);
@@ -113,25 +130,15 @@ const OAuthCallbackPage = ({ onLoginSuccess }) => {
}, 2000);
} catch (err) {
+ console.error('OAuth callback error:', err);
setError(err.message || 'Authentication failed');
setStatus('error');
}
};
- const processTimer = setTimeout(processCallback, 100);
-
- const emergencyTimer = setTimeout(() => {
- 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]);
+ // Call immediately instead of with setTimeout
+ processCallback();
+ }, [navigate, onLoginSuccess]);
diff --git a/src/pages/ProfilePage.js b/src/pages/ProfilePage.js
index 7ac19ae..28ad029 100644
--- a/src/pages/ProfilePage.js
+++ b/src/pages/ProfilePage.js
@@ -209,19 +209,37 @@ const ProfilePage = ({ currentUser }) => {
setLoading(true);
setError(null);
+ console.log('Loading profile for username:', 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;
- // Look for exact username match
- if (searchResults.accounts) {
+ // Look for exact username match (try multiple variations)
+ if (searchResults.accounts && searchResults.accounts.length > 0) {
+ // First try exact username match
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) {
+ 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');
}
@@ -265,6 +283,20 @@ const ProfilePage = ({ currentUser }) => {
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 () => {
if (!currentUser || !profile) return;
@@ -426,6 +458,7 @@ const ProfilePage = ({ currentUser }) => {
currentUser={currentUser}
onFavorite={() => {}}
onReblog={() => {}}
+ onDelete={handleDelete}
onReply={() => {}}
/>
))
diff --git a/src/pages/PublicTimelinePage.js b/src/pages/PublicTimelinePage.js
index 84e82d8..d05a0d7 100644
--- a/src/pages/PublicTimelinePage.js
+++ b/src/pages/PublicTimelinePage.js
@@ -90,7 +90,7 @@ const EmptyState = styled.div`
}
`;
-const PublicTimelinePage = () => {
+const PublicTimelinePage = ({ currentUser }) => {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
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 = () => {
if (posts.length > 0 && hasMore && !loadingMore) {
setLoadingMore(true);
@@ -234,8 +248,10 @@ const PublicTimelinePage = () => {
console.log('Reply to:', post)}
/>
))}
diff --git a/src/pages/StatusPage.js b/src/pages/StatusPage.js
index d010519..c3a4a2e 100644
--- a/src/pages/StatusPage.js
+++ b/src/pages/StatusPage.js
@@ -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
const buildReplyTree = (posts, parentId = null, depth = 0) => {
return posts
@@ -178,6 +200,7 @@ const StatusPage = ({ currentUser }) => {
currentUser={currentUser}
onFavorite={handleFavorite}
onReblog={handleReblog}
+ onDelete={handleDelete}
onReply={() => {}}
compact={depth > 0}
/>
@@ -233,6 +256,7 @@ const StatusPage = ({ currentUser }) => {
currentUser={currentUser}
onFavorite={handleFavorite}
onReblog={handleReblog}
+ onDelete={handleDelete}
onReply={() => {}}
/>
@@ -246,6 +270,7 @@ const StatusPage = ({ currentUser }) => {
currentUser={currentUser}
onFavorite={handleFavorite}
onReblog={handleReblog}
+ onDelete={handleDelete}
onReply={() => {}}
showFullContent={true}
/>