Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions app/(public)/join/[code]/JoinButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,36 @@ export default function JoinButton({

if (!board) throw new Error("Invalid invite code");

const { data: existingMembership } = await supabase
.from("leaderboard_members")
.select("id")
.eq("leaderboard_id", board.id)
.eq("user_id", user.id)
.maybeSingle();

if (existingMembership) {
return { alreadyMember: true };
}
const { error } = await supabase.from("leaderboard_members").insert({
leaderboard_id: board.id,
user_id: user.id,
});

if (error) throw error;
return board;
return { alreadyMember: false };
})();

try {
await toast.promise(joinPromise, {
pending: "Joining leaderboard...",
success: "You're in! Welcome to the leaderboard.",
success: {
render({ data }) {
const payload = data as { alreadyMember: boolean };
return payload.alreadyMember
? "You're already a member. Opening leaderboard..."
: "You're in! Welcome to the leaderboard.";
},
},
error: {
render({ data }) {
const err = data as Error;
Expand Down
4 changes: 2 additions & 2 deletions app/(public)/join/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ export default async function JoinPage({ searchParams }: Props) {
.select("id")
.eq("leaderboard_id", leaderboard.id)
.eq("user_id", user.id)
.single();
alreadyMember = !!membership;
.maybeSingle();
alreadyMember = user.id === leaderboard.owner_id || !!membership;
}

return (
Expand Down
35 changes: 35 additions & 0 deletions app/components/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,40 @@ export default function Chat({ user }: { user: User }) {
return messages.filter((m) => (m.text || "").toLowerCase().includes(lowerSearch));
}, [messages, messageSearch]);

const handleUnsendMessage = async (messageId: string) => {
if (!conversationId) return;
if (messageId.startsWith("temp-") || messageId.startsWith("live-")) {
toast.info("Please wait a moment and try again.");
return;
}

const removedMessage = messages.find((message) => message.id === messageId);
if (!removedMessage) return;

setMessages((prev) => prev.filter((message) => message.id !== messageId));

const { error } = await supabase
.from("messages")
.delete()
.eq("id", messageId)
.eq("sender_id", user.id);

if (error) {
setMessages((prev) => {
if (prev.some((message) => message.id === messageId)) return prev;
const next = [...prev, removedMessage];
next.sort(
(a, b) =>
new Date(a.created_at).getTime() - new Date(b.created_at).getTime(),
);
return next;
});
toast.error(error.message || "Unable to unsend message.");
return;
}

toast.success("Message unsent.");
};
return (
<>
<MediaViewerModal
Expand Down Expand Up @@ -497,6 +531,7 @@ export default function Chat({ user }: { user: User }) {
bottomRef={bottomRef}
badgesByUserId={badgesByUserId}
onUserProfileClick={openPrivateChatFromGlobalProfile}
onUnsendMessage={handleUnsendMessage}
/>
</div>

Expand Down
Loading
Loading