Skip to content
Merged
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
7 changes: 6 additions & 1 deletion backend/MCP_Execution_Server/src/routes/user.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,13 @@ export function userRouter(userService: UserService): Router {
router.post(
"/unsubscribe/user",
async (req: Request, res: Response, next: NextFunction): Promise<void> => {
const { fid } = req.body;
const apiKey = req.header("x-api-key");

if (!apiKey || apiKey !== process.env.INTERNAL_API_KEY) {
res.status(401).json({ error: "Unauthorized: Invalid API key" });
return;
}
const { fid } = req.body;
if (!fid) {
res.status(400).json({ error: "Missing User FID" });
return;
Expand Down
36 changes: 36 additions & 0 deletions frontend/src/app/api/backend/unsubscribe/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { NextRequest, NextResponse } from "next/server";

export async function POST(request: NextRequest) {
try {
const { fid } = await request.json();

const response = await fetch(
`${process.env.NEXT_PUBLIC_BACKEND_URL}/api/unsubscribe/user`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": process.env.INTERNAL_API_KEY!,
},
body: JSON.stringify({ fid }),
},
);

const data = await response.json();

if (!response.ok) {
return NextResponse.json(
{ message: data.message || "Unsubscribe failed" },
{ status: response.status },
);
}

return NextResponse.json(data);
} catch (e) {
console.error("Error in unsubscribe route:", e);
return NextResponse.json(
{ message: "Internal server error" },
{ status: 500 },
);
}
}
59 changes: 47 additions & 12 deletions frontend/src/components/Landing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,20 @@ const registerUser = async (fid: number) => {
return response.json();
};

const unsubscribeUser = async (fid: number) => {
const response = await fetch(`/api/backend/unsubscribe`, {
method: "POST",
body: JSON.stringify({ fid }),
});

if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || "Unsubscribe failed");
}

return response.json();
};

export default function Home() {
const { context } = useFrame();
const [isSubscribed, setSubscribed] = useState(false);
Expand All @@ -97,7 +111,6 @@ export default function Home() {
},
});

console.log(fetchUserQuery.data, isSubscribed);
const mutation = useMutation({
mutationFn: registerUser,
onSuccess: (data) => {
Expand All @@ -108,10 +121,25 @@ export default function Home() {
});
},
onError: (error) => {
setSubscribed(false);
console.error("Error registering user:", error);
},
});

const unsubscribeMutation = useMutation({
mutationFn: unsubscribeUser,
onSuccess: (data) => {
console.log("Unsubscribe successful:", data);
setSubscribed(false);
queryClient.refetchQueries({
queryKey: ["userSubscription", context?.user?.fid],
});
},
onError: (error) => {
console.error("Error unsubscribing user:", error);
},
});

const handleComposeMutation = useMutation({
mutationFn: async () => {
const result = await sdk.actions.composeCast({
Expand All @@ -122,12 +150,17 @@ export default function Home() {
},
});

const handleSubscribe = () => {
const handleSubscribe = async () => {
if (!context || !context.user?.displayName) {
console.log("User not logged in");
return;
}
mutation.mutate(context.user.fid);
await mutation.mutateAsync(context.user.fid);
try {
await sdk.actions.addFrame();
} catch (error) {
console.log("Error adding frame:", error);
}
setSubscribed(true);
};
useEffect(() => {
Expand Down Expand Up @@ -280,18 +313,20 @@ export default function Home() {
{mutation.isPending ? "Loading..." : "Count me in !"}
</button>
) : (
<>
<p className="text-sm font-semibold text-green-600">
🎉 You&apos;re already subscribed!
</p>
<div className="flex flex-col gap-3">
<button
onClick={() => handleComposeMutation.mutate()}
disabled={handleComposeMutation.isPending}
className="mt-6 px-4 py-2 text-[14.1px] bg-black text-white rounded-[10px] font-semibold hover:scale-105 transition"
onClick={() =>
unsubscribeMutation.mutate(context?.user.fid as number)
}
disabled={unsubscribeMutation.isPending}
className="mt-6 px-4 py-2 text-[14.1px] bg-red-600 text-white rounded-[10px] font-semibold hover:bg-red-700 transition"
>
Share with your friends!
Unsubscribe
</button>
</>
<p className="text-xs font-semibold text-red-600">
We are sad to see you go
</p>
</div>
)}
</div>
<p className="mt-4 text-gray-600 text-xs max-w-md text-center font-semibold">
Expand Down