diff --git a/apps/marginfi-api/src/app/layout.tsx b/apps/marginfi-api/src/app/layout.tsx deleted file mode 100644 index a14e64fcd5..0000000000 --- a/apps/marginfi-api/src/app/layout.tsx +++ /dev/null @@ -1,16 +0,0 @@ -export const metadata = { - title: 'Next.js', - description: 'Generated by Next.js', -} - -export default function RootLayout({ - children, -}: { - children: React.ReactNode -}) { - return ( - - {children} - - ) -} diff --git a/apps/marginfi-api/src/app/notifications/route.ts b/apps/marginfi-api/src/app/notifications/route.ts index eac43bac1c..d2bdddc176 100644 --- a/apps/marginfi-api/src/app/notifications/route.ts +++ b/apps/marginfi-api/src/app/notifications/route.ts @@ -102,3 +102,28 @@ export async function POST(request: Request) { return NextResponse.json({ error: "Internal server error" }, { status: 500 }); } } + +export async function DELETE(request: Request) { + const { searchParams } = new URL(request.url); + const wallet = searchParams.get("wallet_address"); + const apiKey = request.headers.get("X-API-KEY"); + + if (!apiKey || apiKey !== process.env.MARGINFI_API_KEY) { + return NextResponse.json({ error: "Invalid or missing API key" }, { status: 401 }); + } + + if (!wallet) { + return NextResponse.json({ error: "Missing wallet address parameter" }, { status: 400 }); + } + + const queryText = `DELETE FROM notification_settings WHERE wallet_address = '${wallet}'`; + + try { + const res = await db.query(queryText); + console.log(res); + return NextResponse.json({ success: true }, { status: 200 }); + } catch (error) { + console.error("Database error:", error); + return NextResponse.json({ error: "Internal server error" }, { status: 500 }); + } +} diff --git a/apps/marginfi-v2-ui/src/components/common/Wallet/WalletSettings.tsx b/apps/marginfi-v2-ui/src/components/common/Wallet/WalletSettings.tsx index 77eaa6b400..b88a6653f5 100644 --- a/apps/marginfi-v2-ui/src/components/common/Wallet/WalletSettings.tsx +++ b/apps/marginfi-v2-ui/src/components/common/Wallet/WalletSettings.tsx @@ -10,7 +10,7 @@ import { useConvertkit } from "~/hooks/useConvertkit"; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "~/components/ui/accordion"; import { WalletTokens, Token, WalletOnramp } from "~/components/common/Wallet"; import { Label } from "~/components/ui/label"; -import { IconCheck, IconInfoCircle, IconLoader, IconAlertTriangle } from "~/components/ui/icons"; +import { IconCheck, IconInfoCircle, IconLoader, IconAlertTriangle, IconX } from "~/components/ui/icons"; import { Input } from "~/components/ui/input"; import { Checkbox } from "~/components/ui/checkbox"; import { Button } from "~/components/ui/button"; @@ -38,6 +38,7 @@ export const WalletSettings = ({ walletAddress, tokens }: WalletSettingsProps) = ybx: false, }); const [errorMsg, setErrorMsg] = React.useState(null); + const [showClearNotifications, setShowClearNotifications] = React.useState(false); const notificationFormDisabled = React.useMemo(() => { return walletSettingsState === WalletSettingsState.UPDATING || !email; @@ -86,6 +87,7 @@ export const WalletSettings = ({ walletAddress, tokens }: WalletSettingsProps) = setErrorMsg(null); setWalletSettingsState(WalletSettingsState.SUCCESS); + setShowClearNotifications(true); setTimeout(() => { setWalletSettingsState(WalletSettingsState.DEFAULT); @@ -107,7 +109,7 @@ export const WalletSettings = ({ walletAddress, tokens }: WalletSettingsProps) = if (!res.ok) { // document not found which means notifications have not been set - const { success, message } = await res.json(); + const { success } = await res.json(); if (success) { return; } @@ -123,6 +125,32 @@ export const WalletSettings = ({ walletAddress, tokens }: WalletSettingsProps) = health: data.account_health, ybx: data.ybx_updates, }); + setShowClearNotifications(Boolean(data.email)); + }, [walletAddress]); + + const clearNotifications = React.useCallback(async () => { + const deleteRes = await fetch(window.location.origin + "/api/user/notifications", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + walletAddress: walletAddress.toBase58(), + deleteRecord: true, + }), + }); + + if (!deleteRes.ok) { + setErrorMsg("There was an error clearing your notification settings. Please try again."); + return; + } + + setEmail(null); + setNotificationSettings({ + health: false, + ybx: false, + }); + setShowClearNotifications(false); }, [walletAddress]); React.useEffect(() => { @@ -251,6 +279,18 @@ export const WalletSettings = ({ walletAddress, tokens }: WalletSettingsProps) = )} + + {showClearNotifications && ( + + )} diff --git a/apps/marginfi-v2-ui/src/pages/api/user/notifications.ts b/apps/marginfi-v2-ui/src/pages/api/user/notifications.ts index a841a813f1..6a4fbc23b6 100644 --- a/apps/marginfi-v2-ui/src/pages/api/user/notifications.ts +++ b/apps/marginfi-v2-ui/src/pages/api/user/notifications.ts @@ -10,9 +10,29 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } if (req.method === "POST") { - const { email, walletAddress, accountHealth, ybxUpdates } = req.body; + const { email, walletAddress, accountHealth, ybxUpdates, deleteRecord } = req.body; try { + if (deleteRecord) { + const response = await fetch(`${apiUrl}/notifications?wallet_address=${walletAddress}`, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + "X-API-KEY": apiKey, + }, + }); + + if (response.ok) { + return res.status(200).json({ success: true, message: "Notification settings deleted" }); + } else { + const errorData = await response.json(); + console.error("Error deleting notifications settings via API:", errorData); + return res + .status(response.status) + .json({ success: false, message: errorData.message || "Failed to delete notification settings" }); + } + } + const response = await fetch(`${apiUrl}/notifications`, { method: "POST", headers: {