Skip to content

Commit

Permalink
Merge pull request #239 from klaviyo/ab/CHNL-14651/add-klaviyo-form-p…
Browse files Browse the repository at this point in the history
…review

[CHNL-14651] add Klaviyo form preview
  • Loading branch information
ab1470 authored Nov 29, 2024
2 parents b283644 + f980580 commit ecb62d0
Show file tree
Hide file tree
Showing 8 changed files with 433 additions and 2 deletions.
6 changes: 5 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ let package = Package(
name: "KlaviyoUI",
dependencies: ["KlaviyoSwift"],
path: "Sources/KlaviyoUI",
resources: [.process("KlaviyoWebView/Resources")]),
resources: [
.process("KlaviyoWebView/Resources"),
.process("KlaviyoWebView/Development Assets/Scripts"),
.process("KlaviyoWebView/Development Assets/HTML")
]),
.testTarget(
name: "KlaviyoUITests",
dependencies: [
Expand Down
184 changes: 184 additions & 0 deletions Sources/KlaviyoUI/KlaviyoWebView/Development Assets/HTML/jstest.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, viewport-fit=cover"/>
<style>
* {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
margin: 0;
padding: 0;
box-sizing: border-box;
}

body {
margin: 0;
padding: 0;
background-color: rgba(0, 0, 0, 0.5); /* Translucent background */
display: flex;
align-items: start;
justify-content: center;
height: 100vh; /* Full height */
overflow: hidden; /* Prevent scrolling */
padding-top: env(safe-area-inset-top);
padding-right: env(safe-area-inset-right);
padding-bottom: env(safe-area-inset-bottom);
padding-left: env(safe-area-inset-left);
}

.content-container {
background: white;
border-radius: 16px;
box-shadow: 0 12px 12px rgba(0, 0, 0, 0.4);
width: 90%;
max-width: 500px; /* Limit the content width */
overflow: auto; /* Enable scrolling */
padding: 24px;
max-height: 100%; /* Prevent it from exceeding the viewport */
}

.title {
margin-bottom: 16px;
}

.section {
background: white;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
margin-bottom: 16px;
overflow: hidden;
}

.section-title {
font-size: 16px;
font-weight: bold;
padding: 12px;
background-color: #f0f0f5;
}

.button-section {
padding: 12px;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}

.setting {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px;
border-bottom: 1px solid #e0e0e0;
cursor: pointer;
}

.setting:last-child {
border-bottom: none;
}

.switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}

.switch input {
display: none;
}

.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: background-color 0.4s;
border-radius: 34px;
}

.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
transition: transform 0.4s;
border-radius: 50%;
}

input:checked + .slider {
background-color: #2196F3;
}

input:checked + .slider:before {
transform: translateX(26px);
}

.button {
padding: 12px 72px;
margin: 4px 8px;
transition: background-color 0.3s;
box-sizing: border-box;
border-radius: 12px;
}

.button:hover {
opacity: 0.8;
}
</style>
</head>
<body>
<div class="content-container">
<div class="title">
<h1>Javascript Bridge<br>Test Page</h1>
</div>

<div class="section">
<div class="section-title">Toggle</div>
<div class="setting">
<span id="toggle-status">Toggle is off</span>
<label class="switch">
<input type="checkbox" name="myCheckbox">
<span class="slider round"></span>
</label>
</div>
</div>

<div class="section">
<div class="section-title">Buttons</div>
<div class="button-section">
<button class="button" id="close-button">Close</button>
</div>
</div>

<!-- Added placeholder content to force scrolling -->
<div class="section">
<div class="section-title">Placeholder Content</div>
<div class="setting">
<span>Item 1</span>
</div>
<div class="setting">
<span>Item 2</span>
</div>
</div>
</div>

<script>
document.getElementById("close-button").addEventListener("click", function() {
window.close();
});
</script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//
// JSTestWebViewModel.swift
// klaviyo-swift-sdk
//
// Created by Andrew Balmer on 11/18/24.
//

#if DEBUG
import Combine
import Foundation
import WebKit

class JSTestWebViewModel: KlaviyoWebViewModeling {
let url: URL
let loadScripts: [String: WKUserScript]?

/// Publishes scripts for the `WKWebView` to execute.
private var continuation: AsyncStream<(script: String, callback: ((Result<Any?, Error>) -> Void)?)>.Continuation?
lazy var scriptStream: AsyncStream<(script: String, callback: ((Result<Any?, Error>) -> Void)?)> = AsyncStream { [weak self] continuation in
self?.continuation = continuation
}

init(url: URL) {
self.url = url
loadScripts = JSTestWebViewModel.initializeLoadScripts()
}

private static func initializeLoadScripts() -> [String: WKUserScript] {
var scripts: [String: WKUserScript] = [:]

if let toggleHandlerScript = try? FileIO.getFileContents(path: "toggleHandler", type: "js") {
let script = WKUserScript(source: toggleHandlerScript, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
scripts["toggleMessageHandler"] = script
}

return scripts
}

// MARK: handle WKWebView events

func handleNavigationEvent(_ event: WKNavigationEvent) {
// TODO: handle navigation events
}

func handleScriptMessage(_ message: WKScriptMessage) {
if message.name == "toggleMessageHandler" {
guard let dict = message.body as? [String: AnyObject] else {
return
}

guard let toggleEnabled = dict["toggleEnabled"] as? Bool else {
return
}

print("toggle enabled: \(toggleEnabled)")

let newStatus = toggleEnabled ? "Toggle is on" : "Toggle is off"

let script = "document.getElementById('toggle-status').innerText = \"\(newStatus)\""

continuation?.yield((script, { result in
switch result {
case let .success(content):
if let successMessage = content as? String {
print("Successfully evaluated Javascript; message: \(successMessage)")
}
case let .failure(failure):
print("Javascript evaluation failed; message: \(failure.localizedDescription)")
}
}))
}
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//
// PreviewGridViewController.swift
// klaviyo-swift-sdk
//
// Created by Andrew Balmer on 10/23/24.
//

#if DEBUG
import Foundation
import UIKit

/// A sample grid view with randomly-colored tiles for internal Xcode preview purposes only.
class PreviewGridViewController: UIViewController, UICollectionViewDataSource {
var collectionView: UICollectionView!

override func viewDidLoad() {
super.viewDidLoad()

let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalWidth(0.4))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
group.interItemSpacing = .flexible(12)
let section = NSCollectionLayoutSection(group: group)
section.interGroupSpacing = 12
section.contentInsets = .init(top: 0, leading: 16, bottom: 0, trailing: 16)

let layout = UICollectionViewCompositionalLayout(section: section)

collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
collectionView.dataSource = self

view.addSubview(collectionView)

// Disable autoresizing mask translation for Auto Layout
collectionView.translatesAutoresizingMaskIntoConstraints = false

// Set up constraints using safeAreaLayoutGuide
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
collectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
}

// MARK: UICollectionViewDataSource

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
12
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
cell.backgroundColor = UIColor(
red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1),
alpha: 1.0)
cell.layer.cornerRadius = 12.0
return cell
}
}

// MARK: - Previews

#if swift(>=5.9)
@available(iOS 17.0, *)
#Preview {
PreviewTabViewController()
}
#endif
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// PreviewTabViewController.swift
// klaviyo-swift-sdk
//
// Created by Andrew Balmer on 10/23/24.
//

#if DEBUG
import Foundation
import UIKit

/// A sample tab view for internal Xcode preview purposes only.
class PreviewTabViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()

let firstVC = PreviewGridViewController()
let secondVC = UIViewController()
let thirdVC = UIViewController()

firstVC.title = "Browse"

firstVC.tabBarItem = UITabBarItem(title: "Browse", image: UIImage(systemName: "house"), tag: 0)
secondVC.tabBarItem = UITabBarItem(title: "Search", image: UIImage(systemName: "magnifyingglass"), tag: 1)
thirdVC.tabBarItem = UITabBarItem(title: "Profile", image: UIImage(systemName: "person"), tag: 2)

viewControllers = [
UINavigationController(rootViewController: firstVC),
UINavigationController(rootViewController: secondVC),
UINavigationController(rootViewController: thirdVC)
]

firstVC.navigationController?.navigationBar.prefersLargeTitles = true
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
var _selector = document.querySelector('input[name=myCheckbox]');
_selector.addEventListener('change', function(event) {
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.toggleMessageHandler) {
window.webkit.messageHandlers.toggleMessageHandler.postMessage({
"toggleEnabled": _selector.checked
});
}
});
Loading

0 comments on commit ecb62d0

Please sign in to comment.