Copy disabled (too large)
Download .txt
Showing preview only (11,293K chars total). Download the full file to get everything.
Repository: walmat/nebula
Branch: main
Commit: 176ae287cbf8
Files: 634
Total size: 10.6 MB
Directory structure:
gitextract_l8lb8z_d/
├── .eslintignore
├── .eslintrc.js
├── .gitattributes
├── .github/
│ └── ISSUE_TEMPLATE/
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── .prettierrc
├── .stylelintrc
├── app/
│ ├── 3ds.html
│ ├── Harvester.html
│ ├── Question.html
│ ├── __mocks__/
│ │ ├── dns.tsx
│ │ ├── electron-ga.tsx
│ │ ├── electron.tsx
│ │ ├── fileMock.tsx
│ │ ├── request-promise.tsx
│ │ └── styleMock.tsx
│ ├── api/
│ │ └── sys/
│ │ ├── fileOps.ts
│ │ └── index.ts
│ ├── app.html
│ ├── auth.html
│ ├── classes/
│ │ ├── AppUpdate.ts
│ │ ├── Boot.ts
│ │ ├── Notification.ts
│ │ ├── ProxyTester.ts
│ │ └── Storage.ts
│ ├── components/
│ │ ├── Analytics/
│ │ │ ├── Loadable.tsx
│ │ │ ├── __tests__/
│ │ │ │ └── Analytics.spec.tsx
│ │ │ ├── actions/
│ │ │ │ ├── checkouts.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── news.tsx
│ │ │ ├── components/
│ │ │ │ ├── checkouts.tsx
│ │ │ │ ├── expenses.tsx
│ │ │ │ ├── news.tsx
│ │ │ │ ├── orders.tsx
│ │ │ │ ├── stats.tsx
│ │ │ │ └── welcome.tsx
│ │ │ ├── index.tsx
│ │ │ ├── reducers/
│ │ │ │ ├── checkouts.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── news.tsx
│ │ │ ├── styles/
│ │ │ │ ├── checkouts.tsx
│ │ │ │ ├── expenses.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── news.tsx
│ │ │ │ ├── orders.tsx
│ │ │ │ ├── shipments.tsx
│ │ │ │ ├── stats.tsx
│ │ │ │ └── welcome.tsx
│ │ │ └── types.tsx
│ │ ├── App/
│ │ │ ├── App.tsx
│ │ │ ├── Providers.tsx
│ │ │ ├── Root.tsx
│ │ │ ├── __tests__/
│ │ │ │ ├── App.spec.tsx
│ │ │ │ └── Root.spec.tsx
│ │ │ ├── actions.tsx
│ │ │ ├── components/
│ │ │ │ ├── titlebar/
│ │ │ │ │ └── Titlebar.tsx
│ │ │ │ └── toolbar/
│ │ │ │ ├── area.tsx
│ │ │ │ ├── body.tsx
│ │ │ │ ├── menu.tsx
│ │ │ │ └── profile.tsx
│ │ │ ├── reducers.tsx
│ │ │ ├── selectors.tsx
│ │ │ └── styles/
│ │ │ ├── Titlebar.tsx
│ │ │ ├── ToolbarAreaPane.tsx
│ │ │ └── index.tsx
│ │ ├── Calendar/
│ │ │ ├── Calendar.tsx
│ │ │ ├── CalendarMonth.tsx
│ │ │ ├── CalendarYear.tsx
│ │ │ ├── Container.tsx
│ │ │ ├── Month.tsx
│ │ │ └── ViewSelect.tsx
│ │ ├── Captchas/
│ │ │ ├── Harvesters.tsx
│ │ │ ├── Loadable.tsx
│ │ │ ├── __tests__/
│ │ │ │ └── Harvesters.spec.tsx
│ │ │ ├── actions/
│ │ │ │ ├── captchas.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── components/
│ │ │ │ ├── actionBar/
│ │ │ │ │ └── ActionBar.tsx
│ │ │ │ ├── card/
│ │ │ │ │ └── index.tsx
│ │ │ │ └── grid/
│ │ │ │ └── index.tsx
│ │ │ ├── reducers/
│ │ │ │ ├── captchas.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── selectors.tsx
│ │ │ └── styles/
│ │ │ ├── actionBar.tsx
│ │ │ ├── card.tsx
│ │ │ ├── createDialog.tsx
│ │ │ └── index.tsx
│ │ ├── DebouncedInput/
│ │ │ └── DebouncedInput.tsx
│ │ ├── ErrorBoundary/
│ │ │ ├── components/
│ │ │ │ ├── GenerateErrorReport.tsx
│ │ │ │ └── GenerateErrorReportBody.tsx
│ │ │ ├── index.tsx
│ │ │ └── styles/
│ │ │ ├── GenerateErrorReport.tsx
│ │ │ └── index.tsx
│ │ ├── ImportExport/
│ │ │ ├── components/
│ │ │ │ └── dialog.tsx
│ │ │ ├── index.tsx
│ │ │ └── styles/
│ │ │ └── index.tsx
│ │ ├── Legal/
│ │ │ ├── PrivacyPolicy/
│ │ │ │ ├── Loadable.tsx
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── PrivacyPolicy.spec.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── styles/
│ │ │ │ └── index.tsx
│ │ │ └── TermsOfService/
│ │ │ ├── Loadable.tsx
│ │ │ ├── __tests__/
│ │ │ │ └── TermsOfService.spec.tsx
│ │ │ ├── index.tsx
│ │ │ └── styles/
│ │ │ └── index.tsx
│ │ ├── LoadingIndicator/
│ │ │ ├── index.tsx
│ │ │ └── styles/
│ │ │ └── index.tsx
│ │ ├── NoChildrenComponent/
│ │ │ ├── index.tsx
│ │ │ └── styles/
│ │ │ └── index.tsx
│ │ ├── Profiles/
│ │ │ ├── Loadable.tsx
│ │ │ ├── Profiles.tsx
│ │ │ ├── __tests__/
│ │ │ │ └── Profiles.spec.tsx
│ │ │ ├── actions/
│ │ │ │ ├── index.tsx
│ │ │ │ └── profiles.tsx
│ │ │ ├── components/
│ │ │ │ ├── actionBar/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── card/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── create/
│ │ │ │ │ ├── ProfileCreateDialog.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── ProfileCreateDialog.spec.tsx
│ │ │ │ │ ├── billing.tsx
│ │ │ │ │ ├── payment.tsx
│ │ │ │ │ └── shipping.tsx
│ │ │ │ └── grid/
│ │ │ │ └── index.tsx
│ │ │ ├── reducers/
│ │ │ │ ├── current.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── location.tsx
│ │ │ │ ├── payment.tsx
│ │ │ │ └── profiles.tsx
│ │ │ ├── selectors.tsx
│ │ │ └── styles/
│ │ │ ├── actionBar.tsx
│ │ │ ├── card.tsx
│ │ │ ├── createDialog.tsx
│ │ │ └── index.tsx
│ │ ├── Progressbar/
│ │ │ ├── Loadable.tsx
│ │ │ ├── index.tsx
│ │ │ └── styles/
│ │ │ └── index.tsx
│ │ ├── Proxies/
│ │ │ ├── Loadable.tsx
│ │ │ ├── Proxies.tsx
│ │ │ ├── __tests__/
│ │ │ │ └── Proxies.spec.tsx
│ │ │ ├── actions/
│ │ │ │ └── index.tsx
│ │ │ ├── components/
│ │ │ │ ├── ProxyActionBar.tsx
│ │ │ │ ├── ProxyCreateDialog.tsx
│ │ │ │ ├── Table/
│ │ │ │ │ ├── ProxyTable.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── tableHead.tsx
│ │ │ │ │ │ ├── tableRow.tsx
│ │ │ │ │ │ └── tableToolbar.tsx
│ │ │ │ │ └── styles/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── tableToolbar.tsx
│ │ │ │ └── __tests__/
│ │ │ │ └── ProxyCreateDialog.spec.tsx
│ │ │ ├── reducers/
│ │ │ │ ├── current.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── proxies.tsx
│ │ │ ├── selectors.tsx
│ │ │ └── styles/
│ │ │ ├── actionBar.tsx
│ │ │ ├── createDialog.tsx
│ │ │ └── index.tsx
│ │ ├── ReportBugs/
│ │ │ ├── Loadable.tsx
│ │ │ ├── __tests__/
│ │ │ │ └── ReportBugs.spec.tsx
│ │ │ ├── index.tsx
│ │ │ └── styles/
│ │ │ └── index.tsx
│ │ ├── Settings/
│ │ │ ├── actions.tsx
│ │ │ ├── components/
│ │ │ │ └── dialog/
│ │ │ │ ├── ProductField.tsx
│ │ │ │ ├── ProfileField.tsx
│ │ │ │ ├── StoreField.tsx
│ │ │ │ ├── accounts.tsx
│ │ │ │ ├── defaults.tsx
│ │ │ │ ├── generics.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── rates.tsx
│ │ │ │ └── webhooks.tsx
│ │ │ ├── index.tsx
│ │ │ ├── reducers/
│ │ │ │ ├── accounts.tsx
│ │ │ │ ├── currentAccount.tsx
│ │ │ │ ├── currentWebhook.tsx
│ │ │ │ ├── defaults.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── rates.ts
│ │ │ │ ├── settings.tsx
│ │ │ │ └── webhooks.tsx
│ │ │ ├── selectors.tsx
│ │ │ └── styles/
│ │ │ └── index.tsx
│ │ ├── Sidebar/
│ │ │ ├── Sidebar.tsx
│ │ │ ├── __tests__/
│ │ │ │ └── Sidebar.spec.tsx
│ │ │ ├── components/
│ │ │ │ ├── AnimatedLogo.tsx
│ │ │ │ ├── icons.tsx
│ │ │ │ └── menuItems.tsx
│ │ │ └── styles/
│ │ │ └── index.tsx
│ │ ├── Tasks/
│ │ │ ├── Loadable.tsx
│ │ │ ├── Tasks.tsx
│ │ │ ├── __tests__/
│ │ │ │ └── Tasks.spec.tsx
│ │ │ ├── actions/
│ │ │ │ └── index.tsx
│ │ │ ├── components/
│ │ │ │ ├── Table/
│ │ │ │ │ ├── TableData.tsx
│ │ │ │ │ ├── TableWrapper.tsx
│ │ │ │ │ ├── TaskList.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── TableBodyWrapper.tsx
│ │ │ │ │ │ ├── TableHeader.tsx
│ │ │ │ │ │ ├── cells/
│ │ │ │ │ │ │ ├── checkbox.tsx
│ │ │ │ │ │ │ ├── product.tsx
│ │ │ │ │ │ │ ├── profile.tsx
│ │ │ │ │ │ │ ├── proxies.tsx
│ │ │ │ │ │ │ ├── sizes.tsx
│ │ │ │ │ │ │ ├── status.tsx
│ │ │ │ │ │ │ ├── store.tsx
│ │ │ │ │ │ │ └── taskId.tsx
│ │ │ │ │ │ ├── header/
│ │ │ │ │ │ │ ├── checkbox.tsx
│ │ │ │ │ │ │ ├── product.tsx
│ │ │ │ │ │ │ ├── profile.tsx
│ │ │ │ │ │ │ ├── proxies.tsx
│ │ │ │ │ │ │ ├── sizes.tsx
│ │ │ │ │ │ │ ├── status.tsx
│ │ │ │ │ │ │ ├── store.tsx
│ │ │ │ │ │ │ └── taskId.tsx
│ │ │ │ │ │ ├── icons.tsx
│ │ │ │ │ │ ├── tableRow.tsx
│ │ │ │ │ │ ├── tableToolbar.tsx
│ │ │ │ │ │ └── toolbar/
│ │ │ │ │ │ ├── clock.tsx
│ │ │ │ │ │ ├── filter.tsx
│ │ │ │ │ │ ├── groups.tsx
│ │ │ │ │ │ ├── monitor.tsx
│ │ │ │ │ │ ├── retry.tsx
│ │ │ │ │ │ └── stagger.tsx
│ │ │ │ │ └── styles/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── tableToolbar.tsx
│ │ │ │ ├── actionBar/
│ │ │ │ │ ├── actionBar.tsx
│ │ │ │ │ ├── copyBtn.tsx
│ │ │ │ │ ├── createBtn.tsx
│ │ │ │ │ ├── deleteBtn.tsx
│ │ │ │ │ ├── editBtn.tsx
│ │ │ │ │ ├── startBtn.tsx
│ │ │ │ │ └── stopBtn.tsx
│ │ │ │ ├── create/
│ │ │ │ │ ├── AccountField.tsx
│ │ │ │ │ ├── CaptchaField.tsx
│ │ │ │ │ ├── CategoryField.tsx
│ │ │ │ │ ├── CheckoutDelayField.tsx
│ │ │ │ │ ├── DateField.tsx
│ │ │ │ │ ├── DiscountField.tsx
│ │ │ │ │ ├── FootsiteForm.tsx
│ │ │ │ │ ├── MaxPriceField.tsx
│ │ │ │ │ ├── MinPriceField.tsx
│ │ │ │ │ ├── MockToggle.tsx
│ │ │ │ │ ├── NumberOfTasksField.tsx
│ │ │ │ │ ├── OneCheckout.tsx
│ │ │ │ │ ├── PasswordField.tsx
│ │ │ │ │ ├── PayPalField.tsx
│ │ │ │ │ ├── PokemonForm.tsx
│ │ │ │ │ ├── ProductField.tsx
│ │ │ │ │ ├── ProfileField.tsx
│ │ │ │ │ ├── ProxiesField.tsx
│ │ │ │ │ ├── QuantityField.tsx
│ │ │ │ │ ├── RatesField.tsx
│ │ │ │ │ ├── RestockMode.tsx
│ │ │ │ │ ├── SecureBypassField.tsx
│ │ │ │ │ ├── ShopifyForm.tsx
│ │ │ │ │ ├── SizesField.tsx
│ │ │ │ │ ├── StoreField.tsx
│ │ │ │ │ ├── StyleIdField.tsx
│ │ │ │ │ ├── SupremeForm.tsx
│ │ │ │ │ ├── TaskCreateDialog.tsx
│ │ │ │ │ ├── TaskForm.tsx
│ │ │ │ │ ├── TaskModeField.tsx
│ │ │ │ │ ├── UseRotateProxies.tsx
│ │ │ │ │ ├── VariationField.tsx
│ │ │ │ │ ├── YeezySupplyForm.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── TaskCreateDialog.spec.tsx
│ │ │ │ │ ├── clearBtn.tsx
│ │ │ │ │ ├── closeBtn.tsx
│ │ │ │ │ └── createBtn.tsx
│ │ │ │ └── edits/
│ │ │ │ └── TaskEditDialog.tsx
│ │ │ ├── reducers/
│ │ │ │ ├── current.tsx
│ │ │ │ ├── delays.tsx
│ │ │ │ ├── edits.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── tasks.tsx
│ │ │ ├── selectors.tsx
│ │ │ ├── styles/
│ │ │ │ ├── actionBar.tsx
│ │ │ │ ├── createDialog.tsx
│ │ │ │ └── index.tsx
│ │ │ └── useTaskKeyPress.tsx
│ │ ├── featureFlag/
│ │ │ ├── FeatureFlagContext.tsx
│ │ │ └── NebulaFeatureFlags.ts
│ │ └── ui/
│ │ ├── Select.tsx
│ │ └── table/
│ │ ├── IndeterminateCheckbox.tsx
│ │ ├── RenderRow.tsx
│ │ ├── RowTable.tsx
│ │ ├── Table.tsx
│ │ ├── TableCell.tsx
│ │ └── TableVirtualized.tsx
│ ├── constants/
│ │ ├── countries.json
│ │ ├── env.js
│ │ ├── index.ts
│ │ ├── ipc.ts
│ │ ├── meta.js
│ │ ├── regexes.js
│ │ └── sizes.js
│ ├── hooks/
│ │ ├── useAnalyticsFile.tsx
│ │ ├── useAutoSolveLifecycle.tsx
│ │ ├── useAutoUpdateLifecycle.tsx
│ │ ├── useEscape.tsx
│ │ ├── useInterval.ts
│ │ ├── useNotificationLifecycle.tsx
│ │ ├── useProxiesStatus.tsx
│ │ ├── useQuickTaskLifecycle.tsx
│ │ ├── useTaskLifecycle.tsx
│ │ ├── useTaskStatus.tsx
│ │ ├── useTraceUpdate.ts
│ │ ├── useUpdateProfiles.tsx
│ │ ├── useUpdateProxies.tsx
│ │ ├── useUpdateStagger.tsx
│ │ ├── useUpdateWebhooks.tsx
│ │ └── useWhyDidYouUpdate.ts
│ ├── index.tsx
│ ├── main.dev.ts
│ ├── mainWindow/
│ │ └── windows.ts
│ ├── menu.ts
│ ├── routing/
│ │ ├── ClientRouter.ts
│ │ └── routes.ts
│ ├── store/
│ │ ├── configureStore/
│ │ │ ├── dev.ts
│ │ │ ├── index.ts
│ │ │ └── prod.ts
│ │ ├── migrations.ts
│ │ └── reducers.ts
│ ├── styles/
│ │ ├── js/
│ │ │ ├── index.tsx
│ │ │ ├── mixins.tsx
│ │ │ ├── themes.ts
│ │ │ └── variables.tsx
│ │ ├── scss/
│ │ │ ├── app.global.scss
│ │ │ ├── base/
│ │ │ │ ├── _base.scss
│ │ │ │ ├── _extends.scss
│ │ │ │ ├── _mixins.scss
│ │ │ │ ├── _variables.scss
│ │ │ │ └── mixins/
│ │ │ │ ├── _align-items.scss
│ │ │ │ ├── _animate-link.scss
│ │ │ │ ├── _animations.scss
│ │ │ │ ├── _backface-visibility.scss
│ │ │ │ ├── _background-cover.scss
│ │ │ │ ├── _border.scss
│ │ │ │ ├── _box-model.scss
│ │ │ │ ├── _box-shadow.scss
│ │ │ │ ├── _breakpoint.scss
│ │ │ │ ├── _clearfix.scss
│ │ │ │ ├── _display.scss
│ │ │ │ ├── _display_flex.scss
│ │ │ │ ├── _flex.scss
│ │ │ │ ├── _hide-text.scss
│ │ │ │ ├── _horz-vert-center.scss
│ │ │ │ ├── _hover-focus.scss
│ │ │ │ ├── _inline-block.scss
│ │ │ │ ├── _inner-shadow.scss
│ │ │ │ ├── _keyframes.scss
│ │ │ │ ├── _linear-gradient-angle.scss
│ │ │ │ ├── _linear-gradient.scss
│ │ │ │ ├── _margin-auto.scss
│ │ │ │ ├── _mediumFont.scss
│ │ │ │ ├── _min-breakpoint.scss
│ │ │ │ ├── _opacity.scss
│ │ │ │ ├── _placeholder.scss
│ │ │ │ ├── _rem.scss
│ │ │ │ ├── _replace-text.scss
│ │ │ │ ├── _retina.scss
│ │ │ │ ├── _rounded-corners.scss
│ │ │ │ ├── _single-transform.scss
│ │ │ │ ├── _text-shadow.scss
│ │ │ │ ├── _transform.scss
│ │ │ │ ├── _transitions.scss
│ │ │ │ ├── _translate.scss
│ │ │ │ └── _triangles.scss
│ │ │ └── themes/
│ │ │ ├── fonts.scss
│ │ │ └── reset.scss
│ │ └── select.tsx
│ ├── tasks/
│ │ ├── common/
│ │ │ ├── classes/
│ │ │ │ ├── index.ts
│ │ │ │ ├── monitor.ts
│ │ │ │ └── task.ts
│ │ │ ├── constants/
│ │ │ │ └── index.ts
│ │ │ ├── contexts/
│ │ │ │ ├── footsite.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── pokemon.ts
│ │ │ │ ├── shopify.ts
│ │ │ │ └── yeezysupply.ts
│ │ │ ├── index.ts
│ │ │ └── utils/
│ │ │ ├── index.ts
│ │ │ ├── logger.ts
│ │ │ ├── queues.ts
│ │ │ ├── request.ts
│ │ │ ├── rfrl.ts
│ │ │ └── timer.ts
│ │ ├── footsites/
│ │ │ ├── classes/
│ │ │ │ ├── functions/
│ │ │ │ │ ├── billing.ts
│ │ │ │ │ ├── captcha.ts
│ │ │ │ │ ├── cart.ts
│ │ │ │ │ ├── checkout.ts
│ │ │ │ │ ├── email.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── information.ts
│ │ │ │ │ ├── queue.ts
│ │ │ │ │ ├── session.ts
│ │ │ │ │ ├── shipping.ts
│ │ │ │ │ └── stock.ts
│ │ │ │ ├── tasks/
│ │ │ │ │ ├── base.ts
│ │ │ │ │ └── index.ts
│ │ │ │ └── types/
│ │ │ │ ├── datadome.d.ts
│ │ │ │ ├── geetest.d.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── stock.d.ts
│ │ │ │ └── variant.d.ts
│ │ │ ├── constants/
│ │ │ │ └── index.ts
│ │ │ ├── index.ts
│ │ │ ├── mocks/
│ │ │ │ ├── addToCart.ts
│ │ │ │ ├── cookies/
│ │ │ │ │ ├── champs.js
│ │ │ │ │ ├── cookies.ts
│ │ │ │ │ ├── eb.js
│ │ │ │ │ ├── fa.js
│ │ │ │ │ ├── ftl-ca.js
│ │ │ │ │ ├── ftl-kids.js
│ │ │ │ │ └── ftl-us.js
│ │ │ │ ├── getProductInfo.ts
│ │ │ │ ├── getProductPage.ts
│ │ │ │ ├── getSession.ts
│ │ │ │ ├── getStock.ts
│ │ │ │ ├── submitCheckout.ts
│ │ │ │ └── submitInformation.ts
│ │ │ └── utils/
│ │ │ ├── __tests__/
│ │ │ │ └── pickVariant.test.ts
│ │ │ ├── cleanseHeaderData.ts
│ │ │ ├── dfValues.ts
│ │ │ ├── forms.ts
│ │ │ ├── index.ts
│ │ │ └── pickVariant.ts
│ │ ├── index.ts
│ │ ├── managers/
│ │ │ ├── analytics.ts
│ │ │ ├── browser/
│ │ │ │ └── index.ts
│ │ │ ├── cache/
│ │ │ │ ├── cache.ts
│ │ │ │ └── windows.ts
│ │ │ ├── captcha/
│ │ │ │ ├── autoSolve.ts
│ │ │ │ ├── captcha.ts
│ │ │ │ ├── windows.ts
│ │ │ │ └── youtube.ts
│ │ │ ├── checkout.ts
│ │ │ ├── checkpoint/
│ │ │ │ └── index.tsx
│ │ │ ├── geetest/
│ │ │ │ └── index.ts
│ │ │ ├── index.ts
│ │ │ ├── interception/
│ │ │ │ ├── index.ts
│ │ │ │ └── window.ts
│ │ │ ├── notification.ts
│ │ │ ├── profile/
│ │ │ │ ├── profile.ts
│ │ │ │ └── typings.d.ts
│ │ │ ├── proxy.ts
│ │ │ ├── queue/
│ │ │ │ └── index.ts
│ │ │ ├── restart.ts
│ │ │ ├── tasks/
│ │ │ │ ├── choose.ts
│ │ │ │ └── index.ts
│ │ │ ├── typings.d.ts
│ │ │ ├── utils.ts
│ │ │ └── webhook/
│ │ │ ├── aycd.ts
│ │ │ ├── discord.ts
│ │ │ ├── index.ts
│ │ │ └── slack.ts
│ │ ├── pokemon/
│ │ │ ├── classes/
│ │ │ │ ├── functions/
│ │ │ │ │ ├── captcha.ts
│ │ │ │ │ ├── cart.ts
│ │ │ │ │ ├── checkout.ts
│ │ │ │ │ ├── datadome.ts
│ │ │ │ │ ├── email.ts
│ │ │ │ │ ├── encrypt.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── information.ts
│ │ │ │ │ ├── payment.ts
│ │ │ │ │ ├── product.ts
│ │ │ │ │ └── session.ts
│ │ │ │ └── tasks/
│ │ │ │ ├── base.ts
│ │ │ │ └── index.ts
│ │ │ ├── constants/
│ │ │ │ └── index.ts
│ │ │ ├── index.ts
│ │ │ ├── types/
│ │ │ │ ├── cart.d.ts
│ │ │ │ ├── checkout.d.ts
│ │ │ │ ├── datadome.d.ts
│ │ │ │ ├── geetest.d.ts
│ │ │ │ ├── index.d.ts
│ │ │ │ ├── information.d.ts
│ │ │ │ ├── key.d.ts
│ │ │ │ ├── order.d.ts
│ │ │ │ ├── payment.d.ts
│ │ │ │ ├── product.d.ts
│ │ │ │ ├── products.d.ts
│ │ │ │ ├── success.d.ts
│ │ │ │ └── token.d.ts
│ │ │ └── utils/
│ │ │ ├── cards.ts
│ │ │ ├── decode.ts
│ │ │ ├── encrypt.ts
│ │ │ ├── forms.ts
│ │ │ ├── index.ts
│ │ │ └── pickVariant.ts
│ │ ├── shopify/
│ │ │ ├── classes/
│ │ │ │ ├── functions/
│ │ │ │ │ ├── account.ts
│ │ │ │ │ ├── cart.ts
│ │ │ │ │ ├── challenge.ts
│ │ │ │ │ ├── checkout.ts
│ │ │ │ │ ├── checkpoint.ts
│ │ │ │ │ ├── config.ts
│ │ │ │ │ ├── customer.ts
│ │ │ │ │ ├── discount.ts
│ │ │ │ │ ├── homepage.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── order.ts
│ │ │ │ │ ├── password.ts
│ │ │ │ │ ├── payment.ts
│ │ │ │ │ ├── paypal.ts
│ │ │ │ │ ├── product.ts
│ │ │ │ │ ├── queue.ts
│ │ │ │ │ ├── review.ts
│ │ │ │ │ ├── session.ts
│ │ │ │ │ └── shipping.ts
│ │ │ │ ├── monitor.ts
│ │ │ │ ├── rates.ts
│ │ │ │ └── tasks/
│ │ │ │ ├── base.ts
│ │ │ │ ├── fast.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── pfutile.ts
│ │ │ │ ├── preload.ts
│ │ │ │ └── safe.ts
│ │ │ ├── constants/
│ │ │ │ ├── gateways.ts
│ │ │ │ └── index.ts
│ │ │ ├── index.ts
│ │ │ ├── mocks/
│ │ │ │ ├── __cookies__.ts
│ │ │ │ ├── apiCheckouts.tsx
│ │ │ │ ├── checkout.ts
│ │ │ │ ├── deadstockQuestion.ts
│ │ │ │ ├── kithMock.tsx
│ │ │ │ ├── paymentsConfig.ts
│ │ │ │ ├── responseTypes.ts
│ │ │ │ └── sessions.ts
│ │ │ ├── types/
│ │ │ │ ├── cart.d.ts
│ │ │ │ ├── index.d.ts
│ │ │ │ ├── product.d.ts
│ │ │ │ └── rates.d.ts
│ │ │ └── utils/
│ │ │ ├── __tests__/
│ │ │ │ └── pickVariant.test.ts
│ │ │ ├── forms.ts
│ │ │ ├── index.ts
│ │ │ ├── mocks/
│ │ │ │ └── kithNewBalance.ts
│ │ │ ├── parse.ts
│ │ │ ├── pickVariant.ts
│ │ │ └── protection.ts
│ │ └── yeezysupply/
│ │ ├── classes/
│ │ │ ├── functions/
│ │ │ │ ├── 3ds.ts
│ │ │ │ ├── akamai.ts
│ │ │ │ ├── bloom.ts
│ │ │ │ ├── cart.ts
│ │ │ │ ├── checkout.ts
│ │ │ │ ├── homepage.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── information.ts
│ │ │ │ ├── mpulse.ts
│ │ │ │ ├── pixel.ts
│ │ │ │ ├── product.ts
│ │ │ │ ├── splash.ts
│ │ │ │ ├── stock.ts
│ │ │ │ └── waiting.ts
│ │ │ ├── tasks/
│ │ │ │ ├── base.ts
│ │ │ │ └── index.ts
│ │ │ └── types/
│ │ │ └── index.ts
│ │ ├── constants/
│ │ │ └── index.ts
│ │ ├── index.ts
│ │ ├── mocks/
│ │ │ ├── addToCart.ts
│ │ │ ├── cookies.ts
│ │ │ ├── getAvailability.ts
│ │ │ ├── getProductInfo.ts
│ │ │ ├── getProductPage.ts
│ │ │ ├── submitCheckout.ts
│ │ │ └── submitInformation.ts
│ │ └── utils/
│ │ ├── __tests__/
│ │ │ └── pickVariant.test.ts
│ │ ├── dfValues.ts
│ │ ├── forms.ts
│ │ ├── index.ts
│ │ └── pickVariant.ts
│ └── utils/
│ ├── assert.ts
│ ├── bootHelper.ts
│ ├── captchaTypes.ts
│ ├── cardFormatter.ts
│ ├── comparators.ts
│ ├── convertObjectToArray.ts
│ ├── createWindows.ts
│ ├── date.js
│ ├── eventHandling.ts
│ ├── funcs.js
│ ├── getPlatform.ts
│ ├── gzip.ts
│ ├── imgForCardType.ts
│ ├── imgsrc.ts
│ ├── isEncoded.ts
│ ├── isOnline.ts
│ ├── isPackaged.js
│ ├── loadFile.ts
│ ├── loadUrls.ts
│ ├── log.ts
│ ├── paths.js
│ ├── pkginfo.js
│ ├── proxy.ts
│ ├── randInt.ts
│ ├── reducerPrefixer.ts
│ ├── saveFile.ts
│ ├── sleep.ts
│ ├── storageHelper.ts
│ ├── styleResets.ts
│ ├── testProxies.ts
│ ├── titlebarDoubleClick.ts
│ ├── trimFat.ts
│ ├── url.ts
│ └── validateTasks.ts
├── autosolve-client.d.ts
├── babel.config.js
├── babelx.js
├── chrome-paths.d.ts
├── config/
│ └── env/
│ ├── env.dev.js
│ ├── env.prod.js
│ └── index.js
├── electron-builder.yml
├── internals/
│ └── scripts/
│ ├── AfterPack.js
│ ├── CheckBuiltsExist.js
│ ├── CheckNodeEnv.js
│ ├── CheckPortInUse.js
│ ├── CheckYarn.js
│ └── Notarize.js
├── jest.config.js
├── jest.setup.js
├── jsdom-extra.d.ts
├── package.json
├── preloads/
│ ├── 3ds.js
│ ├── auth.js
│ └── harvester.js
├── test/
│ ├── babel-transformer.js
│ ├── babelRegisterTs.js
│ ├── debug.ts
│ ├── mockOffsetSize.tsx
│ ├── polyfill.js
│ └── testUtils.tsx
├── tsconfig.json
└── webpack/
├── config.base.js
├── config.eslint.js
├── config.main.prod.babel.js
├── config.renderer.dev.babel.js
├── config.renderer.dev.dll.babel.js
└── config.renderer.prod.babel.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintignore
================================================
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
.eslintcache
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
# OSX
.DS_Store
# flow-typed
flow-typed/npm/*
!flow-typed/npm/module_vx.x.x.js
# App packaged
release
app/*.prod.js
app/style.css
app/style.css.map
dist
dll
main.js
main.js.map
.idea
npm-debug.log.*
__snapshots__
# Package.json
package.json
.travis.yml
.idea
vendors
build
docs
.vscode
.github
app/dll
.prettierrc
.stylelintrc
.eslintrc.json
================================================
FILE: .eslintrc.js
================================================
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
sourceType: 'module',
allowImportExportEverywhere: true,
ecmaVersion: 10,
ecmaFeatures: {
modules: true,
},
},
env: {
browser: true,
node: true,
jest: true,
es6: true,
},
plugins: ['import', 'promise', 'compat', 'react', '@typescript-eslint'],
extends: ['airbnb', 'plugin:prettier/recommended', 'prettier/react'],
settings: {
'import/resolver': {
webpack: {
config: 'webpack/config.eslint.js',
},
node: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
'eslint-import-resolver-typescript': true,
},
},
rules: {
'linebreak-style': 0,
'arrow-parens': 'off',
'compat/compat': 'error',
'consistent-return': 'off',
'comma-dangle': 'off',
'generator-star-spacing': 'off',
'import/no-unresolved': 'error',
'import/extensions': [
'error',
'always',
{
ts: 'never',
tsx: 'never',
js: 'never',
jsx: 'never',
},
],
'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
'jsx-a11y/anchor-is-valid': 'off',
'jsx-a11y/label-has-for': 'off',
'jsx-a11y/no-noninteractive-element-interactions': 'off',
'jsx-a11y/label-has-associated-control': 'off',
'jsx-a11y/no-static-element-interactions': 'off',
'jsx-a11y/click-events-have-key-events': 'off',
'no-console': [
'error',
{
allow: ['info', 'error', 'warn'],
},
],
'no-use-before-define': 'off',
'no-multi-assign': 'off',
'prettier/prettier': ['error', { singleQuote: true }],
'promise/param-names': 'error',
'promise/always-return': 'error',
'promise/catch-or-return': 'error',
'promise/no-native': 'off',
'react/sort-comp': [
'error',
{
order: ['type-annotations', 'static-methods', 'lifecycle', 'everything-else', 'render'],
},
],
'react/jsx-no-bind': 'off',
'react/jsx-filename-extension': ['error', { extensions: ['.js', '.jsx', '.ts', '.tsx'] }],
'react/prefer-stateless-function': 'off',
strict: 'off',
'import/prefer-default-export': 'off',
'arrow-body-style': 'off',
'no-underscore-dangle': 'off',
'class-methods-use-this': 'off',
'no-shadow': 'off',
'react/prop-types': 'off',
'import/no-dynamic-require': 'off',
'no-unused-vars': 'off', //use typescript version.
'no-restricted-syntax': 1,
'@typescript-eslint/no-unused-vars': [
'error', // setting this to warn for now...
// TODO fix these when we finish typescript migration.
{
args: 'after-used',
argsIgnorePattern: '^(args|theme|props|state|ownProps|dispatch|getState)|_',
varsIgnorePattern: '^(args|variables|mixins|args|log)',
},
],
},
globals: {
fetchMock: true,
},
};
================================================
FILE: .gitattributes
================================================
* text eol=lf
*.png binary
*.jpg binary
*.jpeg binary
*.ico binary
*.icns binary
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**Expected behavior**
If you're describing a bug, tell us what should happen.
If you're suggesting a change/improvement, tell us how it should work.
**Current Behavior**
If describing a bug, tell us what happens instead of the expected behavior.
If suggesting a change/improvement, explain the difference between current behavior.
**Possible Solution**
Not obligatory, but suggest a fix/reason for the bug or ideas how to implement the addition or change.
**Steps to Reproduce**
Provide a link to a live example or an unambiguous set of steps to reproduce this bug. Include code to reproduce, if relevant
1.
2.
3.
4.
**Environment**
Include as many relevant details about the environment you experienced the bug in
- Node version :
- Version or Branch used :
- Operating System and version [e.g. macOS 10.14 Mojave]:
- App Version [e.g. v2.0.0]:
**Screenshots / Recordings**
If applicable, add screenshots to help explain your problem.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: You want something added to the app or code.
title: ''
labels: enhancement
assignees: ''
---
================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
.eslintcache
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules/
app/node_modules
# OSX
.DS_Store
# flow-typed
flow-typed/npm/*
!flow-typed/npm/module_vx.x.x.js
# App packaged
release
app/build
app/*.prod.js
app/renderer.prod.js
app/style.css
dist
dll
main.js
main.js.map
.idea
npm-debug.log.*
package-lock.json
app/certs/*.pem
app/certs/*
certs/*
todo.txt
*yarn-error.log
eslint-common-rules.txt
build/entitlements.mas.plist
*embedded.provisionprofile
junit.xml
.VSCodeCounter
electron
================================================
FILE: .prettierrc
================================================
{
"overrides": [
{
"files": [".prettierrc", ".babelrc", ".eslintrc", ".stylelintrc"],
"options": {
"parser": "json"
}
}
],
"singleQuote": true,
"trailingComma": "none",
"arrowParens": "avoid",
"endOfLine": "auto"
}
================================================
FILE: .stylelintrc
================================================
{
"extends": ["stylelint-config-standard", "stylelint-config-prettier"],
"rules": {
"at-rule-no-unknown": null,
"no-descending-specificity": null
}
}
================================================
FILE: app/3ds.html
================================================
<html>
<body>
<form method="POST" action="" id="Cardinal-CCA-Form">
<input type="hidden" name="PaReq" value="" />
<input type="hidden" name="MD" value="" />
<input type="hidden" name="TermUrl" value="" />
</form>
</body>
</html>
================================================
FILE: app/Harvester.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no"
/>
<script>
if (!crossOriginIsolated) SharedArrayBuffer = ArrayBuffer;
</script>
<script src="https://nebulabots.s3.amazonaws.com/virtualpointer.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
<title>Captcha Harvester</title>
<style>
html,
body {
border-radius: 3px;
border: none;
height: 100%;
width: 100%;
overflow: hidden;
}
body {
max-width: 450px;
margin: auto;
}
button:hover {
opacity: 0.85;
}
button:focus {
outline: none;
}
#close-btn {
position: absolute;
top: 16px;
right: 16px;
cursor: pointer;
}
#minimize-btn {
position: absolute;
top: 8px;
right: 48px;
cursor: pointer;
}
#minimize-btn:hover,
#close-btn:hover {
cursor: pointer;
opacity: 0.43333;
}
#titlebar {
user-select: none;
position: absolute;
top: 0;
left: 0;
right: 60px;
height: 32px;
background: transparent;
-webkit-user-select: none;
-webkit-app-region: drag;
}
.noselect {
-webkit-touch-callout: none;
-webkit-user-select: none;
user-select: none;
}
#harvester-name {
font-size: 2em;
font-weight: 500;
left: 14px;
position: absolute;
font-family: 'Roboto';
}
#harvester-type {
font-size: 14px;
font-weight: 400;
position: absolute;
font-family: 'Roboto';
top: 58px;
left: 14px;
}
#harvester-id {
font-size: 12px;
font-weight: 400;
position: absolute;
font-family: 'Roboto';
top: 85px;
left: 14px;
}
#harvester-platform {
position: absolute;
margin: auto;
position: absolute;
font-family: 'Roboto';
top: 0;
left: 0;
bottom: 0;
right: 0;
opacity: 0.25;
width: 45px;
height: 45px;
object-fit: scale-down;
}
.not-solving {
color: unset;
}
.solving {
color: #8e83f4;
}
.light {
color: #000;
background-color: #f4f4f4;
}
.dark {
color: #fff;
background-color: #202126;
}
svg {
background: transparent !important;
}
#captcha {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
transform: scale(0.85);
}
#loader {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
}
.loading {
height: 300px;
width: 100%;
}
.visible {
visibility: visible;
}
.hidden {
visibility: hidden;
height: 0 !important;
width: 0 !important;
}
#g-recaptcha {
display: flex;
}
::-webkit-scrollbar {
display: none;
}
</style>
</head>
<body>
<div id="titlebar"></div>
<div class="noselect" id="minimize-btn">
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><title>Minimize</title><path d="M6 19h12v2H6z" fill="#616161" fill-opacity="1"/><path d="M0 0h24v24H0V0z" fill="none"/></svg>
</div>
<div class="noselect" id="close-btn">
<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24">
<rect id="backgroundrect" width="100%" height="100%" x="0" y="0" fill="none" stroke="none" />
<g class="currentLayer">
<title>Close</title>
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"
id="svg_1" class="selected" fill="#616161" fill-opacity="1" />
</g>
</svg>
</div>
<h1 class="noselect" id="harvester-name">Default</h1>
<h1 class="noselect" id="harvester-type">Captcha Harvester</h1>
<h1 class="noselect" id="harvester-id"></h1>
<div id="loader">
<svg class="loading noselect" version="1.1" id="L4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="-75 -100 200 300" enable-background="new 0 0 0 0" xml:space="preserve">
<circle fill="#616161" stroke="none" cx="6" cy="50" r="6">
<animate
attributeName="opacity"
dur="1s"
values="0;1;0"
repeatCount="indefinite"
begin="0.1"/>
</circle>
<circle fill="#616161" stroke="none" cx="26" cy="50" r="6">
<animate
attributeName="opacity"
dur="1s"
values="0;1;0"
repeatCount="indefinite"
begin="0.2"/>
</circle>
<circle fill="#616161" stroke="none" cx="46" cy="50" r="6">
<animate
attributeName="opacity"
dur="1s"
values="0;1;0"
repeatCount="indefinite"
begin="0.3"/>
</circle>
</svg>
</div>
<div id="captcha">
<div class="g-recaptcha" id="g-recaptcha"></div>
</div>
</body>
</html>
================================================
FILE: app/Question.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link
href="https://fonts.googleapis.com/css2?family=Roboto&display=swap"
rel="stylesheet"
/>
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no"
/>
<title>Nebula Omega</title>
<style>
* {
font-family: Roboto;
-webkit-app-region: no-drag;
user-select: none;
outline: none;
/* force everything underneath the #titlebar */
z-index: 9997;
}
svg:hover,
button:hover {
cursor: pointer;
opacity: 0.75;
}
html,
body {
height: 100%;
width: 100%;
}
body {
margin: 0;
}
#titlebar {
-webkit-app-region: drag !important;
height: 48px;
top: 0;
left: 0;
right: 0;
z-index: 9998;
}
#close,
#minimize {
position: absolute;
height: 28px;
width: auto;
/* force both of the icons over the #titlebar */
z-index: 9999;
fill: #ffffff;
}
#submit:hover,
#close:hover,
#minimize:hover {
cursor: pointer;
}
#close {
right: 12px;
top: 12px;
}
#minimize {
right: 46px;
top: 2px;
}
#iframe {
margin: 0 auto;
height: 70%;
width: 90%;
margin: none;
padding: none;
}
#iframe > iframe {
border: none;
border-radius: 4px;
}
#answer-container {
width: 94%;
margin: 8px auto;
flex-wrap: wrap;
align-content: center;
align-items: center;
justify-content: center;
padding: 0;
display: flex;
}
.answer-input {
margin: 2%;
border: none;
padding: 0px 16px;
border-radius: 4px;
width: 100%;
height: 29px;
}
#button-container {
width: 100%;
height: 5%;
display: flex;
flex-wrap: wrap;
align-content: center;
align-items: center;
justify-content: center;
padding: 0;
margin: 0;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
}
#submit-answers {
margin-left: 2%;
margin-right: 2%;
width: 50%;
height: 100%;
letter-spacing: 2px;
font-weight: 700;
background: linear-gradient(90deg, #8377f4 0%, #a49bff 100%);
border-radius: 4px;
border: none;
color: #ffffff;
}
</style>
</head>
<body>
<div id="titlebar"></div>
<svg
id="close"
xmlns="http://www.w3.org/2000/svg"
height="24"
viewBox="0 0 24 24"
width="24"
>
<path d="M0 0h24v24H0z" fill="none" />
<path
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"
/>
</svg>
<svg
id="minimize"
xmlns="http://www.w3.org/2000/svg"
height="24"
viewBox="0 0 24 24"
width="24"
>
<path d="M0 0h24v24H0V0z" fill="none" />
<path d="M6 19h12v2H6z" />
</svg>
<div id="iframe"></div>
<div id="answer-container"></div>
<div id="button-container">
<button id="submit-answers" type="submit">Submit</button>
</div>
</body>
</html>
================================================
FILE: app/__mocks__/dns.tsx
================================================
const dns = {
lookup: (_, cb) => cb(null)
};
export default dns;
================================================
FILE: app/__mocks__/electron-ga.tsx
================================================
class Analytics {
send = jest.fn();
}
export default Analytics;
================================================
FILE: app/__mocks__/electron.tsx
================================================
import createIPCMock from 'electron-mock-ipc';
const mocked = createIPCMock();
export const { ipcMain, ipcRenderer } = mocked;
export const app = {
getPath: jest.fn(name => {
return name;
}),
getName: jest.fn(),
getVersion: jest.fn()
};
export const require = jest.fn();
export const match = jest.fn();
export const remote = {
app
};
export const dialog = jest.fn();
================================================
FILE: app/__mocks__/fileMock.tsx
================================================
module.exports = {};
================================================
FILE: app/__mocks__/request-promise.tsx
================================================
// import { CoreOptions, Request } from 'request';
// import { debugConsole } from '../../test/debug';
// const requestPromise = jest.requireActual('request-promise');
// const mockRequest = async (
// uri: string,
// options: CoreOptions
// ): Promise<Request> => {
// // eslint-disable-next-line
// debugConsole({
// mockRequest: true,
// uri,
// method: options.method,
// headers: options.headers,
// json: options.json,
// body: options.body
// });
// return requestPromise(uri, options);
// };
// const mockJar = () => {
// return {
// setCookie: jest.fn(),
// getCookiesString: jest.fn(() => 'cookies'),
// getCookies: jest.fn(() => [])
// };
// };
// const request = jest.fn(mockRequest);
// request.jar = jest.fn(mockJar);
// const mockResponseOnce = fn => request.mockImplementationOnce(fn);
// request.mockResponseOnce = mockResponseOnce;
// request.jar.mockJarOnce = fn => request.jar.mockImplementation(fn);
// export default request;
================================================
FILE: app/__mocks__/styleMock.tsx
================================================
module.exports = {};
================================================
FILE: app/api/sys/fileOps.ts
================================================
import {
existsSync as _existsSync,
writeFile as _writeFileAsync,
appendFile as _appendFileAsync,
readFileSync as _readFileSync,
writeFileSync as _writeFileSync
} from 'fs';
import { EOL } from 'os';
import mkdirp from 'mkdirp';
import rimraf from 'rimraf';
export const writeFileAsync = (filePath: string, text: string) => {
const options = { mode: 0o755 };
_writeFileAsync(filePath, text, options, err => {
if (err) {
console.error(err, `writeFileAsync`);
}
});
};
export const writeFileSync = (filePath: string, text: string) => {
const options = { mode: 0o755 };
try {
_writeFileSync(filePath, text, options);
} catch (err) {
console.error(err, `writeFileSync`);
}
};
export const appendFileAsync = (filePath: string, text: string) => {
const options = { mode: 0o755 };
_appendFileAsync(filePath, text + EOL, options, err => {
if (err) {
console.error(err, `appendFileAsync`);
}
});
};
export const readFileSync = (filePath: string) => {
const options = { encoding: 'utf8' };
return _readFileSync(filePath, options);
};
export const fileExistsSync = (filePath: string) => _existsSync(filePath);
export const createDirSync = (newFolderPath: string) => {
mkdirp.sync(newFolderPath);
};
export const deleteFilesSync = (filePath: string) => {
rimraf.sync(filePath);
};
================================================
FILE: app/api/sys/index.ts
================================================
/* eslint no-await-in-loop: off */
import {
readdir as fsReaddir,
rename as fsRename,
existsSync,
statSync,
lstatSync
} from 'fs';
import Promise from 'bluebird';
import junk from 'junk';
import rimraf from 'rimraf';
import mkdirp from 'mkdirp';
import path from 'path';
import moment from 'moment';
import { exec } from 'child_process';
import findLodash from 'lodash/find';
import { log } from '../../utils/log';
import { isArray } from '../../utils/funcs';
const readdir = Promise.promisify(fsReaddir);
const execPromise = Promise.promisify(exec);
export const promisifiedExec = (command: string) => {
try {
return execPromise(command);
} catch (e) {
log.error(e);
return null;
}
};
export const promisifiedExecNoCatch = (command: string) => execPromise(command);
export const checkFileExists = async (filePath: string) => {
try {
if (typeof filePath === 'undefined' || filePath === null) {
return false;
}
let _isArray = false;
if (isArray(filePath)) {
_isArray = true;
}
let fullPath = null;
if (_isArray) {
for (let i = 0; i < filePath.length; i += 1) {
const item = filePath[i];
fullPath = path.resolve(item);
if (existsSync(fullPath)) {
return true;
}
}
return false;
}
fullPath = path.resolve(filePath);
return existsSync(fullPath);
} catch (e) {
log.error(e);
return false;
}
};
/**
Local device ->
*/
export const asyncReadLocalDir = async ({
filePath,
ignoreHidden = true
}: {
filePath: string;
ignoreHidden?: boolean;
}) => {
try {
const response = [];
const { error, data } = await readdir(filePath)
.then((res: any) => {
return {
data: res,
error: null
};
})
.catch(e => {
return {
data: null,
error: e
};
});
if (error) {
log.error(error, `asyncReadLocalDir`);
return { error: true, data: null };
}
let files = data;
files = data.filter(junk.not);
if (ignoreHidden) {
files = data.filter((item: string) => !/(^|\/)\.[^\/\.]/g.test(item)); // eslint-disable-line no-useless-escape
}
for (let i = 0; i < files.length; i += 1) {
const file = files[i];
const fullPath = path.resolve(filePath, file);
if (!existsSync(fullPath)) {
continue; // eslint-disable-line no-continue
}
const stat = statSync(fullPath);
const isFolder = lstatSync(fullPath).isDirectory();
const extension = path.extname(fullPath);
const { size, atime: dateTime } = stat;
if (findLodash(response, { path: fullPath })) {
continue; // eslint-disable-line no-continue
}
response.push({
name: file,
path: fullPath,
extension,
size,
isFolder,
dateAdded: moment(dateTime).format('YYYY-MM-DD HH:mm:ss')
});
}
return { error, data: response };
} catch (e) {
log.error(e);
return { error: true, data: null };
}
};
export const promisifiedRimraf = (item: any) => {
try {
return new Promise(resolve => {
rimraf(item, {}, error => {
resolve({
data: null,
stderr: error,
error
});
});
});
} catch (e) {
log.error(e);
return null;
}
};
export const delLocalFiles = async ({ fileList }: { fileList: any[] }) => {
try {
if (!fileList || fileList.length < 1) {
return { error: `No files selected.`, stderr: null, data: null };
}
for (let i = 0; i < fileList.length; i += 1) {
const item = fileList[i];
const { error } = await promisifiedRimraf(item);
if (error) {
log.error(`${error}`, `delLocalFiles -> rm error`);
return { error, stderr: null, data: false };
}
}
return { error: null, stderr: null, data: true };
} catch (e) {
log.error(e);
return { error: e, stderr: null, data: false };
}
};
const promisifiedRename = ({
oldFilePath,
newFilePath
}: {
oldFilePath: string;
newFilePath: string;
}) => {
try {
return new Promise(resolve => {
fsRename(oldFilePath, newFilePath, error => {
resolve({
data: null,
stderr: error,
error
});
});
});
} catch (e) {
log.error(e);
return null;
}
};
export const renameLocalFiles = async ({
oldFilePath,
newFilePath
}: {
oldFilePath: string;
newFilePath: string;
}) => {
try {
if (
typeof oldFilePath === 'undefined' ||
oldFilePath === null ||
typeof newFilePath === 'undefined' ||
newFilePath === null
) {
return { error: `No files selected.`, stderr: null, data: null };
}
const { error } = await promisifiedRename({ oldFilePath, newFilePath });
if (error) {
log.error(`${error}`, `renameLocalFiles -> mv error`);
return { error, stderr: null, data: false };
}
return { error: null, stderr: null, data: true };
} catch (e) {
log.error(e);
return { error: e, stderr: null, data: false };
}
};
const promisifiedMkdir = ({ newFolderPath }: { newFolderPath: string }) => {
try {
return new Promise(resolve => {
mkdirp(newFolderPath, error => {
resolve({ data: null, stderr: error, error });
});
});
} catch (e) {
log.error(e);
return null;
}
};
export const newLocalFolder = async ({
newFolderPath
}: {
newFolderPath: string;
}) => {
try {
if (typeof newFolderPath === 'undefined' || newFolderPath === null) {
return { error: `Invalid path.`, stderr: null, data: null };
}
const { error } = await promisifiedMkdir({ newFolderPath });
if (error) {
log.error(`${error}`, `newLocalFolder -> mkdir error`);
return { error, stderr: null, data: false };
}
return { error: null, stderr: null, data: true };
} catch (e) {
log.error(e);
return { error: e, stderr: null, data: false };
}
};
================================================
FILE: app/app.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no"
/>
<script>
if (!crossOriginIsolated) SharedArrayBuffer = ArrayBuffer;
</script>
<title>Nebula Omega</title>
<script>
(function() {
if (!process.env.HOT) {
const head = document.getElementsByTagName('head')[0];
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = './dist/style.css';
head.appendChild(link);
}
})();
</script>
</head>
<body>
<div id="root"></div>
<script>
(function() {
const scripts = [];
let PORT;
// Dynamically insert the DLL script in development env in the
// renderer process
if (process.env.NODE_ENV === 'development') {
scripts.push('../dll/renderer.dev.dll.js');
PORT = require('../config/env').PORT;
}
// Dynamically insert the bundled app script in the renderer process
scripts.push(
process.env.HOT
? 'http://localhost:' + PORT + '/dist/renderer.dev.js'
: './dist/renderer.prod.js'
);
document.write(
scripts
.map(script => `<script defer src="${script}"><\/script>`)
.join('')
);
})();
</script>
</body>
</html>
================================================
FILE: app/auth.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no"
/>
<script>
if (!crossOriginIsolated) SharedArrayBuffer = ArrayBuffer;
</script>
<title>Nebula Omega</title>
<style>
* {
font-family: Roboto;
-webkit-app-region: no-drag;
user-select: none;
outline: none;
/* force everything underneath the #titlebar */
z-index: 9997;
}
svg:hover, button:hover {
opacity: 0.75;
}
html, body {
height: 100%;
width: 100%;
}
body {
margin: 0;
}
#titlebar {
-webkit-app-region: drag !important;
height: 48px;
top: 0;
left: 0;
right: 0;
z-index: 9998;
}
#logo {
height: 96px;
width: auto;
margin-top: -114px;
margin-bottom: 32px;
}
#close, #minimize {
position: absolute;
height: 28px;
width: auto;
/* force both of the icons over the #titlebar */
z-index: 9999;
fill: #ffffff;
}
#activate:hover, #close:hover, #minimize:hover {
cursor: pointer;
}
#close {
right: 12px;
top: 12px;
}
#minimize {
right: 46px;
top: 2px;
}
#welcome {
margin: 0;
font-size:24px;
letter-spacing: 2px;
font-weight: 700;
color: #ffffff;
text-align: center;
}
#subtext {
font-size:14px;
font-weight: 500;
color: #C1C1C2;
text-align: center;
margin-bottom: 32px;
}
#license {
background-color: #2E2F34;
border-radius: 4px;
border: none;
font-size: 14px;
text-align: center;
color: #ffffff;
padding-left: 8px;
padding-right: 8px;
height: 32px;
width: 262px;
margin-bottom: 16px;
}
#activate {
height: 32px;
letter-spacing: 2px;
font-weight: 700;
background: linear-gradient(90deg, #8377F4 0%, #A49BFF 100%);
border-radius: 4px;
border: none;
color: #ffffff;
}
#copyright {
position: absolute;
left: 0;
right: 0;
margin: auto;
bottom: 8px;
width: 200px;
font-style: normal;
font-weight: normal;
font-size: 14px;
color: #C1C1C2;
}
#status {
text-transform: uppercase;
text-align: center;
position: absolute;
bottom: 72px;
font-size: 12px;
color: #FF3A5E;
}
.hidden {
visibility: hidden;
}
.disabled {
opacity: 0.55 !important;
cursor: not-allowed !important;
}
.visible {
visibility: visible;
}
.flex-container {
height: calc(100% - 48px);
padding: 0;
margin: 0;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
align-items: center;
justify-content: center;
}
.flex-column {
display: flex;
flex-direction: column;
}
.fade-in {
animation-delay: 0s;
animation: fadeIn ease 2.5s;
}
@keyframes fadeIn {
0% {opacity:0;}
100% {opacity:1;}
}
.lds-ring {
z-index: 99999;
position: absolute;
top: 67.5%;
left: 47.5%;
}
.lds-ring div {
z-index: 100000;
box-sizing: border-box;
display: block;
position: absolute;
width: 16px;
height: 16px;
margin: 8px;
border: 2px solid #fff;
border-radius: 50%;
animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
border-color: #fff transparent transparent transparent;
}
.lds-ring div:nth-child(1) {
animation-delay: -0.45s;
}
.lds-ring div:nth-child(2) {
animation-delay: -0.3s;
}
.lds-ring div:nth-child(3) {
animation-delay: -0.15s;
}
@keyframes lds-ring {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<div id="titlebar"></div>
<svg id="close" xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
<svg id="minimize" xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M6 19h12v2H6z"/></svg>
<div class="flex-container flex-column">
<div class="flex-row">
<img id="logo" class="fade-in" draggable="false" src="https://nebulabots.s3.amazonaws.com/logo.png" />
</div>
<div class="flex-row">
<h1 id="welcome">Welcome Back!</h1>
<p id="subtext">Please enter your license key below</p>
<div class="flex-column">
<input id="license" placeholder="XXXXX-XXXXX-XXXXX-XXXXX" />
<button id="activate">SIGN IN →
<div id="loader-container">
<div id="loader" class="lds-ring">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
</button>
</div>
</div>
<p id="status"></p>
</div>
<p id="copyright">© 2021 Nebula Automation, LLC</p>
</body>
</html>
================================================
FILE: app/classes/AppUpdate.ts
================================================
/* eslint-disable import/first */
import { app, dialog, BrowserWindow } from 'electron';
import { autoUpdater, CancellationToken } from 'electron-updater';
import { version } from '../../package.json';
app.getVersion = () => version;
import { isConnected } from '../utils/isOnline';
import { log } from '../utils/log';
import { isPackaged } from '../utils/isPackaged';
import { PATHS } from '../utils/paths';
import { ENABLE_BACKGROUND_AUTO_UPDATE } from '../constants';
import { unixTimestampNow } from '../utils/date';
import { getMainWindow } from '../mainWindow/windows';
import { undefinedOrNull } from '../utils/funcs';
let progressbarWindow: BrowserWindow | null = null;
let mainWindow: BrowserWindow;
const createChildWindow = () => {
try {
return new BrowserWindow({
parent: mainWindow,
modal: true,
show: false,
height: 150,
width: 600,
title: 'Update downloading...',
resizable: false,
minimizable: false,
maximizable: false,
fullscreenable: false,
movable: false,
webPreferences: {
nodeIntegration: true
}
});
} catch (e) {
log.error(e, `AppUpdate -> createChildWindow`);
return null;
}
};
const fireProgressbar = () => {
try {
if (progressbarWindow) {
progressbarWindow.show();
progressbarWindow.focus();
return;
}
progressbarWindow = createChildWindow();
if (progressbarWindow) {
progressbarWindow.loadURL(`${PATHS.loadUrlPath}#progressbarPage`);
progressbarWindow.webContents.on('did-finish-load', () => {
if (progressbarWindow) {
progressbarWindow.show();
progressbarWindow.focus();
}
});
progressbarWindow.on('closed', () => {
progressbarWindow = null;
});
progressbarWindow.on('unresponsive', (error: any) => {
log.error(error, `AppUpdate -> progressbarWindow -> onerror`);
});
}
} catch (e) {
log.error(e, `AppUpdate -> fireProgressbar`);
}
};
export default class AppUpdate {
autoUpdater: any;
domReadyFlag: boolean;
updateInitFlag: boolean;
updateForceCheckFlag: boolean;
_errorDialog: {
timeGenerated: number;
title: string | null;
message: string | null;
};
cancellationToken: any;
updateIsDownloading: any;
updateIsActive: number;
disableAutoUpdateCheck: boolean;
constructor() {
this.autoUpdater = autoUpdater;
if (!isPackaged) {
this.autoUpdater.updateConfigPath = PATHS.appUpdateFile;
}
// Just in case we end up attaching more than 10 listeners
this.autoUpdater.setMaxListeners(Infinity);
this.autoUpdater.autoDownload = ENABLE_BACKGROUND_AUTO_UPDATE;
this.domReadyFlag = false;
this.updateInitFlag = false;
this.updateForceCheckFlag = false;
this._errorDialog = {
timeGenerated: 0,
title: null,
message: null
};
this.cancellationToken = new CancellationToken();
this.updateIsDownloading = false;
this.updateIsActive = 0; // 0 = no, 1 = update check in progress, -1 = update in progress
this.disableAutoUpdateCheck = false;
}
init() {
try {
if (this.updateInitFlag) {
return;
}
this.autoUpdater.on('error', (error: any) => {
const errorMsg =
error == null ? 'unknown' : (error.stack || error).toString();
if (progressbarWindow) {
progressbarWindow.close();
}
this.closeActiveUpdates();
if (this.isNetworkError(error)) {
this.spitMessageDialog(
'Update Error',
'Oops.. A network error occured. Try again!',
'error'
);
log.doLog(error);
this.updateForceCheckFlag = false;
this.disableAutoUpdateCheck = false;
this.updateIsActive = 0;
return;
}
if (/Cannot find channel/i.test(error)) {
this.spitMessageDialog(
'No Updates Found',
'You have the latest version installed.',
'info'
);
log.doLog(error);
this.updateForceCheckFlag = false;
this.disableAutoUpdateCheck = false;
this.updateIsActive = 0;
return;
}
this.spitMessageDialog(
'Update Error',
'Oops.. Some error occured while updating the app. Try again!',
'error'
);
this.updateForceCheckFlag = false;
this.disableAutoUpdateCheck = false;
this.updateIsActive = 0;
log.error(errorMsg, `AppUpdate -> onerror`);
});
this.autoUpdater.on('update-available', async () => {
if (progressbarWindow && this.updateIsActive !== -1) {
progressbarWindow.close();
}
const { response } = await dialog.showMessageBox({
type: 'info',
title: 'Update Available',
message: 'New version available. Download now?',
buttons: ['Yes', 'No']
});
if (response === 0) {
if (progressbarWindow) {
progressbarWindow.close();
}
this.closeActiveUpdates(-1);
this.initDownloadUpdatesProgress();
this.autoUpdater.downloadUpdate(this.cancellationToken);
}
this.closeActiveUpdates();
this.updateForceCheckFlag = false;
this.disableAutoUpdateCheck = false;
this.updateIsActive = 0;
});
this.autoUpdater.on('download-progress', (progress: any) => {
if (!progressbarWindow) {
return;
}
this.setUpdateProgressWindow({ value: progress.percent || 0 });
});
this.autoUpdater.on('update-downloaded', async () => {
this.closeActiveUpdates();
if (progressbarWindow) {
progressbarWindow.close();
}
await dialog.showMessageBox({
type: 'info',
title: 'Update Installed',
message: 'Downloaded! Application will relaunch now.',
buttons: ['Continue']
});
this.autoUpdater.quitAndInstall();
});
this.updateInitFlag = true;
} catch (e) {
log.error(e, `AppUpdate -> init`);
}
}
pollForUpdates() {
try {
this.setMainWindow();
if (!mainWindow) {
return;
}
isConnected()
.then((connected: any) => {
if (!connected) {
return null;
}
if (this.updateIsActive === 1 || this.disableAutoUpdateCheck) {
return null;
}
this.autoUpdater.on('update-not-available', () => {
this.updateForceCheckFlag = false;
this.disableAutoUpdateCheck = false;
this.updateIsActive = 0;
});
if (this.updateIsDownloading) {
this.cancellationToken.cancel();
}
this.autoUpdater.checkForUpdates();
this.updateIsActive = 1;
return true;
})
.catch(() => {});
} catch (e) {
log.error(e, `AppUpdate -> checkForUpdates`);
}
}
checkForUpdates() {
try {
this.setMainWindow();
if (!mainWindow) {
return;
}
isConnected()
.then((connected: any) => {
if (!connected) {
return null;
}
if (this.updateIsActive === 1 || this.disableAutoUpdateCheck) {
return null;
}
this.autoUpdater.on('checking-for-update', () => {
this.setCheckUpdatesProgress();
});
this.autoUpdater.on('update-not-available', () => {
this.closeActiveUpdates();
if (progressbarWindow) {
progressbarWindow.close();
}
this.updateForceCheckFlag = false;
this.disableAutoUpdateCheck = false;
this.updateIsActive = 0;
});
if (this.updateIsDownloading) {
this.cancellationToken.cancel();
}
this.autoUpdater.checkForUpdates();
this.updateIsActive = 1;
return true;
})
.catch(() => {});
} catch (e) {
log.error(e, `AppUpdate -> checkForUpdates`);
}
}
async forceCheck() {
try {
this.setMainWindow();
if (!mainWindow) {
return;
}
if (!this.updateForceCheckFlag && this.updateIsActive !== 1) {
this.autoUpdater.once('update-not-available', async () => {
this.closeActiveUpdates();
if (progressbarWindow) {
progressbarWindow.close();
}
await dialog.showMessageBox({
title: 'No update found!',
message: 'You have the latest version installed.',
buttons: ['Close']
});
this.updateForceCheckFlag = false;
this.disableAutoUpdateCheck = false;
this.updateIsActive = 0;
});
}
if (this.updateIsActive === 1) {
return;
}
if (this.updateIsActive === -1) {
const { response } = await dialog.showMessageBox({
title: 'Update in progress',
message:
'Another update is in progess. Are you sure want to restart the update?',
buttons: ['Yes', 'No']
});
if (response === 0) {
if (this.updateIsDownloading) {
this.cancellationToken.cancel();
}
this.autoUpdater.checkForUpdates();
this.updateIsActive = -1;
}
return;
}
if (this.updateIsDownloading) {
this.cancellationToken.cancel();
}
this.autoUpdater.checkForUpdates();
this.updateForceCheckFlag = true;
this.disableAutoUpdateCheck = true;
this.updateIsActive = 1;
} catch (e) {
log.error(e, `AppUpdate -> forceCheck`);
}
}
setCheckUpdatesProgress() {
try {
isConnected()
.then((connected: any) => {
if (!connected) {
this.spitMessageDialog(
'Checking For Updates',
'Internet connection is unavailable.'
);
return null;
}
fireProgressbar();
this.setTaskBarProgressBar(2);
if (progressbarWindow) {
progressbarWindow.webContents.on('dom-ready', () => {
if (progressbarWindow) {
progressbarWindow.webContents.send(
'progressBarDataCommunication',
{
progressTitle: `Checking For Updates`,
progressBodyText: `Please wait...`,
value: 0,
variant: `indeterminate`
}
);
}
});
}
return true;
})
.catch(() => {});
} catch (e) {
log.error(e, `AppUpdate -> setCheckUpdatesProgress`);
}
}
initDownloadUpdatesProgress() {
try {
isConnected()
.then((connected: any) => {
if (!connected) {
this.spitMessageDialog(
'Downloading Updates',
'Internet connection is unavailable.'
);
return null;
}
fireProgressbar();
this.updateIsDownloading = true;
this.domReadyFlag = false;
this.setUpdateProgressWindow({ value: 0 });
return true;
})
.catch(() => {});
} catch (e) {
log.error(e, `AppUpdate -> initDownloadUpdatesProgress`);
}
}
setUpdateProgressWindow({ value = 0 }) {
try {
const data = {
progressTitle: `Downloading Updates`,
progressBodyText: `Please wait...`,
value,
variant: `determinate`
};
this.setTaskBarProgressBar(value / 100);
if (this.domReadyFlag && progressbarWindow) {
progressbarWindow.webContents.send(
'progressBarDataCommunication',
data
);
return;
}
if (progressbarWindow) {
progressbarWindow.webContents.on('dom-ready', () => {
if (progressbarWindow) {
progressbarWindow.webContents.send(
'progressBarDataCommunication',
data
);
this.domReadyFlag = true;
}
});
}
} catch (e) {
log.error(e, `AppUpdate -> setUpdateProgressWindow`);
}
}
setMainWindow() {
const _mainWindow = getMainWindow();
if (!_mainWindow || undefinedOrNull(_mainWindow)) {
return;
}
mainWindow = _mainWindow;
}
setTaskBarProgressBar(value: any) {
try {
if (mainWindow) {
mainWindow.setProgressBar(value);
}
} catch (e) {
log.error(e, `AppUpdate -> setTaskBarProgressBar`);
}
}
isNetworkError(errorObj: any) {
return (
errorObj.message === 'net::ERR_INTERNET_DISCONNECTED' ||
errorObj.message === 'net::ERR_PROXY_CONNECTION_FAILED' ||
errorObj.message === 'net::ERR_CONNECTION_RESET' ||
errorObj.message === 'net::ERR_CONNECTION_CLOSE' ||
errorObj.message === 'net::ERR_NAME_NOT_RESOLVED' ||
errorObj.message === 'net::ERR_CONNECTION_TIMED_OUT'
);
}
async spitMessageDialog(title: string, message: string, type = 'message') {
const { timeGenerated: _timeGenerated } = this._errorDialog;
const delayTime = 1000;
if (
_timeGenerated !== 0 &&
_timeGenerated - unixTimestampNow() < delayTime
) {
return;
}
this._errorDialog = {
timeGenerated: unixTimestampNow(),
title,
message
};
switch (type) {
default:
case 'message':
await dialog.showMessageBox({
title,
message,
buttons: ['Close']
});
break;
case 'error':
dialog.showErrorBox(title, message);
break;
}
}
closeActiveUpdates(updateIsActive = 0) {
this.setTaskBarProgressBar(-1);
this.updateIsActive = updateIsActive;
}
}
================================================
FILE: app/classes/Boot.ts
================================================
/* eslint no-await-in-loop: off */
/**
* Boot
* Note: Don't import log helper file from utils here
*/
import { readdirSync } from 'fs';
import { baseName, PATHS } from '../utils/paths';
import {
fileExistsSync,
writeFileAsync,
createDirSync,
deleteFilesSync
} from '../api/sys/fileOps';
import { daysDiff, yearMonthNow } from '../utils/date';
import { LOG_FILE_ROTATION_CLEANUP_THRESHOLD } from '../constants';
const { logFile, settingsFile, authFile, logDir } = PATHS;
const logFileRotationCleanUpThreshold = LOG_FILE_ROTATION_CLEANUP_THRESHOLD;
export default class Boot {
verifyDirList: string[];
verifyFileList: string[];
settingsFile: string;
authFile: string;
constructor() {
this.verifyDirList = [logDir];
this.verifyFileList = [logFile, settingsFile, authFile];
this.settingsFile = settingsFile;
this.authFile = authFile;
}
async init() {
try {
for (let i = 0; i < this.verifyDirList.length; i += 1) {
const item = this.verifyDirList[i];
if (!(await this.verifyDir(item))) {
await this.createDir(item);
}
}
if (!this.verifyFile(this.authFile)) {
await this.createFile(this.authFile);
}
if (!this.verifyFile(this.settingsFile)) {
await this.createFile(this.settingsFile);
}
for (let i = 0; i < this.verifyFileList.length; i += 1) {
const item = this.verifyFileList[i];
if (!this.verifyFile(item)) {
await this.createFile(item);
}
}
return;
} catch (e) {
console.error(e);
}
}
async verify() {
try {
for (let i = 0; i < this.verifyFileList.length; i += 1) {
const item = this.verifyDirList[i];
if (!(await this.verifyDir(item))) {
return;
}
}
for (let i = 0; i < this.verifyFileList.length; i += 1) {
const item = this.verifyFileList[i];
if (!this.verifyFile(item)) {
return;
}
}
return;
} catch (e) {
console.error(e);
}
}
quickVerify() {
try {
for (let i = 0; i < this.verifyFileList.length; i += 1) {
const item = this.verifyFileList[i];
if (!this.verifyFile(item)) {
return false;
}
}
return true;
} catch (e) {
console.error(e);
return false;
}
}
async verifyDir(filePath: string) {
try {
return fileExistsSync(filePath);
} catch (e) {
console.error(e);
return null;
}
}
async createDir(newFolderPath: string) {
try {
createDirSync(newFolderPath);
} catch (e) {
console.error(e);
}
}
verifyFile(filePath: string) {
try {
return fileExistsSync(filePath);
} catch (e) {
console.error(e);
return null;
}
}
createFile(filePath: string) {
try {
writeFileAsync(filePath, ``);
} catch (e) {
console.error(e);
}
}
cleanRotationFiles() {
try {
const dirFileList = readdirSync(logDir);
const pattern = `^\\${baseName(logFile)}`;
const _regex = new RegExp(pattern, 'gi');
const filesList = dirFileList.filter(elm => {
return !elm.match(_regex);
});
if (filesList === null || filesList.length < 1) {
return null;
}
filesList.map(async a => {
const dateMatch = a.match(/\d{4}-\d{2}/g);
if (
dateMatch === null ||
dateMatch.length < 1 ||
typeof dateMatch[0] === 'undefined' ||
dateMatch[0] === null
) {
return;
}
const _diff = daysDiff(yearMonthNow({}), dateMatch[0]);
if (_diff >= logFileRotationCleanUpThreshold) {
deleteFilesSync(`${logDir}/${a}`);
}
});
return null;
} catch (e) {
console.error(e);
return null;
}
}
}
================================================
FILE: app/classes/Notification.ts
================================================
import { PATHS } from '../utils/paths';
import { IS_DEV } from '../constants/env';
/* Cache of Audio elements, for instant playback */
const cache: any = {};
const VOLUME = 0.55;
// these get packaged into renderer.prod.js which resides in the same filepath as the app.html
const sounds: any = {
DONE: {
url: IS_DEV ? PATHS.successSoundPath : './success.mp3',
volume: VOLUME
},
HEADS_UP: {
url: IS_DEV ? PATHS.notifySoundPath : './notify.mp3',
volume: VOLUME
}
};
function preload() {
// eslint-disable-next-line no-restricted-syntax
for (const name in sounds) {
if (!cache[name]) {
const sound = sounds[name];
const audio = (cache[name] = new window.Audio());
audio.volume = sound.volume;
audio.src = sound.url;
}
}
}
function play(name: string) {
let audio = cache[name];
if (!audio) {
const sound = sounds[name];
if (!sound) {
throw new Error('Invalid sound name');
}
audio = cache[name] = new window.Audio();
audio.volume = sound.volume || VOLUME;
audio.src = sound.url;
}
audio.currentTime = 0;
audio.play();
}
export { preload, play };
================================================
FILE: app/classes/ProxyTester.ts
================================================
import { isEmpty } from 'lodash';
import { ipcMain, IpcMainInvokeEvent, BrowserWindow } from 'electron';
import { IPCKeys } from '../constants/ipc';
import { Proxy } from '../components/Proxies/reducers/current';
import { testProxy } from '../utils/testProxies';
import { StaggeredQueue } from '../tasks/common/utils';
export default class ProxyTester {
mainWindow: BrowserWindow | null;
hasLogged: boolean;
queue: StaggeredQueue;
results: {
[group: string]: {
[ip: string]: {
speed: number | 'failed';
};
};
};
interval: {
[id: string]: any;
};
constructor(mainWindow: BrowserWindow | null) {
this.queue = new StaggeredQueue(false, 20);
this.hasLogged = false;
this.mainWindow = mainWindow;
this.results = {};
this.interval = {};
ipcMain.on(IPCKeys.RequestTestProxy, this.insert);
}
process = async ({ group, id, url }: any) => {
if (this.mainWindow) {
const time = await testProxy(url, id);
if (!this.results[group]) {
this.results[group] = {};
}
this.results[group][id] = time;
}
};
start = (group: string) => {
if (!this.interval[group]) {
this.interval[group] = setInterval(() => {
if (isEmpty(this.results[group])) {
return;
}
if (this.mainWindow) {
this.mainWindow.webContents.send(
IPCKeys.ResponseTestProxy,
group,
this.results[group]
);
this.results[group] = {};
}
}, 1000);
}
};
stop = (group: string) => {
if (this.interval[group]) {
clearInterval(this.interval[group]);
this.interval[group] = null;
}
};
clear = () => {
this.queue.clear();
return Object.keys(this.results).map((id: string) => this.stop(id));
};
remove = (group: string, ip: string) => {
this.queue.removeJob(group, ip);
};
insert = (
_: IpcMainInvokeEvent,
id: string,
url: string,
proxies: Proxy[]
) => {
const promises = proxies.map(({ ip }) =>
this.queue.add(id, ip, this.process, { url })
);
this.start(id);
Promise.all(promises).catch(() => {});
};
}
================================================
FILE: app/classes/Storage.ts
================================================
import { log } from '../utils/log';
import {
readFileSync,
writeFileSync,
deleteFilesSync
} from '../api/sys/fileOps';
export default class Storage {
filePath: string;
constructor(filePath: string) {
this.filePath = filePath;
}
getAll() {
try {
const _stream = readFileSync(this.filePath);
if (
typeof _stream === 'undefined' ||
_stream === null ||
Object.keys(_stream).length < 1
) {
return {};
}
return JSON.parse(_stream);
} catch (e) {
log.error(e, `Storage -> getAll`);
}
}
getItem(key: string) {
try {
if (typeof key === 'undefined' || key === null) {
return null;
}
// get all items
const allItems = this.getAll();
if (allItems[key]) {
return allItems[key];
}
return null;
} catch (e) {
log.error(e, 'Storage -> getItem');
}
}
getItems(keys: any) {
try {
if (typeof keys === 'undefined' || keys === null || keys.length < 0) {
return {};
}
const allItem = this.getAll();
const _return: any = {};
// eslint-disable-next-line array-callback-return
keys.map((a: any) => {
if (typeof allItem[a] === 'undefined' || allItem[a] === null) {
return;
}
_return[a] = allItem[a];
});
return _return;
} catch (e) {
log.error(e, `Storage -> getAll`);
return null;
}
}
setAll({ ...data }) {
try {
writeFileSync(this.filePath, JSON.stringify({ ...data }));
} catch (e) {
log.error(e, `Storage -> setAll`);
}
}
set(key: string, value: any) {
try {
// get all items
const allItems = this.getAll();
// update / set the item
allItems[key] = value;
// write back to file
this.setAll({ ...allItems });
} catch (e) {
log.error(e, 'Storage -> set');
}
}
delete() {
try {
deleteFilesSync(this.filePath);
} catch (e) {
log.error(e, 'Storage -> delete');
}
}
}
================================================
FILE: app/components/Analytics/Loadable.tsx
================================================
import Loadable from 'react-imported-component';
import LoadingIndicator from '../LoadingIndicator';
/* eslint import/no-cycle: [2, { maxDepth: 1 }] */
export default Loadable(() => import('./index'), {
LoadingComponent: LoadingIndicator
});
================================================
FILE: app/components/Analytics/__tests__/Analytics.spec.tsx
================================================
import { render } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import React from 'react';
import Analytics from '../index';
import { withProviders } from '../../../../test/testUtils';
const news = [
{
_id: '5e4e11261c9d440000d10758',
id: '277f561b-928a-40d1-af5b-dca9ea765e1c',
date: 1582174646797,
message:
'The time has finally come.. Close your eyes and take a deep breath. Now open them. Welcome to family. Welcome to Omega.',
type: 'UPDATE'
}
];
beforeEach(() => {
fetchMock.resetMocks();
});
it('should render Analytics', async () => {
fetchMock.mockIf(/^https?:\/\/nebula-auth.herokuapp.com.*$/, async req => {
if (req.url.endsWith('/news')) {
return {
body: JSON.stringify(news)
};
}
if (req.url.endsWith('/checkouts')) {
return {
body: JSON.stringify([])
};
}
return {
status: 404,
body: 'Not Found'
};
});
const Root = withProviders({
Component: Analytics
});
// eslint-disable-next-line
const { debug, getByTestId, getByText } = render(<Root />);
// debug();
expect(getByText('Welcome Back,')).toBeDefined();
});
================================================
FILE: app/components/Analytics/actions/checkouts.tsx
================================================
import prefixer from '../../../utils/reducerPrefixer';
const prefix = '@@Checkouts';
const checkoutTypesList = ['ADD'];
export const checkoutActions = checkoutTypesList.map(t => `${prefix}/${t}`);
export const checkoutActionTypes = prefixer(prefix, checkoutTypesList);
export const addCheckout = checkout => {
return {
type: checkoutActionTypes.ADD,
payload: checkout
};
};
================================================
FILE: app/components/Analytics/actions/index.tsx
================================================
import { checkoutActionTypes, checkoutActions } from './checkouts';
import { newsActionTypes, newsActions } from './news';
export { checkoutActionTypes, newsActionTypes, checkoutActions, newsActions };
================================================
FILE: app/components/Analytics/actions/news.tsx
================================================
import prefixer from '../../../utils/reducerPrefixer';
const prefix = '@@News';
const newsTypesList = ['ADD'];
export const newsActions = newsTypesList.map(t => `${prefix}/${t}`);
export const newsActionTypes = prefixer(prefix, newsTypesList);
export const addNews = news => {
return {
type: newsActionTypes.ADD,
payload: news
};
};
================================================
FILE: app/components/Analytics/components/checkouts.tsx
================================================
import React from 'react';
import classnames from 'classnames';
import { useDispatch, useSelector } from 'react-redux';
import { FixedSizeList as List } from 'react-window';
import AutoSizer from 'react-virtualized-auto-sizer';
import { Typography, Grid, Tooltip, Fade } from '@material-ui/core';
import { orderBy, isPlainObject } from 'lodash';
import { useConfirm } from 'material-ui-confirm';
import FileCopyIcon from '@material-ui/icons/FileCopy';
import DoneIcon from '@material-ui/icons/Done';
import { makeStyles } from '@material-ui/styles';
import NoChildrenComponent from '../../NoChildrenComponent';
import { imageForCard } from '../../../utils/imgForCardType';
import { styles } from '../styles/checkouts';
import { setAnalyticsFile } from '../../Settings/actions';
import { loadCSVFile } from '../../../utils/loadFile';
import { RootState } from '../../../store/reducers';
const useStyles = makeStyles(styles);
const CheckoutComponent = ({
checkout,
style
}: {
checkout: any;
style: any;
}) => {
const styles = useStyles();
let storeValue = checkout.store;
if (isPlainObject(storeValue)) {
storeValue = checkout.store.name;
}
let productValue = checkout.product;
if (isPlainObject(productValue)) {
productValue = checkout.product.name;
}
let cardValue = checkout.card;
if (!cardValue && checkout.profile) {
cardValue = checkout.profile.type;
}
return (
<Grid
style={{ ...style, padding: '2px 12px 2px 12px' }}
container
direction="row"
>
<Grid item style={{ width: '100%', maxWidth: '100%', display: 'flex' }}>
<Tooltip TransitionComponent={Fade} title={storeValue}>
<Typography
style={{
display: 'flex',
flexDirection: 'column',
fontSize: 10,
flex: 1,
maxWidth: '25%',
alignItems: 'flex-start',
alignSelf: 'center',
whiteSpace: 'nowrap',
overflow: 'hidden',
'& > *': {
margin: '0 16px 0 0',
overflow: 'hidden'
}
}}
component="div"
variant="body1"
>
<span>{storeValue}</span>
</Typography>
</Tooltip>
<Tooltip TransitionComponent={Fade} title={productValue}>
<Typography
style={{
display: 'flex',
flexDirection: 'column',
fontSize: 10,
flex: 2,
alignItems: 'flex-start',
alignSelf: 'center',
overflow: 'hidden',
whiteSpace: 'nowrap',
margin: 'auto 8px'
}}
variant="body1"
>
{productValue}
</Typography>
</Tooltip>
<Typography
style={{
display: 'flex',
flexDirection: 'column',
flex: 1,
fontSize: 10,
alignItems: 'flex-end',
alignSelf: 'center',
whiteSpace: 'nowrap',
margin: '0'
}}
variant="body1"
title={cardValue || ''}
>
{cardValue ? (
<img
className={styles.cardType}
alt=""
src={imageForCard(cardValue)}
/>
) : null}
</Typography>
</Grid>
</Grid>
);
};
type RowProps = {
data: any[];
index: number;
style: any;
};
const Row = ({ data, index, style }: RowProps) => {
const checkout = data[index];
return (
<CheckoutComponent
key={checkout?.id || checkout?._id?.toString()}
checkout={checkout}
style={style}
/>
);
};
const CheckoutsLoader = ({ checkouts }: { checkouts: any[] }) => (
<AutoSizer>
{({ height, width }) => (
<List
className="checkouts--list"
height={height}
itemCount={checkouts.length}
itemSize={24}
width={width}
itemData={checkouts}
>
{Row}
</List>
)}
</AutoSizer>
);
const CheckoutsGrid = ({ checkouts }: { checkouts: any[] }) => {
if (!checkouts.length) {
return <NoChildrenComponent label="No Checkouts" variant="body1" />;
}
return <CheckoutsLoader checkouts={checkouts} />;
};
const CheckoutsComponent = () => {
const styles = useStyles();
const dispatch = useDispatch();
const confirm = useConfirm();
const file = useSelector((state: RootState) => state.Settings.analyticsFile);
const checkouts = useSelector((state: RootState) =>
orderBy(
state.Checkouts.filter((checkout: any) => checkout.success),
checkout => Number(checkout.date),
'desc'
)
);
const attachFile = async () => {
if (file) {
try {
await confirm({
title: `Are you sure you want to detach the analytics file?`,
description: `File location: ${file}`,
confirmationText: 'Yes',
cancellationText: 'No',
dialogProps: {
classes: {
paper: styles.paperRoot
}
},
confirmationButtonProps: {
classes: {
root: styles.confirmBtn
},
style: {
width: 105,
height: 35,
background:
'linear-gradient(90deg, rgba(131,119,244,1) 0%, rgba(164,155,255,1) 100%)',
color: '#fff'
}
},
cancellationButtonProps: {
classes: {
root: styles.cancelBtn
},
style: {
width: 105,
height: 35
}
}
});
return dispatch(setAnalyticsFile(''));
} catch (e) {
// noop...
}
return null;
}
const path = await loadCSVFile();
if (!path) {
return;
}
return dispatch(setAnalyticsFile(path));
};
return (
<Grid className={styles.container} item xs={3}>
<div className={styles.root}>
<Grid container direction="row" className={styles.gridTop}>
<Grid item className={styles.icon}>
{file ? (
<Tooltip title={`File loaded: ${file}`}>
<FileCopyIcon
className={
file
? classnames(styles.activeIcon, styles.iconSvg)
: styles.iconSvg
}
onClick={attachFile}
/>
</Tooltip>
) : (
<DoneIcon className={styles.iconSvg} onClick={attachFile} />
)}
</Grid>
<Grid item>
<Typography className={styles.welcome} variant="h6">
<span className={styles.bold}>{checkouts.length}</span>
</Typography>
<Typography variant="body1">
Total{' '}
{!checkouts.length || checkouts.length > 1
? 'Checkouts'
: 'Checkout'}
</Typography>
</Grid>
</Grid>
<Grid container direction="row" className={styles.gridBottom}>
<CheckoutsGrid checkouts={checkouts} />
</Grid>
</div>
</Grid>
);
};
export default CheckoutsComponent;
================================================
FILE: app/components/Analytics/components/expenses.tsx
================================================
/* eslint-disable no-console */
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import moment from 'moment';
import classNames from 'classnames';
import { groupBy } from 'lodash';
import ReactApexChart from 'react-apexcharts';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import { Typography, Grid, Select, MenuItem } from '@material-ui/core';
import { makeStyles } from '@material-ui/styles';
import { RootState } from '../../../store/reducers';
import {
EXPENSES_OPTIONS_LIGHT,
EXPENSES_OPTIONS_DARK,
VIEWS
} from '../../../constants';
import { makeExpensesView } from '../../Settings/selectors';
import { setField, SETTINGS_FIELDS } from '../../Settings/actions';
import { styles } from '../styles/expenses';
const useStyles = makeStyles(styles);
const group = (data: any) =>
groupBy(data, ({ date }) => moment(Number(date)).day());
const strip = (currency: string | number) =>
Number(currency?.toString().replace(/[^0-9.-]+/g, ''));
const buildData = (success: any[]) => {
const successData = group(success);
const data = [];
// loop over each day of the week...
for (let i = 0; i < 7; i += 1) {
if (successData[i]) {
data.push(
Number(
successData[i].reduce(
(prev, curr) => prev + strip(curr.amount || curr.product?.price),
0
)
).toFixed(2)
);
} else {
data.push(0);
}
}
return data;
};
const ExpensesComponent = () => {
const styles = useStyles();
const dispatch = useDispatch();
const expensesView = useSelector(makeExpensesView);
const theme = useSelector((state: RootState) => state.Theme);
const checkouts = useSelector((state: RootState) =>
state.Checkouts.filter((checkout: any) => checkout.success).filter(
(checkout: any) =>
moment(Number(checkout.date)).unix() >=
moment().subtract(expensesView, 'days').unix()
)
);
const total = checkouts.reduce(
(prev: any, curr: any) =>
prev + strip(curr?.amount || curr?.product?.price),
0
);
const seriesOptions =
theme === 0 ? EXPENSES_OPTIONS_LIGHT : EXPENSES_OPTIONS_DARK;
const series = [{ name: '', data: buildData(checkouts) }];
return (
<Grid className={styles.gridItem} item xs={6}>
<div className={styles.root}>
<Grid container direction="row" className={styles.colContainer}>
<Grid container direction="column" className={styles.firstCol}>
<Typography className={styles.header} variant="h6">
Money Spent
</Typography>
<Typography className={styles.subtext} variant="h6">
in USD
</Typography>
</Grid>
<Grid item className={styles.secondCol}>
<Typography className={styles.totalText} variant="h6">
${new Intl.NumberFormat('en-US').format(total)} Total
</Typography>
</Grid>
<Grid item className={styles.thirdCol}>
<Typography className={styles.subselect} variant="h6">
<Select
value={expensesView}
disableUnderline
onChange={(e: any) =>
dispatch(
setField(
SETTINGS_FIELDS.EXPENSES_VIEW,
e.target.value || ''
)
)
}
className={styles.selectPeriod}
SelectDisplayProps={{
style: {
paddingTop: 7,
fontWeight: 400
}
}}
inputProps={{
classes: {
icon: styles.dropdownIcon
}
}}
IconComponent={ExpandMoreIcon}
MenuProps={{
MenuListProps: {
classes: {
root: styles.menuList
}
},
anchorOrigin: {
vertical: 'bottom',
horizontal: 'left'
},
transformOrigin: {
vertical: 'top',
horizontal: 'left'
},
getContentAnchorEl: null
}}
>
<MenuItem value={VIEWS.Weekly} className={styles.menuItem}>
Last 7 Days
</MenuItem>
<MenuItem value={VIEWS.Monthly} className={styles.menuItem}>
Last 30 Days
</MenuItem>
<MenuItem value={VIEWS.Yearly} className={styles.menuItem}>
Last 365 Days
</MenuItem>
</Select>
</Typography>
</Grid>
</Grid>
<Grid
container
direction="row"
className={classNames(styles.colContainer, styles.chartContainer)}
>
<ReactApexChart
options={seriesOptions}
series={series}
type="bar"
width="400px"
height="150px"
/>
</Grid>
</div>
</Grid>
);
};
export default ExpensesComponent;
================================================
FILE: app/components/Analytics/components/news.tsx
================================================
import React from 'react';
import { useSelector } from 'react-redux';
import { sortBy } from 'lodash';
import moment from 'moment';
import { Typography, Grid } from '@material-ui/core';
import { makeStyles } from '@material-ui/styles';
import NoChildrenComponent from '../../NoChildrenComponent';
import { styles } from '../styles/news';
const typeColors: any = {
UPDATE: '#58D67D',
DROP: '#9389F9'
};
const messages: any = {
UPDATE: ' - Update - ',
DROP: ' - Drop - '
};
const useStyles = makeStyles(styles);
const NewsRow = ({
news: { date, type, message },
styles
}: {
news: any;
styles: any;
}) => {
return (
<Grid container direction="row" className={styles.newsItem}>
<Grid item className={styles.flexFirst}>
<div
className={styles.status}
style={{ backgroundColor: typeColors[type] }}
/>
<Typography className={styles.date} component="div" variant="body1">
{moment(Number(date)).format('MM/DD')}
</Typography>
<Typography
className={styles.messageBuffer}
component="div"
variant="body1"
>
{messages[type]}
</Typography>
<Typography className={styles.message} component="span" variant="body1">
{message}
</Typography>
</Grid>
</Grid>
);
};
const NewsGrid = () => {
const styles = useStyles();
const news = useSelector(({ News }: { News: any[] }) => News);
if (!news.length) {
return <NoChildrenComponent label="No News" variant="body1" />;
}
return (
<>
{sortBy(news, n => Number(n.date))
.reverse()
.map(n => (
<NewsRow key={n.id} news={n} styles={styles} />
))}
</>
);
};
const NewsComponent = () => {
const styles = useStyles();
return (
<Grid className={styles.gridItem} item xs={6}>
<div className={styles.root}>
<Grid container direction="row" className={styles.colContainer}>
<Grid item className={styles.firstCol}>
<Typography className={styles.header} variant="h6">
News
</Typography>
</Grid>
</Grid>
<Grid container direction="row" className={styles.gridBottom}>
<NewsGrid />
</Grid>
</div>
</Grid>
);
};
export default NewsComponent;
================================================
FILE: app/components/Analytics/components/orders.tsx
================================================
import React from 'react';
import { useSelector } from 'react-redux';
import { Typography, Grid } from '@material-ui/core';
import LocalShippingIcon from '@material-ui/icons/LocalShipping';
import { makeStyles } from '@material-ui/styles';
import NoChildrenComponent from '../../NoChildrenComponent';
import { imageForCard } from '../../../utils/imgForCardType';
import { styles } from '../styles/orders';
import { RootState } from '../../../store/reducers';
const useStyles = makeStyles(styles);
const OrderComponent = ({
order: { store, product, card },
styles
}: {
order: any;
styles: any;
}) => (
<Grid container direction="row" className={styles.tableRow}>
<Grid item className={styles.margin}>
<Typography className={styles.store} variant="body1" title={store}>
{store}
</Typography>
<Typography className={styles.product} variant="body1" title={product}>
{product}
</Typography>
<Typography className={styles.card} variant="body1">
<img alt="" src={imageForCard(card)} />
</Typography>
</Grid>
</Grid>
);
const OrdersGrid = ({ orders, styles }: { orders: any[]; styles: any }) => {
if (!orders.length) {
return <NoChildrenComponent label="No Orders" variant="body1" />;
}
return (
<div className={styles.table}>
{orders.map(order => (
<OrderComponent key={order.id} order={order} styles={styles} />
))}
</div>
);
};
const OrdersComponent = () => {
const styles = useStyles();
const orders = useSelector((state: RootState) =>
state.Checkouts.filter((checkout: any) => checkout.delivered)
);
return (
<Grid className={styles.container} item xs={3}>
<div className={styles.root}>
<Grid container direction="row" className={styles.gridTop}>
<Grid item className={styles.icon}>
<LocalShippingIcon className={styles.iconSvg} />
</Grid>
<Grid item>
<Typography className={styles.welcome} variant="h6">
<span className={styles.bold}>{orders.length}</span>
</Typography>
<Typography variant="body1">
{!orders.length || orders.length > 1 ? 'Orders' : 'Order'}{' '}
Received
</Typography>
</Grid>
</Grid>
<Grid container direction="row" className={styles.gridBottom}>
<OrdersGrid orders={orders} styles={styles} />
</Grid>
</div>
</Grid>
);
};
export default OrdersComponent;
================================================
FILE: app/components/Analytics/components/stats.tsx
================================================
/* eslint-disable no-restricted-syntax */
/* eslint-disable no-console */
import React, { useCallback } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import moment from 'moment';
import { groupBy } from 'lodash';
import ReactApexChart from 'react-apexcharts';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import { Typography, Grid, Select, MenuItem } from '@material-ui/core';
import { createSelector } from 'reselect';
import { makeStyles } from '@material-ui/styles';
import { RootState } from '../../../store/reducers';
import {
STATS_OPTIONS_LIGHT,
STATS_OPTIONS_DARK,
VIEWS
} from '../../../constants';
import { setField, SETTINGS_FIELDS } from '../../Settings/actions';
import { styles } from '../styles/stats';
const group = (data: any) =>
groupBy(data, ({ date }) => moment(Number(date)).startOf('day').unix());
const useStyles = makeStyles(styles);
const getCheckouts = (state: any) => state.Checkouts;
const getStatsView = (state: any) => state.Settings.statsView;
const getCheckoutsForStatsView = createSelector(
[getCheckouts, getStatsView],
(checkouts, statsView) => {
return checkouts.filter(
(checkout: any) =>
moment(Number(checkout.date)).unix() >=
moment().subtract(Number(statsView), 'days').unix()
);
}
);
const extractSuccessData = (success: any[], statsView: string) => {
const successData = Array.from(Array(Number(statsView)), () => 0);
for (const [time, checkouts] of Object.entries(group(success))) {
if (checkouts?.length) {
successData[daysFrom(now, Number(time)) - 1] = checkouts.length;
}
}
return successData.reverse();
};
const extractFailedData = (failed: any[], statsView: string) => {
const failedData = Array.from(Array(Number(statsView)), () => 0);
for (const [time, checkouts] of Object.entries(group(failed))) {
if (checkouts?.length) {
failedData[daysFrom(now, Number(time)) - 1] = checkouts.length;
}
}
return failedData.reverse();
};
const daysFrom = (start: number, end: number) =>
Math.ceil(
moment.duration(moment.unix(start).diff(moment.unix(end))).asDays()
);
const now = moment().unix();
const StatsComponent = () => {
const styles = useStyles();
const dispatch = useDispatch();
const theme = useSelector((state: RootState) => state.Theme);
const statsView = useSelector((state: RootState) => state.Settings.statsView);
const checkouts = useSelector(getCheckoutsForStatsView);
const failed = checkouts.filter((checkout: any) => !checkout.success);
const success = checkouts.filter((checkout: any) => checkout.success);
const successData = useCallback(extractSuccessData(success, statsView), [
success.length,
statsView
]);
const failedData = useCallback(extractFailedData(failed, statsView), [
failed.length,
statsView
]);
const seriesOptions = theme === 0 ? STATS_OPTIONS_LIGHT : STATS_OPTIONS_DARK;
const series = [
{
name: 'Success',
data: successData
},
{
name: 'Failed',
data: failedData
}
];
const _setStatsView = (option: string) => {
dispatch(setField(SETTINGS_FIELDS.STATS_VIEW, option));
};
return (
<Grid className={styles.gridItem} item xs={6}>
<div className={styles.root}>
<Grid container direction="row" className={styles.colContainer}>
<Grid item className={styles.firstCol}>
<Typography className={styles.header} variant="h6">
Checkout Statistics
</Typography>
</Grid>
<Grid item className={styles.thirdCol}>
<Typography className={styles.subselect} variant="h6">
<Select
value={statsView}
disableUnderline
onChange={({ target }: { target: any }) =>
_setStatsView(target.value)
}
className={styles.selectPeriod}
SelectDisplayProps={{
style: {
paddingTop: 7,
fontWeight: 400
}
}}
inputProps={{
classes: {
icon: styles.dropdownIcon
}
}}
IconComponent={ExpandMoreIcon}
MenuProps={{
MenuListProps: {
classes: {
root: styles.menuList
}
},
anchorOrigin: {
vertical: 'bottom',
horizontal: 'left'
},
transformOrigin: {
vertical: 'top',
horizontal: 'left'
},
getContentAnchorEl: null
}}
>
<MenuItem value={VIEWS.Weekly} className={styles.menuItem}>
Last 7 Days
</MenuItem>
<MenuItem value={VIEWS.Monthly} className={styles.menuItem}>
Last 30 Days
</MenuItem>
<MenuItem value={VIEWS.Yearly} className={styles.menuItem}>
Last 365 Days
</MenuItem>
</Select>
</Typography>
</Grid>
</Grid>
<Grid container direction="row" className={styles.colContainer}>
<ReactApexChart
options={seriesOptions}
series={series}
type="area"
height="170px"
width="407px"
/>
</Grid>
</div>
</Grid>
);
};
export default StatsComponent;
================================================
FILE: app/components/Analytics/components/welcome.tsx
================================================
import React from 'react';
import { PURGE } from 'redux-persist';
import { useSelector, useDispatch } from 'react-redux';
import { useSpring, animated } from 'react-spring';
import { Typography, Button, Grid } from '@material-ui/core';
import { useConfirm } from 'material-ui-confirm';
import { makeStyles } from '@material-ui/styles';
import { log } from '../../../utils/log';
import { quit } from '../../../utils/createWindows';
import { makeUser } from '../../App/selectors';
import { styles } from '../styles/welcome';
const useStyles = makeStyles(styles);
const AnimatedWelcomeText = () => {
const styles = useStyles();
const { name } = useSelector(makeUser);
const props = useSpring({
delay: 500,
opacity: 1,
from: { opacity: 0 },
config: { duration: 850 }
});
return (
<animated.div style={props}>
<Typography className={styles.welcome} variant="h4">
Welcome Back,
<span className={styles.bold}> {name}</span>
</Typography>
</animated.div>
);
};
const AnimatedActionButtons = () => {
const props = useSpring({
opacity: 1,
from: { opacity: 0 },
config: { duration: 850 }
});
const styles = useStyles();
const dispatch = useDispatch();
const confirm = useConfirm();
const deactivateHandler = async (e: any) => {
e.stopPropagation();
try {
await confirm({
title: `Are you sure you want to deactivate?`,
description:
'Your data will persist, but you will need to authenticate on next launch.',
confirmationText: 'Yes',
cancellationText: 'No',
dialogProps: {
classes: {
paper: styles.paperRoot
}
},
confirmationButtonProps: {
classes: {
root: styles.confirmBtn
},
style: {
width: 105,
height: 35,
background:
'linear-gradient(90deg, rgba(131,119,244,1) 0%, rgba(164,155,255,1) 100%)',
color: '#fff'
}
},
cancellationButtonProps: {
classes: {
root: styles.cancelBtn
},
style: {
width: 105,
height: 35
}
}
});
} catch (e) {
if (!e) {
return;
}
log.error(e, 'Welcome -> Deactivate');
}
};
const handleReset = async () => {
try {
await confirm({
title: `Are you sure you want to reset application data?`,
description: 'This action cannot be undone.',
confirmationText: 'Yes',
cancellationText: 'No',
dialogProps: {
classes: {
paper: styles.paperRoot
}
},
confirmationButtonProps: {
classes: {
root: styles.confirmBtn
},
style: {
width: 105,
height: 35,
background:
'linear-gradient(90deg, rgba(131,119,244,1) 0%, rgba(164,155,255,1) 100%)',
color: '#fff'
}
},
cancellationButtonProps: {
classes: {
root: styles.cancelBtn
},
style: {
width: 105,
height: 35
}
}
});
dispatch({
type: PURGE,
key: 'root',
result: () => null
});
setTimeout(() => quit(), 2500);
} catch (e) {
if (!e) {
return;
}
log.error(e, 'Tasks -> Reset All Data');
}
};
return (
<animated.div style={props}>
<Button
color="secondary"
onClick={deactivateHandler}
className={styles.unbindBtn}
>
Deactivate
</Button>
<Button
color="secondary"
onClick={handleReset}
className={styles.joinDiscordBtn}
>
Reset All Data
</Button>
</animated.div>
);
};
const WelcomeComponent = () => {
const styles = useStyles();
return (
<Grid className={styles.gridItem} item xs={6}>
<div className={styles.root}>
<div className={styles.background}>
<AnimatedWelcomeText />
<div className={styles.row}>
<AnimatedActionButtons />
</div>
</div>
</div>
</Grid>
);
};
export default WelcomeComponent;
================================================
FILE: app/components/Analytics/index.tsx
================================================
import React from 'react';
import { makeStyles } from '@material-ui/styles';
import { Grid } from '@material-ui/core';
import { styles } from './styles';
// first row
import WelcomeComponent from './components/welcome';
import CheckoutsComponent from './components/checkouts';
import OrrdersComponent from './components/orders';
// second row
import ExpensesComponent from './components/expenses';
const useStyles = makeStyles(styles);
const Analytics = () => {
const styles = useStyles();
return (
<div className={styles.root}>
<Grid className={styles.row} container>
<Grid container item xs={12} className={styles.grid}>
<WelcomeComponent />
<CheckoutsComponent />
<OrrdersComponent />
</Grid>
<Grid container item xs={12} className={styles.grid}>
<ExpensesComponent />
</Grid>
</Grid>
</div>
);
};
export default Analytics;
================================================
FILE: app/components/Analytics/reducers/checkouts.tsx
================================================
import { PURGE } from 'redux-persist';
import { checkoutActionTypes } from '../actions/checkouts';
type Action = {
type: string;
payload?: any;
};
export type Checkouts = [];
export const initialState: Checkouts = [];
export function Checkouts(state = initialState, action: Action) {
const { type, payload } = action;
switch (type) {
case PURGE:
return [...initialState];
case checkoutActionTypes.ADD: {
if (!payload) {
return state;
}
return payload;
}
default:
return state;
}
}
================================================
FILE: app/components/Analytics/reducers/index.tsx
================================================
import { Checkouts } from './checkouts';
import { News } from './news';
export { Checkouts, News };
================================================
FILE: app/components/Analytics/reducers/news.tsx
================================================
import { PURGE } from 'redux-persist';
import { newsActionTypes } from '../actions';
type Action = {
type: string;
payload?: any;
};
export type NewsObject = {};
export type News = NewsObject[];
export const newsInitialState: News = [];
export function News(state = newsInitialState, action: Action) {
const { type, payload } = action;
switch (type) {
case PURGE:
return [...newsInitialState];
case newsActionTypes.ADD: {
if (!payload) {
return state;
}
return payload;
}
default:
return state;
}
}
================================================
FILE: app/components/Analytics/styles/checkouts.tsx
================================================
import { variables, mixins } from '../../../styles/js';
export const styles = theme => {
return {
container: {
maxHeight: '100%'
},
cardType: {
filter: `contrast(${theme.palette.primary.contrast})`
},
root: {
backgroundColor: theme.palette.primary.secondary,
color: theme.palette.primary.color,
height: '100%',
margin: '0 10px',
flexGrow: 1,
padding: 0,
listStyle: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
flexDirection: 'column',
borderRadius: 8,
transition: theme.transitions.create(['background-color'], {
duration: 300
})
},
row: {
flexDirection: 'row'
},
table: {
display: 'table',
tableLayout: 'fixed',
width: '100%'
},
tableRow: {
display: 'table-row'
},
margin: {
width: '100%',
height: 24,
display: 'flex'
},
gridTop: {
marginBottom: 8
},
gridBottom: {
height: '100%',
overflowY: 'scroll',
marginBottom: 8,
'&::-webkit-scrollbar': {
display: 'none !important'
}
},
paperRoot: {
backgroundColor: theme.palette.primary.background,
color: theme.palette.primary.color
},
confirmBtn: {
width: 105,
height: 35,
background:
'linear-gradient(90deg, rgba(131,119,244,1) 0%, rgba(164,155,255,1) 100%)',
color: '#fff'
},
cancelBtn: {
width: 105,
height: 35,
background: theme.palette.primary.secondary,
color: theme.palette.primary.color,
'&:hover': {
opacity: 0.5,
background: theme.palette.primary.secondary,
color: theme.palette.primary.color
}
},
activeIcon: {
color: '#4BB543 !important',
transition: theme.transitions.create(['color'], {
duration: 300
}),
'&:hover': {
opacity: 0.5,
transition: theme.transitions.create(['color'], {
duration: 300
}),
color: '#B33A3A !important'
}
},
grid: {
width: `100%`
},
store: {
display: 'table-cell',
whiteSpace: 'nowrap',
alignSelf: 'center',
fontSize: 10,
margin: 'auto 8px auto 16px',
width: '20%',
overflow: 'hidden'
},
product: {
display: 'table-cell',
whiteSpace: 'nowrap',
alignSelf: 'center',
fontSize: 10,
margin: 'auto 8px',
width: '100%',
overflow: 'hidden'
},
card: {
display: 'table-cell',
alignSelf: 'center',
fontSize: 10,
margin: 'auto 8px'
},
icon: {
background: '#EEEDFC',
width: 40,
height: 40,
borderRadius: '50%',
margin: '16px 8px 0 8px'
},
iconSvg: {
display: 'block',
margin: 'auto',
marginTop: 8,
color: '#8377F4',
cursor: 'pointer'
},
bold: {
fontWeight: 700,
whiteSpace: 'pre'
},
welcome: {
color: theme.palette.primary.color,
display: 'flex',
justifyContent: 'flex-start',
alignSelf: 'flex-start',
marginTop: '8px'
}
};
};
================================================
FILE: app/components/Analytics/styles/expenses.tsx
================================================
import { variables, mixins } from '../../../styles/js';
export const styles = theme => {
return {
gridItem: {
height: '100%'
},
root: {
backgroundColor: theme.palette.primary.secondary,
color: theme.palette.primary.color,
height: '100%',
marginRight: 10,
flexGrow: 1,
padding: 0,
listStyle: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
flexDirection: 'column',
borderRadius: 8,
transition: theme.transitions.create(['background-color'], {
duration: 300
})
},
dropdownIcon: {
color: theme.palette.primary.color,
fontSize: 16,
marginTop: 4
},
menuList: {
fontSize: 10,
padding: 0,
backgroundColor: theme.palette.primary.background,
color: theme.palette.primary.color
},
chartContainer: {
width: '100%',
height: '200px',
position: 'relative'
},
row: {
flexDirection: 'row'
},
grid: {
width: `100%`
},
noPadding: {
padding: 0
},
bold: {
fontWeight: 700,
whiteSpace: 'pre'
},
colContainer: {
justifyContent: 'center',
textAlign: 'center'
},
firstCol: {
display: 'inline-flex',
flex: 1
},
secondCol: {
display: 'inline-flex',
justifyContent: 'center',
textAlign: 'center',
flex: 1
},
thirdCol: {
display: 'inline-flex',
textAlign: 'right',
alignSelf: 'flex-start',
flex: 1
},
header: {
display: 'flex',
justifyContent: 'flex-start',
alignSelf: 'flex-start',
marginTop: '8px',
marginLeft: '8px',
fontWeight: 500,
fontSize: '16px'
},
menuItem: {
padding: '4px 8px',
fontSize: 10,
textAlign: 'center'
},
subtext: {
display: 'flex',
justifyContent: 'flex-start',
alignSelf: 'flex-start',
marginLeft: '8px',
fontWeight: 400,
fontSize: '12px'
},
totalText: {
display: 'flex',
margin: '16px auto',
fontWeight: 700,
fontSize: '12px',
textAlign: 'center'
},
selectPeriod: {
minWidth: 83,
fontSize: 12,
padding: 0,
color: theme.palette.primary.color
},
subselect: {
display: 'flex',
color: theme.palette.primary.color,
margin: '5px 8px 0 auto',
fontWeight: 700,
fontSize: '12px',
textAlign: 'right'
}
};
};
================================================
FILE: app/components/Analytics/styles/index.tsx
================================================
import { variables, mixins } from '../../../styles/js';
export const styles = theme => {
return {
root: {
margin: 35,
marginTop: 75,
display: 'flex',
flexDirection: 'column',
width: '100%',
height: 'calc(100% - 100px)'
},
row: {
height: '100%'
},
grid: {
margin: '10px 10px 10px 0',
height: '30%'
}
};
};
================================================
FILE: app/components/Analytics/styles/news.tsx
================================================
import { variables, mixins } from '../../../styles/js';
export const styles = theme => {
return {
gridItem: {
height: '100%'
},
root: {
backgroundColor: theme.palette.primary.secondary,
color: theme.palette.primary.color,
height: '100%',
marginLeft: 10,
flexGrow: 1,
padding: 0,
listStyle: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
flexDirection: 'column',
borderRadius: 8,
transition: theme.transitions.create(['background-color'], {
duration: 300
})
},
row: {
flexDirection: 'row'
},
date: {
fontWeight: 700,
fontSize: 12,
display: 'inline-flex'
},
messageBuffer: {
fontWeight: 500,
fontSize: 12,
display: 'inline',
fontStyle: 'italic'
},
message: {
fontWeight: 500,
fontSize: 12,
display: 'inline',
wordWrap: 'break-word',
overflowWrap: 'break-word'
},
flexFirst: {
// margin: 'auto 0'
},
newsItem: {
margin: '4px 16px',
width: 'calc(100% - 32px)',
height: 'auto',
display: 'flex'
},
grid: {
width: `100%`
},
gridBottom: {
overflowY: 'scroll',
flexWrap: 'nowrap',
height: '100%',
display: 'flex',
margin: '8px 0',
flexDirection: 'column',
'&::-webkit-scrollbar': {
display: 'none !important'
}
},
status: {
height: 8,
width: 8,
margin: '0 8px 0 0',
display: 'inline-flex',
borderRadius: '50%'
},
bold: {
fontWeight: 700,
whiteSpace: 'pre'
},
colContainer: {
justifyContent: 'center',
textAlign: 'center'
},
firstCol: {
display: 'inline-flex',
flex: 1
},
header: {
display: 'flex',
justifyContent: 'flex-start',
alignSelf: 'flex-start',
marginTop: '8px',
marginLeft: '8px',
fontWeight: 500,
fontSize: '16px'
},
welcome: {
display: 'flex',
justifyContent: 'flex-start',
alignSelf: 'flex-start',
marginTop: '8px'
}
};
};
================================================
FILE: app/components/Analytics/styles/orders.tsx
================================================
import { variables, mixins } from '../../../styles/js';
export const styles = theme => {
return {
container: {
maxHeight: '100%'
},
root: {
backgroundColor: theme.palette.primary.secondary,
color: theme.palette.primary.color,
height: '100%',
marginLeft: 10,
flexGrow: 1,
padding: 0,
listStyle: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
flexDirection: 'column',
borderRadius: 8,
transition: theme.transitions.create(['background-color'], {
duration: 300
})
},
row: {
flexDirection: 'row'
},
table: {
display: 'table',
tableLayout: 'fixed',
width: '100%'
},
tableRow: {
display: 'table-row'
},
margin: {
width: '100%',
height: 24,
display: 'flex'
},
gridTop: {
marginBottom: 8
},
gridBottom: {
overflowY: 'scroll',
height: '100%',
marginBottom: 8,
'&::-webkit-scrollbar': {
display: 'none !important'
}
},
grid: {
width: `100%`
},
store: {
display: 'table-cell',
whiteSpace: 'nowrap',
alignSelf: 'center',
fontSize: 10,
margin: 'auto 8px auto 16px',
width: '20%',
overflow: 'hidden'
},
product: {
display: 'table-cell',
whiteSpace: 'nowrap',
alignSelf: 'center',
fontSize: 10,
margin: 'auto 8px',
width: '100%',
overflow: 'hidden'
},
card: {
display: 'table-cell',
alignSelf: 'center',
fontSize: 10,
margin: 'auto 8px'
},
icon: {
background: '#FFEDDC',
width: 40,
height: 40,
borderRadius: '50%',
margin: '16px 8px 0 8px'
},
iconSvg: {
display: 'block',
margin: 'auto',
marginTop: 8,
color: '#FFB15E'
},
bold: {
fontWeight: 700,
whiteSpace: 'pre'
},
welcome: {
display: 'flex',
justifyContent: 'flex-start',
alignSelf: 'flex-start',
marginTop: '8px'
}
};
};
================================================
FILE: app/components/Analytics/styles/shipments.tsx
================================================
import { variables, mixins } from '../../../styles/js';
export const styles = theme => {
return {
loadingSpinner: {
alignItems: 'center',
justifyContent: 'center',
marginLeft: '50%',
marginTop: '10%'
},
gridItem: {
height: '100%'
},
root: {
backgroundColor: theme.palette.primary.secondary,
color: theme.palette.primary.color,
height: '100%',
marginLeft: 10,
flexGrow: 1,
padding: 0,
listStyle: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
flexDirection: 'column',
borderRadius: 8,
transition: theme.transitions.create(['background-color'], {
duration: 300
})
},
hide: {
display: 'none'
},
row: {
flexDirection: 'row'
},
text: {
fontSize: 10,
textAlign: 'center',
color: theme.palette.primary.color,
margin: 'auto 0',
'& > *': {
textAlign: 'center'
}
},
addBtn: {
height: 21,
width: 21,
backgroundColor: '#8E83F4',
borderRadius: '50%',
color: '#fff',
fontSize: 10,
'&:hover': {
backgroundColor: 'rgba(142 ,131, 244, 0.555)'
}
},
searchRoot: {
border: `1px solid ${theme.palette.primary.border}`,
backgroundColor: theme.palette.primary.background,
boxShadow: 'none'
},
grid: {
width: `100%`
},
statusWaiting: {
backgroundColor: '#FFB15E',
borderRadius: '50%',
height: 8,
width: 8,
margin: '0 8px 0 0'
},
statusDelivered: {
backgroundColor: '#58d67d',
borderRadius: '50%',
height: 8,
width: 8,
margin: '0 8px 0 0'
},
statusPill: {
backgroundColor: '#FFB15E',
borderRadius: 11,
height: 17,
width: 90,
margin: '-5px 0 6px auto',
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center'
},
store: {
fontWeight: 700,
fontSize: 10,
margin: '0 0 4px 0'
},
ordered: {
lineHeight: 1.43,
fontWeight: 700,
fontSize: 8,
color: '#fff'
},
storeSubtext: {
textTransform: 'capitalize',
fontSize: 10
},
locationIcon: {
margin: 'auto',
height: 10,
width: 10,
marginRight: 4
},
locationText: {
fontSize: 10
},
gridBottom: {
overflowY: 'scroll',
height: '100%',
marginBottom: 8,
'&::-webkit-scrollbar': {
display: 'none !important'
}
},
searchContainer: {
display: 'flex',
flexDirection: 'column',
width: 'calc(100% - 32px)',
height: '100%'
},
shipmentItem: {
margin: '4px 16px',
width: '100%',
height: 45,
display: 'flex'
},
flexBottom: {
display: 'flex',
flexWrap: 'wrap'
},
firstCol: {
display: 'inline-flex',
flex: 1
},
flexFirst: {
margin: 'auto 0'
},
adjustML: {
marginLeft: '-15px !important'
},
flexEnd: {
margin: 'auto auto 5px auto',
display: 'flex',
flexWrap: 'wrap'
},
bold: {
fontWeight: 700,
whiteSpace: 'pre'
},
colContainer: {
justifyContent: 'center',
textAlign: 'center'
},
header: {
display: 'flex',
justifyContent: 'flex-start',
alignSelf: 'flex-start',
marginTop: '8px',
marginLeft: '8px',
fontWeight: 500,
fontSize: '16px'
},
welcome: {
display: 'flex',
justifyContent: 'flex-start',
alignSelf: 'flex-start',
marginTop: '8px'
}
};
};
================================================
FILE: app/components/Analytics/styles/stats.tsx
================================================
import { variables, mixins } from '../../../styles/js';
export const styles = theme => {
return {
gridItem: {
height: '100%'
},
root: {
backgroundColor: theme.palette.primary.secondary,
color: theme.palette.primary.color,
height: '100%',
marginRight: 10,
flexGrow: 1,
padding: 0,
listStyle: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
flexDirection: 'column',
borderRadius: 8,
transition: theme.transitions.create(['background-color'], {
duration: 300
})
},
dropdownIcon: {
color: theme.palette.primary.color,
fontSize: 16,
marginTop: 4
},
menuList: {
fontSize: 10,
padding: 0,
backgroundColor: theme.palette.primary.background,
color: theme.palette.primary.color
},
row: {
flexDirection: 'row'
},
grid: {
width: `100%`
},
menuItem: {
padding: '4px 8px',
fontSize: 10,
textAlign: 'center'
},
bold: {
fontWeight: 700,
whiteSpace: 'pre'
},
colContainer: {
width: '100%',
justifyContent: 'center',
textAlign: 'center'
},
firstCol: {
display: 'inline-flex',
flex: 1
},
secondCol: {
display: 'inline-flex',
justifyContent: 'center',
textAlign: 'center',
flex: 1
},
thirdCol: {
display: 'inline-flex',
justifyContent: 'center',
alignSelf: 'flex-start',
textAlign: 'right',
flex: 1
},
header: {
display: 'flex',
justifyContent: 'flex-start',
alignSelf: 'flex-start',
marginTop: '8px',
marginLeft: '8px',
fontWeight: 500,
fontSize: '16px'
},
subtext: {
display: 'flex',
justifyContent: 'flex-start',
alignSelf: 'flex-start',
marginLeft: '8px',
fontWeight: 400,
fontSize: '12px'
},
totalText: {
display: 'flex',
margin: '0 auto',
fontWeight: 700,
fontSize: '12px',
textAlign: 'center'
},
selectPeriod: {
minWidth: 83,
fontSize: 12,
padding: 0,
color: theme.palette.primary.color
},
subselect: {
display: 'flex',
margin: '5px 8px 0 auto',
fontWeight: 700,
fontSize: '12px',
textAlign: 'right'
}
};
};
================================================
FILE: app/components/Analytics/styles/welcome.tsx
================================================
import { mixins } from '../../../styles/js';
export const styles = theme => {
return {
gridItem: {
height: '100%'
},
root: {
background:
'linear-gradient(90deg, rgba(131,119,244,1) 0%, rgba(164,155,255,1) 100%)',
height: '100%',
marginRight: 10,
flexGrow: 1,
padding: 0,
listStyle: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
borderRadius: 8,
transition: theme.transitions.create(['background-color'], {
duration: 300
})
},
row: {
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
},
bold: {
fontWeight: 700,
whiteSpace: 'pre'
},
welcome: {
color: '#fff',
display: 'flex',
justifyContent: 'center',
alignSelf: 'center',
margin: '0 0 16px 0',
fontWeight: 300
},
paperRoot: {
backgroundColor: theme.palette.primary.background,
color: theme.palette.primary.color
},
confirmBtn: {
width: 105,
height: 35,
background:
'linear-gradient(90deg, rgba(131,119,244,1) 0%, rgba(164,155,255,1) 100%)',
color: '#fff'
},
cancelBtn: {
width: 105,
height: 35,
background: theme.palette.primary.secondary,
color: theme.palette.primary.color,
'&:hover': {
opacity: 0.5,
background: theme.palette.primary.secondary,
color: theme.palette.primary.color
}
},
unbindBtn: {
fontSize: '12px',
justifyContent: 'center',
alignSelf: 'center',
fontWeight: 400,
marginRight: '12px',
padding: '6px 16px',
transition: theme.transitions.create(['opacity'], { duration: 300 }),
...mixins().btnNegative
},
joinDiscordBtn: {
opacity: 0.5,
fontSize: '12px',
justifyContent: 'center',
alignSelf: 'center',
fontWeight: 400,
padding: '6px 16px',
transition: theme.transitions.create(['opacity'], { duration: 300 }),
...mixins().btnNegative
}
};
};
================================================
FILE: app/components/Analytics/types.tsx
================================================
/* eslint-disable camelcase */
// Generated by https://quicktype.io
export interface PackageAPIResponse {
id: string;
object: string;
mode: string;
tracking_code: string;
status: string;
created_at: string;
updated_at: string;
signed_by: null;
weight: null;
est_delivery_date: string;
shipment_id: null;
carrier: string;
public_url: string;
tracking_details: TrackingDetail[];
carrier_detail: null;
fees: Fee[];
}
export interface Fee {
object: string;
type: string;
amount: string;
charged: boolean;
refunded: boolean;
}
export interface TrackingDetail {
object: string;
message: string;
status: string;
datetime: string;
source: string;
tracking_location: TrackingLocation;
}
export interface TrackingLocation {
object: string;
city: string;
state: string;
country: null;
zip: string;
}
================================================
FILE: app/components/App/App.tsx
================================================
import React, { useEffect, useCallback } from 'react';
import { ipcRenderer } from 'electron';
import { CssBaseline } from '@material-ui/core';
import { ConfirmProvider } from 'material-ui-confirm';
import { makeStyles } from '@material-ui/styles';
import { log } from '../../utils/log';
import { styles } from './styles';
import ToolbarAreaPane from './components/toolbar/area';
import Titlebar from './components/titlebar/Titlebar';
import Sidebar from '../Sidebar/Sidebar';
import ErrorBoundary from '../ErrorBoundary';
import ClientRouter from '../../routing/ClientRouter';
import { bootLoader } from '../../utils/bootHelper';
import { IPCKeys } from '../../constants/ipc';
import { useProxiesStatus } from '../../hooks/useProxiesStatus';
import { useTaskStatus } from '../../hooks/useTaskStatus';
import { useAnalyticsFile } from '../../hooks/useAnalyticsFile';
import { useQuickTaskLifecycle } from '../../hooks/useQuickTaskLifecycle';
import { useTaskLifecycle } from '../../hooks/useTaskLifecycle';
import { useUpdateProxies } from '../../hooks/useUpdateProxies';
import { useUpdateStagger } from '../../hooks/useUpdateStagger';
import { useUpdateWebhooks } from '../../hooks/useUpdateWebhooks';
import { useUpdateProfiles } from '../../hooks/useUpdateProfiles';
import { useAutoSolveLifecycle } from '../../hooks/useAutoSolveLifecycle';
import { useAutoUpdaterLifecycle } from '../../hooks/useAutoUpdateLifecycle';
import { useNotificationLifecycle } from '../../hooks/useNotificationLifecycle';
const useStyles = makeStyles(styles);
const App = () => {
const styles = useStyles();
useProxiesStatus();
useTaskStatus();
useAnalyticsFile();
useQuickTaskLifecycle();
useTaskLifecycle();
useAutoSolveLifecycle();
useAutoUpdaterLifecycle();
useNotificationLifecycle();
useUpdateProxies();
useUpdateWebhooks();
useUpdateProfiles();
useUpdateStagger();
const setup = useCallback(() => {
try {
window.addEventListener('beforeunload', _cleanup);
ipcRenderer.setMaxListeners(Infinity);
bootLoader.cleanRotationFiles();
} catch (e) {
log.error(e, `App -> setup`);
}
}, []);
const _cleanup = useCallback(() => {
[...Object.values(IPCKeys)].map(key => ipcRenderer.removeAllListeners(key));
window.removeEventListener('beforeunload', _cleanup);
}, []);
useEffect(() => {
setup();
return () => {
_cleanup();
};
}, []);
return (
<div className={styles.root}>
<CssBaseline>
<ConfirmProvider
defaultOptions={{ confirmationButtonProps: { autoFocus: true } }}
>
<Titlebar />
<ErrorBoundary>
<ToolbarAreaPane showMenu />
<div className={styles.row}>
<Sidebar />
<ClientRouter />
</div>
</ErrorBoundary>
</ConfirmProvider>
</CssBaseline>
</div>
);
};
export default App;
================================================
FILE: app/components/App/Providers.tsx
================================================
/* eslint-disable react/no-children-prop */
import React, { useMemo } from 'react';
import { Provider, useSelector } from 'react-redux';
import {
StylesProvider,
ThemeProvider as MuiThemeProvider
} from '@material-ui/styles';
import CheckCircleIcon from '@material-ui/icons/CheckCircle';
import NotificationsIcon from '@material-ui/icons/Notifications';
import ErrorIcon from '@material-ui/icons/Error';
import HelpIcon from '@material-ui/icons/Help';
import CloseIcon from '@material-ui/icons/Close';
import { IconButton } from '@material-ui/core';
import { MuiPickersUtilsProvider } from '@material-ui/pickers';
import { ThemeProvider } from 'styled-components';
import { SnackbarProvider } from 'notistack';
import { createTheme } from '@material-ui/core/styles';
import { Store } from 'redux';
import MomentUtils from '@date-io/moment';
import { getNebulaFeatureFlags } from '../featureFlag/NebulaFeatureFlags';
import { FeatureFlagContext } from '../featureFlag/FeatureFlagContext';
import { light, dark } from './styles';
import { RootState } from '../../store/reducers';
const lightTheme = createTheme(light);
const darkTheme = createTheme(dark);
const getTheme = (type: number) => {
switch (type) {
case 0:
return lightTheme;
case 1:
return darkTheme;
default:
return lightTheme;
}
};
// this has access to redux slices
const ThemeInjector = ({ children }: { children: React.ReactNode }) => {
const theme = useSelector((state: RootState) => state.Theme);
const chosen = useMemo(() => getTheme(theme), [theme]);
const notistackRef = React.createRef();
const onClickDismiss = (key: string | number) => () => {
notistackRef.current.closeSnackbar(key);
};
return (
<StylesProvider injectFirst>
<ThemeProvider theme={chosen}>
<MuiThemeProvider theme={chosen}>
<SnackbarProvider
iconVariant={{
success: <CheckCircleIcon />,
error: <ErrorIcon />,
warning: <NotificationsIcon />,
info: <HelpIcon />
}}
disableWindowBlurListener
preventDuplicate
autoHideDuration={2500}
maxSnack={3}
ref={notistackRef}
action={key => (
<IconButton onClick={onClickDismiss(key)}>
<CloseIcon />
</IconButton>
)}
>
<MuiPickersUtilsProvider utils={MomentUtils}>
{children}
</MuiPickersUtilsProvider>
</SnackbarProvider>
</MuiThemeProvider>
</ThemeProvider>
</StylesProvider>
);
};
type Props = {
store: Store;
children: React.ReactNode;
};
const Providers = ({ store, children }: Props) => {
const features = useMemo(() => {
return getNebulaFeatureFlags();
}, []);
return (
<FeatureFlagContext.Provider value={features}>
<Provider store={store}>
<ThemeInjector children={children} />
</Provider>
</FeatureFlagContext.Provider>
);
};
export default Providers;
================================================
FILE: app/components/App/Root.tsx
================================================
import React from 'react';
import { PersistGate } from 'redux-persist/integration/react';
import { HashRouter } from 'react-router-dom';
import Providers from './Providers';
import App from './App';
type Props = {
store: any;
persistor: any;
};
const Root = ({ store, persistor }: Props) => {
return (
<Providers store={store}>
<PersistGate loading={null} persistor={persistor}>
<HashRouter>
<App />
</HashRouter>
</PersistGate>
</Providers>
);
};
export default Root;
================================================
FILE: app/components/App/__tests__/App.spec.tsx
================================================
import { render } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import React from 'react';
import App from '../App';
import { withProviders } from '../../../../test/testUtils';
const news = [
{
_id: '5e4e11261c9d440000d10758',
id: '277f561b-928a-40d1-af5b-dca9ea765e1c',
date: 1582174646797,
message:
'The time has finally come.. Close your eyes and take a deep breath. Now open them. Welcome to family. Welcome to Omega.',
type: 'UPDATE'
}
];
beforeEach(() => {
fetchMock.resetMocks();
});
it('render a checkbox and modify its values', async () => {
fetchMock.mockIf(/^https?:\/\/nebula-auth.herokuapp.com.*$/, async req => {
if (req.url.endsWith('/news')) {
return {
body: JSON.stringify(news)
};
}
if (req.url.endsWith('/checkouts')) {
return {
body: JSON.stringify([])
};
}
return {
status: 404,
body: 'Not Found'
};
});
const Root = withProviders({
Component: App
});
// eslint-disable-next-line
const { debug, getByTestId, getByText } = render(<Root />);
// debug();
expect(getByText('Dashboard')).toBeDefined();
});
================================================
FILE: app/components/App/__tests__/Root.spec.tsx
================================================
import { render } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import React from 'react';
import Root from '../Root';
import { configureStore, history } from '../../../store/configureStore';
const { store, persistor } = configureStore();
const news = [
{
_id: '5e4e11261c9d440000d10758',
id: '277f561b-928a-40d1-af5b-dca9ea765e1c',
date: 1582174646797,
message:
'The time has finally come.. Close your eyes and take a deep breath. Now open them. Welcome to family. Welcome to Omega.',
type: 'UPDATE'
}
];
beforeEach(() => {
fetchMock.resetMocks();
});
it('render a checkbox and modify its values', async () => {
fetchMock.mockIf(/^https?:\/\/nebula-auth.herokuapp.com.*$/, async req => {
if (req.url.endsWith('/news')) {
return {
body: JSON.stringify(news)
};
}
if (req.url.endsWith('/checkouts')) {
return {
body: JSON.stringify([])
};
}
return {
status: 404,
body: 'Not Found'
};
});
// eslint-disable-next-line
const { debug, getByTestId, getByText } = render(<Root store={store} history={history} persistor={persistor} />);
// debug();
expect(getByText('Dashboard')).toBeDefined();
});
================================================
FILE: app/components/App/actions.tsx
================================================
import prefixer from '../../utils/reducerPrefixer';
const appPrefix = '@@App';
const appActionTypesList = [
'REQ_LOAD',
'RES_LOAD',
'FAIL_LOAD',
'LOGOUT',
'SET_THEME',
'IMPORT_STATE'
];
export const globalActions = appActionTypesList.map(a => `${appPrefix}/${a}`);
export const globalActionTypes = prefixer(appPrefix, appActionTypesList);
export function setTheme(theme: number) {
return {
type: globalActionTypes.SET_THEME,
payload: theme
};
}
export function importAll(state: any) {
return {
type: globalActionTypes.IMPORT_STATE,
payload: state
};
}
export function reqLoadApp() {
return {
type: globalActionTypes.REQ_LOAD
};
}
export function resLoadApp() {
return {
type: globalActionTypes.RES_LOAD
};
}
export function failLoadApp(e: any) {
return {
type: globalActionTypes.FAIL_LOAD,
payload: {
error: e
}
};
}
const userPrefix = '@@User';
const userActionTypesList = ['SET_USER'];
export const userActions = userActionTypesList.map(a => `${userPrefix}/${a}`);
export const userActionTypes = prefixer(userPrefix, userActionTypesList);
export function setUser(user: any) {
return (dispatch: any) => {
dispatch({
type: userActionTypes.SET_USER,
payload: user
});
};
}
const storesPrefix = '@@Stores';
const storesActionTypesList = ['ADD_STORE', 'SET_STORES'];
export const storesActions = storesActionTypesList.map(
a => `${storesPrefix}/${a}`
);
export const storesActionTypes = prefixer(storesPrefix, storesActionTypesList);
export function addStore(newStore: any) {
return {
type: storesActionTypes.ADD_STORE,
payload: newStore
};
}
export function setStores(stores: any[]) {
return {
type: storesActionTypes.SET_STORES,
payload: stores
};
}
================================================
FILE: app/components/App/components/titlebar/Titlebar.tsx
================================================
import React from 'react';
import { makeStyles } from '@material-ui/styles';
import { useLocation } from 'react-router-dom';
import { styles } from '../../styles/Titlebar';
const useStyles = makeStyles(styles);
const Titlebar = () => {
const styles = useStyles();
const { pathname } = useLocation();
return /progressbar/i.test(pathname) ? null : <div className={styles.root} />;
};
export default Titlebar;
================================================
FILE: app/components/App/components/toolbar/area.tsx
================================================
import React from 'react';
import ToolbarBody from './body';
const ToolbarAreaPane = ({ ...parentProps }: any) => {
return <ToolbarBody {...parentProps} />;
};
export default ToolbarAreaPane;
================================================
FILE: app/components/App/components/toolbar/body.tsx
================================================
import React, { useState, useCallback } from 'react';
import { makeStyles } from '@material-ui/styles';
import { useLocation } from 'react-router-dom';
import { ClickAwayListener, AppBar, Toolbar, List } from '@material-ui/core';
import { styles } from '../../styles/ToolbarAreaPane';
import SettingsDialog from '../../../Settings';
import StateDialog from '../../../ImportExport';
import Profile from './profile';
import MenuItems from './menu';
const useStyles = makeStyles(styles);
const ToolbarAreaPane = () => {
const styles = useStyles();
const [anchorEl, setAnchorEl] = useState(null);
const [isSettingsOpen, setIsSettingsOpen] = useState<boolean>(false);
const [isStateOpen, setIsStateOpen] = useState<boolean>(false);
const { pathname } = useLocation();
const handleClick = useCallback(
(event: any) => {
if (anchorEl) {
setAnchorEl(null);
return;
}
setAnchorEl(event.currentTarget);
},
[anchorEl]
);
const handleClose = useCallback(() => {
setAnchorEl(null);
}, []);
const _handleToggleSettings = useCallback(() => {
setIsSettingsOpen(!isSettingsOpen);
handleClose();
}, [isSettingsOpen]);
const _handleToggleState = useCallback(() => {
setIsStateOpen(!isStateOpen);
handleClose();
}, [isStateOpen]);
// don't render the toolbar on the progress window or task group windows...
if (/progress|taskGroup/i.test(pathname)) {
return null;
}
return (
<ClickAwayListener onClickAway={handleClose}>
<div className={styles.root}>
<SettingsDialog
show={isSettingsOpen}
toggleSettings={_handleToggleSettings}
/>
<StateDialog show={isStateOpen} toggleState={_handleToggleState} />
<AppBar position="static" elevation={0} className={styles.appBar}>
<Toolbar className={styles.toolbar} disableGutters>
<div className={styles.toolbarInnerWrapper}>
<List>
<Profile handleClick={handleClick} />
<MenuItems
anchorEl={anchorEl}
handleClose={handleClose}
handleToggleState={_handleToggleState}
handleToggleSettings={_handleToggleSettings}
pathname={pathname}
/>
</List>
</div>
</Toolbar>
</AppBar>
</div>
</ClickAwayListener>
);
};
export default ToolbarAreaPane;
================================================
FILE: app/components/App/components/toolbar/menu.tsx
================================================
import React, { MouseEvent } from 'react';
import { Fade, Menu, MenuItem } from '@material-ui/core';
import { makeStyles } from '@material-ui/styles';
import { close, minimize, quit } from '../../../../utils/createWindows';
import { styles } from '../../styles/ToolbarAreaPane';
const useStyles = makeStyles(styles);
const _renderMenuItem = ({
className,
onClick,
label
}: {
className: string;
onClick: (event: MouseEvent<HTMLElement>) => void;
label: string;
}) => (
<MenuItem key={`menuItem--${label}`} className={className} onClick={onClick}>
{label}
</MenuItem>
);
const extractMenuItems = (
pathname: string,
toggleState: any,
toggleSettings: any,
styles: any
) => {
const action = /privacy|terms|bugs/i.test(pathname) ? close : quit;
if (/privacy|terms|bugs/i.test(pathname)) {
return (
<MenuItem className={styles.condensedMenuItem} onClick={action}>
Close
</MenuItem>
);
}
return [
{
className: styles.condensedMenuItem,
onClick: toggleState,
label: 'State'
},
{
className: styles.condensedMenuItem,
onClick: toggleSettings,
label: 'Settings'
},
{
className: styles.condensedMenuItem,
onClick: minimize,
label: 'Minimize'
},
{
className: styles.condensedMenuItem,
onClick: action,
label: 'Close'
}
].map(_renderMenuItem);
};
const ToolbarAreaPane = ({
anchorEl,
handleClose,
handleToggleState,
handleToggleSettings,
pathname
}: {
anchorEl: any;
handleClose: any;
handleToggleState: any;
handleToggleSettings: any;
pathname: string;
}) => {
const styles = useStyles();
const menuItems = extractMenuItems(
pathname,
handleToggleState,
handleToggleSettings,
styles
);
return (
<Menu
id="simple-menu"
className={styles.toolbarMenu}
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
TransitionComponent={Fade}
MenuListProps={{
classes: {
root: styles.menuList
}
}}
PaperProps={{
style: {
marginTop: 40,
padding: 0
}
}}
style={{
paddingTop: 0,
paddingBottom: 0
}}
>
{menuItems}
</Menu>
);
};
export default ToolbarAreaPane;
================================================
FILE: app/components/App/components/toolbar/profile.tsx
================================================
import React from 'react';
import { useSelector } from 'react-redux';
import classnames from 'classnames';
import { makeStyles } from '@material-ui/styles';
import {
Typography,
Badge,
ListItem,
ListItemText,
Avatar,
Tooltip
} from '@material-ui/core';
import { makeUser } from '../../selectors';
import { styles } from '../../styles/ToolbarAreaPane';
const useStyles = makeStyles(styles);
const ToolbarAreaPane = ({ handleClick }: { handleClick: any }) => {
const styles = useStyles();
const user = useSelector(makeUser);
let badgeStyle = styles.badge;
let displayName = '';
let subtext = '';
let avatarUrl = '';
let badgeTitle = '';
if (user) {
const { id, avatar, name, username, type } = user;
badgeTitle = type;
displayName = name;
subtext = username;
if (avatar) {
if (avatar.startsWith('a_')) {
avatarUrl = `https://cdn.discordapp.com/avatars/${id}/${avatar}.gif`;
} else {
avatarUrl = `https://cdn.discordapp.com/avatars/${id}/${avatar}.png`;
}
}
}
if (badgeTitle === 'Staff') {
badgeStyle = styles.badgeStaff;
}
if (badgeTitle === 'Renewal') {
badgeStyle = styles.badgeMember;
}
if (badgeTitle === 'Lifetime' || badgeTitle === 'F&F') {
badgeStyle = styles.badgeLifetime;
}
return (
<ListItem>
<ListItemText
className={classnames(styles.inline, styles.condenseRight)}
primary={
<Typography
variant="caption"
className={classnames(styles.inline, styles.bold)}
>
{displayName}
</Typography>
}
secondary={
<Typography
variant="caption"
className={classnames(styles.inline, styles.subtext)}
>
{subtext}
</Typography>
}
primaryTypographyProps={{
style: {
lineHeight: 1
}
}}
secondaryTypographyProps={{
style: {
lineHeight: 1
}
}}
/>
<Badge
variant="dot"
classes={{
badge: badgeStyle
}}
className={styles.noAppDrag}
badgeContent=" "
>
<Tooltip title={badgeTitle}>
<Avatar
src={avatarUrl}
onClick={handleClick}
classes={{
img: styles.noAppDrag
}}
className={classnames(styles.noAppDrag, styles.avatar)}
style={{ backgroundColor: 'transparent' }}
/>
</Tooltip>
</Badge>
</ListItem>
);
};
export default ToolbarAreaPane;
================================================
FILE: app/components/App/reducers.tsx
================================================
import { startCase } from 'lodash';
import { PURGE } from 'redux-persist';
import {
globalActionTypes,
userActionTypes,
storesActionTypes
} from './actions';
type Action = {
type: string;
payload?: any;
};
export type User = {
id: string;
username: string;
avatar: string;
name: string;
email: string;
status: string;
type: string;
createdAt: string;
updatedAt: string;
};
export const initialState: User = {
id: '',
username: '',
avatar: '',
name: '',
email: '',
status: '',
type: '',
createdAt: '',
updatedAt: ''
};
export type Theme = number;
export const initialThemeState: Theme = 0;
export function Theme(state = initialThemeState, action: Action) {
const { type, payload } = action;
switch (type) {
case PURGE:
return initialThemeState;
case globalActionTypes.SET_THEME:
return payload;
default:
return state;
}
}
export function User(state = initialState, action: Action) {
const { type, payload } = action;
switch (type) {
case PURGE:
return { ...initialState };
case userActionTypes.SET_USER:
return { ...payload };
default:
return state;
}
}
type Store = {
label: string;
supported: boolean;
value: string;
};
type Platform = {
options: Store[];
_id: string;
index: number;
label: string;
};
export type Stores = Platform[];
export const initialStoresState: Stores | [] = [];
export function Stores(state = initialStoresState, action: Action) {
const { type, payload } = action;
switch (type) {
case PURGE:
return [...initialStoresState];
case storesActionTypes.ADD_STORE: {
if (!payload) {
return state;
}
const { name, url } = payload;
if (!name || !url) {
return state;
}
const index = state.findIndex(({ label }) => label === 'Shopify');
if (index === -1) {
return state;
}
return [...state].map((platform, idx) => {
if (idx !== index) {
return platform;
}
if (platform.options.some(({ value }) => value === url)) {
return platform;
}
const newOptions = [
...platform.options,
{ label: startCase(name), supported: true, value: url }
].sort((a, b) => {
if (b.label < a.label) {
return 1;
}
if (b.label > a.label) {
return -1;
}
return 0;
});
return {
...platform,
options: [...newOptions]
};
});
}
case storesActionTypes.SET_STORES: {
if (payload) {
return [...payload];
}
return state;
}
default:
return state;
}
}
================================================
FILE: app/components/App/selectors.tsx
================================================
import { createSelector } from 'reselect';
import { RootState } from '../../store/reducers';
import { initialState, initialStoresState } from './reducers';
const selectUser = (state: RootState) => state.User;
const selectStores = (state: RootState) => state.Stores;
export const makeUser = createSelector(
selectUser,
state => state || initialState
);
export const makeStores = createSelector(
selectStores,
state => state || initialStoresState
);
================================================
FILE: app/components/App/styles/Titlebar.tsx
================================================
import { mixins } from '../../../styles/js';
export const styles = () => {
return {
root: {
width: `calc(100% - 110px)`,
height: 32,
position: `fixed`,
zIndex: 999,
...mixins().appDragEnable
}
};
};
================================================
FILE: app/components/App/styles/ToolbarAreaPane.tsx
================================================
import { variables, mixins } from '../../../styles/js';
export const styles = theme => {
return {
root: {
backgroundColor: `transparent !important`,
color: theme.palette.primary.color,
position: 'absolute',
width: 'auto',
marginRight: 20,
top: 0,
right: 0
},
dropdownIcon: {
color: theme.palette.primary.color,
fontSize: 16,
marginTop: 4
},
menuList: {
fontSize: 10,
padding: 0,
backgroundColor: theme.palette.primary.background,
color: theme.palette.primary.color
},
badge: {
top: 0,
right: 0,
height: 8,
width: 8,
color: 'white',
backgroundColor: '#D8D8D8'
},
badgeStaff: {
top: 0,
right: 0,
height: 8,
width: 8,
color: 'white',
backgroundColor: '#ff86ab'
},
badgeMember: {
top: 0,
right: 0,
height: 8,
width: 8,
color: 'white',
backgroundColor: '#a097fd'
},
badgeLifetime: {
top: 0,
right: 0,
height: 8,
width: 8,
color: 'white',
backgroundColor: '#29cf8a'
},
inline: {
display: 'flex',
color: theme.palette.primary.color,
flexDirection: 'column',
textAlign: 'right',
lineHeight: 1.25
},
bold: {
fontWeight: 500
},
grow: {
flexGrow: 1
},
subtext: {
fontSize: 10,
color: theme.palette.primary.subtext,
fontWeight: 300
},
toolbarInnerWrapper: {
display: 'flex',
margin: '0 0 0 auto',
padding: 0
},
toolbar: {
width: `auto`,
height: variables().sizes.toolbarHeight
},
appBar: {
backgroundColor: `transparent !important`,
margin: '16px 0 0 0'
},
navBtns: {
margin: 15
},
noAppDrag: {
...mixins().appDragDisable,
...mixins().noDrag
},
navBtnImgs: {
...mixins().noDrag,
...mixins().noselect,
height: 25,
width: `auto`,
'&:hover': {
backgroundColor: 'transparent !important'
}
},
disabledNavBtns: {},
toolbarMenu: {
padding: 0
},
condenseRight: {
paddingRight: 6.5,
height: '100%',
margin: 'auto 0'
},
avatar: {
cursor: 'pointer'
},
condensedMenuItem: {
display: 'flex !important',
justifyContent: 'center',
padding: '8px 4px !important',
fontSize: 12,
fontWeight: 400,
lineHeight: `0.5 !important`
}
};
};
================================================
FILE: app/components/App/styles/index.tsx
================================================
import { variables, mixins } from '../../../styles/js';
export const dark = {
props: {
MuiButtonBase: {
disableRipple: true
}
},
palette: {
primary: {
...variables().styles.darkPalette
},
secondary: {
...variables().styles.secondaryColor
}
},
typography: {
useNextVariants: true,
fontSize: variables().styles.regularFontSize,
fontFamily: [
'Roboto',
'-apple-system',
'BlinkMacSystemFont',
'"Segoe UI"',
'"Helvetica Neue"',
'Arial',
'sans-serif',
'"Apple Color Emoji"',
'"Segoe UI Emoji"',
'"Segoe UI Symbol"'
].join(',')
},
overrides: {
MuiPaper: {
root: {
backgroundColor: variables().styles.darkPalette.background
}
},
MuiTypography: {
root: {
color: variables().styles.darkPalette.color
}
},
MuiInputBase: {
root: {
color: variables().styles.darkPalette.color
},
inputMultiline: {
height: '100%'
}
},
MuiMobileStepper: {
root: {
background: variables().styles.darkPalette.background
}
},
MuiCheckbox: {
root: {
color: variables().styles.darkPalette.checkbox
}
},
MuiSwitch: {
track: {
backgroundColor: variables().styles.darkPalette.subtext
}
},
MuiDialog: {
paper: {
color: variables().styles.darkPalette.color,
backgroundColor: variables().styles.darkPalette.background
}
},
MuiDialogTitle: {
root: {
color: variables().styles.darkPalette.color
}
},
MuiDialogContentText: {
root: {
color: variables().styles.darkPalette.subtext
}
}
}
};
export const light = {
props: {
MuiButtonBase: {
disableRipple: true
}
},
palette: {
primary: {
...variables().styles.lightPalette
},
secondary: {
...variables().styles.secondaryColor
}
},
typography: {
useNextVariants: true,
fontSize: variables().styles.regularFontSize,
fontFamily: [
'Roboto',
'-apple-system',
'BlinkMacSystemFont',
'"Segoe UI"',
'"Helvetica Neue"',
'Arial',
'sans-serif',
'"Apple Color Emoji"',
'"Segoe UI Emoji"',
'"Segoe UI Symbol"'
].join(',')
},
overrides: {
MuiPaper: {
root: {
backgroundColor: variables().styles.lightPalette.background
}
},
MuiTypography: {
root: {
color: variables().styles.lightPalette.color
}
},
MuiInputBase: {
root: {
color: variables().styles.lightPalette.color
},
inputMultiline: {
height: '100%'
}
},
MuiMobileStepper: {
root: {
background: variables().styles.lightPalette.background
}
},
MuiCheckbox: {
root: {
color: variables().styles.lightPalette.checkbox
}
},
MuiSwitch: {
track: {
backgroundColor: variables().styles.lightPalette.subtext
}
},
MuiDialog: {
paper: {
color: variables().styles.lightPalette.color,
backgroundColor: variables().styles.lightPalette.background
}
},
MuiDialogTitle: {
root: {
color: variables().styles.lightPalette.color
}
},
MuiDialogContentText: {
root: {
color: variables().styles.lightPalette.subtext
}
}
}
};
export const styles = theme => {
return {
root: {
display: `flex`,
flexDirection: 'column',
height: `100%`,
background: theme.palette.primary.background
},
noAppDrag: {
...mixins().appDragDisable
},
navBtns: {
paddingLeft: 5
},
navBtnImgs: {
height: 25,
width: `auto`,
...mixins().noDrag,
...mixins().noselect
},
row: {
display: `flex`,
flexDirection: 'row',
height: `100%`
},
col: {
display: `flex`,
flexDirection: 'column',
small: {
flexGrow: 1
},
extend: {
flexGrow: 5
}
},
noProfileError: {
textAlign: `center`,
...mixins().center,
...mixins().absoluteCenter
},
props: {
MuiTypography: {
display: 'block'
}
}
};
};
================================================
FILE: app/components/Calendar/Calendar.tsx
================================================
import React, { useState } from 'react';
import { Text, Flex } from 'rebass';
import { Container } from './Container';
import ViewSelect, { CALENDAR_VIEW } from './ViewSelect';
import CalendarYear from './CalendarYear';
import CalendarMonth from './CalendarMonth';
const getCalendarView = view => {
const mapping = {
[CALENDAR_VIEW.YEAR]: CalendarYear,
[CALENDAR_VIEW.MONTH]: CalendarMonth
};
return view in mapping ? mapping[view] : CalendarYear;
};
const Calendar = () => {
const [view, setView] = useState({
label: 'month',
value: CALENDAR_VIEW.MONTH
});
const CalendarComponent = getCalendarView(view.value);
return (
<Container overflowY="auto">
<Flex mb="10px">
<Text ml="10px">Calendar</Text>
<ViewSelect
value={view}
onChange={value => setView(value)}
maxWidth="200px"
/>
</Flex>
<CalendarComponent />
</Container>
);
};
export default Calendar;
================================================
FILE: app/components/Calendar/CalendarMonth.tsx
================================================
import React from 'react';
import styled from 'styled-components';
import moment from 'moment';
import LeftIcon from '@material-ui/icons/ChevronLeft';
import RightIcon from '@material-ui/icons/ChevronRight';
import { Card } from '@material-ui/core';
import { space } from 'styled-system';
import { Text, Flex } from 'rebass';
import { getWeekday } from './Month';
const WeekdayGrid = styled.div`
font-weight: 500;
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-gap: 10px 5px;
${space}
`;
const DayGrid = styled.div`
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-gap: 10px 5px;
height: 100%;
& :first-child {
grid-column: ${props => props.firstWeekday};
}
${space}
`;
const DayCard = styled(Card)`
border-radius: 10px;
background-color: #fff;
`;
const MonthText = styled(Text)`
font-size: 24px;
font-weight: 700;
text-align: center;
color: #000;
`;
const YearText = styled(Text)`
font-size: 12px;
font-weight: 400;
text-align: center;
color: #616161;
`;
const today = moment();
const CalendarMonth = () => {
const month = moment().format('MMMM');
const year = moment().format('YYYY');
const weekdays = moment.weekdaysMin();
const firstWeekday = getWeekday(today);
const daysInMonth = today.daysInMonth();
const days = Array.from(Array(daysInMonth).keys()).map(i => i + 1);
return (
<>
<Flex justifyContent="center">
<Flex
flexDirection="column"
justifyContent="center"
alignItems="center"
>
<Flex>
<LeftIcon style={{ margin: 'auto 0', color: '#616161' }} />
<MonthText>{month}</MonthText>
<RightIcon style={{ margin: 'auto 0', color: '#616161' }} />
</Flex>
<YearText>{year}</YearText>
</Flex>
</Flex>
<WeekdayGrid mt="16px">
{weekdays.map(wk => (
<Text fontSize="12px" textAlign="center" key={wk}>
{wk.slice(0, 1)}
</Text>
))}
</WeekdayGrid>
<DayGrid firstWeekday={firstWeekday} mt="16px">
{days.map(d => (
<DayCard>
<Text fontSize="10px">{d}</Text>
</DayCard>
))}
</DayGrid>
</>
);
};
export default CalendarMonth;
================================================
FILE: app/components/Calendar/CalendarYear.tsx
================================================
import React from 'react';
import styled from 'styled-components';
import moment from 'moment';
import Month from './Month';
const AnnualGrid = styled.div`
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(4, 1fr);
grid-gap: 25px;
`;
const CalendarYear = () => {
const months = moment.months();
return (
<AnnualGrid>
{months.map((month, i) => (
<Month key={month} month={month} monthIndex={i} />
))}
</AnnualGrid>
);
};
export default CalendarYear;
================================================
FILE: app/components/Calendar/Container.tsx
================================================
import React from 'react';
import styled from 'styled-components';
import { layout } from 'styled-system';
export const Root = styled.div`
width: 100%;
margin: 35px;
margin-top: 55px;
display: flex;
flex-direction: column;
`;
export const Grid = styled.div`
height: 100%;
width: 100%;
`;
export const TableContainer = styled.div`
height: 100%;
&::-webkit-scrollbar: {
display: none;
}
${layout}
overflow-y: hidden;
`;
type Props = {
children: React.ReactNode;
};
export const Container = ({ children, ...rest }: Props) => {
return (
<Root>
<Grid>
<TableContainer {...rest}>{children}</TableContainer>
</Grid>
</Root>
);
};
================================================
FILE: app/components/Calendar/Month.tsx
================================================
import React from 'react';
import { Flex, Text } from 'rebass';
import { space } from 'styled-system';
import moment, { Moment } from 'moment';
import { Card as _Card } from '@material-ui/core';
import styled from 'styled-components';
const Card = styled(_Card)`
border-radius: 10px;
background-color: #fff;
line-height: 1.16;
`;
const DayGrid = styled.div`
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-gap: 10px 5px;
& :first-child {
grid-column: ${props => props.firstWeekday};
}
${space}
`;
export const getWeekday = (date: Moment) => {
const weekday = date.startOf('month').day() % 6;
if (weekday === 0) {
return 7;
}
return weekday;
};
type Props = {
month: string;
};
const Month = ({ month }: Props) => {
const year = moment().get('year');
const months = moment.months();
const monthIndex = months.findIndex(m => m === month);
const weekdays = moment.weekdaysMin();
const date = moment({
year,
month: monthIndex,
day: 1
});
const firstWeekday = getWeekday(date);
const daysInMonth = date.daysInMonth();
const days = Array.from(Array(daysInMonth).keys()).map(i => i + 1);
return (
<Card>
<Flex
mt="10px"
alignItems="center"
justifyContent="center"
flexDirection="column"
>
<Text fontSize="10px" fontWeight="bold">
{month}
</Text>
<Text fontSize="8px">{year}</Text>
</Flex>
<Flex flexDirection="column" ml="15px" mr="15px">
<DayGrid mt="16px">
{weekdays.map(wk => (
<Text fontSize="10px" key={wk}>
{wk.slice(0, 1)}
</Text>
))}
</DayGrid>
<DayGrid firstWeekday={firstWeekday} mt="16px">
{days.map(d => (
<Text fontSize="10px" key={d}>
{d}
</Text>
))}
</DayGrid>
</Flex>
</Card>
);
};
export default Month;
================================================
FILE: app/components/Calendar/ViewSelect.tsx
================================================
import React from 'react';
import WindowedSelect from 'react-windowed-select';
import styled from 'styled-components';
import { FormGroup as _FormGroup } from '@material-ui/core';
import { colorStyles, IndicatorSeparator } from '../../styles/select';
const FormGroup = styled(_FormGroup)`
flex: 1;
display: flex;
`;
export const CALENDAR_VIEW = {
YEAR: 'YEAR',
MONTH: 'MONTH'
};
type Option = {
label: string;
value: string;
};
type Props = {
value: Option;
onChange: (option: Option) => void;
};
const ViewSelect = ({ value, onChange, maxWidth }: Props) => {
const options = [
{
label: 'year',
value: CALENDAR_VIEW.YEAR
},
{
label: 'month',
value: CALENDAR_VIEW.MONTH
}
];
const style = {
...colorStyles(null),
input: styles => ({
...styles,
width: 'auto',
maxWidth,
color: '#000'
}),
control: styles => ({
...styles,
width: 'auto',
maxWidth,
border: '1px solid #979797',
height: 29,
fontSize: 12,
minHeight: 29,
borderRadius: 5,
outline: 'none',
cursor: 'pointer',
boxShadow: 'none',
':hover': {
border: '1px solid #979797',
cursor: 'pointer'
}
})
};
return (
<FormGroup>
<WindowedSelect
required
isClearable
menuPortalTarget={document.body}
menuPlacement="auto"
classNamePrefix="select"
placeholder="Select View"
components={{
IndicatorSeparator
}}
value={value}
options={options}
key="calendar--view"
styles={style}
onChange={onChange}
/>
</FormGroup>
);
};
export default ViewSelect;
================================================
FILE: app/components/Captchas/Harvesters.tsx
================================================
import React from 'react';
import { useDispatch } from 'react-redux';
import { makeStyles } from '@material-ui/styles';
import { Grid } from '@material-ui/core';
import ActionBar from './components/actionBar/ActionBar';
import { createCaptcha } from './actions';
import HarvesterGrid from './components/grid';
import { styles } from './styles';
const useStyles = makeStyles(styles);
const CaptchasPrimitive = () => {
const styles = useStyles();
const dispatch = useDispatch();
const handleCreate = () => dispatch(createCaptcha());
return (
<Grid container direction="row" className={styles.root}>
<ActionBar onCreate={handleCreate} />
<HarvesterGrid />
</Grid>
);
};
export default CaptchasPrimitive;
================================================
FILE: app/components/Captchas/Loadable.tsx
================================================
import Loadable from 'react-imported-component';
import LoadingIndicator from '../LoadingIndicator';
/* eslint import/no-cycle: [2, { maxDepth: 1 }] */
export default Loadable(() => import('./Harvesters'), {
LoadingComponent: LoadingIndicator
});
================================================
FILE: app/components/Captchas/__tests__/Harvesters.spec.tsx
================================================
import { render } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import React from 'react';
import Harvesters from '../Harvesters';
import { withProviders } from '../../../../test/testUtils';
it('should render Harvesters', async () => {
const Root = withProviders({
Component: Harvesters
});
// eslint-disable-next-line
const { debug, getByTestId, getByText } = render(<Root />);
// debug();
expect(getByText('No Harvesters')).toBeDefined();
});
================================================
FILE: app/components/Captchas/actions/captchas.tsx
================================================
import prefixer from '../../../utils/reducerPrefixer';
const prefix = '@@Captcha';
export const captchasActionList = ['DELETE', 'EDIT', 'CREATE', 'THEME'];
export const captchasActions = captchasActionList.map(a => `${prefix}/${a}`);
export const captchasActionTypes = prefixer(prefix, captchasActionList);
export const deleteCaptcha = captcha => {
return dispatch => {
dispatch({
type: captchasActionTypes.DELETE,
payload: captcha
});
};
};
export const createCaptcha = () => {
return dispatch => {
dispatch({
type: captchasActionTypes.CREATE
});
};
};
export const editCaptcha = ({ id, type, field, value }) => ({
type: captchasActionTypes.EDIT,
payload: {
id,
type,
field,
value
}
});
export const changeTheme = (theme = 1) => {
return dispatch => {
dispatch({
type: captchasActionTypes.THEME,
payload: theme
});
};
};
================================================
FILE: app/components/Captchas/actions/index.tsx
================================================
import {
createCaptcha,
editCaptcha,
deleteCaptcha,
captchasActionTypes,
captchasActionList,
captchasActions,
changeTheme
} from './captchas';
export const HARVESTER_TYPES = {
EDIT: 'EDIT'
};
export const HARVESTER_FIELDS = {
NAME: 'name',
STORE: 'store',
PROXY: 'proxy',
TOKEN: 'token',
TYPE: 'type'
};
export {
createCaptcha,
editCaptcha,
deleteCaptcha,
captchasActionList,
captchasActionTypes,
captchasActions,
changeTheme
};
================================================
FILE: app/components/Captchas/components/actionBar/ActionBar.tsx
================================================
import React from 'react';
import { makeStyles } from '@material-ui/styles';
import { Grid } from '@material-ui/core';
import Create from '@material-ui/icons/Add';
import { styles } from '../../styles/actionBar';
type Props = {
onCreate: () => void;
};
const useStyles = makeStyles(styles);
const ActionBarComponent = ({ onCreate }: Props) => {
const styles = useStyles();
return (
<Grid container direction="row" className={styles.root}>
<Grid item xs={12} className={styles.background}>
<Grid item xs={12} className={styles.alignCenter}>
<Grid item className={styles.center}>
<Create className={styles.actionIcon} onClick={onCreate} />
</Grid>
</Grid>
</Grid>
</Grid>
);
};
export default ActionBarComponent;
================================================
FILE: app/components/Captchas/components/card/index.tsx
================================================
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useConfirm } from 'material-ui-confirm';
import { ipcRenderer } from 'electron';
import {
Grid,
IconButton,
Fade,
FormGroup,
Input,
Select as MuiSelect,
Tooltip,
MenuItem
} from '@material-ui/core';
import { makeStyles } from '@material-ui/styles';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import LaunchIcon from '@material-ui/icons/Launch';
import DeleteIcon from '@material-ui/icons/Delete';
import YouTubeIcon from '@material-ui/icons/YouTube';
import LoadingIcon from '@material-ui/icons/Cancel';
import { log } from '../../../../utils/log';
import { styles } from '../../styles/card';
import {
editCaptcha,
deleteCaptcha,
HARVESTER_FIELDS,
HARVESTER_TYPES
} from '../../actions';
import { IPCKeys } from '../../../../constants/ipc';
import { HarvesterOptions, HarvesterTypes } from '../../../../constants';
import { RootState } from '../../../../store/reducers';
const useStyles = makeStyles(styles);
const buildMenuItems = () => {
const styles = useStyles();
const options = [...Object.keys(HarvesterOptions)];
return options.map(option => (
<MenuItem
key={option}
value={HarvesterOptions[option]}
className={styles.menuItem}
>
{option}
</MenuItem>
));
};
const CardComponent = ({ captcha }: { captcha: any }) => {
const styles = useStyles();
const dispatch = useDispatch();
const confirm = useConfirm();
const theme = useSelector((state: RootState) => state.Theme);
const [isLoadingYouTube, setLoadingYoutube] = useState<boolean>(false);
const [isLoadingHarvester, setLoadingHarvester] = useState<boolean>(false);
const editHandler = async (e: any, field: string) => {
dispatch(
editCaptcha({
id: captcha.id,
type: HARVESTER_TYPES.EDIT,
field,
value: e.target.value
})
);
};
const closeHandler = async (e: any) => {
e.stopPropagation();
try {
await confirm({
title: `Remove Harvester "${captcha.name}"?`,
description: 'This action cannot be undone.',
confirmationText: 'Yes',
cancellationText: 'No',
dialogProps: {
classes: {
paper: styles.paperRoot
}
},
confirmationButtonProps: {
classes: {
root: styles.confirmBtn
},
style: {
width: 105,
height: 35,
background:
'linear-gradient(90deg, rgba(131,119,244,1) 0%, rgba(164,155,255,1) 100%)',
color: '#fff'
}
},
cancellationButtonProps: {
classes: {
root: styles.cancelBtn
},
style: {
width: 105,
height: 35
}
}
});
ipcRenderer
.invoke(IPCKeys.CloseHarvesterWindows, { ...captcha })
.then(() => dispatch(deleteCaptcha(captcha)))
.catch(() => {
// TODO: Error handling
});
} catch (e) {
log.error(e, 'Harvesters -> Remove Harvester Cancelled');
}
};
const launchHarvesterHandler = () => {
if (!isLoadingHarvester && !isLoadingYouTube) {
setLoadingHarvester(true);
ipcRenderer
.invoke(IPCKeys.LaunchHarvester, { ...captcha, theme })
.then(() => setLoadingHarvester(false))
.catch(() => setLoadingHarvester(false));
}
};
const cancelLaunchHarvester = () => {
ipcRenderer
.invoke(IPCKeys.CancelLaunchHarvester, { ...captcha })
.then(() => setLoadingHarvester(false))
.catch(() => setLoadingHarvester(false));
};
const launchYouTubeHandler = () => {
if (!isLoadingYouTube && !isLoadingHarvester) {
setLoadingYoutube(true);
ipcRenderer
.invoke(IPCKeys.LaunchYoutube, { ...captcha })
.then(() => setLoadingYoutube(false))
.catch(() => setLoadingYoutube(false));
}
};
const cancelLaunchYouTube = () => {
ipcRenderer
.invoke(IPCKeys.CancelLaunchYouTube, { ...captcha })
.then(() => setLoadingYoutube(false))
.catch(() => setLoadingYoutube(false));
};
return (
<Grid key={captcha.id} item xs={4} md={4} lg={4} xl={4}>
<div className={styles.root}>
<Fade in>
<div className={styles.background}>
<Grid container className={styles.gridContainer} direction="row">
<Grid container direction="column" className={styles.textHolder}>
<Input
onChange={e => editHandler(e, HARVESTER_FIELDS.NAME)}
onBlur={() =>
ipcRenderer.send(IPCKeys.UpdateHarvester, {
...captcha,
theme
})
}
disableUnderline
value={captcha.name}
className={styles.cardHolder}
/>
</Grid>
</Grid>
<Grid container className={styles.gridContainerEnd} direction="row">
<FormGroup classes={{ root: styles.flexFillOne }}>
<MuiSelect
className={styles.input}
name="store"
placeholder="None"
disableUnderline
value={captcha.store}
onChange={e => editHandler(e, HARVESTER_FIELDS.STORE)}
defaultValue={HarvesterOptions.Shopify}
SelectDisplayProps={{
style: {
paddingTop: 7,
fontWeight: 400
}
}}
inputProps={{
classes: {
icon: styles.dropdownIcon
}
}}
IconComponent={ExpandMoreIcon}
MenuProps={{
MenuListProps: {
classes: {
root: styles.menuList
}
},
anchorOrigin: {
vertical: 'bottom',
horizontal: 'left'
},
transformOrigin: {
vertical: 'top',
horizontal: 'left'
},
getContentAnchorEl: null
}}
>
{buildMenuItems()}
</MuiSelect>
</FormGroup>
<FormGroup classes={{ root: styles.flexFillTwo }}>
<MuiSelect
className={styles.input}
name="number"
placeholder="Regular"
disableUnderline
value={captcha.type}
onChange={e => editHandler(e, HARVESTER_FIELDS.TYPE)}
defaultValue={HarvesterTypes.Checkout}
SelectDisplayProps={{
style: {
paddingTop: 7,
fontWeight: 400
}
}}
inputProps={{
classes: {
icon: styles.dropdownIcon
}
}}
IconComponent={ExpandMoreIcon}
MenuProps={{
MenuListProps: {
classes: {
root: styles.menuList
}
},
anchorOrigin: {
vertical: 'bottom',
horizontal: 'left'
},
transformOrigin: {
vertical: 'top',
horizontal: 'left'
},
getContentAnchorEl: null
}}
>
{captcha.store === HarvesterOptions.Shopify ? (
[
HarvesterTypes.Login,
HarvesterTypes.Checkout,
HarvesterTypes.Checkpoint
].map(option => (
<MenuItem
key={option}
value={option}
className={styles.menuItem}
>
{option}
</MenuItem>
))
) : (
<MenuItem
value={HarvesterTypes.Checkout}
className={styles.menuItem}
>
Checkout
</MenuItem>
)}
</MuiSelect>
</FormGroup>
</Grid>
<Grid container className={styles.gridContainerEnd} direction="row">
<Input
disableUnderline
placeholder="192.168.X.X"
className={styles.input}
value={captcha.proxy}
onChange={e => editHandler(e, HARVESTER_FIELDS.PROXY)}
onBlur={() =>
ipcRenderer.send(IPCKeys.UpdateHarvester, {
...captcha,
theme
})
}
/>
</Grid>
<Grid container className={styles.gridContainerEnd} direction="row">
{isLoadingYouTube ? (
<Tooltip title="Cancel">
<IconButton
className={styles.youtubeIconWrapper}
onClick={cancelLaunchYouTube}
>
<LoadingIcon className={styles.youtubeIcon} />
</IconButton>
</Tooltip>
) : (
<Tooltip title="Launch YouTube">
<IconButton
className={styles.youtubeIconWrapper}
disabled={isLoadingYouTube}
onClick={launchYouTubeHandler}
>
<YouTubeIcon className={styles.youtubeIcon} />
</IconButton>
</Tooltip>
)}
{isLoadingHarvester ? (
<Tooltip title="Cancel">
<IconButton
className={styles.youtubeIconWrapper}
onClick={cancelLaunchHarvester}
>
<LoadingIcon className={styles.youtubeIcon} />
</IconButton>
</Tooltip>
) : (
<Tooltip title="Launch Harvester">
<IconButton
className={styles.youtubeIconWrapper}
disabled={isLoadingHarvester}
onClick={launchHarvesterHandler}
>
<LaunchIcon className={styles.youtubeIcon} />
</IconButton>
</Tooltip>
)}
<Tooltip title="Delete Harvester">
<IconButton
className={styles.youtubeIconWrapper}
onClick={closeHandler}
>
<DeleteIcon className={styles.youtubeIcon} />
</IconButton>
</Tooltip>
</Grid>
</div>
</Fade>
</div>
</Grid>
);
};
export default CardComponent;
================================================
FILE: app/components/Captchas/components/grid/index.tsx
================================================
import React from 'react';
import { useSelector } from 'react-redux';
import NoChildrenComponent from '../../../NoChildrenComponent';
import { makeHarvesters } from '../../selectors';
import CardComponent from '../card';
const HarvestersGrid = () => {
const captchas = useSelector(makeHarvesters);
if (!captchas.length) {
return <NoChildrenComponent label="No Harvesters" variant="h6" />;
}
return captchas.map((captcha: any) => (
<CardComponent key={captcha.id} captcha={captcha} />
));
};
export default HarvestersGrid;
================================================
FILE: app/components/Captchas/reducers/captchas.tsx
================================================
import { ipcRenderer } from 'electron';
import uuidv4 from 'uuidv4';
import { PURGE } from 'redux-persist';
import { captchasActionTypes, HARVESTER_FIELDS } from '../actions';
import {
HarvesterOptions,
HarvesterTypes,
Platforms,
platformForStore
} from '../../../constants';
import { IPCKeys } from '../../../constants/ipc';
export const initialState: any[] = [];
type Action = {
type: string;
payload?: any;
};
export type Captchas = [];
export function Captchas(state = initialState, action: Action) {
const { type, payload } = action;
switch (type) {
case PURGE:
return [...initialState];
case captchasActionTypes.CREATE: {
let id: string;
const checker = (c: any) => c.id === id;
do {
id = uuidv4();
} while (state.some(checker));
const count = state.length + 1;
const harvester = {
id,
name: `Harvester ${count}`,
store: HarvesterOptions.Shopify,
platform: Platforms.Shopify,
type: HarvesterTypes.Checkout,
proxy: ''
};
return [...state, harvester];
}
case captchasActionTypes.EDIT: {
if (!payload || (payload && !payload.id)) {
return state;
}
const { id, field, value } = payload;
return state.map(captcha => {
if (captcha.id === id) {
if (field === HARVESTER_FIELDS.STORE) {
const platform = platformForStore(value);
if (platform !== Platforms.Shopify) {
return {
...captcha,
platform,
type: HarvesterTypes.Checkout,
[field]: value
};
}
return {
...captcha,
platform,
[field]: value
};
}
return {
...captcha,
[field]: value
};
}
return captcha;
});
}
case captchasActionTypes.THEME: {
return state.map(harvester => {
ipcRenderer.send(IPCKeys.UpdateTheme, {
theme: payload
});
return harvester;
});
}
case captchasActionTypes.DELETE:
if (payload) {
return state.filter(p => p.id !== payload.id);
}
return state;
default:
return state;
}
}
================================================
FILE: app/components/Captchas/reducers/index.tsx
================================================
import { Captchas } from './captchas';
export { Captchas };
================================================
FILE: app/components/Captchas/selectors.tsx
================================================
import { createSelector } from 'reselect';
import { Captchas } from './reducers';
import { RootState } from '../../store/reducers';
const selectCaptchas = (state: RootState) => state.Captchas;
export const makeHarvesters = createSelector(
selectCaptchas,
state => state || Captchas
);
================================================
FILE: app/components/Captchas/styles/actionBar.tsx
================================================
import { variables, mixins } from '../../../styles/js';
export const styles = theme => {
return {
root: {
justifyContent: 'center',
zIndex: 999
},
background: {
height: 40,
background:
'linear-gradient(90deg, rgba(131,119,244,1) 0%, rgba(164,155,255,1) 100%)',
boxShadow: '0px 4px 8px 0px rgba(0,0,0,0.25)',
borderRadius: '50%',
flexDirection: 'row',
display: 'flex',
position: 'absolute',
bottom: 24,
width: 40
},
alignCenter: {
alignSelf: 'center',
height: '100%'
},
center: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
height: '100%'
},
table: {
height: `calc(100% - 125px)`
},
actionIcon: {
cursor: 'pointer',
color: '#fff',
height: 24,
width: 24,
'&:hover': {
opacity: 0.5
}
},
paper: {
height: '100%',
display: 'flex',
flexDirection: 'column'
},
toolbar: {
paddingLeft: '64px',
paddingRight: '32px'
},
title: {
flex: '0 0 auto'
},
spacer: {
flex: '1 1 100%'
}
};
};
================================================
FILE: app/components/Captchas/styles/card.tsx
================================================
import { variables, mixins } from '../../../styles/js';
export const styles = theme => {
return {
root: {
margin: 10,
backgroundColor: theme.palette.primary.card,
height: 250,
flexGrow: 1,
padding: 0,
listStyle: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
borderRadius: 12,
transition: theme.transitions.create(['background-color'], {
duration: 300
}),
'&:hover': {
transition: theme.transitions.create(['background-color'], {
duration: 300
}),
backgroundColor: 'rgba(131,119,244,1)'
}
},
paperRoot: {
backgroundColor: theme.palette.primary.background,
color: theme.palette.primary.color
},
input: {
borderRadius: 5,
fontSize: 12,
paddingLeft: 8,
paddingRight: 8,
fontWeight: 400,
backgroundColor: theme.palette.primary.background,
color: theme.palette.primary.color,
border: `1px solid ${theme.palette.primary.border}`,
width: '100%'
},
inputShortOne: {
borderRadius: 5,
fontSize: 12,
paddingLeft: 8,
paddingRight: 8,
marginRight: 8,
fontWeight: 400,
backgroundColor: theme.palette.primary.background,
color: theme.palette.primary.color,
border: `1px solid ${theme.palette.primary.border}`,
width: '45%'
},
inputShortTwo: {
borderRadius: 5,
fontSize: 12,
paddingLeft: 8,
paddingRight: 8,
marginLeft: 8,
fontWeight: 400,
backgroundColor: theme.palette.primary.background,
color: theme.palette.primary.color,
border: `1px solid ${theme.palette.primary.border}`,
width: '45%'
},
dropdownIcon: {
color: theme.palette.primary.color,
fontSize: 16,
marginTop: 4,
marginRight: 4
},
confirmBtn: {
width: 105,
height: 35,
background:
'linear-gradient(90deg, rgba(131,119,244,1) 0%, rgba(164,155,255,1) 100%)',
color: '#fff'
},
menuList: {
fontSize: 10,
padding: 0,
backgroundColor: theme.palette.primary.background,
color: theme.palette.primary.color
},
menuItem: {
padding: '4px 8px',
fontSize: 10,
textAlign: 'center'
},
cancelBtn: {
width: 105,
height: 35,
background: theme.palette.primary.secondary,
color: theme.palette.primary.color,
'&:hover': {
opacity: 0.5,
background: theme.palette.primary.secondary,
color: theme.palette.primary.color
}
},
flexFillOne: {
flex: 1,
marginRight: 8
},
flexFillTwo: {
flex: 1,
marginLeft: 8
},
proxyInput: {
background: theme.palette.primary.background,
padding: '0 8px',
borderRadius: 4,
color: theme.palette.primary.color
},
background: {
height: '100%',
width: '100%'
},
gridContainer: {
margin: 24,
width: 'calc(100% - 48px)'
},
gridContainerMid: {
margin: '24px 24px 0 24px',
width: 'calc(100% - 48px)'
},
gridContainerEnd: {
margin: '0 24px 24px 24px',
width: 'calc(100% - 48px)',
justifyContent: 'space-around'
},
cardHolder: {
display: 'flex',
flex: 1,
color: '#fff',
fontSize: '1.5em',
fontWeight: 500,
'&:hover': {
opacity: 0.5,
cursor: 'pointer'
}
},
cardName: {
display: 'flex',
flex: 1,
color: '#fff',
fontSize: 14,
fontWeight: 400
},
textHolder: {
margin: '0 auto 0 0',
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis'
},
imgHolder: {
width: '20%',
margin: 'auto 0'
},
dots: {
display: 'flex',
color: '#fff',
fontSize: 16,
fontWeight: 400,
marginRight: 8
},
cardNumber: {
display: 'flex',
flex: 1,
color: '#fff',
fontSize: 16,
fontWeight: 400
},
actionIconWrapper: {
display: 'flex',
padding: 0,
alignSelf: 'flex-start',
'&:hover': {
background: 'transparent',
backgroundColor: 'transparent'
}
},
youtubeIconWrapper: {
display: 'flex',
padding: 0,
alignSelf: 'flex-start',
'&:hover': {
background: 'transparent',
backgroundColor: 'transparent'
}
},
cardTypeImg: {
height: 50,
width: 50,
objectFit: 'scale-down'
},
actionIcon: {
color: '#fff',
'&:hover': {
opacity: 0.5
}
},
youtubeIcon: {
color: '#fff',
'&:hover': {
opacity: 0.5
},
width: '1.5em',
height: '1.5em'
}
};
};
================================================
FILE: app/components/Captchas/styles/createDialog.tsx
================================================
import { variables } from '../../../styles/js';
export const styles = theme => ({
margin: {},
rootSm: {
width: 350,
height: 415,
backgroundColor: theme.palette.primary.background,
color: theme.palette.primary.color
},
fieldset: {
width: `45%`,
margin: '0 12px',
border: 0,
display: 'inline-flex',
padding: 0,
position: 'relative',
minWidth: 0,
flexDirection: 'column',
verticalAlign: 'top'
},
fieldsetFull: {
width: '100%'
},
dialogContent: {
margin: '16px 48px',
padding: 0
},
subtitle: {
fontSize: 12,
fontWeight: 500
},
fmSettingsStylesFix: {
marginTop: 10
},
formGroupOne: {
margin: '0 4px 16px 0',
flexWrap: 'nowrap',
display: 'inline-flex'
},
formGroupTwo: {
margin: '0 0 16px 4px',
flexWrap: 'nowrap',
display: 'inline-flex'
},
formGroup: {
margin: '0 0 16px 0'
},
formGroupCenter: {
margin: '8px 0 16px 0'
},
subheading: {
marginBottom: 5
},
title: {
color: theme.palette.primary.heading,
display: 'flex',
justifyContent: 'center',
margin: '24px 24px 16px 24px'
},
inputWrapper: {
margin: 0
},
input: {
borderRadius: 5,
fontSize: 12,
paddingLeft: 8,
paddingRight: 8,
fontWeight: 400,
backgroundColor: theme.palette.primary.secondary,
color: theme.palette.primary.color,
border: `1px solid ${theme.palette.primary.border}`,
width: '100%'
},
flexOne: {
flex: 2
},
flexNone: {
flex: 1
},
flex: {
display: 'flex'
},
block: {},
onBoardingPaper: {
position: `relative`,
padding: 10,
marginTop: 4,
backgroundColor: variables().styles.secondaryColor.background
},
onBoardingPaperArrow: {
fontWeight: `bold`,
content: ' ',
borderBottom: `11px solid ${variables().styles.secondaryColor.background}`,
borderLeft: '8px solid transparent',
borderRight: '8px solid transparent',
position: 'absolute',
top: -10,
left: 2
},
onBoardingPaperBody: {
color: variables().styles.primaryColor.background
},
a: {
fontWeight: `bold`
},
menuItem: {
padding: '4px 8px',
fontSize: 10,
textAlign: 'center'
},
stepper: {
maxWidth: 400,
flexGrow: 1
},
bar: {
backgroundColor: '#fff'
},
progressBar: {
backgroundColor: 'rgba(164,155,255, 0.333)',
color: '#d8d8d8'
},
stepperRoot: {
position: 'absolute',
bottom: 0,
width: '100%'
},
dropdownIcon: {
color: theme.palette.primary.color,
fontSize: 16,
marginTop: 4
},
menuList: {
fontSize: 10,
padding: 0,
backgroundColor: theme.palette.primary.background,
color: theme.palette.primary.color
},
btnStart: {
width: 105,
height: 35,
color: '#fff',
borderRadius: 4,
transition: theme.transitions.create(['opacity'], {
duration: 300
}),
background:
'linear-gradient(90deg, rgba(131,119,244,1) 0%, rgba(164,155,255,1) 100%)',
'&:hover': {
background:
'linear-gradient(90deg, rgba(131,119,244,1) 0%, rgba(164,155,255,1) 100%)',
opacity: 0.5,
transition: theme.transitions.create(['opacity'], {
duration: 300
})
},
'&:active': {
background:
'linear-gradient(90deg, rgba(131,119,244,1) 0%, rgba(164,155,255,1) 100%)',
opacity: 0.5,
transition: theme.transitions.create(['opacity'], {
duration: 300
})
}
},
btnEnd: {
width: 105,
height: 35,
color: theme.palette.primary.color,
backgroundColor: theme.palette.primary.secondary,
borderRadius: 4,
border: `1px solid ${theme.palette.primary.border}`,
transition: theme.transitions.create(['opacity'], {
duration: 300
}),
'&:hover': {
opacity: 0.5,
transition: theme.transitions.create(['opacity'], {
duration: 300
})
},
'&:active': {
opacity: 0.5,
transition: theme.transitions.create(['opacity'], {
duration: 300
})
}
}
});
================================================
FILE: app/components/Captchas/styles/index.tsx
================================================
import { variables, mixins } from '../../../styles/js';
export const styles = theme => {
return {
root: {
margin: 25,
marginTop: 75,
display: 'flex',
flexDirection: 'row',
alignContent: 'flex-start',
width: '100%',
height: 'calc(100% - 100px)',
overflow: 'scroll',
'&::-webkit-scrollbar': {
display: 'none'
}
}
};
};
================================================
FILE: app/components/DebouncedInput/DebouncedInput.tsx
================================================
import React, { useState } from 'react';
type Props = {
InputComponent: any;
isNumerical?: boolean;
properties: object;
text?: string;
updateText: (text: string) => void;
};
const DebouncedInput = (props: Props) => {
const {
InputComponent,
isNumerical,
properties,
updateText,
text: inputText
} = props;
const [typingTimeout, setTypingTimeout] = useState<any>(null);
const [text, setText] = useState<string>(inputText || '');
if (!inputText && text !== '' && !typingTimeout) {
setText('');
}
const handleTextChange = (e: any) => {
const { value } = e.target;
if (isNumerical) {
const re = /^[0-9\b]+$/;
if (value === '' || re.test(value.trim())) {
setText(value.trim());
clearTimeout(typingTimeout);
setTypingTimeout(
setTimeout(() => {
updateText(value.trim());
setTypingTimeout(null);
}, 500)
);
return;
}
}
setText(value);
clearTimeout(typingTimeout);
setTypingTimeout(
setTimeout(() => {
updateText(value.trim());
setTypingTimeout(null);
}, 500)
);
};
return (
<InputComponent {...properties} onChange={handleTextChange} value={text} />
);
};
DebouncedInput.defaultProps = {
isNumerical: false,
text: ''
};
export default DebouncedInput;
================================================
FILE: app/components/ErrorBoundary/components/GenerateErrorReport.tsx
================================================
import React, { Component } from 'react';
import { shell, ipcRenderer } from 'electron';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { withStyles } from '@material-ui/styles';
import { log } from '../../../utils/log';
import { styles } from '../styles/GenerateErrorReport';
import { promisifiedRimraf } from '../../../api/sys';
import { fileExistsSync } from '../../../api/sys/fileOps';
import { mailTo } from '../../../constants';
import { compressFile } from '../../../utils/gzip';
import GenerateErrorReportBody from './GenerateErrorReportBody';
import { IPCKeys } from '../../../constants/ipc';
class GenerateErrorReport extends Component {
compressLog = async () => {
try {
const { logFile, logFileZippedPath } = await ipcRenderer.invoke(
IPCKeys.GetLogPath
);
compressFile(logFile, logFileZippedPath);
} catch (e) {
log.error(e, `GenerateErrorReport -> compressLog`);
}
};
handleGenerateErrorLogs = async () => {
try {
const {
mailToInstructions,
logFileZippedPath
} = await ipcRenderer.invoke(IPCKeys.GetLogPath);
const { error } = await promisifiedRimraf(logFileZippedPath);
if (error) {
return null;
}
this.compressLog();
if (!fileExistsSync(logFileZippedPath)) {
return null;
}
if (window) {
window.location.href = `${mailTo} ${mailToInstructions}`;
}
shell.showItemInFolder(logFileZippedPath);
return true;
} catch (e) {
log.error(e, `GenerateErrorReport -> generateErrorLogs`);
return null;
}
};
render() {
const { classes: styles } = this.props;
return (
<GenerateErrorReportBody
styles={styles}
onGenerateErrorLogs={this.handleGenerateErrorLogs}
/>
);
}
}
const mapDispatchToProps = (dispatch, ownProps) =>
bindActionCreators({}, dispatch);
const mapStateToProps = (state, props) => {
return {};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withStyles(styles)(GenerateErrorReport));
================================================
FILE: app/components/ErrorBoundary/components/GenerateErrorReportBody.tsx
================================================
import React, { PureComponent } from 'react';
import { Button } from '@material-ui/core';
export default class GenerateErrorReportBody extends PureComponent {
render() {
const { styles, onGenerateErrorLogs } = this.props as any;
return (
<React.Fragment>
<Button
variant="outlined"
color="primary"
className={styles.btnStart}
onClick={onGenerateErrorLogs}
>
OPEN EMAIL CLIENT
</Button>
</React.Fragment>
);
}
}
================================================
FILE: app/components/ErrorBoundary/index.tsx
================================================
import React, { PureComponent } from 'react';
import { withRouter } from 'react-router-dom';
import { withStyles } from '@material-ui/styles';
import { Typography, Button } from '@material-ui/core';
import { ipcRenderer } from 'electron';
import { EOL } from 'os';
import { log } from '../../utils/log';
import { styles } from './styles';
import { imgsrc } from '../../utils/imgsrc';
import GenerateErrorReport from './components/GenerateErrorReport';
import { IPCKeys } from '../../constants/ipc';
class ErrorBoundary extends PureComponent {
state = {
errorInfo: null
};
componentDidCatch(error, errorInfo) {
this.setState({
errorInfo
});
const _errorInfo = JSON.stringify(errorInfo);
log.doLog(
`Error boundary log capture:${EOL}${error.toString()}${EOL}${_errorInfo}`,
true,
error
);
}
handleReload = async () => {
try {
const { history } = this.props;
history.push('/');
ipcRenderer.invoke(IPCKeys.GetCurrentWindow, 'reload');
} catch (e) {
log.error(e, `ErrorBoundary -> handleReload`);
}
};
render() {
const { classes: styles, children } = this.props;
const { errorInfo } = this.state;
if (errorInfo) {
return (
<div className={styles.root}>
<img
alt="Some Error Occured!"
src={imgsrc('logo.png', false)}
className={styles.bugImg}
/>
<Typography variant="h4" className={styles.headings}>
Uh oh!
</Typography>
<Typography variant="h5" className={styles.headings}>
Looks like we ran into an issue.
</Typography>
<Typography variant="subtitle1" className={styles.subHeading}>
Please send us the generated error log so that we can address this.
</Typography>
<GenerateErrorReport />
<Button
variant="outlined"
className={styles.btnEnd}
onClick={this.handleReload}
>
Return Home
</Button>
</div>
);
}
return children;
}
}
export default withRouter(withStyles(styles)(ErrorBoundary));
================================================
FILE: app/components/ErrorBoundary/styles/GenerateErrorReport.tsx
================================================
import { variables, mixins } from '../../../styles/js';
export const styles = theme => ({
subHeading: {
...mixins().noDrag,
...mixins().noselect,
marginTop: 15
},
instructions: {
listStyle: `none`,
color: variables().styles.textLightColor,
lineHeight: '24px',
marginTop: 15,
paddingLeft: 0,
marginBottom: 15
},
generateLogsBtn: {
marginTop: 15
},
emailIdWrapper: {
color: variables().styles.textLightColor,
marginTop: 15
},
emailId: {
fontWeight: `bold`
},
btnStart: {
marginTop: 15,
height: 35,
color: '#fff',
borderRadius: 4,
transition: theme.transitions.create(['opacity'], {
duration: 300
}),
background:
'linear-gradient(90deg, rgba(131,119,244,1) 0%, rgba(164,155,255,1) 100%)',
'&:hover': {
background:
'linear-gradient(90deg, rgba(131,119,244,1) 0%, rgba(164,155,255,1) 100%)',
opacity: 0.5,
transition: theme.transitions.create(['opacity'], {
duration: 300
})
},
'&:active': {
background:
'linear-gradient(90deg, rgba(131,119,244,1) 0%, rgba(164,155,255,1) 100%)',
opacity: 0.5,
transition: theme.transitions.create(['opacity'], {
duration: 300
})
}
}
});
================================================
FILE: app/components/ErrorBoundary/styles/index.tsx
================================================
import { variables, mixins } from '../../../styles/js';
export const styles = theme => ({
root: {
textAlign: `center`,
...mixins().center,
...mixins().absoluteCenter
},
bugImg: {
...mixins().noDrag,
height: `auto`,
borderRadius: '50%',
width: 150
},
headings: {
...mixins().noDrag,
...mixins().noselect,
marginTop: 15
},
subHeading: {
...mixins().noDrag,
...mixins().noselect,
marginTop: 15
},
goBackBtn: {
marginTop: 15,
marginLeft: 15
},
btnEnd: {
height: 35,
marginTop: 15,
marginLeft: 15,
color: theme.palette.primary.color,
backgroundColor: theme.palette.primary.secondary,
borderRadius: 4,
border: `1px solid ${theme.palette.primary.border}`,
transition: theme.transitions.create(['opacity'], {
duration: 300
}),
'&:hover': {
color: theme.palette.primary.color,
backgroundColor: theme.palette.primary.secondary,
border: `1px solid ${theme.palette.primary.border}`,
opacity: 0.5,
transition: theme.transitions.create(['opacity'], {
duration: 300
})
},
'&:active': {
color: theme.palette.primary.color,
backgroundColor: theme.palette.primary.secondary,
border: `1px solid ${theme.palette.primary.border}`,
opacity: 0.5,
transition: theme.transitions.create(['opacity'], {
duration: 300
})
}
}
});
================================================
FILE: app/components/ImportExport/components/dialog.tsx
================================================
/* eslint-disable @typescript-eslint/no-unused-vars */
import React from 'react';
import { useDispatch, useStore } from 'react-redux';
import classNames from 'classnames';
import { isEmpty } from 'lodash';
import { makeStyles } from '@material-ui/styles';
import {
Typography,
DialogContent,
FormControl,
FormGroup,
Fade,
Button,
Tooltip
} from '@material-ui/core';
import loadFile from '../../../utils/loadFile';
import saveFile from '../../../utils/saveFile';
import { importTasks } from '../../Tasks/actions';
import { importProfiles } from '../../Profiles/actions';
import { importAccounts } from '../../Settings/actions';
import { importAll } from '../../App/actions';
import { styles } from '../styles';
const onExport = ({ state }: { state: any }) => {
if (!state) {
return;
}
return saveFile(state);
};
const useStyles = makeStyles(styles);
const ImportExportDialogContent = () => {
const styles = useStyles();
const dispatch = useDispatch();
const store = useStore();
const state = store.getState();
const { Tasks, Profiles, Accounts } = state;
const { News, Checkouts, Stores, User, ...rest } = state;
const importHandler = async (type: string) => {
const { success, data } = await loadFile(type);
if (success) {
switch (type) {
case 'accounts':
return dispatch(importAccounts(data));
case 'profiles':
return dispatch(importProfiles(data));
case 'tasks':
return dispatch(importTasks(data));
case 'all':
return dispatch(importAll(data));
default:
break;
}
}
return null;
};
return (
<Fade in>
<DialogContent className={styles.dialog}>
<FormControl component="fieldset" className={styles.fieldset}>
<div className={styles.block}>
<FormGroup>
<Typography variant="subtitle2" className={styles.subtitle}>
Profiles
</Typography>
<div className={styles.flexRow}>
<Button
onClick={() => importHandler('profiles')}
color="primary"
className={classNames(
styles.btnPositive,
styles.fieldSetFirst,
styles.flexRow
)}
>
Import
</Button>
{Profiles.length ? (
<Button
onClick={() => onExport({ state: Profiles })}
color="primary"
className={classNames(
styles.btnWarning,
styles.fieldSetSecond,
styles.flexRow
)}
>
Export
</Button>
) : (
<Tooltip title="Please add some profiles in order to export">
<Button
onClick={() => {}}
color="primary"
className={classNames(
styles.btnWarning,
styles.fieldSetSecond,
styles.flexRow
)}
>
Export
</Button>
</Tooltip>
)}
</div>
</FormGroup>
</div>
</FormControl>
<FormControl component="fieldset" className={styles.fieldset}>
<div className={styles.block}>
<FormGroup className={styles.formGroup}>
<Typography variant="subtitle2" className={styles.subtitle}>
Accounts
</Typography>
<div className={styles.flexRow}>
<Button
onClick={() => importHandler('accounts')}
color="primary"
className={classNames(
styles.btnPositive,
styles.fieldSetFirst,
styles.flexRow
)}
>
Import
</Button>
{Accounts.length ? (
<Button
onClick={() => onExport({ state: Accounts })}
color="primary"
className={classNames(
styles.btnWarning,
styles.fieldSetSecond,
styles.flexRow
)}
>
Export
</Button>
) : (
<Tooltip title="Please add some accounts in order to export">
<Button
onClick={() => {}}
color="primary"
className={cla
gitextract_l8lb8z_d/
├── .eslintignore
├── .eslintrc.js
├── .gitattributes
├── .github/
│ └── ISSUE_TEMPLATE/
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── .prettierrc
├── .stylelintrc
├── app/
│ ├── 3ds.html
│ ├── Harvester.html
│ ├── Question.html
│ ├── __mocks__/
│ │ ├── dns.tsx
│ │ ├── electron-ga.tsx
│ │ ├── electron.tsx
│ │ ├── fileMock.tsx
│ │ ├── request-promise.tsx
│ │ └── styleMock.tsx
│ ├── api/
│ │ └── sys/
│ │ ├── fileOps.ts
│ │ └── index.ts
│ ├── app.html
│ ├── auth.html
│ ├── classes/
│ │ ├── AppUpdate.ts
│ │ ├── Boot.ts
│ │ ├── Notification.ts
│ │ ├── ProxyTester.ts
│ │ └── Storage.ts
│ ├── components/
│ │ ├── Analytics/
│ │ │ ├── Loadable.tsx
│ │ │ ├── __tests__/
│ │ │ │ └── Analytics.spec.tsx
│ │ │ ├── actions/
│ │ │ │ ├── checkouts.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── news.tsx
│ │ │ ├── components/
│ │ │ │ ├── checkouts.tsx
│ │ │ │ ├── expenses.tsx
│ │ │ │ ├── news.tsx
│ │ │ │ ├── orders.tsx
│ │ │ │ ├── stats.tsx
│ │ │ │ └── welcome.tsx
│ │ │ ├── index.tsx
│ │ │ ├── reducers/
│ │ │ │ ├── checkouts.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── news.tsx
│ │ │ ├── styles/
│ │ │ │ ├── checkouts.tsx
│ │ │ │ ├── expenses.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── news.tsx
│ │ │ │ ├── orders.tsx
│ │ │ │ ├── shipments.tsx
│ │ │ │ ├── stats.tsx
│ │ │ │ └── welcome.tsx
│ │ │ └── types.tsx
│ │ ├── App/
│ │ │ ├── App.tsx
│ │ │ ├── Providers.tsx
│ │ │ ├── Root.tsx
│ │ │ ├── __tests__/
│ │ │ │ ├── App.spec.tsx
│ │ │ │ └── Root.spec.tsx
│ │ │ ├── actions.tsx
│ │ │ ├── components/
│ │ │ │ ├── titlebar/
│ │ │ │ │ └── Titlebar.tsx
│ │ │ │ └── toolbar/
│ │ │ │ ├── area.tsx
│ │ │ │ ├── body.tsx
│ │ │ │ ├── menu.tsx
│ │ │ │ └── profile.tsx
│ │ │ ├── reducers.tsx
│ │ │ ├── selectors.tsx
│ │ │ └── styles/
│ │ │ ├── Titlebar.tsx
│ │ │ ├── ToolbarAreaPane.tsx
│ │ │ └── index.tsx
│ │ ├── Calendar/
│ │ │ ├── Calendar.tsx
│ │ │ ├── CalendarMonth.tsx
│ │ │ ├── CalendarYear.tsx
│ │ │ ├── Container.tsx
│ │ │ ├── Month.tsx
│ │ │ └── ViewSelect.tsx
│ │ ├── Captchas/
│ │ │ ├── Harvesters.tsx
│ │ │ ├── Loadable.tsx
│ │ │ ├── __tests__/
│ │ │ │ └── Harvesters.spec.tsx
│ │ │ ├── actions/
│ │ │ │ ├── captchas.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── components/
│ │ │ │ ├── actionBar/
│ │ │ │ │ └── ActionBar.tsx
│ │ │ │ ├── card/
│ │ │ │ │ └── index.tsx
│ │ │ │ └── grid/
│ │ │ │ └── index.tsx
│ │ │ ├── reducers/
│ │ │ │ ├── captchas.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── selectors.tsx
│ │ │ └── styles/
│ │ │ ├── actionBar.tsx
│ │ │ ├── card.tsx
│ │ │ ├── createDialog.tsx
│ │ │ └── index.tsx
│ │ ├── DebouncedInput/
│ │ │ └── DebouncedInput.tsx
│ │ ├── ErrorBoundary/
│ │ │ ├── components/
│ │ │ │ ├── GenerateErrorReport.tsx
│ │ │ │ └── GenerateErrorReportBody.tsx
│ │ │ ├── index.tsx
│ │ │ └── styles/
│ │ │ ├── GenerateErrorReport.tsx
│ │ │ └── index.tsx
│ │ ├── ImportExport/
│ │ │ ├── components/
│ │ │ │ └── dialog.tsx
│ │ │ ├── index.tsx
│ │ │ └── styles/
│ │ │ └── index.tsx
│ │ ├── Legal/
│ │ │ ├── PrivacyPolicy/
│ │ │ │ ├── Loadable.tsx
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── PrivacyPolicy.spec.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── styles/
│ │ │ │ └── index.tsx
│ │ │ └── TermsOfService/
│ │ │ ├── Loadable.tsx
│ │ │ ├── __tests__/
│ │ │ │ └── TermsOfService.spec.tsx
│ │ │ ├── index.tsx
│ │ │ └── styles/
│ │ │ └── index.tsx
│ │ ├── LoadingIndicator/
│ │ │ ├── index.tsx
│ │ │ └── styles/
│ │ │ └── index.tsx
│ │ ├── NoChildrenComponent/
│ │ │ ├── index.tsx
│ │ │ └── styles/
│ │ │ └── index.tsx
│ │ ├── Profiles/
│ │ │ ├── Loadable.tsx
│ │ │ ├── Profiles.tsx
│ │ │ ├── __tests__/
│ │ │ │ └── Profiles.spec.tsx
│ │ │ ├── actions/
│ │ │ │ ├── index.tsx
│ │ │ │ └── profiles.tsx
│ │ │ ├── components/
│ │ │ │ ├── actionBar/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── card/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── create/
│ │ │ │ │ ├── ProfileCreateDialog.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── ProfileCreateDialog.spec.tsx
│ │ │ │ │ ├── billing.tsx
│ │ │ │ │ ├── payment.tsx
│ │ │ │ │ └── shipping.tsx
│ │ │ │ └── grid/
│ │ │ │ └── index.tsx
│ │ │ ├── reducers/
│ │ │ │ ├── current.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── location.tsx
│ │ │ │ ├── payment.tsx
│ │ │ │ └── profiles.tsx
│ │ │ ├── selectors.tsx
│ │ │ └── styles/
│ │ │ ├── actionBar.tsx
│ │ │ ├── card.tsx
│ │ │ ├── createDialog.tsx
│ │ │ └── index.tsx
│ │ ├── Progressbar/
│ │ │ ├── Loadable.tsx
│ │ │ ├── index.tsx
│ │ │ └── styles/
│ │ │ └── index.tsx
│ │ ├── Proxies/
│ │ │ ├── Loadable.tsx
│ │ │ ├── Proxies.tsx
│ │ │ ├── __tests__/
│ │ │ │ └── Proxies.spec.tsx
│ │ │ ├── actions/
│ │ │ │ └── index.tsx
│ │ │ ├── components/
│ │ │ │ ├── ProxyActionBar.tsx
│ │ │ │ ├── ProxyCreateDialog.tsx
│ │ │ │ ├── Table/
│ │ │ │ │ ├── ProxyTable.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── tableHead.tsx
│ │ │ │ │ │ ├── tableRow.tsx
│ │ │ │ │ │ └── tableToolbar.tsx
│ │ │ │ │ └── styles/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── tableToolbar.tsx
│ │ │ │ └── __tests__/
│ │ │ │ └── ProxyCreateDialog.spec.tsx
│ │ │ ├── reducers/
│ │ │ │ ├── current.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── proxies.tsx
│ │ │ ├── selectors.tsx
│ │ │ └── styles/
│ │ │ ├── actionBar.tsx
│ │ │ ├── createDialog.tsx
│ │ │ └── index.tsx
│ │ ├── ReportBugs/
│ │ │ ├── Loadable.tsx
│ │ │ ├── __tests__/
│ │ │ │ └── ReportBugs.spec.tsx
│ │ │ ├── index.tsx
│ │ │ └── styles/
│ │ │ └── index.tsx
│ │ ├── Settings/
│ │ │ ├── actions.tsx
│ │ │ ├── components/
│ │ │ │ └── dialog/
│ │ │ │ ├── ProductField.tsx
│ │ │ │ ├── ProfileField.tsx
│ │ │ │ ├── StoreField.tsx
│ │ │ │ ├── accounts.tsx
│ │ │ │ ├── defaults.tsx
│ │ │ │ ├── generics.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── rates.tsx
│ │ │ │ └── webhooks.tsx
│ │ │ ├── index.tsx
│ │ │ ├── reducers/
│ │ │ │ ├── accounts.tsx
│ │ │ │ ├── currentAccount.tsx
│ │ │ │ ├── currentWebhook.tsx
│ │ │ │ ├── defaults.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── rates.ts
│ │ │ │ ├── settings.tsx
│ │ │ │ └── webhooks.tsx
│ │ │ ├── selectors.tsx
│ │ │ └── styles/
│ │ │ └── index.tsx
│ │ ├── Sidebar/
│ │ │ ├── Sidebar.tsx
│ │ │ ├── __tests__/
│ │ │ │ └── Sidebar.spec.tsx
│ │ │ ├── components/
│ │ │ │ ├── AnimatedLogo.tsx
│ │ │ │ ├── icons.tsx
│ │ │ │ └── menuItems.tsx
│ │ │ └── styles/
│ │ │ └── index.tsx
│ │ ├── Tasks/
│ │ │ ├── Loadable.tsx
│ │ │ ├── Tasks.tsx
│ │ │ ├── __tests__/
│ │ │ │ └── Tasks.spec.tsx
│ │ │ ├── actions/
│ │ │ │ └── index.tsx
│ │ │ ├── components/
│ │ │ │ ├── Table/
│ │ │ │ │ ├── TableData.tsx
│ │ │ │ │ ├── TableWrapper.tsx
│ │ │ │ │ ├── TaskList.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── TableBodyWrapper.tsx
│ │ │ │ │ │ ├── TableHeader.tsx
│ │ │ │ │ │ ├── cells/
│ │ │ │ │ │ │ ├── checkbox.tsx
│ │ │ │ │ │ │ ├── product.tsx
│ │ │ │ │ │ │ ├── profile.tsx
│ │ │ │ │ │ │ ├── proxies.tsx
│ │ │ │ │ │ │ ├── sizes.tsx
│ │ │ │ │ │ │ ├── status.tsx
│ │ │ │ │ │ │ ├── store.tsx
│ │ │ │ │ │ │ └── taskId.tsx
│ │ │ │ │ │ ├── header/
│ │ │ │ │ │ │ ├── checkbox.tsx
│ │ │ │ │ │ │ ├── product.tsx
│ │ │ │ │ │ │ ├── profile.tsx
│ │ │ │ │ │ │ ├── proxies.tsx
│ │ │ │ │ │ │ ├── sizes.tsx
│ │ │ │ │ │ │ ├── status.tsx
│ │ │ │ │ │ │ ├── store.tsx
│ │ │ │ │ │ │ └── taskId.tsx
│ │ │ │ │ │ ├── icons.tsx
│ │ │ │ │ │ ├── tableRow.tsx
│ │ │ │ │ │ ├── tableToolbar.tsx
│ │ │ │ │ │ └── toolbar/
│ │ │ │ │ │ ├── clock.tsx
│ │ │ │ │ │ ├── filter.tsx
│ │ │ │ │ │ ├── groups.tsx
│ │ │ │ │ │ ├── monitor.tsx
│ │ │ │ │ │ ├── retry.tsx
│ │ │ │ │ │ └── stagger.tsx
│ │ │ │ │ └── styles/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── tableToolbar.tsx
│ │ │ │ ├── actionBar/
│ │ │ │ │ ├── actionBar.tsx
│ │ │ │ │ ├── copyBtn.tsx
│ │ │ │ │ ├── createBtn.tsx
│ │ │ │ │ ├── deleteBtn.tsx
│ │ │ │ │ ├── editBtn.tsx
│ │ │ │ │ ├── startBtn.tsx
│ │ │ │ │ └── stopBtn.tsx
│ │ │ │ ├── create/
│ │ │ │ │ ├── AccountField.tsx
│ │ │ │ │ ├── CaptchaField.tsx
│ │ │ │ │ ├── CategoryField.tsx
│ │ │ │ │ ├── CheckoutDelayField.tsx
│ │ │ │ │ ├── DateField.tsx
│ │ │ │ │ ├── DiscountField.tsx
│ │ │ │ │ ├── FootsiteForm.tsx
│ │ │ │ │ ├── MaxPriceField.tsx
│ │ │ │ │ ├── MinPriceField.tsx
│ │ │ │ │ ├── MockToggle.tsx
│ │ │ │ │ ├── NumberOfTasksField.tsx
│ │ │ │ │ ├── OneCheckout.tsx
│ │ │ │ │ ├── PasswordField.tsx
│ │ │ │ │ ├── PayPalField.tsx
│ │ │ │ │ ├── PokemonForm.tsx
│ │ │ │ │ ├── ProductField.tsx
│ │ │ │ │ ├── ProfileField.tsx
│ │ │ │ │ ├── ProxiesField.tsx
│ │ │ │ │ ├── QuantityField.tsx
│ │ │ │ │ ├── RatesField.tsx
│ │ │ │ │ ├── RestockMode.tsx
│ │ │ │ │ ├── SecureBypassField.tsx
│ │ │ │ │ ├── ShopifyForm.tsx
│ │ │ │ │ ├── SizesField.tsx
│ │ │ │ │ ├── StoreField.tsx
│ │ │ │ │ ├── StyleIdField.tsx
│ │ │ │ │ ├── SupremeForm.tsx
│ │ │ │ │ ├── TaskCreateDialog.tsx
│ │ │ │ │ ├── TaskForm.tsx
│ │ │ │ │ ├── TaskModeField.tsx
│ │ │ │ │ ├── UseRotateProxies.tsx
│ │ │ │ │ ├── VariationField.tsx
│ │ │ │ │ ├── YeezySupplyForm.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── TaskCreateDialog.spec.tsx
│ │ │ │ │ ├── clearBtn.tsx
│ │ │ │ │ ├── closeBtn.tsx
│ │ │ │ │ └── createBtn.tsx
│ │ │ │ └── edits/
│ │ │ │ └── TaskEditDialog.tsx
│ │ │ ├── reducers/
│ │ │ │ ├── current.tsx
│ │ │ │ ├── delays.tsx
│ │ │ │ ├── edits.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── tasks.tsx
│ │ │ ├── selectors.tsx
│ │ │ ├── styles/
│ │ │ │ ├── actionBar.tsx
│ │ │ │ ├── createDialog.tsx
│ │ │ │ └── index.tsx
│ │ │ └── useTaskKeyPress.tsx
│ │ ├── featureFlag/
│ │ │ ├── FeatureFlagContext.tsx
│ │ │ └── NebulaFeatureFlags.ts
│ │ └── ui/
│ │ ├── Select.tsx
│ │ └── table/
│ │ ├── IndeterminateCheckbox.tsx
│ │ ├── RenderRow.tsx
│ │ ├── RowTable.tsx
│ │ ├── Table.tsx
│ │ ├── TableCell.tsx
│ │ └── TableVirtualized.tsx
│ ├── constants/
│ │ ├── countries.json
│ │ ├── env.js
│ │ ├── index.ts
│ │ ├── ipc.ts
│ │ ├── meta.js
│ │ ├── regexes.js
│ │ └── sizes.js
│ ├── hooks/
│ │ ├── useAnalyticsFile.tsx
│ │ ├── useAutoSolveLifecycle.tsx
│ │ ├── useAutoUpdateLifecycle.tsx
│ │ ├── useEscape.tsx
│ │ ├── useInterval.ts
│ │ ├── useNotificationLifecycle.tsx
│ │ ├── useProxiesStatus.tsx
│ │ ├── useQuickTaskLifecycle.tsx
│ │ ├── useTaskLifecycle.tsx
│ │ ├── useTaskStatus.tsx
│ │ ├── useTraceUpdate.ts
│ │ ├── useUpdateProfiles.tsx
│ │ ├── useUpdateProxies.tsx
│ │ ├── useUpdateStagger.tsx
│ │ ├── useUpdateWebhooks.tsx
│ │ └── useWhyDidYouUpdate.ts
│ ├── index.tsx
│ ├── main.dev.ts
│ ├── mainWindow/
│ │ └── windows.ts
│ ├── menu.ts
│ ├── routing/
│ │ ├── ClientRouter.ts
│ │ └── routes.ts
│ ├── store/
│ │ ├── configureStore/
│ │ │ ├── dev.ts
│ │ │ ├── index.ts
│ │ │ └── prod.ts
│ │ ├── migrations.ts
│ │ └── reducers.ts
│ ├── styles/
│ │ ├── js/
│ │ │ ├── index.tsx
│ │ │ ├── mixins.tsx
│ │ │ ├── themes.ts
│ │ │ └── variables.tsx
│ │ ├── scss/
│ │ │ ├── app.global.scss
│ │ │ ├── base/
│ │ │ │ ├── _base.scss
│ │ │ │ ├── _extends.scss
│ │ │ │ ├── _mixins.scss
│ │ │ │ ├── _variables.scss
│ │ │ │ └── mixins/
│ │ │ │ ├── _align-items.scss
│ │ │ │ ├── _animate-link.scss
│ │ │ │ ├── _animations.scss
│ │ │ │ ├── _backface-visibility.scss
│ │ │ │ ├── _background-cover.scss
│ │ │ │ ├── _border.scss
│ │ │ │ ├── _box-model.scss
│ │ │ │ ├── _box-shadow.scss
│ │ │ │ ├── _breakpoint.scss
│ │ │ │ ├── _clearfix.scss
│ │ │ │ ├── _display.scss
│ │ │ │ ├── _display_flex.scss
│ │ │ │ ├── _flex.scss
│ │ │ │ ├── _hide-text.scss
│ │ │ │ ├── _horz-vert-center.scss
│ │ │ │ ├── _hover-focus.scss
│ │ │ │ ├── _inline-block.scss
│ │ │ │ ├── _inner-shadow.scss
│ │ │ │ ├── _keyframes.scss
│ │ │ │ ├── _linear-gradient-angle.scss
│ │ │ │ ├── _linear-gradient.scss
│ │ │ │ ├── _margin-auto.scss
│ │ │ │ ├── _mediumFont.scss
│ │ │ │ ├── _min-breakpoint.scss
│ │ │ │ ├── _opacity.scss
│ │ │ │ ├── _placeholder.scss
│ │ │ │ ├── _rem.scss
│ │ │ │ ├── _replace-text.scss
│ │ │ │ ├── _retina.scss
│ │ │ │ ├── _rounded-corners.scss
│ │ │ │ ├── _single-transform.scss
│ │ │ │ ├── _text-shadow.scss
│ │ │ │ ├── _transform.scss
│ │ │ │ ├── _transitions.scss
│ │ │ │ ├── _translate.scss
│ │ │ │ └── _triangles.scss
│ │ │ └── themes/
│ │ │ ├── fonts.scss
│ │ │ └── reset.scss
│ │ └── select.tsx
│ ├── tasks/
│ │ ├── common/
│ │ │ ├── classes/
│ │ │ │ ├── index.ts
│ │ │ │ ├── monitor.ts
│ │ │ │ └── task.ts
│ │ │ ├── constants/
│ │ │ │ └── index.ts
│ │ │ ├── contexts/
│ │ │ │ ├── footsite.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── pokemon.ts
│ │ │ │ ├── shopify.ts
│ │ │ │ └── yeezysupply.ts
│ │ │ ├── index.ts
│ │ │ └── utils/
│ │ │ ├── index.ts
│ │ │ ├── logger.ts
│ │ │ ├── queues.ts
│ │ │ ├── request.ts
│ │ │ ├── rfrl.ts
│ │ │ └── timer.ts
│ │ ├── footsites/
│ │ │ ├── classes/
│ │ │ │ ├── functions/
│ │ │ │ │ ├── billing.ts
│ │ │ │ │ ├── captcha.ts
│ │ │ │ │ ├── cart.ts
│ │ │ │ │ ├── checkout.ts
│ │ │ │ │ ├── email.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── information.ts
│ │ │ │ │ ├── queue.ts
│ │ │ │ │ ├── session.ts
│ │ │ │ │ ├── shipping.ts
│ │ │ │ │ └── stock.ts
│ │ │ │ ├── tasks/
│ │ │ │ │ ├── base.ts
│ │ │ │ │ └── index.ts
│ │ │ │ └── types/
│ │ │ │ ├── datadome.d.ts
│ │ │ │ ├── geetest.d.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── stock.d.ts
│ │ │ │ └── variant.d.ts
│ │ │ ├── constants/
│ │ │ │ └── index.ts
│ │ │ ├── index.ts
│ │ │ ├── mocks/
│ │ │ │ ├── addToCart.ts
│ │ │ │ ├── cookies/
│ │ │ │ │ ├── champs.js
│ │ │ │ │ ├── cookies.ts
│ │ │ │ │ ├── eb.js
│ │ │ │ │ ├── fa.js
│ │ │ │ │ ├── ftl-ca.js
│ │ │ │ │ ├── ftl-kids.js
│ │ │ │ │ └── ftl-us.js
│ │ │ │ ├── getProductInfo.ts
│ │ │ │ ├── getProductPage.ts
│ │ │ │ ├── getSession.ts
│ │ │ │ ├── getStock.ts
│ │ │ │ ├── submitCheckout.ts
│ │ │ │ └── submitInformation.ts
│ │ │ └── utils/
│ │ │ ├── __tests__/
│ │ │ │ └── pickVariant.test.ts
│ │ │ ├── cleanseHeaderData.ts
│ │ │ ├── dfValues.ts
│ │ │ ├── forms.ts
│ │ │ ├── index.ts
│ │ │ └── pickVariant.ts
│ │ ├── index.ts
│ │ ├── managers/
│ │ │ ├── analytics.ts
│ │ │ ├── browser/
│ │ │ │ └── index.ts
│ │ │ ├── cache/
│ │ │ │ ├── cache.ts
│ │ │ │ └── windows.ts
│ │ │ ├── captcha/
│ │ │ │ ├── autoSolve.ts
│ │ │ │ ├── captcha.ts
│ │ │ │ ├── windows.ts
│ │ │ │ └── youtube.ts
│ │ │ ├── checkout.ts
│ │ │ ├── checkpoint/
│ │ │ │ └── index.tsx
│ │ │ ├── geetest/
│ │ │ │ └── index.ts
│ │ │ ├── index.ts
│ │ │ ├── interception/
│ │ │ │ ├── index.ts
│ │ │ │ └── window.ts
│ │ │ ├── notification.ts
│ │ │ ├── profile/
│ │ │ │ ├── profile.ts
│ │ │ │ └── typings.d.ts
│ │ │ ├── proxy.ts
│ │ │ ├── queue/
│ │ │ │ └── index.ts
│ │ │ ├── restart.ts
│ │ │ ├── tasks/
│ │ │ │ ├── choose.ts
│ │ │ │ └── index.ts
│ │ │ ├── typings.d.ts
│ │ │ ├── utils.ts
│ │ │ └── webhook/
│ │ │ ├── aycd.ts
│ │ │ ├── discord.ts
│ │ │ ├── index.ts
│ │ │ └── slack.ts
│ │ ├── pokemon/
│ │ │ ├── classes/
│ │ │ │ ├── functions/
│ │ │ │ │ ├── captcha.ts
│ │ │ │ │ ├── cart.ts
│ │ │ │ │ ├── checkout.ts
│ │ │ │ │ ├── datadome.ts
│ │ │ │ │ ├── email.ts
│ │ │ │ │ ├── encrypt.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── information.ts
│ │ │ │ │ ├── payment.ts
│ │ │ │ │ ├── product.ts
│ │ │ │ │ └── session.ts
│ │ │ │ └── tasks/
│ │ │ │ ├── base.ts
│ │ │ │ └── index.ts
│ │ │ ├── constants/
│ │ │ │ └── index.ts
│ │ │ ├── index.ts
│ │ │ ├── types/
│ │ │ │ ├── cart.d.ts
│ │ │ │ ├── checkout.d.ts
│ │ │ │ ├── datadome.d.ts
│ │ │ │ ├── geetest.d.ts
│ │ │ │ ├── index.d.ts
│ │ │ │ ├── information.d.ts
│ │ │ │ ├── key.d.ts
│ │ │ │ ├── order.d.ts
│ │ │ │ ├── payment.d.ts
│ │ │ │ ├── product.d.ts
│ │ │ │ ├── products.d.ts
│ │ │ │ ├── success.d.ts
│ │ │ │ └── token.d.ts
│ │ │ └── utils/
│ │ │ ├── cards.ts
│ │ │ ├── decode.ts
│ │ │ ├── encrypt.ts
│ │ │ ├── forms.ts
│ │ │ ├── index.ts
│ │ │ └── pickVariant.ts
│ │ ├── shopify/
│ │ │ ├── classes/
│ │ │ │ ├── functions/
│ │ │ │ │ ├── account.ts
│ │ │ │ │ ├── cart.ts
│ │ │ │ │ ├── challenge.ts
│ │ │ │ │ ├── checkout.ts
│ │ │ │ │ ├── checkpoint.ts
│ │ │ │ │ ├── config.ts
│ │ │ │ │ ├── customer.ts
│ │ │ │ │ ├── discount.ts
│ │ │ │ │ ├── homepage.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── order.ts
│ │ │ │ │ ├── password.ts
│ │ │ │ │ ├── payment.ts
│ │ │ │ │ ├── paypal.ts
│ │ │ │ │ ├── product.ts
│ │ │ │ │ ├── queue.ts
│ │ │ │ │ ├── review.ts
│ │ │ │ │ ├── session.ts
│ │ │ │ │ └── shipping.ts
│ │ │ │ ├── monitor.ts
│ │ │ │ ├── rates.ts
│ │ │ │ └── tasks/
│ │ │ │ ├── base.ts
│ │ │ │ ├── fast.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── pfutile.ts
│ │ │ │ ├── preload.ts
│ │ │ │ └── safe.ts
│ │ │ ├── constants/
│ │ │ │ ├── gateways.ts
│ │ │ │ └── index.ts
│ │ │ ├── index.ts
│ │ │ ├── mocks/
│ │ │ │ ├── __cookies__.ts
│ │ │ │ ├── apiCheckouts.tsx
│ │ │ │ ├── checkout.ts
│ │ │ │ ├── deadstockQuestion.ts
│ │ │ │ ├── kithMock.tsx
│ │ │ │ ├── paymentsConfig.ts
│ │ │ │ ├── responseTypes.ts
│ │ │ │ └── sessions.ts
│ │ │ ├── types/
│ │ │ │ ├── cart.d.ts
│ │ │ │ ├── index.d.ts
│ │ │ │ ├── product.d.ts
│ │ │ │ └── rates.d.ts
│ │ │ └── utils/
│ │ │ ├── __tests__/
│ │ │ │ └── pickVariant.test.ts
│ │ │ ├── forms.ts
│ │ │ ├── index.ts
│ │ │ ├── mocks/
│ │ │ │ └── kithNewBalance.ts
│ │ │ ├── parse.ts
│ │ │ ├── pickVariant.ts
│ │ │ └── protection.ts
│ │ └── yeezysupply/
│ │ ├── classes/
│ │ │ ├── functions/
│ │ │ │ ├── 3ds.ts
│ │ │ │ ├── akamai.ts
│ │ │ │ ├── bloom.ts
│ │ │ │ ├── cart.ts
│ │ │ │ ├── checkout.ts
│ │ │ │ ├── homepage.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── information.ts
│ │ │ │ ├── mpulse.ts
│ │ │ │ ├── pixel.ts
│ │ │ │ ├── product.ts
│ │ │ │ ├── splash.ts
│ │ │ │ ├── stock.ts
│ │ │ │ └── waiting.ts
│ │ │ ├── tasks/
│ │ │ │ ├── base.ts
│ │ │ │ └── index.ts
│ │ │ └── types/
│ │ │ └── index.ts
│ │ ├── constants/
│ │ │ └── index.ts
│ │ ├── index.ts
│ │ ├── mocks/
│ │ │ ├── addToCart.ts
│ │ │ ├── cookies.ts
│ │ │ ├── getAvailability.ts
│ │ │ ├── getProductInfo.ts
│ │ │ ├── getProductPage.ts
│ │ │ ├── submitCheckout.ts
│ │ │ └── submitInformation.ts
│ │ └── utils/
│ │ ├── __tests__/
│ │ │ └── pickVariant.test.ts
│ │ ├── dfValues.ts
│ │ ├── forms.ts
│ │ ├── index.ts
│ │ └── pickVariant.ts
│ └── utils/
│ ├── assert.ts
│ ├── bootHelper.ts
│ ├── captchaTypes.ts
│ ├── cardFormatter.ts
│ ├── comparators.ts
│ ├── convertObjectToArray.ts
│ ├── createWindows.ts
│ ├── date.js
│ ├── eventHandling.ts
│ ├── funcs.js
│ ├── getPlatform.ts
│ ├── gzip.ts
│ ├── imgForCardType.ts
│ ├── imgsrc.ts
│ ├── isEncoded.ts
│ ├── isOnline.ts
│ ├── isPackaged.js
│ ├── loadFile.ts
│ ├── loadUrls.ts
│ ├── log.ts
│ ├── paths.js
│ ├── pkginfo.js
│ ├── proxy.ts
│ ├── randInt.ts
│ ├── reducerPrefixer.ts
│ ├── saveFile.ts
│ ├── sleep.ts
│ ├── storageHelper.ts
│ ├── styleResets.ts
│ ├── testProxies.ts
│ ├── titlebarDoubleClick.ts
│ ├── trimFat.ts
│ ├── url.ts
│ └── validateTasks.ts
├── autosolve-client.d.ts
├── babel.config.js
├── babelx.js
├── chrome-paths.d.ts
├── config/
│ └── env/
│ ├── env.dev.js
│ ├── env.prod.js
│ └── index.js
├── electron-builder.yml
├── internals/
│ └── scripts/
│ ├── AfterPack.js
│ ├── CheckBuiltsExist.js
│ ├── CheckNodeEnv.js
│ ├── CheckPortInUse.js
│ ├── CheckYarn.js
│ └── Notarize.js
├── jest.config.js
├── jest.setup.js
├── jsdom-extra.d.ts
├── package.json
├── preloads/
│ ├── 3ds.js
│ ├── auth.js
│ └── harvester.js
├── test/
│ ├── babel-transformer.js
│ ├── babelRegisterTs.js
│ ├── debug.ts
│ ├── mockOffsetSize.tsx
│ ├── polyfill.js
│ └── testUtils.tsx
├── tsconfig.json
└── webpack/
├── config.base.js
├── config.eslint.js
├── config.main.prod.babel.js
├── config.renderer.dev.babel.js
├── config.renderer.dev.dll.babel.js
└── config.renderer.prod.babel.js
SYMBOL INDEX (1022 symbols across 201 files)
FILE: app/__mocks__/electron-ga.tsx
class Analytics (line 1) | class Analytics {
FILE: app/classes/AppUpdate.ts
class AppUpdate (line 77) | class AppUpdate {
method constructor (line 100) | constructor() {
method init (line 124) | init() {
method pollForUpdates (line 239) | pollForUpdates() {
method checkForUpdates (line 277) | checkForUpdates() {
method forceCheck (line 324) | async forceCheck() {
method setCheckUpdatesProgress (line 387) | setCheckUpdatesProgress() {
method initDownloadUpdatesProgress (line 425) | initDownloadUpdatesProgress() {
method setUpdateProgressWindow (line 449) | setUpdateProgressWindow({ value = 0 }) {
method setMainWindow (line 484) | setMainWindow() {
method setTaskBarProgressBar (line 493) | setTaskBarProgressBar(value: any) {
method isNetworkError (line 503) | isNetworkError(errorObj: any) {
method spitMessageDialog (line 514) | async spitMessageDialog(title: string, message: string, type = 'messag...
method closeActiveUpdates (line 546) | closeActiveUpdates(updateIsActive = 0) {
FILE: app/classes/Boot.ts
class Boot (line 22) | class Boot {
method constructor (line 31) | constructor() {
method init (line 38) | async init() {
method verify (line 70) | async verify() {
method quickVerify (line 93) | quickVerify() {
method verifyDir (line 110) | async verifyDir(filePath: string) {
method createDir (line 119) | async createDir(newFolderPath: string) {
method verifyFile (line 127) | verifyFile(filePath: string) {
method createFile (line 136) | createFile(filePath: string) {
method cleanRotationFiles (line 144) | cleanRotationFiles() {
FILE: app/classes/Notification.ts
constant VOLUME (line 5) | const VOLUME = 0.55;
function preload (line 19) | function preload() {
function play (line 31) | function play(name: string) {
FILE: app/classes/ProxyTester.ts
class ProxyTester (line 10) | class ProxyTester {
method constructor (line 29) | constructor(mainWindow: BrowserWindow | null) {
FILE: app/classes/Storage.ts
class Storage (line 8) | class Storage {
method constructor (line 11) | constructor(filePath: string) {
method getAll (line 15) | getAll() {
method getItem (line 31) | getItem(key: string) {
method getItems (line 50) | getItems(keys: any) {
method setAll (line 75) | setAll({ ...data }) {
method set (line 83) | set(key: string, value: any) {
method delete (line 98) | delete() {
FILE: app/components/Analytics/components/checkouts.tsx
type RowProps (line 122) | type RowProps = {
FILE: app/components/Analytics/reducers/checkouts.tsx
type Action (line 5) | type Action = {
type Checkouts (line 10) | type Checkouts = [];
function Checkouts (line 14) | function Checkouts(state = initialState, action: Action) {
FILE: app/components/Analytics/reducers/news.tsx
type Action (line 5) | type Action = {
type NewsObject (line 10) | type NewsObject = {};
type News (line 12) | type News = NewsObject[];
function News (line 16) | function News(state = newsInitialState, action: Action) {
FILE: app/components/Analytics/types.tsx
type PackageAPIResponse (line 4) | interface PackageAPIResponse {
type Fee (line 23) | interface Fee {
type TrackingDetail (line 31) | interface TrackingDetail {
type TrackingLocation (line 40) | interface TrackingLocation {
FILE: app/components/App/Providers.tsx
type Props (line 83) | type Props = {
FILE: app/components/App/Root.tsx
type Props (line 8) | type Props = {
FILE: app/components/App/actions.tsx
function setTheme (line 16) | function setTheme(theme: number) {
function importAll (line 23) | function importAll(state: any) {
function reqLoadApp (line 30) | function reqLoadApp() {
function resLoadApp (line 35) | function resLoadApp() {
function failLoadApp (line 41) | function failLoadApp(e: any) {
function setUser (line 56) | function setUser(user: any) {
function addStore (line 73) | function addStore(newStore: any) {
function setStores (line 80) | function setStores(stores: any[]) {
FILE: app/components/App/reducers.tsx
type Action (line 10) | type Action = {
type User (line 15) | type User = {
type Theme (line 39) | type Theme = number;
function Theme (line 43) | function Theme(state = initialThemeState, action: Action) {
function User (line 56) | function User(state = initialState, action: Action) {
type Store (line 70) | type Store = {
type Platform (line 76) | type Platform = {
type Stores (line 83) | type Stores = Platform[];
function Stores (line 86) | function Stores(state = initialStoresState, action: Action) {
FILE: app/components/Calendar/Container.tsx
type Props (line 24) | type Props = {
FILE: app/components/Calendar/Month.tsx
type Props (line 35) | type Props = {
FILE: app/components/Calendar/ViewSelect.tsx
constant CALENDAR_VIEW (line 12) | const CALENDAR_VIEW = {
type Option (line 17) | type Option = {
type Props (line 22) | type Props = {
FILE: app/components/Captchas/actions/index.tsx
constant HARVESTER_TYPES (line 11) | const HARVESTER_TYPES = {
constant HARVESTER_FIELDS (line 15) | const HARVESTER_FIELDS = {
FILE: app/components/Captchas/components/actionBar/ActionBar.tsx
type Props (line 7) | type Props = {
FILE: app/components/Captchas/reducers/captchas.tsx
type Action (line 17) | type Action = {
type Captchas (line 22) | type Captchas = [];
function Captchas (line 24) | function Captchas(state = initialState, action: Action) {
FILE: app/components/DebouncedInput/DebouncedInput.tsx
type Props (line 3) | type Props = {
FILE: app/components/ErrorBoundary/components/GenerateErrorReport.tsx
class GenerateErrorReport (line 15) | class GenerateErrorReport extends Component {
method render (line 61) | render() {
FILE: app/components/ErrorBoundary/components/GenerateErrorReportBody.tsx
class GenerateErrorReportBody (line 4) | class GenerateErrorReportBody extends PureComponent {
method render (line 5) | render() {
FILE: app/components/ErrorBoundary/index.tsx
class ErrorBoundary (line 14) | class ErrorBoundary extends PureComponent {
method componentDidCatch (line 19) | componentDidCatch(error, errorInfo) {
method render (line 41) | render() {
FILE: app/components/Legal/PrivacyPolicy/index.tsx
class PrivacyPolicyPage (line 20) | class PrivacyPolicyPage extends Component {
method componentWillMount (line 21) | componentWillMount() {
method render (line 25) | render() {
FILE: app/components/Legal/TermsOfService/index.tsx
class TermsOfServicePage (line 18) | class TermsOfServicePage extends Component {
method componentWillMount (line 19) | componentWillMount() {
method render (line 23) | render() {
FILE: app/components/Profiles/actions/index.tsx
constant PROFILE_FIELDS (line 19) | const PROFILE_FIELDS = {
constant LOCATION_FIELDS (line 27) | const LOCATION_FIELDS = {
constant PAYMENT_FIELDS (line 39) | const PAYMENT_FIELDS = {
FILE: app/components/Profiles/actions/profiles.tsx
function importProfiles (line 44) | function importProfiles(profiles: any[]) {
function exportProfiles (line 53) | function exportProfiles(profiles: any[]) {
function loadProfile (line 62) | function loadProfile(profile: any) {
function saveProfile (line 72) | function saveProfile(profile: any) {
FILE: app/components/Profiles/reducers/current.tsx
type Action (line 51) | type Action = {
type CurrentProfile (line 56) | type CurrentProfile = {
function CurrentProfile (line 65) | function CurrentProfile(state = initialState, action: Action) {
FILE: app/components/Profiles/reducers/location.tsx
type Address (line 15) | type Address = {
type Action (line 36) | type Action = {
FILE: app/components/Profiles/reducers/payment.tsx
type Payment (line 9) | type Payment = {
type Action (line 17) | type Action = {
FILE: app/components/Profiles/reducers/profiles.tsx
type Profiles (line 11) | type Profiles = CurrentProfile[];
type Action (line 13) | type Action = {
function Profiles (line 20) | function Profiles(state = initialState, action: Action) {
FILE: app/components/Progressbar/index.tsx
class ProgressbarPage (line 10) | class ProgressbarPage extends Component {
method constructor (line 19) | constructor(props: any) {
method componentWillMount (line 34) | componentWillMount() {
method componentWillUnmount (line 65) | componentWillUnmount() {
method render (line 72) | render() {
FILE: app/components/Proxies/actions/index.tsx
function deleteProxies (line 26) | function deleteProxies(group) {
function deleteProxy (line 35) | function deleteProxy(group, proxy) {
function removeFailed (line 44) | function removeFailed(group) {
function resetProxiesStatus (line 53) | function resetProxiesStatus() {
function loadProxies (line 61) | function loadProxies(proxies) {
function selectProxies (line 71) | function selectProxies(selected) {
function setLoading (line 100) | function setLoading(proxies) {
function setSelected (line 107) | function setSelected(selected) {
function setAllSelected (line 114) | function setAllSelected() {
constant PROXY_FIELDS (line 129) | const PROXY_FIELDS = {
FILE: app/components/Proxies/components/Table/ProxyTable.tsx
function comparator (line 42) | function comparator(a: any[], b: any[], orderBy: string) {
function getComparator (line 52) | function getComparator(
function tableSort (line 61) | function tableSort(array: any[], comparator: (a: any, b: any) => number) {
FILE: app/components/Proxies/components/Table/components/tableToolbar.tsx
type LabelValuePair (line 30) | type LabelValuePair = {
FILE: app/components/Proxies/reducers/current.tsx
type Action (line 12) | type Action = {
type Proxy (line 17) | type Proxy = {
type CurrentProxies (line 23) | type CurrentProxies = {
function CurrentProxies (line 30) | function CurrentProxies(state = initialState, action: Action) {
FILE: app/components/Proxies/reducers/proxies.tsx
type Proxies (line 10) | type Proxies = CurrentProxies[];
type Action (line 14) | type Action = {
function Proxies (line 19) | function Proxies(state = initialState, action: Action) {
FILE: app/components/Settings/actions.tsx
function addRates (line 55) | function addRates(data: any) {
function removeRates (line 62) | function removeRates(data: any) {
function uploadAccounts (line 100) | function uploadAccounts(accounts: any[]) {
function importAccounts (line 107) | function importAccounts(accounts: any[]) {
function setField (line 114) | function setField(field: string, value: string) {
function toggleField (line 124) | function toggleField(field: string) {
function toggleStagger (line 131) | function toggleStagger(value: string) {
function editAutoSolve (line 138) | function editAutoSolve(field: string, value: string) {
function setAutoSolveConnected (line 148) | function setAutoSolveConnected(value: boolean) {
function setAnalyticsFile (line 158) | function setAnalyticsFile(value: string | null) {
function editWebhook (line 168) | function editWebhook(field: string, value: string) {
function selectWebhook (line 175) | function selectWebhook(webhook: any) {
function deleteWebhook (line 182) | function deleteWebhook(webhook: any) {
function saveWebhook (line 189) | function saveWebhook(webhook: any) {
function editAccount (line 202) | function editAccount(field: string, value: string) {
function selectAccount (line 214) | function selectAccount(account: any) {
function deleteAccount (line 223) | function deleteAccount(account: any) {
function saveAccount (line 232) | function saveAccount(account: any) {
function selectDefault (line 241) | function selectDefault(field: string, value: any) {
constant DEFAULTS_FIELDS (line 253) | const DEFAULTS_FIELDS = {
constant ACCOUNT_FIELDS (line 261) | const ACCOUNT_FIELDS = {
constant WEBHOOK_FIELDS (line 267) | const WEBHOOK_FIELDS = {
constant AUTOSOLVE_FIELDS (line 273) | const AUTOSOLVE_FIELDS = {
constant SETTINGS_FIELDS (line 279) | const SETTINGS_FIELDS = {
FILE: app/components/Settings/components/dialog/ProductField.tsx
type Props (line 9) | type Props = {
FILE: app/components/Settings/components/dialog/ProfileField.tsx
type Props (line 14) | type Props = {
FILE: app/components/Settings/components/dialog/StoreField.tsx
type Props (line 15) | type Props = {
FILE: app/components/Settings/reducers/accounts.tsx
type Action (line 9) | type Action = {
type Accounts (line 14) | type Accounts = CurrentAccount[];
function Accounts (line 18) | function Accounts(state = accountsInitialState, action: Action) {
FILE: app/components/Settings/reducers/currentAccount.tsx
type CurrentAccount (line 5) | type CurrentAccount = {
type Action (line 12) | type Action = {
function CurrentAccount (line 24) | function CurrentAccount(
FILE: app/components/Settings/reducers/currentWebhook.tsx
type CurrentWebhook (line 5) | type CurrentWebhook = {
type Action (line 13) | type Action = {
function CurrentWebhook (line 26) | function CurrentWebhook(
FILE: app/components/Settings/reducers/defaults.tsx
type Action (line 5) | type Action = {
type Account (line 10) | type Account = {
type Proxies (line 17) | type Proxies = {
type Profile (line 21) | type Profile = {
type Defaults (line 26) | type Defaults = {
function Defaults (line 42) | function Defaults(state = defaultsInitialState, action: Action) {
FILE: app/components/Settings/reducers/rates.ts
type Rate (line 8) | type Rate = {
type Rates (line 14) | type Rates = {
type Action (line 18) | type Action = {
function Rates (line 23) | function Rates(state = ratesInitialState, action: Action) {
FILE: app/components/Settings/reducers/settings.tsx
type AutoSolve (line 10) | type AutoSolve = {
type Store (line 15) | type Store = {
type Settings (line 20) | type Settings = {
type Action (line 61) | type Action = {
function Settings (line 66) | function Settings(state = settingsInitialState, action: Action) {
FILE: app/components/Settings/reducers/webhooks.tsx
type Webhooks (line 11) | type Webhooks = CurrentWebhook[];
type Action (line 13) | type Action = {
function Webhooks (line 18) | function Webhooks(state = webhooksInitialState, action: Action) {
FILE: app/components/Sidebar/components/icons.tsx
constant SIDEBAR_ICONS (line 17) | const SIDEBAR_ICONS: any = {
FILE: app/components/Sidebar/components/menuItems.tsx
constant SIDEBAR (line 3) | const SIDEBAR = {
FILE: app/components/Tasks/actions/index.tsx
function notification (line 96) | function notification(group: string, id: string, type: string) {
function deleteTasks (line 138) | function deleteTasks(group: string, tasks: any[], useTasks = false) {
function selectTasks (line 155) | function selectTasks({
function copyTasks (line 177) | function copyTasks(group: string, tasks: any[]) {
function startTasks (line 209) | function startTasks(group: string, tasks: any[], delays: any) {
function stopTasks (line 236) | function stopTasks(group: string, tasks: any[]) {
function createGroup (line 278) | function createGroup(value: string) {
function selectGroup (line 285) | function selectGroup(id: string | null) {
function deleteGroup (line 292) | function deleteGroup(id: string) {
function importTasks (line 299) | function importTasks(tasks: any) {
constant TASK_FIELDS (line 306) | const TASK_FIELDS = {
function changeDelay (line 338) | function changeDelay(
FILE: app/components/Tasks/components/Table/components/TableBodyWrapper.tsx
type TableBodyProps (line 79) | interface TableBodyProps {
function comparator (line 87) | function comparator(a: any, b: any, orderBy: string) {
function getComparator (line 127) | function getComparator(
function tableSort (line 136) | function tableSort(array: any[], comparator: (a: any, b: any) => number) {
FILE: app/components/Tasks/components/Table/components/icons.tsx
constant MODE_ICONS (line 13) | const MODE_ICONS: any = {
FILE: app/components/Tasks/components/Table/components/tableRow.tsx
type Props (line 18) | type Props = {
FILE: app/components/Tasks/components/Table/components/toolbar/clock.tsx
function Clock (line 9) | function Clock() {
FILE: app/components/Tasks/components/create/AccountField.tsx
type Props (line 15) | type Props = {
FILE: app/components/Tasks/components/create/CaptchaField.tsx
type Props (line 16) | type Props = {
FILE: app/components/Tasks/components/create/CategoryField.tsx
type Props (line 16) | type Props = {
FILE: app/components/Tasks/components/create/CheckoutDelayField.tsx
type Props (line 12) | type Props = {
FILE: app/components/Tasks/components/create/DateField.tsx
type Props (line 10) | type Props = {
FILE: app/components/Tasks/components/create/DiscountField.tsx
type Props (line 11) | type Props = {
FILE: app/components/Tasks/components/create/FootsiteForm.tsx
type Values (line 33) | type Values = {};
type FormProps (line 35) | type FormProps = {
FILE: app/components/Tasks/components/create/MaxPriceField.tsx
type Props (line 11) | type Props = {
FILE: app/components/Tasks/components/create/MinPriceField.tsx
type Props (line 11) | type Props = {
FILE: app/components/Tasks/components/create/MockToggle.tsx
type Props (line 15) | type Props = {
FILE: app/components/Tasks/components/create/NumberOfTasksField.tsx
type Props (line 11) | type Props = {
FILE: app/components/Tasks/components/create/OneCheckout.tsx
type Props (line 16) | type Props = {
FILE: app/components/Tasks/components/create/PasswordField.tsx
type Props (line 11) | type Props = {
FILE: app/components/Tasks/components/create/PayPalField.tsx
type Props (line 16) | type Props = {
FILE: app/components/Tasks/components/create/PokemonForm.tsx
type Values (line 31) | type Values = {};
type FormProps (line 33) | type FormProps = {
FILE: app/components/Tasks/components/create/ProductField.tsx
type Props (line 13) | type Props = {
FILE: app/components/Tasks/components/create/ProfileField.tsx
type Props (line 15) | type Props = {
FILE: app/components/Tasks/components/create/ProxiesField.tsx
type Props (line 14) | type Props = {
FILE: app/components/Tasks/components/create/QuantityField.tsx
type Props (line 11) | type Props = {
FILE: app/components/Tasks/components/create/RatesField.tsx
type Props (line 15) | type Props = {
function extractRatesOptions (line 42) | function extractRatesOptions() {
function getRateValue (line 59) | function getRateValue() {
FILE: app/components/Tasks/components/create/RestockMode.tsx
type Props (line 16) | type Props = {
FILE: app/components/Tasks/components/create/SecureBypassField.tsx
type Props (line 16) | type Props = {
FILE: app/components/Tasks/components/create/ShopifyForm.tsx
type Values (line 45) | type Values = {};
type FormProps (line 47) | type FormProps = {
FILE: app/components/Tasks/components/create/SizesField.tsx
type Props (line 15) | type Props = {
FILE: app/components/Tasks/components/create/StoreField.tsx
type Props (line 18) | type Props = {
FILE: app/components/Tasks/components/create/StyleIdField.tsx
type Props (line 11) | type Props = {
FILE: app/components/Tasks/components/create/SupremeForm.tsx
type Values (line 35) | type Values = {};
type FormProps (line 37) | type FormProps = {
FILE: app/components/Tasks/components/create/TaskForm.tsx
constant PLATFORM_FORM (line 8) | const PLATFORM_FORM = {
FILE: app/components/Tasks/components/create/TaskModeField.tsx
type Props (line 35) | type Props = {
FILE: app/components/Tasks/components/create/UseRotateProxies.tsx
type Props (line 16) | type Props = {
FILE: app/components/Tasks/components/create/VariationField.tsx
type Props (line 12) | type Props = {
FILE: app/components/Tasks/components/create/YeezySupplyForm.tsx
type Values (line 29) | type Values = {};
type FormProps (line 31) | type FormProps = {
FILE: app/components/Tasks/reducers/current.tsx
type Action (line 12) | type Action = {
type Store (line 17) | type Store = {
type Product (line 22) | type Product = {
type Profile (line 30) | type Profile = {
type Proxies (line 35) | type Proxies = {};
type Rate (line 37) | type Rate = {};
type Profiles (line 39) | type Profiles = Profile[];
type CurrentTask (line 41) | type CurrentTask = {
function CurrentTask (line 107) | function CurrentTask(state = initialState, action: Action) {
FILE: app/components/Tasks/reducers/delays.tsx
type Action (line 5) | type Action = {
type Delays (line 10) | type Delays = {
function Delays (line 20) | function Delays(state = initialState, action: Action) {
FILE: app/components/Tasks/reducers/edits.tsx
type Action (line 10) | type Action = {
type EditTask (line 15) | type EditTask = {};
function EditTask (line 19) | function EditTask(state = initialState, action: Action) {
FILE: app/components/Tasks/reducers/tasks.tsx
type Task (line 55) | type Task = {
type Tasks (line 62) | type Tasks = {
function Tasks (line 74) | function Tasks(state = initialState, action: any) {
FILE: app/components/featureFlag/FeatureFlagContext.tsx
type Props (line 20) | type Props = {
FILE: app/components/ui/Select.tsx
type Item (line 26) | type Item = {
type Props (line 30) | type Props = {
FILE: app/components/ui/table/Table.tsx
type Props (line 19) | type Props<D extends object> = {
FILE: app/components/ui/table/TableVirtualized.tsx
type Props (line 26) | type Props<D extends object> = {
FILE: app/constants/index.ts
constant TERMS_OF_SERVICE_TITLE (line 13) | const TERMS_OF_SERVICE_TITLE = `Terms of Service`;
constant PRIVACY_POLICY_PAGE_TITLE (line 15) | const PRIVACY_POLICY_PAGE_TITLE = `Privacy Policy`;
constant EFFECTIVE_DATE (line 17) | const EFFECTIVE_DATE = 'February 20th, 2020';
constant LOG_FILE_ROTATION_CLEANUP_THRESHOLD (line 29) | const LOG_FILE_ROTATION_CLEANUP_THRESHOLD = 30;
constant ENABLE_BACKGROUND_AUTO_UPDATE (line 31) | const ENABLE_BACKGROUND_AUTO_UPDATE = false;
constant AUTO_UPDATE_CHECK_FIREUP_DELAY (line 33) | const AUTO_UPDATE_CHECK_FIREUP_DELAY = 10000;
constant VIEWS (line 456) | const VIEWS = {
constant STATS_OPTIONS_LIGHT (line 469) | const STATS_OPTIONS_LIGHT = {
constant STATS_OPTIONS_DARK (line 542) | const STATS_OPTIONS_DARK = {
type StatusMap (line 625) | type StatusMap = string[];
constant EXPENSES_OPTIONS_LIGHT (line 675) | const EXPENSES_OPTIONS_LIGHT = {
constant EXPENSES_OPTIONS_DARK (line 765) | const EXPENSES_OPTIONS_DARK = {
FILE: app/constants/ipc.ts
type Mapping (line 1) | type Mapping = {
constant HARVEST_STATES (line 89) | const HARVEST_STATES: Mapping = {
FILE: app/constants/meta.js
constant APP_NAME (line 19) | const APP_NAME = `${productName}`;
constant APP_VERSION (line 21) | const APP_VERSION = `${version}`;
constant AUTHOR_EMAIL (line 23) | const AUTHOR_EMAIL = undefinedOrNullChained(author, 'email')
constant AUTHOR_NAME (line 27) | const AUTHOR_NAME = undefinedOrNullChained(author, 'name')
constant APP_DESC (line 31) | const APP_DESC = `${description}`;
constant APP_TITLE (line 33) | const APP_TITLE = `${APP_NAME}`;
constant APP_IDENTIFIER (line 35) | const APP_IDENTIFIER = `${name}`;
constant APP_GITHUB_URL (line 37) | const APP_GITHUB_URL = undefinedOrNullChained(repository, 'url')
constant APP_GITHUB_RELEASES_URL (line 41) | const APP_GITHUB_RELEASES_URL = `${APP_GITHUB_URL}/releases`;
constant APP_DISCORD_SERVER (line 43) | const APP_DISCORD_SERVER = `https://discord.gg/usPeBqV`;
constant APP_WEBSITE (line 45) | const APP_WEBSITE = 'https://twitter.com/nebulabots';
constant APP_ID (line 47) | const APP_ID = undefinedOrNullChained(build, 'appId')
FILE: app/hooks/useEscape.tsx
constant ESCAPE_KEY (line 3) | const ESCAPE_KEY = 27;
FILE: app/hooks/useTraceUpdate.ts
function useTraceUpdate (line 3) | function useTraceUpdate(props: any) {
FILE: app/index.tsx
constant MOUNT_POINT (line 11) | const MOUNT_POINT = document.getElementById('root');
FILE: app/main.dev.ts
function bootTheDevice (line 32) | async function bootTheDevice() {
FILE: app/mainWindow/windows.ts
function createMainWindow (line 103) | async function createMainWindow() {
FILE: app/menu.ts
class MenuBuilder (line 10) | class MenuBuilder {
method constructor (line 17) | constructor({
method buildMenu (line 31) | buildMenu() {
method setupDevelopmentEnvironment (line 47) | setupDevelopmentEnvironment() {
method buildDarwinTemplate (line 74) | buildDarwinTemplate() {
method buildDefaultTemplate (line 243) | buildDefaultTemplate() {
FILE: app/store/reducers.ts
type RootState (line 48) | type RootState = {
FILE: app/styles/js/mixins.tsx
method appDragEnable (line 31) | get appDragEnable() {
FILE: app/tasks/common/classes/monitor.ts
class BaseMonitor (line 11) | class BaseMonitor {
method constructor (line 34) | constructor(context: Context, state: string, platform: string) {
method swapProxies (line 50) | async swapProxies() {
method swap (line 65) | async swap() {
method handleStepLogic (line 120) | async handleStepLogic(_: any): Promise<string> {
method loop (line 124) | async loop() {
method stop (line 176) | stop(id: string) {
method run (line 204) | async run() {
FILE: app/tasks/common/classes/task.ts
class BaseTask (line 12) | class BaseTask {
method constructor (line 39) | constructor(context: Context, state: string, platform: string) {
method retrieveProfile (line 88) | retrieveProfile() {
method swapProxies (line 99) | async swapProxies() {
method waitForCaptcha (line 169) | async waitForCaptcha(message = 'Checkout captcha', autoRemove = false) {
method handleStepLogic (line 198) | async handleStepLogic(_: any): Promise<string> {
method noop (line 202) | async noop() {
method loop (line 220) | async loop() {
method run (line 278) | async run() {
method abort (line 329) | abort() {
FILE: app/tasks/common/contexts/footsite.ts
type FootsiteProduct (line 25) | type FootsiteProduct = {
type ContextObject (line 37) | type ContextObject = {
class FootsiteContext (line 59) | class FootsiteContext {
method constructor (line 118) | constructor({
method addId (line 174) | addId(id: string) {
method isEmpty (line 178) | isEmpty() {
method hasId (line 182) | hasId(id: string) {
method removeId (line 186) | removeId(id: string) {
method setLastProxy (line 190) | setLastProxy(lastProxy: Proxy | null) {
method setProxy (line 194) | setProxy(proxy: Proxy | null) {
method setLastMonitorProxy (line 198) | setLastMonitorProxy(proxy: Proxy | null) {
method setMonitorProxy (line 202) | setMonitorProxy(proxy: Proxy | null) {
method setMessage (line 206) | setMessage(message: string) {
method setLogger (line 210) | setLogger(logger: any) {
method setAborted (line 214) | setAborted(aborted: boolean) {
method setCaptchaToken (line 218) | setCaptchaToken(captchaToken: string) {
FILE: app/tasks/common/contexts/index.ts
type Context (line 6) | type Context =
FILE: app/tasks/common/contexts/pokemon.ts
type ContextObject (line 21) | type ContextObject = {
class PokemonContext (line 43) | class PokemonContext {
method constructor (line 98) | constructor({
method addId (line 150) | addId(id: string) {
method isEmpty (line 154) | isEmpty() {
method hasId (line 158) | hasId(id: string) {
method removeId (line 162) | removeId(id: string) {
method setLastProxy (line 166) | setLastProxy(lastProxy: Proxy | null) {
method setProxy (line 170) | setProxy(proxy: Proxy | null) {
method setLastMonitorProxy (line 174) | setLastMonitorProxy(proxy: Proxy | null) {
method setMonitorProxy (line 178) | setMonitorProxy(proxy: Proxy | null) {
method setMessage (line 182) | setMessage(message: string) {
method setLogger (line 186) | setLogger(logger: any) {
method setAborted (line 190) | setAborted(aborted: boolean) {
method setCaptchaToken (line 194) | setCaptchaToken(captchaToken: string) {
FILE: app/tasks/common/contexts/shopify.ts
type ShopifyProduct (line 24) | type ShopifyProduct = {
type ShopifyAnswers (line 35) | type ShopifyAnswers = {
type ContextObject (line 40) | type ContextObject = {
class ShopifyContext (line 62) | class ShopifyContext {
method constructor (line 127) | constructor({
method addId (line 185) | addId(id: string) {
method isEmpty (line 189) | isEmpty() {
method hasId (line 193) | hasId(id: string) {
method removeId (line 197) | removeId(id: string) {
method setParseType (line 201) | setParseType(parseType: string) {
method setLastProxy (line 205) | setLastProxy(lastProxy: Proxy | null) {
method setProxy (line 209) | setProxy(proxy: Proxy | null) {
method setLastMonitorProxy (line 213) | setLastMonitorProxy(proxy: Proxy | null) {
method setMonitorProxy (line 217) | setMonitorProxy(proxy: Proxy | null) {
method setMessage (line 221) | setMessage(message: string) {
method setLogger (line 225) | setLogger(logger: any) {
method setShopId (line 229) | setShopId(shopId: string) {
method setAccessToken (line 233) | setAccessToken(accessToken: string) {
method setAborted (line 237) | setAborted(aborted: boolean) {
method setCaptchaToken (line 241) | setCaptchaToken(captchaToken: string) {
FILE: app/tasks/common/contexts/yeezysupply.ts
type YeezySupplyProduct (line 22) | type YeezySupplyProduct = {
type ContextObject (line 34) | type ContextObject = {
class YeezySupplyContext (line 56) | class YeezySupplyContext {
method constructor (line 111) | constructor({
method addId (line 163) | addId(id: string) {
method isEmpty (line 167) | isEmpty() {
method hasId (line 171) | hasId(id: string) {
method removeId (line 175) | removeId(id: string) {
method setLastProxy (line 179) | setLastProxy(lastProxy: Proxy | null) {
method setProxy (line 183) | setProxy(proxy: Proxy | null) {
method setLastMonitorProxy (line 187) | setLastMonitorProxy(proxy: Proxy | null) {
method setMonitorProxy (line 191) | setMonitorProxy(proxy: Proxy | null) {
method setMessage (line 195) | setMessage(message: string) {
method setLogger (line 199) | setLogger(logger: any) {
method setAborted (line 203) | setAborted(aborted: boolean) {
method setCaptchaToken (line 207) | setCaptchaToken(captchaToken: string) {
FILE: app/tasks/common/utils/index.ts
type Ellipsis (line 16) | type Ellipsis = {
FILE: app/tasks/common/utils/logger.ts
method getLogger (line 84) | getLogger({ name }: any) {
method log (line 93) | log({ level, id, message }: { level: string; id: string; message: string...
FILE: app/tasks/common/utils/queues.ts
class AsyncQueue (line 6) | class AsyncQueue {
method constructor (line 11) | constructor() {
method backlogLength (line 16) | get backlogLength() {
method lineLength (line 20) | get lineLength() {
method insert (line 24) | insert(datum: any) {
method next (line 39) | next() {
method clear (line 78) | clear() {
method destroy (line 83) | destroy() {
class Queue (line 97) | class Queue {
method constructor (line 100) | constructor() {
method enqueue (line 104) | enqueue(datum: any) {
method dequeue (line 108) | dequeue() {
method isEmpty (line 112) | isEmpty() {
method peek (line 116) | peek() {
method length (line 120) | length() {
class CapacityQueue (line 125) | class CapacityQueue {
method constructor (line 130) | constructor(data = [], size = 100) {
method insert (line 135) | insert(datum = {}) {
method pop (line 143) | pop() {
method shift (line 147) | shift() {
method toString (line 151) | toString() {
type Jobs (line 156) | type Jobs = {
type Job (line 162) | type Job =
class StaggeredQueue (line 169) | class StaggeredQueue {
method constructor (line 186) | constructor(shouldRegister = true, stagger = 5) {
FILE: app/tasks/common/utils/request.ts
type Options (line 9) | type Options = {
FILE: app/tasks/common/utils/timer.ts
class Timer (line 3) | class Timer {
method constructor (line 10) | constructor() {
method start (line 20) | start(time = now()) {
method stop (line 27) | stop(time = now()) {
method reset (line 38) | reset() {
method getStartTime (line 48) | getStartTime() {
method getEndTime (line 55) | getEndTime() {
method getRunTime (line 63) | getRunTime(time = now()) {
method getTotalTime (line 69) | getTotalTime(fixed = 2) {
FILE: app/tasks/footsites/classes/functions/checkout.ts
type CardData (line 63) | type CardData = {
FILE: app/tasks/footsites/classes/tasks/base.ts
class BaseFootsiteTask (line 73) | class BaseFootsiteTask extends BaseTask {
method constructor (line 154) | constructor(context: FootsiteContext, platform = Platforms.Footsites) {
method injectRequester (line 278) | async injectRequester(
method extractCsrfToken (line 314) | async extractCsrfToken(body: GetSessionResponse) {
method extractCartData (line 348) | async extractCartData({ code, guid, totalPrice }: AddToCartResponse) {
method setDefaultCookies (line 372) | async setDefaultCookies() {
method handleQueue (line 433) | async handleQueue(from: string) {
method sendWebhook (line 446) | async sendWebhook(success: boolean, body?: any) {
method getSession (line 731) | async getSession() {
method getOldStock (line 806) | async getOldStock() {
method getStock (line 1026) | async getStock() {
method addToCart (line 1243) | async addToCart() {
method enterQueue (line 1370) | async enterQueue() {
method submitCaptchaChallenge (line 1431) | async submitCaptchaChallenge() {
method handlePow (line 1489) | async handlePow() {
method submitPow (line 1545) | async submitPow() {
method submitEnqueue (line 1597) | async submitEnqueue() {
method waitForQueue (line 1647) | async waitForQueue() {
method handleDatadome (line 1713) | async handleDatadome(body: any) {
method waitForCookie (line 1852) | async waitForCookie() {
method waitForCaptcha (line 1906) | async waitForCaptcha() {
method submitCaptcha (line 1927) | async submitCaptcha() {
method extractDatadomeData (line 2018) | extractDatadomeData(url: string): DatadomeData {
method extractDatadome (line 2031) | async extractDatadome({ cookie }: DatadomeCookie) {
method verifyEmail (line 2054) | async verifyEmail() {
method submitShipping (line 2145) | async submitShipping() {
method submitBilling (line 2233) | async submitBilling() {
method submitInformation (line 2322) | async submitInformation() {
method submitCheckout (line 2412) | async submitCheckout() {
method handleStepLogic (line 2503) | async handleStepLogic(currentState: string) {
method abort (line 2562) | abort() {
FILE: app/tasks/footsites/classes/types/datadome.d.ts
type DatadomeData (line 1) | type DatadomeData = {
type DatadomeCookie (line 12) | type DatadomeCookie = {
FILE: app/tasks/footsites/classes/types/geetest.d.ts
type Geetest (line 2) | type Geetest = {
FILE: app/tasks/footsites/classes/types/index.ts
type baseOptionsObject (line 5) | type baseOptionsObject = {
type slimPrice (line 36) | type slimPrice = {
type productObject (line 43) | type productObject = {
type entriesObject (line 71) | type entriesObject = {
type AddToCartResponse (line 81) | type AddToCartResponse = {
type categoryObject (line 113) | type categoryObject = {
type variationEntry (line 118) | type variationEntry = {
type imageObject (line 124) | type imageObject = {
type attributesObject (line 129) | type attributesObject = {
type priceObject (line 135) | type priceObject = {
type SellableUnit (line 143) | type SellableUnit = {
type sizeChartGridMap (line 157) | type sizeChartGridMap = {
type variantAttributes (line 162) | type variantAttributes = {
type GetStockResponse (line 184) | type GetStockResponse = {
type GetSessionResponse (line 203) | type GetSessionResponse = {
type SubmitInformationResponse (line 225) | type SubmitInformationResponse = {
type SubmitCheckoutResponse (line 248) | type SubmitCheckoutResponse = {
type CreatePaymentResourceResponse (line 252) | type CreatePaymentResourceResponse = {
type resolver (line 261) | type resolver = {
type OnboardGuestResponse (line 270) | type OnboardGuestResponse = {
type SubmitAccountResponse (line 307) | type SubmitAccountResponse = {
type AllowedSkus (line 346) | type AllowedSkus = {
FILE: app/tasks/footsites/classes/types/stock.d.ts
type ProductStock (line 1) | interface ProductStock {
type Model (line 11) | interface Model {
type ProductHierarchy (line 29) | interface ProductHierarchy {
type Style (line 35) | interface Style {
type Price (line 66) | interface Price {
type FlagsAndRestrictions (line 78) | interface FlagsAndRestrictions {
type LaunchAttributes (line 91) | interface LaunchAttributes {
type EligiblePaymentTypes (line 101) | interface EligiblePaymentTypes {
type VendorAttributes (line 111) | interface VendorAttributes {
type Inventory (line 115) | interface Inventory {
type Size (line 125) | interface Size {
type Price2 (line 144) | interface Price2 {
type Inventory2 (line 155) | interface Inventory2 {
type StyleVariant (line 165) | interface StyleVariant {
type Price3 (line 179) | interface Price3 {
type Inventory3 (line 190) | interface Inventory3 {
type SizeChart (line 200) | interface SizeChart {
type SizeChartGridMap (line 207) | interface SizeChartGridMap {
FILE: app/tasks/footsites/classes/types/variant.d.ts
type Variant (line 3) | interface Variant {
FILE: app/tasks/footsites/mocks/cookies/cookies.ts
type list (line 19) | type list = {
FILE: app/tasks/footsites/utils/pickVariant.ts
type PickVariant (line 22) | type PickVariant = {
FILE: app/tasks/managers/analytics.ts
type Data (line 8) | type Data = {
class AnalyticsManager (line 22) | class AnalyticsManager {
method constructor (line 29) | constructor() {
FILE: app/tasks/managers/browser/index.ts
type SessionRequester (line 7) | type SessionRequester = {
class BrowserManager (line 31) | class BrowserManager {
method constructor (line 40) | constructor() {
FILE: app/tasks/managers/cache/cache.ts
type Products (line 6) | type Products = {
type Window (line 10) | type Window = {
class CacheManager (line 16) | class CacheManager {
method constructor (line 23) | constructor(mainWindow: BrowserWindow | null) {
FILE: app/tasks/managers/captcha/autoSolve.ts
type PlatformForUrl (line 68) | type PlatformForUrl = {
FILE: app/tasks/managers/captcha/captcha.ts
type AutoSolveProps (line 36) | type AutoSolveProps = {
type CaptchaDetailProps (line 41) | type CaptchaDetailProps = {
type CaptchaProps (line 51) | type CaptchaProps = {
type InterceptProps (line 66) | type InterceptProps = {
type CaptchaWindow (line 79) | type CaptchaWindow = {
type CaptchaWindows (line 83) | type CaptchaWindows = {
type CaptchaRequester (line 87) | type CaptchaRequester = {
type CaptchaRequesters (line 121) | type CaptchaRequesters = {
type CaptchaIntervals (line 127) | type CaptchaIntervals = {
type TokenQueue (line 131) | type TokenQueue = {
class CaptchaManager (line 139) | class CaptchaManager {
method constructor (line 160) | constructor(
FILE: app/tasks/managers/captcha/youtube.ts
type YoutubeWindow (line 14) | type YoutubeWindow = {
type YoutubeWindows (line 20) | type YoutubeWindows = {
type LaunchProps (line 24) | type LaunchProps = {
class Youtube (line 30) | class Youtube {
method constructor (line 37) | constructor(
FILE: app/tasks/managers/checkout.ts
type DataRequester (line 4) | type DataRequester = {
class CheckoutManager (line 9) | class CheckoutManager {
method constructor (line 16) | constructor() {
FILE: app/tasks/managers/checkpoint/index.tsx
class CheckpointManager (line 6) | class CheckpointManager {
method constructor (line 19) | constructor() {
FILE: app/tasks/managers/geetest/index.ts
type SessionRequester (line 3) | type SessionRequester = {
class GeetestManager (line 11) | class GeetestManager {
method constructor (line 18) | constructor() {
FILE: app/tasks/managers/interception/index.ts
class InterceptionManager (line 6) | class InterceptionManager {
method constructor (line 13) | constructor() {
method insert (line 20) | insert({ id, html }: { id: string; html: string }) {
method interceptResponse (line 54) | async interceptResponse({
method remove (line 78) | remove(id: string) {
FILE: app/tasks/managers/notification.ts
type Notification (line 6) | type Notification = {
class NotificationManager (line 14) | class NotificationManager {
method constructor (line 19) | constructor(mainWindow: BrowserWindow | null) {
FILE: app/tasks/managers/profile/profile.ts
class ProfileManager (line 5) | class ProfileManager {
method constructor (line 10) | constructor(mainWindow: BrowserWindow | null) {
FILE: app/tasks/managers/profile/typings.d.ts
type Profile (line 1) | type Profile = {
type Location (line 10) | type Location = {
type Payment (line 28) | type Payment = {
type Profiles (line 36) | type Profiles = {
FILE: app/tasks/managers/proxy.ts
type Proxies (line 15) | type Proxies = {
class ProxyManager (line 19) | class ProxyManager {
method constructor (line 24) | constructor(mainWindow: BrowserWindow | null) {
FILE: app/tasks/managers/queue/index.ts
class QueueManager (line 3) | class QueueManager {
method constructor (line 11) | constructor() {
FILE: app/tasks/managers/restart.ts
class RestartManager (line 7) | class RestartManager {
method constructor (line 12) | constructor(mainWindow: BrowserWindow | null) {
FILE: app/tasks/managers/tasks/choose.ts
type CreateProps (line 44) | type CreateProps = {
FILE: app/tasks/managers/tasks/index.ts
class TaskManager (line 36) | class TaskManager {
method constructor (line 87) | constructor(logPath: string, mainWindow: BrowserWindow | null) {
method stopAll (line 533) | async stopAll({ group, tasks }: { group: string; tasks: any[] }) {
method update (line 540) | async update(group: string, task: any) {
method updateAll (line 573) | async updateAll(group: string, tasks: any[]) {
method _cleanup (line 577) | async _cleanup(group: string, task: any, monitor: any) {
FILE: app/tasks/managers/typings.d.ts
type Proxies (line 13) | type Proxies = {
type ProxyGroup (line 17) | type ProxyGroup = {
type Proxy (line 24) | type Proxy = {
type RegisterProps (line 32) | type RegisterProps = {
type DeregisterProps (line 37) | type DeregisterProps = {
type ReserveProps (line 41) | type ReserveProps = {
type SwapProps (line 46) | type SwapProps = {
type TestProps (line 52) | type TestProps = {
type Webhook (line 57) | type Webhook = {
type WebhookData (line 66) | type WebhookData = {
type Webhooks (line 98) | type Webhooks = {
type CaptchaQueues (line 102) | type CaptchaQueues = {
type Sessions (line 106) | type Sessions = {
type Messages (line 110) | type Messages = {
type Intervals (line 118) | type Intervals = {
type Tasks (line 122) | type Tasks = {
type Monitors (line 136) | type Monitors = {
FILE: app/tasks/managers/utils.ts
type SetProxyProps (line 78) | type SetProxyProps = {
type SetCookieProps (line 83) | type SetCookieProps = {
type AttachRequesterProps (line 89) | type AttachRequesterProps = {
type DetachRequesterProps (line 99) | type DetachRequesterProps = {
type CheckpointProps (line 167) | type CheckpointProps = {
FILE: app/tasks/managers/webhook/aycd.ts
class AycdClient (line 155) | class AycdClient {
method constructor (line 158) | constructor(url: string) {
FILE: app/tasks/managers/webhook/index.ts
class WebhookManager (line 41) | class WebhookManager {
method constructor (line 44) | constructor() {
method build (line 110) | build(data: WebhookData, type: string) {
method log (line 122) | log(data: WebhookData) {
FILE: app/tasks/pokemon/classes/tasks/base.ts
class BasePokemonTask (line 57) | class BasePokemonTask extends BaseTask {
method constructor (line 126) | constructor(context: PokemonContext, platform = Platforms.Pokemon) {
method injectRequester (line 267) | async injectRequester(data: DatadomeData) {
method extractDatadomeData (line 293) | extractDatadomeData(url: string): DatadomeData {
method removeDatadome (line 306) | async removeDatadome(headers: any) {
method handleDatadome (line 333) | async handleDatadome(body: any, headers: any) {
method waitForCookie (line 459) | async waitForCookie() {
method waitForCaptcha (line 514) | async waitForCaptcha() {
method submitCaptcha (line 531) | async submitCaptcha() {
method extractDatadome (line 599) | async extractDatadome({ cookie }: DatadomeCookie) {
method extractAuthToken (line 619) | async extractAuthToken(headers: any) {
method extractProduct (line 664) | async extractProduct({
method extractProducts (line 765) | async extractProducts({ response }: Products) {
method extractCartResponse (line 791) | async extractCartResponse({ messages, self }: Cart) {
method extractInformationResponse (line 821) | async extractInformationResponse({ billing, shipping }: Information) {
method extractKeyId (line 843) | async extractKeyId({ keyId }: Key) {
method extractPaymentKey (line 869) | async extractPaymentKey(body: string) {
method extractPurchaseForm (line 894) | async extractPurchaseForm({ self }: Payment) {
method sendWebhook (line 917) | async sendWebhook(success: boolean, body = {} as Success) {
method getCookie (line 1188) | async getCookie() {
method getSession (line 1256) | async getSession() {
method getProducts (line 1321) | async getProducts() {
method getProduct (line 1388) | async getProduct() {
method addToCart (line 1461) | async addToCart() {
method submitInformation (line 1541) | async submitInformation() {
method clearCart (line 1637) | async clearCart() {
method getKeyId (line 1716) | async getKeyId() {
method createEncryption (line 1788) | async createEncryption() {
method submitPayment (line 1857) | async submitPayment() {
method submitCheckout (line 1950) | async submitCheckout() {
method handleStepLogic (line 2006) | async handleStepLogic(currentState: string) {
FILE: app/tasks/pokemon/types/cart.d.ts
type link (line 1) | type link = {
type Cart (line 9) | type Cart = {
FILE: app/tasks/pokemon/types/checkout.d.ts
type link (line 1) | type link = {
type message (line 9) | type message = {
type Checkout (line 18) | type Checkout = {
FILE: app/tasks/pokemon/types/datadome.d.ts
type DatadomeData (line 1) | type DatadomeData = {
type DatadomeCookie (line 12) | type DatadomeCookie = {
FILE: app/tasks/pokemon/types/geetest.d.ts
type Geetest (line 1) | interface Geetest {
FILE: app/tasks/pokemon/types/information.d.ts
type link (line 1) | type link = {
type address (line 9) | type address = {
type name (line 20) | type name = {
type Information (line 25) | type Information = {
FILE: app/tasks/pokemon/types/key.d.ts
type Key (line 1) | type Key = {
FILE: app/tasks/pokemon/types/order.d.ts
type link (line 1) | type link = {
type self (line 9) | type self = {
type address (line 15) | type address = {
type name (line 26) | type name = {
type cost (line 31) | type cost = {
type billingaddress (line 37) | type billingaddress = {
type billingaddressinfo (line 45) | type billingaddressinfo = {
type destination (line 49) | type destination = {
type destinationinfo (line 57) | type destinationinfo = {
type deliveries (line 62) | type deliveries = {
type choice (line 66) | type choice = {
type selector (line 83) | type selector = {
type shippingoption (line 87) | type shippingoption = {
type shippingoptioninfo (line 97) | type shippingoptioninfo = {
type paymentmethod (line 102) | type paymentmethod = {
type paymentmethodinfo (line 110) | type paymentmethodinfo = {
type subtotal (line 114) | type subtotal = {
type tax (line 122) | type tax = {
type total (line 130) | type total = {
type order (line 137) | type order = {
type Order (line 149) | type Order = {
FILE: app/tasks/pokemon/types/payment.d.ts
type link (line 1) | type link = {
type Payment (line 9) | type Payment = {
FILE: app/tasks/pokemon/types/product.d.ts
type link (line 1) | type link = {
type availability (line 9) | type availability = {
type code (line 20) | type code = {
type detail (line 31) | type detail = {
type definition (line 38) | type definition = {
type addtocartform (line 54) | type addtocartform = {
type addtowishlistform (line 66) | type addtowishlistform = {
type availability (line 76) | type availability = {
type code (line 87) | type code = {
type priceItem (line 98) | type priceItem = {
type variantDefinition (line 110) | type variantDefinition = {
type element (line 128) | type element = {
type item (line 137) | type item = {
type price (line 141) | type price = {
type priceRange (line 147) | type priceRange = {
type image (line 165) | type image = {
type Product (line 171) | type Product = {
FILE: app/tasks/pokemon/types/products.d.ts
type Products (line 3) | interface Products {
type Response (line 9) | interface Response {
type ProductsDocument (line 15) | interface ProductsDocument {
type Variant (line 37) | interface Variant {
type FacetCounts (line 44) | interface FacetCounts {
type FacetRanges (line 50) | interface FacetRanges {}
type FacetFields (line 52) | interface FacetFields {
type Category (line 80) | interface Category {
type Brand (line 89) | interface Brand {
type CrumbsId (line 94) | interface CrumbsId {
type SizeName (line 99) | interface SizeName {
type CatalogCode (line 104) | interface CatalogCode {
type ViewId (line 109) | interface ViewId {
type PreorderReAuthDelum (line 114) | interface PreorderReAuthDelum {
type OfferType (line 119) | interface OfferType {
type Buyable (line 124) | interface Buyable {
type ItemCategory2 (line 129) | interface ItemCategory2 {
type ItemCategory1 (line 134) | interface ItemCategory1 {
type ItemCategory3 (line 139) | interface ItemCategory3 {
type PurchaseQuantityLimit (line 144) | interface PurchaseQuantityLimit {
type IsPreOrderItem (line 149) | interface IsPreOrderItem {
type PreOrderInventoryLimit (line 154) | interface PreOrderInventoryLimit {
type NotSoldSeparately (line 159) | interface NotSoldSeparately {
type RecommendedAge (line 164) | interface RecommendedAge {
type Msrp (line 169) | interface Msrp {
type AuthorizedToSell (line 174) | interface AuthorizedToSell {
type ItemType (line 179) | interface ItemType {
type Displayable (line 184) | interface Displayable {
type MinimumOrderQuantity (line 189) | interface MinimumOrderQuantity {
type FacetQueries (line 194) | interface FacetQueries {}
type CategoryMap (line 196) | interface CategoryMap {
FILE: app/tasks/pokemon/types/success.d.ts
type link (line 1) | type link = {
type address (line 9) | type address = {
type name (line 20) | type name = {
type price (line 25) | type price = {
type tax (line 31) | type tax = {
type Success (line 37) | type Success = {
FILE: app/tasks/pokemon/types/token.d.ts
type Token (line 1) | type Token = {
FILE: app/tasks/pokemon/utils/encrypt.ts
type Card (line 4) | type Card = {
type KeyId (line 12) | type KeyId = {
type CardType (line 38) | type CardType = '001' | '002' | '042' | '004' | '005' | '007' | '062';
type JsonWebTokenInfo (line 40) | type JsonWebTokenInfo = {
type Payload (line 54) | type Payload = {
type Header (line 60) | type Header = {
type InitializationVector (line 66) | type InitializationVector = Uint8Array;
function importKey (line 119) | function importKey(crypto: Crypto, jsonWebKey: JsonWebKey) {
function wrapKey (line 134) | async function wrapKey(crypto: Crypto, key: CryptoKey, jsonWebKey: JsonW...
function build (line 145) | async function build(
FILE: app/tasks/pokemon/utils/index.ts
type UserAgents (line 6) | type UserAgents = {
FILE: app/tasks/pokemon/utils/pickVariant.ts
type PickVariant (line 22) | type PickVariant = {
type PokemonVariant (line 29) | type PokemonVariant = {
FILE: app/tasks/shopify/classes/monitor.ts
class ShopifyMonitor (line 28) | class ShopifyMonitor extends BaseMonitor {
method constructor (line 37) | constructor(context: ShopifyContext, platform = Platforms.Shopify) {
method patchContext (line 54) | patchContext() {
method getProducts (line 175) | async getProducts() {
method match (line 253) | async match() {
method getProductDetails (line 281) | async getProductDetails() {
method getProduct (line 357) | async getProduct() {
method monitor (line 514) | async monitor() {
method handleStepLogic (line 547) | async handleStepLogic(currentState: string) {
FILE: app/tasks/shopify/classes/rates.ts
class RateFetcher (line 27) | class RateFetcher extends ShopifyTask {
method constructor (line 36) | constructor(context: ShopifyContext, mainWindow: any) {
method retrieveProfile (line 45) | retrieveProfile() {
method getProducts (line 147) | async getProducts() {
method getProductFrontend (line 218) | async getProductFrontend() {
method getProduct (line 315) | async getProduct() {
method monitor (line 371) | async monitor() {
method submitCart (line 404) | async submitCart() {
method getShipping (line 416) | async getShipping() {
method handleStepLogic (line 490) | async handleStepLogic(currentState: string) {
method run (line 523) | async run() {
FILE: app/tasks/shopify/classes/tasks/base.ts
type ShippingRate (line 78) | type ShippingRate = {
type CookieObject (line 84) | type CookieObject = {
type Injected (line 89) | type Injected = {
class ShopifyTask (line 95) | class ShopifyTask extends BaseTask {
method constructor (line 192) | constructor(
method restart (line 269) | async restart() {
method stuffSession (line 440) | async stuffSession() {
method injectRequester (line 520) | async injectRequester({
method sendWebhook (line 556) | async sendWebhook(body: string, success: boolean) {
method enterQueue (line 685) | async enterQueue(from: string) {
method extractRecaptcha (line 752) | extractRecaptcha(body: string) {
method extractDiscountAuthToken (line 787) | extractDiscountAuthToken($: any) {
method extractAuthToken (line 817) | extractAuthToken(selector: string, $: any) {
method extractCheckoutHash (line 837) | extractCheckoutHash(redirect: string) {
method extractFormThings (line 853) | extractFormThings($: any) {
method extractProtection (line 895) | extractProtection($: any, shipping = false) {
method extractShippingMethod (line 915) | extractShippingMethod($: any) {
method extractCurrency (line 936) | extractCurrency(body: string) {
method extractPrice (line 951) | extractPrice($: any) {
method extractProductName (line 982) | extractProductName($: any) {
method extractGateway (line 998) | extractGateway($: any) {
method extractExpressToken (line 1027) | extractExpressToken(redirect: string) {
method extractPayerId (line 1049) | async extractPayerId({ data }: any) {
method extractReturnUrl (line 1087) | async extractReturnUrl({ data }: any) {
method extractKey (line 1128) | extractKey($: any) {
method extractProduct (line 1147) | extractProduct(body: AddToCartResponse) {
method extractAllData (line 1192) | extractAllData(body: string) {
method extractCartForm (line 1215) | extractCartForm(body: string) {
method extractStepToNextStep (line 1238) | extractStepToNextStep(state: string, body: string) {
method getHomepage (line 1436) | async getHomepage() {
method getConfig (line 1473) | async getConfig() {
method submitPassword (line 1540) | async submitPassword() {
method getAccount (line 1597) | async getAccount() {
method submitAccount (line 1670) | async submitAccount() {
method getChallenge (line 1759) | async getChallenge() {
method submitChallenge (line 1810) | async submitChallenge() {
method waitForProduct (line 1898) | async waitForProduct() {
method submitCart (line 1942) | async submitCart() {
method getCart (line 2024) | async getCart() {
method submitCheckpoint (line 2065) | async submitCheckpoint() {
method getQueue (line 2210) | async getQueue() {
method getNextQueue (line 2277) | async getNextQueue() {
method waitForCaptcha (line 2376) | async waitForCaptcha() {
method getCustomer (line 2419) | async getCustomer() {
method submitCustomer (line 2572) | async submitCustomer() {
method getShipping (line 2715) | async getShipping() {
method submitShipping (line 2872) | async submitShipping() {
method getPayment (line 2970) | async getPayment() {
method submitDiscount (line 3117) | async submitDiscount() {
method getTotalPrice (line 3195) | async getTotalPrice() {
method getSession (line 3263) | async getSession() {
method submitPayment (line 3349) | async submitPayment() {
method createGuest (line 3468) | async createGuest() {
method approveGuest (line 3547) | async approveGuest() {
method getCallbackUrl (line 3601) | async getCallbackUrl() {
method getReview (line 3677) | async getReview() {
method getOrder (line 3750) | async getOrder() {
FILE: app/tasks/shopify/classes/tasks/fast.ts
class FastTask (line 52) | class FastTask extends ShopifyTask {
method constructor (line 75) | constructor(context: ShopifyContext) {
method extractProductApi (line 174) | extractProductApi(body: PatchCartResponse) {
method getConfig (line 206) | async getConfig() {
method submitPassword (line 289) | async submitPassword() {
method submitAccount (line 354) | async submitAccount() {
method getChallenge (line 439) | async getChallenge() {
method submitChallenge (line 490) | async submitChallenge() {
method initialize (line 584) | async initialize() {
method retrieveCartInfo (line 674) | async retrieveCartInfo() {
method patchCheckout (line 720) | async patchCheckout() {
method submitCart (line 930) | async submitCart() {
method getCustomer (line 1015) | async getCustomer() {
method getShipping (line 1150) | async getShipping() {
method submitShipping (line 1281) | async submitShipping() {
method getSession (line 1336) | async getSession() {
method submitPayment (line 1483) | async submitPayment() {
method getPayment (line 1690) | async getPayment() {
method submitReview (line 1788) | async submitReview() {
method getOrder (line 1903) | async getOrder() {
method handleStepLogic (line 2008) | async handleStepLogic(currentState: string) {
FILE: app/tasks/shopify/classes/tasks/pfutile.ts
class PfutileTask (line 46) | class PfutileTask extends ShopifyTask {
method constructor (line 47) | constructor(context: ShopifyContext) {
method checkForCheckpoint (line 64) | async checkForCheckpoint() {
method getConfig (line 110) | async getConfig() {
method submitPassword (line 134) | async submitPassword() {
method waitForCheckpoint (line 154) | async waitForCheckpoint() {
method getProduct (line 189) | async getProduct() {
method presubmitCart (line 263) | async presubmitCart() {
method submitCart (line 346) | async submitCart() {
method getCart (line 378) | async getCart() {
method clearCart (line 403) | async clearCart() {
method initialize (line 440) | async initialize() {
method submitCheckpoint (line 524) | async submitCheckpoint() {
method getPayment (line 658) | async getPayment() {
method getSession (line 773) | async getSession() {
method submitPayment (line 860) | async submitPayment() {
method getOrder (line 1002) | async getOrder() {
method handleStepLogic (line 1014) | async handleStepLogic(currentState: string) {
method abort (line 1092) | abort() {
FILE: app/tasks/shopify/classes/tasks/preload.ts
class PreloadTask (line 15) | class PreloadTask extends ShopifyTask {
method constructor (line 16) | constructor(context: ShopifyContext) {
method checkForCheckpoint (line 32) | async checkForCheckpoint() {
method getConfig (line 75) | async getConfig() {
method submitPassword (line 97) | async submitPassword() {
method getProduct (line 117) | async getProduct() {
method submitCart (line 191) | async submitCart() {
method getCart (line 219) | async getCart() {
method clearCart (line 244) | async clearCart() {
method initialize (line 281) | async initialize() {
method getQueue (line 377) | async getQueue() {
method getOrder (line 387) | async getOrder() {
method handleStepLogic (line 399) | async handleStepLogic(currentState: string) {
method abort (line 474) | abort() {
FILE: app/tasks/shopify/classes/tasks/safe.ts
class SafeTask (line 15) | class SafeTask extends ShopifyTask {
method constructor (line 16) | constructor(context: ShopifyContext) {
method checkForCheckpoint (line 31) | async checkForCheckpoint() {
method getConfig (line 74) | async getConfig() {
method submitPassword (line 97) | async submitPassword() {
method submitCart (line 117) | async submitCart() {
method initialize (line 133) | async initialize() {
method getOrder (line 233) | async getOrder() {
method handleStepLogic (line 245) | async handleStepLogic(currentState: string) {
method abort (line 318) | abort() {
FILE: app/tasks/shopify/mocks/apiCheckouts.tsx
type Data (line 5) | type Data = {
type Checkout (line 9) | type Checkout = {
type Note_attributes (line 66) | type Note_attributes = {};
type Shipping_address (line 67) | type Shipping_address = {
type Billing_address (line 82) | type Billing_address = {
FILE: app/tasks/shopify/mocks/paymentsConfig.ts
type PaymentsConfig (line 3) | type PaymentsConfig = {
type PaymentInstruments (line 6) | type PaymentInstruments = {
type ApplePayConfig (line 21) | type ApplePayConfig = {
type Total (line 34) | type Total = {
type CheckoutConfig (line 39) | type CheckoutConfig = {
type ShopifyPayConfig (line 43) | type ShopifyPayConfig = {
type PaypalConfig (line 49) | type PaypalConfig = {
FILE: app/tasks/shopify/mocks/responseTypes.ts
type ResponseMock (line 1) | type ResponseMock<Data> = {
FILE: app/tasks/shopify/mocks/sessions.ts
type Data (line 3) | type Data = {
FILE: app/tasks/shopify/types/cart.d.ts
type GetCartResponse (line 3) | interface GetCartResponse {
type Attributes (line 19) | interface Attributes {}
type Item (line 21) | interface Item {
type Properties (line 59) | interface Properties {}
type FeaturedImage (line 61) | interface FeaturedImage {
type OptionsWithValue (line 69) | interface OptionsWithValue {
FILE: app/tasks/shopify/types/index.d.ts
type properties (line 3) | type properties = {
type featuredImage (line 7) | type featuredImage = {
type optionsWithValue (line 15) | type optionsWithValue = {
type AddToCartMessage (line 20) | type AddToCartMessage = {
type AddToCartResponse (line 27) | type AddToCartResponse = {
type lineItem (line 65) | type lineItem = {
type address (line 90) | type address = {
type PatchCartResponse (line 106) | type PatchCartResponse = {
FILE: app/tasks/shopify/types/product.d.ts
type Meta (line 3) | interface Meta {
type ProductMeta (line 8) | interface ProductMeta {
type VariantMeta (line 16) | interface VariantMeta {
type Page (line 24) | interface Page {
type Product (line 30) | interface Product {
type Variant (line 46) | interface Variant {
type Image (line 66) | interface Image {
type Option (line 78) | interface Option {
FILE: app/tasks/shopify/types/rates.d.ts
type ShippingRates (line 3) | interface ShippingRates {
type ShippingRate (line 7) | interface ShippingRate {
type Checkout (line 16) | interface Checkout {
FILE: app/tasks/shopify/utils/forms.ts
type Property (line 71) | type Property = {
FILE: app/tasks/shopify/utils/parse.ts
function getParseType (line 18) | function getParseType(product: any) {
FILE: app/tasks/shopify/utils/pickVariant.ts
type ShopifyVariant (line 47) | type ShopifyVariant = {
type PickSize (line 70) | type PickSize = {
FILE: app/tasks/yeezysupply/classes/tasks/base.ts
class YeezySupplyTask (line 68) | class YeezySupplyTask extends BaseTask {
method constructor (line 205) | constructor(context: YeezySupplyContext, platform = Platforms.YeezySup...
method resetAllData (line 359) | async resetAllData() {
method checkSaleLive (line 399) | checkSaleLive(state: string) {
method isBanned (line 408) | isBanned(body: string) {
method checkPixel (line 419) | checkPixel($: any) {
method extractBearerAuth (line 447) | async extractBearerAuth(headers: any) {
method extractHashValue (line 463) | extractHashValue($: any) {
method extractProductData (line 484) | async extractProductData(body: ProductInfoResponse) {
method extractCartData (line 523) | async extractCartData(body: AddToCartResponse) {
method extractOutOfStock (line 531) | extractOutOfStock(body: AddToCartResponse) {
method extractErrorMessage (line 543) | extractErrorMessage(body: ErrorSubmitCheckoutResponse) {
method handleGetAkamai (line 548) | async handleGetAkamai(proceedTo: string) {
method handleFirewall (line 580) | async handleFirewall(proceedTo: string) {
method extractPayload (line 594) | async extractPayload(body: string) {
method extractPxId (line 619) | async extractPxId(body: string) {
method removeInSplashCookie (line 672) | async removeInSplashCookie() {
method setDebugSplashCookies (line 683) | async setDebugSplashCookies() {
method setDefaultCookies (line 719) | async setDefaultCookies(cookies: any[]) {
method setBasketCookies (line 734) | async setBasketCookies() {
method setBoomerangCookie (line 758) | async setBoomerangCookie() {
method setSplashCookie (line 785) | async setSplashCookie() {
method getCorrelationHeaders (line 802) | getCorrelationHeaders() {
method sendWebhook (line 818) | async sendWebhook(body: SubmitCheckoutResponse, message = 'Payment fai...
method waitForSale (line 1002) | async waitForSale() {
method getProduct (line 1140) | async getProduct() {
method getShared (line 1155) | async getShared() {
method getConfig (line 1170) | async getConfig() {
method getHomepage (line 1186) | async getHomepage() {
method getSession (line 1279) | async getSession() {
method getPixel (line 1317) | async getPixel() {
method getAkamai (line 1382) | async getAkamai() {
method getBloom (line 1423) | async getBloom() {
method getBasket (line 1472) | async getBasket() {
method getPayload (line 1560) | async getPayload() {
method submitPixel (line 1593) | async submitPixel() {
method getProductPage (line 1749) | async getProductPage() {
method getWrAsset (line 1910) | async getWrAsset() {
method waitInSplash (line 1945) | async waitInSplash() {
method waitForCaptcha (line 2054) | async waitForCaptcha() {
method getProductInfo (line 2081) | async getProductInfo() {
method getAvailability (line 2159) | async getAvailability() {
method getSensor (line 2283) | async getSensor() {
method submitSensor (line 2310) | async submitSensor() {
method addToCart (line 2403) | async addToCart() {
method submitInformation (line 2508) | async submitInformation() {
method submitCheckout (line 2600) | async submitCheckout() {
method waitForLaunch (line 2699) | async waitForLaunch() {
method waitForClose (line 2754) | async waitForClose() {
method completeCheckout (line 2779) | async completeCheckout() {
method handleStepLogic (line 2860) | async handleStepLogic(currentState: string) {
method abort (line 2922) | abort() {
FILE: app/tasks/yeezysupply/classes/types/index.ts
type messageListItem (line 2) | type messageListItem = {
type pricing (line 9) | type pricing = {
type productLineItem (line 20) | type productLineItem = {
type shipmentListItem (line 52) | type shipmentListItem = {
type customer (line 69) | type customer = {
type shippingAddress (line 79) | type shippingAddress = {
type AddToCartResponse (line 93) | type AddToCartResponse = {
type messageList (line 106) | type messageList = {
type ErrorSubmitCheckoutResponse (line 115) | type ErrorSubmitCheckoutResponse = {
type ProductInfoResponse (line 121) | type ProductInfoResponse = {
type paymentInstrumentListItem (line 182) | type paymentInstrumentListItem = {
type SubmitCheckoutResponse (line 193) | type SubmitCheckoutResponse = {
type SubmitInformationResponse (line 213) | type SubmitInformationResponse = {
type CorrelationHeaders (line 225) | type CorrelationHeaders = {
FILE: app/tasks/yeezysupply/utils/pickVariant.ts
type YeezySupplyVariant (line 22) | type YeezySupplyVariant = {
type PickVariant (line 29) | type PickVariant = {
FILE: app/utils/assert.ts
function assert (line 4) | function assert(condition: any, msg?: string): asserts condition {
function assertIsDefined (line 10) | function assertIsDefined<T>(
FILE: app/utils/cardFormatter.ts
function limit (line 1) | function limit(val, max) {
function cardExpiry (line 20) | function cardExpiry(val) {
FILE: app/utils/eventHandling.ts
function EmitAppEvents (line 4) | function EmitAppEvents() {
FILE: app/utils/loadFile.ts
type TitleStrings (line 6) | type TitleStrings = {
FILE: app/utils/log.ts
method info (line 11) | info(e, title = `Log`, logError = false, allowInProd = false) {
method error (line 23) | error(e, title = `Log`, logError = true, allowInProd = false) {
method doLog (line 43) | doLog(e, logError = true, consoleError = null) {
FILE: app/utils/paths.js
constant PATHS (line 31) | const PATHS = {
FILE: autosolve-client.d.ts
type Stringify (line 3) | type Stringify<T> = string;
type AutoSolveCancelProps (line 5) | type AutoSolveCancelProps = Stringify<{
type AutoSolveResponseProps (line 10) | type AutoSolveResponseProps = Stringify<{
type AutoSolveErrorProps (line 17) | type AutoSolveErrorProps = Stringify<{
type AutoSolve (line 22) | interface AutoSolve {
type AutoSolveProps (line 43) | type AutoSolveProps = {
type AutoSolveEventEmitter (line 55) | interface AutoSolveEventEmitter {
FILE: internals/scripts/CheckBuiltsExist.js
function CheckBuildsExist (line 8) | function CheckBuildsExist() {
FILE: internals/scripts/CheckNodeEnv.js
function CheckNodeEnv (line 5) | function CheckNodeEnv(expectedEnv) {
FILE: jest.setup.js
method constructor (line 39) | constructor() {
FILE: preloads/harvester.js
class CaptchaHandler (line 73) | class CaptchaHandler {
method constructor (line 74) | constructor() {
FILE: test/polyfill.js
method getItem (line 25) | getItem(key) {
method setItem (line 28) | setItem(key, value) {
method removeItem (line 31) | removeItem(key) {
method clear (line 34) | clear() {
FILE: test/testUtils.tsx
type WithProviders (line 34) | type WithProviders = {
FILE: webpack/config.renderer.dev.babel.js
method before (line 268) | before() {
Copy disabled (too large)
Download .json
Condensed preview — 634 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (11,443K chars).
[
{
"path": ".eslintignore",
"chars": 887,
"preview": "# Logs\nlogs\n*.log\n\n# Runtime data\npids\n*.pid\n*.seed\n# Directory for instrumented libs generated by jscoverage/JSCover\nli"
},
{
"path": ".eslintrc.js",
"chars": 2911,
"preview": "module.exports = {\n parser: '@typescript-eslint/parser',\n parserOptions: {\n sourceType: 'module',\n allowImportEx"
},
{
"path": ".gitattributes",
"chars": 81,
"preview": "* text eol=lf\n*.png binary\n*.jpg binary\n*.jpeg binary\n*.ico binary\n*.icns binary\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 1128,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n**Describe the b"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 129,
"preview": "---\nname: Feature request\nabout: You want something added to the app or code.\ntitle: ''\nlabels: enhancement\nassignees: '"
},
{
"path": ".gitignore",
"chars": 969,
"preview": "# Logs\nlogs\n*.log\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nl"
},
{
"path": ".prettierrc",
"chars": 261,
"preview": "{\n \"overrides\": [\n {\n \"files\": [\".prettierrc\", \".babelrc\", \".eslintrc\", \".stylelintrc\"],\n \"options\": {\n "
},
{
"path": ".stylelintrc",
"chars": 164,
"preview": "{\n \"extends\": [\"stylelint-config-standard\", \"stylelint-config-prettier\"],\n \"rules\": {\n \"at-rule-no-unknown\": null,\n"
},
{
"path": "app/3ds.html",
"chars": 259,
"preview": "<html>\n <body>\n <form method=\"POST\" action=\"\" id=\"Cardinal-CCA-Form\">\n <input type=\"hidden\" name=\"PaReq\" value="
},
{
"path": "app/Harvester.html",
"chars": 5196,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <meta\n name=\"viewport\"\n content=\"minimum-scal"
},
{
"path": "app/Question.html",
"chars": 3530,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <link\n href=\"https://fonts.googleapis.co"
},
{
"path": "app/__mocks__/dns.tsx",
"chars": 68,
"preview": "const dns = {\n lookup: (_, cb) => cb(null)\n};\n\nexport default dns;\n"
},
{
"path": "app/__mocks__/electron-ga.tsx",
"chars": 67,
"preview": "class Analytics {\n send = jest.fn();\n}\n\nexport default Analytics;\n"
},
{
"path": "app/__mocks__/electron.tsx",
"chars": 383,
"preview": "import createIPCMock from 'electron-mock-ipc';\n\nconst mocked = createIPCMock();\nexport const { ipcMain, ipcRenderer } = "
},
{
"path": "app/__mocks__/fileMock.tsx",
"chars": 21,
"preview": "module.exports = {};\n"
},
{
"path": "app/__mocks__/request-promise.tsx",
"chars": 1008,
"preview": "// import { CoreOptions, Request } from 'request';\n// import { debugConsole } from '../../test/debug';\n\n// const request"
},
{
"path": "app/__mocks__/styleMock.tsx",
"chars": 21,
"preview": "module.exports = {};\n"
},
{
"path": "app/api/sys/fileOps.ts",
"chars": 1350,
"preview": "import {\n existsSync as _existsSync,\n writeFile as _writeFileAsync,\n appendFile as _appendFileAsync,\n readFileSync a"
},
{
"path": "app/api/sys/index.ts",
"chars": 6028,
"preview": "/* eslint no-await-in-loop: off */\n\nimport {\n readdir as fsReaddir,\n rename as fsRename,\n existsSync,\n statSync,\n l"
},
{
"path": "app/app.html",
"chars": 1478,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta\n name=\"viewport\"\n content=\"mi"
},
{
"path": "app/auth.html",
"chars": 5952,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <link href=\"https://fonts.googleapis.com/css2"
},
{
"path": "app/classes/AppUpdate.ts",
"chars": 14000,
"preview": "/* eslint-disable import/first */\nimport { app, dialog, BrowserWindow } from 'electron';\nimport { autoUpdater, Cancellat"
},
{
"path": "app/classes/Boot.ts",
"chars": 3892,
"preview": "/* eslint no-await-in-loop: off */\n\n/**\n * Boot\n * Note: Don't import log helper file from utils here\n */\n\nimport { read"
},
{
"path": "app/classes/Notification.ts",
"chars": 1148,
"preview": "import { PATHS } from '../utils/paths';\nimport { IS_DEV } from '../constants/env';\n/* Cache of Audio elements, for insta"
},
{
"path": "app/classes/ProxyTester.ts",
"chars": 2198,
"preview": "import { isEmpty } from 'lodash';\n\nimport { ipcMain, IpcMainInvokeEvent, BrowserWindow } from 'electron';\nimport { IPCKe"
},
{
"path": "app/classes/Storage.ts",
"chars": 2069,
"preview": "import { log } from '../utils/log';\nimport {\n readFileSync,\n writeFileSync,\n deleteFilesSync\n} from '../api/sys/fileO"
},
{
"path": "app/components/Analytics/Loadable.tsx",
"chars": 245,
"preview": "import Loadable from 'react-imported-component';\nimport LoadingIndicator from '../LoadingIndicator';\n\n/* eslint import/n"
},
{
"path": "app/components/Analytics/__tests__/Analytics.spec.tsx",
"chars": 1196,
"preview": "import { render } from '@testing-library/react';\nimport '@testing-library/jest-dom/extend-expect';\nimport React from 're"
},
{
"path": "app/components/Analytics/actions/checkouts.tsx",
"chars": 389,
"preview": "import prefixer from '../../../utils/reducerPrefixer';\n\nconst prefix = '@@Checkouts';\nconst checkoutTypesList = ['ADD'];"
},
{
"path": "app/components/Analytics/actions/index.tsx",
"chars": 203,
"preview": "import { checkoutActionTypes, checkoutActions } from './checkouts';\nimport { newsActionTypes, newsActions } from './news"
},
{
"path": "app/components/Analytics/actions/news.tsx",
"chars": 348,
"preview": "import prefixer from '../../../utils/reducerPrefixer';\n\nconst prefix = '@@News';\nconst newsTypesList = ['ADD'];\n\nexport "
},
{
"path": "app/components/Analytics/components/checkouts.tsx",
"chars": 7284,
"preview": "import React from 'react';\nimport classnames from 'classnames';\nimport { useDispatch, useSelector } from 'react-redux';\n"
},
{
"path": "app/components/Analytics/components/expenses.tsx",
"chars": 5255,
"preview": "/* eslint-disable no-console */\nimport React from 'react';\nimport { useSelector, useDispatch } from 'react-redux';\nimpor"
},
{
"path": "app/components/Analytics/components/news.tsx",
"chars": 2345,
"preview": "import React from 'react';\nimport { useSelector } from 'react-redux';\nimport { sortBy } from 'lodash';\nimport moment fro"
},
{
"path": "app/components/Analytics/components/orders.tsx",
"chars": 2519,
"preview": "import React from 'react';\nimport { useSelector } from 'react-redux';\nimport { Typography, Grid } from '@material-ui/cor"
},
{
"path": "app/components/Analytics/components/stats.tsx",
"chars": 5652,
"preview": "/* eslint-disable no-restricted-syntax */\n/* eslint-disable no-console */\nimport React, { useCallback } from 'react';\nim"
},
{
"path": "app/components/Analytics/components/welcome.tsx",
"chars": 4305,
"preview": "import React from 'react';\nimport { PURGE } from 'redux-persist';\nimport { useSelector, useDispatch } from 'react-redux'"
},
{
"path": "app/components/Analytics/index.tsx",
"chars": 931,
"preview": "import React from 'react';\nimport { makeStyles } from '@material-ui/styles';\nimport { Grid } from '@material-ui/core';\ni"
},
{
"path": "app/components/Analytics/reducers/checkouts.tsx",
"chars": 554,
"preview": "import { PURGE } from 'redux-persist';\n\nimport { checkoutActionTypes } from '../actions/checkouts';\n\ntype Action = {\n t"
},
{
"path": "app/components/Analytics/reducers/index.tsx",
"chars": 101,
"preview": "import { Checkouts } from './checkouts';\nimport { News } from './news';\n\nexport { Checkouts, News };\n"
},
{
"path": "app/components/Analytics/reducers/news.tsx",
"chars": 572,
"preview": "import { PURGE } from 'redux-persist';\n\nimport { newsActionTypes } from '../actions';\n\ntype Action = {\n type: string;\n "
},
{
"path": "app/components/Analytics/styles/checkouts.tsx",
"chars": 3200,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => {\n return {\n container: {\n "
},
{
"path": "app/components/Analytics/styles/expenses.tsx",
"chars": 2526,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => {\n return {\n gridItem: {\n "
},
{
"path": "app/components/Analytics/styles/index.tsx",
"chars": 388,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => {\n return {\n root: {\n m"
},
{
"path": "app/components/Analytics/styles/news.tsx",
"chars": 2189,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => {\n return {\n gridItem: {\n "
},
{
"path": "app/components/Analytics/styles/orders.tsx",
"chars": 2118,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => {\n return {\n container: {\n "
},
{
"path": "app/components/Analytics/styles/shipments.tsx",
"chars": 3719,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => {\n return {\n loadingSpinner:"
},
{
"path": "app/components/Analytics/styles/stats.tsx",
"chars": 2393,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => {\n return {\n gridItem: {\n "
},
{
"path": "app/components/Analytics/styles/welcome.tsx",
"chars": 2147,
"preview": "import { mixins } from '../../../styles/js';\n\nexport const styles = theme => {\n return {\n gridItem: {\n height: "
},
{
"path": "app/components/Analytics/types.tsx",
"chars": 857,
"preview": "/* eslint-disable camelcase */\n// Generated by https://quicktype.io\n\nexport interface PackageAPIResponse {\n id: string;"
},
{
"path": "app/components/App/App.tsx",
"chars": 2922,
"preview": "import React, { useEffect, useCallback } from 'react';\nimport { ipcRenderer } from 'electron';\nimport { CssBaseline } fr"
},
{
"path": "app/components/App/Providers.tsx",
"chars": 3059,
"preview": "/* eslint-disable react/no-children-prop */\nimport React, { useMemo } from 'react';\nimport { Provider, useSelector } fro"
},
{
"path": "app/components/App/Root.tsx",
"chars": 527,
"preview": "import React from 'react';\nimport { PersistGate } from 'redux-persist/integration/react';\nimport { HashRouter } from 're"
},
{
"path": "app/components/App/__tests__/App.spec.tsx",
"chars": 1194,
"preview": "import { render } from '@testing-library/react';\nimport '@testing-library/jest-dom/extend-expect';\nimport React from 're"
},
{
"path": "app/components/App/__tests__/Root.spec.tsx",
"chars": 1254,
"preview": "import { render } from '@testing-library/react';\nimport '@testing-library/jest-dom/extend-expect';\nimport React from 're"
},
{
"path": "app/components/App/actions.tsx",
"chars": 1786,
"preview": "import prefixer from '../../utils/reducerPrefixer';\n\nconst appPrefix = '@@App';\nconst appActionTypesList = [\n 'REQ_LOAD"
},
{
"path": "app/components/App/components/titlebar/Titlebar.tsx",
"chars": 416,
"preview": "import React from 'react';\nimport { makeStyles } from '@material-ui/styles';\nimport { useLocation } from 'react-router-d"
},
{
"path": "app/components/App/components/toolbar/area.tsx",
"chars": 196,
"preview": "import React from 'react';\nimport ToolbarBody from './body';\n\nconst ToolbarAreaPane = ({ ...parentProps }: any) => {\n r"
},
{
"path": "app/components/App/components/toolbar/body.tsx",
"chars": 2464,
"preview": "import React, { useState, useCallback } from 'react';\nimport { makeStyles } from '@material-ui/styles';\nimport { useLoca"
},
{
"path": "app/components/App/components/toolbar/menu.tsx",
"chars": 2356,
"preview": "import React, { MouseEvent } from 'react';\n\nimport { Fade, Menu, MenuItem } from '@material-ui/core';\n\nimport { makeStyl"
},
{
"path": "app/components/App/components/toolbar/profile.tsx",
"chars": 2626,
"preview": "import React from 'react';\nimport { useSelector } from 'react-redux';\nimport classnames from 'classnames';\nimport { make"
},
{
"path": "app/components/App/reducers.tsx",
"chars": 2747,
"preview": "import { startCase } from 'lodash';\nimport { PURGE } from 'redux-persist';\n\nimport {\n globalActionTypes,\n userActionTy"
},
{
"path": "app/components/App/selectors.tsx",
"chars": 459,
"preview": "import { createSelector } from 'reselect';\nimport { RootState } from '../../store/reducers';\nimport { initialState, init"
},
{
"path": "app/components/App/styles/Titlebar.tsx",
"chars": 242,
"preview": "import { mixins } from '../../../styles/js';\n\nexport const styles = () => {\n return {\n root: {\n width: `calc(10"
},
{
"path": "app/components/App/styles/ToolbarAreaPane.tsx",
"chars": 2538,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => {\n return {\n root: {\n b"
},
{
"path": "app/components/App/styles/index.tsx",
"chars": 4326,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const dark = {\n props: {\n MuiButtonBase: {\n dis"
},
{
"path": "app/components/Calendar/Calendar.tsx",
"chars": 972,
"preview": "import React, { useState } from 'react';\nimport { Text, Flex } from 'rebass';\nimport { Container } from './Container';\ni"
},
{
"path": "app/components/Calendar/CalendarMonth.tsx",
"chars": 2278,
"preview": "import React from 'react';\nimport styled from 'styled-components';\nimport moment from 'moment';\nimport LeftIcon from '@m"
},
{
"path": "app/components/Calendar/CalendarYear.tsx",
"chars": 526,
"preview": "import React from 'react';\nimport styled from 'styled-components';\nimport moment from 'moment';\nimport Month from './Mon"
},
{
"path": "app/components/Calendar/Container.tsx",
"chars": 686,
"preview": "import React from 'react';\nimport styled from 'styled-components';\nimport { layout } from 'styled-system';\n\nexport const"
},
{
"path": "app/components/Calendar/Month.tsx",
"chars": 1961,
"preview": "import React from 'react';\nimport { Flex, Text } from 'rebass';\nimport { space } from 'styled-system';\nimport moment, { "
},
{
"path": "app/components/Calendar/ViewSelect.tsx",
"chars": 1736,
"preview": "import React from 'react';\nimport WindowedSelect from 'react-windowed-select';\nimport styled from 'styled-components';\ni"
},
{
"path": "app/components/Captchas/Harvesters.tsx",
"chars": 736,
"preview": "import React from 'react';\nimport { useDispatch } from 'react-redux';\nimport { makeStyles } from '@material-ui/styles';\n"
},
{
"path": "app/components/Captchas/Loadable.tsx",
"chars": 250,
"preview": "import Loadable from 'react-imported-component';\nimport LoadingIndicator from '../LoadingIndicator';\n\n/* eslint import/n"
},
{
"path": "app/components/Captchas/__tests__/Harvesters.spec.tsx",
"chars": 501,
"preview": "import { render } from '@testing-library/react';\nimport '@testing-library/jest-dom/extend-expect';\nimport React from 're"
},
{
"path": "app/components/Captchas/actions/captchas.tsx",
"chars": 916,
"preview": "import prefixer from '../../../utils/reducerPrefixer';\n\nconst prefix = '@@Captcha';\nexport const captchasActionList = ['"
},
{
"path": "app/components/Captchas/actions/index.tsx",
"chars": 472,
"preview": "import {\n createCaptcha,\n editCaptcha,\n deleteCaptcha,\n captchasActionTypes,\n captchasActionList,\n captchasActions"
},
{
"path": "app/components/Captchas/components/actionBar/ActionBar.tsx",
"chars": 792,
"preview": "import React from 'react';\nimport { makeStyles } from '@material-ui/styles';\nimport { Grid } from '@material-ui/core';\ni"
},
{
"path": "app/components/Captchas/components/card/index.tsx",
"chars": 11429,
"preview": "import React, { useState } from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport { useConfirm } f"
},
{
"path": "app/components/Captchas/components/grid/index.tsx",
"chars": 543,
"preview": "import React from 'react';\nimport { useSelector } from 'react-redux';\nimport NoChildrenComponent from '../../../NoChildr"
},
{
"path": "app/components/Captchas/reducers/captchas.tsx",
"chars": 2328,
"preview": "import { ipcRenderer } from 'electron';\nimport uuidv4 from 'uuidv4';\nimport { PURGE } from 'redux-persist';\n\nimport { ca"
},
{
"path": "app/components/Captchas/reducers/index.tsx",
"chars": 61,
"preview": "import { Captchas } from './captchas';\n\nexport { Captchas };\n"
},
{
"path": "app/components/Captchas/selectors.tsx",
"chars": 292,
"preview": "import { createSelector } from 'reselect';\nimport { Captchas } from './reducers';\n\nimport { RootState } from '../../stor"
},
{
"path": "app/components/Captchas/styles/actionBar.tsx",
"chars": 1209,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => {\n return {\n root: {\n j"
},
{
"path": "app/components/Captchas/styles/card.tsx",
"chars": 4857,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => {\n return {\n root: {\n m"
},
{
"path": "app/components/Captchas/styles/createDialog.tsx",
"chars": 4059,
"preview": "import { variables } from '../../../styles/js';\n\nexport const styles = theme => ({\n margin: {},\n rootSm: {\n width: "
},
{
"path": "app/components/Captchas/styles/index.tsx",
"chars": 398,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => {\n return {\n root: {\n m"
},
{
"path": "app/components/DebouncedInput/DebouncedInput.tsx",
"chars": 1373,
"preview": "import React, { useState } from 'react';\n\ntype Props = {\n InputComponent: any;\n isNumerical?: boolean;\n properties: o"
},
{
"path": "app/components/ErrorBoundary/components/GenerateErrorReport.tsx",
"chars": 2118,
"preview": "import React, { Component } from 'react';\nimport { shell, ipcRenderer } from 'electron';\nimport { connect } from 'react-"
},
{
"path": "app/components/ErrorBoundary/components/GenerateErrorReportBody.tsx",
"chars": 514,
"preview": "import React, { PureComponent } from 'react';\nimport { Button } from '@material-ui/core';\n\nexport default class Generate"
},
{
"path": "app/components/ErrorBoundary/index.tsx",
"chars": 2181,
"preview": "import React, { PureComponent } from 'react';\nimport { withRouter } from 'react-router-dom';\nimport { withStyles } from "
},
{
"path": "app/components/ErrorBoundary/styles/GenerateErrorReport.tsx",
"chars": 1279,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => ({\n subHeading: {\n ...mixins"
},
{
"path": "app/components/ErrorBoundary/styles/index.tsx",
"chars": 1432,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => ({\n root: {\n textAlign: `cen"
},
{
"path": "app/components/ImportExport/components/dialog.tsx",
"chars": 8634,
"preview": "/* eslint-disable @typescript-eslint/no-unused-vars */\nimport React from 'react';\nimport { useDispatch, useStore } from "
},
{
"path": "app/components/ImportExport/index.tsx",
"chars": 1380,
"preview": "import React, { useMemo } from 'react';\nimport { makeStyles } from '@material-ui/styles';\nimport classNames from 'classn"
},
{
"path": "app/components/ImportExport/styles/index.tsx",
"chars": 4892,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => ({\n margin: {},\n root: {},\n d"
},
{
"path": "app/components/Legal/PrivacyPolicy/Loadable.tsx",
"chars": 248,
"preview": "import Loadable from 'react-imported-component';\nimport LoadingIndicator from '../../LoadingIndicator';\n\n/* eslint impor"
},
{
"path": "app/components/Legal/PrivacyPolicy/__tests__/PrivacyPolicy.spec.tsx",
"chars": 1205,
"preview": "import { render } from '@testing-library/react';\nimport '@testing-library/jest-dom/extend-expect';\nimport React from 're"
},
{
"path": "app/components/Legal/PrivacyPolicy/index.tsx",
"chars": 18680,
"preview": "import React, { Component } from 'react';\nimport { withStyles } from '@material-ui/styles';\nimport { Typography } from '"
},
{
"path": "app/components/Legal/PrivacyPolicy/styles/index.tsx",
"chars": 708,
"preview": "import { variables, mixins } from '../../../../styles/js';\n\nexport const styles = theme => ({\n root: {\n color: theme"
},
{
"path": "app/components/Legal/TermsOfService/Loadable.tsx",
"chars": 248,
"preview": "import Loadable from 'react-imported-component';\nimport LoadingIndicator from '../../LoadingIndicator';\n\n/* eslint impor"
},
{
"path": "app/components/Legal/TermsOfService/__tests__/TermsOfService.spec.tsx",
"chars": 1210,
"preview": "import { render } from '@testing-library/react';\nimport '@testing-library/jest-dom/extend-expect';\nimport React from 're"
},
{
"path": "app/components/Legal/TermsOfService/index.tsx",
"chars": 17346,
"preview": "import React, { Component } from 'react';\nimport { withStyles } from '@material-ui/styles';\nimport { Typography } from '"
},
{
"path": "app/components/Legal/TermsOfService/styles/index.tsx",
"chars": 708,
"preview": "import { variables, mixins } from '../../../../styles/js';\n\nexport const styles = theme => ({\n root: {\n color: theme"
},
{
"path": "app/components/LoadingIndicator/index.tsx",
"chars": 426,
"preview": "import React from 'react';\nimport { makeStyles } from '@material-ui/styles';\nimport CircularProgress from '@material-ui/"
},
{
"path": "app/components/LoadingIndicator/styles/index.tsx",
"chars": 106,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => ({\n root: {}\n});\n"
},
{
"path": "app/components/NoChildrenComponent/index.tsx",
"chars": 788,
"preview": "import React from 'react';\nimport { makeStyles } from '@material-ui/styles';\nimport { Typography, Grid } from '@material"
},
{
"path": "app/components/NoChildrenComponent/styles/index.tsx",
"chars": 552,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => ({\n root: {\n display: 'flex'"
},
{
"path": "app/components/Profiles/Loadable.tsx",
"chars": 197,
"preview": "import Loadable from 'react-imported-component';\nimport LoadingIndicator from '../LoadingIndicator';\n\nexport default Loa"
},
{
"path": "app/components/Profiles/Profiles.tsx",
"chars": 610,
"preview": "import React from 'react';\nimport { makeStyles } from '@material-ui/styles';\nimport { Grid } from '@material-ui/core';\ni"
},
{
"path": "app/components/Profiles/__tests__/Profiles.spec.tsx",
"chars": 1194,
"preview": "import { render } from '@testing-library/react';\nimport '@testing-library/jest-dom/extend-expect';\nimport React from 're"
},
{
"path": "app/components/Profiles/actions/index.tsx",
"chars": 979,
"preview": "import {\n importProfiles,\n exportProfiles,\n editProfile,\n loadProfile,\n saveProfile,\n deleteProfile,\n deleteProfi"
},
{
"path": "app/components/Profiles/actions/profiles.tsx",
"chars": 1912,
"preview": "import prefixer from '../../../utils/reducerPrefixer';\nimport { toggleField, SETTINGS_FIELDS } from '../../Settings/acti"
},
{
"path": "app/components/Profiles/components/actionBar/index.tsx",
"chars": 2505,
"preview": "import React from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport { useConfirm } from 'material-"
},
{
"path": "app/components/Profiles/components/card/index.tsx",
"chars": 4002,
"preview": "import React from 'react';\nimport { useDispatch } from 'react-redux';\nimport { useConfirm } from 'material-ui-confirm';\n"
},
{
"path": "app/components/Profiles/components/create/ProfileCreateDialog.tsx",
"chars": 4590,
"preview": "import React from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport { makeStyles } from '@material"
},
{
"path": "app/components/Profiles/components/create/__tests__/ProfileCreateDialog.spec.tsx",
"chars": 1774,
"preview": "import { render, fireEvent } from '@testing-library/react';\nimport '@testing-library/jest-dom/extend-expect';\nimport Rea"
},
{
"path": "app/components/Profiles/components/create/billing.tsx",
"chars": 8169,
"preview": "import React from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport WindowedSelect from 'react-win"
},
{
"path": "app/components/Profiles/components/create/payment.tsx",
"chars": 5233,
"preview": "import React, { useState } from 'react';\nimport { useDispatch } from 'react-redux';\nimport Cards from 'react-credit-card"
},
{
"path": "app/components/Profiles/components/create/shipping.tsx",
"chars": 9012,
"preview": "import React from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport WindowedSelect from 'react-win"
},
{
"path": "app/components/Profiles/components/grid/index.tsx",
"chars": 531,
"preview": "import React from 'react';\nimport { useSelector } from 'react-redux';\nimport NoChildrenComponent from '../../../NoChildr"
},
{
"path": "app/components/Profiles/reducers/current.tsx",
"chars": 2135,
"preview": "import { PURGE } from 'redux-persist';\n\nimport { profilesActionTypes, PROFILE_FIELDS } from '../actions';\nimport { locat"
},
{
"path": "app/components/Profiles/reducers/index.tsx",
"chars": 121,
"preview": "import { CurrentProfile } from './current';\nimport { Profiles } from './profiles';\n\nexport { CurrentProfile, Profiles };"
},
{
"path": "app/components/Profiles/reducers/location.tsx",
"chars": 1369,
"preview": "import { LOCATION_FIELDS } from '../actions';\n\nexport const location: Address = {\n name: '',\n address: '',\n apt: '',\n"
},
{
"path": "app/components/Profiles/reducers/payment.tsx",
"chars": 484,
"preview": "export const payment: Payment = {\n holder: '',\n card: '',\n exp: '',\n cvv: '',\n type: ''\n};\n\nexport type Payment = {"
},
{
"path": "app/components/Profiles/reducers/profiles.tsx",
"chars": 3538,
"preview": "import uuidv4 from 'uuidv4';\nimport valid from 'card-validator';\nimport { ipcRenderer } from 'electron';\nimport { PURGE "
},
{
"path": "app/components/Profiles/selectors.tsx",
"chars": 492,
"preview": "import { createSelector } from 'reselect';\nimport { Profiles, CurrentProfile } from './reducers';\n\nimport { RootState } "
},
{
"path": "app/components/Profiles/styles/actionBar.tsx",
"chars": 1430,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => {\n return {\n root: {\n j"
},
{
"path": "app/components/Profiles/styles/card.tsx",
"chars": 2670,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => {\n return {\n cardCell: {\n "
},
{
"path": "app/components/Profiles/styles/createDialog.tsx",
"chars": 2589,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => ({\n margin: {},\n rootLg: {\n "
},
{
"path": "app/components/Profiles/styles/index.tsx",
"chars": 422,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => {\n return {\n root: {\n m"
},
{
"path": "app/components/Progressbar/Loadable.tsx",
"chars": 245,
"preview": "import Loadable from 'react-imported-component';\nimport LoadingIndicator from '../LoadingIndicator';\n\n/* eslint import/n"
},
{
"path": "app/components/Progressbar/index.tsx",
"chars": 2286,
"preview": "import { ipcRenderer } from 'electron';\nimport React, { Component } from 'react';\nimport { withStyles } from '@material-"
},
{
"path": "app/components/Progressbar/styles/index.tsx",
"chars": 326,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => ({\n root: {\n textAlign: `lef"
},
{
"path": "app/components/Proxies/Loadable.tsx",
"chars": 196,
"preview": "import Loadable from 'react-imported-component';\nimport LoadingIndicator from '../LoadingIndicator';\n\nexport default Loa"
},
{
"path": "app/components/Proxies/Proxies.tsx",
"chars": 661,
"preview": "import React from 'react';\nimport { makeStyles } from '@material-ui/styles';\n\nimport ProxyTable from './components/Table"
},
{
"path": "app/components/Proxies/__tests__/Proxies.spec.tsx",
"chars": 1189,
"preview": "import { render } from '@testing-library/react';\nimport '@testing-library/jest-dom/extend-expect';\nimport React from 're"
},
{
"path": "app/components/Proxies/actions/index.tsx",
"chars": 2640,
"preview": "/* eslint-disable no-unused-vars */\n\nimport prefixer from '../../../utils/reducerPrefixer';\nimport { toggleField, SETTIN"
},
{
"path": "app/components/Proxies/components/ProxyActionBar.tsx",
"chars": 6233,
"preview": "import React from 'react';\nimport { useSelector, useDispatch } from 'react-redux';\nimport classnames from 'classnames';\n"
},
{
"path": "app/components/Proxies/components/ProxyCreateDialog.tsx",
"chars": 4676,
"preview": "import React, { useEffect, useState } from 'react';\nimport { ipcRenderer } from 'electron';\nimport { useDispatch, useSel"
},
{
"path": "app/components/Proxies/components/Table/ProxyTable.tsx",
"chars": 5022,
"preview": "import React, { useEffect, useState, memo, useCallback } from 'react';\nimport { ipcRenderer } from 'electron';\nimport me"
},
{
"path": "app/components/Proxies/components/Table/components/tableHead.tsx",
"chars": 3011,
"preview": "import React from 'react';\nimport { useDispatch } from 'react-redux';\nimport { makeStyles } from '@material-ui/styles';\n"
},
{
"path": "app/components/Proxies/components/Table/components/tableRow.tsx",
"chars": 3214,
"preview": "import React from 'react';\nimport { useDispatch } from 'react-redux';\nimport classnames from 'classnames';\nimport { make"
},
{
"path": "app/components/Proxies/components/Table/components/tableToolbar.tsx",
"chars": 3830,
"preview": "import React from 'react';\nimport { ipcRenderer } from 'electron';\nimport { useDispatch, useSelector } from 'react-redux"
},
{
"path": "app/components/Proxies/components/Table/styles/index.tsx",
"chars": 3646,
"preview": "export const styles = theme => ({\n tableRoot: {\n width: '100%',\n height: '100%'\n },\n table: {\n height: '100%"
},
{
"path": "app/components/Proxies/components/Table/styles/tableToolbar.tsx",
"chars": 1523,
"preview": "'use strict';\n\nimport { mixins } from '../../../../../styles/js';\n\nexport const styles = theme => ({\n root: {\n paddi"
},
{
"path": "app/components/Proxies/components/__tests__/ProxyCreateDialog.spec.tsx",
"chars": 635,
"preview": "import { render } from '@testing-library/react';\nimport '@testing-library/jest-dom/extend-expect';\nimport React from 're"
},
{
"path": "app/components/Proxies/reducers/current.tsx",
"chars": 1376,
"preview": "import { PURGE } from 'redux-persist';\n\nimport { proxiesActionTypes, PROXY_FIELDS } from '../actions';\n\nexport const ini"
},
{
"path": "app/components/Proxies/reducers/index.tsx",
"chars": 118,
"preview": "import { CurrentProxies } from './current';\nimport { Proxies } from './proxies';\n\nexport { Proxies, CurrentProxies };\n"
},
{
"path": "app/components/Proxies/reducers/proxies.tsx",
"chars": 5703,
"preview": "import { PURGE } from 'redux-persist';\n\nimport { ipcRenderer } from 'electron';\nimport { proxiesActionTypes } from '../a"
},
{
"path": "app/components/Proxies/selectors.tsx",
"chars": 735,
"preview": "import { createSelector } from 'reselect';\nimport { CurrentProxies, Proxies } from './reducers';\n\nimport { RootState } f"
},
{
"path": "app/components/Proxies/styles/actionBar.tsx",
"chars": 2142,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => {\n return {\n root: {\n j"
},
{
"path": "app/components/Proxies/styles/createDialog.tsx",
"chars": 4088,
"preview": "import { variables } from '../../../styles/js';\n\nexport const styles = theme => ({\n margin: {},\n root: {\n height: 4"
},
{
"path": "app/components/Proxies/styles/index.tsx",
"chars": 692,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => {\n return {\n root: {\n w"
},
{
"path": "app/components/ReportBugs/Loadable.tsx",
"chars": 245,
"preview": "import Loadable from 'react-imported-component';\nimport LoadingIndicator from '../LoadingIndicator';\n\n/* eslint import/n"
},
{
"path": "app/components/ReportBugs/__tests__/ReportBugs.spec.tsx",
"chars": 1203,
"preview": "import { render } from '@testing-library/react';\nimport '@testing-library/jest-dom/extend-expect';\nimport React from 're"
},
{
"path": "app/components/ReportBugs/index.tsx",
"chars": 612,
"preview": "import React from 'react';\nimport { makeStyles } from '@material-ui/styles';\nimport { Helmet } from 'react-helmet';\nimpo"
},
{
"path": "app/components/ReportBugs/styles/index.tsx",
"chars": 178,
"preview": "import { mixins } from '../../../styles/js';\n\nexport const styles = () => ({\n root: {\n textAlign: `center`,\n ...m"
},
{
"path": "app/components/Settings/actions.tsx",
"chars": 6325,
"preview": "import prefixer from '../../utils/reducerPrefixer';\nimport { HookTypes } from '../../constants';\n\nconst settingsPrefix ="
},
{
"path": "app/components/Settings/components/dialog/ProductField.tsx",
"chars": 1198,
"preview": "import React from 'react';\nimport { makeStyles } from '@material-ui/styles';\nimport { Typography, FormGroup, Input } fro"
},
{
"path": "app/components/Settings/components/dialog/ProfileField.tsx",
"chars": 1944,
"preview": "import React from 'react';\nimport { useSelector } from 'react-redux';\nimport WindowedSelect from 'react-windowed-select'"
},
{
"path": "app/components/Settings/components/dialog/StoreField.tsx",
"chars": 2086,
"preview": "import React from 'react';\nimport { useSelector } from 'react-redux';\nimport CreatableSelect from 'react-select/creatabl"
},
{
"path": "app/components/Settings/components/dialog/accounts.tsx",
"chars": 6276,
"preview": "import React from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport WindowedSelect from 'react-win"
},
{
"path": "app/components/Settings/components/dialog/defaults.tsx",
"chars": 9459,
"preview": "import React from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport CreatableSelect from 'react-se"
},
{
"path": "app/components/Settings/components/dialog/generics.tsx",
"chars": 9460,
"preview": "import React, { useState } from 'react';\nimport { ipcRenderer } from 'electron';\nimport { makeStyles } from '@material-u"
},
{
"path": "app/components/Settings/components/dialog/index.tsx",
"chars": 7751,
"preview": "import React, { useState, useEffect } from 'react';\nimport { ipcRenderer } from 'electron';\nimport { makeStyles } from '"
},
{
"path": "app/components/Settings/components/dialog/rates.tsx",
"chars": 7602,
"preview": "import React, { useState } from 'react';\nimport { useSelector, useDispatch } from 'react-redux';\nimport { ipcRenderer } "
},
{
"path": "app/components/Settings/components/dialog/webhooks.tsx",
"chars": 6435,
"preview": "import React from 'react';\nimport { ipcRenderer } from 'electron';\nimport { useSelector, useDispatch } from 'react-redux"
},
{
"path": "app/components/Settings/index.tsx",
"chars": 355,
"preview": "import React, { useMemo } from 'react';\nimport SettingsDialog from './components/dialog';\n\nconst Settings = ({\n show,\n "
},
{
"path": "app/components/Settings/reducers/accounts.tsx",
"chars": 2709,
"preview": "import uuidv4 from 'uuidv4';\nimport { PURGE } from 'redux-persist';\n\nimport { CurrentAccount } from './currentAccount';\n"
},
{
"path": "app/components/Settings/reducers/currentAccount.tsx",
"chars": 1574,
"preview": "import { PURGE } from 'redux-persist';\n\nimport { accountsActionTypes } from '../actions';\n\nexport type CurrentAccount = "
},
{
"path": "app/components/Settings/reducers/currentWebhook.tsx",
"chars": 1532,
"preview": "import { PURGE } from 'redux-persist';\n\nimport { webhookActionTypes } from '../actions';\n\nexport type CurrentWebhook = {"
},
{
"path": "app/components/Settings/reducers/defaults.tsx",
"chars": 1105,
"preview": "import { PURGE } from 'redux-persist';\n\nimport { defaultsActionTypes } from '../actions';\n\ntype Action = {\n type: strin"
},
{
"path": "app/components/Settings/reducers/index.tsx",
"chars": 736,
"preview": "import { Settings, settingsInitialState } from './settings';\nimport { Accounts, accountsInitialState } from './accounts'"
},
{
"path": "app/components/Settings/reducers/rates.ts",
"chars": 1170,
"preview": "import { unionBy } from 'lodash';\nimport { PURGE } from 'redux-persist';\n\nimport { ratesActionTypes } from '../actions';"
},
{
"path": "app/components/Settings/reducers/settings.tsx",
"chars": 3146,
"preview": "import { ipcRenderer } from 'electron';\nimport { PURGE } from 'redux-persist';\n\nimport { settingsActionTypes } from '../"
},
{
"path": "app/components/Settings/reducers/webhooks.tsx",
"chars": 1504,
"preview": "import { ipcRenderer } from 'electron';\nimport uuidv4 from 'uuidv4';\nimport { PURGE } from 'redux-persist';\n\nimport { we"
},
{
"path": "app/components/Settings/selectors.tsx",
"chars": 2486,
"preview": "import { createSelector } from 'reselect';\nimport {\n accountsInitialState,\n currentAccountInitialState,\n webhooksInit"
},
{
"path": "app/components/Settings/styles/index.tsx",
"chars": 6191,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => ({\n margin: {},\n root: {},\n d"
},
{
"path": "app/components/Sidebar/Sidebar.tsx",
"chars": 15231,
"preview": "import React, { Fragment, useState, useCallback } from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\n"
},
{
"path": "app/components/Sidebar/__tests__/Sidebar.spec.tsx",
"chars": 468,
"preview": "import { render } from '@testing-library/react';\nimport '@testing-library/jest-dom/extend-expect';\nimport React from 're"
},
{
"path": "app/components/Sidebar/components/AnimatedLogo.tsx",
"chars": 1694,
"preview": "import React, { useState, useCallback } from 'react';\nimport { animated, useSpring } from 'react-spring';\nimport { Fade "
},
{
"path": "app/components/Sidebar/components/icons.tsx",
"chars": 1310,
"preview": "import React from 'react';\n\nimport AppsIcon from '@material-ui/icons/Apps';\nimport EventNoteTwoToneIcon from '@material-"
},
{
"path": "app/components/Sidebar/components/menuItems.tsx",
"chars": 992,
"preview": "import { routeTo } from '../../../routing/routes';\n\nexport const SIDEBAR = {\n // USELESS WITHOUT API\n // Dashboard: {\n"
},
{
"path": "app/components/Sidebar/styles/index.tsx",
"chars": 4595,
"preview": "import { variables, mixins } from '../../../styles/js';\n\nexport const styles = theme => ({\n root: {\n boxShadow: `5px"
},
{
"path": "app/components/Tasks/Loadable.tsx",
"chars": 194,
"preview": "import Loadable from 'react-imported-component';\nimport LoadingIndicator from '../LoadingIndicator';\n\nexport default Loa"
},
{
"path": "app/components/Tasks/Tasks.tsx",
"chars": 1003,
"preview": "import React, { useCallback, useMemo, useState } from 'react';\nimport { makeStyles } from '@material-ui/styles';\n\nimport"
},
{
"path": "app/components/Tasks/__tests__/Tasks.spec.tsx",
"chars": 1961,
"preview": "import { render } from '@testing-library/react';\nimport '@testing-library/jest-dom/extend-expect';\nimport React from 're"
},
{
"path": "app/components/Tasks/actions/index.tsx",
"chars": 6808,
"preview": "/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable no-unused-vars */\n\nimport { ipcRenderer } from "
},
{
"path": "app/components/Tasks/components/Table/TableData.tsx",
"chars": 2678,
"preview": "import React, { useMemo } from 'react';\nimport { useSelector } from 'react-redux';\nimport { makeStyles } from '@material"
},
{
"path": "app/components/Tasks/components/Table/TableWrapper.tsx",
"chars": 1526,
"preview": "import React, { useCallback, useState } from 'react';\nimport { makeStyles } from '@material-ui/styles';\nimport { Table }"
},
{
"path": "app/components/Tasks/components/Table/TaskList.tsx",
"chars": 711,
"preview": "import React from 'react';\nimport { makeStyles } from '@material-ui/styles';\n\nimport { styles } from './styles';\n\nimport"
},
{
"path": "app/components/Tasks/components/Table/components/TableBodyWrapper.tsx",
"chars": 5013,
"preview": "import React, { memo, useCallback, useMemo } from 'react';\nimport memoize from 'memoize-one';\nimport { useSelector, useD"
},
{
"path": "app/components/Tasks/components/Table/components/TableHeader.tsx",
"chars": 3031,
"preview": "import React from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport classnames from 'classnames';\n"
},
{
"path": "app/components/Tasks/components/Table/components/cells/checkbox.tsx",
"chars": 899,
"preview": "import React, { useMemo } from 'react';\nimport classnames from 'classnames';\nimport { makeStyles } from '@material-ui/st"
},
{
"path": "app/components/Tasks/components/Table/components/cells/product.tsx",
"chars": 2767,
"preview": "import React, { useMemo } from 'react';\nimport { useSelector } from 'react-redux';\nimport classnames from 'classnames';\n"
},
{
"path": "app/components/Tasks/components/Table/components/cells/profile.tsx",
"chars": 796,
"preview": "import React, { useMemo } from 'react';\nimport classnames from 'classnames';\nimport { makeStyles } from '@material-ui/st"
},
{
"path": "app/components/Tasks/components/Table/components/cells/proxies.tsx",
"chars": 796,
"preview": "import React, { useMemo } from 'react';\nimport classnames from 'classnames';\nimport { makeStyles } from '@material-ui/st"
},
{
"path": "app/components/Tasks/components/Table/components/cells/sizes.tsx",
"chars": 1130,
"preview": "import React, { useMemo } from 'react';\nimport classnames from 'classnames';\nimport { makeStyles } from '@material-ui/st"
},
{
"path": "app/components/Tasks/components/Table/components/cells/status.tsx",
"chars": 2283,
"preview": "import React from 'react';\nimport { ipcRenderer } from 'electron';\n\nimport classnames from 'classnames';\nimport { makeSt"
}
]
// ... and 434 more files (download for full content)
About this extraction
This page contains the full source code of the walmat/nebula GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 634 files (10.6 MB), approximately 2.8M tokens, and a symbol index with 1022 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.