Skip to content
Merged
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
21 changes: 21 additions & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,27 @@ export default function App() {

return [{ fieldKey: 'email', message: 'Invalid email' }];
}}
onRegister={ async (_) => {
await new Promise((resolve) => setTimeout(resolve, 1000));

return [{ fieldKey: 'email', message: 'Invalid register!!!!!' }];
}}
onSubscribeClick={ (e, prevent) => {
console.log('onSubscribeClick', e.nativeEvent);
prevent();
}}
onLoginClick={ (e, prevent) => {
console.log('onLoginClick', e.nativeEvent);
prevent();
}}
onDiscoveryLinkClick={ (e, prevent) => {
console.log('onDiscoveryLinkClick', e.nativeEvent);
prevent();
}}
onDataPolicyClick={ (e, prevent) => {
console.log('onDataPolicyClick', e.nativeEvent);
prevent();
}}
/>
</View>
</SafeAreaView>
Expand Down
14 changes: 11 additions & 3 deletions ios/NativePaywallModule.mm
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,20 @@ @implementation NativePaywallModule
- (void)emit:(NSString *)event
data:(NSString *)data {

NSString *notifName = @"registerNotification";
NSString *extractedEventName = @"";
NSRange eventPrefixRange = [event rangeOfString:@"event."];
NSRange resolveSuffixRange = [event rangeOfString:@":resolve" options:NSBackwardsSearch];

if ([event containsString:@"onFormSubmit"]) {
notifName = @"formSubmitNotification";
if (eventPrefixRange.location != NSNotFound && resolveSuffixRange.location != NSNotFound &&
eventPrefixRange.location + eventPrefixRange.length < resolveSuffixRange.location) {
Comment thread
MorganBerger marked this conversation as resolved.

NSRange nameRange = NSMakeRange(eventPrefixRange.location + eventPrefixRange.length,
resolveSuffixRange.location - (eventPrefixRange.location + eventPrefixRange.length));
extractedEventName = [event substringWithRange:nameRange];
}

NSString *notifName = [[NSString alloc] initWithFormat:@"%@Notification", extractedEventName];

[NSNotificationCenter.defaultCenter postNotificationName:notifName
object:self
userInfo:@{@"object": data}];
Expand Down
76 changes: 65 additions & 11 deletions ios/PaywallView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ @implementation PaywallView {
NSMutableDictionary *_formSubmitObservers;
NSMutableDictionary *_registerObservers;

NSMutableDictionary *_preventActionObservers;

Access * access;

BOOL parented;
Expand Down Expand Up @@ -95,6 +97,7 @@ - (instancetype)initWithFrame:(CGRect)frame

_formSubmitObservers = [[NSMutableDictionary alloc] init];
_registerObservers = [[NSMutableDictionary alloc] init];
_preventActionObservers = [[NSMutableDictionary alloc] init];
}
return self;
}
Expand Down Expand Up @@ -207,42 +210,54 @@ - (void)initEvents
self.eventEmitter.onPaywallSeen(rnEvent);
}];

[access onSubscribeTappedWithOnce:false :^(ClickEvent * _Nullable event, void (^ _Nonnull callback)(void)) {
[access onSubscribeTappedWithOnce:false :^(ClickEvent * _Nullable event, void (^ _Nonnull prevent)()) {
NSNumber *messageId = [self setupObserverForNotif:@"onSubscribeClickNotification" method:prevent];

PaywallViewEventEmitter::OnSubscribeClick rnEvent = PaywallViewEventEmitter::OnSubscribeClick {
[event.widget UTF8String],
[event.actionName UTF8String],
[event.button UTF8String],
[event.url UTF8String],
[event.button UTF8String],
[messageId doubleValue],
};
self.eventEmitter.onSubscribeClick(rnEvent);
}];

[access onLoginTappedWithOnce:false :^(ClickEvent * _Nullable event, void (^ _Nonnull callback)(void)) {

[access onLoginTappedWithOnce:false :^(ClickEvent * _Nullable event, void (^ _Nonnull prevent)()) {
NSNumber *messageId = [self setupObserverForNotif:@"onLoginClickNotification" method:prevent];

PaywallViewEventEmitter::OnLoginClick rnEvent = PaywallViewEventEmitter::OnLoginClick {
[event.widget UTF8String],
[event.actionName UTF8String],
[event.button UTF8String],
[event.url UTF8String],
[event.button UTF8String],
[messageId doubleValue],
};
self.eventEmitter.onLoginClick(rnEvent);
}];

[access onDiscoveryLinkTappedWithOnce:false :^(ClickEvent * _Nullable event, void (^ _Nonnull callback)(void)) {
[access onDiscoveryLinkTappedWithOnce:false :^(ClickEvent * _Nullable event, void (^ _Nonnull prevent)()) {
NSNumber *messageId = [self setupObserverForNotif:@"onDiscoveryLinkClickNotification" method:prevent];

PaywallViewEventEmitter::OnDiscoveryLinkClick rnEvent = PaywallViewEventEmitter::OnDiscoveryLinkClick {
[event.widget UTF8String],
[event.actionName UTF8String],
[event.button UTF8String],
[event.url UTF8String],
[messageId doubleValue],
};
self.eventEmitter.onDiscoveryLinkClick(rnEvent);
}];

[access onDataPolicyTappedWithOnce:false :^(ClickEvent * _Nullable event, void (^ _Nonnull callback)(void)) {
[access onDataPolicyTappedWithOnce:false :^(ClickEvent * _Nullable event, void (^ _Nonnull prevent)()) {
NSNumber *messageId = [self setupObserverForNotif:@"onDataPolicyClickNotification" method:prevent];

PaywallViewEventEmitter::OnDataPolicyClick rnEvent = PaywallViewEventEmitter::OnDataPolicyClick {
[event.widget UTF8String],
[event.actionName UTF8String],
[event.button UTF8String],
[event.url UTF8String],
[messageId doubleValue],
};
self.eventEmitter.onDataPolicyClick(rnEvent);
}];
Expand All @@ -255,6 +270,7 @@ - (void)initEvents
};
self.eventEmitter.onAlternativeClick(rnEvent);
}];

[access onErrorWithOnce:false :^(ErrorEvent * _Nullable event, void (^ _Nonnull)(void)) {
PaywallViewEventEmitter::OnError rnEvent = PaywallViewEventEmitter::OnError {
[event.error UTF8String]
Expand Down Expand Up @@ -283,7 +299,8 @@ - (void)initEvents
}];

[access onFormSubmitWithOnce:false submitter:^(FormEvent * _Nonnull event, void (^ _Nonnull method)(NSArray<InvalidForm *> * _Nonnull)) {
NSString *notifName = @"formSubmitNotification";
NSString *notifName = @"onFormSubmitNotification";

NSNumber *messageId = @(arc4random());

NSString *fieldsStr = [self arrayToString:event.fields.allKeys];
Expand All @@ -307,8 +324,11 @@ - (void)initEvents

self.eventEmitter.onFormSubmit(rnEvent);
}];

[access onRegisterWithOnce:false :^(RegisterEvent * _Nonnull event, void (^ _Nonnull method)(NSString * _Nullable)) {
NSString *notifName = @"registerNotification";

NSString *notifName = @"onRegisterNotification";

NSNumber *messageId = @(arc4random());

NSString *newsletterId = event.newsletterId ? event.newsletterId : @"";
Expand All @@ -332,6 +352,40 @@ - (void)initEvents
}];
}

-(NSNumber*)setupObserverForNotif:(NSString*)notifName method:(void (^ _Nonnull)())prevent
{
NSNumber *messageId = @(arc4random());

id observer = [NSNotificationCenter.defaultCenter addObserverForName:notifName
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification * _Nonnull notification) {
[self onClickNotification:notification messageId:messageId method:prevent];
}];

Comment thread
MorganBerger marked this conversation as resolved.
[self->_preventActionObservers setObject:observer forKey:messageId];

return messageId;
}

-(void)onClickNotification:(NSNotification*)notification
messageId:(NSNumber*)messageId
method:(void (^ _Nonnull)())prevent
{
NSDictionary *dataDict = [self extractDictFromNotifObject: notification.userInfo[@"object"]];

if (dataDict[@"_messageId"] == messageId) {
[NSNotificationCenter.defaultCenter removeObserver:_preventActionObservers[messageId]];
[_preventActionObservers removeObjectForKey:messageId];
Comment thread
MorganBerger marked this conversation as resolved.

BOOL prevented = [(NSNumber*)dataDict[@"prevented"] boolValue];

if (prevented) {
prevent();
}
}
}

-(void)onFormSubmitNotification:(NSNotification*)notification
messageId:(NSNumber*)messageId
method:(void (^ _Nonnull)(NSArray<InvalidForm *> * _Nonnull))method
Expand Down Expand Up @@ -369,9 +423,9 @@ -(void)onRegisterNotification:(NSNotification*)notification
if (dict[@"_messageId"] == messageId) {
NSArray *remoteArray = dict[@"data"];

NSString* message;
NSString* message = nil;

if (dict.count > 0) {
if (remoteArray.count > 0) {
message = remoteArray[0][@"message"];
}

Expand Down
49 changes: 47 additions & 2 deletions src/Paywall/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ import PaywallView, {
type NativeProps,
type FormEvent,
type RegisterEvent,
type ClickEvent,
} from '../specs/PaywallViewNativeComponent';
import NativePaywallModule from '../specs/NativePaywallModule';
import type { NativeSyntheticEvent } from 'react-native';

export interface PaywallProps extends Omit<
NativeProps,
'appId' | 'config' | 'texts' | 'styles' | 'variables' |
'onFormSubmit' | 'onRegister'
'onFormSubmit' | 'onRegister' |
'onSubscribeClick' | 'onLoginClick' | 'onDiscoveryLinkClick' | 'onDataPolicyClick'
> {
/**
* Optional unique paywall id. When released, the snippet with the same id
Expand All @@ -32,6 +34,11 @@ export interface PaywallProps extends Omit<

onFormSubmit?: DirectEventHandlerWithResult<FormEvent, FieldError[]>;
onRegister?: DirectEventHandlerWithResult<RegisterEvent, FieldError[]>;

onSubscribeClick?: (event: NativeSyntheticEvent<ClickEvent>, prevent: () => void) => void | Promise<void>;
onLoginClick?: (event: NativeSyntheticEvent<ClickEvent>, prevent: () => void) => void | Promise<void>;
onDiscoveryLinkClick?: (event: NativeSyntheticEvent<ClickEvent>, prevent: () => void) => void | Promise<void>;
onDataPolicyClick?: (event: NativeSyntheticEvent<ClickEvent>, prevent: () => void) => void | Promise<void>;
}

export interface PaywallState {
Expand All @@ -51,6 +58,10 @@ const Paywall = ({
onRelease,
onFormSubmit,
onRegister,
onSubscribeClick,
onLoginClick,
onDiscoveryLinkClick,
onDataPolicyClick,
...rest
}: PaywallProps) => {
const {
Expand All @@ -72,6 +83,7 @@ const Paywall = ({
...factoryConfig,
...config,
}), [config, factoryConfig]);

const serializedConfig = useMemo(() => (
JSON.stringify({
...rawConfig,
Expand All @@ -92,13 +104,14 @@ const Paywall = ({
const innerRef = useRef(null);

const sendMessage = (
e: NativeSyntheticEvent<FormEvent | RegisterEvent>,
e: NativeSyntheticEvent<FormEvent | RegisterEvent | ClickEvent>,
type: string,
data: any,
) => {
const message = JSON.stringify({
type,
data,
prevented: (e.nativeEvent as any).prevented,
_messageId: e.nativeEvent._messageId
});

Expand All @@ -114,6 +127,26 @@ const Paywall = ({
NativePaywallModule.emit('poool:rn:event.' + type, message);
};

const sendClickEvent = async (
event: NativeSyntheticEvent<ClickEvent>,
eventName: string,
onClick: ((e: NativeSyntheticEvent<ClickEvent>, prevent: () => void) => void) | undefined,
) => {
event.persist();

try {
event.nativeEvent.prevented = false;
await onClick?.(event, () => {
event.nativeEvent.prevented = true;
});
sendMessage(event, eventName + ':resolve', {});
} catch (error) {
sendMessage(event, eventName + ':reject', {
message: (error as Error).message || error,
});
}
};

return (
<PaywallView
ref={innerRef}
Expand Down Expand Up @@ -166,6 +199,18 @@ const Paywall = ({
});
}
}}
onSubscribeClick={ async (e) => {
await sendClickEvent(e, 'onSubscribeClick', onSubscribeClick);
}}
onLoginClick={ async (e) => {
await sendClickEvent(e, 'onLoginClick', onLoginClick);
}}
onDataPolicyClick={ async (e) => {
await sendClickEvent(e, 'onDataPolicyClick', onDataPolicyClick);
}}
onDiscoveryLinkClick={ async (e) => {
await sendClickEvent(e, 'onDiscoveryLinkClick', onDiscoveryLinkClick);
}}
/>
);
};
Expand Down
2 changes: 2 additions & 0 deletions src/specs/PaywallViewNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ export interface RegisterEvent {
export interface ClickEvent extends WidgetEvent {
url: string;
button: string;
_messageId: CodegenTypes.Double;
prevented: boolean;
}

export interface AlternativeClickEvent extends WidgetEvent {
Expand Down
Loading