Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Xpert and five9 Chat implementation #84

Draft
wants to merge 28 commits into
base: 2U/develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
22d8cf7
feat: initial adding xpert/five9 package, added LiveChatConfig
rnr Sep 19, 2024
4024c42
chore: added closeChat WKScriptEvent
rnr Sep 20, 2024
43bc9b2
chore: added ignoreSafe keyboard area
rnr Sep 23, 2024
b433daf
chore: split config on xpert and five9 configurations
rnr Sep 23, 2024
c093a05
chore: added manual generation of five9 form
rnr Sep 24, 2024
6fa8441
chore: got rid five9 extra parameters
rnr Sep 24, 2024
82cbc0b
chore: got rid five9 config
rnr Sep 25, 2024
f930f92
chore: added chat icon
rnr Sep 26, 2024
9aadef2
chore: replace segment script and use_case config
rnr Sep 26, 2024
0875d84
chore: added dark icon
rnr Sep 27, 2024
117f2d0
chore: clear background for chat on iPad, fixed useCase string
rnr Sep 27, 2024
2298b1d
chore: added loading indocator
rnr Sep 27, 2024
7b05d7d
chore: little refactor
rnr Sep 27, 2024
ee63768
chore: added internet checking, delete test button
rnr Sep 27, 2024
5158a94
chore: fix for Xcode 16
rnr Sep 29, 2024
2a6777e
chore: added five9Enabled parameter to config
rnr Oct 2, 2024
f9df9ab
chore: generated mocks
rnr Oct 2, 2024
f82c1ba
chore: added package tests
rnr Oct 2, 2024
31ea7d2
chore: deleted local package
rnr Oct 2, 2024
1e5a45e
chore: added package via SPM
rnr Oct 2, 2024
5445315
chore: deleted commented code
rnr Oct 2, 2024
0783fc1
Merge branch '2U/develop' into feat/xpert-five9-implementation
rnr Oct 7, 2024
886cd01
chore: changed xpert package branch
rnr Oct 7, 2024
f51959f
chore: added Camera privacy string
rnr Oct 7, 2024
e6d34de
chore: added baseURL to xpert config
rnr Oct 10, 2024
cc6e4a2
chore: moved launch button to separate view, added on main and on reg…
rnr Oct 10, 2024
b72c752
chore: added microphone privacy string
rnr Oct 11, 2024
59e9e4b
chore: use latest xpert package branch
rnr Oct 11, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
import SwiftUI
import Core
import Theme
import Swinject

public struct SignUpView: View {

@State
private var disclosureGroupOpen: Bool = false

@Environment (\.isHorizontal) private var isHorizontal
@Environment(\.isHorizontal) private var isHorizontal

@ObservedObject
private var viewModel: SignUpViewModel
Expand All @@ -27,7 +28,7 @@ public struct SignUpView: View {
}

public var body: some View {
ZStack(alignment: .top) {
ZStack(alignment: .bottomTrailing) {
VStack {
ThemeAssets.headerBackground.swiftUIImage
.resizable()
Expand Down Expand Up @@ -192,11 +193,16 @@ public struct SignUpView: View {
}
}
}
// Chat Icon
LaunchChatView(
router: Container.shared.resolve(AuthorizationRouter.self)!,
connectivity: Container.shared.resolve(ConnectivityProtocol.self)!
)
}
.ignoresSafeArea(.all, edges: .horizontal)
.background(Theme.Colors.background.ignoresSafeArea(.all))
.hideNavigationBar()
.onFirstAppear{
.onFirstAppear {
viewModel.trackScreenEvent()
}
}
Expand Down
42 changes: 42 additions & 0 deletions Authorization/AuthorizationTests/AuthorizationMock.generated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -999,6 +999,13 @@ open class AuthorizationRouterMock: AuthorizationRouter, Mock {
perform?()
}

@MainActor
open func showLiveChat(animated: Bool) {
addInvocation(.m_showLiveChat__animated_animated(Parameter<Bool>.value(`animated`)))
let perform = methodPerformValue(.m_showLiveChat__animated_animated(Parameter<Bool>.value(`animated`))) as? (Bool) -> Void
perform?(`animated`)
}


fileprivate enum MethodType {
case m_showUpdateRequiredView__showAccountLink_showAccountLink(Parameter<Bool>)
Expand All @@ -1025,6 +1032,7 @@ open class AuthorizationRouterMock: AuthorizationRouter, Mock {
case m_hideUpgradeLoaderView__animated_animated(Parameter<Bool>)
case m_showRestoreProgressView
case m_hideRestoreProgressView
case m_showLiveChat__animated_animated(Parameter<Bool>)

static func compareParameters(lhs: MethodType, rhs: MethodType, matcher: Matcher) -> Matcher.ComparisonResult {
switch (lhs, rhs) {
Expand Down Expand Up @@ -1158,6 +1166,11 @@ open class AuthorizationRouterMock: AuthorizationRouter, Mock {
case (.m_showRestoreProgressView, .m_showRestoreProgressView): return .match

case (.m_hideRestoreProgressView, .m_hideRestoreProgressView): return .match

case (.m_showLiveChat__animated_animated(let lhsAnimated), .m_showLiveChat__animated_animated(let rhsAnimated)):
var results: [Matcher.ParameterComparisonResult] = []
results.append(Matcher.ParameterComparisonResult(Parameter.compare(lhs: lhsAnimated, rhs: rhsAnimated, with: matcher), lhsAnimated, rhsAnimated, "animated"))
return Matcher.ComparisonResult(results)
default: return .none
}
}
Expand Down Expand Up @@ -1188,6 +1201,7 @@ open class AuthorizationRouterMock: AuthorizationRouter, Mock {
case let .m_hideUpgradeLoaderView__animated_animated(p0): return p0.intValue
case .m_showRestoreProgressView: return 0
case .m_hideRestoreProgressView: return 0
case let .m_showLiveChat__animated_animated(p0): return p0.intValue
}
}
func assertionName() -> String {
Expand Down Expand Up @@ -1216,6 +1230,7 @@ open class AuthorizationRouterMock: AuthorizationRouter, Mock {
case .m_hideUpgradeLoaderView__animated_animated: return ".hideUpgradeLoaderView(animated:)"
case .m_showRestoreProgressView: return ".showRestoreProgressView()"
case .m_hideRestoreProgressView: return ".hideRestoreProgressView()"
case .m_showLiveChat__animated_animated: return ".showLiveChat(animated:)"
}
}
}
Expand Down Expand Up @@ -1264,6 +1279,8 @@ open class AuthorizationRouterMock: AuthorizationRouter, Mock {
public static func showRestoreProgressView() -> Verify { return Verify(method: .m_showRestoreProgressView)}
@MainActor
public static func hideRestoreProgressView() -> Verify { return Verify(method: .m_hideRestoreProgressView)}
@MainActor
public static func showLiveChat(animated: Parameter<Bool>) -> Verify { return Verify(method: .m_showLiveChat__animated_animated(`animated`))}
}

public struct Perform {
Expand Down Expand Up @@ -1348,6 +1365,10 @@ open class AuthorizationRouterMock: AuthorizationRouter, Mock {
public static func hideRestoreProgressView(perform: @escaping () -> Void) -> Perform {
return Perform(method: .m_hideRestoreProgressView, performs: perform)
}
@MainActor
public static func showLiveChat(animated: Parameter<Bool>, perform: @escaping (Bool) -> Void) -> Perform {
return Perform(method: .m_showLiveChat__animated_animated(`animated`), performs: perform)
}
}

public func given(_ method: Given) {
Expand Down Expand Up @@ -1611,6 +1632,13 @@ open class BaseRouterMock: BaseRouter, Mock {
perform?()
}

@MainActor
open func showLiveChat(animated: Bool) {
addInvocation(.m_showLiveChat__animated_animated(Parameter<Bool>.value(`animated`)))
let perform = methodPerformValue(.m_showLiveChat__animated_animated(Parameter<Bool>.value(`animated`))) as? (Bool) -> Void
perform?(`animated`)
}


fileprivate enum MethodType {
case m_backToRoot__animated_animated(Parameter<Bool>)
Expand All @@ -1636,6 +1664,7 @@ open class BaseRouterMock: BaseRouter, Mock {
case m_hideUpgradeLoaderView__animated_animated(Parameter<Bool>)
case m_showRestoreProgressView
case m_hideRestoreProgressView
case m_showLiveChat__animated_animated(Parameter<Bool>)

static func compareParameters(lhs: MethodType, rhs: MethodType, matcher: Matcher) -> Matcher.ComparisonResult {
switch (lhs, rhs) {
Expand Down Expand Up @@ -1764,6 +1793,11 @@ open class BaseRouterMock: BaseRouter, Mock {
case (.m_showRestoreProgressView, .m_showRestoreProgressView): return .match

case (.m_hideRestoreProgressView, .m_hideRestoreProgressView): return .match

case (.m_showLiveChat__animated_animated(let lhsAnimated), .m_showLiveChat__animated_animated(let rhsAnimated)):
var results: [Matcher.ParameterComparisonResult] = []
results.append(Matcher.ParameterComparisonResult(Parameter.compare(lhs: lhsAnimated, rhs: rhsAnimated, with: matcher), lhsAnimated, rhsAnimated, "animated"))
return Matcher.ComparisonResult(results)
default: return .none
}
}
Expand Down Expand Up @@ -1793,6 +1827,7 @@ open class BaseRouterMock: BaseRouter, Mock {
case let .m_hideUpgradeLoaderView__animated_animated(p0): return p0.intValue
case .m_showRestoreProgressView: return 0
case .m_hideRestoreProgressView: return 0
case let .m_showLiveChat__animated_animated(p0): return p0.intValue
}
}
func assertionName() -> String {
Expand Down Expand Up @@ -1820,6 +1855,7 @@ open class BaseRouterMock: BaseRouter, Mock {
case .m_hideUpgradeLoaderView__animated_animated: return ".hideUpgradeLoaderView(animated:)"
case .m_showRestoreProgressView: return ".showRestoreProgressView()"
case .m_hideRestoreProgressView: return ".hideRestoreProgressView()"
case .m_showLiveChat__animated_animated: return ".showLiveChat(animated:)"
}
}
}
Expand Down Expand Up @@ -1867,6 +1903,8 @@ open class BaseRouterMock: BaseRouter, Mock {
public static func showRestoreProgressView() -> Verify { return Verify(method: .m_showRestoreProgressView)}
@MainActor
public static func hideRestoreProgressView() -> Verify { return Verify(method: .m_hideRestoreProgressView)}
@MainActor
public static func showLiveChat(animated: Parameter<Bool>) -> Verify { return Verify(method: .m_showLiveChat__animated_animated(`animated`))}
}

public struct Perform {
Expand Down Expand Up @@ -1948,6 +1986,10 @@ open class BaseRouterMock: BaseRouter, Mock {
public static func hideRestoreProgressView(perform: @escaping () -> Void) -> Perform {
return Perform(method: .m_hideRestoreProgressView, performs: perform)
}
@MainActor
public static func showLiveChat(animated: Parameter<Bool>, perform: @escaping (Bool) -> Void) -> Perform {
return Perform(method: .m_showLiveChat__animated_animated(`animated`), performs: perform)
}
}

public func given(_ method: Given) {
Expand Down
20 changes: 20 additions & 0 deletions Core/Core.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,10 @@
9784D47E2BF7762800AFEFFF /* FullScreenErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9784D47D2BF7762800AFEFFF /* FullScreenErrorView.swift */; };
A51CDBE72B6D21F2009B6D4E /* SegmentConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51CDBE62B6D21F2009B6D4E /* SegmentConfig.swift */; };
A53A32352B233DEC005FE38A /* ThemeConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53A32342B233DEC005FE38A /* ThemeConfig.swift */; };
A5713D9E2CB83D4F00881A62 /* LaunchChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5713D9D2CB83D4F00881A62 /* LaunchChatView.swift */; };
A5713DA02CB83DB900881A62 /* LaunchChatViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5713D9F2CB83DB900881A62 /* LaunchChatViewModel.swift */; };
A595689B2B6173DF00ED4F90 /* BranchConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A595689A2B6173DF00ED4F90 /* BranchConfig.swift */; };
A5986EF72C9C647600CF4B5D /* LiveChatConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5986EF62C9C647600CF4B5D /* LiveChatConfig.swift */; };
A5CAA1EC2C526901007690D9 /* SecureInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CAA1EB2C526901007690D9 /* SecureInputView.swift */; };
A5F4E7B52B61544A00ACD166 /* BrazeConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5F4E7B42B61544A00ACD166 /* BrazeConfig.swift */; };
BA30427F2B20B320009B64B7 /* SocialAuthError.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA30427D2B20B299009B64B7 /* SocialAuthError.swift */; };
Expand Down Expand Up @@ -416,7 +419,10 @@
9D5B06CAA99EA5CD49CBE2BB /* Pods-App-Core.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core.debugdev.xcconfig"; path = "Target Support Files/Pods-App-Core/Pods-App-Core.debugdev.xcconfig"; sourceTree = "<group>"; };
A51CDBE62B6D21F2009B6D4E /* SegmentConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegmentConfig.swift; sourceTree = "<group>"; };
A53A32342B233DEC005FE38A /* ThemeConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemeConfig.swift; sourceTree = "<group>"; };
A5713D9D2CB83D4F00881A62 /* LaunchChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchChatView.swift; sourceTree = "<group>"; };
A5713D9F2CB83DB900881A62 /* LaunchChatViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchChatViewModel.swift; sourceTree = "<group>"; };
A595689A2B6173DF00ED4F90 /* BranchConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BranchConfig.swift; sourceTree = "<group>"; };
A5986EF62C9C647600CF4B5D /* LiveChatConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveChatConfig.swift; sourceTree = "<group>"; };
A5CAA1EB2C526901007690D9 /* SecureInputView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SecureInputView.swift; path = Core/View/Base/SecureInputView.swift; sourceTree = SOURCE_ROOT; };
A5F4E7B42B61544A00ACD166 /* BrazeConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrazeConfig.swift; sourceTree = "<group>"; };
BA30427D2B20B299009B64B7 /* SocialAuthError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocialAuthError.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -846,6 +852,7 @@
0770DE7728D0C49E006D8A5D /* Base */ = {
isa = PBXGroup;
children = (
A5713D9C2CB83D1900881A62 /* LaunchChatButton */,
9784D47C2BF7761F00AFEFFF /* FullScreenErrorView */,
064987882B4D69FE0071642A /* Webview */,
A5CAA1EB2C526901007690D9 /* SecureInputView.swift */,
Expand Down Expand Up @@ -956,6 +963,15 @@
path = FullScreenErrorView;
sourceTree = "<group>";
};
A5713D9C2CB83D1900881A62 /* LaunchChatButton */ = {
isa = PBXGroup;
children = (
A5713D9D2CB83D4F00881A62 /* LaunchChatView.swift */,
A5713D9F2CB83DB900881A62 /* LaunchChatViewModel.swift */,
);
path = LaunchChatButton;
sourceTree = "<group>";
};
BA30427C2B20B235009B64B7 /* SocialAuth */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1047,6 +1063,7 @@
A53A32342B233DEC005FE38A /* ThemeConfig.swift */,
E0D586192B2FF74C009B4BA7 /* DiscoveryConfig.swift */,
14D912D82C2553C70077CCCE /* FullStoryConfig.swift */,
A5986EF62C9C647600CF4B5D /* LiveChatConfig.swift */,
);
path = Config;
sourceTree = "<group>";
Expand Down Expand Up @@ -1300,6 +1317,7 @@
BA981BD02B91ED50005707C2 /* FullScreenProgressView.swift in Sources */,
0236961F28F9A2F600EEF206 /* AuthEndpoint.swift in Sources */,
02B3E3B32930198600A50475 /* AVPlayerViewControllerExtension.swift in Sources */,
A5713DA02CB83DB900881A62 /* LaunchChatViewModel.swift in Sources */,
BAD9CA332B28A8F300DE790A /* AjaxProvider.swift in Sources */,
0295C885299B99DD00ABE571 /* RefreshableScrollView.swift in Sources */,
A51CDBE72B6D21F2009B6D4E /* SegmentConfig.swift in Sources */,
Expand Down Expand Up @@ -1386,6 +1404,7 @@
071009D028D1E3A600344290 /* Constants.swift in Sources */,
0770DE1928D0847D006D8A5D /* BaseRouter.swift in Sources */,
BA30427F2B20B320009B64B7 /* SocialAuthError.swift in Sources */,
A5713D9E2CB83D4F00881A62 /* LaunchChatView.swift in Sources */,
06EA8A532BFE006F005DFB90 /* StoreKitHandlerProtocol.swift in Sources */,
0284DBFE28D48C5300830893 /* CourseItem.swift in Sources */,
0248C92329C075EF00DC8402 /* CourseBlockModel.swift in Sources */,
Expand Down Expand Up @@ -1426,6 +1445,7 @@
062C69BB2C199C2A002BD311 /* MainTab.swift in Sources */,
02CA59842BD7DDBE00D517AA /* DashboardConfig.swift in Sources */,
0727877B28D24A1D002E9142 /* HeadersRedirectHandler.swift in Sources */,
A5986EF72C9C647600CF4B5D /* LiveChatConfig.swift in Sources */,
0236961B28F9A28B00EEF206 /* AuthInteractor.swift in Sources */,
A5CAA1EC2C526901007690D9 /* SecureInputView.swift in Sources */,
0770DE3028D09793006D8A5D /* EndPointType.swift in Sources */,
Expand Down
22 changes: 22 additions & 0 deletions Core/Core/Assets.xcassets/chatIcon.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"images" : [
{
"filename" : "icon_chat_edx.pdf",
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "icon_chat_edx_dark.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.
Binary file not shown.
6 changes: 6 additions & 0 deletions Core/Core/Configuration/BaseRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ public protocol BaseRouter {

@MainActor
func hideRestoreProgressView()

@MainActor
func showLiveChat(animated: Bool)
}

extension BaseRouter {
Expand Down Expand Up @@ -179,5 +182,8 @@ open class BaseRouterMock: BaseRouter {

@MainActor
public func hideRestoreProgressView() {}

@MainActor
public func showLiveChat(animated: Bool) {}
}
#endif
4 changes: 4 additions & 0 deletions Core/Core/Configuration/Config/Config.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public protocol ConfigProtocol {
var URIScheme: String { get }
var ecommerceURL: String? { get }
var fullStory: FullStoryConfig { get }
var liveChat: LiveChatConfig { get }
}

public enum TokenType: String {
Expand Down Expand Up @@ -201,6 +202,9 @@ public class ConfigMock: Config {
],
"APPLE_SIGNIN": [
"ENABLED": true
],
"XPERT_FIVE9": [
"ENABLED": true
]
]

Expand Down
36 changes: 36 additions & 0 deletions Core/Core/Configuration/Config/LiveChatConfig.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// LiveChatConfig.swift
// Core
//
// Created by Anton Yarmolenka on 19/09/2024.
//

import Foundation

private enum Keys: String, RawStringExtractable {
case enabled = "ENABLED"
case xpertKey = "XPERTKEY"
case useCase = "USECASE"
case segmentKey = "SEGMENTKEY"
}

public final class LiveChatConfig {
public var enabled: Bool = false
public var xpertKey: String = ""
public var useCase: String = ""
public var segmentKey: String = ""

init(dictionary: [String: AnyObject]) {
xpertKey = dictionary[Keys.xpertKey] as? String ?? ""
useCase = dictionary[Keys.useCase] as? String ?? ""
segmentKey = dictionary[Keys.segmentKey] as? String ?? ""
enabled = dictionary[Keys.enabled] as? Bool ?? false
}
}

private let configKey = "XPERT_FIVE9"
extension Config {
public var liveChat: LiveChatConfig {
LiveChatConfig(dictionary: self[configKey] as? [String: AnyObject] ?? [:])
}
}
1 change: 1 addition & 0 deletions Core/Core/SwiftGen/Assets.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ public enum CoreAssets {
public static let calendarSyncIcon = ImageAsset(name: "calendarSyncIcon")
public static let certificate = ImageAsset(name: "certificate")
public static let certificateBadge = ImageAsset(name: "certificateBadge")
public static let chatIcon = ImageAsset(name: "chatIcon")
public static let check = ImageAsset(name: "check")
public static let checkEmail = ImageAsset(name: "checkEmail")
public static let chevronRight = ImageAsset(name: "chevron_right")
Expand Down
Loading
Loading