wip
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* ElectronCheckoutConfirmationAdapter
|
||||
* Implements ICheckoutConfirmationPort using Electron IPC for main-renderer communication.
|
||||
*/
|
||||
|
||||
import type { BrowserWindow } from 'electron';
|
||||
import { ipcMain } from 'electron';
|
||||
import { Result } from '../../../shared/result/Result';
|
||||
import type { ICheckoutConfirmationPort, CheckoutConfirmationRequest } from '../../../application/ports/ICheckoutConfirmationPort';
|
||||
import { CheckoutConfirmation } from '../../../domain/value-objects/CheckoutConfirmation';
|
||||
|
||||
export class ElectronCheckoutConfirmationAdapter implements ICheckoutConfirmationPort {
|
||||
private mainWindow: BrowserWindow;
|
||||
private pendingConfirmation: {
|
||||
resolve: (confirmation: CheckoutConfirmation) => void;
|
||||
reject: (error: Error) => void;
|
||||
timeoutId: NodeJS.Timeout;
|
||||
} | null = null;
|
||||
|
||||
constructor(mainWindow: BrowserWindow) {
|
||||
this.mainWindow = mainWindow;
|
||||
this.setupIpcHandlers();
|
||||
}
|
||||
|
||||
private setupIpcHandlers(): void {
|
||||
// Listen for confirmation response from renderer
|
||||
ipcMain.on('checkout:confirm', (_event, decision: 'confirmed' | 'cancelled' | 'timeout') => {
|
||||
if (!this.pendingConfirmation) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear timeout
|
||||
clearTimeout(this.pendingConfirmation.timeoutId);
|
||||
|
||||
// Create confirmation based on decision
|
||||
const confirmation = CheckoutConfirmation.create(decision);
|
||||
this.pendingConfirmation.resolve(confirmation);
|
||||
this.pendingConfirmation = null;
|
||||
});
|
||||
}
|
||||
|
||||
async requestCheckoutConfirmation(
|
||||
request: CheckoutConfirmationRequest
|
||||
): Promise<Result<CheckoutConfirmation>> {
|
||||
try {
|
||||
// Only allow one pending confirmation at a time
|
||||
if (this.pendingConfirmation) {
|
||||
return Result.err(new Error('Confirmation already pending'));
|
||||
}
|
||||
|
||||
// Send request to renderer
|
||||
this.mainWindow.webContents.send('checkout:request-confirmation', {
|
||||
price: request.price.toDisplayString(),
|
||||
state: request.state.isReady() ? 'ready' : 'insufficient_funds',
|
||||
sessionMetadata: request.sessionMetadata,
|
||||
timeoutMs: request.timeoutMs,
|
||||
});
|
||||
|
||||
// Wait for response with timeout
|
||||
const confirmation = await new Promise<CheckoutConfirmation>((resolve, reject) => {
|
||||
const timeoutId = setTimeout(() => {
|
||||
this.pendingConfirmation = null;
|
||||
const timeoutConfirmation = CheckoutConfirmation.create('timeout');
|
||||
resolve(timeoutConfirmation);
|
||||
}, request.timeoutMs);
|
||||
|
||||
this.pendingConfirmation = {
|
||||
resolve,
|
||||
reject,
|
||||
timeoutId,
|
||||
};
|
||||
});
|
||||
|
||||
return Result.ok(confirmation);
|
||||
} catch (error) {
|
||||
this.pendingConfirmation = null;
|
||||
return Result.err(
|
||||
error instanceof Error ? error : new Error('Failed to request confirmation')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public cleanup(): void {
|
||||
if (this.pendingConfirmation) {
|
||||
clearTimeout(this.pendingConfirmation.timeoutId);
|
||||
this.pendingConfirmation = null;
|
||||
}
|
||||
ipcMain.removeAllListeners('checkout:confirm');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user