diff --git a/apps/frontend/escrow/types/escrow-events.ts b/apps/frontend/escrow/types/escrow-events.ts new file mode 100644 index 00000000..e0e16d69 --- /dev/null +++ b/apps/frontend/escrow/types/escrow-events.ts @@ -0,0 +1,17 @@ +export type EscrowEventType = + | 'escrow:status_changed' + | 'escrow:funded' + | 'escrow:completed' + | 'escrow:condition_fulfilled' + | 'escrow:dispute_filed' + | 'escrow:dispute_resolved'; + + export interface EscrowRealtimeEvent { + escrowId: string; + + type: EscrowEventType; + + timestamp: string; + + payload: Record; +} diff --git a/apps/frontend/hooks/useNotificationPreferences.ts b/apps/frontend/hooks/useNotificationPreferences.ts new file mode 100644 index 00000000..2b0591b4 --- /dev/null +++ b/apps/frontend/hooks/useNotificationPreferences.ts @@ -0,0 +1,27 @@ +export function useNotificationPreferences() { + + const preferencesQuery = + useQuery({ + queryKey: [ + 'notification-preferences', + ], + queryFn: getPreferences, + }); + + const saveMutation = + useMutation({ + mutationFn: + updatePreferences, + + onSuccess() { + toast.success( + 'Preferences updated', + ); + }, + + onError() { + toast.error( + 'Failed to update preferences', + ); + }, + }); \ No newline at end of file diff --git a/apps/frontend/lib/websocket/escrow-events.ts b/apps/frontend/lib/websocket/escrow-events.ts new file mode 100644 index 00000000..c5178a73 --- /dev/null +++ b/apps/frontend/lib/websocket/escrow-events.ts @@ -0,0 +1,69 @@ +import { socket } from './client'; + +export function joinEscrowRoom( + escrowId: string, +) { + socket.emit( + 'join', + `escrow:${escrowId}`, + ); +} + +export function leaveEscrowRoom( + escrowId: string, +) { + socket.emit( + 'leave', + `escrow:${escrowId}`, + ); +} + +export function subscribeToEscrowEvents( + callback: ( + event: EscrowRealtimeEvent, + ) => void, +) { + const handlers = [ + 'escrow:status_changed', + 'escrow:funded', + 'escrow:completed', + 'escrow:condition_fulfilled', + 'escrow:dispute_filed', + 'escrow:dispute_resolved', + ]; + + handlers.forEach(event => + socket.on(event, callback), + ); + + return () => { + handlers.forEach(event => + socket.off(event, callback), + ); + }; +} + +export function LiveIndicator({ + connected, +}: Props) { + return ( +
+ + + {connected + ? 'Live' + : 'Reconnecting'} +
+ ); +} \ No newline at end of file diff --git a/apps/frontend/services/notificationPreferences.ts b/apps/frontend/services/notificationPreferences.ts new file mode 100644 index 00000000..85b3d7c1 --- /dev/null +++ b/apps/frontend/services/notificationPreferences.ts @@ -0,0 +1,21 @@ +export async function getPreferences() { + const response = await api.get( + '/notifications/preferences', + ); + + return response.data; +} + +export async function updatePreferences( + preferences: NotificationPreference[], +) { + const response = await api.put( + '/notifications/preferences', + { + preferences, + }, + ); + + return response.data; +} + diff --git a/apps/frontend/services/webhooks.ts b/apps/frontend/services/webhooks.ts new file mode 100644 index 00000000..d666ec38 --- /dev/null +++ b/apps/frontend/services/webhooks.ts @@ -0,0 +1,26 @@ +export async function getWebhooks() { + const response = + await api.get('/webhooks'); + + return response.data; +} + +export async function createWebhook( + payload: CreateWebhookDto, +) { + const response = + await api.post( + '/webhooks', + payload, + ); + + return response.data; +} + +export async function deleteWebhook( + id: string, +) { + await api.delete( + `/webhooks/${id}`, + ); +} \ No newline at end of file diff --git a/apps/frontend/settings/page.tsx b/apps/frontend/settings/page.tsx new file mode 100644 index 00000000..e69de29b diff --git a/apps/frontend/types/notification-preferences.ts b/apps/frontend/types/notification-preferences.ts new file mode 100644 index 00000000..22d8b01c --- /dev/null +++ b/apps/frontend/types/notification-preferences.ts @@ -0,0 +1,16 @@ +export enum NotificationEventType { + ESCROW_CREATED = 'ESCROW_CREATED', + ESCROW_FUNDED = 'ESCROW_FUNDED', + MILESTONE_RELEASED = 'MILESTONE_RELEASED', + ESCROW_COMPLETED = 'ESCROW_COMPLETED', + DISPUTE_CREATED = 'DISPUTE_CREATED', + DISPUTE_RESOLVED = 'DISPUTE_RESOLVED', +} + +export interface NotificationPreference { + eventType: NotificationEventType; + + emailEnabled: boolean; + + webhookEnabled: boolean; +} \ No newline at end of file