├── .gitignore
├── .npmignore
├── .prettierrc.json
├── .vscode
└── settings.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── RNZendeskChat.d.ts
├── RNZendeskChat.podspec
├── android
├── .gitignore
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── taskrabbit
│ └── zendesk
│ ├── RNZendeskChatModule.java
│ └── RNZendeskChatPackage.java
├── index.js
├── ios
├── RNZendeskChat.xcodeproj
│ └── project.pbxproj
├── RNZendeskChatModule.h
└── RNZendeskChatModule.m
├── package.json
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependency directory
2 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
3 | node_modules
4 | package-lock.json
5 | yarn-error.log
6 | ios/RNZendeskChat/RNZendeskChat.xcodeproj/xcuserdata
7 | ios/RNZendeskChat/RNZendeskChat.xcodeproj/project.xcworkspace
8 |
9 | # Xcode
10 | #
11 | build/
12 | *.pbxuser
13 | !default.pbxuser
14 | *.mode1v3
15 | !default.mode1v3
16 | *.mode2v3
17 | !default.mode2v3
18 | *.perspectivev3
19 | !default.perspectivev3
20 | *.xcworkspace
21 | !Scripts/xctool/xctool.xcworkspace
22 | !default.xcworkspace
23 | xcuserdata
24 | *.xccheckout
25 | *.moved-aside
26 | DerivedData
27 | *.hmap
28 | *.ipa
29 | *.xcuserstate
30 | project.xcworkspace
31 |
32 | # OSX
33 | #
34 | .DS_Store
35 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .vscode/*
2 | .gitignore
3 | *.log
4 | .prettierrc.json
5 |
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "overrides": [
3 | {
4 | "files": "package.json",
5 | "options": { "parser": "json" }
6 | }
7 | ],
8 | "proseWrap": "never",
9 | "trailingComma": "all",
10 | "useTabs": true
11 | }
12 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.words": [
3 | "autodetect",
4 | "barthelemy",
5 | "bot",
6 | "bot's",
7 | "chua",
8 | "cocoapod",
9 | "cocoapods",
10 | "fbartho",
11 | "gabrielperales",
12 | "jrichardlai",
13 | "kachanovskyi",
14 | "perales",
15 | "zanechua",
16 | "zendesk",
17 | "zendesk's",
18 | "zopim"
19 | ],
20 | "files.exclude": {
21 | "**/.classpath": true,
22 | "**/.project": true,
23 | "**/.settings": true,
24 | "**/.factorypath": true
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | This project hasn't kept a changelog historically, and it would be infeasible to retroactively create one.
4 |
5 | Instead, for the near future, releases will be encapsulated by a [milestone](https://github.com/taskrabbit/react-native-zendesk-chat/milestones) and [Github Releases](https://github.com/taskrabbit/react-native-zendesk-chat/releases)
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) TaskRabbit, Inc. and its affiliates.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-native-zendesk-chat
2 |
3 | Simple module that supports displaying Zendesk Chat within a React Native Application.
4 |
5 | This library assumes you're familiar with Zendesk's Official Documentation: [iOS](https://developer.zendesk.com/embeddables/docs/chat-sdk-v-2-for-ios/introduction) and [Android](https://developer.zendesk.com/embeddables/docs/chat-sdk-v-2-for-android/introduction).
6 |
7 | ## VERSIONS
8 |
9 | - For **Zendesk Chat v2** use version >= 0.4.0 (this requires RN 0.59 or later!)
10 | - For RN version >= 0.59 use version >= 0.3.0 (Zendesk Chat v1)
11 | - For RN version < 0.59 use version <= 0.2.2 (Zendesk Chat v1)
12 |
13 | ## Known Issues
14 |
15 | ## Getting Started
16 |
17 | With npm:
18 |
19 | `npm install react-native-zendesk-chat --save`
20 |
21 | or with yarn:
22 |
23 | `yarn add react-native-zendesk-chat`
24 |
25 | ### QuickStart & Usage
26 |
27 | 1. Setup Native Dependencies
**iOS** If you're on react-native >= 0.60 and you have Cocoapods setup, then you just need to:
28 |
29 | ```bash
30 | $ yarn install # and see if there are any errors
31 | $ (cd ios; pod install) # and see if there are any errors
32 | # -- you may need to do `pod install --repo-update`
33 | ```
34 |
35 | If you're on older react-native versions, please see the [Advanced Setup](#advanced-setup) section below
36 |
37 | **Android** If you're on react-native >= 0.60, Android should autodetect this dependency. If you're on 0.59, you may need to call `react-native link`
38 |
39 | 2. Call the JS Initializer:
40 |
41 | ```javascript
42 | import ZendeskChat from "react-native-zendesk-chat";
43 |
44 | // Once in your application:
45 | ZendeskChat.init("YOUR_ZENDESK_ACCOUNT_KEY");
46 |
47 | // Optionally specify the appId provided by Zendesk
48 | ZendeskChat.init("YOUR_ZENDESK_ACCOUNT_KEY", "APP_ID_PROVIDED_BY_ZENDESK");
49 | ```
50 |
51 | 3. Show the Chat UI
52 |
53 | ```javascript
54 | // On button press, when you want to show chat:
55 | ZendeskChat.startChat({
56 | name: user.full_name,
57 | email: user.email,
58 | phone: user.mobile_phone,
59 | tags: ["tag1", "tag2"],
60 | department: "Your department",
61 | // The behaviorFlags are optional, and each default to 'true' if omitted
62 | behaviorFlags: {
63 | showAgentAvailability: true,
64 | showChatTranscriptPrompt: true,
65 | showPreChatForm: true,
66 | showOfflineForm: true,
67 | },
68 | // The preChatFormOptions are optional & each defaults to "optional" if omitted
69 | preChatFormOptions: {
70 | name: !user.full_name ? "required" : "optional",
71 | email: "optional",
72 | phone: "optional",
73 | department: "required",
74 | },
75 | localizedDismissButtonTitle: "Dismiss",
76 | });
77 | ```
78 |
79 |
80 | ### Obtaining the `YOUR_ZENDESK_ACCOUNT_KEY`
81 | To optain your zendesk account key see the instructions in [Initializing the SDK](https://api.zopim.com/web-sdk/#initializing-the-sdk) in the Zendesk SDK.
82 |
83 | To get your account key, follow these steps:
84 |
85 | 1. In the Zendesk Chat Dashboard, click on your profile in the upper right corner and click on the 'Check Connection' option:
86 | 
87 | 1. In the dialog, copy the account key value
88 | 
89 |
90 |
91 | ### Styling
92 |
93 | Changing the UI Styling is mostly achieved through native techniques.
94 |
95 | On Android, this is the [official documentation](https://developer.zendesk.com/embeddables/docs/android-unified-sdk/customize_the_look#how-theming-works) -- and an example might be adding these [3 lines to your app theme](https://github.com/zendesk/sdk_demo_app_android/blob/ae4c551f78911e983b0aac06967628f46be15e54/app/src/main/res/values/styles.xml#L5-L7)
96 |
97 | While on iOS, the options are more minimal -- check the [official doc page](https://developer.zendesk.com/embeddables/docs/chat-sdk-v-2-for-ios/customize_the_look#styling-the-chat-screen)
98 |
99 | ### Migrating
100 |
101 | _From react-native-zendesk-chat <= 0.3.0_
102 |
103 | To migrate from previous versions of the library, you should probably remove all integration steps you applied, and start over from the [Quick Start](#quickstart--usage).
104 |
105 | The JS API calls are very similar, with mostly additive changes.
106 |
107 | ### Advanced Setup
108 |
109 | Advanced users, or users running on older versions of react-native may want to initialize things in native.
110 |
111 | #### iOS: Manually Setting up with Cocoapods
112 |
113 | If you're on iOS < 0.60, you may need to manually install the cocoapod:
114 |
115 | Add a reference to your Podfile:
116 |
117 | ```Podfile
118 | pod 'RNZendeskChat', :git => 'https://github.com/taskrabbit/react-native-zendesk-chat.git'
119 | ```
120 |
121 | then run pod install: `(cd ios; pod install)`
122 |
123 | or manually:
124 |
125 | In Xcode, drag and drop `node_modules/react-native-zendesk-chat/RNZendeskChat.m` and `node_modules/react-native-zendesk-chat/RNZendeskChat.h` into your project.
126 |
127 | #### iOS: Configure `ZDCChat` in `AppDelegate.m`:
128 |
129 | ```objective-c
130 | #import
131 |
132 | // ...
133 |
134 | // Inside the appropriate appDidFinishLaunching method
135 | [ZDCChat initializeWithAccountKey:@"YOUR_ZENDESK_ACCOUNT_KEY" appId:"YOUR_ZENDESK_APP_ID"];
136 |
137 | // And access other interesting APIs
138 | ```
139 |
140 | #### Android: Manual Setup & Configuration
141 |
142 | If you're on react-native < 0.60, you should be able to call `react-native link`.
143 |
144 | If this doesn't work, then you may need to do a complete manual install as follows:
145 |
146 | 1. Open up `android/app/main/java/[...]/MainApplication.java`
147 |
148 | - Add `import com.taskrabbit.zendesk.*;` to the imports at the top of the file
149 | - Add `new RNZendeskChatPackage(this)` to the list returned by the `getPackages()` method
150 |
151 | 2. Append the following lines to `android/settings.gradle`:
152 |
153 | ```gradle
154 | include ':react-native-zendesk-chat'
155 | project(':react-native-zendesk-chat').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-zendesk-chat/android')
156 | ```
157 |
158 | 3. Insert the following lines inside the dependencies block in `android/app/build.gradle`:
159 |
160 | For RN >= 0.60:
161 |
162 | ```gradle
163 | dependencies {
164 | //
165 | api group: 'com.zendesk', name: 'chat', version: '2.2.0'
166 | api group: 'com.zendesk', name: 'messaging', version: '4.3.1'
167 | ```
168 | also in project build.gradle
169 |
170 | Add ```gradle
171 | maven { url 'https://zendesk.jfrog.io/zendesk/repo' }```
172 |
173 | For RN < 0.60:
174 |
175 | ```gradle
176 | compile project(':react-native-zendesk-chat')
177 | ```
178 |
179 | 4. Configure `Chat` in `android/app/main/java/[...]/MainActivity.java`
180 |
181 | ```java
182 | // Note: there is a JS method to do this -- prefer doing that! -- This is for advanced users only.
183 |
184 | // Call this once in your Activity's bootup lifecycle
185 | Chat.INSTANCE.init(mReactContext, key, appId);
186 | ```
187 |
188 | ## Contributing
189 |
190 | - Pull Requests are encouraged!
191 | - Be respectful!
192 | - The trunk branch of this repo is called `main`
193 |
194 | ## License
195 |
196 | React Native Zendesk Chat is MIT licensed, as found in the [LICENSE](https://github.com/taskrabbit/react-native-zendesk-chat/LICENSE) file.
197 |
--------------------------------------------------------------------------------
/RNZendeskChat.d.ts:
--------------------------------------------------------------------------------
1 | declare module "react-native-zendesk-chat" {
2 | interface VisitorInfoOptions {
3 | name?: string;
4 | email?: string;
5 | phone?: string;
6 | }
7 |
8 | interface MessagingOptionsCommon {
9 | /** Set this to set the bot's displayName */
10 | botName?: string;
11 | }
12 | interface MessagingOptions_iOS extends MessagingOptionsCommon {
13 | /** Will be loaded using [UIImage imageWithName:…] ) */
14 | botAvatarName?: string;
15 | /** Will be loaded using [UIImage imageWithData:[NSData dataWithContentsOfUrl:…]] */
16 | botAvatarUrl?: string;
17 | }
18 | interface MessagingOptions_Android extends MessagingOptionsCommon {
19 | /** Will be loaded from your native asset resources */
20 | botAvatarDrawableId?: number;
21 | }
22 |
23 | /** Current default is "optional" */
24 | type PreChatFormFieldOptionVisibility = "hidden" | "optional" | "required";
25 |
26 | interface StartChatOptions extends VisitorInfoOptions {
27 | department?: string;
28 | tags?: string[];
29 |
30 | behaviorFlags?: {
31 | /**
32 | * if omitted, the form is enabled
33 | *
34 | * @warning Android: If you enable preChat form with `required` or `optional` for keys
35 | * Then any visitor info you provide statically as VisitorInfoOptions will be ignored.
36 | * This is documented upstream here: https://support.zendesk.com/hc/en-us/articles/360055343673
37 | */
38 | showPreChatForm?: boolean;
39 | /** if omitted, the prompt is enabled */
40 | showChatTranscriptPrompt?: boolean;
41 | /** if omitted, the form is enabled */
42 | showOfflineForm?: boolean;
43 | /** if omitted, the agent availability message is enabled */
44 | showAgentAvailability?: boolean;
45 | };
46 |
47 | /**
48 | * If omitted, the preChatForm will be left as default in Zendesk, be explicit if you want control.
49 | *
50 | * @warning Android: If you provide the preChat form with `required` or `optional` for keys
51 | * Then any visitor info you provide statically as VisitorInfoOptions will be ignored.
52 | * This is documented upstream here: https://support.zendesk.com/hc/en-us/articles/360055343673
53 | */
54 | preChatFormOptions?: {
55 | /** Should we ask the user for a contact email? */
56 | email?: PreChatFormFieldOptionVisibility;
57 | /** Should we ask the user their name? */
58 | name?: PreChatFormFieldOptionVisibility;
59 | /** Should we ask the user for their phone number? */
60 | phone?: PreChatFormFieldOptionVisibility;
61 | /** Should we ask the user which department? */
62 | department?: PreChatFormFieldOptionVisibility;
63 | };
64 |
65 | /**
66 | * Configure the Chat-Bot (if any)
67 | */
68 | messagingOptions?: MessagingOptions_iOS & MessagingOptions_Android;
69 |
70 | /**
71 | * If not provided, this will be "Close" -- not localized!
72 | *
73 | * -- iOS Only (Android: shows just a Back Button)
74 | */
75 | localizedDismissButtonTitle?: string;
76 | }
77 |
78 | class RNZendeskChatModuleImpl {
79 | /**
80 | * Must be called before calling startChat/setVisitorInfo
81 | * - (Advanced users may configure this natively instead of calling this from JS)
82 | */
83 | init: (zendeskAccountKey: string, appId?: string) => void;
84 |
85 | /**
86 | * Presents the Zendesk Chat User Interface
87 | */
88 | startChat: (options: StartChatOptions) => void;
89 | /**
90 | * Backwards Compatibility!
91 | * - You can pass all these parameters to RNZendeskChatModule.startChat
92 | * - So you should probably prefer that method
93 | */
94 | setVisitorInfo: (options: VisitorInfoOptions) => void;
95 |
96 | /**
97 | * Configure the token to start receiving Push Notifications
98 | */
99 | registerPushToken: (token: string) => void;
100 |
101 | /**
102 | * Check if there are available agents
103 | */
104 | areAgentsOnline: () => Promise;
105 | }
106 |
107 | const RNZendeskChatModule: RNZendeskChatModuleImpl;
108 |
109 | export default RNZendeskChatModule;
110 | }
111 |
--------------------------------------------------------------------------------
/RNZendeskChat.podspec:
--------------------------------------------------------------------------------
1 | require 'json'
2 |
3 | package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4 |
5 | Pod::Spec.new do |s|
6 | s.name = 'RNZendeskChat'
7 | s.version = package['version']
8 | s.summary = package['description']
9 | s.license = package['license']
10 | s.authors = package['author']
11 | s.homepage = package['homepage']
12 | s.platform = :ios, '10'
13 | s.source = { git: 'https://github.com/taskrabbit/react-native-zendesk-chat.git', tag: "v#{s.version}" }
14 | s.source_files = 'ios/*.{h,m}'
15 | s.static_framework = true
16 |
17 | s.framework = 'Foundation'
18 | s.framework = 'UIKit'
19 |
20 | s.dependency 'React-Core'
21 | s.dependency 'ZendeskChatSDK', '~> 2.9'
22 | end
23 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | # Android-specific gitignoreables
2 |
3 | .idea
4 | .gradle
5 | **/*.iml
6 | build/
7 | .idea
8 | .gradle
9 | local.properties
10 |
11 | # Classpath can differ on developer machines, though I think it's relative currently
12 | .classpath
13 | # Project files can contain developer-specific config? It's unclear,
14 | # and the community debates whether they should be ignored.
15 | # Since they're auto-generated sometimes, this should be okay?
16 | .project
17 |
18 | # I think this is genned by vscode-java extension
19 | org.eclipse.buildship.core.prefs
20 | org.eclipse.jdt.core.prefs
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | def safeExtGet(prop, fallback) {
4 | rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
5 | }
6 |
7 | buildscript {
8 | repositories {
9 | jcenter()
10 | google()
11 | }
12 |
13 | dependencies {
14 | classpath 'com.android.tools.build:gradle:3.2.1'
15 | }
16 | }
17 |
18 | android {
19 | compileSdkVersion safeExtGet('compileSdkVersion', 28)
20 | buildToolsVersion safeExtGet('buildToolsVersion', "28.0.3")
21 |
22 | defaultConfig {
23 | minSdkVersion safeExtGet('minSdkVersion', 16)
24 | targetSdkVersion safeExtGet('targetSdkVersion', 28)
25 | versionCode 1
26 | versionName "1.0"
27 | }
28 | }
29 |
30 | repositories {
31 | mavenCentral()
32 | jcenter()
33 | google()
34 | maven { url 'https://zendesk.jfrog.io/zendesk/repo' }
35 | }
36 |
37 | dependencies {
38 | implementation "com.facebook.react:react-native:+"
39 |
40 | api group: 'com.zendesk', name: 'chat', version: safeExtGet('zendeskChatVersion', '3.1.0')
41 | api group: 'com.zendesk', name: 'messaging', version: safeExtGet('zendeskMessagingVersion', '5.1.0')
42 | }
43 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/android/src/main/java/com/taskrabbit/zendesk/RNZendeskChatModule.java:
--------------------------------------------------------------------------------
1 | package com.taskrabbit.zendesk;
2 |
3 | import android.app.Activity;
4 | import android.content.pm.ApplicationInfo;
5 | import android.util.Log;
6 |
7 | import com.facebook.react.bridge.Promise;
8 | import com.facebook.react.bridge.ReactApplicationContext;
9 | import com.facebook.react.bridge.ReactContext;
10 | import com.facebook.react.bridge.ReactContextBaseJavaModule;
11 | import com.facebook.react.bridge.ReactMethod;
12 | import com.facebook.react.bridge.ReadableArray;
13 | import com.facebook.react.bridge.ReadableMap;
14 | import com.facebook.react.bridge.ReadableType;
15 | import com.facebook.react.bridge.WritableNativeMap;
16 |
17 | import zendesk.chat.Account;
18 | import zendesk.chat.AccountStatus;
19 | import zendesk.chat.Chat;
20 | import zendesk.chat.ChatConfiguration;
21 | import zendesk.chat.ChatEngine;
22 | import zendesk.chat.ChatSessionStatus;
23 | import zendesk.chat.ChatState;
24 | import zendesk.chat.ObservationScope;
25 | import zendesk.chat.Observer;
26 | import zendesk.chat.ProfileProvider;
27 | import zendesk.chat.PreChatFormFieldStatus;
28 | import zendesk.chat.PushNotificationsProvider;
29 | import zendesk.chat.VisitorInfo;
30 | import zendesk.messaging.MessagingActivity;
31 | import zendesk.messaging.MessagingConfiguration;
32 | import com.zendesk.service.ErrorResponse;
33 | import com.zendesk.service.ZendeskCallback;
34 |
35 | import java.lang.String;
36 | import java.util.ArrayList;
37 |
38 | public class RNZendeskChatModule extends ReactContextBaseJavaModule {
39 | private static final String TAG = "[RNZendeskChatModule]";
40 |
41 | private ArrayList currentUserTags = new ArrayList();
42 |
43 | private ReadableMap pendingVisitorInfo = null;
44 | private ObservationScope observationScope = null;
45 |
46 | // private class Converters {
47 | public static ArrayList getArrayListOfStrings(ReadableMap options, String key, String functionHint) {
48 | ArrayList result = new ArrayList();
49 |
50 | if (!options.hasKey(key)) {
51 | return result;
52 | }
53 | if (options.getType(key) != ReadableType.Array) {
54 | Log.e(RNZendeskChatModule.TAG, "wrong type for key '" + key + "' when processing " + functionHint
55 | + ", expected an Array of Strings.");
56 | return result;
57 | }
58 | ReadableArray arr = options.getArray(key);
59 | for (int i = 0; i < arr.size(); i++) {
60 | if (arr.isNull(i)) {
61 | continue;
62 | }
63 | if (arr.getType(i) != ReadableType.String) {
64 | Log.e(RNZendeskChatModule.TAG, "wrong type for key '" + key + "[" + i + "]' when processing "
65 | + functionHint + ", expected entry to be a String.");
66 | }
67 | result.add(arr.getString(i));
68 | }
69 | return result;
70 | }
71 |
72 | public static String getStringOrNull(ReadableMap options, String key, String functionHint) {
73 | if (!options.hasKey(key)) {
74 | return null;
75 | }
76 | if (options.getType(key) != ReadableType.String) {
77 | Log.e(RNZendeskChatModule.TAG,
78 | "wrong type for key '" + key + "' when processing " + functionHint + ", expected a String.");
79 | return null;
80 | }
81 | return options.getString(key);
82 | }
83 |
84 | public static int getIntOrDefault(ReadableMap options, String key, String functionHint, int defaultValue) {
85 | if (!options.hasKey(key)) {
86 | return defaultValue;
87 | }
88 | if (options.getType(key) != ReadableType.String) {
89 | Log.e(RNZendeskChatModule.TAG,
90 | "wrong type for key '" + key + "' when processing " + functionHint + ", expected an Integer.");
91 | return defaultValue;
92 | }
93 | return options.getInt(key);
94 | }
95 |
96 | public static boolean getBooleanOrDefault(ReadableMap options, String key, String functionHint,
97 | boolean defaultValue) {
98 | if (!options.hasKey(key)) {
99 | return defaultValue;
100 | }
101 | if (options.getType(key) != ReadableType.Boolean) {
102 | Log.e(RNZendeskChatModule.TAG,
103 | "wrong type for key '" + key + "' when processing " + functionHint + ", expected a Boolean.");
104 | return defaultValue;
105 | }
106 | return options.getBoolean(key);
107 | }
108 |
109 | public static PreChatFormFieldStatus getFieldStatusOrDefault(ReadableMap options, String key,
110 | PreChatFormFieldStatus defaultValue) {
111 | if (!options.hasKey(key)) {
112 | return defaultValue;
113 | }
114 | if (options.getType(key) != ReadableType.String) {
115 | Log.e(RNZendeskChatModule.TAG, "wrong type for key '" + key
116 | + "' when processing startChat(preChatFormOptions), expected one of ('required' | 'optional' | 'hidden').");
117 | return defaultValue;
118 | }
119 | switch (options.getString(key)) {
120 | case "required":
121 | return PreChatFormFieldStatus.REQUIRED;
122 | case "optional":
123 | return PreChatFormFieldStatus.OPTIONAL;
124 | case "hidden":
125 | return PreChatFormFieldStatus.HIDDEN;
126 | default:
127 | Log.e(RNZendeskChatModule.TAG, "wrong type for key '" + key
128 | + "' when processing startChat(preChatFormOptions), expected one of ('required' | 'optional' | 'hidden').");
129 | return defaultValue;
130 | }
131 | }
132 |
133 | public static ReadableMap getReadableMap(ReadableMap options, String key, String functionHint) {
134 | if (!options.hasKey(key)) {
135 | return new WritableNativeMap();
136 | }
137 | if (options.getType(key) != ReadableType.Map) {
138 | Log.e(RNZendeskChatModule.TAG,
139 | "wrong type for key '" + key + "' when processing " + functionHint + ", expected a config hash.");
140 | return new WritableNativeMap();
141 | }
142 | return options.getMap(key);
143 | }
144 |
145 | private void selectVisitorInfoFieldIfPreChatFormHidden(String key, WritableNativeMap output, ReadableMap input, ReadableMap shouldInclude) {
146 | if ((!input.hasKey(key) || input.getType(key) != ReadableType.String)
147 | || (shouldInclude.hasKey(key) && shouldInclude.getType(key) == ReadableType.String && !"hidden".equals(shouldInclude.getString(key))) ) {
148 | return;
149 | }
150 |
151 | String value = input.getString(key);
152 | if (((mReactContext.getApplicationInfo().flags
153 | & ApplicationInfo.FLAG_DEBUGGABLE) == 0)) {
154 | // We don't want other Apps to monitor our app's production logs for this debug information.
155 | // If you patch the app to enable it yourself, that's your choice!
156 | value = "";
157 | }
158 |
159 | Log.d(TAG, "selectVisitorInfo to set later " + key + " '" + value + "'");
160 | output.putString(key, input.getString(key));
161 | }
162 | // }
163 |
164 | private ReactContext mReactContext;
165 |
166 | public RNZendeskChatModule(ReactApplicationContext reactContext) {
167 | super(reactContext);
168 | mReactContext = reactContext;
169 | }
170 |
171 | @Override
172 | public String getName() {
173 | return "RNZendeskChatModule";
174 | }
175 |
176 | @ReactMethod
177 | public void setVisitorInfo(ReadableMap options) {
178 | _setVisitorInfo(options);
179 | }
180 | private boolean _setVisitorInfo(ReadableMap options) {
181 | boolean anyValuesWereSet = false;
182 | VisitorInfo.Builder builder = VisitorInfo.builder();
183 |
184 | String name = getStringOrNull(options, "name", "visitorInfo");
185 | if (name != null) {
186 | builder = builder.withName(name);
187 | anyValuesWereSet = true;
188 | }
189 | String email = getStringOrNull(options, "email", "visitorInfo");
190 | if (email != null) {
191 | builder = builder.withEmail(email);
192 | anyValuesWereSet = true;
193 | }
194 | String phone = getStringOrNull(options, "phone", "visitorInfo");
195 | if (phone != null) {
196 | builder = builder.withPhoneNumber(phone);
197 | anyValuesWereSet = true;
198 | }
199 |
200 | VisitorInfo visitorInfo = builder.build();
201 |
202 | if (Chat.INSTANCE.providers() == null) {
203 | Log.e(TAG,
204 | "Zendesk Internals are undefined -- did you forget to call RNZendeskModule.init()?");
205 | return false;
206 | }
207 |
208 | Chat.INSTANCE.providers().profileProvider().setVisitorInfo(visitorInfo, null);
209 |
210 | return anyValuesWereSet;
211 | }
212 |
213 | // Unfortunately, react-native: android doesn't support the following
214 | // - Java's Method Overloading
215 | // - automatically providing null to undefined parameters (like iOS)
216 | //
217 | // As a result, we need to guarantee this is always called with 2 parameters from JS
218 | //
219 | // This method has been renamed to make that clear, and index.js is adding the
220 | // correct interface for init() at runtime
221 | @ReactMethod
222 | public void _initWith2Args(String key, String appId) {
223 | if (appId != null) {
224 | Chat.INSTANCE.init(mReactContext, key, appId);
225 | } else {
226 | Chat.INSTANCE.init(mReactContext, key);
227 | }
228 | Log.d(TAG, "Chat.INSTANCE was properly initialized from JS.");
229 | }
230 |
231 | private ChatConfiguration.Builder loadBehaviorFlags(ChatConfiguration.Builder b, ReadableMap options) {
232 | boolean defaultValue = true;
233 | String logHint = "startChat(behaviorFlags)";
234 |
235 | return b.withPreChatFormEnabled(getBooleanOrDefault(options, "showPreChatForm", logHint, defaultValue))
236 | .withTranscriptEnabled(getBooleanOrDefault(options, "showChatTranscriptPrompt", logHint, defaultValue))
237 | .withOfflineFormEnabled(getBooleanOrDefault(options, "showOfflineForm", logHint, defaultValue))
238 | .withAgentAvailabilityEnabled(
239 | getBooleanOrDefault(options, "showAgentAvailability", logHint, defaultValue));
240 | }
241 |
242 | private ChatConfiguration.Builder loadPreChatFormConfiguration(ChatConfiguration.Builder b, ReadableMap options) {
243 | PreChatFormFieldStatus defaultValue = PreChatFormFieldStatus.OPTIONAL;
244 | return b.withNameFieldStatus(getFieldStatusOrDefault(options, "name", defaultValue))
245 | .withEmailFieldStatus(getFieldStatusOrDefault(options, "email", defaultValue))
246 | .withPhoneFieldStatus(getFieldStatusOrDefault(options, "phone", defaultValue))
247 | .withDepartmentFieldStatus(getFieldStatusOrDefault(options, "department", defaultValue));
248 | }
249 | // Produces a ReadableMap suitable for passing to setVisitorInfo that only has the fields that won't be asked by the preChatForm
250 | private ReadableMap hiddenVisitorInfoData(ReadableMap allVisitorInfo, ReadableMap preChatFormOptions) {
251 | WritableNativeMap output = new WritableNativeMap();
252 | selectVisitorInfoFieldIfPreChatFormHidden("email", output, allVisitorInfo, preChatFormOptions);
253 | selectVisitorInfoFieldIfPreChatFormHidden("name", output, allVisitorInfo, preChatFormOptions);
254 | selectVisitorInfoFieldIfPreChatFormHidden("phone", output, allVisitorInfo, preChatFormOptions);
255 | return output;
256 | }
257 |
258 | private void loadTags(ReadableMap options) {
259 | // ZendeskChat Android treats the tags persistently, so you have to add/remove
260 | // as things change -- aka doing a diff :-(
261 | // ZendeskChat iOS just lets you override the full array so this isn't
262 | // necessary on that side.
263 | if (Chat.INSTANCE.providers() == null) {
264 | Log.e(TAG,
265 | "Zendesk Internals are undefined -- did you forget to call RNZendeskModule.init()?");
266 | return;
267 | }
268 |
269 | ProfileProvider profileProvider = Chat.INSTANCE.providers().profileProvider();
270 | ArrayList activeTags = (ArrayList) currentUserTags.clone();
271 |
272 | ArrayList allProvidedTags = RNZendeskChatModule.getArrayListOfStrings(options, "tags", "startChat");
273 | ArrayList newlyIntroducedTags = (ArrayList) allProvidedTags.clone();
274 |
275 | newlyIntroducedTags.remove(activeTags); // Now just includes tags to add
276 | currentUserTags.removeAll(allProvidedTags); // Now just includes tags to delete
277 |
278 | if (!currentUserTags.isEmpty()) {
279 | profileProvider.removeVisitorTags(currentUserTags, null);
280 | }
281 | if (!newlyIntroducedTags.isEmpty()) {
282 | profileProvider.addVisitorTags(newlyIntroducedTags, null);
283 | }
284 |
285 | currentUserTags = allProvidedTags;
286 | }
287 |
288 | private MessagingConfiguration.Builder loadBotSettings(ReadableMap options,
289 | MessagingConfiguration.Builder builder) {
290 | if (options == null) {
291 | return builder;
292 | }
293 | String botName = getStringOrNull(options, "botName", "loadBotSettings");
294 | if (botName != null) {
295 | builder = builder.withBotLabelString(botName);
296 | }
297 | int avatarDrawable = getIntOrDefault(options, "botAvatarDrawableId", "loadBotSettings", -1);
298 | if (avatarDrawable != -1) {
299 | builder = builder.withBotAvatarDrawable(avatarDrawable);
300 | }
301 |
302 | return builder;
303 | }
304 |
305 | @ReactMethod
306 | public void startChat(ReadableMap options) {
307 | if (Chat.INSTANCE.providers() == null) {
308 | Log.e(TAG,
309 | "Zendesk Internals are undefined -- did you forget to call RNZendeskModule.init()?");
310 | return;
311 | }
312 | pendingVisitorInfo = null;
313 | boolean didSetVisitorInfo = _setVisitorInfo(options);
314 |
315 | ReadableMap flagHash = RNZendeskChatModule.getReadableMap(options, "behaviorFlags", "startChat");
316 |
317 | boolean showPreChatForm = getBooleanOrDefault(flagHash, "showPreChatForm", "startChat(behaviorFlags)", true);
318 | boolean needsToSetVisitorInfoAfterChatStart = showPreChatForm && didSetVisitorInfo;
319 |
320 | ChatConfiguration.Builder chatBuilder = loadBehaviorFlags(ChatConfiguration.builder(), flagHash);
321 | if (showPreChatForm) {
322 | ReadableMap preChatFormOptions = getReadableMap(options, "preChatFormOptions", "startChat");
323 | chatBuilder = loadPreChatFormConfiguration(chatBuilder, preChatFormOptions);
324 | pendingVisitorInfo = hiddenVisitorInfoData(options, preChatFormOptions);
325 | }
326 | ChatConfiguration chatConfig = chatBuilder.build();
327 |
328 | String department = RNZendeskChatModule.getStringOrNull(options, "department", "startChat");
329 | if (department != null) {
330 | Chat.INSTANCE.providers().chatProvider().setDepartment(department, null);
331 | }
332 |
333 | loadTags(options);
334 |
335 | MessagingConfiguration.Builder messagingBuilder = loadBotSettings(
336 | getReadableMap(options, "messagingOptions", "startChat"), MessagingActivity.builder());
337 |
338 | if (needsToSetVisitorInfoAfterChatStart) {
339 | setupChatStartObserverToSetVisitorInfo();
340 | }
341 |
342 | Activity activity = getCurrentActivity();
343 | if (activity != null) {
344 | messagingBuilder.withEngines(ChatEngine.engine()).show(activity, chatConfig);
345 | } else {
346 | Log.e(TAG, "Could not load getCurrentActivity -- no UI can be displayed without it.");
347 | }
348 | }
349 |
350 | @ReactMethod
351 | public void registerPushToken(String token) {
352 | PushNotificationsProvider pushProvider = Chat.INSTANCE.providers().pushNotificationsProvider();
353 |
354 | if (pushProvider != null) {
355 | pushProvider.registerPushToken(token);
356 | }
357 | }
358 |
359 | // https://support.zendesk.com/hc/en-us/articles/360055343673
360 | public void setupChatStartObserverToSetVisitorInfo(){
361 | // Create a temporary observation scope until the chat is started.
362 | observationScope = new ObservationScope();
363 | Chat.INSTANCE.providers().chatProvider().observeChatState(observationScope, new Observer() {
364 | @Override
365 | public void update(ChatState chatState) {
366 | ChatSessionStatus chatStatus = chatState.getChatSessionStatus();
367 | // Status achieved after the PreChatForm is completed
368 | if (chatStatus == ChatSessionStatus.STARTED) {
369 | observationScope.cancel(); // Once the chat is started disable the observation
370 | observationScope = null; // Clean things up to avoid confusion.
371 | if (pendingVisitorInfo == null) { return; }
372 |
373 | // Update the information MID chat here. All info but Department can be updated
374 | // Add here the code to set the selected visitor info *after* the preChatForm is complete
375 | _setVisitorInfo(pendingVisitorInfo);
376 | pendingVisitorInfo = null;
377 |
378 | Log.d(TAG, "Set the VisitorInfo after chat start");
379 | } else {
380 | // There are few other statuses that you can observe but they are unused in this example
381 | Log.d(TAG, "[observerSetup] - ChatSessionUpdate -> (unused) status : " + chatStatus.toString());
382 | }
383 | }
384 | });
385 | }
386 |
387 | @ReactMethod
388 | public void areAgentsOnline(final Promise promise) {
389 | Chat.INSTANCE.providers().accountProvider().getAccount(new ZendeskCallback() {
390 | @Override
391 | public void onSuccess(Account account) {
392 | AccountStatus status = account.getStatus();
393 |
394 | switch (status) {
395 | case ONLINE:
396 | promise.resolve(true);
397 | break;
398 |
399 | default:
400 | promise.resolve(false);
401 | break;
402 | }
403 | }
404 |
405 | @Override
406 | public void onError(ErrorResponse errorResponse) {
407 | promise.reject("no-available-zendesk-account", "DevError: Not connected to Zendesk or network issue");
408 | }
409 | });
410 | }
411 | }
412 |
--------------------------------------------------------------------------------
/android/src/main/java/com/taskrabbit/zendesk/RNZendeskChatPackage.java:
--------------------------------------------------------------------------------
1 | package com.taskrabbit.zendesk;
2 |
3 | import com.facebook.react.ReactPackage;
4 | import com.facebook.react.bridge.JavaScriptModule;
5 | import com.facebook.react.bridge.NativeModule;
6 | import com.facebook.react.bridge.ReactApplicationContext;
7 | import com.facebook.react.uimanager.ViewManager;
8 |
9 | import java.util.ArrayList;
10 | import java.util.Collections;
11 | import java.util.List;
12 |
13 | public class RNZendeskChatPackage implements ReactPackage {
14 |
15 | @Override
16 | public List createNativeModules(
17 | ReactApplicationContext reactContext) {
18 | List modules = new ArrayList<>();
19 |
20 | modules.add(new RNZendeskChatModule(reactContext));
21 | return modules;
22 | }
23 |
24 | public List> createJSModules() {
25 | return Collections.emptyList();
26 | }
27 |
28 | @Override
29 | public List createViewManagers(ReactApplicationContext reactApplicationContext) {
30 | return Collections.emptyList();
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import { NativeModules } from "react-native";
2 |
3 | const RNZendeskChatModule = NativeModules.RNZendeskChatModule;
4 |
5 | // react-native doesn't support method overloading for Java or Objective-C
6 | // So this code implements the init method but makes sure to
7 | // always call it with two defined parameters, passing null for the second as needed
8 | // Reference: https://github.com/facebook/react-native/blob/07d090dbc6c46b8f3760dbd25dbe0540c18cb3f3/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaModuleWrapper.java#L85-L86
9 |
10 | RNZendeskChatModule.init = (key, appId) => {
11 | return RNZendeskChatModule._initWith2Args(key, appId || null);
12 | };
13 |
14 | /**
15 | * TypeScript Documentation for this Module describes the available methods & parameters
16 | *
17 | * @see { ./RNZendeskChat.d.ts }
18 | */
19 | export default RNZendeskChatModule;
20 |
--------------------------------------------------------------------------------
/ios/RNZendeskChat.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | B6462ECD1C603E5C0010294B /* RNZendeskChatModule.m in Sources */ = {isa = PBXBuildFile; fileRef = B6462ECC1C603E5C0010294B /* RNZendeskChatModule.m */; };
11 | /* End PBXBuildFile section */
12 |
13 | /* Begin PBXCopyFilesBuildPhase section */
14 | B6462EBD1C603E340010294B /* CopyFiles */ = {
15 | isa = PBXCopyFilesBuildPhase;
16 | buildActionMask = 2147483647;
17 | dstPath = "include/$(PRODUCT_NAME)";
18 | dstSubfolderSpec = 16;
19 | files = (
20 | );
21 | runOnlyForDeploymentPostprocessing = 0;
22 | };
23 | /* End PBXCopyFilesBuildPhase section */
24 |
25 | /* Begin PBXFileReference section */
26 | B6462EBF1C603E340010294B /* libRNZendeskChat.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNZendeskChat.a; sourceTree = BUILT_PRODUCTS_DIR; };
27 | B6462ECB1C603E5C0010294B /* RNZendeskChatModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNZendeskChatModule.h; sourceTree = ""; };
28 | B6462ECC1C603E5C0010294B /* RNZendeskChatModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNZendeskChatModule.m; sourceTree = ""; };
29 | /* End PBXFileReference section */
30 |
31 | /* Begin PBXFrameworksBuildPhase section */
32 | B6462EBC1C603E340010294B /* Frameworks */ = {
33 | isa = PBXFrameworksBuildPhase;
34 | buildActionMask = 2147483647;
35 | files = (
36 | );
37 | runOnlyForDeploymentPostprocessing = 0;
38 | };
39 | /* End PBXFrameworksBuildPhase section */
40 |
41 | /* Begin PBXGroup section */
42 | B6462EB61C603E340010294B = {
43 | isa = PBXGroup;
44 | children = (
45 | B6462ECB1C603E5C0010294B /* RNZendeskChatModule.h */,
46 | B6462ECC1C603E5C0010294B /* RNZendeskChatModule.m */,
47 | B6462EC01C603E340010294B /* Products */,
48 | );
49 | sourceTree = "";
50 | };
51 | B6462EC01C603E340010294B /* Products */ = {
52 | isa = PBXGroup;
53 | children = (
54 | B6462EBF1C603E340010294B /* libRNZendeskChat.a */,
55 | );
56 | name = Products;
57 | sourceTree = "";
58 | };
59 | /* End PBXGroup section */
60 |
61 | /* Begin PBXNativeTarget section */
62 | B6462EBE1C603E340010294B /* RNZendeskChat */ = {
63 | isa = PBXNativeTarget;
64 | buildConfigurationList = B6462EC81C603E340010294B /* Build configuration list for PBXNativeTarget "RNZendeskChat" */;
65 | buildPhases = (
66 | B6462EBB1C603E340010294B /* Sources */,
67 | B6462EBC1C603E340010294B /* Frameworks */,
68 | B6462EBD1C603E340010294B /* CopyFiles */,
69 | );
70 | buildRules = (
71 | );
72 | dependencies = (
73 | );
74 | name = RNZendeskChat;
75 | productName = RNZendeskChat;
76 | productReference = B6462EBF1C603E340010294B /* libRNZendeskChat.a */;
77 | productType = "com.apple.product-type.library.static";
78 | };
79 | /* End PBXNativeTarget section */
80 |
81 | /* Begin PBXProject section */
82 | B6462EB71C603E340010294B /* Project object */ = {
83 | isa = PBXProject;
84 | attributes = {
85 | LastUpgradeCheck = 0720;
86 | ORGANIZATIONNAME = TaskRabbit;
87 | TargetAttributes = {
88 | B6462EBE1C603E340010294B = {
89 | CreatedOnToolsVersion = 7.2;
90 | };
91 | };
92 | };
93 | buildConfigurationList = B6462EBA1C603E340010294B /* Build configuration list for PBXProject "RNZendeskChat" */;
94 | compatibilityVersion = "Xcode 3.2";
95 | developmentRegion = English;
96 | hasScannedForEncodings = 0;
97 | knownRegions = (
98 | en,
99 | );
100 | mainGroup = B6462EB61C603E340010294B;
101 | productRefGroup = B6462EC01C603E340010294B /* Products */;
102 | projectDirPath = "";
103 | projectRoot = "";
104 | targets = (
105 | B6462EBE1C603E340010294B /* RNZendeskChat */,
106 | );
107 | };
108 | /* End PBXProject section */
109 |
110 | /* Begin PBXSourcesBuildPhase section */
111 | B6462EBB1C603E340010294B /* Sources */ = {
112 | isa = PBXSourcesBuildPhase;
113 | buildActionMask = 2147483647;
114 | files = (
115 | B6462ECD1C603E5C0010294B /* RNZendeskChatModule.m in Sources */,
116 | );
117 | runOnlyForDeploymentPostprocessing = 0;
118 | };
119 | /* End PBXSourcesBuildPhase section */
120 |
121 | /* Begin XCBuildConfiguration section */
122 | B6462EC61C603E340010294B /* Debug */ = {
123 | isa = XCBuildConfiguration;
124 | buildSettings = {
125 | ALWAYS_SEARCH_USER_PATHS = NO;
126 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
127 | CLANG_CXX_LIBRARY = "libc++";
128 | CLANG_ENABLE_MODULES = YES;
129 | CLANG_ENABLE_OBJC_ARC = YES;
130 | CLANG_WARN_BOOL_CONVERSION = YES;
131 | CLANG_WARN_CONSTANT_CONVERSION = YES;
132 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
133 | CLANG_WARN_EMPTY_BODY = YES;
134 | CLANG_WARN_ENUM_CONVERSION = YES;
135 | CLANG_WARN_INT_CONVERSION = YES;
136 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
137 | CLANG_WARN_UNREACHABLE_CODE = YES;
138 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
139 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
140 | COPY_PHASE_STRIP = NO;
141 | DEBUG_INFORMATION_FORMAT = dwarf;
142 | ENABLE_STRICT_OBJC_MSGSEND = YES;
143 | ENABLE_TESTABILITY = YES;
144 | GCC_C_LANGUAGE_STANDARD = gnu99;
145 | GCC_DYNAMIC_NO_PIC = NO;
146 | GCC_NO_COMMON_BLOCKS = YES;
147 | GCC_OPTIMIZATION_LEVEL = 0;
148 | GCC_PREPROCESSOR_DEFINITIONS = (
149 | "DEBUG=1",
150 | "$(inherited)",
151 | );
152 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
153 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
154 | GCC_WARN_UNDECLARED_SELECTOR = YES;
155 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
156 | GCC_WARN_UNUSED_FUNCTION = YES;
157 | GCC_WARN_UNUSED_VARIABLE = YES;
158 | IPHONEOS_DEPLOYMENT_TARGET = 9.2;
159 | MTL_ENABLE_DEBUG_INFO = YES;
160 | ONLY_ACTIVE_ARCH = YES;
161 | SDKROOT = iphoneos;
162 | };
163 | name = Debug;
164 | };
165 | B6462EC71C603E340010294B /* Release */ = {
166 | isa = XCBuildConfiguration;
167 | buildSettings = {
168 | ALWAYS_SEARCH_USER_PATHS = NO;
169 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
170 | CLANG_CXX_LIBRARY = "libc++";
171 | CLANG_ENABLE_MODULES = YES;
172 | CLANG_ENABLE_OBJC_ARC = YES;
173 | CLANG_WARN_BOOL_CONVERSION = YES;
174 | CLANG_WARN_CONSTANT_CONVERSION = YES;
175 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
176 | CLANG_WARN_EMPTY_BODY = YES;
177 | CLANG_WARN_ENUM_CONVERSION = YES;
178 | CLANG_WARN_INT_CONVERSION = YES;
179 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
180 | CLANG_WARN_UNREACHABLE_CODE = YES;
181 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
182 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
183 | COPY_PHASE_STRIP = NO;
184 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
185 | ENABLE_NS_ASSERTIONS = NO;
186 | ENABLE_STRICT_OBJC_MSGSEND = YES;
187 | GCC_C_LANGUAGE_STANDARD = gnu99;
188 | GCC_NO_COMMON_BLOCKS = YES;
189 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
190 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
191 | GCC_WARN_UNDECLARED_SELECTOR = YES;
192 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
193 | GCC_WARN_UNUSED_FUNCTION = YES;
194 | GCC_WARN_UNUSED_VARIABLE = YES;
195 | IPHONEOS_DEPLOYMENT_TARGET = 9.2;
196 | MTL_ENABLE_DEBUG_INFO = NO;
197 | SDKROOT = iphoneos;
198 | VALIDATE_PRODUCT = YES;
199 | };
200 | name = Release;
201 | };
202 | B6462EC91C603E340010294B /* Debug */ = {
203 | isa = XCBuildConfiguration;
204 | buildSettings = {
205 | HEADER_SEARCH_PATHS = (
206 | "$(inherited)",
207 | "$(SRCROOT)/../../../React/**",
208 | "$(SRCROOT)/../../react-native/React/**",
209 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
210 | );
211 | OTHER_LDFLAGS = "-ObjC";
212 | PRODUCT_NAME = "$(TARGET_NAME)";
213 | SKIP_INSTALL = YES;
214 | };
215 | name = Debug;
216 | };
217 | B6462ECA1C603E340010294B /* Release */ = {
218 | isa = XCBuildConfiguration;
219 | buildSettings = {
220 | HEADER_SEARCH_PATHS = (
221 | "$(inherited)",
222 | "$(SRCROOT)/../../../React/**",
223 | "$(SRCROOT)/../../react-native/React/**",
224 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
225 | );
226 | OTHER_LDFLAGS = "-ObjC";
227 | PRODUCT_NAME = "$(TARGET_NAME)";
228 | SKIP_INSTALL = YES;
229 | };
230 | name = Release;
231 | };
232 | /* End XCBuildConfiguration section */
233 |
234 | /* Begin XCConfigurationList section */
235 | B6462EBA1C603E340010294B /* Build configuration list for PBXProject "RNZendeskChat" */ = {
236 | isa = XCConfigurationList;
237 | buildConfigurations = (
238 | B6462EC61C603E340010294B /* Debug */,
239 | B6462EC71C603E340010294B /* Release */,
240 | );
241 | defaultConfigurationIsVisible = 0;
242 | defaultConfigurationName = Release;
243 | };
244 | B6462EC81C603E340010294B /* Build configuration list for PBXNativeTarget "RNZendeskChat" */ = {
245 | isa = XCConfigurationList;
246 | buildConfigurations = (
247 | B6462EC91C603E340010294B /* Debug */,
248 | B6462ECA1C603E340010294B /* Release */,
249 | );
250 | defaultConfigurationIsVisible = 0;
251 | defaultConfigurationName = Release;
252 | };
253 | /* End XCConfigurationList section */
254 | };
255 | rootObject = B6462EB71C603E340010294B /* Project object */;
256 | }
257 |
--------------------------------------------------------------------------------
/ios/RNZendeskChatModule.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import
4 |
5 | @interface RNZendeskChatModule : NSObject
6 |
7 | @end
8 |
--------------------------------------------------------------------------------
/ios/RNZendeskChatModule.m:
--------------------------------------------------------------------------------
1 | //
2 | // RNZendeskChat.m
3 | // Tasker
4 | //
5 | // Created by Jean-Richard Lai on 11/23/15.
6 | //
7 |
8 |
9 | #import "RNZendeskChatModule.h"
10 |
11 | #import
12 | #import
13 |
14 | #import
15 | #import
16 | #import
17 | #import
18 |
19 |
20 | @implementation RCTConvert (ZDKChatFormFieldStatus)
21 |
22 | RCT_ENUM_CONVERTER(ZDKFormFieldStatus,
23 | (@{
24 | @"required": @(ZDKFormFieldStatusRequired),
25 | @"optional": @(ZDKFormFieldStatusOptional),
26 | @"hidden": @(ZDKFormFieldStatusHidden),
27 | }),
28 | ZDKFormFieldStatusOptional,
29 | integerValue);
30 |
31 | @end
32 |
33 | @interface RNZendeskChatModule ()
34 | @end
35 |
36 | @implementation RNZendeskChatModule
37 | // Backwards compatibility with the unnecessary setVisitorInfo method
38 | ZDKChatAPIConfiguration *_visitorAPIConfig;
39 |
40 |
41 | RCT_EXPORT_MODULE(RNZendeskChatModule);
42 |
43 | RCT_EXPORT_METHOD(setVisitorInfo:(NSDictionary *)options) {
44 | if (!NSThread.isMainThread) {
45 | dispatch_async(dispatch_get_main_queue(), ^{
46 | [self setVisitorInfo:options];
47 | });
48 | return;
49 | }
50 |
51 | ZDKChat.instance.configuration = _visitorAPIConfig = [self applyVisitorInfo:options intoConfig: _visitorAPIConfig ?: [[ZDKChatAPIConfiguration alloc] init]];
52 | }
53 |
54 | - (ZDKChatAPIConfiguration*)applyVisitorInfo:(NSDictionary*)options intoConfig:(ZDKChatAPIConfiguration*)config {
55 | if (options[@"department"]) {
56 | config.department = options[@"department"];
57 | }
58 | if (options[@"tags"]) {
59 | config.tags = options[@"tags"];
60 | }
61 | config.visitorInfo = [[ZDKVisitorInfo alloc] initWithName:options[@"name"]
62 | email:options[@"email"]
63 | phoneNumber:options[@"phone"]];
64 |
65 | NSLog(@"[RNZendeskChatModule] Applied visitor info: department: %@ tags: %@, email: %@, name: %@, phone: %@", config.department, config.tags, config.visitorInfo.email, config.visitorInfo.name, config.visitorInfo.phoneNumber);
66 | return config;
67 | }
68 |
69 | #define RNZDKConfigHashErrorLog(options, what)\
70 | if (!!options) {\
71 | NSLog(@"[RNZendeskChatModule] Invalid %@ -- expected a config hash", what);\
72 | }
73 |
74 | - (ZDKMessagingConfiguration *)messagingConfigurationFromConfig:(NSDictionary*)options {
75 | ZDKMessagingConfiguration *config = [[ZDKMessagingConfiguration alloc] init];
76 | if (!options || ![options isKindOfClass:NSDictionary.class]) {
77 | RNZDKConfigHashErrorLog(options, @"MessagingConfiguration config options");
78 | return config;
79 | }
80 | if (options[@"botName"]) {
81 | config.name = options[@"botName"];
82 | }
83 |
84 | if (options[@"botAvatarName"]) {
85 | config.botAvatar = [UIImage imageNamed:@"botAvatarName"];
86 | } else if (options[@"botAvatarUrl"]) {
87 | config.botAvatar = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:options[@"botAvatarUrl"]]]];
88 | }
89 |
90 | return config;
91 | }
92 |
93 | - (ZDKChatFormConfiguration * _Nullable)preChatFormConfigurationFromConfig:(NSDictionary*)options {
94 | if (!options || ![options isKindOfClass:NSDictionary.class]) {
95 | RNZDKConfigHashErrorLog(options, @"pre-Chat-Form Configuration Options");
96 | return nil;
97 | }
98 | #define ParseFormFieldStatus(key)\
99 | ZDKFormFieldStatus key = [RCTConvert ZDKFormFieldStatus:options[@"" #key]]
100 | ParseFormFieldStatus(name);
101 | ParseFormFieldStatus(email);
102 | ParseFormFieldStatus(phone);
103 | ParseFormFieldStatus(department);
104 | #undef ParseFormFieldStatus
105 | return [[ZDKChatFormConfiguration alloc] initWithName:name
106 | email:email
107 | phoneNumber:phone
108 | department:department];
109 | }
110 | - (ZDKChatConfiguration *)chatConfigurationFromConfig:(NSDictionary*)options {
111 | options = options ?: @{};
112 |
113 | ZDKChatConfiguration* config = [[ZDKChatConfiguration alloc] init];
114 | if (![options isKindOfClass:NSDictionary.class]){
115 | RNZDKConfigHashErrorLog(options, @"Chat Configuration Options");
116 | return config;
117 | }
118 | NSDictionary * behaviorFlags = options[@"behaviorFlags"];
119 | if (!behaviorFlags || ![behaviorFlags isKindOfClass:NSDictionary.class]) {
120 | RNZDKConfigHashErrorLog(behaviorFlags, @"BehaviorFlags -- expected a config hash");
121 | behaviorFlags = NSDictionary.dictionary;
122 | }
123 |
124 | #define ParseBehaviorFlag(key, target)\
125 | config.target = [RCTConvert BOOL: behaviorFlags[@"" #key] ?: @YES]
126 | ParseBehaviorFlag(showPreChatForm, isPreChatFormEnabled);
127 | ParseBehaviorFlag(showChatTranscriptPrompt, isChatTranscriptPromptEnabled);
128 | ParseBehaviorFlag(showOfflineForm, isOfflineFormEnabled);
129 | ParseBehaviorFlag(showAgentAvailability, isAgentAvailabilityEnabled);
130 | #undef ParseBehaviorFlag
131 |
132 | if (config.isPreChatFormEnabled) {
133 | ZDKChatFormConfiguration * formConfig = [self preChatFormConfigurationFromConfig:options[@"preChatFormOptions"]];
134 | if (!!formConfig) {
135 | // Zendesk Swift Code crashes if you provide a nil form
136 | config.preChatFormConfiguration = formConfig;
137 | }
138 | }
139 | return config;
140 | }
141 |
142 | RCT_EXPORT_METHOD(startChat:(NSDictionary *)options) {
143 | if (!options || ![options isKindOfClass: NSDictionary.class]) {
144 | if (!!options){
145 | NSLog(@"[RNZendeskChatModule] Invalid JS startChat Configuration Options -- expected a config hash");
146 | }
147 | options = NSDictionary.dictionary;
148 | }
149 |
150 | dispatch_sync(dispatch_get_main_queue(), ^{
151 |
152 | ZDKChat.instance.configuration = [self applyVisitorInfo:options
153 | intoConfig: _visitorAPIConfig ?: [[ZDKChatAPIConfiguration alloc] init]];
154 |
155 | ZDKChatConfiguration * chatConfig = [self chatConfigurationFromConfig:options];
156 |
157 | NSError *error = nil;
158 | NSArray *engines = @[
159 | [ZDKChatEngine engineAndReturnError:&error]
160 | ];
161 | if (!!error) {
162 | NSLog(@"[RNZendeskChatModule] Internal Error loading ZDKChatEngine %@", error);
163 | return;
164 | }
165 |
166 | ZDKMessagingConfiguration *messagingConfig = [self messagingConfigurationFromConfig: options[@"messagingOptions"]];
167 |
168 | UIViewController *viewController = [ZDKMessaging.instance buildUIWithEngines:engines
169 | configs:@[chatConfig, messagingConfig]
170 | error:&error];
171 | if (!!error) {
172 | NSLog(@"[RNZendeskChatModule] Internal Error building ZDKMessagingUI %@",error);
173 | return;
174 | }
175 |
176 | viewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: options[@"localizedDismissButtonTitle"] ?: @"Close"
177 | style: UIBarButtonItemStylePlain
178 | target: self
179 | action: @selector(dismissChatUI)];
180 |
181 | UINavigationController *chatController = [[UINavigationController alloc] initWithRootViewController: viewController];
182 | [RCTPresentedViewController() presentViewController:chatController animated:YES completion:nil];
183 | });
184 | }
185 |
186 | - (void) dismissChatUI {
187 | [RCTPresentedViewController() dismissViewControllerAnimated:YES completion:nil];
188 | }
189 |
190 | RCT_EXPORT_METHOD(_initWith2Args:(NSString *)zenDeskKey appId:(NSString *)appId) {
191 | if (appId) {
192 | [ZDKChat initializeWithAccountKey:zenDeskKey appId:appId queue:dispatch_get_main_queue()];
193 | } else {
194 | [ZDKChat initializeWithAccountKey:zenDeskKey queue:dispatch_get_main_queue()];
195 | }
196 | }
197 |
198 | RCT_EXPORT_METHOD(registerPushToken:(NSString *)token) {
199 | dispatch_sync(dispatch_get_main_queue(), ^{
200 | [ZDKChat registerPushTokenString:token];
201 | });
202 | }
203 |
204 | RCT_EXPORT_METHOD(areAgentsOnline:
205 | (RCTPromiseResolveBlock) resolve
206 | rejecter: (RCTPromiseRejectBlock) reject) {
207 |
208 | [ZDKChat.accountProvider getAccount:^(ZDKChatAccount *account, NSError *error) {
209 | if (account) {
210 | switch (account.accountStatus) {
211 | case ZDKChatAccountStatusOnline:
212 | resolve(@YES);
213 | break;
214 |
215 | default:
216 | resolve(@NO);
217 | break;
218 | }
219 | } else {
220 | reject(@"no-available-zendesk-account", @"DevError: Not connected to Zendesk or network issue", error);
221 | }
222 | }];
223 | }
224 |
225 | @end
226 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-zendesk-chat",
3 | "version": "0.4.1",
4 | "description": "React Native Wrapper around Zopim Zendesk Chat",
5 | "main": "index.js",
6 | "types": "RNZendeskChat.d.ts",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/taskrabbit/react-native-zendesk-chat"
10 | },
11 | "scripts": {
12 | "prettier": "prettier",
13 | "prettier:all": "prettier --write '**/*.json' '**/*.js' '**/*.ts' ",
14 | "lint": "eslint"
15 | },
16 | "keywords": [
17 | "zendesk",
18 | "chat",
19 | "react-native",
20 | "react",
21 | "ios",
22 | "android",
23 | "react-component"
24 | ],
25 | "homepage": "https://github.com/taskrabbit/react-native-zendesk-chat.git",
26 | "bugs": "https://github.com/taskrabbit/react-native-zendesk-chat/issues",
27 | "author": "jrichardlai",
28 | "contributors": [
29 | "Brian Leonard ",
30 | "Frederic Barthelemy ",
31 | "Gabriel Perales ",
32 | "Jean-Richard Lai ",
33 | "Jordan Smith ",
34 | "Michael Kachanovskyi ",
35 | "Robert Murray ",
36 | "Zane Chua "
37 | ],
38 | "license": "MIT",
39 | "devDependencies": { "prettier": "2.0.x", "eslint": "7.3.x" },
40 | "peerDependencies": {
41 | "react": "^16.11.0",
42 | "react-native": "0.60.x | 0.61.x | 0.62.x | 0.63.x"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@babel/code-frame@^7.0.0":
6 | version "7.10.3"
7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.3.tgz#324bcfd8d35cd3d47dae18cde63d752086435e9a"
8 | integrity sha512-fDx9eNW0qz0WkUeqL6tXEXzVlPh6Y5aCDEZesl0xBGA8ndRukX91Uk44ZqnkECp01NAZUdCAl+aiQNGi0k88Eg==
9 | dependencies:
10 | "@babel/highlight" "^7.10.3"
11 |
12 | "@babel/helper-validator-identifier@^7.10.3":
13 | version "7.10.3"
14 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.3.tgz#60d9847f98c4cea1b279e005fdb7c28be5412d15"
15 | integrity sha512-bU8JvtlYpJSBPuj1VUmKpFGaDZuLxASky3LhaKj3bmpSTY6VWooSM8msk+Z0CZoErFye2tlABF6yDkT3FOPAXw==
16 |
17 | "@babel/highlight@^7.10.3":
18 | version "7.10.3"
19 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.3.tgz#c633bb34adf07c5c13156692f5922c81ec53f28d"
20 | integrity sha512-Ih9B/u7AtgEnySE2L2F0Xm0GaM729XqqLfHkalTsbjXGyqmf/6M0Cu0WpvqueUlW+xk88BHw9Nkpj49naU+vWw==
21 | dependencies:
22 | "@babel/helper-validator-identifier" "^7.10.3"
23 | chalk "^2.0.0"
24 | js-tokens "^4.0.0"
25 |
26 | "@types/color-name@^1.1.1":
27 | version "1.1.1"
28 | resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
29 | integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
30 |
31 | acorn-jsx@^5.2.0:
32 | version "5.2.0"
33 | resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe"
34 | integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==
35 |
36 | acorn@^7.2.0:
37 | version "7.3.1"
38 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.3.1.tgz#85010754db53c3fbaf3b9ea3e083aa5c5d147ffd"
39 | integrity sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==
40 |
41 | ajv@^6.10.0, ajv@^6.10.2:
42 | version "6.12.2"
43 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd"
44 | integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==
45 | dependencies:
46 | fast-deep-equal "^3.1.1"
47 | fast-json-stable-stringify "^2.0.0"
48 | json-schema-traverse "^0.4.1"
49 | uri-js "^4.2.2"
50 |
51 | ansi-colors@^3.2.1:
52 | version "3.2.4"
53 | resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
54 | integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==
55 |
56 | ansi-regex@^4.1.0:
57 | version "4.1.0"
58 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
59 | integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
60 |
61 | ansi-regex@^5.0.0:
62 | version "5.0.0"
63 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
64 | integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
65 |
66 | ansi-styles@^3.2.0, ansi-styles@^3.2.1:
67 | version "3.2.1"
68 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
69 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
70 | dependencies:
71 | color-convert "^1.9.0"
72 |
73 | ansi-styles@^4.1.0:
74 | version "4.2.1"
75 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359"
76 | integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==
77 | dependencies:
78 | "@types/color-name" "^1.1.1"
79 | color-convert "^2.0.1"
80 |
81 | argparse@^1.0.7:
82 | version "1.0.10"
83 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
84 | integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
85 | dependencies:
86 | sprintf-js "~1.0.2"
87 |
88 | astral-regex@^1.0.0:
89 | version "1.0.0"
90 | resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
91 | integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
92 |
93 | balanced-match@^1.0.0:
94 | version "1.0.0"
95 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
96 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
97 |
98 | brace-expansion@^1.1.7:
99 | version "1.1.11"
100 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
101 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
102 | dependencies:
103 | balanced-match "^1.0.0"
104 | concat-map "0.0.1"
105 |
106 | callsites@^3.0.0:
107 | version "3.1.0"
108 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
109 | integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
110 |
111 | chalk@^2.0.0:
112 | version "2.4.2"
113 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
114 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
115 | dependencies:
116 | ansi-styles "^3.2.1"
117 | escape-string-regexp "^1.0.5"
118 | supports-color "^5.3.0"
119 |
120 | chalk@^4.0.0:
121 | version "4.1.0"
122 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a"
123 | integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==
124 | dependencies:
125 | ansi-styles "^4.1.0"
126 | supports-color "^7.1.0"
127 |
128 | color-convert@^1.9.0:
129 | version "1.9.3"
130 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
131 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
132 | dependencies:
133 | color-name "1.1.3"
134 |
135 | color-convert@^2.0.1:
136 | version "2.0.1"
137 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
138 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
139 | dependencies:
140 | color-name "~1.1.4"
141 |
142 | color-name@1.1.3:
143 | version "1.1.3"
144 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
145 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
146 |
147 | color-name@~1.1.4:
148 | version "1.1.4"
149 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
150 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
151 |
152 | concat-map@0.0.1:
153 | version "0.0.1"
154 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
155 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
156 |
157 | cross-spawn@^7.0.2:
158 | version "7.0.3"
159 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
160 | integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
161 | dependencies:
162 | path-key "^3.1.0"
163 | shebang-command "^2.0.0"
164 | which "^2.0.1"
165 |
166 | debug@^4.0.1:
167 | version "4.1.1"
168 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
169 | integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
170 | dependencies:
171 | ms "^2.1.1"
172 |
173 | deep-is@^0.1.3:
174 | version "0.1.3"
175 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
176 | integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
177 |
178 | doctrine@^3.0.0:
179 | version "3.0.0"
180 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
181 | integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
182 | dependencies:
183 | esutils "^2.0.2"
184 |
185 | emoji-regex@^7.0.1:
186 | version "7.0.3"
187 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
188 | integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
189 |
190 | enquirer@^2.3.5:
191 | version "2.3.5"
192 | resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.5.tgz#3ab2b838df0a9d8ab9e7dff235b0e8712ef92381"
193 | integrity sha512-BNT1C08P9XD0vNg3J475yIUG+mVdp9T6towYFHUv897X0KoHBjB1shyrNmhmtHWKP17iSWgo7Gqh7BBuzLZMSA==
194 | dependencies:
195 | ansi-colors "^3.2.1"
196 |
197 | escape-string-regexp@^1.0.5:
198 | version "1.0.5"
199 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
200 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
201 |
202 | eslint-scope@^5.1.0:
203 | version "5.1.0"
204 | resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5"
205 | integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==
206 | dependencies:
207 | esrecurse "^4.1.0"
208 | estraverse "^4.1.1"
209 |
210 | eslint-utils@^2.0.0:
211 | version "2.1.0"
212 | resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
213 | integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
214 | dependencies:
215 | eslint-visitor-keys "^1.1.0"
216 |
217 | eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.2.0:
218 | version "1.3.0"
219 | resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
220 | integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
221 |
222 | eslint@7.3.x:
223 | version "7.3.1"
224 | resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.3.1.tgz#76392bd7e44468d046149ba128d1566c59acbe19"
225 | integrity sha512-cQC/xj9bhWUcyi/RuMbRtC3I0eW8MH0jhRELSvpKYkWep3C6YZ2OkvcvJVUeO6gcunABmzptbXBuDoXsjHmfTA==
226 | dependencies:
227 | "@babel/code-frame" "^7.0.0"
228 | ajv "^6.10.0"
229 | chalk "^4.0.0"
230 | cross-spawn "^7.0.2"
231 | debug "^4.0.1"
232 | doctrine "^3.0.0"
233 | enquirer "^2.3.5"
234 | eslint-scope "^5.1.0"
235 | eslint-utils "^2.0.0"
236 | eslint-visitor-keys "^1.2.0"
237 | espree "^7.1.0"
238 | esquery "^1.2.0"
239 | esutils "^2.0.2"
240 | file-entry-cache "^5.0.1"
241 | functional-red-black-tree "^1.0.1"
242 | glob-parent "^5.0.0"
243 | globals "^12.1.0"
244 | ignore "^4.0.6"
245 | import-fresh "^3.0.0"
246 | imurmurhash "^0.1.4"
247 | is-glob "^4.0.0"
248 | js-yaml "^3.13.1"
249 | json-stable-stringify-without-jsonify "^1.0.1"
250 | levn "^0.4.1"
251 | lodash "^4.17.14"
252 | minimatch "^3.0.4"
253 | natural-compare "^1.4.0"
254 | optionator "^0.9.1"
255 | progress "^2.0.0"
256 | regexpp "^3.1.0"
257 | semver "^7.2.1"
258 | strip-ansi "^6.0.0"
259 | strip-json-comments "^3.1.0"
260 | table "^5.2.3"
261 | text-table "^0.2.0"
262 | v8-compile-cache "^2.0.3"
263 |
264 | espree@^7.1.0:
265 | version "7.1.0"
266 | resolved "https://registry.yarnpkg.com/espree/-/espree-7.1.0.tgz#a9c7f18a752056735bf1ba14cb1b70adc3a5ce1c"
267 | integrity sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw==
268 | dependencies:
269 | acorn "^7.2.0"
270 | acorn-jsx "^5.2.0"
271 | eslint-visitor-keys "^1.2.0"
272 |
273 | esprima@^4.0.0:
274 | version "4.0.1"
275 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
276 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
277 |
278 | esquery@^1.2.0:
279 | version "1.3.1"
280 | resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57"
281 | integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==
282 | dependencies:
283 | estraverse "^5.1.0"
284 |
285 | esrecurse@^4.1.0:
286 | version "4.2.1"
287 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
288 | integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==
289 | dependencies:
290 | estraverse "^4.1.0"
291 |
292 | estraverse@^4.1.0, estraverse@^4.1.1:
293 | version "4.3.0"
294 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
295 | integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
296 |
297 | estraverse@^5.1.0:
298 | version "5.1.0"
299 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.1.0.tgz#374309d39fd935ae500e7b92e8a6b4c720e59642"
300 | integrity sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==
301 |
302 | esutils@^2.0.2:
303 | version "2.0.3"
304 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
305 | integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
306 |
307 | fast-deep-equal@^3.1.1:
308 | version "3.1.3"
309 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
310 | integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
311 |
312 | fast-json-stable-stringify@^2.0.0:
313 | version "2.1.0"
314 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
315 | integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
316 |
317 | fast-levenshtein@^2.0.6:
318 | version "2.0.6"
319 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
320 | integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
321 |
322 | file-entry-cache@^5.0.1:
323 | version "5.0.1"
324 | resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c"
325 | integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==
326 | dependencies:
327 | flat-cache "^2.0.1"
328 |
329 | flat-cache@^2.0.1:
330 | version "2.0.1"
331 | resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
332 | integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==
333 | dependencies:
334 | flatted "^2.0.0"
335 | rimraf "2.6.3"
336 | write "1.0.3"
337 |
338 | flatted@^2.0.0:
339 | version "2.0.2"
340 | resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138"
341 | integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==
342 |
343 | fs.realpath@^1.0.0:
344 | version "1.0.0"
345 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
346 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
347 |
348 | functional-red-black-tree@^1.0.1:
349 | version "1.0.1"
350 | resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
351 | integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
352 |
353 | glob-parent@^5.0.0:
354 | version "5.1.1"
355 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
356 | integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==
357 | dependencies:
358 | is-glob "^4.0.1"
359 |
360 | glob@^7.1.3:
361 | version "7.1.6"
362 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
363 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
364 | dependencies:
365 | fs.realpath "^1.0.0"
366 | inflight "^1.0.4"
367 | inherits "2"
368 | minimatch "^3.0.4"
369 | once "^1.3.0"
370 | path-is-absolute "^1.0.0"
371 |
372 | globals@^12.1.0:
373 | version "12.4.0"
374 | resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8"
375 | integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==
376 | dependencies:
377 | type-fest "^0.8.1"
378 |
379 | has-flag@^3.0.0:
380 | version "3.0.0"
381 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
382 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
383 |
384 | has-flag@^4.0.0:
385 | version "4.0.0"
386 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
387 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
388 |
389 | ignore@^4.0.6:
390 | version "4.0.6"
391 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
392 | integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
393 |
394 | import-fresh@^3.0.0:
395 | version "3.2.1"
396 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66"
397 | integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==
398 | dependencies:
399 | parent-module "^1.0.0"
400 | resolve-from "^4.0.0"
401 |
402 | imurmurhash@^0.1.4:
403 | version "0.1.4"
404 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
405 | integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
406 |
407 | inflight@^1.0.4:
408 | version "1.0.6"
409 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
410 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
411 | dependencies:
412 | once "^1.3.0"
413 | wrappy "1"
414 |
415 | inherits@2:
416 | version "2.0.4"
417 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
418 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
419 |
420 | is-extglob@^2.1.1:
421 | version "2.1.1"
422 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
423 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
424 |
425 | is-fullwidth-code-point@^2.0.0:
426 | version "2.0.0"
427 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
428 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
429 |
430 | is-glob@^4.0.0, is-glob@^4.0.1:
431 | version "4.0.1"
432 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
433 | integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
434 | dependencies:
435 | is-extglob "^2.1.1"
436 |
437 | isexe@^2.0.0:
438 | version "2.0.0"
439 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
440 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
441 |
442 | js-tokens@^4.0.0:
443 | version "4.0.0"
444 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
445 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
446 |
447 | js-yaml@^3.13.1:
448 | version "3.14.0"
449 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482"
450 | integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==
451 | dependencies:
452 | argparse "^1.0.7"
453 | esprima "^4.0.0"
454 |
455 | json-schema-traverse@^0.4.1:
456 | version "0.4.1"
457 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
458 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
459 |
460 | json-stable-stringify-without-jsonify@^1.0.1:
461 | version "1.0.1"
462 | resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
463 | integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
464 |
465 | levn@^0.4.1:
466 | version "0.4.1"
467 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
468 | integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
469 | dependencies:
470 | prelude-ls "^1.2.1"
471 | type-check "~0.4.0"
472 |
473 | lodash@^4.17.14:
474 | version "4.17.19"
475 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
476 | integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
477 |
478 | minimatch@^3.0.4:
479 | version "3.0.4"
480 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
481 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
482 | dependencies:
483 | brace-expansion "^1.1.7"
484 |
485 | minimist@^1.2.5:
486 | version "1.2.5"
487 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
488 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
489 |
490 | mkdirp@^0.5.1:
491 | version "0.5.5"
492 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
493 | integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
494 | dependencies:
495 | minimist "^1.2.5"
496 |
497 | ms@^2.1.1:
498 | version "2.1.2"
499 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
500 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
501 |
502 | natural-compare@^1.4.0:
503 | version "1.4.0"
504 | resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
505 | integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
506 |
507 | once@^1.3.0:
508 | version "1.4.0"
509 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
510 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
511 | dependencies:
512 | wrappy "1"
513 |
514 | optionator@^0.9.1:
515 | version "0.9.1"
516 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
517 | integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==
518 | dependencies:
519 | deep-is "^0.1.3"
520 | fast-levenshtein "^2.0.6"
521 | levn "^0.4.1"
522 | prelude-ls "^1.2.1"
523 | type-check "^0.4.0"
524 | word-wrap "^1.2.3"
525 |
526 | parent-module@^1.0.0:
527 | version "1.0.1"
528 | resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
529 | integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
530 | dependencies:
531 | callsites "^3.0.0"
532 |
533 | path-is-absolute@^1.0.0:
534 | version "1.0.1"
535 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
536 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
537 |
538 | path-key@^3.1.0:
539 | version "3.1.1"
540 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
541 | integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
542 |
543 | prelude-ls@^1.2.1:
544 | version "1.2.1"
545 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
546 | integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
547 |
548 | prettier@2.0.x:
549 | version "2.0.5"
550 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4"
551 | integrity sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==
552 |
553 | progress@^2.0.0:
554 | version "2.0.3"
555 | resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
556 | integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
557 |
558 | punycode@^2.1.0:
559 | version "2.1.1"
560 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
561 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
562 |
563 | regexpp@^3.1.0:
564 | version "3.1.0"
565 | resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
566 | integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==
567 |
568 | resolve-from@^4.0.0:
569 | version "4.0.0"
570 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
571 | integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
572 |
573 | rimraf@2.6.3:
574 | version "2.6.3"
575 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
576 | integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
577 | dependencies:
578 | glob "^7.1.3"
579 |
580 | semver@^7.2.1:
581 | version "7.3.2"
582 | resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
583 | integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
584 |
585 | shebang-command@^2.0.0:
586 | version "2.0.0"
587 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
588 | integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
589 | dependencies:
590 | shebang-regex "^3.0.0"
591 |
592 | shebang-regex@^3.0.0:
593 | version "3.0.0"
594 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
595 | integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
596 |
597 | slice-ansi@^2.1.0:
598 | version "2.1.0"
599 | resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636"
600 | integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==
601 | dependencies:
602 | ansi-styles "^3.2.0"
603 | astral-regex "^1.0.0"
604 | is-fullwidth-code-point "^2.0.0"
605 |
606 | sprintf-js@~1.0.2:
607 | version "1.0.3"
608 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
609 | integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
610 |
611 | string-width@^3.0.0:
612 | version "3.1.0"
613 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
614 | integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
615 | dependencies:
616 | emoji-regex "^7.0.1"
617 | is-fullwidth-code-point "^2.0.0"
618 | strip-ansi "^5.1.0"
619 |
620 | strip-ansi@^5.1.0:
621 | version "5.2.0"
622 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
623 | integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
624 | dependencies:
625 | ansi-regex "^4.1.0"
626 |
627 | strip-ansi@^6.0.0:
628 | version "6.0.0"
629 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
630 | integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
631 | dependencies:
632 | ansi-regex "^5.0.0"
633 |
634 | strip-json-comments@^3.1.0:
635 | version "3.1.0"
636 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.0.tgz#7638d31422129ecf4457440009fba03f9f9ac180"
637 | integrity sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==
638 |
639 | supports-color@^5.3.0:
640 | version "5.5.0"
641 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
642 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
643 | dependencies:
644 | has-flag "^3.0.0"
645 |
646 | supports-color@^7.1.0:
647 | version "7.1.0"
648 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1"
649 | integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==
650 | dependencies:
651 | has-flag "^4.0.0"
652 |
653 | table@^5.2.3:
654 | version "5.4.6"
655 | resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e"
656 | integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==
657 | dependencies:
658 | ajv "^6.10.2"
659 | lodash "^4.17.14"
660 | slice-ansi "^2.1.0"
661 | string-width "^3.0.0"
662 |
663 | text-table@^0.2.0:
664 | version "0.2.0"
665 | resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
666 | integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
667 |
668 | type-check@^0.4.0, type-check@~0.4.0:
669 | version "0.4.0"
670 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
671 | integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
672 | dependencies:
673 | prelude-ls "^1.2.1"
674 |
675 | type-fest@^0.8.1:
676 | version "0.8.1"
677 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
678 | integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
679 |
680 | uri-js@^4.2.2:
681 | version "4.2.2"
682 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
683 | integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
684 | dependencies:
685 | punycode "^2.1.0"
686 |
687 | v8-compile-cache@^2.0.3:
688 | version "2.1.1"
689 | resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745"
690 | integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==
691 |
692 | which@^2.0.1:
693 | version "2.0.2"
694 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
695 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
696 | dependencies:
697 | isexe "^2.0.0"
698 |
699 | word-wrap@^1.2.3:
700 | version "1.2.3"
701 | resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
702 | integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
703 |
704 | wrappy@1:
705 | version "1.0.2"
706 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
707 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
708 |
709 | write@1.0.3:
710 | version "1.0.3"
711 | resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3"
712 | integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==
713 | dependencies:
714 | mkdirp "^0.5.1"
715 |
--------------------------------------------------------------------------------