@vtex/order-manager
Advanced tools
Comparing version 0.0.3-2 to 0.0.3-3
@@ -0,8 +1,724 @@ | ||
/*! | ||
* @vtex/order-manager v0.0.3-3 | ||
* (c) VTEX | ||
* Released under the MIT License. | ||
*/ | ||
'use strict' | ||
'use strict'; | ||
if (process.env.NODE_ENV === 'production') { | ||
module.exports = require('./order-manager.cjs.production.min.js') | ||
} else { | ||
module.exports = require('./order-manager.cjs.development.js') | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
var React = require('react'); | ||
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } | ||
var React__default = /*#__PURE__*/_interopDefaultLegacy(React); | ||
/*! ***************************************************************************** | ||
Copyright (c) Microsoft Corporation. | ||
Permission to use, copy, modify, and/or distribute this software for any | ||
purpose with or without fee is hereby granted. | ||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH | ||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, | ||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR | ||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | ||
PERFORMANCE OF THIS SOFTWARE. | ||
***************************************************************************** */ | ||
var __assign = function() { | ||
__assign = Object.assign || function __assign(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
function __awaiter(thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
} | ||
function __generator(thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
} | ||
// Adapted from https://github.com/BalassaMarton/sequential-task-queue/blob/master/src/sequential-task-queue.ts | ||
/** | ||
* Standard cancellation reasons. {@link SequentialTaskQueue} sets {@link CancellationToken.reason} | ||
* to one of these values when cancelling a task for a reason other than the user code calling | ||
* {@link CancellationToken.cancel}. | ||
*/ | ||
var cancellationTokenReasons = { | ||
/** Used when the task was cancelled in response to a call to {@link SequentialTaskQueue.cancel} */ | ||
cancel: Object.create(null), | ||
/** Used when the task was cancelled after its timeout has passed */ | ||
timeout: Object.create(null), | ||
}; | ||
/** | ||
* Standard event names used by {@link SequentialTaskQueue} | ||
*/ | ||
var sequentialTaskQueueEvents = { | ||
drained: 'drained', | ||
error: 'error', | ||
timeout: 'timeout', | ||
}; | ||
function isPromise(obj) { | ||
return obj && typeof obj.then === 'function'; | ||
} | ||
function noop$1() { } | ||
/** | ||
* FIFO task queue to run tasks in predictable order, without concurrency. | ||
*/ | ||
var SequentialTaskQueue = /** @class */ (function () { | ||
/** | ||
* Creates a new instance of {@link SequentialTaskQueue} | ||
* @param options - Configuration options for the task queue. | ||
*/ | ||
function SequentialTaskQueue(options) { | ||
var _a, _b; | ||
this.queue = []; | ||
this._isClosed = false; | ||
this.waiters = []; | ||
if (!options) | ||
options = {}; | ||
this.defaultTimeout = options.timeout; | ||
this.name = (_a = options.name) !== null && _a !== void 0 ? _a : 'SequentialTaskQueue'; | ||
this.scheduler = (_b = options.scheduler) !== null && _b !== void 0 ? _b : SequentialTaskQueue.defaultScheduler; | ||
} | ||
Object.defineProperty(SequentialTaskQueue.prototype, "isClosed", { | ||
/** Indicates if the queue has been closed. Calling {@link SequentialTaskQueue.push} on a closed queue will result in an exception. */ | ||
get: function () { | ||
return this._isClosed; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
/** | ||
* Adds a new task to the queue. | ||
* @param {Function} task - The function to call when the task is run | ||
* @param {TaskOptions} options - An object containing arguments and options for the task. | ||
* @returns {CancellablePromiseLike<any>} A promise that can be used to await or cancel the task. | ||
*/ | ||
SequentialTaskQueue.prototype.push = function (task, options) { | ||
var _this = this; | ||
if (this._isClosed) { | ||
throw new Error(this.name + " has been previously closed"); | ||
} | ||
var taskEntry = { | ||
callback: task, | ||
args: (options === null || options === void 0 ? void 0 : options.args) | ||
? Array.isArray(options.args) | ||
? options.args.slice() | ||
: [options.args] | ||
: [], | ||
timeout: (options === null || options === void 0 ? void 0 : options.timeout) !== undefined ? options.timeout : this.defaultTimeout, | ||
cancellationToken: { | ||
cancel: function (reason) { return _this.cancelTask(taskEntry, reason); }, | ||
}, | ||
resolve: undefined, | ||
reject: undefined, | ||
}; | ||
taskEntry.args.push(taskEntry.cancellationToken); | ||
this.queue.push(taskEntry); | ||
this.scheduler.schedule(function () { return _this.next(); }); | ||
var result = new Promise(function (resolve, reject) { | ||
taskEntry.resolve = resolve; | ||
taskEntry.reject = reject; | ||
}); | ||
result.cancel = function (reason) { | ||
return taskEntry.cancellationToken.cancel(reason); | ||
}; | ||
return result; | ||
}; | ||
/** | ||
* Cancels the currently running task (if any), and clears the queue. | ||
* @returns {Promise} A Promise that is fulfilled when the queue is empty and the current task has been cancelled. | ||
*/ | ||
SequentialTaskQueue.prototype.cancel = function () { | ||
var _this = this; | ||
if (this.currentTask) { | ||
this.cancelTask(this.currentTask, cancellationTokenReasons.cancel); | ||
} | ||
var queue = this.queue.splice(0); | ||
// Cancel all and emit a drained event if there were tasks waiting in the queue | ||
if (queue.length) { | ||
queue.forEach(function (task) { | ||
return _this.cancelTask(task, cancellationTokenReasons.cancel); | ||
}); | ||
this.emit(sequentialTaskQueueEvents.drained); | ||
} | ||
return this.wait(); | ||
}; | ||
SequentialTaskQueue.prototype.indexOf = function (task) { | ||
var _a; | ||
if (((_a = this.currentTask) === null || _a === void 0 ? void 0 : _a.callback) === task) { | ||
return 0; | ||
} | ||
var queueIndex = this.queue | ||
// Skip cancelled tasks | ||
.filter(function (taskEntry) { var _a; return !((_a = taskEntry.cancellationToken) === null || _a === void 0 ? void 0 : _a.cancelled); }) | ||
.findIndex(function (taskEntry) { return taskEntry.callback === task; }); | ||
if (queueIndex < 0) { | ||
// Task not found, return -1 | ||
return queueIndex; | ||
} | ||
// The `currentTask` is also part of the queue, although | ||
// it isn't in the `queue` array, so we should account for | ||
// its existence and shift the index by 1 if it is set. | ||
return queueIndex + (this.currentTask !== undefined ? 1 : 0); | ||
}; | ||
/** | ||
* Closes the queue, preventing new tasks to be added. | ||
* Any calls to {@link SequentialTaskQueue.push} after closing the queue will result in an exception. | ||
* @param {boolean} cancel - Indicates that the queue should also be cancelled. | ||
* @returns {Promise} A Promise that is fulfilled when the queue has finished executing remaining tasks. | ||
*/ | ||
SequentialTaskQueue.prototype.close = function (cancel) { | ||
if (!this._isClosed) { | ||
this._isClosed = true; | ||
if (cancel) | ||
return this.cancel(); | ||
} | ||
return this.wait(); | ||
}; | ||
/** | ||
* Returns a promise that is fulfilled when the queue is empty. | ||
* @returns {Promise} | ||
*/ | ||
SequentialTaskQueue.prototype.wait = function () { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var _this = this; | ||
return __generator(this, function (_a) { | ||
if (!this.currentTask && this.queue.length === 0) | ||
return [2 /*return*/, Promise.resolve()]; | ||
return [2 /*return*/, new Promise(function (resolve) { | ||
_this.waiters.push(resolve); | ||
})]; | ||
}); | ||
}); | ||
}; | ||
/** | ||
* Adds an event handler for a named event. | ||
* @param {string} evt - Event name. See the readme for a list of valid events. | ||
* @param {Function} handler - Event handler. When invoking the handler, the queue will set itself as the `this` argument of the call. | ||
*/ | ||
SequentialTaskQueue.prototype.on = function (evt, handler) { | ||
var _a; | ||
this.events = (_a = this.events) !== null && _a !== void 0 ? _a : {}; | ||
(this.events[evt] || (this.events[evt] = [])).push(handler); | ||
}; | ||
/** | ||
* Adds a single-shot event handler for a named event. | ||
* @param {string} evt - Event name. See the readme for a list of valid events. | ||
* @param {Function} handler - Event handler. When invoking the handler, the queue will set itself as the `this` argument of the call. | ||
*/ | ||
SequentialTaskQueue.prototype.once = function (evt, handler) { | ||
var _this = this; | ||
var cb = function () { | ||
var args = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
args[_i] = arguments[_i]; | ||
} | ||
_this.removeListener(evt, cb); | ||
handler.apply(_this, args); | ||
}; | ||
this.on(evt, cb); | ||
}; | ||
/** | ||
* Removes an event handler. | ||
* @param {string} evt - Event name | ||
* @param {Function} handler - Event handler to be removed | ||
*/ | ||
SequentialTaskQueue.prototype.removeListener = function (evt, handler) { | ||
if (this.events) { | ||
var list = this.events[evt]; | ||
if (list) { | ||
var i = 0; | ||
while (i < list.length) { | ||
if (list[i] === handler) | ||
list.splice(i, 1); | ||
else | ||
i++; | ||
} | ||
} | ||
} | ||
}; | ||
/** @see {@link SequentialTaskQueue.removeListener} */ | ||
SequentialTaskQueue.prototype.off = function (evt, handler) { | ||
return this.removeListener(evt, handler); | ||
}; | ||
SequentialTaskQueue.prototype.emit = function (evt) { | ||
var _this = this; | ||
var _a; | ||
var args = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
args[_i - 1] = arguments[_i]; | ||
} | ||
if ((_a = this.events) === null || _a === void 0 ? void 0 : _a[evt]) { | ||
try { | ||
this.events[evt].forEach(function (fn) { return fn.apply(_this, args); }); | ||
} | ||
catch (e) { | ||
console.error(this.name + ": Exception in '" + evt + "' event handler", e); | ||
} | ||
} | ||
}; | ||
SequentialTaskQueue.prototype.next = function () { | ||
var _this = this; | ||
// Try running the next task, if not currently running one | ||
if (!this.currentTask) { | ||
var task_1 = this.queue.shift(); | ||
// skip cancelled tasks | ||
while (task_1 === null || task_1 === void 0 ? void 0 : task_1.cancellationToken.cancelled) | ||
task_1 = this.queue.shift(); | ||
if (task_1) { | ||
try { | ||
this.currentTask = task_1; | ||
if (task_1.timeout) { | ||
task_1.timeoutHandle = setTimeout(function () { | ||
_this.emit(sequentialTaskQueueEvents.timeout); | ||
_this.cancelTask(task_1, cancellationTokenReasons.timeout); | ||
}, task_1.timeout); | ||
} | ||
var res = task_1.callback.apply(undefined, task_1.args); | ||
if (res && isPromise(res)) { | ||
res.then(function (result) { | ||
task_1.result = result; | ||
_this.doneTask(task_1); | ||
}, function (err) { | ||
_this.doneTask(task_1, err); | ||
}); | ||
} | ||
else { | ||
task_1.result = res; | ||
this.doneTask(task_1); | ||
} | ||
} | ||
catch (e) { | ||
this.doneTask(task_1, e); | ||
} | ||
} | ||
else { | ||
// queue is empty, call waiters | ||
this.callWaiters(); | ||
} | ||
} | ||
}; | ||
SequentialTaskQueue.prototype.cancelTask = function (task, reason) { | ||
task.cancellationToken.cancelled = true; | ||
task.cancellationToken.reason = reason; | ||
this.doneTask(task); | ||
}; | ||
SequentialTaskQueue.prototype.doneTask = function (task, error) { | ||
var _this = this; | ||
if (task.timeoutHandle) | ||
clearTimeout(task.timeoutHandle); | ||
task.cancellationToken.cancel = noop$1; | ||
if (error) { | ||
this.emit(sequentialTaskQueueEvents.error, error); | ||
task.reject.call(undefined, error); | ||
} | ||
else if (task.cancellationToken.cancelled) { | ||
task.reject.call(undefined, task.cancellationToken.reason); | ||
} | ||
else { | ||
task.resolve.call(undefined, task.result); | ||
} | ||
if (this.currentTask === task) { | ||
this.currentTask = undefined; | ||
if (!this.queue.length) { | ||
this.emit(sequentialTaskQueueEvents.drained); | ||
this.callWaiters(); | ||
} | ||
else { | ||
this.scheduler.schedule(function () { return _this.next(); }); | ||
} | ||
} | ||
}; | ||
SequentialTaskQueue.prototype.callWaiters = function () { | ||
var waiters = this.waiters.splice(0); | ||
waiters.forEach(function (waiter) { return waiter(); }); | ||
}; | ||
SequentialTaskQueue.defaultScheduler = { | ||
schedule: function (callback) { return setTimeout(function () { return callback(); }, 0); }, | ||
}; | ||
return SequentialTaskQueue; | ||
}()); | ||
SequentialTaskQueue.defaultScheduler = { | ||
schedule: typeof setImmediate === 'function' | ||
? function (callback) { return setImmediate(function () { return callback(); }); } | ||
: function (callback) { return setTimeout(function () { return callback(); }, 0); }, | ||
}; | ||
var TASK_CANCELLED_CODE = 'TASK_CANCELLED'; | ||
// keep default value as -1 to indicate this order form | ||
// is the initial value (not yet synchonized with server). | ||
var UNSYNC_ORDER_FORM_VALUE = -1; | ||
var DEFAULT_ORDER_FORM_ID = 'default-order-form'; | ||
var TaskQueue = /** @class */ (function () { | ||
function TaskQueue() { | ||
var _this = this; | ||
this.queue = new SequentialTaskQueue(); | ||
this.taskIdMap = {}; | ||
this.listeners = {}; | ||
this.isEmpty = true; | ||
this.queue.on('drained', function () { | ||
_this.isEmpty = true; | ||
_this.emit('Fulfilled'); | ||
}); | ||
} | ||
TaskQueue.prototype.isWaiting = function (id) { | ||
return !!this.taskIdMap[id]; | ||
}; | ||
TaskQueue.prototype.enqueue = function (task, id) { | ||
var _this = this; | ||
if (this.isEmpty) { | ||
this.isEmpty = false; | ||
this.emit('Pending'); | ||
} | ||
if (id && this.taskIdMap[id]) { | ||
this.taskIdMap[id].promise.cancel(); | ||
} | ||
var wrappedTask = function () { | ||
if (id && _this.taskIdMap[id]) { | ||
delete _this.taskIdMap[id]; | ||
} | ||
return new Promise(function (resolve, reject) { | ||
var handleOnline = function () { return __awaiter(_this, void 0, void 0, function () { | ||
var result, err_1; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
_a.trys.push([0, 2, , 3]); | ||
return [4 /*yield*/, task()]; | ||
case 1: | ||
result = _a.sent(); | ||
resolve(result); | ||
return [3 /*break*/, 3]; | ||
case 2: | ||
err_1 = _a.sent(); | ||
// we might have gone offline when this request was in-flight | ||
// so we need to wait to be online again and replay this request | ||
if (!navigator.onLine) { | ||
return [2 /*return*/]; | ||
} | ||
reject(err_1); | ||
return [3 /*break*/, 3]; | ||
case 3: | ||
window.removeEventListener('online', handleOnline); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); }; | ||
window.addEventListener('online', handleOnline); | ||
if (navigator.onLine) { | ||
handleOnline(); | ||
} | ||
}); | ||
}; | ||
var promise = this.queue.push(wrappedTask); | ||
var cancelPromise = promise.cancel; | ||
promise.cancel = function () { | ||
return cancelPromise({ | ||
code: TASK_CANCELLED_CODE, | ||
index: _this.queue.indexOf(wrappedTask), | ||
}); | ||
}; | ||
if (id) { | ||
this.taskIdMap[id] = { | ||
task: task, | ||
promise: promise, | ||
}; | ||
} | ||
return promise; | ||
}; | ||
TaskQueue.prototype.listen = function (event, cb) { | ||
var _this = this; | ||
if (!this.listeners[event]) { | ||
this.listeners[event] = []; | ||
} | ||
this.listeners[event].push(cb); | ||
var unlisten = function () { | ||
var index = _this.listeners[event].indexOf(cb); | ||
if (index !== -1) { | ||
_this.listeners[event].splice(index, 1); | ||
} | ||
}; | ||
return unlisten; | ||
}; | ||
TaskQueue.prototype.emit = function (event) { | ||
if (this.listeners[event]) { | ||
this.listeners[event].forEach(function (cb) { return cb(); }); | ||
} | ||
}; | ||
return TaskQueue; | ||
}()); | ||
var OrderQueueContext = React.createContext(undefined); | ||
var useQueueStatus = function (listen) { | ||
var queueStatus = React.useRef('Fulfilled'); | ||
React.useLayoutEffect(function () { | ||
var unlisten = listen('Pending', function () { return (queueStatus.current = 'Pending'); }); | ||
return unlisten; | ||
}, [listen]); | ||
React.useLayoutEffect(function () { | ||
var unlisten = listen('Fulfilled', function () { return (queueStatus.current = 'Fulfilled'); }); | ||
return unlisten; | ||
}, [listen]); | ||
return queueStatus; | ||
}; | ||
var OrderQueueProvider = function (_a) { | ||
var children = _a.children; | ||
var queue = React.useState(function () { return new TaskQueue(); })[0]; | ||
var value = React.useMemo(function () { return ({ | ||
enqueue: queue.enqueue.bind(queue), | ||
listen: queue.listen.bind(queue), | ||
isWaiting: queue.isWaiting.bind(queue), | ||
}); }, [queue]); | ||
return (React__default['default'].createElement(OrderQueueContext.Provider, { value: value }, children)); | ||
}; | ||
var useOrderQueue = function () { | ||
var context = React.useContext(OrderQueueContext); | ||
if (context === undefined) { | ||
throw new Error('useOrderQueue must be used within a OrderQueueProvider'); | ||
} | ||
return context; | ||
}; | ||
var OrderQueue = { | ||
OrderQueueProvider: OrderQueueProvider, | ||
useOrderQueue: useOrderQueue, | ||
useQueueStatus: useQueueStatus, | ||
}; | ||
var createUseMessages = function (_a) { | ||
var clearOrderFormMessages = _a.clearOrderFormMessages, useToast = _a.useToast; | ||
var useOrderFormMessages = function (orderForm, setOrderForm) { | ||
var _a = React.useState([]), messages = _a[0], setMessages = _a[1]; | ||
var _b = useToast(), showToast = _b.showToast, toastState = _b.toastState; | ||
var _c = useOrderQueue(), enqueue = _c.enqueue, listen = _c.listen; | ||
var queueStatusRef = useQueueStatus(listen); | ||
React.useEffect(function () { | ||
if (toastState.isToastVisible || !messages.length) { | ||
return; | ||
} | ||
showToast(messages[0].text); | ||
setMessages(function (queue) { return queue.slice(1); }); | ||
}, [showToast, toastState.isToastVisible, messages]); | ||
React.useEffect(function () { | ||
var _a, _b; | ||
if (!((_b = (_a = orderForm.messages) === null || _a === void 0 ? void 0 : _a.generalMessages) === null || _b === void 0 ? void 0 : _b.length)) { | ||
return; | ||
} | ||
setMessages(function (prevMessages) { var _a, _b; return prevMessages.concat((_b = (_a = orderForm.messages) === null || _a === void 0 ? void 0 : _a.generalMessages) !== null && _b !== void 0 ? _b : []); }); | ||
setOrderForm(function (prevOrderForm) { | ||
return __assign(__assign({}, prevOrderForm), { messages: __assign(__assign({}, prevOrderForm.messages), { generalMessages: [] }) }); | ||
}); | ||
var enqueuePromise = enqueue(function () { return __awaiter(void 0, void 0, void 0, function () { | ||
var data; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, clearOrderFormMessages({ | ||
variables: { orderFormId: orderForm.id }, | ||
})]; | ||
case 1: | ||
data = (_a.sent()).data; | ||
return [2 /*return*/, data.clearOrderFormMessages]; | ||
} | ||
}); | ||
}); }); | ||
enqueuePromise.then(function (updatedOrderForm) { | ||
if (queueStatusRef.current === 'Fulfilled') { | ||
setOrderForm(updatedOrderForm); | ||
} | ||
}, function (err) { | ||
if (err.code === TASK_CANCELLED_CODE) { | ||
return; | ||
} | ||
throw err; | ||
}); | ||
}, [ | ||
enqueue, | ||
orderForm.id, | ||
orderForm.messages, | ||
queueStatusRef, | ||
setOrderForm, | ||
]); | ||
}; | ||
return useOrderFormMessages; | ||
}; | ||
var _a, _b, _c, _d; | ||
var orderFormOptimizationEnabled = (_d = (_c = (_b = (_a = window.__RUNTIME__) === null || _a === void 0 ? void 0 : _a.settings) === null || _b === void 0 ? void 0 : _b['vtex.store']) === null || _c === void 0 ? void 0 : _c.enableOrderFormOptimization) !== null && _d !== void 0 ? _d : false; | ||
/** | ||
* Heuristic function to determine whether or not the local | ||
* order form (stored in localStorage) should be replaced by | ||
* the remote order form. | ||
*/ | ||
var shouldUpdateOrderForm = function (localOrderForm, remoteOrderForm) { | ||
return (localOrderForm.value === UNSYNC_ORDER_FORM_VALUE || | ||
(orderFormOptimizationEnabled && | ||
localOrderForm.id !== remoteOrderForm.id && | ||
localOrderForm.id !== DEFAULT_ORDER_FORM_ID)); | ||
}; | ||
var reducer = function (prevOrderForm, updateOrderForm) { | ||
if (typeof updateOrderForm === 'function') { | ||
return __assign(__assign({}, prevOrderForm), updateOrderForm(__assign(__assign({}, prevOrderForm), { value: prevOrderForm.value === UNSYNC_ORDER_FORM_VALUE | ||
? 0 | ||
: prevOrderForm.value }))); | ||
} | ||
return __assign(__assign({}, prevOrderForm), updateOrderForm); | ||
}; | ||
var saveLocalOrderForm = function (orderForm) { | ||
localStorage.setItem('orderform', JSON.stringify(orderForm)); | ||
}; | ||
var getLocalOrderForm = function () { | ||
var _a; | ||
return typeof document === 'undefined' | ||
? null | ||
: JSON.parse((_a = localStorage.getItem('orderform')) !== null && _a !== void 0 ? _a : 'null'); | ||
}; | ||
var noop = function () { }; | ||
function createOrderFormProvider$1(_a) { | ||
var useOrderFormMessages = _a.useOrderFormMessages, useGetOrderForm = _a.useGetOrderForm; | ||
var defaultOrderForm = { | ||
id: DEFAULT_ORDER_FORM_ID, | ||
items: [], | ||
value: UNSYNC_ORDER_FORM_VALUE, | ||
totalizers: [], | ||
marketingData: {}, | ||
canEditData: false, | ||
loggedIn: false, | ||
paymentData: { | ||
isValid: false, | ||
installmentOptions: [], | ||
paymentSystems: [], | ||
payments: [], | ||
availableAccounts: [], | ||
}, | ||
messages: { | ||
couponMessages: [], | ||
generalMessages: [], | ||
}, | ||
shipping: { | ||
isValid: false, | ||
deliveryOptions: [], | ||
pickupOptions: [], | ||
}, | ||
}; | ||
var OrderFormContext = React.createContext({ | ||
orderForm: defaultOrderForm, | ||
setOrderForm: noop, | ||
error: undefined, | ||
loading: false, | ||
}); | ||
var OrderFormProvider = function (_a) { | ||
var _b; | ||
var children = _a.children; | ||
var _c = useGetOrderForm(), loading = _c.loading, data = _c.data, error = _c.error; | ||
var shouldUseLocalOrderForm = typeof document !== 'undefined' && !navigator.onLine; | ||
var _d = React.useReducer(reducer, (_b = (shouldUseLocalOrderForm ? getLocalOrderForm() : defaultOrderForm)) !== null && _b !== void 0 ? _b : defaultOrderForm), orderForm = _d[0], setOrderForm = _d[1]; | ||
// use a different variable to store the loading state because if some | ||
// component uses the `loading` from the Apollo query they won't be perfectly | ||
// synchronized with our `orderForm` state and could cause some anomalies. | ||
var _e = React.useState(!shouldUseLocalOrderForm), orderFormLoading = _e[0], setOrderFormLoading = _e[1]; | ||
var listen = useOrderQueue().listen; | ||
var queueStatusRef = useQueueStatus(listen); | ||
React.useEffect(function () { | ||
if (loading || error || !data) { | ||
return; | ||
} | ||
var localOrderForm = getLocalOrderForm(); | ||
if (localOrderForm != null) { | ||
if (!shouldUpdateOrderForm(localOrderForm, data.orderForm) || | ||
// if the queue is fulfilled, we will use the remote order form | ||
// regardless of the local status. | ||
// | ||
// if the queue is pending the remote order form isn't important because | ||
// it is expected that when the last task in the queue is finalized, the | ||
// component will call `setOrderForm` with the most up-to-date value. | ||
queueStatusRef.current !== 'Fulfilled') { | ||
setOrderFormLoading(false); | ||
setOrderForm(function (prevOrderForm) { | ||
if (prevOrderForm.id !== defaultOrderForm.id) { | ||
return prevOrderForm; | ||
} | ||
return localOrderForm; | ||
}); | ||
return; | ||
} | ||
} | ||
setOrderForm(data.orderForm); | ||
setOrderFormLoading(false); | ||
}, [data, error, loading, queueStatusRef]); | ||
React.useEffect(function () { | ||
saveLocalOrderForm(orderForm); | ||
}, [orderForm]); | ||
useOrderFormMessages(orderForm, setOrderForm); | ||
var value = React.useMemo(function () { return ({ | ||
error: error, | ||
orderForm: __assign(__assign({}, orderForm), { value: orderForm.value === UNSYNC_ORDER_FORM_VALUE ? 0 : orderForm.value, messages: __assign(__assign({}, orderForm.messages), { generalMessages: [] }) }), | ||
setOrderForm: setOrderForm, | ||
loading: orderFormLoading, | ||
}); }, [error, orderForm, orderFormLoading]); | ||
return (React__default['default'].createElement(OrderFormContext.Provider, { value: value }, children)); | ||
}; | ||
function useOrderForm() { | ||
var context = React.useContext(OrderFormContext); | ||
if (context === undefined) { | ||
throw new Error('useOrderForm must be used within a OrderFormProvider'); | ||
} | ||
return context; | ||
} | ||
return { OrderFormProvider: OrderFormProvider, useOrderForm: useOrderForm }; | ||
} | ||
function createOrderFormProvider(_a) { | ||
var useToast = _a.useToast, clearOrderFormMessages = _a.clearOrderFormMessages, useGetOrderForm = _a.useGetOrderForm; | ||
var useOrderFormMessages = createUseMessages({ | ||
useToast: useToast, | ||
clearOrderFormMessages: clearOrderFormMessages, | ||
}); | ||
return createOrderFormProvider$1({ useOrderFormMessages: useOrderFormMessages, useGetOrderForm: useGetOrderForm }); | ||
} | ||
exports.OrderQueue = OrderQueue; | ||
exports.createOrderFormProvider = createOrderFormProvider; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@vtex/order-manager", | ||
"version": "0.0.3-2", | ||
"version": "0.0.3-3", | ||
"description": "", | ||
"cdn": "dist/index.umd.js", | ||
"main": "dist/index.js", | ||
"typings": "dist/index.d.ts", | ||
"license": "", | ||
"files": [ | ||
"dist", | ||
"src" | ||
], | ||
"engines": { | ||
"node": ">=10" | ||
}, | ||
"types": "types/index.d.ts", | ||
"unpkg": "dist/index.umd.js", | ||
"module": "dist/index.esm.js", | ||
"jsdelivr": "dist/index.umd.js", | ||
"umd:main": "dist/index.umd.js", | ||
"scripts": { | ||
"start": "tsdx watch", | ||
"build": "tsdx build", | ||
"test": "echo 'not implemented'", | ||
"lint": "eslint src/ --ext .tsx,.ts", | ||
"size": "size-limit", | ||
"analyze": "size-limit --why" | ||
"doc": "typedoc src/index.ts", | ||
"test": "vtex-test-tools test", | ||
"lint": "eslint --ext js,jsx,ts,tsx .", | ||
"build": "rollup --config ./rollup.config.js", | ||
"prepublishOnly": "npm run doc && npm run build && npm run test" | ||
}, | ||
"dependencies": { | ||
"react": "17.0.1" | ||
}, | ||
"peerDependencies": { | ||
"react": ">=16" | ||
"react": "16 || 17" | ||
}, | ||
"module": "dist/order-manager.esm.js", | ||
"size-limit": [ | ||
{ | ||
"path": "dist/order-manager.cjs.production.min.js", | ||
"limit": "10 KB" | ||
}, | ||
{ | ||
"path": "dist/order-manager.esm.js", | ||
"limit": "10 KB" | ||
} | ||
], | ||
"devDependencies": { | ||
"@size-limit/preset-small-lib": "^4.10.1", | ||
"@types/jest": "^26.0.14", | ||
"@types/prettier": "^2.1.2", | ||
"@types/react": "^17.0.3", | ||
"@types/react-dom": "^17.0.2", | ||
"@typescript-eslint/eslint-plugin": "^4.18.0", | ||
"@typescript-eslint/parser": "^4.18.0", | ||
"eslint": "^7.22.0", | ||
"eslint-plugin-jest": "^24.3.1", | ||
"eslint-plugin-react": "^7.22.0", | ||
"react": "^17.0.1", | ||
"react-dom": "^17.0.1", | ||
"size-limit": "^4.10.1", | ||
"tsdx": "^0.14.1", | ||
"tslib": "^2.1.0", | ||
"typescript": "^4.2.3" | ||
} | ||
"@vtex/prettier-config": "^0.3.6", | ||
"@vtex/test-tools": "^3.4.1", | ||
"@vtex/tsconfig": "^0.5.6", | ||
"eslint": "^7.11.0", | ||
"eslint-config-vtex-react": "^6.9.5", | ||
"prettier": "^2.1.2", | ||
"rollup": "^2.29.0", | ||
"rollup-plugin-typescript2": "^0.27.3", | ||
"ts-jest": "^26.4.1", | ||
"typedoc": "^0.20.32", | ||
"typedoc-plugin-markdown": "^3.6.0", | ||
"typescript": "^4.0.3" | ||
}, | ||
"files": [ | ||
"dist/", | ||
"types/" | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/vtex/order-manager.git" | ||
}, | ||
"author": { | ||
"name": "VTEX" | ||
}, | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/vtex/order-manager/issues" | ||
}, | ||
"homepage": "https://github.com/vtex/order-manager#readme" | ||
} |
@@ -1,3 +0,57 @@ | ||
# Order Manager (NPM package) | ||
# Order Manager (NPM Package) | ||
[![Build Status](https://travis-ci.org/vtex/order-manager.svg?branch=master)](https://travis-ci.org/vtex/order-manager) | ||
[![License](https://badgen.net/github/license/vtex/order-manager)](./LICENSE) | ||
[![Library minified size](https://badgen.net/bundlephobia/min/@vtex/order-manager)](https://bundlephobia.com/result?p=@vtex/order-manager) | ||
[![Library minified + gzipped size](https://badgen.net/bundlephobia/minzip/@vtex/order-manager)](https://bundlephobia.com/result?p=@vtex/order-manager) | ||
This package is an abstraction to decouple the Order Manager logic from VTEX IO. Refer to the [repository root's README](../../../docs/README.md) for more information. | ||
## Installation | ||
This library is published in the NPM registry and can be installed using any compatible package manager. | ||
```sh | ||
npm install @vtex/order-manager --save | ||
# For Yarn, use the command below. | ||
yarn add @vtex/order-manager | ||
``` | ||
### Installation from CDN | ||
This module has an UMD bundle available through JSDelivr and Unpkg CDNs. | ||
```html | ||
<!-- For UNPKG use the code below. --> | ||
<script src="https://unpkg.com/@vtex/order-manager"></script> | ||
<!-- For JSDelivr use the code below. --> | ||
<script src="https://cdn.jsdelivr.net/npm/@vtex/order-manager"></script> | ||
<script> | ||
// UMD module is exposed through the "orderManager" global variable. | ||
console.log(orderManager) | ||
</script> | ||
``` | ||
## Documentation | ||
[Documentation generated from source files by Typedoc](./docs/README.md). | ||
## License | ||
Released under [MIT License](./LICENSE). | ||
); | ||
</script> | ||
``` | ||
## Documentation | ||
[Documentation generated from source files by Typedoc](./docs/README.md). | ||
## License | ||
Released under [MIT License](./LICENSE). | ||
``` |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
173218
25
1685
1
58
0
2
15
1
+ Addedreact@17.0.1
+ Addedobject-assign@4.1.1(transitive)
+ Addedreact@17.0.1(transitive)
- Removedreact@18.3.1(transitive)