Skip to content

Commit

Permalink
notification cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
0age committed Dec 7, 2024
1 parent cac7a8d commit 00d0e70
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 9 deletions.
4 changes: 0 additions & 4 deletions frontend/src/components/BalanceDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,12 @@ export function BalanceDisplay(): JSX.Element | null {
const [selectedLock, setSelectedLock] = useState<SelectedLockData | null>(
null
);
const [isWithdrawalLoading, setIsWithdrawalLoading] = useState(false);
const [, setUpdateTrigger] = useState(0);

const handleDisableWithdrawal = async (lockId: string) => {
if (!lockId) return;

try {
setIsWithdrawalLoading(true);
await disableForcedWithdrawal({
args: [BigInt(lockId)],
});
Expand All @@ -85,8 +83,6 @@ export function BalanceDisplay(): JSX.Element | null {
? error.message
: 'Failed to disable forced withdrawal',
});
} finally {
setIsWithdrawalLoading(false);
}
};

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Transfer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export function Transfer({
message:
switchError instanceof Error
? switchError.message
: 'Failed to switch network',
: 'Failed to switch network. Please switch manually.',
});
return;
}
Expand Down
107 changes: 103 additions & 4 deletions frontend/src/context/NotificationProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,119 @@
import { ReactNode } from 'react';
import { Fragment, ReactNode, useState, useEffect } from 'react';
import { Transition } from '@headlessui/react';
import { CheckCircleIcon, XCircleIcon } from '@heroicons/react/24/outline';
import { XMarkIcon } from '@heroicons/react/20/solid';
import { NotificationContext } from './notification-context';

interface Notification {
id: string;
type: 'success' | 'error' | 'warning' | 'info';
title: string;
message: string;
timestamp: number;
}

export function NotificationProvider({ children }: { children: ReactNode }) {
const [notifications, setNotifications] = useState<Notification[]>([]);

const showNotification = (notification: {
type: 'success' | 'error' | 'warning' | 'info';
title: string;
message: string;
}) => {
// For now, just console.log the notification
// You can implement a proper notification system later
console.log('Notification:', notification);
const timestamp = Date.now();
const id = `${timestamp}-${Math.random().toString(36).slice(2, 7)}`;
setNotifications((prev) => [...prev, { ...notification, id, timestamp }]);
};

// Remove notifications after 5 seconds
useEffect(() => {
const timer = setInterval(() => {
setNotifications((prev) => {
const now = Date.now();
return prev.filter(
(notification) => now - notification.timestamp < 5000
);
});
}, 100);

return () => clearInterval(timer);
}, []);

return (
<NotificationContext.Provider value={{ showNotification }}>
{children}
<div
aria-live="assertive"
className="pointer-events-none fixed inset-0 flex items-end px-4 py-6 sm:items-start sm:p-6"
>
<div className="flex w-full flex-col items-center space-y-4 sm:items-end">
{notifications.map((notification) => (
<Transition
key={notification.id}
show={true}
as={Fragment}
enter="transform ease-out duration-300 transition"
enterFrom="translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-2"
enterTo="translate-y-0 opacity-100 sm:translate-x-0"
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="pointer-events-auto w-full max-w-sm overflow-hidden rounded-lg bg-[#0a0a0a] shadow-lg ring-1 ring-gray-800">
<div className="p-4">
<div className="flex items-start">
<div className="flex-shrink-0">
{notification.type === 'success' ? (
<CheckCircleIcon
className="h-6 w-6 text-[#00ff00]"
aria-hidden="true"
/>
) : notification.type === 'error' ? (
<XCircleIcon
className="h-6 w-6 text-red-400"
aria-hidden="true"
/>
) : notification.type === 'warning' ? (
<XCircleIcon
className="h-6 w-6 text-yellow-400"
aria-hidden="true"
/>
) : (
<CheckCircleIcon
className="h-6 w-6 text-blue-400"
aria-hidden="true"
/>
)}
</div>
<div className="ml-3 w-0 flex-1 pt-0.5">
<p className="text-sm font-medium text-gray-100">
{notification.title}
</p>
<p className="mt-1 text-sm text-gray-400">
{notification.message}
</p>
</div>
<div className="ml-4 flex flex-shrink-0">
<button
type="button"
className="inline-flex rounded-md bg-[#0a0a0a] text-gray-500 hover:text-gray-400 focus:outline-none focus:ring-2 focus:ring-[#00ff00] focus:ring-offset-2 focus:ring-offset-[#0a0a0a]"
onClick={() => {
setNotifications((prev) =>
prev.filter((n) => n.id !== notification.id)
);
}}
>
<span className="sr-only">Close</span>
<XMarkIcon className="h-5 w-5" aria-hidden="true" />
</button>
</div>
</div>
</div>
</div>
</Transition>
))}
</div>
</div>
</NotificationContext.Provider>
);
}
43 changes: 43 additions & 0 deletions frontend/src/hooks/useCompact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,48 @@ export function useCompact() {
}
};

const enableForcedWithdrawal = async ({ args }: WithdrawalParams) => {
if (!isSupportedChain(chainId)) {
throw new Error('Unsupported chain');
}

const chain = chains[chainId];
if (!chain) {
throw new Error('Chain configuration not found');
}

try {
const hash = await writeContract({
address: COMPACT_ADDRESS as `0x${string}`,
abi: [
COMPACT_ABI.find((x) => x.name === 'enableForcedWithdrawal'),
] as const,
functionName: 'enableForcedWithdrawal',
args,
account: address,
chain,
});
showNotification({
type: 'success',
title: 'Transaction Submitted',
message:
'Your enable forced withdrawal transaction has been submitted.',
});
return hash;
} catch (error) {
console.error('Enable forced withdrawal error:', error);
showNotification({
type: 'error',
title: 'Error',
message:
error instanceof Error
? error.message
: 'Failed to enable forced withdrawal',
});
throw error;
}
};

const forcedWithdrawal = async ({ args }: WithdrawalParams) => {
if (!isSupportedChain(chainId)) {
throw new Error('Unsupported chain');
Expand Down Expand Up @@ -193,6 +235,7 @@ export function useCompact() {

return {
deposit,
enableForcedWithdrawal,
disableForcedWithdrawal,
forcedWithdrawal,
isSupported: isSupportedChain(chainId),
Expand Down

0 comments on commit 00d0e70

Please sign in to comment.