react-native-klarna-inapp-sdk 2.4.10 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/android/build.gradle +3 -1
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/KlarnaMobileSDKPackage.java +5 -1
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/checkout/KlarnaCheckoutViewManager.java +4 -10
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/WebViewResizeObserver.java +28 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/event/ComponentEventSender.java +5 -1
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/ui/ResizeObserverWrapperView.java +2 -2
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/ui/WrapperView.java +2 -2
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/ui/YogaLayoutHelper.java +39 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/expresscheckout/KlarnaExpressCheckoutViewCallback.kt +30 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/expresscheckout/KlarnaExpressCheckoutViewEventSender.kt +80 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/expresscheckout/KlarnaExpressCheckoutViewManager.java +544 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/osm/KlarnaOSMViewEventHandler.java +30 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/osm/KlarnaOSMViewEventSender.java +64 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/osm/KlarnaOSMViewManager.java +356 -0
- package/android/src/newarch/java/com/klarna/mobile/sdk/reactnative/spec/RNKlarnaExpressCheckoutViewSpec.java +31 -0
- package/android/src/newarch/java/com/klarna/mobile/sdk/reactnative/spec/RNKlarnaOSMViewSpec.java +31 -0
- package/android/src/oldarch/java/com/klarna/mobile/sdk/reactnative/spec/RNKlarnaExpressCheckoutViewSpec.java +36 -0
- package/android/src/oldarch/java/com/klarna/mobile/sdk/reactnative/spec/RNKlarnaOSMViewSpec.java +32 -0
- package/android/src/test/java/com/klarna/mobile/sdk/reactnative/KlarnaMobileSDKPackageTest.java +5 -1
- package/android/src/test/java/com/klarna/mobile/sdk/reactnative/common/ui/YogaLayoutHelperTest.java +79 -0
- package/android/src/test/java/com/klarna/mobile/sdk/reactnative/expresscheckout/KlarnaExpressCheckoutViewManagerTest.java +259 -0
- package/android/src/test/java/com/klarna/mobile/sdk/reactnative/osm/KlarnaOSMViewEventHandlerTest.java +136 -0
- package/android/src/test/java/com/klarna/mobile/sdk/reactnative/osm/KlarnaOSMViewEventSenderTest.java +184 -0
- package/android/src/test/java/com/klarna/mobile/sdk/reactnative/osm/KlarnaOSMViewManagerTest.java +385 -0
- package/ios/RNKlarnaMobileSDK.xcodeproj/project.pbxproj +55 -1
- package/ios/Sources/KlarnaExpressCheckoutViewManager.h +5 -0
- package/ios/Sources/KlarnaExpressCheckoutViewManager.mm +39 -0
- package/ios/Sources/KlarnaOSMViewManager.h +5 -0
- package/ios/Sources/KlarnaOSMViewManager.mm +59 -0
- package/ios/Sources/view/KlarnaExpressCheckoutButtonDelegateProxy.swift +145 -0
- package/ios/Sources/view/KlarnaExpressCheckoutViewWrapper.h +41 -0
- package/ios/Sources/view/KlarnaOSMViewWrapper.h +48 -0
- package/ios/Sources/view/newarch/KlarnaExpressCheckoutViewWrapper.mm +228 -0
- package/ios/Sources/view/newarch/KlarnaOSMViewWrapper.mm +294 -0
- package/ios/Sources/view/newarch/KlarnaStandaloneWebViewWrapper.mm +20 -13
- package/ios/Sources/view/oldarch/KlarnaExpressCheckoutViewWrapper.mm +222 -0
- package/ios/Sources/view/oldarch/KlarnaOSMViewWrapper.mm +273 -0
- package/ios/Sources/view/oldarch/KlarnaStandaloneWebViewWrapper.mm +11 -13
- package/ios/Tests/KlarnaExpressCheckoutViewWrapperTests.m +391 -0
- package/ios/Tests/KlarnaOSMViewWrapperTests.m +450 -0
- package/ios/Tests/KlarnaStandaloneWebViewWrapperTests.m +105 -0
- package/lib/commonjs/KlarnaExpressCheckoutView.js +75 -0
- package/lib/commonjs/KlarnaExpressCheckoutView.js.map +1 -0
- package/lib/commonjs/KlarnaOSMView.js +94 -0
- package/lib/commonjs/KlarnaOSMView.js.map +1 -0
- package/lib/commonjs/index.js +99 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/specs/KlarnaExpressCheckoutViewNativeComponent.js +11 -0
- package/lib/commonjs/specs/KlarnaExpressCheckoutViewNativeComponent.js.map +1 -0
- package/lib/commonjs/specs/KlarnaOSMViewNativeComponent.js +16 -0
- package/lib/commonjs/specs/KlarnaOSMViewNativeComponent.js.map +1 -0
- package/lib/commonjs/types/button/KlarnaButtonShape.js +14 -0
- package/lib/commonjs/types/button/KlarnaButtonShape.js.map +1 -0
- package/lib/commonjs/types/button/KlarnaButtonStyle.js +13 -0
- package/lib/commonjs/types/button/KlarnaButtonStyle.js.map +1 -0
- package/lib/commonjs/types/button/KlarnaButtonTheme.js +14 -0
- package/lib/commonjs/types/button/KlarnaButtonTheme.js.map +1 -0
- package/lib/commonjs/types/common/KlarnaExpressCheckoutSessionOptions.js +9 -0
- package/lib/commonjs/types/common/KlarnaExpressCheckoutSessionOptions.js.map +1 -0
- package/lib/commonjs/types/common/KlarnaOSMPlacementKey.js +2 -0
- package/lib/commonjs/types/common/KlarnaOSMPlacementKey.js.map +1 -0
- package/lib/commonjs/types/common/KlarnaTheme.js +14 -0
- package/lib/commonjs/types/common/KlarnaTheme.js.map +1 -0
- package/lib/module/KlarnaExpressCheckoutView.js +64 -0
- package/lib/module/KlarnaExpressCheckoutView.js.map +1 -0
- package/lib/module/KlarnaOSMView.js +84 -0
- package/lib/module/KlarnaOSMView.js.map +1 -0
- package/lib/module/index.js +9 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/specs/KlarnaExpressCheckoutViewNativeComponent.js +3 -0
- package/lib/module/specs/KlarnaExpressCheckoutViewNativeComponent.js.map +1 -0
- package/lib/module/specs/KlarnaOSMViewNativeComponent.js +7 -0
- package/lib/module/specs/KlarnaOSMViewNativeComponent.js.map +1 -0
- package/lib/module/types/button/KlarnaButtonShape.js +7 -0
- package/lib/module/types/button/KlarnaButtonShape.js.map +1 -0
- package/lib/module/types/button/KlarnaButtonStyle.js +6 -0
- package/lib/module/types/button/KlarnaButtonStyle.js.map +1 -0
- package/lib/module/types/button/KlarnaButtonTheme.js +7 -0
- package/lib/module/types/button/KlarnaButtonTheme.js.map +1 -0
- package/lib/module/types/common/KlarnaExpressCheckoutSessionOptions.js +2 -0
- package/lib/module/types/common/KlarnaExpressCheckoutSessionOptions.js.map +1 -0
- package/lib/module/types/common/KlarnaOSMPlacementKey.js +2 -0
- package/lib/module/types/common/KlarnaOSMPlacementKey.js.map +1 -0
- package/lib/module/types/common/KlarnaTheme.js +7 -0
- package/lib/module/types/common/KlarnaTheme.js.map +1 -0
- package/lib/typescript/KlarnaExpressCheckoutView.d.ts +47 -0
- package/lib/typescript/KlarnaExpressCheckoutView.d.ts.map +1 -0
- package/lib/typescript/KlarnaOSMView.d.ts +36 -0
- package/lib/typescript/KlarnaOSMView.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +9 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/specs/KlarnaExpressCheckoutViewNativeComponent.d.ts +45 -0
- package/lib/typescript/specs/KlarnaExpressCheckoutViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/specs/KlarnaOSMViewNativeComponent.d.ts +35 -0
- package/lib/typescript/specs/KlarnaOSMViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/types/button/KlarnaButtonShape.d.ts +6 -0
- package/lib/typescript/types/button/KlarnaButtonShape.d.ts.map +1 -0
- package/lib/typescript/types/button/KlarnaButtonStyle.d.ts +5 -0
- package/lib/typescript/types/button/KlarnaButtonStyle.d.ts.map +1 -0
- package/lib/typescript/types/button/KlarnaButtonTheme.d.ts +6 -0
- package/lib/typescript/types/button/KlarnaButtonTheme.d.ts.map +1 -0
- package/lib/typescript/types/common/KlarnaExpressCheckoutSessionOptions.d.ts +10 -0
- package/lib/typescript/types/common/KlarnaExpressCheckoutSessionOptions.d.ts.map +1 -0
- package/lib/typescript/types/common/KlarnaOSMPlacementKey.d.ts +2 -0
- package/lib/typescript/types/common/KlarnaOSMPlacementKey.d.ts.map +1 -0
- package/lib/typescript/types/common/KlarnaTheme.d.ts +6 -0
- package/lib/typescript/types/common/KlarnaTheme.d.ts.map +1 -0
- package/package.json +5 -3
- package/react-native-klarna-inapp-sdk.podspec +2 -1
- package/src/KlarnaExpressCheckoutView.tsx +169 -0
- package/src/KlarnaOSMView.tsx +157 -0
- package/src/index.tsx +9 -0
- package/src/specs/KlarnaExpressCheckoutViewNativeComponent.ts +66 -0
- package/src/specs/KlarnaOSMViewNativeComponent.ts +50 -0
- package/src/types/button/KlarnaButtonShape.ts +5 -0
- package/src/types/button/KlarnaButtonStyle.ts +4 -0
- package/src/types/button/KlarnaButtonTheme.ts +5 -0
- package/src/types/common/KlarnaExpressCheckoutSessionOptions.ts +13 -0
- package/src/types/common/KlarnaOSMPlacementKey.ts +3 -0
- package/src/types/common/KlarnaTheme.ts +5 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
#if RCT_NEW_ARCH_ENABLED
|
|
2
|
+
|
|
3
|
+
#import <AVFoundation/AVFoundation.h>
|
|
4
|
+
#import <react/renderer/components/RNKlarnaMobileSDK/ComponentDescriptors.h>
|
|
5
|
+
#import <react/renderer/components/RNKlarnaMobileSDK/EventEmitters.h>
|
|
6
|
+
#import <react/renderer/components/RNKlarnaMobileSDK/Props.h>
|
|
7
|
+
#import <react/renderer/components/RNKlarnaMobileSDK/RCTComponentViewHelpers.h>
|
|
8
|
+
#import "../KlarnaOSMViewWrapper.h"
|
|
9
|
+
#import "../../common/RNMobileSDKUtils.h"
|
|
10
|
+
#import "RCTFabricComponentsPlugins.h"
|
|
11
|
+
#import <KlarnaMobileSDK/KlarnaMobileSDK.h>
|
|
12
|
+
#import <KlarnaMobileSDK/KlarnaMobileSDK-Swift.h>
|
|
13
|
+
|
|
14
|
+
using namespace facebook::react;
|
|
15
|
+
|
|
16
|
+
@interface KlarnaOSMViewWrapper () <KlarnaEventHandler, KlarnaSizingDelegate, RCTRNKlarnaOSMViewViewProtocol>
|
|
17
|
+
|
|
18
|
+
@property (nonatomic, strong) KlarnaOSMView* klarnaOSMView;
|
|
19
|
+
@property (nonatomic, assign) BOOL isOSMViewReadyEventSent;
|
|
20
|
+
|
|
21
|
+
@end
|
|
22
|
+
|
|
23
|
+
@implementation KlarnaOSMViewWrapper
|
|
24
|
+
|
|
25
|
+
#pragma mark - Initialization
|
|
26
|
+
|
|
27
|
+
- (instancetype)initWithFrame:(CGRect)frame
|
|
28
|
+
{
|
|
29
|
+
self = [super initWithFrame:frame];
|
|
30
|
+
if (self) {
|
|
31
|
+
self.isOSMViewReadyEventSent = NO;
|
|
32
|
+
self.backgroundColor = [UIColor clearColor];
|
|
33
|
+
static const auto defaultProps = std::make_shared<const RNKlarnaOSMViewProps>();
|
|
34
|
+
_props = defaultProps;
|
|
35
|
+
[self initializeKlarnaOSMView];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return self;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
|
42
|
+
{
|
|
43
|
+
return concreteComponentDescriptorProvider<RNKlarnaOSMViewComponentDescriptor>();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
Class<RCTComponentViewProtocol> RNKlarnaOSMViewCls(void)
|
|
47
|
+
{
|
|
48
|
+
return KlarnaOSMViewWrapper.class;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args {
|
|
52
|
+
RCTRNKlarnaOSMViewHandleCommand(self, commandName, args);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
#pragma mark - KlarnaOSMView Props Update
|
|
56
|
+
|
|
57
|
+
- (void)updateProps:(const facebook::react::Props::Shared &)props oldProps:(const facebook::react::Props::Shared &)oldProps {
|
|
58
|
+
const auto &oldViewProps = *std::static_pointer_cast<RNKlarnaOSMViewProps const>(_props);
|
|
59
|
+
const auto &newViewProps = *std::static_pointer_cast<RNKlarnaOSMViewProps const>(props);
|
|
60
|
+
|
|
61
|
+
if (oldViewProps.clientId != newViewProps.clientId) {
|
|
62
|
+
NSString *value = [[NSString alloc] initWithUTF8String:newViewProps.clientId.c_str()];
|
|
63
|
+
self.klarnaOSMView.clientId = value;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (oldViewProps.placementKey != newViewProps.placementKey) {
|
|
67
|
+
NSString *value = [[NSString alloc] initWithUTF8String:newViewProps.placementKey.c_str()];
|
|
68
|
+
self.klarnaOSMView.placementKey = value;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (oldViewProps.locale != newViewProps.locale) {
|
|
72
|
+
NSString *value = [[NSString alloc] initWithUTF8String:newViewProps.locale.c_str()];
|
|
73
|
+
if (value.length > 0) {
|
|
74
|
+
self.klarnaOSMView.locale = value;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (oldViewProps.purchaseAmount != newViewProps.purchaseAmount) {
|
|
79
|
+
NSString *value = [[NSString alloc] initWithUTF8String:newViewProps.purchaseAmount.c_str()];
|
|
80
|
+
if (value.length > 0) {
|
|
81
|
+
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
|
|
82
|
+
formatter.numberStyle = NSNumberFormatterDecimalStyle;
|
|
83
|
+
NSNumber *amount = [formatter numberFromString:value];
|
|
84
|
+
if (amount != nil) {
|
|
85
|
+
[self.klarnaOSMView setPurchaseAmount:amount];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (oldViewProps.environment != newViewProps.environment) {
|
|
91
|
+
NSString *value = [[NSString alloc] initWithUTF8String:newViewProps.environment.c_str()];
|
|
92
|
+
if (value.length > 0) {
|
|
93
|
+
if ([value isEqualToString:@"playground"]) {
|
|
94
|
+
self.klarnaOSMView.environment = KlarnaEnvironment.playground;
|
|
95
|
+
} else if ([value isEqualToString:@"production"]) {
|
|
96
|
+
self.klarnaOSMView.environment = KlarnaEnvironment.production;
|
|
97
|
+
} else if ([value isEqualToString:@"staging"]) {
|
|
98
|
+
self.klarnaOSMView.environment = KlarnaEnvironment.staging;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (oldViewProps.region != newViewProps.region) {
|
|
104
|
+
NSString *value = [[NSString alloc] initWithUTF8String:newViewProps.region.c_str()];
|
|
105
|
+
if (value.length > 0) {
|
|
106
|
+
if ([value isEqualToString:@"eu"]) {
|
|
107
|
+
self.klarnaOSMView.region = KlarnaRegion.eu;
|
|
108
|
+
} else if ([value isEqualToString:@"na"]) {
|
|
109
|
+
self.klarnaOSMView.region = KlarnaRegion.na;
|
|
110
|
+
} else if ([value isEqualToString:@"oc"]) {
|
|
111
|
+
self.klarnaOSMView.region = KlarnaRegion.oc;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (oldViewProps.theme != newViewProps.theme) {
|
|
117
|
+
NSString *value = [[NSString alloc] initWithUTF8String:newViewProps.theme.c_str()];
|
|
118
|
+
if (value.length > 0) {
|
|
119
|
+
if ([value isEqualToString:@"light"]) {
|
|
120
|
+
self.klarnaOSMView.theme = KlarnaThemeLight;
|
|
121
|
+
} else if ([value isEqualToString:@"dark"]) {
|
|
122
|
+
self.klarnaOSMView.theme = KlarnaThemeDark;
|
|
123
|
+
} else if ([value isEqualToString:@"automatic"]) {
|
|
124
|
+
self.klarnaOSMView.theme = KlarnaThemeAutomatic;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
BOOL styleChanged = NO;
|
|
130
|
+
if (oldViewProps.backgroundColor != newViewProps.backgroundColor) {
|
|
131
|
+
styleChanged = YES;
|
|
132
|
+
}
|
|
133
|
+
if (oldViewProps.textColor != newViewProps.textColor) {
|
|
134
|
+
styleChanged = YES;
|
|
135
|
+
}
|
|
136
|
+
if (styleChanged) {
|
|
137
|
+
NSString *bgColorStr = [[NSString alloc] initWithUTF8String:newViewProps.backgroundColor.c_str()];
|
|
138
|
+
NSString *txtColorStr = [[NSString alloc] initWithUTF8String:newViewProps.textColor.c_str()];
|
|
139
|
+
[self updateStyleConfigurationWithBackgroundColor:bgColorStr textColor:txtColorStr];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
[super updateProps:props oldProps:oldProps];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
- (void)updateEventEmitter:(const facebook::react::EventEmitter::Shared &)eventEmitter
|
|
146
|
+
{
|
|
147
|
+
[super updateEventEmitter:eventEmitter];
|
|
148
|
+
|
|
149
|
+
if (!self.isOSMViewReadyEventSent && self.klarnaOSMView != nil && _eventEmitter) {
|
|
150
|
+
auto emitter = std::dynamic_pointer_cast<const RNKlarnaOSMViewEventEmitter>(_eventEmitter);
|
|
151
|
+
if (emitter) {
|
|
152
|
+
emitter->onOSMViewReady({});
|
|
153
|
+
self.isOSMViewReadyEventSent = YES;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
#pragma mark - KlarnaOSMView Setup
|
|
159
|
+
|
|
160
|
+
- (void)initializeKlarnaOSMView {
|
|
161
|
+
self.isOSMViewReadyEventSent = NO;
|
|
162
|
+
self.klarnaOSMView = [[KlarnaOSMView alloc] init];
|
|
163
|
+
self.klarnaOSMView.eventHandler = self;
|
|
164
|
+
self.klarnaOSMView.sizingDelegate = self;
|
|
165
|
+
self.klarnaOSMView.backgroundColor = [UIColor clearColor];
|
|
166
|
+
|
|
167
|
+
self.klarnaOSMView.translatesAutoresizingMaskIntoConstraints = NO;
|
|
168
|
+
|
|
169
|
+
[self addSubview:self.klarnaOSMView];
|
|
170
|
+
|
|
171
|
+
[NSLayoutConstraint activateConstraints:[[NSArray alloc] initWithObjects:
|
|
172
|
+
[self.klarnaOSMView.topAnchor constraintEqualToAnchor:self.topAnchor],
|
|
173
|
+
[self.klarnaOSMView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
|
|
174
|
+
[self.klarnaOSMView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
|
|
175
|
+
[self.klarnaOSMView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor], nil
|
|
176
|
+
]];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
#pragma mark - Style Configuration
|
|
180
|
+
|
|
181
|
+
- (void)updateStyleConfigurationWithBackgroundColor:(NSString *)bgColorStr textColor:(NSString *)txtColorStr {
|
|
182
|
+
UIColor *bgColor = [self colorFromHexString:bgColorStr];
|
|
183
|
+
UIColor *txtColor = [self colorFromHexString:txtColorStr];
|
|
184
|
+
|
|
185
|
+
if (bgColor || txtColor) {
|
|
186
|
+
KlarnaOSMStyleBuilder *builder = [[KlarnaOSMStyleBuilder alloc] init];
|
|
187
|
+
if (bgColor) {
|
|
188
|
+
[builder setBackgroundColor:bgColor];
|
|
189
|
+
}
|
|
190
|
+
if (txtColor) {
|
|
191
|
+
KlarnaTextStyleBuilder *textStyleBuilder = [[KlarnaTextStyleBuilder alloc] init];
|
|
192
|
+
[textStyleBuilder setTextColor:txtColor];
|
|
193
|
+
[builder setTextStyleConfiguration:[textStyleBuilder build]];
|
|
194
|
+
}
|
|
195
|
+
self.klarnaOSMView.styleConfiguration = [builder build];
|
|
196
|
+
} else {
|
|
197
|
+
self.klarnaOSMView.styleConfiguration = nil;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
- (UIColor *)colorFromHexString:(NSString *)hexString {
|
|
202
|
+
if (!hexString || hexString.length == 0) {
|
|
203
|
+
return nil;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
NSString *cleanString = [hexString stringByReplacingOccurrencesOfString:@"#" withString:@""];
|
|
207
|
+
if (cleanString.length != 6 && cleanString.length != 8) {
|
|
208
|
+
return nil;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
unsigned int rgbValue = 0;
|
|
212
|
+
NSScanner *scanner = [NSScanner scannerWithString:cleanString];
|
|
213
|
+
[scanner scanHexInt:&rgbValue];
|
|
214
|
+
|
|
215
|
+
if (cleanString.length == 8) {
|
|
216
|
+
return [UIColor colorWithRed:((rgbValue & 0xFF000000) >> 24) / 255.0
|
|
217
|
+
green:((rgbValue & 0x00FF0000) >> 16) / 255.0
|
|
218
|
+
blue:((rgbValue & 0x0000FF00) >> 8) / 255.0
|
|
219
|
+
alpha:(rgbValue & 0x000000FF) / 255.0];
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16) / 255.0
|
|
223
|
+
green:((rgbValue & 0x00FF00) >> 8) / 255.0
|
|
224
|
+
blue:(rgbValue & 0x0000FF) / 255.0
|
|
225
|
+
alpha:1.0];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
#pragma mark - Methods Exposed to React Native
|
|
229
|
+
|
|
230
|
+
- (void)render {
|
|
231
|
+
UIViewController *hostVC = [self reactViewController];
|
|
232
|
+
if (hostVC) {
|
|
233
|
+
self.klarnaOSMView.hostViewController = hostVC;
|
|
234
|
+
}
|
|
235
|
+
[self.klarnaOSMView render];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
- (UIViewController *)reactViewController {
|
|
239
|
+
UIResponder *responder = self;
|
|
240
|
+
while (responder) {
|
|
241
|
+
if ([responder isKindOfClass:[UIViewController class]]) {
|
|
242
|
+
return (UIViewController *)responder;
|
|
243
|
+
}
|
|
244
|
+
responder = [responder nextResponder];
|
|
245
|
+
}
|
|
246
|
+
return nil;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
#pragma mark - UIView Lifecycle
|
|
250
|
+
|
|
251
|
+
- (void)didMoveToWindow {
|
|
252
|
+
[super didMoveToWindow];
|
|
253
|
+
if (!self.window) {
|
|
254
|
+
self.isOSMViewReadyEventSent = NO;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
#pragma mark - KlarnaEventHandler
|
|
259
|
+
|
|
260
|
+
- (void)klarnaComponent:(id<KlarnaComponent>)klarnaComponent dispatchedEvent:(KlarnaProductEvent *)event {
|
|
261
|
+
// OSM view does not emit product events
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
- (void)klarnaComponent:(id<KlarnaComponent>)klarnaComponent encounteredError:(KlarnaError *)error {
|
|
265
|
+
if (_eventEmitter) {
|
|
266
|
+
auto emitter = std::dynamic_pointer_cast<const RNKlarnaOSMViewEventEmitter>(_eventEmitter);
|
|
267
|
+
if (emitter) {
|
|
268
|
+
emitter->onError(RNKlarnaOSMViewEventEmitter::OnError{
|
|
269
|
+
.error = {
|
|
270
|
+
.name = std::string([error.name UTF8String]),
|
|
271
|
+
.message = std::string([error.message UTF8String]),
|
|
272
|
+
.isFatal = error.isFatal,
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
#pragma mark - KlarnaSizingDelegate
|
|
280
|
+
|
|
281
|
+
- (void)klarnaComponent:(id<KlarnaComponent>)klarnaComponent resizedToHeight:(CGFloat)height {
|
|
282
|
+
if (_eventEmitter) {
|
|
283
|
+
auto emitter = std::dynamic_pointer_cast<const RNKlarnaOSMViewEventEmitter>(_eventEmitter);
|
|
284
|
+
if (emitter) {
|
|
285
|
+
emitter->onResized(RNKlarnaOSMViewEventEmitter::OnResized{
|
|
286
|
+
.height = std::string([[[NSNumber numberWithFloat:height] stringValue] UTF8String]),
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
@end
|
|
293
|
+
|
|
294
|
+
#endif
|
|
@@ -19,6 +19,7 @@ using namespace facebook::react;
|
|
|
19
19
|
@interface KlarnaStandaloneWebViewWrapper () <KlarnaStandaloneWebViewDelegate, KlarnaEventHandler, RCTRNKlarnaStandaloneWebViewViewProtocol>
|
|
20
20
|
|
|
21
21
|
@property (nonatomic, strong) KlarnaStandaloneWebView *klarnaStandaloneWebView;
|
|
22
|
+
@property (nonatomic, strong) NSString *returnUrl;
|
|
22
23
|
|
|
23
24
|
typedef void (^WebViewOperation)(WKWebView *);
|
|
24
25
|
|
|
@@ -31,11 +32,6 @@ NSString *const PROPERTY_NAME_ESTIMATED_PROGRESS = @"estimatedProgress";
|
|
|
31
32
|
|
|
32
33
|
- (id)init {
|
|
33
34
|
self = [super init];
|
|
34
|
-
// TODO: What should we pass here for 'returnUrl'?
|
|
35
|
-
[self initializeKlarnaStandaloneWebView: @"returnUrl://"];
|
|
36
|
-
self.klarnaStandaloneWebView.delegate = self;
|
|
37
|
-
self.klarnaStandaloneWebView.eventHandler = self;
|
|
38
|
-
[self.klarnaStandaloneWebView addObserver:self forKeyPath:PROPERTY_NAME_ESTIMATED_PROGRESS options:NSKeyValueObservingOptionNew context:nil];
|
|
39
35
|
return self;
|
|
40
36
|
}
|
|
41
37
|
|
|
@@ -82,13 +78,17 @@ NSString *const PROPERTY_NAME_ESTIMATED_PROGRESS = @"estimatedProgress";
|
|
|
82
78
|
|
|
83
79
|
#pragma mark - React Native Overrides
|
|
84
80
|
|
|
85
|
-
- (void)initializeKlarnaStandaloneWebView
|
|
86
|
-
self.klarnaStandaloneWebView = [[KlarnaStandaloneWebView alloc] initWithReturnURL:[NSURL URLWithString:returnUrl]];
|
|
81
|
+
- (void)initializeKlarnaStandaloneWebView {
|
|
82
|
+
self.klarnaStandaloneWebView = [[KlarnaStandaloneWebView alloc] initWithReturnURL:[NSURL URLWithString:self.returnUrl]];
|
|
83
|
+
self.klarnaStandaloneWebView.delegate = self;
|
|
84
|
+
self.klarnaStandaloneWebView.eventHandler = self;
|
|
85
|
+
[self.klarnaStandaloneWebView addObserver:self forKeyPath:PROPERTY_NAME_ESTIMATED_PROGRESS options:NSKeyValueObservingOptionNew context:nil];
|
|
86
|
+
|
|
87
87
|
self.klarnaStandaloneWebView.translatesAutoresizingMaskIntoConstraints = NO;
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
[self addSubview:self.klarnaStandaloneWebView];
|
|
90
90
|
[self setWebViewBackgroundToTransparent];
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
[NSLayoutConstraint activateConstraints:[[NSArray alloc] initWithObjects:
|
|
93
93
|
[self.klarnaStandaloneWebView.topAnchor constraintEqualToAnchor:self.topAnchor],
|
|
94
94
|
[self.klarnaStandaloneWebView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
|
|
@@ -141,17 +141,24 @@ Class<RCTComponentViewProtocol>RNKlarnaStandaloneWebViewCls(void)
|
|
|
141
141
|
{
|
|
142
142
|
const auto &oldViewProps = *std::static_pointer_cast<RNKlarnaStandaloneWebViewProps const>(_props);
|
|
143
143
|
const auto &newViewProps = *std::static_pointer_cast<RNKlarnaStandaloneWebViewProps const>(props);
|
|
144
|
-
|
|
144
|
+
|
|
145
145
|
if (oldViewProps.returnUrl != newViewProps.returnUrl) {
|
|
146
146
|
NSString *newReturnUrl = [[NSString alloc] initWithUTF8String: newViewProps.returnUrl.c_str()];
|
|
147
|
-
self.
|
|
147
|
+
self.returnUrl = newReturnUrl;
|
|
148
|
+
if (newReturnUrl.length > 0) {
|
|
149
|
+
if (self.klarnaStandaloneWebView == nil) {
|
|
150
|
+
[self initializeKlarnaStandaloneWebView];
|
|
151
|
+
} else {
|
|
152
|
+
self.klarnaStandaloneWebView.returnURL = [NSURL URLWithString:newReturnUrl];
|
|
153
|
+
}
|
|
154
|
+
}
|
|
148
155
|
}
|
|
149
|
-
|
|
156
|
+
|
|
150
157
|
WebViewOperation setBounces = ^(WKWebView *webView) {
|
|
151
158
|
webView.scrollView.bounces = newViewProps.bounces;
|
|
152
159
|
};
|
|
153
160
|
[self applyOperationToWebViews:setBounces];
|
|
154
|
-
|
|
161
|
+
|
|
155
162
|
[super updateProps:props oldProps:oldProps];
|
|
156
163
|
}
|
|
157
164
|
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
#if !RCT_NEW_ARCH_ENABLED
|
|
2
|
+
|
|
3
|
+
#import <React/RCTLog.h>
|
|
4
|
+
#import "../KlarnaExpressCheckoutViewWrapper.h"
|
|
5
|
+
#import <KlarnaMobileSDK/KlarnaMobileSDK.h>
|
|
6
|
+
#import <KlarnaMobileSDK/KlarnaMobileSDK-Swift.h>
|
|
7
|
+
|
|
8
|
+
#if __has_include("react_native_klarna_inapp_sdk-Swift.h")
|
|
9
|
+
#import "react_native_klarna_inapp_sdk-Swift.h"
|
|
10
|
+
#elif __has_include("RNKlarnaMobileSDK-Swift.h")
|
|
11
|
+
#import "RNKlarnaMobileSDK-Swift.h"
|
|
12
|
+
#else
|
|
13
|
+
#import <RNKlarnaMobileSDK/RNKlarnaMobileSDK-Swift.h>
|
|
14
|
+
#endif
|
|
15
|
+
|
|
16
|
+
@interface KlarnaExpressCheckoutViewWrapper ()
|
|
17
|
+
|
|
18
|
+
@property (nonatomic, strong) KlarnaExpressCheckoutButton* expressCheckoutButton;
|
|
19
|
+
@property (nonatomic, strong) KlarnaExpressCheckoutButtonDelegateProxy* delegateProxy;
|
|
20
|
+
@property (nonatomic, assign) BOOL isButtonCreated;
|
|
21
|
+
|
|
22
|
+
@end
|
|
23
|
+
|
|
24
|
+
@implementation KlarnaExpressCheckoutViewWrapper
|
|
25
|
+
|
|
26
|
+
#pragma mark - Initialization
|
|
27
|
+
|
|
28
|
+
- (instancetype)initWithFrame:(CGRect)frame
|
|
29
|
+
{
|
|
30
|
+
self = [super initWithFrame:frame];
|
|
31
|
+
if (self) {
|
|
32
|
+
self.backgroundColor = [UIColor clearColor];
|
|
33
|
+
self.isButtonCreated = NO;
|
|
34
|
+
self.autoFinalize = YES;
|
|
35
|
+
self.collectShippingAddress = NO;
|
|
36
|
+
[self setupDelegateProxy];
|
|
37
|
+
}
|
|
38
|
+
return self;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
- (void)setupDelegateProxy {
|
|
42
|
+
self.delegateProxy = [[KlarnaExpressCheckoutButtonDelegateProxy alloc] init];
|
|
43
|
+
|
|
44
|
+
__weak __typeof(self) weakSelf = self;
|
|
45
|
+
|
|
46
|
+
self.delegateProxy.onAuthorizedHandler = ^(NSDictionary * _Nonnull response) {
|
|
47
|
+
__strong __typeof(weakSelf) strongSelf = weakSelf;
|
|
48
|
+
if (!strongSelf || !strongSelf.onAuthorized) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
strongSelf.onAuthorized(@{
|
|
52
|
+
@"authorizationResponse": response
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
self.delegateProxy.onErrorHandler = ^(NSString * _Nonnull name, NSString * _Nonnull message, BOOL isFatal) {
|
|
57
|
+
__strong __typeof(weakSelf) strongSelf = weakSelf;
|
|
58
|
+
if (!strongSelf || !strongSelf.onError) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
strongSelf.onError(@{
|
|
62
|
+
@"error": @{
|
|
63
|
+
@"name": name,
|
|
64
|
+
@"message": message,
|
|
65
|
+
@"isFatal": @(isFatal),
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
#pragma mark - React Native Property Setters
|
|
72
|
+
|
|
73
|
+
- (void)setSessionType:(NSString *)sessionType {
|
|
74
|
+
_sessionType = sessionType;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
- (void)setClientId:(NSString *)clientId {
|
|
78
|
+
_clientId = clientId;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
- (void)setClientToken:(NSString *)clientToken {
|
|
82
|
+
_clientToken = clientToken;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
- (void)setLocale:(NSString *)locale {
|
|
86
|
+
_locale = locale;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
- (void)setEnvironment:(NSString *)environment {
|
|
90
|
+
_environment = environment;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
- (void)setRegion:(NSString *)region {
|
|
94
|
+
_region = region;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
- (void)setReturnUrl:(NSString *)returnUrl {
|
|
98
|
+
_returnUrl = returnUrl;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
- (void)setTheme:(NSString *)theme {
|
|
102
|
+
_theme = theme;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
- (void)setShape:(NSString *)shape {
|
|
106
|
+
_shape = shape;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
- (void)setButtonStyle:(NSString *)buttonStyle {
|
|
110
|
+
_buttonStyle = buttonStyle;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
- (void)setAutoFinalize:(BOOL)autoFinalize {
|
|
114
|
+
_autoFinalize = autoFinalize;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
- (void)setCollectShippingAddress:(BOOL)collectShippingAddress {
|
|
118
|
+
_collectShippingAddress = collectShippingAddress;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
- (void)setSessionData:(NSString *)sessionData {
|
|
122
|
+
_sessionData = sessionData;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
#pragma mark - React Native Lifecycle
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Called by React Native after a batch of prop updates is applied.
|
|
129
|
+
*
|
|
130
|
+
* The SDK button is configured entirely through its constructor, so any prop
|
|
131
|
+
* change recreates the button. The delegate proxy is reused across instances.
|
|
132
|
+
*/
|
|
133
|
+
- (void)didSetProps:(NSArray<NSString *> *)changedProps {
|
|
134
|
+
[super didSetProps:changedProps];
|
|
135
|
+
if (self.isButtonCreated) {
|
|
136
|
+
[self resetButton];
|
|
137
|
+
}
|
|
138
|
+
[self createButtonIfNeeded];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
#pragma mark - Button Creation
|
|
142
|
+
|
|
143
|
+
- (void)resetButton {
|
|
144
|
+
if (self.expressCheckoutButton) {
|
|
145
|
+
[self.expressCheckoutButton removeFromSuperview];
|
|
146
|
+
self.expressCheckoutButton = nil;
|
|
147
|
+
}
|
|
148
|
+
self.isButtonCreated = NO;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
- (void)createButtonIfNeeded {
|
|
152
|
+
if (self.isButtonCreated) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
KlarnaExpressCheckoutButton *button = [KlarnaExpressCheckoutHelper
|
|
157
|
+
createButtonWithSessionType:self.sessionType ?: @""
|
|
158
|
+
clientId:self.clientId ?: @""
|
|
159
|
+
clientToken:self.clientToken ?: @""
|
|
160
|
+
locale:self.locale
|
|
161
|
+
returnUrl:self.returnUrl ?: @""
|
|
162
|
+
delegate:self.delegateProxy
|
|
163
|
+
theme:self.theme
|
|
164
|
+
shape:self.shape
|
|
165
|
+
buttonStyle:self.buttonStyle
|
|
166
|
+
autoFinalize:self.autoFinalize
|
|
167
|
+
collectShippingAddress:self.collectShippingAddress
|
|
168
|
+
sessionData:self.sessionData
|
|
169
|
+
environment:self.environment
|
|
170
|
+
region:self.region];
|
|
171
|
+
|
|
172
|
+
if (button) {
|
|
173
|
+
self.expressCheckoutButton = button;
|
|
174
|
+
self.expressCheckoutButton.translatesAutoresizingMaskIntoConstraints = NO;
|
|
175
|
+
[self addSubview:self.expressCheckoutButton];
|
|
176
|
+
|
|
177
|
+
[NSLayoutConstraint activateConstraints:@[
|
|
178
|
+
[self.expressCheckoutButton.topAnchor constraintEqualToAnchor:self.topAnchor],
|
|
179
|
+
[self.expressCheckoutButton.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
|
|
180
|
+
[self.expressCheckoutButton.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
|
|
181
|
+
[self.expressCheckoutButton.trailingAnchor constraintEqualToAnchor:self.trailingAnchor],
|
|
182
|
+
]];
|
|
183
|
+
|
|
184
|
+
self.isButtonCreated = YES;
|
|
185
|
+
|
|
186
|
+
// Send resize event after layout
|
|
187
|
+
__weak __typeof(self) weakResizeSelf = self;
|
|
188
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
189
|
+
__strong __typeof(weakResizeSelf) strongSelf = weakResizeSelf;
|
|
190
|
+
if (strongSelf && strongSelf.onResized && strongSelf.expressCheckoutButton) {
|
|
191
|
+
CGFloat height = strongSelf.expressCheckoutButton.intrinsicContentSize.height;
|
|
192
|
+
if (height > 0) {
|
|
193
|
+
strongSelf.onResized(@{
|
|
194
|
+
@"height": [[NSNumber numberWithFloat:height] stringValue]
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
#pragma mark - Layout
|
|
203
|
+
|
|
204
|
+
- (void)layoutSubviews {
|
|
205
|
+
[super layoutSubviews];
|
|
206
|
+
if (self.expressCheckoutButton) {
|
|
207
|
+
self.expressCheckoutButton.frame = self.bounds;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
#pragma mark - UIView Lifecycle
|
|
212
|
+
|
|
213
|
+
- (void)didMoveToWindow {
|
|
214
|
+
[super didMoveToWindow];
|
|
215
|
+
if (!self.window) {
|
|
216
|
+
[self resetButton];
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
@end
|
|
221
|
+
|
|
222
|
+
#endif
|