Skip to content

Commit 80eab3a

Browse files
authored
Merge pull request #1304 from Anthony-19/feat/add_request
Feat/add request
2 parents 55cafc1 + 45abd08 commit 80eab3a

6 files changed

Lines changed: 81 additions & 66 deletions

File tree

Dechat/dex_with_fiat_frontend/src/app/api/webhook/route.ts

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -166,24 +166,25 @@ export async function POST(request: NextRequest) {
166166
// Handle different event types
167167
switch (event.event) {
168168
case 'transfer.success': {
169-
const existingRecord = getTransferStatus(event.data.reference);
169+
const data = event.data ?? {};
170+
const existingRecord = getTransferStatus(data.reference ?? '');
170171
const updatedAt = new Date().toISOString();
171172
telemetry.addLog(span.spanId, 'info', 'Processing transfer success', {
172-
reference: event.data.reference,
173-
amount: event.data.amount,
174-
recipient: event.data.recipient,
175-
status: event.data.status,
173+
reference: data.reference,
174+
amount: data.amount,
175+
recipient: data.recipient,
176+
status: data.status,
176177
});
177178
console.log('Transfer successful:', {
178-
reference: event.data.reference,
179-
amount: event.data.amount,
180-
recipient: event.data.recipient,
181-
status: event.data.status,
179+
reference: data.reference,
180+
amount: data.amount,
181+
recipient: data.recipient,
182+
status: data.status,
182183
});
183184
const nextRecord = setTransferStatus({
184-
reference: event.data.reference,
185+
reference: data.reference ?? '',
185186
status: 'success',
186-
amount: event.data.amount,
187+
amount: data.amount,
187188
updatedAt,
188189
clientSessionId: existingRecord?.clientSessionId,
189190
});
@@ -197,27 +198,28 @@ export async function POST(request: NextRequest) {
197198
}
198199

199200
case 'transfer.failed': {
200-
const existingRecord = getTransferStatus(event.data.reference);
201+
const data = event.data ?? {};
202+
const existingRecord = getTransferStatus(data.reference ?? '');
201203
const updatedAt = new Date().toISOString();
202204
telemetry.addLog(span.spanId, 'warn', 'Processing transfer failure', {
203-
reference: event.data.reference,
204-
amount: event.data.amount,
205-
recipient: event.data.recipient,
206-
status: event.data.status,
207-
failureReason: event.data.failure_reason,
205+
reference: data.reference,
206+
amount: data.amount,
207+
recipient: data.recipient,
208+
status: data.status,
209+
failureReason: data.failure_reason,
208210
});
209211
console.log('Transfer failed:', {
210-
reference: event.data.reference,
211-
amount: event.data.amount,
212-
recipient: event.data.recipient,
213-
status: event.data.status,
214-
failure_reason: event.data.failure_reason,
212+
reference: data.reference,
213+
amount: data.amount,
214+
recipient: data.recipient,
215+
status: data.status,
216+
failure_reason: data.failure_reason,
215217
});
216218
const nextRecord = setTransferStatus({
217-
reference: event.data.reference,
219+
reference: data.reference ?? '',
218220
status: 'failed',
219-
amount: event.data.amount,
220-
failureReason: event.data.failure_reason,
221+
amount: data.amount,
222+
failureReason: data.failure_reason,
221223
updatedAt,
222224
clientSessionId: existingRecord?.clientSessionId,
223225
});
@@ -232,24 +234,25 @@ export async function POST(request: NextRequest) {
232234
}
233235

234236
case 'transfer.reversed': {
235-
const existingRecord = getTransferStatus(event.data.reference);
237+
const data = event.data ?? {};
238+
const existingRecord = getTransferStatus(data.reference ?? '');
236239
const updatedAt = new Date().toISOString();
237240
telemetry.addLog(span.spanId, 'info', 'Processing transfer reversal', {
238-
reference: event.data.reference,
239-
amount: event.data.amount,
240-
recipient: event.data.recipient,
241-
status: event.data.status,
241+
reference: data.reference,
242+
amount: data.amount,
243+
recipient: data.recipient,
244+
status: data.status,
242245
});
243246
console.log('Transfer reversed:', {
244-
reference: event.data.reference,
245-
amount: event.data.amount,
246-
recipient: event.data.recipient,
247-
status: event.data.status,
247+
reference: data.reference,
248+
amount: data.amount,
249+
recipient: data.recipient,
250+
status: data.status,
248251
});
249252
const nextRecord = setTransferStatus({
250-
reference: event.data.reference,
253+
reference: data.reference ?? '',
251254
status: 'reversed',
252-
amount: event.data.amount,
255+
amount: data.amount,
253256
updatedAt,
254257
clientSessionId: existingRecord?.clientSessionId,
255258
});

Dechat/dex_with_fiat_frontend/src/components/Message.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ export default function Message({ message, onActionClick, onRetry, shouldAnimate
148148
// Safely parse the timestamp — guards against deserialized string values
149149
const timestamp = toDate(message.timestamp);
150150

151+
const handleMessageKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
152+
if (hasError && e.key === 'r' && !e.ctrlKey && !e.metaKey) {
153+
retry.retryNow();
154+
}
155+
};
156+
151157
return (
152158
<motion.div
153159
data-testid="message"

Dechat/dex_with_fiat_frontend/src/components/__tests__/TransactionAmountDisplay.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,8 @@ describe('TransactionAmountDisplay - Framer Motion Animations', () => {
179179
afterEach(cleanup);
180180

181181
it('renders with motion.div wrapper for container animation', () => {
182-
const { container } = render(<TransactionAmountDisplay amount={100} asset="XLM" />);
183-
const wrapper = container.querySelector('.flex.flex-col');
182+
render(<TransactionAmountDisplay amount={100} asset="XLM" />);
183+
const wrapper = document.querySelector('.flex.flex-col');
184184
expect(wrapper).toBeInTheDocument();
185185
});
186186

Dechat/dex_with_fiat_frontend/src/hooks/useChatHistory.test.ts

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,6 @@ describe('Thread pinning ordering', () => {
125125
// after the closure was captured would be invisible to the lookup.
126126
// Fix: reads from `sessionsRef.current` which is kept current via a
127127
// synchronous ref-update effect.
128-
//
129-
// Because these are pure-logic tests (no React rendering required) they
130-
// replicate the core logic inline and verify the corrected behaviour.
131128

132129
describe('Race-condition fix: updateCurrentSession functional updater (#1213)', () => {
133130
it('update is a no-op when currentSessionId is null in latest state', () => {
@@ -202,8 +199,10 @@ describe('Race-condition fix: loadSession uses sessionsRef (#1213)', () => {
202199
// Callback captured here with empty sessions
203200
expect(loadSession('new')).toBeNull();
204201

205-
// Session added later — ref is updated synchronously (as the useEffect does)
206-
sessionsRef.current = [{ id: 'new', messages: ['hi'] }];
202+
describe('updateCurrentSession guard reads fresh state (regression #1223)', () => {
203+
beforeEach(() => {
204+
vi.clearAllMocks();
205+
});
207206

208207
// Now loadSession finds it, despite being "captured" before it existed
209208
const found = loadSession('new');
@@ -235,3 +234,26 @@ describe('Race-condition fix: loadSession uses sessionsRef (#1213)', () => {
235234
expect(nextState).toBe(state);
236235
});
237236
});
237+
238+
describe('Race-condition fix: loadSession uses sessionsRef (#1213)', () => {
239+
it('lookup finds a session added after the callback was captured', () => {
240+
// Simulate sessionsRef — always points to latest sessions array
241+
const sessionsRef = { current: [] as { id: string; messages: string[] }[] };
242+
243+
// Simulate the fixed loadSession using sessionsRef
244+
const loadSession = (sessionId: string) => {
245+
return sessionsRef.current.find((s) => s.id === sessionId) ?? null;
246+
};
247+
248+
// Callback captured here with empty sessions
249+
expect(loadSession('new')).toBeNull();
250+
251+
// Session added later — ref is updated synchronously (as the useEffect does)
252+
sessionsRef.current = [{ id: 'new', messages: ['hi'] }];
253+
254+
// Now loadSession finds it, despite being "captured" before it existed
255+
const found = loadSession('new');
256+
expect(found).not.toBeNull();
257+
expect(found?.messages).toEqual(['hi']);
258+
});
259+
});

Dechat/dex_with_fiat_frontend/src/hooks/useChatHistory.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export const useChatHistory = () => {
3939
}
4040
}, [historyState]);
4141

42-
// Debounced search avoids triggering a lookup on every keystroke
42+
// Debounced search - avoids triggering a lookup on every keystroke
4343
useEffect(() => {
4444
if (!searchQuery.trim()) {
4545
setSearchResults([]);
@@ -87,7 +87,7 @@ export const useChatHistory = () => {
8787
// `historyState.currentSessionId` from the closure, which could be stale
8888
// if multiple state updates were in-flight. The early-return guard has
8989
// been moved inside the functional updater so it always sees the latest
90-
// committed state no stale snapshot can cause a phantom update or a
90+
// committed state - no stale snapshot can cause a phantom update or a
9191
// missed guard.
9292
setHistoryState((prev) => {
9393
// Guard inside the functional updater so it always reads fresh state,

Dechat/dex_with_fiat_frontend/src/lib/chatTelemetry.ts

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -95,17 +95,8 @@ export interface NetworkStatusTelemetryPayload {
9595
source: 'initial' | 'browser-event' | 'connectivity-check';
9696
}
9797

98-
/** Split-view (two-thread comparison panel) interactions. */
99-
export type SplitViewTelemetryAction =
100-
| 'open'
101-
| 'close'
102-
| 'set_left_session'
103-
| 'set_right_session'
104-
| 'swap_sessions'
105-
| 'select_message';
106-
10798
export interface SplitViewTelemetryPayload {
108-
action: SplitViewTelemetryAction;
99+
action: 'open' | 'close' | 'set_left_session' | 'set_right_session' | 'swap_sessions' | 'select_message';
109100
leftSessionId?: string | null;
110101
rightSessionId?: string | null;
111102
}
@@ -493,17 +484,6 @@ export const chatTelemetry = {
493484
emit('network_status', payload);
494485
},
495486

496-
/**
497-
* Emit a `split_view` event recording an interaction with the two-thread
498-
* comparison panel (open/close/swap/session-select). Issue #1208: gives
499-
* product/analytics visibility into how often split view is used and
500-
* which actions are most common, using the same consent-gated, batched
501-
* `chatTelemetry` pipeline as every other chat event.
502-
*/
503-
splitView(payload: SplitViewTelemetryPayload): void {
504-
emit('split_view', payload);
505-
},
506-
507487
/**
508488
* Emit an `avatar_color_check` event that records whether the avatar
509489
* foreground/background colour pair meets WCAG AA contrast (4.5:1).
@@ -518,4 +498,8 @@ export const chatTelemetry = {
518498
avatarColorCheck(payload: AvatarColorTelemetryPayload): void {
519499
emit('avatar_color_check', payload);
520500
},
501+
502+
splitView(payload: SplitViewTelemetryPayload): void {
503+
emit('split_view', payload);
504+
},
521505
};

0 commit comments

Comments
 (0)