-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
🎟️ [OJS] Payment request coupon fixes (#43)
* fixes * wip * fix * cleanup * cleanup * cleanup * ver bump
- Loading branch information
Showing
13 changed files
with
494 additions
and
46 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { z } from 'zod'; | ||
import { CdeConnection, CdeMessage } from './cde-connection'; | ||
import { CheckoutPreviewRequest } from './shared-models'; | ||
import { PreviewCheckoutResponse } from './cde_models'; | ||
|
||
const queryCDE = async <T extends z.ZodType>( | ||
cdeConn: CdeConnection, | ||
data: CdeMessage, | ||
responseSchema: T | ||
): Promise<z.infer<T>> => { | ||
// Leaving these as commented out for easier debugging later | ||
// console.log('[cde-client] Querying CDE with path and connection:', data.type, cdeConn); | ||
const response = await cdeConn.send(data); | ||
// console.log('[cde-client] Got response from CDE:', response); | ||
if (!checkIfConformsToSchema(response, responseSchema)) { | ||
const result = responseSchema.safeParse(response); | ||
if (result.success) throw new Error('Invalid state'); | ||
throw result.error; | ||
} | ||
return response; | ||
}; | ||
|
||
const checkIfConformsToSchema = <T extends z.ZodType>(value: unknown, schema: T): value is T => { | ||
return schema.safeParse(value).success; | ||
}; | ||
|
||
// Endpoints start here | ||
|
||
export const getCheckoutPreview = async ( | ||
cdeConn: CdeConnection, | ||
request: CheckoutPreviewRequest | ||
): Promise<PreviewCheckoutResponse> => { | ||
return await queryCDE(cdeConn, { type: 'get_checkout_preview', payload: request }, PreviewCheckoutResponse); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { CallSender, Connection, connectToChild } from 'penpal'; | ||
import { useState } from 'react'; | ||
import useAsyncEffect from 'use-async-effect'; | ||
|
||
export type CdeMessage = { | ||
type: string; | ||
} & Record<string, unknown>; | ||
|
||
export type CdeConnection = { | ||
send: (data: CdeMessage) => Promise<unknown>; | ||
}; | ||
|
||
type HookReturnType = { | ||
cdeConn: CdeConnection | null; | ||
connectToCdeIframe: (iframe: HTMLIFrameElement) => Promise<void>; | ||
}; | ||
|
||
type ConnectionStatus = | ||
| { | ||
status: 'none'; | ||
} | ||
| { | ||
status: 'connecting'; | ||
} | ||
| { | ||
status: 'waiting'; | ||
conn: Connection<CallSender>; | ||
} | ||
| { | ||
status: 'connected'; | ||
conn: CdeConnection; | ||
}; | ||
|
||
export const useCDEConnection = (): HookReturnType => { | ||
const [childConn, setChildConn] = useState<ConnectionStatus>({ status: 'none' }); | ||
|
||
const connectToCdeIframe = async (iframe: HTMLIFrameElement): Promise<void> => { | ||
if (childConn.status !== 'none') { | ||
console.warn('registerIframe called more than once'); | ||
return; | ||
} | ||
console.log('Connecting to CDE iframe...', iframe); | ||
setChildConn({ status: 'connecting' }); | ||
const conn = connectToChild({ | ||
iframe, | ||
debug: true, | ||
}); | ||
setChildConn({ status: 'waiting', conn }); | ||
}; | ||
|
||
// Wait for connection | ||
useAsyncEffect(async () => { | ||
if (childConn.status !== 'waiting') return; | ||
const child: unknown = await childConn.conn.promise; | ||
const isValidConnObject = await checkIfValidCdeConnectionObject(child); | ||
if (!isResultValid(child, isValidConnObject)) { | ||
throw new Error(`Got invalid CDE connection object`); | ||
} | ||
setChildConn({ status: 'connected', conn: child }); | ||
}, [childConn.status]); | ||
|
||
return { | ||
cdeConn: childConn.status === 'connected' ? childConn.conn : null, | ||
connectToCdeIframe, | ||
}; | ||
}; | ||
|
||
const checkIfValidCdeConnectionObject = async (obj: unknown): Promise<boolean> => { | ||
if (typeof obj !== 'object' || !obj) return false; | ||
try { | ||
const ping: CdeMessage = { type: 'ping' }; | ||
// @ts-expect-error `send` typing | ||
const result = await obj.send(ping); | ||
if (result !== true) { | ||
throw new Error(`Expected 'true' after ping, got ${JSON.stringify(result)}`); | ||
} | ||
return true; | ||
} catch (e) { | ||
console.error(`Invalid CDE connection check:`, e); | ||
return false; | ||
} | ||
}; | ||
|
||
// Work around as an async type guard | ||
const isResultValid = (obj: unknown, isValid: boolean): obj is CdeConnection => { | ||
return !!obj && isValid; | ||
}; |
Oops, something went wrong.