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
17 changes: 17 additions & 0 deletions apps/frontend/escrow/types/escrow-events.ts
Original file line number Diff line number Diff line change
@@ -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<string, unknown>;
}
27 changes: 27 additions & 0 deletions apps/frontend/hooks/useNotificationPreferences.ts
Original file line number Diff line number Diff line change
@@ -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',
);
},
});
69 changes: 69 additions & 0 deletions apps/frontend/lib/websocket/escrow-events.ts
Original file line number Diff line number Diff line change
@@ -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 (
<div
className="
flex items-center gap-2
text-sm
"
>
<span
className={
connected
? 'bg-green-500'
: 'bg-yellow-500'
}
/>

{connected
? 'Live'
: 'Reconnecting'}
</div>
);
}
21 changes: 21 additions & 0 deletions apps/frontend/services/notificationPreferences.ts
Original file line number Diff line number Diff line change
@@ -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;
}

26 changes: 26 additions & 0 deletions apps/frontend/services/webhooks.ts
Original file line number Diff line number Diff line change
@@ -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}`,
);
}
Empty file added apps/frontend/settings/page.tsx
Empty file.
16 changes: 16 additions & 0 deletions apps/frontend/types/notification-preferences.ts
Original file line number Diff line number Diff line change
@@ -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;
}
Loading