fuse-importer 0.21.0 → 0.23.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +259 -0
  2. package/lib/esm/Importer/ImporterContextProvider.d.ts +31 -4
  3. package/lib/esm/Importer/ImporterContextProvider.js +40 -33
  4. package/lib/esm/Importer/Matcher/index.js +6 -5
  5. package/lib/esm/Importer/PreviewModeBanner.d.ts +2 -0
  6. package/lib/esm/Importer/PreviewModeBanner.js +20 -0
  7. package/lib/esm/Importer/Review/index.js +14 -18
  8. package/lib/esm/Importer/SpreadsheetReviewContextProvider.js +1 -1
  9. package/lib/esm/Importer/Stepper.js +10 -3
  10. package/lib/esm/Importer/Uploader/DragAndDropImporter/ImporterDropzone.js +4 -1
  11. package/lib/esm/Importer/Uploader/HeadersPreview.js +19 -17
  12. package/lib/esm/Importer/common/Spreadsheet/SpreadsheetContextProvider.js +7 -5
  13. package/lib/esm/Importer/common/Spreadsheet/common/FieldHeader.d.ts +7 -0
  14. package/lib/esm/Importer/common/Spreadsheet/common/FieldHeader.js +31 -0
  15. package/lib/esm/Importer/common/Spreadsheet/common/fields/SpeadsheetAutocomplete.d.ts +11 -6
  16. package/lib/esm/Importer/common/Spreadsheet/common/fields/SpeadsheetAutocomplete.js +6 -7
  17. package/lib/esm/Importer/common/Spreadsheet/common/fields/SpreadsheetInput.d.ts +4 -4
  18. package/lib/esm/Importer/common/Spreadsheet/common/fields/SpreadsheetInput.js +4 -5
  19. package/lib/esm/Importer/common/Spreadsheet/common/fields/index.d.ts +6 -5
  20. package/lib/esm/Importer/common/Spreadsheet/common/fields/index.js +14 -6
  21. package/lib/esm/Importer/common/Spreadsheet/common/index.d.ts +3 -0
  22. package/lib/esm/Importer/common/Spreadsheet/common/index.js +53 -9
  23. package/lib/esm/Importer/common/Spreadsheet/index.js +28 -57
  24. package/lib/esm/Importer/common/Spreadsheet/inputs/Boolean.d.ts +3 -0
  25. package/lib/esm/Importer/common/Spreadsheet/inputs/Boolean.js +18 -0
  26. package/lib/esm/Importer/common/Spreadsheet/inputs/EmailInput.d.ts +3 -0
  27. package/lib/esm/Importer/common/Spreadsheet/inputs/EmailInput.js +14 -0
  28. package/lib/esm/Importer/common/Spreadsheet/inputs/EnumInput.d.ts +6 -0
  29. package/lib/esm/Importer/common/Spreadsheet/inputs/EnumInput.js +30 -0
  30. package/lib/esm/Importer/common/Spreadsheet/inputs/FloatInput.d.ts +3 -0
  31. package/lib/esm/Importer/common/Spreadsheet/inputs/FloatInput.js +16 -0
  32. package/lib/esm/Importer/common/Spreadsheet/inputs/IntegerInput.d.ts +3 -0
  33. package/lib/esm/Importer/common/Spreadsheet/inputs/IntegerInput.js +16 -0
  34. package/lib/esm/Importer/common/Spreadsheet/inputs/StringInput.d.ts +3 -0
  35. package/lib/esm/Importer/common/Spreadsheet/inputs/StringInput.js +14 -0
  36. package/lib/esm/Importer/common/Spreadsheet/inputs/index.d.ts +13 -0
  37. package/lib/esm/Importer/common/Spreadsheet/inputs/index.js +20 -0
  38. package/lib/esm/Importer/common/index.d.ts +2 -2
  39. package/lib/esm/Importer/common/index.js +2 -2
  40. package/lib/esm/Importer/index.d.ts +1 -0
  41. package/lib/esm/Importer/index.js +3 -4
  42. package/lib/esm/Importer/theme.d.ts +225 -0
  43. package/lib/esm/Importer/theme.js +18 -0
  44. package/lib/esm/common/buttons.d.ts +15 -5
  45. package/lib/esm/common/buttons.js +13 -11
  46. package/lib/esm/common/index.js +1 -1
  47. package/lib/esm/common/inputs/Autocomplete.d.ts +2 -2
  48. package/lib/esm/common/inputs/TextInput.js +8 -1
  49. package/lib/esm/common/logo.js +1 -1
  50. package/lib/esm/styled/themeType.d.ts +1 -1
  51. package/lib/esm/styled/utils.d.ts +3 -0
  52. package/lib/esm/styled/utils.js +4 -3
  53. package/lib/esm/types.d.ts +7 -2
  54. package/lib/esm/types.js +4 -1
  55. package/lib/main.js +1 -1
  56. package/package.json +2 -2
  57. package/lib/esm/Importer/useCustomImporter.d.ts +0 -4
  58. package/lib/esm/Importer/useCustomImporter.js +0 -81
package/README.md ADDED
@@ -0,0 +1,259 @@
1
+ <div>
2
+ <center>
3
+ <a href="https://fuse.flatironsdevelopment.com/users/sign-up?utm_source=npmjs&utm_medium=Fuse+importer+logo&utm_campaign=NPM">
4
+ <img src="https://wp.flatironsdevelopment.com/wp-content/uploads/2022/07/fuse-logo.png">
5
+
6
+ </a>
7
+ </center>
8
+ <br>
9
+ <br>
10
+ <p>
11
+ Flatirons Fuse is a customizable and powerful CSV Importer that works with all front-end languages.
12
+ </p>
13
+ </div>
14
+
15
+ ## Table of Contents
16
+
17
+ - [Installation](#installation)
18
+ - [Introduction](#introduction)
19
+ - [Registration](#registration)
20
+ - [Create Your First Template](#create-your-first-template)
21
+ - [Getting started](#getting-started)
22
+ - [More Examples](#more-examples)
23
+ - [Usage](#usage)
24
+ - [FuseImporter Hooks](#fuseimporter-hooks)
25
+ - [`show`](#show)
26
+ - [`close`](#close)
27
+ - [`onClose`](#onclose)
28
+ - [`onValidateRecord`](#onvalidaterecord)
29
+ - [`formatRecord`](#formatrecord)
30
+ - [`onSubmit`](#onsubmit)
31
+
32
+ ## Installation
33
+
34
+ You can use Yarn, NPM, or a CDN to install the importer.
35
+
36
+ Install with npm:
37
+
38
+ ```bash
39
+ npm install fuse-importer --save
40
+ ```
41
+
42
+ Install with yarn:
43
+
44
+ ```bash
45
+ yarn add fuse-importer
46
+ ```
47
+
48
+ Install with CDN:
49
+
50
+ ```html
51
+ <script
52
+ type="text/javascript"
53
+ src="https://unpkg.com/fuse-importer@latest.js"
54
+ ></script>
55
+ ```
56
+
57
+ ## Introduction
58
+
59
+ Flatirons Fuse is our solution to the inevitable difficulties of getting customer data into your solution. We provide a white-labeled, customizable CSV and Spreadsheet import experience that is above all effective and flexible. Not only do we save you the time and effort of developing your own import solution, but we also ensure that setup and integration with your systems are a breeze.
60
+
61
+ To get started with our solution, you're going to need a free account and to create a template on our platform: [Flatirons Fuse](https://fuse.flatironsdevelopment.com/users/sign-up?utm_source=npmjs&utm_medium=Flatirons+Fuse+Get+Started&utm_campaign=NPM)
62
+
63
+ To use the importer you will need two keys:
64
+
65
+ - Your **Organization's API key**: You can find this at the top of the [Templates page](#create-your-first-template).
66
+ - Your **Template's ID**: You can find this in the table on the [Templates page](#create-your-first-template).
67
+
68
+ For more information see our [full documentation.](https://fuse-docs.flatironsdevelopment.com?utm_source=npmjs&utm_medium=Fuse+importer+Full+Documentation&utm_campaign=NPM)
69
+
70
+ Check it out in action:
71
+
72
+ <center>
73
+ <a href="https://fuse.flatironsdevelopment.com/users/sign-up?utm_source=npmjs&utm_medium=Fuse+importer+Gif&utm_campaign=NPM">
74
+ <img src="https://wp.flatironsdevelopment.com/wp-content/uploads/2022/07/Flatirons-Fuse-users-Columns-7-July-2022.gif">
75
+ </a>
76
+ </center>
77
+
78
+ ## Registration
79
+
80
+ If you don't have an account yet, you can go over the [Registration](https://fuse-docs.flatironsdevelopment.com/getting-started/registration?utm_source=npmjs&utm_medium=Registration&utm_campaign=NPM).
81
+
82
+ ## Create Your First Template
83
+
84
+ If you don’t have a Template yet, you can go over [Create Your First Template](https://fuse-docs.flatironsdevelopment.com/getting-started/create-your-first-template?utm_source=npmjs&utm_medium=Create+Your+First+Template&utm_campaign=NPM). Template represents the fields and validations that your own system accepts, also known as your data schema.
85
+
86
+ ## Getting started
87
+
88
+ ```html
89
+ <!DOCTYPE html>
90
+ <html>
91
+ <head>
92
+ <script
93
+ type="text/javascript"
94
+ src="https://unpkg.com/fuse-importer@latest"
95
+ ></script>
96
+ <script type="text/javascript">
97
+ const organizationApiKey = "YOUR ORGANIZATIONS API KEY";
98
+ const templateId = "YOUR TEMPLATE ID";
99
+ const importer = new FuseImporter(organizationApiKey, templateId);
100
+
101
+ importer.onValidateRecord = async (record) => {
102
+ // return no frontend validation errors
103
+ return {};
104
+ };
105
+
106
+ importer.onSubmit = async (records) => {
107
+ // an empty hash will tell us the import was successful!
108
+ return {
109
+ message: "Your data was imported successfully",
110
+ errors: {},
111
+ };
112
+ };
113
+
114
+ window.showFuseImporter = () => {
115
+ if (
116
+ organizationApiKey.indexOf("YOUR") !== -1 ||
117
+ templateId.indexOf("YOUR") !== -1
118
+ ) {
119
+ window.confirm(
120
+ "You need to configure your organization api key and template id."
121
+ );
122
+ return;
123
+ }
124
+ importer.show();
125
+ };
126
+ </script>
127
+ </head>
128
+
129
+ <body>
130
+ <button onclick="javascript:showFuseImporter()">Show Importer</button>
131
+ </body>
132
+ </html>
133
+ ```
134
+
135
+ ## More Examples
136
+
137
+ - [Quickstart Examples](https://fuse-docs.flatironsdevelopment.com/installation/quickstart-examples?utm_source=npmjs&utm_medium=More+Examples+Quickstart+Examples&utm_campaign=NPM)
138
+ - [React.js](https://fuse-docs.flatironsdevelopment.com/use-cases/react.js-csv-importer?utm_source=npmjs&utm_medium=More+Examples+React&utm_campaign=NPM)
139
+ - [Angular](https://fuse-docs.flatironsdevelopment.com/use-cases/angular-csv-importer?utm_source=npmjs&utm_medium=More+Examples+Angular&utm_campaign=NPM)
140
+ - [Vue.js](https://fuse-docs.flatironsdevelopment.com/use-cases/vue.js-csv-importer?utm_source=npmjs&utm_medium=More+Examples+Vue&utm_campaign=NPM)
141
+
142
+ ## Usage
143
+
144
+ ```typescript
145
+ import FuseImporter from "fuse-importer";
146
+
147
+ const organizationApiKey = "YOUR ORGANIZATIONS API KEY";
148
+ const templateId = "YOUR TEMPLATE ID";
149
+ const importer = new FuseImporter(organizationApiKey, templateId);
150
+ ```
151
+
152
+ ### FuseImporter Hooks
153
+
154
+ Hooks allow you to show the importer, run validations, and submit records to your backend.
155
+
156
+ #### `show`
157
+
158
+ The show function does exactly what it sounds like; it launches the importer. Ensure you have initialized the importer properly beforehand. Use this function like so:
159
+
160
+ ```typescript
161
+ importer.show();
162
+ ```
163
+
164
+ #### `close`
165
+
166
+ The close function allows you to remove the importer from the view.
167
+
168
+ ```typescript
169
+ importer.close();
170
+ ```
171
+
172
+ #### `onClose`
173
+
174
+ The onClose function allows you to be notified when the importer is removed from the view.
175
+
176
+ ```typescript
177
+ importer.onClose = () => {
178
+ console.log("The importer was closed!");
179
+ };
180
+ ```
181
+
182
+ #### `onValidateRecord`
183
+
184
+ The `onValidationRecord` hook is called for each row (record) that a customer uploads. It allows you to specify custom frontend validations and display error messages in the importer for the user to fix. When you create a Template, each column contains an `internal key`. These internal keys represent the
185
+
186
+ Return values:
187
+
188
+ - If the record has no errors, we expect you to return an empty object: `return {}`;
189
+ - If the record has validation errors, you can specify them like so:
190
+
191
+ ```typescript
192
+ importer.onValidateRecord = async (record) => {
193
+ const errors = {};
194
+
195
+ // force emails to include gmail
196
+ if (!record.email?.includes("gmail")) {
197
+ errors["email"] = "Email must be from Gmail";
198
+ }
199
+
200
+ return errors;
201
+ };
202
+ ```
203
+
204
+ #### `formatRecord`
205
+
206
+ The `formatRecord` hook can be used to format data automatically on behalf of a user. For example, if you have a field called `first_name` and you know that your system always requires `first_name` to be capitalized, you can use this callback to uppercase all `first_name` records like so:
207
+
208
+ ```typescript
209
+ importer.formatRecord = (record) => {
210
+ const newRecord = { ...record };
211
+
212
+ // capitalize first letter in first_name
213
+ if (typeof newRecord.first_name === "string") {
214
+ newRecord.first_name =
215
+ newRecord.first_name.charAt(0).toUpperCase() +
216
+ newRecord.first_name.slice(1);
217
+ }
218
+
219
+ return newRecord;
220
+ };
221
+ ```
222
+
223
+ #### `onSubmit`
224
+
225
+ `onSubmit` will pass all records to you after the user has made any necessary corrections to frontend validations. This callback expects you to submit the records to your backend in whatever way you typically would, we do not submit the records for you.
226
+
227
+ This callback also allows you to pass back any backend errors for specific rows. Each record passed to this callback will have a unique identifier under the key `record._meta.id`. In this case of a backend validation or error occurring, you can tell the importer to show a specific error to the user for a row. Note that after submission, only records with errors will remain visible to the user.
228
+
229
+ Return values:
230
+
231
+ - If there were no backend errors, pass back an empty errors object and a message to show to the user like so:
232
+
233
+ ```typescript
234
+ importer.onSubmit = async (records) => {
235
+ // submit to backend here
236
+ let message = "Data imported successfully";
237
+ return {
238
+ message,
239
+ errors: {},
240
+ };
241
+ };
242
+ ```
243
+
244
+ - If you find an error with a record in your backend, you can tell the importer to show the error to the user like so:
245
+
246
+ ```typescript
247
+ importer.onSubmit = async (records) => {
248
+ // submit to your backend here
249
+
250
+ return {
251
+ errors: {
252
+ [records[0]._meta.id]: {
253
+ email: "Email is already taken. Emails must be unique.",
254
+ first_name: "First Name must be capitalized.",
255
+ },
256
+ },
257
+ };
258
+ };
259
+ ```
@@ -1,6 +1,7 @@
1
1
  import Fuse from "fuse.js";
2
2
  import React from "react";
3
3
  import { ImporterOptions, OnValidateBatch, OnValidateRecord, FormatRecord } from "../types";
4
+ import { ImporterStylePreferences } from "./theme";
4
5
  import { FuseApi } from "./FuseApi";
5
6
  export declare const fusejsOptions: Fuse.IFuseOptions<string>;
6
7
  export declare type HeaderMatchings = {
@@ -20,8 +21,28 @@ export declare type TemplateHeader = {
20
21
  column_type: string;
21
22
  internal_key: string;
22
23
  values: string[];
24
+ pattern: string;
23
25
  };
24
- declare type State = {
26
+ export declare type Organization = {
27
+ id: number;
28
+ name: string;
29
+ trial_mode: boolean;
30
+ plan: {
31
+ title: string;
32
+ allow_style_customization: boolean;
33
+ has_records_limit: boolean;
34
+ allowed_records: number;
35
+ };
36
+ };
37
+ export declare type Column = {
38
+ column_type: string;
39
+ internal_key: string;
40
+ label: string;
41
+ pattern: string;
42
+ required: boolean;
43
+ values: string[];
44
+ };
45
+ export declare type State = {
25
46
  resetImport: () => void;
26
47
  currentStepIndex: number;
27
48
  setCurrentStepIndex: React.Dispatch<number>;
@@ -46,9 +67,10 @@ declare type State = {
46
67
  fuseApi: FuseApi;
47
68
  formatRecord: FormatRecord;
48
69
  importerOptions: ImporterOptions;
49
- canOrganizationCustomize: boolean;
70
+ theme: any;
71
+ logoURL: string;
50
72
  };
51
- declare type Props = {
73
+ export declare type Props = {
52
74
  templateSlug: string;
53
75
  apiToken: string;
54
76
  options: ImporterOptions;
@@ -58,6 +80,11 @@ declare type Props = {
58
80
  onValidateRecord?: OnValidateRecord;
59
81
  onValidateBatch?: OnValidateBatch;
60
82
  };
83
+ export declare type TemplateInfo = {
84
+ columns: Column[];
85
+ importer_style_preferences: ImporterStylePreferences;
86
+ organization: Organization;
87
+ name: string;
88
+ };
61
89
  export declare const ImporterContextProvider: ({ templateSlug, apiToken, children, options, onClose, formatRecord, onValidateBatch, onValidateRecord, }: Props) => JSX.Element;
62
90
  export declare const useImporterContext: () => State;
63
- export {};
@@ -47,9 +47,10 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
47
47
  };
48
48
  import { jsx as _jsx } from "react/jsx-runtime";
49
49
  import Fuse from "fuse.js";
50
- import { createContext, useContext, useEffect, useState } from "react";
50
+ import { createContext, useContext, useEffect, useMemo, useState, } from "react";
51
51
  import { FieldTypes, } from "../types";
52
52
  import { getColumnType } from "./common/utils";
53
+ import { theme, getCustomTheme, } from "./theme";
53
54
  import { FuseApi } from "./FuseApi";
54
55
  export var fusejsOptions = {
55
56
  includeScore: true,
@@ -63,21 +64,24 @@ export var ImporterContextProvider = function (_a) {
63
64
  var _d = useState(null), templateError = _d[0], setTemplateError = _d[1];
64
65
  var _e = useState(null), templateHeaders = _e[0], setTemplateHeaders = _e[1];
65
66
  var _f = useState(null), uploadedData = _f[0], setUploadedData = _f[1];
66
- var _g = useState(false), canOrganizationCustomize = _g[0], _setCanOrganizationCustomize = _g[1];
67
- var _h = useState(null), templateHeaderMatchings = _h[0], setTemplateHeaderMatchings = _h[1];
68
- var _j = useState(null), enumFieldValueMatchings = _j[0], setEnumFieldValueMatchings = _j[1];
69
- var _k = useState(null), uploadedDataEnumFieldValues = _k[0], setUploadedDataEnumFieldValues = _k[1];
70
- var _l = useState(false), inTrialMode = _l[0], setInTrialMode = _l[1];
71
- var fuseApi = new FuseApi(options.env, apiToken);
72
- var uploadedDataHeaders = uploadedData &&
73
- uploadedData[0].map(function (ud) { return (typeof ud === "number" ? ud.toString() : ud); });
74
- var setCanOrganizationCustomize = function (organization) {
75
- var _a;
76
- var customizablePlans = ["pro", "unlimited"];
77
- var planTitle = (_a = organization.plan) === null || _a === void 0 ? void 0 : _a.title;
78
- var isPlanCustomizable = customizablePlans.includes(planTitle);
79
- _setCanOrganizationCustomize(isPlanCustomizable);
80
- };
67
+ var _g = useState(null), organization = _g[0], setOrganization = _g[1];
68
+ var _h = useState({
69
+ theme: theme,
70
+ logoURL: null,
71
+ }), style = _h[0], setStyle = _h[1];
72
+ var _j = useState(null), templateHeaderMatchings = _j[0], setTemplateHeaderMatchings = _j[1];
73
+ var _k = useState(null), enumFieldValueMatchings = _k[0], setEnumFieldValueMatchings = _k[1];
74
+ var _l = useState(null), uploadedDataEnumFieldValues = _l[0], setUploadedDataEnumFieldValues = _l[1];
75
+ var fuseApi = useMemo(function () { return new FuseApi(options.env, apiToken); }, [
76
+ options.env,
77
+ apiToken,
78
+ ]);
79
+ var uploadedDataHeaders = useMemo(function () {
80
+ return uploadedData &&
81
+ uploadedData[0].map(function (ud) {
82
+ return typeof ud === "number" ? ud.toString() : ud;
83
+ });
84
+ }, [uploadedData]);
81
85
  useEffect(function () {
82
86
  if (!templateHeaderMatchings)
83
87
  return;
@@ -102,25 +106,30 @@ export var ImporterContextProvider = function (_a) {
102
106
  });
103
107
  setUploadedDataEnumFieldValues(_uploadedDataEnumFieldValues);
104
108
  }, [templateHeaderMatchings]);
109
+ useEffect(function () {
110
+ if (uploadedData)
111
+ setHeadersFromDataset();
112
+ }, [uploadedData]);
105
113
  useEffect(function () {
106
114
  (function () { return __awaiter(void 0, void 0, void 0, function () {
107
- var data, organization, error_1, errorMsg;
108
- var _a, _b;
109
- return __generator(this, function (_c) {
110
- switch (_c.label) {
115
+ var _a, organization_1, columns, importer_style_preferences, error_1, errorMsg;
116
+ var _b, _c;
117
+ return __generator(this, function (_d) {
118
+ switch (_d.label) {
111
119
  case 0:
112
- _c.trys.push([0, 2, , 3]);
120
+ _d.trys.push([0, 2, , 3]);
113
121
  return [4 /*yield*/, fuseApi.get("/api/v1/importer/templates/".concat(templateSlug))];
114
122
  case 1:
115
- data = (_c.sent()).data;
116
- organization = data.organization;
117
- setCanOrganizationCustomize(organization);
118
- setTemplateHeaders(data.columns);
119
- setInTrialMode(organization.trial_mode);
123
+ _a = (_d.sent()).data, organization_1 = _a.organization, columns = _a.columns, importer_style_preferences = _a.importer_style_preferences;
124
+ setOrganization(organization_1);
125
+ setTemplateHeaders(columns);
126
+ if (organization_1.plan && organization_1.plan.allow_style_customization) {
127
+ setStyle(getCustomTheme(importer_style_preferences));
128
+ }
120
129
  return [3 /*break*/, 3];
121
130
  case 2:
122
- error_1 = _c.sent();
123
- errorMsg = ((_b = (_a = error_1.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.message) ||
131
+ error_1 = _d.sent();
132
+ errorMsg = ((_c = (_b = error_1.response) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.message) ||
124
133
  "There was an error preventing the data importer from loading. Check your API Token and try again.";
125
134
  setTemplateError(errorMsg);
126
135
  return [3 /*break*/, 3];
@@ -129,10 +138,6 @@ export var ImporterContextProvider = function (_a) {
129
138
  });
130
139
  }); })();
131
140
  }, []);
132
- useEffect(function () {
133
- if (uploadedData)
134
- setHeadersFromDataset();
135
- }, [uploadedData]);
136
141
  var resetImport = function () {
137
142
  setUploadedData(null);
138
143
  setTemplateHeaderMatchings(null);
@@ -147,6 +152,7 @@ export var ImporterContextProvider = function (_a) {
147
152
  });
148
153
  setTemplateHeaderMatchings(_templateHeaderMatchings);
149
154
  };
155
+ var inTrialMode = organization === null || organization === void 0 ? void 0 : organization.trial_mode;
150
156
  var value = {
151
157
  setUploadedData: setUploadedData,
152
158
  currentStepIndex: currentStepIndex,
@@ -172,7 +178,8 @@ export var ImporterContextProvider = function (_a) {
172
178
  inTrialMode: inTrialMode,
173
179
  onClose: onClose,
174
180
  fuseApi: fuseApi,
175
- canOrganizationCustomize: canOrganizationCustomize,
181
+ theme: style.theme,
182
+ logoURL: style.logoURL,
176
183
  };
177
184
  return (_jsx(ImporterContext.Provider, __assign({ value: value }, { children: children })));
178
185
  };
@@ -14,6 +14,7 @@ var __assign = (this && this.__assign) || function () {
14
14
  return __assign.apply(this, arguments);
15
15
  };
16
16
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
17
+ import { useMemo } from "react";
17
18
  import styled, { css } from "styled-components";
18
19
  import { FieldTypes } from "../..";
19
20
  import { Div } from "../../styled/utils";
@@ -26,11 +27,11 @@ var Dot = styled(Div)(function (_a) {
26
27
  });
27
28
  var Matcher = function () {
28
29
  var _a = useImporterContext(), matcherSubstep = _a.matcherSubstep, templateHeaders = _a.templateHeaders;
29
- var enumFieldsCount = templateHeaders.filter(function (th) { return th.column_type === FieldTypes.enum; }).length;
30
- var dots = [];
31
- for (var step = 0; step < 2; step++)
32
- dots.push(_jsx(Dot, { isSelected: matcherSubstep === step }, step));
33
- return (_jsxs(_Fragment, { children: [_jsx(Div, __assign({ centered: true }, { children: _jsx(Div, __assign({ w: 30, mt: 40, mb: 16, alignCenter: true, spaceBetween: true }, { children: enumFieldsCount > 0 && dots })) })), matcherSubstep === 0 && _jsx(HeaderMatcher, {}), matcherSubstep === 1 && _jsx(EnumFieldsMatchers, {})] }));
30
+ var enumFieldsCount = useMemo(function () {
31
+ return templateHeaders.filter(function (th) { return th.column_type === FieldTypes.enum; }).length;
32
+ }, [templateHeaders]);
33
+ var dotsUI = (_jsxs(_Fragment, { children: [_jsx(Dot, { isSelected: matcherSubstep === 0 }), _jsx(Dot, { isSelected: matcherSubstep === 1 })] }));
34
+ return (_jsxs(_Fragment, { children: [_jsx(Div, __assign({ centered: true }, { children: _jsx(Div, __assign({ w: 30, mt: 40, mb: 16, alignCenter: true, spaceBetween: true }, { children: enumFieldsCount > 0 && dotsUI })) })), matcherSubstep === 0 && _jsx(HeaderMatcher, {}), matcherSubstep === 1 && _jsx(EnumFieldsMatchers, {})] }));
34
35
  };
35
36
  export { Matcher };
36
37
  var templateObject_1, templateObject_2;
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare const PreviewModeBanner: () => JSX.Element;
@@ -0,0 +1,20 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ import { theme } from "../styled/theme";
14
+ import { Div, Span } from "../styled/utils";
15
+ import { useImporterContext } from "./ImporterContextProvider";
16
+ export var PreviewModeBanner = function () {
17
+ var previewMode = useImporterContext().importerOptions.previewMode;
18
+ return previewMode ? (_jsxs(Div, __assign({ bg: theme.colors.blue100, h: 80, alignCenter: true }, { children: [_jsx(Div, __assign({ ml: 33, mr: 8 }, { children: infoIcon })), _jsx(Span, __assign({ mr: 16 }, { children: "You’re currently in Preview mode." }))] }))) : null;
19
+ };
20
+ var infoIcon = (_jsxs("svg", __assign({ width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, { children: [_jsx("circle", { cx: "14", cy: "2.5", r: "2.5", fill: "#0EBEBE" }), _jsx("path", { d: "M15.5075 8H6L5 10.5L10 11L6.57474 18.9354C6.57474 18.9354 6.40657 20.1663 6.57474 20.9247C6.76276 21.7725 6.97074 22.2838 7.56727 22.9139C8.6672 24.0757 9.95115 24.1037 11.5374 23.9085C14.2577 23.5737 17 19.5 17 19.5L15.5075 17.9408C15.5075 17.9408 13.5223 19.93 12.5298 19.93C11.5373 19.93 11.5374 18.9354 11.5374 18.9354L15.5075 8Z", fill: "#0EBEBE" })] })));
@@ -14,18 +14,11 @@ import { useMemo } from "react";
14
14
  import { Div } from "../../styled/utils";
15
15
  import { FieldTypes } from "../../types";
16
16
  import { Spreadsheet } from "../common/Spreadsheet";
17
+ import { isFloat, isInteger, isTrue } from "../common/Spreadsheet/common/index";
17
18
  import { getColumnType, getSpreadsheetRowWidth } from "../common/utils";
18
19
  import { useImporterContext } from "../ImporterContextProvider";
19
20
  import { useSpreadsheetReviewContext } from "../SpreadsheetReviewContextProvider";
20
21
  import { AppResponseModal } from "./AppResponseModal";
21
- var valueIsTrue = function (value) {
22
- var _value = (value || "").toString().toLowerCase();
23
- return ["true", "yes", "1", "y", "on", "t"].includes(_value);
24
- };
25
- var valueIsInteger = function (value) { return /^-?[0-9]+$/.test(value + ""); };
26
- var valueIsNumber = function (value) {
27
- return /^-?[0-9]+(?:\.[0-9]+)?$/.test(value + "");
28
- };
29
22
  var useInitialData = function () {
30
23
  var _a = useImporterContext(), templateHeaderMatchings = _a.templateHeaderMatchings, enumFieldValueMatchings = _a.enumFieldValueMatchings, templateHeaders = _a.templateHeaders, uploadedDataHeaders = _a.uploadedDataHeaders, uploadedData = _a.uploadedData, formatRecord = _a.formatRecord;
31
24
  return useMemo(function () {
@@ -50,11 +43,11 @@ var useInitialData = function () {
50
43
  if (columnType === FieldTypes.enum)
51
44
  record[key] = enumFieldValueMatchings[templateLabel][value];
52
45
  if (columnType === FieldTypes.boolean)
53
- record[key] = valueIsTrue(value);
46
+ record[key] = isTrue(value);
54
47
  if (columnType === FieldTypes.float)
55
- record[key] = valueIsNumber(value) ? parseFloat(value) : undefined;
48
+ record[key] = isFloat(value) ? parseFloat(value) : value;
56
49
  if (columnType === FieldTypes.integer)
57
- record[key] = valueIsInteger(value) ? parseInt(value) : undefined;
50
+ record[key] = isInteger(value) ? parseInt(value) : value;
58
51
  });
59
52
  return formatRecord ? formatRecord(record) : record;
60
53
  };
@@ -71,13 +64,16 @@ var Review = function () {
71
64
  var _a = useImporterContext(), templateHeaders = _a.templateHeaders, onValidateRecord = _a.onValidateRecord, onValidateBatch = _a.onValidateBatch, _b = _a.importerOptions, batchValidationDelayMs = _b.batchValidationDelayMs, batchValidationSize = _b.batchValidationSize;
72
65
  var initialData = useInitialData();
73
66
  var _c = useSpreadsheetReviewContext(), submittedData = _c.submittedData, appResponse = _c.appResponse, setReviewedData = _c.setReviewedData;
74
- var fields = templateHeaders.map(function (templateHeader) { return ({
75
- label: templateHeader.label,
76
- name: templateHeader.internal_key,
77
- type: FieldTypes[templateHeader.column_type] || FieldTypes.string,
78
- isRequired: templateHeader.required,
79
- options: templateHeader.values,
80
- }); });
67
+ var fields = useMemo(function () {
68
+ return templateHeaders.map(function (templateHeader) { return ({
69
+ label: templateHeader.label,
70
+ name: templateHeader.internal_key,
71
+ type: FieldTypes[templateHeader.column_type] || FieldTypes.string,
72
+ isRequired: templateHeader.required,
73
+ options: templateHeader.values,
74
+ pattern: templateHeader.pattern,
75
+ }); });
76
+ }, [templateHeaders]);
81
77
  var spreadsheetUI = useMemo(function () { return (_jsx(Div, { children: _jsx(Spreadsheet, __assign({ rowWidth: getSpreadsheetRowWidth(fields, 6), options: {
82
78
  batchValidationDelayMs: batchValidationDelayMs,
83
79
  batchValidationSize: batchValidationSize || initialData.length,
@@ -47,8 +47,8 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
47
47
  };
48
48
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
49
49
  import { createContext, useContext, useState } from "react";
50
- import { getUnsubmittedData } from ".";
51
50
  import { AppLoading } from "./common/AppLoading";
51
+ import { getUnsubmittedData } from "./common/utils";
52
52
  import { useImporterContext } from "./ImporterContextProvider";
53
53
  var SpreadsheetReviewContext = createContext({});
54
54
  export var SpreadsheetReviewContextProvider = function (_a) {
@@ -31,7 +31,7 @@ var StepIndexWrapper = styled(Div)(templateObject_2 || (templateObject_2 = __mak
31
31
  return p.isSelected && css(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n height: 32px;\n width: 32px;\n border: solid 1px ", ";\n color: ", ";\n background-color: ", ";\n "], ["\n height: 32px;\n width: 32px;\n border: solid 1px ", ";\n color: ", ";\n background-color: ", ";\n "])), function (p) { return p.theme.colors.blue500; }, function (p) { return p.theme.colors.white; }, function (p) { return p.theme.colors.blue500; });
32
32
  });
33
33
  var StepperWrapper = styled(Div)(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n background-color: ", ";\n user-select: none;\n border-bottom: 1px solid ", ";\n"], ["\n background-color: ", ";\n user-select: none;\n border-bottom: 1px solid ", ";\n"])), function (p) { return p.theme.colors.white; }, function (p) { return p.theme.colors.gray300; });
34
- var Logo = styled.img(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n max-height: 70px;\n position: absolute;\n left: 41px;\n"], ["\n max-height: 70px;\n position: absolute;\n left: 41px;\n"])));
34
+ var Logo = styled.img(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n max-height: 70px;\n max-width: 300px;\n position: absolute;\n left: 41px;\n"], ["\n max-height: 70px;\n max-width: 300px;\n position: absolute;\n left: 41px;\n"])));
35
35
  var StepIndex = function (_a) {
36
36
  var index = _a.index, isSelected = _a.isSelected, isCompleted = _a.isCompleted;
37
37
  return (_jsx(_Fragment, { children: isCompleted ? (_jsx(Div, __assign({ centered: true, body2: true, bold: true, mr: 8 }, { children: whiteCheckIcon }))) : (_jsx(StepIndexWrapper, __assign({ centered: true, body2: true, bold: true, mr: 8, isSelected: isSelected }, { children: index }))) }));
@@ -112,8 +112,15 @@ var Stepper = function (_a) {
112
112
  }
113
113
  };
114
114
  var goBack = function () {
115
- setMatcherSubstep(0);
116
- setCurrentStepIndex(currentStepIndex - 1);
115
+ var isMatchingColumnValues = matcherSubstep === 1;
116
+ var isInMachStep = currentStepIndex === 1;
117
+ var shouldBackOnlyMatcherSubStep = isMatchingColumnValues && isInMachStep;
118
+ if (shouldBackOnlyMatcherSubStep) {
119
+ setMatcherSubstep(matcherSubstep - 1);
120
+ }
121
+ else {
122
+ setCurrentStepIndex(currentStepIndex - 1);
123
+ }
117
124
  };
118
125
  var skipStep = function () {
119
126
  setStep();
@@ -61,7 +61,10 @@ var ImporterDropzone = function () {
61
61
  reader.onload = function (event) {
62
62
  var results = event.target.result;
63
63
  var getDataFromFile = function (fileResults) {
64
- var workBook = XLSX.read(fileResults, { type: "array" });
64
+ var workBook = XLSX.read(fileResults, {
65
+ type: "array",
66
+ raw: true,
67
+ });
65
68
  var workBookName = workBook.SheetNames[0];
66
69
  var sheet = workBook.Sheets[workBookName];
67
70
  return XLSX.utils.sheet_to_json(sheet, { header: 1 });