Skip to content

Commit

Permalink
Add manual locale override capability
Browse files Browse the repository at this point in the history
The configuration accepts a manual locale override, which is `nil` by default.
If the Core SDK returns an incorrect manual locale override, then the Widgets
SDK also returns an error on configuration to let know the integrator about it.
If the integrator provides a wrong site API key, this commit also makes sure to
inform the integrator instead of hanging.

Also, the settings screen now includes the possibility to add a manual locale
override visually. If it's empty, then it sends nil.

MOB-2798
  • Loading branch information
gersonnoboa authored and EgorovEI committed Nov 6, 2023
1 parent 6e1327f commit b85ebdd
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 183 deletions.
304 changes: 152 additions & 152 deletions GliaWidgets/Localization.swift

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions GliaWidgets/Public/Configuration/Configuration+Mock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ extension Configuration {
authMethod: AuthorizationMethod = .siteApiKey(id: "site-api-key-id", secret: "site-api-key-secret"),
environment: Environment = .beta,
site: String = "site-id",
companyName: String = ""
companyName: String = "",
manualLocaleOverride: String? = nil
) -> Self {
Configuration(
authorizationMethod: authMethod,
environment: environment,
site: site,
companyName: companyName
companyName: companyName,
manualLocaleOverride: manualLocaleOverride
)
}
}
Expand Down
10 changes: 8 additions & 2 deletions GliaWidgets/Public/Configuration/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,27 @@ public struct Configuration {
public let isWhiteLabelApp: Bool
/// Company name. Appears during connection with operator.
public let companyName: String
/// The name of the manual locale override. If not set, or if set as `nil`,
/// then the default locale from site settings will be used.
public var manualLocaleOverride: String?
/// Initializes the configuration.
///
/// - Parameters:
/// - authorizationMethod: The site authorization method.
/// - environment: The environment to use.
/// - site: The site to use.
/// - visitorContext: Additional context about the visitor that operator may need.
///
/// - manualLocaleOverride: The name of the manual locale override.
/// If not set, or if set as `nil`, then the default locale from site settings will be used.
public init(
authorizationMethod: AuthorizationMethod,
environment: Environment,
site: String,
visitorContext: VisitorContext? = nil,
pushNotifications: PushNotifications = .disabled,
isWhiteLabelApp: Bool = false,
companyName: String = ""
companyName: String = "",
manualLocaleOverride: String? = nil
) {
self.authorizationMethod = authorizationMethod
self.environment = environment
Expand All @@ -41,6 +46,7 @@ public struct Configuration {
self.pushNotifications = pushNotifications
self.isWhiteLabelApp = isWhiteLabelApp
self.companyName = companyName
self.manualLocaleOverride = manualLocaleOverride
}
}

Expand Down
18 changes: 16 additions & 2 deletions GliaWidgets/Public/Glia/Glia.swift
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,23 @@ public class Glia {
}

completion(.success(()))
case let .failure(error):
case .failure(let error):
typealias ProcessError = CoreSdkClient.ConfigurationProcessError
var errorForCompletion: GliaError = .internalError

// To avoid the integrator having to figure out if an error is a `GliaError`
// or a `ConfigurationProcessError`, the `ConfigurationProcessError` is translated
// into a `GliaError`.
if let processError = error as? ProcessError {
if processError == .invalidSiteApiKeyCredentials {
errorForCompletion = GliaError.invalidSiteApiKeyCredentials
} else if processError == .localeRetrieval {
errorForCompletion = GliaError.invalidLocale
}
}

debugPrint("💥 Core SDK configuration is not valid. Unexpected error='\(error)'.")
completion(.failure(error))
completion(.failure(errorForCompletion))
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions GliaWidgets/Public/GliaError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@ public enum GliaError: Error {
case configuringDuringEngagementIsNotAllowed
case clearingVisitorSessionDuringEngagementIsNotAllowed
case startingEngagementWithNoQueueIdsIsNotAllowed
case invalidSiteApiKeyCredentials
case invalidLocale
case internalError
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ class ChatCoordinator: SubFlowCoordinator, FlowCoordinator {
)
self.controller = chatController
return chatController

}

private func presentMediaPickerController(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ extension CoreSdkClient {
typealias FileError = GliaCoreSDK.FileError
typealias GeneralError = GliaCoreSDK.GeneralError
typealias GliaCoreError = GliaCoreSDK.GliaCoreError
typealias ConfigurationProcessError = GliaCoreSDK.GliaCore.ConfigurationProcessError
typealias Interactable = GliaCoreSDK.Interactable
typealias MediaDirection = GliaCoreSDK.MediaDirection
typealias MediaError = GliaCoreSDK.MediaError
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ extension CoreSDKConfigurator {
siteId: configuration.site,
region: configuration.environment.region,
authorizingMethod: configuration.authorizationMethod.coreAuthorizationMethod,
pushNotifications: configuration.pushNotifications.coreSdk
pushNotifications: configuration.pushNotifications.coreSdk,
manualLocaleOverride: configuration.manualLocaleOverride
)
coreSdk.configureWithConfiguration(sdkConfiguration, completion)
}
Expand Down
22 changes: 17 additions & 5 deletions TestingApp/Extensions/Configuration.Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ extension Configuration {
.init(
authorizationMethod: .siteApiKey(id: "", secret: ""),
environment: env,
site: ""
site: "",
manualLocaleOverride: nil
)
}
}
Expand All @@ -25,15 +26,17 @@ extension Configuration {
return nil
}

let visitorAssetId = queryItems.first(where: { $0.name == "visitor_context_asset_id" })?.value ?? ""
let visitorAssetId = queryItems.first { $0.name == "visitor_context_asset_id" }?.value ?? ""
let visitorContext = UUID(uuidString: visitorAssetId)
.map(Configuration.VisitorContext.init(assetId:))
let manualLocaleOverride = queryItems.first { $0.name == "manual_locale_override" }?.value ?? nil

self = .init(
authorizationMethod: .siteApiKey(id: siteApiKeyId, secret: siteApiKeySecret),
environment: environment,
site: siteId,
visitorContext: visitorContext
visitorContext: visitorContext,
manualLocaleOverride: manualLocaleOverride
)
}
}
Expand All @@ -56,7 +59,12 @@ private extension Environment {

extension Configuration: Codable {
enum CodingKeys: String, CodingKey {
case authorizationMethod, environment, site, visitorContext, pushNotifications
case authorizationMethod,
environment,
site,
visitorContext,
pushNotifications,
manualLocaleOverride
}

public init(from decoder: Decoder) throws {
Expand All @@ -66,7 +74,8 @@ extension Configuration: Codable {
environment: container.decode(Environment.self, forKey: .environment),
site: container.decode(String.self, forKey: .site),
visitorContext: container.decodeIfPresent(VisitorContext.self, forKey: .visitorContext),
pushNotifications: container.decodeIfPresent(PushNotifications.self, forKey: .pushNotifications) ?? .disabled
pushNotifications: container.decodeIfPresent(PushNotifications.self, forKey: .pushNotifications) ?? .disabled,
manualLocaleOverride: container.decodeIfPresent(String.self, forKey: .manualLocaleOverride) ?? nil
)
}

Expand All @@ -77,6 +86,7 @@ extension Configuration: Codable {
try container.encode(site, forKey: .site)
try container.encode(visitorContext, forKey: .visitorContext)
try container.encode(pushNotifications, forKey: .pushNotifications)
try container.encode(manualLocaleOverride, forKey: .manualLocaleOverride)
}
}

Expand Down Expand Up @@ -163,6 +173,8 @@ extension Configuration.PushNotifications: RawRepresentable, Codable {
return "sandbox"
case .production:
return "production"
@unknown default:
return ""
}
}

Expand Down
17 changes: 15 additions & 2 deletions TestingApp/Settings/SettingsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ final class SettingsViewController: UIViewController {
private var queueIDCell: SettingsTextCell!
private var environmentCell: EnvironmentSettingsTextCell!
private var visitorContextAssedIdCell: SettingsTextCell!
private var manualLocaleOverrideCell: SettingsTextCell!
private var bubbleFeatureCell: SettingsSwitchCell!
private var primaryColorCell: SettingsColorCell!
private var secondaryColorCell: SettingsColorCell!
Expand Down Expand Up @@ -151,6 +152,13 @@ private extension SettingsViewController {
text: props.config.visitorContext?.assetId.uuidString ?? ""
)
visitorContextAssedIdCell.textField.accessibilityIdentifier = "settings_visitor_context_assetId_textfield"

manualLocaleOverrideCell = SettingsTextCell(
title: "Manual locale override:",
text: props.config.manualLocaleOverride ?? ""
)
manualLocaleOverrideCell.textField.accessibilityIdentifier = "settings_manual_locale_override_textfield"

bubbleFeatureCell = SettingsSwitchCell(
title: "Present \"Bubble\" overlay in engagement time",
isOn: props.features ~= .bubbleView
Expand Down Expand Up @@ -272,7 +280,8 @@ private extension SettingsViewController {
siteApiKeyIdCell,
siteApiKeySecretCell,
queueIDCell,
visitorContextAssedIdCell
visitorContextAssedIdCell,
manualLocaleOverrideCell
]
configurationSection = Section(
title: "Glia configuration",
Expand All @@ -284,12 +293,16 @@ private extension SettingsViewController {
private func updateConfiguration() {
let uuid = UUID(uuidString: visitorContextAssedIdCell.textField.text ?? "")

let manualLocaleOverrideText = manualLocaleOverrideCell.textField.text ?? ""
let manualLocaleOverride = manualLocaleOverrideText.isEmpty ? nil : manualLocaleOverrideText

props.changeConfig(
Configuration(
authorizationMethod: siteApiKey,
environment: environmentCell.environment,
site: siteCell.textField.text ?? "",
visitorContext: uuid.map { Configuration.VisitorContext(assetId: $0) }
visitorContext: uuid.map { Configuration.VisitorContext(assetId: $0) },
manualLocaleOverride: manualLocaleOverride
)
)

Expand Down
38 changes: 24 additions & 14 deletions TestingApp/ViewController/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ class ViewController: UIViewController {

private func showErrorAlert(using error: Error) {
if let gliaError = error as? GliaError {

switch gliaError {
case GliaError.engagementExists:
alert(message: "Failed to start\nEngagement is ongoing, please use 'Resume' button")
Expand All @@ -101,6 +100,10 @@ class ViewController: UIViewController {
alert(message: "Failed to start\nCall Visualizer engagement is ongoing")
case GliaError.configuringDuringEngagementIsNotAllowed:
alert(message: "The operation couldn't be completed. '\(gliaError)'.")
case GliaError.invalidSiteApiKeyCredentials:
alert(message: "Failed to configure the SDK, invalid credentials")
case GliaError.invalidLocale:
alert(message: "Failed to configure the SDK, invalid locale override specified")
default:
alert(message: "Failed to start\nCheck Glia parameters in Settings")
}
Expand Down Expand Up @@ -240,6 +243,7 @@ extension ViewController {
self?.configureButton.accessibilityIdentifier = originalIdentifier
debugPrint(printable)
}

do {
try Glia.sharedInstance.configure(
with: configuration
Expand All @@ -249,7 +253,7 @@ extension ViewController {
completionBlock("SDK has been configured")
completion?(.success(()))
case let .failure(error):
completionBlock(error)
completionBlock("Error configuring the SDK")
completion?(.failure(error))
}
}
Expand Down Expand Up @@ -373,7 +377,6 @@ extension ViewController {
}

func setupPushHandler() {
let waitForActiveEngagement = GliaCore.sharedInstance.waitForActiveEngagement(completion:)
GliaCore.sharedInstance.pushNotifications.handler = { [weak self] push in
switch (push.type, push.timing) {
// Open chat transcript only when the push notification has come
Expand Down Expand Up @@ -403,19 +406,26 @@ extension ViewController {

@IBAction private func toggleAuthentication() {
catchingError {
try Glia.sharedInstance.configure(with: configuration) { [weak self] in
try Glia.sharedInstance.configure(with: configuration) { [weak self] result in
guard let self = self else { return }
self.catchingError {
let authentication = try Self.authentication()
switch authentication.isAuthenticated {
case false:
self.showAuthorize(with: authentication)
case true:
self.showDeauthorize(
authorization: authentication,
from: self.toggleAuthenticateButton
)

switch result {
case .success:
self.catchingError {
let authentication = try Self.authentication()
switch authentication.isAuthenticated {
case false:
self.showAuthorize(with: authentication)
case true:
self.showDeauthorize(
authorization: authentication,
from: self.toggleAuthenticateButton
)
}
}

case .failure(let error):
self.showErrorAlert(using: error)
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions swiftgen-strings.stencil
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ import Foundation
{% elif param.lookupFunction %}
{{accessModifier}} static var {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}: String { return {{enumName}}.tr("{{table}}", "{{string.key}}", fallback: "{{translation}}") }
{% else %}
{{accessModifier}} static let {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{enumName}}.tr("{{table}}", "{{string.key}}", fallback: "{{translation}}")
{{accessModifier}} static var {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}: String { {{enumName}}.tr("{{table}}", "{{string.key}}", fallback: "{{translation}}") }
{% if string.key == "general.company_name" %}
/// {{translation}} without asking string provider
{{accessModifier}} static let {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}LocalFallbackOnly = {{enumName}}.tr("{{table}}", "{{string.key}}", fallback: "{{translation}}", stringProviding: nil)
{{accessModifier}} static var {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}LocalFallbackOnly: String { {{enumName}}.tr("{{table}}", "{{string.key}}", fallback: "{{translation}}", stringProviding: nil) }
{% endif %}
{% endif %}
{% endfor %}
Expand Down

0 comments on commit b85ebdd

Please sign in to comment.