{"version":3,"file":"static/js/index.21cb3d99.js","sources":["webpack://Snaily/./src/api/automationApi.ts","webpack://Snaily/./src/api/api-rtk.ts","webpack://Snaily/./src/features/team/const.ts","webpack://Snaily/./src/shared/integrations/mui.tsx","webpack://Snaily/./src/features/notifications/slice.ts","webpack://Snaily/./src/shared/redux-helpers.ts","webpack://Snaily/./src/redux/reducers/leftSideMenu.ts","webpack://Snaily/./src/shared/hooks/store.ts","webpack://Snaily/./src/shared/hooks/left-side.ts","webpack://Snaily/./src/shared/hooks/useDocumentTitle.ts","webpack://Snaily/./src/shared/hooks/useIntersectionObserver.ts","webpack://Snaily/./src/shared/hooks/useMount.ts","webpack://Snaily/./src/shared/hooks/useSwitcher.ts","webpack://Snaily/./src/features/notifications/ui/Notification/Notification.tsx","webpack://Snaily/./src/features/notifications/ui/Snackbar.tsx","webpack://Snaily/./src/features/notifications/ui/SnackNotification/Attention.tsx","webpack://Snaily/./src/features/notifications/ui/SnackNotification/Default.tsx","webpack://Snaily/./src/config/objectConst.js","webpack://Snaily/./src/shared/errors/BackendValidationError.ts","webpack://Snaily/./src/shared/errors/BadGatewayError.ts","webpack://Snaily/./src/shared/errors/FatalError.ts","webpack://Snaily/./src/shared/errors/NotAuthorizedError.ts","webpack://Snaily/./src/api/contactsPageSize.ts","webpack://Snaily/./src/redux/reducers/app.ts","webpack://Snaily/./src/actions/app.js","webpack://Snaily/./src/actions/connector.ts","webpack://Snaily/./src/api/httpRequest.js","webpack://Snaily/./src/api/api.js","webpack://Snaily/./src/shared/integrations/sentry.ts","webpack://Snaily/./src/config/helpers.js","webpack://Snaily/./src/features/subscription/utils.ts","webpack://Snaily/./src/shared/errors/notificate.ts","webpack://Snaily/./src/features/notifications/utils/error.ts","webpack://Snaily/./src/shared/errors/RequestTimedOutError.ts","webpack://Snaily/./src/api/utils/rtk.ts","webpack://Snaily/./src/features/messaging/utils/adapters.ts","webpack://Snaily/./src/features/messaging/model/slice.ts","webpack://Snaily/./src/shared/day.ts","webpack://Snaily/./src/features/messaging/const.ts","webpack://Snaily/./src/features/messaging/utils/utils.ts","webpack://Snaily/./src/features/messaging/utils/selectors.ts","webpack://Snaily/./src/features/messaging/utils/query.ts","webpack://Snaily/./src/features/messaging/utils/update.ts","webpack://Snaily/./src/features/messaging/api.ts","webpack://Snaily/./src/features/messaging/utils/optimistic.ts","webpack://Snaily/./src/features/messaging/hooks/useCurrentId.ts","webpack://Snaily/./src/features/messaging/hooks/useConversationalist.ts","webpack://Snaily/./src/features/messaging/ui/const.ts","webpack://Snaily/./src/shared/styles/a11y.module.scss?64a0","webpack://Snaily/./src/shared/styles/context-actions.module.scss?80dd","webpack://Snaily/./src/shared/styles/typography.module.scss?40d7","webpack://Snaily/./src/shared/ui/Button/Button.module.scss?b517","webpack://Snaily/./src/shared/ui/Button/Button.tsx","webpack://Snaily/./src/shared/ui/CustomSelect/DropdownIndicator.tsx","webpack://Snaily/./src/shared/ui/CustomSelect/CustomSelect.module.scss?c614","webpack://Snaily/./src/shared/ui/CustomSelect/CustomSelect.tsx","webpack://Snaily/./src/shared/ui/Segmented/Radios.tsx","webpack://Snaily/./src/shared/ui/Segmented/Segmented.module.scss?3b21","webpack://Snaily/./src/shared/ui/StackIcon/keys.ts","webpack://Snaily/./src/shared/ui/StackIcon/StackIcon.tsx","webpack://Snaily/./src/components/molecules/ModalWindow/index.js","webpack://Snaily/./src/features/messaging/ui/DeleteMessage.tsx","webpack://Snaily/./src/features/messaging/ui/Empty/Empty.tsx","webpack://Snaily/./src/features/messaging/ui/Empty/Empty.module.scss?b765","webpack://Snaily/./src/shared/observer.ts","webpack://Snaily/./src/features/messaging/ui/FilterForm/FilterForm.module.scss?f023","webpack://Snaily/./src/features/messaging/ui/FilterForm/TempDebug.tsx","webpack://Snaily/./src/features/messaging/ui/Emoji/style.module.scss?6dbc","webpack://Snaily/./src/features/messaging/ui/Emoji/Select.tsx","webpack://Snaily/./src/features/messaging/ui/MessageActions/MessageActions.module.scss?fc6a","webpack://Snaily/./src/features/messaging/ui/MessageActions/utils.ts","webpack://Snaily/./src/features/messaging/ui/MessageActions/MessageActions.tsx","webpack://Snaily/./src/components/atoms/responsiveButton/index.tsx","webpack://Snaily/./src/features/messaging/ui/Emoji/FormPicker.tsx","webpack://Snaily/./src/features/messaging/ui/MessageForm/MessageForm.module.scss?bb0c","webpack://Snaily/./src/features/messaging/ui/MessageForm/MessageForm.tsx","webpack://Snaily/./src/features/messaging/ui/MessageForm/useRead.ts","webpack://Snaily/./src/features/messaging/ui/MessageForm/utils/addChar.ts","webpack://Snaily/./src/features/messaging/ui/Chat/Chat.module.scss?1b54","webpack://Snaily/./src/components/atoms/FullLoader/FullLoader.tsx","webpack://Snaily/./src/components/atoms/FullLoader/FullLoader.module.scss?b338","webpack://Snaily/./src/features/messaging/ui/Emoji/Reactions.tsx","webpack://Snaily/./src/shared/polyfills/positioning.ts","webpack://Snaily/./src/shared/utils.ts","webpack://Snaily/./src/features/messaging/ui/Message/Message.module.scss?d2f7","webpack://Snaily/./src/features/messaging/ui/Message/Body.tsx","webpack://Snaily/./src/features/messaging/ui/Message/Message.tsx","webpack://Snaily/./src/features/messaging/ui/MessageActions/useOpened.ts","webpack://Snaily/./src/features/messaging/ui/Chat/Conversation.tsx","webpack://Snaily/./src/features/messaging/ui/Chat/Chat.tsx","webpack://Snaily/./src/features/messaging/ui/ChatHeader/ChatHeader.module.scss?3a31","webpack://Snaily/./src/features/messaging/ui/ChatHeader/SyncButton.tsx","webpack://Snaily/./src/features/messaging/ui/ChatHeader/ChatHeader.tsx","webpack://Snaily/./src/features/messaging/ui/QuickActions/QuickActions.module.scss?747a","webpack://Snaily/./src/features/messaging/ui/QuickActions/utils/open.ts","webpack://Snaily/./src/features/messaging/ui/QuickActions/QuickActions.tsx","webpack://Snaily/./src/features/messaging/ui/Thumbnail/Thumbnail.module.scss?76bc","webpack://Snaily/./src/features/messaging/ui/Thumbnail/Thumbnail.tsx","webpack://Snaily/./src/features/messaging/ui/QuickActions/useOpened.ts","webpack://Snaily/./src/features/messaging/ui/Conversations/Conversations.module.scss?11e6","webpack://Snaily/./src/features/messaging/ui/Conversations/Conversations.tsx","webpack://Snaily/./src/features/messaging/hooks/useSelectFirstChat.ts","webpack://Snaily/./src/features/messaging/ui/FilterForm/FilterForm.tsx","webpack://Snaily/./src/features/executions/api.ts","webpack://Snaily/./src/features/executions/ui/ConversationTogglers/ConversationTogglers.tsx","webpack://Snaily/./src/features/executions/ui/ConversationTogglers/ConversationTogglers.module.scss?33b2","webpack://Snaily/./src/features/executions/utils.ts","webpack://Snaily/./src/features/messaging/ui/ResumeButton.tsx","webpack://Snaily/./src/features/messaging/ui/Mailbox/Mailbox.tsx","webpack://Snaily/./src/features/messaging/ui/Mailbox/Mailbox.module.scss?e511","webpack://Snaily/./src/features/messaging/ui/UnreadCount/UnreadCount.module.scss?74ce","webpack://Snaily/./src/features/messaging/ui/UnreadCount/UnreadCount.tsx","webpack://Snaily/./src/redux/reducers/activity.js","webpack://Snaily/./src/redux/reducers/campaign.js","webpack://Snaily/./src/redux/reducers/campaignCreate.ts","webpack://Snaily/./src/redux/reducers/campaigns.ts","webpack://Snaily/./src/redux/reducers/contacts.js","webpack://Snaily/./src/redux/reducers/filters.js","webpack://Snaily/./src/redux/reducers/home.js","webpack://Snaily/./src/redux/reducers/teams.js","webpack://Snaily/./src/redux/store.ts","webpack://Snaily/./src/config/notifications.ts","webpack://Snaily/./src/features/notifications/utils/snack.ts","webpack://Snaily/./src/features/workspace/api.ts","webpack://Snaily/./src/features/workspace/ui/Perfomed/Performed.tsx","webpack://Snaily/./src/features/workspace/utils/refetch.ts","webpack://Snaily/./src/features/workspace/utils/selectors.ts","webpack://Snaily/./src/components/app/connectorFactory.js","webpack://Snaily/./src/shared/connector/singleton.ts","webpack://Snaily/./src/shared/connector/hooks.ts","webpack://Snaily/./src/shared/hooks/useLatest.ts","webpack://Snaily/./src/shared/connector/redux-sync.ts","webpack://Snaily/./src/shared/connector/index.ts","webpack://Snaily/./src/api/linkedInProfileOpener.js","webpack://Snaily/./src/components/atoms/LinkedInBlock/index.js","webpack://Snaily/./src/tools/functions.js","webpack://Snaily/./src/actions/mapping.typed.ts","webpack://Snaily/./src/actions/mapping.js","webpack://Snaily/./src/api/activity/apiActivity.js","webpack://Snaily/./src/actions/activity.js","webpack://Snaily/./src/features/activity/hooks.ts","webpack://Snaily/./src/components/molecules/dailyLimitsEditor/DailyLimitsEditor.module.scss?6c83","webpack://Snaily/./src/components/molecules/dailyLimitsEditor/index.tsx","webpack://Snaily/./src/components/molecules/account/AccountProfile.module.scss?3431","webpack://Snaily/./src/components/molecules/account/adapter.ts","webpack://Snaily/./src/components/molecules/account/accountProfile.tsx","webpack://Snaily/./src/components/molecules/TableTeams/subscriptionHelper.js","webpack://Snaily/./src/components/molecules/dateSelection/utils.ts","webpack://Snaily/./src/components/molecules/dateSelection/hooks.ts","webpack://Snaily/./src/components/atoms/DateInput/index.js","webpack://Snaily/./src/components/molecules/dateSelection/DateSelection.tsx","webpack://Snaily/./src/components/molecules/SelectTimeZone/SelectTimeZone.module.scss?ce82","webpack://Snaily/./src/components/molecules/SelectTimeZone/index.tsx","webpack://Snaily/./src/components/molecules/account/workingHoursProfile/utils.ts","webpack://Snaily/./src/components/molecules/account/workingHoursProfile/index.tsx","webpack://Snaily/./src/components/molecules/account/automationMode/index.tsx","webpack://Snaily/./src/components/molecules/account/subscriptionBilling/index.js","webpack://Snaily/./src/components/molecules/account/workingHoursProfile/workingHours.tsx","webpack://Snaily/./src/components/molecules/account/workingHoursProfile/hooks.ts","webpack://Snaily/./src/components/atoms/SupportButton/SupportButton.module.scss?62ee","webpack://Snaily/./src/components/atoms/SupportButton/SupportButton.tsx","webpack://Snaily/./src/actions/contacts.js","webpack://Snaily/./src/api/campaign/apiCampaign.js","webpack://Snaily/./src/actions/campaign.typed.ts","webpack://Snaily/./src/actions/campaign.js","webpack://Snaily/./src/actions/filters.js","webpack://Snaily/./src/components/atoms/tooltipCustom/index.js","webpack://Snaily/./src/components/molecules/trialNotification/TrialNotification.module.scss?dba0","webpack://Snaily/./src/components/molecules/trialNotification/index.tsx","webpack://Snaily/./src/components/molecules/leftSideMenu/index.tsx","webpack://Snaily/./src/components/molecules/leftSideMenu/LeftSideMenu.module.scss?df03","webpack://Snaily/./src/components/molecules/navigationMenu/NavigationMenu.module.scss?6f5b","webpack://Snaily/./src/components/molecules/navigationMenu/NavigationMenu.tsx","webpack://Snaily/./src/components/atoms/Logo/index.js","webpack://Snaily/./src/api/connector/api.ts","webpack://Snaily/./src/shared/hooks/useStopReloadSession.ts","webpack://Snaily/./src/components/organisms/userProfilePersona/UserHeaderWidget.module.scss?f00b","webpack://Snaily/./src/components/organisms/userProfilePersona/LogOut.tsx","webpack://Snaily/./src/components/organisms/userProfilePersona/dropDownMenu.tsx","webpack://Snaily/./src/components/organisms/userProfilePersona/index.tsx","webpack://Snaily/./src/components/organisms/Header/Header.module.scss?3965","webpack://Snaily/./src/components/organisms/Header/ImpersonatedTimer.tsx","webpack://Snaily/./src/components/organisms/Header/index.tsx","webpack://Snaily/./src/components/templates/homeTemplate/HomeTemplate.module.scss?42c7","webpack://Snaily/./src/components/templates/homeTemplate/Legacy.tsx","webpack://Snaily/./src/components/templates/homeTemplate/LoggedLayout.tsx","webpack://Snaily/./src/pages/account/AccountPage.module.scss?bcf8","webpack://Snaily/./src/pages/account/index.tsx","webpack://Snaily/./src/components/atoms/ExceededLimitNotification/index.js","webpack://Snaily/./src/components/atoms/WorkingHoursNotification/index.js","webpack://Snaily/./src/components/molecules/linkedInNotLogged/LinkedInNotLogged.tsx","webpack://Snaily/./src/components/molecules/linkedInNotLogged/LinkedInNotLogged.module.scss?38ec","webpack://Snaily/./src/api/executionHumanState.js","webpack://Snaily/./src/api/stepExecutionState.js","webpack://Snaily/./src/api/statesDescriptor.js","webpack://Snaily/./src/components/molecules/tableActivity/index.js","webpack://Snaily/./src/pages/activityQueue/ActivityPage.module.scss?1bf8","webpack://Snaily/./src/pages/activityQueue/index.tsx","webpack://Snaily/./src/components/atoms/HintTooltip/index.js","webpack://Snaily/./src/components/atoms/ConfirmationDialog/index.js","webpack://Snaily/./src/components/atoms/ExportToCSVButton/index.js","webpack://Snaily/./src/features/campaigns/api.ts","webpack://Snaily/./src/features/campaigns/const.ts","webpack://Snaily/./src/features/campaigns/ui/SubInfo/SubInfo.tsx","webpack://Snaily/./src/components/atoms/mTablePagination/CustomPagination.module.scss?4f1d","webpack://Snaily/./src/components/atoms/mTablePagination/Actions.tsx","webpack://Snaily/./src/components/atoms/mTablePagination/PaginationWrapper.tsx","webpack://Snaily/./src/components/molecules/tableCampaigns/index.js","webpack://Snaily/./src/components/atoms/Tag/index.tsx","webpack://Snaily/./src/components/atoms/DropdownSimple/index.js","webpack://Snaily/./src/components/atoms/ConfirmationDialogRunning/index.js","webpack://Snaily/./src/components/atoms/buttonCreateCampaigns/index.js","webpack://Snaily/./src/components/atoms/TextFieldCustom/index.tsx","webpack://Snaily/./src/components/molecules/CampaignFilters/Statuses.module.scss?5731","webpack://Snaily/./src/components/molecules/CampaignFilters/Statuses.tsx","webpack://Snaily/./src/components/molecules/CampaignFilters/index.tsx","webpack://Snaily/./src/components/templates/NoSearchResult/NoSearchResult.tsx","webpack://Snaily/./src/components/templates/NoSearchResult/NoSearchResult.module.scss?6b50","webpack://Snaily/./src/components/templates/NoSearchResult/index.tsx","webpack://Snaily/./src/pages/archiveCampaigns/index.js","webpack://Snaily/./src/actions/campaignCreate.ts","webpack://Snaily/./src/components/atoms/ErrorHelper/index.js","webpack://Snaily/./src/components/molecules/formField/index.js","webpack://Snaily/./src/components/organisms/CampaingsStepCreate/timer.js","webpack://Snaily/./src/components/atoms/ErrorHelperStep/index.js","webpack://Snaily/./src/components/molecules/selectContainer/index.js","webpack://Snaily/./src/components/organisms/CampaingsStepCreate/ActionSelect.module.scss?1867","webpack://Snaily/./src/components/organisms/CampaingsStepCreate/ActionSelect.tsx","webpack://Snaily/./src/shared/hooks/useMenuPopup.ts","webpack://Snaily/./src/components/organisms/CampaingsStepCreate/utils/actions.ts","webpack://Snaily/./src/components/organisms/CampaingsStepCreate/utils/index.ts","webpack://Snaily/./src/components/organisms/CampaingsStepCreate/step.js","webpack://Snaily/./src/components/organisms/CampaingsStepCreate/index.tsx","webpack://Snaily/./src/components/templates/notFoundTemplate/index.tsx","webpack://Snaily/./src/pages/notfound/index.js","webpack://Snaily/./src/pages/campaignCreate/index.tsx","webpack://Snaily/./src/api/hubspot/api.ts","webpack://Snaily/./src/components/organisms/Hubspot/CampaignsHubspot.module.scss?3695","webpack://Snaily/./src/components/organisms/Hubspot/utils.ts","webpack://Snaily/./src/components/organisms/Hubspot/index.tsx","webpack://Snaily/./src/pages/campaignHubspot/index.tsx","webpack://Snaily/./src/components/templates/noCampaignsYetTemplate/index.tsx","webpack://Snaily/./src/components/templates/noCampaignsYetTemplate/NoCampaignsYetTemplate.module.scss?5505","webpack://Snaily/./src/api/pauseReason.js","webpack://Snaily/./src/components/molecules/InformationalTip/index.js","webpack://Snaily/./src/components/molecules/buildStatusCampaign/index.js","webpack://Snaily/./src/components/molecules/personalCampaignsStatistics/index.js","webpack://Snaily/./src/pages/campaigns/index.tsx","webpack://Snaily/./src/components/atoms/buttonAddToCampaigns/index.js","webpack://Snaily/./src/components/atoms/ConfirmationDialogContacts/index.js","webpack://Snaily/./src/components/atoms/ConfirmationDialogExclude/index.js","webpack://Snaily/./src/components/atoms/customCellRenderer/index.js","webpack://Snaily/./src/components/atoms/customCheckbox/index.js","webpack://Snaily/./src/components/atoms/headerCheckbox/index.js","webpack://Snaily/./src/components/atoms/tableSettingsModal/index.js","webpack://Snaily/./src/components/atoms/tooltipCustomTable/index.js","webpack://Snaily/./src/components/atoms/tooltipCustomWrapper/index.js","webpack://Snaily/./src/components/molecules/TableUsers/btn-group.js","webpack://Snaily/./src/components/molecules/TableUsers/functions.js","webpack://Snaily/./src/components/molecules/TableUsers/informationBlock.js","webpack://Snaily/./src/components/molecules/TableUsers/SortIcon.module.scss?6995","webpack://Snaily/./src/components/molecules/TableUsers/sortIcons.tsx","webpack://Snaily/./src/components/molecules/TableUsers/index.js","webpack://Snaily/./src/components/atoms/ReactDatePicker/ReactDatePicker.tsx","webpack://Snaily/./src/components/atoms/DatePickerRange/DatePickerRange.module.scss?95a7","webpack://Snaily/./src/components/atoms/DatePickerRange/DatePickerRange.tsx","webpack://Snaily/./src/components/atoms/RadioGroupCustom/index.js","webpack://Snaily/./src/components/organisms/filters/const.ts","webpack://Snaily/./src/components/organisms/filters/index.js","webpack://Snaily/./src/components/organisms/filters/Filters.module.scss?f931","webpack://Snaily/./src/components/molecules/filterNavigation/index.js","webpack://Snaily/./src/components/templates/noContactsYetTemplate/index.js","webpack://Snaily/./src/components/molecules/ModalForCsvExport/index.js","webpack://Snaily/./src/components/organisms/CsvExport/constants.js","webpack://Snaily/./src/components/organisms/ExportTab/index.js","webpack://Snaily/./src/components/atoms/DropZone/index.js","webpack://Snaily/./src/components/organisms/CsvExport/ErrorExport/index.js","webpack://Snaily/./src/components/organisms/CsvExport/ExportComplete/index.js","webpack://Snaily/./src/components/atoms/CsvExportUploader/index.js","webpack://Snaily/./src/components/organisms/CsvExport/FoundContacts/index.js","webpack://Snaily/./src/components/atoms/DropZoneFull/index.js","webpack://Snaily/./src/components/organisms/CsvExport/ExportContent/index.js","webpack://Snaily/./src/components/organisms/CsvExport/ExportContentSearch/index.js","webpack://Snaily/./src/components/organisms/CsvExport/index.js","webpack://Snaily/./src/components/atoms/TextFieldBig/index.js","webpack://Snaily/./src/actions/import.ts","webpack://Snaily/./src/pages/contacts/index.js","webpack://Snaily/./src/pages/Mailbox.tsx","webpack://Snaily/./src/features/team/api.ts","webpack://Snaily/./src/features/team/util/selector.ts","webpack://Snaily/./src/features/team/hooks/useHasInvited.ts","webpack://Snaily/./src/features/team/hooks/useIsEnable.ts","webpack://Snaily/./src/features/team/hooks/useParamPerson.ts","webpack://Snaily/./src/features/team/ui/SignIn/SignIn.tsx","webpack://Snaily/./src/features/team/ui/SignIn/SignIn.module.scss?ee4e","webpack://Snaily/./src/actions/teams.js","webpack://Snaily/./src/components/molecules/ModalPersonas/index.js","webpack://Snaily/./src/features/team/ui/Fallbacks/style.module.scss?1925","webpack://Snaily/./src/features/team/ui/Fallbacks/ModalIncludesTeam.tsx","webpack://Snaily/./src/features/team/ui/Wrapper/useInviteModal.ts","webpack://Snaily/./src/features/team/ui/Fallbacks/ModalNotTeam.tsx","webpack://Snaily/./src/features/team/ui/Fallbacks/ModalNotTeam.module.scss?abbc","webpack://Snaily/./src/features/team/ui/Fallbacks/UpgradeSubscriptionTeam.tsx","webpack://Snaily/./src/features/team/ui/Fallbacks/Fallbacks.tsx","webpack://Snaily/./src/features/team/ui/Wrapper/Wrapper.tsx","webpack://Snaily/./src/features/team/hooks/useSidebar.ts","webpack://Snaily/./src/pages/MessagingPage.tsx","webpack://Snaily/./src/components/molecules/descriptionList/index.js","webpack://Snaily/./src/components/molecules/statisticList/index.tsx","webpack://Snaily/./src/components/organisms/chart/index.js","webpack://Snaily/./src/components/organisms/chart/chartModel.js","webpack://Snaily/./src/components/organisms/descriptionSegment/DescriptionSegment.module.scss?6326","webpack://Snaily/./src/components/organisms/descriptionSegment/index.tsx","webpack://Snaily/./src/components/organisms/headerTemplate/index.js","webpack://Snaily/./src/components/atoms/SegmentButtonGroup/index.js","webpack://Snaily/./src/components/organisms/CampaignDescriptionSegment/style.module.scss?ad56","webpack://Snaily/./src/components/organisms/CampaignDescriptionSegment/SubActions.tsx","webpack://Snaily/./src/components/organisms/CampaignDescriptionSegment/index.js","webpack://Snaily/./src/pages/singleCampaign/index.js","webpack://Snaily/./src/components/organisms/AddContactsModal/index.tsx","webpack://Snaily/./src/components/molecules/filterNavigationExecutions/index.js","webpack://Snaily/./src/components/organisms/filtersExecutions/index.js","webpack://Snaily/./src/pages/singleContacts/utils.ts","webpack://Snaily/./src/pages/singleContacts/hooks/useOpenContacts.ts","webpack://Snaily/./src/pages/singleContacts/fallback-cards/style.module.scss?ee4a","webpack://Snaily/./src/pages/singleContacts/fallback-cards/ContactCards.tsx","webpack://Snaily/./src/pages/singleContacts/fallback-cards/Launch.tsx","webpack://Snaily/./src/pages/singleContacts/index.js","webpack://Snaily/./src/components/molecules/TableTeamsInvite/index.js","webpack://Snaily/./src/pages/team/useLegacyPersonas.ts","webpack://Snaily/./src/pages/team/invitations/index.tsx","webpack://Snaily/./src/components/molecules/ModalSubscription/index.js","webpack://Snaily/./src/components/molecules/TableTeams/index.js","webpack://Snaily/./src/pages/team/members/MembersPage.tsx","webpack://Snaily/./src/components/organisms/filtersTeam/index.js","webpack://Snaily/./src/components/molecules/CampaignFiltersTeams/index.js","webpack://Snaily/./src/components/molecules/personalCampaignsStatistics/sortIconsCampaigns.js","webpack://Snaily/./src/components/molecules/TeamCampaignStatistics/index.js","webpack://Snaily/./src/pages/team/statistics/temp.ts","webpack://Snaily/./src/pages/team/statistics/index.tsx","webpack://Snaily/./src/features/orders/api.ts","webpack://Snaily/./src/features/subscription/api.ts","webpack://Snaily/./src/pages/upgrade/hooks/useLeftMenu.ts","webpack://Snaily/./src/pages/upgrade/UpgradePage.tsx","webpack://Snaily/./src/features/subscription/hooks/usePlans.ts","webpack://Snaily/./src/pages/upgrade/hooks/useCheckout.ts","webpack://Snaily/./src/components/templates/authTemplate/AuthTemplate.module.scss?c2b0","webpack://Snaily/./src/components/templates/authTemplate/index.tsx","webpack://Snaily/./src/components/containers/badAuthContainer/index.tsx","webpack://Snaily/./src/components/app/AuthCallback.tsx","webpack://Snaily/./src/components/app/ErrorBoundary.js","webpack://Snaily/./src/components/app/hooks/useListeners.ts","webpack://Snaily/./src/shared/integrations/gtm.ts","webpack://Snaily/./src/shared/integrations/hotjar.ts","webpack://Snaily/./src/components/molecules/ModalVerified/index.js","webpack://Snaily/./src/components/molecules/ModalVerifiedError/index.js","webpack://Snaily/./src/components/app/InvitationCallback.js","webpack://Snaily/./src/api/referrerDetector.ts","webpack://Snaily/./src/features/onboard/ui/NoAuth/NoAuth.tsx","webpack://Snaily/./src/features/onboard/ui/NoInstalled/NoInstalled.tsx","webpack://Snaily/./src/features/onboard/ui/NoInstalled/NoInstalled.module.scss?6c91","webpack://Snaily/./src/shared/ui/Dialog/polyfill.tsx","webpack://Snaily/./src/shared/ui/Dialog/ControlledDialog.tsx","webpack://Snaily/./src/features/onboard/ui/NoLinkedin/NoLinkedinContainer.module.scss?608e","webpack://Snaily/./src/features/onboard/ui/NoLinkedin/modal.tsx","webpack://Snaily/./src/features/onboard/ui/NoLinkedin/NoLinkedin.tsx","webpack://Snaily/./src/features/onboard/ui/NoTimezone/NoTimezone.module.scss?ebd4","webpack://Snaily/./src/features/onboard/ui/NoTimezone/NoTimezone.tsx","webpack://Snaily/./src/features/onboard/ui/NoWorkingHours/NoWorkingHours.module.scss?69f2","webpack://Snaily/./src/features/onboard/ui/NoWorkingHours/Modal.tsx","webpack://Snaily/./src/features/onboard/ui/NoWorkingHours/NoWorkingHours.tsx","webpack://Snaily/./src/features/onboard/ui/Controller.tsx","webpack://Snaily/./src/components/app/LayoutUser.tsx","webpack://Snaily/./src/components/app/ReferrerPage.js","webpack://Snaily/./src/components/app/utils/auth-check.ts","webpack://Snaily/./src/components/app/utils/init.ts","webpack://Snaily/./src/index.tsx","webpack://Snaily/./src/components/app/App.tsx","webpack://Snaily/./src/components/app/hooks/useTrackingUser.ts","webpack://Snaily/./src/shared/polyfills/index.ts"],"sourcesContent":["import { createApi } from '@reduxjs/toolkit/query/react'\r\n\r\nimport { CONSTS } from '../config/objectConst'\r\nimport { axiosBaseQuery } from './utils/rtk'\r\n\r\n// const baseQuery = fetchBaseQuery({\r\n// baseUrl: CONSTS.API.URL_AUTOMATION,\r\n\r\n// async prepareHeaders(headers) {\r\n// const token = await connectorAPI.getAccessToken();\r\n// headers.set(\"Authorization\", token);\r\n// },\r\n// });\r\n\r\nexport const enum Tag {\r\n\tConversation = 'C',\r\n\tMessages = 'M',\r\n\tUnreadStats = 'U'\r\n}\r\n\r\nexport const automationApi = createApi({\r\n\tbaseQuery: axiosBaseQuery({\r\n\t\tbaseUrl: CONSTS.API.URL_AUTOMATION\r\n\t}),\r\n\tendpoints: () => ({}),\r\n\treducerPath: 'automationApi',\r\n\ttagTypes: [Tag.Conversation, Tag.Messages, Tag.UnreadStats]\r\n})\r\n","import { createApi } from '@reduxjs/toolkit/query/react'\r\n\r\nimport { CONSTS } from '../config/objectConst'\r\nimport { axiosBaseQuery } from './utils/rtk'\r\n\r\nexport const enum Tag {\r\n\tExecutions = 'E',\r\n\tSubscription = 'S',\r\n\tTeamMembers = 'TM',\r\n\tWorkspaceStats = 'WS'\r\n}\r\n\r\nexport const apiRTK = createApi({\r\n\tbaseQuery: axiosBaseQuery({\r\n\t\tbaseUrl: CONSTS.API.URL\r\n\t}),\r\n\tendpoints: () => ({}),\r\n\treducerPath: 'api',\r\n\ttagTypes: [\r\n\t\tTag.Subscription,\r\n\t\tTag.WorkspaceStats,\r\n\t\tTag.TeamMembers,\r\n\t\tTag.Executions\r\n\t]\r\n})\r\n","import members from 'assets/image/icons/svg/people-group-active.svg'\r\nimport invited from 'assets/image/icons/svg/sent-inventActive.svg'\r\nimport statistics from 'assets/image/icons/svg/statisticsActive.svg'\r\n\r\nconst enum TeamSideId {\r\n\tMembers,\r\n\tStatistics,\r\n\tInvites\r\n}\r\n\r\nconst SIDEBAR_ITEMS = [\r\n\t{\r\n\t\tid: TeamSideId.Members,\r\n\t\timage: members,\r\n\t\tlink: '/team/members',\r\n\t\ttitle: 'Members'\r\n\t},\r\n\t{\r\n\t\tid: TeamSideId.Statistics,\r\n\t\timage: statistics,\r\n\t\tlink: '/team/statistics',\r\n\t\ttitle: 'Statistics'\r\n\t},\r\n\t{\r\n\t\tid: TeamSideId.Invites,\r\n\t\timage: invited,\r\n\t\tlink: '/team/invitations',\r\n\t\ttitle: 'Pending invites'\r\n\t}\r\n]\r\n\r\nexport { SIDEBAR_ITEMS, TeamSideId }\r\n","/* eslint-disable perfectionist/sort-objects */\r\nimport type { FC, PropsWithChildren } from 'react'\r\n\r\nimport { createTheme, ThemeProvider } from '@mui/material/styles'\r\n\r\nconst theme = createTheme({\r\n\tpalette: {\r\n\t\tprimary: {\r\n\t\t\tmain: 'hsl(173deg 87% 37%)' // ! Don't support css vars\r\n\t\t\t// dark: 'var(--primary-text)'\r\n\t\t}\r\n\t},\r\n\r\n\tcomponents: {\r\n\t\tMuiTextField: {\r\n\t\t\tstyleOverrides: {\r\n\t\t\t\troot: {\r\n\t\t\t\t\t'& .MuiOutlinedInput-input': {\r\n\t\t\t\t\t\tbackgroundColor: '#fff',\r\n\t\t\t\t\t\tcolor: '#202020',\r\n\t\t\t\t\t\tfontSize: '0.875rem',\r\n\t\t\t\t\t\tfontWeight: 'normal',\r\n\t\t\t\t\t\tlineHeight: '1.43'\r\n\t\t\t\t\t\t// outlineColor: 'var(--primary)',\r\n\t\t\t\t\t},\r\n\t\t\t\t\t'& .MuiOutlinedInput-notchedOutline': {\r\n\t\t\t\t\t\tborderColor: 'var(--grey-nuance)'\r\n\t\t\t\t\t},\r\n\t\t\t\t\t'& .Mui-focused .MuiOutlinedInput-notchedOutline': {\r\n\t\t\t\t\t\tborderColor: 'var(--primary)',\r\n\t\t\t\t\t\tborderWidth: '1px'\r\n\t\t\t\t\t},\r\n\t\t\t\t\t'&:hover .MuiOutlinedInput-notchedOutline': {\r\n\t\t\t\t\t\tborderColor: 'var(--primary)',\r\n\t\t\t\t\t\tborderWidth: '1px'\r\n\t\t\t\t\t},\r\n\t\t\t\t\t'& .MuiAutocomplete-popupIndicator:hover': {\r\n\t\t\t\t\t\tbackgroundColor: 'transparent'\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\ttypography: {\r\n\t\tfontFamily: 'var(--main-font)'\r\n\t}\r\n})\r\n\r\nexport const MUITheme: FC = ({ children }) => (\r\n\t {children}\r\n)\r\n","import { createSlice, type PayloadAction } from '@reduxjs/toolkit'\r\n\r\nimport type {\r\n\tNotiFicationButton,\r\n\tNotiFicationDatum\r\n} from '../../config/notifications'\r\n\r\ninterface MessageState extends Omit {\r\n\tbutton: NotiFicationButton | null\r\n\topen: boolean\r\n}\r\n\r\nconst INITIAL_MESSAGE: MessageState = {\r\n\tbutton: null,\r\n\tcontent: '',\r\n\topen: false,\r\n\tstyle: 'default',\r\n\ttitle: ''\r\n}\r\n\r\ninterface NotificationState extends RootNotification {\r\n\tmessage: MessageState\r\n}\r\n\r\ninterface RootNotification {\r\n\terror: boolean\r\n\tstatus: boolean\r\n\ttext: string\r\n}\r\n\r\nconst initialState: NotificationState = {\r\n\terror: true,\r\n\tmessage: INITIAL_MESSAGE,\r\n\tstatus: false,\r\n\ttext: ''\r\n}\r\n\r\nconst slice = createSlice({\r\n\tinitialState,\r\n\tname: 'notification',\r\n\treducers: {\r\n\t\tnotificationUse(state, action: PayloadAction) {\r\n\t\t\tstate.error = action.payload.error\r\n\t\t\tstate.status = action.payload.status\r\n\t\t\tstate.text = action.payload.text\r\n\t\t},\r\n\r\n\t\tresetSnack(state) {\r\n\t\t\tstate.message = INITIAL_MESSAGE\r\n\t\t},\r\n\r\n\t\tshowSnack(state, action: PayloadAction) {\r\n\t\t\tstate.message = {\r\n\t\t\t\t...state.message,\r\n\t\t\t\t...action.payload,\r\n\t\t\t\tbutton: action.payload.button ?? null,\r\n\t\t\t\topen: true\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\tselectors: {\r\n\t\terror: state => state.error,\r\n\t\tmessage: state => state.message,\r\n\t\tsnackOpen: state => state.message.open,\r\n\t\tsnackStyle: state => state.message.style,\r\n\t\tstatus: state => state.status,\r\n\t\ttext: state => state.text\r\n\t}\r\n})\r\n\r\nconst actions = slice.actions\r\nconst selectors = slice.selectors\r\n\r\nexport { actions, selectors, slice }\r\n","import type { PayloadAction } from '@reduxjs/toolkit'\r\n\r\nexport const createSetter =\r\n\t(key: K) =>\r\n\t(state: Slice, { payload }: PayloadAction) => {\r\n\t\tstate[key] = payload\r\n\t}\r\n","import { createSlice, type PayloadAction } from '@reduxjs/toolkit'\r\nimport { createSetter } from 'shared/redux-helpers'\r\n\r\ninterface BottomItem {\r\n\tid: number\r\n\timage: string\r\n\tlink: string\r\n\ttitle: string\r\n}\r\n\r\ninterface ListItem {\r\n\tid: string\r\n\tname: string\r\n}\r\n\r\ninterface Slice {\r\n\tactive: null | number\r\n\tleftSide: {\r\n\t\tbottomList: BottomItem[]\r\n\t\tlabel?: string\r\n\t\tlist?: any[]\r\n\t\ttype:\r\n\t\t\t| ''\r\n\t\t\t| 'account'\r\n\t\t\t| 'campaign'\r\n\t\t\t| 'contacts'\r\n\t\t\t| 'messaging'\r\n\t\t\t| 'team'\r\n\t\t\t| 'upgrade'\r\n\t}\r\n}\r\n\r\nconst initialState: Slice = {\r\n\tactive: null,\r\n\tleftSide: {\r\n\t\tbottomList: [],\r\n\t\tlabel: '',\r\n\t\tlist: [],\r\n\t\ttype: ''\r\n\t}\r\n}\r\n\r\nconst leftSideSlice = createSlice({\r\n\tinitialState,\r\n\tname: 'leftSideMenu',\r\n\treducers: {\r\n\t\tsetActive: createSetter('active'),\r\n\t\tsetLeftSide: createSetter('leftSide'),\r\n\r\n\t\tupdateListName(state, action: PayloadAction) {\r\n\t\t\tconst { id, name } = action.payload\r\n\t\t\tconst found = state.leftSide.list?.find(item => item.id === id)\r\n\r\n\t\t\tif (found) {\r\n\t\t\t\tfound.name = name\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\tselectors: {\r\n\t\tactive: state => state.active,\r\n\t\t// @ts-ignore I guess should be contacts\r\n\t\tisContact: state => state.leftSide.type === 'contact'\r\n\t}\r\n})\r\n\r\nconst leftSideActions = leftSideSlice.actions,\r\n\tleftSideSelectors = leftSideSlice.selectors\r\n\r\nexport type LeftMenuType = LeftSide['type']\r\nexport type LeftSide = Slice['leftSide']\r\n\r\nexport { leftSideActions, leftSideSelectors, leftSideSlice }\r\n","import type { ActionCreatorsMapObject, AsyncThunk } from '@reduxjs/toolkit'\r\nimport type { TypedUseSelectorHook } from 'react-redux'\r\n\r\nimport { bindActionCreators } from '@reduxjs/toolkit'\r\nimport { useMemo } from 'react'\r\nimport { useDispatch, useSelector } from 'react-redux'\r\n\r\nimport type { AppDispatch, RootState } from '../../redux/store'\r\n\r\nconst useAppDispatch = () => useDispatch()\r\nconst useAppSelector: TypedUseSelectorHook = useSelector\r\n\r\nconst useActionCreators = (\r\n\tactions: Actions\r\n): BoundActions => {\r\n\tconst dispatch = useAppDispatch()\r\n\r\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: dispatch is stable\r\n\treturn useMemo(() => bindActionCreators(actions, dispatch), [])\r\n}\r\n\r\ntype BoundActions = {\r\n\t[key in keyof Actions]: Actions[key] extends AsyncThunk\r\n\t\t? BoundAsyncThunk\r\n\t\t: Actions[key]\r\n}\r\n\r\ntype BoundAsyncThunk> = (\r\n\t...args: Parameters\r\n) => ReturnType>\r\n\r\nexport { useActionCreators, useAppDispatch, useAppSelector }\r\n","import type { ActionCreatorWithPayload } from '@reduxjs/toolkit'\r\n\r\nimport { useEffect } from 'react'\r\n\r\nimport {\r\n\ttype LeftSide,\r\n\tleftSideActions\r\n} from '../../redux/reducers/leftSideMenu'\r\nimport { useAppDispatch } from './store'\r\n\r\nexport type LeftSideInput = LeftSide\r\n\r\nconst createHook =\r\n\t(creator: ActionCreatorWithPayload) =>\r\n\t(input: Input) => {\r\n\t\tconst dispatch = useAppDispatch()\r\n\r\n\t\t// biome-ignore lint/correctness/useExhaustiveDependencies: false alarm, creator is partial application\r\n\t\tuseEffect(() => {\r\n\t\t\tdispatch(creator(input))\r\n\t\t}, [dispatch, input])\r\n\t}\r\n\r\nexport const useActive = createHook(leftSideActions.setActive)\r\nexport const useLeft = createHook(leftSideActions.setLeftSide)\r\n","import { useEffect } from 'react'\r\n\r\n// TODO Drop this hook in React 19\r\nexport function useDocumentTitle(title: string) {\r\n\tuseEffect(restoreOriginal, [])\r\n\r\n\tuseEffect(() => {\r\n\t\tdocument.title = title\r\n\t}, [title])\r\n}\r\n\r\nfunction restoreOriginal() {\r\n\tconst initialTitle = document.title\r\n\treturn () => {\r\n\t\tdocument.title = initialTitle\r\n\t}\r\n}\r\n","import { useCallback, useRef, useState } from 'react'\r\n\r\nexport function useIntersectionObserver(\r\n\toptions: IntersectionObserverInit = {}\r\n) {\r\n\tconst { root = null, rootMargin = '0px', threshold = 1 } = options\r\n\tconst [entry, setEntry] = useState(null)\r\n\r\n\tconst previousObserver = useRef(null)\r\n\r\n\tconst customRef = useCallback(\r\n\t\t(node: any) => {\r\n\t\t\tif (previousObserver.current) {\r\n\t\t\t\tpreviousObserver.current.disconnect()\r\n\t\t\t\tpreviousObserver.current = null\r\n\t\t\t}\r\n\r\n\t\t\tif (node?.nodeType === Node.ELEMENT_NODE) {\r\n\t\t\t\tconst observer = new IntersectionObserver(\r\n\t\t\t\t\t([entry]) => {\r\n\t\t\t\t\t\tsetEntry(entry)\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{ root, rootMargin, threshold }\r\n\t\t\t\t)\r\n\r\n\t\t\t\tobserver.observe(node)\r\n\t\t\t\tpreviousObserver.current = observer\r\n\t\t\t}\r\n\t\t},\r\n\t\t[threshold, root, rootMargin]\r\n\t)\r\n\r\n\treturn [customRef, entry] as const\r\n}\r\n","import type { EffectCallback } from 'react'\r\n\r\nimport { useEffect } from 'react'\r\n\r\ntype Destructor = () => void\r\n\r\nconst useMount = (effect: EffectCallback) => useEffect(effect, [])\r\nconst useUnMount = (destructor: Destructor) => useMount(() => destructor)\r\nexport { useMount, useUnMount }\r\n","import { useMemo, useState } from 'react'\r\n\r\nconst toggle = (prev: boolean) => !prev\r\n\r\nexport function useSwitcher(initialValue = false) {\r\n\tconst [value, setValue] = useState(initialValue)\r\n\tconst methods = useMemo(\r\n\t\t() => ({\r\n\t\t\toff: () => setValue(false),\r\n\t\t\ton: () => setValue(true),\r\n\t\t\ttoggle: () => setValue(toggle)\r\n\t\t}),\r\n\t\t[]\r\n\t)\r\n\r\n\treturn Object.assign(methods, { isOn: value })\r\n}\r\n","import './style.scss'\r\n\r\nimport clsx from 'clsx'\r\nimport { useAppSelector } from 'shared/hooks'\r\n\r\nimport { selectors } from '../../slice'\r\n\r\nexport function Notification() {\r\n\tconst status = useAppSelector(selectors.status)\r\n\tconst text = useAppSelector(selectors.text)\r\n\tconst isError = useAppSelector(selectors.error)\r\n\r\n\treturn status ? (\r\n\t\t\r\n\t\t\t{text}\r\n\t\t\r\n\t) : null\r\n}\r\n","import type { FC } from 'react'\r\n\r\nimport LibSnackbar from '@mui/material/Snackbar'\r\nimport { useActionCreators, useAppSelector } from 'shared/hooks'\r\n\r\nimport { actions, selectors } from '../slice'\r\nimport * as SnackNotification from '../ui/SnackNotification'\r\n\r\nconst styleToCN = {\r\n\tattention: 'snackbar-notification-attention',\r\n\tdefault: 'snackbar-notification'\r\n}\r\n\r\nconst styleToComponent = {\r\n\tattention: SnackNotification.Attention,\r\n\tdefault: SnackNotification.Default\r\n}\r\n\r\nexport function Snackbar() {\r\n\tconst { resetSnack } = useActionCreators(actions)\r\n\r\n\tconst style = useAppSelector(selectors.snackStyle)\r\n\tconst isOpen = useAppSelector(selectors.snackOpen)\r\n\r\n\tlet Component: false | FC = false\r\n\r\n\tComponent = styleToComponent[style]\r\n\r\n\treturn (\r\n\t\t}\r\n\t\t\tonClose={(_, reason) => {\r\n\t\t\t\tif (reason !== 'clickaway') {\r\n\t\t\t\t\treturn resetSnack()\r\n\t\t\t\t}\r\n\t\t\t}}\r\n\t\t\topen={isOpen}\r\n\t\t/>\r\n\t)\r\n}\r\n","import snail from 'assets/image/snail-catches.png'\r\nimport { useActionCreators, useAppSelector } from 'shared/hooks'\r\n\r\nimport { actions, selectors } from '../../slice'\r\n\r\nexport function Attention() {\r\n\tconst message = useAppSelector(selectors.message)\r\n\tconst { resetSnack } = useActionCreators(actions)\r\n\treturn (\r\n\t\t
\r\n\t\t\t\r\n\t\t\t
\r\n\t\t\t\t
\r\n\t\t\t\t\t{message.title}\r\n\t\t\t\t\t resetSnack()}\r\n\t\t\t\t\t/>\r\n\t\t\t\t
\r\n\t\t\t\t\r\n\r\n\t\t\t\t{message.button && (\r\n\t\t\t\t\t
\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{message.button.title}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t
\r\n\t\t\t\t)}\r\n\t\t\t
\r\n\t\t
\r\n\t)\r\n}\r\n","import { useActionCreators, useAppSelector } from 'shared/hooks'\r\n\r\nimport { actions, selectors } from '../../slice'\r\n\r\nexport function Default() {\r\n\tconst message = useAppSelector(selectors.message)\r\n\tconst { resetSnack } = useActionCreators(actions)\r\n\r\n\treturn (\r\n\t\t
\r\n\t\t\t
\r\n\t\t\t
\r\n\t\t\t\t
\r\n\t\t\t\t\t{message.title}\r\n\t\t\t\t\t resetSnack()}\r\n\t\t\t\t\t/>\r\n\t\t\t\t
\r\n\t\t\t\t\r\n\t\t\t\t{message.button && (\r\n\t\t\t\t\t
\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{message.button.title}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t
\r\n\t\t\t\t)}\r\n\t\t\t
\r\n\t\t
\r\n\t)\r\n}\r\n","export const CONSTS = {\r\n \"API\": {\r\n \"URL\": \"https://api.snaily.io/api/v1/\",\r\n \"URL_AUTOMATION\": \"https://automation.snaily.io/v2/\"\r\n },\r\n \"APP_VERSION\": \"4.0.4.6\",\r\n \"AVAILABLE_ACTIONS\": {\r\n \"Connect\": {\r\n \"MaxLength\": 290,\r\n \"Title\": \"Connect\",\r\n \"Type\": \"Connect\",\r\n \"Visible\": true\r\n },\r\n \"EndorseSkill\": {\r\n \"Title\": \"Endorse a skill\",\r\n \"Type\": \"EndorseSkill\",\r\n \"Visible\": false\r\n },\r\n \"Follow\": {\r\n \"Title\": \"Follow\",\r\n \"Type\": \"Follow\",\r\n \"Visible\": true\r\n },\r\n \"Message\": {\r\n \"MaxLength\": 3000,\r\n \"Title\": \"Message\",\r\n \"Type\": \"Message\",\r\n \"Visible\": true\r\n },\r\n \"ReactOnPost\": {\r\n \"Title\": \"Like a post\",\r\n \"Type\": \"ReactOnPost\",\r\n \"Visible\": true\r\n },\r\n \"ScrapeProfile\": {\r\n \"Title\": \"Scrape profile\",\r\n \"Type\": \"ScrapeProfile\",\r\n \"Visible\": false\r\n },\r\n \"VisitProfile\": {\r\n \"Title\": \"Visit Profile\",\r\n \"Type\": \"VisitProfile\",\r\n \"Visible\": false\r\n }\r\n },\r\n \"BETA_FEATURES\": {\r\n \"HUBSPOT_INTEGRATION_TEAMS\": [\r\n \"223bafffadb74a2ab4174f680eeefeea\"\r\n ],\r\n \"SYNC_INTEGRATION_PERSONAS\": []\r\n },\r\n \"CAMPAIGN_MAX_LENGTH\": 50,\r\n \"COLORS_CAMPAIGNS\": {\r\n \"cancelled\": \"#DEB4FF\",\r\n \"failed\": \"#ED0000\",\r\n \"ignored\": \"#EBD6FC\",\r\n \"inProgress\": \"var(--status-paused)\",\r\n \"inQueue\": \"#DCDCDC\",\r\n \"responded\": \"#04C300\",\r\n \"skipped\": \"#BC68FD\"\r\n },\r\n \"confirmationDialogs\": {\r\n \"1.1\": {\r\n \"content\": \"The system will stop all activities with this contact.\",\r\n \"title\": \"Cancel conversation?\"\r\n },\r\n \"1.10\": {\r\n \"content\": \"New campaign will be created.
It will contain the same steps.\",\r\n \"title\": \"Clone campaign?\"\r\n },\r\n \"1.11\": {\r\n \"content\": \"Subscription will be upgraded.
You might be prorated charge for a difference.\",\r\n \"title\": \"Upgrade subscription?\"\r\n },\r\n \"1.12\": {\r\n \"content\": \"Subscription will be downgraded.\",\r\n \"title\": \"Downgrade subscription?\"\r\n },\r\n \"1.13\": {\r\n \"content\": \"This message will be deleted for all participants in the conversation.\",\r\n \"title\": \"Delete message?\"\r\n },\r\n \"1.2\": {\r\n \"content\": \"Stop all activities for this campaign.\",\r\n \"title\": \"Cancel campaign?\"\r\n },\r\n \"1.3\": {\r\n \"content\": \"Changes will not be saved.\",\r\n \"title\": \"Leave campaign master?\"\r\n },\r\n \"1.4\": {\r\n \"content\": \"This action and all next actions will be deleted.\",\r\n \"title\": \"Delete this action?\"\r\n },\r\n \"1.5\": {\r\n \"content\": \"Activities queue will be created for {contacts_count} contacts.
Edit of this campaign will be limited.\",\r\n \"title\": \"Launch now?\"\r\n },\r\n \"1.6\": {\r\n \"content\": \"Contacts will be excluded from this campaign.\",\r\n \"title\": \"Exclude contacts?\"\r\n },\r\n \"1.7\": {\r\n \"content\": \"It will be moved to the Archive.\",\r\n \"title\": \"Archive campaign?\"\r\n },\r\n \"1.8\": {\r\n \"content\": \"Contacts will be excluded from this campaign.\",\r\n \"title\": \"Exclude contacts?\"\r\n },\r\n \"1.9\": {\r\n \"content\": \"{contacts_count} contacts will be deleted from the system.\",\r\n \"title\": \"Delete contacts?\"\r\n },\r\n \"c1.13\": {\r\n \"content\": \"The invitation for {email} be deleted from the system.\",\r\n \"title\": \"Revoke invitation?\"\r\n },\r\n \"c1.14\": {\r\n \"content\": \"{nickname}({email}) will be removed.\",\r\n \"title\": \"Are you sure you want to remove this member?\"\r\n },\r\n \"c1.15\": {\r\n \"content\": \"This conversation will be deleted permanently.\",\r\n \"title\": \"Delete conversation from your inbox?\"\r\n },\r\n \"c1.16\": {\r\n \"content\": \"The system will resume chain of automatic actions.\",\r\n \"title\": \"Resume conversation?\"\r\n }\r\n },\r\n \"DAILY_LIMITS\": {\r\n \"FOLLOW\": [\r\n {\r\n \"label\": \"0\",\r\n \"value\": \"0\"\r\n },\r\n {\r\n \"label\": \"5\",\r\n \"value\": \"5\"\r\n },\r\n {\r\n \"label\": \"10\",\r\n \"value\": \"10\"\r\n },\r\n {\r\n \"label\": \"15\",\r\n \"value\": \"15\"\r\n },\r\n {\r\n \"label\": \"20\",\r\n \"value\": \"20\"\r\n },\r\n {\r\n \"label\": \"25\",\r\n \"value\": \"25\"\r\n },\r\n {\r\n \"label\": \"30\",\r\n \"value\": \"30\"\r\n },\r\n {\r\n \"label\": \"35\",\r\n \"value\": \"35\"\r\n },\r\n {\r\n \"label\": \"40\",\r\n \"value\": \"40\"\r\n },\r\n {\r\n \"label\": \"45\",\r\n \"value\": \"45\"\r\n },\r\n {\r\n \"label\": \"50\",\r\n \"value\": \"50\"\r\n },\r\n {\r\n \"label\": \"55\",\r\n \"value\": \"55\"\r\n },\r\n {\r\n \"label\": \"60\",\r\n \"value\": \"60\"\r\n },\r\n {\r\n \"label\": \"65\",\r\n \"value\": \"65\"\r\n },\r\n {\r\n \"label\": \"70\",\r\n \"value\": \"70\"\r\n },\r\n {\r\n \"label\": \"75\",\r\n \"value\": \"75\"\r\n },\r\n {\r\n \"label\": \"80\",\r\n \"value\": \"80\"\r\n },\r\n {\r\n \"label\": \"85\",\r\n \"value\": \"85\"\r\n },\r\n {\r\n \"label\": \"90\",\r\n \"value\": \"90\"\r\n },\r\n {\r\n \"label\": \"95\",\r\n \"value\": \"95\"\r\n },\r\n {\r\n \"label\": \"100\",\r\n \"value\": \"100\"\r\n }\r\n ],\r\n \"INVITATIONS\": [\r\n {\r\n \"label\": \"0\",\r\n \"value\": \"0\"\r\n },\r\n {\r\n \"label\": \"5\",\r\n \"value\": \"5\"\r\n },\r\n {\r\n \"label\": \"10\",\r\n \"value\": \"10\"\r\n },\r\n {\r\n \"label\": \"15\",\r\n \"value\": \"15\"\r\n },\r\n {\r\n \"label\": \"20\",\r\n \"value\": \"20\"\r\n },\r\n {\r\n \"label\": \"25\",\r\n \"value\": \"25\"\r\n },\r\n {\r\n \"label\": \"30\",\r\n \"value\": \"30\"\r\n },\r\n {\r\n \"label\": \"35\",\r\n \"value\": \"35\"\r\n },\r\n {\r\n \"label\": \"40\",\r\n \"value\": \"40\"\r\n },\r\n {\r\n \"label\": \"45\",\r\n \"value\": \"45\"\r\n },\r\n {\r\n \"label\": \"50\",\r\n \"value\": \"50\"\r\n },\r\n {\r\n \"label\": \"55\",\r\n \"value\": \"55\"\r\n },\r\n {\r\n \"label\": \"60\",\r\n \"value\": \"60\"\r\n },\r\n {\r\n \"label\": \"65\",\r\n \"value\": \"65\"\r\n },\r\n {\r\n \"label\": \"70\",\r\n \"value\": \"70\"\r\n },\r\n {\r\n \"label\": \"75\",\r\n \"value\": \"75\"\r\n }\r\n ],\r\n \"LIKES\": [\r\n {\r\n \"label\": \"0\",\r\n \"value\": \"0\"\r\n },\r\n {\r\n \"label\": \"5\",\r\n \"value\": \"5\"\r\n },\r\n {\r\n \"label\": \"10\",\r\n \"value\": \"10\"\r\n },\r\n {\r\n \"label\": \"15\",\r\n \"value\": \"15\"\r\n },\r\n {\r\n \"label\": \"20\",\r\n \"value\": \"20\"\r\n },\r\n {\r\n \"label\": \"25\",\r\n \"value\": \"25\"\r\n },\r\n {\r\n \"label\": \"30\",\r\n \"value\": \"30\"\r\n },\r\n {\r\n \"label\": \"35\",\r\n \"value\": \"35\"\r\n },\r\n {\r\n \"label\": \"40\",\r\n \"value\": \"40\"\r\n },\r\n {\r\n \"label\": \"45\",\r\n \"value\": \"45\"\r\n },\r\n {\r\n \"label\": \"50\",\r\n \"value\": \"50\"\r\n },\r\n {\r\n \"label\": \"55\",\r\n \"value\": \"55\"\r\n },\r\n {\r\n \"label\": \"60\",\r\n \"value\": \"60\"\r\n },\r\n {\r\n \"label\": \"65\",\r\n \"value\": \"65\"\r\n },\r\n {\r\n \"label\": \"70\",\r\n \"value\": \"70\"\r\n },\r\n {\r\n \"label\": \"75\",\r\n \"value\": \"75\"\r\n },\r\n {\r\n \"label\": \"80\",\r\n \"value\": \"80\"\r\n },\r\n {\r\n \"label\": \"85\",\r\n \"value\": \"85\"\r\n },\r\n {\r\n \"label\": \"90\",\r\n \"value\": \"90\"\r\n },\r\n {\r\n \"label\": \"95\",\r\n \"value\": \"95\"\r\n },\r\n {\r\n \"label\": \"100\",\r\n \"value\": \"100\"\r\n }\r\n ],\r\n \"MESSAGES\": [\r\n {\r\n \"label\": \"0\",\r\n \"value\": \"0\"\r\n },\r\n {\r\n \"label\": \"5\",\r\n \"value\": \"5\"\r\n },\r\n {\r\n \"label\": \"10\",\r\n \"value\": \"10\"\r\n },\r\n {\r\n \"label\": \"15\",\r\n \"value\": \"15\"\r\n },\r\n {\r\n \"label\": \"20\",\r\n \"value\": \"20\"\r\n },\r\n {\r\n \"label\": \"25\",\r\n \"value\": \"25\"\r\n },\r\n {\r\n \"label\": \"30\",\r\n \"value\": \"30\"\r\n },\r\n {\r\n \"label\": \"35\",\r\n \"value\": \"35\"\r\n },\r\n {\r\n \"label\": \"40\",\r\n \"value\": \"40\"\r\n },\r\n {\r\n \"label\": \"45\",\r\n \"value\": \"45\"\r\n },\r\n {\r\n \"label\": \"50\",\r\n \"value\": \"50\"\r\n },\r\n {\r\n \"label\": \"55\",\r\n \"value\": \"55\"\r\n },\r\n {\r\n \"label\": \"60\",\r\n \"value\": \"60\"\r\n },\r\n {\r\n \"label\": \"65\",\r\n \"value\": \"65\"\r\n },\r\n {\r\n \"label\": \"70\",\r\n \"value\": \"70\"\r\n },\r\n {\r\n \"label\": \"75\",\r\n \"value\": \"75\"\r\n },\r\n {\r\n \"label\": \"80\",\r\n \"value\": \"80\"\r\n },\r\n {\r\n \"label\": \"85\",\r\n \"value\": \"85\"\r\n },\r\n {\r\n \"label\": \"90\",\r\n \"value\": \"90\"\r\n },\r\n {\r\n \"label\": \"95\",\r\n \"value\": \"95\"\r\n },\r\n {\r\n \"label\": \"100\",\r\n \"value\": \"100\"\r\n }\r\n ]\r\n },\r\n \"DEFAULT_DATE_ACTIONS_VALUE\": {\r\n \"CONNECT\": {\r\n \"DELAY\": {\r\n \"DEFAULT\": 30,\r\n \"MIN_VALUE_MINUTES\": 0\r\n },\r\n \"WITHDRAW\": {\r\n \"DEFAULT\": 10\r\n }\r\n },\r\n \"MESSAGE_TIMEOUTS_DAYS\": [\r\n 3,\r\n 7,\r\n 14,\r\n 30,\r\n 30,\r\n 30,\r\n 30,\r\n 30,\r\n 30,\r\n 30,\r\n 30,\r\n 30\r\n ]\r\n },\r\n \"DELAY_TIMEOUT\": 1576800,\r\n \"EMOTION\": [\r\n \"Like\",\r\n \"Celebrate\",\r\n \"Support\",\r\n \"Love\",\r\n \"Insightful\",\r\n \"Funny\"\r\n ],\r\n \"EXTENSION_ID\": \"febgaeoegckcdcdhammknmiobpjkpgbe\",\r\n \"EXTENSION_INSTALL_URL\": \"https://chrome.google.com/webstore/detail/febgaeoegckcdcdhammknmiobpjkpgbe\",\r\n \"GOOGLE_TAG_MANAGER\": {\r\n \"ID\": \"GTM-KSFX6VJ\"\r\n },\r\n \"HELP_URL\": \"https://snaily.io/support/\",\r\n \"HJ_ID\": 2778252,\r\n \"HJ_SV\": 6,\r\n \"IMPORT_MAX_LENGTH\": 50,\r\n \"IS_RESIZABLE_TABLE\": false,\r\n \"LINKEDIN_URL\": \"https://www.linkedin.com/search/results/people\",\r\n \"LOGS_SETTINGS\": {\r\n \"didCatch\": false,\r\n \"rejection\": false\r\n },\r\n \"MAIN_CUSTOM_FIELDS\": [\r\n \"{first name}\",\r\n \"{last name}\",\r\n \"{company name}\",\r\n \"{position title}\"\r\n ],\r\n \"MESSAGING\": {\r\n \"OFFLINE_INTERVAL_IN_MINUTES\": 15,\r\n \"REFRESH_INTERVAL_IN_SECONDS\": 60\r\n },\r\n \"NICK_NAME_MAX_LENGTH\": 50,\r\n \"ON_BOARDING\": {\r\n \"2.1\": {\r\n \"conditions\": {\r\n \"onBoarding\": true,\r\n \"runningActivitiesEnabled\": false\r\n },\r\n \"content\": \"Let’s make Snaily better together! Tell us more about your experience.\",\r\n \"isClosable\": true,\r\n \"title\": \"Leave us your feedback\"\r\n },\r\n \"2.2\": {\r\n \"conditions\": {\r\n \"onBoarding\": true,\r\n \"runningActivitiesEnabled\": true\r\n },\r\n \"content\": \"You can check scheduled actions in the activities queue.\",\r\n \"isClosable\": true,\r\n \"sideTitle\": \"2/2\",\r\n \"title\": \"Press to run activities on LinkedIn!\"\r\n },\r\n \"2.3\": {\r\n \"conditions\": {\r\n \"onBoarding\": true,\r\n \"runningActivitiesEnabled\": false\r\n },\r\n \"content\": \"Choose an action to set it up!\",\r\n \"isClosable\": true,\r\n \"title\": \"Step 1\"\r\n },\r\n \"2.4\": {\r\n \"conditions\": {\r\n \"onBoarding\": true,\r\n \"runningActivitiesEnabled\": false\r\n },\r\n \"content\": \"Create a sequence of follow-up messages!\",\r\n \"isClosable\": true,\r\n \"title\": \"Add next action\"\r\n },\r\n \"2.5\": {\r\n \"conditions\": {\r\n \"onBoarding\": true,\r\n \"runningActivitiesEnabled\": false\r\n },\r\n \"content\": \"Apply filters and add contacts to your campaign.\",\r\n \"isClosable\": true,\r\n \"title\": \"Available contacts\"\r\n },\r\n \"2.6\": {\r\n \"conditions\": {\r\n \"onBoarding\": true,\r\n \"runningActivitiesEnabled\": false\r\n },\r\n \"content\": \"All your active, paused and finished campaigns will be listed here.\",\r\n \"isClosable\": true,\r\n \"sideTitle\": \"1/2\",\r\n \"title\": \"Find your campaigns here!\"\r\n },\r\n \"2.7\": {\r\n \"conditions\": {\r\n \"onBoarding\": true,\r\n \"runningActivitiesEnabled\": false\r\n },\r\n \"content\": \"Press to rocket your campaign right now!\",\r\n \"isClosable\": true,\r\n \"title\": \"Launch your campaign!\"\r\n }\r\n },\r\n \"OVERFLOW_CUSTOM_FIELDS\": [\r\n \"{country}\",\r\n \"{custom field 1}\",\r\n \"{custom field 2}\",\r\n \"{custom field 3}\"\r\n ],\r\n \"PAGE_SIZE\": 25,\r\n \"PRIVACY_POLICY\": \"https://snaily.io/privacy-policy/\",\r\n \"PROJECT_NAME\": \"Snaily\",\r\n \"ROLES\": {\r\n \"Manager\": \"manager\",\r\n \"Owner\": \"owner\",\r\n \"User\": \"user\"\r\n },\r\n \"SALES_NAVIGATOR\": \"https://www.linkedin.com/sales/search/people\",\r\n \"SUBSCRIPTIONS\": {\r\n \"BASIC\": {\r\n \"ID\": \"basic\",\r\n \"NAME\": \"Basic\",\r\n \"PRICE\": 38\r\n },\r\n \"EXPERIMENTAL\": {\r\n \"ID\": \"early-birds\",\r\n \"NAME\": \"Early birds\",\r\n \"PRICE\": 38\r\n },\r\n \"PRO\": {\r\n \"ID\": \"pro\",\r\n \"NAME\": \"Pro \",\r\n \"PRICE\": 59\r\n },\r\n \"STATE\": {\r\n \"ACTIVE\": \"active\",\r\n \"CANCELED\": \"canceled\",\r\n \"OVERDUE\": \"overdue\"\r\n },\r\n \"TEAM\": {\r\n \"ID\": \"team\",\r\n \"NAME\": \"Team\",\r\n \"PRICE\": 75\r\n },\r\n \"TRIAL\": {\r\n \"ID\": \"trial\",\r\n \"NAME\": \"Trial\",\r\n \"PRICE\": 0\r\n }\r\n },\r\n \"TERMS_AND_CONDITIONS_URL\": \"https://snaily.io/terms-and-conditions/\",\r\n \"TIME_ZONES\": [\r\n {\r\n \"label\": \"GMT-12:00\",\r\n \"value\": \"-720\"\r\n },\r\n {\r\n \"label\": \"GMT-11:00\",\r\n \"value\": \"-660\"\r\n },\r\n {\r\n \"label\": \"GMT-10:00\",\r\n \"value\": \"-600\"\r\n },\r\n {\r\n \"label\": \"GMT-09:30\",\r\n \"value\": \"-570\"\r\n },\r\n {\r\n \"label\": \"GMT-09:00\",\r\n \"value\": \"-540\"\r\n },\r\n {\r\n \"label\": \"GMT-08:00\",\r\n \"value\": \"-480\"\r\n },\r\n {\r\n \"label\": \"GMT-07:00\",\r\n \"value\": \"-420\"\r\n },\r\n {\r\n \"label\": \"GMT-06:00\",\r\n \"value\": \"-360\"\r\n },\r\n {\r\n \"label\": \"GMT-05:00\",\r\n \"value\": \"-300\"\r\n },\r\n {\r\n \"label\": \"GMT-04:00\",\r\n \"value\": \"-240\"\r\n },\r\n {\r\n \"label\": \"GMT-03:30\",\r\n \"value\": \"-210\"\r\n },\r\n {\r\n \"label\": \"GMT-03:00\",\r\n \"value\": \"-180\"\r\n },\r\n {\r\n \"label\": \"GMT-02:00\",\r\n \"value\": \"-120\"\r\n },\r\n {\r\n \"label\": \"GMT-01:00\",\r\n \"value\": \"-60\"\r\n },\r\n {\r\n \"label\": \"GMT-00:00\",\r\n \"value\": \"0\"\r\n },\r\n {\r\n \"label\": \"GMT+01:00\",\r\n \"value\": \"60\"\r\n },\r\n {\r\n \"label\": \"GMT+02:00\",\r\n \"value\": \"120\"\r\n },\r\n {\r\n \"label\": \"GMT+03:00\",\r\n \"value\": \"180\"\r\n },\r\n {\r\n \"label\": \"GMT+03:30\",\r\n \"value\": \"210\"\r\n },\r\n {\r\n \"label\": \"GMT+04:00\",\r\n \"value\": \"240\"\r\n },\r\n {\r\n \"label\": \"GMT+04:30\",\r\n \"value\": \"270\"\r\n },\r\n {\r\n \"label\": \"GMT+05:00\",\r\n \"value\": \"300\"\r\n },\r\n {\r\n \"label\": \"GMT+05:30\",\r\n \"value\": \"330\"\r\n },\r\n {\r\n \"label\": \"GMT+05:45\",\r\n \"value\": \"345\"\r\n },\r\n {\r\n \"label\": \"GMT+06:00\",\r\n \"value\": \"360\"\r\n },\r\n {\r\n \"label\": \"GMT+06:30\",\r\n \"value\": \"390\"\r\n },\r\n {\r\n \"label\": \"GMT+07:00\",\r\n \"value\": \"420\"\r\n },\r\n {\r\n \"label\": \"GMT+08:00\",\r\n \"value\": \"480\"\r\n },\r\n {\r\n \"label\": \"GMT+08:45\",\r\n \"value\": \"525\"\r\n },\r\n {\r\n \"label\": \"GMT+09:00\",\r\n \"value\": \"540\"\r\n },\r\n {\r\n \"label\": \"GMT+09:30\",\r\n \"value\": \"570\"\r\n },\r\n {\r\n \"label\": \"GMT+10:00\",\r\n \"value\": \"600\"\r\n },\r\n {\r\n \"label\": \"GMT+10:30\",\r\n \"value\": \"630\"\r\n },\r\n {\r\n \"label\": \"GMT+11:00\",\r\n \"value\": \"660\"\r\n },\r\n {\r\n \"label\": \"GMT+12:00\",\r\n \"value\": \"720\"\r\n }\r\n ],\r\n \"TIPS\": {\r\n \"n4.1\": {\r\n \"content\": [\r\n \"You used all monthly personalized invitations which LinkedIn gives for free every month and now your automation is stuck.\",\r\n \"Due to that we have paused this campaign.\",\r\n \"\",\r\n \"To resume this campaign you need to make an action first, we propose you to consider 2 options:\",\r\n \"- leave connection invitation message empty, LinkedIn allows to send message less invitations for free;\",\r\n \"- buy Premium LinkedIn or Sales Navigator, paid subscriptions don't have such limitations;\",\r\n \"\",\r\n \"Once you settle this you should just run this campaign once again.\"\r\n ],\r\n \"more\": \"\",\r\n \"title\": \"Used free custom invitations\"\r\n },\r\n \"n4.2\": {\r\n \"content\": [\r\n \"Looks like you are using free LinkedIn which limits invitation messages up to 200 symbols.\",\r\n \"Your invitation message in this campaign is getting longer and we can't send it.\",\r\n \"Due to that we have paused this campaign.\",\r\n \"\",\r\n \"We would like to recommend you to consider next options to resume your campaign:\",\r\n \"- make the invitation message shorter, ideally it should be 190-195 symbols to let it be less than 200 symbols after personalization.\",\r\n \"Take into account that LinkedIn allows a limited number of personalized invitations for Free profiles, usually it is 5-10 invitations per month\",\r\n \"- buy one of the paid LinkedIn subscriptions like Premium or Sales Navigator.\",\r\n \"Such subscriptions allow you to send invitation messages up to 300 symbols without monthly limits.\",\r\n \"\",\r\n \"Once you settle this you should just run this campaign once again.\"\r\n ],\r\n \"more\": \"\",\r\n \"title\": \"Too long invitation\"\r\n },\r\n \"n4.3\": {\r\n \"content\": [\r\n \"The weekly LinkedIn's invitation limit has been reached.\",\r\n \"Snaily will resume sending invitations next week.\"\r\n ],\r\n \"more\": \"\",\r\n \"title\": \"Out of invites\"\r\n },\r\n \"n4.4\": {\r\n \"content\": [\r\n \"Paste a text containing urls of LinkedIn profiles and Snaily will automatically recognize them. Once you export them you will get only profile URLs, contact details will be scraped during campaign execution.\"\r\n ],\r\n \"more\": \"\",\r\n \"title\": \"Information\"\r\n },\r\n \"n4.5\": {\r\n \"content\": [\r\n \"This is advanced export that allows customizing LinkedIn profiles by changing profile information or adding custom fields. It is working only with a specific CSV file format. Please download the example to get familiar with it.\"\r\n ],\r\n \"more\": \"\",\r\n \"title\": \"Information\"\r\n }\r\n },\r\n \"WORKING_HOURS\": 10\r\n}\r\n","export class BackendValidationError extends Error {\r\n\tget axios() {\r\n\t\treturn this.#errors\r\n\t}\r\n\t#errors\r\n\tconstructor(errors: { description: string }[]) {\r\n\t\tsuper(errors[0].description)\r\n\t\tthis.#errors = errors\r\n\t\tthis.name = 'BackendValidationError'\r\n\r\n\t\tif (Error.captureStackTrace) {\r\n\t\t\tError.captureStackTrace(this, BackendValidationError)\r\n\t\t}\r\n\t}\r\n}\r\n","export class BadGatewayError extends Error {\r\n\tget skipLogging() {\r\n\t\treturn true\r\n\t}\r\n\r\n\tconstructor(message: string) {\r\n\t\tsuper(message)\r\n\t\tthis.name = 'BadGatewayError'\r\n\r\n\t\tif (Error.captureStackTrace) {\r\n\t\t\tError.captureStackTrace(this, BadGatewayError)\r\n\t\t}\r\n\t}\r\n}\r\n","export class FatalError extends Error {\r\n\tconstructor(message: string) {\r\n\t\tsuper(message)\r\n\t\tthis.name = 'FatalError'\r\n\r\n\t\tif (Error.captureStackTrace) {\r\n\t\t\tError.captureStackTrace(this, FatalError)\r\n\t\t}\r\n\t}\r\n}\r\n","export class NotAuthorizedError extends Error {\r\n\tconstructor(message: string) {\r\n\t\tsuper(message)\r\n\t\tthis.name = 'NotAuthorizedError'\r\n\r\n\t\tif (Error.captureStackTrace) {\r\n\t\t\tError.captureStackTrace(this, NotAuthorizedError)\r\n\t\t}\r\n\t}\r\n}\r\n","import { CONSTS } from '../config/objectConst'\r\n\r\nconst KEY = 'contactsPageSize'\r\n\r\nexport const contactsPageSize = {\r\n\tget() {\r\n\t\tlet result = CONSTS.PAGE_SIZE\r\n\t\tconst saved = localStorage.getItem(KEY)\r\n\r\n\t\tif (saved) {\r\n\t\t\tresult = Number(saved)\r\n\t\t}\r\n\r\n\t\treturn result\r\n\t},\r\n\r\n\tsave(value: number) {\r\n\t\tlocalStorage.setItem(KEY, String(value))\r\n\t}\r\n}\r\n","import type { connectorFactory } from 'components/app/connectorFactory'\r\n\r\nimport { createSlice, type PayloadAction } from '@reduxjs/toolkit'\r\nimport { helpersFunc } from 'config/helpers'\r\n\r\nimport type { AppProfile } from './app.types'\r\n\r\ninterface AppState {\r\n\tappPage: string\r\n\tappProfile: null | Partial\r\n\tappProfileDone: boolean\r\n\tassociatedLinkedInProfile: boolean\r\n\tauth: 'auth' | 'loading' | 'none'\r\n\tconnector: ReturnType\r\n\terrorRequest: ErrorRequest\r\n\r\n\tisInstalledDone: boolean\r\n\tlinkedInAuth: boolean\r\n\tlinkedProfile: any\r\n\tlinkedProfileDone: boolean\r\n\tpageContentLoader: boolean\r\n\tpageModalLoader: boolean\r\n\tsubscription: any\r\n\ttableContentLoader: boolean\r\n\ttoken: string\r\n}\r\n\r\ninterface ErrorRequest {\r\n\tactivityQueue: boolean\r\n\tcampaigns: boolean\r\n\tcampaignsTeams: boolean\r\n\tcontacts: boolean\r\n}\r\n\r\nconst initialState: AppState = {\r\n\tappPage: '/campaigns',\r\n\tappProfile: {},\r\n\tappProfileDone: false,\r\n\tassociatedLinkedInProfile: true,\r\n\tauth: 'loading',\r\n\t// @ts-ignore init work only in App.\r\n\t// TODO: Maybe better to replace into separate context\r\n\tconnector: {},\r\n\terrorRequest: {\r\n\t\tactivityQueue: false,\r\n\t\tcampaigns: false,\r\n\t\tcampaignsTeams: false,\r\n\t\tcontacts: false\r\n\t},\r\n\tisInstalledDone: false,\r\n\tlinkedInAuth: true,\r\n\tlinkedProfile: {},\r\n\tlinkedProfileDone: false,\r\n\tpageContentLoader: true,\r\n\tpageModalLoader: false,\r\n\tsubscription: null,\r\n\ttableContentLoader: false,\r\n\ttoken: ''\r\n}\r\n\r\nconst selectPersona = (state: AppState) =>\r\n\tstate.appProfile?.impersonatedPersona ?? state.appProfile\r\n\r\nconst appSlice = createSlice({\r\n\tinitialState,\r\n\tname: 'app',\r\n\treducers: {\r\n\t\tappAuth(state, action: PayloadAction) {\r\n\t\t\tstate.auth = action.payload\r\n\t\t},\r\n\t\tchangeLinkedInAuthStatus(state, action: PayloadAction) {\r\n\t\t\tstate.linkedInAuth = action.payload\r\n\t\t},\r\n\t\tchangePage(state, action: PayloadAction) {\r\n\t\t\tstate.appPage = action.payload\r\n\t\t},\r\n\t\tchangePageContentLoaderStatus(\r\n\t\t\tstate,\r\n\t\t\taction: PayloadAction\r\n\t\t) {\r\n\t\t\tstate.pageContentLoader = action.payload\r\n\t\t},\r\n\t\tchangePageModalLoader(state, action: PayloadAction) {\r\n\t\t\tstate.pageModalLoader = action.payload\r\n\t\t},\r\n\r\n\t\tchangeTableContentLoaderStatus(state, action: PayloadAction) {\r\n\t\t\tstate.tableContentLoader = action.payload\r\n\t\t},\r\n\r\n\t\tcreateConnector: (state, action) => {\r\n\t\t\tstate.connector = action.payload\r\n\t\t},\r\n\t\tsetAppProfile: (\r\n\t\t\tstate,\r\n\t\t\taction: PayloadAction>\r\n\t\t) => {\r\n\t\t\tstate.appProfile = action.payload.appProfile\r\n\t\t\tstate.appProfileDone = action.payload.appProfileDone\r\n\t\t},\r\n\t\tsetAssociatedLinkedInProfile(state, action: PayloadAction) {\r\n\t\t\tstate.associatedLinkedInProfile = action.payload\r\n\t\t},\r\n\r\n\t\tsetLinkedProfile: (\r\n\t\t\tstate,\r\n\t\t\taction: PayloadAction<\r\n\t\t\t\tPick\r\n\t\t\t>\r\n\t\t) => {\r\n\t\t\tstate.linkedProfile = action.payload.linkedProfile\r\n\t\t\tstate.linkedProfileDone = action.payload.linkedProfileDone\r\n\t\t},\r\n\r\n\t\tsetSubscriptions(state, action: PayloadAction) {\r\n\t\t\tstate.subscription = action.payload\r\n\t\t},\r\n\r\n\t\tupdateErrorRequest(state, action: PayloadAction) {\r\n\t\t\tconst old = state.errorRequest\r\n\t\t\tstate.errorRequest = {\r\n\t\t\t\t...old,\r\n\t\t\t\t...action.payload\r\n\t\t\t}\r\n\t\t},\r\n\r\n\t\tupdateInstalled(state, action: PayloadAction) {\r\n\t\t\tstate.isInstalledDone = action.payload\r\n\t\t}\r\n\t},\r\n\tselectors: {\r\n\t\tappProfile: state => state.appProfile,\r\n\t\tappProfileDone: state => state.appProfileDone,\r\n\t\tauth: state => state.auth,\r\n\t\tconnector: state => state.connector,\r\n\t\terrorRequest: state => state.errorRequest,\r\n\t\tfullName(state) {\r\n\t\t\tconst { familyName = '', givenName = '' } = selectPersona(state) ?? {}\r\n\r\n\t\t\treturn `${givenName} ${familyName}`\r\n\t\t},\r\n\t\thasAutomation: state => selectPersona(state)?.isBackendAutomation ?? false,\r\n\t\tisBetaUser: state => state.appProfile?.isBetaUser || false,\r\n\t\tisImpersonated: state => Boolean(state.appProfile?.impersonatedPersona),\r\n\t\tisInstalled: state => {\r\n\t\t\ttry {\r\n\t\t\t\treturn state.connector.extension?.isInstalled() ?? true\r\n\t\t\t\t// ! Something messed with flags. If we remove isInstalledDone no auth widget showed before update profile\r\n\t\t\t} catch (e) {\r\n\t\t\t\thelpersFunc.logEnjectServicePromise(e)\r\n\t\t\t\treturn false\r\n\t\t\t}\r\n\t\t},\r\n\t\tisInstalledDone: state => state.isInstalledDone,\r\n\t\tisReadyConnector: state => {\r\n\t\t\tconst keys = Object.keys(state.connector)\r\n\t\t\treturn keys.length > 0\r\n\t\t},\r\n\t\tisUpgraded: ({ appProfile }) =>\r\n\t\t\tappProfile?.impersonatedPersona ||\r\n\t\t\t(appProfile?.subscriptionIsActive &&\r\n\t\t\t\tappProfile?.subscriptionOwnerId &&\r\n\t\t\t\tappProfile.subscriptionOwnerId !== appProfile?.personaId),\r\n\t\tlinkedProfile: state => state.linkedProfile,\r\n\t\tlinkedProfileDone: state => state.linkedProfileDone,\r\n\t\tnotLoggedLI: app => !(app.linkedInAuth && app.associatedLinkedInProfile),\r\n\t\tpersona: selectPersona,\r\n\t\tpersonIdLi: state => selectPersona(state)?.linkedInProfile?.entityId ?? '',\r\n\t\trefreshAccessToken: state => state.connector.auth.refreshAccessToken,\r\n\t\tsignInUnderTeamMember: state => state.connector.auth.signInUnderTeamMember,\r\n\t\tsubscription: state => state.subscription,\r\n\t\tsubscriptionIsActive: state => state.appProfile?.subscriptionIsActive,\r\n\t\ttimezoneOffset: state => state.appProfile?.timezoneOffset,\r\n\t\ttoken: state => state.token\r\n\t}\r\n})\r\n\r\nconst appActions = appSlice.actions\r\nconst appSelectors = appSlice.selectors\r\nexport { appActions, appSelectors, appSlice }\r\nexport type AuthStatus = AppState['auth']\r\n","import { api } from \"../api/api\";\nimport { appActions } from \"../redux/reducers/app.ts\";\nimport { leftSideActions } from \"../redux/reducers/leftSideMenu.ts\";\nimport store from \"../redux/store.ts\";\n\nexport const app = {\n changeActiveItem(active) {\n store.dispatch(leftSideActions.setActive(active));\n },\n changePage(page) {\n store.dispatch(appActions.changePage(page));\n },\n\n changePageContentLoaderStatus(status) {\n store.dispatch(appActions.changePageContentLoaderStatus(status));\n },\n\n changePageModalLoader(status) {\n store.dispatch(appActions.changePageModalLoader(status));\n },\n\n changeTableContentLoaderStatus(status) {\n store.dispatch(appActions.changeTableContentLoaderStatus(status));\n },\n\n setAppProfile(body) {\n store.dispatch(appActions.setAppProfile(body));\n },\n\n setLinkedProfile(body) {\n store.dispatch(appActions.setLinkedProfile(body));\n },\n\n setNewData: async (url, data) => {\n const response = await api.setNewData(url, data);\n return response;\n },\n\n setSubscriptions(body) {\n store.dispatch(appActions.setSubscriptions(body));\n },\n\n // Example action click\n /* appInit() {\n if (\n localStorage.getItem(\"campaignCreateName\") &&\n localStorage.getItem(\"campaignCreateName\").length > 0\n ) {\n campaignCreate.create(localStorage.getItem(\"campaignCreateName\"));\n }\n }, */\n\n updateErrorRequest(body) {\n store.dispatch(appActions.updateErrorRequest(body));\n },\n};\n","import { api } from 'api/api'\r\nimport { helpersFunc } from 'config/helpers'\r\nimport { CONSTS } from 'config/objectConst'\r\nimport store from 'redux/store'\r\nimport { FatalError, notifyError } from 'shared/errors'\r\n\r\nimport { appActions, appSelectors } from '../redux/reducers/app'\r\nimport { app } from './app'\r\n\r\nasync function setUpInit() {\r\n\tconst isInstalled = appSelectors.isInstalled(store.getState())\r\n\tstore.dispatch(appActions.updateInstalled(true))\r\n\tif (!isInstalled) {\r\n\t\treturn\r\n\t}\r\n\r\n\tconst [snailyProfile, linkedInProfile] = await Promise.all([\r\n\t\tconnectorAPI.getSnailyProfile(),\r\n\t\tconnectorAPI.getLinkedProfile()\r\n\t])\r\n\r\n\tif (snailyProfile && linkedInProfile) {\r\n\t\tconst subscription = await api.getSubscription()\r\n\t\tsubscription?.data && app.setSubscriptions(subscription?.data)\r\n\t}\r\n}\r\n\r\nlet onGoingSetup = false\r\n\r\nexport const connectorAPI = {\r\n\tgetAccessToken: async () => {\r\n\t\tconst connector = appSelectors.connector(store.getState())\r\n\t\ttry {\r\n\t\t\tconst result = await connector.auth?.getAccessToken()\r\n\t\t\treturn result\r\n\t\t} catch (e) {\r\n\t\t\tconst shouldReload =\r\n\t\t\t\te instanceof Error && e.name === 'ExtensionNotInstalledError'\r\n\t\t\tif (shouldReload) {\r\n\t\t\t\twindow.location.reload()\r\n\t\t\t}\r\n\r\n\t\t\tconsole.log(e)\r\n\t\t\t/* you are don't ever loged token error because for logged you needed token - helpersFunc.logEnjectServicePromise(e); */\r\n\t\t}\r\n\t},\r\n\r\n\tgetLinkedProfile: async () => {\r\n\t\ttry {\r\n\t\t\tapp.setLinkedProfile({\r\n\t\t\t\tlinkedProfile: {},\r\n\t\t\t\tlinkedProfileDone: false\r\n\t\t\t})\r\n\r\n\t\t\tconst connector = appSelectors.connector(store.getState())\r\n\t\t\tconst linkedProfile = await connector.auth.getAssociatedLinkedInProfile()\r\n\r\n\t\t\tapp.setLinkedProfile({\r\n\t\t\t\tlinkedProfile,\r\n\t\t\t\tlinkedProfileDone: true\r\n\t\t\t})\r\n\t\t\treturn linkedProfile\r\n\t\t} catch (error) {\r\n\t\t\tapp.setLinkedProfile({\r\n\t\t\t\tlinkedProfile: {},\r\n\t\t\t\tlinkedProfileDone: true\r\n\t\t\t})\r\n\r\n\t\t\tnotifyError(error)\r\n\t\t}\r\n\t},\r\n\r\n\tgetSnailyProfile: async () => {\r\n\t\ttry {\r\n\t\t\tconst snailyConnector = appSelectors.connector(store.getState())\r\n\t\t\tconst appProfile = await snailyConnector.auth.getSnailyProfile()\r\n\t\t\tapp.setAppProfile({ appProfile, appProfileDone: true })\r\n\t\t\treturn appProfile\r\n\t\t} catch (error) {\r\n\t\t\thelpersFunc.logEnjectServicePromise(error)\r\n\t\t\t//#88 introduce FatalError and throw it here instead of generic Error with Message FATAL ERROR\r\n\t\t\tthrow new FatalError(\r\n\t\t\t\t`Unhandled exception occurs during getting ${CONSTS.PROJECT_NAME} profile`\r\n\t\t\t)\r\n\t\t}\r\n\t},\r\n\r\n\tsetUpInit: async () => {\r\n\t\tif (onGoingSetup) {\r\n\t\t\treturn\r\n\t\t}\r\n\r\n\t\tonGoingSetup = true\r\n\t\ttry {\r\n\t\t\tawait setUpInit()\r\n\t\t} catch (e) {\r\n\t\t\tconsole.error(e)\r\n\t\t} finally {\r\n\t\t\tonGoingSetup = false\r\n\t\t}\r\n\t}\r\n}\r\n","import axios from \"axios\";\n\nimport { connectorAPI } from \"../actions/connector\";\nimport {\n BackendValidationError,\n RequestTimedOutError,\n NotAuthorizedError,\n BadGatewayError,\n} from \"../shared/errors\";\n\nexport const httpRequest = async (data) => {\n let startTime = Date.now();\n try {\n const token = await connectorAPI.getAccessToken();\n axios.defaults.headers.common[\"Authorization\"] = token;\n\n //defined once again in a case if getAccessToken was slow, exchanged tokens\n startTime = Date.now();\n\n const result = await axios(data);\n return result;\n } catch (error) {\n const endTime = Date.now();\n if (\n error.response?.status === 502 ||\n error.response?.status === 503 ||\n error.response?.status === 504 ||\n error.message.includes(\"Network Error\")\n ) {\n throw new BadGatewayError(\n \"Bad network or service is temporarily unavailable.\"\n );\n }\n if (error.response?.status === 422) {\n throw new BackendValidationError(error.response.data.errors);\n }\n if (error.response?.status === 403) {\n throw new NotAuthorizedError(\"Not authorized\");\n }\n\n if (error.message.includes(\"timeout exceeded\")) {\n throw new RequestTimedOutError(\n `${data.method} ${data.url} is timed out, took ${endTime - startTime}`\n );\n }\n\n if (error) {\n throw new HttpRequestError(error);\n }\n }\n};\n\nexport class HttpRequestError extends Error {\n #axiosError;\n\n constructor(axiosError) {\n super(axiosError.message);\n this.#axiosError = axiosError;\n this.name = \"HttpRequestError\";\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, HttpRequestError);\n }\n }\n\n get axios() {\n return this.#axiosError;\n }\n\n get skipLogging() {\n return true;\n }\n}\n","/*\n This All action on api\n https://github.com/public-apis/public-apis\n*/\nimport { CONSTS } from \"../config/objectConst\";\nimport { contactsPageSize } from \"./contactsPageSize\";\nimport { httpRequest } from \"./httpRequest\";\n\nconst createParams = (data) => {\n let { archived, filter, keywords, orderby, skip } = data;\n let archivedParam = \"\";\n const statuses = filter ? filter : \"\";\n let resultFilters = \"\";\n const take = CONSTS.PAGE_SIZE;\n if (!orderby) {\n orderby = orderby ? orderby : \"created desc\";\n }\n if (archived !== undefined) {\n archivedParam = `archived eq ${archived}`;\n }\n if (archivedParam || statuses) {\n resultFilters = `&$filter=${archivedParam}${\n statuses ? ` ${archivedParam ? \"and\" : \"\"} ${statuses}` : \"\"\n }`;\n }\n\n return `?${take ? \"&$take=\" + take : \"\"}${\n skip ? \"&$skip=\" + skip : \"\"\n }${resultFilters}${keywords ? \"&$searchQuery=\" + keywords : \"\"}${\n orderby ? \"&$orderby=\" + orderby : \"\"\n }`;\n};\n\nexport const api = {\n acceptTeamInvitation: async (code) => {\n return await httpRequest({\n data: {\n code,\n },\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"POST\",\n\n url: `${CONSTS.API.URL}team/personas/accept-invitation`,\n });\n },\n buyMemberSubscriptionApi: async (id, plan, coupon) => {\n return await httpRequest({\n data: {\n coupon,\n plan_id: plan,\n },\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"POST\",\n\n url: `${CONSTS.API.URL}team/personas/${id}/subscription`,\n });\n },\n cancelSubscription: async () => {\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Content-Type\": \"application/json\",\n },\n method: \"PUT\",\n url: `${CONSTS.API.URL}subscription/cancel`,\n });\n },\n cancelTeamMemberSubscriptionApi: async (id) => {\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"PUT\",\n url: `${CONSTS.API.URL}team/personas/${id}/subscription/cancel`,\n });\n },\n\n cloneCampaignApi: async (id) => {\n const result = await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Content-Type\": \"application/json\",\n },\n method: \"PUT\",\n url: `${CONSTS.API.URL}campaigns/${id}/clone`,\n });\n return result;\n },\n completeCampaignApi: async (id) => {\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Content-Type\": \"application/json\",\n },\n method: \"PUT\",\n url: `${CONSTS.API.URL}campaigns/${id}/complete`,\n });\n },\n createLogEnjectService: async (data) => {\n try {\n return await httpRequest({\n data,\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Content-Type\": \"application/json\",\n },\n method: \"POST\",\n url: `${CONSTS.API.URL}logs`,\n });\n } catch (e) {\n console.error(e);\n }\n },\n deleteContacts: async (data) => {\n const { filter, keywords } = { ...data };\n let newKeywords = keywords;\n if (keywords && keywords.includes(\"\\\\*\")) {\n newKeywords = keywords.replaceAll(\"\\\\*\", \"*\");\n }\n\n let params = `?${filter ? \"$filter=\" + filter : \"\"}`;\n params += `${newKeywords ? \"&$searchQuery=\" + newKeywords : \"\"}`;\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"DELETE\",\n url: `${CONSTS.API.URL}contacts${params}`,\n });\n },\n\n deleteTeamMember: async (id) => {\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"DELETE\",\n url: `${CONSTS.API.URL}team/personas/${id}`,\n });\n },\n editImportsApi: async (data) => {\n const { id, name } = { ...data };\n return await httpRequest({\n data: {\n name,\n },\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Content-Type\": \"application/json\",\n },\n method: \"PUT\",\n url: `${CONSTS.API.URL}imports/${id}`,\n });\n },\n editMemberNickNameApi: async (data) => {\n const { id, name } = { ...data };\n return await httpRequest({\n data: {\n name,\n },\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Content-Type\": \"application/json\",\n },\n method: \"PUT\",\n url: `${CONSTS.API.URL}team/personas/${id}/nickname`,\n });\n },\n exportCampaignsTeamApi: async (data) => {\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"GET\",\n url: `${CONSTS.API.URL}team/campaigns/export${createParams(data)}`,\n });\n },\n exportContactsApi: async (data) => {\n let { filter, keywords, orderby } = { ...data };\n\n if (!orderby) {\n orderby = \"imported desc\";\n }\n let newKeywords = keywords;\n if (keywords && keywords.includes(\"\\\\*\")) {\n newKeywords = keywords.replaceAll(\"\\\\*\", \"*\");\n }\n const params = `?${filter ? \"&$filter=\" + filter : \"\"}${\n newKeywords ? \"&$searchQuery=\" + newKeywords : \"\"\n }${orderby ? \"&$orderby=\" + orderby : \"\"}`;\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"GET\",\n url: `${CONSTS.API.URL}contacts/export${params}`,\n });\n },\n\n exportContactsApiExecutions: async (data) => {\n let { filter, keywords, orderby } = { ...data };\n\n if (!orderby) {\n orderby = \"imported desc\";\n }\n let newKeywords = keywords;\n if (keywords && keywords.includes(\"\\\\*\")) {\n newKeywords = keywords.replaceAll(\"\\\\*\", \"*\");\n }\n const params = `?${filter ? \"&$filter=\" + filter : \"\"}${\n newKeywords ? \"&$searchQuery=\" + newKeywords : \"\"\n }${orderby ? \"&$orderby=\" + orderby : \"\"}`;\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"GET\",\n url: `${CONSTS.API.URL}executions/export${params}`,\n });\n },\n\n exportCsvExampleApi: async () => {\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"GET\",\n url: `${CONSTS.API.URL}contacts/csv-example`,\n });\n },\n\n exportRecentActivitiesApi: async (data) => {\n const { filter, keywords } = { ...data };\n\n let newKeywords = keywords;\n if (keywords && keywords.includes(\"\\\\*\")) {\n newKeywords = keywords.replaceAll(\"\\\\*\", \"*\");\n }\n\n const params = `?${filter ? \"&$filter=\" + filter : \"\"}${\n newKeywords ? \"&$searchQuery=\" + newKeywords : \"\"\n }`;\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"GET\",\n url: `${CONSTS.API.URL}recent-activities/export${params}`,\n });\n },\n\n getCampaignExecutionsStatisticsApi: async (id) => {\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"GET\",\n url: `${CONSTS.API.URL}campaigns/${id}/executions-statistics`,\n });\n },\n\n getCampaignsApi: async (data) => {\n let { archived, filter, keywords, orderby, skip, take } = {\n ...data,\n };\n let archivedParam = \"\";\n const statuses = filter ? filter : \"\";\n let resultFilters = \"\";\n\n if (!take) {\n take = CONSTS.PAGE_SIZE;\n }\n if (!orderby) {\n orderby = orderby ? orderby : \"created desc\";\n }\n if (archived !== undefined) {\n archivedParam = `(archived eq ${archived})`;\n }\n if (archivedParam || statuses) {\n resultFilters = `&$filter=${archivedParam}${\n statuses ? ` ${archivedParam ? \"and\" : \"\"} (${statuses})` : \"\"\n }`;\n }\n\n const params = `?${take ? \"&$take=\" + take : \"\"}${\n skip ? \"&$skip=\" + skip : \"\"\n }${resultFilters}${keywords ? \"&$searchQuery=\" + keywords : \"\"}${\n orderby ? \"&$orderby=\" + orderby : \"\"\n }`;\n\n return await httpRequest({\n headers: {\n Accept: \"application/json\",\n \"Access-Control-Allow-Origin\": \"*\",\n \"Content-Type\": \"application/json\",\n },\n method: \"GET\",\n url: `${CONSTS.API.URL}campaigns/page${params}`,\n });\n },\n getCampaignsTeamApi: async (data) => {\n return await httpRequest({\n headers: {\n Accept: \"application/json\",\n \"Access-Control-Allow-Origin\": \"*\",\n \"Content-Type\": \"application/json\",\n },\n method: \"GET\",\n url: `${CONSTS.API.URL}team/campaigns${createParams(data)}`,\n });\n },\n\n getContactsApi: async (data) => {\n let { filter, keywords, orderby, skip } = { ...data };\n const take = contactsPageSize.get();\n if (!orderby) {\n orderby = \"imported desc\";\n }\n let newKeywords = keywords;\n if (keywords && keywords.includes(\"\\\\*\")) {\n newKeywords = keywords.replaceAll(\"\\\\*\", \"*\");\n }\n const params = `?${take ? \"&$take=\" + take : \"\"}${\n skip ? \"&$skip=\" + skip : \"\"\n }${filter ? \"&$filter=\" + filter : \"\"}${\n newKeywords ? \"&$searchQuery=\" + newKeywords : \"\"\n }${orderby ? \"&$orderby=\" + orderby : \"\"}`;\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"GET\",\n url: `${CONSTS.API.URL}contacts/page${params}`,\n });\n },\n\n getContactsCountApi: async (data) => {\n const { filter, keywords } = { ...data };\n const params = `?${keywords ? \"&$searchQuery=\" + keywords : \"\"}${\n filter ? \"&$filter=\" + filter : \"\"\n }`;\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"GET\",\n url: `${CONSTS.API.URL}contacts/count${params}`,\n });\n },\n\n getContactsExecutionsApi: async (data) => {\n const { filter, keywords, orderby, skip } = data;\n const take = contactsPageSize.get();\n let newKeywords = keywords;\n if (keywords && keywords.includes(\"\\\\*\")) {\n newKeywords = keywords.replaceAll(\"\\\\*\", \"*\");\n }\n const params = `?${take ? \"&$take=\" + take : \"\"}${\n skip ? \"&$skip=\" + skip : \"\"\n }${filter ? \"&$filter=\" + filter : \"\"}${\n newKeywords ? \"&$searchQuery=\" + newKeywords : \"\"\n }${orderby ? \"&$orderby=\" + orderby : \"\"}`;\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"GET\",\n url: `${CONSTS.API.URL}executions/page${params}`,\n });\n },\n getContactsLocationApi: async (data) => {\n let { keywords, take } = { ...data };\n if (!take) {\n take = 10;\n }\n const params = `?${keywords ? \"&$searchQuery=\" + keywords : \"\"}${\n take ? \"&$take=\" + take : \"\"\n }`;\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"GET\",\n url: `${CONSTS.API.URL}contacts/locations${params}`,\n });\n },\n\n getImportsApi: async (id) => {\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"GET\",\n url: `${CONSTS.API.URL}imports/${id}`,\n });\n },\n getManagementUrl: async () => {\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"GET\",\n url: `${CONSTS.API.URL}subscription/management-url`,\n });\n },\n getRecentImportsApi: async () => {\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"GET\",\n url: `${CONSTS.API.URL}imports/recent`,\n });\n },\n getSubscription: async () => {\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"GET\",\n url: `${CONSTS.API.URL}subscription`,\n });\n },\n\n // ! probably dead code\n getWorkingHours: async () => {\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"GET\",\n url: `${CONSTS.API.URL}workspace/working-hours-in-minutes`,\n });\n },\n inviteTeamMember: async (email) => {\n return await httpRequest({\n data: {\n email,\n },\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"POST\",\n\n url: `${CONSTS.API.URL}team/personas/invite`,\n });\n },\n\n ordersSync: async (orderId, orderReference) => {\n return await httpRequest({\n data: {\n order_id: orderId,\n reference: orderReference,\n },\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"POST\",\n url: `${CONSTS.API.URL}orders/sync`,\n });\n },\n previewContacts: async (data) => {\n const { filter, keywords } = { ...data };\n let newKeywords = keywords;\n if (keywords && keywords.includes(\"\\\\*\")) {\n newKeywords = keywords.replaceAll(\"\\\\*\", \"*\");\n }\n\n let params = `?${filter ? \"$filter=\" + filter : \"\"}`;\n params += `${newKeywords ? \"&$searchQuery=\" + newKeywords : \"\"}`;\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"get\",\n url: `${CONSTS.API.URL}contacts/delete/preview${params}`,\n });\n },\n resendTeamInvitation: async (id) => {\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"POST\",\n url: `${CONSTS.API.URL}team/personas/${id}/resend-invitation`,\n });\n },\n\n resumeSubscription: async () => {\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Content-Type\": \"application/json\",\n },\n method: \"PUT\",\n url: `${CONSTS.API.URL}subscription/resume`,\n });\n },\n resumeTeamMemberSubscriptionApi: async (id) => {\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"PUT\",\n url: `${CONSTS.API.URL}team/personas/${id}/subscription/resume`,\n });\n },\n setDailyLimits: async (limits) => {\n const data = {\n daily_linkedin_follow_limit: +limits.followPerDayLimit.value,\n daily_linkedin_invitations_limit: +limits.invitationPerDayLimit.value,\n daily_linkedin_messages_limit: +limits.messagesPerDayLimit.value,\n daily_linkedin_react_on_post_limit: +limits.likesPerDayLimit.value,\n };\n return await httpRequest({\n data,\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Content-Type\": \"application/json\",\n },\n method: \"PUT\",\n url: `${CONSTS.API.URL}workspace/daily-limits`,\n });\n },\n setExecutionComplete: async (id) => {\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Content-Type\": \"application/json\",\n },\n method: \"PUT\",\n url: `${CONSTS.API.URL}executions/${id}/complete`,\n });\n },\n setNewData: async (url, data) => {\n return await httpRequest({\n data,\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Content-Type\": \"application/json\",\n },\n method: \"PUT\",\n url: `${CONSTS.API.URL}${url}`,\n });\n },\n startCampaignApi: async (id) => {\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Content-Type\": \"application/json\",\n },\n method: \"PUT\",\n url: `${CONSTS.API.URL}campaigns/${id}/run`,\n });\n },\n\n stopCampaignApi: async (id) => {\n return await httpRequest({\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Content-Type\": \"application/json\",\n },\n method: \"PUT\",\n url: `${CONSTS.API.URL}campaigns/${id}/stop`,\n });\n },\n\n updateRoleApi: async (id, role) => {\n return await httpRequest({\n data: {\n role,\n },\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Content-Type\": \"application/json\",\n },\n method: \"PUT\",\n url: `${CONSTS.API.URL}team/personas/${id}`,\n });\n },\n\n upgradeMemberSubscriptionApi: async (id, plan, coupon) => {\n return await httpRequest({\n data: {\n coupon,\n plan_id: plan,\n },\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n method: \"PUT\",\n\n url: `${CONSTS.API.URL}team/personas/${id}/subscription`,\n });\n },\n upgradeSubscription: async (id) => {\n return await httpRequest({\n data: { plan_id: id },\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Content-Type\": \"application/json\",\n },\n method: \"PUT\",\n url: `${CONSTS.API.URL}subscription/upgrade`,\n });\n },\n};\n","import { CONSTS } from '../../config/objectConst'\r\n\r\nconst isEnabled = import.meta.env.PUBLIC_SENTRY === 'true'\r\n\r\nasync function initSentry(userId: string) {\r\n\tif (!isEnabled) {\r\n\t\treturn\r\n\t}\r\n\r\n\tconst { init, setContext, setTag } = await import('@sentry/react')\r\n\r\n\tinit({\r\n\t\tallowUrls: [\r\n\t\t\t'app.snaily.io',\r\n\t\t\t'sandbox-app.snaily.io',\r\n\t\t\t'chrome-extension://febgaeoegckcdcdhammknmiobpjkpgbe',\r\n\t\t\t'chrome-extension://gjncjmifcnnbaggdakbkgdmfkmknijhb'\r\n\t\t],\r\n\t\t//integrations: [new BrowserTracing()],\r\n\r\n\t\tdsn: 'https://c563bd35cb0f4697bda0dfe29df80483@o1303236.ingest.sentry.io/6541994',\r\n\t\t// Set tracesSampleRate to 1.0 to capture 100%\r\n\t\t// of transactions for performance monitoring.\r\n\t\t// We recommend adjusting this value in production\r\n\t\ttracesSampleRate: 0.5\r\n\t})\r\n\r\n\tsetContext('app', {\r\n\t\tuserId,\r\n\t\tversion: CONSTS.APP_VERSION\r\n\t})\r\n\tsetTag('app_version', CONSTS.APP_VERSION)\r\n}\r\n\r\nasync function reportToSentry(error: unknown) {\r\n\tif (isEnabled) {\r\n\t\tconst { captureException } = await import('@sentry/react')\r\n\r\n\t\tcaptureException(error)\r\n\t}\r\n}\r\n\r\nexport { initSentry, reportToSentry }\r\n","import { api } from \"../api/api\";\nimport ErrorStackParser from \"error-stack-parser\";\n// configs\nimport { CONSTS } from \"./objectConst\";\nimport { HttpRequestError } from \"../api/httpRequest\";\nimport { reportToSentry } from \"../shared/integrations/sentry\";\n\nconst isThirdPartyExtensionError = (stackTrace) => {\n const result =\n stackTrace.includes(\"chrome-extension://\") &&\n !stackTrace.includes(`chrome-extension://${CONSTS.EXTENSION_ID}`);\n return result;\n};\n\nconst isExtensionDisabled = (error) => {\n const result =\n error instanceof Error && error.name === \"ExtensionNotInstalledError\";\n return result;\n};\n\nconst isMissMatchWithBackend = (error) => {\n const result =\n error instanceof HttpRequestError &&\n error.axios.response &&\n error.axios.response.status === 404;\n return result;\n};\n\nconst logEnjectService = async (error) => {\n if (isExtensionDisabled() || isMissMatchWithBackend()) {\n window.location.reload();\n }\n\n if (error.skipLogging) {\n console.warn(error);\n return;\n }\n\n let stackTrace;\n try {\n stackTrace = [...ErrorStackParser.parse(error).map((item) => item.source)]\n .join(\" \\n \")\n .trim();\n\n if (isThirdPartyExtensionError(stackTrace)) {\n return;\n }\n\n reportToSentry(error);\n } catch (e) {\n reportToSentry(error);\n reportToSentry(e);\n return;\n }\n\n const data = {\n severity: \"Error\",\n event_id: \"AppGenericError\",\n message: \"Unhandled app error {Message}, {StackTrace},{Version}\",\n args: [`${error.name}:${error.message}`, stackTrace, CONSTS.APP_VERSION],\n };\n\n await api.createLogEnjectService(data);\n};\n\nexport const helpersFunc = {\n logEnjectServiceCatch: (error) => {\n if (CONSTS.LOGS_SETTINGS.didCatch) {\n logEnjectService(error);\n }\n },\n logEnjectServicePromise: (error) => {\n console.log(error);\n if (CONSTS.LOGS_SETTINGS.rejection) {\n logEnjectService(error);\n }\n },\n logEnjectService404: async () => {\n const data = {\n severity: \"Warning\",\n event_id: \"AppGenericError\",\n message: `404 page {Href}`,\n args: [window.location.href],\n };\n await api.createLogEnjectService(data);\n },\n};\n","import { notificationUtils } from 'features/notifications'\r\nimport { appSelectors } from 'redux/reducers/app'\r\nimport { NotAuthorizedError } from 'shared/errors'\r\n\r\nimport store from '../../redux/store'\r\n\r\nexport function shouldUpgrade(error: Error | string) {\r\n\tconst isExpired =\r\n\t\terror instanceof NotAuthorizedError &&\r\n\t\t!appSelectors.subscriptionIsActive(store.getState())\r\n\r\n\tif (isExpired) {\r\n\t\tnotificationUtils.snackById('3.17')\r\n\t}\r\n\r\n\treturn isExpired\r\n}\r\n","import { helpersFunc } from 'config/helpers'\r\nimport { notificationUtils } from 'features/notifications'\r\nimport { subscriptionUtils } from 'features/subscription'\r\n\r\nconst catchNotification = (action: () => Promise) =>\r\n\taction().catch(notifyError)\r\n\r\nfunction getMessage(error: Error) {\r\n\tswitch (error.name) {\r\n\t\tcase 'BadGatewayError':\r\n\t\tcase 'RequestTimedOutError':\r\n\t\t\treturn 'Bad network or service is temporarily unavailable. Please, try again later.'\r\n\t\tcase 'OldExtensionError':\r\n\t\t\treturn 'Please download new extension version'\r\n\r\n\t\tdefault:\r\n\t\t\treturn error.message ? error.message : error.name\r\n\t}\r\n}\r\n\r\nfunction notifyError(error: unknown, isError = true, duration = 5000) {\r\n\tlet text = ''\r\n\tif (error instanceof Error) {\r\n\t\tif (subscriptionUtils.shouldUpgrade(error)) {\r\n\t\t\treturn\r\n\t\t}\r\n\r\n\t\ttext = getMessage(error)\r\n\t\thelpersFunc.logEnjectServicePromise(error)\r\n\t}\r\n\r\n\tnotificationUtils.show(text, isError, duration)\r\n}\r\n\r\nexport { catchNotification, notifyError }\r\n","import store from '../../../redux/store.ts'\r\nimport { actions } from '../slice.ts'\r\n\r\nexport function show(text: string, isError = true, duration = 5_000) {\r\n\tstore.dispatch(\r\n\t\tactions.notificationUse({\r\n\t\t\terror: isError,\r\n\t\t\tstatus: true,\r\n\t\t\ttext\r\n\t\t})\r\n\t)\r\n\tsetTimeout(() => {\r\n\t\tstore.dispatch(\r\n\t\t\tactions.notificationUse({\r\n\t\t\t\terror: isError,\r\n\t\t\t\tstatus: false,\r\n\t\t\t\ttext: ''\r\n\t\t\t})\r\n\t\t)\r\n\t}, duration)\r\n}\r\n","export class RequestTimedOutError extends Error {\r\n\tget skipLogging() {\r\n\t\treturn false\r\n\t}\r\n\r\n\tconstructor(message: string) {\r\n\t\tsuper(message)\r\n\t\tthis.name = 'RequestTimedOutError'\r\n\r\n\t\tif (Error.captureStackTrace) {\r\n\t\t\tError.captureStackTrace(this, RequestTimedOutError)\r\n\t\t}\r\n\t}\r\n}\r\n","import type { BaseQueryFn } from '@reduxjs/toolkit/query'\r\nimport type { AxiosRequestConfig, AxiosResponse } from 'axios'\r\n\r\nimport { notifyError } from 'shared/errors'\r\n\r\nimport { httpRequest } from '../httpRequest'\r\n\r\nconst axiosBaseQuery =\r\n\t(\r\n\t\t{ baseUrl }: { baseUrl: string } = { baseUrl: '' }\r\n\t): BaseQueryFn<\r\n\t\t{\r\n\t\t\tdata?: AxiosRequestConfig['data']\r\n\t\t\theaders?: AxiosRequestConfig['headers']\r\n\t\t\tmethod?: AxiosRequestConfig['method']\r\n\t\t\tparams?: AxiosRequestConfig['params']\r\n\t\t\turl: string\r\n\t\t},\r\n\t\tunknown,\r\n\t\tunknown\r\n\t> =>\r\n\tasync ({ data, headers, method, params, url }) => {\r\n\t\ttry {\r\n\t\t\tconst result = await httpRequest({\r\n\t\t\t\tdata,\r\n\t\t\t\theaders,\r\n\t\t\t\tmethod,\r\n\t\t\t\tparams,\r\n\t\t\t\turl: baseUrl + url\r\n\t\t\t})\r\n\t\t\treturn { data: (result as AxiosResponse).data }\r\n\t\t} catch (axiosError) {\r\n\t\t\tnotifyError(axiosError)\r\n\r\n\t\t\treturn {\r\n\t\t\t\terror: true\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\nexport { axiosBaseQuery }\r\n","import { createEntityAdapter } from '@reduxjs/toolkit'\r\n\r\nimport type { Conversation, Message } from '../model/types'\r\n\r\nconst conversations = createEntityAdapter<\r\n\tConversation,\r\n\tConversation['entity_id']\r\n>({\r\n\tselectId: conversation => conversation.entity_id\r\n\t// sortComparer: sortNewFirst\r\n})\r\n\r\nconst messages = createEntityAdapter({\r\n\tselectId: message => message.message_id\r\n})\r\n\r\nexport { conversations, messages }\r\n","import {\r\n\tcreateSlice,\r\n\ttype EntityState,\r\n\ttype PayloadAction\r\n} from '@reduxjs/toolkit'\r\nimport { createSetter } from 'shared/redux-helpers'\r\n\r\nimport type {\r\n\tConversation,\r\n\tFilter,\r\n\tGetProps,\r\n\tMessage,\r\n\tUpdateConversation\r\n} from './types'\r\n\r\nimport { api } from '../api'\r\nimport { adapters } from '../utils'\r\n\r\ninterface EditMessage {\r\n\tid: string\r\n\ttext: string\r\n}\r\n\r\ninterface Slice extends GetProps {\r\n\tconversations: EntityState\r\n\teditMessage: EditMessage | null\r\n\tfocusedInboxEnabled: boolean\r\n\tmessages: EntityState\r\n\tmessageToDelete: string\r\n}\r\n\r\nconst initialState: Slice = {\r\n\tconversations: adapters.conversations.getInitialState(),\r\n\teditMessage: null,\r\n\tfilter: 'primary',\r\n\tfocusedInboxEnabled: false,\r\n\tmessages: adapters.messages.getInitialState(),\r\n\tmessageToDelete: '',\r\n\tsearch: ''\r\n}\r\n\r\nfunction resetFilter(state: Slice) {\r\n\tsetFilter(state, state.focusedInboxEnabled ? 'focused' : 'primary')\r\n}\r\n\r\nfunction setFilter(state: Slice, filter: Filter) {\r\n\tstate.filter = filter\r\n\tsetSearch(state, '')\r\n}\r\n\r\nfunction setSearch(state: Slice, search: string) {\r\n\tstate.search = search\r\n}\r\n\r\nconst tabFilters = new Set(['focused', 'other'])\r\n\r\nconst slice = createSlice({\r\n\textraReducers: builder =>\r\n\t\tbuilder.addMatcher(\r\n\t\t\tapi.endpoints.settings.matchFulfilled,\r\n\t\t\t(state, { payload: { focusedInboxEnabled } }) => {\r\n\t\t\t\tstate.focusedInboxEnabled = focusedInboxEnabled\r\n\t\t\t\tresetFilter(state)\r\n\t\t\t}\r\n\t\t),\r\n\r\n\tinitialState,\r\n\tname: 'messaging',\r\n\treducers: {\r\n\t\taddConversations(state, action: PayloadAction) {\r\n\t\t\tadapters.conversations.upsertMany(state.conversations, action)\r\n\t\t},\r\n\r\n\t\taddMessages(state, action: PayloadAction) {\r\n\t\t\tadapters.messages.upsertMany(state.messages, action)\r\n\t\t},\r\n\t\tresetDeleteMessage(state) {\r\n\t\t\tstate.messageToDelete = ''\r\n\t\t},\r\n\t\tresetEditMessage(state) {\r\n\t\t\tstate.editMessage = null\r\n\t\t},\r\n\t\tresetFilter,\r\n\t\tresetSearch: state => setSearch(state, ''),\r\n\r\n\t\tsetEditMessage: createSetter('editMessage'),\r\n\t\tsetFilter: (state, { payload }: PayloadAction) =>\r\n\t\t\tsetFilter(state, payload),\r\n\t\tsetMessageToDelete: createSetter('messageToDelete'),\r\n\r\n\t\tsetSearch: (state, { payload }: PayloadAction) =>\r\n\t\t\tsetSearch(state, payload),\r\n\t\tupdateMessage(\r\n\t\t\tstate,\r\n\t\t\taction: PayloadAction<{ changes: Partial; id: string }>\r\n\t\t) {\r\n\t\t\tadapters.messages.updateOne(state.messages, action.payload)\r\n\t\t},\r\n\r\n\t\tupdateRead(\r\n\t\t\tstate,\r\n\t\t\t{ payload: { id, mark } }: PayloadAction\r\n\t\t) {\r\n\t\t\tadapters.conversations.updateOne(state.conversations, {\r\n\t\t\t\tchanges: { unread_count: Number(!mark) },\r\n\t\t\t\tid\r\n\t\t\t})\r\n\t\t},\r\n\t\tupdateStar(\r\n\t\t\tstate,\r\n\t\t\t{ payload: { id, mark } }: PayloadAction\r\n\t\t) {\r\n\t\t\tadapters.conversations.updateOne(state.conversations, {\r\n\t\t\t\tchanges: { is_starred: mark },\r\n\t\t\t\tid\r\n\t\t\t})\r\n\t\t}\r\n\t},\r\n\r\n\tselectors: {\r\n\t\t/**\r\n\t\t * ! For entity adapter only\r\n\t\t * */\r\n\t\tconversations: state => state.conversations,\r\n\t\tdeleteMessage: state => state.messageToDelete,\r\n\t\teditMessage: state => state.editMessage,\r\n\t\tfilter: state => state.filter,\r\n\t\t/**\r\n\t\t * ! For entity adapter only\r\n\t\t * */\r\n\t\tmessages: state => state.messages,\r\n\t\tsearch: state => state.search,\r\n\t\tsearchMode: state => Boolean(state.search),\r\n\t\twithTabs: ({ filter, search }) => Boolean(!search && tabFilters.has(filter))\r\n\t}\r\n})\r\n\r\nconst actions = slice.actions\r\n\r\nexport { actions, slice }\r\n","import appDay from 'dayjs'\r\nimport timezone from 'dayjs/plugin/timezone'\r\nimport utc from 'dayjs/plugin/utc'\r\n// import isToday from \"dayjs/plugin/isToday\";\r\n\r\n// appDay.extend(isToday);\r\nappDay.extend(utc)\r\nappDay.extend(timezone)\r\n\r\nexport { appDay }\r\n","const ROUTES = ['/messaging', '/messaging/thread/:conversation'] as const\r\n\r\nconst Label = {\r\n\tEmoji: 'Open Emoji Keyboard'\r\n}\r\n\r\nexport { Label, ROUTES }\r\n","import type { Dayjs } from 'dayjs'\r\n\r\nimport { appDay } from 'shared/day'\r\n\r\nimport type { Message, RenderContent } from '../model/types'\r\n\r\nimport { ROUTES } from '../const'\r\n\r\nconst NOW = appDay()\r\n\r\nconst formatChatDate = (day: Dayjs) => {\r\n\tif (day.isSame(NOW, 'day')) {\r\n\t\treturn 'Today'\r\n\t}\r\n\r\n\treturn formatDateTime(day)\r\n}\r\n\r\nconst formatTime = (timeString: string) => {\r\n\tconst asDay = appDay(timeString)\r\n\treturn asDay.format('HH:mm')\r\n}\r\n\r\nconst formatDateTime = (dateTimeString: Dayjs | string) => {\r\n\tconst asDay = appDay(dateTimeString)\r\n\r\n\tif (asDay.isSame(NOW, 'day')) {\r\n\t\treturn asDay.format('HH:mm')\r\n\t}\r\n\tif (asDay.isSame(NOW, 'year')) {\r\n\t\treturn asDay.format('DD MMM')\r\n\t}\r\n\treturn asDay.format('DD MMM, YYYY')\r\n}\r\n\r\nconst findRenderContent = (\r\n\tcontents: RenderContent[]\r\n): keyof RenderContent | null => {\r\n\tfor (const content of contents) {\r\n\t\tfor (const key in content) {\r\n\t\t\tconst typed = key as keyof RenderContent\r\n\r\n\t\t\tconst value = content[typed]\r\n\r\n\t\t\tif (value !== null) {\r\n\t\t\t\treturn typed\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn null\r\n}\r\n\r\ntype CreatedAt = Pick\r\n\r\nconst sortOldFirst = (first: CreatedAt, second: CreatedAt) =>\r\n\tappDay(first.created_at).diff(second.created_at)\r\n\r\nconst sortNewFirst = (first: CreatedAt, second: CreatedAt) =>\r\n\tappDay(second.created_at).diff(first.created_at)\r\n\r\ninterface MessageWithFlag {\r\n\tid: string\r\n\tshowAvatar: boolean\r\n}\r\n\r\nclass MessageTransformer {\r\n\tlastDay: Dayjs | null = null\r\n\r\n\t#lastUser = ''\r\n\r\n\ttransform(message: Message): MessageWithFlag {\r\n\t\tconst asDay = appDay(message.created_at)\r\n\r\n\t\tconst isSameUser = this.#checkUser(message.from?.entityId ?? '')\r\n\t\tlet showAvatar = true\r\n\r\n\t\tif (isSameUser && this.lastDay) {\r\n\t\t\tshowAvatar = this.#checkInterval(asDay)\r\n\t\t}\r\n\r\n\t\tthis.lastDay = asDay\r\n\r\n\t\treturn {\r\n\t\t\tid: message.message_id,\r\n\t\t\tshowAvatar\r\n\t\t}\r\n\t}\r\n\r\n\t#checkInterval(day: Dayjs) {\r\n\t\tconst minutes = day.diff(this.lastDay, 'minutes')\r\n\t\treturn minutes > 1\r\n\t}\r\n\r\n\t#checkUser(user: string) {\r\n\t\tconst isSame = this.#lastUser === user\r\n\t\tthis.#lastUser = user\r\n\r\n\t\treturn isSame\r\n\t}\r\n}\r\n\r\nfunction createMessageMap(messages: Message[]) {\r\n\tmessages.sort(sortOldFirst)\r\n\tconst days: Dayjs[] = []\r\n\r\n\tconst transformer = new MessageTransformer()\r\n\r\n\tconst map = messages.reduce>(\r\n\t\t(map, message) => {\r\n\t\t\tconst result = transformer.transform(message)\r\n\r\n\t\t\tif (!transformer.lastDay) {\r\n\t\t\t\treturn map\r\n\t\t\t}\r\n\r\n\t\t\tconst date = transformer.lastDay.startOf('day')\r\n\t\t\tconst key = date.toISOString()\r\n\r\n\t\t\tif (key in map) {\r\n\t\t\t\tmap[key].push(result)\r\n\t\t\t} else {\r\n\t\t\t\tdays.push(date)\r\n\t\t\t\tmap[key] = [result]\r\n\t\t\t}\r\n\r\n\t\t\treturn map\r\n\t\t},\r\n\t\t{}\r\n\t)\r\n\r\n\treturn { days, map }\r\n}\r\n\r\nconst getConversationUrl = (conversation: string) =>\r\n\tROUTES[1].replace(':conversation', conversation)\r\n\r\nexport {\r\n\tcreateMessageMap,\r\n\tfindRenderContent,\r\n\tformatChatDate,\r\n\tformatDateTime,\r\n\tformatTime,\r\n\tgetConversationUrl,\r\n\tsortNewFirst,\r\n\tsortOldFirst\r\n}\r\n","import type { RootState } from 'redux/store'\r\n\r\nimport { createSelector } from '@reduxjs/toolkit'\r\nimport { appSelectors } from 'redux/reducers/app'\r\n\r\nimport type { Conversation, Message } from '../model/types'\r\n\r\nimport { api } from '../api'\r\nimport { slice } from '../model/slice'\r\nimport * as adapters from './adapters'\r\nimport { createMessageMap } from './utils'\r\n\r\nconst simpleSelectors = slice.selectors\r\n\r\nconst getRoot = (state: RootState) => state\r\nconst placeholderId = (id: string) => id\r\n\r\nconst createConversationsSelector = createSelector(\r\n\tsimpleSelectors.filter,\r\n\tsimpleSelectors.search,\r\n\t(filter, search) => api.endpoints.conversations.select({ filter, search })\r\n)\r\n\r\nconst selectConversations = createSelector(\r\n\tgetRoot,\r\n\tcreateConversationsSelector,\r\n\t(root, select) => {\r\n\t\tlet nextCursor = ''\r\n\t\tconst conversations: Conversation[] = []\r\n\r\n\t\tconst { data, isUninitialized, originalArgs } = select(root)\r\n\t\tif (!isUninitialized && data) {\r\n\t\t\tnextCursor = data?.nextCursor ?? ''\r\n\t\t\tconversations.push(...data.items)\r\n\r\n\t\t\tif (nextCursor) {\r\n\t\t\t\tfunction checkNext() {\r\n\t\t\t\t\tconst select = api.endpoints.conversationsNext.select({\r\n\t\t\t\t\t\t...originalArgs!,\r\n\t\t\t\t\t\tnextCursor\r\n\t\t\t\t\t})\r\n\r\n\t\t\t\t\tconst { data, isUninitialized } = select(root)\r\n\r\n\t\t\t\t\tif (!isUninitialized && data) {\r\n\t\t\t\t\t\tconversations.push(...data.items)\r\n\t\t\t\t\t\tnextCursor = data.nextCursor ?? ''\r\n\r\n\t\t\t\t\t\tif (nextCursor) {\r\n\t\t\t\t\t\t\tcheckNext()\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcheckNext()\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn { conversations, nextCursor }\r\n\t}\r\n)\r\n\r\nconst selectParticipants = createSelector(placeholderId, id =>\r\n\tapi.endpoints.participants.select(id)\r\n)\r\n\r\nconst selectConversationalist = createSelector(\r\n\tappSelectors.personIdLi,\r\n\t(state: RootState, conversation: string) =>\r\n\t\tselectParticipants(conversation)(state),\r\n\t(id, { data: participants }) =>\r\n\t\tparticipants?.find(participant => participant.entityId !== id)\r\n)\r\n\r\nconst createMessagesSelector = createSelector(placeholderId, id =>\r\n\tapi.endpoints.messages.select(id)\r\n)\r\n\r\nconst selectConversation = createSelector(\r\n\tgetRoot,\r\n\t(_: RootState, id: string) => createMessagesSelector(id),\r\n\t(root, select) => {\r\n\t\tconst messages: Message[] = []\r\n\t\tlet prevCursor = ''\r\n\r\n\t\tconst { data, isUninitialized, originalArgs: id } = select(root)\r\n\t\tif (!isUninitialized && data) {\r\n\t\t\tmessages.push(...data.items)\r\n\r\n\t\t\tprevCursor = data.prevCursor ?? ''\r\n\t\t\tif (prevCursor) {\r\n\t\t\t\tfunction checkPrev() {\r\n\t\t\t\t\tconst select = api.endpoints.messagesPrev.select({\r\n\t\t\t\t\t\tid: id!,\r\n\t\t\t\t\t\tprevCursor\r\n\t\t\t\t\t})\r\n\r\n\t\t\t\t\tconst { data, isUninitialized } = select(root)\r\n\r\n\t\t\t\t\tif (!isUninitialized && data) {\r\n\t\t\t\t\t\tmessages.push(...data.items)\r\n\t\t\t\t\t\tprevCursor = data.prevCursor ?? ''\r\n\r\n\t\t\t\t\t\tif (prevCursor) {\r\n\t\t\t\t\t\t\tcheckPrev()\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcheckPrev()\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn { ...createMessageMap(messages), prevCursor }\r\n\t}\r\n)\r\n\r\nexport const selectors = {\r\n\t...simpleSelectors,\r\n\tconversation: selectConversation,\r\n\tconversationalist: selectConversationalist,\r\n\tconversations: adapters.conversations.getSelectors(\r\n\t\tsimpleSelectors.conversations\r\n\t),\r\n\tmessages: adapters.messages.getSelectors(simpleSelectors.messages),\r\n\tshowedConversations: selectConversations\r\n}\r\n","import { connectorAPI } from 'actions/connector'\r\nimport { CONSTS } from 'config/objectConst'\r\n\r\nimport type { AttachmentProps } from '../model/types'\r\n\r\nexport async function fetchAttachments(\r\n\t{ accepts, id, url }: AttachmentProps,\r\n\t{\r\n\t\tsignal\r\n\t}: {\r\n\t\tsignal?: AbortSignal\r\n\t}\r\n) {\r\n\tconst token = await connectorAPI.getAccessToken()\r\n\tconst response = await fetch(\r\n\t\t`${CONSTS.API.URL_AUTOMATION}conversations/${id}/attachments/${encodeURIComponent(url)}`,\r\n\t\t{\r\n\t\t\theaders: {\r\n\t\t\t\tAccept: accepts,\r\n\t\t\t\tAuthorization: token\r\n\t\t\t},\r\n\t\t\tmethod: 'GET',\r\n\t\t\tsignal\r\n\t\t}\r\n\t)\r\n\r\n\tconst blob = await response.blob()\r\n\r\n\treturn { data: URL.createObjectURL(blob) }\r\n}\r\n","import type * as Api from '../model/types'\r\n\r\nimport store from '../../../redux/store'\r\nimport { actions } from '../model/slice'\r\n\r\nfunction saveConversations(response: Api.ConversationResponse) {\r\n\tconst { items } = response\r\n\tconst action = actions.addConversations(items)\r\n\tstore.dispatch(action)\r\n\r\n\treturn response\r\n}\r\n\r\nfunction saveMessages(response: Api.EventsResponse) {\r\n\tconst { items } = response\r\n\tconst action = actions.addMessages(items)\r\n\tstore.dispatch(action)\r\n\r\n\treturn response\r\n}\r\n\r\nexport { saveConversations, saveMessages }\r\n","import { automationApi, Tag } from 'api/automationApi'\r\n\r\nimport type { RootState } from '../../redux/store'\r\nimport type * as Api from './model/types'\r\n\r\nimport { updateReactions } from './utils/optimistic'\r\nimport { fetchAttachments } from './utils/query'\r\nimport { saveConversations, saveMessages } from './utils/update'\r\n\r\nexport const api = automationApi.injectEndpoints({\r\n\tendpoints: create => ({\r\n\t\tarchive: create.mutation({\r\n\t\t\tinvalidatesTags: [Tag.Conversation],\r\n\t\t\tquery: ({ id, mark }) => ({\r\n\t\t\t\tmethod: 'PUT',\r\n\t\t\t\turl: `conversations/${id}/${mark ? 'archive' : 'unarchive'}`\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\tattachment: create.query({\r\n\t\t\tqueryFn: fetchAttachments\r\n\t\t}),\r\n\r\n\t\tconversations: create.query({\r\n\t\t\tprovidesTags: [Tag.Conversation],\r\n\t\t\tquery: ({ filter, search }) => {\r\n\t\t\t\tconst type = search ? 'search' : filter\r\n\r\n\t\t\t\treturn {\r\n\t\t\t\t\tparams: {\r\n\t\t\t\t\t\tkeywords: search || undefined\r\n\t\t\t\t\t},\r\n\t\t\t\t\turl: `mailboxes/${type}/conversations/recent`\r\n\t\t\t\t}\r\n\t\t\t},\r\n\r\n\t\t\ttransformResponse: saveConversations\r\n\t\t}),\r\n\r\n\t\tconversationsNext: create.query({\r\n\t\t\tprovidesTags: [Tag.Conversation],\r\n\t\t\tquery: ({ filter, nextCursor, search }) => {\r\n\t\t\t\tconst type = search ? 'search' : filter\r\n\r\n\t\t\t\treturn {\r\n\t\t\t\t\tparams: {\r\n\t\t\t\t\t\tkeywords: search || undefined,\r\n\t\t\t\t\t\tnextCursor\r\n\t\t\t\t\t},\r\n\t\t\t\t\turl: `mailboxes/${type}/conversations/next`\r\n\t\t\t\t}\r\n\t\t\t},\r\n\r\n\t\t\ttransformResponse: saveConversations\r\n\t\t}),\r\n\r\n\t\tdelete: create.mutation({\r\n\t\t\tinvalidatesTags: [Tag.Conversation],\r\n\t\t\tquery: id => ({\r\n\t\t\t\tmethod: 'DELETE',\r\n\t\t\t\turl: `conversations/${id}`\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\tdeleteMessage: create.mutation({\r\n\t\t\tinvalidatesTags: [Tag.Messages],\r\n\t\t\tquery: ({ conversation, id }) => ({\r\n\t\t\t\tmethod: 'DELETE',\r\n\t\t\t\turl: `conversations/${conversation}/events/${id}`\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\teditMessage: create.mutation({\r\n\t\t\tinvalidatesTags: [Tag.Messages],\r\n\t\t\tquery: ({ conversation, id, message }) => ({\r\n\t\t\t\tdata: message,\r\n\t\t\t\theaders: {\r\n\t\t\t\t\t/**\r\n\t\t\t\t\t * ! Don't delete\r\n\t\t\t\t\t * RTK Query sends plain string as FormData if Content-Type is not set\r\n\t\t\t\t\t * */\r\n\t\t\t\t\t'Content-Type': 'application/json'\r\n\t\t\t\t},\r\n\t\t\t\tmethod: 'PUT',\r\n\t\t\t\turl: `conversations/${conversation}/events/${id}`\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\tmarkRead: create.mutation({\r\n\t\t\tinvalidatesTags: [Tag.Conversation, Tag.UnreadStats],\r\n\t\t\tquery: ({ id, mark }) => ({\r\n\t\t\t\tmethod: 'PUT',\r\n\t\t\t\turl: `conversations/${id}/${mark ? 'read' : 'unread'}`\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\tmessages: create.query({\r\n\t\t\tprovidesTags: [Tag.Messages],\r\n\t\t\tquery: conversation => ({\r\n\t\t\t\turl: `conversations/${conversation}/events/recent`\r\n\t\t\t}),\r\n\t\t\ttransformResponse: saveMessages\r\n\t\t}),\r\n\r\n\t\tmessagesPrev: create.query<\r\n\t\t\tApi.EventsResponse,\r\n\t\t\t{ id: string; prevCursor: string }\r\n\t\t>({\r\n\t\t\tprovidesTags: [Tag.Messages],\r\n\t\t\tquery: ({ id, prevCursor }) => ({\r\n\t\t\t\tparams: {\r\n\t\t\t\t\tprevCursor\r\n\t\t\t\t},\r\n\t\t\t\turl: `conversations/${id}/events/next`\r\n\t\t\t}),\r\n\t\t\ttransformResponse: saveMessages\r\n\t\t}),\r\n\r\n\t\tparticipants: create.query({\r\n\t\t\tquery: conversation => ({\r\n\t\t\t\turl: `conversations/${conversation}/participants`\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\treaction: create.mutation({\r\n\t\t\tinvalidatesTags: [Tag.Messages],\r\n\t\t\tonQueryStarted: async (props, { dispatch, getState, queryFulfilled }) => {\r\n\t\t\t\tconst state = getState() as RootState\r\n\r\n\t\t\t\tconst cancel = updateReactions(props, { dispatch, state })\r\n\r\n\t\t\t\ttry {\r\n\t\t\t\t\tawait queryFulfilled\r\n\t\t\t\t} catch {\r\n\t\t\t\t\tcancel()\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\tquery: ({ conversation, emoji, mark, message }) => ({\r\n\t\t\t\tmethod: mark ? 'POST' : 'DELETE',\r\n\t\t\t\turl: `conversations/${conversation}/events/${message}/reactions/${emoji}`\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\tsendMessage: create.mutation({\r\n\t\t\tinvalidatesTags: [Tag.Messages],\r\n\t\t\tquery: ({ conversation, message }) => ({\r\n\t\t\t\tdata: { attachments: [], message },\r\n\t\t\t\tmethod: 'POST',\r\n\t\t\t\turl: `conversations/${conversation}/events`\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\tsetFocus: create.mutation({\r\n\t\t\tinvalidatesTags: [Tag.Conversation],\r\n\t\t\tquery: id => ({\r\n\t\t\t\tmethod: 'PUT',\r\n\t\t\t\turl: `conversations/${id}/focused`\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\tsetOther: create.mutation({\r\n\t\t\tinvalidatesTags: [Tag.Conversation],\r\n\t\t\tquery: id => ({\r\n\t\t\t\tmethod: 'PUT',\r\n\t\t\t\turl: `conversations/${id}/other`\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\tsettings: create.query<{ focusedInboxEnabled: boolean }, void>({\r\n\t\t\tquery: () => ({\r\n\t\t\t\turl: 'settings'\r\n\t\t\t})\r\n\t\t}),\r\n\t\tstar: create.mutation({\r\n\t\t\tquery: ({ id, mark }) => ({\r\n\t\t\t\tmethod: 'PUT',\r\n\t\t\t\turl: `conversations/${id}/${mark ? 'star' : 'unstar'}`\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\tsync: create.mutation({\r\n\t\t\tquery: id => ({\r\n\t\t\t\tmethod: 'POST',\r\n\t\t\t\turl: `conversations/${id}/sync`\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\tunread: create.query({\r\n\t\t\tprovidesTags: [Tag.UnreadStats],\r\n\t\t\tquery: () => ({\r\n\t\t\t\turl: 'messaging/unread-conversations-counters'\r\n\t\t\t})\r\n\t\t})\r\n\t}),\r\n\toverrideExisting: true\r\n})\r\n","import type { AppDispatch, RootState } from '../../../redux/store'\r\nimport type { ReactionBody } from '../model/types'\r\n\r\nimport { actions } from '../model/slice'\r\nimport { selectors } from './selectors'\r\n\r\nfunction updateReactions(\r\n\t{ emoji, mark, message }: Omit,\r\n\t{ dispatch, state }: { dispatch: AppDispatch; state: RootState }\r\n) {\r\n\tconst { reaction_summaries: olds } = selectors.messages.selectById(\r\n\t\tstate,\r\n\t\tmessage\r\n\t)\r\n\r\n\tconst found = olds.findIndex(reaction => reaction.emoji === emoji)\r\n\r\n\tconst patch = [...olds]\r\n\r\n\tconst shouldAddNewOne = mark && found === -1\r\n\r\n\tif (shouldAddNewOne) {\r\n\t\tpatch.push({\r\n\t\t\tcount: 1,\r\n\t\t\temoji,\r\n\t\t\tviewerReacted: true\r\n\t\t})\r\n\t} else {\r\n\t\tconst exist = found !== -1\r\n\t\tif (exist) {\r\n\t\t\tconst newOne = { ...olds[found] }\r\n\t\t\tconst shouldRemove = !mark && newOne.count < 2\r\n\r\n\t\t\tif (shouldRemove) {\r\n\t\t\t\tpatch.splice(found, 1)\r\n\t\t\t} else {\r\n\t\t\t\tnewOne.count += mark ? 1 : -1\r\n\t\t\t\tnewOne.viewerReacted = mark\r\n\r\n\t\t\t\tpatch[found] = newOne\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tdispatch(\r\n\t\tactions.updateMessage({\r\n\t\t\tchanges: { reaction_summaries: patch },\r\n\t\t\tid: message\r\n\t\t})\r\n\t)\r\n\r\n\treturn () =>\r\n\t\tdispatch(\r\n\t\t\tactions.updateMessage({\r\n\t\t\t\tchanges: { reaction_summaries: olds },\r\n\t\t\t\tid: message\r\n\t\t\t})\r\n\t\t)\r\n}\r\n\r\nexport { updateReactions }\r\n","import { useParams } from 'react-router-dom'\r\n\r\nexport const useCurrentId = () =>\r\n\tuseParams<{ conversation?: string }>()?.conversation ?? ''\r\n","import { useAppSelector } from 'shared/hooks'\r\n\r\nimport { api } from '../api'\r\nimport { selectors } from '../utils/selectors'\r\nimport { useCurrentId } from './useCurrentId'\r\n\r\nexport function useConversationalist() {\r\n\tconst id = useCurrentId()\r\n\tapi.useParticipantsQuery(id, {\r\n\t\tskip: !id\r\n\t})\r\n\r\n\treturn useAppSelector(state => selectors.conversationalist(state, id))\r\n}\r\n","import type { SubscriptionOptions } from '@reduxjs/toolkit/query'\r\n\r\nimport Archived from 'assets/image/icons/svg/icons/archived.svg'\r\nimport InMail from 'assets/image/icons/svg/icons/inmail.svg'\r\nimport MyConnections from 'assets/image/icons/svg/icons/myConnections.svg'\r\nimport Spam from 'assets/image/icons/svg/icons/spam.svg'\r\nimport Starred from 'assets/image/icons/svg/icons/starred.svg'\r\nimport Unread from 'assets/image/icons/svg/icons/unread.svg'\r\nimport { CONSTS } from 'config/objectConst'\r\n\r\nimport type { Filter } from '../model/types'\r\n\r\nconst isDev = import.meta.env.DEV\r\n\r\ninterface FilterItem {\r\n\ticon: string\r\n\tkey: Filter\r\n\ttitle: string\r\n}\r\n\r\nconst FILTERS: FilterItem[] = [\r\n\t{ icon: Unread, key: 'unread', title: 'Unread' },\r\n\t{ icon: Starred, key: 'starred', title: 'Starred' },\r\n\t{ icon: InMail, key: 'in-mail', title: 'InMail' },\r\n\t{ icon: MyConnections, key: 'my-connections', title: 'My connections' },\r\n\t{ icon: Archived, key: 'archive', title: 'Archived' },\r\n\t{ icon: Spam, key: 'spam', title: 'Spam' }\r\n]\r\n\r\nconst INTERVAL_OPTIONS = {\r\n\tpollingInterval: isDev\r\n\t\t? undefined\r\n\t\t: CONSTS.MESSAGING.REFRESH_INTERVAL_IN_SECONDS * 1000,\r\n\tskipPollingIfUnfocused: true\r\n}\r\n\r\ninterface Tab {\r\n\tlabel: string\r\n\tvalue: Filter\r\n}\r\n\r\nconst TABS: Tab[] = [\r\n\t{\r\n\t\tlabel: 'Focused',\r\n\t\tvalue: 'focused'\r\n\t},\r\n\t{\r\n\t\tlabel: 'Other',\r\n\t\tvalue: 'other'\r\n\t}\r\n]\r\n\r\nconst PULLING_OPTIONS: SubscriptionOptions = {\r\n\tpollingInterval: CONSTS.MESSAGING.REFRESH_INTERVAL_IN_SECONDS * 1_000,\r\n\trefetchOnReconnect: true,\r\n\tskipPollingIfUnfocused: true\r\n}\r\n\r\nexport { FILTERS, INTERVAL_OPTIONS, PULLING_OPTIONS, TABS }\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"hidden\":\"hidden-mbG5bi\"};","// extracted by css-extract-rspack-plugin\nexport default {\"menu\":\"menu-qnf96_\",\"action\":\"action-ST2LYA\",\"show\":\"show-d7AWXG\"};","// extracted by css-extract-rspack-plugin\nexport default {\"subtitle\":\"subtitle-IMPwFc\",\"caption\":\"caption-pteJCK\",\"buttonSm\":\"buttonSm-Ox4S8D\",\"buttonSmB\":\"buttonSmB-IQbAMs\",\"largeButton\":\"largeButton-UeAXUK\",\"mediumBody\":\"mediumBody-PX0apz\"};","// extracted by css-extract-rspack-plugin\nexport default {\"rect\":\"rect-H9zkIL\",\"primary\":\"primary-Uk1A2K\",\"secondary\":\"secondary-Ke1bHh\",\"bordered-dark\":\"bordered-dark-Yv7bh6\",\"borderedDark\":\"bordered-dark-Yv7bh6\",\"bordered\":\"bordered-uznCWK\"};","import type { ComponentProps, ElementType } from 'react'\r\n\r\nimport clsx from 'clsx'\r\nimport { typo } from 'shared/styles'\r\n\r\nimport css from './Button.module.scss'\r\n\r\ntype ButtonOwnProps = {\r\n\tas?: E\r\n\tshape?: 'rect'\r\n\ttypography?: string\r\n\tvariant?: 'bordered' | 'bordered-dark' | 'primary' | 'secondary'\r\n}\r\n\r\ntype ButtonProps = ButtonOwnProps &\r\n\tOmit, keyof ButtonOwnProps>\r\n\r\nexport function Button({\r\n\tas,\r\n\tclassName,\r\n\tshape = 'rect',\r\n\ttypography = typo.buttonSmB,\r\n\tvariant = 'primary',\r\n\t...props\r\n}: ButtonProps) {\r\n\tconst Tag = as ?? 'button'\r\n\r\n\treturn (\r\n\t\t\r\n\t)\r\n}\r\n","import Arrow from 'assets/image/icons/svg/icons/arrow-down-thin.svg'\r\nimport { memo } from 'react'\r\nimport {\r\n\tcomponents,\r\n\ttype DropdownIndicatorProps,\r\n\ttype GroupBase\r\n} from 'react-select'\r\n\r\nimport css from './CustomSelect.module.scss'\r\n\r\nconst DropdownIndicator_ = <\r\n\tOption_2,\r\n\tIsMulti_2 extends boolean,\r\n\tGroup_2 extends GroupBase\r\n>(\r\n\tprops: DropdownIndicatorProps\r\n) => (\r\n\t\r\n\t\tarrow\r\n\t\r\n)\r\n\r\nexport const DropdownIndicator = memo(DropdownIndicator_)\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"select\":\"select-TuL3HF\",\"control\":\"control-lgIdX4\",\"open\":\"open-CK2zjh\",\"disabled\":\"disabled-v_cUxc\",\"option\":\"option-kHfm5l\",\"selected\":\"selected-zvnGGi\",\"indicator\":\"indicator-IDbGig\",\"list\":\"list-vHvGvy\",\"menu\":\"menu-rJ2sd1\",\"single\":\"single-FDCWDv\",\"container\":\"container-EJBM3X\",\"arrow\":\"arrow-_UMa0_\"};","import clsx from 'clsx'\r\nimport Select, { type GroupBase, type Props } from 'react-select'\r\nimport { typo } from 'shared/styles'\r\n\r\nimport css from './CustomSelect.module.scss'\r\nimport { DropdownIndicator } from './DropdownIndicator'\r\n\r\nexport const CustomSelect = <\r\n\tOption,\r\n\tIsMulti extends boolean = false,\r\n\tGroup extends GroupBase
\r\n\t\t\r\n\t)\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"root\":\"root-GYvbPc\",\"currentAnchor\":\"currentAnchor-e6NPsn\",\"menu\":\"menu-eX2sXJ\",\"subTrigger\":\"subTrigger-kn9LfD\",\"subMenu\":\"subMenu-MSX5f6\",\"show\":\"show-HMgz3S\"};","import type { SyntheticEvent } from 'react'\r\n\r\nimport { Computed, Observer } from 'shared/observer'\r\n\r\nlet menu: HTMLDivElement | null = null\r\n\r\nconst lastTrigger = new Observer(null)\r\n\r\nconst openId = new Computed(lastTrigger, button => button?.dataset.id ?? '')\r\n\r\nlet timeoutId: number = Number.NaN\r\n\r\nfunction manualSet(element: typeof menu) {\r\n\tmenu = element\r\n}\r\n\r\nfunction open(event: SyntheticEvent) {\r\n\tconst trigger = event.currentTarget\r\n\r\n\tclearTimeout(timeoutId)\r\n\r\n\ttimeoutId = window.setTimeout(() => {\r\n\t\tlastTrigger.value?.focus()\r\n\t\tlastTrigger.value = trigger\r\n\r\n\t\tmenu?.showPopover()\r\n\t}, 400)\r\n}\r\n\r\nconst close = () => {\r\n\tlastTrigger.value = null\r\n\tmenu?.hidePopover()\r\n}\r\n\r\nconst isActive = () =>\r\n\tmenu?.contains(document.activeElement) || menu?.matches(':hover')\r\n\r\nconst onTriggerClose = (_event: SyntheticEvent) => {\r\n\tif (!isActive()) {\r\n\t\tclose()\r\n\t}\r\n}\r\n\r\nfunction closeOnBlur() {\r\n\tconst hoveredTrigger = lastTrigger.value?.matches(':hover')\r\n\r\n\tif (!hoveredTrigger) {\r\n\t\tclose()\r\n\t}\r\n}\r\n\r\nexport {\r\n\tclose,\r\n\tcloseOnBlur,\r\n\tlastTrigger,\r\n\tmanualSet,\r\n\tmenu,\r\n\tonTriggerClose,\r\n\topen,\r\n\topenId\r\n}\r\n","import clsx from 'clsx'\r\nimport { useConversationalist } from 'features/messaging/hooks'\r\nimport { type ButtonHTMLAttributes, useId, useSyncExternalStore } from 'react'\r\nimport { appDay } from 'shared/day'\r\nimport { useActionCreators, useAppSelector } from 'shared/hooks'\r\nimport { contextActions, typo } from 'shared/styles'\r\nimport { StackIcon } from 'shared/ui'\r\n\r\nimport type { Message } from '../../model/types'\r\n\r\nimport { actions } from '../../model/slice'\r\nimport { selectors } from '../../utils/selectors'\r\nimport { EmojiSelect } from '../Emoji/Select'\r\nimport css from './MessageActions.module.scss'\r\nimport { closeOnBlur, manualSet, onTriggerClose, openId } from './utils'\r\n\r\nconst isFresh = (day?: string) =>\r\n\tBoolean(day) && appDay().diff(day, 'hour') <= 1\r\n\r\nexport function MessageActions() {\r\n\tconst menuId = useId()\r\n\r\n\tconst contextId = useSyncExternalStore(openId.subscribe, () => openId.value)\r\n\tconst message = useAppSelector(state =>\r\n\t\tselectors.messages.selectById(state, contextId)\r\n\t)\r\n\r\n\tconst conversationalist = useConversationalist()\r\n\r\n\tconst isInterlocutorsMessage =\r\n\t\tmessage?.from?.entityId === conversationalist?.entityId\r\n\r\n\tconst showContextMenu =\r\n\t\t!isInterlocutorsMessage && isFresh(message?.created_at)\r\n\r\n\treturn (\r\n\t\t\r\n\t\t\t
\r\n\t\t\t\t{message && }\r\n\r\n\t\t\t\t{showContextMenu && }\r\n\t\t\t
\r\n\t\t\r\n\t)\r\n}\r\n\r\nfunction SubActions({ message_id: id = '', text = '' }: Message) {\r\n\tconst subActions = useId()\r\n\tconst { setEditMessage, setMessageToDelete } = useActionCreators(actions)\r\n\r\n\tconst actionProps = {\r\n\t\tclassName: contextActions.action,\r\n\t\tpopovertarget: subActions,\r\n\t\tpopovertargetaction: 'hide',\r\n\t\ttype: 'button'\r\n\t} as ButtonHTMLAttributes\r\n\r\n\treturn (\r\n\t\t<>\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\r\n\t\t\t\t\r\n\t\t\t\t\t\tsetEditMessage({\r\n\t\t\t\t\t\t\tid,\r\n\t\t\t\t\t\t\ttext\r\n\t\t\t\t\t\t})\r\n\t\t\t\t\t}\r\n\t\t\t\t\t{...actionProps}\r\n\t\t\t\t>\r\n\t\t\t\t\tEdit\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t)\r\n}\r\n","import type { ButtonHTMLAttributes } from 'react'\r\n\r\nimport CircularProgress from '@mui/material/CircularProgress'\r\n\r\nexport const ResponsiveButton = ({\r\n\tchildren,\r\n\tclassName,\r\n\tisLoading = false,\r\n\tonClick,\r\n\r\n\t...props\r\n}: ButtonHTMLAttributes & {\r\n\tisLoading?: boolean\r\n}) => (\r\n\t\r\n\t\t{isLoading ? (\r\n\t\t\t\r\n\t\t) : (\r\n\t\t\tchildren\r\n\t\t)}\r\n\t\r\n)\r\n","import data from '@emoji-mart/data'\r\nimport Picker from '@emoji-mart/react'\r\nimport { useId, useRef } from 'react'\r\nimport { StackIcon } from 'shared/ui'\r\n\r\nimport { Label } from '../../const'\r\nimport css from './style.module.scss'\r\n\r\nexport function FormEmojiPicker({\r\n\tonEmojiClick\r\n}: { onEmojiClick: (emoji: string) => void }) {\r\n\tconst ref = useRef(null)\r\n\tconst id = useId()\r\n\treturn (\r\n\t\t<>\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\r\n\t\t\t\r\n\t\t\t\t {\r\n\t\t\t\t\t\tonEmojiClick?.(emoji)\r\n\t\t\t\t\t\tref.current?.hidePopover()\r\n\t\t\t\t\t}}\r\n\t\t\t\t/>\r\n\t\t\t\r\n\t\t\r\n\t)\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"form\":\"form-DE2rUm\",\"expanded\":\"expanded-Sz_XIs\",\"editMode\":\"editMode-t9svFZ\",\"submits\":\"submits-y1zqg1\",\"button\":\"button-k4CIJf\",\"subActions\":\"subActions-toWdxl\",\"actions\":\"actions-UEJcaD\",\"expand\":\"expand-UKbKW3\",\"edit\":\"edit-dnni6z\",\"area\":\"area-kniClI\"};","import attach from 'assets/image/icons/svg/attach.svg'\r\nimport attachments from 'assets/image/icons/svg/icons/attchments.svg'\r\nimport clsx from 'clsx'\r\nimport { ResponsiveButton } from 'components/atoms/responsiveButton'\r\nimport {\r\n\ttype ChangeEventHandler,\r\n\ttype FormEventHandler,\r\n\tuseEffect,\r\n\tuseRef,\r\n\tuseState\r\n} from 'react'\r\nimport { useActionCreators, useAppSelector } from 'shared/hooks'\r\nimport { StackIcon } from 'shared/ui'\r\n\r\nimport { api } from '../../api'\r\nimport { useCurrentId } from '../../hooks'\r\nimport { actions } from '../../model/slice'\r\nimport { selectors } from '../../utils/selectors'\r\nimport { FormEmojiPicker } from '../Emoji/FormPicker'\r\nimport css from './MessageForm.module.scss'\r\nimport { useRead } from './useRead'\r\nimport { insertCharacterAtCursor } from './utils/addChar'\r\n\r\ninterface InnerForm extends HTMLFormElement {\r\n\ttext: HTMLTextAreaElement\r\n}\r\n\r\nexport function MessageForm({\r\n\tisExpand,\r\n\ttoggleExpand\r\n}: {\r\n\tisExpand: boolean\r\n\ttoggleExpand: () => void\r\n}) {\r\n\tconst conversation = useCurrentId()\r\n\r\n\tconst [disableSend, setDisableSend] = useState(true)\r\n\r\n\tconst [sendMessage, sendMessageProps] = api.useSendMessageMutation()\r\n\tconst [updateMessage, updateMessageProps] = api.useEditMessageMutation()\r\n\r\n\tconst { resetEditMessage } = useActionCreators(actions)\r\n\tconst messageToEdit = useAppSelector(selectors.editMessage)\r\n\r\n\tconst isNewMessage = messageToEdit === null\r\n\tconst isEditMode = !isNewMessage\r\n\r\n\tconst checkIfChanged: ChangeEventHandler = event => {\r\n\t\tconst area = event.currentTarget\r\n\r\n\t\tconst isInitialValue = isEditMode && area.value === messageToEdit.text\r\n\r\n\t\tsetDisableSend(isInitialValue || area.value.trim().length === 0)\r\n\t}\r\n\r\n\tconst ref = useRef(null)\r\n\r\n\tconst cancelEdit: FormEventHandler = () => {\r\n\t\tresetEditMessage()\r\n\t\tsetDisableSend(true)\r\n\t}\r\n\r\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: as planned\r\n\tuseEffect(() => ref.current?.reset(), [conversation])\r\n\r\n\tuseEffect(() => {\r\n\t\tif (messageToEdit?.text && ref.current) {\r\n\t\t\tconst area = ref.current.text\r\n\t\t\tarea.value = messageToEdit.text\r\n\t\t\tarea?.focus()\r\n\t\t}\r\n\t}, [messageToEdit?.text])\r\n\r\n\tconst markRead = useRead()\r\n\r\n\tconst handleSubmit: FormEventHandler = event => {\r\n\t\tevent.preventDefault()\r\n\r\n\t\tconst form = event.currentTarget,\r\n\t\t\tbody = {\r\n\t\t\t\tconversation,\r\n\t\t\t\tmessage: form.text.value\r\n\t\t\t}\r\n\r\n\t\tconst mutation = isEditMode\r\n\t\t\t? updateMessage({ ...body, id: messageToEdit.id })\r\n\t\t\t: sendMessage(body)\r\n\r\n\t\tmutation\r\n\t\t\t.unwrap()\r\n\t\t\t.catch(console.error)\r\n\t\t\t.then(() => form.reset())\r\n\t}\r\n\r\n\treturn (\r\n\t\t\r\n\t\t\t{isEditMode &&

Edit Message

}\r\n\r\n\t\t\t\r\n\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\r\n\t\t\t
\r\n\t\t\t\t
\r\n\t\t\t\t\t{isNewMessage && [\r\n\t\t\t\t\t\tattachments,\r\n\t\t\t\t\t\tattach\r\n\t\t\t\t\t]}\r\n\r\n\t\t\t\t\t {\r\n\t\t\t\t\t\t\tconst area = ref.current?.text\r\n\r\n\t\t\t\t\t\t\tif (area) {\r\n\t\t\t\t\t\t\t\tinsertCharacterAtCursor(area, emoji)\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}}\r\n\t\t\t\t\t/>\r\n\t\t\t\t
\r\n\t\t\t\t{isNewMessage ? (\r\n\t\t\t\t\t\r\n\t\t\t\t\t\tSend\r\n\t\t\t\t\t\r\n\t\t\t\t) : (\r\n\t\t\t\t\t
\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tCancel\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tSave\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t
\r\n\t\t\t\t)}\r\n\t\t\t
\r\n\t\t\r\n\t)\r\n}\r\n","import { useCurrentId } from 'features/messaging/hooks'\r\n\r\nimport store from '../../../../redux/store'\r\nimport { api } from '../../api'\r\nimport { selectors } from '../../utils/selectors'\r\n\r\nexport function useRead() {\r\n\tconst id = useCurrentId()\r\n\r\n\tconst [readMutation] = api.useMarkReadMutation()\r\n\r\n\treturn () => {\r\n\t\tconst state = store.getState()\r\n\r\n\t\tconst conversation = selectors.conversations.selectById(state, id)\r\n\r\n\t\tif (conversation.unread_count) {\r\n\t\t\treadMutation({ id, mark: true })\r\n\t\t}\r\n\t}\r\n}\r\n","export function insertCharacterAtCursor(\r\n\ttextarea: HTMLTextAreaElement,\r\n\tchar: string\r\n): void {\r\n\tconst start = textarea.selectionStart\r\n\tconst end = textarea.selectionEnd\r\n\r\n\ttextarea.value =\r\n\t\ttextarea.value.slice(0, start) + char + textarea.value.slice(end)\r\n\ttextarea.selectionStart = textarea.selectionEnd = start + char.length\r\n\r\n\ttextarea.focus()\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"root\":\"root-YsQFlq\",\"date\":\"date-Q1U3iC\",\"messages\":\"messages-mZMubz\",\"chat\":\"chat-xquAQz\",\"shrinkChat\":\"shrinkChat-lSSrhj\",\"section\":\"section-Jwuy9U\",\"prev\":\"prev-X0aqYR\"};","import CircularProgress from '@mui/material/CircularProgress'\r\nimport clsx from 'clsx'\r\n\r\nimport css from './FullLoader.module.scss'\r\n\r\nexport function FullLoader({\r\n\tclassName,\r\n\tsize = 60\r\n}: { className?: string; size?: number }) {\r\n\treturn (\r\n\t\t
\r\n\t\t\t\r\n\t\t
\r\n\t)\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"wrapper\":\"wrapper-UaCIaF\"};","import type { Message } from '../../model/types'\r\n\r\nimport { api } from '../../api'\r\nimport { useCurrentId } from '../../hooks'\r\nimport css from './style.module.scss'\r\n\r\nexport function Reactions({\r\n\tmessage_id: message,\r\n\treaction_summaries: reactions\r\n}: Message) {\r\n\tconst [react, options] = api.useReactionMutation()\r\n\tconst conversation = useCurrentId()\r\n\r\n\tfunction isNotReadyYet(emoji: string) {\r\n\t\tconst isSameMessage = options.originalArgs?.message === message\r\n\t\tconst isSameEmoji = options.originalArgs?.emoji === emoji\r\n\r\n\t\treturn options.isLoading && isSameMessage && isSameEmoji\r\n\t}\r\n\r\n\treturn (\r\n\t\treactions.length > 0 && (\r\n\t\t\t
\r\n\t\t\t\t{reactions.map(({ count, emoji, viewerReacted }) => (\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\treact({ conversation, emoji, mark: !viewerReacted, message })\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\ttype='button'\r\n\t\t\t\t\t>\r\n\t\t\t\t\t\t{emoji} {count}\r\n\t\t\t\t\t\r\n\t\t\t\t))}\r\n\t\t\t
\r\n\t\t)\r\n\t)\r\n}\r\n","import type { Placement } from '@floating-ui/dom'\r\n\r\nconst hasSupport = 'anchorName' in document.documentElement.style\r\n\r\nasync function updatePositioningWithLib(\r\n\ttrigger: HTMLElement,\r\n\tpopover: HTMLElement,\r\n\tplacement: Placement = 'bottom-end'\r\n) {\r\n\tconst { autoUpdate, computePosition, flip, offset } = await import(\r\n\t\t'@floating-ui/dom'\r\n\t)\r\n\r\n\treturn autoUpdate(trigger, popover, () =>\r\n\t\tcomputePosition(trigger, popover, {\r\n\t\t\tmiddleware: [offset(10), flip()],\r\n\t\t\tplacement\r\n\t\t}).then(({ x, y }) => {\r\n\t\t\tObject.assign(popover.style, {\r\n\t\t\t\tleft: `${x}px`,\r\n\t\t\t\ttop: `${y}px`\r\n\t\t\t})\r\n\t\t})\r\n\t)\r\n}\r\n\r\nexport { hasSupport, updatePositioningWithLib }\r\n","const ORDINALS = ['th', 'st', 'nd', 'rd']\r\nconst SIZES = ['B', 'KB', 'MB', 'GB', 'TB']\r\n\r\nconst escapeSpecialChars = (string: string) =>\r\n\tstring.replace(/[+\\-&|!(){}[\\]^\"~*?:\\\\]/gm, char => `\\\\${char}`)\r\n\r\n/*\r\n* Use intl if you will need to support other locales\r\nconst ordinal = new Intl.PluralRules('en-US', { type: 'ordinal' })\r\n\r\nconst suff: Partial> = {\r\n\tfew: 'rd',\r\n\tone: 'st',\r\n\ttwo: 'nd'\r\n}\r\n\tconst key = ordinal.select(asNumber)\r\n\treturn `${asNumber}${suff[key] ?? 'th'}`\r\n*/\r\n\r\nfunction ordinalNumber(numberLike: unknown) {\r\n\tconst asNumber = Number(numberLike)\r\n\r\n\tif (Number.isNaN(asNumber)) {\r\n\t\treturn numberLike\r\n\t}\r\n\r\n\tconst v = asNumber % 100\r\n\r\n\treturn asNumber + (ORDINALS[(v - 20) % 10] || ORDINALS[v] || ORDINALS[0])\r\n}\r\n\r\nconst formatFileSize = (bytes: number) => {\r\n\tlet size = bytes\r\n\r\n\tlet index = 0\r\n\tfor (; size >= 1024 && index < SIZES.length - 1; index++) {\r\n\t\tsize /= 1024\r\n\t}\r\n\r\n\tsize = Math.round(size)\r\n\treturn `${size} ${SIZES[index]}`\r\n}\r\n\r\nexport { escapeSpecialChars, formatFileSize, ordinalNumber }\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"root\":\"root-Ag1acx\",\"system\":\"system-RpeCK5\",\"textBlock\":\"textBlock-KUOotI\",\"avatar\":\"avatar-pAy4DK\",\"sender\":\"sender-fQxycV\",\"name\":\"name-RBslaI\",\"time\":\"time-G5y2MU\",\"menuTrigger\":\"menuTrigger-pPsCer\",\"reactions\":\"reactions-Enth14\",\"messageActive\":\"messageActive-ExTPtV\",\"message\":\"message-pXKr3X\",\"actions\":\"actions-hZwwjU\",\"wrapper\":\"wrapper-y7YvPW\",\"action\":\"action-wQ21b_\",\"file\":\"file-z5FNfH\",\"fileName\":\"fileName-oc16YK\",\"image\":\"image-KRI0u1\"};","import { formatFileSize } from 'shared/utils'\r\n\r\nimport type { Message, RenderContent } from '../../model/types'\r\n\r\nimport { api } from '../../api'\r\nimport { findRenderContent } from '../../utils/utils'\r\nimport css from './Message.module.scss'\r\n\r\nconst BLOB_TYPES: (keyof RenderContent)[] = ['file']\r\n\r\nconst findLinks = (text: string) => {\r\n\tconst regex = /((https?|ftp):\\/\\/[^\\s/$.?#].[^\\s]*)/gi\r\n\tconst elements = text\r\n\t\t.split(regex)\r\n\t\t.filter(element => element !== 'https' && element !== 'http')\r\n\treturn elements.map((element, index) => {\r\n\t\tif (regex.test(element)) {\r\n\t\t\treturn (\r\n\t\t\t\t\r\n\t\t\t\t\t{element}\r\n\t\t\t\t\r\n\t\t\t)\r\n\t\t}\r\n\t\treturn {element}\r\n\t})\r\n}\r\n\r\nexport function MessageBody(message: Message) {\r\n\tconst renderKey = findRenderContent(message.render_content)!\r\n\tconst content = message.render_content[0]?.[renderKey]\r\n\tconst attachQuery = api.useAttachmentQuery(\r\n\t\t{\r\n\t\t\taccepts: content?.recommended_accept_header ?? '',\r\n\t\t\tid: message.message_id,\r\n\t\t\turl: content?.url ?? ''\r\n\t\t},\r\n\t\t{\r\n\t\t\tskip: !content || !BLOB_TYPES.includes(renderKey)\r\n\t\t}\r\n\t)\r\n\r\n\tlet url = content?.url ?? ''\r\n\r\n\tif (attachQuery.isSuccess) {\r\n\t\turl = attachQuery.data\r\n\t}\r\n\r\n\tif (message.render_format === 'RECALLED') {\r\n\t\treturn (\r\n\t\t\t

This message has been deleted.

\r\n\t\t)\r\n\t}\r\n\tconst isEditedMessage = message.render_format === 'EDITED'\r\n\tconst renderedText = (\r\n\t\t

\r\n\t\t\t{findLinks(message.text)}{' '}\r\n\t\t\t{isEditedMessage && (Edited)}\r\n\t\t

\r\n\t)\r\n\r\n\tif (!renderKey) {\r\n\t\treturn renderedText\r\n\t}\r\n\r\n\tswitch (renderKey) {\r\n\t\tcase 'audio':\r\n\t\t\treturn (\r\n\t\t\t\t
\r\n\t\t\t\t\t{message.text && (\r\n\t\t\t\t\t\t
{renderedText}
\r\n\t\t\t\t\t)}\r\n\t\t\t\t\t
\r\n\t\t\t)\r\n\r\n\t\tcase 'external_media':\r\n\t\t\treturn (\r\n\t\t\t\t<>\r\n\t\t\t\t\t{message.text && (\r\n\t\t\t\t\t\t
{renderedText}
\r\n\t\t\t\t\t)}\r\n\t\t\t\t\tgif\r\n\t\t\t\t\r\n\t\t\t)\r\n\r\n\t\tcase 'file':\r\n\t\t\treturn (\r\n\t\t\t\t
\r\n\t\t\t\t\t{message.text && (\r\n\t\t\t\t\t\t
{renderedText}
\r\n\t\t\t\t\t)}\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t{content?.name}\r\n\t\t\t\t\t\t{formatFileSize(content?.byte_size ?? 0)}\r\n\t\t\t\t\t\r\n\t\t\t\t
\r\n\t\t\t)\r\n\r\n\t\tcase 'vector_image':\r\n\t\t\treturn (\r\n\t\t\t\t
\r\n\t\t\t\t\t{message.text && (\r\n\t\t\t\t\t\t
{renderedText}
\r\n\t\t\t\t\t)}\r\n\r\n\t\t\t\t\t\r\n\t\t\t\t
\r\n\t\t\t)\r\n\r\n\t\tcase 'video_meeting':\r\n\t\t\treturn (\r\n\t\t\t\t
\r\n\t\t\t\t\t

\r\n\t\t\t\t\t\tVideo meetings are not supported\r\n\t\t\t\t\t

\r\n\t\t\t\t
\r\n\t\t\t)\r\n\r\n\t\tdefault:\r\n\t\t\treturn

{message.text}

\r\n\t}\r\n}\r\n","import clsx from 'clsx'\r\nimport { memo } from 'react'\r\nimport { appDay } from 'shared/day'\r\nimport { useAppSelector } from 'shared/hooks'\r\n\r\nimport user from '../../../../assets/image/icons/svg/user.svg'\r\nimport { selectors } from '../../utils/selectors'\r\nimport { formatTime } from '../../utils/utils'\r\nimport { Reactions } from '../Emoji/Reactions'\r\nimport { messageActions } from '../MessageActions'\r\nimport { useOpened } from '../MessageActions/useOpened'\r\n// import anchor from '../MessageActions/MessageActions.module.scss'\r\nimport { MessageBody } from './Body'\r\nimport css from './Message.module.scss'\r\n\r\nfunction Message_({\r\n\tid,\r\n\tshowAvatar = false\r\n}: { id: string } & { showAvatar?: boolean }) {\r\n\tconst message = useAppSelector(state =>\r\n\t\tselectors.messages.selectById(state, id)\r\n\t)\r\n\r\n\tconst { isOpen, openClass, triggerRef } = useOpened(id)\r\n\r\n\tif (!message) {\r\n\t\treturn null\r\n\t}\r\n\r\n\tconst created = appDay(message.created_at)\r\n\r\n\tconst isSystemMessage = message.render_format === 'SYSTEM'\r\n\tconst isDeleted = message.render_format === 'RECALLED'\r\n\r\n\tconst showActions = isDeleted ? undefined : messageActions.open\r\n\r\n\tconst closeActions = isDeleted ? undefined : messageActions.onTriggerClose\r\n\r\n\t// const closeActions = (event: SyntheticEvent) => {\r\n\t// \tsetContextMessage(null)\r\n\t// \tmessageActions.onTriggerClose()\r\n\t// }\r\n\r\n\treturn (\r\n\t\t
\r\n\t\t\t{!isSystemMessage && showAvatar && (\r\n\t\t\t\t\r\n\t\t\t)}\r\n\t\t\t
\r\n\t\t\t\t{showAvatar && (\r\n\t\t\t\t\t

\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{message.from?.fullName}\r\n\t\t\t\t\t\t\r\n\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{formatTime(message.created_at)}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t

\r\n\t\t\t\t)}\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t
\r\n\t\t\t\t{!isDeleted && }\r\n\t\t\t\r\n\t\t
\r\n\t)\r\n}\r\n\r\nexport const Message = memo(Message_)\r\n","import { useEffect, useRef, useState } from 'react'\r\nimport {\r\n\thasSupport,\r\n\tupdatePositioningWithLib\r\n} from 'shared/polyfills/positioning'\r\n\r\nimport css from './MessageActions.module.scss'\r\nimport { menu, openId } from './utils'\r\nexport function useOpened(id = '') {\r\n\tconst triggerRef = useRef(null)\r\n\tconst [isOpen, setIsOpen] = useState(false)\r\n\r\n\tuseEffect(() => {\r\n\t\tconst controller = new AbortController()\r\n\r\n\t\tcontroller.signal.addEventListener('abort', () => setIsOpen(false), {\r\n\t\t\tonce: true\r\n\t\t})\r\n\r\n\t\topenId.subscribe(() => {\r\n\t\t\tconst isSame = id === openId.value\r\n\r\n\t\t\tif (hasSupport) {\r\n\t\t\t\tsetIsOpen(isSame)\r\n\t\t\t} else {\r\n\t\t\t\tif (!isSame && menu && triggerRef.current) {\r\n\t\t\t\t\tupdatePositioningWithLib(triggerRef.current, menu).then(\r\n\t\t\t\t\t\tunsubscribe => {\r\n\t\t\t\t\t\t\tcontroller.signal.addEventListener('abort', unsubscribe, {\r\n\t\t\t\t\t\t\t\tonce: true\r\n\t\t\t\t\t\t\t})\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t)\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}, controller.signal)\r\n\r\n\t\treturn () => {\r\n\t\t\tcontroller.abort()\r\n\t\t}\r\n\t}, [id])\r\n\r\n\treturn {\r\n\t\tisOpen,\r\n\t\topenClass: isOpen && css.currentAnchor,\r\n\t\ttriggerRef\r\n\t}\r\n}\r\n","import type { Dayjs } from 'dayjs'\r\n\r\nimport CircularProgress from '@mui/material/CircularProgress'\r\nimport clsx from 'clsx'\r\nimport { type MutableRefObject, useEffect, useRef } from 'react'\r\nimport { useAppSelector, useIntersectionObserver } from 'shared/hooks'\r\n\r\nimport { FullLoader } from '../../../../components/atoms/FullLoader/FullLoader.tsx'\r\nimport { api } from '../../api.ts'\r\nimport { useCurrentId } from '../../hooks/index.ts'\r\nimport { selectors } from '../../utils/selectors.ts'\r\nimport { formatChatDate } from '../../utils/utils.ts'\r\nimport { PULLING_OPTIONS } from '../const.ts'\r\nimport { useIsPulling } from '../FilterForm/TempDebug.tsx'\r\nimport { Message } from '../Message/Message.tsx'\r\nimport css from './Chat.module.scss'\r\n// import { restoreScroll } from './utils.ts'\r\n\r\nconst getId = (id: string, day?: Dayjs) => `${id}-${day?.unix()}`\r\n\r\nexport function Conversation({ className }: { className?: string }) {\r\n\tconst scrollableRef = useRef(null)\r\n\tconst conversation = useCurrentId()\r\n\r\n\tconst { days, map, prevCursor } = useAppSelector(root =>\r\n\t\tselectors.conversation(root, conversation)\r\n\t)\r\n\r\n\tconst [chatSpinner, entry] = useIntersectionObserver({\r\n\t\troot: scrollableRef.current\r\n\t})\r\n\r\n\tconst isPulling = useIsPulling()\r\n\r\n\tconst recentQuery = api.useMessagesQuery(\r\n\t\tconversation,\r\n\t\tisPulling\r\n\t\t\t? {\r\n\t\t\t\t\t...PULLING_OPTIONS,\r\n\t\t\t\t\tskip: !conversation\r\n\t\t\t\t}\r\n\t\t\t: {\r\n\t\t\t\t\tskip: !conversation\r\n\t\t\t\t}\r\n\t)\r\n\r\n\tapi.useMessagesPrevQuery(\r\n\t\t{ id: conversation, prevCursor },\r\n\t\t{\r\n\t\t\tskip: !(conversation && prevCursor && entry?.isIntersecting)\r\n\t\t}\r\n\t)\r\n\r\n\tconst scrollId = useRef('')\r\n\r\n\tconst showLoader =\r\n\t\trecentQuery.isLoading ||\r\n\t\t(recentQuery.isFetching && !recentQuery.currentData)\r\n\r\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: No need\r\n\tuseEffect(() => {\r\n\t\tif (prevCursor && entry?.isIntersecting && !scrollId.current) {\r\n\t\t\tscrollId.current = getId(conversation, days[0])\r\n\r\n\t\t\treturn () => {\r\n\t\t\t\tsetTimeout(() => {\r\n\t\t\t\t\tdocument.getElementById(scrollId.current)?.scrollIntoView({\r\n\t\t\t\t\t\tbehavior: 'instant',\r\n\t\t\t\t\t\tblock: 'start',\r\n\t\t\t\t\t\tinline: 'nearest'\r\n\t\t\t\t\t})\r\n\r\n\t\t\t\t\tscrollId.current = ''\r\n\t\t\t\t}, 0)\r\n\t\t\t}\r\n\t\t}\r\n\t}, [prevCursor, entry?.isIntersecting])\r\n\r\n\tuseScrollToEnd(scrollableRef, !showLoader)\r\n\r\n\treturn (\r\n\t\t\r\n\t\t\t{showLoader && }\r\n\t\t\t{prevCursor && (\r\n\t\t\t\t
\r\n\t\t\t\t\t\r\n\t\t\t\t
\r\n\t\t\t)}\r\n\r\n\t\t\t{days.map(day => {\r\n\t\t\t\tconst key = day.toISOString()\r\n\r\n\t\t\t\treturn (\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t
\r\n\t\t\t\t\t\t\t{map[key].map(message => (\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t))}\r\n\t\t\t\t\t\t
\r\n\t\t\t\t\t\r\n\t\t\t\t)\r\n\t\t\t})}\r\n\t\t\r\n\t)\r\n}\r\n\r\nfunction useScrollToEnd(\r\n\tscrollableRef: MutableRefObject,\r\n\tisReady = false\r\n) {\r\n\tconst firstRender = useRef(false)\r\n\tuseEffect(() => {\r\n\t\tif (isReady && !firstRender.current) {\r\n\t\t\tconst wrapper = scrollableRef.current\r\n\r\n\t\t\tif (wrapper) {\r\n\t\t\t\tconst children = wrapper.childNodes\r\n\t\t\t\tconst last = children[children.length - 1]\r\n\r\n\t\t\t\tif (last instanceof HTMLElement) {\r\n\t\t\t\t\tlast?.scrollIntoView({\r\n\t\t\t\t\t\tbehavior: 'auto',\r\n\t\t\t\t\t\tblock: 'end',\r\n\t\t\t\t\t\tinline: 'nearest'\r\n\t\t\t\t\t})\r\n\r\n\t\t\t\t\tfirstRender.current = true\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}, [isReady, scrollableRef])\r\n}\r\n","import { useSwitcher } from 'shared/hooks'\r\n\r\nimport { useCurrentId } from '../../hooks'\r\nimport { MessageActions } from '../MessageActions'\r\nimport { MessageForm } from '../MessageForm/MessageForm'\r\nimport css from './Chat.module.scss'\r\nimport { Conversation } from './Conversation'\r\n\r\nexport function Chat() {\r\n\tconst conversation = useCurrentId()\r\n\r\n\tconst expand = useSwitcher(false)\r\n\r\n\treturn conversation ? (\r\n\t\t<>\r\n\t\t\t\r\n\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t) : null\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"header\":\"header-Tj9mvA\",\"lead\":\"lead-wOsj1o\",\"link\":\"link-Q064aE\",\"person\":\"person-XBPbEI\",\"sync\":\"sync-TEgX80\"};","import CircularProgress from '@mui/material/CircularProgress'\r\nimport { CONSTS } from 'config/objectConst'\r\nimport { appSelectors } from 'redux/reducers/app'\r\nimport { useAppSelector } from 'shared/hooks'\r\nimport { Button } from 'shared/ui'\r\n\r\nimport { api } from '../../api'\r\nimport { useCurrentId } from '../../hooks'\r\nimport css from './ChatHeader.module.scss'\r\n\r\nfunction SyncButton() {\r\n\tconst [send, { isLoading }] = api.useSyncMutation()\r\n\r\n\tconst id = useCurrentId()\r\n\r\n\treturn (\r\n\t\t !isLoading && send(id)}\r\n\t\t\ttype='button'\r\n\t\t\tvariant='secondary'\r\n\t\t>\r\n\t\t\t{isLoading ? (\r\n\t\t\t\t\r\n\t\t\t) : (\r\n\t\t\t\t'Sync'\r\n\t\t\t)}\r\n\t\t\r\n\t)\r\n}\r\n\r\nfunction useSyncAllowed() {\r\n\tconst id = useAppSelector(\r\n\t\tstate => appSelectors.persona(state)?.personaId ?? ''\r\n\t)\r\n\r\n\treturn (\r\n\t\tCONSTS.BETA_FEATURES.SYNC_INTEGRATION_PERSONAS.includes('any') ||\r\n\t\tCONSTS.BETA_FEATURES.SYNC_INTEGRATION_PERSONAS.includes(id)\r\n\t)\r\n}\r\n\r\nexport { SyncButton, useSyncAllowed }\r\n","import { useConversationalist } from '../../hooks'\r\nimport css from './ChatHeader.module.scss'\r\nimport { SyncButton, useSyncAllowed } from './SyncButton'\r\n\r\nexport function ChatHeader() {\r\n\tconst conversationalist = useConversationalist()\r\n\tconst hasSync = useSyncAllowed()\r\n\treturn (\r\n\t\tconversationalist && (\r\n\t\t\t
\r\n\t\t\t\t\r\n\t\t\t\t\t

{conversationalist.fullName}

\r\n\t\t\t\t\r\n\t\t\t\t

{conversationalist.occupation}

\r\n\t\t\t\t{hasSync && }\r\n\t\t\t
\r\n\t\t)\r\n\t)\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"menu\":\"menu-fci1QB\",\"currentAnchor\":\"currentAnchor-Uv2hh6\",\"action\":\"action-amPW7z\"};","import type { MouseEvent } from 'react'\r\n\r\nimport { Computed, Observer } from 'shared/observer'\r\n\r\nlet isOpen = false\r\nlet menu: HTMLDivElement | null = null\r\n\r\nconst lastTrigger = new Observer(null)\r\n\r\nconst openId = new Computed(lastTrigger, button => button?.value ?? '')\r\n\r\nfunction manualSet(element: typeof menu) {\r\n\tmenu = element\r\n}\r\n\r\nfunction openActions(event: MouseEvent) {\r\n\tconst trigger = event.currentTarget\r\n\r\n\tconst isTheSame = lastTrigger.value === trigger\r\n\tlastTrigger.value = trigger\r\n\r\n\tif (menu) {\r\n\t\tif (isTheSame) {\r\n\t\t\tisOpen ? menu.hidePopover() : menu.showPopover()\r\n\t\t\tisOpen = !isOpen\r\n\t\t} else {\r\n\t\t\tisOpen = true\r\n\t\t\tmenu.showPopover()\r\n\t\t}\r\n\t}\r\n}\r\n\r\nconst close = () => {\r\n\tisOpen = false\r\n\tmenu?.hidePopover()\r\n}\r\n\r\nexport { close, manualSet, menu, openActions, openId }\r\n","import clsx from 'clsx'\r\nimport ModalWindow from 'components/molecules/ModalWindow'\r\nimport { CONSTS } from 'config/objectConst'\r\nimport { useId, useSyncExternalStore } from 'react'\r\nimport { useActionCreators, useAppSelector, useSwitcher } from 'shared/hooks'\r\nimport { contextActions, typo } from 'shared/styles'\r\n\r\nimport type { Conversation } from '../../model/types'\r\n\r\nimport { api } from '../../api'\r\nimport { actions } from '../../model/slice'\r\nimport { selectors } from '../../utils/selectors'\r\nimport css from './QuickActions.module.scss'\r\nimport { close, manualSet, openId } from './utils/open'\r\n\r\nconst actionCN = clsx(contextActions.action, css.action)\r\n\r\nexport function QuickActions() {\r\n\tconst id = useSyncExternalStore(openId.subscribe, () => openId.value)\r\n\tconst conversation = useAppSelector(state =>\r\n\t\tselectors.conversations.selectById(state, id)\r\n\t)\r\n\tconst menuId = useId()\r\n\r\n\treturn (\r\n\t\t\r\n\t\t\t{conversation && (\r\n\t\t\t\t<>\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t)}\r\n\t\t\r\n\t)\r\n}\r\n\r\nfunction Archive({ entity_id: id }: Conversation) {\r\n\tconst filter = useAppSelector(selectors.filter)\r\n\r\n\tconst inOnArchive = filter === 'archive'\r\n\tconst [mutation, { isLoading, originalArgs }] = api.useArchiveMutation()\r\n\r\n\treturn (\r\n\t\t {\r\n\t\t\t\tmutation({\r\n\t\t\t\t\tid,\r\n\t\t\t\t\tmark: !inOnArchive\r\n\t\t\t\t})\r\n\t\t\t\tclose()\r\n\t\t\t}}\r\n\t\t\ttype='button'\r\n\t\t>\r\n\t\t\t{inOnArchive ? 'Restore' : 'Archive'}\r\n\t\t\r\n\t)\r\n}\r\n\r\nfunction DeleteAction({ entity_id: conversation }: Conversation) {\r\n\tconst modal = useSwitcher(false)\r\n\tconst [mutation, { isLoading, originalArgs }] = api.useDeleteMutation()\r\n\r\n\treturn (\r\n\t\t<>\r\n\t\t\t {\r\n\t\t\t\t\tmodal.on()\r\n\t\t\t\t\tclose()\r\n\t\t\t\t}}\r\n\t\t\t\ttype='button'\r\n\t\t\t>\r\n\t\t\t\tDelete conversation\r\n\t\t\t\r\n\r\n\t\t\t {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tawait mutation(conversation).unwrap()\r\n\t\t\t\t\t\tmodal.off()\r\n\t\t\t\t\t} catch (e) {\r\n\t\t\t\t\t\tconsole.error(e)\r\n\t\t\t\t\t}\r\n\t\t\t\t}}\r\n\t\t\t\tconfirmText='Yes'\r\n\t\t\t\t{...CONSTS.confirmationDialogs['c1.15']}\r\n\t\t\t\topen={modal.isOn}\r\n\t\t\t/>\r\n\t\t\r\n\t)\r\n}\r\n\r\nfunction OtherOrFocused({ entity_id: conversation }: Conversation) {\r\n\tconst filter = useAppSelector(selectors.filter),\r\n\t\tshouldShow = useAppSelector(selectors.withTabs)\r\n\r\n\tconst [focusedMutation, focusedOptions] = api.useSetFocusMutation(),\r\n\t\t[otherMutation, otherOptions] = api.useSetOtherMutation()\r\n\r\n\tif (!shouldShow) {\r\n\t\treturn null\r\n\t}\r\n\r\n\tconst isOnFocused = filter === 'focused'\r\n\tconst isOnGoing = focusedOptions.isLoading || otherOptions.isLoading\r\n\r\n\tconst mutation = isOnFocused ? otherMutation : focusedMutation\r\n\tconst label = `Move to ${isOnFocused ? 'Other' : 'Focused'}`\r\n\r\n\treturn (\r\n\t\t {\r\n\t\t\t\tmutation(conversation)\r\n\t\t\t\tclose()\r\n\t\t\t}}\r\n\t\t\ttype='button'\r\n\t\t>\r\n\t\t\t{label}\r\n\t\t\r\n\t)\r\n}\r\n\r\nfunction Read({ entity_id: id, unread_count: unread }: Conversation) {\r\n\tconst { updateRead } = useActionCreators(actions)\r\n\r\n\tconst [readMutation, { isLoading, originalArgs }] = api.useMarkReadMutation()\r\n\r\n\tconst isUnread = Boolean(unread)\r\n\r\n\tconst label = `Mark as ${isUnread ? 'read' : 'unread'}`\r\n\r\n\treturn (\r\n\t\t {\r\n\t\t\t\tconst oldBody = {\r\n\t\t\t\t\tid,\r\n\t\t\t\t\tmark: !isUnread\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst newBody = {\r\n\t\t\t\t\tid,\r\n\t\t\t\t\tmark: isUnread\r\n\t\t\t\t}\r\n\r\n\t\t\t\tupdateRead(newBody)\r\n\t\t\t\tclose()\r\n\t\t\t\ttry {\r\n\t\t\t\t\tawait readMutation(newBody).unwrap()\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\tupdateRead(oldBody)\r\n\t\t\t\t}\r\n\t\t\t}}\r\n\t\t\ttype='button'\r\n\t\t>\r\n\t\t\t{label}\r\n\t\t\r\n\t)\r\n}\r\n\r\nfunction Star({ entity_id: id, is_starred: isStarred }: Conversation) {\r\n\tconst { updateStar } = useActionCreators(actions)\r\n\r\n\tconst [starMutation, { isLoading, originalArgs }] = api.useStarMutation()\r\n\r\n\treturn (\r\n\t\t {\r\n\t\t\t\tconst oldBody = {\r\n\t\t\t\t\tid,\r\n\t\t\t\t\tmark: isStarred\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst newBody = {\r\n\t\t\t\t\tid,\r\n\t\t\t\t\tmark: !isStarred\r\n\t\t\t\t}\r\n\r\n\t\t\t\tupdateStar(newBody)\r\n\t\t\t\tclose()\r\n\t\t\t\ttry {\r\n\t\t\t\t\tawait starMutation(newBody).unwrap()\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\tupdateStar(oldBody)\r\n\t\t\t\t}\r\n\t\t\t}}\r\n\t\t\ttype='button'\r\n\t\t>\r\n\t\t\t{isStarred ? 'Remove star' : 'Star'}\r\n\t\t\r\n\t)\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"time\":\"time-ImSz8L\",\"actionTrigger\":\"actionTrigger-erfiov\",\"root\":\"root-niXkKm\",\"title\":\"title-LvqjJe\",\"avatar\":\"avatar-TtAC8Q\",\"text\":\"text-PZ0yeo\",\"body\":\"body-MdPQ8i\",\"type\":\"type-URgWIy\",\"message\":\"message-cy6lyj\"};","import MoreHorizIcon from '@mui/icons-material/MoreHoriz'\r\nimport clsx from 'clsx'\r\nimport { memo, useMemo } from 'react'\r\nimport { Link } from 'react-router-dom'\r\nimport { useAppDispatch, useAppSelector } from 'shared/hooks'\r\n\r\nimport type { Message, Participant, RenderContent } from '../../model/types'\r\n\r\nimport attach from '../../../../assets/image/icons/svg/attach.svg'\r\nimport star from '../../../../assets/image/icons/svg/star.svg'\r\nimport user from '../../../../assets/image/icons/svg/user.svg'\r\nimport { appSelectors } from '../../../../redux/reducers/app'\r\nimport { api } from '../../api'\r\nimport { selectors } from '../../utils/selectors'\r\nimport {\r\n\tfindRenderContent,\r\n\tformatDateTime,\r\n\tgetConversationUrl\r\n} from '../../utils/utils'\r\nimport { openActions, useOpened } from '../QuickActions'\r\nimport css from './Thumbnail.module.scss'\r\n\r\nconst contentTypePreviewText: Partial> = {\r\n\taudio: 'a voice message',\r\n\texternal_media: 'a GIF',\r\n\tfile: 'an attachment',\r\n\tunsupported_content: 'a post',\r\n\tvector_image: 'an attachment',\r\n\tvideo_meeting: 'a video meeting'\r\n}\r\n\r\nfunction PreviewText({\r\n\tconversationalist,\r\n\tconversationType,\r\n\tisInterlocutor,\r\n\tmessage,\r\n\trenderContent\r\n}: {\r\n\tconversationalist?: Participant\r\n\tconversationType: null | string\r\n\r\n\tisInterlocutor: boolean\r\n\tmessage?: Message\r\n\trenderContent: keyof RenderContent | null\r\n}) {\r\n\tconst sender = isInterlocutor\r\n\t\t? `${conversationalist?.firstName} sent`\r\n\t\t: 'You sent'\r\n\r\n\tconst subject = message?.subject\r\n\r\n\tif (renderContent) {\r\n\t\tconst showAttachIcon =\r\n\t\t\t(!subject && renderContent === 'vector_image') || renderContent === 'file'\r\n\r\n\t\tlet text = subject || contentTypePreviewText[renderContent]\r\n\r\n\t\tif (!conversationType) {\r\n\t\t\ttext = `${sender} ${text}`\r\n\t\t}\r\n\r\n\t\tif (showAttachIcon) {\r\n\t\t\treturn (\r\n\t\t\t\t

\r\n\t\t\t\t\t{conversationType && (\r\n\t\t\t\t\t\t{conversationType}\r\n\t\t\t\t\t)}\r\n\t\t\t\t\tattach\r\n\t\t\t\t\t{text}\r\n\t\t\t\t

\r\n\t\t\t)\r\n\t\t}\r\n\r\n\t\treturn (\r\n\t\t\t<>\r\n\t\t\t\t{conversationType && (\r\n\t\t\t\t\t{conversationType}\r\n\t\t\t\t)}\r\n\t\t\t\t{` ${text}`}\r\n\t\t\t\r\n\t\t)\r\n\t}\r\n\r\n\treturn subject || message?.text || 'No message'\r\n}\r\n\r\nfunction Thumbnail_({\r\n\tid,\r\n\tisSelected = false\r\n}: { id: string; isSelected?: boolean }) {\r\n\tconst conversation = useAppSelector(state =>\r\n\t\tselectors.conversations.selectById(state, id)\r\n\t)\r\n\r\n\tconst {\r\n\t\tconversation_type: conversationType,\r\n\r\n\t\tevents,\r\n\t\theadline,\r\n\t\tis_starred: isStarred,\r\n\r\n\t\tparticipants,\r\n\r\n\t\tunread_count: unread\r\n\t} = conversation\r\n\r\n\tconst dispatch = useAppDispatch()\r\n\tconst [readMutation] = api.useMarkReadMutation()\r\n\r\n\tconst userEntityId = useAppSelector(appSelectors.personIdLi)\r\n\r\n\tconst message: Message | undefined = events[0]\r\n\r\n\tconst { openClass, triggerRef } = useOpened(id)\r\n\r\n\tconst isMessageDeleted = message?.render_format === 'RECALLED'\r\n\tconst isSystemMessage = message?.render_format === 'SYSTEM'\r\n\r\n\tconst conversationalist = useMemo(\r\n\t\t() =>\r\n\t\t\tparticipants.find(participant => participant.entityId !== userEntityId),\r\n\t\t[participants, userEntityId]\r\n\t)\r\n\r\n\tconst isInterlocutor = conversationalist?.entityId === message?.from?.entityId\r\n\tconst renderContent = findRenderContent(message?.render_content)\r\n\r\n\tconst handleMailboxItemClick = () => {\r\n\t\tdispatch(api.util.upsertQueryData('participants', id, participants))\r\n\t\tif (unread) {\r\n\t\t\treadMutation({ id, mark: true })\r\n\t\t}\r\n\t}\r\n\tconst showUnread = Boolean(unread)\r\n\r\n\treturn (\r\n\t\t
  • \r\n\t\t\t\r\n\r\n\t\t\t\r\n\t\t\t\t{conversationalist?.fullName}\r\n\t\t\t\r\n\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\r\n\t\t\t{headline &&

    {headline}

    }\r\n\t\t\t
    \r\n\t\t\t\t{isMessageDeleted ? (\r\n\t\t\t\t\t

    This message has been deleted.

    \r\n\t\t\t\t) : (\r\n\t\t\t\t\t
    \r\n\t\t\t\t\t\t{!renderContent && !isSystemMessage && (\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t{conversationType\r\n\t\t\t\t\t\t\t\t\t? `${conversationType} `\r\n\t\t\t\t\t\t\t\t\t: isInterlocutor\r\n\t\t\t\t\t\t\t\t\t\t? `${conversationalist?.firstName}: `\r\n\t\t\t\t\t\t\t\t\t\t: 'You: '}\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t)}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t
    \r\n\t\t\t\t)}\r\n\t\t\t\t{isStarred && star}\r\n\t\t\t\t{showUnread &&
    {unread}
    }\r\n\t\t\t
    \r\n\t\t
  • \r\n\t)\r\n}\r\n\r\nexport const Thumbnail = memo(Thumbnail_)\r\n","import { useEffect, useRef, useState } from 'react'\r\nimport {\r\n\thasSupport,\r\n\tupdatePositioningWithLib\r\n} from 'shared/polyfills/positioning'\r\n\r\nimport css from './QuickActions.module.scss'\r\nimport { menu, openId } from './utils/open'\r\nexport function useOpened(id = '') {\r\n\tconst triggerRef = useRef(null)\r\n\tconst [isOpen, setIsOpen] = useState(false)\r\n\r\n\tuseEffect(() => {\r\n\t\tlet unmount: (() => void) | null = null\r\n\r\n\t\tconst unobserve = openId.subscribe(() => {\r\n\t\t\tconst isSame = id === openId.value\r\n\t\t\tif (hasSupport) {\r\n\t\t\t\tsetIsOpen(isSame)\r\n\r\n\t\t\t\tunmount = () => setIsOpen(false)\r\n\t\t\t} else {\r\n\t\t\t\tif (!isSame && menu && triggerRef.current) {\r\n\t\t\t\t\tunmount?.()\r\n\r\n\t\t\t\t\tupdatePositioningWithLib(triggerRef.current, menu).then(\r\n\t\t\t\t\t\tunsubscribe => {\r\n\t\t\t\t\t\t\tunmount = unsubscribe\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t)\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t})\r\n\r\n\t\treturn () => {\r\n\t\t\tunmount?.()\r\n\t\t\tunobserve()\r\n\t\t}\r\n\t}, [id])\r\n\r\n\treturn {\r\n\t\tisOpen,\r\n\t\topenClass: isOpen && css.currentAnchor,\r\n\t\ttriggerRef\r\n\t}\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"chats\":\"chats-z98Rd7\",\"loader\":\"loader-QglU8u\",\"nextLoader\":\"nextLoader-Q4HUsj\",\"empty\":\"empty-IRqxgq\"};","import CircularProgress from '@mui/material/CircularProgress'\r\nimport clsx from 'clsx'\r\nimport { useRef } from 'react'\r\nimport { useAppSelector, useIntersectionObserver } from 'shared/hooks'\r\nimport typo from 'shared/styles/typography.module.scss'\r\n\r\nimport type { GetProps } from '../../model/types'\r\n\r\nimport emptySnail from '../../../../assets/image/snail-no.png'\r\nimport { FullLoader } from '../../../../components/atoms/FullLoader/FullLoader'\r\nimport { api } from '../../api'\r\nimport { useCurrentId } from '../../hooks'\r\nimport { useSelectFirstChat } from '../../hooks'\r\nimport { selectors } from '../../utils/selectors'\r\nimport { PULLING_OPTIONS } from '../const'\r\nimport { useIsPulling } from '../FilterForm/TempDebug'\r\nimport { Thumbnail } from '../Thumbnail/Thumbnail'\r\nimport css from './Conversations.module.scss'\r\n\r\nconst EMPTY = (\r\n\t
    \r\n\t\tSnail show stop sign\r\n\t\t
    No results found
    \r\n\t
    \r\n)\r\n\r\nexport function Conversations() {\r\n\tconst filter = useAppSelector(selectors.filter),\r\n\t\tsearch = useAppSelector(selectors.search),\r\n\t\t{ conversations, nextCursor } = useAppSelector(\r\n\t\t\tselectors.showedConversations\r\n\t\t)\r\n\r\n\tconst props: GetProps = { filter, search }\r\n\r\n\tconst mailboxRef = useRef(null),\r\n\t\tprevProps = useRef(props)\r\n\r\n\tconst [chatSpinner, entry] = useIntersectionObserver({\r\n\t\troot: mailboxRef.current\r\n\t})\r\n\tconst current = useCurrentId()\r\n\r\n\tconst isPulling = useIsPulling()\r\n\r\n\tconst settingQuery = api.useSettingsQuery()\r\n\tconst { isFetching, isLoading, isSuccess } = api.useConversationsQuery(\r\n\t\tprops,\r\n\t\tisPulling\r\n\t\t\t? {\r\n\t\t\t\t\t...PULLING_OPTIONS,\r\n\t\t\t\t\tskip: !settingQuery.isSuccess\r\n\t\t\t\t}\r\n\t\t\t: {\r\n\t\t\t\t\tskip: !settingQuery.isSuccess\r\n\t\t\t\t}\r\n\t)\r\n\r\n\tconst shouldFetchNext =\r\n\t\tsettingQuery.isSuccess && nextCursor && entry?.isIntersecting\r\n\r\n\tapi.useConversationsNextQuery(\r\n\t\t{ ...props, nextCursor },\r\n\t\t{\r\n\t\t\tskip: !shouldFetchNext\r\n\t\t}\r\n\t)\r\n\r\n\tconst isChangedProps = !(\r\n\t\tprevProps.current.filter === filter && prevProps.current.search === search\r\n\t)\r\n\r\n\tuseSelectFirstChat(conversations)\r\n\r\n\tconst shouldShowLoader =\r\n\t\t\tisLoading ||\r\n\t\t\tBoolean(isChangedProps && isFetching) ||\r\n\t\t\tsettingQuery.isLoading,\r\n\t\tisReady = isSuccess && !shouldShowLoader\r\n\r\n\tif (!shouldShowLoader) {\r\n\t\tprevProps.current = props\r\n\t}\r\n\r\n\tif (shouldShowLoader) {\r\n\t\treturn \r\n\t}\r\n\r\n\tif (isReady && conversations.length === 0) {\r\n\t\treturn EMPTY\r\n\t}\r\n\r\n\treturn (\r\n\t\t
      \r\n\t\t\t{conversations.map(conversation => (\r\n\t\t\t\t\r\n\t\t\t))}\r\n\r\n\t\t\t{nextCursor && (\r\n\t\t\t\t
    • \r\n\t\t\t\t\t\r\n\t\t\t\t
    • \r\n\t\t\t)}\r\n\t\t
    \r\n\t)\r\n}\r\n","import { useEffect } from 'react'\r\nimport { useHistory } from 'react-router-dom'\r\nimport { useAppDispatch } from 'shared/hooks'\r\n\r\nimport type { Conversation } from '../model/types'\r\n\r\nimport { api } from '../api'\r\nimport { getConversationUrl } from '../utils/utils'\r\nimport { useCurrentId } from './useCurrentId'\r\n\r\nexport function useSelectFirstChat(conversations?: Conversation[]) {\r\n\tconst conversation = useCurrentId()\r\n\tconst dispatch = useAppDispatch()\r\n\tconst { push } = useHistory()\r\n\r\n\tuseEffect(() => {\r\n\t\tif (!conversation) {\r\n\t\t\tif (conversations?.length) {\r\n\t\t\t\tconst { entity_id: id, participants } = conversations[0]\r\n\t\t\t\tdispatch(api.util.upsertQueryData('participants', id, participants))\r\n\t\t\t\tpush(getConversationUrl(id))\r\n\t\t\t}\r\n\t\t}\r\n\t}, [push, conversation, conversations, dispatch])\r\n}\r\n","import TuneIcon from '@mui/icons-material/Tune'\r\nimport clsx from 'clsx'\r\nimport throttle from 'lodash/throttle.js'\r\nimport { type ChangeEventHandler, useId, useMemo, useRef } from 'react'\r\nimport { useActionCreators, useAppSelector } from 'shared/hooks'\r\nimport { contextActions } from 'shared/styles'\r\nimport * as Segmented from 'shared/ui/Segmented'\r\n\r\nimport type { Filter } from '../../model/types'\r\n\r\nimport Close from '../../../../assets/image/icons/buttons/close.svg'\r\nimport close from '../../../../assets/image/icons/svg/icons/Close-black.svg'\r\nimport { actions } from '../../model/slice.ts'\r\nimport { selectors } from '../../utils/selectors.ts'\r\nimport { FILTERS, TABS } from '../const.ts'\r\nimport css from './FilterForm.module.scss'\r\nimport { TempDebugButton } from './TempDebug.tsx'\r\n\r\nexport function FilterForm() {\r\n\tconst id = useId()\r\n\r\n\tconst filter = useAppSelector(selectors.filter),\r\n\t\tisSearchMode = useAppSelector(selectors.searchMode),\r\n\t\tshowTabs = useAppSelector(selectors.withTabs)\r\n\tconst { resetFilter, resetSearch, setFilter, setSearch } =\r\n\t\tuseActionCreators(actions)\r\n\r\n\tconst onInputChange: ChangeEventHandler = useMemo(\r\n\t\t() => throttle(event => setSearch(event.target.value), 800),\r\n\t\t[setSearch]\r\n\t)\r\n\r\n\tconst ref = useRef(null)\r\n\r\n\tconst shouldShowFilterButton =\r\n\t\t!isSearchMode &&\r\n\t\t(filter === 'unread' ||\r\n\t\t\tfilter === 'in-mail' ||\r\n\t\t\tfilter === 'archive' ||\r\n\t\t\tfilter === 'my-connections' ||\r\n\t\t\tfilter === 'starred' ||\r\n\t\t\tfilter === 'spam')\r\n\r\n\treturn (\r\n\t\t {\r\n\t\t\t\tconst form = event.currentTarget\r\n\t\t\t\tconst input = event.target\r\n\r\n\t\t\t\tif (input instanceof HTMLInputElement) {\r\n\t\t\t\t\tif (input.name === 'filter') {\r\n\t\t\t\t\t\tform.reset()\r\n\t\t\t\t\t\tsetFilter(input.value as Filter)\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\t// if (input.name === 'search') {\r\n\r\n\t\t\t\t// }\r\n\t\t\t}}\r\n\t\t\tonReset={resetSearch as () => void}\r\n\t\t>\r\n\t\t\t
    \r\n\t\t\t\t\r\n\t\t\t\t\r\n\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t
    \r\n\r\n\t\t\t{shouldShowFilterButton && (\r\n\t\t\t\t void}\r\n\t\t\t\t\ttype='reset'\r\n\t\t\t\t>\r\n\t\t\t\t\tclose\r\n\t\t\t\t\t{filter}\r\n\t\t\t\t\r\n\t\t\t)}\r\n\r\n\t\t\t\r\n\t\t\t\t{FILTERS.map(({ icon, key, title }, index) => (\r\n\t\t\t\t\t {\r\n\t\t\t\t\t\t\tsetFilter(key)\r\n\t\t\t\t\t\t\tref.current?.reset()\r\n\t\t\t\t\t\t}}\r\n\t\t\t\t\t\ttype='button'\r\n\t\t\t\t\t>\r\n\t\t\t\t\t\tfilterIcon\r\n\t\t\t\t\t\t{title}\r\n\t\t\t\t\t\r\n\t\t\t\t))}\r\n\t\t\t\r\n\r\n\t\t\t{showTabs && (\r\n\t\t\t\t\r\n\t\t\t\t\t{TABS.map(({ label, value }) => (\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{label}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t))}\r\n\t\t\t\t\r\n\t\t\t)}\r\n\t\t\r\n\t)\r\n}\r\n","import { apiRTK, Tag } from 'api/api-rtk'\r\n\r\nimport type * as API from './types'\r\n\r\nexport const api = apiRTK.injectEndpoints({\r\n\tendpoints: create => ({\r\n\t\tcomplete: create.mutation({\r\n\t\t\tinvalidatesTags: [Tag.Executions],\r\n\t\t\tquery: id => ({\r\n\t\t\t\tmethod: 'PUT',\r\n\t\t\t\turl: `executions/${id}/complete`\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\tpage: create.query>({\r\n\t\t\tprovidesTags: [Tag.Executions],\r\n\t\t\tquery: params => ({\r\n\t\t\t\tmethod: 'GET',\r\n\t\t\t\tparams,\r\n\t\t\t\turl: 'executions/page'\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\tresume: create.mutation({\r\n\t\t\tinvalidatesTags: [Tag.Executions],\r\n\t\t\tquery: id => ({\r\n\t\t\t\tmethod: 'PUT',\r\n\t\t\t\turl: `executions/${id}/resume`\r\n\t\t\t})\r\n\t\t})\r\n\t})\r\n})\r\n","import CircularProgress from '@mui/material/CircularProgress'\r\nimport ModalWindow from 'components/molecules/ModalWindow'\r\nimport { CONSTS } from 'config/objectConst'\r\nimport { notificationUtils } from 'features/notifications'\r\nimport { useMemo } from 'react'\r\nimport { useSwitcher } from 'shared/hooks'\r\nimport { Button } from 'shared/ui'\r\n\r\nimport type * as API from '../../types'\r\n\r\nimport { api } from '../../api'\r\nimport css from './ConversationTogglers.module.scss'\r\n\r\nconst getEnabled = (key: keyof API.Actions, executions?: API.Execution[]) =>\r\n\texecutions?.find(execution => execution.actions[key].enabled)\r\n\r\nexport function ConversationTogglers({\r\n\tid\r\n}: { className?: string; id: string }) {\r\n\tconst { data } = api.usePageQuery({\r\n\t\t$filter: `linkedin_contact/linkedin_entity_id eq '${id}'`,\r\n\t\t$orderby: 'created desc',\r\n\t\t$take: 1\r\n\t})\r\n\r\n\tconst [resume, resumeOptions] = api.useResumeMutation()\r\n\tconst [complete, completeOptions] = api.useCompleteMutation()\r\n\r\n\tconst resumeSwitcher = useSwitcher()\r\n\tconst cancelSwitcher = useSwitcher()\r\n\r\n\tconst executionToResume = useMemo(\r\n\t\t() => getEnabled('resume', data?.documents),\r\n\t\t[data]\r\n\t)\r\n\r\n\tconst executionToCancel = useMemo(\r\n\t\t() => getEnabled('complete', data?.documents),\r\n\t\t[data]\r\n\t)\r\n\r\n\tconst isDisabledResume = executionToResume === undefined\r\n\tconst isDisabledCancel = executionToCancel === undefined\r\n\r\n\treturn (\r\n\t\t\r\n\t\t\t
  • \r\n\t\t\t\t\r\n\t\t\t\t\t{resumeOptions.isLoading ? (\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t) : (\r\n\t\t\t\t\t\t'Resume conversation'\r\n\t\t\t\t\t)}\r\n\t\t\t\t\r\n\r\n\t\t\t\t{!isDisabledResume && (\r\n\t\t\t\t\t {\r\n\t\t\t\t\t\t\tif (!resumeOptions.isLoading && executionToResume) {\r\n\t\t\t\t\t\t\t\tresume(executionToResume.id)\r\n\t\t\t\t\t\t\t\t\t.unwrap()\r\n\t\t\t\t\t\t\t\t\t.then(() => notificationUtils.snackById('n3.33'))\r\n\t\t\t\t\t\t\t\t\t.catch(console.error)\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}}\r\n\t\t\t\t\t\tconfirmText='Yes'\r\n\t\t\t\t\t\tloading={resumeOptions.isLoading}\r\n\t\t\t\t\t\t{...CONSTS.confirmationDialogs['c1.16']}\r\n\t\t\t\t\t\topen={resumeSwitcher.isOn}\r\n\t\t\t\t\t/>\r\n\t\t\t\t)}\r\n\t\t\t
  • \r\n\r\n\t\t\t
  • \r\n\t\t\t\t\r\n\t\t\t\t\t{completeOptions.isLoading ? (\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t) : (\r\n\t\t\t\t\t\t'Cancel conversation'\r\n\t\t\t\t\t)}\r\n\t\t\t\t\r\n\r\n\t\t\t\t{!isDisabledCancel && (\r\n\t\t\t\t\t {\r\n\t\t\t\t\t\t\tif (!completeOptions.isLoading && executionToCancel) {\r\n\t\t\t\t\t\t\t\tcomplete(executionToCancel.id)\r\n\t\t\t\t\t\t\t\t\t.unwrap()\r\n\t\t\t\t\t\t\t\t\t.then(() => notificationUtils.snackById('n3.34'))\r\n\t\t\t\t\t\t\t\t\t.catch(console.error)\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}}\r\n\t\t\t\t\t\tconfirmText='Yes'\r\n\t\t\t\t\t\tloading={completeOptions.isLoading}\r\n\t\t\t\t\t\t{...CONSTS.confirmationDialogs['1.1']}\r\n\t\t\t\t\t\topen={cancelSwitcher.isOn}\r\n\t\t\t\t\t/>\r\n\t\t\t\t)}\r\n\t\t\t
  • \r\n\t\t
    \r\n\t)\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"root\":\"root-iy1J0z\"};","import { Tag } from 'api/api-rtk'\r\n\r\nimport { api } from './api'\r\n\r\nexport const refetch = () => api.util.invalidateTags([Tag.Executions])\r\n","import { ExecutionsUI } from 'features/executions'\r\n\r\nimport { useConversationalist } from '../hooks'\r\n\r\nexport function ResumeButton() {\r\n\tconst conversationalist = useConversationalist()\r\n\r\n\tif (conversationalist) {\r\n\t\treturn \r\n\t}\r\n}\r\n","import '../styles.scss'\r\nimport { Chat } from '../Chat/Chat'\r\nimport { ChatHeader } from '../ChatHeader/ChatHeader'\r\nimport { Conversations } from '../Conversations/Conversations'\r\nimport { FilterForm } from '../FilterForm/FilterForm'\r\nimport { QuickActions } from '../QuickActions'\r\nimport { ResumeButton } from '../ResumeButton'\r\nimport css from './Mailbox.module.scss'\r\n\r\nexport function Mailbox() {\r\n\treturn (\r\n\t\t
    \r\n\t\t\t
    \r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t
    \r\n\t\t\t\r\n\t\t\t
    \r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t
    \r\n\r\n\t\t\t
    \r\n\t\t\t\t\r\n\t\t\t
    \r\n\t\t
    \r\n\t)\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"wrapper\":\"wrapper-K3Nv3y\",\"side\":\"side-exx7jG\",\"future\":\"future-F96sWg\",\"main\":\"main-ypR0Pa\"};","// extracted by css-extract-rspack-plugin\nexport default {\"count\":\"count-dx0suI\"};","import type { UnreadStats } from '../../model/types'\r\n\r\nimport css from './UnreadCount.module.scss'\r\nexport function UnreadCount({\r\n\tinbox = 0\r\n}: Pick, 'inbox'>) {\r\n\treturn inbox > 0 && {inbox}\r\n}\r\n","/*\n *\n * activity reducer\n *\n */\nconst initialState = {\n activity: [],\n total: -1,\n};\n\nconst activity = (state = initialState, action) => {\n switch (action.type) {\n case \"ALL_ACTIVITIES\":\n return Object.assign({}, state, {\n activity: action.payload.activity,\n total: action.payload.total,\n });\n default:\n return state;\n }\n};\n\nexport default activity;\n","/*\n *\n * campaign reducer\n *\n */\nconst initialState = {\n id: null,\n campaignLoaderController: false,\n createCampaignController: false,\n updateCampaignController: false,\n count: 0,\n list: [],\n statistics: {\n awaiting: 0,\n progress: 0,\n succeed: 0,\n failed: 0,\n skipped: 0,\n cancelled: 0,\n },\n actions: [],\n singleLoaderPage: true,\n};\n\nconst campaign = (state = initialState, action) => {\n switch (action.type) {\n case \"CAMPAIGN\":\n return Object.assign({}, state, {\n ...action.payload,\n });\n\n case \"CLEAR_CAMPAIGN\": {\n return { ...state, id: null, statistics: {}, actions: [] };\n }\n\n case \"CAMPAIGN_LOADER_CONTROLLER\":\n return Object.assign({}, state, {\n campaignLoaderController: action.payload.campaignLoaderController,\n });\n\n case \"CAMPAIGN_CONNECT_COUNT\":\n return Object.assign({}, state, {\n count: action.payload.count,\n });\n\n case \"CAMPAIGN_CONNECT_LIST\":\n return Object.assign({}, state, {\n list: action.payload.list,\n });\n\n case \"CREATE_CAMPAIGN_CONTROLLER\":\n return Object.assign({}, state, {\n createCampaignController: action.payload.createCampaignController,\n });\n\n case \"UPDATE_CAMPAIGN_CONTROLLER\":\n return Object.assign({}, state, {\n updateCampaignController: action.payload.updateCampaignController,\n });\n\n case \"CAMPAIGN_SINGLE_LOADER_CONTROLLER\":\n return Object.assign({}, state, {\n singleLoaderPage: action.payload.singleLoaderPage,\n });\n\n default:\n return state;\n }\n};\n\nexport default campaign;\n","import { createSlice } from '@reduxjs/toolkit'\r\nimport { createSetter } from 'shared/redux-helpers'\r\n\r\nconst initialState = {\r\n\tfinishStep: '',\r\n\tname: '',\r\n\tzoomMessageWindow: ''\r\n}\r\n\r\ntype Slice = typeof initialState\r\n\r\nconst campaignCreateSlice = createSlice({\r\n\tinitialState,\r\n\tname: 'campaignCreate',\r\n\treducers: {\r\n\t\t// setName: createSetter(\"name\"), ! unused old CAMPAIGN_CREATE\r\n\t\tsetFinishStep: createSetter('finishStep'),\r\n\t\tsetZoom: createSetter('zoomMessageWindow')\r\n\t}\r\n})\r\n\r\nconst campaignCreateActions = campaignCreateSlice.actions\r\n\r\nexport { campaignCreateActions, campaignCreateSlice }\r\n","import { createSlice, type PayloadAction } from '@reduxjs/toolkit'\r\nimport { createSetter } from 'shared/redux-helpers'\r\n\r\nconst initialState = {\r\n\tcampaigns: [] as { id: string }[],\r\n\tcampaignsCount: null,\r\n\tfilters: {\r\n\t\tactive: false,\r\n\t\tcancelled: false,\r\n\t\tcompleted: false,\r\n\t\tdrafted: false,\r\n\t\tstopped: false\r\n\t},\r\n\thaveCampaigns: false,\r\n\tloadCampaignsController: false,\r\n\tscrollToAction: false,\r\n\tsearchArchiveValue: '',\r\n\tsearchValue: ''\r\n}\r\n\r\ntype Slice = typeof initialState\r\n\r\nconst isFilterActive = (state: Slice) =>\r\n\tObject.values(state.filters).some(filter => filter === true)\r\n\r\nconst campaignsSlice = createSlice({\r\n\tinitialState,\r\n\tname: 'campaigns',\r\n\treducers: {\r\n\t\tsetArchive: createSetter('searchArchiveValue'),\r\n\t\tsetCampaigns(\r\n\t\t\tstate,\r\n\t\t\t{ payload }: PayloadAction>\r\n\t\t) {\r\n\t\t\tstate.campaigns = payload.campaigns\r\n\t\t\tstate.campaignsCount = payload.campaignsCount\r\n\t\t},\r\n\t\tsetFilters: createSetter('filters'),\r\n\t\tsetHaveCampaigns: createSetter('haveCampaigns'),\r\n\t\tsetLoadCampaigns: createSetter('loadCampaignsController'),\r\n\r\n\t\tsetScrollToAction: createSetter('scrollToAction'),\r\n\t\tsetSearch: createSetter('searchValue'),\r\n\r\n\t\ttoggleFilter(state, { payload }: PayloadAction) {\r\n\t\t\tstate.filters[payload] = !state.filters[payload]\r\n\t\t},\r\n\t\tupdateOne(state, action: PayloadAction) {\r\n\t\t\tconst update = action.payload\r\n\t\t\tconst index = state.campaigns.findIndex(item => item.id === update.id)\r\n\r\n\t\t\tif (index > -1) {\r\n\t\t\t\tstate.campaigns[index] = update\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\tselectors: {\r\n\t\tfilterQuery: ({ filters }) => {\r\n\t\t\tconst filtersArray = []\r\n\r\n\t\t\tif (filters.active) {\r\n\t\t\t\tfiltersArray.push(`(state eq 'Running')`)\r\n\t\t\t}\r\n\t\t\tif (filters.stopped) {\r\n\t\t\t\tfiltersArray.push(`(state eq 'Stopped')`)\r\n\t\t\t}\r\n\t\t\tif (filters.completed) {\r\n\t\t\t\tfiltersArray.push(`(state eq 'Completed')`)\r\n\t\t\t}\r\n\t\t\tif (filters.drafted) {\r\n\t\t\t\tfiltersArray.push(`(state eq 'Compose')`)\r\n\t\t\t}\r\n\r\n\t\t\treturn filtersArray.join(' or ')\r\n\t\t},\r\n\r\n\t\tfilters: state => state.filters,\r\n\t\tisFilterActive,\r\n\t\tisFilterOrSearchActive: state =>\r\n\t\t\tBoolean(state.searchValue) || isFilterActive(state),\r\n\t\tsearch: state => state.searchValue\r\n\t}\r\n})\r\n\r\nconst campaignsActions = campaignsSlice.actions\r\nconst campaignsSelectors = campaignsSlice.selectors\r\n\r\nexport { campaignsActions, campaignsSelectors, campaignsSlice }\r\n","/*\n *\n * Contacts reducer\n *\n */\nconst initialState = {\n imports: [],\n contacts: [],\n contactsCount: null,\n contactsModal: [],\n contactsCountModal: null,\n haveContacts: false,\n contactsPage: 0,\n columnSize: [],\n typeContacts: \"\",\n typeCampaigns: \"\",\n isModalVisible: false,\n contactsPageModal: 0,\n};\n\nconst contacts = (state = initialState, action) => {\n switch (action.type) {\n case \"ALL_CONTACTS\":\n return Object.assign({}, state, {\n contacts: action.payload.contacts,\n });\n case \"IS_MODAL_VISIBLE\":\n return Object.assign({}, state, {\n isModalVisible: action.payload.isModalVisible,\n });\n case \"CONTACTS_COUNT\":\n return Object.assign({}, state, {\n contactsCount: action.payload.contactsCount,\n });\n case \"ALL_CONTACTS_MODAL\":\n return Object.assign({}, state, {\n contactsModal: action.payload.contactsModal,\n });\n case \"CONTACTS_COUNT_MODAL\":\n return Object.assign({}, state, {\n contactsCountModal: action.payload.contactsCountModal,\n });\n case \"CONTACTS_PAGE\":\n return Object.assign({}, state, {\n contactsPage: action.payload.contactsPage,\n });\n case \"CONTACTS_PAGE_MODAL\":\n return Object.assign({}, state, {\n contactsPageModal: action.payload.contactsPageModal,\n });\n case \"COLUMN_SIZE\":\n return Object.assign({}, state, {\n columnSize: action.payload.columnSize,\n });\n case \"TYPE_CONTACTS\":\n return Object.assign({}, state, {\n typeContacts: action.payload.typeContacts,\n });\n case \"TYPE_CAMPAIGNS\":\n return Object.assign({}, state, {\n typeCampaigns: action.payload.typeCampaigns,\n });\n case \"RECENT_IMPORTS\":\n return Object.assign({}, state, {\n imports: action.payload.imports,\n });\n case \"HAVE_CONTACTS\":\n return Object.assign({}, state, {\n haveContacts: action.payload.haveContacts,\n });\n case \"UPDATE_IMPORTED_CONTACT\":\n return Object.assign({}, state, {\n imports: action.payload.imports,\n });\n default:\n return state;\n }\n};\n\nexport default contacts;\n","/*\n *\n * Filters reducer\n *\n */\n\nexport const initialFilterData = [\n {\n id: 1,\n name: \"connection\",\n exclude: false,\n search: false,\n value: [],\n tag: \"\",\n },\n {\n id: 2,\n name: \"location\",\n exclude: false,\n search: false,\n value: [],\n tag: \"\",\n },\n {\n id: 3,\n name: \"industry\",\n exclude: false,\n search: false,\n value: [],\n tag: \"\",\n },\n {\n id: 4,\n name: \"keywords\",\n exclude: false,\n search: true,\n value: [],\n tag: \"\",\n },\n {\n id: 5,\n name: \"company\",\n exclude: false,\n search: false,\n value: [],\n tag: \"\",\n },\n {\n id: 6,\n selectId: 9,\n name: \"contacted\",\n exclude: false,\n search: false,\n value: [\n { id: 1, value: null },\n { id: 2, value: null },\n ],\n tag: \"\",\n },\n {\n id: 7,\n name: \"status\",\n exclude: false,\n search: false,\n value: \"\",\n tag: \"\",\n },\n {\n id: 8,\n name: \"createdSelect\",\n exclude: false,\n search: false,\n value: null,\n },\n {\n id: 9,\n name: \"contactedSelect\",\n exclude: false,\n search: false,\n value: null,\n },\n {\n id: 10,\n name: \"campaigns\",\n exclude: false,\n search: false,\n value: [],\n tag: \"\",\n },\n {\n id: 11,\n name: \"exclude contactedSelect\",\n exclude: false,\n search: false,\n value: null,\n },\n {\n id: 12,\n name: \"NOT: keywords\",\n exclude: true,\n search: true,\n value: [],\n tag: \"\",\n },\n {\n id: 13,\n name: \"NOT: campaigns\",\n exclude: true,\n search: false,\n value: [],\n tag: \"\",\n },\n {\n id: 14,\n selectId: 11,\n name: \"NOT: contacted\",\n exclude: true,\n search: false,\n value: [\n { id: 1, value: null },\n { id: 2, value: null },\n ],\n tag: \"\",\n },\n {\n id: 15,\n selectId: 8,\n name: \"created\",\n exclude: false,\n search: false,\n value: [\n { id: 1, value: null },\n { id: 2, value: null },\n ],\n tag: \"\",\n },\n];\n\nconst initialState = {\n filterData: [...initialFilterData],\n filterDataForModal: [...initialFilterData],\n options: {\n colourOptions: [\n { key: 1, text: \"1st\", value: 1 },\n { key: 2, text: \"2nd\", value: 2 },\n { key: 3, text: \"3rd+\", value: 3 },\n ],\n location: [],\n industry: [\n { key: 1, text: \"Design\", value: \"Design\" },\n { key: 2, text: \"Development\", value: \"Development\" },\n { key: 3, text: \"Management\", value: \"Management\" },\n ],\n keywords: [\n { key: 1, text: \"CEO\", value: \"CEO\" },\n { key: 2, text: \"Web Design\", value: \"Web Design\" },\n { key: 3, text: \"UX Design\", value: \"UX Design\" },\n ],\n contacted: [\n { key: 1, text: \"Last day\", value: \"day\" },\n { key: 2, text: \"Last week\", value: \"week\" },\n { key: 3, text: \"Last month\", value: \"month\" },\n { key: 4, text: \"Last year\", value: \"year\" },\n { key: 5, text: \"Custom\", value: \"custom\" },\n ],\n campaigns: [],\n status: [\n { key: 1, text: \"All\", value: \"\" },\n { key: 2, text: \"Premium only\", value: \"premium\" },\n ],\n },\n filtersQuery: false,\n filtersQueryForModal: false,\n searchQuery: false,\n searchQueryForModal: false,\n stringParams: \"\",\n};\n\nconst filters = (state = initialState, action) => {\n switch (action.type) {\n case \"FILTERS_PARAMS\":\n return Object.assign({}, state, {\n filterData: action.payload.filterData,\n });\n case \"FILTERS_PARAMS_FOR_MODAL\":\n return Object.assign({}, state, {\n filterDataForModal: action.payload.filterDataForModal,\n });\n case \"OPTIONS_PARAMS\":\n return Object.assign({}, state, {\n options: { ...state.options, ...action.payload },\n });\n case \"FILTERS_QUERY\":\n return Object.assign({}, state, {\n filtersQuery: action.payload.filtersQuery,\n });\n case \"FILTERS_QUERY_FOR_MODAL\":\n return Object.assign({}, state, {\n filtersQueryForModal: action.payload.filtersQueryForModal,\n });\n case \"FILTERS_SEARCH_QUERY\":\n return Object.assign({}, state, {\n searchQuery: action.payload.searchQuery,\n });\n case \"FILTERS_QUERY_CLEAR\":\n return Object.assign({}, state, {\n searchQuery: \"\",\n filtersQuery: \"\",\n });\n case \"FILTERS_SEARCH_QUERY_FOR_MODAL\":\n return Object.assign({}, state, {\n searchQueryForModal: action.payload.searchQueryForModal,\n });\n case \"FILTERS_STRING_PARAMS\":\n return Object.assign({}, state, {\n stringParams: action.payload.stringParams,\n });\n\n default:\n return state;\n }\n};\n\nexport default filters;\n","/*\n *\n * Home reducer\n *\n */\nconst initialState = {\n ready: false,\n error: null,\n};\n\nconst home = (state = initialState, action) => {\n switch (action.type) {\n case \"HOME_READY\":\n return Object.assign({}, state, {\n value: action.payload.value,\n ready: true,\n error: null,\n });\n\n case \"HOME_ACTION_API\":\n return Object.assign({}, state, {\n value: action.payload.value,\n ready: true,\n error: null,\n });\n\n default:\n return state;\n }\n};\n\nexport default home;\n","const initialState = {\n campaignsTeams: [],\n haveCampaignsTeams: false,\n searchValueTeams: \"\",\n loadCampaignsTeamsController: false,\n campaignsTeamsCount: null,\n filters: {\n active: false,\n stopped: false,\n completed: false,\n drafted: false,\n cancelled: false,\n },\n};\n\nconst campaignsTeams = (state = initialState, action) => {\n switch (action.type) {\n case \"CAMPAIGNS_TEAMS_ARRAY\":\n return Object.assign({}, state, {\n campaignsTeams: action.payload.campaignsTeams,\n campaignsTeamsCount: action.payload.campaignsTeamsCount,\n });\n case \"LOAD_CAMPAIGNS_TEAMS_CONTROLLER\":\n return Object.assign({}, state, {\n loadCampaignsTeamsController:\n action.payload.loadCampaignsTeamsController,\n });\n\n case \"HAVE_CAMPAIGNS_TEAMS\":\n return Object.assign({}, state, {\n haveCampaignsTeams: action.payload.haveCampaignsTeams,\n });\n case \"SEARCH_VALUE_TEAMS\":\n return Object.assign({}, state, {\n searchValueTeams: action.payload.searchValue,\n });\n\n case \"CHANGE_FILTER_STATUS_TEAMS\":\n return Object.assign({}, state, {\n filters: action.payload.filters,\n });\n\n default:\n return state;\n }\n};\n\nexport default campaignsTeams;\n","/**\r\n * Create the store with asynchronously loaded reducers\r\n */\r\n\r\nimport { configureStore } from '@reduxjs/toolkit'\r\nimport { mailboxSlice } from 'features/messaging'\r\nimport { notificationSlice } from 'features/notifications'\r\n\r\nimport { apiRTK } from '../api/api-rtk'\r\nimport { automationApi } from '../api/automationApi'\r\nimport activity from './reducers/activity'\r\nimport { appSlice } from './reducers/app'\r\nimport campaign from './reducers/campaign'\r\nimport { campaignCreateSlice } from './reducers/campaignCreate'\r\nimport { campaignsSlice } from './reducers/campaigns'\r\nimport contacts from './reducers/contacts'\r\nimport filters from './reducers/filters'\r\nimport home from './reducers/home'\r\nimport { leftSideSlice } from './reducers/leftSideMenu'\r\nimport campaignsTeams from './reducers/teams'\r\n\r\nconst store = configureStore({\r\n\tmiddleware: getDefaultMiddleware =>\r\n\t\tgetDefaultMiddleware({\r\n\t\t\t// ! Store data like this in not Redux way. Better to refactor\r\n\t\t\timmutableCheck: false,\r\n\t\t\tserializableCheck: false\r\n\t\t\t// serializableCheck: {\r\n\t\t\t// ignoredActions: [appSlice.actions.createConnector.type],\r\n\t\t\t// ignoredPaths: [\"app.connector\"],\r\n\t\t\t// },\r\n\t\t}).concat([automationApi.middleware, apiRTK.middleware]),\r\n\r\n\treducer: {\r\n\t\tactivity,\r\n\t\t[apiRTK.reducerPath]: apiRTK.reducer,\r\n\t\t[appSlice.name]: appSlice.reducer,\r\n\t\t[automationApi.reducerPath]: automationApi.reducer,\r\n\t\tcampaign,\r\n\t\t[campaignCreateSlice.name]: campaignCreateSlice.reducer,\r\n\t\t[campaignsSlice.name]: campaignsSlice.reducer,\r\n\t\tcampaignsTeams,\r\n\t\tcontacts,\r\n\t\tfilters,\r\n\t\thome,\r\n\t\t[leftSideSlice.name]: leftSideSlice.reducer,\r\n\t\t[mailboxSlice.reducerPath]: mailboxSlice.reducer,\r\n\t\t[notificationSlice.name]: notificationSlice.reducer\r\n\t}\r\n})\r\n\r\ntype AppDispatch = typeof store.dispatch\r\ntype RootState = ReturnType\r\n\r\nexport type { AppDispatch, RootState }\r\n\r\nexport default store\r\n","// TODO: Bad decision to inline html here. Better use plain string and style DOM node with `text-wrap: pretty;`\r\n\r\ninterface NotiFicationButton {\r\n\tlink: string\r\n\ttitle: string\r\n}\r\ninterface NotiFicationDatum {\r\n\tbutton?: NotiFicationButton\r\n\tcontent: string\r\n\tstyle: 'attention' | 'default'\r\n\ttitle: string\r\n}\r\n\r\ntype SnackKey = keyof typeof NOTIFICATION\r\n\r\nexport type { NotiFicationButton, NotiFicationDatum, SnackKey }\r\nexport const NOTIFICATION = {\r\n\t'3.1': {\r\n\t\tcontent: 'Campaign is created.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Congratulations!'\r\n\t},\r\n\t'3.10': {\r\n\t\tbutton: {\r\n\t\t\tlink: '/archive',\r\n\t\t\ttitle: 'Archive'\r\n\t\t},\r\n\t\tcontent: 'You can find it in the archive.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Campaign is archived'\r\n\t},\r\n\t'3.13': {\r\n\t\tbutton: {\r\n\t\t\tlink: '/activities-queue',\r\n\t\t\ttitle: 'Activities queue'\r\n\t\t},\r\n\t\tcontent:\r\n\t\t\t'All activities are rescheduled
    according to new working hours.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Working hours are changed'\r\n\t},\r\n\t'3.14': {\r\n\t\tbutton: {\r\n\t\t\tlink: '/activities-queue',\r\n\t\t\ttitle: 'Activities queue'\r\n\t\t},\r\n\t\tcontent:\r\n\t\t\t'All activities are rescheduled
    according to the new time zone.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Time zone is changed'\r\n\t},\r\n\t'3.15': {\r\n\t\tbutton: {\r\n\t\t\tlink: '/activities-queue',\r\n\t\t\ttitle: 'Activities queue'\r\n\t\t},\r\n\t\tcontent: 'All activities are rescheduled according to the new limits.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Daily limits is changed'\r\n\t},\r\n\t'3.16': {\r\n\t\tbutton: {\r\n\t\t\tlink: '/activities-queue',\r\n\t\t\ttitle: 'Activities queue'\r\n\t\t},\r\n\t\tcontent: 'All activities are rescheduled.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Contacts are excluded'\r\n\t},\r\n\t'3.17': {\r\n\t\tbutton: {\r\n\t\t\tlink: '/upgrade',\r\n\t\t\ttitle: 'Upgrade subscription'\r\n\t\t},\r\n\t\tcontent: 'Upgrade your subscription to
    continue using Snaily.',\r\n\t\tstyle: 'attention',\r\n\t\ttitle: 'Subscription is expired'\r\n\t},\r\n\t'3.18': {\r\n\t\tbutton: {\r\n\t\t\tlink: '/activities-queue',\r\n\t\t\ttitle: 'Activities queue'\r\n\t\t},\r\n\t\tcontent: 'All activities are rescheduled.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Contacts are added'\r\n\t},\r\n\t'3.19': {\r\n\t\tcontent: 'Your subscription is activated.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Congratulations!'\r\n\t},\r\n\t'3.20': {\r\n\t\tcontent: 'Contacts are deleted from the system.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Done!'\r\n\t},\r\n\t'3.21': {\r\n\t\tcontent: 'Campaign is cloned.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Done!'\r\n\t},\r\n\t'3.29': {\r\n\t\tcontent: 'The subscription has been canceled.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Done!'\r\n\t},\r\n\t'3.3': {\r\n\t\tcontent: '',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'The action is removed'\r\n\t},\r\n\t'3.4a': {\r\n\t\tbutton: {\r\n\t\t\tlink: '/campaigns/{var}',\r\n\t\t\ttitle: 'Go to campaign'\r\n\t\t},\r\n\t\tcontent: '',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Contacts are added'\r\n\t},\r\n\t'3.4b': {\r\n\t\tcontent: '',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Contacts are added'\r\n\t},\r\n\t'3.5a': {\r\n\t\tcontent: 'You may find it in all contacts.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Contact is excluded'\r\n\t},\r\n\t'3.5b': {\r\n\t\tcontent: 'You may find them in all contacts.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Contacts are excluded'\r\n\t},\r\n\t'3.6': {\r\n\t\tbutton: {\r\n\t\t\tlink: '/activities-queue',\r\n\t\t\ttitle: 'Activities queue'\r\n\t\t},\r\n\t\tcontent: 'See the list of actions in the activities queue.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Campaign is launched'\r\n\t},\r\n\t'3.7': {\r\n\t\tcontent: 'You can resume it at any time.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Campaign is paused'\r\n\t},\r\n\t'3.8': {\r\n\t\tbutton: {\r\n\t\t\tlink: '/activities-queue',\r\n\t\t\ttitle: 'Activities queue'\r\n\t\t},\r\n\t\tcontent:\r\n\t\t\t\"All campaign's activities have been removed
    from the activities queue.\",\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Campaign is cancelled'\r\n\t},\r\n\t'3.9': {\r\n\t\tbutton: {\r\n\t\t\tlink: '/activities-queue',\r\n\t\t\ttitle: 'Activities queue'\r\n\t\t},\r\n\t\tcontent: 'See the activities to be taken in the activities queue.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Campaign is resumed'\r\n\t},\r\n\t'n3.22': {\r\n\t\tcontent: 'Subscription has been upgraded.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Done!'\r\n\t},\r\n\t'n3.23': {\r\n\t\tcontent: 'Invitation has been sent. Await for confirmation.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Done!'\r\n\t},\r\n\t'n3.26': {\r\n\t\tcontent: 'Subscription has been upgraded.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Done!'\r\n\t},\r\n\t'n3.27': {\r\n\t\tcontent: 'The invitation has been resent.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Done!'\r\n\t},\r\n\t'n3.28': {\r\n\t\tcontent: 'Invitation for {email} is revoked.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Done!'\r\n\t},\r\n\t'n3.30': {\r\n\t\tcontent: 'The subscription has been resumed.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Done!'\r\n\t},\r\n\t'n3.31': {\r\n\t\tcontent: 'The team member has been deleted.',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Done!'\r\n\t},\r\n\t'n3.32': {\r\n\t\tcontent: 'Contact name is changed',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Done!'\r\n\t},\r\n\t'n3.33': {\r\n\t\tcontent: 'Conversation is resumed',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Done!'\r\n\t},\r\n\t'n3.34': {\r\n\t\tcontent: 'Conversation is cancelled',\r\n\t\tstyle: 'default',\r\n\t\ttitle: 'Done!'\r\n\t}\r\n} satisfies Record\r\n","import {\r\n\tNOTIFICATION,\r\n\ttype NotiFicationDatum,\r\n\ttype SnackKey\r\n} from 'config/notifications'\r\nimport store from 'redux/store'\r\n\r\nimport { actions } from '../slice'\r\n\r\nconst showSnack = (message: NotiFicationDatum) =>\r\n\tstore.dispatch(actions.showSnack(message))\r\n\r\nfunction snackById(key: SnackKey) {\r\n\tconst message = NOTIFICATION[key]\r\n\tshowSnack(message)\r\n}\r\n\r\nexport { showSnack, snackById }\r\n","import { apiRTK, Tag } from 'api/api-rtk'\r\n\r\nimport type * as WorkSpace from './types'\r\n\r\nexport const workspaceApi = apiRTK.injectEndpoints({\r\n\tendpoints: create => ({\r\n\t\tautomationMode: create.query({\r\n\t\t\tquery: () => ({\r\n\t\t\t\turl: 'workspace/automation-mode'\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\tsetWorkingHours: create.mutation>({\r\n\t\t\tasync onQueryStarted(patch, { dispatch, queryFulfilled }) {\r\n\t\t\t\tconst patchResult = dispatch(\r\n\t\t\t\t\tworkspaceApi.util.updateQueryData('workingHours', undefined, draft =>\r\n\t\t\t\t\t\tObject.assign(draft, patch)\r\n\t\t\t\t\t)\r\n\t\t\t\t)\r\n\r\n\t\t\t\ttry {\r\n\t\t\t\t\tawait queryFulfilled\r\n\t\t\t\t} catch {\r\n\t\t\t\t\tpatchResult.undo()\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\tquery: hours => ({\r\n\t\t\t\tdata: hours,\r\n\t\t\t\tmethod: 'PUT', // working as POST, rewrite all hours\r\n\t\t\t\turl: 'workspace/working-hours-in-minutes'\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\tstatistics: create.query({\r\n\t\t\tprovidesTags: [Tag.WorkspaceStats],\r\n\t\t\tquery: params => ({\r\n\t\t\t\tparams,\r\n\t\t\t\turl: 'workspace/period-statistics'\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\ttimezoneOffset: create.mutation({\r\n\t\t\tinvalidatesTags: [Tag.WorkspaceStats],\r\n\t\t\tquery: offset => ({\r\n\t\t\t\tdata: {\r\n\t\t\t\t\ttimezone_offset: offset\r\n\t\t\t\t},\r\n\t\t\t\tmethod: 'PUT',\r\n\t\t\t\turl: 'workspace/timezone-offset'\r\n\t\t\t})\r\n\t\t}),\r\n\t\tworkingHours: create.query({\r\n\t\t\tquery: () => ({\r\n\t\t\t\turl: 'workspace/working-hours-in-minutes'\r\n\t\t\t})\r\n\t\t})\r\n\t}),\r\n\toverrideExisting: true\r\n})\r\n","import type { WorkSpace } from '../../'\r\n\r\nimport './style.scss'\r\n\r\ntype Key = keyof Omit\r\n\r\nconst KEYS: {\r\n\tkey: Key\r\n\tlabel: string\r\n\tmax?: Key\r\n}[] = [\r\n\t{\r\n\t\tkey: 'invitations_sent',\r\n\t\tlabel: 'Sent invitations',\r\n\t\tmax: 'invitations_limit'\r\n\t},\r\n\t{\r\n\t\tkey: 'invitations_accepted_count',\r\n\t\tlabel: 'Accepted invitations'\r\n\t},\r\n\t{\r\n\t\tkey: 'withdrawn_count',\r\n\t\tlabel: 'Withdrawn invitations'\r\n\t},\r\n\t{\r\n\t\tkey: 'messages_count',\r\n\t\tlabel: 'Sent messages',\r\n\t\tmax: 'messages_limit'\r\n\t},\r\n\t{\r\n\t\tkey: 'replied_count',\r\n\t\tlabel: 'Replied'\r\n\t},\r\n\t{\r\n\t\tkey: 'react_on_post_count',\r\n\t\tlabel: 'Likes',\r\n\t\tmax: 'react_on_post_limit'\r\n\t},\r\n\t{\r\n\t\tkey: 'follow_count',\r\n\t\tlabel: 'Followed',\r\n\t\tmax: 'follow_limit'\r\n\t}\r\n]\r\n\r\nfunction getWidth(value: number, max: number) {\r\n\tif (value === 0 && max === 0) {\r\n\t\treturn 0\r\n\t}\r\n\r\n\t// legacy logic\r\n\tif (max <= value) {\r\n\t\treturn 100\r\n\t}\r\n\r\n\tmax ||= value + 1\r\n\treturn (value / max) * 100\r\n}\r\n\r\nexport const Performed = ({\r\n\tlimit = false,\r\n\tstatistics\r\n}: {\r\n\tlimit?: boolean\r\n\tstatistics?: WorkSpace.Stats\r\n}) => (\r\n\t
      \r\n\t\t{KEYS.map(({ key, label, max }) => {\r\n\t\t\tconst value = statistics?.[key] || 0\r\n\r\n\t\t\tlet itemMaxV: '~' | number = '~'\r\n\r\n\t\t\tif (max && limit && statistics) {\r\n\t\t\t\titemMaxV = statistics[max]\r\n\t\t\t}\r\n\r\n\t\t\tconst maxValue = itemMaxV === '~' ? 50 : Number(itemMaxV)\r\n\r\n\t\t\treturn (\r\n\t\t\t\t
    • \r\n\t\t\t\t\t
      \r\n\t\t\t\t\t\t
      {label}
      \r\n\r\n\t\t\t\t\t\t
      \r\n\t\t\t\t\t\t\t
      \r\n\t\t\t\t\t\t\t\t{value}/{itemMaxV || 0}\r\n\t\t\t\t\t\t\t
      \r\n\t\t\t\t\t\t
      \r\n\t\t\t\t\t
      \r\n\t\t\t\t\t
      \r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t \r\n\t\t\t\t\t\t
      \r\n\t\t\t\t\t\r\n\t\t\t\t
    • \r\n\t\t\t)\r\n\t\t})}\r\n\t
    \r\n)\r\n","import { Tag } from 'api/api-rtk'\r\n\r\nimport store from '../../../redux/store'\r\nimport { workspaceApi } from '../api'\r\n\r\nexport function refetchStatistics() {\r\n\tconst action = workspaceApi.util.invalidateTags([Tag.WorkspaceStats])\r\n\treturn store.dispatch(action)\r\n}\r\n","import type { ConfigType } from 'dayjs'\r\n\r\nimport { createSelector } from '@reduxjs/toolkit'\r\nimport { appDay } from 'shared/day'\r\n\r\nimport { appSelectors } from '../../../redux/reducers/app'\r\n\r\nconst addInUtc = (input: ConfigType, minutes: number) =>\r\n\tappDay(input).utc().add(minutes, 'minutes')\r\n\r\nconst selectNowWithOffset = createSelector(\r\n\tappSelectors.timezoneOffset,\r\n\toffset => addInUtc(Date.now(), offset ?? 0)\r\n)\r\n\r\nconst selectCurrentDay = createSelector(selectNowWithOffset, now => ({\r\n\tstart: now.startOf('day').toISOString(),\r\n\t// eslint-disable-next-line perfectionist/sort-objects\r\n\tend: now.endOf('day').toISOString()\r\n}))\r\n\r\nexport { selectCurrentDay, selectNowWithOffset }\r\n"," \nclass SnailyError extends Error {\n\n #metadata;\n\n constructor(message, metadata) {\n super(message);\n this.name = \"SnailyError\";\n this.#metadata = metadata;\n\n // noinspection JSUnresolvedVariable\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, SnailyError);\n }\n }\n\n get metadata() {\n return this.#metadata;\n }\n\n toString() {\n let result = `${super.toString()}; Metadata: ${JSON.stringify(this.#metadata)}`;\n return result;\n }\n\n}\n\nclass ExtensionNotInstalledError extends SnailyError {\n\n constructor(message, metadata) {\n super(message, metadata);\n this.name = \"ExtensionNotInstalledError\";\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ExtensionNotInstalledError);\n }\n }\n\n get skipLogging() {\n return true;\n }\n}\n\nconst officialEmojiExpression = () => {\n // https://mths.be/emoji\n return /[#*0-9]\\uFE0F?\\u20E3|[\\xA9\\xAE\\u203C\\u2049\\u2122\\u2139\\u2194-\\u2199\\u21A9\\u21AA\\u231A\\u231B\\u2328\\u23CF\\u23ED-\\u23EF\\u23F1\\u23F2\\u23F8-\\u23FA\\u24C2\\u25AA\\u25AB\\u25B6\\u25C0\\u25FB\\u25FC\\u25FE\\u2600-\\u2604\\u260E\\u2611\\u2614\\u2615\\u2618\\u2620\\u2622\\u2623\\u2626\\u262A\\u262E\\u262F\\u2638-\\u263A\\u2640\\u2642\\u2648-\\u2653\\u265F\\u2660\\u2663\\u2665\\u2666\\u2668\\u267B\\u267E\\u267F\\u2692\\u2694-\\u2697\\u2699\\u269B\\u269C\\u26A0\\u26A7\\u26AA\\u26B0\\u26B1\\u26BD\\u26BE\\u26C4\\u26C8\\u26CF\\u26D1\\u26D3\\u26E9\\u26F0-\\u26F5\\u26F7\\u26F8\\u26FA\\u2702\\u2708\\u2709\\u270F\\u2712\\u2714\\u2716\\u271D\\u2721\\u2733\\u2734\\u2744\\u2747\\u2757\\u2763\\u27A1\\u2934\\u2935\\u2B05-\\u2B07\\u2B1B\\u2B1C\\u2B55\\u3030\\u303D\\u3297\\u3299]\\uFE0F?|[\\u261D\\u270C\\u270D](?:\\uFE0F|\\uD83C[\\uDFFB-\\uDFFF])?|[\\u270A\\u270B](?:\\uD83C[\\uDFFB-\\uDFFF])?|[\\u23E9-\\u23EC\\u23F0\\u23F3\\u25FD\\u2693\\u26A1\\u26AB\\u26C5\\u26CE\\u26D4\\u26EA\\u26FD\\u2705\\u2728\\u274C\\u274E\\u2753-\\u2755\\u2795-\\u2797\\u27B0\\u27BF\\u2B50]|\\u26F9(?:\\uFE0F|\\uD83C[\\uDFFB-\\uDFFF])?(?:\\u200D[\\u2640\\u2642]\\uFE0F?)?|\\u2764\\uFE0F?(?:\\u200D(?:\\uD83D\\uDD25|\\uD83E\\uDE79))?|\\uD83C(?:[\\uDC04\\uDD70\\uDD71\\uDD7E\\uDD7F\\uDE02\\uDE37\\uDF21\\uDF24-\\uDF2C\\uDF36\\uDF7D\\uDF96\\uDF97\\uDF99-\\uDF9B\\uDF9E\\uDF9F\\uDFCD\\uDFCE\\uDFD4-\\uDFDF\\uDFF5\\uDFF7]\\uFE0F?|[\\uDF85\\uDFC2\\uDFC7](?:\\uD83C[\\uDFFB-\\uDFFF])?|[\\uDFC3\\uDFC4\\uDFCA](?:\\uD83C[\\uDFFB-\\uDFFF])?(?:\\u200D[\\u2640\\u2642]\\uFE0F?)?|[\\uDFCB\\uDFCC](?:\\uFE0F|\\uD83C[\\uDFFB-\\uDFFF])?(?:\\u200D[\\u2640\\u2642]\\uFE0F?)?|[\\uDCCF\\uDD8E\\uDD91-\\uDD9A\\uDE01\\uDE1A\\uDE2F\\uDE32-\\uDE36\\uDE38-\\uDE3A\\uDE50\\uDE51\\uDF00-\\uDF20\\uDF2D-\\uDF35\\uDF37-\\uDF7C\\uDF7E-\\uDF84\\uDF86-\\uDF93\\uDFA0-\\uDFC1\\uDFC5\\uDFC6\\uDFC8\\uDFC9\\uDFCF-\\uDFD3\\uDFE0-\\uDFF0\\uDFF8-\\uDFFF]|\\uDDE6\\uD83C[\\uDDE8-\\uDDEC\\uDDEE\\uDDF1\\uDDF2\\uDDF4\\uDDF6-\\uDDFA\\uDDFC\\uDDFD\\uDDFF]|\\uDDE7\\uD83C[\\uDDE6\\uDDE7\\uDDE9-\\uDDEF\\uDDF1-\\uDDF4\\uDDF6-\\uDDF9\\uDDFB\\uDDFC\\uDDFE\\uDDFF]|\\uDDE8\\uD83C[\\uDDE6\\uDDE8\\uDDE9\\uDDEB-\\uDDEE\\uDDF0-\\uDDF5\\uDDF7\\uDDFA-\\uDDFF]|\\uDDE9\\uD83C[\\uDDEA\\uDDEC\\uDDEF\\uDDF0\\uDDF2\\uDDF4\\uDDFF]|\\uDDEA\\uD83C[\\uDDE6\\uDDE8\\uDDEA\\uDDEC\\uDDED\\uDDF7-\\uDDFA]|\\uDDEB\\uD83C[\\uDDEE-\\uDDF0\\uDDF2\\uDDF4\\uDDF7]|\\uDDEC\\uD83C[\\uDDE6\\uDDE7\\uDDE9-\\uDDEE\\uDDF1-\\uDDF3\\uDDF5-\\uDDFA\\uDDFC\\uDDFE]|\\uDDED\\uD83C[\\uDDF0\\uDDF2\\uDDF3\\uDDF7\\uDDF9\\uDDFA]|\\uDDEE\\uD83C[\\uDDE8-\\uDDEA\\uDDF1-\\uDDF4\\uDDF6-\\uDDF9]|\\uDDEF\\uD83C[\\uDDEA\\uDDF2\\uDDF4\\uDDF5]|\\uDDF0\\uD83C[\\uDDEA\\uDDEC-\\uDDEE\\uDDF2\\uDDF3\\uDDF5\\uDDF7\\uDDFC\\uDDFE\\uDDFF]|\\uDDF1\\uD83C[\\uDDE6-\\uDDE8\\uDDEE\\uDDF0\\uDDF7-\\uDDFB\\uDDFE]|\\uDDF2\\uD83C[\\uDDE6\\uDDE8-\\uDDED\\uDDF0-\\uDDFF]|\\uDDF3\\uD83C[\\uDDE6\\uDDE8\\uDDEA-\\uDDEC\\uDDEE\\uDDF1\\uDDF4\\uDDF5\\uDDF7\\uDDFA\\uDDFF]|\\uDDF4\\uD83C\\uDDF2|\\uDDF5\\uD83C[\\uDDE6\\uDDEA-\\uDDED\\uDDF0-\\uDDF3\\uDDF7-\\uDDF9\\uDDFC\\uDDFE]|\\uDDF6\\uD83C\\uDDE6|\\uDDF7\\uD83C[\\uDDEA\\uDDF4\\uDDF8\\uDDFA\\uDDFC]|\\uDDF8\\uD83C[\\uDDE6-\\uDDEA\\uDDEC-\\uDDF4\\uDDF7-\\uDDF9\\uDDFB\\uDDFD-\\uDDFF]|\\uDDF9\\uD83C[\\uDDE6\\uDDE8\\uDDE9\\uDDEB-\\uDDED\\uDDEF-\\uDDF4\\uDDF7\\uDDF9\\uDDFB\\uDDFC\\uDDFF]|\\uDDFA\\uD83C[\\uDDE6\\uDDEC\\uDDF2\\uDDF3\\uDDF8\\uDDFE\\uDDFF]|\\uDDFB\\uD83C[\\uDDE6\\uDDE8\\uDDEA\\uDDEC\\uDDEE\\uDDF3\\uDDFA]|\\uDDFC\\uD83C[\\uDDEB\\uDDF8]|\\uDDFD\\uD83C\\uDDF0|\\uDDFE\\uD83C[\\uDDEA\\uDDF9]|\\uDDFF\\uD83C[\\uDDE6\\uDDF2\\uDDFC]|\\uDFF3\\uFE0F?(?:\\u200D(?:\\u26A7\\uFE0F?|\\uD83C\\uDF08))?|\\uDFF4(?:\\u200D\\u2620\\uFE0F?|\\uDB40\\uDC67\\uDB40\\uDC62\\uDB40(?:\\uDC65\\uDB40\\uDC6E\\uDB40\\uDC67|\\uDC73\\uDB40\\uDC63\\uDB40\\uDC74|\\uDC77\\uDB40\\uDC6C\\uDB40\\uDC73)\\uDB40\\uDC7F)?)|\\uD83D(?:[\\uDC08\\uDC26](?:\\u200D\\u2B1B)?|[\\uDC3F\\uDCFD\\uDD49\\uDD4A\\uDD6F\\uDD70\\uDD73\\uDD76-\\uDD79\\uDD87\\uDD8A-\\uDD8D\\uDDA5\\uDDA8\\uDDB1\\uDDB2\\uDDBC\\uDDC2-\\uDDC4\\uDDD1-\\uDDD3\\uDDDC-\\uDDDE\\uDDE1\\uDDE3\\uDDE8\\uDDEF\\uDDF3\\uDDFA\\uDECB\\uDECD-\\uDECF\\uDEE0-\\uDEE5\\uDEE9\\uDEF0\\uDEF3]\\uFE0F?|[\\uDC42\\uDC43\\uDC46-\\uDC50\\uDC66\\uDC67\\uDC6B-\\uDC6D\\uDC72\\uDC74-\\uDC76\\uDC78\\uDC7C\\uDC83\\uDC85\\uDC8F\\uDC91\\uDCAA\\uDD7A\\uDD95\\uDD96\\uDE4C\\uDE4F\\uDEC0\\uDECC](?:\\uD83C[\\uDFFB-\\uDFFF])?|[\\uDC6E\\uDC70\\uDC71\\uDC73\\uDC77\\uDC81\\uDC82\\uDC86\\uDC87\\uDE45-\\uDE47\\uDE4B\\uDE4D\\uDE4E\\uDEA3\\uDEB4-\\uDEB6](?:\\uD83C[\\uDFFB-\\uDFFF])?(?:\\u200D[\\u2640\\u2642]\\uFE0F?)?|[\\uDD74\\uDD90](?:\\uFE0F|\\uD83C[\\uDFFB-\\uDFFF])?|[\\uDC00-\\uDC07\\uDC09-\\uDC14\\uDC16-\\uDC25\\uDC27-\\uDC3A\\uDC3C-\\uDC3E\\uDC40\\uDC44\\uDC45\\uDC51-\\uDC65\\uDC6A\\uDC79-\\uDC7B\\uDC7D-\\uDC80\\uDC84\\uDC88-\\uDC8E\\uDC90\\uDC92-\\uDCA9\\uDCAB-\\uDCFC\\uDCFF-\\uDD3D\\uDD4B-\\uDD4E\\uDD50-\\uDD67\\uDDA4\\uDDFB-\\uDE2D\\uDE2F-\\uDE34\\uDE37-\\uDE44\\uDE48-\\uDE4A\\uDE80-\\uDEA2\\uDEA4-\\uDEB3\\uDEB7-\\uDEBF\\uDEC1-\\uDEC5\\uDED0-\\uDED2\\uDED5-\\uDED7\\uDEDC-\\uDEDF\\uDEEB\\uDEEC\\uDEF4-\\uDEFC\\uDFE0-\\uDFEB\\uDFF0]|\\uDC15(?:\\u200D\\uD83E\\uDDBA)?|\\uDC3B(?:\\u200D\\u2744\\uFE0F?)?|\\uDC41\\uFE0F?(?:\\u200D\\uD83D\\uDDE8\\uFE0F?)?|\\uDC68(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|\\u2764\\uFE0F?\\u200D\\uD83D(?:\\uDC8B\\u200D\\uD83D)?\\uDC68|\\uD83C[\\uDF3E\\uDF73\\uDF7C\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D(?:[\\uDC68\\uDC69]\\u200D\\uD83D(?:\\uDC66(?:\\u200D\\uD83D\\uDC66)?|\\uDC67(?:\\u200D\\uD83D[\\uDC66\\uDC67])?)|[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uDC66(?:\\u200D\\uD83D\\uDC66)?|\\uDC67(?:\\u200D\\uD83D[\\uDC66\\uDC67])?)|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C(?:\\uDFFB(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|\\u2764\\uFE0F?\\u200D\\uD83D(?:\\uDC8B\\u200D\\uD83D)?\\uDC68\\uD83C[\\uDFFB-\\uDFFF]|\\uD83C[\\uDF3E\\uDF73\\uDF7C\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E(?:[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]|\\uDD1D\\u200D\\uD83D\\uDC68\\uD83C[\\uDFFC-\\uDFFF])))?|\\uDFFC(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|\\u2764\\uFE0F?\\u200D\\uD83D(?:\\uDC8B\\u200D\\uD83D)?\\uDC68\\uD83C[\\uDFFB-\\uDFFF]|\\uD83C[\\uDF3E\\uDF73\\uDF7C\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E(?:[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]|\\uDD1D\\u200D\\uD83D\\uDC68\\uD83C[\\uDFFB\\uDFFD-\\uDFFF])))?|\\uDFFD(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|\\u2764\\uFE0F?\\u200D\\uD83D(?:\\uDC8B\\u200D\\uD83D)?\\uDC68\\uD83C[\\uDFFB-\\uDFFF]|\\uD83C[\\uDF3E\\uDF73\\uDF7C\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E(?:[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]|\\uDD1D\\u200D\\uD83D\\uDC68\\uD83C[\\uDFFB\\uDFFC\\uDFFE\\uDFFF])))?|\\uDFFE(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|\\u2764\\uFE0F?\\u200D\\uD83D(?:\\uDC8B\\u200D\\uD83D)?\\uDC68\\uD83C[\\uDFFB-\\uDFFF]|\\uD83C[\\uDF3E\\uDF73\\uDF7C\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E(?:[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]|\\uDD1D\\u200D\\uD83D\\uDC68\\uD83C[\\uDFFB-\\uDFFD\\uDFFF])))?|\\uDFFF(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|\\u2764\\uFE0F?\\u200D\\uD83D(?:\\uDC8B\\u200D\\uD83D)?\\uDC68\\uD83C[\\uDFFB-\\uDFFF]|\\uD83C[\\uDF3E\\uDF73\\uDF7C\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E(?:[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]|\\uDD1D\\u200D\\uD83D\\uDC68\\uD83C[\\uDFFB-\\uDFFE])))?))?|\\uDC69(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|\\u2764\\uFE0F?\\u200D\\uD83D(?:\\uDC8B\\u200D\\uD83D)?[\\uDC68\\uDC69]|\\uD83C[\\uDF3E\\uDF73\\uDF7C\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D(?:[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uDC66(?:\\u200D\\uD83D\\uDC66)?|\\uDC67(?:\\u200D\\uD83D[\\uDC66\\uDC67])?|\\uDC69\\u200D\\uD83D(?:\\uDC66(?:\\u200D\\uD83D\\uDC66)?|\\uDC67(?:\\u200D\\uD83D[\\uDC66\\uDC67])?))|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C(?:\\uDFFB(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|\\u2764\\uFE0F?\\u200D\\uD83D(?:[\\uDC68\\uDC69]|\\uDC8B\\u200D\\uD83D[\\uDC68\\uDC69])\\uD83C[\\uDFFB-\\uDFFF]|\\uD83C[\\uDF3E\\uDF73\\uDF7C\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E(?:[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]|\\uDD1D\\u200D\\uD83D[\\uDC68\\uDC69]\\uD83C[\\uDFFC-\\uDFFF])))?|\\uDFFC(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|\\u2764\\uFE0F?\\u200D\\uD83D(?:[\\uDC68\\uDC69]|\\uDC8B\\u200D\\uD83D[\\uDC68\\uDC69])\\uD83C[\\uDFFB-\\uDFFF]|\\uD83C[\\uDF3E\\uDF73\\uDF7C\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E(?:[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]|\\uDD1D\\u200D\\uD83D[\\uDC68\\uDC69]\\uD83C[\\uDFFB\\uDFFD-\\uDFFF])))?|\\uDFFD(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|\\u2764\\uFE0F?\\u200D\\uD83D(?:[\\uDC68\\uDC69]|\\uDC8B\\u200D\\uD83D[\\uDC68\\uDC69])\\uD83C[\\uDFFB-\\uDFFF]|\\uD83C[\\uDF3E\\uDF73\\uDF7C\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E(?:[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]|\\uDD1D\\u200D\\uD83D[\\uDC68\\uDC69]\\uD83C[\\uDFFB\\uDFFC\\uDFFE\\uDFFF])))?|\\uDFFE(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|\\u2764\\uFE0F?\\u200D\\uD83D(?:[\\uDC68\\uDC69]|\\uDC8B\\u200D\\uD83D[\\uDC68\\uDC69])\\uD83C[\\uDFFB-\\uDFFF]|\\uD83C[\\uDF3E\\uDF73\\uDF7C\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E(?:[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]|\\uDD1D\\u200D\\uD83D[\\uDC68\\uDC69]\\uD83C[\\uDFFB-\\uDFFD\\uDFFF])))?|\\uDFFF(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|\\u2764\\uFE0F?\\u200D\\uD83D(?:[\\uDC68\\uDC69]|\\uDC8B\\u200D\\uD83D[\\uDC68\\uDC69])\\uD83C[\\uDFFB-\\uDFFF]|\\uD83C[\\uDF3E\\uDF73\\uDF7C\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E(?:[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]|\\uDD1D\\u200D\\uD83D[\\uDC68\\uDC69]\\uD83C[\\uDFFB-\\uDFFE])))?))?|\\uDC6F(?:\\u200D[\\u2640\\u2642]\\uFE0F?)?|\\uDD75(?:\\uFE0F|\\uD83C[\\uDFFB-\\uDFFF])?(?:\\u200D[\\u2640\\u2642]\\uFE0F?)?|\\uDE2E(?:\\u200D\\uD83D\\uDCA8)?|\\uDE35(?:\\u200D\\uD83D\\uDCAB)?|\\uDE36(?:\\u200D\\uD83C\\uDF2B\\uFE0F?)?)|\\uD83E(?:[\\uDD0C\\uDD0F\\uDD18-\\uDD1F\\uDD30-\\uDD34\\uDD36\\uDD77\\uDDB5\\uDDB6\\uDDBB\\uDDD2\\uDDD3\\uDDD5\\uDEC3-\\uDEC5\\uDEF0\\uDEF2-\\uDEF8](?:\\uD83C[\\uDFFB-\\uDFFF])?|[\\uDD26\\uDD35\\uDD37-\\uDD39\\uDD3D\\uDD3E\\uDDB8\\uDDB9\\uDDCD-\\uDDCF\\uDDD4\\uDDD6-\\uDDDD](?:\\uD83C[\\uDFFB-\\uDFFF])?(?:\\u200D[\\u2640\\u2642]\\uFE0F?)?|[\\uDDDE\\uDDDF](?:\\u200D[\\u2640\\u2642]\\uFE0F?)?|[\\uDD0D\\uDD0E\\uDD10-\\uDD17\\uDD20-\\uDD25\\uDD27-\\uDD2F\\uDD3A\\uDD3F-\\uDD45\\uDD47-\\uDD76\\uDD78-\\uDDB4\\uDDB7\\uDDBA\\uDDBC-\\uDDCC\\uDDD0\\uDDE0-\\uDDFF\\uDE70-\\uDE7C\\uDE80-\\uDE88\\uDE90-\\uDEBD\\uDEBF-\\uDEC2\\uDECE-\\uDEDB\\uDEE0-\\uDEE8]|\\uDD3C(?:\\u200D[\\u2640\\u2642]\\uFE0F?|\\uD83C[\\uDFFB-\\uDFFF])?|\\uDDD1(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|\\uD83C[\\uDF3E\\uDF73\\uDF7C\\uDF84\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E(?:[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]|\\uDD1D\\u200D\\uD83E\\uDDD1))|\\uD83C(?:\\uDFFB(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|\\u2764\\uFE0F?\\u200D(?:\\uD83D\\uDC8B\\u200D)?\\uD83E\\uDDD1\\uD83C[\\uDFFC-\\uDFFF]|\\uD83C[\\uDF3E\\uDF73\\uDF7C\\uDF84\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E(?:[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]|\\uDD1D\\u200D\\uD83E\\uDDD1\\uD83C[\\uDFFB-\\uDFFF])))?|\\uDFFC(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|\\u2764\\uFE0F?\\u200D(?:\\uD83D\\uDC8B\\u200D)?\\uD83E\\uDDD1\\uD83C[\\uDFFB\\uDFFD-\\uDFFF]|\\uD83C[\\uDF3E\\uDF73\\uDF7C\\uDF84\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E(?:[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]|\\uDD1D\\u200D\\uD83E\\uDDD1\\uD83C[\\uDFFB-\\uDFFF])))?|\\uDFFD(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|\\u2764\\uFE0F?\\u200D(?:\\uD83D\\uDC8B\\u200D)?\\uD83E\\uDDD1\\uD83C[\\uDFFB\\uDFFC\\uDFFE\\uDFFF]|\\uD83C[\\uDF3E\\uDF73\\uDF7C\\uDF84\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E(?:[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]|\\uDD1D\\u200D\\uD83E\\uDDD1\\uD83C[\\uDFFB-\\uDFFF])))?|\\uDFFE(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|\\u2764\\uFE0F?\\u200D(?:\\uD83D\\uDC8B\\u200D)?\\uD83E\\uDDD1\\uD83C[\\uDFFB-\\uDFFD\\uDFFF]|\\uD83C[\\uDF3E\\uDF73\\uDF7C\\uDF84\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E(?:[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]|\\uDD1D\\u200D\\uD83E\\uDDD1\\uD83C[\\uDFFB-\\uDFFF])))?|\\uDFFF(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|\\u2764\\uFE0F?\\u200D(?:\\uD83D\\uDC8B\\u200D)?\\uD83E\\uDDD1\\uD83C[\\uDFFB-\\uDFFE]|\\uD83C[\\uDF3E\\uDF73\\uDF7C\\uDF84\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E(?:[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]|\\uDD1D\\u200D\\uD83E\\uDDD1\\uD83C[\\uDFFB-\\uDFFF])))?))?|\\uDEF1(?:\\uD83C(?:\\uDFFB(?:\\u200D\\uD83E\\uDEF2\\uD83C[\\uDFFC-\\uDFFF])?|\\uDFFC(?:\\u200D\\uD83E\\uDEF2\\uD83C[\\uDFFB\\uDFFD-\\uDFFF])?|\\uDFFD(?:\\u200D\\uD83E\\uDEF2\\uD83C[\\uDFFB\\uDFFC\\uDFFE\\uDFFF])?|\\uDFFE(?:\\u200D\\uD83E\\uDEF2\\uD83C[\\uDFFB-\\uDFFD\\uDFFF])?|\\uDFFF(?:\\u200D\\uD83E\\uDEF2\\uD83C[\\uDFFB-\\uDFFE])?))?)/g;\n};\n\nconst utils = (function () {\n\n function isJson(obj) {\n let result = obj && obj.constructor === {}.constructor;\n return result;\n }\n\n function cutFirstLine(source) {\n let result = source.substring(source.indexOf('\\n') + 2);\n return result;\n }\n\n let monthAbbr = [\n \"Jan\",\n \"Feb\",\n \"Mar\",\n \"Apr\",\n \"May\",\n \"Jun\",\n \"Jul\",\n \"Aug\",\n \"Sep\",\n \"Oct\",\n \"Nov\",\n \"Dec\"\n ];\n\n function unifyHoursOrMinutes(source) {\n if (source < 10) {\n return `0${source}`;\n }\n\n return source;\n }\n\n function unofficialEmojiExpression() {\n return /\\u2388/g;\n }\n\n return {\n\n toString (obj) {\n let result = \"\";\n if (obj instanceof Error) {\n do {\n result += obj.stack;\n if (obj.InnerError) {\n obj = obj.InnerError;\n result += \"\\n *** Inner error ***\\n\";\n } else {\n obj = null;\n }\n } while (obj)\n } else if (isJson(obj)) {\n result = JSON.stringify(obj);\n } else {\n result = obj;\n }\n return result;\n },\n\n timeConverter (timestamp) {\n let unixTimeStamp = parseInt(timestamp);\n const result = new Date(unixTimeStamp).toLocaleString();\n return result;\n },\n\n isJson,\n\n cutFirstLine,\n\n getStackTrace () {\n let error = new Error();\n let withoutErrorLine = cutFirstLine(error.stack);\n let result = cutFirstLine(withoutErrorLine);\n return result;\n },\n\n isIterable (obj) {\n if (!obj) {\n return false;\n }\n\n const result = typeof obj[Symbol.iterator] === 'function';\n return result;\n },\n\n addDays (date, days) {\n let hours = 24;\n let minutes = 60;\n let seconds = 60;\n let dateEpoch = date.getTime() + days * hours * minutes * seconds * 1000;\n let result = new Date(dateEpoch);\n return result;\n },\n\n addMinutes (date, minutes) {\n let seconds = 60;\n let dateEpoch = date.getTime() + minutes * seconds * 1000;\n let result = new Date(dateEpoch);\n return result;\n },\n\n dateTimeToString(source) {\n let result = `${source.getDate()} ${monthAbbr[source.getMonth()]} ${source.getFullYear()} ${unifyHoursOrMinutes(source.getHours())}:${unifyHoursOrMinutes(source.getMinutes())}`;\n return result;\n },\n\n toDateFromIso8651(source) {\n let number = Date.parse(source);\n if (isNaN(number)) {\n return null;\n }\n\n let result = new Date(number);\n return result;\n },\n\n toDateFromEpoch(epoch) {\n //let utcEpoch = epoch + 60 * 1000 * (new Date().getTimezoneOffset());\n //let result = new Date(utcEpoch);\n //return result;\n let result = new Date(epoch);\n return result;\n },\n\n clone(source) {\n let str = JSON.stringify(source);\n let result = JSON.parse(str);\n return result;\n },\n\n cutOffEmoji(input) {\n if (!input) {\n return input;\n }\n\n //let oldExpression = /\\p{Emoji}+/gu;\n let result = input.replaceAll(officialEmojiExpression(), '')\n .replaceAll(unofficialEmojiExpression(), '');\n return result;\n },\n\n cutEdges(str) {\n const result = str.substring(1, str.length - 1);\n return result;\n },\n\n getChromeVersion() {\n try {\n let result = /Chrome\\/([0-9.]+)/.exec(navigator.userAgent)[1];\n return result;\n } catch {\n return \"\";\n }\n },\n\n // brackets are not escaped by default https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/encodeuricomponent\n // they must be escaped\n customEncodeUri(source) {\n let result = encodeURIComponent(source);\n result = result.replaceAll('(', '%28');\n result = result.replaceAll(')', '%29');\n return result;\n },\n\n customDecodeUri(source) {\n let result = decodeURIComponent(source);\n return result;\n }\n\n };\n})();\n\nconst metadataFactory = (function () {\n\n const factoryResult = {\n\n create () {\n let result = {\n correlationId: crypto.randomUUID()\n };\n return result;\n }\n };\n\n return factoryResult;\n})();\n\nconst backendTopics = {\n export: \"export\",\n global: \"global\",\n tabMessage: \"tabMessage\",\n apiProxy: \"apiProxy\",\n linkedInProxy: \"linkedInProxy\",\n linkedInProxyV2: \"linkedInProxyV2\",\n linkedInProxyHeaders: \"linkedInProxyHeaders\",\n linkedInService: \"linkedInService\",\n linkedInVoyagerSpy: \"linkedInVoyagerSpy\",\n linkedInHeadersRewriter: \"linkedInHeadersRewriter\",\n salesNavigatorProxy: \"salesNavigatorProxy\",\n salesNavigatorService: \"salesNavigatorService\",\n salesNavigatorVoyagerSpy: \"salesNavigatorVoyagerSpy\",\n oauth: \"oauth\",\n logging: \"logging\",\n traceableRequests: \"traceableRequests\",\n scheduler: \"scheduler\",\n exportContacts: \"exportContacts\",\n system: \"system\",\n settings: \"settings\",\n localStorage: \"localStorage\",\n reliability: \"reliability\",\n campaignsRunner: \"campaignsRunner\",\n offscreen: \"offscreen\"\n};\n\nconst backendCommandsFactory = (function () {\n\n const factoryResult = {\n\n system: {\n\n createGetExtensionSettings (metadata) {\n let result = {\n target: backendTopics.system,\n command: \"getExtensionSettings\",\n args: {\n metadata\n },\n skipTracing: true\n };\n return result;\n }\n },\n\n settings: {\n\n createGetApplicationsSettings (metadata) {\n let result = {\n target: backendTopics.settings,\n command: \"getApplicationsSettings\",\n args: {\n metadata\n }\n };\n return result;\n }\n },\n\n apiProxy: {\n\n createCreateExportTag (name, type, exportMetadata, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"createExportTag\",\n args: {\n parameter: {\n name,\n type,\n metadata: exportMetadata\n },\n metadata\n }\n };\n return result;\n },\n\n createExportTaggedContacts (tagId, contacts, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"exportTaggedContacts\",\n args: {\n parameter: {\n tagId,\n contacts\n },\n metadata\n },\n };\n return result;\n },\n\n createAddMetadataToTag (tagId, exportMetadata, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"addMetadataToTag\",\n args: {\n parameter: {\n tagId,\n metadata: exportMetadata\n },\n metadata\n }\n };\n return result;\n },\n\n createSyncConversations (conversations, timestamp, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"syncConversations\",\n args: {\n parameter: {\n conversations,\n timestamp\n },\n metadata\n }\n };\n return result;\n },\n\n createSyncConnections (connections, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"syncConnections\",\n args: {\n parameter: {\n connections\n },\n metadata\n }\n };\n return result;\n },\n\n createSyncContact (contactId, contact, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"syncContact\",\n args: {\n parameter: {\n contactId,\n contact\n },\n metadata\n }\n };\n return result;\n },\n\n createGetNextOperations (metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"getNextOperations\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createGetOperation (campaignExecutionId, stepNumber, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"getOperation\",\n args: {\n parameter: {\n campaignExecutionId,\n stepNumber\n },\n metadata\n }\n };\n return result;\n },\n\n createGetWithdrawOperations (metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"getWithdrawOperations\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createStepExecuted (campaignId, campaignExecutionId, stepNumber, actionResult, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"stepExecuted\",\n args: {\n parameter: {\n campaignId,\n campaignExecutionId,\n stepNumber,\n actionResult\n },\n metadata\n }\n };\n return result;\n },\n\n createStepError (campaignId, campaignExecutionId, stepNumber, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"stepExecutionError\",\n args: {\n parameter: {\n campaignId,\n campaignExecutionId,\n stepNumber\n },\n metadata\n }\n };\n return result;\n },\n\n createStepSkipped (campaignId, campaignExecutionId, stepNumber, reason, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"stepSkipped\",\n args: {\n parameter: {\n campaignId,\n campaignExecutionId,\n stepNumber,\n reason\n },\n metadata\n }\n };\n return result;\n },\n\n createStepWithdrawn (campaignId, campaignExecutionId, stepNumber, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"stepWithdrawn\",\n args: {\n parameter: {\n campaignId,\n campaignExecutionId,\n stepNumber\n },\n metadata\n }\n };\n return result;\n },\n\n createStepWithdrawError (campaignId, campaignExecutionId, stepNumber, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"stepWithdrawError\",\n args: {\n parameter: {\n campaignId,\n campaignExecutionId,\n stepNumber\n },\n metadata\n }\n };\n return result;\n },\n\n createReportExceedLimit (operationType, code, campaignId, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"reportExceedLimit\",\n args: {\n parameter: {\n operationType,\n code,\n campaignId\n },\n metadata\n }\n };\n return result;\n },\n\n createGetMyProfile (metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"getMyProfile\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createAddLinkedInProfile (linkedInProfile, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"addLinkedInProfile\",\n args: {\n parameter: {\n linkedInProfile\n },\n metadata\n }\n };\n return result;\n },\n\n createGetLinkedInProfiles (metadata) {\n const result = {\n target: backendTopics.apiProxy,\n command: \"getLinkedInProfiles\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createGetWorkingHours (metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"getWorkingHours\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createSetRunningActivities (state, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"setRunningActivities\",\n args: {\n parameter: {\n state\n },\n metadata\n }\n\n };\n return result;\n },\n\n createRefreshCampaignExecutions (metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"refreshCampaignExecutions\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createEndAutomationRun (metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"endAutomationRun\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createExchangeAuthorizationCode (code, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"exchangeAuthorizationCode\",\n args: {\n parameter: {\n code\n },\n metadata\n }\n };\n return result;\n },\n\n createSwitchToWorkspace (linkedInProfileId, metadata) {\n const result = {\n target: backendTopics.apiProxy,\n command: \"switchToWorkspace\",\n args: {\n parameter: {\n linkedInProfileId\n },\n metadata\n }\n };\n return result;\n },\n\n createRevokeToken (metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"revokeToken\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createGetRecentExports (metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"getRecentExports\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createReportLogEntry (logEventId, severity, message, args, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"reportLogEntry\",\n args: {\n parameter: {\n logEventId,\n severity,\n message,\n args\n },\n metadata\n },\n skipTracing: true\n };\n return result;\n },\n\n createRefreshAuthTokens (metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"refreshAuthTokens\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createGetAccessToken (metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"getAccessToken\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createIsCompatibleWithCurrentExtension (metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"isCompatibleWithCurrentExtension\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createExtensionDetected (metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"extensionDetected\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createSetWorkingHours (workingHours, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"setWorkingHours\",\n args: {\n parameter: {\n workingHours\n },\n metadata\n }\n };\n return result;\n },\n\n createSignInUnderTeamMember (personaId, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"signInUnderTeamMember\",\n args: {\n parameter: {\n personaId\n },\n metadata\n }\n };\n return result;\n },\n\n createSignOutUnderTeamMember (metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"signOutUnderTeamMember\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createGetCurrentDateTime (metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"getCurrentDateTime\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createCreateLinkedInTrackingId (uuid, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"createLinkedInTrackingId\",\n args: {\n parameter: {\n uuid\n },\n metadata\n }\n };\n return result;\n },\n\n createReportCustomMessageTooLong (campaignId, campaignExecutionId, stepNumber, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"reportCustomMessageTooLong\",\n args: {\n parameter: {\n campaignId,\n campaignExecutionId,\n stepNumber\n },\n metadata\n }\n };\n return result;\n },\n\n backendAutomation: {\n\n createSaveLinkedinHeaders (linkedIn, salesNavigator, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"saveLinkedinHeaders\",\n args: {\n parameter: {\n linkedIn,\n salesNavigator\n },\n metadata\n }\n };\n return result;\n },\n\n createGetCurrentProfile (linkedInHeaders, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"getCurrentLinkedInProfile\",\n args: {\n parameter: {\n linkedIn: linkedInHeaders\n },\n metadata\n }\n };\n return result;\n },\n\n createGetLinkedInContactsFromSearchPage (searchRequest, referrer, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"getLinkedInContactsFromSearchPage\",\n args: {\n parameter: {\n searchRequest,\n referrer\n },\n metadata\n }\n };\n return result;\n },\n\n createGetLinkedInContactsFromGroupPage (searchRequest, typeaheadQuery, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"getLinkedInContactsFromGroupPage\",\n args: {\n parameter: {\n searchRequest,\n typeaheadQuery\n },\n metadata\n }\n };\n return result;\n },\n\n createGetSalesNavigatorContactsFromSearchPage (searchRequest, referer, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"getSalesNavigatorContactsFromSearchPage\",\n args: {\n parameter: {\n searchRequest,\n referer\n },\n metadata\n }\n };\n return result;\n },\n\n createGetSalesNavigatorContactsFromLeadsList (searchRequest, referer, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"getSalesNavigatorContactsFromLeadsList\",\n args: {\n parameter: {\n searchRequest,\n referer\n },\n metadata\n }\n };\n return result;\n },\n\n createGetContact (id, metadata) {\n let result = {\n target: backendTopics.apiProxy,\n command: \"getContact\",\n args: {\n parameter: {\n id\n },\n metadata\n }\n };\n return result;\n }\n }\n },\n\n linkedInProxy: {\n\n authorize: {\n V2: {\n\n createTypeInConversation (conversationId, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"typeInConversation\",\n args: {\n parameter: {\n conversationId,\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createGetContactActions (id, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"getContactActions\",\n args: {\n parameter: {\n id,\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createGetConnections (start, count, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"getConnections\",\n args: {\n parameter: {\n start,\n count,\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createGetCurrentProfile (headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"getCurrentProfile\",\n args: {\n parameter: {\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createGetConversationEventsByCursor (selfEntityId, conversationId, prevCursor, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"getConversationEventsByCursor\",\n args: {\n parameter: {\n selfEntityId,\n conversationId,\n prevCursor,\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createUnfollowContact (entityId, publicIdentifier, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"unfollowContact\",\n args: {\n parameter: {\n entityId,\n publicIdentifier,\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createFollowContactTopPosts (entityId, publicIdentifier, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"followContactTopPosts\",\n args: {\n parameter: {\n entityId,\n publicIdentifier,\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createFollowContactAllPosts (entityId, publicIdentifier, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"followContactAllPosts\",\n args: {\n parameter: {\n entityId,\n publicIdentifier,\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createWithdrawInvitation (invitationId, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"withdrawInvitation\",\n args: {\n parameter: {\n invitationId,\n headers,\n },\n metadata\n }\n };\n return result;\n },\n\n createMarkConversationAsRead (conversationId, selfEntityId, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"markConversationAsRead\",\n args: {\n parameter: {\n conversationId,\n selfEntityId,\n headers,\n },\n metadata\n }\n };\n return result;\n },\n\n createGetContactsFromSearchPage (searchRequest, referrer, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"getContactsFromSearchPage\",\n args: {\n parameter: {\n searchRequest,\n referrer,\n headers,\n },\n metadata\n }\n };\n return result;\n },\n\n createGetContactsFromGroupPage (searchRequest, typeaheadQuery, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"getContactsFromGroupPage\",\n args: {\n parameter: {\n searchRequest,\n typeaheadQuery,\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createGetContactLatestJobs (entityId, publicIdentifier, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"getContactLatestJobs\",\n args: {\n parameter: {\n entityId,\n publicIdentifier,\n headers,\n },\n metadata\n }\n };\n return result;\n },\n\n createGetContactMiniProfile (id, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"getContactMiniProfile\",\n args: {\n parameter: {\n id,\n headers,\n },\n metadata\n }\n };\n return result;\n },\n\n createReactOnContactPost (postEntityId, postType, publicIdentifier, reaction, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"reactOnContactPost\",\n args: {\n parameter: {\n postEntityId,\n postType,\n publicIdentifier,\n reaction,\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createGetContactRecentPosts (entityId, publicIdentifier, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"getContactRecentPosts\",\n args: {\n parameter: {\n entityId,\n publicIdentifier,\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createCreateConversation (selfEntityId, recipientEntityId, message, trackingId, recipientId, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"createConversation\",\n args: {\n parameter: {\n selfEntityId,\n recipientEntityId,\n message,\n trackingId,\n recipientId,\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createGetConversationsByLastUpdatedBefore (selfEntityId, createdBefore, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"getConversationsByLastUpdatedBefore\",\n args: {\n parameter: {\n selfEntityId,\n createdBefore,\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createGetConversationsByCursor (selfEntityId, nextCursor, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"getConversationsByCursor\",\n args: {\n parameter: {\n selfEntityId,\n nextCursor,\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createCreateInvitation (entityId, message, publicIdentifier, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"createInvitation\",\n args: {\n parameter: {\n entityId,\n message,\n publicIdentifier,\n headers,\n },\n metadata\n }\n };\n return result;\n },\n\n createCreateConversationEvent (selfEntityId, conversationId, message, trackingId, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"createConversationEvent\",\n args: {\n parameter: {\n selfEntityId,\n conversationId,\n message,\n trackingId,\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createGetConversationRecentEvents (selfEntityId, conversationId, deliveredAt, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"getConversationRecentEvents\",\n args: {\n parameter: {\n selfEntityId,\n conversationId,\n deliveredAt,\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createGetFirstContactSkills (publicIdentifier, entityId, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"getFirstContactSkills\",\n args: {\n parameter: {\n publicIdentifier,\n entityId,\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createGetNextContactSkills (listComponent, includeMetadata, start, count, publicIdentifier, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"getNextContactSkills\",\n args: {\n parameter: {\n listComponent,\n includeMetadata,\n start,\n count,\n publicIdentifier,\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createEndorseContactSkill (publicIdentifier, profileEndorsedSkill, headers, metadata) {\n let result = {\n target: backendTopics.linkedInProxyV2,\n command: \"endorseContactSkill\",\n args: {\n parameter: {\n publicIdentifier,\n profileEndorsedSkill,\n headers\n },\n metadata\n }\n };\n return result;\n }\n },\n },\n\n headers: {\n\n createGetLastLinkedInRequestHeaders (metadata) {\n let result = {\n target: backendTopics.linkedInProxyHeaders,\n command: \"getLastLinkedInRequestHeaders\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createGetLastSalesNavigatorRequestHeaders (metadata) {\n let result = {\n target: backendTopics.linkedInProxyHeaders,\n command: \"getLastSalesNavigatorRequestHeaders\",\n args: {\n metadata\n }\n };\n return result;\n }\n }\n\n },\n\n linkedInService: {\n\n createGetContactsFromSearchPage (searchRequest, referrer, metadata) {\n let result = {\n target: backendTopics.linkedInService,\n command: \"getContactsFromSearchPage\",\n args: {\n parameter: {\n searchRequest,\n referrer\n },\n metadata\n }\n };\n return result;\n },\n\n createGetContactsFromGroupPage (searchRequest, typeaheadQuery, metadata) {\n let result = {\n target: backendTopics.linkedInService,\n command: \"getContactsFromGroupPage\",\n args: {\n parameter: {\n searchRequest,\n typeaheadQuery\n },\n metadata\n }\n };\n return result;\n },\n\n createReadNewConnections (connectedAfter, metadata) {\n let result = {\n target: backendTopics.linkedInService,\n command: \"readNewConnections\",\n args: {\n parameter: {\n connectedAfter\n },\n metadata\n }\n };\n return result;\n },\n\n createReadNewConversations (createdAfter, createdBefore, metadata) {\n let result = {\n target: backendTopics.linkedInService,\n command: \"readNewConversations\",\n args: {\n parameter: {\n createdAfter,\n createdBefore\n },\n metadata\n }\n };\n return result;\n },\n\n createSendMessage (publicIdentifier, entityId, message, metadata) {\n let result = {\n target: backendTopics.linkedInService,\n command: \"sendMessage\",\n args: {\n parameter: {\n publicIdentifier,\n entityId,\n message\n },\n metadata\n }\n };\n return result;\n },\n\n createConnect (publicIdentifier, entityId, message, metadata) {\n let result = {\n target: backendTopics.linkedInService,\n command: \"connect\",\n args: {\n parameter: {\n publicIdentifier,\n entityId,\n message\n },\n metadata\n }\n };\n return result;\n },\n\n createWithdraw (invitationId, metadata) {\n let result = {\n target: backendTopics.linkedInService,\n command: \"withdraw\",\n args: {\n parameter: {\n invitationId\n },\n metadata\n }\n };\n return result;\n },\n\n createGetContactFullProfile (id, metadata) {\n let result = {\n target: backendTopics.linkedInService,\n command: \"getContactFullProfile\",\n args: {\n parameter: {\n id\n },\n metadata\n }\n };\n return result;\n },\n\n createGetCurrentProfile (metadata) {\n let result = {\n target: backendTopics.linkedInService,\n command: \"getCurrentProfile\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createFollow (publicIdentifier, entityId, metadata) {\n let result = {\n target: backendTopics.linkedInService,\n command: \"follow\",\n args: {\n parameter: {\n publicIdentifier,\n entityId\n },\n metadata\n }\n };\n return result;\n },\n\n createReactOnRecentContactPost (publicIdentifier, entityId, reaction, metadata) {\n let result = {\n target: backendTopics.linkedInService,\n command: \"reactOnRecentContactPost\",\n args: {\n parameter: {\n publicIdentifier,\n reaction,\n entityId\n },\n metadata\n }\n };\n return result;\n },\n\n createEndorseMostPopularContactSkill (publicIdentifier, entityId, metadata) {\n let result = {\n target: backendTopics.linkedInService,\n command: \"endorseMostPopularContactSkill\",\n args: {\n parameter: {\n publicIdentifier,\n entityId\n },\n metadata\n }\n };\n return result;\n },\n\n createNormalize (miniProfile, metadata) {\n let result = {\n target: backendTopics.linkedInService,\n command: \"normalize\",\n args: {\n parameter: {\n miniProfile\n },\n metadata\n }\n };\n return result;\n },\n\n },\n\n linkedInVoyagerSpy: {\n\n createResetCache (metadata) {\n let result = {\n target: backendTopics.linkedInVoyagerSpy,\n command: \"resetCache\",\n args: {\n metadata\n }\n };\n return result;\n }\n },\n\n linkedInHeadersRewriter: {\n\n createSetReferer (referrer, metadata) {\n let result = {\n target: backendTopics.linkedInHeadersRewriter,\n command: \"setReferer\",\n args: {\n parameter: {\n referrer\n },\n metadata\n }\n };\n return result;\n },\n\n createResetReferer (metadata) {\n let result = {\n target: backendTopics.linkedInHeadersRewriter,\n command: \"resetReferer\",\n args: {\n metadata\n }\n };\n return result;\n }\n\n },\n\n salesNavigatorProxy: {\n\n authorize: {\n\n createGetContactsFromSearchPage (searchRequest, referer, headers, metadata) {\n let result = {\n target: backendTopics.salesNavigatorProxy,\n command: \"getContactsFromSearchPage\",\n args: {\n parameter: {\n searchRequest,\n referer,\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createGetContactsFromLeadsList (searchRequest, referer, headers, metadata) {\n let result = {\n target: backendTopics.salesNavigatorProxy,\n command: \"getContactsFromLeadsList\",\n args: {\n parameter: {\n searchRequest,\n referer,\n headers\n },\n metadata\n }\n };\n return result;\n }\n\n }\n\n },\n\n salesNavigatorService: {\n\n createGetContactsFromSearchPage (searchRequest, referer, metadata) {\n let result = {\n target: backendTopics.salesNavigatorService,\n command: \"getContactsFromSearchPage\",\n args: {\n parameter: {\n searchRequest,\n referer\n },\n metadata\n }\n };\n return result;\n },\n\n createGetContactsFromLeadsList (searchRequest, referer, metadata) {\n let result = {\n target: backendTopics.salesNavigatorService,\n command: \"getContactsFromLeadsList\",\n args: {\n parameter: {\n searchRequest,\n referer\n },\n metadata\n }\n };\n return result;\n },\n },\n\n auth: {\n\n createSignOut (metadata) {\n let result = {\n target: backendTopics.oauth,\n command: \"signOut\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createGetSignInUri (state, referrer, metadata) {\n let result = {\n target: backendTopics.oauth,\n command: \"getSigninUri\",\n args: {\n parameter: {\n state,\n referrer,\n },\n metadata\n }\n };\n return result;\n }\n\n },\n\n localStorage: {\n\n createGetSnailyProfile (metadata) {\n let result = {\n target: backendTopics.localStorage,\n command: \"getSnailyProfile\",\n args: {\n metadata,\n checkSignedInLinkedInUser: true\n }\n };\n return result;\n },\n\n createGetLatestKnownSnailyProfile (metadata) {\n let result = {\n target: backendTopics.localStorage,\n command: \"getLatestKnownSnailyProfile\",\n args: {\n metadata,\n checkSignedInLinkedInUser: false\n }\n };\n return result;\n },\n\n createGetUserLogLevel (metadata) {\n let result = {\n target: backendTopics.localStorage,\n command: \"getUserLogLevel\",\n args: {\n metadata\n },\n skipTracing: true\n };\n return result;\n },\n\n createGetLinkedInProfile (metadata) {\n let result = {\n target: backendTopics.localStorage,\n command: \"getLinkedInProfile\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createGetSignedInPersonaJwtTokens (metadata) {\n let result = {\n target: backendTopics.localStorage,\n command: \"getSignedInPersonaJwtTokens\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createGetSignedInLinkedInUser (metadata) {\n let result = {\n target: backendTopics.localStorage,\n command: \"getSignedInLinkedInUser\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createSaveSignedInPersonaJwtTokens (jwtTokens, metadata) {\n let result = {\n target: backendTopics.localStorage,\n command: \"saveSignedInPersonaJwtTokens\",\n args: {\n parameter: {\n jwtTokens\n },\n metadata\n }\n };\n return result;\n },\n\n createDeleteSignedInPersonaJwtTokens (metadata) {\n let result = {\n target: backendTopics.localStorage,\n command: \"deleteSignedInPersonaJwtTokens\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createGetImpersonatedPersonaJwtTokens (metadata) {\n let result = {\n target: backendTopics.localStorage,\n command: \"getImpersonatedPersonaJwtTokens\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createSaveImpersonatedPersonaJwtTokens (jwtTokens, metadata) {\n let result = {\n target: backendTopics.localStorage,\n command: \"saveImpersonatedPersonaJwtTokens\",\n args: {\n parameter: {\n jwtTokens\n },\n metadata\n }\n };\n return result;\n },\n\n createDeleteImpersonatedPersonaJwtTokens (metadata) {\n let result = {\n target: backendTopics.localStorage,\n command: \"deleteImpersonatedPersonaJwtTokens\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createGetPendingCommands (metadata) {\n let result = {\n target: backendTopics.localStorage,\n command: \"getPendingCommands\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createSavePendingCommands (commands, metadata) {\n let result = {\n target: backendTopics.localStorage,\n command: \"savePendingCommands\",\n args: {\n parameter: {\n commands\n },\n metadata\n }\n };\n return result;\n },\n\n createDeletePendingCommands (metadata) {\n let result = {\n target: backendTopics.localStorage,\n command: \"deletePendingCommands\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createGetLinkedInHeaders (metadata) {\n let result = {\n target: backendTopics.localStorage,\n command: \"getLinkedInHeaders\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createSaveLinkedInHeaders (headers, metadata) {\n let result = {\n target: backendTopics.localStorage,\n command: \"saveLinkedInHeaders\",\n args: {\n parameter: {\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n createGetSalesNavigatorHeaders (metadata) {\n let result = {\n target: backendTopics.localStorage,\n command: \"getSalesNavigatorHeaders\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createSaveSalesNavigatorHeaders (headers, metadata) {\n let result = {\n target: backendTopics.localStorage,\n command: \"saveSalesNavigatorHeaders\",\n args: {\n parameter: {\n headers\n },\n metadata\n }\n };\n return result;\n },\n\n },\n\n automation: {\n\n createGetExportState (metadata) {\n let result = {\n target: backendTopics.exportContacts,\n command: \"getState\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createStartCsvExport (type, publicIdentifiers, metadata) {\n let result = {\n target: backendTopics.exportContacts,\n command: \"start\",\n args: {\n parameter: {\n type,\n details: {\n publicIdentifiers\n }\n },\n metadata\n }\n };\n return result;\n },\n\n createStartCsvContactsExport (type, contacts, metadata) {\n let result = {\n target: backendTopics.exportContacts,\n command: \"start\",\n args: {\n parameter: {\n type,\n details: {\n contacts\n }\n },\n metadata\n }\n };\n return result;\n },\n\n createStartExportContactsFromUrl (tabId, type, url, metadata) {\n let result = {\n target: backendTopics.exportContacts,\n command: \"start\",\n args: {\n parameter: {\n tabId,\n type,\n details: {\n url\n }\n },\n metadata\n }\n };\n return result;\n },\n\n createStopExport (metadata) {\n let result = {\n target: backendTopics.exportContacts,\n command: \"stop\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createClearExport (metadata) {\n let result = {\n target: backendTopics.exportContacts,\n command: \"clear\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createGetExportHref (exportId, metadata) {\n let result = {\n target: backendTopics.exportContacts,\n command: \"getExportHref\",\n args: {\n parameter: {\n exportId\n },\n metadata\n }\n };\n return result;\n }\n\n },\n\n browser: {\n\n createGetTabInfo (tabId, metadata) {\n let result = {\n target: backendTopics.global,\n command: 'getTabInfoAsync',\n args: {\n parameter: {\n tabId\n },\n metadata\n }\n };\n return result;\n },\n\n createTabMessage (tabId, message, metadata) {\n let result = {\n target: backendTopics.tabMessage,\n command: \"sendMessage\",\n args: {\n parameter: {\n tabId,\n message\n },\n metadata\n }\n };\n return result;\n }\n },\n\n logging: {\n\n createLogError (logEntryId, parameters, metadata) {\n let result = {\n target: backendTopics.logging,\n command: \"logError\",\n args: {\n parameter: {\n logEntryId,\n parameters\n },\n metadata\n },\n skipTracing: true\n };\n return result;\n },\n\n createLogTrace (logEntryId, parameters, metadata) {\n let result = {\n target: backendTopics.logging,\n command: \"logTrace\",\n args: {\n parameter: {\n logEntryId,\n parameters\n },\n metadata\n },\n skipTracing: true\n };\n return result;\n },\n\n createLogInformation (logEntryId, parameters, metadata) {\n let result = {\n target: backendTopics.logging,\n command: \"logInformation\",\n args: {\n parameter: {\n logEntryId,\n parameters\n },\n metadata\n },\n skipTracing: true\n };\n return result;\n },\n\n createLogWaring (logEntryId, parameters, metadata) {\n let result = {\n target: backendTopics.logging,\n command: \"logWarning\",\n args: {\n parameter: {\n logEntryId,\n parameters\n },\n metadata\n },\n skipTracing: true\n };\n return result;\n }\n },\n\n traceable: {\n\n createHttpRequest (uri, requestInit, metadata) {\n let result = {\n target: backendTopics.traceableRequests,\n command: \"httpRequest\",\n args: {\n parameter: {\n uri,\n requestInit\n },\n metadata\n },\n skipTracing: true\n };\n return result;\n }\n\n },\n\n reliability: {\n\n createResendPendingCommandsIfAny (metadata) {\n let result = {\n target: backendTopics.reliability,\n command: \"resendPendingCommandsIfAny\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createReliablePublish (command, metadata) {\n let result = {\n target: backendTopics.reliability,\n command: \"reliablePublish\",\n args: {\n parameter: {\n command\n },\n metadata\n }\n };\n return result;\n }\n },\n\n campaignsRunner: {\n\n createIsInWorkingHours (metadata) {\n let result = {\n target: backendTopics.campaignsRunner,\n command: \"isInWorkingHours\",\n args: {\n metadata\n }\n };\n return result;\n },\n },\n\n // these commands are needed only in development\n offScreen: {\n\n isUpdateAvailable (metadata) {\n let result = {\n target: backendTopics.offscreen,\n command: \"isUpdateAvailable\",\n args: {\n metadata\n }\n };\n return result;\n },\n\n createUpdateAvailable (metadata) {\n let result = {\n target: backendTopics.offscreen,\n command: \"updateAvailable\",\n args: {\n metadata\n }\n };\n return result;\n },\n }\n };\n\n return factoryResult;\n\n})();\n\nclass ExtensionRuntimeError extends SnailyError {\n\n constructor(message, request, metadata) {\n super(message, request, metadata);\n this.name = \"ExtensionRuntimeError\";\n\n // noinspection JSUnresolvedVariable\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ExtensionRuntimeError);\n }\n }\n\n toString() {\n let result = `${super.toString()}; Request: ${JSON.stringify(this.request)}`;\n return result;\n }\n}\n\n/**\n * This error happens when there is no handler for a message.\n * It could happens when popup is closed and backendBroker fires an event.\n */\nclass MissingReceiverExtensionRuntimeError extends ExtensionRuntimeError {\n\n constructor(message, request, metadata) {\n super(message, request, metadata);\n this.name = \"MissingReceiverExtensionRuntimeError\";\n\n // noinspection JSUnresolvedVariable\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, MissingReceiverExtensionRuntimeError);\n }\n }\n\n get skipLogging() {\n return true;\n }\n}\n\n/**\n * This error happens when handler ends execution before sendResponse is called.\n * It is most likely improper implementation , see details https://developer.chrome.com/docs/extensions/mv2/messaging/\n */\n\nclass PortClosedExtensionRuntimeError extends ExtensionRuntimeError {\n\n constructor(message, request, metadata) {\n super(message, request, metadata);\n this.name = \"PortClosedExtensionRuntimeError\";\n\n // noinspection JSUnresolvedVariable\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, PortClosedExtensionRuntimeError);\n }\n }\n\n get skipLogging() {\n return true;\n }\n}\n\nconst runtimeErrorsFactory = (function () {\n\n const factory = {\n\n create (message, stackTrace, request, metadata) {\n let result;\n if (message === \"Could not establish connection. Receiving end does not exist.\") {\n result = new MissingReceiverExtensionRuntimeError(message, request, metadata);\n } else if (message === \"The message port closed before a response was received.\") {\n result = new PortClosedExtensionRuntimeError(message, request, metadata);\n } else {\n result = new ExtensionRuntimeError(message, request, metadata);\n }\n\n if (stackTrace) {\n result.stack += `\\n Inner async invocation \\n ${stackTrace} \\n`;\n }\n return result;\n }\n };\n return factory;\n\n})();\n\nclass BadGatewayError extends SnailyError {\n\n constructor(message, metadata) {\n super(message, metadata);\n this.name = \"BadGatewayError\";\n\n // noinspection JSUnresolvedVariable\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, BadGatewayError);\n }\n }\n\n get skipLogging() {\n return true;\n }\n\n}\n\nclass NotAuthenticatedError extends SnailyError {\n\n constructor(message, metadata) {\n super(message, metadata);\n this.name = \"NotAuthenticatedError\";\n\n // noinspection JSUnresolvedVariable\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, NotAuthenticatedError);\n }\n }\n\n}\n\nclass NotAuthorizedError extends SnailyError {\n\n constructor(message, metadata) {\n super(message, metadata);\n this.name = \"NotAuthorizedError\";\n\n // noinspection JSUnresolvedVariable\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, NotAuthorizedError);\n }\n }\n\n}\n\nclass BadRequestError extends SnailyError {\n\n constructor(message, metadata) {\n super(message, metadata);\n this.name = \"BadRequestError\";\n\n // noinspection JSUnresolvedVariable\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, BadRequestError);\n }\n }\n\n}\n\nclass ProxyAuthenticationRequiredError extends SnailyError {\n\n constructor(message, metadata) {\n super(message, metadata);\n this.name = \"ProxyAuthenticationRequiredError\";\n\n // noinspection JSUnresolvedVariable\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ProxyAuthenticationRequiredError);\n }\n }\n\n}\n\nclass UnprocessableEntityError extends SnailyError {\n\n constructor(message, metadata) {\n super(message, metadata);\n this.name = \"UnprocessableEntityError\";\n\n // noinspection JSUnresolvedVariable\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, UnprocessableEntityError);\n }\n }\n\n}\n\nclass EmptySearchPageError extends SnailyError {\n\n constructor(response, metadata) {\n super(response.statusText, metadata);\n this.name = \"EmptySearchPageError\";\n this.url = response.url;\n\n // noinspection JSUnresolvedVariable\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, EmptySearchPageError);\n }\n }\n}\n\nclass OldExtensionError extends SnailyError {\n\n constructor(message, metadata) {\n super(message, metadata);\n this.name = \"OldExtensionError\";\n\n // noinspection JSUnresolvedVariable\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, OldExtensionError);\n }\n }\n\n}\n\nclass SnailySignInRequiredError extends SnailyError {\n\n constructor(body, metadata) {\n super(body, metadata);\n this.name = \"SnailySignInRequiredError\";\n\n // noinspection JSUnresolvedVariable\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, SnailySignInRequiredError);\n }\n }\n\n}\n\nclass LinkedInSignInRequiredError extends SnailyError {\n\n constructor(message, metadata) {\n super(message, metadata);\n this.name = \"LinkedInSignInRequiredError\";\n\n // noinspection JSUnresolvedVariable\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, LinkedInSignInRequiredError);\n }\n }\n\n}\n\nclass LinkedInProfileAlreadyUsedError extends SnailyError {\n\n constructor(message, metadata) {\n super(message, metadata);\n this.name = \"LinkedInProfileAlreadyUsedError\";\n\n // noinspection JSUnresolvedVariable\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, LinkedInProfileAlreadyUsedError);\n }\n }\n\n get skipLogging() {\n return true;\n }\n\n}\n\nclass InvalidOperationError extends SnailyError {\n\n constructor(message, metadata) {\n super(message, metadata);\n this.name = \"InvalidOperationError\";\n\n // noinspection JSUnresolvedVariable\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, InvalidOperationError);\n }\n }\n \n}\n\nconst errorsFactory = (function () {\n\n const result = {\n\n create (input, innerStackTrace, metadata) {\n\n let result;\n switch (input.name) {\n\n case 'BadGatewayError':\n result = new BadGatewayError(input.message, metadata);\n break;\n\n case 'NotAuthenticatedError':\n result = new NotAuthenticatedError(input.message, metadata);\n break;\n\n case 'NotAuthorizedError':\n result = new NotAuthorizedError(input.message, metadata);\n break;\n\n case 'BadRequestError':\n result = new BadRequestError(input.message, metadata);\n break;\n\n case 'ProxyAuthenticationRequiredError':\n result = new ProxyAuthenticationRequiredError(input.message, metadata);\n break;\n\n case 'UnprocessableEntityError':\n result = new UnprocessableEntityError(input.message, metadata);\n break;\n\n case 'EmptySearchPageError':\n result = new EmptySearchPageError(input.message, metadata);\n break;\n\n case 'MissingReceiverExtensionRuntimeError':\n result = new MissingReceiverExtensionRuntimeError(input.message, metadata);\n break;\n\n case 'PortClosedExtensionRuntimeError':\n result = new PortClosedExtensionRuntimeError(input.message, metadata);\n break;\n\n case 'ExtensionRuntimeError':\n result = new ExtensionRuntimeError(input.message, metadata);\n break;\n\n case 'OldExtensionError':\n result = new OldExtensionError(input.message, metadata);\n break;\n\n case 'SnailySignInRequiredError':\n result = new SnailySignInRequiredError(input.message, metadata);\n break;\n\n case 'LinkedInSignInRequiredError':\n result = new LinkedInSignInRequiredError(input.message, metadata);\n break;\n\n case 'LinkedInProfileAlreadyUsedError':\n result = new LinkedInProfileAlreadyUsedError(input.message, metadata);\n break;\n\n default:\n result = new InvalidOperationError(input.message, metadata);\n }\n\n result.stack += `\\n Original invocation ${input.stack}\\n`;\n if (innerStackTrace) {\n result.stack += `\\n Inner async invocation \\n ${innerStackTrace} \\n`;\n }\n\n return result;\n },\n\n };\n return result;\n\n})();\n\nclass SnailyPromise extends Promise {\n\n constructor(callback) {\n let temp = {};\n Error.captureStackTrace(temp, SnailyPromise);\n const stackTrace = utils.cutFirstLine(temp.stack);\n\n const wrappedCallback = function (resolve, reject) {\n try {\n callback(resolve, function (e) {\n if (utils.isJson(e)) {\n if (e.stack) {\n e.stack = e.stack + \"\\n\" + stackTrace + \"\\n\";\n } else {\n e.stack = stackTrace;\n }\n }\n reject(e);\n });\n } catch (exp) {\n //ToDo;\n throw exp;\n }\n };\n super(wrappedCallback);\n }\n\n catch(...args) {\n let data = super.catch(...args);\n return data;\n }\n}\n\nclass ClientError extends SnailyError {\n\n constructor(message, metadata) {\n super(message, metadata);\n this.name = \"ClientError\";\n\n // noinspection JSUnresolvedVariable\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ClientError);\n }\n }\n}\n\nclass ChromeRuntimeAdapter {\n async sendMessage(command) {\n let innerStackTrace = utils.getStackTrace();\n const result = await new SnailyPromise(function (resolve, reject) {\n try {\n chrome.runtime.sendMessage(\n command,\n function (response) {\n let error;\n if (chrome.runtime.lastError) {\n error = runtimeErrorsFactory.create(chrome.runtime.lastError.message, innerStackTrace, command, command.args.metadata);\n reject(error);\n //need to distinguish null and undefined\n } else if (response) {\n //ToDo: might be something more explicit\n if (response.error) {\n error = errorsFactory.create(response.error, innerStackTrace, command.args.metadata);\n reject(error);\n } else {\n resolve(response);\n }\n } else {\n resolve(null);\n }\n });\n } catch (exp) {\n //this could happens when extension is reloaded\n const error = runtimeErrorsFactory.create(exp.message, innerStackTrace, command, command.args.metadata);\n reject(error);\n }\n });\n return result;\n }\n\n async sendTabMessage(args) {\n let innerStackTrace = utils.getStackTrace();\n const result = await new SnailyPromise(function (resolve, reject) {\n try {\n chrome.tabs.sendMessage(args.parameter.tabId,\n args.parameter.message,\n function (response) {\n //need to distinguish null and undefined\n if (!chrome.runtime.lastError) {\n //ToDo: might be something more explicit\n if (response && response.error) {\n\n const innerError = new Error(response.error.message);\n innerError.stack = response.error.stack;\n let errorMessage = utils.toString(innerError);\n\n let clientError = new ClientError(errorMessage, args, args.metadata);\n clientError.stack += `\\n Inner Error \\n ${innerStackTrace} \\n`;\n reject(clientError);\n\n } else {\n resolve(response);\n }\n } else {\n let error = runtimeErrorsFactory.create(chrome.runtime.lastError.message, innerStackTrace, args, args.metadata);\n reject(error);\n }\n });\n } catch (exp) {\n //this could happens when extension is reloaded\n const error = runtimeErrorsFactory.create(exp.message, innerStackTrace, args, args.metadata);\n reject(error);\n }\n });\n return result;\n }\n\n async sendExtensionMessage(extensionId, message) {\n let innerStackTrace = utils.getStackTrace();\n const result = await new SnailyPromise(function (resolve, reject) {\n try {\n chrome.runtime.sendMessage(\n extensionId,\n message,\n function (response) {\n let error;\n if (chrome.runtime.lastError) {\n error = runtimeErrorsFactory.create(chrome.runtime.lastError.message, innerStackTrace, message, message.args.metadata);\n reject(error);\n //need to distinguish null and undefined\n } else if (response !== undefined && response !== null) {\n //ToDo: might be something more explicit\n if (response.error) {\n error = errorsFactory.create(response.error, innerStackTrace, message.args.metadata);\n reject(error);\n } else {\n resolve(response);\n }\n } else {\n resolve(null);\n }\n });\n } catch (exp) {\n //this could happens when extension is reloaded\n const error = runtimeErrorsFactory.create(exp.message, innerStackTrace, message, message.args.metadata);\n reject(error);\n }\n });\n return result;\n }\n\n async createTab(url) {\n let tabInfo = {\n url\n };\n let result = await new SnailyPromise(function (resolve) {\n chrome.tabs.create(tabInfo,\n function (tab) {\n resolve(tab);\n });\n });\n return result;\n }\n\n async clearAlarm(name) {\n let result = await new SnailyPromise(function (resolve) {\n chrome.alarms.clear(name,\n function (wasCleared) {\n resolve(wasCleared);\n });\n });\n return result;\n }\n\n async getAlarm(name) {\n const result = await new SnailyPromise(function (resolve) {\n chrome.alarms.get(name,\n function (alarm) {\n resolve(alarm);\n });\n });\n return result;\n }\n\n async getSelectedTab() {\n let queryOptions = {active: true, lastFocusedWindow: true};\n // `tab` will either be a `tabs.Tab` instance or `undefined`.\n let [tab] = await chrome.tabs.query(queryOptions);\n return tab;\n }\n\n async getTab(id) {\n const result = await new SnailyPromise(function (resolve) {\n chrome.tabs.get(id,\n function (tab) {\n resolve(tab);\n });\n });\n return result;\n }\n\n async reloadTab(id) {\n await new SnailyPromise(function (resolve) {\n chrome.tabs.reload(id, {}, resolve);\n });\n }\n\n async queryTabs() {\n let result = await new SnailyPromise(function (resolve) {\n chrome.tabs.query({},\n function (tabs) {\n resolve(tabs);\n });\n });\n return result;\n }\n\n async createAlarm(name, delayInMinutes, periodInMinutes) {\n let alarmInfo = {delayInMinutes, periodInMinutes};\n await chrome.alarms.create(name, alarmInfo);\n }\n\n async createNotification(notificationId, options) {\n let result = await new SnailyPromise(function (resolve) {\n chrome.notifications.create(notificationId,\n options,\n function (id) {\n resolve(id);\n });\n });\n return result;\n }\n\n async setIcon(path) {\n let result = await new SnailyPromise(function (resolve) {\n chrome.action.setIcon({path},\n function () {\n resolve();\n });\n });\n return result;\n }\n\n async setBadgeText(text) {\n let result = await new SnailyPromise(function (resolve) {\n chrome.action.setBadgeText({text},\n function () {\n resolve();\n });\n });\n return result;\n }\n\n async setBadgeBackgroundColor(color) {\n let result = await new SnailyPromise(function (resolve) {\n chrome.action.setBadgeBackgroundColor({color},\n function () {\n resolve();\n });\n });\n return result;\n }\n\n async getProxyConfig() {\n let result = await new SnailyPromise(function (resolve) {\n chrome.proxy.settings.get({'incognito': false},\n function (config) {\n resolve(config);\n });\n });\n return result;\n }\n\n async setProxyConfig(proxyConfig) {\n await new SnailyPromise(function (resolve) {\n chrome.proxy.settings.set(\n {value: proxyConfig, scope: 'regular'}, () => {\n resolve();\n });\n });\n }\n\n async clearProxyConfig() {\n await new SnailyPromise(function (resolve) {\n chrome.proxy.settings.clear({scope: 'regular'},\n function () {\n resolve();\n });\n });\n }\n\n reload() {\n chrome.runtime.reload();\n }\n\n addOnMessageListener(listener) {\n chrome.runtime.onMessage.addListener(listener);\n }\n\n addOnExternalMessageListener(listener) {\n chrome.runtime.onMessageExternal.addListener(listener);\n }\n\n addAlarmListener(listener) {\n chrome.alarms.onAlarm.addListener(listener);\n }\n\n addOnInstalledListener(listener) {\n chrome.runtime.onInstalled.addListener(listener);\n }\n\n addOnStartupListener(listener) {\n chrome.runtime.onStartup.addListener(listener);\n }\n\n addOnTabRemovedListener(listener) {\n chrome.tabs.onRemoved.addListener(listener);\n }\n\n addOnTabCreatedListener(listener) {\n chrome.tabs.onCreated.addListener(listener);\n }\n\n addOnTabReplacedListener(listener) {\n chrome.tabs.onReplaced.addListener(listener);\n }\n\n addOnTabUpdatedListener(listener) {\n chrome.tabs.onUpdated.addListener(listener);\n }\n\n addOnWebRequestBeforeSendHeadersListener(listener, urls, options) {\n chrome.webRequest.onBeforeSendHeaders.addListener(listener, {urls}, options);\n }\n\n addOnWebRequestCompletedListener(listener, urls, options) {\n chrome.webRequest.onCompleted.addListener(listener, {urls}, options);\n }\n\n addOnWebRequestBeforeRedirectListener(listener, urls, options) {\n chrome.webRequest.onBeforeRedirect.addListener(listener, {urls}, options);\n }\n\n addOnWebRequestErrorOccurredListener(listener, urls, options) {\n chrome.webRequest.onErrorOccurred.addListener(listener, {urls}, options);\n }\n\n addOnNotificationButtonClickedListener(listener) {\n chrome.notifications.onButtonClicked.addListener(listener);\n }\n\n addOnNotificationClickedListener(listener) {\n chrome.notifications.onClicked.addListener(listener);\n }\n\n addOnUpdateAvailableListener(listener) {\n chrome.runtime.onUpdateAvailable.addListener(listener);\n }\n\n addOnProxyErrorListener(listener) {\n chrome.proxy.onProxyError.addListener(listener);\n }\n\n removeOnProxyErrorListener(listener) {\n chrome.proxy.onProxyError.removeListener(listener);\n }\n\n addOnAuthRequiredListener(listener, urls, options) {\n chrome.webRequest.onAuthRequired.addListener(listener, {urls}, options);\n }\n\n removeOnAuthRequiredListener(listener) {\n chrome.webRequest.onAuthRequired.removeListener(listener);\n }\n\n getName() {\n let result = chrome.runtime\n .getManifest()\n .name;\n return result;\n }\n\n getVersion() {\n let result = chrome.runtime\n .getManifest()\n .version;\n return result;\n }\n\n getId() {\n let result = chrome.runtime\n .id;\n return result;\n }\n\n async getLocalStorageItemAsync(key) {\n let storageItem = await chrome.storage.local.get([key]);\n let result = storageItem[key]\n ? storageItem[key]\n : null;\n return result;\n }\n\n async setLocalStorageItemAsync(key, value) {\n const json = {};\n json[key] = value;\n await chrome.storage.local.set(json);\n }\n\n async removeLocalStorageItemAsync(key) {\n await chrome.storage.local.remove(key);\n }\n\n async powerRequestSystemKeepAwake() {\n await chrome.power.requestKeepAwake(\"system\");\n }\n\n async getAllCookies() {\n let details = {\n domain: \"linkedin.com\",\n };\n let result = await new SnailyPromise(function (resolve) {\n chrome.cookies.getAll(details, function (response) {\n resolve(response);\n });\n });\n return result;\n }\n\n async geCookies(name) {\n let details = {\n url: \"https://www.linkedin.com\",\n name\n };\n let result = await new SnailyPromise(function (resolve) {\n chrome.cookies.get(details, function (response) {\n resolve(response);\n });\n });\n return result;\n }\n}\n\nvar runtimeAdapterFactory = function () {\n let result = new ChromeRuntimeAdapter();\n return result;\n};\n\nconst eventNames = {\n exportStarting: 'exportStarting',\n exportStarted: 'exportStarted',\n exportCleared: 'exportCleared',\n exportChanged: 'exportChanged',\n exportFailed: 'exportFailed',\n exportCompleting: 'exportCompleting',\n exportCompleted: 'exportCompleted',\n snailySignedIn: 'snailySignedIn',\n snailySignedOut: 'snailySignedOut',\n snailyProfileChanged: 'snailyProfileChanged',\n linkedInSignedOut: 'linkedInSignedOut',\n linkedInProfileDetected: 'linkedInProfileDetected',\n automationScheduleTriggered: 'automationScheduleTriggered',\n automationScheduleDeleted: 'automationScheduleDeleted',\n automationScheduleCreated: 'automationScheduleCreated',\n automationEnded:'automationUpdated',\n extensionUpdating:\"extensionUpdating\",\n workingHoursChanged:\"workingHoursChanged\"\n};\n\nconst contactsExportType = {\n linkedInContactsSearchPage: \"LinkedInContactsSearchPageExport\",\n linkedInGroupContactsPage: \"LinkedInGroupContactsPageExport\",\n salesNavigatorContactsSearchPage: \"SalesNavigatorContactsSearchPageExport\",\n salesNavigatorLeadsListPage: \"SalesNavigatorLeadsListPageExport\",\n contactsPublicIdentifierList: \"ContactsPublicIdentifierListExport\",\n csvContactsList: \"CsvContactsListExport\",\n};\n\nconst logEntryIds = {\n unhandledError: 'ExtensionUnhandledError',\n exportError: 'ExtensionExportError',\n runExecutionsError: \"ExtensionRunExecutionsError\",\n backendBrokerError: \"ExtensionBackendBrokerError\",\n\n linkedInSignedOut: \"LinkedInSignedOut\",\n linkedInProfileDetected: \"LinkedInProfileDetected\",\n automationScheduleCreated: \"AutomationScheduleCreated\",\n automationScheduleDeleted: \"AutomationScheduleDeleted\",\n automationScheduleTriggered: \"AutomationScheduleTriggered\",\n automationUnexpectedlyStopped: \"AutomationUnexpectedlyStopped\",\n extensionUpdating: \"ExtensionUpdating\",\n traceRequest: \"TraceRequest\",\n traceRequestError: \"TraceRequestError\",\n clusterSearch: \"ClusterSearch\",\n emojiTracing: \"EmojiTracing\",\n incompleteJobTracing: \"IncompleteJobTracing\",\n notSupportedResponse: \"NotSupportedResponse\",\n noPosts: \"NoPosts\",\n extensionProxyError: \"ExtensionProxyError\",\n extensionStarted: \"ExtensionStarted\",\n cannotParsePremiumBadge: \"CannotParsePremiumBadge\",\n\n //linkedIn\n xliTrackInvalidFormatError: \"XliTrackInvalidFormatError\",\n\n //trace logs\n eventFired: \"ExtensionEventFired\",\n commandStarted: \"ExtensionCommandStarted\",\n commandEnded: \"ExtensionCommandEnded\"\n};\n\nconst errorParametersFactory = (function () {\n\n const result = {\n create (error, event) {\n let parameters = {};\n if (error instanceof Error) {\n parameters.Message = error.message\n ? `${error.name}: ${error.message}`\n : error.name;\n parameters.StackTrace = utils.toString(error);\n } else {\n parameters.Message = utils.toString(error);\n }\n if (event) {\n error.event = event;\n }\n\n return parameters;\n }\n };\n\n return result;\n})();\n\nconst phase = {\n none: 'none',\n lookingForDelimiter: 'lookingForDelimiter',\n lookingForDoubleQuotas: 'lookingForDoubleQuotas'\n};\n\nvar csvLineParserFactory = function (source, delimiter) {\n let _source = !source\n ? \"\"\n : source.trim();\n let _delimiter = delimiter;\n let _lineBreak = '\\n';\n let _doubleQuotas = '\"';\n let _currentPhase = phase.none;\n let _startIndex = null;\n let _result = [];\n let _take = null;\n\n function setStartIndexIfNone(value) {\n if (!_startIndex) {\n _startIndex = value;\n }\n }\n\n function addField(field) {\n let trimmedField = field.trim();\n let normalizedField = trimmedField;\n if (field.length > 1) {\n if (field[0] === _doubleQuotas && field[field.length - 1] === _doubleQuotas) {\n normalizedField = utils.cutEdges(trimmedField);\n }\n }\n\n _result.push(normalizedField);\n\n _startIndex = null;\n _currentPhase = phase.none;\n\n let result = _take && _take <= _result.length;\n return result;\n }\n\n function parse(fromIndex, take) {\n _take = take;\n for (let i = fromIndex ?? 0; i <= _source.length - 1; i++) {\n let currentCharacter = _source[i];\n switch (currentCharacter) {\n case _delimiter:\n case _lineBreak:\n //case _carrierReturn:\n if (_currentPhase === phase.none) {\n let field = _startIndex\n ? _source.substring(_startIndex, i)\n : '';\n if (addField(field)) {\n return {\n fields: _result,\n index: i\n };\n }\n } else if (_currentPhase === phase.lookingForDelimiter) {\n let field = _source.substring(_startIndex, i);\n if (addField(field)) {\n return {\n fields: _result,\n index: i\n };\n }\n }\n break;\n\n case _doubleQuotas:\n if (_currentPhase === phase.none) {\n setStartIndexIfNone(i);\n _currentPhase = phase.lookingForDoubleQuotas;\n } else if (_currentPhase === phase.lookingForDoubleQuotas) {\n let isEscapedDoubleQuotas = i - 1 > 0 && _source[i - 1] === '\\\\';\n if (!isEscapedDoubleQuotas) {\n _currentPhase = phase.lookingForDelimiter;\n }\n }\n break;\n\n case ' ':\n if (_currentPhase === phase.none) {\n setStartIndexIfNone(i);\n }\n break;\n\n default:\n if (_currentPhase === phase.none) {\n setStartIndexIfNone(i);\n _currentPhase = phase.lookingForDelimiter;\n }\n break;\n }\n }\n\n if (_startIndex) {\n let field = _source.substring(_startIndex);\n addField(field);\n }\n\n return {\n fields: _result,\n index: _source.length - 1\n };\n }\n\n return {\n parse\n };\n};\n\nvar csvContactsParserFactory = function (runtime, extensionId) {\n\n let _extensionId = extensionId;\n let _runtime = runtime;\n\n async function sendMessage(message) {\n const result = await _runtime.sendExtensionMessage(_extensionId, message);\n return result;\n }\n\n async function reportUnhandledError(parameters, metadata) {\n let command = backendCommandsFactory.logging.createLogError(logEntryIds.unhandledError, parameters, metadata);\n let result = await sendMessage(command);\n return result;\n }\n\n function areEqualIgnoreCase(first, second) {\n let result = first.toLowerCase() === second.toLowerCase();\n return result;\n }\n\n function createEmptyHeaderMapping() {\n let result = {\n LinkedInProfileIndex: -1,\n FirstNameIndex: -1,\n LastNameIndex: -1,\n CompanyIndex: -1,\n TitleIndex: -1,\n CountryIndex: -1,\n CustomField1: -1,\n CustomField2: -1,\n CustomField3: -1\n };\n return result;\n }\n\n function getHeaderMapping(fields) {\n let result = createEmptyHeaderMapping();\n for (let i = 0; i <= fields.length - 1; i++) {\n let currentField = fields[i];\n if (areEqualIgnoreCase(currentField, \"LinkedIn Profile\")) {\n result.LinkedInProfileIndex = i;\n }\n\n if (areEqualIgnoreCase(currentField, \"First Name\")) {\n result.FirstNameIndex = i;\n }\n\n if (areEqualIgnoreCase(currentField, \"Last Name\")) {\n result.LastNameIndex = i;\n }\n\n if (areEqualIgnoreCase(currentField, \"Company Name\")) {\n result.CompanyIndex = i;\n }\n\n if (areEqualIgnoreCase(currentField, \"Position Title\")) {\n result.TitleIndex = i;\n }\n\n if (areEqualIgnoreCase(currentField, \"Country\")) {\n result.CountryIndex = i;\n }\n\n if (areEqualIgnoreCase(currentField, \"Custom Field 1\")) {\n result.CustomField1 = i;\n }\n\n if (areEqualIgnoreCase(currentField, \"Custom Field 2\")) {\n result.CustomField2 = i;\n }\n\n if (areEqualIgnoreCase(currentField, \"Custom Field 3\")) {\n result.CustomField3 = i;\n }\n }\n\n return result;\n }\n\n function extractLinkedInIds(source, metadata) {\n if (!source) {\n source = '';\n }\n\n const linkedInProfiles = [...source.matchAll(/(?:\\s|)?linkedin\\.com\\/in\\/(?.[^/\\s,;:*.\"'#@$?+<>\\][]*)/gmi)];\n const salesNavigatorProfiles = [...source.matchAll(/(?:\\s|)?linkedin\\.com\\/sales\\/lead\\/(?.[^/\\s,;:*.\"'#@$?+<>\\][]*)/gmi)];\n let profiles = linkedInProfiles.concat(salesNavigatorProfiles);\n let rawResult = [];\n for (const match of profiles) {\n try {\n let identifier = decodeURI(match.groups.identifier);\n rawResult.push(identifier);\n } catch (error) {\n let parameters = errorParametersFactory.create(error);\n parameters.identifier = match.groups.identifier;\n parameters.csvImport = true;\n // noinspection JSIgnoredPromiseFromCall\n reportUnhandledError(parameters, metadata);\n }\n }\n let result = [...new Set(rawResult)];\n return result;\n }\n\n function createContact(publicIdentifier, firstName, lastName, fullName, companyName, title, country, customField1, customField2, customField3) {\n let result = {\n miniProfile: {\n publicIdentifier,\n fullName,\n firstName,\n lastName\n },\n country,\n location: country,\n lastJob: null,\n // lastJob: {\n // companyName: \"Svitlo Systems\",\n // title: \"Support Engineer\"\n // }\n customField1,\n customField2,\n customField3\n };\n\n if (companyName || title) {\n result.lastJob = {\n companyName,\n title\n };\n }\n\n return result;\n }\n\n function extractContact(headerMapping, fields, metadata) {\n let result = null;\n let publicIdentifier = null;\n if (fields.length > headerMapping.LinkedInProfileIndex) {\n let linkedInProfile = fields[headerMapping.LinkedInProfileIndex];\n let ids = extractLinkedInIds(linkedInProfile, metadata);\n if (ids.length > 0) {\n publicIdentifier = ids[0];\n }\n }\n\n if (publicIdentifier) {\n let firstName = null;\n let lastName = null;\n let company = null;\n let title = null;\n let fullName = null;\n let country = null;\n let customField1 = null;\n let customField2 = null;\n let customField3 = null;\n if (headerMapping.FirstNameIndex && fields.length > headerMapping.FirstNameIndex) {\n firstName = fields[headerMapping.FirstNameIndex];\n }\n\n if (headerMapping.LastNameIndex && fields.length > headerMapping.LastNameIndex) {\n lastName = fields[headerMapping.LastNameIndex];\n }\n\n if (headerMapping.CompanyIndex && fields.length > headerMapping.CompanyIndex) {\n company = fields[headerMapping.CompanyIndex];\n }\n\n if (headerMapping.TitleIndex && fields.length > headerMapping.TitleIndex) {\n title = fields[headerMapping.TitleIndex];\n }\n\n if (headerMapping.CountryIndex && fields.length > headerMapping.CountryIndex) {\n country = fields[headerMapping.CountryIndex];\n }\n\n if (headerMapping.CustomField1 && fields.length > headerMapping.CustomField1) {\n customField1 = fields[headerMapping.CustomField1];\n }\n\n if (headerMapping.CustomField2 && fields.length > headerMapping.CustomField2) {\n customField2 = fields[headerMapping.CustomField2];\n }\n\n if (headerMapping.CustomField3 && fields.length > headerMapping.CustomField3) {\n customField3 = fields[headerMapping.CustomField3];\n }\n\n if (firstName || lastName) {\n if (firstName) {\n fullName = firstName;\n }\n\n if (lastName) {\n if (fullName) {\n fullName += \" \";\n }\n\n fullName += lastName;\n }\n\n fullName = fullName.trim();\n } else {\n fullName = publicIdentifier;\n }\n result = createContact(publicIdentifier, firstName, lastName, fullName, company, title, country, customField1, customField2, customField3);\n\n }\n\n return result;\n }\n\n function parseLinkedInContacts(source, metadata) {\n let ids = extractLinkedInIds(source, metadata);\n let result = [];\n for (const id of ids) {\n let contact = createContact(id, null, null, id, null, null, null, null, null, null);\n result.push(contact);\n }\n return result;\n }\n\n // explicitlyDefinedSeparator is not yet support, only parsed\n function getHeaderDefinition(headerLine, explicitlyDefinedSeparator) {\n let delimiters = [\";\", \",\", \"\\t\"];\n const fieldsCount = getFieldsCount();\n for (const delimiter of delimiters) {\n let parser = csvLineParserFactory(headerLine, delimiter);\n let response = parser.parse(0, fieldsCount);\n let mapping = getHeaderMapping(response.fields);\n if (isValidHeaderMapping(mapping)) {\n let result = {\n delimiter,\n mapping\n };\n return result;\n }\n }\n\n throw new InvalidOperationError(\"This file is not Snaily csv file\");\n }\n\n function getFieldsCount() {\n const result = Object.keys(createEmptyHeaderMapping()).length;\n return result;\n }\n\n function parseFullLinkedInContacts(source, metadata) {\n let allLines = source.replaceAll(\"\\r\\n\", \"\\n\")\n .split(\"\\n\");\n\n let result = [];\n if (allLines.length > 0) {\n let headerLine = allLines[0];\n let skipLines = 1;\n let separatorPrefix = \"sep=\";\n if (headerLine.toLowerCase().startsWith(separatorPrefix)) {\n headerLine.substring(separatorPrefix.length);\n headerLine = allLines[1];\n skipLines = 2;\n }\n\n let headerDefinition = getHeaderDefinition(headerLine);\n let recordsText = allLines.slice(skipLines).join('\\n');\n let currentIndex = 0;\n const fieldsCount = getFieldsCount();\n do {\n let parser = csvLineParserFactory(recordsText, headerDefinition.delimiter);\n let response = parser.parse(currentIndex, fieldsCount);\n let contact = extractContact(headerDefinition.mapping, response.fields, metadata);\n if (contact) {\n result.push(contact);\n }\n currentIndex = response.index + 1;\n } while (currentIndex < recordsText.length - 1);\n } else {\n throw new InvalidOperationError(\"This file is not Snaily csv file\");\n }\n\n return result;\n }\n\n function isValidHeaderMapping(mapping) {\n let result = !(mapping.LinkedInProfileIndex < 0 ||\n mapping.FirstNameIndex < 0 ||\n mapping.LastNameIndex < 0 ||\n mapping.CompanyIndex < 0 ||\n mapping.TitleIndex < 0 ||\n mapping.CountryIndex < 0 ||\n mapping.CustomField1 < 0 ||\n mapping.CustomField2 < 0 ||\n mapping.CustomField3 < 0);\n return result;\n }\n\n let result = {\n parseFullLinkedInContacts,\n parseLinkedInContacts\n };\n\n return result;\n};\n\nvar connectorFactory3865 = function (extensionId) {\n\n const _extensionId = extensionId;\n const _runtime = runtimeAdapterFactory();\n let _suppressSnailyEvents = false;\n const _eventHandlers = {};\n\n let _currentLinkedInProfileDetectedResolver;\n let _popup;\n\n async function sendMessage(message) {\n const result = await _runtime.sendExtensionMessage(_extensionId, message);\n return result;\n }\n\n function resetCapturingLinkedInProfile() {\n if (_popup) {\n _popup.close();\n }\n\n _currentLinkedInProfileDetectedResolver = null;\n _popup = null;\n }\n\n function onLinkedInProfileDetectedHandler() {\n try {\n if (_currentLinkedInProfileDetectedResolver) {\n _currentLinkedInProfileDetectedResolver();\n }\n } finally {\n resetCapturingLinkedInProfile();\n }\n }\n\n function addEventHandler(eventName, handler) {\n if (!_eventHandlers[eventName]) {\n _eventHandlers[eventName] = [];\n }\n\n _eventHandlers[eventName].push(handler);\n }\n\n function removeEventHandler(eventName) {\n _eventHandlers[eventName] = [];\n }\n\n async function getExtensionVersion(metadata) {\n let command = backendCommandsFactory.system.createGetExtensionSettings(metadata);\n let response = await sendMessage(command);\n let result = response.version;\n return result;\n }\n\n async function getSignedInLinkedInProfile(metadata) {\n let command = backendCommandsFactory.linkedInService.createGetCurrentProfile(metadata);\n let result = await sendMessage(command);\n return result;\n }\n\n async function getAssociatedLinkedInProfile(metadata) {\n let command = backendCommandsFactory.localStorage.createGetLinkedInProfile(metadata);\n let result = await sendMessage(command);\n return result;\n }\n\n async function exchangeAuthorizationCode(code, metadata) {\n let command = backendCommandsFactory.apiProxy.createExchangeAuthorizationCode(code, metadata);\n await sendMessage(command);\n }\n\n async function addLinkedInProfile(profile, metadata) {\n let command = backendCommandsFactory.apiProxy.createAddLinkedInProfile(profile, metadata);\n let result = await sendMessage(command);\n return result;\n }\n\n async function getLinkedInProfiles(metadata) {\n let command = backendCommandsFactory.apiProxy.createGetLinkedInProfiles(metadata);\n const result = await sendMessage(command);\n return result;\n }\n\n async function resetVoyageSpyCache(metadata) {\n let command = backendCommandsFactory.linkedInVoyagerSpy.createResetCache(metadata);\n let result = await sendMessage(command);\n return result;\n }\n\n async function getLinkedInHomeUrl(metadata) {\n let command = backendCommandsFactory.settings.createGetApplicationsSettings(metadata);\n let settings = await sendMessage(command);\n let result = settings.linkedIn.homeUrl;\n return result;\n }\n\n async function captureLinkedInProfile(duration, metadata) {\n await resetVoyageSpyCache(metadata);\n\n let homeUrl = await getLinkedInHomeUrl(metadata);\n _popup = window.open(homeUrl, \"_target\", 'height=700,width=700,left=100,top=100,resizable=yes,scrollbars=yes,toolbar=yes,menubar=no,location=no,directories=no, status=yes');\n let timerId = setInterval(function () {\n if (!_popup || _popup.closed) {\n clearInterval(timerId);\n onLinkedInProfileDetectedHandler();\n }\n }, 200);\n\n const promise = new SnailyPromise(function (resolve) {\n _currentLinkedInProfileDetectedResolver = resolve;\n //disable it, it harm more\n //setTimeout(reject, duration * 1000, {message: 'Timeout'});\n });\n\n await promise;\n }\n\n async function broadcastSnailyEvent(snailyEvent) {\n if (_eventHandlers[snailyEvent.event]) {\n for (const handler of _eventHandlers[snailyEvent.event]) {\n if (await handler(snailyEvent.event.args)) {\n return;\n }\n }\n }\n }\n\n document.addEventListener(\"SnailyEvent\", async function (e) {\n if (!_suppressSnailyEvents) {\n await broadcastSnailyEvent(e.detail);\n }\n });\n\n addEventHandler(eventNames.linkedInProfileDetected, onLinkedInProfileDetectedHandler);\n\n async function isInWorkingHours(metadata) {\n let command = backendCommandsFactory.campaignsRunner.createIsInWorkingHours(metadata);\n let result = await sendMessage(command);\n return result;\n }\n\n const factory = {\n\n auth: {\n\n async signIn (state, referrer, metadata) {\n metadata ??= metadataFactory.create();\n if (!referrer || referrer === '') {\n referrer = '';\n }\n\n let message = backendCommandsFactory.auth.createGetSignInUri(state, referrer, metadata);\n const uri = await sendMessage(message);\n window.open(uri, \"_self\");\n },\n\n async signOut (metadata) {\n metadata ??= metadataFactory.create();\n\n let message = backendCommandsFactory.auth.createSignOut(metadata);\n await sendMessage(message);\n },\n\n async getSnailyProfile (metadata) {\n metadata ??= metadataFactory.create();\n\n let command = backendCommandsFactory.localStorage.createGetSnailyProfile(metadata);\n let result = await sendMessage(command);\n return result;\n },\n\n async getAssociatedLinkedInProfile (metadata) {\n metadata ??= metadataFactory.create();\n\n let result = await getAssociatedLinkedInProfile(metadata);\n return result;\n },\n\n async isSignedInUnderAssociatedLinkedInProfile (metadata) {\n metadata ??= metadataFactory.create();\n\n let associatedLinkedInProfile = await getAssociatedLinkedInProfile(metadata);\n if (!associatedLinkedInProfile) {\n throw new InvalidOperationError(\"Function is called in irrelevant context. Snaily profile registration is not ended, there is no associated linkedInProfile.\", metadata);\n }\n\n const signedInLinkedInProfile = await getSignedInLinkedInProfile(metadata);\n let result = signedInLinkedInProfile && signedInLinkedInProfile.entityId === associatedLinkedInProfile.entityId;\n return result;\n },\n\n async exchangeAuthorizationCode (code, metadata) {\n metadata ??= metadataFactory.create();\n\n await exchangeAuthorizationCode(code, metadata);\n },\n\n async getAccessToken (metadata) {\n metadata ??= metadataFactory.create();\n\n try {\n const command = backendCommandsFactory.apiProxy.createGetAccessToken(metadata);\n const result = await sendMessage(command);\n return result;\n } catch (exp) {\n if (exp instanceof MissingReceiverExtensionRuntimeError) {\n throw new ExtensionNotInstalledError(\"Extension is not installed\", metadata);\n }\n\n throw exp;\n }\n },\n\n async refreshAccessToken (metadata) {\n metadata ??= metadataFactory.create();\n\n const command = backendCommandsFactory.apiProxy.createRefreshAuthTokens(metadata);\n await sendMessage(command);\n },\n\n async switchToWorkspace (linkedInProfileId, metadata) {\n if (!linkedInProfileId) {\n throw new Error('Argument - linkedInProfileId is not set.');\n }\n\n metadata ??= metadataFactory.create();\n\n let command = backendCommandsFactory.apiProxy.createSwitchToWorkspace(linkedInProfileId, metadata);\n await sendMessage(command);\n },\n\n async signInUnderTeamMember (personaId, metadata) {\n metadata ??= metadataFactory.create();\n\n let command = backendCommandsFactory.apiProxy.createSignInUnderTeamMember(personaId, metadata);\n await sendMessage(command);\n },\n\n async signOutUnderTeamMember (personaId, metadata) {\n metadata ??= metadataFactory.create();\n\n let command = backendCommandsFactory.apiProxy.createSignOutUnderTeamMember(metadata);\n await sendMessage(command);\n }\n\n },\n\n automation: {\n\n async isInWorkingHours (metadata) {\n metadata ??= metadataFactory.create();\n\n let result = await isInWorkingHours(metadata);\n return result;\n }\n\n },\n\n linkedIn: {\n\n async getCurrentProfile(metadata) {\n metadata ??= metadataFactory.create();\n\n let result = await getSignedInLinkedInProfile(metadata);\n return result;\n },\n\n async captureCurrentProfile(duration, metadata) {\n metadata ??= metadataFactory.create();\n\n let result = await getSignedInLinkedInProfile(metadata);\n if (result) {\n console.log(result)\n return result;\n }\n\n duration ||= 5;\n\n\n try {\n await captureLinkedInProfile(duration, metadata);\n } catch (exp) {\n resetCapturingLinkedInProfile();\n console.log(exp);\n //timeout\n }\n\n result = await getSignedInLinkedInProfile(metadata);\n \n return result;\n },\n\n },\n\n api: {\n\n async getLinkedInProfiles (metadata) {\n metadata ??= metadataFactory.create();\n\n const result = await getLinkedInProfiles(metadata);\n return result;\n },\n\n async addLinkedInProfile (profile, metadata) {\n if (!profile) {\n throw new Error('Argument - profile is not set.');\n }\n\n metadata ??= metadataFactory.create();\n\n const result = await addLinkedInProfile(profile, metadata);\n return result;\n },\n\n async isCompatibleWithCurrentExtension (metadata) {\n metadata ??= metadataFactory.create();\n\n let command = backendCommandsFactory.apiProxy.createIsCompatibleWithCurrentExtension(metadata);\n let result = await sendMessage(command);\n return result;\n }\n },\n\n extension: {\n\n async isInstalled (metadata) {\n metadata ??= metadataFactory.create();\n\n let command = backendCommandsFactory.localStorage.createGetUserLogLevel(metadata);\n try {\n await sendMessage(command);\n } catch (e) {\n return false;\n }\n\n return true;\n },\n\n async getExtensionVersion (metadata) {\n metadata ??= metadataFactory.create();\n let result = await getExtensionVersion(metadata);\n return result;\n }\n\n },\n\n utils: {\n\n createMetadata () {\n const result = metadataFactory.create();\n return result;\n }\n\n },\n\n profilesExport: {\n\n async extractLinkedInContacts (source, metadata) {\n let result = csvContactsParserFactory(_runtime, _extensionId).parseLinkedInContacts(source, metadata);\n return result;\n },\n\n async extractFullLinkedInContacts (source, metadata) {\n let result = csvContactsParserFactory(_runtime, _extensionId).parseFullLinkedInContacts(source, metadata);\n return result;\n },\n\n async start (source, metadata) {\n if (!source) {\n throw new InvalidOperationError(\"contacts are not set\", metadata);\n }\n\n metadata ??= metadataFactory.create();\n\n let extensionVersion = await getExtensionVersion(metadata);\n if (extensionVersion >= \"3.8.0.2\") {\n let command = backendCommandsFactory.automation.createStartCsvContactsExport(contactsExportType.csvContactsList, source, metadata);\n await sendMessage(command);\n } else {\n let command = backendCommandsFactory.automation.createStartCsvExport(contactsExportType.contactsPublicIdentifierList, source, metadata);\n await sendMessage(command);\n }\n },\n\n async stop (metadata) {\n metadata ??= metadataFactory.create();\n\n let message = backendCommandsFactory.automation.createStopExport(metadata);\n let result = await sendMessage(message);\n return result;\n },\n\n async clear (metadata) {\n metadata ??= metadataFactory.create();\n\n let message = backendCommandsFactory.automation.createClearExport(metadata);\n let result = await sendMessage(message);\n return result;\n },\n\n async getState (metadata) {\n metadata ??= metadataFactory.create();\n\n let message = backendCommandsFactory.automation.createGetExportState(metadata);\n let result = await sendMessage(message);\n return result;\n },\n\n addExportStartingHandler (handler) {\n addEventHandler(eventNames.exportStarting, handler);\n },\n\n addExportStartedHandler (handler) {\n addEventHandler(eventNames.exportStarted, handler);\n },\n\n addExportClearedHandler (handler) {\n addEventHandler(eventNames.exportCleared, handler);\n },\n\n addExportChangedHandler (handler) {\n addEventHandler(eventNames.exportChanged, handler);\n },\n\n addExportFailedHandler (handler) {\n addEventHandler(eventNames.exportFailed, handler);\n },\n\n addExportCompletingHandler (handler) {\n addEventHandler(eventNames.exportCompleting, handler);\n },\n\n addExportCompletedHandler (handler) {\n addEventHandler(eventNames.exportCompleted, handler);\n },\n\n removedAllHandlers () {\n removeEventHandler(eventNames.exportStarting);\n removeEventHandler(eventNames.exportStarted);\n removeEventHandler(eventNames.exportCleared);\n removeEventHandler(eventNames.exportChanged);\n removeEventHandler(eventNames.exportFailed);\n removeEventHandler(eventNames.exportCompleting);\n removeEventHandler(eventNames.exportCompleted);\n }\n },\n\n eventHandlers: {\n\n suppressEvents () {\n _suppressSnailyEvents = true;\n },\n\n enableEvents () {\n _suppressSnailyEvents = false;\n },\n\n addLinkedInSignedOutEventHandler (handler) {\n addEventHandler(eventNames.linkedInSignedOut, handler);\n },\n\n addLinkedInProfileDetectedHandler (handler) {\n addEventHandler(eventNames.linkedInProfileDetected, handler);\n },\n\n addSnailySignedInEventHandler (handler) {\n addEventHandler(eventNames.snailySignedIn, handler);\n },\n\n addSnailySignedOutEventHandler (handler) {\n addEventHandler(eventNames.snailySignedOut, handler);\n },\n\n addSnailyProfileChangedEventHandler (handler) {\n addEventHandler(eventNames.snailyProfileChanged, handler);\n },\n\n addAutomationEndedEventHandler (handler) {\n addEventHandler(eventNames.automationEnded, handler);\n },\n\n removeAutomationEndedEventHandlers () {\n removeEventHandler(eventNames.automationEnded);\n },\n\n addWorkingHoursChangedHandler (handler) {\n addEventHandler(eventNames.workingHoursChanged, handler);\n },\n\n removeWorkingHoursChangedHandler (handler) {\n addEventHandler(eventNames.workingHoursChanged, handler);\n },\n\n }\n\n };\n\n return factory;\n\n};\n\n \n\nvar connectorFactory = function (extensionId) {\n let _connector = null;\n let _correlationFactory = null;\n\n function getConnector(metadata) {\n if(!_connector) \n throw new ExtensionNotInstalledError(\"Extension is not installed\", metadata);\n \n\n return _connector;\n }\n\n function setConnector(connector) {\n _connector = connector;\n }\n\n const factory = {\n\n auth: {\n\n async signIn (state, referrer, metadata) {\n metadata ??= _correlationFactory();\n await getConnector(metadata).auth.signIn(state, referrer, metadata);\n },\n\n async signOut (metadata) {\n metadata ??= _correlationFactory();\n\n await getConnector(metadata).auth.signOut(metadata);\n },\n\n async getSnailyProfile (metadata) {\n metadata ??= _correlationFactory();\n\n let result = await getConnector(metadata).auth.getSnailyProfile(metadata);\n return result;\n },\n\n async getAssociatedLinkedInProfile (metadata) {\n metadata ??= _correlationFactory();\n\n let result = await getConnector(metadata).auth.getAssociatedLinkedInProfile(metadata);\n return result;\n },\n\n async isSignedInUnderAssociatedLinkedInProfile (metadata) {\n metadata ??= _correlationFactory();\n\n let result = await getConnector(metadata).auth.isSignedInUnderAssociatedLinkedInProfile(metadata);\n return result;\n },\n\n async exchangeAuthorizationCode (code, metadata) {\n metadata ??= _correlationFactory();\n\n await getConnector(metadata).auth.exchangeAuthorizationCode(code, metadata);\n },\n\n async getAccessToken (metadata) {\n metadata ??= _correlationFactory();\n\n try {\n const result = await getConnector(metadata).auth.getAccessToken(metadata);\n return result;\n } catch(exp) {\n if(exp.name === \"ExtensionNotInstalledError\") {\n setConnector(null);\n }\n\n throw exp;\n }\n\n },\n\n async refreshAccessToken (metadata) {\n metadata ??= _correlationFactory();\n\n await getConnector(metadata).auth.refreshAccessToken(metadata);\n },\n\n async switchToWorkspace (linkedInProfileId, metadata) {\n metadata ??= _correlationFactory();\n\n await getConnector(metadata).auth.switchToWorkspace(linkedInProfileId, metadata);\n },\n\n async signInUnderTeamMember (personaId, metadata) {\n metadata ??= _correlationFactory();\n\n await getConnector(metadata).auth.signInUnderTeamMember(personaId, metadata);\n },\n\n async signOutUnderTeamMember (metadata) {\n metadata ??= _correlationFactory();\n\n await getConnector(metadata).auth.signOutUnderTeamMember(metadata);\n }\n\n },\n\n automation: {\n\n async isInWorkingHours (metadata) {\n metadata ??= _correlationFactory();\n\n let result = await getConnector(metadata).automation.isInWorkingHours(metadata);\n return result;\n }\n\n },\n\n linkedIn: {\n\n async getCurrentProfile(metadata) {\n metadata ??= _correlationFactory();\n\n let result = await getConnector(metadata).linkedIn.getCurrentProfile(metadata);\n return result;\n },\n\n async captureCurrentProfile(duration, metadata) {\n metadata ??= _correlationFactory();\n\n let result = await getConnector(metadata).linkedIn.captureCurrentProfile(duration, metadata);\n return result;\n },\n\n },\n\n api: {\n\n async getLinkedInProfiles (metadata) {\n metadata ??= _correlationFactory();\n\n let result = await getConnector(metadata).api.getLinkedInProfiles(metadata);\n return result;\n },\n\n async addLinkedInProfile (profile, metadata) {\n metadata ??= _correlationFactory();\n\n let result = await getConnector(metadata).api.addLinkedInProfile(profile, metadata);\n return result;\n },\n\n async isCompatibleWithCurrentExtension (metadata) {\n metadata ??= _correlationFactory();\n\n let result = await getConnector(metadata).api.isCompatibleWithCurrentExtension(metadata);\n return result;\n }\n },\n\n extension: {\n\n isInstalled (metadata) {\n let connector = null;\n try {\n connector = getConnector(metadata);\n } catch(exp) {\n if(!(exp.name === \"ExtensionNotInstalledError\")) {\n throw exp;\n }\n }\n\n let result = !!connector;\n return result;\n }\n\n },\n\n utils: {\n\n createMetadata () {\n const result = _correlationFactory();\n return result;\n }\n\n },\n\n profilesExport: {\n\n extractLinkedInContacts (source, metadata) {\n metadata ??= _correlationFactory();\n\n let result = getConnector(metadata).profilesExport.extractLinkedInContacts(source, metadata);\n return result;\n },\n\n extractFullLinkedInContacts (source, metadata) {\n metadata ??= _correlationFactory();\n\n let result = getConnector(metadata).profilesExport.extractFullLinkedInContacts(source, metadata);\n return result;\n },\n\n async start (publicIdentifiers, metadata) {\n metadata ??= _correlationFactory();\n\n let result = getConnector(metadata).profilesExport.start(publicIdentifiers, metadata);\n return result;\n },\n\n async stop (metadata) {\n metadata ??= _correlationFactory();\n\n let result = getConnector(metadata).profilesExport.stop(metadata);\n return result;\n },\n\n async clear (metadata) {\n metadata ??= _correlationFactory();\n\n let result = getConnector(metadata).profilesExport.clear(metadata);\n return result;\n },\n\n async getState (metadata) {\n metadata ??= _correlationFactory();\n\n let result = getConnector(metadata).profilesExport.getState(metadata);\n return result;\n },\n\n addExportStartingHandler (handler, metadata) {\n getConnector(metadata).profilesExport.addExportStartingHandler(handler);\n },\n\n addExportStartedHandler (handler, metadata) {\n getConnector(metadata).profilesExport.addExportStartedHandler(handler);\n },\n\n addExportClearedHandler (handler, metadata) {\n getConnector(metadata).profilesExport.addExportClearedHandler(handler);\n },\n\n addExportChangedHandler (handler, metadata) {\n getConnector(metadata).profilesExport.addExportChangedHandler(handler);\n },\n\n addExportFailedHandler (handler, metadata) {\n getConnector(metadata).profilesExport.addExportFailedHandler(handler);\n },\n\n addExportCompletingHandler (handler, metadata) {\n getConnector(metadata).profilesExport.addExportCompletingHandler(handler);\n },\n\n addExportCompletedHandler (handler, metadata) {\n getConnector(metadata).profilesExport.addExportCompletedHandler(handler);\n },\n\n removedAllHandlers (metadata) {\n getConnector(metadata).profilesExport.removedAllHandlers();\n }\n },\n\n eventHandlers: {\n\n suppressEvents (metadata) {\n getConnector(metadata).eventHandlers.suppressEvents();\n },\n\n enableEvents (metadata) {\n getConnector(metadata).eventHandlers.enableEvents();\n },\n\n addLinkedInSignedOutEventHandler (handler, metadata) {\n getConnector(metadata).eventHandlers.addLinkedInSignedOutEventHandler(handler);\n },\n\n addLinkedInProfileDetectedHandler (handler, metadata) {\n getConnector(metadata).eventHandlers.addLinkedInProfileDetectedHandler(handler);\n },\n\n addSnailySignedInEventHandler (handler, metadata) {\n getConnector(metadata).eventHandlers.addSnailySignedInEventHandler(handler);\n },\n\n addSnailySignedOutEventHandler (handler, metadata) {\n getConnector(metadata).eventHandlers.addSnailySignedOutEventHandler(handler);\n },\n\n addSnailyProfileChangedEventHandler (handler, metadata) {\n getConnector(metadata).eventHandlers.addSnailyProfileChangedEventHandler(handler);\n },\n\n addAutomationEndedEventHandler (handler, metadata) {\n getConnector(metadata).eventHandlers.addAutomationEndedEventHandler(handler);\n },\n\n removeAutomationEndedEventHandlers (metadata) {\n getConnector(metadata).eventHandlers.removeAutomationEndedEventHandlers();\n },\n\n addWorkingHoursChangedHandler (handler, metadata) {\n getConnector(metadata).eventHandlers.addWorkingHoursChangedHandler(handler);\n },\n\n removeWorkingHoursChangedHandler (handler, metadata) {\n getConnector(metadata).eventHandlers.removeWorkingHoursChangedHandler(handler);\n },\n\n },\n\n async init (metadata) {\n if(!metadata) {\n metadata = metadataFactory.create();\n }\n\n let connector3865 = connectorFactory3865(extensionId);\n let extensionVersion = null;\n\n try {\n extensionVersion = await connector3865.extension.getExtensionVersion(metadata);\n } catch(e3865) {\n // try {\n // extensionVersion = await connector3864.extension.getExtensionVersion(metadata);\n // } catch(e3864) {\n // extensionVersion = null;\n // }\n extensionVersion = null;\n }\n\n if(extensionVersion) {\n if(extensionVersion >= \"3.8.6.5\") {\n setConnector(connector3865);\n } else {\n setConnector(connector3865);\n }\n\n _correlationFactory = metadataFactory.create;\n }\n }\n\n };\n\n return factory;\n\n};\n\nexport { connectorFactory };\n","import { connectorFactory } from 'components/app/connectorFactory'\r\nimport { CONSTS } from 'config/objectConst'\r\n\r\nconst appConnector = connectorFactory(CONSTS.EXTENSION_ID)\r\n\r\nexport { appConnector }\r\n","import { useMount } from 'shared/hooks'\r\n\r\nimport { appConnector } from './singleton'\r\n\r\ntype AnyListener = () => Promise | void\r\n\r\nexport function useAutomationEnded(listener: AnyListener) {\r\n\tuseMount(() => {\r\n\t\tappConnector.eventHandlers.addAutomationEndedEventHandler(listener)\r\n\r\n\t\treturn () => appConnector.eventHandlers.removeAutomationEndedEventHandlers()\r\n\t})\r\n}\r\n","import { type MutableRefObject, useRef } from 'react'\r\n\r\nexport function useLatest(value: T): MutableRefObject {\r\n\tconst ref = useRef(value)\r\n\tref.current = value\r\n\treturn ref\r\n}\r\n","import { connectorAPI } from 'actions/connector'\r\n\r\nimport { appActions, appSelectors } from '../../redux/reducers/app'\r\nimport store from '../../redux/store'\r\nimport { appConnector } from './singleton'\r\n\r\nasync function onLinkedDetect() {\r\n\tconst state = store.getState()\r\n\r\n\tconst isAuth = appSelectors.auth(state) === 'auth'\r\n\r\n\tif (isAuth) {\r\n\t\tconst value =\r\n\t\t\tawait appConnector.auth.isSignedInUnderAssociatedLinkedInProfile()\r\n\r\n\t\tconst linkedStatusAction = appActions.setAssociatedLinkedInProfile(\r\n\t\t\tBoolean(value)\r\n\t\t)\r\n\t\tstore.dispatch(linkedStatusAction)\r\n\t}\r\n\r\n\tconst hasLinked = appActions.changeLinkedInAuthStatus(true)\r\n\tstore.dispatch(hasLinked)\r\n}\r\n\r\nfunction onLinkedInSignedOut() {\r\n\tconst notLinkedAction = appActions.changeLinkedInAuthStatus(false)\r\n\tstore.dispatch(notLinkedAction)\r\n}\r\n\r\nasync function onSnailyProfileChange() {\r\n\tconst state = store.getState()\r\n\r\n\tconst hours = appSelectors.appProfile(state)?.workingHoursSet\r\n\r\n\t/*if profile is completely filled*/\r\n\tif (hours) {\r\n\t\tawait connectorAPI.getSnailyProfile()\r\n\t}\r\n\r\n\tawait connectorAPI.setUpInit()\r\n}\r\n\r\nfunction onSnailySignIn() {\r\n\tconst state = store.getState()\r\n\r\n\tconst token = appSelectors.token(state)\r\n\r\n\tif (!token) {\r\n\t\tconnectorAPI.setUpInit()\r\n\t}\r\n}\r\n\r\nfunction saveToRedux() {\r\n\tconst saveAction = appActions.createConnector(appConnector)\r\n\tstore.dispatch(saveAction)\r\n}\r\n\r\nfunction setUpEvents() {\r\n\tappConnector.eventHandlers.addLinkedInSignedOutEventHandler(\r\n\t\tonLinkedInSignedOut\r\n\t)\r\n\tappConnector.eventHandlers.addLinkedInProfileDetectedHandler(onLinkedDetect)\r\n\r\n\tappConnector.eventHandlers.addSnailySignedInEventHandler(onSnailySignIn)\r\n\r\n\tappConnector.eventHandlers.addSnailyProfileChangedEventHandler(\r\n\t\tonSnailyProfileChange\r\n\t)\r\n}\r\n\r\nexport { saveToRedux, setUpEvents }\r\n","import { saveToRedux, setUpEvents } from './redux-sync'\r\nimport { appConnector } from './singleton'\r\n\r\nconst fullReload = () => document.location.reload()\r\n\r\nappConnector.init().then(() => {\r\n\tsaveToRedux()\r\n\r\n\tif (appConnector.extension.isInstalled()) {\r\n\t\tsetUpEvents()\r\n\t\tappConnector.eventHandlers.addSnailySignedOutEventHandler(fullReload)\r\n\t}\r\n})\r\n\r\nexport { appConnector }\r\n","import { appConnector } from \"shared/connector\";\n\nexport const linkedInProfileOpener = {\n open: async (profile) => {\n const linkedInProfile = await appConnector.linkedIn.getCurrentProfile();\n let id = \"\";\n if (linkedInProfile) {\n id = profile.entityId ? profile.entityId : profile.publicIdentifier;\n } else {\n id = profile.publicIdentifier\n ? profile.publicIdentifier\n : profile.entityId;\n }\n\n window.open(`https://www.linkedin.com/in/${id}/`, \"_blank\");\n },\n};\n","import { useState } from \"react\";\nimport linkIcon from \"../../../assets/image/icons/svg/icons/Link.svg\";\nimport linkIconAccent from \"../../../assets/image/icons/svg/icons/linkIconAccent.svg\";\n\nimport \"./style.scss\";\nimport { linkedInProfileOpener } from \"../../../api/linkedInProfileOpener\";\nimport { useAppSelector } from \"shared/hooks\";\nimport { appSelectors } from \"../../../redux/reducers/app\";\n\nconst LinkedInBlock = () => {\n const [loadedPicture, setLoadedPicture] = useState(false);\n const appProfile = useAppSelector(appSelectors.appProfile);\n const linkedInfo = useAppSelector(appSelectors.linkedProfile);\n\n const personFullName = useAppSelector(appSelectors.fullName);\n\n const openLinkedinProfile = () => linkedInProfileOpener.open(linkedInfo);\n\n const openLinkedinProfilePersona = () =>\n linkedInProfileOpener.open(appProfile.impersonatedPersona.linkedInProfile);\n\n return (\n
    \n
    \n LinkedIn profile\n {appProfile?.impersonatedPersona ? (\n
    \n
    \n {appProfile.impersonatedPersona.linkedInProfile.pictureUrl && (\n setLoadedPicture(true)}\n />\n )}\n {!appProfile.impersonatedPersona.linkedInProfile.pictureUrl && (\n
    \n )}\n {appProfile.impersonatedPersona.linkedInProfile.pictureUrl &&\n !loadedPicture &&
    }\n
    \n \n \"linkIcon\"\n {personFullName}\n
    \n
    \n ) : (\n
    \n
    \n {linkedInfo.pictureUrl && (\n setLoadedPicture(true)}\n />\n )}\n {!linkedInfo.pictureUrl &&
    }\n {linkedInfo.pictureUrl && !loadedPicture && (\n
    \n )}\n
    \n
    \n \"linkIcon\"\n \n {linkedInfo.givenName} {linkedInfo.familyName}\n \n
    \n
    \n )}\n
    \n
    \n
    \n );\n};\n\nexport default LinkedInBlock;\n","import { appDay } from \"shared/day\";\nimport { CONSTS } from \"../config/objectConst\";\n\nexport const functions = {\n isDate(value) {\n switch (typeof value) {\n case \"number\":\n return true;\n case \"string\":\n return !isNaN(Date.parse(value));\n case \"object\":\n if (value instanceof Date) {\n return !isNaN(value.getTime());\n }\n break;\n default:\n return false;\n }\n },\n getMonth(monthIndex) {\n const months = [\n \"Jan\",\n \"Feb\",\n \"Mar\",\n \"Apr\",\n \"May\",\n \"Jun\",\n \"Jul\",\n \"Aug\",\n \"Sep\",\n \"Oct\",\n \"Nov\",\n \"Dec\",\n ];\n return months.find((item, index) => index === monthIndex);\n },\n\n // TODO: Probably could be managed via dayjs\n parseDateToDMY(date, divider = \".\") {\n const dateParsed = Date.parse(date);\n const dateObject = new Date(dateParsed);\n\n if (!dateParsed) {\n return \"...\";\n }\n\n // TODO #698 change global date format\n // return `${\n // dateObject.getMonth() + 1 < 10\n // ? `0${dateObject.getMonth() + 1}`\n // : dateObject.getMonth() + 1\n // }${divider}${\n // dateObject.getDate() < 10\n // ? `0${dateObject.getDate()}`\n // : dateObject.getDate()\n // }${divider}${dateObject.getFullYear()}`;\n\n return appDay(date).format(\"DD MMM YYYY\");\n // return `${\n // dateObject.getMonth() + 1 < 10\n // ? `0${dateObject.getMonth() + 1}`\n // : dateObject.getMonth() + 1\n // }${divider}${\n // dateObject.getDate() < 10\n // ? `0${dateObject.getDate()}`\n // : dateObject.getDate()\n // }${divider}${dateObject.getFullYear()}`;\n },\n\n // TODO: Probably could be managed via dayjs\n parseTimeToHM(date, divider = \":\") {\n const dateParsed = Date.parse(date);\n const dateObject = new Date(dateParsed);\n return `${\n dateObject.getHours() < 10\n ? `0${dateObject.getHours()}`\n : dateObject.getHours()\n }${divider}${\n dateObject.getMinutes() < 10\n ? `0${dateObject.getMinutes()}`\n : dateObject.getMinutes()\n }`;\n },\n\n validateHours(value) {\n const startTimeInHours = value && value.split(\"-\")[0].split(\":\")[0];\n const startTimeInMinutes = value && value.split(\"-\")[0].split(\":\")[1];\n const endTimeInHours = value && value.split(\"-\")[1].split(\":\")[0];\n const endTimeInMinutes = value && value.split(\"-\")[1].split(\":\")[1];\n const totalTime = this.getTotalTime(\n Number(startTimeInHours),\n Number(endTimeInHours),\n Number(startTimeInMinutes),\n Number(endTimeInMinutes)\n );\n\n if (!value) {\n return \"Input the time\";\n } else if (\n startTimeInMinutes < 0 ||\n endTimeInMinutes < 0 ||\n startTimeInMinutes > 59 ||\n endTimeInMinutes > 59 ||\n startTimeInHours < 0 ||\n startTimeInHours > 24 ||\n endTimeInHours < 0 ||\n endTimeInHours > 24 ||\n startTimeInHours > endTimeInHours ||\n startTimeInHours.indexOf(\"_\") !== -1 ||\n endTimeInHours.indexOf(\"_\") !== -1 ||\n startTimeInMinutes.indexOf(\"_\") !== -1 ||\n endTimeInMinutes.indexOf(\"_\") !== -1\n ) {\n return \"Invalid interval format\";\n } else if (totalTime / 60 > CONSTS.WORKING_HOURS) {\n return `Total interval can't exceed ${CONSTS.WORKING_HOURS} hours`;\n } else {\n return \"\";\n }\n },\n getTotalTime(\n startTimeInHours,\n endTimeInHours,\n startTimeInMinutes,\n endTimeInMinutes\n ) {\n if (endTimeInHours === 0) {\n return 24 - startTimeInHours;\n }\n return Math.abs(\n startTimeInHours * 60 +\n startTimeInMinutes -\n (endTimeInHours * 60 + endTimeInMinutes)\n );\n },\n isValidOnBoardingConditions(appProfile, onBoardingNumber) {\n //#113, for a reason appProfile is null, it should not lead to an error\n if (!appProfile) {\n return true;\n }\n const conditions = CONSTS.ON_BOARDING[onBoardingNumber].conditions;\n for (const key of Object.keys(conditions)) {\n if (conditions[key] !== appProfile[key]) {\n return false;\n }\n }\n return true;\n },\n calculatePercentage(number, total) {\n const dimension = 10;\n const result =\n total !== 0\n ? Math.round((number / total + Number.EPSILON) * 100 * dimension) /\n dimension\n : 0;\n return result;\n },\n roundToDecimal(number) {\n // Same to `Number(Number(number.toFixed(1)))`\n const result = Math.round(number * 10 + Number.EPSILON) / 10;\n return result;\n },\n\n getFileName() {\n const date = new Date();\n return `${CONSTS.PROJECT_NAME}Export_${\n String(date.getDate()).padStart(2, \"0\") +\n \"_\" +\n String(date.getMonth() + 1).padStart(2, \"0\") +\n \"_\" +\n date.getFullYear() +\n \"_\" +\n date.getHours() +\n \"_\" +\n date.getMinutes() +\n \"_\" +\n date.getSeconds()\n }.csv`;\n },\n};\nexport const saveData = (function () {\n const a = document.createElement(\"a\");\n document.body.appendChild(a);\n a.style = \"display: none\";\n return function (data, fileName) {\n const json = data,\n blob = new Blob([json], { type: \"octet/stream\" }),\n url = window.URL.createObjectURL(blob);\n a.href = url;\n a.download = fileName;\n a.click();\n window.URL.revokeObjectURL(url);\n };\n})();\n","import type { Team } from 'features/team'\r\n\r\nconst adaptPersona = ({\r\n\tadded,\r\n\temail,\r\n\tlinkedin_profile,\r\n\tnickname,\r\n\tpending,\r\n\tpersona_id,\r\n\trole,\r\n\tsubscription\r\n}: Team.Persona) => ({\r\n\tadded,\r\n\tavatar: linkedin_profile?.picture_url,\r\n\temail,\r\n\tentityId: linkedin_profile?.linkedin_entity_id,\r\n\tid: persona_id,\r\n\tlinkedin_profile,\r\n\tnickname,\r\n\tpending,\r\n\tpublicIdentifier: linkedin_profile?.linkedin_public_identifier,\r\n\trole,\r\n\tsubscription\r\n})\r\n\r\nexport { adaptPersona }\r\n","import { functions } from \"../tools/functions\";\nimport isDate from \"lodash/isDate\";\nimport lFind from \"lodash/find\";\nimport { CONSTS } from \"../config/objectConst\";\nimport { adaptPersona } from \"./mapping.typed\";\n\nconst propertyToReadableDate = (item, property) => {\n const isValidProp = item.hasOwnProperty(property) && item[property];\n\n return isValidProp ? mapping.initDateValue(new Date(item[property])) : \"\";\n};\n\nexport const mapping = {\n campaignTransform: (item) => ({\n id: item.id,\n name: item.name,\n count: item.target_audience_count,\n statistics: item.statistics,\n email: item?.owner?.email,\n avatar: item?.owner?.linkedin_profile?.picture_url,\n entityId: item?.owner?.linkedin_profile?.linkedin_entity_id,\n nickname: item?.owner?.nickname,\n personaId: item?.owner?.persona_id,\n publicIdentifier: item?.owner?.linkedin_profile?.linkedin_public_identifier,\n linkedin_profile: item?.owner?.linkedin_profile,\n created: item.created,\n target_audience_count: item.target_audience_count,\n in_queue_count: item.in_queue_count,\n archive: item.archived,\n allowEditSteps: !item.archived && item.state !== \"Completed\",\n allowAddSteps: !item.archived && item.state === \"Compose\",\n events: item.actions,\n complete_reason: item.complete_reason ? item.complete_reason : false,\n pause_reason: item.pause_reason || \"\",\n information: [\n {\n id: 1,\n label: \"Status:\",\n value: mapping.initStatusValue(item.state, item.complete_reason),\n color:\n mapping.initColorValue[\n mapping.initStatusValue(item.state, item.complete_reason)\n ],\n pause_reason: item.pause_reason || \"\",\n },\n {\n id: 2,\n label: \"Contacts:\",\n value: item.target_audience_count,\n },\n {\n id: 3,\n label: \"Start date:\",\n value: propertyToReadableDate(item, \"started\"),\n },\n {\n id: 4,\n label: \"End date:\",\n value: propertyToReadableDate(item, \"completed\"),\n },\n ],\n completed_date: item.completed ? new Date(item.completed) : false,\n actions:\n item.steps.length > 0 ? mapping.buildCampaignsSteps(item.steps) : [],\n }),\n buildCampaignsArray: (array) => array.map(mapping.campaignTransform),\n buildCampaignsStatistics(object) {\n const {\n not_started,\n in_progress,\n succeed,\n ignored,\n cancelled,\n skipped,\n failed,\n } = {\n ...object,\n };\n\n return {\n not_started,\n in_progress,\n succeed,\n ignored,\n cancelled,\n skipped,\n failed,\n };\n },\n buildActionStatistics(object) {\n const {\n not_started,\n succeed,\n cancelled,\n in_progress,\n ignored,\n skipped,\n failed,\n } = {\n ...object,\n };\n return {\n statistics: {\n not_started,\n succeed,\n cancelled,\n in_progress,\n ignored,\n skipped,\n failed,\n },\n };\n },\n\n activeName(type) {\n switch (type) {\n case CONSTS.AVAILABLE_ACTIONS.Connect.Type:\n return CONSTS.AVAILABLE_ACTIONS.Connect.Title;\n\n case CONSTS.AVAILABLE_ACTIONS.Message.Type:\n return CONSTS.AVAILABLE_ACTIONS.Message.Title;\n\n case CONSTS.AVAILABLE_ACTIONS.VisitProfile.Type:\n return CONSTS.AVAILABLE_ACTIONS.VisitProfile.Title;\n\n case CONSTS.AVAILABLE_ACTIONS.Follow.Type:\n return CONSTS.AVAILABLE_ACTIONS.Follow.Title;\n\n case CONSTS.AVAILABLE_ACTIONS.ReactOnPost.Type:\n return CONSTS.AVAILABLE_ACTIONS.ReactOnPost.Title;\n\n case CONSTS.AVAILABLE_ACTIONS.EndorseSkill.Type:\n return CONSTS.AVAILABLE_ACTIONS.EndorseSkill.Title;\n\n case CONSTS.AVAILABLE_ACTIONS.ScrapeProfile.Type:\n return CONSTS.AVAILABLE_ACTIONS.ScrapeProfile.Title;\n\n default:\n throw new Error(`Not supported action type ${type}`);\n }\n },\n buildCampaignsSteps(steps) {\n const campaignSteps = steps.map((item, index) => {\n if (item.type !== \"Delay\") {\n return {\n id: index + 1,\n name: mapping.activeName(item.type),\n type: item.type,\n mainCustomFields:\n item.type === \"ReactOnPost\" && CONSTS.MAIN_CUSTOM_FIELDS,\n index: `Action_${index + 1}`,\n information: [],\n arrow:\n item.type === CONSTS.AVAILABLE_ACTIONS.Connect.Type ||\n item.type === CONSTS.AVAILABLE_ACTIONS.Message.Type ||\n item.type === CONSTS.AVAILABLE_ACTIONS.ReactOnPost.Type,\n open: false,\n params: {\n launchActionIn: false,\n mainCustomFields:\n item.type !== \"ReactOnPost\" && CONSTS.MAIN_CUSTOM_FIELDS,\n overflowCustomFields:\n item.type !== \"ReactOnPost\" && CONSTS.OVERFLOW_CUSTOM_FIELDS,\n currentEmotion: item.type === \"ReactOnPost\" && item.reaction,\n emotion: item.type === \"ReactOnPost\" && CONSTS.EMOTION,\n textarea: item.type !== \"ReactOnPost\" && String,\n period: item.type !== \"ReactOnPost\" ? Number : false,\n sendMessageTo: false,\n },\n values: {\n launchActionIn: 0,\n mainCustomFields: CONSTS.MAIN_CUSTOM_FIELDS,\n overflowCustomFields: CONSTS.OVERFLOW_CUSTOM_FIELDS,\n textarea: item.message_template,\n period: item.timeout,\n currentEmotion: item.type === \"ReactOnPost\" && item.reaction,\n sendMessageTo: \"\",\n delay: 0,\n },\n validation: {\n actionName: true,\n textarea: true,\n },\n status: false,\n };\n }\n return false;\n });\n\n const connectStep = lFind(campaignSteps, {\n type: CONSTS.AVAILABLE_ACTIONS.Connect.Type,\n });\n if (connectStep) {\n const delayStep = lFind(steps, { type: \"Delay\" });\n connectStep.values.delay = delayStep\n ? delayStep.timeout\n : CONSTS.DEFAULT_DATE_ACTIONS_VALUE.CONNECT.DELAY.DEFAULT;\n }\n return campaignSteps.filter((i) => i);\n },\n\n campaignsForTable: (array) =>\n array.map((item) => ({\n id: item.id,\n name: item.name,\n status: lFind(item.information, [\"id\", 1]).value,\n steps: item.actions,\n qtyContacts: lFind(item.information, [\"id\", 2]).value,\n events: item.events,\n complete_reason: item.complete_reason,\n statistics: item.statistics,\n nickname: item.nickname || \"\",\n personaId: item.personaId || \"\",\n email: item.email || \"\",\n avatar: item.avatar || \"\",\n entityId: item.entityId || \"\",\n publicIdentifier: item.publicIdentifier || \"\",\n linkedin_profile: item.linkedin_profile || \"\",\n target_audience_count: item.target_audience_count,\n pause_reason: item.pause_reason || \"\",\n in_queue_count: item.in_queue_count,\n created: item.created,\n date: [\n lFind(item.information, [\"id\", 3]).value,\n item.completed_date || false,\n ],\n })),\n buildRecentImports: (array) => {\n const newArray = array.map((item) => {\n const newItem = {};\n newItem.id = item.id;\n newItem.name = item.name;\n return newItem;\n });\n return newArray;\n },\n buildContacts: (array) => {\n const newArray = array.map((item) => {\n const newItem = {};\n newItem.actions = item.actions;\n newItem.id = item.id;\n newItem.date = new Date(item.created);\n newItem.avatar = item.picture_url;\n newItem.fullName = item.full_name\n ? item.full_name\n : item.linkedin_public_identifier;\n newItem.position = item.occupation;\n newItem.account = item.is_premium;\n newItem.connection = item.distance;\n newItem.entityId = item.linkedin_entity_id;\n newItem.publicIdentifier = item.linkedin_public_identifier;\n newItem.location = item.location;\n newItem.lastJob = item.last_job;\n newItem.created = item.created;\n newItem.contacted = item.contacted;\n newItem.customField1 = item.custom_field_1;\n newItem.customField2 = item.custom_field_2;\n newItem.customField3 = item.custom_field_3;\n\n return newItem;\n });\n return newArray;\n },\n buildPersonas: (array) => array.map(adaptPersona),\n buildActivity: (array) => {\n const newArray = array.map((item, index) => {\n const { campaign, execution } = item;\n\n const indexAction = lFind(execution.step_executions, { type: \"Delay\" })\n ? item.step_number > 0\n ? item.step_number\n : 1\n : item.step_number + 1;\n const header =\n item.operation_type === CONSTS.AVAILABLE_ACTIONS.Connect.Type\n ? \"Note message\"\n : CONSTS.AVAILABLE_ACTIONS.Message.Title;\n return {\n id: index,\n contact_id: execution.linkedin_contact.id,\n fullName: execution.linkedin_contact.full_name\n ? execution.linkedin_contact.full_name\n : execution.linkedin_contact.linkedin_public_identifier,\n campaign_name: `${campaign.name}`,\n campaign_id: campaign.id,\n activity: mapping.activeName(item.operation_type),\n campaignExecutions: execution.step_executions,\n start_in: item.run_in_minutes,\n state: execution.state,\n human_state: execution.human_state,\n actions: item.actions,\n indexAction,\n campaignExecutionId: execution.id,\n stepNumber: item.step_number,\n message: item.message,\n header,\n conversation_url: execution.conversation_url,\n avatar: execution.linkedin_contact.picture_url,\n entityId: execution.linkedin_contact.linkedin_entity_id,\n publicIdentifier: execution.linkedin_contact.linkedin_public_identifier,\n };\n });\n return newArray;\n },\n buildCampaignContacts: (contacts, executions) => {\n const newArray = contacts.map((item) => {\n const newItem = {};\n newItem.id = item.id;\n newItem.date = new Date(item.created);\n newItem.avatar = item.picture_url;\n newItem.fullName = item.full_name;\n\n newItem.position = item.occupation;\n newItem.account = item.is_premium;\n newItem.connection = item.distance;\n newItem.campaignExecutions = {};\n newItem.entityId = item.linkedin_entity_id;\n newItem.publicIdentifier = item.linkedin_public_identifier;\n newItem.lastJob = item.linkedin_contact.last_job;\n newItem.contacted = item.linkedin_contact.contacted;\n newItem.location = item.linkedin_contact.location;\n newItem.customField1 = item.custom_field_1;\n newItem.customField2 = item.custom_field_2;\n newItem.customField3 = item.custom_field_3;\n\n if (executions.length > 0) {\n newItem.campaignExecutions = executions.find(\n (elem) => elem.id === item.id\n );\n }\n return newItem;\n });\n return newArray;\n },\n buildOption: (array, type) => {\n const newArray = array.map((item, index) => {\n const newItem = {};\n switch (type) {\n case \"locations\":\n newItem.key = index + 1;\n newItem.text = item.key;\n newItem.value = item.key;\n break;\n case \"campaigns\":\n newItem.key = index + 1;\n newItem.text = item.name;\n newItem.value = item.id;\n newItem.color =\n mapping.initColorValue[\n mapping.initStatusValue(item.state, item.complete_reason)\n ];\n break;\n\n default:\n break;\n }\n return newItem;\n });\n return newArray;\n },\n initStatusValue: (state, complete_reason) => {\n if (\n state === \"Completed\" &&\n (complete_reason === \"User\" || complete_reason === \"System\")\n ) {\n return \"Completed\";\n }\n\n return state;\n },\n\n initDateValue: (value) => {\n return isDate(value)\n ? functions.parseDateToDMY(value, \"/\") +\n \" \" +\n functions.parseTimeToHM(value)\n : String(value);\n },\n\n initColorValue: {\n Compose: \"var(--light-grey)\",\n Running: \"#04c300\",\n Stopped: \"var(--status-paused)\",\n Completed: \"var(--status-completed)\",\n },\n};\n","import { CONSTS } from \"../../config/objectConst\";\nimport { httpRequest } from \"../httpRequest\";\nimport store from \"../../redux/store.ts\";\nimport { mapping } from \"../../actions/mapping\";\n\nexport const apiActivity = {\n getActivities: async (data) => {\n const { take } = { ...data };\n const params = `?${take ? \"&$take=\" + take : \"\"}`;\n try {\n const response = await httpRequest({\n url: `${CONSTS.API.URL}workspace/activities-queue${params}`,\n method: \"GET\",\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n });\n\n if (response.data) {\n store.dispatch({\n type: \"ALL_ACTIVITIES\",\n payload: {\n activity: response.data\n ? mapping.buildActivity(response.data.documents)\n : [],\n\n total: response.data.total,\n },\n });\n }\n\n if (!response.data) {\n store.dispatch({\n type: \"ALL_ACTIVITIES\",\n payload: {\n activity: [],\n total: -1,\n },\n });\n }\n } catch (error) {\n store.dispatch({\n type: \"ALL_ACTIVITIES\",\n payload: {\n activity: [],\n total: -1,\n },\n });\n throw error;\n }\n },\n\n getStepMessage: async (campaignExecutionId, stepNumber) => {\n return await httpRequest({\n url: `${CONSTS.API.URL}executions/${campaignExecutionId}/steps/${stepNumber}/message`,\n method: \"GET\",\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n });\n },\n};\n","import store from \"../redux/store.ts\";\nimport { app } from \"./app\";\nimport { apiActivity } from \"../api/activity/apiActivity\";\nimport { appSelectors } from \"../redux/reducers/app.ts\";\nimport { notifyError } from \"shared/errors/notificate.ts\";\n\nexport const activity = {\n getActivities: async (fromEvent) => {\n if (!fromEvent) {\n app.changePageContentLoaderStatus(true);\n app.changeTableContentLoaderStatus(true);\n }\n\n const oldRequest = appSelectors.errorRequest(store.getState());\n\n !oldRequest.activityQueue &&\n app.updateErrorRequest({\n activityQueue: true,\n });\n\n try {\n await apiActivity.getActivities();\n\n app.updateErrorRequest({\n activityQueue: false,\n });\n\n if (!fromEvent) {\n app.changePageContentLoaderStatus(false);\n app.changeTableContentLoaderStatus(false);\n }\n } catch (error) {\n notifyError(error);\n app.changePageContentLoaderStatus(false);\n app.changeTableContentLoaderStatus(false);\n }\n },\n};\n","import { activity } from 'actions/activity'\r\nimport { useCallback } from 'react'\r\nimport { useLocation } from 'react-router-dom'\r\n\r\n// TODO: better to revalidate query in RTK\r\nexport function useRefetch() {\r\n\tconst { pathname } = useLocation()\r\n\r\n\treturn useCallback(() => {\r\n\t\tif (pathname === '/activities-queue') {\r\n\t\t\tactivity.getActivities()\r\n\t\t}\r\n\t}, [pathname])\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"root\":\"root-nybNrn\",\"row\":\"row-kKzUjF\",\"loader\":\"loader-SUYytj\",\"label\":\"label-I8zQn6\"};","import CircularProgress from '@mui/material/CircularProgress'\r\nimport clsx from 'clsx'\r\nimport { activityHooks } from 'features/activity'\r\nimport { notificationUtils } from 'features/notifications'\r\nimport { workspaceUtils } from 'features/workspace'\r\nimport { useId, useMemo, useState } from 'react'\r\nimport { notifyError } from 'shared/errors'\r\nimport { typo } from 'shared/styles'\r\nimport { CustomSelect } from 'shared/ui'\r\n\r\nimport { api } from '../../../api/api'\r\nimport { CONSTS } from '../../../config/objectConst'\r\nimport css from './DailyLimitsEditor.module.scss'\r\n\r\nconst showActivitySnack = () => notificationUtils.snackById('3.15')\r\n\r\ninterface Option {\r\n\tlabel: string\r\n\tvalue: string\r\n}\r\n\r\ninterface TempStats {\r\n\tfollow_limit?: number\r\n\tinvitations_limit?: number\r\n\tmessages_limit?: number\r\n\treact_on_post_limit?: number\r\n}\r\n\r\nconst getInit = (options: Option[], value: TempStats[keyof TempStats]) => {\r\n\tvalue ??= 0\r\n\r\n\treturn options.find(el => Number(el.value) === value)\r\n}\r\n\r\nexport function DailyLimitsEditor({\r\n\tcustomStatistics\r\n}: {\r\n\tcustomStatistics: TempStats\r\n}) {\r\n\tconst currentLimits = useMemo(\r\n\t\t() => ({\r\n\t\t\tfollowPerDayLimit: getInit(\r\n\t\t\t\tCONSTS.DAILY_LIMITS.FOLLOW,\r\n\t\t\t\tcustomStatistics.follow_limit\r\n\t\t\t),\r\n\t\t\tinvitationPerDayLimit: getInit(\r\n\t\t\t\tCONSTS.DAILY_LIMITS.INVITATIONS,\r\n\t\t\t\tcustomStatistics.invitations_limit\r\n\t\t\t),\r\n\t\t\tlikesPerDayLimit: getInit(\r\n\t\t\t\tCONSTS.DAILY_LIMITS.LIKES,\r\n\t\t\t\tcustomStatistics.react_on_post_limit\r\n\t\t\t),\r\n\t\t\tmessagesPerDayLimit: getInit(\r\n\t\t\t\tCONSTS.DAILY_LIMITS.MESSAGES,\r\n\t\t\t\tcustomStatistics.messages_limit\r\n\t\t\t)\r\n\t\t}),\r\n\t\t[customStatistics]\r\n\t)\r\n\r\n\tconst id = useId()\r\n\r\n\tconst refetchActivity = activityHooks.useRefetch()\r\n\r\n\tconst [loaderMessages, setLoaderMessages] = useState(false)\r\n\tconst [loaderInvitation, setLoaderInvitation] = useState(false)\r\n\tconst [loaderLikes, setLoaderLikes] = useState(false)\r\n\tconst [loaderFollow, setLoaderFollow] = useState(false)\r\n\r\n\tconst update = (path: Partial) =>\r\n\t\tapi\r\n\t\t\t.setDailyLimits({ ...currentLimits, ...path })\r\n\t\t\t.then(() => {\r\n\t\t\t\tshowActivitySnack()\r\n\t\t\t\tworkspaceUtils.refetchStatistics()\r\n\t\t\t})\r\n\t\t\t.catch(notifyError)\r\n\treturn (\r\n\t\t
    \r\n\t\t\t
    \r\n\t\t\t\t\r\n\t\t\t\t\tMax invitations per day:\r\n\t\t\t\t\r\n\r\n\t\t\t\t{currentLimits.invitationPerDayLimit && (\r\n\t\t\t\t\t {\r\n\t\t\t\t\t\t\tif (!invitationPerDayLimit) {\r\n\t\t\t\t\t\t\t\treturn\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tsetLoaderInvitation(true)\r\n\r\n\t\t\t\t\t\t\tupdate({ invitationPerDayLimit }).finally(() => {\r\n\t\t\t\t\t\t\t\tsetLoaderInvitation(false)\r\n\t\t\t\t\t\t\t\trefetchActivity()\r\n\t\t\t\t\t\t\t})\r\n\t\t\t\t\t\t}}\r\n\t\t\t\t\t\toptions={CONSTS.DAILY_LIMITS.INVITATIONS}\r\n\t\t\t\t\t\tvalue={currentLimits.invitationPerDayLimit}\r\n\t\t\t\t\t/>\r\n\t\t\t\t)}\r\n\r\n\t\t\t\t{loaderInvitation && (\r\n\t\t\t\t\t\r\n\t\t\t\t)}\r\n\t\t\t
    \r\n\r\n\t\t\t
    \r\n\t\t\t\t\r\n\t\t\t\t\tMax messages per day:\r\n\t\t\t\t\r\n\r\n\t\t\t\t{currentLimits.messagesPerDayLimit && (\r\n\t\t\t\t\t {\r\n\t\t\t\t\t\t\tif (!messagesPerDayLimit) {\r\n\t\t\t\t\t\t\t\treturn\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tsetLoaderMessages(true)\r\n\r\n\t\t\t\t\t\t\tupdate({ messagesPerDayLimit }).finally(() => {\r\n\t\t\t\t\t\t\t\tsetLoaderMessages(false)\r\n\t\t\t\t\t\t\t\trefetchActivity()\r\n\t\t\t\t\t\t\t})\r\n\t\t\t\t\t\t}}\r\n\t\t\t\t\t\toptions={CONSTS.DAILY_LIMITS.MESSAGES}\r\n\t\t\t\t\t\tvalue={currentLimits.messagesPerDayLimit}\r\n\t\t\t\t\t/>\r\n\t\t\t\t)}\r\n\r\n\t\t\t\t{loaderMessages && (\r\n\t\t\t\t\t\r\n\t\t\t\t)}\r\n\t\t\t
    \r\n\r\n\t\t\t
    \r\n\t\t\t\t\r\n\t\t\t\t\tMax likes per day:\r\n\t\t\t\t\r\n\r\n\t\t\t\t{currentLimits.likesPerDayLimit && (\r\n\t\t\t\t\t {\r\n\t\t\t\t\t\t\tif (!likesPerDayLimit) {\r\n\t\t\t\t\t\t\t\treturn\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tsetLoaderLikes(true)\r\n\r\n\t\t\t\t\t\t\tupdate({ likesPerDayLimit }).finally(() => {\r\n\t\t\t\t\t\t\t\tsetLoaderLikes(false)\r\n\t\t\t\t\t\t\t\trefetchActivity()\r\n\t\t\t\t\t\t\t})\r\n\t\t\t\t\t\t}}\r\n\t\t\t\t\t\toptions={CONSTS.DAILY_LIMITS.LIKES}\r\n\t\t\t\t\t\tvalue={currentLimits.likesPerDayLimit}\r\n\t\t\t\t\t/>\r\n\t\t\t\t)}\r\n\r\n\t\t\t\t{loaderLikes && (\r\n\t\t\t\t\t\r\n\t\t\t\t)}\r\n\t\t\t
    \r\n\t\t\t
    \r\n\t\t\t\t\r\n\t\t\t\t\tMax following per day:\r\n\t\t\t\t\r\n\r\n\t\t\t\t{currentLimits.followPerDayLimit && (\r\n\t\t\t\t\t {\r\n\t\t\t\t\t\t\tif (!followPerDayLimit) {\r\n\t\t\t\t\t\t\t\treturn\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tsetLoaderFollow(true)\r\n\r\n\t\t\t\t\t\t\tupdate({ followPerDayLimit }).finally(() => {\r\n\t\t\t\t\t\t\t\tsetLoaderFollow(false)\r\n\t\t\t\t\t\t\t\trefetchActivity()\r\n\t\t\t\t\t\t\t})\r\n\t\t\t\t\t\t}}\r\n\t\t\t\t\t\toptions={CONSTS.DAILY_LIMITS.FOLLOW}\r\n\t\t\t\t\t\tvalue={currentLimits.followPerDayLimit}\r\n\t\t\t\t\t/>\r\n\t\t\t\t)}\r\n\r\n\t\t\t\t{loaderFollow && (\r\n\t\t\t\t\t\r\n\t\t\t\t)}\r\n\t\t\t
    \r\n\t\t
    \r\n\t)\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"root\":\"root-EtQQWo\",\"name\":\"name-kfW8I8\",\"email\":\"email-fQF5bp\",\"line\":\"line-SgPh_5\",\"date\":\"date-lhZYcL\",\"calendar\":\"calendar-NCNXkS\",\"modal\":\"modal-y4aPOs\",\"buttons\":\"buttons-GaVWpz\",\"button\":\"button-VW1mjI\",\"show\":\"show-kW4bqb\"};","import type { ConfigType, Dayjs } from 'dayjs'\r\nimport type { Range } from 'react-date-range'\r\n\r\nimport { appDay } from 'shared/day.ts'\r\n\r\nexport type LocalRange = {\r\n\tend: Dayjs\r\n\tstart: Dayjs\r\n}\r\n\r\nfunction saveSameTimeInUtc(input: ConfigType) {\r\n\tconst asDay = appDay(input)\r\n\tconst offset = asDay.utcOffset()\r\n\r\n\treturn asDay.utc().add(offset, 'minutes')\r\n}\r\n\r\nconst fromDay = ({ end, start }: LocalRange): Range[] => [\r\n\t{\r\n\t\tcolor: '#0cb39f',\r\n\t\tendDate: end.toDate(),\r\n\t\tkey: 'selection',\r\n\t\tstartDate: start.toDate()\r\n\t}\r\n]\r\n\r\nconst fromPicker = ([{ endDate, startDate }]: Range[]): LocalRange => ({\r\n\tend: saveSameTimeInUtc(endDate).endOf('day'),\r\n\tstart: saveSameTimeInUtc(startDate).startOf('day')\r\n})\r\n\r\nexport { fromDay, fromPicker }\r\n","import './style.scss'\r\n\r\nimport CircularProgress from '@mui/material/CircularProgress'\r\nimport { connectorAPI } from 'actions/connector.ts'\r\nimport calendar from 'assets/image/icons/svg/calendar.svg'\r\nimport clsx from 'clsx'\r\nimport 'react-date-range/dist/styles.css' // main css file\r\nimport 'react-date-range/dist/theme/default.css' // theme css file\r\nimport {\r\n\tworkspaceApi,\r\n\tWorkSpaceUI,\r\n\tworkspaceUtils\r\n} from 'features/workspace/index.ts'\r\nimport { useEffect, useId, useRef, useState } from 'react'\r\nimport { DateRangePicker, type Range } from 'react-date-range'\r\nimport { useAutomationEnded } from 'shared/connector/hooks.ts'\r\nimport { useAppSelector } from 'shared/hooks/store.ts'\r\nimport { useLatest } from 'shared/hooks/useLatest.ts'\r\nimport { typo } from 'shared/styles'\r\nimport { Button } from 'shared/ui/index.ts'\r\n\r\nimport type { LocalRange } from './adapter.ts'\r\n\r\nimport { appSelectors } from '../../../redux/reducers/app.ts'\r\nimport LinkedInBlock from '../../atoms/LinkedInBlock'\r\nimport { DailyLimitsEditor } from '../dailyLimitsEditor'\r\nimport css from './AccountProfile.module.scss'\r\nimport * as adapter from './adapter.ts'\r\n\r\nexport function AccountProfile() {\r\n\tconst popoverId = useId()\r\n\tconst popoverRef = useRef(null)\r\n\r\n\tconst end = useAppSelector(workspaceUtils.selectNowWithOffset)\r\n\tconst email = useAppSelector(\r\n\t\tstate => appSelectors.persona(state)?.email ?? ''\r\n\t)\r\n\r\n\tconst [rangeState, setRangeState] = useState(() => ({\r\n\t\tend: end.endOf('day'),\r\n\t\tstart: end.startOf('month')\r\n\t}))\r\n\r\n\tconst [pickerState, setPickerState] = useState(() =>\r\n\t\tadapter.fromDay(rangeState)\r\n\t)\r\n\r\n\tconst fullName = useAppSelector(appSelectors.fullName)\r\n\r\n\tconst {\r\n\t\tdata: statistics,\r\n\t\tisFetching,\r\n\t\tisSuccess\r\n\t} = workspaceApi.useStatisticsQuery({\r\n\t\tstart: rangeState.start.toISOString(),\r\n\r\n\t\t// eslint-disable-next-line perfectionist/sort-objects\r\n\t\tend: rangeState.end.toISOString()\r\n\t})\r\n\r\n\tconst setDate = () => {\r\n\t\tif (isFetching) {\r\n\t\t\treturn\r\n\t\t}\r\n\t\tconst adapted = adapter.fromPicker(pickerState)\r\n\t\tsetRangeState(adapted)\r\n\t}\r\n\r\n\tuseEffect(() => {\r\n\t\tif (!isFetching && isSuccess) {\r\n\t\t\tpopoverRef.current?.hidePopover()\r\n\t\t}\r\n\t}, [isFetching, isSuccess])\r\n\r\n\tuseAutomationEnded(() => {\r\n\t\tworkspaceUtils.refetchStatistics()\r\n\t\tconnectorAPI.getSnailyProfile()\r\n\t})\r\n\r\n\tconst datedRange = [rangeState.start, rangeState.end]\r\n\t\t.map(date => date.format('DD MMM YYYY'))\r\n\t\t.join(' - ')\r\n\r\n\tconst cancel = () => popoverRef.current?.hidePopover()\r\n\r\n\tconst rangeRef = useLatest(rangeState)\r\n\r\n\tuseEffect(() => {\r\n\t\tconst restoreOriginal = (event: Event) => {\r\n\t\t\tconst isClose = 'newState' in event && event.newState === 'closed'\r\n\t\t\tif (isClose) {\r\n\t\t\t\tconst oldValue = adapter.fromDay(rangeRef.current)\r\n\r\n\t\t\t\tsetPickerState(oldValue)\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpopoverRef.current?.addEventListener('toggle', restoreOriginal)\r\n\r\n\t\treturn () =>\r\n\t\t\tpopoverRef.current?.removeEventListener('toggle', restoreOriginal)\r\n\t}, [rangeRef])\r\n\r\n\treturn (\r\n\t\t
    \r\n\t\t\t

    {fullName}

    \r\n\t\t\t{email &&

    {email}

    }\r\n\r\n\t\t\t
    \r\n\t\t\t\r\n\t\t\t\r\n\t\t\t
    \r\n\r\n\t\t\t

    \r\n\t\t\t\tPerformed \r\n\r\n\t\t\t\t{datedRange}\r\n\r\n\t\t\t\t\r\n\t\t\t\t\tcalendar\r\n\t\t\t\t\r\n\t\t\t

    \r\n\r\n\t\t\t {\r\n\t\t\t\t\te.preventDefault()\r\n\t\t\t\t\tsetDate()\r\n\t\t\t\t}}\r\n\t\t\t\t// @ts-ignore Recheck in React 19\r\n\t\t\t\tpopover='auto'\r\n\t\t\t\tref={popoverRef}\r\n\t\t\t>\r\n\t\t\t\t setPickerState([selection])}\r\n\t\t\t\t\tranges={pickerState}\r\n\t\t\t\t\t// showSelectionPreview={true}\r\n\t\t\t\t\tweekStartsOn={1}\r\n\t\t\t\t/>\r\n\t\t\t\t
    \r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t
    \r\n\t\t\t\r\n\r\n\t\t\t\r\n\t\t
    \r\n\t)\r\n}\r\n","import { CONSTS } from \"../../../config/objectConst\";\n\nexport const subscriptionHelper = {\n getStatusTags: (subscription) => {\n const result = [];\n if (subscription.is_active) {\n result.push({\n text: \"Active\",\n style: \"containerBilling__name-bold-green\",\n });\n } else {\n result.push({\n text: \"Inactive\",\n style: \"containerBilling__name-bold-grey\",\n });\n }\n\n if (subscription.state === CONSTS.SUBSCRIPTIONS.STATE.CANCELED) {\n result.push({\n text: \"Canceled\",\n style: \"containerBilling__name-bold-red\",\n });\n }\n\n if (subscription.state === CONSTS.SUBSCRIPTIONS.STATE.OVERDUE) {\n result.push({\n text: \"Overdue\",\n style: \"containerBilling__name-bold-orange\",\n });\n }\n\n return result;\n },\n\n showNextCharge: (subscription) => {\n const result = subscription.state === CONSTS.SUBSCRIPTIONS.STATE.ACTIVE;\n return result;\n },\n\n showNextChargePrice: (subscription) => {\n const result = subscription.actual_price !== 0;\n return result;\n },\n};\n","import type { WorkSpace } from 'features/workspace'\r\n\r\nimport { functions } from 'tools/functions'\r\n\r\nconst INITIAL_HOURS = '09:00-19:00'\r\n\r\nconst DAYS: WorkSpace.WeekDayName[] = [\r\n\t'monday',\r\n\t'tuesday',\r\n\t'wednesday',\r\n\t'thursday',\r\n\t'friday',\r\n\t'saturday',\r\n\t'sunday'\r\n]\r\n\r\ntype AppWorkingHours = Record\r\n\r\ninterface Day {\r\n\terrorMessage: string\r\n\tisSelected: boolean\r\n\tvalue: string\r\n}\r\n\r\nconst isWeekDay = (index: number) => index < 5\r\nconst getInitials = (isSelected?: (index: number) => boolean) =>\r\n\tDAYS.reduce((values, day, index) => {\r\n\t\tvalues[day] = {\r\n\t\t\terrorMessage: '',\r\n\t\t\tisSelected: isSelected ? isSelected(index) : false,\r\n\t\t\tvalue: INITIAL_HOURS\r\n\t\t}\r\n\r\n\t\treturn values\r\n\t}, {} as AppWorkingHours)\r\n\r\nfunction transformToWorkingHours(hours: AppWorkingHours) {\r\n\tconst workspaceHours: Partial = {}\r\n\r\n\tlet isValid = true,\r\n\t\toneOrMoreSelected = false\r\n\r\n\tfor (const day of DAYS) {\r\n\t\tconst value = hours[day]\r\n\r\n\t\tif (!value.isSelected) {\r\n\t\t\tworkspaceHours[day] = []\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\tconst validationMessage = functions.validateHours(value.value)\r\n\t\tconst [start, end] = value.value && value.value.split('-')\r\n\t\tconst [startTimeInHours, startTimeInMinutes] = start.split(':').map(Number)\r\n\t\tconst [endTimeInHours, endTimeInMinutes] = end.split(':').map(Number)\r\n\r\n\t\tconst totalTime = functions.getTotalTime(\r\n\t\t\tstartTimeInHours,\r\n\t\t\tendTimeInHours,\r\n\t\t\tstartTimeInMinutes,\r\n\t\t\tendTimeInMinutes\r\n\t\t)\r\n\r\n\t\thours[day].errorMessage = validationMessage\r\n\t\tif (validationMessage.length) {\r\n\t\t\tisValid = false\r\n\t\t}\r\n\t\toneOrMoreSelected = true\r\n\t\tworkspaceHours[day] = [\r\n\t\t\t{\r\n\t\t\t\tduration: totalTime,\r\n\t\t\t\tstart: startTimeInHours * 60 + startTimeInMinutes\r\n\t\t\t}\r\n\t\t]\r\n\t}\r\n\r\n\treturn {\r\n\t\tisValid,\r\n\t\toneOrMoreSelected,\r\n\t\tworkspaceHours\r\n\t}\r\n}\r\n\r\nexport { DAYS, getInitials, isWeekDay, transformToWorkingHours }\r\nexport type { AppWorkingHours, Day }\r\n","import type { WorkSpace } from 'features/workspace'\r\n\r\nimport { type Dispatch, type SetStateAction, useMemo } from 'react'\r\n\r\nimport { type AppWorkingHours, DAYS } from './utils'\r\n\r\nconst useHasSelected = (hours: AppWorkingHours) =>\r\n\tuseMemo(() => DAYS.some(key => hours[key].isSelected), [hours])\r\n\r\nconst useDateHandlers = (setter: Dispatch>) =>\r\n\tuseMemo(\r\n\t\t() => ({\r\n\t\t\thandleHoursChange: (day: WorkSpace.WeekDayName, value: string) =>\r\n\t\t\t\tsetter(previous => {\r\n\t\t\t\t\tconst next = { ...previous[day] }\r\n\t\t\t\t\tnext.value = value\r\n\r\n\t\t\t\t\treturn { ...previous, [day]: next }\r\n\t\t\t\t}),\r\n\r\n\t\t\ttoggleDay: (day: WorkSpace.WeekDayName) =>\r\n\t\t\t\tsetter(previous => {\r\n\t\t\t\t\tconst next = { ...previous[day] }\r\n\t\t\t\t\tnext.isSelected = !next.isSelected\r\n\r\n\t\t\t\t\treturn { ...previous, [day]: next }\r\n\t\t\t\t})\r\n\t\t}),\r\n\t\t[setter]\r\n\t)\r\n\r\nexport { useDateHandlers, useHasSelected }\r\n","import InputMask from \"react-input-mask\";\nimport \"./style.scss\";\nimport { StackIcon } from \"shared/ui\";\n\nconst DateInput = ({\n disabled,\n day,\n handleDateChange,\n errorMessage,\n value,\n}) => {\n const dateHandler = (e) => {\n const value = e.target.value;\n handleDateChange(day, value);\n };\n\n return (\n
    \n
    \n \n\n \n
    \n {errorMessage.length && !disabled ? (\n
    {errorMessage}
    \n ) : null}\n
    \n );\n};\n\nexport default DateInput;\n","import type { WorkSpace } from 'features/workspace'\r\n\r\nimport './style.scss'\r\n\r\nimport clsx from 'clsx'\r\n\r\nimport type { Day } from './utils'\r\n\r\nimport DateInput from '../../atoms/DateInput'\r\n\r\nexport const DateSelection = ({\r\n\tclassName,\r\n\tdateSelectionHandler,\r\n\tdayOfWeek,\r\n\thandleDateChange,\r\n\thours\r\n}: {\r\n\tclassName?: string\r\n\tdateSelectionHandler: (day: WorkSpace.WeekDayName) => void\r\n\r\n\tdayOfWeek: WorkSpace.WeekDayName\r\n\thandleDateChange: (day: WorkSpace.WeekDayName, value: string) => void\r\n\r\n\thours: Day\r\n}) => (\r\n\t\r\n\t\t\r\n\t\t\r\n\t
    \r\n)\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"root\":\"root-gOoKOk\",\"loader\":\"loader-UOoN6t\"};","import CircularProgress from '@mui/material/CircularProgress'\r\nimport { createSelector } from '@reduxjs/toolkit'\r\nimport { CONSTS } from 'config/objectConst'\r\nimport { activityHooks } from 'features/activity'\r\nimport { notificationUtils } from 'features/notifications'\r\nimport { workspaceApi } from 'features/workspace'\r\nimport { useState } from 'react'\r\nimport { useAppSelector, useSwitcher } from 'shared/hooks'\r\nimport { CustomSelect } from 'shared/ui'\r\n\r\nimport { appSelectors } from '../../../redux/reducers/app'\r\nimport store from '../../../redux/store'\r\nimport css from './SelectTimeZone.module.scss'\r\n\r\nexport interface Option {\r\n\tlabel: string\r\n\tvalue: string\r\n}\r\n\r\nconst selectCurrentOption = createSelector(\r\n\tappSelectors.timezoneOffset,\r\n\toffset =>\r\n\t\tCONSTS.TIME_ZONES.find(item => +item.value === offset) ??\r\n\t\tCONSTS.TIME_ZONES[0]\r\n)\r\n\r\nexport function SelectTimeZone() {\r\n\tconst openSwitcher = useSwitcher(false)\r\n\r\n\tconst [value, setValue] = useState(getInitial)\r\n\r\n\tconst refreshAccessToken = useAppSelector(appSelectors.refreshAccessToken)\r\n\r\n\tconst [send, { isLoading }] = workspaceApi.useTimezoneOffsetMutation()\r\n\tconst refetchActivity = activityHooks.useRefetch()\r\n\r\n\tconst handleChangeTimeZone = async (option: null | Option) => {\r\n\t\tif (option === null || option === value || isLoading) {\r\n\t\t\treturn\r\n\t\t}\r\n\r\n\t\tconst oldValue = value\r\n\t\tconst timezoneOffset = Number(option.value)\r\n\t\tsetValue(option)\r\n\r\n\t\ttry {\r\n\t\t\tawait send(timezoneOffset).unwrap()\r\n\r\n\t\t\tnotificationUtils.snackById('3.14')\r\n\t\t\tPromise.all([refreshAccessToken(), refetchActivity()])\r\n\t\t} catch (error) {\r\n\t\t\tsetValue(oldValue)\r\n\t\t}\r\n\t}\r\n\r\n\treturn (\r\n\t\t
    \r\n\t\t\t\r\n\r\n\t\t\t{isLoading && (\r\n\t\t\t\t\r\n\t\t\t)}\r\n\t\t
    \r\n\t)\r\n}\r\n\r\nfunction getInitial(): Option {\r\n\tconst state = store.getState()\r\n\treturn selectCurrentOption(state)\r\n}\r\n","import type { WorkSpace } from 'features/workspace'\r\n\r\nconst format = (time: [number, number]) =>\r\n\ttime.map(n => n.toString().padStart(2, '0')).join(':')\r\n\r\nconst getTime = (allMinutes: number): [number, number] => {\r\n\tconst hours = Math.floor(allMinutes / 60)\r\n\tconst minutes = allMinutes % 60\r\n\treturn [hours, minutes]\r\n}\r\n\r\nconst getHoursInterval = ({ duration, start }: WorkSpace.Day) =>\r\n\t[start, start + duration].map(getTime).map(format).join('-')\r\n\r\nexport { getHoursInterval }\r\n","import '../style.scss'\r\n\r\nimport type { CommonIcon } from 'shared/ui/StackIcon/keys'\r\n\r\nimport { useState } from 'react'\r\nimport { StackIcon } from 'shared/ui'\r\n\r\nimport AutomationMode from '../automationMode'\r\nimport SubscriptionBilling from '../subscriptionBilling'\r\nimport WorkingHours from './workingHours'\r\n\r\nconst enum Tab {\r\n\tAutomation,\r\n\tWorkingHours,\r\n\tSubscriptionBilling\r\n}\r\n\r\nconst Content = {\r\n\t[Tab.Automation]: AutomationMode,\r\n\t[Tab.SubscriptionBilling]: SubscriptionBilling,\r\n\t[Tab.WorkingHours]: WorkingHours\r\n}\r\n\r\nconst TABS = [\r\n\t{ icon: 'comp-network', key: Tab.Automation, title: 'Automation Mode' },\r\n\t{ icon: 'clock', key: Tab.WorkingHours, title: 'Working Hours' },\r\n\t{\r\n\t\ticon: 'dollar',\r\n\t\tkey: Tab.SubscriptionBilling,\r\n\t\ttitle: 'Subscription Billing'\r\n\t}\r\n]\r\n\r\nexport function WorkingHoursProfile() {\r\n\tconst [tab, setTab] = useState(Tab.Automation)\r\n\tconst Component = Content[tab]\r\n\r\n\treturn (\r\n\t\t
    \r\n\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t\t\t\t{TABS.map(({ icon, key, title }) => {\r\n\t\t\t\t\t\tconst isActive = tab === key\r\n\t\t\t\t\t\treturn (\r\n\t\t\t\t\t\t\t setTab(key)}\r\n\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t{title}\r\n\t\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t)\r\n\t\t\t\t\t})}\r\n\t\t\t\t
    \r\n\t\t\t
    \r\n\t\t\t
     
    \r\n\t\t\t\r\n\t\t
    \r\n\t)\r\n}\r\n","import { workspaceApi } from 'features/workspace'\r\n\r\nimport cloud from '../../../../assets/image/icons/svg/icons/cloud.svg'\r\nimport computer from '../../../../assets/image/icons/svg/icons/computer.svg'\r\nimport './style.scss'\r\nimport warning from '../../../../assets/image/icons/svg/icons/warning.svg'\r\nimport { FullLoader } from '../../../atoms/FullLoader/FullLoader.tsx'\r\n\r\nconst AutomationMode = () => {\r\n\tconst {\r\n\t\tdata: autoMode,\r\n\t\tisLoading,\r\n\t\tisSuccess\r\n\t} = workspaceApi.useAutomationModeQuery()\r\n\r\n\tif (isLoading) {\r\n\t\treturn \r\n\t}\r\n\tif (!isSuccess) {\r\n\t\treturn null\r\n\t}\r\n\r\n\tconst {\r\n\t\tcity_name: city,\r\n\t\tcountry_code: countryCode,\r\n\t\tip_address: ip,\r\n\t\tis_cloud: isCloud\r\n\t} = autoMode\r\n\treturn (\r\n\t\t
    \r\n\t\t\t
    \r\n\t\t\t\t{isCloud ? (\r\n\t\t\t\t\t<>\r\n\t\t\t\t\t\t

    \r\n\t\t\t\t\t\t\tProcessing:{' '}\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t{' '}\r\n\t\t\t\t\t\t\t\tcloud In cloud\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t

    \r\n\t\t\t\t\t\t

    \r\n\t\t\t\t\t\t\tIP Address: {ip}\r\n\t\t\t\t\t\t

    \r\n\t\t\t\t\t\t

    \r\n\t\t\t\t\t\t\tLocation:{' '}\r\n\t\t\t\t\t\t\t{`${city}, ${countryCode}`}\r\n\t\t\t\t\t\t

    \r\n\t\t\t\t\t\r\n\t\t\t\t) : (\r\n\t\t\t\t\t

    \r\n\t\t\t\t\t\tProcessing:{' '}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{' '}\r\n\t\t\t\t\t\t\tcomputer locally on your PC{' '}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t

    \r\n\t\t\t\t)}\r\n\t\t\t
    \r\n\t\t\t
    \r\n\t\t\t\twarning\r\n\t\t\t\t{isCloud ? (\r\n\t\t\t\t\t
    \r\n\t\t\t\t\t\t

    \r\n\t\t\t\t\t\t\tSnaily.io operates LinkedIn automation using cloud servers and\r\n\t\t\t\t\t\t\tassigns a dedicated IP address for the process. Through the\r\n\t\t\t\t\t\t\tsnaily.io extension, all manual actions performed on LinkedIn are\r\n\t\t\t\t\t\t\tseamlessly executed using the same allocated IP address.\r\n\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\tThis ensures consistency and reliability in your LinkedIn\r\n\t\t\t\t\t\t\tactivities while maintaining anonymity and security.\r\n\t\t\t\t\t\t

    \r\n\t\t\t\t\t
    \r\n\t\t\t\t) : (\r\n\t\t\t\t\t
    \r\n\t\t\t\t\t\t

    \r\n\t\t\t\t\t\t\tSnaily.io operates LinkedIn automation from your PC, which is\r\n\t\t\t\t\t\t\tsuitable if you manage a single LinkedIn account and can maintain\r\n\t\t\t\t\t\t\tyour PC online during working hours.\r\n\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t
    However, this mode has a drawback: snaily.io does not\r\n\t\t\t\t\t\t\tfunction when your PC is turned off or if you lose internet\r\n\t\t\t\t\t\t\tconnectivity.\r\n\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\tIf you wish to keep automation running even when your PC is turned\r\n\t\t\t\t\t\t\toff or you experience an internet outage, you can transition\r\n\t\t\t\t\t\t\tsnaily.io automation to the cloud. This option is available for{' '}\r\n\t\t\t\t\t\t\tPRO or{' '}\r\n\t\t\t\t\t\t\tTEAM plan subscribers.\r\n\t\t\t\t\t\t

    \r\n\t\t\t\t\t
    \r\n\t\t\t\t)}\r\n\t\t\t
    \r\n\t\t
    \r\n\t)\r\n}\r\n\r\nexport default AutomationMode\r\n","import { useEffect, useState } from \"react\";\nimport { api } from \"api/api\";\nimport { CONSTS } from \"config/objectConst\";\nimport { functions } from \"tools/functions\";\nimport { ResponsiveButton } from \"../../../atoms/responsiveButton/index.tsx\";\nimport { Link } from \"react-router-dom\";\nimport CircularProgress from \"@mui/material/CircularProgress\";\nimport { useSelector } from \"react-redux\";\nimport { subscriptionHelper } from \"../../TableTeams/subscriptionHelper\";\nimport \"./style.scss\";\nimport { appActions, appSelectors } from \"../../../../redux/reducers/app.ts\";\nimport { useActionCreators, useAppSelector } from \"shared/hooks\";\nimport { notifyError } from \"shared/errors/notificate.ts\";\n\nfunction SubscriptionBilling() {\n const subscription = useAppSelector(appSelectors.subscription);\n const refreshAccessToken = useAppSelector(appSelectors.refreshAccessToken);\n const currentUser = useAppSelector(appSelectors.persona);\n const { setSubscriptions } = useActionCreators(appActions);\n const [appProfileChanged, setAppProfileChanged] = useState(null);\n const [isCancelSubscription, setIsCancelSubscription] = useState(false);\n const [isResumeSubscription, setIsResumeSubscription] = useState(false);\n const [isLoadingPaymentMethods, setIsLoadingPaymentMethods] = useState(false);\n const [isLoadingSubscription, setIsLoadingSubscription] = useState(null);\n const needLoading = isResumeSubscription || isCancelSubscription;\n const appProfile = useSelector((state) => state.app.appProfile);\n const fullName = useAppSelector(appSelectors.fullName);\n\n useEffect(() => {\n if (subscription === null) {\n getSubscription();\n }\n }, [subscription]);\n\n const isActivatedByOwner = () => {\n const result =\n appProfile.teamRole &&\n currentUser.subscriptionOwnerId &&\n currentUser.subscriptionOwnerId !== currentUser.personaId;\n return result;\n };\n\n const isActivatedByUserItself = () => {\n const result =\n appProfile.teamRole &&\n currentUser.subscriptionOwnerId &&\n currentUser.subscriptionOwnerId === currentUser.personaId;\n return result;\n };\n\n const isAllowedToManageSubscription = () => {\n const result =\n !appProfile.impersonatedPersona &&\n (!appProfile.subscriptionOwnerId ||\n appProfile.subscriptionOwnerId === appProfile.personaId);\n return result;\n };\n\n const isActiveTrial = () => {\n const result =\n subscription &&\n subscription.plan_id === CONSTS.SUBSCRIPTIONS.TRIAL.ID &&\n subscription.is_active;\n return result;\n };\n\n const isInactiveTrial = () => {\n const result =\n subscription &&\n subscription.plan_id === CONSTS.SUBSCRIPTIONS.TRIAL.ID &&\n !subscription.is_active;\n return result;\n };\n\n const isActiveNotCancelledNotTrial = () => {\n const result =\n subscription &&\n subscription.plan_id !== CONSTS.SUBSCRIPTIONS.TRIAL.ID &&\n subscription.is_active &&\n subscription.state !== CONSTS.SUBSCRIPTIONS.STATE.CANCELED;\n return result;\n };\n\n const isActiveCancelledNotTrial = () => {\n const result =\n subscription &&\n subscription.plan_id !== CONSTS.SUBSCRIPTIONS.TRIAL.ID &&\n subscription.is_active &&\n subscription.state === CONSTS.SUBSCRIPTIONS.STATE.CANCELED;\n return result;\n };\n\n const isInactiveNotTrial = () => {\n const result =\n subscription &&\n subscription.plan_id !== CONSTS.SUBSCRIPTIONS.TRIAL.ID &&\n !subscription.is_active;\n return result;\n };\n\n const getPlanName = (planId) => {\n const result = CONSTS.SUBSCRIPTIONS[planId]\n ? CONSTS.SUBSCRIPTIONS[planId].NAME\n : planId;\n return result;\n };\n\n const getSubscription = async () => {\n isLoadingSubscription === null && setIsLoadingSubscription(true);\n try {\n const subscription = await api.getSubscription();\n subscription?.data && setSubscriptions(subscription?.data);\n } catch (error) {\n notifyError(error);\n } finally {\n setIsLoadingSubscription(false);\n }\n };\n\n const getNextChargeValue = () => {\n const result = subscriptionHelper.showNextCharge(subscription)\n ? getOriginalNextChargeValue()\n : \"-\";\n return result;\n };\n\n const getOriginalNextChargeValue = () => {\n const result = functions.parseDateToDMY(subscription.next_charge_date, \"/\");\n return result;\n };\n\n return (\n
    \n {isActiveTrial() && (\n <>\n
    \n Subscription plan \n

    \n {`${CONSTS.SUBSCRIPTIONS.TRIAL.NAME}`}\n

    \n
    \n
    \n
    \n

    Activated Date

    \n

    \n {functions.parseDateToDMY(subscription.activation_date, \"/\")}\n

    \n
    \n

    Expires on

    \n

    \n {getOriginalNextChargeValue()}\n

    \n
    \n
    \n
    \n

    Status

    \n
    \n {subscriptionHelper\n .getStatusTags(subscription)\n .map((status) => (\n

    \n {status.text}\n

    \n ))}\n
    \n
    \n

    Price

    \n

    Free

    \n
    \n
    \n
    \n {isAllowedToManageSubscription() && (\n \n {\"Upgrade subscription\"}\n \n )}\n \n )}\n {isInactiveTrial() && (\n <>\n
    \n Subscription plan \n

    \n {`${CONSTS.SUBSCRIPTIONS.TRIAL.NAME}`}\n

    \n
    \n
    \n
    \n

    Activated Date

    \n

    \n {functions.parseDateToDMY(subscription.activation_date, \"/\")}\n

    \n
    \n

    Expired on

    \n

    \n {getOriginalNextChargeValue()}\n

    \n
    \n
    \n
    \n

    Status

    \n
    \n {subscription &&\n subscriptionHelper\n .getStatusTags(subscription)\n .map((status) => (\n

    \n {status.text}\n

    \n ))}\n
    \n
    \n

    Price

    \n

    Free

    \n
    \n
    \n
    \n \n {\"Upgrade subscription\"}\n \n \n )}\n\n {isActiveNotCancelledNotTrial() && (\n <>\n
    \n Subscription plan \n

    {`${getPlanName(\n subscription.plan_id\n )}`}

    \n
    \n
    \n
    \n

    Activated Date

    \n

    \n {functions.parseDateToDMY(subscription.activation_date, \"/\")}\n

    \n
    \n

    Next charge

    \n

    \n {getNextChargeValue()}\n

    \n
    \n
    \n
    \n

    Status

    \n
    \n {subscription &&\n subscriptionHelper\n .getStatusTags(subscription)\n .map((status) => (\n

    \n {status.text}\n

    \n ))}\n
    \n
    \n

    Price

    \n
    \n

    \n {subscription.actual_price}\n $/mo\n

    \n {subscription.actual_price !== subscription.base_price && (\n

    \n {subscription.base_price}$\n

    \n )}\n
    \n
    \n
    \n
    \n {isActivatedByOwner() && (\n <>\n

    Activated by:

    \n team owner\n \n )}\n {isActivatedByUserItself() && (\n <>\n

    Activated by:

    \n

    \n {fullName}\n \n ({currentUser.email})\n \n

    \n \n )}\n {isAllowedToManageSubscription() && (\n <>\n
    \n \n {\"Upgrade subscription\"}\n \n {\n setIsCancelSubscription(true);\n try {\n const response = await api.cancelSubscription();\n if (!response) {\n return;\n }\n if (response.status === 200) {\n await refreshAccessToken();\n setAppProfileChanged(true);\n await getSubscription();\n }\n } catch (error) {\n notifyError(error);\n } finally {\n setIsCancelSubscription(false);\n }\n }}\n >\n {\"Cancel subscription\"}\n \n
    \n
    \n

    Payment details

    \n {\n setIsLoadingPaymentMethods(true);\n try {\n const response = await api.getManagementUrl();\n if (!response) {\n return;\n }\n if (response.status === 200) {\n window.open(response.data);\n }\n } catch (error) {\n notifyError(error);\n } finally {\n setIsLoadingPaymentMethods(false);\n }\n }}\n >\n Manage payment methods\n \n \n )}\n \n )}\n\n {isActiveCancelledNotTrial() && (\n <>\n
    \n Subscription plan \n

    {`${getPlanName(\n subscription.plan_id\n )}`}

    \n
    \n
    \n
    \n

    Activated Date

    \n

    \n {functions.parseDateToDMY(subscription.activation_date, \"/\")}\n

    \n
    \n

    Next charge

    \n

    -

    \n
    \n
    \n
    \n

    Status

    \n
    \n {subscription &&\n subscriptionHelper\n .getStatusTags(subscription)\n .map((status) => (\n

    \n {status.text}\n

    \n ))}\n
    \n
    \n

    Price

    \n
    \n

    \n {subscription.actual_price}\n $/mo\n

    \n {subscription.actual_price !== subscription.base_price && (\n

    \n {subscription.base_price}$\n

    \n )}\n
    \n
    \n
    \n
    \n {isActivatedByOwner() && (\n <>\n

    Activated by:

    \n team owner\n \n )}\n {isActivatedByUserItself() && (\n <>\n

    Activated by:

    \n

    \n {currentUser.givenName} {currentUser.familyName}\n \n ({currentUser.email})\n \n

    \n \n )}\n {isAllowedToManageSubscription() && (\n <>\n
    \n \n Upgrade subscription\n \n {\n setIsResumeSubscription(true);\n try {\n const response = await api.resumeSubscription();\n if (!response) {\n return;\n }\n if (response.status === 200) {\n await refreshAccessToken();\n setAppProfileChanged(true);\n await getSubscription();\n }\n } catch (error) {\n notifyError(error);\n } finally {\n setIsResumeSubscription(false);\n }\n }}\n >\n Resume subscription\n \n
    \n
    \n

    Payment details

    \n {\n setIsLoadingPaymentMethods(true);\n try {\n const response = await api.getManagementUrl();\n if (!response) {\n return;\n }\n if (response.status === 200) {\n window.open(response.data);\n }\n } catch (error) {\n notifyError(error);\n } finally {\n setIsLoadingPaymentMethods(false);\n }\n }}\n >\n Manage payment methods\n \n \n )}\n \n )}\n\n {isInactiveNotTrial() && (\n <>\n
    \n Subscription plan \n

    {`${getPlanName(\n subscription.plan_id\n )}`}

    \n
    \n
    \n
    \n

    Activated Date

    \n

    \n {functions.parseDateToDMY(subscription.activation_date, \"/\")}\n

    \n
    \n

    Next charge

    \n

    -

    \n
    \n
    \n
    \n
    \n

    Status

    \n {subscription &&\n subscriptionHelper\n .getStatusTags(subscription)\n .map((status) => (\n

    \n {status.text}\n

    \n ))}\n
    \n
    \n

    Price

    \n
    \n

    \n {subscription.actual_price}\n $/mo\n

    \n {subscription.actual_price !== subscription.base_price && (\n

    \n {subscription.base_price}$\n

    \n )}\n
    \n
    \n
    \n
    \n \n {\"Upgrade subscription\"}\n \n
    \n

    Payment details

    \n {\n setIsLoadingPaymentMethods(true);\n try {\n const response = await api.getManagementUrl();\n if (!response) {\n return;\n }\n if (response.status === 200) {\n window.open(response.data);\n }\n } catch (error) {\n notifyError(error);\n } finally {\n setIsLoadingPaymentMethods(false);\n }\n }}\n >\n {\"Manage payment methods\"}\n \n \n )}\n {isLoadingSubscription && (\n
    \n \n
    \n )}\n
    \n );\n}\n\nexport default SubscriptionBilling;\n","import exclaimIcon from 'assets/image/icons/svg/exclaim.svg'\r\nimport { ResponsiveButton } from 'components/atoms/responsiveButton/index.tsx'\r\nimport { useDateHandlers } from 'components/molecules/dateSelection/hooks.ts'\r\nimport { CONSTS } from 'config/objectConst.js'\r\nimport { notificationUtils } from 'features/notifications/index.ts'\r\nimport { workspaceApi } from 'features/workspace'\r\nimport { useEffect } from 'react'\r\n\r\nimport {\r\n\tDateSelection,\r\n\tDAYS,\r\n\ttransformToWorkingHours,\r\n\tuseHasSelected\r\n} from '../../dateSelection/index.ts'\r\nimport { SelectTimeZone } from '../../SelectTimeZone/index.tsx'\r\nimport { useEditMode, useHours } from './hooks.ts'\r\n\r\nfunction WorkingHours() {\r\n\tconst { hours, setHours } = useHours()\r\n\r\n\tconst [mutation, mutationOptions] = workspaceApi.useSetWorkingHoursMutation()\r\n\r\n\tconst { cancelEdit, isEdit, tornOff, turnOn } = useEditMode({\r\n\t\thours,\r\n\t\tsetHours\r\n\t})\r\n\r\n\tuseEffect(() => {\r\n\t\tif (mutationOptions.isSuccess) {\r\n\t\t\tnotificationUtils.snackById('3.13')\r\n\t\t\ttornOff()\r\n\t\t}\r\n\t}, [mutationOptions.isSuccess, tornOff])\r\n\r\n\tconst saveWorkingHours = () => {\r\n\t\tconst { isValid, oneOrMoreSelected, workspaceHours } =\r\n\t\t\ttransformToWorkingHours(hours)\r\n\r\n\t\tsetHours({ ...hours })\r\n\r\n\t\tif (isValid && oneOrMoreSelected) {\r\n\t\t\tmutation(workspaceHours)\r\n\t\t}\r\n\t}\r\n\r\n\tconst hasSelected = useHasSelected(hours)\r\n\r\n\tconst { handleHoursChange, toggleDay } = useDateHandlers(setHours)\r\n\r\n\treturn (\r\n\t\t<>\r\n\t\t\t
    \r\n\t\t\t\t
    Time zone:
    \r\n\r\n\t\t\t\t\r\n\t\t\t
    \r\n\r\n\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t\t\t\t
    \r\n\t\t\t\t\t\t
    Schedule
    \r\n\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\texclaimIcon\r\n\t\t\t\t\t\t\tYou can work up to {CONSTS.WORKING_HOURS} hours a day.\r\n\t\t\t\t\t\t
    \r\n\t\t\t\t\t
    \r\n\t\t\t\t\t{DAYS.map(key => {\r\n\t\t\t\t\t\treturn (\r\n\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t{isEdit ? (\r\n\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t) : (\r\n\t\t\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t\t\t

    {key}

    \r\n\t\t\t\t\t\t\t\t\t\t{hours[key].isSelected ? (\r\n\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t{hours[key].value}\r\n\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t) : (\r\n\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t__:__-__:__\r\n\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t)}\r\n\t\t\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t)}\r\n\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t)\r\n\t\t\t\t\t})}\r\n\t\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t\t\t\t{isEdit ? (\r\n\t\t\t\t\t\t<>\r\n\t\t\t\t\t\t\t\r\n\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t{'Apply'}\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t) : (\r\n\t\t\t\t\t\t turnOn(hours)}\r\n\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\tEdit\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t)}\r\n\t\t\t\t
    \r\n\t\t\t
    \r\n\t\t\r\n\t)\r\n}\r\n\r\nexport default WorkingHours\r\n","import {\r\n\ttype AppWorkingHours,\r\n\tDAYS,\r\n\tgetInitials\r\n} from 'components/molecules/dateSelection'\r\nimport { workspaceApi } from 'features/workspace'\r\nimport { useEffect, useMemo, useRef, useState } from 'react'\r\n\r\nimport { getHoursInterval } from './utils'\r\n\r\nfunction useEditMode({ hours, setHours }: ReturnType) {\r\n\tconst [isEdit, setIsEdit] = useState(false)\r\n\tconst saved = useRef(hours)\r\n\r\n\tconst handlers = useMemo(\r\n\t\t() => ({\r\n\t\t\tcancelEdit: () => {\r\n\t\t\t\tsetIsEdit(false)\r\n\t\t\t\tsetHours(saved.current)\r\n\t\t\t},\r\n\t\t\ttornOff: () => setIsEdit(false),\r\n\t\t\tturnOn: (hours: AppWorkingHours) => {\r\n\t\t\t\tsaved.current = hours\r\n\t\t\t\tsetIsEdit(true)\r\n\t\t\t}\r\n\t\t}),\r\n\t\t[setHours]\r\n\t)\r\n\r\n\treturn { ...handlers, isEdit }\r\n}\r\n\r\nfunction useHours() {\r\n\tconst [hours, setHours] = useState(getInitials)\r\n\r\n\tconst { data, isSuccess } = workspaceApi.useWorkingHoursQuery()\r\n\r\n\tuseEffect(() => {\r\n\t\tif (!isSuccess) {\r\n\t\t\treturn\r\n\t\t}\r\n\r\n\t\tsetHours(previousHours =>\r\n\t\t\tDAYS.reduce(\r\n\t\t\t\t(nextHours, day) => {\r\n\t\t\t\t\tconst workingDay = data[day]\r\n\t\t\t\t\tif (workingDay.length > 0) {\r\n\t\t\t\t\t\tnextHours[day].isSelected = true\r\n\t\t\t\t\t\tnextHours[day].value = getHoursInterval(workingDay[0])\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\treturn nextHours\r\n\t\t\t\t},\r\n\t\t\t\t{ ...previousHours }\r\n\t\t\t)\r\n\t\t)\r\n\t}, [data, isSuccess])\r\n\r\n\treturn { hours, setHours }\r\n}\r\n\r\nexport { useEditMode, useHours }\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"root\":\"root-QVYmRx\"};","import './style.scss'\r\n\r\nimport { typo } from 'shared/styles'\r\nimport { Button } from 'shared/ui'\r\n\r\nimport icon from '../../../assets/image/icons/svg/icons/support.svg'\r\nimport { CONSTS } from '../../../config/objectConst'\r\nimport css from './SupportButton.module.scss'\r\n\r\nexport const SupportButton = () => (\r\n\t\r\n\t\tLifebuoy.\r\n\t\tHelp Center\r\n\t\r\n)\r\n","import store from \"../redux/store.ts\";\nimport pageIcon from \"../assets/image/icons/left-side-menu/page.svg\";\nimport { api } from \"../api/api\";\nimport { mapping } from \"./mapping\";\nimport { app } from \"./app\";\nimport { helpersFunc } from \"../config/helpers\";\nimport lFindIndex from \"lodash/findIndex\";\nimport {\n leftSideActions,\n leftSideSelectors,\n} from \"../redux/reducers/leftSideMenu.ts\";\nimport { notifyError } from \"shared/errors/notificate.ts\";\n\nexport const contacts = {\n loadContactsList: (list) => {\n const leftSide = {\n type: \"contacts\",\n label: \"Recently imported\",\n bottomList: [\n {\n id: 1,\n image: pageIcon,\n title: \"All contacts\",\n link: \"/contacts\",\n },\n ],\n list,\n };\n store.dispatch(leftSideActions.setLeftSide(leftSide));\n },\n getRecentImports: async () => {\n if (!leftSideSelectors.isContact(store.getState())) {\n contacts.loadContactsList([]);\n }\n try {\n const response = await api.getRecentImportsApi();\n const formatResponse = mapping.buildRecentImports(\n response.data ? response.data : []\n );\n store.dispatch({\n type: \"RECENT_IMPORTS\",\n payload: {\n imports: response.data,\n },\n });\n contacts.loadContactsList(formatResponse);\n } catch (error) {\n store.dispatch({\n type: \"RECENT_IMPORTS\",\n payload: {\n imports: [],\n },\n });\n contacts.loadContactsList([]);\n helpersFunc.logEnjectServicePromise(error);\n }\n },\n getImports: async (id) => {\n try {\n const response = await api.getImportsApi(id);\n return response;\n } catch (error) {\n console.error(error);\n }\n },\n\n getContacts: async (data, status, companyId, rerender = true, modal) => {\n if (rerender) {\n contacts.clearContacts();\n app.changePageContentLoaderStatus(true);\n app.changeTableContentLoaderStatus(true);\n }\n if (modal) {\n app.changePageModalLoader(true);\n }\n let contactsArray = [];\n let executions = [];\n let response;\n try {\n if (\n (data.status && data.status !== \"Compose\") ||\n (status && status !== \"Compose\")\n ) {\n const contactsExecutionsRes = await api.getContactsExecutionsApi({\n skip: data.skip,\n filter: companyId ? `campaign_id eq '${companyId}'` : data.filter,\n orderby:\n data.orderby && data.orderby !== \"imported asc\"\n ? data.orderby\n : \"created asc, id asc\",\n keywords: data.keywords,\n });\n if (contactsExecutionsRes.status === 200) {\n executions = contactsExecutionsRes.data.documents;\n }\n response = contactsExecutionsRes;\n const linkedin_contacts = contactsExecutionsRes.data.documents.map(\n (el) => {\n const { id, ...linkedin_contact } = el.linkedin_contact;\n return { ...el, ...linkedin_contact };\n }\n );\n\n response = {\n ...contactsExecutionsRes,\n data: {\n ...contactsExecutionsRes.data,\n documents: [...linkedin_contacts],\n },\n };\n } else {\n response = await api.getContactsApi(data);\n }\n\n if (!response.data) {\n contacts.haveContacts(false);\n }\n\n if (response.data && !modal) {\n if (response.data.documents.length > 0) {\n contacts.haveContacts(true);\n store.dispatch({\n type: \"CONTACTS_COUNT\",\n payload: {\n contactsCount: response.data.total,\n },\n });\n }\n contactsArray =\n (data.status && data.status !== \"Compose\") ||\n (status && status !== \"Compose\")\n ? mapping.buildCampaignContacts(response.data.documents, executions)\n : mapping.buildContacts(response.data.documents);\n }\n\n app.updateErrorRequest({\n contacts: false,\n });\n\n if (!modal) {\n store.dispatch({\n type: \"ALL_CONTACTS\",\n payload: {\n contacts: contactsArray,\n },\n });\n }\n return response;\n } catch (error) {\n store.dispatch(\n app.updateErrorRequest({\n contacts: true,\n })\n );\n\n contacts.haveContacts(false);\n notifyError(error);\n\n store.dispatch({\n type: \"ALL_CONTACTS\",\n payload: {\n contacts: [],\n },\n });\n return { status: \"error\", response: error.response };\n } finally {\n rerender && app.changePageContentLoaderStatus(false);\n rerender && app.changeTableContentLoaderStatus(false);\n setTimeout(() => {\n app.changePageModalLoader(false);\n }, 200);\n }\n },\n haveContacts: (status) => {\n store.dispatch({\n type: \"HAVE_CONTACTS\",\n payload: {\n haveContacts: status,\n },\n });\n },\n columnSize: (data) => {\n store.dispatch({\n type: \"COLUMN_SIZE\",\n payload: {\n columnSize: data,\n },\n });\n },\n\n typeContacts: (data) => {\n store.dispatch({\n type: \"TYPE_CONTACTS\",\n payload: {\n typeContacts: data,\n },\n });\n },\n typeCampaigns: (data) => {\n store.dispatch({\n type: \"TYPE_CAMPAIGNS\",\n payload: {\n typeCampaigns: data,\n },\n });\n },\n\n changeContactsPage: (page) => {\n store.dispatch({\n type: \"CONTACTS_PAGE\",\n payload: {\n contactsPage: page,\n },\n });\n },\n changeContactsPageModal: (page) => {\n store.dispatch({\n type: \"CONTACTS_PAGE_MODAL\",\n payload: {\n contactsPageModal: page,\n },\n });\n },\n\n clearContacts: () => {\n store.dispatch({\n type: \"ALL_CONTACTS\",\n payload: {\n contacts: [],\n },\n });\n store.dispatch({\n type: \"CONTACTS_COUNT\",\n payload: {\n contactsCount: 0,\n },\n });\n\n store.dispatch({\n type: \"HAVE_CONTACTS\",\n payload: {\n haveContacts: false,\n },\n });\n },\n cancelExecution: (data) => {\n store.dispatch({\n type: \"ALL_CONTACTS\",\n payload: {\n contacts: data,\n },\n });\n app.changeTableContentLoaderStatus(false);\n },\n updateImportedContact: (data) => {\n const tempImports = store.getState().contacts.imports;\n const index = lFindIndex(tempImports, {\n id: data.id,\n });\n tempImports.splice(index, 1, data);\n store.dispatch({\n type: \"UPDATE_IMPORTED_CONTACT\",\n payload: {\n imports: tempImports,\n },\n });\n },\n};\n","/*\n This All action on api\n https://github.com/public-apis/public-apis\n*/\nimport { CONSTS } from \"../../config/objectConst\";\nimport { httpRequest } from \"../httpRequest\";\n\nexport const apiCampaign = {\n createCampaign: async (name) => {\n //let data = new FormData();\n //data.append(\"name\", name);\n return await httpRequest({\n url: `${CONSTS.API.URL}campaigns`,\n method: \"POST\",\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n data: { name },\n });\n },\n updateCampaign: async ({ id, steps }) => {\n //let data = new FormData();\n //data.append(\"name\", name);\n return await httpRequest({\n url: `${CONSTS.API.URL}campaigns/${id}/update_steps`,\n method: \"PUT\",\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n data: { steps },\n });\n },\n\n getSettingsHubspotApi: async (id) => {\n return await httpRequest({\n url: `${CONSTS.API.URL}campaigns/${id}/settings/hubspot`,\n method: \"GET\",\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n });\n },\n\n getCampaignById: async (id) => {\n return await httpRequest({\n url: `${CONSTS.API.URL}campaigns/${id}`,\n method: \"GET\",\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n });\n },\n getCampaigns: async () => {\n return await httpRequest({\n url: `${CONSTS.API.URL}campaigns/page?%24take=${CONSTS.PAGE_SIZE}&$orderby=created asc&$filter=archived eq false`,\n method: \"GET\",\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n });\n },\n\n addTargetAudience: async (data) => {\n return await httpRequest({\n url: `${CONSTS.API.URL}campaigns/${data.id}/target_audience${\n data.params ? `?&$filter=${data.params}` : \"\"\n }`,\n\n method: \"PUT\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Access-Control-Allow-Origin\": \"*\",\n },\n });\n },\n getPreviewAddTargetAudience: async (data) => {\n const { keywords, filter, id } = { ...data };\n const params = `?${keywords ? \"&$searchQuery=\" + keywords : \"\"}${\n filter ? \"&$filter=\" + filter : \"\"\n }`;\n return await httpRequest({\n url: `${CONSTS.API.URL}campaigns/${id}/target_audience/preview${params}`,\n method: \"GET\",\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n });\n },\n getPreviewRemoveTargetAudience: async (data) => {\n return await httpRequest({\n url: `${CONSTS.API.URL}executions/delete/preview${\n data.filter ? \"?&$filter=\" + data.filter : \"\"\n }${data.keywords ? \"?&$searchQuery=\" + data.keywords : \"\"}`,\n method: \"GET\",\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n });\n },\n\n removeContactsFromCampaignApi: async (data) => {\n const { campaignId, filter } = { ...data };\n return await httpRequest({\n url: `${CONSTS.API.URL}campaigns/${campaignId}/target_audience${\n filter ? `?&$filter=${filter}` : \"\"\n }`,\n method: \"DELETE\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Access-Control-Allow-Origin\": \"*\",\n },\n });\n },\n\n removeExecutionsFromCampaignApi: async (data) => {\n return await httpRequest({\n url: `${CONSTS.API.URL}executions/delete${\n data.filter ? \"?&$filter=\" + data.filter : \"\"\n }${data.keywords ? \"?&$searchQuery=\" + data.keywords : \"\"}`,\n method: \"DELETE\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Access-Control-Allow-Origin\": \"*\",\n },\n });\n },\n\n editCampaignApi: async (data) => {\n const { id, name } = { ...data };\n return await httpRequest({\n url: `${CONSTS.API.URL}campaigns/${id}/update`,\n method: \"PUT\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Access-Control-Allow-Origin\": \"*\",\n },\n data: {\n name,\n },\n });\n },\n\n addCampaignToArchiveApi: async (id) => {\n return await httpRequest({\n url: `${CONSTS.API.URL}campaigns/${id}/archive`,\n method: \"PUT\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Access-Control-Allow-Origin\": \"*\",\n },\n });\n },\n removeCampaignFromArchiveApi: async (id) => {\n return await httpRequest({\n url: `${CONSTS.API.URL}campaigns/${id}/unarchive`,\n method: \"PUT\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Access-Control-Allow-Origin\": \"*\",\n },\n });\n },\n\n getPreviewOfStartupCampaing: async (id) => {\n return await httpRequest({\n url: `${CONSTS.API.URL}campaigns/${id}/preview`,\n method: \"GET\",\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n });\n },\n exportCampaignsApi: async ({ filter, orderby, searchValue, archived }) => {\n let archivedParam = \"\";\n const statuses = filter ? filter : \"\";\n let resultFilters = \"\";\n if (!orderby) {\n orderby = \"created desc\";\n }\n\n if (archived !== undefined) {\n archivedParam = `(archived eq ${archived})`;\n }\n if (archivedParam || statuses) {\n resultFilters = `&$filter=${archivedParam}${\n statuses ? ` ${archivedParam ? \"and\" : \"\"} (${statuses})` : \"\"\n }`;\n }\n const params = `?${resultFilters}${\n searchValue ? \"&$searchQuery=\" + searchValue : \"\"\n }${orderby ? \"&$orderby=\" + orderby : \"\"}`;\n return await httpRequest({\n url: `${CONSTS.API.URL}campaigns/export${params}`,\n method: \"GET\",\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n },\n });\n },\n};\n","import { api } from 'api/api'\r\nimport { apiCampaign } from 'api/campaign/apiCampaign'\r\nimport { NOTIFICATION, type SnackKey } from 'config/notifications'\r\nimport { CONSTS } from 'config/objectConst'\r\nimport { notificationUtils } from 'features/notifications'\r\nimport { notifyError } from 'shared/errors'\r\n\r\nimport { appSelectors } from '../redux/reducers/app'\r\nimport {\r\n\tcampaignsActions,\r\n\tcampaignsSelectors\r\n} from '../redux/reducers/campaigns'\r\nimport store from '../redux/store'\r\nimport { app } from './app'\r\nimport { filters } from './filters'\r\nimport { mapping } from './mapping'\r\n\r\nfunction getContactAddedSnack(fromKey: 'contacts' | string, importId: string) {\r\n\tconst noteId: '3.4a' | '3.4b' = fromKey === 'contacts' ? '3.4a' : '3.4b'\r\n\r\n\tconst nextSnack = { ...NOTIFICATION[noteId] }\r\n\tif ('button' in nextSnack) {\r\n\t\tnextSnack.button.link = nextSnack.button.link.replace('{var}', importId)\r\n\t}\r\n\r\n\treturn nextSnack\r\n}\r\n\r\nfunction refreshAccessToken(): Promise {\r\n\tconst root = store.getState()\r\n\tconst action = appSelectors.refreshAccessToken(root)\r\n\r\n\treturn action()\r\n}\r\n\r\nconst getFilterQuery = () => campaignsSelectors.filterQuery(store.getState())\r\n\r\ninterface GetCampaigns {\r\n\torderby?: ''\r\n\tpage: 0\r\n\tsearchValue?: ''\r\n}\r\n\r\nasync function completeCampaign(\r\n\tid: string,\r\n\tgetCampaigns: GetCampaigns,\r\n\tload = api.completeCampaignApi,\r\n\tnotificationKey: SnackKey = '3.8'\r\n) {\r\n\tapp.changeTableContentLoaderStatus(true)\r\n\r\n\ttry {\r\n\t\tawait load(id)\r\n\r\n\t\tawait updateCampaigns(id, getCampaigns)\r\n\r\n\t\tawait refreshAccessToken()\r\n\r\n\t\tnotificationUtils.showSnack(NOTIFICATION[notificationKey])\r\n\t} catch (error) {\r\n\t\tnotifyError(error)\r\n\t} finally {\r\n\t\tapp.changeTableContentLoaderStatus(false)\r\n\t}\r\n}\r\n\r\nasync function updateCampaigns(id: string, getCampaigns: GetCampaigns) {\r\n\tif (getCampaigns) {\r\n\t\tawait filters.getCampaigns({\r\n\t\t\tarchived: false,\r\n\t\t\tfilter: getFilterQuery(),\r\n\t\t\tkeywords: getCampaigns.searchValue,\r\n\t\t\torderby: getCampaigns.orderby,\r\n\t\t\tskip: getCampaigns.page > 0 ? getCampaigns.page * CONSTS.PAGE_SIZE : 0\r\n\t\t})\r\n\t} else {\r\n\t\tconst response = (await apiCampaign.getCampaignById(id)) as any\r\n\t\tconst payload = mapping.campaignTransform(response.data)\r\n\t\tstore.dispatch(campaignsActions.updateOne(payload))\r\n\t}\r\n}\r\n\r\nexport {\r\n\tcompleteCampaign,\r\n\tgetContactAddedSnack,\r\n\tgetFilterQuery,\r\n\trefreshAccessToken,\r\n\tupdateCampaigns\r\n}\r\n","import store from \"../redux/store.ts\";\nimport {\n leftSideActions,\n leftSideSelectors,\n} from \"../redux/reducers/leftSideMenu.ts\";\nimport { campaignsActions } from \"../redux/reducers/campaigns.ts\";\nimport lFilter from \"lodash/filter\";\nimport { apiCampaign } from \"../api/campaign/apiCampaign\";\nimport { mapping } from \"./mapping\";\nimport { app } from \"./app\";\nimport { contacts } from \"./contacts\";\nimport { api } from \"../api/api\";\nimport { filters } from \"./filters\";\nimport { helpersFunc } from \"../config/helpers\";\n// icons\nimport pageIcon from \"../assets/image/icons/left-side-menu/page.svg\";\nimport archiveIcon from \"../assets/image/icons/svg/archive-icon-yellow.svg\";\nimport turnIcon from \"../assets/image/icons/svg/turn.svg\";\nimport { CONSTS } from \"../config/objectConst\";\n\nimport { notifyError } from \"shared/errors/notificate.ts\";\nimport {\n completeCampaign,\n getContactAddedSnack,\n getFilterQuery,\n refreshAccessToken,\n updateCampaigns,\n} from \"./campaign.typed.ts\";\nimport { notificationUtils } from \"features/notifications/index.ts\";\nimport { NOTIFICATION } from \"config/notifications.ts\";\n\nexport const campaign = {\n loadCampaignList(data, type) {\n const leftSide = {\n type: type ? type : \"campaign\",\n label: \"Recently created\",\n bottomList: [\n {\n id: 2,\n image: turnIcon,\n title: \"Activities queue\",\n link: \"/activities-queue\",\n },\n {\n id: 1,\n image: pageIcon,\n title: \"All campaigns list\",\n link: \"/campaigns\",\n },\n {\n id: 3,\n image: archiveIcon,\n title: \"Archive\",\n link: \"/archive\",\n },\n ],\n list: data,\n };\n store.dispatch(leftSideActions.setLeftSide(leftSide));\n },\n\n changeCampaignLoaderController(value) {\n store.dispatch({\n type: \"CAMPAIGN_LOADER_CONTROLLER\",\n payload: {\n campaignLoaderController: value,\n },\n });\n },\n\n changeCreateCampaignController(value) {\n store.dispatch({\n type: \"CREATE_CAMPAIGN_CONTROLLER\",\n payload: {\n createCampaignController: value,\n },\n });\n },\n\n changeUpdateCampaignController(value) {\n store.dispatch({\n type: \"UPDATE_CAMPAIGN_CONTROLLER\",\n payload: {\n updateCampaignController: value,\n },\n });\n },\n\n changeCampaignsLoadController(loadCampaignsController) {\n store.dispatch(\n campaignsActions.setLoadCampaignsController(loadCampaignsController)\n );\n },\n\n changeCampaginSingleLoaderPage(value) {\n store.dispatch({\n type: \"CAMPAIGN_SINGLE_LOADER_CONTROLLER\",\n payload: {\n singleLoaderPage: value,\n },\n });\n },\n\n getRecentCampaigns: async (type) => {\n if (!leftSideSelectors.isContact(store.getState())) {\n campaign.loadCampaignList([]);\n }\n try {\n const response = await api.getCampaignsApi({ take: 5 });\n if (response.status === 204) {\n campaign.loadCampaignList([]);\n }\n if (response.status === 200) {\n campaign.loadCampaignList(response.data.documents, type);\n }\n } catch (error) {\n notifyError(error);\n campaign.loadCampaignList([]);\n }\n },\n\n campaignClearId() {\n store.dispatch({\n type: \"CLEAR_CAMPAIGN\",\n });\n },\n\n async getCampaignId(id, rerender = true) {\n campaign.changeCampaginSingleLoaderPage(true);\n\n if (rerender) {\n app.changePageContentLoaderStatus(true);\n campaign.campaignClearId();\n }\n\n let response = null;\n try {\n response = await apiCampaign.getCampaignById(id);\n if (response.status === 204) {\n return null;\n }\n\n //await campaign.getContactsByCampaign(id);\n app.changeActiveItem(id);\n const payload = mapping.campaignTransform(response.data);\n\n if (!rerender) {\n payload.actions = store.getState().campaign.actions;\n }\n\n store.dispatch({\n type: \"CAMPAIGN\",\n payload,\n });\n } finally {\n app.changePageContentLoaderStatus(false);\n if (rerender) {\n app.changePageContentLoaderStatus(false);\n campaign.changeCampaginSingleLoaderPage(false);\n }\n }\n return response;\n },\n\n getContactsByCampaign: async (id) => {\n app.changePageContentLoaderStatus(true);\n app.changeTableContentLoaderStatus(true);\n try {\n const contactsRes = await api.getContactsApi({\n filter: `campaigns/any(c:c eq '${id}')`,\n });\n const contactsExecutionsRes = await api.getContactsExecutionsApi({\n filter: `campaign_id eq '${id}'`,\n });\n let executions = [];\n if (contactsExecutionsRes.status === 200) {\n executions = contactsExecutionsRes.data.documents;\n }\n if (contactsRes.data) {\n store.dispatch({\n type: \"CAMPAIGN_CONNECT_LIST\",\n payload: {\n list: mapping.buildCampaignContacts(\n contactsRes.data.documents,\n executions\n ),\n },\n });\n } else {\n store.dispatch({\n type: \"CAMPAIGN_CONNECT_LIST\",\n payload: {\n list: [],\n },\n });\n }\n } catch (error) {\n notifyError(error);\n store.dispatch({\n type: \"CAMPAIGN_CONNECT_LIST\",\n payload: {\n list: [],\n },\n });\n } finally {\n app.changePageContentLoaderStatus(false);\n app.changeTableContentLoaderStatus(false);\n }\n },\n\n async createCampaign(name, history) {\n campaign.changeCreateCampaignController(true);\n try {\n const response = await apiCampaign.createCampaign(name);\n\n campaign.getRecentCampaigns();\n notificationUtils.snackById(\"3.1\");\n\n history.push(`/campaigns/${response.data.id}/tune`);\n app.changeActiveItem(response.data.id);\n //app.changeActiveItem(response.data.id);\n } catch (error) {\n notifyError(error);\n } finally {\n campaign.changeCreateCampaignController(false);\n }\n },\n\n async createCampaignWithContacts(data) {\n const {\n name,\n history,\n audience,\n selectAllUsersValue,\n filters,\n campId,\n from,\n activeImportId,\n keywords,\n } = { ...data };\n campaign.changeCreateCampaignController(true);\n try {\n const response = await apiCampaign.createCampaign(name);\n\n if (selectAllUsersValue) {\n await campaign.addAllContactsToCampaign(\n filters,\n response.data.id,\n name,\n from,\n activeImportId,\n campId,\n keywords\n );\n } else {\n await apiCampaign.addTargetAudience({\n id: response.data.id,\n audience,\n params: `id in (${audience.map((item) => `'${item}'`)})`,\n });\n }\n\n campaign.getRecentCampaigns();\n\n notificationUtils.snackById(\"3.1\");\n\n history.push(`/campaigns/${response.data.id}/tune`);\n app.changeActiveItem(response.data.id);\n } catch (error) {\n notifyError(error);\n } finally {\n campaign.changeCreateCampaignController(false);\n }\n },\n\n async updateCampaign(data) {\n campaign.changeUpdateCampaignController(true);\n try {\n const response = await apiCampaign.updateCampaign(data);\n campaign.getRecentCampaigns();\n return response;\n } catch (error) {\n notifyError(error);\n } finally {\n campaign.changeUpdateCampaignController(false);\n }\n },\n\n async getCampaignsParams({ updateLeftMenu }) {\n campaign.changeCampaignsLoadController(true);\n try {\n const response = await apiCampaign.getCampaigns();\n campaign.changeCampaignsLoadController(false);\n\n store.dispatch(\n campaignsActions.setCampaigns({\n campaigns: mapping.buildCampaignsArray(response.data),\n })\n );\n if (response.data.length > 0) {\n campaign.haveCampaigns(true);\n }\n if (updateLeftMenu) {\n campaign.loadCampaignList(response.data);\n }\n } catch (e) {\n campaign.haveCampaigns(false);\n campaign.changeCampaignsLoadController(false);\n helpersFunc.logEnjectServicePromise(e);\n if (updateLeftMenu) {\n campaign.loadCampaignList([]);\n }\n }\n },\n\n haveCampaigns(haveCampaigns) {\n store.dispatch(campaignsActions.setHaveCampaigns(haveCampaigns));\n },\n\n searchArchiveValue(value) {\n store.dispatch(campaignsActions.setArchive(value));\n },\n\n addAllContactsToCampaign: async (\n data,\n importId,\n campaignName,\n fromKey,\n activeImportId,\n refreshContacts,\n keywordsForModal\n ) => {\n const filterData =\n fromKey === \"single-contacts\" ? data.filterDataForModal : data.filterData;\n const mainFilter = filters.buildFilterQuery(filterData);\n\n let filterQuery = mainFilter ?? \"\";\n if (activeImportId) {\n const importFilter = `tags/any(c:c eq '${activeImportId}')`;\n filterQuery = mainFilter\n ? `${importFilter} and ${mainFilter}`\n : importFilter;\n }\n\n const params = keywordsForModal\n ? `${filterQuery}&$searchQuery=${keywordsForModal}`\n : filterQuery;\n\n campaign.changeCreateCampaignController(true);\n\n try {\n await apiCampaign.addTargetAudience({ id: importId, params });\n\n notificationUtils.showSnack(getContactAddedSnack(fromKey, importId));\n\n if (refreshContacts && fromKey === \"single-contacts\") {\n refreshContacts();\n }\n } catch (error) {\n notifyError(error);\n } finally {\n campaign.changeCreateCampaignController(false);\n }\n },\n\n removeAllContactsFromCampaign: async (data) => {\n app.changePageContentLoaderStatus(true);\n app.changeTableContentLoaderStatus(true);\n try {\n await apiCampaign.removeContactsFromCampaignApi(data);\n contacts.clearContacts();\n notificationUtils.snackById(\"3.5b\");\n } catch (error) {\n notifyError(error);\n } finally {\n app.changePageContentLoaderStatus(false);\n app.changeTableContentLoaderStatus(false);\n }\n },\n\n addContactsToCampaign: async (data, refreshContacts) => {\n campaign.changeCreateCampaignController(true);\n try {\n const response = await apiCampaign.addTargetAudience({\n id: data.id,\n audience: data.audience,\n params: `id in (${data.audience.map((item) => `'${item}'`)})`,\n });\n\n store.dispatch({\n type: \"CAMPAIGN\",\n payload: mapping.campaignTransform(response.data),\n });\n\n const nextSnack = data.running\n ? NOTIFICATION[\"3.18\"]\n : getContactAddedSnack(data.from, data.id);\n\n notificationUtils.showSnack(nextSnack);\n\n if (refreshContacts) {\n refreshContacts();\n }\n } catch (error) {\n notifyError(error);\n } finally {\n campaign.changeCreateCampaignController(false);\n }\n },\n\n removeContactsFromCampaign: async (data) => {\n app.changePageContentLoaderStatus(true);\n app.changeTableContentLoaderStatus(true);\n try {\n const response = await apiCampaign.removeContactsFromCampaignApi(data);\n store.dispatch({\n type: \"CAMPAIGN\",\n payload: mapping.campaignTransform(response.data),\n });\n\n notificationUtils.showSnack(\n NOTIFICATION[data.audience.length > 1 ? \"3.5b\" : \"3.5a\"]\n );\n } catch (error) {\n notifyError(error);\n } finally {\n app.changePageContentLoaderStatus(false);\n app.changeTableContentLoaderStatus(false);\n }\n },\n\n startCampaign: async (id, status, getCampaigns) => {\n app.changePageContentLoaderStatus(true);\n app.changeTableContentLoaderStatus(true);\n try {\n await api.startCampaignApi(id);\n\n notificationUtils.snackById(status === \"Stopped\" ? \"3.9\" : \"3.6\");\n\n await updateCampaigns(id, getCampaigns);\n await refreshAccessToken();\n } catch (error) {\n notifyError(error);\n } finally {\n app.changeTableContentLoaderStatus(false);\n app.changePageContentLoaderStatus(false);\n }\n },\n\n stopCampaign(id, getCampaigns) {\n completeCampaign(id, getCampaigns, api.stopCampaignApi, \"3.7\");\n },\n\n completeCampaign(id, getCampaigns) {\n completeCampaign(id, getCampaigns, api.completeCampaignApi, \"3.8\");\n },\n\n cloneCampaign: async (id) => {\n app.changeTableContentLoaderStatus(true);\n try {\n const response = await api.cloneCampaignApi(id);\n notificationUtils.snackById(\"3.21\");\n return response.data;\n } catch (error) {\n notifyError(error);\n } finally {\n app.changeTableContentLoaderStatus(false);\n }\n },\n\n getCampaignExecutionsStatistics: async (id) => {\n try {\n const response = await api.getCampaignExecutionsStatisticsApi(id);\n store.dispatch({\n type: \"CAMPAIGN\",\n payload: {\n executionsStatistics: mapping.buildCampaignsStatistics(response.data),\n actions: campaign.buildActionsStatistics(\n lFilter(response.data.steps, (el) => el.is_visible === true)\n ),\n },\n });\n } catch (error) {\n helpersFunc.logEnjectServicePromise(error);\n }\n },\n\n buildActionsStatistics: (array) => {\n const actions = [...store.getState().campaign.actions];\n const newActions = [];\n array.forEach((item, indexOne) => {\n actions.forEach((element, indexTwo) => {\n if (indexOne === indexTwo) {\n newActions.push({\n ...element,\n ...mapping.buildActionStatistics(item),\n });\n }\n });\n });\n return newActions;\n },\n\n editCampaign: async (data) => {\n const { name, id } = { ...data };\n try {\n const response = await apiCampaign.editCampaignApi(data);\n\n store.dispatch({\n type: \"CAMPAIGN\",\n payload: {\n name: response.data.name,\n },\n });\n store.dispatch(\n leftSideActions.updateListName({\n id,\n name,\n })\n );\n } catch (error) {\n notifyError(error);\n }\n },\n\n addCampaignToArchive: async (id, keywords, page, orderby) => {\n try {\n await apiCampaign.addCampaignToArchiveApi(id);\n await filters.getCampaigns({\n archived: false,\n skip: page > 0 ? page * CONSTS.PAGE_SIZE : 0,\n filter: getFilterQuery(),\n keywords,\n orderby,\n });\n\n notificationUtils.snackById(\"3.10\");\n } catch (error) {\n notifyError(error);\n } finally {\n app.changeTableContentLoaderStatus(false);\n }\n },\n\n removeCampaignFromArchive: async (id, keywords, page, orderby) => {\n try {\n await apiCampaign.removeCampaignFromArchiveApi(id);\n await filters.getCampaigns({\n archived: true,\n skip: page > 0 ? page * CONSTS.PAGE_SIZE : 0,\n keywords,\n orderby,\n });\n } catch (error) {\n notifyError(error);\n } finally {\n app.changeTableContentLoaderStatus(false);\n }\n },\n\n openCampaignContacts: (props, launchCampaignDialog) => {\n const result = props.history.push({\n pathname: `/campaigns/${props.campaign.id}/contacts`,\n state: { launchCampaignDialog },\n });\n return result;\n },\n};\n","import store from \"../redux/store.ts\";\nimport { campaignsActions } from \"../redux/reducers/campaigns.ts\";\nimport isBoolean from \"lodash/isBoolean\";\nimport lFind from \"lodash/find\";\nimport isDate from \"lodash/isDate\";\nimport isString from \"lodash/isString\";\nimport isNumber from \"lodash/isNumber\";\nimport isPlainObject from \"lodash/isPlainObject\";\n\nimport { functions } from \"../tools/functions\";\nimport * as utils from \"../shared/utils.ts\";\nimport { mapping } from \"./mapping\";\nimport { contacts } from \"./contacts\";\nimport { api } from \"../api/api\";\nimport { campaign } from \"./campaign\";\nimport { app } from \"./app\";\nimport { appSelectors } from \"../redux/reducers/app.ts\";\nimport { notifyError } from \"shared/errors/notificate.ts\";\n\nexport const filters = {\n changeFilters(object, isAllData) {\n let filterData;\n if (isAllData) {\n filterData = object;\n } else {\n filterData = [...store.getState().filters.filterData];\n const index = filterData.indexOf(object);\n filterData[index] = object;\n }\n\n store.dispatch({\n type: \"FILTERS_PARAMS\",\n payload: {\n filterData,\n },\n });\n },\n\n changeFiltersForModal(object, isAllData) {\n let filterData;\n if (isAllData) {\n filterData = object;\n } else {\n filterData = [...store.getState().filters.filterDataForModal];\n const index = filterData.indexOf(object);\n filterData[index] = object;\n }\n\n store.dispatch({\n type: \"FILTERS_PARAMS_FOR_MODAL\",\n payload: {\n filterDataForModal: filterData,\n },\n });\n },\n\n changeAllTags(array) {\n return array.map((item) => {\n return filters.changeTag(item, array);\n });\n },\n\n changeTag(object, array) {\n const filterData = [...array];\n const index = filterData.indexOf(object);\n if (object.hasOwnProperty(\"tag\")) {\n object.tag = filters.buildTagText(object);\n }\n filterData[index] = object;\n return filterData;\n },\n\n buildTagText(item) {\n if (Array.isArray(item.value) && lFind(item.value, \"value\")) {\n if (isDate(lFind(item.value, \"value\").value)) {\n const datesArray = [];\n if (item.value[\"0\"].value) {\n datesArray.push(functions.parseDateToDMY(item.value[\"0\"].value, \"/\"));\n }\n if (item.value[\"1\"].value) {\n datesArray.push(functions.parseDateToDMY(item.value[\"1\"].value, \"/\"));\n }\n return item.name + \": \" + datesArray.join(\" - \");\n } else {\n if (item.value.length > 1) {\n return item.name + \" (\" + item.value.length + \")\";\n } else {\n if (item.value.length > 0 && item.exclude) {\n return \"NOT: \" + item.value[0].text;\n }\n if (item.value.length > 0) {\n return item.value[0].text;\n }\n return \"\";\n }\n }\n }\n if (isString(item.value) || isNumber(item.value)) {\n return item.value;\n }\n if (isDate(item.value)) {\n return (\n item.value.getDate() +\n \" \" +\n functions.getMonth(item.value.getMonth()) +\n \" \" +\n item.value.getFullYear()\n );\n }\n if (isPlainObject(item.value)) {\n return item.value.text;\n }\n },\n\n buildSearchQuery(array) {\n const newArray = [];\n array.forEach((item) => {\n if (item.search && item.value.length > 0) {\n newArray.push(`(${this.getSearchQuery(item.value, item.exclude)})`);\n }\n });\n return newArray.join(\" AND \");\n },\n\n getSearchQuery(array, exclude) {\n const newArray = array.map((item) => {\n const result = `(${utils.escapeSpecialChars(item.value)})`;\n\n return exclude ? `NOT ${result}` : result;\n });\n return newArray.join(\" OR \");\n },\n\n buildFilterExecutionsQuery(array) {\n const filtersArray = [];\n const newArray = [...array];\n const renamedArray = newArray.map((item) => {\n const newItem = { ...item };\n if (newItem.id === 1) {\n newItem.name = \"distance\";\n }\n if (newItem.id === 4) {\n newItem.name = \"linkedin_contact/is_premium\";\n newItem.value = newItem.value ? true : \"\";\n }\n return newItem;\n });\n renamedArray.forEach((item) => {\n if (\n Array.isArray(item.value) &&\n item.value.length > 0 &&\n lFind(item.value, \"value\") &&\n !item.search\n ) {\n if (isDate(lFind(item.value, \"value\").value)) {\n filtersArray.push(\n \"(\" + filters.buildDataFilterParams(item.value, item.name) + \")\"\n );\n } else {\n if (item.name === \"campaigns\") {\n filtersArray.push(\"(\" + filters.buildCampaigns(item.value) + \")\");\n } else {\n filtersArray.push(\n \"(\" +\n filters\n .buildArrayFilterParams(\n item.value,\n item.name === \"state\"\n ? item.name\n : `linkedin_contact/${item.name}`\n )\n .join(\" or \") +\n \")\"\n );\n }\n }\n }\n if (isBoolean(item.value)) {\n filtersArray.push(`${item.name} eq ${item.value}`);\n }\n });\n return filtersArray.join(\" and \");\n },\n\n buildFilterQuery(array) {\n const filtersArray = [];\n const newArray = [...array];\n const renamedArray = newArray.map((item) => {\n const newItem = { ...item };\n if (newItem.id === 1) {\n newItem.name = \"distance\";\n }\n if (newItem.id === 7) {\n newItem.name = \"is_premium\";\n newItem.value = newItem.value ? true : \"\";\n }\n if (newItem.id === 13) {\n newItem.name = \"campaigns\";\n }\n if (newItem.id === 14) {\n newItem.name = \"contacted\";\n }\n return newItem;\n });\n renamedArray.forEach((item) => {\n if (\n Array.isArray(item.value) &&\n item.value.length > 0 &&\n lFind(item.value, \"value\") &&\n !item.search\n ) {\n if (isDate(lFind(item.value, \"value\").value)) {\n if (item.exclude) {\n filtersArray.push(\n \"not (\" +\n filters.buildDataFilterParams(item.value, item.name) +\n \")\"\n );\n } else {\n filtersArray.push(\n \"(\" + filters.buildDataFilterParams(item.value, item.name) + \")\"\n );\n }\n } else {\n if (item.name === \"campaigns\") {\n if (item.exclude) {\n filtersArray.push(\n \"not (\" + filters.buildCampaigns(item.value) + \")\"\n );\n } else {\n filtersArray.push(\"(\" + filters.buildCampaigns(item.value) + \")\");\n }\n } else {\n filtersArray.push(\n \"(\" +\n filters\n .buildArrayFilterParams(item.value, item.name)\n .join(\" or \") +\n \")\"\n );\n }\n }\n }\n if (isBoolean(item.value)) {\n filtersArray.push(`${item.name} eq ${item.value}`);\n }\n });\n return filtersArray.join(\" and \");\n },\n\n buildDataFilterParams(array, name) {\n const dataArray = [];\n array.forEach((item) => {\n if (item.value) {\n if (item.id === 1) {\n dataArray.push(`${name} gt ${item.value.toISOString()}`);\n }\n if (item.id === 2) {\n dataArray.push(`${name} lt ${item.value.toISOString()}`);\n }\n }\n return item;\n });\n return dataArray.join(\" and \");\n },\n\n buildArrayFilterParams(array, name) {\n return array.map((item) => {\n let result = `${name} eq `;\n result += isNaN(item.value) ? `'${item.value}'` : item.value;\n return result;\n });\n },\n\n addKeyword(value, id, isModal) {\n const element = lFind(\n store.getState().filters[isModal ? \"filterDataForModal\" : \"filterData\"],\n [\"id\", id]\n );\n\n filters.buildKeywords(element, value, isModal);\n },\n\n buildKeywords(element, value, isModal) {\n const newValues = [...element.value];\n if (value && !lFind(newValues, [\"value\", value])) {\n newValues.push({\n key: filters.setKey(newValues),\n text: value,\n value,\n });\n element.value = newValues;\n\n if (isModal) {\n filters.changeFiltersForModal(element);\n } else {\n filters.changeFilters(element);\n }\n }\n },\n\n buildCampaigns(array) {\n const newArray = array.map((item) => {\n return `campaigns/any(c:c eq '${item.value}')`;\n });\n return newArray.join(\" or \");\n },\n\n setKey(array) {\n const newArray = [...array];\n for (let index = 0; index < 1000; index++) {\n if (!lFind(newArray, [\"key\", index + 1])) {\n return index + 1;\n }\n }\n },\n\n changeFilterQuery: (filtersArray, searchQuery) => {\n store.dispatch({\n type: \"FILTERS_QUERY_FOR_MODAL\",\n payload: {\n filtersQueryForModal: filtersArray,\n },\n });\n\n store.dispatch({\n type: \"FILTERS_SEARCH_QUERY_FOR_MODAL\",\n payload: {\n searchQueryForModal: searchQuery,\n },\n });\n },\n\n getContacts: async (\n filterData,\n importId,\n fromKey,\n _,\n search,\n location,\n sort\n ) => {\n const filtersArray = [];\n const filtersQuery = filters.buildFilterQuery(filterData);\n const searchQuery = filters.buildSearchQuery(filterData);\n if (importId) {\n if (fromKey === \"contacts\") {\n filtersArray.push(`tags/any(c:c eq '${importId}')`);\n }\n if (fromKey === \"addToCampaign\") {\n filtersArray.push(`not (campaigns/any(c:c eq '${importId}'))`);\n }\n }\n if (filtersQuery) {\n filtersArray.push(filtersQuery);\n }\n\n store.dispatch({\n type: \"FILTERS_QUERY\",\n payload: {\n filtersQuery: filtersArray.join(\" and \"),\n },\n });\n\n store.dispatch({\n type: \"FILTERS_SEARCH_QUERY\",\n payload: {\n searchQuery,\n },\n });\n contacts.getContacts({\n skip: 0,\n filter: filtersArray.join(\" and \"),\n keywords: search,\n orderby: location?.includes(\"/import\")\n ? sort\n ? sort\n : \"imported asc\"\n : sort,\n });\n },\n\n changeFiltersQueryForModal: (filterData, fromKey, importId) => {\n const filtersArray = [];\n const filtersQuery = filters.buildFilterQuery(filterData);\n const searchQueryForModal = filters.buildSearchQuery(filterData);\n if (fromKey === \"addToCampaignOfModal\") {\n filtersArray.push(`not (campaigns/any(c:c eq '${importId}'))`);\n }\n if (filtersQuery) {\n filtersArray.push(filtersQuery);\n }\n store.dispatch({\n type: \"FILTERS_SEARCH_QUERY_FOR_MODAL\",\n payload: {\n searchQueryForModal,\n },\n });\n store.dispatch({\n type: \"FILTERS_QUERY_FOR_MODAL\",\n payload: {\n filtersQueryForModal: filtersArray.length && filtersArray.join(\" and \"),\n },\n });\n },\n\n getContactsLocation: async (data) => {\n try {\n const response = await api.getContactsLocationApi(data);\n store.dispatch({\n type: \"OPTIONS_PARAMS\",\n payload: {\n location:\n response.status === 204\n ? []\n : mapping.buildOption(response.data, \"locations\"),\n },\n });\n } catch (error) {\n notifyError(error);\n store.dispatch({\n type: \"OPTIONS_PARAMS\",\n payload: {\n location: [],\n },\n });\n }\n },\n\n getCampaignsField: async (data) => {\n const objForRequest = data\n ? data\n : {\n take: 10,\n filter: \"not (state eq 'Compose')\",\n };\n try {\n const response = await api.getCampaignsApi(objForRequest);\n store.dispatch({\n type: \"OPTIONS_PARAMS\",\n payload: {\n campaigns:\n response.status === 204\n ? []\n : mapping.buildOption(response.data.documents, \"campaigns\"),\n },\n });\n } catch (error) {\n notifyError(error);\n store.dispatch({\n type: \"OPTIONS_PARAMS\",\n payload: {\n campaigns: [],\n },\n });\n }\n },\n\n getCampaigns: async (data, rerender = true) => {\n const { updateLeftMenu } = { ...data };\n !appSelectors.errorRequest(store.getState()).campaigns &&\n app.updateErrorRequest({\n campaigns: true,\n });\n\n try {\n const response = await api.getCampaignsApi(data);\n\n store.dispatch(\n campaignsActions.setCampaigns({\n campaigns: response.data\n ? mapping.buildCampaignsArray(response.data.documents)\n : [],\n\n campaignsCount: response.data.total,\n })\n );\n\n if (response.data) {\n if (response.data.documents.length > 0) {\n campaign.haveCampaigns(true);\n }\n if (updateLeftMenu) {\n campaign.loadCampaignList(response.data.documents);\n }\n }\n\n app.updateErrorRequest({\n campaigns: false,\n });\n } catch (error) {\n notifyError(error);\n store.dispatch(\n campaignsActions.setCampaigns({\n campaigns: [],\n })\n );\n\n if (updateLeftMenu) {\n campaign.loadCampaignList([]);\n }\n } finally {\n rerender && app.changePageContentLoaderStatus(false);\n rerender && app.changeTableContentLoaderStatus(false);\n }\n },\n\n getArchivedCampaigns: async () => {\n try {\n return await api.getCampaignsApi({\n archived: true,\n });\n } catch (error) {\n notifyError(error);\n app.changePageContentLoaderStatus(false);\n app.changeTableContentLoaderStatus(false);\n }\n },\n\n clearFilter(item, from) {\n item.tag = \"\";\n const fromModal = from === \"addToCampaignOfModal\";\n if (Array.isArray(item.value)) {\n // a bit stupid approach, let it be\n const isTimeRange = item.value.length === 2;\n if (isTimeRange) {\n item.value = [\n { id: 1, value: null },\n { id: 2, value: null },\n ];\n const element = lFind(\n [\n ...store.getState().filters[\n fromModal ? \"filterDataForModal\" : \"filterData\"\n ],\n ],\n [\"id\", item.selectId]\n );\n element.value = null;\n fromModal\n ? filters.changeFiltersForModal(element)\n : filters.changeFilters(element);\n } else {\n item.value = [];\n }\n }\n if (isString(item.value)) {\n item.value = \"\";\n }\n if (isPlainObject(item.value)) {\n item.value = null;\n }\n fromModal ? this.changeFiltersForModal(item) : this.changeFilters(item);\n },\n\n clearAllFilters(forModal) {\n const filterData = [\n {\n id: 1,\n name: \"connection\",\n exclude: false,\n search: false,\n value: [],\n tag: \"\",\n },\n {\n id: 2,\n name: \"location\",\n exclude: false,\n search: false,\n value: [],\n tag: \"\",\n },\n {\n id: 3,\n name: \"industry\",\n exclude: false,\n search: false,\n value: [],\n tag: \"\",\n },\n {\n id: 4,\n name: \"keywords\",\n exclude: false,\n search: true,\n value: [],\n tag: \"\",\n },\n {\n id: 5,\n name: \"company\",\n exclude: false,\n search: false,\n value: [],\n tag: \"\",\n },\n {\n id: 6,\n selectId: 9,\n name: \"contacted\",\n exclude: false,\n search: false,\n value: [\n { id: 1, value: null },\n { id: 2, value: null },\n ],\n tag: \"\",\n },\n {\n id: 7,\n name: \"status\",\n exclude: false,\n search: false,\n value: \"\",\n tag: \"\",\n },\n {\n id: 8,\n name: \"createdSelect\",\n exclude: false,\n search: false,\n value: null,\n },\n {\n id: 9,\n name: \"contactedSelect\",\n exclude: false,\n search: false,\n value: null,\n },\n {\n id: 10,\n name: \"campaigns\",\n exclude: false,\n search: false,\n value: [],\n tag: \"\",\n },\n {\n id: 11,\n name: \"exclude contactedSelect\",\n exclude: false,\n search: false,\n value: null,\n },\n {\n id: 12,\n name: \"NOT: keywords\",\n exclude: true,\n search: true,\n value: [],\n tag: \"\",\n },\n {\n id: 13,\n name: \"NOT: campaigns\",\n exclude: true,\n search: false,\n value: [],\n tag: \"\",\n },\n {\n id: 14,\n selectId: 11,\n name: \"NOT: contacted\",\n exclude: true,\n search: false,\n value: [\n { id: 1, value: null },\n { id: 2, value: null },\n ],\n tag: \"\",\n },\n {\n id: 15,\n selectId: 8,\n name: \"created\",\n exclude: false,\n search: false,\n value: [\n { id: 1, value: null },\n { id: 2, value: null },\n ],\n tag: \"\",\n },\n ];\n store.dispatch({\n type: forModal ? \"FILTERS_PARAMS_FOR_MODAL\" : \"FILTERS_PARAMS\",\n payload: {\n [forModal ? \"filterDataForModal\" : \"filterData\"]: filterData,\n },\n });\n return filterData;\n },\n};\n","import { Tooltip, styled } from \"@mui/material\";\n\nconst CustomTooltip = styled(({ className, ...props }) => (\n \n))(({ theme, visible }) => ({\n fontSize: \"14px\",\n lineHeight: \"19px\",\n padding: \"2px 12px 3px 12px\",\n width: \"fit-content\",\n maxWidth: \"95vw\",\n marginTop: \"9px\",\n visibility: visible ? \"visible\" : \"hidden\",\n opacity: visible ? 1 : 0,\n transition: \"opacity 0.3s ease, visibility 0.3s ease\",\n}));\n\nexport const CustomTip = styled(({ className, ...props }) => (\n \n))(({ theme }) => ({\n fontSize: \"14px\",\n lineHeight: \"19px\",\n padding: \"2px 12px 3px 12px\",\n width: \"fit-content\",\n maxWidth: \"95vw\",\n marginTop: \"9px\",\n visibility: \"visible\",\n opacity: 1,\n transition: \"opacity 0.3s ease, visibility 0.3s ease\",\n}));\n\nconst TooltipCustom = (props) => {\n const { arrow, title, children, isVisible } = props;\n\n return title ? (\n \n {title?.split(\"\\n\").map((paragraph, index) => (\n

    \n {paragraph}\n

    \n ))}\n
    \n }\n arrow={arrow}\n visible={isVisible}\n enterDelay={500}\n enterNextDelay={500}\n leaveDelay={0}\n >\n {children}\n \n ) : (\n children\n );\n};\n\nexport default TooltipCustom;\n","// extracted by css-extract-rspack-plugin\nexport default {\"yellow\":\"yellow-xGSsOx\",\"root\":\"root-DHOdFW\",\"accent\":\"accent-bl8WWa\",\"title\":\"title-bA0z38\",\"cta\":\"cta-uAp_t2\",\"pic\":\"pic-TFH2lx\"};","import unhappyImage from 'assets/image/snail-no.png'\r\nimport happyImage from 'assets/image/snail-subscription.png'\r\nimport { CONSTS } from 'config/objectConst'\r\nimport { Link } from 'react-router-dom'\r\nimport { appDay } from 'shared/day'\r\nimport { useAppSelector } from 'shared/hooks'\r\nimport { Button } from 'shared/ui'\r\n\r\nimport { appSelectors } from '../../../redux/reducers/app'\r\nimport css from './TrialNotification.module.scss'\r\n\r\nconst NOW = appDay(),\r\n\tTRIAL_KEY = CONSTS.SUBSCRIPTIONS.TRIAL.ID\r\n\r\nexport function TrialNotification() {\r\n\t// ! was broken before switch to FC, connected to not exist state\r\n\t// const isImpersonated = useAppSelector(appSelectors.isImpersonated)\r\n\tconst isImpersonated = false\r\n\r\n\tconst subscription = useAppSelector(appSelectors.subscription)\r\n\r\n\tconst isActive = Boolean(subscription?.is_active),\r\n\t\tisTrial = subscription?.plan_id === TRIAL_KEY,\r\n\t\tisActiveSubscription = !isTrial && isActive && !isImpersonated,\r\n\t\tisActiveTrial = isTrial && isActive && !isImpersonated,\r\n\t\tisExpiredTrial = isTrial && !isActive && !isImpersonated,\r\n\t\tisInactiveSubscription = !isTrial && !isActive && !isImpersonated,\r\n\t\tisSubscriptionExpired = isExpiredTrial || isInactiveSubscription\r\n\r\n\tif (!subscription?.plan_id) {\r\n\t\treturn null\r\n\t}\r\n\r\n\tconst generateTitle = () => {\r\n\t\tif (isActiveTrial) {\r\n\t\t\treturn `Trial will expire in ${getUnits(subscription.next_charge_date)}`\r\n\t\t}\r\n\r\n\t\tif (isExpiredTrial) {\r\n\t\t\treturn 'Trial period is expired'\r\n\t\t}\r\n\t\tif (isActiveSubscription) {\r\n\t\t\treturn 'Subscription is active'\r\n\t\t}\r\n\t\tif (isInactiveSubscription) {\r\n\t\t\treturn 'Subscription is inactive'\r\n\t\t}\r\n\t}\r\n\r\n\treturn (\r\n\t\t
    \r\n\t\t\t

    {generateTitle()}

    \r\n\t\t\t\r\n\r\n\t\t\t\r\n\t\t
    \r\n\t)\r\n}\r\n\r\nfunction getUnits(datetime: string) {\r\n\tconst asDay = appDay(datetime)\r\n\r\n\tlet diff = Math.ceil(asDay.diff(NOW, 'hour', true))\r\n\r\n\tlet units = 'hour'\r\n\tif (diff > 24) {\r\n\t\tunits = 'day'\r\n\t\tdiff = Math.ceil(asDay.diff(NOW, 'day', true))\r\n\t}\r\n\r\n\tif (diff > 1) {\r\n\t\tunits += 's'\r\n\t}\r\n\treturn `${diff} ${units}`\r\n}\r\n\r\nexport default TrialNotification\r\n","import type { LeftMenuType } from 'redux/reducers/leftSideMenu'\r\n\r\nimport { app } from 'actions/app'\r\nimport { contacts } from 'actions/contacts'\r\nimport { filters } from 'actions/filters'\r\nimport clearListIcon from 'assets/image/icons/left-side-menu/clear-list.svg'\r\nimport clsx from 'clsx'\r\n\r\nimport './style.scss'\r\n\r\nimport { Link, useHistory, useParams } from 'react-router-dom'\r\nimport { useAppSelector } from 'shared/hooks'\r\n\r\nimport TooltipCustom from '../../atoms/tooltipCustom'\r\nimport TrialNotification from '../trialNotification'\r\nimport css from './LeftSideMenu.module.scss'\r\n\r\nconst linkBuilder = (type: LeftMenuType, id: string, archived = false) => {\r\n\tconst link = archived ? '/archive' : '/campaigns'\r\n\tswitch (type) {\r\n\t\tcase 'campaign':\r\n\t\tcase 'team':\r\n\t\t\treturn `${link}/${id}`\r\n\r\n\t\tcase 'contacts':\r\n\t\t\treturn `/campaigns/${id}/contacts`\r\n\r\n\t\tdefault:\r\n\t\t\treturn ''\r\n\t}\r\n}\r\n\r\nexport function LeftSideMenu({\r\n\tclassName\r\n}: {\r\n\tclassName?: string\r\n}) {\r\n\tconst active = useAppSelector(state => state.leftSideMenu.active),\r\n\t\tcampaign = useAppSelector(state => state.campaign),\r\n\t\tleftSide = useAppSelector(state => state.leftSideMenu.leftSide)\r\n\r\n\tconst { id } = useParams<{ id?: string }>()\r\n\tconst { push } = useHistory()\r\n\r\n\tconst bottomListActiveHandler = (item: any) => {\r\n\t\tif (leftSide.type === 'account') {\r\n\t\t\treturn\r\n\t\t}\r\n\t\tif (id) {\r\n\t\t\tif (campaign.archive && item.link === '/archive') {\r\n\t\t\t\treturn 'active semi-bold'\r\n\t\t\t}\r\n\t\t\tif (!campaign.archive && item.link === '/campaigns') {\r\n\t\t\t\tconst campaign = leftSide.list?.find(item => item.id === id)\r\n\t\t\t\treturn !campaign ? 'active semi-bold' : ''\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\treturn active === item.id ? 'active semi-bold' : ''\r\n\t\t}\r\n\t}\r\n\r\n\tconst clickOnLink = (item: { id: string }) => {\r\n\t\tapp.changeActiveItem(item.id)\r\n\t\tcontacts.changeContactsPage(0)\r\n\t\tpush(`/campaigns/${item.id}`)\r\n\t}\r\n\r\n\tconst onClickRecentImportItem = (item: { id: string }) => {\r\n\t\tapp.changeActiveItem(item.id)\r\n\t\tfilters.clearAllFilters()\r\n\t\tcontacts.changeContactsPage(0)\r\n\t}\r\n\r\n\treturn (\r\n\t\t
    \r\n\t\t\t
    \r\n\t\t\t\t{leftSide.type === 'messaging' && (\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t{'pageIcon'}\r\n\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t{leftSide.bottomList[0].title}\r\n\t\t\t\t\t\r\n\t\t\t\t)}\r\n\t\t\t\t{leftSide.type === 'account' && (\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t{'pageIcon'}\r\n\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t{leftSide.bottomList[0].title}\r\n\t\t\t\t\t\r\n\t\t\t\t)}\r\n\r\n\t\t\t\t{leftSide.type === 'team' && leftSide.bottomList && (\r\n\t\t\t\t\t<>\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t{'pageIcon'}\r\n\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t{leftSide.bottomList[0].title}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t
      \r\n\t\t\t\t\t\t\t{leftSide.bottomList.slice(1).map(item => {\r\n\t\t\t\t\t\t\t\treturn (\r\n\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t
      \r\n\t\t\t\t\t\t\t\t\t\t\t\t{'pageIcon'}\r\n\t\t\t\t\t\t\t\t\t\t\t
      \r\n\t\t\t\t\t\t\t\t\t\t\t{item.title}\r\n\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t)\r\n\t\t\t\t\t\t\t})}\r\n\t\t\t\t\t\t
    \r\n\t\t\t\t\t\r\n\t\t\t\t)}\r\n\t\t\t\t{leftSide.type === 'campaign' && (\r\n\t\t\t\t\t<>\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t{'pageIcon'}\r\n\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t{leftSide.bottomList[0].title}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t
      \r\n\t\t\t\t\t\t\t{leftSide.bottomList.slice(1).map(item => {\r\n\t\t\t\t\t\t\t\treturn (\r\n\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t
      \r\n\t\t\t\t\t\t\t\t\t\t\t\t{'pageIcon'}\r\n\t\t\t\t\t\t\t\t\t\t\t
      \r\n\t\t\t\t\t\t\t\t\t\t\t{item.title}\r\n\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t)\r\n\t\t\t\t\t\t\t})}\r\n\t\t\t\t\t\t
    \r\n\r\n\t\t\t\t\t\t{leftSide.list && leftSide.list?.length > 0 && (\r\n\t\t\t\t\t\t\t<>\r\n\t\t\t\t\t\t\t\t
    {leftSide.label}
    \r\n\t\t\t\t\t\t\t\t
      \r\n\t\t\t\t\t\t\t\t\t{leftSide.list?.map(item => {\r\n\t\t\t\t\t\t\t\t\t\treturn (\r\n\t\t\t\t\t\t\t\t\t\t\t!item.archived && (\r\n\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t{leftSide.type === 'contacts' ? (\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t onClickRecentImportItem(item)}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={`/contacts/import/${item.id}`}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t 24 ? item.name : ''}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t 24\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? 'ellipsis'\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: 'left-list-text'\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{item.name}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t

      \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t) : (\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t clickOnLink(item)}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tlinkBuilder(\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tleftSide.type,\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\titem.id,\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\titem.archived\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t) || ''\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t 24 ? item.name : ''}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t 24\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? 'ellipsis'\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: 'left-list-text'\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{item.name}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t

      \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t)\r\n\t\t\t\t\t\t\t\t\t\t)\r\n\t\t\t\t\t\t\t\t\t})}\r\n\t\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t)}\r\n\t\t\t\t\t\r\n\t\t\t\t)}\r\n\t\t\t\t{leftSide.type === 'contacts' && (\r\n\t\t\t\t\t<>\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t{'pageIcon'}\r\n\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t{leftSide.bottomList[0].title}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t{leftSide.list && leftSide.list?.length > 0 && (\r\n\t\t\t\t\t\t\t<>\r\n\t\t\t\t\t\t\t\t{' '}\r\n\t\t\t\t\t\t\t\t
    {leftSide.label}
    \r\n\t\t\t\t\t\t\t\t
      \r\n\t\t\t\t\t\t\t\t\t{leftSide.list?.map(item => {\r\n\t\t\t\t\t\t\t\t\t\treturn (\r\n\t\t\t\t\t\t\t\t\t\t\t!item.archived && (\r\n\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t{leftSide.type === 'contacts' ? (\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t onClickRecentImportItem(item)}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={`/contacts/import/${item.id}`}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t 24 ? item.name : ''}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t 24\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? 'ellipsis'\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: 'left-list-text'\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{item.name}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t

      \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t) : (\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t clickOnLink(item)}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tlinkBuilder(\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tleftSide.type,\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\titem.id,\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\titem.archived\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t) || ''\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t 24 ? item.name : ''}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t 24\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? 'ellipsis'\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: 'left-list-text'\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{item.name}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t

      \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t)\r\n\t\t\t\t\t\t\t\t\t\t)\r\n\t\t\t\t\t\t\t\t\t})}\r\n\t\t\t\t\t\t\t\t
    {' '}\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t)}\r\n\t\t\t\t\t\r\n\t\t\t\t)}\r\n\t\t\t
    \r\n\t\t\t\r\n\t\t
    \r\n\t)\r\n}\r\n\r\nexport default LeftSideMenu\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"root\":\"root-dukD6S\",\"list\":\"list-q4ZMe_\",\"with-shift\":\"with-shift-JJgVIR\",\"withShift\":\"with-shift-JJgVIR\"};","// extracted by css-extract-rspack-plugin\nexport default {\"list\":\"list-kUJmqa\",\"link\":\"link-T2HrMx\",\"active\":\"active-v5KFW9\"};","import clsx from 'clsx'\r\nimport { mailboxApi, MailboxUI } from 'features/messaging'\r\nimport { memo } from 'react'\r\nimport { Link, useLocation } from 'react-router-dom'\r\nimport { useAppSelector } from 'shared/hooks'\r\nimport typo from 'shared/styles/typography.module.scss'\r\n\r\nimport { appSelectors } from '../../../redux/reducers/app'\r\nimport css from './NavigationMenu.module.scss'\r\n\r\ninterface LinkItem {\r\n\thref: string\r\n\tisCurrent: (pathname: string) => boolean\r\n\tlabel: string\r\n}\r\n\r\nconst createLink = (\r\n\thref: string,\r\n\tlabel: string,\r\n\tisCurrent = (pathname: string) => pathname.startsWith(href)\r\n): LinkItem => ({\r\n\thref,\r\n\tisCurrent,\r\n\tlabel\r\n})\r\n\r\nconst links: LinkItem[] = [\r\n\tcreateLink(\r\n\t\t'/campaigns',\r\n\t\t'Campaigns',\r\n\t\tpathname =>\r\n\t\t\tpathname.startsWith('/campaigns') || pathname.startsWith('/archive')\r\n\t),\r\n\tcreateLink('/contacts', 'Contacts'),\r\n\tcreateLink('/team/members', 'Team', pathname => pathname.startsWith('/team'))\r\n]\r\n\r\nconst mailboxLink: LinkItem = createLink('/messaging', 'Messaging')\r\n\r\nfunction NavigationMenu_() {\r\n\tconst { pathname } = useLocation()\r\n\r\n\tconst isBetaUser = useAppSelector(appSelectors.isBetaUser)\r\n\tconst renderLinks = isBetaUser ? links.concat(mailboxLink) : links\r\n\r\n\treturn (\r\n\t\t\r\n\t)\r\n}\r\n\r\nfunction UnreadCount() {\r\n\tconst hasAutomatization = useAppSelector(appSelectors.hasAutomation)\r\n\r\n\tconst isPulling = MailboxUI.useIsPulling()\r\n\r\n\tconst { data } = mailboxApi.useUnreadQuery(\r\n\t\tundefined,\r\n\t\tisPulling\r\n\t\t\t? {\r\n\t\t\t\t\t...MailboxUI.PULLING_OPTIONS,\r\n\t\t\t\t\tskip: !hasAutomatization\r\n\t\t\t\t}\r\n\t\t\t: {\r\n\t\t\t\t\tskip: !hasAutomatization\r\n\t\t\t\t}\r\n\t)\r\n\r\n\treturn \r\n}\r\n\r\nexport const NavigationMenu = memo(NavigationMenu_)\r\n","import { Component } from \"react\";\nimport { Link } from \"react-router-dom\";\nimport logo from \"../../../assets/image/logo.svg\";\n// style\nimport \"./style.scss\";\n\nexport class Logo extends Component {\n render() {\n return (\n \n
    \n \"Logo\"\n
    \n \n );\n }\n}\n\nexport default Logo;\n","import { appConnector } from 'shared/connector'\r\n\r\nimport type { Profile } from './types'\r\n\r\nimport { apiRTK } from '../api-rtk'\r\n\r\nexport const connectorApi = apiRTK.injectEndpoints({\r\n\tendpoints: create => ({\r\n\t\tcaptureLinkedIn: create.mutation({\r\n\t\t\tasync queryFn() {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tconst data = await appConnector.linkedIn.captureCurrentProfile()\r\n\t\t\t\t\treturn { data }\r\n\t\t\t\t} catch (error) {\r\n\t\t\t\t\treturn { error }\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}),\r\n\r\n\t\tsignInUnderTeamMember: create.mutation({\r\n\t\t\tasync queryFn(id) {\r\n\t\t\t\tconst signIn = appConnector.auth.signInUnderTeamMember\r\n\r\n\t\t\t\ttry {\r\n\t\t\t\t\tawait signIn(id)\r\n\t\t\t\t\treturn { data: true }\r\n\t\t\t\t} catch (error) {\r\n\t\t\t\t\treturn { error }\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}),\r\n\r\n\t\tsignOut: create.mutation({\r\n\t\t\tasync queryFn() {\r\n\t\t\t\tconst signOut = appConnector.auth.signOut\r\n\r\n\t\t\t\ttry {\r\n\t\t\t\t\tawait signOut()\r\n\t\t\t\t\treturn { data: true }\r\n\t\t\t\t} catch (error) {\r\n\t\t\t\t\treturn { error }\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}),\r\n\r\n\t\tstopMemberSession: create.mutation({\r\n\t\t\tasync queryFn() {\r\n\t\t\t\tconst signOut = appConnector.auth.signOutUnderTeamMember\r\n\r\n\t\t\t\ttry {\r\n\t\t\t\t\tawait signOut()\r\n\t\t\t\t\treturn { data: true }\r\n\t\t\t\t} catch (error) {\r\n\t\t\t\t\treturn { error }\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t})\r\n\t}),\r\n\toverrideExisting: true\r\n})\r\n","import { connectorApi } from 'api/connector/api'\r\nimport { useHistory } from 'react-router-dom'\r\nimport { notifyError } from 'shared/errors'\r\n\r\nexport function useStopReloadSession() {\r\n\tconst { push } = useHistory()\r\n\r\n\tconst [signOutMember, mutationOptions] =\r\n\t\tconnectorApi.useStopMemberSessionMutation()\r\n\r\n\treturn [\r\n\t\t() =>\r\n\t\t\tsignOutMember()\r\n\t\t\t\t.unwrap()\r\n\t\t\t\t.then(() => push('/team/members'))\r\n\t\t\t\t.catch(notifyError),\r\n\t\tmutationOptions\r\n\t] as const\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"wrapper\":\"wrapper-VafBhZ\",\"trigger\":\"trigger-jE7qYm\",\"name\":\"name-hNSfoq\",\"popover\":\"popover-waRokx\",\"line\":\"line-khLO0i\",\"logOut\":\"logOut-1qE7t2\",\"footer\":\"footer-QY1ewX\",\"showFilters\":\"showFilters-Mi8j0B\"};","import { connectorApi } from 'api/connector/api.ts'\r\nimport { ResponsiveButton } from 'components/atoms/responsiveButton'\r\nimport { useAppSelector } from 'shared/hooks/store.ts'\r\nimport { useStopReloadSession } from 'shared/hooks/useStopReloadSession.ts'\r\n\r\nimport { appSelectors } from '../../../redux/reducers/app'\r\nimport css from './UserHeaderWidget.module.scss'\r\n\r\nexport function LogOut() {\r\n\tconst impersonatedPersona = useAppSelector(appSelectors.isImpersonated)\r\n\r\n\tconst [signOutMember, { isLoading: isLoadingStopSession }] =\r\n\t\tuseStopReloadSession()\r\n\tconst [signOut, { isLoading }] = connectorApi.useSignOutMutation()\r\n\r\n\treturn impersonatedPersona ? (\r\n\t\t\r\n\t\t\tStop session\r\n\t\t\r\n\t) : (\r\n\t\t signOut()}\r\n\t\t>\r\n\t\t\tLog Out\r\n\t\t\r\n\t)\r\n}\r\n","import CircularProgress from '@mui/material/CircularProgress'\r\nimport { CONSTS } from 'config/objectConst.js'\r\nimport { workspaceApi, WorkSpaceUI, workspaceUtils } from 'features/workspace'\r\nimport { useEffect, useRef } from 'react'\r\nimport { Link } from 'react-router-dom'\r\nimport { useAppSelector } from 'shared/hooks/index.ts'\r\nimport { useLatest } from 'shared/hooks/useLatest.ts'\r\nimport { typo } from 'shared/styles'\r\nimport { Button, StackIcon } from 'shared/ui/index.ts'\r\n\r\nimport LinkedInBlock from '../../atoms/LinkedInBlock/index.js'\r\nimport { LogOut } from './LogOut.tsx'\r\nimport css from './UserHeaderWidget.module.scss'\r\n\r\n/*\r\n\t? Refetch statistics on open popover\r\n\r\n\tIn future when all query will wrapped with RTK query, we could refetch stats with invalidate query\r\n*/\r\n\r\nexport function DropDownMenu() {\r\n\tconst rangeState = useAppSelector(workspaceUtils.selectCurrentDay)\r\n\tconst [fetch, { data: statistics, isFetching }] =\r\n\t\tworkspaceApi.useLazyStatisticsQuery()\r\n\r\n\tconst popoverRef = useRef(null)\r\n\tconst close = () => popoverRef.current?.hidePopover()\r\n\r\n\tconst fetchRef = useLatest(fetch)\r\n\tuseEffect(() => {\r\n\t\tif (!popoverRef.current) {\r\n\t\t\treturn\r\n\t\t}\r\n\r\n\t\tconst controller = new AbortController()\r\n\r\n\t\tconst popover = popoverRef.current\r\n\r\n\t\tfunction listener(event: Event) {\r\n\t\t\tif ('newState' in event && event.newState === 'open') {\r\n\t\t\t\tfetchRef.current(rangeState)\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpopover.addEventListener('toggle', listener, {\r\n\t\t\tsignal: controller.signal\r\n\t\t})\r\n\r\n\t\treturn () => controller.abort()\r\n\t}, [rangeState, fetchRef])\r\n\r\n\treturn (\r\n\t\t\r\n\t\t\t\r\n\r\n\t\t\t
    \r\n\r\n\t\t\t\r\n\r\n\t\t\t
    \r\n\t\t\t
    \r\n\t\t\t\t

    \r\n\t\t\t\t\tPerformed today:{' '}\r\n\t\t\t\t\t{isFetching && (\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t)}\r\n\t\t\t\t

    \r\n\t\t\t\t\r\n\t\t\t
    \r\n\t\t\t
    \r\n\t\t\t\r\n\r\n\t\t\t
    \r\n\t\t\t
    \r\n\t\t\t\t\r\n\t\t\t\t\tTerms of use\r\n\t\t\t\t\r\n\r\n\t\t\t\t\r\n\t\t\t\t\tPrivacy policy\r\n\t\t\t\t\r\n\t\t\t
    \r\n\t\t\r\n\t)\r\n}\r\n","import clsx from 'clsx'\r\n\r\n// Style\r\nimport './style.scss'\r\n\r\nimport { useAppSelector } from 'shared/hooks'\r\nimport { typo } from 'shared/styles'\r\n\r\nimport { appSelectors } from '../../../redux/reducers/app'\r\nimport { DropDownMenu } from './dropDownMenu'\r\nimport css from './UserHeaderWidget.module.scss'\r\n\r\nexport function UserProfilePersona() {\r\n\tconst email = useAppSelector(\r\n\t\tstate => appSelectors.persona(state)?.email ?? ''\r\n\t)\r\n\tconst fullName = useAppSelector(appSelectors.fullName)\r\n\r\n\tif (!email) {\r\n\t\treturn null\r\n\t}\r\n\r\n\treturn (\r\n\t\t<>\r\n\t\t\t\r\n\t\t\t\t{fullName}\r\n\t\t\t\t{email}\r\n\t\t\t\r\n\r\n\t\t\t\r\n\t\t\r\n\t)\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"navigation\":\"navigation-YaIHvU\"};","import timer from 'assets/image/icons/svg/timer.svg'\r\nimport { useEffect, useState } from 'react'\r\nimport { appDay } from 'shared/day.ts'\r\nimport { useAppSelector } from 'shared/hooks/store.ts'\r\nimport { useLatest } from 'shared/hooks/useLatest.ts'\r\nimport { useStopReloadSession } from 'shared/hooks/useStopReloadSession.ts'\r\n\r\nimport type { RootState } from '../../../redux/store.ts'\r\n\r\nimport { appSelectors } from '../../../redux/reducers/app'\r\nimport { ResponsiveButton } from '../../atoms/responsiveButton/index.tsx'\r\n\r\nconst enum Border {\r\n\tReload = 30_000,\r\n\t/** 5 minutes */\r\n\tShow = 300_000\r\n}\r\n\r\nconst selectExpired = (state: RootState) =>\r\n\tappSelectors.persona(state)?.accessTokenExpiresAt ?? ''\r\n\r\nexport function ImpersonatedTimer() {\r\n\tconst expired = useAppSelector(selectExpired)\r\n\tconst [logOut, { isLoading }] = useStopReloadSession()\r\n\r\n\tconst [timerStarted, setTimerStarted] = useState(false)\r\n\r\n\tconst logOutRef = useLatest(logOut)\r\n\r\n\tuseEffect(() => {\r\n\t\tif (expired) {\r\n\t\t\tconst diff = appDay(expired).diff(Date.now(), 'ms')\r\n\t\t\tif (diff <= Border.Show) {\r\n\t\t\t\treturn setTimerStarted(true)\r\n\t\t\t}\r\n\r\n\t\t\tconst delay = diff - Border.Show\r\n\t\t\tconst timer = setTimeout(() => {\r\n\t\t\t\tsetTimerStarted(true)\r\n\t\t\t}, delay)\r\n\r\n\t\t\treturn () => clearTimeout(timer)\r\n\t\t}\r\n\t}, [expired])\r\n\r\n\tuseEffect(() => {\r\n\t\tif (!expired) {\r\n\t\t\treturn\r\n\t\t}\r\n\t\tconst delay = appDay(expired).diff(Date.now(), 'ms') + Border.Reload\r\n\r\n\t\tif (delay <= 0) {\r\n\t\t\tlogOutRef.current()\r\n\t\t\treturn\r\n\t\t}\r\n\r\n\t\tconst timer = setTimeout(logOutRef.current, delay)\r\n\t\treturn () => clearTimeout(timer)\r\n\t}, [expired, logOutRef])\r\n\r\n\treturn (\r\n\t\t
    \r\n\t\t\t{timerStarted && }\r\n\t\t\t\r\n\t\t\t\tStop session\r\n\t\t\t\r\n\t\t
    \r\n\t)\r\n}\r\n\r\nfunction Timer() {\r\n\tconst expired = useAppSelector(selectExpired)\r\n\tconst [showed, setShowed] = useState(0)\r\n\r\n\tuseEffect(() => {\r\n\t\tfunction updateUI() {\r\n\t\t\tconst minutes = appDay(expired).diff(Date.now(), 'minutes')\r\n\t\t\tsetShowed(minutes)\r\n\t\t}\r\n\r\n\t\tupdateUI()\r\n\t\tconst interval = setInterval(updateUI, 1_000)\r\n\r\n\t\treturn () => clearInterval(interval)\r\n\t}, [expired])\r\n\r\n\treturn (\r\n\t\t<>\r\n\t\t\ttimer\r\n\t\t\t{showed} min{' '}\r\n\t\t\t|\r\n\t\t\r\n\t)\r\n}\r\n","import type { HTMLAttributes } from 'react'\r\n\r\nimport { linkedInProfileOpener } from 'api/linkedInProfileOpener'\r\nimport linkIconAccent from 'assets/image/icons/svg/icons/linkIconAccent.svg'\r\nimport clsx from 'clsx'\r\nimport { NavigationMenu } from 'components/molecules/navigationMenu/NavigationMenu.tsx'\r\nimport { NotificationUI } from 'features/notifications'\r\nimport { useAppSelector } from 'shared/hooks/store.ts'\r\n\r\nimport './style.scss'\r\nimport { appSelectors } from '../../../redux/reducers/app'\r\nimport Logo from '../../atoms/Logo'\r\nimport { UserProfilePersona } from '../userProfilePersona'\r\nimport css from './Header.module.scss'\r\nimport { ImpersonatedTimer } from './ImpersonatedTimer.tsx'\r\n\r\nexport function Header({ className }: HTMLAttributes) {\r\n\tconst isImpersonated = useAppSelector(appSelectors.isImpersonated)\r\n\r\n\treturn (\r\n\t\t
    \r\n\t\t\t\r\n\t\t\t
    \r\n\t\t\t\t\r\n\r\n\t\t\t\t{isImpersonated && }\r\n\r\n\t\t\t\t\r\n\t\t\t\t\t{isImpersonated && }\r\n\r\n\t\t\t\t\t\r\n\t\t\t\t
    \r\n\t\t\t\t\r\n\t\t\t\r\n\t\t
    \r\n\t)\r\n}\r\n\r\n// ? Why not link\r\nfunction LinkedLink() {\r\n\tconst linkedInProfile = useAppSelector(\r\n\t\tstate => appSelectors.persona(state)?.linkedInProfile\r\n\t)\r\n\r\n\treturn (\r\n\t\t {\r\n\t\t\t\tlinkedInProfileOpener.open(linkedInProfile)\r\n\t\t\t}}\r\n\t\t\tsrc={linkIconAccent}\r\n\t\t/>\r\n\t)\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"root\":\"root-dzzDzo\",\"header\":\"header-nM0Zjb\",\"side\":\"side-Rjb2PP\",\"main\":\"main-FybDsM\"};","import type { PropsWithChildren } from 'react'\r\n\r\nimport clsx from 'clsx'\r\nimport { SupportButton } from 'components/atoms/SupportButton/SupportButton.js'\r\nimport { CONSTS } from 'config/objectConst.js'\r\nimport { useLocation } from 'react-router-dom'\r\n// @ts-ignore\r\nimport { Element } from 'react-scroll'\r\nimport { useDocumentTitle } from 'shared/hooks'\r\n\r\nimport LeftSideMenu from '../../molecules/leftSideMenu/index.js'\r\nimport { Header } from '../../organisms/Header/index'\r\nimport css from './HomeTemplate.module.scss'\r\n\r\nexport function HomeTemplate({\r\n\tchildren,\r\n\tid = 'homeTemplateContainerID'\r\n}: PropsWithChildren<{\r\n\tid?: string\r\n}>) {\r\n\tconst location = useLocation()\r\n\tuseDocumentTitle(CONSTS.PROJECT_NAME)\r\n\treturn (\r\n\t\t
    \r\n\t\t\t
    \r\n\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t{children}\r\n\t\t\t\r\n\t\t\t\r\n\t\t
    \r\n\t)\r\n}\r\n","import type { HTMLAttributes } from 'react'\r\n\r\nimport clsx from 'clsx'\r\nimport { SupportButton } from 'components/atoms/SupportButton/SupportButton.js'\r\nimport { CONSTS } from 'config/objectConst.js'\r\nimport { useDocumentTitle } from 'shared/hooks'\r\n\r\nimport LeftSideMenu from '../../molecules/leftSideMenu/index.js'\r\nimport { Header } from '../../organisms/Header/index'\r\nimport css from './HomeTemplate.module.scss'\r\n\r\n// Simple variant\r\n\r\nexport function LoggedLayout({\r\n\tclassName,\r\n\t...props\r\n}: HTMLAttributes) {\r\n\tuseDocumentTitle(CONSTS.PROJECT_NAME)\r\n\treturn (\r\n\t\t
    \r\n\t\t\t
    \r\n\r\n\t\t\t\r\n\t\t\t
    \r\n\r\n\t\t\t\r\n\t\t
    \r\n\t)\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"root\":\"root-bPtbyR\"};","import accountSvg from 'assets/image/icons/svg/account.svg'\r\nimport { AccountProfile } from 'components/molecules/account/accountProfile.tsx'\r\nimport { WorkingHoursProfile } from 'components/molecules/account/workingHoursProfile/index.tsx'\r\nimport { HomeTemplate } from 'components/templates/homeTemplate'\r\nimport { useEffect } from 'react'\r\nimport { leftSideHooks, useActionCreators } from 'shared/hooks'\r\n\r\nimport { appActions } from '../../redux/reducers/app.ts'\r\nimport css from './AccountPage.module.scss'\r\n\r\nconst leftSide: leftSideHooks.LeftSideInput = {\r\n\tbottomList: [\r\n\t\t{\r\n\t\t\tid: 1,\r\n\t\t\timage: accountSvg,\r\n\t\t\tlink: '/account',\r\n\t\t\ttitle: 'Snaily account'\r\n\t\t}\r\n\t],\r\n\ttype: 'account'\r\n}\r\n\r\nfunction AccountPage() {\r\n\tconst { changePage } = useActionCreators(appActions)\r\n\r\n\tleftSideHooks.useLeft(leftSide)\r\n\r\n\tuseEffect(() => {\r\n\t\tchangePage('/account')\r\n\t}, [changePage])\r\n\r\n\treturn (\r\n\t\t\r\n\t\t\t
    \r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t
    \r\n\t\t
    \r\n\t)\r\n}\r\n\r\nexport default AccountPage\r\n","import \"./style.scss\";\n\nimport dangerIcon from \"../../../assets/image/icons/svg/icons/dangerIconRed.svg\";\n\nimport noPng from \"../../../assets/image/snail-no.png\";\n\nconst ExceededLimitNotification = ({ children }) => {\n return (\n
    \n \n \n {children}\n
    \n );\n};\n\nexport default ExceededLimitNotification;\n","import \"./style.scss\";\n\nimport dangerIconBlack from \"../../../assets/image/icons/svg/icons/dangerIconRed.svg\";\nimport workingHours from \"../../../assets/image/snail-no.png\";\n\nconst WorkingHoursNotification = ({ children }) => {\n return (\n
    \n \n \n {children}\n
    \n );\n};\n\nexport default WorkingHoursNotification;\n","import { useState } from 'react'\r\nimport { useAppSelector, useMount } from 'shared/hooks'\r\n\r\nimport dangerIcon from '../../../assets/image/icons/svg/icons/danger.svg'\r\nimport { appSelectors } from '../../../redux/reducers/app'\r\nimport css from './LinkedInNotLogged.module.scss'\r\n\r\nexport function LinkedInNotLogged() {\r\n\tconst isNotLogged = useAppSelector(appSelectors.notLoggedLI)\r\n\r\n\treturn isNotLogged && \r\n}\r\n\r\nfunction NotLoggedInner() {\r\n\tconst linkedInfo = useAppSelector(\r\n\t\tstate => appSelectors.appProfile(state)?.linkedInProfile\r\n\t)\r\n\tconst profile = useAppSelector(appSelectors.linkedProfile)\r\n\tconst connector = useAppSelector(appSelectors.connector)\r\n\tconst [linkedInProfile, setLinkedInProfile] = useState(null)\r\n\r\n\tlet id = profile?.publicIdentifier || profile?.entityId\r\n\r\n\tif (linkedInProfile) {\r\n\t\tid = profile?.entityId || profile?.publicIdentifier\r\n\t}\r\n\r\n\tuseMount(() => {\r\n\t\tconnector.linkedIn.getCurrentProfile().then((res: any) => {\r\n\t\t\tsetLinkedInProfile(res)\r\n\t\t})\r\n\t})\r\n\r\n\treturn (\r\n\t\t
    \r\n\t\t\t\r\n\r\n\t\t\t\r\n\t\t\t\tYou are not logged in to LinkedIn with{' '}\r\n\t\t\t\t\r\n\t\t\t\t\t{`${linkedInfo?.givenName} ${linkedInfo?.familyName} account.`}\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t
    \r\n\t)\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"link\":\"link-THjdgV\",\"root\":\"root-EAnkWz\",\"icon\":\"icon-jC41O2\"};","export const executionHumanState = {\n NotStarted: \"NotStarted\",\n InProgress: \"InProgress\",\n Succeed: \"Succeed\",\n Ignored: \"Ignored\",\n Skipped: \"Skipped\",\n Cancelled: \"Cancelled\",\n Failed: \"Failed\",\n};\n","import { executionHumanState } from \"./executionHumanState\";\n\nexport const stepExecutionState = {\n NotStarted: executionHumanState.NotStarted,\n InQueue: \"InQueue\",\n InProgress: executionHumanState.InProgress,\n Succeed: executionHumanState.Succeed,\n Ignored: executionHumanState.Ignored,\n Failed: executionHumanState.Failed,\n Cancelled: executionHumanState.Cancelled,\n Skipped: executionHumanState.Skipped,\n};\n","import { CONSTS } from \"../config/objectConst\";\nimport { stepExecutionState } from \"./stepExecutionState\";\nimport { executionHumanState } from \"./executionHumanState\";\n\nconst InProgressDefaultTitle = \"In Progress\";\nconst FailedDefaultTitle = \"System error\";\nconst CancelledDefaultTitle = \"Cancelled by you\";\nconst SkippedDefaultTitle = \"Skipped by system\";\nconst NotStartedDefaultTitle = \"Not started\";\nconst SucceedDefaultTitle = \"Responded\";\nconst IgnoredDefaultTitle = \"Not responded\";\n\nfunction getInProgressDescription(stepType) {\n switch (stepType) {\n case CONSTS.AVAILABLE_ACTIONS.Connect.Type:\n return \"Awaiting for connect\";\n case CONSTS.AVAILABLE_ACTIONS.Message.Type:\n return \"Awaiting for response\";\n default:\n return InProgressDefaultTitle;\n }\n}\n\nfunction getIgnoredDescription(stepType) {\n switch (stepType) {\n case CONSTS.AVAILABLE_ACTIONS.Connect.Type:\n return \"Withdrawn\";\n default:\n return IgnoredDefaultTitle;\n }\n}\n\nfunction getSucceedDescription(stepType) {\n switch (stepType) {\n case CONSTS.AVAILABLE_ACTIONS.Connect.Type:\n return \"Connected\";\n default:\n return SucceedDefaultTitle;\n }\n}\n\nexport const statesDescriptor = {\n getStepTitle(stepState, stepType) {\n switch (stepState) {\n case stepExecutionState.NotStarted:\n return NotStartedDefaultTitle;\n case stepExecutionState.InQueue:\n return \"In queue\";\n case stepExecutionState.InProgress:\n return getInProgressDescription(stepType);\n case stepExecutionState.Succeed:\n return getSucceedDescription(stepType);\n case stepExecutionState.Ignored:\n return getIgnoredDescription(stepType);\n case stepExecutionState.Failed:\n return FailedDefaultTitle;\n case stepExecutionState.Cancelled:\n return CancelledDefaultTitle;\n case stepExecutionState.Skipped:\n return SkippedDefaultTitle;\n default:\n throw new Error(`Not supported step state - ${stepState}`);\n }\n },\n\n getExecutionTitle(state) {\n switch (state) {\n case executionHumanState.NotStarted:\n return NotStartedDefaultTitle;\n case stepExecutionState.InProgress:\n return InProgressDefaultTitle;\n case stepExecutionState.Succeed:\n return SucceedDefaultTitle;\n case stepExecutionState.Ignored:\n return IgnoredDefaultTitle;\n case stepExecutionState.Cancelled:\n return CancelledDefaultTitle;\n case stepExecutionState.Skipped:\n return SkippedDefaultTitle;\n case stepExecutionState.Failed:\n return FailedDefaultTitle;\n default:\n throw new Error(`Not supported execution state - ${state}`);\n }\n },\n\n detectColor(state, step) {\n // NotStarted step is a special case, it is colored by own color.\n // All other steps are colored by execution state.\n if (step?.human_state === \"NotStarted\") {\n return \"#EBEDF2\";\n }\n\n switch (state) {\n case stepExecutionState.NotStarted:\n case stepExecutionState.InQueue:\n return CONSTS.COLORS_CAMPAIGNS.inQueue;\n case stepExecutionState.InProgress:\n return CONSTS.COLORS_CAMPAIGNS.inProgress;\n case stepExecutionState.Succeed:\n return CONSTS.COLORS_CAMPAIGNS.responded;\n case stepExecutionState.Ignored:\n return CONSTS.COLORS_CAMPAIGNS.ignored;\n case stepExecutionState.Cancelled:\n return CONSTS.COLORS_CAMPAIGNS.cancelled;\n case stepExecutionState.Skipped:\n return CONSTS.COLORS_CAMPAIGNS.skipped;\n case stepExecutionState.Failed:\n return CONSTS.COLORS_CAMPAIGNS.failed;\n default:\n throw new Error(`Not supported execution state ${state}`);\n }\n },\n};\n","import React, { Component } from \"react\";\nimport lFilter from \"lodash/filter\";\nimport sortBy from \"lodash/sortBy\";\nimport Table from \"@mui/material/Table\";\nimport TableBody from \"@mui/material/TableBody\";\nimport TableCell from \"@mui/material/TableCell\";\nimport TableContainer from \"@mui/material/TableContainer\";\nimport TableHead from \"@mui/material/TableHead\";\nimport TableRow from \"@mui/material/TableRow\";\nimport CircularProgress from \"@mui/material/CircularProgress\";\nimport { Dropdown, Loader } from \"semantic-ui-react\";\n// Components\nimport TooltipCustom from \"../../atoms/tooltipCustom\";\n\n// actions and functions\nimport { campaign } from \"../../../actions/campaign\";\nimport { contacts } from \"../../../actions/contacts\";\nimport { app } from \"../../../actions/app\";\n\n// icons\nimport infoBlackIcon from \"../../../assets/image/icons/tables/info-black.svg\";\nimport iconArrow from \"../../../assets/image/icons/tables/arrow-rigth.svg\";\nimport iconMessage from \"../../../assets/image/icons/tables/message.svg\";\nimport avatarSvg from \"../../../assets/image/icons/svg/user.svg\";\n\n// Style\nimport \"../TableUsers/style.scss\";\nimport \"./style.scss\";\nimport inIcon from \"../../../assets/image/icons/tables/linkedin-icon-gray.svg\";\nimport { apiActivity } from \"../../../api/activity/apiActivity\";\nimport { linkedInProfileOpener } from \"../../../api/linkedInProfileOpener\";\nimport { statesDescriptor } from \"../../../api/statesDescriptor\";\nimport { contactsPageSize } from \"../../../api/contactsPageSize\";\nimport { Link } from \"react-router-dom\";\nimport { connect } from \"react-redux\";\n\nexport class TableActivity extends Component {\n constructor(props) {\n super(props);\n\n this.state = {\n isLocalModalVisible: false,\n page: 0,\n rowsPerPage: contactsPageSize.get(),\n contactsOnPage: [],\n selected: [],\n selectedOnPage: [],\n filterRows: [],\n dropDownController: false,\n scrollBarWidth: false,\n actionMessage: \"\",\n actionMessageLoader: true,\n };\n this.wrapper = React.createRef();\n }\n\n componentDidMount() {\n window.addEventListener(\"resize\", this.handleResize);\n this.setState({\n contactsOnPage: this.getContactsOnPage(this.state.page),\n });\n }\n\n componentWillUnmount() {\n window.removeEventListener(\"resize\", this.handleResize);\n }\n\n componentDidUpdate() {\n const scrollbarWidth =\n this.wrapper.current.offsetWidth - this.wrapper.current.clientWidth;\n\n if (scrollbarWidth > 0 && this.state.scrollBarWidth === false) {\n this.setState({ scrollBarWidth: true });\n }\n\n if (scrollbarWidth === 0 && this.state.scrollBarWidth === true) {\n this.setState({ scrollBarWidth: false });\n }\n }\n\n handleResize = () => {\n const scrollbarWidth =\n this.wrapper.current.offsetWidth - this.wrapper.current.clientWidth;\n\n if (scrollbarWidth > 0 && this.state.scrollBarWidth === false) {\n this.setState({ scrollBarWidth: true });\n }\n\n if (scrollbarWidth === 0 && this.state.scrollBarWidth === true) {\n this.setState({ scrollBarWidth: false });\n }\n };\n\n getContactsOnPage = (page) => {\n const newContacts = this.props.contacts.activity.filter(\n (item, index) =>\n this.state.rowsPerPage * page <= index &&\n index < this.state.rowsPerPage * (page + 1)\n );\n return newContacts.map((item) => item.id);\n };\n\n handleChangeRowsPerPage = (event) => {\n this.setState({\n page: 0,\n rowsPerPage: parseInt(event.target.value, 10),\n });\n };\n\n Sort = () => {\n this.setState({\n rows: sortBy(this.props.contacts.activity, [\n function (o) {\n return o.name;\n },\n ]),\n });\n };\n\n Filter = () => {\n this.setState({\n rows: lFilter(this.props.contacts.activity, { status: 1 }),\n });\n };\n\n handleClick = (event, name) => {\n const selectedIndex = this.state.selected.indexOf(name);\n let newSelected = [];\n\n if (selectedIndex === -1) {\n newSelected = newSelected.concat(this.state.selected, name);\n } else if (selectedIndex === 0) {\n newSelected = newSelected.concat(this.state.selected.slice(1));\n } else if (selectedIndex === this.state.selected.length - 1) {\n newSelected = newSelected.concat(this.state.selected.slice(0, -1));\n } else if (selectedIndex > 0) {\n newSelected = newSelected.concat(\n this.state.selected.slice(0, selectedIndex),\n this.state.selected.slice(selectedIndex + 1)\n );\n }\n this.setState({\n selected: newSelected,\n });\n };\n\n isSelected = (name) => this.state.selected.indexOf(name) !== -1;\n\n onSelectAllPageClick = (event) => {\n if (event.target.checked) {\n let newSelecteds = this.getContactsOnPage(this.state.page);\n newSelecteds = newSelecteds.filter(\n (item) => !this.state.selected.includes(item)\n );\n this.setState({\n selected: this.state.selected.concat(newSelecteds),\n });\n return;\n }\n this.setState({\n selected: this.state.selected.filter(\n (item) => !this.state.contactsOnPage.includes(item)\n ),\n });\n };\n\n onSelectAllClick = () => {\n const newSelecteds = this.props.contacts.activity.map((item) => item.id);\n this.setState({\n selected: newSelecteds,\n });\n };\n\n onClearAllClick = () => {\n this.setState({\n selected: [],\n });\n };\n\n clearCheckboxes = () => {\n this.setState({ selected: [] });\n };\n\n dropDownController = async (value, campaignExecutionId, stepNumber) => {\n this.setState({\n dropDownController: value,\n });\n if (campaignExecutionId) {\n try {\n this.setState({ actionMessageLoader: true });\n const response = await apiActivity.getStepMessage(\n campaignExecutionId,\n stepNumber\n );\n this.setState({ actionMessage: response.data });\n } finally {\n this.setState({ actionMessageLoader: false });\n }\n } else {\n this.setState({ actionMessage: \"\" });\n }\n };\n\n removeContactsFromCampaign = async (audience, campaignId) => {\n app.changeTableContentLoaderStatus(true);\n await campaign.removeContactsFromCampaign({\n id: campaignId,\n audience,\n });\n this.setState({\n selected: [],\n });\n //await campaign.getContactsByCampaign(campaignId);\n await campaign.getCampaignId(campaignId);\n\n await contacts.getContacts({\n skip: 0,\n filter: `campaigns/any(c:c eq '${campaignId}')`,\n orderby: \"created asc\",\n });\n\n app.changeTableContentLoaderStatus(false);\n };\n\n menuClasses = (index) => {\n if (this.props.contacts.activity.length > 6) {\n if (index > this.props.contacts.activity.length - 3) {\n return \"position-top\";\n }\n }\n return \"position-bottom\";\n };\n\n upwardController = (index) => {\n if (this.props.contacts.activity.length > 6) {\n if (index > this.props.contacts.activity.length - 3) {\n return true;\n }\n }\n return false;\n };\n\n buttonsActions = (row, index) => {\n const openLinkedinProfile = () => linkedInProfileOpener.open(row);\n\n return (\n row.actions && (\n
    \n {\n row.actions.show_details.enabled &&\n this.dropDownController(\n true,\n row.campaignExecutionId,\n row.stepNumber\n );\n this.setState({ isLocalModalVisible: true });\n }}\n onClose={() => {\n this.dropDownController(false);\n\n this.setState({ isLocalModalVisible: true });\n }}\n icon={\n \n \"infoBlackIcon\"\n \n }\n direction=\"left\"\n >\n \n \n
    \n \n Action #{row.indexAction}:\n \n
    {row.header}
    \n
    \n
    \n
    \n {!this.state.actionMessageLoader ? (\n
    \n                            {this.state.actionMessage}\n                          
    \n ) : (\n \n )}\n
    \n
    \n
    \n
    \n
    \n \n \n\n \n \n \"linkedin\n \n \n\n \n {\n row.actions.open_conversation.enabled &&\n window.open(row.conversation_url, \"_blank\");\n }}\n >\n \"messageIcon\"\n \n \n \n {row.actions.open_campaign.enabled ? (\n \n \"arrowIcon\"\n \n ) : (\n \n )}\n \n
    \n )\n );\n };\n\n findColor = (state) => {\n switch (state) {\n case \"findColor\":\n return \"red\";\n\n default:\n break;\n }\n };\n\n renderSteps = (row, item) => {\n const items = [];\n for (const index in row) {\n row[index].is_visible &&\n items.push(\n \n \n \n );\n }\n\n return items;\n };\n\n buildStartIn = (value) => {\n if (value === 0) {\n return \"processing\";\n }\n if (value < 60) {\n return `${value} min`;\n }\n\n if (value >= 60 && value < 1440) {\n const getHours = Math.floor(value / 60);\n const lastMinute = value - getHours * 60;\n const hourName = getHours > 1 ? \"hours\" : \"hour\";\n\n return `${getHours}${\" \"} ${hourName} ${\n lastMinute > 0 ? `${lastMinute} min` : \"\"\n }`;\n }\n\n if (value > 1440) {\n const getDays = Math.floor(value / 1440);\n const lastHour = Math.floor((value - getDays * 1440) / 60);\n const lastMinute = value - getDays * 1440 - lastHour * 60;\n const hourName = lastHour > 1 ? \"hours\" : \"hour\";\n\n return `${getDays > 1 ? `${getDays} days` : `${getDays} day`} ${\n lastHour > 0 ? `${lastHour} ${\" \"} ${hourName}` : \"\"\n } ${lastMinute > 0 ? `${lastMinute} min` : \"\"}`;\n }\n\n return value;\n };\n\n render() {\n return (\n this.state.rowsPerPage\n ? \"table-with-footer\"\n : \"\"\n }`}*/\n >\n \n {this.props.app.tableContentLoader &&\n !this.props.app.pageContentLoader && (\n
    \n \n
    \n )}\n \n \n \n \n {this.state.selected.length > 0 ? (\n
    \n {this.state.selected.length ===\n this.props.contacts.activity.length ? (\n <>\n \n {this.state.selected.length} selected |{\" \"}\n \n \n Clear\n \n \n ) : (\n <>\n \n {this.state.selected.length} of{\" \"}\n {this.props.contacts.activity.length} selected |{\" \"}\n \n \n Select all\n \n \n )}\n
    \n ) : (\n \"Contact\"\n )}\n
    \n {/* Company */}\n Campaign\n Activity\n\n Status\n\n Starts In\n
    \n
    \n this.state.rowsPerPage\n ? \"table-with-footer-activities\"\n : \"table-with-out-footer-activities\"\n }`}\n >\n {this.props.contacts.activity\n // .slice(\n // this.state.page * this.state.rowsPerPage,\n // this.state.page * this.state.rowsPerPage +\n // this.state.rowsPerPage\n // )\n .map((row, index) => (\n \n \n
    \n \n
    \n
    \n {row.fullName}\n
    \n
    \n
    \n
    \n \n
    \n {row.campaign_name}\n
    \n
    \n \n
    {row.activity}
    \n
    \n \n
    \n {this.renderSteps(row.campaignExecutions, row)}\n
    \n
    \n \n
    \n
    \n {this.buildStartIn(row.start_in)}\n
    \n {this.buttonsActions(row, index)}\n
    \n \n
    \n ))}\n \n \n \n {/*
    \n \n
    */}\n \n );\n }\n}\n\nconst mapStateToProps = (state) => ({\n app: state.app,\n contacts: state.activity,\n});\n\nexport default connect(mapStateToProps)(TableActivity);\n","// extracted by css-extract-rspack-plugin\nexport default {\"root\":\"root-BTRwgX\",\"title\":\"title-ujZHQp\"};","import clsx from 'clsx'\r\nimport { FullLoader } from 'components/atoms/FullLoader/FullLoader.tsx'\r\nimport { useEffect, useState } from 'react'\r\nimport { useAutomationEnded } from 'shared/connector/hooks.ts'\r\nimport { notifyError } from 'shared/errors/notificate.ts'\r\nimport { useAppSelector } from 'shared/hooks/store.ts'\r\nimport { typo } from 'shared/styles'\r\n\r\nimport { activity } from '../../actions/activity.js'\r\nimport { app } from '../../actions/app.js'\r\nimport { campaign } from '../../actions/campaign.js'\r\nimport ExceededLimitNotification from '../../components/atoms/ExceededLimitNotification/index.js'\r\nimport WorkingHoursNotification from '../../components/atoms/WorkingHoursNotification/index.js'\r\nimport { LinkedInNotLogged } from '../../components/molecules/linkedInNotLogged/LinkedInNotLogged.tsx'\r\nimport TableActivity from '../../components/molecules/tableActivity/index.js'\r\nimport { LoggedLayout } from '../../components/templates/homeTemplate'\r\nimport { appSelectors } from '../../redux/reducers/app.ts'\r\nimport css from './ActivityPage.module.scss'\r\n\r\nexport function ActivityPage() {\r\n\tconst connector = useAppSelector(appSelectors.connector),\r\n\t\tisLoading = useAppSelector(state => state.app.pageContentLoader),\r\n\t\tpersona = useAppSelector(appSelectors.persona)\r\n\r\n\tconst [isInWorkHours, setIsInWorkHours] = useState(null)\r\n\r\n\tasync function getWorkingHours() {\r\n\t\ttry {\r\n\t\t\tconst workingHours = await connector.automation.isInWorkingHours()\r\n\t\t\tsetIsInWorkHours(workingHours)\r\n\t\t} catch (error) {\r\n\t\t\tnotifyError(error)\r\n\t\t\tsetIsInWorkHours(true)\r\n\t\t}\r\n\t}\r\n\r\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: \r\n\tuseEffect(() => {\r\n\t\tgetWorkingHours()\r\n\t\tapp.changeActiveItem(2)\r\n\t\tcampaign.getRecentCampaigns()\r\n\r\n\t\t// TODO: Replace fetch campaign to RTK Query\r\n\t\tactivity.getActivities()\r\n\t}, [])\r\n\r\n\tuseAutomationEnded(() => {\r\n\t\tcampaign.getRecentCampaigns()\r\n\t\tactivity.getActivities(true)\r\n\t})\r\n\r\n\treturn (\r\n\t\t\r\n\t\t\t\r\n\r\n\t\t\t{isLoading && }\r\n\t\t\t{!isLoading && (\r\n\t\t\t\t<>\r\n\t\t\t\t\t

    Activities queue

    \r\n\r\n\t\t\t\t\t{persona?.exceedLinkedInInvitationsLimit ? (\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\tThe weekly limit for sending invitations has been exceeded\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t) : (\r\n\t\t\t\t\t\t!isInWorkHours &&\r\n\t\t\t\t\t\tisInWorkHours !== null && (\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\tThe activities will starts upon your working hours\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t)\r\n\t\t\t\t\t)}\r\n\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t)}\r\n\t\t
    \r\n\t)\r\n}\r\n","import { useState } from \"react\";\nimport \"./style.scss\";\nimport Close from \"../../../assets/image/icons/svg/icons/Close-black.svg\";\n\nconst HintTooltip = ({\n handlerClose,\n placement,\n classes,\n tooltip,\n enabled,\n}) => {\n const [isOpen, setIsOpen] = useState(true);\n return enabled && isOpen ? (\n \n {tooltip.sideTitle ? (\n
    {tooltip.sideTitle}
    \n ) : (\n
    \n )}\n
    \n {tooltip.title}\n

    {tooltip.content}

    \n
    \n {tooltip.isClosable && (\n {\n setIsOpen(false);\n handlerClose();\n }}\n >\n \"close\n \n )}\n \n \n ) : (\n <>\n );\n};\n\nexport default HintTooltip;\n","import \"./style.scss\";\n\nimport dogNo from \"./../../../assets/image/snail-no.png\";\nimport dogThinks from \"./../../../assets/image/snail-typing.png\";\n\nconst ConfirmationDialog = ({\n confirmationDialog,\n closeHandler,\n startCampaign,\n}) => {\n const handlerConfirm = (id) => {\n closeHandler();\n startCampaign(id);\n };\n\n const getConfirmationContent = () => {\n let totalCount = 0;\n\n if (\n confirmationDialog.data.validation_rules_summary.length &&\n confirmationDialog.data.valid_audience_count\n ) {\n return (\n
    \n

    \n Sorry, the system can’t process\n
    some of the contacts\n

    \n
    \n
    \n {confirmationDialog.data.validation_rules_summary.map(\n (item, index) => {\n totalCount += item.count;\n return {`${item.count} contacts:`};\n }\n )}\n
    \n
    \n {confirmationDialog.data.validation_rules_summary.map(\n (item, index) => {\n return {item.description};\n }\n )}\n
    \n
    \n
    \n

    \n The system will process{\" \"}\n {confirmationDialog.data.valid_audience_count} contacts,\n

    \n

    {totalCount} will be automatically excluded.

    \n

    Would you like to proceed?

    \n
    \n\n
    \n \n Cancel\n \n handlerConfirm(confirmationDialog.id)}\n >\n Confirm\n \n
    \n
    \n );\n }\n\n if (\n confirmationDialog.data.validation_rules_summary.length &&\n !confirmationDialog.data.valid_audience_count\n ) {\n return (\n
    \n

    \n Sorry, the system can’t run
    \n this campaign\n

    \n
    \n
    \n {confirmationDialog.data.validation_rules_summary.map(\n (item, index) => {\n return
    {`${item.count} contacts:`}
    ;\n }\n )}\n
    \n
    \n {confirmationDialog.data.validation_rules_summary.map(\n (item, index) => {\n return
    {item.description}
    ;\n }\n )}\n
    \n
    \n
    \n

    \n Please change your contacts\n
    or campaign steps\n

    \n
    \n
    \n \n Ok\n \n
    \n
    \n );\n }\n };\n\n const isPositiveAudienceCount =\n confirmationDialog.data.validation_rules_summary.length &&\n confirmationDialog.data.valid_audience_count;\n\n return (\n
    \n {getConfirmationContent()}\n \n
    \n );\n};\n\nexport default ConfirmationDialog;\n","import CircularProgress from \"@mui/material/CircularProgress\";\nimport images from \"../../../assets/image/icons/buttons/export.svg\";\nimport imagesDisable from \"../../../assets/image/icons/buttons/export-disabled.svg\";\n\nimport \"./style.scss\";\n\nconst ExportToCSVButton = ({\n onClick,\n disabled,\n isLoading,\n text,\n isInteraction,\n}) => (\n !isLoading && onClick()}\n disabled={disabled}\n >\n \n {isLoading ? (\n
    \n \n
    \n ) : (\n <>\n \n \n {text}\n \n \n )}\n \n \n);\n\nexport default ExportToCSVButton;\n","import { apiRTK } from 'api/api-rtk'\r\n\r\nimport type { Campaign } from './types'\r\n\r\nexport const api = apiRTK.injectEndpoints({\r\n\tendpoints: create => ({\r\n\t\tgetById: create.query({\r\n\t\t\tquery: id => ({\r\n\t\t\t\turl: `campaigns/${id}`\r\n\t\t\t})\r\n\t\t})\r\n\t}),\r\n\toverrideExisting: true\r\n})\r\n","const statusToCN = {\r\n\tCompleted: 'completed',\r\n\tCompose: 'drafted',\r\n\tRunning: 'active',\r\n\tStopped: 'paused'\r\n} as const\r\n\r\nexport { statusToCN }\r\n","import type { MouseEvent } from 'react'\r\n\r\nimport clsx from 'clsx'\r\nimport { Link } from 'react-router-dom'\r\n\r\nimport { statusToCN } from '../../const'\r\n\r\nconst notPropagate = (e: MouseEvent) => e.stopPropagation()\r\n\r\ninterface Step {\r\n\tid: number\r\n\tname: string\r\n}\r\n\r\n// TODO: replace `.add-contacts-button-team` into separate component. Combine with `\r\n\t\t\t)}\r\n\r\n\t\t\t onPageChange(e, page - 1)}\r\n\t\t\t>\r\n\t\t\t\t\r\n\t\t\t\r\n\r\n\t\t\t
    \r\n\t\t\t\t{setPaginationInform()}\r\n\t\t\t
    \r\n\r\n\t\t\t onPageChange(e, page + 1)}\r\n\t\t\t>\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t{showLastButton && (\r\n\t\t\t\t onPageChange(e, pageTotal - 1)}\r\n\t\t\t\t>\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t)}\r\n\t\t\r\n\t)\r\n}\r\n","import TablePagination from '@mui/material/TablePagination'\r\n\r\nimport { Actions } from './Actions'\r\nimport css from './CustomPagination.module.scss'\r\n\r\ntype Props = Omit[0], 'ActionsComponent'>\r\n\r\nexport const PaginationWrapper = (props: Props) => (\r\n\t\r\n)\r\n","import React, { Component } from \"react\";\nimport Table from \"@mui/material/Table\";\nimport TableBody from \"@mui/material/TableBody\";\nimport TableCell from \"@mui/material/TableCell\";\nimport TableContainer from \"@mui/material/TableContainer\";\nimport TableHead from \"@mui/material/TableHead\";\nimport TableRow from \"@mui/material/TableRow\";\nimport TooltipCustom from \"../../atoms/tooltipCustom\";\nimport { functions, saveData } from \"../../../tools/functions\";\n// actions\nimport { campaign } from \"../../../actions/campaign\";\nimport { app } from \"../../../actions/app\";\n// Components\nimport CircularProgress from \"@mui/material/CircularProgress\";\n// Icons\nimport iconArch from \"../../../assets/image/icons/svg/icons/arch.svg\";\nimport iconClone from \"../../../assets/image/icons/svg/icons/clone.svg\";\nimport iconUnarchive from \"../../../assets/image/icons/svg/icons/unarch.svg\";\nimport iconStart from \"../../../assets/image/icons/svg/icons/start.svg\";\nimport iconPause from \"../../../assets/image/icons/svg/icons/pause.svg\";\nimport iconStop from \"../../../assets/image/icons/svg/icons/stop.svg\";\n\n// Style\nimport \"./style.scss\";\nimport { CONSTS } from \"../../../config/objectConst\";\nimport HintTooltip from \"../../atoms/HintTooltip\";\nimport ModalWindow from \"../ModalWindow\";\nimport { apiCampaign } from \"../../../api/campaign/apiCampaign\";\nimport ConfirmationDialog from \"../../atoms/ConfirmationDialog\";\nimport { filters } from \"../../../actions/filters\";\nimport Checkbox from \"@mui/material/Checkbox\";\nimport selectedCheckboxIcon from \"../../../assets/image/icons/tables/checkbox2.svg\";\nimport partiallySelectedCheckboxIcon from \"../../../assets/image/icons/tables/checkbox3.svg\";\nimport notSelectedCheckboxIcon from \"../../../assets/image/icons/tables/checkbox.svg\";\nimport ExportToCSVButton from \"../../atoms/ExportToCSVButton\";\nimport { CampaignsUI } from \"features/campaigns\";\nimport { notifyError } from \"shared/errors\";\nimport { PaginationWrapper } from \"components/atoms/mTablePagination/PaginationWrapper\";\nimport { appConnector } from \"shared/connector\";\n\nexport class TableCampaigns extends Component {\n constructor(props) {\n super(props);\n\n this.state = {\n isIconActive: {\n name: true,\n started: false,\n acceptance_rate: true,\n invitation_sent: true,\n messages_sent: true,\n reply_rate: true,\n started_count: true,\n },\n isLoadingCSV: false,\n campaignsOnPage: [],\n selected: [],\n rows: [],\n\n rowsPerPage: CONSTS.PAGE_SIZE,\n filterRows: [],\n paginationLabel: \"\",\n modalData: null,\n confirmationDialog: {\n id: null,\n status: false,\n data: {},\n },\n selectAllCampaignsValue: false,\n selectedValues: 0,\n rowData: {\n id: null,\n name: \"\",\n },\n scrollBarWidth: false,\n };\n this.wrapper = React.createRef();\n }\n isSelected = (name) => this.state.selected.indexOf(name) !== -1;\n\n componentDidMount() {\n appConnector.eventHandlers.addAutomationEndedEventHandler(async () => {\n campaign.getRecentCampaigns();\n\n await filters.getCampaigns({\n archived: false,\n skip:\n this.props.tableCampaignsPage > 0\n ? this.props.tableCampaignsPage * CONSTS.PAGE_SIZE\n : 0,\n filter: this.props.filterQuery,\n keywords: this.props.searchValue,\n });\n });\n if (this.props.campaignsLoading) {\n this.getCampaigns();\n }\n window.addEventListener(\"resize\", this.handleResize);\n }\n\n componentWillUnmount() {\n appConnector.eventHandlers.removeAutomationEndedEventHandlers();\n window.removeEventListener(\"resize\", this.handleResize);\n }\n\n onSelectAllClick = () => {\n const newSelecteds = this.props.campaigns.map((item) => item.id);\n this.setState({\n selected: newSelecteds,\n selectedValues: this.props.campaignsCount,\n selectAllCampaignsValue: true,\n });\n };\n\n exportCampaigns = async () => {\n const selectAllFilter = this.props.filterQuery;\n const selectId = this.state.selected;\n try {\n this.setState({ isLoadingCSV: true });\n const response = await apiCampaign.exportCampaignsApi({\n filter: this.state.selectAllCampaignsValue\n ? selectAllFilter\n : `id in (${selectId.map((item) => `'${item}'`)})`,\n orderby: this.props.orderby,\n archived: false,\n searchValue: this.state.selectAllCampaignsValue\n ? this.props.searchValue\n : \"\",\n });\n if (response.status === 200) {\n const data = response.data,\n fileName = functions.getFileName();\n saveData(data, fileName);\n }\n } catch (error) {\n notifyError(error);\n }\n this.setState({\n selected: [],\n });\n this.setState({ isLoadingCSV: false });\n };\n\n componentDidUpdate() {\n this.handleResize();\n }\n handleClick = (event, name) => {\n const selectedIndex = this.state.selected.indexOf(name);\n let newSelected = [];\n\n if (selectedIndex === -1) {\n newSelected = newSelected.concat(this.state.selected, name);\n } else if (selectedIndex === 0) {\n this.setState({\n selectAllCampaignsValue: false,\n });\n newSelected = newSelected.concat(this.state.selected.slice(1));\n } else if (selectedIndex === this.state.selected.length - 1) {\n this.setState({\n selectAllCampaignsValue: false,\n });\n newSelected = newSelected.concat(this.state.selected.slice(0, -1));\n } else if (selectedIndex > 0) {\n this.setState({\n selectAllCampaignsValue: false,\n });\n newSelected = newSelected.concat(\n this.state.selected.slice(0, selectedIndex),\n this.state.selected.slice(selectedIndex + 1)\n );\n }\n this.setState({\n selected: newSelected,\n selectedValues: newSelected.length,\n });\n };\n\n onSelectAllPageClick = (event) => {\n this.setState({\n selectAllCampaignsValue: false,\n selectedValues:\n this.props.campaignsCount <= this.props.campaigns.length\n ? this.props.campaignsCount\n : this.props.campaigns.length,\n });\n\n if (event.target.checked) {\n let newSelected = this.props.campaigns;\n newSelected = newSelected.filter(\n (item) => !this.state.selected.includes(item)\n );\n\n this.setState({\n selected: this.state.selected.concat(newSelected).map((item, index) => {\n return item.id;\n }),\n });\n return;\n }\n\n this.setState({\n selected: [],\n selectedValues: 0,\n });\n };\n\n handleResize = () => {\n const scrollbarWidth =\n this.wrapper.current.offsetWidth - this.wrapper.current.clientWidth;\n\n if (scrollbarWidth > 0 && this.state.scrollBarWidth === false) {\n this.setState({ scrollBarWidth: true });\n }\n\n if (scrollbarWidth === 0 && this.state.scrollBarWidth === true) {\n this.setState({ scrollBarWidth: false });\n }\n };\n\n getCampaigns = async () => {\n app.changeTableContentLoaderStatus(true);\n await filters.getCampaigns({\n skip: 0,\n archived: this.props.archive,\n filter: this.props.filterQuery,\n keywords: this.props.searchValue,\n });\n\n app.changeTableContentLoaderStatus(false);\n };\n\n handleChangePage = async (event, newPage) => {\n app.changeTableContentLoaderStatus(true);\n\n await filters.getCampaigns({\n skip: newPage > 0 ? newPage * CONSTS.PAGE_SIZE : 0,\n archived: this.props.archive,\n filter: this.props.filterQuery,\n keywords: this.props.searchValue,\n });\n this.props.setTableCampaignsStatisticsPage(newPage);\n app.changeTableContentLoaderStatus(false);\n };\n\n setActiveFilterIcon(key, value) {\n this.setState({\n isIconActive: {\n ...{\n contact: true,\n headline: true,\n account: true,\n connection: true,\n imported: true,\n },\n [key]: value,\n },\n });\n }\n\n onClickCampaign = (id) => {\n this.props.archive\n ? this.props.history.push(`/archive/${id}`)\n : this.props.history.push(`/campaigns/${id}`);\n };\n\n addToArchive = (id) => {\n app.changeTableContentLoaderStatus(true);\n\n campaign.addCampaignToArchive(\n id,\n\n this.props.searchValue,\n this.props.tableCampaignsPage\n );\n };\n\n // startStopController = (id, status) => {};\n\n removeFromArchive = async (id) => {\n app.changeTableContentLoaderStatus(true);\n await campaign.removeCampaignFromArchive(\n id,\n this.props.searchValue,\n this.props.tableCampaignsPage\n );\n this.setState({\n selected: this.state.selected.filter((item) => item !== id),\n selectedValues: this.state.selectedValues - 1,\n });\n };\n\n cloneHandler = async (campaignId) => {\n const response = await campaign.cloneCampaign(campaignId);\n if (response) {\n this.props.history.push(`/campaigns/${response.id}/tune`);\n }\n };\n\n actionHandler = ({ type, id, events, status }) => {\n try {\n switch (type) {\n case \"1.2\":\n events.complete.enabled &&\n campaign.completeCampaign(id, {\n page: this.props.tableCampaignsPage,\n\n searchValue: this.props.searchValue,\n });\n break;\n\n case \"1.5\":\n events.run.enabled &&\n campaign.startCampaign(id, status, {\n page: this.props.tableCampaignsPage,\n\n searchValue: this.props.searchValue,\n });\n break;\n\n case \"1.7\":\n events.archive.enabled && this.addToArchive(id);\n break;\n\n case \"1.10\":\n events.clone.enabled && this.cloneHandler(id);\n break;\n default:\n break;\n }\n } finally {\n this.setState({ modalData: null });\n }\n };\n\n startHandler = async (id, events, status) => {\n try {\n if (status === \"Stopped\") {\n return await campaign.startCampaign(id, status, {\n page: this.props.tableCampaignsPage,\n\n searchValue: this.props.searchValue,\n });\n }\n\n app.changeTableContentLoaderStatus(true);\n const preview = await apiCampaign.getPreviewOfStartupCampaing(id);\n\n if (!preview.data.validation_rules_summary.length) {\n this.setState({\n modalData: {\n type: \"1.5\",\n id,\n events,\n status,\n data: preview.data,\n },\n });\n } else {\n this.setState({\n confirmationDialog: {\n id,\n status: true,\n data: preview.data,\n },\n modalData: {\n type: \"1.5\",\n id,\n events,\n status,\n data: preview.data,\n },\n });\n }\n } catch (error) {\n notifyError(error);\n } finally {\n app.changeTableContentLoaderStatus(false);\n }\n };\n\n onClearAllClick = () => {\n this.setState({\n selected: [],\n selectedValues: 0,\n selectAllCampaignsValue: false,\n });\n };\n\n buttonsActions = (id, status, events, date) => {\n return (\n \n {!this.props.archive && (\n <>\n \n {\n e.stopPropagation();\n events.run.enabled && this.startHandler(id, events, status);\n }}\n >\n \"iconStart\"\n \n \n\n \n {\n e.stopPropagation();\n\n events.stop.enabled &&\n campaign.stopCampaign(id, {\n page: this.props.tableCampaignsPage,\n\n searchValue: this.props.searchValue,\n });\n }}\n >\n \"iconStop\"\n \n \n\n \n {\n e.stopPropagation();\n events.complete.enabled &&\n this.setState({\n modalData: { type: \"1.2\", id, events },\n });\n }}\n >\n \"iconPause\"\n \n \n\n \n {\n e.stopPropagation();\n events.clone.enabled &&\n this.setState({\n modalData: { type: \"1.10\", id, events },\n });\n }}\n >\n \"clone\"\n \n \n\n \n {\n e.stopPropagation();\n events.archive.enabled &&\n this.setState({\n modalData: { type: \"1.7\", id, events },\n });\n }}\n >\n \"archive\"\n \n \n \n )}\n\n {this.props.archive && (\n <>\n \n {\n e.stopPropagation();\n events.unarchive.enabled && this.removeFromArchive(id);\n }}\n >\n \"unarchive\"\n \n \n \n )}\n \n );\n };\n\n buildStatus = (status, complete_reason) => {\n switch (status) {\n case \"Running\":\n return
    active
    ;\n case \"Stopped\":\n return
    paused
    ;\n case \"Completed\":\n return
    completed
    ;\n case \"Compose\":\n return
    draft
    ;\n\n default:\n break;\n }\n };\n\n render() {\n const getDataClientWidth = (row) =>\n (row?.name?.length > 25 &&\n document.documentElement.clientWidth > 1000 &&\n document.documentElement.clientWidth < 1530) ||\n (row?.name?.length > 30 &&\n document.documentElement.clientWidth > 1530 &&\n document.documentElement.clientWidth < 1740) ||\n (row?.name?.length > 35 &&\n document.documentElement.clientWidth > 1744 &&\n document.documentElement.clientWidth < 1918) ||\n (row?.name?.length > 42 &&\n document.documentElement.clientWidth > 1918 &&\n document.documentElement.clientWidth < 2133) ||\n (row?.name?.length > 49 &&\n document.documentElement.clientWidth > 2132 &&\n document.documentElement.clientWidth < 2401);\n return (\n this.state.rowsPerPage\n ? \"table-with-footer\"\n : \"\"\n }`}\n >\n
    \n \n {this.props.app.tableContentLoader &&\n !this.props.app.pageContentLoader && (\n
    \n \n
    \n )}\n \n \n \n \n
    \n \n this.props.campaigns.includes(item)\n ).length\n }\n checked={this.state.selected.length > 0}\n onChange={this.onSelectAllPageClick}\n inputProps={{ \"aria-label\": \"select all desserts\" }}\n indeterminateIcon={\n \"checkbox\"\n }\n icon={\n \"checkbox\"\n }\n checkedIcon={\n \n this.state.selectedValues\n ? partiallySelectedCheckboxIcon\n : selectedCheckboxIcon\n }\n alt=\"checkbox\"\n />\n }\n />\n
    \n
    \n \n {this.state.selected.length > 0 ? (\n
    \n <>\n {this.state.selectedValues > 0 && (\n
    \n \n {this.state.selectedValues} of{\" \"}\n {this.props.campaignsCount} selected |{\" \"}\n \n {!this.state.selectAllCampaignsValue && (\n \n Select all\n \n )}\n\n {this.state.selectAllCampaignsValue && (\n \n Clear\n \n )}\n
    \n )}\n
    \n {\n this.exportCampaigns();\n }}\n text=\"Export to CSV\"\n >\n
    \n \n
    \n ) : (\n \"Campaign\"\n )}\n \n \n Status\n \n \n Invites sent\n \n \n Acceptance rate\n \n \n Messages sent\n \n \n Reply rate\n \n \n \n Created\n
    \n \n \n \n this.state.rowsPerPage\n ? \"table-with-footer\"\n : \"table-with-out-footer\"\n }`}\n >\n {this.props.campaigns.map((row, index) => (\n \n \n
    \n this.handleClick(event, row.id)}\n checked={this.isSelected(row.id)}\n inputProps={{\n \"aria-labelledby\": `enhanced-table-checkbox-${index}`,\n }}\n icon={\n \"checkbox\"\n }\n checkedIcon={\n \"checkbox\"\n }\n />\n
    \n
    \n\n this.onClickCampaign(row.id)}\n style={{ width: \"28%\" }}\n scope=\"row\"\n className=\"name semi-bold title-company\"\n >\n
    \n
    \n \n \n {row.name}\n

    \n \n\n \n
    \n
    \n \n this.onClickCampaign(row.id)}\n className=\"contacts\"\n style={{ width: \"10%\" }}\n >\n {this.buildStatus(row.status, row.complete_reason)}\n \n this.onClickCampaign(row.id)}\n className=\"contacts text-accent\"\n style={{ width: \"10%\" }}\n >\n {row.statistics.invitation_sent}\n \n this.onClickCampaign(row.id)}\n className=\"contacts\"\n style={{ width: \"10%\" }}\n >\n
    \n
    \n {row.statistics.acceptance_rate\n ? functions\n .roundToDecimal(row.statistics.acceptance_rate)\n .toString() + \"%\"\n : \"...\"}\n
    \n
    \n \n this.onClickCampaign(row.id)}\n className=\"contacts text-accent\"\n style={{ width: \"10%\" }}\n >\n {row.statistics.messages_sent}\n \n\n \n \n this.onClickCampaign(row.id)}\n className={`contacts text-accent ${\n this.state.scrollBarWidth\n ? \"width-with_scroll-percent\"\n : \"width-with-out_scroll-percent\"\n }`}\n >\n {row.statistics.reply_rate !== null\n ? functions\n .roundToDecimal(row.statistics.reply_rate)\n .toString() + \"%\"\n : \"...\"}\n \n this.onClickCampaign(row.id)}\n className={\n this.state.scrollBarWidth\n ? \"width-with_scroll-teams\"\n : \"width-with-out_scroll-teams\"\n }\n >\n
    \n {`${\n row.created\n ? functions.parseDateToDMY(row.created, \"/\")\n : \"...\"\n }`}\n
    \n \n
    \n {this.buttonsActions(\n row.id,\n row.status,\n row.events,\n row.date\n )}\n
    \n \n \n
    \n ))}\n \n \n \n {\n localStorage.setItem(\"2.6\", \"true\");\n }}\n />\n \n {this.props.campaignsCount > this.state.rowsPerPage && (\n this.state.rowsPerPage\n ? \"table-footer-accent\"\n : \"table-footer\"\n }\n >\n \n \n )}\n this.setState({ modalData: null })}\n confirmHandler={() => this.actionHandler(this.state.modalData)}\n title={\n this.state?.modalData\n ? CONSTS.confirmationDialogs[this.state.modalData?.type].title\n : \"\"\n }\n content={\n this.state.modalData\n ? CONSTS.confirmationDialogs[\n this.state.modalData?.type\n ].content.replace(\n \"{contacts_count}\",\n this.state.modalData?.data?.valid_audience_count\n )\n : \"\"\n }\n />\n\n \n this.setState({\n confirmationDialog: { id: null, status: false, data: {} },\n modalData: null,\n })\n }\n classes={\"confirmation-launch-modal\"}\n >\n \n this.setState({\n confirmationDialog: { id: null, status: false, data: {} },\n modalData: null,\n })\n }\n startCampaign={() => {\n this.actionHandler(this.state.modalData);\n }}\n />\n \n \n );\n }\n}\n\nexport default TableCampaigns;\n","import type { MouseEventHandler } from 'react'\r\n\r\nimport clsx from 'clsx'\r\n\r\nimport './style.scss'\r\n\r\nimport { StackIcon } from 'shared/ui'\r\n\r\nexport function Tag({\r\n\tonClick,\r\n\ttext,\r\n\ttype = 'small'\r\n}: {\r\n\tonClick?: MouseEventHandler\r\n\ttext: string\r\n\ttype: 'big' | 'small'\r\n}) {\r\n\treturn (\r\n\t\t\r\n\t\t\t\r\n\r\n\t\t\t
    {text}
    \r\n\t\t\r\n\t)\r\n}\r\n\r\nexport default Tag\r\n","import { useEffect, useId, useState } from \"react\";\nimport PropTypes from \"prop-types\";\nimport Autocomplete from \"@mui/material/Autocomplete\";\nimport makeStyles from \"@mui/styles/makeStyles\";\nimport \"./style.scss\";\nimport TextField from \"@mui/material/TextField\";\nimport ArrowIcon from \"../../../assets/image/icons/svg/arrow-down-grey.svg\";\nimport CircularProgress from \"@mui/material/CircularProgress\";\nimport Tag from \"../Tag\";\nimport { Chip, Box } from \"@mui/material\";\n\nDropdownSimple.propTypes = {\n id: PropTypes.number,\n multiple: PropTypes.bool,\n tags: PropTypes.bool,\n customIcon: PropTypes.node,\n options: PropTypes.arrayOf(PropTypes.object).isRequired,\n value: PropTypes.any,\n onChange: PropTypes.func.isRequired,\n onTagClick: PropTypes.func,\n label: PropTypes.string,\n placeholder: PropTypes.string,\n dataForAuto: PropTypes.any,\n};\n\nexport function DropdownSimple(props) {\n const [showAll, setShowAll] = useState(false);\n const [open, setOpen] = useState(false);\n const [loading, setLoading] = useState(false);\n const classes = useStyles(props.fromTeams);\n const id = useId();\n const [inputVal, setInputVal] = useState(null);\n\n const getOptions = async () => {\n setOpen(true);\n setLoading(true);\n if (props.options.length === 0 || props.dataForAuto) {\n await props.getOptions();\n }\n //await props.getOptions({ take: 10 });\n setLoading(false);\n };\n\n useEffect(() => {\n let delayDebounceFn;\n setLoading(true);\n\n if (props.dataForAuto && inputVal !== null && open) {\n delayDebounceFn = setTimeout(async () => {\n await props.getOptions({\n ...props.dataForAuto,\n take: 10,\n keywords: inputVal + \"*\",\n });\n setLoading(false);\n }, 1000);\n } else {\n setLoading(false);\n }\n\n return () => clearTimeout(delayDebounceFn);\n }, [inputVal]);\n\n const onInputChange = async (value) => {\n if (props.dataForAuto) {\n setInputVal(value);\n }\n };\n\n return (\n \n {props.label && (\n \n {props.label}\n \n )}\n {\n setOpen(false);\n }}\n loading={loading}\n autoHighlight\n options={loading ? [] : props.options}\n getOptionLabel={(option) => option.text}\n renderOption={(props, option) => (\n
  • \n {option.color && (\n \n )}\n {option.img && (\n \n )}\n \n {option.text}\n {option.text2 && (\n \n {option.text2}\n \n )}\n \n
  • \n )}\n value={props.value}\n isOptionEqualToValue={(option, value) => option.key === value.key}\n onChange={props.onChange}\n onInputChange={(event, value, reason) => onInputChange(value)}\n popupIcon={\n props.customIcon ? (\n props.customIcon\n ) : (\n \n )\n }\n classes={classes}\n className={props.customIcon ? \"custom-icon\" : \"\"}\n renderInput={(params) => (\n \n {loading && }\n {params.InputProps.endAdornment}\n \n ),\n },\n }}\n />\n )}\n renderTags={(tagValue, getTagProps) =>\n tagValue.map((option, index) => (\n \n ))\n }\n />\n {props.multiple && props.tags && (\n
    \n {props.value.map((item, index) => {\n if (index <= 2) {\n return (\n props.onTagClick(props.id, item)}\n />\n );\n }\n return \"\";\n })}\n {props.value.length > 3 &&\n (showAll ? (\n
    \n {props.value.map((item, index) => {\n if (index > 2) {\n return (\n props.onTagClick(props.id, item)}\n />\n );\n }\n return \"\";\n })}\n
    \n ) : (\n setShowAll(true)}\n >\n Show more\n \n ))}\n
    \n )}\n \n );\n}\n\nconst useStyles = makeStyles(() => ({\n inputRoot: {\n padding: \"6px 50px 6px 13px !important\",\n backgroundColor: \"#ffffff\",\n },\n input: {\n color: \"#202020\",\n padding: \"0 !important\",\n fontWeight: \"normal !important\",\n fontSize: \"14px !important\",\n lineHeight: \"20px !important\",\n },\n option: {\n color: \"#202020 !important\",\n padding: \"6px 12px !important\",\n fontWeight: \"normal !important\",\n fontSize: \"14px !important\",\n lineHeight: \"20px !important\",\n },\n noOptions: {\n color: \"#202020 !important\",\n fontWeight: \"normal !important\",\n fontSize: \"14px !important\",\n lineHeight: \"20px !important\",\n },\n tag: {\n display: \"none !important\",\n },\n popper: {},\n paper: {\n padding: \"0 !important\",\n margin: \"0 !important\",\n boxShadow: \"none\",\n borderRight: \"1px solid #0cb39f\",\n borderLeft: \"1px solid #0cb39f\",\n borderBottom: \"1px solid #0cb39f\",\n borderRadius: \"4px\",\n color: \"#202020 !important\",\n fontWeight: \"normal !important\",\n fontSize: \"14px !important\",\n lineHeight: \"20px !important\",\n },\n}));\n\nexport default DropdownSimple;\n","import { useState } from \"react\";\nimport \"./style.scss\";\nimport { ResponsiveButton } from \"../responsiveButton/index.tsx\";\nimport dogNo from \"./../../../assets/image/snail-no.png\";\nimport dogThinks from \"./../../../assets/image/snail-typing.png\";\n\nconst ConfirmationDialogRunning = ({\n confirmationDialog,\n closeHandler,\n addContacts,\n}) => {\n const [isLoading, setIsLoading] = useState(false);\n const handlerConfirm = async () => {\n setIsLoading(true);\n try {\n await addContacts();\n await closeHandler();\n } finally {\n setIsLoading(false);\n }\n };\n\n const getConfirmationContent = () => {\n let totalCount = 0;\n\n if (\n confirmationDialog.data.validation_rules_summary.length &&\n confirmationDialog.data.valid_audience_count\n ) {\n return (\n
    \n

    \n Sorry, the system can't add\n
    some of the contacts\n

    \n
    \n
    \n {confirmationDialog.data.validation_rules_summary.map(\n (item, index) => {\n totalCount += item.count;\n return {`${item.count} contacts:`};\n }\n )}\n
    \n
    \n {confirmationDialog.data.validation_rules_summary.map(\n (item, index) => {\n return {item.description};\n }\n )}\n
    \n
    \n
    \n

    \n The system will add {confirmationDialog.data.valid_audience_count}{\" \"}\n contacts,\n

    \n

    {totalCount} will not be added.

    \n

    Would you like to proceed?

    \n
    \n\n
    \n \n Cancel\n \n {\n await handlerConfirm(confirmationDialog.id);\n closeHandler();\n }}\n >\n Confirm\n \n
    \n
    \n );\n }\n\n if (\n confirmationDialog.data.validation_rules_summary.length &&\n !confirmationDialog.data.valid_audience_count\n ) {\n return (\n
    \n

    \n Sorry, the system can't add
    \n these contacts\n

    \n
    \n
    \n {confirmationDialog.data.validation_rules_summary.map(\n (item, index) => {\n return
    {`${item.count} contacts:`}
    ;\n }\n )}\n
    \n
    \n {confirmationDialog.data.validation_rules_summary.map(\n (item, index) => {\n return
    {item.description}
    ;\n }\n )}\n
    \n
    \n
    \n

    Please select other contacts

    \n
    \n
    \n \n Ok\n \n
    \n
    \n );\n }\n };\n\n const isPositiveAudienceCount =\n confirmationDialog.data.validation_rules_summary.length &&\n confirmationDialog.data.valid_audience_count;\n\n return (\n
    \n {getConfirmationContent()}\n \n
    \n );\n};\n\nexport default ConfirmationDialogRunning;\n","import { Component } from \"react\";\nimport { connect } from \"react-redux\";\nimport { withRouter } from \"react-router-dom\";\nimport { Modal } from \"semantic-ui-react\";\n// Actions\nimport { campaign } from \"../../../actions/campaign\";\n// Images, Icons\nimport closeIcon from \"../../../assets/image/icons/svg/line/Close.svg\";\nimport { app } from \"../../../actions/app\";\nimport DropdownSimple from \"../DropdownSimple\";\nimport { filters } from \"../../../actions/filters\";\nimport { ResponsiveButton } from \"../../atoms/responsiveButton/index.tsx\";\nimport { apiCampaign } from \"../../../api/campaign/apiCampaign\";\nimport ModalWindow from \"../../molecules/ModalWindow\";\nimport ConfirmationDialogRunning from \"../ConfirmationDialogRunning\";\nimport { CONSTS } from \"../../../config/objectConst\";\nimport imagesAdd from \"../../../assets/image/icons/buttons/add.svg\";\nimport imagesAddDisable from \"../../../assets/image/icons/buttons/add-disabled.svg\";\nimport imagesCreate from \"../../../assets/image/icons/buttons/imagesCreate.svg\";\nimport imagesCreateDisable from \"../../../assets/image/icons/buttons/imagesCreateDisable.svg\";\n// import plusIcon from '../../../assets/image/icons/svg/icons/Plus2.svg'\n// import { Button } from \"shared/ui/index.ts\";\n\nexport class ButtonCreateCampaigns extends Component {\n constructor(props) {\n super(props);\n\n this.state = {\n isCloseModal: false,\n modalController: false,\n companyId: \"\",\n campaignName: \"\",\n error: false,\n needLoader: false,\n searchedCampaign: null,\n confirmationDialog: {\n id: null,\n status: false,\n data: {},\n },\n };\n }\n\n componentDidUpdate(prevProps, prevState) {\n if (\n (this.state.confirmationDialog.status !==\n prevState.confirmationDialog.status &&\n this.state.confirmationDialog.status === false) ||\n (this.state.isCloseModal !== prevState.isCloseModal &&\n this.state.isCloseModal === true)\n ) {\n this.handlerModal();\n this.setState({ isCloseModal: false, searchedCampaign: null });\n this.props.clearCheckboxesFunc();\n }\n }\n\n handlerModal = () => {\n if (this.props.from === \"contacts\" && this.props.type === \"new\") {\n localStorage.setItem(\"2.5\", \"true\");\n }\n this.setState({\n modalController: !this.state.modalController,\n });\n };\n\n handlerChange = (e) => {\n if (e.target.value.length <= CONSTS.CAMPAIGN_MAX_LENGTH) {\n this.setState({ companyId: e.target.value });\n this.setState({\n error: false,\n });\n } else {\n this.setState({\n error: true,\n });\n }\n };\n\n handlerCompany = async (e) => {\n let preview = \"\";\n const activeImportId = this.props.match.path.includes(\"contacts/import/\")\n ? this.props.activeImportId\n : \"\";\n if (\n (this.props.type === \"add\" &&\n this.props.campaigns.find(\n (campaign) => campaign.id === this.state.companyId\n ).information?.[0].value === \"Running\") ||\n (this.props.type === \"add\" &&\n this.props.campaigns.find(\n (campaign) => campaign.id === this.state.companyId\n ).information?.[0].value === \"Stopped\") ||\n (this.props.type === \"add\" &&\n this.props.campaigns.find(\n (campaign) => campaign.id === this.state.companyId\n ).information?.[0].value === \"Completed\")\n ) {\n this.setState({\n needLoader: true,\n });\n\n const filerQuery =\n activeImportId && !this.props.filters.filtersQuery\n ? `tags/any(c:c eq '${activeImportId}')`\n : this.props.filters.filtersQuery;\n\n preview = await apiCampaign.getPreviewAddTargetAudience({\n id: this.state.companyId,\n filter:\n filerQuery && this.props.selectAllUsersValue\n ? filerQuery\n : this.props.selectAllUsersValue\n ? ``\n : `id in (${this?.props?.contacts?.map((item) => `'${item}'`)})`,\n keywords: this.props.keywords ? this.props.keywords : \"\",\n });\n this.setState({\n needLoader: false,\n });\n }\n\n if (this.props.contacts) {\n if (this.props.type === \"add\") {\n if (\n (this.props.campaigns.find(\n (campaign) => campaign.id === this.state.companyId\n ).information?.[0].value === \"Running\" &&\n preview.data.validation_rules_summary.length === 0) ||\n (this.props.campaigns.find(\n (campaign) => campaign.id === this.state.companyId\n ).information?.[0].value === \"Stopped\" &&\n preview.data.validation_rules_summary.length === 0) ||\n (this.props.campaigns.find(\n (campaign) => campaign.id === this.state.companyId\n ).information?.[0].value === \"Completed\" &&\n preview.data.validation_rules_summary.length === 0) ||\n this.props.campaigns.find(\n (campaign) => campaign.id === this.state.companyId\n ).information?.[0].value === \"Compose\" ||\n (preview.data.validation_rules_summary.length === 0 &&\n preview.data.valid_audience_count > 0)\n ) {\n if (this.props.selectAllUsersValue) {\n await campaign.addAllContactsToCampaign(\n this.props.filters,\n this.state.companyId,\n this.state.campaignName,\n this.props.from,\n activeImportId,\n this.props.refreshContacts,\n this.props.keywords,\n () => {\n app.changeTableContentLoaderStatus(true);\n this.props.clearCheckboxesFunc();\n }\n );\n } else {\n await campaign.addContactsToCampaign({\n id: this.state.companyId,\n name: this.state.campaignName,\n audience: this.props.contacts,\n from: this.props.from,\n });\n }\n } else {\n return this.setState({\n confirmationDialog: {\n id: this.state.companyId,\n status: true,\n data: preview.data,\n },\n });\n }\n }\n if (this.props.type === \"new\") {\n await campaign.createCampaignWithContacts({\n name: this.state.companyId,\n audience: this.props.contacts,\n history: this.props.history,\n selectAllUsersValue: this.props.selectAllUsersValue,\n filters: this.props.filters,\n companyId: this.state.companyId,\n from: this.props.from,\n activeImportId,\n keywords: this.props.keywords,\n });\n }\n this.props.clearCheckboxesFunc();\n } else {\n if (this.props.type === \"new\") {\n await campaign.createCampaign(this.state.companyId, this.props.history);\n }\n }\n this.setState({\n companyId: \"\",\n modalController: !this.state.modalController,\n searchedCampaign: null,\n });\n };\n\n mapCampaigns = (array) =>\n array.map((item) => ({\n key: item.id,\n text: item.name,\n value: item.id,\n color: item.information?.[0].color,\n }));\n getCampaigns = async (data) => {\n await filters.getCampaigns({\n archived: false,\n filter: \"\",\n take: 10,\n ...data,\n });\n };\n\n autocompleteHandler = (e, newValue) => {\n this.setState({\n searchedCampaign: newValue ?? null,\n companyId: newValue?.value ?? \"\",\n campaignName: newValue?.name ?? \"\",\n });\n };\n\n addContactsToRunningCampaign = async () => {\n const activeImportId = this.props.match.path.includes(\"contacts/import/\")\n ? this.props.activeImportId\n : \"\";\n if (this.props.selectAllUsersValue) {\n await campaign.addAllContactsToCampaign(\n this.props.filters,\n this.state.companyId,\n this.state.campaignName,\n this.props.from,\n activeImportId,\n this.props.refreshContacts,\n this.props.keywords,\n () => {\n app.changeTableContentLoaderStatus(true);\n this.props.clearCheckboxesFunc();\n }\n );\n } else {\n await campaign.addContactsToCampaign({\n id: this.state.companyId,\n name: this.state.campaignName,\n audience: this.props.contacts,\n from: this.props.from,\n });\n }\n this.props.clearCheckboxesFunc();\n this.setState({\n companyId: \"\",\n modalController: !this.state.modalController,\n });\n };\n modalBody = () => {\n let text = \"\";\n if (!this.props.createCampaignController && this.props.type === \"add\") {\n text = \"Confirm\";\n }\n if (!this.props.createCampaignController && this.props.type === \"new\") {\n text = \"Create\";\n }\n return (\n
    \n
    \n \n
    \n
    \n {this.props.type === \"new\" && (\n <>\n

    Name your campaign

    \n \n to set up the sequence of actions{\" \"}\n {this.props.contacts\n ? `for ${\n this.props.selectAllUsersValue\n ? this.props.contactsCount\n : this.props.contacts.length\n } contacts`\n : \"\"}\n \n \n )}\n {this.props.type === \"add\" && (\n <>\n

    Add contacts to campaign

    \n \n Select the campaign to add{\" \"}\n {this.props.selectAllUsersValue\n ? this.props.contactsCount\n : this.props.contacts.length}{\" \"}\n contacts\n \n \n )}\n
    \n {this.props.type === \"new\" && (\n {\n if (e.key === \"Enter\" && this.state.companyId) {\n this.handlerCompany();\n }\n }}\n />\n )}\n {this.props.type === \"add\" && (\n \n )}\n \n {text}\n \n
    \n
    \n
    \n );\n };\n\n render() {\n const { disabled, classes, text } = this.props;\n\n return (\n <>\n \n {this.modalBody()}\n \n {/* \n \n\n {text === 'Add campaign' && (\n \n )}\n\n\n {text === \"Add to campaign\" && (\n \n )}\n {text === \"Create campaign\" && (\n \n )}\n {text}\n */}\n \n {text === \"Add to campaign\" && (\n \n )}\n {text === \"Create campaign\" && (\n \n )}\n {text}\n \n\n \n this.setState({\n confirmationDialog: {\n id: null,\n status: false,\n data: {},\n },\n })\n }\n classes={\"confirmation-launch-modal\"}\n >\n \n this.setState({\n isCloseModal: true,\n confirmationDialog: {\n id: null,\n status: false,\n data: {},\n },\n })\n }\n addContacts={this.addContactsToRunningCampaign}\n />\n \n \n );\n }\n}\n\nconst mapStateToProps = function (state) {\n return {\n createCampaignController: state.campaign.createCampaignController,\n campaigns: state.campaigns.campaigns,\n filters: state.filters,\n contactsCount: state.contacts.contactsCount,\n };\n};\n\nexport default connect(mapStateToProps)(withRouter(ButtonCreateCampaigns));\n","import type {\r\n\tChangeEventHandler,\r\n\tFocusEventHandler,\r\n\tKeyboardEventHandler,\r\n\tReactNode\r\n} from 'react'\r\n\r\nimport InputAdornment from '@mui/material/InputAdornment'\r\nimport TextField from '@mui/material/TextField'\r\nimport makeStyles from '@mui/styles/makeStyles'\r\nimport { useId } from 'react'\r\n\r\nfunction TextFieldCustom({\r\n\tendAdornment,\r\n\tlabel,\r\n\tonBlur,\r\n\tonChange,\r\n\tonEnter,\r\n\tplaceholder,\r\n\tvalue\r\n}: {\r\n\tendAdornment?: ReactNode\r\n\tlabel?: string\r\n\tonBlur?: FocusEventHandler\r\n\tonChange?: ChangeEventHandler\r\n\tonEnter?: KeyboardEventHandler\r\n\tplaceholder?: string\r\n\tvalue?: string\r\n}) {\r\n\tconst classes = useStyles()\r\n\tconst uniqueId = useId()\r\n\r\n\tconst onKeyUp: KeyboardEventHandler = e => {\r\n\t\tif (e.key === 'Enter') {\r\n\t\t\tonEnter?.(e)\r\n\t\t}\r\n\t}\r\n\r\n\tconst endIcon = endAdornment ? (\r\n\t\t{endAdornment}\r\n\t) : (\r\n\t\t''\r\n\t)\r\n\r\n\treturn (\r\n\t\t
    \r\n\t\t\t{label && (\r\n\t\t\t\t\r\n\t\t\t)}\r\n\t\t\t\r\n\t\t
    \r\n\t)\r\n}\r\n\r\nconst useStyles = makeStyles(_ => ({\r\n\troot: {\r\n\t\t'& .Mui-focused .MuiOutlinedInput-notchedOutline': {\r\n\t\t\tborderColor: '#0cb39f',\r\n\t\t\tborderWidth: '1px'\r\n\t\t},\r\n\t\t'& .MuiOutlinedInput-input': {\r\n\t\t\tbackgroundColor: '#ffffff',\r\n\t\t\tcolor: '#202020',\r\n\t\t\tfontSize: '14px',\r\n\t\t\tfontWeight: 'normal',\r\n\t\t\tlineHeight: '20px',\r\n\t\t\tpadding: '8px 40px 8px 13px'\r\n\t\t},\r\n\t\t'&:hover .MuiOutlinedInput-notchedOutline': {\r\n\t\t\tborderColor: '#0cb39f',\r\n\t\t\tborderWidth: '1px'\r\n\t\t},\r\n\t\tbackgroundColor: '#fff',\r\n\t\twidth: '220px'\r\n\t}\r\n}))\r\n\r\nexport default TextFieldCustom\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"root\":\"root-PYQHCJ\",\"title\":\"title-ixVzUz\",\"filters\":\"filters-C7BClJ\",\"filter\":\"filter-tIZ3Zg\",\"active\":\"active-R8AfEl\",\"stopped\":\"stopped-oKuvRz\",\"completed\":\"completed-W3FY3q\",\"drafted\":\"drafted-i0g5dE\",\"not-exist\":\"not-exist-jql__F\",\"notExist\":\"not-exist-jql__F\"};","import type { ChangeEventHandler, FieldsetHTMLAttributes } from 'react'\r\n\r\nimport clsx from 'clsx'\r\nimport { useCallback } from 'react'\r\nimport { useAppDispatch, useAppSelector } from 'shared/hooks'\r\nimport { typo } from 'shared/styles'\r\n\r\nimport {\r\n\tcampaignsActions,\r\n\tcampaignsSelectors\r\n} from '../../../redux/reducers/campaigns'\r\nimport { CustomTip } from '../../atoms/tooltipCustom'\r\nimport css from './Statuses.module.scss'\r\n\r\nconst labels = ['draft', 'paused', 'active', 'completed']\r\nconst filters = ['drafted', 'stopped', 'active', 'completed'] as const\r\n\r\nexport function Statuses({\r\n\tclassName,\r\n\t...props\r\n}: FieldsetHTMLAttributes) {\r\n\tconst state = useAppSelector(campaignsSelectors.filters)\r\n\r\n\tconst dispatch = useAppDispatch()\r\n\r\n\tconst onChange: ChangeEventHandler = useCallback(\r\n\t\tevent => {\r\n\t\t\tconst filter = event.target.value as (typeof filters)[number]\r\n\r\n\t\t\tdispatch(campaignsActions.toggleFilter(filter))\r\n\t\t},\r\n\t\t[dispatch]\r\n\t)\r\n\r\n\treturn (\r\n\t\t
    \r\n\t\t\tStatus: \r\n\t\t\t
    \r\n\t\t\t\t{filters.map((filter, index) => (\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t))}\r\n\t\t\t
    \r\n\t\t
    \r\n\t)\r\n}\r\n","import { useState } from 'react'\r\nimport { useEffect } from 'react'\r\nimport { useAppDispatch, useAppSelector, useUnMount } from 'shared/hooks'\r\n\r\nimport { app } from '../../../actions/app'\r\nimport './style.scss'\r\nimport { filters } from '../../../actions/filters'\r\nimport iconSearch from '../../../assets/image/icons/svg/search-icon-grey.svg'\r\nimport {\r\n\tcampaignsActions,\r\n\tcampaignsSelectors\r\n} from '../../../redux/reducers/campaigns'\r\nimport ButtonCreateCampaigns from '../../atoms/buttonCreateCampaigns'\r\nimport TextFieldCustom from '../../atoms/TextFieldCustom'\r\nimport { Statuses } from './Statuses'\r\n\r\nexport function CampaignFilters({\r\n\tarchive = false,\r\n\torderby = '',\r\n\tsetPage\r\n}: {\r\n\tarchive?: boolean\r\n\torderby?: string\r\n\tsetPage(page: number): void\r\n}) {\r\n\tconst keywords = useAppSelector(campaignsSelectors.search)\r\n\tconst [search, setSearch] = useState(keywords)\r\n\tconst filter = useAppSelector(campaignsSelectors.filterQuery)\r\n\r\n\tconst dispatch = useAppDispatch()\r\n\r\n\tconst onSearchEnter = () => {\r\n\t\tif (search !== keywords) {\r\n\t\t\tdispatch(campaignsActions.setSearch(search))\r\n\t\t}\r\n\t}\r\n\r\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: \r\n\tuseEffect(() => {\r\n\t\tsetPage(0)\r\n\r\n\t\tapp.changeTableContentLoaderStatus(true)\r\n\r\n\t\tconst body: any = {\r\n\t\t\tarchived: archive,\r\n\t\t\tkeywords: search\r\n\t\t}\r\n\r\n\t\tif (!archive) {\r\n\t\t\tbody.filter = filter\r\n\t\t\tbody.orderby = orderby\r\n\t\t}\r\n\r\n\t\tfilters.getCampaigns(body)\r\n\t}, [filter, orderby, archive, search])\r\n\r\n\tuseUnMount(() => {\r\n\t\tdispatch(campaignsActions.setSearch(search))\r\n\t})\r\n\r\n\treturn (\r\n\t\t
    \r\n\t\t\t

    Campaigns

    \r\n\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t\t\t\t\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tonBlur={onSearchEnter}\r\n\t\t\t\t\t\tonChange={e => setSearch(e.target.value)}\r\n\t\t\t\t\t\tonEnter={onSearchEnter}\r\n\t\t\t\t\t\tplaceholder={'Search'}\r\n\t\t\t\t\t\tvalue={search}\r\n\t\t\t\t\t/>\r\n\t\t\t\t
    \r\n\t\t\t\t{!archive && [\r\n\t\t\t\t\t,\r\n\t\t\t\t\t\r\n\t\t\t\t]}\r\n\t\t\t
    \r\n\t\t
    \r\n\t)\r\n}\r\n","import picture from 'assets/image/snail-looking-for.png'\r\n\r\nimport './style.scss'\r\n\r\nimport { CONSTS } from 'config/objectConst'\r\nimport { typo } from 'shared/styles'\r\n\r\nimport css from './NoSearchResult.module.scss'\r\n\r\nexport function NoSearchResult({\r\n\tlead\r\n}: {\r\n\tlead: string\r\n}) {\r\n\treturn (\r\n\t\t
    \r\n\t\t\tOoops… Nothing was found!\r\n\t\t\t\r\n\t\t\t

    {lead}

    \r\n\t\t
    \r\n\t)\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"yellow\":\"yellow-1qJ9hT\",\"root\":\"root-DHgvmR\",\"lead\":\"lead-eXnbyL\",\"pic\":\"pic-RAJa5j\"};","import { NoSearchResult } from './NoSearchResult'\r\n\r\nexport const NoFilterCampaignResult = () => (\r\n\t\r\n)\r\nexport const NoContactsFound = () => (\r\n\t\r\n)\r\n","import { Component } from \"react\";\nimport { connect } from \"react-redux\";\nimport { withRouter } from \"react-router-dom\";\n// Components\nimport { HomeTemplate } from \"../../components/templates/homeTemplate\";\nimport TableCampaigns from \"../../components/molecules/tableCampaigns\";\n// Actions\nimport { app } from \"../../actions/app\";\nimport { campaign } from \"../../actions/campaign\";\nimport { mapping } from \"../../actions/mapping\";\nimport CircularProgress from \"@mui/material/CircularProgress\";\nimport { filters } from \"../../actions/filters\";\nimport { CampaignFilters } from \"../../components/molecules/CampaignFilters\";\n\nimport { campaignsSelectors } from \"../../redux/reducers/campaigns.ts\";\nimport { NoFilterCampaignResult } from \"components/templates/NoSearchResult\";\n\nexport class ArchiveCampaignsPage extends Component {\n constructor(props) {\n super(props);\n\n this.state = {\n modalController: false,\n companyName: \"\",\n\n tableCampaignsStatisticsPage: 0,\n };\n }\n async componentDidMount() {\n app.changePage(\"/campaigns\");\n app.changeActiveItem(3);\n app.changePageContentLoaderStatus(true);\n campaign.getRecentCampaigns();\n await filters.getCampaigns({\n archived: true,\n keywords: this.props.searchArchiveValue,\n });\n app.changePageContentLoaderStatus(false);\n }\n\n render() {\n return (\n \n {this.props.app.pageContentLoader && (\n
    \n \n
    \n )}\n \n this.setState({ tableCampaignsStatisticsPage: value })\n }\n />\n {this.props.campaignsCount === 0 &&\n this.props.isSearchOrFilterApplied ? (\n \n ) : (\n \n this.setState({ tableCampaignsStatisticsPage: value })\n }\n tableCampaignsStatisticsPage={\n this.state.tableCampaignsStatisticsPage\n }\n />\n )}\n
    \n );\n }\n}\n\nconst mapStateToProps = function (state) {\n return {\n app: state.app,\n filters: state.filters,\n createCampaignController: state.campaign.createCampaignController,\n campaignsCount: state.campaigns.campaignsCount,\n campaigns: state.campaigns.campaigns,\n haveCampaigns: state.campaigns.haveCampaigns,\n searchValue: state.campaigns.searchValue,\n leftSide: state.leftSideMenu.leftSide,\n isSearchOrFilterApplied: campaignsSelectors.isFilterOrSearchActive(state),\n filterQuery: campaignsSelectors.filterQuery(state),\n };\n};\n\nexport default connect(mapStateToProps)(withRouter(ArchiveCampaignsPage));\n","import { campaignCreateActions } from 'redux/reducers/campaignCreate.ts'\r\nimport { notifyError } from 'shared/errors/notificate.ts'\r\n\r\nimport { CONSTS } from '../config/objectConst.js'\r\nimport { campaignsActions } from '../redux/reducers/campaigns.ts'\r\nimport store from '../redux/store.ts'\r\nimport { campaign } from './campaign.js'\r\n\r\ninterface SendStep {\r\n\tmessage_template?: string\r\n\treaction?: string\r\n\ttimeout: number\r\n\ttype: string\r\n}\r\n\r\ninterface WorkingStep {\r\n\tname: string\r\n\ttype: string\r\n\tvalues: {\r\n\t\tcurrentEmotion?: string\r\n\t\tdelay?: number\r\n\t\tperiod?: number\r\n\t\ttextarea?: string\r\n\t}\r\n}\r\n\r\nconst adaptSteps = ({ type, values }: WorkingStep): SendStep => ({\r\n\tmessage_template: values.textarea || '',\r\n\treaction:\r\n\t\ttype === CONSTS.AVAILABLE_ACTIONS.ReactOnPost.Type\r\n\t\t\t? values.currentEmotion\r\n\t\t\t: undefined,\r\n\ttimeout: values.period || 0,\r\n\ttype\r\n})\r\n\r\nfunction insertDelay(steps: SendStep[], originals: WorkingStep[]) {\r\n\tconst index = originals.findIndex(\r\n\t\t({ name }) => name === CONSTS.AVAILABLE_ACTIONS.Connect.Type\r\n\t)\r\n\r\n\tconst isExist = index > -1,\r\n\t\tisLast = index === originals.length - 1\r\n\r\n\tif (isExist && !isLast) {\r\n\t\tconst delayObject = {\r\n\t\t\ttimeout: originals[index].values.delay || 0,\r\n\t\t\ttype: 'Delay'\r\n\t\t}\r\n\t\tsteps.splice(index + 1, 0, delayObject)\r\n\t}\r\n}\r\n\r\nexport const campaignCreate = {\r\n\teditScrollEvent(value: boolean) {\r\n\t\tconst action = campaignsActions.setScrollToAction(value)\r\n\t\tstore.dispatch(action)\r\n\t},\r\n\r\n\tasync save(stepValues: WorkingStep[], id: string, history: () => void) {\r\n\t\ttry {\r\n\t\t\tconst steps = stepValues.map(adaptSteps)\r\n\t\t\tinsertDelay(steps, stepValues)\r\n\t\t\tconst response = await campaign.updateCampaign({\r\n\t\t\t\tid,\r\n\t\t\t\tsteps\r\n\t\t\t})\r\n\r\n\t\t\tif (response) {\r\n\t\t\t\thistory()\r\n\t\t\t}\r\n\t\t} catch (error) {\r\n\t\t\tnotifyError(error)\r\n\t\t}\r\n\t},\r\n\r\n\tzoomMessageWindow(value = '') {\r\n\t\tconst action = campaignCreateActions.setZoom(value)\r\n\t\tstore.dispatch(action)\r\n\t}\r\n}\r\n","import { Component } from \"react\";\nimport \"./style.scss\";\n\nexport class ErrorHelper extends Component {\n render() {\n return (\n
    \n
    \n
    {this.props.children}
    \n
    \n );\n }\n}\n\nexport default ErrorHelper;\n","import { Component } from \"react\";\n// Style\nimport \"./style.scss\";\n\nexport class FormField extends Component {\n render() {\n return (\n
    \n
    \n \n \n {this.props.label}{\" \"}\n {this.props.required ? * : null}\n \n \n {Array.isArray(this.props.beaforeLabel)\n ? this.props.beaforeLabel.map((item, index) => (\n {item}\n ))\n : this.props.beaforeLabel}\n \n
    \n
    {this.props.children}
    \n
    \n \n );\n }\n}\n\nexport default FormField;\n","import { useEffect, useState } from \"react\";\n// components\n// icons\nimport ClockIcon from \"../../../assets/image/icons/png/solid-medium/clock.png\";\nimport { CONSTS } from \"../../../config/objectConst\";\n// style\nimport \"./timer.scss\";\n\nconst TimerComponent = (props) => {\n const [minValue, setMinValue] = useState(0);\n const [hoursValue, setHoursValue] = useState(0);\n const [dayValue, setDayValue] = useState(0);\n\n useEffect(() => {\n const days = props.time / 60 / 24;\n const hours = (props.time - Math.floor(days) * 24 * 60) / 60;\n const mins =\n props.time - Math.floor(days) * 24 * 60 - Math.floor(hours) * 60;\n\n setDayValue(Math.floor(days));\n setHoursValue(Math.floor(hours));\n setMinValue(Math.floor(mins));\n }, [props.time]);\n\n useEffect(() => {\n const mValue = minValue ? minValue : 0;\n const hValue = hoursValue ? hoursValue : 0;\n const dValue = dayValue ? dayValue : 0;\n const result = mValue + hValue * 60 + dValue * 60 * 24;\n props.timerChanger(props.item, result, props.unique);\n }, [minValue, hoursValue, dayValue]);\n\n const handleChange = (value, flag) => {\n switch (flag) {\n case \"minutes\":\n setMinValue(value);\n break;\n case \"hours\":\n setHoursValue(value);\n break;\n case \"days\":\n setDayValue(value);\n break;\n\n default:\n break;\n }\n };\n\n return (\n \n {props.label && (\n
    \n \"ClockIcon\"\n {props.label}\n
    \n )}\n\n
    \n \n\n \n \n
    \n \n );\n};\n\nexport default TimerComponent;\n\nexport const InputWithArrows = (props) => {\n const [maxValue, setMaxValue] = useState(0);\n const [minValue, setMinValue] = useState(0);\n const [focus, setFocus] = useState(false);\n\n useEffect(() => {\n setMaxValue(props.maxValue);\n }, [props.maxValue]);\n\n useEffect(() => {\n setMinValue(props.minValue);\n }, [props.minValue]);\n\n const handleChange = (e) => {\n const value = e.target.value;\n if (value !== \"\") {\n if (value >= 0 && value <= maxValue) {\n props.handleChange(parseInt(value), props.flag);\n }\n } else {\n props.handleChange(value, props.flag);\n }\n };\n\n const onUpValue = () => {\n if (props.defaultValue + 1 <= maxValue) {\n props.handleChange(parseInt(props.defaultValue + 1), props.flag);\n }\n };\n\n const onDownValue = () => {\n if (props.defaultValue - 1 >= minValue) {\n props.handleChange(parseInt(props.defaultValue - 1), props.flag);\n }\n };\n\n const onFocusArrows = () => {\n setFocus(true);\n };\n\n const onBlurArrows = () => {\n setFocus(false);\n };\n\n const handleBlur = (e) => {\n const value = e.target.value;\n if (!value || value === \"0\") {\n props.handleChange(props.minValue, props.flag);\n }\n };\n\n return (\n
    \n {props.flag && (\n
    \n {props.flag}\n
    \n )}\n \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n \n );\n};\n","import { Component } from \"react\";\nimport \"./style.scss\";\n\nexport class ErrorHelperStep extends Component {\n render() {\n return (\n
    \n
    \n
    {this.props.children}
    \n
    \n );\n }\n}\n\nexport default ErrorHelperStep;\n","import React, { Component } from \"react\";\nimport {\n Select,\n MenuItem,\n RadioGroup,\n FormControlLabel,\n Radio,\n} from \"@mui/material\";\nimport FormField from \"../formField\";\nimport TimerComponent from \"../../organisms/CampaingsStepCreate/timer\";\nimport ErrorHelper from \"../../atoms/ErrorHelper\";\nimport ErrorHelperStep from \"../../atoms/ErrorHelperStep\";\nimport { campaignCreate } from \"../../../actions/campaignCreate\";\nimport TextareaAutosize from \"react-textarea-autosize\";\nimport { scroller } from \"react-scroll\";\nimport { CONSTS } from \"../../../config/objectConst\";\nimport imgPoints from \"../../../assets/image/icons/svg/points.svg\";\n\nimport Like from \"../../../assets/image/icons/emotions/like.png\";\nimport Support from \"../../../assets/image/icons/emotions/support.png\";\nimport Celebrate from \"../../../assets/image/icons/emotions/celebrate.png\";\nimport Funny from \"../../../assets/image/icons/emotions/funny.png\";\nimport Love from \"../../../assets/image/icons/emotions/love.png\";\nimport Insightful from \"../../../assets/image/icons/emotions/insightful.png\";\n\nconst imageMap = {\n Like,\n Support,\n Celebrate,\n Funny,\n Love,\n Insightful,\n};\n\nexport class SelectContainer extends Component {\n constructor(props) {\n super(props);\n this.message = React.createRef();\n\n this.state = {\n id: props.item.id ? props.item.id : \"\",\n name: props.item.name ? props.item.name : \"\",\n index: props.index ? props.index : \"\",\n launchActionIn: props.item.values.launchActionIn\n ? props.item.values.launchActionIn\n : 0,\n period: props.item.values.period ? props.item.values.period : \"\",\n message: props.item.values.textarea ? props.item.values.textarea : \"\",\n messageSelectionStart: 0,\n messageSelectionEnd: 0,\n sendMessageTo: props.item.values.sendMessageTo\n ? props.item.values.sendMessageTo\n : \"Contacts, who never replied\",\n values: props.item.values ? props.item.values : [],\n validation: props.item.validation ? props.item.validation : [],\n customNestedFields: false,\n currentEmotion: props.item.params.currentEmotion || \"Like\",\n };\n }\n\n componentDidUpdate(prevProps) {\n if (this.props.item.name !== prevProps.item.name) {\n this.setState({\n name: this.props.item.name,\n });\n }\n }\n\n save = () => {\n this.props.getSave(this.props.item.index);\n };\n\n arrayErrorMessages = (message) => {\n const newArrayErrorMessages = [];\n this.props\n .checkMessage(message)\n .map((el) => newArrayErrorMessages.push(el[0]));\n return [...new Set(newArrayErrorMessages)];\n };\n // launchAction and period Selected\n launchActionIn = (e, item) => {\n this.setState({\n launchActionIn: e.target.value,\n });\n this.props.validationLaunchActionIn(e.target.value, item.index);\n };\n handlePeriod = (value, item) => {\n this.setState({\n period: value,\n });\n this.props.validationPeriod(value, item.index);\n };\n\n // Textarea Actions\n handleMessage = (e, type) => {\n this.setState({\n message: e.target.value,\n messageSelectionStart: e.target.selectionStart,\n messageSelectionEnd: e.target.selectionEnd,\n });\n if (this.props.item.type) {\n this.props.validationMessage(e.target.value, this.props.item.index);\n }\n };\n handleMessageKeyDown = (e) => {\n this.setState({\n messageSelectionStart: e.target.selectionStart,\n messageSelectionEnd: e.target.selectionEnd,\n });\n };\n handleClickMessage = (e) => {\n this.setState({\n messageSelectionStart: e.target.selectionStart,\n messageSelectionEnd: e.target.selectionEnd,\n });\n };\n\n scrollHandler = () => {\n scroller.scrollTo(\n `myScrollToElement-zoomed-message`,\n {\n duration: 150,\n delay: 0,\n smooth: false,\n containerId: \"homeTemplateContainerID\",\n offset: -25,\n },\n 0\n );\n };\n\n // Event click on field label -\n // add to textarea new values\n clickOnField = (value) => {\n const prevText = this.state.message.slice(\n 0,\n this.state.messageSelectionStart\n );\n const beforeText = this.state.message.slice(\n this.state.messageSelectionEnd,\n this.message.length\n );\n const newText = \"\";\n this.setState({\n message: newText.concat(prevText, value, beforeText),\n });\n this.props.validationMessage(\n newText.concat(prevText, value, beforeText),\n this.props.item.index\n );\n this.message.current.focus();\n setTimeout(() => {\n this.message.current.setSelectionRange(\n this.state.messageSelectionStart + value.length,\n this.state.messageSelectionStart + value.length\n );\n this.setState({\n messageSelectionStart: this.state.messageSelectionStart + value.length,\n messageSelectionEnd: this.state.messageSelectionStart + value.length,\n });\n }, 0);\n };\n\n // Radio buttons - actions\n handleRadio = (e) => {\n this.setState({\n sendMessageTo: e.target.value,\n });\n };\n\n isValidLength = () => {\n return (\n this.state.message.length >\n (this.props.item.type === CONSTS.AVAILABLE_ACTIONS.Connect.Type\n ? CONSTS.AVAILABLE_ACTIONS.Connect.MaxLength\n : CONSTS.AVAILABLE_ACTIONS.Message.MaxLength)\n );\n };\n\n resizeHandler = () => {\n if (this.props.item.values.textarea) {\n this.props.setActionId(this.props.item.id);\n this.scrollHandler();\n }\n\n campaignCreate.zoomMessageWindow(this.state.message);\n };\n\n render() {\n return (\n
    \n {/* Launch action in */}\n {this.props.item.params.launchActionIn && (\n \n this.launchActionIn(e, this.props.item)}\n value={Number(this.state.launchActionIn)}\n icon={\"none\"}\n className=\"select chose-action\"\n MenuProps={{\n getContentAnchorEl: null,\n anchorOrigin: {\n vertical: \"bottom\",\n horizontal: \"left\",\n },\n }}\n >\n Immediately\n 1 hour\n 2 hrs\n 1 day\n 2 days\n 3 days\n 1 week\n \n \n )}\n {/* Custom fields */}\n {this.state.customNestedFields && (\n \n this.setState({\n customNestedFields: false,\n })\n }\n >
    \n )}\n\n {this.props.item.params.mainCustomFields && (\n \n
    \n
      \n {this.props.item.params.mainCustomFields.map((item, index) => {\n return (\n {\n this.clickOnField(item);\n }}\n >\n {item}\n \n );\n })}\n
    \n \n this.setState({\n customNestedFields: !this.state.customNestedFields,\n })\n }\n >\n \"points\"\n
    \n {this.state.customNestedFields &&\n this.props.item.params.overflowCustomFields && (\n
      \n {this.props.item.params.overflowCustomFields.map(\n (item, index) => {\n return (\n {\n this.clickOnField(item);\n this.setState({\n customNestedFields: false,\n });\n }}\n >\n {item}\n \n );\n }\n )}\n
    \n )}\n \n \n )}\n {this.props.item.params.emotion && (\n \n
      \n {this.props.item.params.emotion.map((item, index) => {\n return (\n {\n this.props.saveReaction(item, this.props.item.index);\n this.setState({\n currentEmotion: item,\n });\n }}\n >\n \n \n {item}\n

      \n \n );\n })}\n
    \n \n )}\n {/* Text message */}\n {this.props.item.params.textarea && (\n \n \n
    \n  \n
    \n this.handleMessage(e, this.props.item.type)}\n onClick={this.handleClickMessage}\n onKeyDown={this.handleMessageKeyDown}\n value={this.state.message}\n placeholder=\"Note something...\"\n />\n
    \n \n (\n this.props.item.type ===\n CONSTS.AVAILABLE_ACTIONS.Connect.Type\n ? CONSTS.AVAILABLE_ACTIONS.Connect.MaxLength\n : CONSTS.AVAILABLE_ACTIONS.Message.MaxLength\n )\n ? \"counter__error\"\n : \"\"\n }`}\n >\n {this.state.message.length}\n \n /\n {this.props.item.type === CONSTS.AVAILABLE_ACTIONS.Connect.Type\n ? CONSTS.AVAILABLE_ACTIONS.Connect.MaxLength\n : CONSTS.AVAILABLE_ACTIONS.Message.MaxLength}\n
    \n \n {this.props.item.validation.textarea !== undefined &&\n !this.props.item.validation.textarea &&\n this.state.message.length === 0 &&\n this.props.item.type ===\n CONSTS.AVAILABLE_ACTIONS.Message.Type && (\n Enter your message\n )}\n\n {this.props.checkMessage(this.state.message).length !== 0 && (\n
    \n {this.arrayErrorMessages(this.state.message).map((el) => (\n \n {\" \"}\n {el} is not supported\n \n ))}\n
    \n )}\n\n {this.state.message.length >\n (this.props.item.type === CONSTS.AVAILABLE_ACTIONS.Connect.Type\n ? CONSTS.AVAILABLE_ACTIONS.Connect.MaxLength\n : CONSTS.AVAILABLE_ACTIONS.Message.MaxLength) && (\n Too long message\n )}\n \n )}\n {/* Send message to */}\n {this.props.item.params.sendMessageTo && (\n \n \n }\n label=\"All contacts\"\n />\n }\n label=\"Contacts, who never replied\"\n />\n \n \n )}\n {/* Checking period */}\n {this.props.item.params.period &&\n this.state.name === CONSTS.AVAILABLE_ACTIONS.Connect.Title && (\n \n
    \n \n
    \n \n )}\n \n );\n }\n}\n\nexport default SelectContainer;\n","// extracted by css-extract-rspack-plugin\nexport default {\"action-text\":\"action-text-N2E3vf\",\"actionText\":\"action-text-N2E3vf\",\"trigger\":\"trigger-Rg8eHe\",\"active\":\"active-MbAvFe\",\"wrapper\":\"wrapper-OKE7zp\",\"not-exist\":\"not-exist-GSM45y\",\"notExist\":\"not-exist-GSM45y\"};","import Menu from '@mui/material/Menu'\r\nimport MenuItem from '@mui/material/MenuItem'\r\nimport clsx from 'clsx'\r\nimport { CONSTS } from 'config/objectConst'\r\nimport { useMemo } from 'react'\r\nimport { useMenuPopup } from 'shared/hooks'\r\nimport { typo } from 'shared/styles'\r\n\r\nimport type { Action } from './utils/actions'\r\n\r\nimport PlusIcon from '../../../assets/image/icons/svg/icons/Plus2.svg'\r\nimport css from './ActionSelect.module.scss'\r\n\r\nexport function ActionSelect({\r\n\tactions,\r\n\tactionsList,\r\n\tonChange\r\n}: {\r\n\tactions: Action[]\r\n\tactionsList: any[]\r\n\tonChange: any\r\n}) {\r\n\tconst menu = useMenuPopup()\r\n\r\n\tconst filteredList = useMemo(\r\n\t\t() =>\r\n\t\t\tactionsList.filter(\r\n\t\t\t\tel =>\r\n\t\t\t\t\tel.name === CONSTS.AVAILABLE_ACTIONS.Message.Title ||\r\n\t\t\t\t\tel.name === 'Endorse a skill' ||\r\n\t\t\t\t\tel.name === CONSTS.AVAILABLE_ACTIONS.Connect.Title\r\n\t\t\t),\r\n\t\t[actionsList]\r\n\t)\r\n\r\n\tconst isMenuItemDisabled = (item: Action) =>\r\n\t\t!item.localeAvailable ||\r\n\t\t(item.name === CONSTS.AVAILABLE_ACTIONS.Connect.Title &&\r\n\t\t\tfilteredList.length > 0)\r\n\r\n\treturn (\r\n\t\t<>\r\n\t\t\t {\r\n\t\t\t\t\tmenu.openMenu(event)\r\n\t\t\t\t\tlocalStorage.setItem('2.3', 'true')\r\n\t\t\t\t}}\r\n\t\t\t\ttype='button'\r\n\t\t\t>\r\n\t\t\t\tPlusIcon\r\n\t\t\t\t\r\n\t\t\t\t\t{actionsList.length === 0 ? 'Add action' : 'Add next action'}\r\n\t\t\t\t\r\n\r\n\t\t\t\t\r\n\t\t\t\r\n\r\n\t\t\t\r\n\t\t\t\t{actions\r\n\t\t\t\t\t.filter(el => el.available)\r\n\t\t\t\t\t.map((action, index) => {\r\n\t\t\t\t\t\tconst isDisabled = isMenuItemDisabled(action)\r\n\r\n\t\t\t\t\t\treturn (\r\n\t\t\t\t\t\t\t {\r\n\t\t\t\t\t\t\t\t\tonChange(action)\r\n\t\t\t\t\t\t\t\t\tmenu.closeMenu()\r\n\t\t\t\t\t\t\t\t}}\r\n\t\t\t\t\t\t\t\tvalue={action.name}\r\n\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t{action.name}\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t)\r\n\t\t\t\t\t})}\r\n\t\t\t\r\n\t\t\r\n\t)\r\n}\r\n","import { type MouseEvent, useId, useMemo, useState } from 'react'\r\n\r\nexport function useMenuPopup() {\r\n\tconst menu = useId()\r\n\r\n\tconst [anchorEl, setAnchorEl] = useState(null)\r\n\r\n\tconst isOpen = Boolean(anchorEl)\r\n\r\n\tconst methods = useMemo(\r\n\t\t() => ({\r\n\t\t\tcloseMenu() {\r\n\t\t\t\tsetAnchorEl(null)\r\n\t\t\t},\r\n\r\n\t\t\topenMenu(event: MouseEvent) {\r\n\t\t\t\tsetAnchorEl(event.currentTarget)\r\n\t\t\t}\r\n\t\t}),\r\n\t\t[]\r\n\t)\r\n\r\n\treturn {\r\n\t\tisOpen,\r\n\t\tmenuCn: `${menu}-menu`,\r\n\t\ttriggerCn: `${menu}-trigger`,\r\n\t\t...methods,\r\n\t\tanchorEl\r\n\t}\r\n}\r\n","import { CONSTS } from 'config/objectConst'\r\n\r\nexport const getActions = (): Action[] => [\r\n\t{\r\n\t\tarrow: true,\r\n\t\tavailable: CONSTS.AVAILABLE_ACTIONS.Connect.Visible,\r\n\t\tlocaleAvailable: true,\r\n\t\tname: CONSTS.AVAILABLE_ACTIONS.Connect.Title,\r\n\t\topen: true,\r\n\t\tparams: {\r\n\t\t\tlaunchActionIn: false,\r\n\t\t\tmainCustomFields: CONSTS.MAIN_CUSTOM_FIELDS,\r\n\t\t\toverflowCustomFields: CONSTS.OVERFLOW_CUSTOM_FIELDS,\r\n\t\t\tperiod: Number,\r\n\t\t\tsendMessageTo: false,\r\n\t\t\ttextarea: String\r\n\t\t},\r\n\t\tstatus: false,\r\n\t\ttype: CONSTS.AVAILABLE_ACTIONS.Connect.Type,\r\n\t\tvalidation: {\r\n\t\t\tactionName: true\r\n\t\t},\r\n\t\tvalues: {\r\n\t\t\tdelay: CONSTS.DEFAULT_DATE_ACTIONS_VALUE.CONNECT.DELAY.DEFAULT,\r\n\t\t\tlaunchActionIn: 0,\r\n\t\t\tmainCustomFields: CONSTS.MAIN_CUSTOM_FIELDS,\r\n\t\t\toverflowCustomFields: CONSTS.OVERFLOW_CUSTOM_FIELDS,\r\n\t\t\tperiod: CONSTS.DEFAULT_DATE_ACTIONS_VALUE.CONNECT.WITHDRAW.DEFAULT * 1440,\r\n\t\t\tsendMessageTo: 'Contacts, who never replied',\r\n\t\t\ttextarea: ''\r\n\t\t}\r\n\t},\r\n\t{\r\n\t\tarrow: true,\r\n\t\tavailable: CONSTS.AVAILABLE_ACTIONS.Message.Visible,\r\n\t\tlocaleAvailable: true,\r\n\t\tname: CONSTS.AVAILABLE_ACTIONS.Message.Title,\r\n\t\topen: true,\r\n\t\tparams: {\r\n\t\t\tlaunchActionIn: false,\r\n\t\t\tmainCustomFields: CONSTS.MAIN_CUSTOM_FIELDS,\r\n\t\t\toverflowCustomFields: CONSTS.OVERFLOW_CUSTOM_FIELDS,\r\n\t\t\tperiod: false,\r\n\t\t\tsendMessageTo: false,\r\n\t\t\ttextarea: String\r\n\t\t},\r\n\t\tstatus: false,\r\n\t\ttype: CONSTS.AVAILABLE_ACTIONS.Message.Type\r\n\t},\r\n\t{\r\n\t\tarrow: false,\r\n\t\tavailable: CONSTS.AVAILABLE_ACTIONS.VisitProfile.Visible,\r\n\t\tlocaleAvailable: true,\r\n\t\tname: CONSTS.AVAILABLE_ACTIONS.VisitProfile.Title,\r\n\t\topen: false,\r\n\t\tparams: {\r\n\t\t\tlaunchActionIn: false,\r\n\t\t\tperiod: false,\r\n\t\t\tsendMessageTo: false\r\n\t\t},\r\n\t\tstatus: false,\r\n\t\ttype: CONSTS.AVAILABLE_ACTIONS.VisitProfile.Type\r\n\t},\r\n\t{\r\n\t\tarrow: false,\r\n\t\tavailable: CONSTS.AVAILABLE_ACTIONS.Follow.Visible,\r\n\t\tlocaleAvailable: true,\r\n\t\tname: CONSTS.AVAILABLE_ACTIONS.Follow.Title,\r\n\t\topen: false,\r\n\t\tparams: {\r\n\t\t\tlaunchActionIn: false,\r\n\t\t\tperiod: false,\r\n\t\t\tsendMessageTo: false\r\n\t\t},\r\n\t\tstatus: false,\r\n\t\ttype: CONSTS.AVAILABLE_ACTIONS.Follow.Type\r\n\t},\r\n\t{\r\n\t\tarrow: true,\r\n\t\tavailable: CONSTS.AVAILABLE_ACTIONS.ReactOnPost.Visible,\r\n\t\tlocaleAvailable: true,\r\n\t\t// ? I guess it's error, should be in params\r\n\t\tmainCustomFields: CONSTS.MAIN_CUSTOM_FIELDS,\r\n\t\tname: CONSTS.AVAILABLE_ACTIONS.ReactOnPost.Title,\r\n\t\topen: true,\r\n\t\tparams: {\r\n\t\t\tcurrentEmotion: 'Like',\r\n\t\t\temotion: CONSTS.EMOTION,\r\n\t\t\tlaunchActionIn: false,\r\n\t\t\tperiod: false,\r\n\t\t\tsendMessageTo: false\r\n\t\t},\r\n\t\tstatus: false,\r\n\t\ttype: CONSTS.AVAILABLE_ACTIONS.ReactOnPost.Type\r\n\t},\r\n\t{\r\n\t\tarrow: false,\r\n\t\tavailable: CONSTS.AVAILABLE_ACTIONS.EndorseSkill.Visible,\r\n\t\tlocaleAvailable: true,\r\n\t\tname: CONSTS.AVAILABLE_ACTIONS.EndorseSkill.Title,\r\n\t\topen: false,\r\n\t\tparams: {\r\n\t\t\tlaunchActionIn: false,\r\n\t\t\tperiod: false,\r\n\t\t\tsendMessageTo: false\r\n\t\t},\r\n\t\tstatus: false,\r\n\t\ttype: CONSTS.AVAILABLE_ACTIONS.EndorseSkill.Type\r\n\t},\r\n\t{\r\n\t\tarrow: false,\r\n\t\tavailable: CONSTS.AVAILABLE_ACTIONS.ScrapeProfile.Visible,\r\n\t\tlocaleAvailable: true,\r\n\t\tname: CONSTS.AVAILABLE_ACTIONS.ScrapeProfile.Title,\r\n\t\topen: false,\r\n\t\tparams: {\r\n\t\t\tlaunchActionIn: false,\r\n\t\t\tperiod: false,\r\n\t\t\tsendMessageTo: false\r\n\t\t},\r\n\t\tstatus: false,\r\n\t\ttype: CONSTS.AVAILABLE_ACTIONS.ScrapeProfile.Type\r\n\t}\r\n]\r\n\r\nexport type Action = {\r\n\tarrow: boolean\r\n\tavailable: boolean\r\n\tlocaleAvailable: boolean\r\n\tmainCustomFields?: string[]\r\n\tname: string\r\n\topen: boolean\r\n\tparams: {\r\n\t\tcurrentEmotion?: string\r\n\t\temotion?: string[]\r\n\t\tlaunchActionIn: boolean\r\n\t\tmainCustomFields?: string[]\r\n\t\toverflowCustomFields?: string[]\r\n\t\tperiod: false | NumberConstructor\r\n\t\tsendMessageTo: boolean\r\n\t\ttextarea?: StringConstructor\r\n\t}\r\n\tstatus: boolean\r\n\ttype: string\r\n\r\n\tvalidation?: {\r\n\t\tactionName: boolean\r\n\t}\r\n\r\n\tvalues?: {\r\n\t\tdelay: number\r\n\t\tlaunchActionIn: number\r\n\t\tmainCustomFields: string[]\r\n\t\toverflowCustomFields: string[]\r\n\t\tperiod: number\r\n\t\tsendMessageTo: string\r\n\t\ttextarea: string\r\n\t}\r\n}\r\n","import { CONSTS } from 'config/objectConst'\r\n\r\nconst typeToCN = {\r\n\t[CONSTS.AVAILABLE_ACTIONS.Connect.Type]: 'connect',\r\n\r\n\t[CONSTS.AVAILABLE_ACTIONS.EndorseSkill.Type]: 'endorse-a-skill',\r\n\r\n\t[CONSTS.AVAILABLE_ACTIONS.Follow.Type]: 'follow',\r\n\r\n\t[CONSTS.AVAILABLE_ACTIONS.Message.Type]: 'message',\r\n\r\n\t[CONSTS.AVAILABLE_ACTIONS.ReactOnPost.Type]: 'like-a-post',\r\n\r\n\t[CONSTS.AVAILABLE_ACTIONS.ScrapeProfile.Type]: 'scrape-profile',\r\n\r\n\t[CONSTS.AVAILABLE_ACTIONS.VisitProfile.Type]: 'view-profile'\r\n}\r\n\r\nexport const getTypeCN = (type: string) => {\r\n\tconst value = typeToCN[type]\r\n\r\n\tif (value) {\r\n\t\treturn value\r\n\t}\r\n\r\n\tthrow new Error(`Not supported action type ${type}`)\r\n}\r\n","import React, { Component } from \"react\";\nimport { connect } from \"react-redux\";\nimport { withRouter } from \"react-router-dom\";\n\nimport { Element, scroller } from \"react-scroll\";\nimport lFind from \"lodash/find\";\nimport lFilter from \"lodash/filter\";\n\n// Actions\nimport { campaignCreate } from \"../../../actions/campaignCreate\";\nimport ErrorHelper from \"../../atoms/ErrorHelper\";\n// Components\nimport SelectContainer from \"../../molecules/selectContainer\";\nimport FormField from \"../../molecules/formField\";\nimport TimerComponent from \"./timer\";\nimport ModalWindow from \"../../molecules/ModalWindow\";\n// Images\nimport deleteIcon from \"../../../assets/image/icons/svg/icons/delete-icon.svg\";\n// icons\nimport ArrowIcon from \"../../../assets/image/icons/svg/icons/Arrow-down.svg\";\n\nimport HintTooltip from \"../../atoms/HintTooltip\";\n// configs\nimport { CONSTS } from \"../../../config/objectConst\";\nimport { functions } from \"../../../tools/functions\";\nimport { ResponsiveButton } from \"../../atoms/responsiveButton/index.tsx\";\nimport { campaign } from \"../../../actions/campaign\";\n\nimport { notificationUtils } from \"features/notifications/index.ts\";\nimport { notifyError } from \"shared/errors/notificate.ts\";\nimport { ActionSelect } from \"./ActionSelect.tsx\";\nimport { getActions } from \"./utils/actions.ts\";\nimport { getTypeCN } from \"./utils/index.ts\";\n\nconst fillInWithData = (from) => {\n return from.map((item) => {\n return {\n type: item.type,\n delay: item.values.delay,\n period: item.values.period,\n textarea: item.values.textarea,\n };\n });\n};\nconst objectsAreSame = (x, y) => {\n let objectsAreSame = true;\n const xValues = Object.values(x);\n const yValues = Object.values(y);\n xValues.forEach((item, index) => {\n if (item !== yValues[index]) {\n return (objectsAreSame = false);\n }\n });\n return objectsAreSame;\n};\nexport class Step extends Component {\n constructor(props) {\n super(props);\n\n this.state = {\n isConnectDelay: null,\n campaignId: null,\n actions: getActions(),\n saveDisabledController: false,\n actionsList: [],\n actionsListInitial: [],\n isOpenModalCancel: false,\n modalDeleteValue: null,\n\n chooseActionMessageOpen: false,\n\n isDataChanged: false,\n actionId: null,\n scrollBarWidth: false,\n };\n this.saveCaseActionsValue = [];\n this.wrapper = React.createRef();\n }\n\n componentDidMount() {\n window.addEventListener(\"resize\", this.handleResize);\n if (this.props.scrollToAction) {\n setTimeout(() => {\n scroller.scrollTo(\n `myScrollToElement-${this.props.scrollToAction}`,\n {\n duration: 150,\n delay: 0,\n smooth: false,\n containerId: \"homeTemplateContainerID\",\n offset: 250,\n },\n 0\n );\n campaignCreate.editScrollEvent(false);\n }, 0);\n }\n\n if (this.props.campaign.id !== null) {\n this.setState({\n actionsList: this.props.campaign.actions,\n campaignId: this.props.campaign.id,\n });\n }\n }\n\n componentWillUnmount() {\n campaignCreate.zoomMessageWindow(\"\");\n window.removeEventListener(\"resize\", this.handleResize);\n }\n\n componentDidUpdate(prevProps) {\n if (\n this.props.campaign.id &&\n prevProps.campaign.id !== this.props.campaign.id\n ) {\n this.setState({\n actionsList: this.props.campaign.actions,\n actionsListInitial: fillInWithData(this.props.campaign.actions),\n });\n }\n this.handleResize();\n }\n\n handleResize = () => {\n if (this.wrapper.current) {\n const scrollbarWidth =\n this.wrapper.current.offsetWidth - this.wrapper.current.clientWidth;\n\n if (scrollbarWidth > 0 && this.state.scrollBarWidth === false) {\n this.setState({ scrollBarWidth: true });\n }\n\n if (scrollbarWidth === 0 && this.state.scrollBarWidth === true) {\n this.setState({ scrollBarWidth: false });\n }\n }\n };\n\n scrollToElement = (id) => {\n setTimeout(() => {\n scroller.scrollTo(\n `myScrollToElement-Action_${id}`,\n {\n duration: 150,\n delay: 0,\n smooth: false,\n containerId: \"homeTemplateContainerID\",\n },\n 0\n );\n }, 0);\n };\n\n setUniqueId = (array) => {\n const newArray = [...array];\n for (let index = 0; index < 1000; index++) {\n if (!lFind(newArray, [\"index\", `Action_${index + 1}`])) {\n return index + 1;\n }\n }\n };\n\n handleSelect = (action) => {\n const choseObject = action;\n const choseObjectParams = { ...choseObject.params };\n const newChoseObject = { ...choseObject, params: choseObjectParams };\n const buildObject = {\n id: this.setUniqueId(this.state.actionsList),\n index: `Action_${this.setUniqueId(this.state.actionsList)}`,\n open: true,\n validation: {\n actionName: true,\n textarea: true,\n period: true,\n },\n values: {\n launchActionIn: 0,\n currentEmotion: \"Like\",\n mainCustomFields: CONSTS.MAIN_CUSTOM_FIELDS,\n overflowCustomFields: CONSTS.OVERFLOW_CUSTOM_FIELDS,\n emotion: CONSTS.EMOTION,\n textarea: \"\",\n period:\n CONSTS.DEFAULT_DATE_ACTIONS_VALUE.MESSAGE_TIMEOUTS_DAYS[\n this.state.actionsList.length\n ] * 1440,\n sendMessageTo: \"Contacts, who never replied\",\n },\n ...newChoseObject,\n };\n setTimeout(() => {\n scroller.scrollTo(\n `myScrollToElement-${buildObject.index}`,\n {\n duration: 150,\n delay: 0,\n smooth: false,\n containerId: \"homeTemplateContainerID\",\n offset: -25,\n },\n 0\n );\n }, 0);\n\n if (action.name === CONSTS.AVAILABLE_ACTIONS.Message.Title) {\n this.setState((state) => ({\n actionsList: state.actionsList.map((item) => (item.open = false)),\n }));\n }\n\n if (\n this.state.actionsList.length <\n CONSTS.DEFAULT_DATE_ACTIONS_VALUE.MESSAGE_TIMEOUTS_DAYS.length\n ) {\n this.setState({ actionsList: [...this.state.actionsList, buildObject] });\n }\n };\n\n // Saves Action\n getSave = (index) => {\n this.state.actionsList.forEach((item, itemIndex) => {\n if (\n this.state.actionsList.length === 1 &&\n item.name === CONSTS.AVAILABLE_ACTIONS.Connect.Title\n ) {\n item.values.delay = 0;\n }\n if (!this.saveCaseActionsValue.includes(item) && item.index === index) {\n this.saveCaseActionsValue.push(item);\n }\n });\n if (this.saveCaseActionsValue.length === this.state.actionsList.length) {\n campaignCreate.save(\n this.saveCaseActionsValue,\n this.props.campaign.id,\n () => {\n if (this.props.campaign.allowAddSteps) {\n return campaign.openCampaignContacts(this.props, true);\n } else {\n return this.props.history.push({\n pathname: `/campaigns/${this.props.campaign.id}`,\n });\n }\n }\n );\n }\n };\n\n save = () => {\n this.state.actionsList.map((item, index) =>\n this.refs[`child${index + 1}`].save()\n );\n };\n\n checkMessage = (message) => {\n const fields = [...message.matchAll(/{(?.*?)}/gim)];\n\n const customFields = [\n ...CONSTS.MAIN_CUSTOM_FIELDS,\n ...CONSTS.OVERFLOW_CUSTOM_FIELDS,\n ];\n\n return fields.filter((el) => !customFields.some((rule) => rule === el[0]));\n };\n\n isError = () =>\n this.state.actionsList.map((el) => this.checkMessage(el.values.textarea));\n\n saveDisabledController = (array) => {\n // This function checked status validation\n // and return value\n const ar = [];\n if (array.length > 0) {\n array.forEach((item) => {\n for (const el in item.validation) {\n ar.push(item.validation[el]);\n }\n });\n if (lFilter(ar, (item) => item === false).length > 0) {\n return false;\n } else {\n return true;\n }\n } else {\n return true;\n }\n };\n\n textAreaLengthValidation = () => {\n return this.state.actionsList.some(\n (item) =>\n item.values.textarea.length >\n (item.type === CONSTS.AVAILABLE_ACTIONS.Connect.Type\n ? CONSTS.AVAILABLE_ACTIONS.Connect.MaxLength\n : CONSTS.AVAILABLE_ACTIONS.Message.MaxLength)\n );\n };\n\n findIndexActionsWithError = (list) => {\n const result = lFilter(list, (el) => {\n return (\n !el.validation.textarea &&\n el.type === CONSTS.AVAILABLE_ACTIONS.Message.Type\n );\n });\n\n /* TODO if find try, scroll to element and open acardion */\n\n if (result.length > 0) {\n for (const element of result) {\n element.open = true;\n }\n\n this.setState({ actionsList: this.state.actionsList });\n\n setTimeout(() => {\n scroller.scrollTo(\n `myScrollToElement-${result[0].index}`,\n {\n duration: 500,\n delay: 0,\n smooth: true,\n containerId: \"homeTemplateContainerID\",\n offset: -25,\n },\n 0\n );\n }, 0);\n }\n };\n\n setOpenConnect = () => {\n setTimeout(() => {\n scroller.scrollTo(\n `myScrollToElement-Action_1`,\n {\n duration: 500,\n delay: 0,\n smooth: true,\n containerId: \"homeTemplateContainerID\",\n offset: -25,\n },\n 0\n );\n }, 0);\n };\n\n setFieldsData = () => {\n this.setState({ isConnectDelay: true });\n\n this.showErrorMessages(() => {\n this.showErrorMessageCallback();\n this.findIndexActionsWithError(this.state.actionsList);\n });\n };\n\n showErrorMessageCallback = () => {\n if (this.saveDisabledController(this.state.actionsList)) {\n ((!this.textAreaLengthValidation() &&\n this.state.actionsList.find(\n (item) => item.name === CONSTS.AVAILABLE_ACTIONS.Connect.Title\n )?.values?.delay >=\n CONSTS.DEFAULT_DATE_ACTIONS_VALUE.CONNECT.DELAY.MIN_VALUE_MINUTES) ||\n this.state.actionsList.find(\n (item) => item.name === CONSTS.AVAILABLE_ACTIONS.Connect.Title\n )?.values?.delay === undefined) &&\n !this.isError()?.some((el) => el.length !== 0) &&\n this.save();\n }\n };\n\n showErrorMessages = (callback) => {\n const newActionsList = this.state.actionsList.map((item) => {\n if (\n (item.validation.hasOwnProperty(\"textarea\") &&\n item.validation.textarea &&\n item.values.textarea.length === 0 &&\n item.type === CONSTS.AVAILABLE_ACTIONS.Message.Type) ||\n (item.validation.hasOwnProperty(\"textarea\") &&\n item.validation.textarea &&\n this.checkMessage(item.values.textarea).length !== 0)\n ) {\n item.validation.textarea = false;\n }\n return item;\n });\n this.setState(\n { actionsList: newActionsList },\n callback ? () => callback() : null\n );\n };\n\n // validation message\n validationMessage = (value, index) => {\n const newActionsList = this.state.actionsList.map((item) => {\n const maxLength =\n item.type === CONSTS.AVAILABLE_ACTIONS.Connect.Type\n ? CONSTS.AVAILABLE_ACTIONS.Connect.MaxLength\n : CONSTS.AVAILABLE_ACTIONS.Message.MaxLength;\n\n if (item.index === index) {\n if (item.type === CONSTS.AVAILABLE_ACTIONS.Connect.Type) {\n item.validation.textarea = maxLength >= value.length;\n }\n if (item.type === CONSTS.AVAILABLE_ACTIONS.Message.Type) {\n item.validation.textarea =\n value.length > 0 && maxLength >= value.length;\n }\n\n item.values.textarea = value;\n }\n return item;\n });\n this.setState({\n actionsList: newActionsList,\n });\n };\n\n saveReaction = (value, index) => {\n const newActionsList = this.state.actionsList.map((item) => {\n if (item.index === index) {\n if (item.type === CONSTS.AVAILABLE_ACTIONS.ReactOnPost.Type) {\n item.values.currentEmotion = value;\n }\n }\n return item;\n });\n this.setState({\n actionsList: newActionsList,\n });\n };\n\n validationLaunchActionIn = (value, index) => {\n const newActionsList = this.state.actionsList.map((item) => {\n if (item.index === index) {\n item.values.launchActionIn = value;\n }\n return item;\n });\n this.setState({\n actionsList: newActionsList,\n });\n };\n\n validationPeriod = (value, index) => {\n const newActionsList = this.state.actionsList.map((item) => {\n if (item.index === index) {\n item.values.period = value;\n }\n return item;\n });\n this.setState({\n actionsList: newActionsList,\n });\n };\n\n deleteAction = (id) => {\n try {\n const index = this.state.actionsList.findIndex(\n (item) => item.index === id\n );\n if (index === -1) {\n return;\n }\n const newActionsList = this.state.actionsList.splice(0, index);\n this.setState(\n { actionsList: newActionsList, modalDeleteValue: null },\n () => notificationUtils.snackById(\"3.3\")\n );\n } catch (error) {\n notifyError(error);\n }\n };\n\n isEqualValues = () => {\n let isEqual = true;\n const values = fillInWithData(this.state.actionsList);\n fillInWithData(this.state.actionsList, values);\n values.forEach((item, index) => {\n if (!objectsAreSame(item, this.state.actionsListInitial[index])) {\n return (isEqual = false);\n }\n });\n return isEqual;\n };\n\n handleCancel = () => {\n if (\n this.state.actionsListInitial.length !== this.state.actionsList.length ||\n !this.isEqualValues()\n ) {\n this.setState({ isOpenModalCancel: true });\n } else {\n this.props.history.push(\"/campaigns\");\n }\n };\n\n accordionClick = (e, item) => {\n const newActionsList = this.state.actionsList.map((el) => {\n if (el.id === item.id) {\n el.open = !item.open;\n }\n return el;\n });\n this.setState({\n actionsList: newActionsList,\n });\n };\n\n timerChanger = (item, result, unique) => {\n const nowObject = lFind(this.state.actionsList, { index: item.index });\n if (!unique) {\n this.state.isConnectDelay && this.setState({ isConnectDelay: false });\n if (item.name === CONSTS.AVAILABLE_ACTIONS.Connect.Title) {\n if (nowObject.values.delay !== result) {\n const findEl = this.state.actionsList.filter(\n (el) => el.name === CONSTS.AVAILABLE_ACTIONS.Connect.Title\n );\n\n const findInd = this.state.actionsList.indexOf(findEl[0]);\n this.state.actionsList[findInd].values.delay = result;\n }\n } else {\n if (nowObject.values.delay !== result) {\n nowObject.values.period = result;\n\n return nowObject;\n }\n }\n } else {\n const findEl = this.state.actionsList.filter(\n (el) => el.name === CONSTS.AVAILABLE_ACTIONS.Connect.Title\n );\n const findInd = this.state.actionsList.indexOf(findEl[0]);\n this.state.actionsList[findInd].values.period = result;\n }\n };\n\n accordionGeneratorLabelText = (item, index, arrow) => {\n if (item.name === CONSTS.AVAILABLE_ACTIONS.Message.Title && index > 0) {\n return (\n

    \n Action {index + 1}: Follow up message\n

    \n );\n } else {\n return (\n

    \n Action {index + 1}:{item.name}\n

    \n );\n }\n };\n\n getDelayDescription = (item) => {\n switch (item.type) {\n case CONSTS.AVAILABLE_ACTIONS.Connect.Type:\n return [\"Once connection is\",
    , \"accepted, wait\"];\n case CONSTS.AVAILABLE_ACTIONS.Message.Type:\n return [\"If no response in\"];\n default:\n return [\"After execution\"];\n }\n };\n\n renderMainActionField = () => {\n return (\n
    \n \n \n {\n window.localStorage.setItem(\"2.3\", \"true\");\n }}\n />\n \n
    \n );\n };\n\n render() {\n const actionNumber = this.state.actionsList.length;\n return (\n
    \n
    \n
    \n \n {this.state.actionsList.map((item, index) => (\n \n \n item.arrow && this.accordionClick(e, item)}\n className=\"action-label-wrap\"\n >\n {item.arrow && (\n \"arrow\"\n )}\n
    \n {this.accordionGeneratorLabelText(\n item,\n index,\n item.arrow\n )}\n
    \n
    \n\n {this.props.campaign.allowAddSteps && (\n {\n const days =\n CONSTS.DEFAULT_DATE_ACTIONS_VALUE\n .MESSAGE_TIMEOUTS_DAYS[\n this.state.actionsList.length - 2\n ] * 1440;\n const newArr = [...this.state.actionsList];\n\n newArr[\n this.state.actionsList.length - 1\n ].values.period = days;\n this.setState({\n modalDeleteValue: item.index,\n actionsList: newArr,\n });\n }}\n >\n \n
    Delete
    \n
    \n )}\n
    \n \n this.setState({ actionId: id })}\n checkMessage={this.checkMessage}\n />\n \n {(item.name !== CONSTS.AVAILABLE_ACTIONS.Connect.Title ||\n (this.state.actionsList &&\n this.state.actionsList[this.state.actionsList.length - 1]\n ?.name !== CONSTS.AVAILABLE_ACTIONS.Connect.Title)) && (\n \n \n {item.name === CONSTS.AVAILABLE_ACTIONS.Connect.Title &&\n this.state.actionsList.find(\n (item) =>\n item.name === CONSTS.AVAILABLE_ACTIONS.Connect.Title\n )?.values?.delay <\n CONSTS.DEFAULT_DATE_ACTIONS_VALUE.CONNECT.DELAY\n .MIN_VALUE_MINUTES &&\n this.state.isConnectDelay && (\n
    \n \n {\" \"}\n Must be at least{\" \"}\n {\n CONSTS.DEFAULT_DATE_ACTIONS_VALUE.CONNECT.DELAY\n .MIN_VALUE_MINUTES\n }{\" \"}\n minutes\n \n
    \n )}\n \n )}\n \n ))}\n \n {!this.props.zoomMessageWindow && (\n \n {this.props.campaign.allowAddSteps &&\n actionNumber <\n CONSTS.DEFAULT_DATE_ACTIONS_VALUE.MESSAGE_TIMEOUTS_DAYS\n .length &&\n this.renderMainActionField()}\n\n
    \n \n Cancel\n \n \n {\"Save\"}\n \n {((this.state.actionsList.find(\n (item) => item.name === CONSTS.AVAILABLE_ACTIONS.Connect.Title\n )?.values?.delay <\n CONSTS.DEFAULT_DATE_ACTIONS_VALUE.CONNECT.DELAY\n .MIN_VALUE_MINUTES &&\n this.state.isConnectDelay &&\n this.setOpenConnect()) ||\n (this.state.actionsList.find(\n (item) =>\n item.name === CONSTS.AVAILABLE_ACTIONS.Connect.Title\n )?.values?.delay <\n CONSTS.DEFAULT_DATE_ACTIONS_VALUE.CONNECT.DELAY\n .MIN_VALUE_MINUTES &&\n this.state.isConnectDelay &&\n actionNumber > 1) ||\n !this.saveDisabledController(this.state.actionsList) ||\n this.isError()?.some((el) => el.length !== 0)) && (\n
    \n Please fix all warnings\n
    \n )}\n
    \n \n )}\n {!!this.props.zoomMessageWindow && (\n
    \n {\n campaignCreate.zoomMessageWindow(\"\");\n this.scrollToElement(this.state.actionId);\n }}\n >\n  \n
    \n \n
    \n                  {this.props.zoomMessageWindow}\n                
    \n \n \n )}\n this.setState({ isOpenModalCancel: false })}\n confirmHandler={() => this.props.history.push(\"/campaigns\")}\n />\n this.setState({ modalDeleteValue: null })}\n confirmHandler={() =>\n this.deleteAction(this.state.modalDeleteValue)\n }\n />\n \n \n );\n }\n}\n\nconst mapStateToProps = function (state) {\n return {\n count: state.campaign.count,\n updateCampaignController: state.campaign.updateCampaignController,\n scrollToAction: state.campaigns.scrollToAction,\n zoomMessageWindow: state.campaignCreate.zoomMessageWindow,\n appProfile: state.app.appProfile,\n campaign: state.campaign,\n };\n};\n\nexport default connect(mapStateToProps)(withRouter(Step));\n","import { FullLoader } from 'components/atoms/FullLoader/FullLoader'\r\nimport { useEffect } from 'react'\r\n\r\n// Style\r\nimport './style.scss'\r\n\r\nimport { useParams } from 'react-router-dom'\r\nimport { Element } from 'react-scroll'\r\nimport { useActionCreators, useAppSelector, useSwitcher } from 'shared/hooks'\r\n\r\n// Actions\r\nimport { campaign } from '../../../actions/campaign'\r\nimport { campaignCreateActions } from '../../../redux/reducers/campaignCreate'\r\nimport exclaim from './../../../assets/image/icons/svg/exclaim-black.svg'\r\n// Components\r\nimport ContainerStep from './step'\r\n\r\n// const getStatus = (info) => info.find((item) => item.id === 1).value;\r\n\r\n// TODO: remove necro code, replace loading for parent FC\r\n\r\nexport function CampaignSteps({\r\n\tonNotFound\r\n}: {\r\n\tonNotFound(): void\r\n}) {\r\n\tconst loaderSwitcher = useSwitcher(true)\r\n\r\n\tconst errorSwitcher = useSwitcher(false)\r\n\r\n\tconst { id } = useParams<{ id: string }>()\r\n\r\n\tconst name = useAppSelector(state => state.campaign.name)\r\n\tconst allowAddSteps = useAppSelector(state => state.campaign.allowAddSteps)\r\n\r\n\tuseSyncFinishStep()\r\n\r\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: setters is memoized\r\n\tuseEffect(() => {\r\n\t\tloaderSwitcher.on()\r\n\t\terrorSwitcher.off()\r\n\r\n\t\tcampaign\r\n\t\t\t.getCampaignId(id)\r\n\t\t\t.catch(e => {\r\n\t\t\t\tconsole.error(e)\r\n\t\t\t\terrorSwitcher.on()\r\n\t\t\t})\r\n\t\t\t.then(res => {\r\n\t\t\t\tif (!res) {\r\n\t\t\t\t\tonNotFound()\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t\t.finally(() => {\r\n\t\t\t\tloaderSwitcher.off()\r\n\t\t\t})\r\n\t}, [id, onNotFound])\r\n\r\n\tif (loaderSwitcher.isOn) {\r\n\t\treturn \r\n\t}\r\n\r\n\treturn (\r\n\t\t
    \r\n\t\t\t
    \r\n\t\t\t\t{/*
    \r\n\t\t\t\t\t

    {labelName}

    \r\n\t\t\t\t
    */}\r\n\t\t\t\t\r\n\t\t\t\t\t

    {name}

    \r\n\t\t\t\t\r\n\t\t\t
    \r\n\r\n\t\t\t{!allowAddSteps && !errorSwitcher.isOn && (\r\n\t\t\t\t
    \r\n\t\t\t\t\t\r\n\t\t\t\t\t

    \r\n\t\t\t\t\t\tThe campaign has already started, editing is limited\r\n\t\t\t\t\t

    \r\n\t\t\t\t
    \r\n\t\t\t)}\r\n\r\n\t\t\t{!errorSwitcher.isOn && }\r\n\t\t
    \r\n\t)\r\n}\r\n\r\nfunction useSyncFinishStep() {\r\n\tconst count = useAppSelector(state => state.campaign.count)\r\n\tconst { setFinishStep } = useActionCreators(campaignCreateActions)\r\n\r\n\tuseEffect(() => {\r\n\t\tsetFinishStep(count > 0 ? '1' : '2')\r\n\t}, [count, setFinishStep])\r\n}\r\n","import './style.scss'\r\n\r\nimport type { PropsWithChildren } from 'react'\r\n\r\nimport { useDocumentTitle } from 'shared/hooks'\r\n\r\nexport function NotFoundContainer({ children }: PropsWithChildren) {\r\n\tuseDocumentTitle('404')\r\n\r\n\treturn children\r\n}\r\n","import { Component } from \"react\";\nimport { NotFoundContainer } from \"../../components/templates/notFoundTemplate\";\nimport { Link } from \"react-router-dom\";\nimport Image404 from \"../../assets/image/404.png\";\nimport { helpersFunc } from \"../../config/helpers\";\n\nexport class NotfoundPage extends Component {\n componentDidMount() {\n helpersFunc.logEnjectService404();\n }\n render() {\n return (\n \n
    \n
    \n \"404\"\n
    \n

    Oooopss...

    \n

    \n Its seems like the page that are you looking for is no longer\n here\n

    \n \n Go home!\n \n
    \n
    \n
    \n
    \n );\n }\n}\n\nexport default NotfoundPage;\n","import { useMount } from 'shared/hooks/useMount.ts'\r\nimport { useSwitcher } from 'shared/hooks/useSwitcher.ts'\r\n\r\n// Actions\r\nimport { app } from '../../actions/app.js'\r\nimport { campaign } from '../../actions/campaign.js'\r\nimport { CampaignSteps } from '../../components/organisms/CampaingsStepCreate'\r\n// Components\r\nimport { HomeTemplate } from '../../components/templates/homeTemplate'\r\nimport NotfoundPage from '../notfound/index.js'\r\n\r\nexport function CampaignsCreatePage() {\r\n\tconst pageFound = useSwitcher(true)\r\n\r\n\tuseMount(() => {\r\n\t\tapp.changePage('/campaigns')\r\n\t\tapp.changeActiveItem(1)\r\n\t\tcampaign.getRecentCampaigns()\r\n\t})\r\n\r\n\treturn pageFound.isOn ? (\r\n\t\t\r\n\t\t\t\r\n\t\t\r\n\t) : (\r\n\t\t\r\n\t)\r\n}\r\n","import type * as ApiHubSpot from './types'\r\n\r\nimport { apiRTK } from '../api-rtk'\r\n\r\nexport const hubSpotApi = apiRTK.injectEndpoints({\r\n\tendpoints: create => ({\r\n\t\toptions: create.query({\r\n\t\t\tquery: fieldName => ({\r\n\t\t\t\turl: `integrations/hubspot/contacts/properties/${fieldName}/options`\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\tsettings: create.query({\r\n\t\t\tquery: id => ({\r\n\t\t\t\turl: `campaigns/${id}/settings/hubspot`\r\n\t\t\t})\r\n\t\t}),\r\n\r\n\t\tupdateSettings: create.mutation<\r\n\t\t\tApiHubSpot.Settings,\r\n\t\t\tApiHubSpot.UpdateSettingsBody\r\n\t\t>({\r\n\t\t\tonQueryStarted({ id, ...patch }, { dispatch, queryFulfilled }) {\r\n\t\t\t\tconst patchResult = dispatch(\r\n\t\t\t\t\thubSpotApi.util.updateQueryData('settings', id, draft =>\r\n\t\t\t\t\t\tObject.assign(draft, patch)\r\n\t\t\t\t\t)\r\n\t\t\t\t)\r\n\r\n\t\t\t\tqueryFulfilled.catch(patchResult.undo)\r\n\t\t\t},\r\n\r\n\t\t\tquery: ({ id, ...data }) => ({\r\n\t\t\t\tdata,\r\n\t\t\t\tmethod: 'PUT',\r\n\t\t\t\turl: `campaigns/${id}/settings/hubspot`\r\n\t\t\t})\r\n\t\t})\r\n\t}),\r\n\toverrideExisting: true\r\n})\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"title\":\"title-XxP3z3\",\"root\":\"root-x2nRd7\",\"dropdown\":\"dropdown-DdlHoo\",\"label\":\"label-vTEn48\",\"buttons\":\"buttons-f7xgT2\",\"button\":\"button-uE0rVR\",\"alt\":\"alt-gmvazp\",\"wrapper\":\"wrapper-C1djRh\"};","import type { ApiHubSpot } from '../../../api/hubspot'\r\n\r\ninterface Values {\r\n\tlead: ApiHubSpot.Options[]\r\n\tsub?: ApiHubSpot.Options\r\n}\r\n\r\nfunction isSameArray(firsts: El[], seconds: El[]) {\r\n\tif (firsts.length !== seconds.length) {\r\n\t\treturn false\r\n\t}\r\n\r\n\treturn firsts.length === 0 || firsts.every((el, i) => el === seconds[i])\r\n}\r\n\r\nconst isSame = (updated: Values, old: Values) =>\r\n\tupdated.sub === old.sub && isSameArray(updated.lead, old.lead)\r\n\r\nfunction adaptToServer({ lead, sub }: Values): ApiHubSpot.StaticField[] {\r\n\tconst fields: ApiHubSpot.StaticField[] = []\r\n\r\n\tfields.push({\r\n\t\tkey: 'lead_source',\r\n\t\tvalues: lead.map(el => el.value)\r\n\t})\r\n\r\n\tif (sub) {\r\n\t\tfields.push({\r\n\t\t\tkey: 'contact_sub_source',\r\n\t\t\tvalues: [sub.value]\r\n\t\t})\r\n\t}\r\n\r\n\treturn fields\r\n}\r\n\r\nfunction adaptToState(\r\n\tfields: ApiHubSpot.StaticField[],\r\n\tsources: ApiHubSpot.Options[],\r\n\tsubSources: ApiHubSpot.Options[]\r\n): Values {\r\n\tconst lead = fields.find(field => field.key === 'lead_source')?.values ?? []\r\n\tconst sub =\r\n\t\tfields.find(field => field.key === 'contact_sub_source')?.values[0] ?? ''\r\n\r\n\treturn {\r\n\t\tlead: lead.flatMap(el => sources.find(item => item.value === el) ?? []),\r\n\t\tsub: subSources.find(el => el.value === sub)\r\n\t}\r\n}\r\n\r\nexport { adaptToServer, adaptToState, isSame }\r\n\r\nexport type { Values }\r\n","import clsx from 'clsx'\r\nimport { campaignApi } from 'features/campaigns'\r\nimport {\r\n\ttype FormEventHandler,\r\n\tuseEffect,\r\n\tuseId,\r\n\tuseMemo,\r\n\tuseRef,\r\n\tuseState\r\n} from 'react'\r\nimport { Link, useHistory, useParams } from 'react-router-dom'\r\nimport Select, { type MultiValue, type SingleValue } from 'react-select'\r\n\r\nimport type { ApiHubSpot } from '../../../api/hubspot'\r\n\r\nimport { hubSpotApi } from '../../../api/hubspot/api.ts'\r\nimport { FullLoader } from '../../atoms/FullLoader/FullLoader'\r\nimport { ResponsiveButton } from '../../atoms/responsiveButton'\r\nimport css from './CampaignsHubspot.module.scss'\r\nimport { adaptToServer, adaptToState, isSame, type Values } from './utils'\r\n\r\nconst INITIAL: Values = {\r\n\tlead: [],\r\n\tsub: undefined\r\n}\r\n\r\nexport function CampaignsHubspot() {\r\n\tconst sourceId = useId()\r\n\tconst subSourceId = useId()\r\n\r\n\tconst { id = '' } = useParams<{ id?: string }>()\r\n\tconst { push } = useHistory()\r\n\r\n\tconst campaignQuery = campaignApi.useGetByIdQuery(id, {\r\n\t\tskip: !id\r\n\t})\r\n\r\n\tconst optionsQuery = hubSpotApi.useOptionsQuery('lead_source')\r\n\tconst subOptionsQuery = hubSpotApi.useOptionsQuery('contact_sub_source')\r\n\tconst settingsQuery = hubSpotApi.useSettingsQuery(id)\r\n\tconst [update, updateOptions] = hubSpotApi.useUpdateSettingsMutation()\r\n\r\n\tconst sourceOptions = optionsQuery.data ?? INITIAL.lead\r\n\tconst subSourceOptions = subOptionsQuery.data ?? INITIAL.lead\r\n\tconst [lead, setLead] = useState(INITIAL.lead)\r\n\tconst campaignName = campaignQuery.data?.name ?? ''\r\n\tconst [sub, setSub] = useState(INITIAL.sub)\r\n\r\n\tconst initial = useRef(INITIAL)\r\n\r\n\tconst isInitialValues = useMemo(\r\n\t\t() => isSame({ lead, sub }, initial.current),\r\n\t\t[sub, lead]\r\n\t)\r\n\r\n\tuseEffect(() => {\r\n\t\tif (settingsQuery.data && sourceOptions.length && subSourceOptions.length) {\r\n\t\t\tconst fields = settingsQuery.data.static_fields\r\n\r\n\t\t\tinitial.current = adaptToState(fields, sourceOptions, subSourceOptions)\r\n\t\t\tsetLead(initial.current.lead)\r\n\t\t\tsetSub(initial.current.sub)\r\n\t\t}\r\n\t}, [sourceOptions, subSourceOptions, settingsQuery.data])\r\n\r\n\tconst backLink = `/campaigns/${id}`\r\n\r\n\tconst sendForm: FormEventHandler = event => {\r\n\t\tevent.preventDefault()\r\n\r\n\t\tupdate({\r\n\t\t\tid,\r\n\t\t\tstatic_fields: adaptToServer({ lead, sub })\r\n\t\t})\r\n\t\t\t.unwrap()\r\n\t\t\t.catch(console.error)\r\n\t\t\t.then(() => push(backLink))\r\n\t}\r\n\r\n\tconst isLoading =\r\n\t\tsettingsQuery.isLoading ||\r\n\t\toptionsQuery.isLoading ||\r\n\t\tsubOptionsQuery.isLoading\r\n\r\n\treturn isLoading ? (\r\n\t\t\r\n\t) : (\r\n\t\t
    \r\n\t\t\t
    {campaignName}
    \r\n\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t\t\t\t\r\n\t\t\t\t\t) => void\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\toptions={sourceOptions}\r\n\t\t\t\t\t\tplaceholder='Select...'\r\n\t\t\t\t\t\tvalue={lead}\r\n\t\t\t\t\t/>\r\n\t\t\t\t
    \r\n\r\n\t\t\t\t
    \r\n\t\t\t\t\t\r\n\t\t\t\t\t) => void\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\toptions={subSourceOptions}\r\n\t\t\t\t\t\tplaceholder='Select...'\r\n\t\t\t\t\t\tvalue={sub}\r\n\t\t\t\t\t/>\r\n\t\t\t\t
    \r\n\r\n\t\t\t\t
    \r\n\t\t\t\t\t\r\n\t\t\t\t\t\tCancel\r\n\t\t\t\t\t\r\n\r\n\t\t\t\t\t\r\n\t\t\t\t\t\tSave\r\n\t\t\t\t\t\r\n\t\t\t\t
    \r\n\t\t\t
    \r\n\t\t
    \r\n\t)\r\n}\r\n","import { CampaignsHubspot } from '../../components/organisms/Hubspot'\r\nimport { HomeTemplate } from '../../components/templates/homeTemplate'\r\n\r\nexport function CampaignsHubspotPage() {\r\n\treturn (\r\n\t\t\r\n\t\t\t\r\n\t\t\r\n\t)\r\n\r\n\t// \r\n}\r\n","import imageDog from '../../../assets/image/snail-looking-for.png'\r\nimport ButtonCreateCampaigns from '../../atoms/buttonCreateCampaigns'\r\nimport css from './NoCampaignsYetTemplate.module.scss'\r\nexport function NoCampaignsYetTemplate() {\r\n\treturn (\r\n\t\t
    \r\n\t\t\tReady to start?\r\n\t\t\tsnail\r\n\t\t\t

    \r\n\t\t\t\tNo campaigns yet.
    \r\n\t\t\t\tCreate your first campaign to get more leads on LinkedIn\r\n\t\t\t

    \r\n\t\t\t\r\n\t\t
    \r\n\t)\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"yellow\":\"yellow-PfhNoM\",\"body\":\"body-siEGue\",\"pic\":\"pic-Xu6kHp\"};","export const pauseReason = {\n exceed: {\n code: \"ExceedFreeMonthlyPersonalizedInvitations\",\n tipId: \"n4.1\",\n },\n tooLong: {\n code: \"TooLongInvitationMessage\",\n tipId: \"n4.2\",\n },\n};\n","import \"./style.scss\";\nimport arrow from \"../../../assets/image/icons/svg/arrow-left.svg\";\nimport fragment from \"../../../assets/image/icons/svg/fragment.svg\";\n\nconst InformationalTip = ({\n data,\n onClose,\n arrowPosition,\n centered,\n maxWidth,\n}) => {\n return (\n
    \n \n

    \n {data.title}\n

    \n
      \n {data.content.map((item, i) => (\n \n ))}\n
    \n {data.more && (\n onClose(false)}\n >\n More\n \"arrow\"\n \n )}\n
    \n );\n};\n\nexport default InformationalTip;\n","import lock from \"../../../assets/image/icons/svg/lock.svg\";\n\n// Style\nimport \"./style.scss\";\nimport { CONSTS } from \"../../../config/objectConst\";\n\nimport InformationalTip from \"../InformationalTip\";\nimport { pauseReason } from \"../../../api/pauseReason\";\n\nexport const buildStatus = ({\n id,\n pauseReasonStatus,\n status,\n campaignIdWithTip,\n onClick,\n}) => {\n switch (status) {\n case \"Running\":\n return
    active
    ;\n case \"Stopped\":\n return (\n
    \n paused{\" \"}\n
    \n {(pauseReasonStatus === pauseReason.exceed.code ||\n pauseReasonStatus === pauseReason.tooLong.code) && (\n onClick(id)}\n />\n )}\n {campaignIdWithTip === id && (\n () => undefined}\n data={\n CONSTS.TIPS[\n Object.values(pauseReason).find(\n (item) => item.code === pauseReasonStatus\n ).tipId\n ]\n }\n />\n )}\n
    \n
    \n );\n case \"Completed\":\n return
    completed
    ;\n case \"Compose\":\n return
    draft
    ;\n\n default:\n break;\n }\n};\n","import React, { Component } from \"react\";\nimport { withRouter } from \"react-router-dom\";\nimport Table from \"@mui/material/Table\";\nimport TableBody from \"@mui/material/TableBody\";\nimport TableCell from \"@mui/material/TableCell\";\nimport TableContainer from \"@mui/material/TableContainer\";\nimport TableHead from \"@mui/material/TableHead\";\nimport TableRow from \"@mui/material/TableRow\";\nimport { functions, saveData } from \"../../../tools/functions\";\nimport TooltipCustom from \"../../atoms/tooltipCustom\";\nimport Checkbox from \"@mui/material/Checkbox\";\n// actions\nimport { campaign } from \"../../../actions/campaign\";\nimport { app } from \"../../../actions/app\";\n// Components\nimport CircularProgress from \"@mui/material/CircularProgress\";\nimport { PaginationWrapper } from \"components/atoms/mTablePagination/PaginationWrapper\";\n\n// Icons\nimport selectedCheckboxIcon from \"../../../assets/image/icons/tables/checkbox2.svg\";\nimport partiallySelectedCheckboxIcon from \"../../../assets/image/icons/tables/checkbox3.svg\";\nimport notSelectedCheckboxIcon from \"../../../assets/image/icons/tables/checkbox.svg\";\nimport iconArch from \"../../../assets/image/icons/svg/icons/arch.svg\";\nimport iconClone from \"../../../assets/image/icons/svg/icons/clone.svg\";\nimport iconStart from \"../../../assets/image/icons/svg/icons/start.svg\";\nimport iconPause from \"../../../assets/image/icons/svg/icons/pause.svg\";\nimport iconStop from \"../../../assets/image/icons/svg/icons/stop.svg\";\n\n// Style\nimport \"./style.scss\";\nimport { CONSTS } from \"../../../config/objectConst\";\nimport HintTooltip from \"../../atoms/HintTooltip\";\nimport ModalWindow from \"../ModalWindow\";\nimport { apiCampaign } from \"../../../api/campaign/apiCampaign\";\nimport ConfirmationDialog from \"../../atoms/ConfirmationDialog\";\nimport { filters } from \"../../../actions/filters\";\nimport ExportToCSVButton from \"../../atoms/ExportToCSVButton\";\nimport { pauseReason } from \"../../../api/pauseReason\";\nimport { buildStatus } from \"../buildStatusCampaign\";\nimport clsx from \"clsx\";\nimport { mapping } from \"actions/mapping\";\nimport { connect } from \"react-redux\";\nimport { campaignsSelectors } from \"../../../redux/reducers/campaigns\";\nimport { CampaignsUI } from \"features/campaigns\";\nimport { notifyError } from \"shared/errors\";\nimport { appConnector } from \"shared/connector\";\n\nexport class PersonalCampaignsStatistics extends Component {\n constructor(props) {\n super(props);\n\n this.state = {\n isIconActive: {\n name: true,\n started: false,\n acceptance_rate: true,\n invitation_sent: true,\n messages_sent: true,\n reply_rate: true,\n started_count: true,\n },\n isLoadingCSV: false,\n campaignsOnPage: [],\n selected: [],\n rows: [],\n campaignIdWithTip: \"\",\n rowsPerPage: CONSTS.PAGE_SIZE,\n filterRows: [],\n paginationLabel: \"\",\n modalData: null,\n confirmationDialog: {\n id: null,\n status: false,\n data: {},\n },\n selectAllCampaignsValue: false,\n selectedValues: 0,\n rowData: {\n id: null,\n name: \"\",\n },\n scrollBarWidth: false,\n };\n this.wrapper = React.createRef();\n }\n\n componentDidMount() {\n appConnector.eventHandlers.addAutomationEndedEventHandler(async () => {\n campaign.getRecentCampaigns();\n\n await filters.getCampaigns({\n archived: false,\n skip:\n this.props.tableCampaignsStatisticsPage > 0\n ? this.props.tableCampaignsStatisticsPage * CONSTS.PAGE_SIZE\n : 0,\n filter: this.props.filterQuery,\n keywords: this.props.searchValue,\n orderby: this.props.orderby,\n });\n });\n\n this.getCampaignsBySort();\n window.addEventListener(\"resize\", this.handleResize);\n this.handleResize();\n }\n\n componentWillUnmount() {\n appConnector.eventHandlers.removeAutomationEndedEventHandlers();\n window.removeEventListener(\"resize\", this.handleResize);\n }\n\n componentDidUpdate(prevProps, prevState) {\n if (this.props.orderby !== prevProps?.orderby) {\n this.getCampaignsBySort();\n }\n this.handleResize();\n }\n\n onSelectAllClick = () => {\n const newSelecteds = this.props.campaigns.map((item) => item.id);\n this.setState({\n selected: newSelecteds,\n selectedValues: this.props.campaignsCount,\n selectAllCampaignsValue: true,\n });\n };\n\n onClearAllClick = () => {\n this.setState({\n selected: [],\n selectedValues: 0,\n selectAllCampaignsValue: false,\n });\n };\n\n handleClick = (event, name) => {\n const selectedIndex = this.state.selected.indexOf(name);\n let newSelected = [];\n\n if (selectedIndex === -1) {\n newSelected = newSelected.concat(this.state.selected, name);\n } else if (selectedIndex === 0) {\n this.setState({\n selectAllCampaignsValue: false,\n });\n newSelected = newSelected.concat(this.state.selected.slice(1));\n } else if (selectedIndex === this.state.selected.length - 1) {\n this.setState({\n selectAllCampaignsValue: false,\n });\n newSelected = newSelected.concat(this.state.selected.slice(0, -1));\n } else if (selectedIndex > 0) {\n this.setState({\n selectAllCampaignsValue: false,\n });\n newSelected = newSelected.concat(\n this.state.selected.slice(0, selectedIndex),\n this.state.selected.slice(selectedIndex + 1)\n );\n }\n this.setState({\n selected: newSelected,\n selectedValues: newSelected.length,\n });\n };\n\n handleResize = () => {\n const scrollbarWidth =\n this.wrapper.current.offsetWidth - this.wrapper.current.clientWidth;\n\n if (scrollbarWidth > 0 && this.state.scrollBarWidth === false) {\n this.setState({ scrollBarWidth: true });\n }\n\n if (scrollbarWidth === 0 && this.state.scrollBarWidth === true) {\n this.setState({ scrollBarWidth: false });\n }\n };\n\n isSelected = (name) => this.state.selected.indexOf(name) !== -1;\n\n getCampaignsBySort = async (newPage) => {\n app.changeTableContentLoaderStatus(true);\n\n await filters.getCampaigns({\n skip:\n this.props.tableCampaignsStatisticsPage > 0\n ? this.props.tableCampaignsStatisticsPage * CONSTS.PAGE_SIZE\n : 0,\n archived: false,\n filter: this.props.filterQuery,\n orderby: this.props.orderby,\n\n keywords: this.props.searchValue,\n });\n\n app.changeTableContentLoaderStatus(false);\n };\n\n handleChangePage = async (event, newPage) => {\n app.changeTableContentLoaderStatus(true);\n\n await filters.getCampaigns({\n skip: newPage > 0 ? newPage * CONSTS.PAGE_SIZE : 0,\n archived: false,\n filter: this.props.filterQuery,\n keywords: this.props.searchValue,\n orderby: this.props.orderby,\n });\n this.props.setTableCampaignsStatisticsPage(newPage);\n app.changeTableContentLoaderStatus(false);\n };\n\n setActiveFilterIcon(key, value) {\n this.setState({\n isIconActive: {\n ...{\n name: true,\n started: true,\n acceptance_rate: true,\n invitation_sent: true,\n messages_sent: true,\n reply_rate: true,\n started_count: true,\n },\n [key]: value,\n },\n });\n }\n\n onClickCampaign = (id) => {\n this.props.history.push(`/campaigns/${id}`);\n };\n\n onClickStatus = (id) => {\n this.setState({\n campaignIdWithTip: id,\n });\n };\n\n addToArchive = async (id) => {\n app.changeTableContentLoaderStatus(true);\n\n await campaign.addCampaignToArchive(\n id,\n\n this.props.searchValue,\n this.props.tableCampaignsStatisticsPage,\n this.props.orderby\n );\n this.setState({\n selected: this.state.selected.filter((item) => item !== id),\n selectedValues: this.state.selectedValues - 1,\n });\n };\n\n onSelectAllPageClick = (event) => {\n this.setState({\n selectAllCampaignsValue: false,\n selectedValues:\n this.props.campaignsCount <= this.props.campaigns.length\n ? this.props.campaignsCount\n : this.props.campaigns.length,\n });\n\n if (event.target.checked) {\n let newSelected = this.props.campaigns;\n newSelected = newSelected.filter(\n (item) => !this.state.selected.includes(item)\n );\n\n this.setState({\n selected: this.state.selected.concat(newSelected).map((item, index) => {\n return item.id;\n }),\n });\n return;\n }\n\n this.setState({\n selected: [],\n selectedValues: 0,\n });\n };\n\n exportCampaigns = async () => {\n const selectAllFilter = this.props.filterQuery;\n const selectId = this.state.selected;\n try {\n this.setState({ isLoadingCSV: true });\n const response = await apiCampaign.exportCampaignsApi({\n filter: this.state.selectAllCampaignsValue\n ? selectAllFilter\n : `id in (${selectId.map((item) => `'${item}'`)})`,\n orderby: this.props.orderby,\n archived: false,\n searchValue: this.state.selectAllCampaignsValue\n ? this.props.searchValue\n : \"\",\n });\n if (response.status === 200) {\n const data = response.data,\n fileName = functions.getFileName();\n saveData(data, fileName);\n }\n } catch (error) {\n notifyError(error);\n }\n this.setState({\n selected: [],\n });\n this.setState({ isLoadingCSV: false });\n };\n\n stopCampaign = (e, events, id) => {\n e.stopPropagation();\n\n events.stop.enabled &&\n campaign.stopCampaign(id, {\n page: this.props.tableCampaignsStatisticsPage,\n\n searchValue: this.props.searchValue,\n orderby: this.props.orderby,\n });\n };\n completeCampaign = (e, events, id) => {\n e.stopPropagation();\n events.complete.enabled &&\n this.setState({\n modalData: { type: \"1.2\", id, events },\n });\n };\n\n cloneCampaign = (e, events, id) => {\n e.stopPropagation();\n events.clone.enabled &&\n this.setState({\n modalData: { type: \"1.10\", id, events },\n });\n };\n\n archiveCampaign = (e, events, id) => {\n e.stopPropagation();\n events.archive.enabled &&\n this.setState({\n modalData: { type: \"1.7\", id, events },\n });\n };\n unArchiveCampaign = (e, events, id) => {\n e.stopPropagation();\n events.unarchive.enabled && this.removeFromArchive(id);\n };\n\n runCampaign = (e, events, id, status) => {\n e.stopPropagation();\n events.run.enabled && this.startHandler(id, events, status);\n };\n\n removeFromArchive = (id) => {\n app.changeTableContentLoaderStatus(true);\n campaign.removeCampaignFromArchive(\n id,\n this.props.searchValue,\n this.props.tableCampaignsStatisticsPage,\n this.props.orderby\n );\n };\n\n cloneHandler = async (campaignId) => {\n const response = await campaign.cloneCampaign(campaignId);\n if (response) {\n this.props.history.push(`/campaigns/${response.id}/tune`);\n }\n };\n\n actionHandler = ({ type, id, events, status }) => {\n try {\n switch (type) {\n case \"1.2\":\n events.complete.enabled &&\n campaign.completeCampaign(id, {\n page: this.props.tableCampaignsStatisticsPage,\n\n searchValue: this.props.searchValue,\n orderby: this.props.orderby,\n });\n break;\n\n case \"1.5\":\n events.run.enabled &&\n campaign.startCampaign(id, status, {\n page: this.props.tableCampaignsStatisticsPage,\n\n searchValue: this.props.searchValue,\n orderby: this.props.orderby,\n });\n break;\n\n case \"1.7\":\n events.archive.enabled && this.addToArchive(id);\n break;\n\n case \"1.10\":\n events.clone.enabled && this.cloneHandler(id);\n break;\n default:\n break;\n }\n } finally {\n this.setState({ modalData: null });\n }\n };\n\n startHandler = async (id, events, status) => {\n try {\n if (status === \"Stopped\") {\n return await campaign.startCampaign(id, status, {\n page: this.props.tableCampaignsStatisticsPage,\n\n searchValue: this.props.searchValue,\n orderby: this.props.orderby,\n });\n }\n\n app.changeTableContentLoaderStatus(true);\n const preview = await apiCampaign.getPreviewOfStartupCampaing(id);\n\n if (!preview.data.validation_rules_summary.length) {\n this.setState({\n modalData: {\n type: \"1.5\",\n id,\n events,\n status,\n data: preview.data,\n },\n });\n } else {\n this.setState({\n confirmationDialog: {\n id,\n status: true,\n data: preview.data,\n },\n modalData: {\n type: \"1.5\",\n id,\n events,\n status,\n data: preview.data,\n },\n });\n }\n } catch (error) {\n notifyError(error);\n } finally {\n app.changeTableContentLoaderStatus(false);\n }\n };\n\n buttonsActions = (id, status, events, date) => {\n return (\n \n <>\n \n {\n this.runCampaign(e, events, id, status);\n }}\n >\n \"iconStart\"\n \n \n\n \n {\n this.stopCampaign(e, events, id);\n }}\n >\n \"iconStop\"\n \n \n\n \n {\n this.completeCampaign(e, events, id);\n }}\n >\n \"iconPause\"\n \n \n\n \n {\n this.cloneCampaign(e, events, id);\n }}\n >\n \"clone\"\n \n \n\n \n {\n this.archiveCampaign(e, events, id);\n }}\n >\n \"archive\"\n \n \n \n \n );\n };\n\n render() {\n const getDataClientWidth = (row) =>\n (row?.name?.length > 30 &&\n document.documentElement.clientWidth > 1000 &&\n document.documentElement.clientWidth < 1537) ||\n (row?.name?.length > 45 &&\n document.documentElement.clientWidth > 1537 &&\n document.documentElement.clientWidth < 1746);\n\n return (\n this.state.rowsPerPage\n ? \"table-with-footer\"\n : \"\"\n }`}\n >\n {this.state.campaignIdWithTip && (\n \n this.setState({\n campaignIdWithTip: \"\",\n })\n }\n />\n )}\n
    \n \n {this.props.app.tableContentLoader &&\n !this.props.app.pageContentLoader && (\n
    \n \n
    \n )}\n \n \n \n \n
    \n \n this.props.campaigns.includes(item)\n ).length\n }\n checked={this.state.selected.length > 0}\n onChange={this.onSelectAllPageClick}\n inputProps={{ \"aria-label\": \"select all desserts\" }}\n indeterminateIcon={\n \"checkbox\"\n }\n icon={\n \"checkbox\"\n }\n checkedIcon={\n \n this.state.selectedValues\n ? partiallySelectedCheckboxIcon\n : selectedCheckboxIcon\n }\n alt=\"checkbox\"\n />\n }\n />\n
    \n
    \n \n {this.state.selected.length > 0 ? (\n
    \n <>\n {this.state.selectedValues > 0 && (\n
    \n \n {this.state.selectedValues} of{\" \"}\n {this.props.campaignsCount} selected |{\" \"}\n \n {!this.state.selectAllCampaignsValue && (\n \n Select all\n \n )}\n\n {this.state.selectAllCampaignsValue && (\n \n Clear\n \n )}\n
    \n )}\n
    \n {\n this.exportCampaigns();\n }}\n text=\"Export to CSV\"\n >\n
    \n \n
    \n ) : (\n \"Campaign\"\n )}\n \n \n Status\n \n \n Invites sent\n \n \n Acceptance rate\n \n \n Messages sent\n \n \n Reply rate\n \n \n \n Created\n
    \n \n \n \n this.state.rowsPerPage\n ? \"table-with-footer\"\n : \"table-with-out-footer\"\n }`}\n >\n {this.props.campaigns.map((row, index) => (\n \n \n
    \n this.handleClick(event, row.id)}\n checked={this.isSelected(row.id)}\n inputProps={{\n \"aria-labelledby\": `enhanced-table-checkbox-${index}`,\n }}\n icon={\n \"checkbox\"\n }\n checkedIcon={\n \"checkbox\"\n }\n />\n
    \n
    \n\n this.onClickCampaign(row.id)}\n style={{ width: \"28%\" }}\n scope=\"row\"\n className=\"name semi-bold title-company\"\n >\n
    \n
    \n \n \n {row.name}\n

    \n \n\n \n
    \n
    \n \n {\n row.pause_reason !== pauseReason.exceed.code &&\n row.pause_reason !== pauseReason.tooLong.code &&\n this.onClickCampaign(row.id);\n }}\n className=\"contacts flex-container\"\n style={{ width: \"10%\" }}\n >\n {buildStatus({\n id: row.id,\n pauseReasonStatus: row.pause_reason,\n status: row.status,\n campaignIdWithTip: this.state.campaignIdWithTip,\n onClick: this.onClickStatus,\n })}\n \n this.onClickCampaign(row.id)}\n className=\"contacts text-accent\"\n style={{ width: \"10%\" }}\n >\n {row.statistics.invitation_sent}\n \n this.onClickCampaign(row.id)}\n className=\"contacts\"\n style={{ width: \"10%\" }}\n >\n
    \n
    \n {row.statistics.acceptance_rate\n ? functions\n .roundToDecimal(row.statistics.acceptance_rate)\n .toString() + \"%\"\n : \"...\"}\n
    \n
    \n \n this.onClickCampaign(row.id)}\n className=\"contacts text-accent\"\n style={{ width: \"10%\" }}\n >\n {row.statistics.messages_sent}\n \n\n \n \n this.onClickCampaign(row.id)}\n className={`contacts text-accent ${\n this.state.scrollBarWidth\n ? \"width-with_scroll-percent\"\n : \"width-with-out_scroll-percent\"\n }`}\n >\n {row.statistics.reply_rate !== null\n ? functions\n .roundToDecimal(row.statistics.reply_rate)\n .toString() + \"%\"\n : \"...\"}\n \n this.onClickCampaign(row.id)}\n className={\n this.state.scrollBarWidth\n ? \"width-with_scroll-teams\"\n : \"width-with-out_scroll-teams\"\n }\n >\n
    \n {`${\n row.created\n ? functions.parseDateToDMY(row.created, \"/\")\n : \"...\"\n }`}\n
    \n \n
    \n {this.buttonsActions(\n row.id,\n row.status,\n row.events,\n row.date\n )}\n
    \n \n \n
    \n ))}\n \n \n \n {\n localStorage.setItem(\"2.6\", \"true\");\n }}\n />\n \n {this.props.campaignsCount > this.state.rowsPerPage && (\n this.state.rowsPerPage\n ? \"table-footer-accent\"\n : \"table-footer\"\n }\n >\n \n \n )}\n this.setState({ modalData: null })}\n confirmHandler={() => this.actionHandler(this.state.modalData)}\n title={\n this.state?.modalData\n ? CONSTS.confirmationDialogs[this.state.modalData?.type].title\n : \"\"\n }\n content={\n this.state.modalData\n ? CONSTS.confirmationDialogs[\n this.state.modalData?.type\n ].content.replace(\n \"{contacts_count}\",\n this.state.modalData?.data?.valid_audience_count\n )\n : \"\"\n }\n />\n\n \n this.setState({\n confirmationDialog: { id: null, status: false, data: {} },\n modalData: null,\n })\n }\n classes={\"confirmation-launch-modal\"}\n >\n \n this.setState({\n confirmationDialog: { id: null, status: false, data: {} },\n modalData: null,\n })\n }\n startCampaign={() => {\n this.actionHandler(this.state.modalData);\n }}\n />\n \n \n );\n }\n}\n\nconst mapStateToProps = function (state) {\n return {\n app: state.app,\n campaigns: mapping.campaignsForTable(state.campaigns.campaigns),\n campaignsCount: state.campaigns.campaignsCount,\n searchValue: state.campaigns.searchValue,\n filterQuery: campaignsSelectors.filterQuery(state),\n };\n};\n\nexport default connect(mapStateToProps)(\n withRouter(PersonalCampaignsStatistics)\n);\n","import CircularProgress from '@mui/material/CircularProgress'\r\nimport { CampaignFilters } from 'components/molecules/CampaignFilters/index.tsx'\r\nimport { NoCampaignsYetTemplate } from 'components/templates/noCampaignsYetTemplate/index.tsx'\r\nimport { NoFilterCampaignResult } from 'components/templates/NoSearchResult'\r\nimport { useState } from 'react'\r\nimport { appSelectors } from 'redux/reducers/app.ts'\r\nimport { useAppSelector } from 'shared/hooks/store.ts'\r\nimport { useMount, useUnMount } from 'shared/hooks/useMount.ts'\r\n\r\n// Actions\r\nimport { app } from '../../actions/app.js'\r\nimport { campaign } from '../../actions/campaign.js'\r\nimport { filters } from '../../actions/filters.js'\r\nimport { LinkedInNotLogged } from '../../components/molecules/linkedInNotLogged/LinkedInNotLogged.tsx'\r\nimport PersonalCampaignsStatistics from '../../components/molecules/personalCampaignsStatistics/index.js'\r\n// Components\r\nimport { HomeTemplate } from '../../components/templates/homeTemplate'\r\nimport { campaignsSelectors } from '../../redux/reducers/campaigns.ts'\r\n\r\nexport function CampaignsPage() {\r\n\tconst [campaignsLoading, setCampaignsLoading] = useState(false)\r\n\r\n\tconst [orderby] = useState('created desc')\r\n\r\n\tconst [page, setPage] = useState(0)\r\n\r\n\tconst campaigns = useAppSelector(state => state.campaigns.campaigns),\r\n\t\tconnector = useAppSelector(appSelectors.connector),\r\n\t\terror = useAppSelector(state => state.app.errorRequest.campaigns),\r\n\t\tfilterQuery = useAppSelector(campaignsSelectors.filterQuery),\r\n\t\thaveCampaigns = useAppSelector(state => state.campaigns.haveCampaigns),\r\n\t\tisSearchOrFilterApplied = useAppSelector(\r\n\t\t\tcampaignsSelectors.isFilterOrSearchActive\r\n\t\t),\r\n\t\tleftSide = useAppSelector(state => state.leftSideMenu.leftSide),\r\n\t\tpageContentLoader = useAppSelector(state => state.app.pageContentLoader),\r\n\t\tsearchValue = useAppSelector(state => state.campaigns.searchValue)\r\n\r\n\tuseMount(() => {\r\n\t\tfirstLoad()\r\n\t})\r\n\r\n\tasync function firstLoad() {\r\n\t\tapp.changePageContentLoaderStatus(true)\r\n\t\tsetCampaignsLoading(true)\r\n\r\n\t\ttry {\r\n\t\t\tfilters.clearAllFilters(true)\r\n\t\t\tfilters.changeFilterQuery('', false)\r\n\t\t\tapp.changePage('/campaigns')\r\n\t\t\tapp.changeActiveItem(1)\r\n\r\n\t\t\t// TODO: Replace fetch campaign to RTK Query\r\n\t\t\tawait filters.getCampaigns({\r\n\t\t\t\tarchived: false,\r\n\t\t\t\tfilter: filterQuery,\r\n\t\t\t\tkeywords: searchValue,\r\n\t\t\t\torderby\r\n\t\t\t})\r\n\r\n\t\t\tawait campaign.getRecentCampaigns()\r\n\t\t} finally {\r\n\t\t\tsetCampaignsLoading(false)\r\n\t\t\tapp.changePageContentLoaderStatus(false)\r\n\t\t}\r\n\t}\r\n\r\n\tuseUnMount(() => {\r\n\t\tconnector.eventHandlers.removeAutomationEndedEventHandlers()\r\n\t})\r\n\r\n\tconst hasLeftItems = Boolean(leftSide.list?.length)\r\n\r\n\treturn (\r\n\t\t\r\n\t\t\t\r\n\t\t\t{(pageContentLoader || campaignsLoading) && (\r\n\t\t\t\t
    \r\n\t\t\t\t\t\r\n\t\t\t\t
    \r\n\t\t\t)}\r\n\r\n\t\t\t{!haveCampaigns && !error && !hasLeftItems ? (\r\n\t\t\t\t\r\n\t\t\t) : (\r\n\t\t\t\t<>\r\n\t\t\t\t\t{/**/}\r\n\t\t\t\t\t\r\n\r\n\t\t\t\t\t{campaigns.length === 0 && !error && isSearchOrFilterApplied ? (\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t) : (\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t)}\r\n\t\t\t\t\r\n\t\t\t)}\r\n\t\t
    \r\n\t)\r\n}\r\n\r\nexport default CampaignsPage\r\n","import { useState } from \"react\";\nimport { connect } from \"react-redux\";\nimport { withRouter } from \"react-router-dom\";\nimport { ResponsiveButton } from \"../responsiveButton/index.tsx\";\n// actions\nimport { campaign } from \"../../../actions/campaign\";\nimport { contacts } from \"../../../actions/contacts\";\nimport { app } from \"../../../actions/app\";\nimport { filters } from \"../../../actions/filters\";\nimport { apiCampaign } from \"../../../api/campaign/apiCampaign\";\nimport ModalWindow from \"../../molecules/ModalWindow\";\nimport ConfirmationDialogRunning from \"../ConfirmationDialogRunning\";\nimport { contactsPageSize } from \"../../../api/contactsPageSize\";\nimport { useActionCreators } from \"../../../shared/hooks/index\";\nimport { appActions } from \"../../../redux/reducers/app\";\n\nconst ButtonAddToCampaigns = (props) => {\n const { contactsCount, contacts: selectedContacts } = props;\n const [confirmationDialog, setConfirmationDialog] = useState({\n id: null,\n status: false,\n data: {},\n });\n const [needLoader, setNeedLoader] = useState(false);\n const { changePageModalLoader } = useActionCreators(appActions);\n\n const refreshContacts = async () => {\n changePageModalLoader(true);\n const pageSize = contactsPageSize.get();\n let newPage =\n props.page * pageSize >= contactsCount - pageSize &&\n props.page * pageSize === contactsCount - selectedContacts.length\n ? props.page - 1\n : props.page;\n newPage = newPage >= 0 ? newPage : 0;\n props.setPage(newPage);\n\n await props.getContacts({\n skip: newPage * pageSize,\n filter: props.filters.filtersQueryForModal\n ? props.filters.filtersQueryForModal\n : `not (campaigns/any(c:c eq '${props.campaign.id}'))`,\n keywords: props.keywordsForModal ? props.keywordsForModal : \"\",\n });\n\n if (\n props.from === \"single-contacts\" &&\n (props.campaign.information?.[0].value === \"Running\" ||\n props.campaign.information?.[0].value === \"Stopped\" ||\n props.campaign.information?.[0].value === \"Completed\")\n ) {\n await contacts.getContacts({\n skip: props.contactsPage * pageSize,\n orderby: \"created asc\",\n status: \"Running\",\n filter: `campaign_id eq '${props.campaign.id}'`,\n });\n } else if (props.from === \"single-contacts\") {\n await contacts.getContacts({\n skip: props.contactsPage * pageSize,\n filter: `campaigns/any(c:c eq '${props.campaign.id}')`,\n orderby: \"imported asc\",\n });\n campaign.getCampaignId(props.campaign.id);\n }\n props.setSelectedContacts();\n if (\n props.from === \"campaigns\" &&\n props.campaign.information?.[0].value === \"Compose\"\n ) {\n const filtersArray = props.buildFiltersArray(props.campaignFilters);\n app.changePageContentLoaderStatus(true);\n await filters.getCampaigns({\n archived: false,\n filter: `${filtersArray.join(\" or \")}`,\n keywords: props.searchValue,\n });\n app.changePageContentLoaderStatus(false);\n props.clearCheckboxesFunc();\n }\n if (props.history.location.state?.launchCampaignDialog === true) {\n campaign.openCampaignContacts(props, false);\n }\n changePageModalLoader(false);\n };\n\n const handlerClick = async () => {\n let preview = \"\";\n if (\n props.campaign.information?.[0].value === \"Running\" ||\n props.campaign.information?.[0].value === \"Stopped\" ||\n props.campaign.information?.[0].value === \"Completed\"\n ) {\n setNeedLoader(true);\n preview = await apiCampaign.getPreviewAddTargetAudience({\n id: props.campaign.id,\n filter:\n props.filters.filtersQueryForModal && props.selectAllUsersValue\n ? props.filters.filtersQueryForModal\n : props.selectAllUsersValue\n ? `not (campaigns/any(c:c eq '${props.campaign.id}'))`\n : `id in (${props.contacts.map((item) => `'${item}'`)})`,\n keywords: props.keywordsForModal ? props.keywordsForModal : \"\",\n });\n setNeedLoader(false);\n }\n const campaignId = props.campaign.id;\n const activeImportId = props.match.path.includes(\"contacts/import/\")\n ? this.props.activeImportId\n : \"\";\n const campaignName = props.campaign.name;\n if (\n (props.campaign.information?.[0].value === \"Running\" &&\n preview?.data?.validation_rules_summary?.length === 0) ||\n (props.campaign.information?.[0].value === \"Stopped\" &&\n preview?.data?.validation_rules_summary?.length === 0) ||\n (props.campaign.information?.[0].value === \"Completed\" &&\n preview?.data?.validation_rules_summary?.length === 0) ||\n (preview?.data?.validation_rules_summary?.length === 0 &&\n preview?.data?.valid_audience_count > 0) ||\n props.campaign.information?.[0].value === \"Compose\"\n ) {\n if (props.selectAllUsersValue) {\n campaign.addAllContactsToCampaign(\n props.filters,\n campaignId,\n campaignName,\n props.from,\n activeImportId,\n refreshContacts,\n props.keywordsForModal\n );\n\n return;\n }\n\n await campaign.addContactsToCampaign(\n {\n id: campaignId,\n name: campaignName,\n audience: props.contacts,\n from: props.from,\n running: props.campaign.information?.[0].value !== \"Compose\",\n },\n refreshContacts\n );\n } else {\n return setConfirmationDialog({\n id: campaignId,\n status: true,\n data: preview.data,\n });\n }\n };\n const addContactsToRunningCampaignModal = () => {\n const campaignId = props.campaign.id;\n const activeImportId = props.match.path.includes(\"contacts/import/\")\n ? this.props.activeImportId\n : \"\";\n const campaignName = props.campaign.name;\n if (props.selectAllUsersValue) {\n campaign.addAllContactsToCampaign(\n props.filters,\n campaignId,\n campaignName,\n props.from,\n activeImportId,\n refreshContacts,\n props.keywordsForModal\n );\n\n return;\n }\n\n campaign.addContactsToCampaign(\n {\n id: campaignId,\n name: campaignName,\n audience: props.contacts,\n from: props.from,\n },\n refreshContacts\n );\n };\n return (\n <>\n !props.createCampaignController && handlerClick()}\n isLoading={props.createCampaignController || needLoader}\n disabled={props.disabled}\n >\n {props.text}\n \n \n setConfirmationDialog({ id: null, status: false, data: {} })\n }\n classes={\"confirmation-launch-modal\"}\n >\n \n setConfirmationDialog({ id: null, status: false, data: {} })\n }\n addContacts={addContactsToRunningCampaignModal}\n />\n \n \n );\n};\n\nconst mapStateToProps = function (state) {\n return {\n createCampaignController: state.campaign.createCampaignController,\n campaigns: state.campaigns.campaigns,\n filters: state.filters,\n };\n};\n\nexport default connect(mapStateToProps)(withRouter(ButtonAddToCampaigns));\n","import \"./style.scss\";\n\nimport dogNo from \"./../../../assets/image/snail-no.png\";\nimport dogThinks from \"./../../../assets/image/snail-typing.png\";\n\nconst ConfirmationDialogContacts = ({\n confirmationDialogContacts,\n closeHandler,\n deleted,\n}) => {\n const handlerConfirm = () => {\n closeHandler();\n deleted();\n };\n\n const getConfirmationContent = () => {\n let totalCount = 0;\n\n if (\n confirmationDialogContacts.data.validation_rules_summary.length &&\n confirmationDialogContacts.data.valid_audience_count\n ) {\n return (\n
    \n

    \n Sorry, the system can't delete\n
    some of the contacts\n

    \n
    \n
    \n {confirmationDialogContacts.data.validation_rules_summary.map(\n (item, index) => {\n totalCount += item.count;\n return {`${item.count} contacts:`};\n }\n )}\n
    \n
    \n {confirmationDialogContacts.data.validation_rules_summary.map(\n (item, index) => {\n return {item.description};\n }\n )}\n
    \n
    \n
    \n

    \n The system will delete{\" \"}\n {confirmationDialogContacts.data.valid_audience_count} contacts,\n

    \n

    {totalCount} contacts will be skipped.

    \n

    Would you like to proceed?

    \n
    \n\n
    \n \n Cancel\n \n handlerConfirm(confirmationDialogContacts.id)}\n >\n Confirm\n \n
    \n
    \n );\n }\n\n if (\n confirmationDialogContacts.data.validation_rules_summary.length &&\n !confirmationDialogContacts.data.valid_audience_count\n ) {\n return (\n
    \n

    \n Sorry, the system can't delete
    \n these contacts.\n

    \n
    \n
    \n {confirmationDialogContacts.data.validation_rules_summary.map(\n (item, index) => {\n return
    {`${item.count} contacts:`}
    ;\n }\n )}\n
    \n
    \n {confirmationDialogContacts.data.validation_rules_summary.map(\n (item, index) => {\n return
    {item.description}
    ;\n }\n )}\n
    \n
    \n
    \n

    Please, select other contacts.

    \n
    \n
    \n \n Ok\n \n
    \n
    \n );\n }\n };\n\n const isPositiveAudienceCount =\n confirmationDialogContacts?.data?.validation_rules_summary?.length &&\n confirmationDialogContacts?.data?.valid_audience_count;\n\n return (\n
    \n {getConfirmationContent()}\n \n
    \n );\n};\n\nexport default ConfirmationDialogContacts;\n","import \"./style.scss\";\n\nimport dogNo from \"./../../../assets/image/snail-no.png\";\nimport dogThinks from \"./../../../assets/image/snail-typing.png\";\n\nconst ConfirmationDialogExclude = ({\n confirmationDialog,\n closeHandler,\n exclude,\n}) => {\n const handlerConfirm = () => {\n closeHandler();\n exclude();\n };\n\n const getConfirmationContent = () => {\n let totalCount = 0;\n\n if (\n confirmationDialog.data.validation_rules_summary.length &&\n confirmationDialog.data.valid_audience_count\n ) {\n return (\n
    \n

    \n Sorry, the system can't exclude\n
    some of the contacts\n

    \n
    \n
    \n {confirmationDialog.data.validation_rules_summary.map(\n (item, index) => {\n totalCount += item.count;\n return {`${item.count} contacts:`};\n }\n )}\n
    \n
    \n {confirmationDialog.data.validation_rules_summary.map(\n (item, index) => {\n return {item.description};\n }\n )}\n
    \n
    \n
    \n

    \n The system will exclude{\" \"}\n {confirmationDialog.data.valid_audience_count} contacts,\n

    \n

    {totalCount} will not be excluded.

    \n

    Would you like to proceed?

    \n
    \n\n
    \n \n Cancel\n \n handlerConfirm(confirmationDialog.id)}\n >\n Confirm\n \n
    \n
    \n );\n }\n\n if (\n confirmationDialog.data.validation_rules_summary.length &&\n !confirmationDialog.data.valid_audience_count\n ) {\n return (\n
    \n

    \n Sorry, the system can't exclude
    \n these contacts.\n

    \n
    \n
    \n {confirmationDialog.data.validation_rules_summary.map(\n (item, index) => {\n return
    {`${item.count} contacts:`}
    ;\n }\n )}\n
    \n
    \n {confirmationDialog.data.validation_rules_summary.map(\n (item, index) => {\n return
    {item.description}
    ;\n }\n )}\n
    \n
    \n
    \n

    Please, select other contacts.

    \n
    \n
    \n \n Ok\n \n
    \n
    \n );\n }\n };\n\n const isPositiveAudienceCount =\n confirmationDialog?.data?.validation_rules_summary?.length &&\n confirmationDialog?.data?.valid_audience_count;\n\n return (\n
    \n {getConfirmationContent()}\n \n
    \n );\n};\n\nexport default ConfirmationDialogExclude;\n","import React from \"react\";\nimport TooltipCustom from \"../tooltipCustom\";\n\nimport inIcon from \"../../../assets/image/icons/tables/in.svg\";\nimport linkSvgGold from \"../../../assets/image/icons/tables/goldLink.svg\";\nimport avatarSvg from \"../../../assets/image/icons/svg/user.svg\";\n\nimport \"./style.scss\";\nimport { ordinalNumber } from \"../../../shared/utils\";\n\nconst CustomCellRenderer = ({ data }) => {\n return (\n
    \n \n\n
    {data.contact.fullName}
    \n\n {data.contact.connection && (\n
    \n

    \n
    \n {ordinalNumber(data.contact.connection)}\n
    \n
    \n )}\n
    \n {data.contact.account ? {\"premium\"} : <>}\n {\n e.preventDefault();\n await data.contact.openLinkedInProfile();\n }}\n >\n \n \"link\n \n
    \n
    \n \n );\n};\n\nexport default React.memo(CustomCellRenderer);\n","import React from \"react\";\nimport Checkbox from \"@mui/material/Checkbox\";\nimport notSelectedCheckboxIcon from \"../../../assets/image/icons/tables/checkbox.svg\";\nimport selectedCheckboxIcon from \"../../../assets/image/icons/tables/checkbox2.svg\";\n\nconst CustomCheckbox = (props) => {\n const { data } = props;\n return (\n props.handleClick(data.id)}\n checked={data.isSelected}\n inputProps={{\n \"aria-labelledby\": `enhanced-table-checkbox-${data.id}`,\n }}\n icon={\"checkbox\"}\n checkedIcon={\"checkbox\"}\n />\n );\n};\n\nexport default React.memo(CustomCheckbox);\n","import notSelectedCheckboxIcon from \"../../../assets/image/icons/tables/checkbox.svg\";\n\nconst HeaderCheckbox = (props) => {\n return (\n
    \n props.handleChange(true)}\n />\n
    \n );\n};\n\nexport default HeaderCheckbox;\n","import { useState, useEffect } from \"react\";\nimport Checkbox from \"@mui/material/Checkbox\";\nimport notSelectedCheckboxIcon from \"../../../assets/image/icons/tables/checkbox.svg\";\nimport selectedCheckboxIcon from \"../../../assets/image/icons/tables/checkbox2.svg\";\nimport selectedCheckboxDisabledIcon from \"../../../assets/image/icons/tables/checkbox2-disabled.svg\";\n\nimport \"./style.scss\";\n\nconst TableSettingsModal = (props) => {\n const [dataSettingsTable, setDataSettingsTable] = useState(\n props.executions\n ? JSON.parse(localStorage?.getItem(\"executionsGridSettings\"))\n : JSON.parse(localStorage?.getItem(\"contactsGridSettings\"))\n );\n\n useEffect(() => {\n setDataSettingsTable(\n props.executions\n ? JSON.parse(localStorage?.getItem(\"executionsGridSettings\"))\n : JSON.parse(localStorage?.getItem(\"contactsGridSettings\"))\n );\n }, []);\n\n return (\n
    \n
    \n {dataSettingsTable\n ?.filter((el) => el.colId !== \"select\")\n ?.filter((el) => el.colId !== \"created\")\n ?.map((item, index) => {\n return (\n
    \n {\n const newDataSizeTable = dataSettingsTable.map(\n (itemData) => {\n if (itemData.colId === item.colId) {\n itemData.hide = !itemData.hide;\n }\n return itemData;\n }\n );\n setDataSettingsTable(newDataSizeTable);\n }}\n disabled={item.colId === \"select\" || item.colId === \"contact\"}\n checked={!item.hide}\n inputProps={{ \"aria-labelledby\": \"label-\" + item.colId }}\n icon={\"checkbox\"}\n checkedIcon={\n item.colId === \"select\" || item.colId === \"contact\" ? (\n \n ) : (\n \"checkbox\"\n )\n }\n disableRipple={true}\n />\n\n \n
    \n );\n })}\n
    \n\n {\n props.executions\n ? localStorage.setItem(\n \"executionsGridSettings\",\n JSON.stringify(dataSettingsTable)\n )\n : localStorage.setItem(\n \"contactsGridSettings\",\n JSON.stringify(dataSettingsTable)\n );\n props.updateDataSizeTable(dataSettingsTable);\n props.closeModal();\n }}\n >\n Apply\n \n
    \n
    \n );\n};\n\nexport default TableSettingsModal;\n","import React, { useEffect } from \"react\";\nimport makeStyles from \"@mui/styles/makeStyles\";\nimport Tooltip from \"@mui/material/Tooltip\";\nimport { useSelector } from \"react-redux\";\n\nconst useStyles = makeStyles((theme) => ({\n customTooltip: {\n fontSize: \"14px\",\n lineHeight: \"19px\",\n padding: \"2px 12px 3px 12px\",\n width: \"fit-content\",\n maxWidth: \"95vw\",\n marginTop: (props) => (props.margin ? \"7px\" : \"9px\"),\n },\n}));\n\nconst TooltipCustom = (props) => {\n const { arrow, title, children, margin, field } = props;\n\n const classes = useStyles({ margin });\n const [headlineWidth, setHeadlineWidth] = React.useState(0);\n const [currentHeadlineWidth, setCurrentHeadlineWidth] = React.useState(0);\n const state = useSelector(\n (state) =>\n state.contacts.columnSize.find((col) => col.colId === field)?.width\n );\n\n const typeContacts = useSelector((state) => state.contacts.typeContacts);\n\n useEffect(() => {\n function measureTextCanvas(text, font) {\n const canvas = document.createElement(\"canvas\");\n const context = canvas.getContext(\"2d\");\n context.font = font;\n return context.measureText(text).width;\n }\n setCurrentHeadlineWidth(measureTextCanvas(title, \"15.669px Open Sans\"));\n\n setTimeout(() => {\n const dataSizeTable =\n typeContacts !== \"single\"\n ? JSON.parse(localStorage?.getItem(\"contactsGridSettings\"))\n : JSON.parse(localStorage?.getItem(\"executionsGridSettings\"));\n\n const getColumnWidthByColId = (colId) => {\n const column = dataSizeTable?.find((column) => column.colId === colId);\n return column ? column.width : undefined;\n };\n\n const width = getColumnWidthByColId(field);\n\n setHeadlineWidth(width);\n }, 100);\n }, [state]);\n\n return title && currentHeadlineWidth > headlineWidth ? (\n \n {title?.split(\"\\n\").map((paragraph, index) => (\n

    \n {paragraph}\n

    \n ))}\n
    \n }\n enterDelay={500}\n enterNextDelay={500}\n leaveDelay={0}\n arrow={arrow}\n >\n {children}\n \n ) : (\n children\n );\n};\n\nexport default TooltipCustom;\n","import React from \"react\";\nimport TooltipCustomTable from \"../tooltipCustomTable\";\nimport \"./style.scss\";\n\nconst CustomTooltipWrapper = (props) => {\n const { value } = props;\n return (\n \n
    {value}
    \n
    \n );\n};\n\nconst areEqual = (prevProps, nextProps) => {\n return prevProps.value === nextProps.value;\n};\n\nexport default React.memo(CustomTooltipWrapper, areEqual);\n","import { useState, useEffect } from \"react\";\nimport { Dropdown } from \"semantic-ui-react\";\n\nimport lFilter from \"lodash/filter\";\nimport { mapping } from \"../../../actions/mapping\";\n// components\nimport TooltipCustom from \"../../atoms/tooltipCustom\";\n// icons\nimport messageIcon from \"../../../assets/image/icons/png/message.svg\";\nimport infoBlackIcon from \"../../../assets/image/icons/tables/info-black.svg\";\nimport inIcon from \"../../../assets/image/icons/tables/linkedin-icon-gray.svg\";\nimport iconRemove from \"../../../assets/image/icons/tables/remove.svg\";\nimport iconStop from \"../../../assets/image/icons/svg/icons/stop.svg\";\nimport { CONSTS } from \"../../../config/objectConst\";\nimport ModalWindow from \"../ModalWindow\";\nimport { linkedInProfileOpener } from \"../../../api/linkedInProfileOpener\";\nimport { statesDescriptor } from \"../../../api/statesDescriptor\";\nimport { useAppSelector } from \"../../../shared/hooks\";\nimport { appSelectors } from \"../../../redux/reducers/app\";\n\nconst BtnGroupContainer = (props) => {\n const [actions, setActions] = useState([]);\n const [isOpen, setIsOpen] = useState(false);\n const [isModalVisible, setIsModalVisible] = useState(false);\n const connector = useAppSelector(appSelectors.connector);\n\n useEffect(() => {\n if (props.row.campaignExecutions.step_executions) {\n setActions(\n lFilter(\n props.row.campaignExecutions.step_executions,\n (el) => el.type !== \"Delay\"\n )\n );\n }\n return () => {\n setActions([]);\n };\n }, [props.row]);\n\n const menuClasses = () => {\n if (props.size > 6) {\n if (props.index > props.size - 3) {\n return \"position-top\";\n }\n }\n return \"position-bottom\";\n };\n\n const upwardController = () => {\n if (props.size > 6) {\n if (props.index > props.size - 3) {\n return true;\n }\n }\n return false;\n };\n\n const openLinkedinProfile = () => linkedInProfileOpener.open(props.row);\n\n const cancelExecution = () => {\n props.row.campaignExecutions.actions.complete.enabled &&\n props.handlerCompleteExecutions(props.row.campaignExecutions.id);\n setIsOpen(false);\n };\n\n return (\n
    \n {\n if (props.row.campaignExecutions.actions.show_details.enabled) {\n setIsModalVisible(true);\n\n props.dropDownController(true);\n }\n }}\n onClose={() => {\n setIsModalVisible(false);\n props.dropDownController(false);\n }}\n icon={\n \n \"infoBlackIcon\"\n \n }\n >\n \n \n
    \n

    \n {statesDescriptor.getExecutionTitle(\n props.row.campaignExecutions.state\n )}\n

    \n
    \n {actions &&\n actions.map((item, index) => {\n return (\n
    \n
    \n
    \n Action #{index + 1}:{\" \"}\n
    \n
    \n {mapping.activeName(item.type)}\n
    \n
    \n
    \n
    \n Status:\n
    \n
    \n
    \n \n {statesDescriptor.getStepTitle(\n item.human_state,\n item.type\n )}\n \n
    \n
    \n
    \n );\n })}\n
    \n
    \n \n \n \n\n \n \n \"linkedin\n \n \n\n \n {\n props.row.campaignExecutions.actions.open_conversation.enabled &&\n window.open(\n props.row.campaignExecutions.conversation_url,\n \"_blank\"\n );\n }}\n >\n \"messageIcon\"\n \n \n {props.type === \"single\" && props.campaignStatus === \"Compose\" && (\n \n props.removeContactsFromCampaign([props.row], props.campaignId)\n }\n >\n \"timeIcon\"\n \n )}\n {props.type === \"all\" && (\n \n )}\n \n {\n e.stopPropagation();\n props.row.campaignExecutions.actions.complete.enabled &&\n setIsOpen(true);\n }}\n >\n \"iconPause\"\n \n \n setIsOpen(false)}\n confirmHandler={cancelExecution}\n />\n \n );\n};\n\nexport default BtnGroupContainer;\n","import { api } from \"../../../api/api\";\nimport { functions, saveData } from \"../../../tools/functions\";\nimport { contacts } from \"../../../actions/contacts\";\nimport { apiCampaign } from \"../../../api/campaign/apiCampaign\";\nimport { app } from \"../../../actions/app\";\nimport { campaign } from \"../../../actions/campaign\";\nimport { linkedInProfileOpener } from \"../../../api/linkedInProfileOpener\";\nimport { mapping } from \"../../../actions/mapping\";\nimport store from \"../../../redux/store.ts\";\nimport { notificationUtils } from \"features/notifications/index.ts\";\nimport { notifyError } from \"shared/errors/notificate.ts\";\nimport { executionsUtils } from \"features/executions/index.ts\";\n\nexport function onClearAllClick() {\n const newContacts =\n this.props.type === \"add-to-campaign\"\n ? this.state.contactsModal\n : this.state.contacts;\n\n for (const contact of newContacts) {\n setNewDataUnChecked.call(this, contact.id);\n }\n\n this.setState({\n selected: [],\n selectedValues: 0,\n selectAllUsersValue: false,\n });\n}\n\nexport function onSelectAllClick() {\n const newContacts =\n this.props.type === \"add-to-campaign\"\n ? this.state.contactsModal\n : this.state.contacts;\n const newContactsCount =\n this.props.type === \"add-to-campaign\"\n ? this.props.contactsCountModal\n : this.props.contactsCount;\n const newSelected = newContacts.map((item) => item.id);\n\n for (const contact of newContacts) {\n setNewDataChecked.call(this, contact.id);\n }\n\n this.setState({\n selected: newSelected,\n selectedValues: newContactsCount,\n selectAllUsersValue: true,\n });\n}\n\nexport function createFilter() {\n const result =\n this.props.history.location.pathname !== \"/contacts\"\n ? this.props.filters.filtersQuery\n ? this.props.filters.filtersQuery\n : `tags/any(c:c eq '${this.props.activeImportId}')`\n : this.props.filters.filtersQuery;\n return result;\n}\n\nexport function createCriteriaForSelectedContacts() {\n const selectId = this.state.selected;\n const filterContacts = createFilter.call(this);\n const filterImport = `id in (${selectId.map((item) => `'${item}'`)})`;\n const result = {\n filter: this.state.selectAllUsersValue ? filterContacts : filterImport,\n keywords: this.props.keywords ? this.props.keywords : \"\",\n orderby:\n this.props.history.location.pathname === \"/contacts\"\n ? this.props.isFiltering\n : this.props.isFiltering,\n };\n return result;\n}\n\nexport function getNewPage() {\n const getNewPage =\n this.props.type === \"add-to-campaign\"\n ? this.props.contactsPageModal\n : this.props.contactsPage;\n const newContactsCount =\n this.props.type === \"add-to-campaign\"\n ? this.props.contactsCountModal\n : this.props.contactsCount;\n let newPage =\n getNewPage * this.state.initialValuePagination >=\n newContactsCount - this.state.initialValuePagination &&\n getNewPage * this.state.initialValuePagination === newContactsCount\n ? getNewPage - 1\n : getNewPage;\n return (newPage = newPage >= 0 ? newPage : 0);\n}\n\nexport async function previewContacts() {\n try {\n const data = createCriteriaForSelectedContacts.call(this);\n const preview = await api.previewContacts(data);\n\n if (preview.status === 200) {\n if (preview.data?.validation_rules_summary.length === 0) {\n this.setState({ isDeleteContactsOpened: true });\n } else {\n return this.setState({\n confirmationDialogContacts: {\n status: true,\n data: preview.data,\n },\n });\n }\n getNewPage.call(this);\n }\n } catch (error) {\n notifyError(error);\n }\n}\n\nexport async function exportRecentActivities() {\n const selectedIds = this.state.selected;\n const filterExpression = this.state.selectAllUsersValue\n ? this.props.filterQueryExecutions\n ? this.props.filterQueryExecutions\n : `(campaign_id eq '${this.props.campaignId}')`\n : `id in (${selectedIds.map((item) => `'${item}'`)})`;\n\n const queryParameters = {\n filter: filterExpression,\n keywords: this.props.keywordsExecutions\n ? this.props.keywordsExecutions\n : \"\",\n };\n\n try {\n this.setState({ isLoadingInteractionLog: true });\n const response = await api.exportRecentActivitiesApi(queryParameters);\n if (response.status === 200) {\n const data = response.data,\n fileName = functions.getFileName();\n saveData(data, fileName);\n }\n } catch (error) {\n notifyError(error);\n } finally {\n this.setState({\n selected: [],\n });\n this.setState({ isLoadingInteractionLog: false });\n }\n}\n\nexport async function removeExecutionsFromCampaign() {\n this.props.setIsExcludeLoader(true);\n await apiCampaign.removeExecutionsFromCampaignApi({\n filter:\n this.state.selectAllUsersValue && this.props.filterQueryExecutions\n ? `${this.props.filterQueryExecutions}${\n this.props.keywordsExecutions\n ? \"&$searchQuery=\" + this.props.keywordsExecutions\n : \"\"\n }`\n : this.state.selectAllUsersValue\n ? `campaign_id eq '${this.props.campaignId}'${\n this.props.keywordsExecutions\n ? \"&$searchQuery=\" + this.props.keywordsExecutions\n : \"\"\n }`\n : `id in (${this.state.selected.map((item) => `'${item}'`)})`,\n });\n\n executionsUtils.refetch();\n\n const newPage = getNewPage.call(this);\n\n await contacts.getContacts({\n take: this.state.initialValuePagination,\n skip: newPage * this.state.initialValuePagination,\n orderby: this.props.isFiltering ? this.props.isFiltering : \"created asc\",\n status: \"Running\",\n filter:\n this.props.filterQueryExecutions || this.props.keywordsExecutions\n ? `${\n this.props.filterQueryExecutions\n ? this.props.filterQueryExecutions\n : \"\"\n }${\n this.props.keywordsExecutions\n ? \"&$searchQuery=\" + this.props.keywordsExecutions\n : \"\"\n }`\n : `campaign_id eq '${this.props.campaignId}'`,\n });\n this.setState({\n selected: [],\n });\n this.props.setIsExcludeLoader(false);\n notificationUtils.snackById(\"3.16\");\n}\n\nexport async function exportContactsForCampaign() {\n const selectId = this.state.selected;\n const filterCompose = this.state.selectAllUsersValue\n ? `campaigns/any(c:c eq '${this.props.match.params.id}')`\n : `id in (${selectId.map((item) => `'${item}'`)})`;\n const filterNoCompose = this.state.selectAllUsersValue\n ? this.props.filterQueryExecutions\n ? this.props.filterQueryExecutions\n : `(campaign_id eq '${this.props.campaignId}')`\n : `id in (${selectId.map((item) => `'${item}'`)})`;\n\n const dataCompose = {\n filter: filterCompose,\n orderby: this.props.isFiltering ? this.props.isFiltering : \"created asc\",\n };\n const dataExecutions = {\n filter: filterNoCompose,\n orderby: this.props.isFilteringExecutions.includes(\"import\")\n ? \"created asc\"\n : this.props.isFilteringExecutions,\n keywords: this.props.keywordsExecutions\n ? this.props.keywordsExecutions\n : \"\",\n };\n\n try {\n this.setState({ isLoadingCSVCampaigns: true });\n const response =\n this.props.campaignStatus === \"Compose\"\n ? await api.exportContactsApi(dataCompose)\n : await api.exportContactsApiExecutions(dataExecutions);\n if (response.status === 200) {\n const data = response.data,\n fileName = functions.getFileName();\n saveData(data, fileName);\n }\n } catch (error) {\n notifyError(error);\n } finally {\n this.setState({\n selected: [],\n });\n this.setState({ isLoadingCSVCampaigns: false });\n }\n}\n\nexport function areDisabledSelectionActions() {\n const result = this.state.selected.length === 0;\n return result;\n}\n\nexport async function deleteContacts() {\n const newPage =\n this.props.type === \"add-to-campaign\"\n ? this.props.contactsPageModal\n : this.props.contactsPage;\n this.setState({ isDeleteContactsOpened: false });\n app.changePageContentLoaderStatus(true);\n try {\n const data = createCriteriaForSelectedContacts.call(this);\n await api.deleteContacts(data);\n const criteria = {\n take: this.state.initialValuePagination,\n skip: newPage * this.state.initialValuePagination,\n filter: createFilter.call(this),\n keywords: this.props.filters.searchQuery\n ? this.props.filters.searchQuery\n : \"\",\n orderby: this.props.isFiltering ? this.props.isFiltering : \"\",\n };\n\n let response = await contacts.getContacts(criteria);\n if (\n response.status === 200 &&\n response.data.documents.length === 0 &&\n response.data.total > 0\n ) {\n criteria.skip -= this.state.initialValuePagination;\n response = await contacts.getContacts(criteria);\n }\n\n if (response.status === 200) {\n notificationUtils.snackById(\"3.20\");\n }\n } catch (error) {\n notifyError(error);\n } finally {\n this.setState({\n selected: [],\n });\n app.changePageContentLoaderStatus(false);\n }\n}\n\nexport async function exportContacts() {\n const data = createCriteriaForSelectedContacts.call(this);\n try {\n this.setState({ isLoadingCSV: true });\n const response = await api.exportContactsApi(data);\n if (response.status === 200) {\n const data = response.data,\n fileName = functions.getFileName();\n saveData(data, fileName);\n }\n } catch (error) {\n notifyError(error);\n }\n clearCheckboxes.call(this);\n this.setState({ isLoadingCSV: false });\n}\n\nexport function clearCheckboxes() {\n const newContacts =\n this.props.type === \"add-to-campaign\"\n ? this.state.contactsModal\n : this.state.contacts;\n\n for (const contact of newContacts) {\n setNewDataUnChecked.call(this, contact.id);\n }\n\n this.setState({\n selected: [],\n selectedValues: 0,\n });\n}\n\nexport function setNewDataUnChecked(id) {\n var rowNode = this.state.gridApi.getRowNode(id);\n var newData = this.state.rowData?.find((item) => item.id === id);\n newData.isSelected = false;\n rowNode.setDataValue(\"select\", false);\n}\n\nexport function setNewDataChecked(id) {\n var rowNode = this.state.gridApi.getRowNode(id);\n var newData = this.state.rowData?.find((item) => item.id === id);\n newData.isSelected = true;\n rowNode.setDataValue(\"select\", true);\n}\n\nexport function setNewData(id) {\n var rowNode = this.state.gridApi.getRowNode(id);\n var newData = this.state.rowData?.find((item) => item.id === id);\n newData.isSelected = !newData.isSelected;\n rowNode.setDataValue(\"select\", newData?.isSelected);\n}\n\nexport function handleClick(id) {\n const selectedIndex = this.state.selected.indexOf(id);\n let newSelected = [];\n\n if (selectedIndex === -1) {\n newSelected = newSelected.concat(this.state.selected, id);\n } else if (selectedIndex === 0) {\n this.setState({\n selectAllUsersValue: false,\n });\n newSelected = newSelected.concat(this.state.selected.slice(1));\n } else if (selectedIndex === this.state.selected.length - 1) {\n this.setState({\n selectAllUsersValue: false,\n });\n newSelected = newSelected.concat(this.state.selected.slice(0, -1));\n } else if (selectedIndex > 0) {\n this.setState({\n selectAllUsersValue: false,\n });\n newSelected = newSelected.concat(\n this.state.selected.slice(0, selectedIndex),\n this.state.selected.slice(selectedIndex + 1)\n );\n }\n setNewData.call(this, id);\n this.setState({\n selected: newSelected,\n selectedValues: newSelected.length,\n });\n}\n\nexport function onSelectAllPageClick(isChecked) {\n const newContacts =\n this.props.type === \"add-to-campaign\"\n ? this.state.contactsModal\n : this.state.contacts;\n if (isChecked) {\n for (const contact of newContacts) {\n setNewDataChecked.call(this, contact.id);\n }\n\n this.setState({\n selected:\n this.props.type === \"add-to-campaign\"\n ? this.props.contactsModal?.map((contact) => contact.id)\n : this.props.contacts?.map((contact) => contact.id),\n selectedValues: newContacts.length,\n });\n } else {\n for (const contact of newContacts) {\n setNewDataUnChecked.call(this, contact.id);\n }\n\n this.setState({\n selected: [],\n selectedValues: 0,\n });\n }\n}\n\nexport async function handlerCompleteExecutions(id) {\n try {\n app.changeTableContentLoaderStatus(true);\n const response = await api.setExecutionComplete(id);\n executionsUtils.refetch();\n if (response.status === 200) {\n const campaignExecutionsId = response.data.id;\n const executionIndex =\n this.props.type === \"add-to-campaign\"\n ? this.props.contactsModal.findIndex((item) => {\n return item.campaignExecutions.id === campaignExecutionsId;\n })\n : this.props.contacts.findIndex((item) => {\n return item.campaignExecutions.id === campaignExecutionsId;\n });\n const tempContacts =\n this.props.type === \"add-to-campaign\"\n ? this.props.contactsModal\n : this.props.contacts;\n tempContacts[executionIndex].campaignExecutions = response.data;\n contacts.cancelExecution(tempContacts);\n }\n await campaign.getCampaignId(this.props.match.params.id);\n } catch (error) {\n notifyError(error);\n } finally {\n app.changeTableContentLoaderStatus(false);\n }\n}\n\nexport async function removeContactsFromCampaign(audience, campaignId) {\n if (this.state.selectAllUsersValue) {\n await campaign.removeAllContactsFromCampaign({\n campaignId,\n });\n } else {\n await campaign.removeContactsFromCampaign({\n campaignId,\n filter: `id in (${audience.map((item) => `'${item}'`)})`,\n audience,\n });\n }\n\n const newPage = getNewPage.call(this);\n await contacts.getContacts({\n take: this.state.initialValuePagination,\n skip: newPage * this.state.initialValuePagination,\n filter: `campaigns/any(c:c eq '${campaignId}')`,\n orderby: this.props.isFiltering ? this.props.isFiltering : \"imported asc\",\n });\n this.setState({\n selected: [],\n });\n await campaign.getCampaignId(campaignId);\n}\n\nexport function onGridReady(params) {\n this.setState({\n gridApi: params.api,\n gridColumnApi: params.columnApi,\n });\n}\n\nexport function dropDownController(value) {\n this.setState({\n dropDownController: value,\n });\n}\n\nexport function dropDownControllerContact(value) {\n this.setState({\n dropDownControllerContact: value,\n });\n}\n\nexport async function getContactsBySort() {\n if (this.props.type === \"single\" && this.props.campaignStatus !== \"Compose\") {\n contacts.getContacts({\n status: \"Active\",\n skip: 0,\n take: this.state.initialValuePagination,\n filter: this.props.filterQueryExecutions\n ? this.props.filterQueryExecutions\n : [`campaign_id eq '${this.props.match.params.id}'`],\n orderby: this.props.isFilteringExecutions.includes(\"created\")\n ? this.props.isFilteringExecutions\n : this.props.isFilteringExecutions,\n\n keywords: this.props.keywordsExecutions\n ? this.props.keywordsExecutions\n : \"\",\n });\n }\n if (this.props.type === \"single\" && this.props.campaignStatus === \"Compose\") {\n contacts.getContacts({\n take: this.state.initialValuePagination,\n skip: 0,\n filter: `campaigns/any(c:c eq '${this.props.campaignId}')`,\n orderby: this.props.isFiltering,\n });\n }\n if (this?.props?.history?.location?.pathname.includes(\"/import\")) {\n contacts.getContacts({\n take: this.state.initialValuePagination,\n orderby: this.props.isFiltering,\n skip: 0,\n filter: this.props.filters.filtersQuery\n ? this.props.filters.filtersQuery\n : `tags/any(c:c eq '${this.props.match.params.id}')`,\n keywords: this.props.keywords || this.props.filters.searchQuery || \"\",\n });\n }\n if (this?.props?.history?.location?.pathname === \"/contacts\") {\n contacts.getContacts({\n take: this.state.initialValuePagination,\n orderby:\n this.props.history.location.pathname === \"/contacts\" ||\n this.props.history.location.pathname.includes(\"/campaigns\")\n ? this.props.isFiltering\n : \"imported asc\",\n filter: this?.props?.filters?.filtersQuery\n ? this.props.filters.filtersQuery\n : \"\",\n keywords: this.props.keywords || this.props.filters.searchQuery || \"\",\n });\n }\n contacts.changeContactsPage(0);\n}\n\nexport async function getContactsOnPage() {\n return this.props.type === \"add-to-campaign\"\n ? this.props.contactsModal\n : this.props.contacts;\n}\n\nexport async function handleChangePage(events, newPage) {\n try {\n if (this.props.match.params.id) {\n if (this.props.type === \"add-to-campaign\") {\n contacts.changeContactsPageModal(newPage);\n const filter = this.props.filters.filtersQueryForModal\n ? this.props.filters.filtersQueryForModal\n : `not (campaigns/any(c:c eq '${this.props.match.params.id}'))`;\n const response = await contacts.getContacts(\n {\n take: this.state.initialValuePagination,\n skip: newPage > 0 ? newPage * this.state.initialValuePagination : 0,\n filter,\n keywords: this.props.keywords ? this.props.keywords : \"\",\n orderby: this.props.isFiltering\n ? this.props.isFiltering\n : \"imported desc\",\n },\n undefined,\n undefined,\n false,\n true\n );\n if (response.data) {\n if (response.data.documents.length > 0) {\n contacts.haveContacts(true);\n store.dispatch({\n type: \"CONTACTS_COUNT_MODAL\",\n payload: {\n contactsCountModal: response.data.total,\n },\n });\n }\n store.dispatch({\n type: \"ALL_CONTACTS_MODAL\",\n payload: {\n contactsModal: mapping.buildContacts(response.data.documents),\n },\n });\n app.changePageContentLoaderStatus(false);\n app.changeTableContentLoaderStatus(false);\n }\n return;\n }\n if (\n this.props.type === \"single\" &&\n this.props.campaignStatus === \"Compose\"\n ) {\n contacts.changeContactsPage(newPage);\n contacts.getContacts(\n {\n take: this.state.initialValuePagination,\n skip: newPage > 0 ? newPage * this.state.initialValuePagination : 0,\n filter: `campaigns/any(c:c eq '${this.props.match.params.id}')`,\n orderby: this.props.isFiltering\n ? this.props.isFiltering\n : \"imported asc\",\n },\n this.props.campaignStatus,\n this.props.match.params.id\n );\n return;\n }\n if (\n this.props.type === \"single\" &&\n this.props.campaignStatus !== \"Compose\"\n ) {\n contacts.changeContactsPage(newPage);\n contacts.getContacts(\n {\n take: this.state.initialValuePagination,\n skip: newPage > 0 ? newPage * this.state.initialValuePagination : 0,\n filter: this.props.filterQueryExecutions\n ? this.props.filterQueryExecutions\n : [`campaign_id eq '${this.props.match.params.id}'`],\n orderby: this.props.isFilteringExecutions\n ? this.props.isFilteringExecutions\n : \"created asc\",\n keywords: this.props.keywordsExecutions\n ? this.props.keywordsExecutions\n : \"\",\n },\n this.props.campaignStatus\n );\n return;\n }\n contacts.changeContactsPage(newPage);\n contacts.getContacts({\n take: this.state.initialValuePagination,\n orderby: this.props.isFiltering\n ? this.props.isFiltering\n : \"imported asc\",\n skip: newPage > 0 ? newPage * this.state.initialValuePagination : 0,\n filter: this.props.filters.filtersQuery\n ? this.props.filters.filtersQuery\n : `tags/any(c:c eq '${this.props.match.params.id}')`,\n keywords: this.props.filters.searchQuery\n ? this.props.filters.searchQuery\n : this.props.keywords\n ? this.props.keywords\n : \"\",\n });\n } else {\n contacts.changeContactsPage(newPage);\n contacts.getContacts({\n take: this.state.initialValuePagination,\n skip: newPage > 0 ? newPage * this.state.initialValuePagination : 0,\n filter: this.props.filters.filtersQuery\n ? this.props.filters.filtersQuery\n : \"\",\n keywords: this.props.keywords ? this.props.keywords : \"\",\n orderby: this.props.isFiltering ? this.props.isFiltering : \"\",\n });\n }\n this.setState({\n contactsOnPage: getContactsOnPage.call(this, newPage),\n });\n } catch (error) {\n notifyError(error);\n }\n}\n\nexport async function onClickExclude() {\n let preview = \"\";\n if (this.state.isCampaignsRunning) {\n this.setState({\n needLoader: true,\n });\n preview = await apiCampaign.getPreviewRemoveTargetAudience({\n filter:\n this.state.selectAllUsersValue && this.props.filterQueryExecutions\n ? `${this.props.filterQueryExecutions}${\n this.props.keywordsExecutions\n ? \"&$searchQuery=\" + this.props.keywordsExecutions\n : \"\"\n }`\n : this.state.selectAllUsersValue\n ? `campaign_id eq '${this.props.campaignId}'${\n this.props.keywordsExecutions\n ? \"&$searchQuery=\" + this.props.keywordsExecutions\n : \"\"\n }`\n : `id in (${this.state.selected.map((item) => `'${item}'`)})`,\n });\n this.setState({\n needLoader: false,\n });\n }\n\n if (\n preview &&\n ((this.props.campaignStatus === \"Running\" &&\n preview?.data?.validation_rules_summary?.length === 0) ||\n (this.props.campaignStatus === \"Stopped\" &&\n preview?.data?.validation_rules_summary?.length === 0) ||\n (this.props.campaignStatus === \"Completed\" &&\n preview?.data?.validation_rules_summary?.length === 0) ||\n (preview?.data?.validation_rules_summary?.length === 0 &&\n preview?.data?.valid_audience_count > 0))\n ) {\n this.setState({ isExcludeContactsOpened: true });\n } else {\n return this.setState({\n confirmationDialog: {\n id: this.state.companyId,\n status: true,\n data: preview.data,\n },\n });\n }\n}\n\nexport async function deleteHandler() {\n this.setState({ isExcludeContactsOpened: false });\n if (this.state.isCampaignsRunning) {\n removeExecutionsFromCampaign.call(\n this,\n this.state.selected,\n this.props.campaignId\n );\n } else {\n removeContactsFromCampaign.call(\n this,\n this.state.selected,\n this.props.campaignId\n );\n }\n}\n\nexport function createDataArray(colState) {\n return [\n {\n colId: \"select\",\n width: colState.find((el) => el.colId === \"select\").width,\n hide: false,\n title: \"Select\",\n },\n\n {\n colId: \"contact\",\n width: colState.find((el) => el.colId === \"contact\").width,\n hide: false,\n title: \"Contact\",\n },\n {\n colId: \"headline\",\n width: colState.find((el) => el.colId === \"headline\").width,\n hide: colState.find((el) => el.colId === \"headline\").hide,\n title: \"Headline\",\n },\n {\n colId: \"location\",\n width: colState.find((el) => el.colId === \"location\").width,\n hide: colState.find((el) => el.colId === \"location\").hide,\n title: \"Location\",\n },\n {\n colId: \"status\",\n width: colState.find((el) => el.colId === \"status\").width,\n hide: colState.find((el) => el.colId === \"status\").hide,\n title: \"Status\",\n },\n {\n colId: \"lastAction\",\n width: colState.find((el) => el.colId === \"lastAction\").width,\n hide: colState.find((el) => el.colId === \"lastAction\").hide,\n title: \"Last Action\",\n },\n {\n colId: \"added\",\n width: colState.find((el) => el.colId === \"added\").width,\n hide: colState.find((el) => el.colId === \"added\").hide,\n title: \"Added\",\n },\n {\n colId: \"custom1\",\n width: colState.find((el) => el.colId === \"custom1\").width,\n hide: colState.find((el) => el.colId === \"custom1\").hide,\n title: \"Custom 1\",\n },\n {\n colId: \"custom2\",\n width: colState.find((el) => el.colId === \"custom2\").width,\n hide: colState.find((el) => el.colId === \"custom2\").hide,\n title: \"Custom 2\",\n },\n {\n colId: \"custom3\",\n width: colState.find((el) => el.colId === \"custom3\").width,\n hide: colState.find((el) => el.colId === \"custom3\").hide,\n title: \"Custom 3\",\n },\n ];\n}\n\nexport function createDataArrayAll(colState) {\n return [\n {\n colId: \"select\",\n width: colState.find((el) => el.colId === \"select\").width,\n hide: colState.find((el) => el.colId === \"select\").hide,\n title: \"Select\",\n },\n\n {\n colId: \"contact\",\n width: colState.find((el) => el.colId === \"contact\").width,\n hide: colState.find((el) => el.colId === \"contact\").hide,\n title: \"Contact\",\n },\n {\n colId: \"headline\",\n width: colState.find((el) => el.colId === \"headline\").width,\n hide: colState.find((el) => el.colId === \"headline\").hide,\n title: \"Headline\",\n },\n {\n colId: \"location\",\n width: colState.find((el) => el.colId === \"location\").width,\n hide: colState.find((el) => el.colId === \"location\").hide,\n title: \"Location\",\n },\n {\n colId: \"lastAction\",\n width: colState.find((el) => el.colId === \"lastAction\").width,\n hide: colState.find((el) => el.colId === \"lastAction\").hide,\n title: \"Last Action\",\n },\n {\n colId: \"imported\",\n width: colState.find((el) => el.colId === \"imported\").width,\n hide: colState.find((el) => el.colId === \"imported\").hide,\n title: \"Imported\",\n },\n {\n colId: \"created\",\n width: colState.find((el) => el.colId === \"created\").width,\n hide: colState.find((el) => el.colId === \"created\").hide,\n title: \"Created\",\n },\n {\n colId: \"custom1\",\n width: colState.find((el) => el.colId === \"custom1\").width,\n hide: colState.find((el) => el.colId === \"custom1\").hide,\n title: \"Custom 1\",\n },\n {\n colId: \"custom2\",\n width: colState.find((el) => el.colId === \"custom2\").width,\n hide: colState.find((el) => el.colId === \"custom2\").hide,\n title: \"Custom 2\",\n },\n {\n colId: \"custom3\",\n width: colState.find((el) => el.colId === \"custom3\").width,\n hide: colState.find((el) => el.colId === \"custom3\").hide,\n title: \"Custom 3\",\n },\n ];\n}\n\nexport function saveState() {\n if (this.state.gridColumnApi) {\n const colState = this.state.gridColumnApi.getColumnState();\n const data =\n this.props.type === \"single\"\n ? createDataArray.call(this, colState)\n : createDataArrayAll.call(this, colState);\n\n this.setState({\n data,\n });\n contacts.columnSize(data);\n contacts.typeContacts(this.props.type);\n contacts.typeCampaigns(this.props.campaignStatus);\n this.SavedColState.current = colState;\n this.state.gridColumnApi.applyColumnState({\n state: data,\n });\n\n this.state.type === \"single\"\n ? localStorage.setItem(\"executionsGridSettings\", JSON.stringify(data))\n : localStorage.setItem(\"contactsGridSettings\", JSON.stringify(data));\n }\n}\n\nexport function onColumnResized(event) {\n if (event.finished && event.source !== \"flex\") {\n if (this.state.gridColumnApi) {\n saveState.call(this);\n }\n }\n}\n\nexport const heightGenerator = (type) => {\n switch (type) {\n case \"add-to-campaign\":\n return \"calc(100vh - 255px)\";\n case \"all\":\n return \"calc(100vh - 240px)\";\n case \"single\":\n return \"calc(100vh - 240px)\";\n case \"compose\":\n return \"calc(100vh - 195px)\";\n\n default:\n return \"calc(100vh - 240px)\";\n }\n};\n\nexport const getStylePagination = (isOpenMenuPagination) => ({\n control: (base) => {\n return {\n ...base,\n \"&:hover\": {\n border: isOpenMenuPagination\n ? \"1px solid #0cb39f\"\n : \"1px solid #EBEDF2\",\n },\n border: isOpenMenuPagination ? \"1px solid #0cb39f\" : \"1px solid #EBEDF2\",\n boxShadow: \"\",\n fontWeight: 400,\n fontSize: 14,\n background: \"#FFF\",\n borderTopLeftRadius: 0,\n borderTopRightRadius: 0,\n opacity: \"1\",\n color: \"#202020\",\n width: \"150px\",\n cursor: \"pointer\",\n minHeight: \"32px\",\n };\n },\n indicatorsContainer: (base) => ({\n ...base,\n borderLeft: isOpenMenuPagination\n ? \"1px solid #0cb39f\"\n : \"1px solid #EBEDF2\",\n }),\n indicatorSeparator: (base) => ({\n ...base,\n backgroundColor: \"transparent\",\n paddingTop: \"5px\",\n paddingBottom: \"5px\",\n }),\n singleValue: (base) => ({\n ...base,\n }),\n dropdownIndicator: (base) => ({\n ...base,\n padding: \"5px 3px\",\n height: \"32px\",\n color: \"#202020\",\n }),\n valueContainer: (provided, state) => ({\n ...provided,\n height: \"32px\",\n }),\n option: (styles, { isSelected }) => ({\n ...styles,\n fontSize: 14,\n color: \"#000\",\n backgroundColor: isSelected ? \"#F7F7F7\" : \"transparent\",\n \"&:active\": {\n backgroundColor: \"transparent\",\n },\n \"&:hover\": { backgroundColor: \"#F7F7F7\", cursor: \"pointer\" },\n }),\n menuList: (base) => ({\n ...base,\n position: \"absolute\",\n left: \"-1px\",\n bottom: \"34px\",\n backgroundColor: \"#fff\",\n width: \"150px\",\n border: \"1px solid #0cb39f\",\n borderBottom: \"1px solid transparent\",\n }),\n menu: (base) => ({\n ...base,\n boxShadow: \"\",\n marginTop: 0,\n borderTopLeftRadius: 0,\n borderTopRightRadius: 0,\n borderTop: 0,\n }),\n});\n\nexport function getInitialWidth(colId, isSingle) {\n const dataSizeTable = !isSingle\n ? JSON.parse(localStorage?.getItem(\"contactsGridSettings\"))\n : JSON.parse(localStorage?.getItem(\"executionsGridSettings\"));\n const column = dataSizeTable?.find((el) => el.colId === colId);\n return column ? column.width : null;\n}\n\nexport function getColumnProperty(colId, defaultValue, isSingle) {\n const dataSizeTable = !isSingle\n ? JSON.parse(localStorage?.getItem(\"contactsGridSettings\"))\n : JSON.parse(localStorage?.getItem(\"executionsGridSettings\"));\n const column = dataSizeTable?.find((el) => el.colId === colId);\n return column ? column.hide : defaultValue;\n}\nexport function getInitialWidthOrFlex(colId, defaultWidth, isSingle) {\n const width = getInitialWidth(colId, defaultWidth, isSingle);\n return width !== null ? { width } : { flex: 1 };\n}\nexport function getInitialWidthOrFlexSmall(colId, defaultWidth, isSingle) {\n const width = getInitialWidth(colId, defaultWidth, isSingle);\n return width !== null ? { width } : { flex: 0.5 };\n}\n\nexport function transformContactsData(avatarSvg) {\n const newContacts =\n this.props.type === \"add-to-campaign\"\n ? this.props.contactsModal\n : this.props.contacts;\n\n return newContacts.map((row) => ({\n id: row.id,\n isSelected: this.state?.selected?.includes(row.id) || false,\n contact: {\n avatar: row.avatar ? row.avatar : avatarSvg,\n fullName: row.fullName,\n connection: row.connection,\n account: row.account,\n openLinkedInProfile: () => linkedInProfileOpener.open(row),\n },\n headline: row.position,\n status:\n row.campaignExecutions &&\n this.renderSteps(\n row.campaignExecutions.step_executions,\n row.campaignExecutions\n ),\n location: row.location,\n lastAction: functions.parseDateToDMY(row.contacted, \"/\"),\n imported: functions.parseDateToDMY(row.date, \"/\"),\n created: functions.parseDateToDMY(row.created, \"/\"),\n added: row.campaignExecutions?.created\n ? functions.parseDateToDMY(row.campaignExecutions.created, \"/\")\n : functions.parseDateToDMY(row.created, \"/\"),\n campaignExecutions: row.campaignExecutions,\n actions: row.actions,\n fullName: row.fullName,\n publicIdentifier: row.publicIdentifier,\n position: row.position,\n contacted: row.contacted,\n connection: row.connection,\n\n account: row.account,\n avatar: row.avatar,\n entityId: row.entityId,\n custom1: row.customField1,\n custom2: row.customField2,\n custom3: row.customField3,\n }));\n}\n","import { useState, useEffect } from \"react\";\nimport { Dropdown, Loader } from \"semantic-ui-react\";\n\n// components\nimport TooltipCustom from \"../../atoms/tooltipCustom\";\n// icons\nimport infoBlackIcon from \"../../../assets/image/icons/tables/info-black.svg\";\nimport iconArrow from \"../../../assets/image/icons/png/arrow-green.png\";\n\nimport { api } from \"../../../api/api\";\nimport { statesDescriptor } from \"../../../api/statesDescriptor\";\n\nconst InformationBlock = (props) => {\n const [isModalVisible, setIsModalVisible] = useState(false);\n const [executionsList, setExecutionsList] = useState([]);\n const [currentId, setCurrentId] = useState(\"\");\n const [isLoading, setLoading] = useState(false);\n const [campaignState, setCampaignState] = useState([]);\n const getExecutionsContact = async () => {\n let arrayIdCampaigns;\n let data;\n try {\n if (currentId) {\n arrayIdCampaigns = await api.getContactsExecutionsApi({\n filter: `(linkedin_contact/id eq '${currentId}')`,\n orderby: \"created desc\",\n });\n if (arrayIdCampaigns.data.documents.length > 0) {\n setCampaignState(\n arrayIdCampaigns.data.documents.reduce((acc, doc) => {\n acc[doc.campaign_id] = doc.state;\n return acc;\n }, {})\n );\n const campaignIds = arrayIdCampaigns.data.documents.map(\n (doc) => doc.campaign_id\n );\n\n data = await api.getCampaignsApi({\n filter: `id in ('${campaignIds.join(\"', '\")}')`,\n });\n setExecutionsList(data.data.documents);\n }\n }\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n if (currentId) {\n getExecutionsContact();\n }\n }, [currentId]);\n\n const menuClasses = () => {\n if (props.size > 6) {\n if (props.index > props.size - 3) {\n return \"position-top\";\n }\n }\n return \"position-bottom\";\n };\n\n const upwardController = () => {\n if (props.size > 6) {\n if (props.index > props.size - 3) {\n return true;\n }\n }\n return false;\n };\n\n return (\n
    \n {\n setIsModalVisible(true);\n props.dropDownController(props.row.id);\n setCurrentId(props.row.id);\n setLoading(true);\n }}\n onClose={() => {\n setIsModalVisible(false);\n props.dropDownController(\"\");\n setCurrentId(\"\");\n }}\n icon={\n \n \"infoBlackIcon\"\n \n }\n >\n \n \n
    \n {isLoading || !currentId ? (\n
    \n \n
    \n ) : (\n <>\n

    \n Participate in campaigns\n

    \n {executionsList.length === 0 ? (\n
    No campaigns
    \n ) : (\n <>\n {executionsList?.map((item) => (\n \n
    \n
    \n {\n const url = item.archived\n ? `/archive/${item.id}`\n : `/campaigns/${item.id}`;\n window.open(url, \"_blank\");\n }}\n className=\"text-dropdown-title\"\n >\n
    \n {item.name}\n
    \n \n
    \n
    \n
    \n \n
    \n {statesDescriptor.getExecutionTitle(\n campaignState[item.id]\n )}\n
    \n
    \n
    \n
    \n ))}\n \n )}\n \n )}\n \n \n \n \n \n );\n};\n\nexport default InformationBlock;\n","// extracted by css-extract-rspack-plugin\nexport default {\"icon\":\"icon-WpYgkp\",\"desc\":\"desc-ktz2fz\"};","import clsx from 'clsx'\r\nimport { StackIcon } from 'shared/ui'\r\n\r\nimport css from './SortIcon.module.scss'\r\n\r\nconst SortIcon = (props: {\r\n\tidx: string\r\n\tisFiltering: string\r\n\tisRunning: boolean\r\n\tisSortedAsc: Record\r\n\tsetIsFiltering: any\r\n\tsetIsSortedAsc: any\r\n\tsort: string\r\n\ttext: string\r\n}) => {\r\n\tconst {\r\n\t\tidx,\r\n\t\tisFiltering = '',\r\n\t\tisRunning,\r\n\t\tisSortedAsc,\r\n\t\tsetIsFiltering,\r\n\t\tsetIsSortedAsc,\r\n\t\tsort,\r\n\t\ttext\r\n\t} = props\r\n\tconst isActive = isFiltering.includes(sort)\r\n\tconst getSortType = (idx: string, type: 'asc' | 'desc', running: string) => {\r\n\t\tswitch (idx) {\r\n\t\t\tcase 'contact':\r\n\t\t\t\treturn isRunning ? `${running}full_name ${type}` : `full_name ${type}`\r\n\t\t\tcase 'contacted':\r\n\t\t\t\treturn isRunning ? `${running}contacted ${type}` : `contacted ${type}`\r\n\t\t\tcase 'created':\r\n\t\t\t\treturn `created ${type}, id ${type}`\r\n\t\t\tcase 'custom_field_1':\r\n\t\t\t\treturn isRunning\r\n\t\t\t\t\t? `${running}custom_field_1 ${type}`\r\n\t\t\t\t\t: `custom_field_1 ${type}`\r\n\t\t\tcase 'custom_field_2':\r\n\t\t\t\treturn isRunning\r\n\t\t\t\t\t? `${running}custom_field_2 ${type}`\r\n\t\t\t\t\t: `custom_field_2 ${type}`\r\n\t\t\tcase 'custom_field_3':\r\n\t\t\t\treturn isRunning\r\n\t\t\t\t\t? `${running}custom_field_3 ${type}`\r\n\t\t\t\t\t: `custom_field_3 ${type}`\r\n\t\t\tcase 'headline':\r\n\t\t\t\treturn isRunning\r\n\t\t\t\t\t? `${running}occupation ${type} `\r\n\t\t\t\t\t: `occupation ${type}`\r\n\r\n\t\t\tcase 'imported':\r\n\t\t\t\treturn `imported ${type}`\r\n\t\t\tcase 'location':\r\n\t\t\t\treturn isRunning ? `${running}location ${type} ` : `location ${type}`\r\n\t\t\tcase 'status':\r\n\t\t\t\treturn `state ${type} `\r\n\t\t\tdefault:\r\n\t\t\t\treturn `imported ${type}`\r\n\t\t}\r\n\t}\r\n\r\n\tconst isAscend = isSortedAsc[idx]\r\n\tconst willBeAsc = !isAscend || !isActive\r\n\r\n\treturn (\r\n\t\t {\r\n\t\t\t\tsetIsSortedAsc(idx, willBeAsc)\r\n\t\t\t\tsetIsFiltering(\r\n\t\t\t\t\t`${getSortType(idx, willBeAsc ? 'asc' : 'desc', 'linkedin_contact/')}`\r\n\t\t\t\t)\r\n\t\t\t}}\r\n\t\t>\r\n\t\t\t

    {text}

    \r\n\t\t\t\r\n\t\t\r\n\t)\r\n}\r\n\r\nexport default SortIcon\r\n","import Checkbox from \"@mui/material/Checkbox\";\nimport CircularProgress from \"@mui/material/CircularProgress\";\nimport { AgGridReact } from \"ag-grid-react\";\nimport { PaginationWrapper } from \"components/atoms/mTablePagination/PaginationWrapper.tsx\";\nimport { ResponsiveButton } from \"components/atoms/responsiveButton\";\nimport React, { Component } from \"react\";\nimport { connect } from \"react-redux\";\nimport Select from \"react-select\";\n\nimport { contactsPageSize } from \"../../../api/contactsPageSize\";\nimport { statesDescriptor } from \"../../../api/statesDescriptor\";\nimport avatarSvg from \"../../../assets/image/icons/svg/user.svg\";\nimport selectedCheckboxIcon from \"../../../assets/image/icons/tables/checkbox2.svg\";\nimport partiallySelectedCheckboxIcon from \"../../../assets/image/icons/tables/checkbox3.svg\";\nimport notSelectedCheckboxIcon from \"../../../assets/image/icons/tables/checkbox.svg\";\nimport iconExcludeDisabled from \"../../../assets/image/icons/tables/exclude-disabled.svg\";\nimport iconExclude from \"../../../assets/image/icons/tables/exclude.svg\";\nimport inIconGray from \"../../../assets/image/icons/tables/linkedin-icon-gray.svg\";\nimport iconRemoveDisabled from \"../../../assets/image/icons/tables/remove-disabled.svg\";\nimport iconRemove from \"../../../assets/image/icons/tables/remove.svg\";\nimport { CONSTS } from \"../../../config/objectConst\";\nimport ButtonAddToCampaigns from \"../../atoms/buttonAddToCampaigns\";\nimport ButtonCreateCampaigns from \"../../atoms/buttonCreateCampaigns\";\nimport ConfirmationDialogContacts from \"../../atoms/ConfirmationDialogContacts\";\nimport ConfirmationDialogExclude from \"../../atoms/ConfirmationDialogExclude\";\nimport CustomCellRenderer from \"../../atoms/customCellRenderer\";\nimport CustomCheckbox from \"../../atoms/customCheckbox\";\nimport ExportToCSVButton from \"../../atoms/ExportToCSVButton\";\nimport HeaderCheckbox from \"../../atoms/headerCheckbox\";\nimport TableSettingsModal from \"../../atoms/tableSettingsModal\";\n\nimport \"ag-grid-community/dist/styles/ag-grid.css\";\nimport \"ag-grid-community/dist/styles/ag-theme-balham.css\";\n\nimport \"./style.scss\";\nimport TooltipCustom from \"../../atoms/tooltipCustom\";\nimport CustomTooltipWrapper from \"../../atoms/tooltipCustomWrapper\";\nimport ModalWindow from \"../ModalWindow\";\nimport BtnGroupContainer from \"./btn-group\";\nimport {\n areDisabledSelectionActions,\n clearCheckboxes,\n deleteContacts,\n deleteHandler,\n dropDownController,\n dropDownControllerContact,\n exportContacts,\n exportContactsForCampaign,\n exportRecentActivities,\n getColumnProperty,\n getContactsBySort,\n getInitialWidth,\n getInitialWidthOrFlex,\n getInitialWidthOrFlexSmall,\n getNewPage,\n getStylePagination,\n handleChangePage,\n handleClick,\n handlerCompleteExecutions,\n heightGenerator,\n onClearAllClick,\n onClickExclude,\n onColumnResized,\n onGridReady,\n onSelectAllClick,\n onSelectAllPageClick,\n previewContacts,\n removeContactsFromCampaign,\n removeExecutionsFromCampaign,\n saveState,\n transformContactsData,\n} from \"./functions\";\nimport InformationBlock from \"./informationBlock\";\nimport SortIcon from \"./sortIcons\";\nimport { appSelectors } from \"../../../redux/reducers/app\";\nimport { linkedInProfileOpener } from \"api/linkedInProfileOpener\";\n\nconst SHOW_ITEMS = [10, 25, 50, 100].map((amount) => ({\n label: `Show ${amount} items`,\n value: amount,\n}));\n\nclass TableUsers extends Component {\n constructor(props) {\n super(props);\n this.state = {\n columnDefs: [\n {\n cellRendererFramework: CustomCheckbox,\n cellRendererParams: {\n handleClick: handleClick.bind(this),\n },\n field: \"select\",\n headerComponentFramework: HeaderCheckbox,\n headerComponentParams: {\n handleChange: onSelectAllPageClick.bind(this),\n },\n headerName: \"\",\n hide: false,\n initialWidth: 65,\n suppressMovable: true,\n },\n {\n cellRendererFramework: CustomCellRenderer,\n field: \"contact\",\n headerName: \"CONTACT\",\n hide: getColumnProperty.call(\n this,\n \"contact\",\n false,\n this.props.type === \"single\"\n ),\n resizable: CONSTS.IS_RESIZABLE_TABLE ? true : false,\n suppressMovable: true,\n ...getInitialWidthOrFlex.call(\n this,\n \"contact\",\n this.props.type === \"single\"\n ),\n headerComponentFramework: () =>\n this.createSortData(\"Contact\", \"full_name\", \"contact\"),\n },\n\n {\n cellRendererFramework: (params) => (\n \n ),\n field: \"headline\",\n headerName: \"HEADLINE\",\n hide: getColumnProperty.call(\n this,\n \"headline\",\n false,\n this.props.type === \"single\"\n ),\n resizable: CONSTS.IS_RESIZABLE_TABLE ? true : false,\n suppressMovable: true,\n ...getInitialWidthOrFlex.call(\n this,\n \"headline\",\n this.props.type === \"single\"\n ),\n\n headerComponentFramework: () =>\n this.createSortData(\"Headline\", \"occupation\", \"headline\"),\n },\n {\n field: \"location\",\n headerName: \"LOCATION\",\n hide: getColumnProperty.call(\n this,\n \"location\",\n false,\n this.props.type === \"single\"\n ),\n resizable: CONSTS.IS_RESIZABLE_TABLE ? true : false,\n suppressMovable: true,\n ...getInitialWidthOrFlexSmall.call(\n this,\n \"location\",\n this.props.type === \"single\"\n ),\n headerComponentFramework: () =>\n this.createSortData(\"Location\", \"location\", \"location\"),\n },\n {\n field: \"status\",\n headerName: \"STATUS\",\n hide:\n this.props.type !== \"single\"\n ? true\n : getColumnProperty.call(\n this,\n \"status\",\n this.props.type !== \"single\",\n this.props.type === \"single\"\n ),\n resizable: CONSTS.IS_RESIZABLE_TABLE ? true : false,\n suppressMovable: true,\n ...getInitialWidthOrFlexSmall.call(\n this,\n \"status\",\n this.props.type === \"single\"\n ),\n cellRenderer: \"CustomCellStatusRerender\",\n headerComponentFramework: () => this.createData(\"Status\"),\n },\n {\n field: \"lastAction\",\n headerName: \"LAST ACTION\",\n hide: getColumnProperty.call(\n this,\n \"lastAction\",\n false,\n this.props.type === \"single\"\n ),\n resizable: CONSTS.IS_RESIZABLE_TABLE ? true : false,\n suppressMovable: true,\n ...getInitialWidthOrFlexSmall.call(\n this,\n \"lastAction\",\n this.props.type === \"single\"\n ),\n headerComponentFramework: () =>\n this.createSortData(\"Last Action\", \"contacted\", \"contacted\"),\n },\n {\n field: \"imported\",\n headerName: \"IMPORTED\",\n hide:\n this.props.type !== \"single\"\n ? getColumnProperty.call(\n this,\n \"imported\",\n false,\n this.props.type === \"single\"\n )\n : true,\n resizable: CONSTS.IS_RESIZABLE_TABLE ? true : false,\n suppressMovable: true,\n ...getInitialWidthOrFlexSmall.call(\n this,\n \"imported\",\n this.props.type === \"single\"\n ),\n headerComponentFramework: () =>\n this.createSortData(\"Imported\", \"imported\", \"imported\"),\n },\n {\n field: this.props.type === \"single\" ? \"added\" : \"created\",\n headerName: this.props.type === \"single\" ? \"ADDED\" : \"CREATED\",\n hide: getColumnProperty.call(\n this,\n this.props.type === \"single\" ? \"added\" : \"created\",\n this.props.type !== \"single\",\n this.props.type === \"single\"\n ),\n resizable: CONSTS.IS_RESIZABLE_TABLE ? true : false,\n suppressMovable: true,\n ...getInitialWidthOrFlexSmall.call(\n this,\n \"added\",\n this.props.type === \"single\"\n ),\n headerComponentFramework: () =>\n this.createSortData(\n this.props.type === \"single\" ? \"Added\" : \"Created\",\n \"created\",\n \"created\"\n ),\n },\n {\n cellRendererFramework: (params) => (\n \n ),\n field: \"custom1\",\n headerComponentFramework: () =>\n this.createSortData(\"Custom 1\", \"custom_field_1\", \"custom_field_1\"),\n headerName: \"CUSTOM 1\",\n hide: getColumnProperty.call(\n this,\n \"custom1\",\n true,\n this.props.type === \"single\"\n ),\n initialWidth: getInitialWidth.call(\n this,\n \"custom1\",\n this.props.type === \"single\"\n ),\n resizable: CONSTS.IS_RESIZABLE_TABLE ? true : false,\n suppressMovable: true,\n },\n {\n cellRendererFramework: (params) => (\n \n ),\n field: \"custom2\",\n headerComponentFramework: () =>\n this.createSortData(\"Custom 2\", \"custom_field_2\", \"custom_field_2\"),\n headerName: \"CUSTOM 2\",\n hide: getColumnProperty.call(\n this,\n \"custom2\",\n true,\n this.props.type === \"single\"\n ),\n initialWidth: getInitialWidth.call(\n this,\n \"custom2\",\n this.props.type === \"single\"\n ),\n resizable: CONSTS.IS_RESIZABLE_TABLE ? true : false,\n suppressMovable: true,\n },\n {\n cellRendererFramework: (params) => (\n \n ),\n field: \"custom3\",\n headerComponentFramework: () =>\n this.createSortData(\"Custom 3\", \"custom_field_3\", \"custom_field_3\"),\n headerName: \"CUSTOM 3\",\n hide: getColumnProperty.call(\n this,\n \"custom3\",\n true,\n this.props.type === \"single\"\n ),\n initialWidth: getInitialWidth.call(\n this,\n \"custom3\",\n this.props.type === \"single\"\n ),\n resizable: CONSTS.IS_RESIZABLE_TABLE ? true : false,\n suppressMovable: true,\n },\n {\n cellRenderer: \"ActionBtnRenderer\",\n headerName: \"Action Buttons\",\n pinned: \"right\",\n width:\n this.props.type === \"single\" &&\n this.props.campaignStatus !== \"Compose\"\n ? 170\n : 50,\n },\n ],\n confirmationDialog: {\n data: {},\n id: null,\n status: false,\n },\n confirmationDialogContacts: {\n data: {},\n status: false,\n },\n contacts: this.props.contacts,\n contactsModal: this.props.contactsModal,\n dropDownController: false,\n dropDownControllerContact: \"\",\n filterRows: [],\n getRowNodeId(data) {\n return data.id;\n },\n gridApi: null,\n hide: false,\n\n initialValuePagination: contactsPageSize.get(),\n isCampaignsRunning:\n this.props.campaignStatus === \"Running\" ||\n this.props.campaignStatus === \"Stopped\" ||\n this.props.campaignStatus === \"Completed\",\n isDelete: false,\n isDeleteContactsOpened: false,\n isExcludeContactsOpened: false,\n isLoadingCSV: false,\n isLoadingCSVCampaigns: false,\n isLoadingInteractionLog: false,\n isOpenMenuPagination: false,\n isRunningCampaigns:\n this.props.type === \"single\" && this.props.campaignStatus !== \"Compose\",\n needLoader: false,\n rowData: transformContactsData.call(this, avatarSvg),\n scrollBarWidth: false,\n selectAllUsersValue: false,\n selected: [],\n\n selectedValues: 0,\n status: this.props.campaignStatus,\n type: this.props.type,\n };\n\n this.onGridReadyBound = onGridReady.bind(this);\n this.SavedColState = React.createRef();\n }\n\n buttonsActions = (row, type, index) => {\n if (type === \"single\" || type === \"all\") {\n if (row.campaignExecutions?.actions) {\n return (\n row.campaignExecutions?.actions && (\n \n )\n );\n }\n if (row.actions?.open_linkedin_profile.enabled) {\n return (\n \n {type === \"all\" && (\n \n )}\n \n linkedInProfileOpener.open(row)}\n >\n \"linkedin\n \n \n \n );\n }\n }\n };\n\n changePagination(value) {\n this.setState({\n initialValuePagination: value,\n });\n\n this.props.setInitialValuePagination(value.toString());\n\n contactsPageSize.save(value);\n }\n componentDidUpdate(prevProps, prevState) {\n if (this.props.contacts && this.props.contacts !== prevProps.contacts) {\n this.setState({\n contacts: this.props.contacts,\n rowData: transformContactsData.call(this, avatarSvg),\n });\n }\n if (\n (this.props.contactsModal &&\n this.props.contactsModal !== prevProps.contactsModal) ||\n (this.props.isModalVisible &&\n this.props.isModalVisible !== prevProps.isModalVisible)\n ) {\n this.setState({\n contactsModal: this.props.contactsModal,\n rowData: transformContactsData.call(this, avatarSvg),\n });\n }\n\n if (\n this.props.isTableSettingsVisible &&\n this.props.isTableSettingsVisible !== prevProps.isTableSettingsVisible\n ) {\n saveState.call(this);\n }\n if (this.props.match.url !== prevProps.match.url) {\n this.props.dispatch({\n type: \"FILTERS_QUERY_CLEAR\",\n });\n }\n if (\n this.props.isFiltering !== prevProps.isFiltering &&\n this.type !== \"add-to-campaign\"\n ) {\n getContactsBySort.call(this);\n }\n if (\n this.props.isFilteringExecutions !== prevProps.isFilteringExecutions &&\n this.type !== \"add-to-campaign\"\n ) {\n getContactsBySort.call(this);\n }\n if (\n this.state.initialValuePagination !== prevState.initialValuePagination\n ) {\n handleChangePage.call(this);\n }\n }\n\n createData = (text) => {\n return (\n
    \n

    {text}

    \n
    \n );\n };\n\n createSortData = (text, sort, index) => {\n return (\n
    \n \n
    \n );\n };\n\n render() {\n const newPage =\n this.props.type === \"add-to-campaign\"\n ? this.props.contactsPageModal\n : this.props.contactsPage;\n const contactsCount =\n this.props.type === \"add-to-campaign\"\n ? this.props.contactsCountModal\n : this.props.contactsCount;\n const stylePagination = getStylePagination(this.state.isOpenMenuPagination);\n\n const accentPagination =\n contactsCount && contactsCount > this.state.initialValuePagination;\n\n return (\n <>\n {this.props.isTableSettingsVisible && (\n this.props.setIsTableSettingsVisible(false)}\n />\n )}\n \n {this.state.selectedValues > 0 && (\n
    \n <>\n
    \n 0}\n checkedIcon={\n \n this.state.selectedValues\n ? partiallySelectedCheckboxIcon\n : selectedCheckboxIcon\n : this.props.contacts.length >\n this.state.selectedValues\n ? partiallySelectedCheckboxIcon\n : selectedCheckboxIcon\n }\n />\n }\n icon={\"checkbox\"}\n indeterminate={\n this.props.type === \"add-to-campaign\"\n ? this.props.contactsModal &&\n this.props.contactsModal.length <\n this.state.selected.filter((item) =>\n this.props.contactsModal.includes(item)\n ).length\n : this.props.contacts &&\n this.props.contacts.length <\n this.state.selected.filter((item) =>\n this.props.contacts.includes(item)\n ).length\n }\n inputProps={{ \"aria-label\": \"select all items\" }}\n onChange={() => onSelectAllPageClick.call(this, false)}\n />\n
    \n {this.state.selectedValues > 0 && (\n
    \n \n {this.state.selectedValues} of {contactsCount} selected |{\" \"}\n \n {!this.state.selectAllUsersValue && (\n \n Select all\n \n )}\n\n {this.state.selectAllUsersValue && (\n \n Clear\n \n )}\n
    \n )}\n {this.props.checkboxs && (\n
    \n {this.props.type === \"all\" && (\n <>\n
    \n {\n exportContacts.call(this);\n }}\n text=\"Export to CSV\"\n />\n
    \n\n
    \n \n
    \n
    \n \n
    \n
    \n {\n previewContacts.call(this);\n }}\n >\n <>\n \n Delete\n \n \n
    \n \n )}\n {this.props.type === \"single\" && (\n <>\n {this.props.campaignStatus !== \"Compose\" && (\n
    \n {this.props.profile?.isProPlanAccessible ===\n false ? (\n <>\n \n
    \n
    \n pro\n
    \n
    \n \n {\n exportRecentActivities.call(this);\n }}\n text=\"Export Interaction Log\"\n />\n \n ) : (\n {\n exportRecentActivities.call(this);\n }}\n text=\"Export Interaction Log\"\n />\n )}\n
    \n )}\n
    \n {\n exportContactsForCampaign.call(this);\n }}\n text=\"Export Contacts\"\n >\n
    \n \n )}\n {this.props.type === \"single\" && (\n
    \n \n (this.state.isCampaignsRunning &&\n onClickExclude.call(this)) ||\n this.setState({\n isExcludeContactsOpened: true,\n })\n }\n >\n {this.state.needLoader ? (\n
    \n \n
    \n ) : (\n <>\n \n Exclude\n \n )}\n \n
    \n )}\n {this.props.type === \"add-to-campaign\" && (\n <>\n
    \n
    \n \n this.setState({\n selected: [],\n selectedValues: 0,\n })\n }\n text=\"Add to campaign\"\n />\n
    \n
    \n \n )}\n
    \n )}\n \n
    \n )}\n {this.props.app.tableContentLoader &&\n !this.props.app.pageContentLoader ? (\n
    \n \n
    \n ) : (\n \n (this.props.type === \"single\" || this.props.type === \"all\") &&\n this.buttonsActions(\n props.data,\n this.props.type,\n props.node.rowIndex\n ),\n cellRendererFramework: (params) => (\n \n ),\n CustomCellRenderer,\n CustomCellStatusRerender: (props) =>\n this.props.type === \"single\" &&\n this.props.campaignStatus !== \"Compose\"\n ? this.renderSteps(\n props.data.campaignExecutions?.step_executions,\n props.data.campaignExecutions\n )\n : \"...\",\n CustomCheckbox,\n HeaderCheckbox,\n }}\n getRowNodeId={(data) => data.id}\n onColumnResized={onColumnResized.bind(this)}\n onGridReady={onGridReady.bind(this)}\n rowData={this.state.rowData}\n rowSelection=\"multiple\"\n suppressRowClickSelection\n />\n )}\n \n {accentPagination ? (\n \n ) : (\n
    \n )}\n\n \n {\n this.setState({\n isOpenMenuPagination: false,\n });\n }}\n onChange={(e) => {\n const value = Number(e.value);\n this.changePagination(value);\n }}\n onFocus={() => {\n this.setState({\n isOpenMenuPagination: true,\n });\n }}\n options={SHOW_ITEMS}\n styles={stylePagination}\n value={SHOW_ITEMS.find(\n (el) => el.value === this.state.initialValuePagination\n )}\n />\n
    \n \n\n \n this.setState({ isExcludeContactsOpened: false })\n }\n closeText=\"No\"\n confirmHandler={deleteHandler.bind(this)}\n confirmText=\"Yes\"\n content={\n CONSTS.confirmationDialogs[\n this.state.isCampaignsRunning ? 1.8 : 1.6\n ].content\n }\n open={this.state.isExcludeContactsOpened}\n setIsDelete={(value) => {\n this.setState({ isDelete: value });\n }}\n title={\n CONSTS.confirmationDialogs[\n this.state.isCampaignsRunning ? 1.8 : 1.6\n ].title\n }\n />\n {this.state.isCampaignsRunning && (\n \n this.setState({\n confirmationDialog: {\n data: {},\n id: null,\n status: false,\n },\n })\n }\n open={this.state.confirmationDialog.status}\n >\n \n this.setState({\n confirmationDialog: {\n data: {},\n id: null,\n status: false,\n },\n })\n }\n confirmationDialog={this.state.confirmationDialog}\n exclude={removeExecutionsFromCampaign.bind(this)}\n />\n \n )}\n \n this.setState({\n confirmationDialogContacts: {\n data: {},\n id: null,\n status: false,\n },\n })\n }\n open={this.state.confirmationDialogContacts.status}\n >\n \n this.setState({\n confirmationDialogContacts: {\n data: {},\n id: null,\n status: false,\n },\n })\n }\n confirmationDialogContacts={this.state.confirmationDialogContacts}\n deleted={deleteContacts.bind(this)}\n />\n \n\n \n this.setState({ isDeleteContactsOpened: false })\n }\n closeText=\"No\"\n confirmHandler={deleteContacts.bind(this)}\n confirmText=\"Yes\"\n content={CONSTS.confirmationDialogs[1.9].content.replace(\n \"{contacts_count}\",\n this.state.selectedValues\n )}\n open={this.state.isDeleteContactsOpened}\n title={CONSTS.confirmationDialogs[1.9].title.replace(\n \"{contacts_count}\",\n this.state.selectedValues\n )}\n />\n \n {this.props.isTableSettingsVisible && (\n this.props.setIsTableSettingsVisible(false)}\n executions={this.props.type === \"single\"}\n updateDataSizeTable={this.updateDataSizeTable}\n />\n )}\n \n );\n }\n\n renderSteps = (row, item) => {\n const items = [];\n for (const index in row) {\n row[index].is_visible &&\n items.push(\n \n \n \n );\n }\n\n return
    {items}
    ;\n };\n\n updateDataSizeTable = (dataSizeTable) => {\n if (this.state.type !== \"single\") {\n localStorage.setItem(\n \"contactsGridSettings\",\n JSON.stringify(dataSizeTable)\n );\n this.state.gridColumnApi.applyColumnState({ state: dataSizeTable });\n } else if (this.state.type === \"single\") {\n localStorage.setItem(\n \"executionsGridSettings\",\n JSON.stringify(dataSizeTable)\n );\n this.state.gridColumnApi.applyColumnState({ state: dataSizeTable });\n }\n };\n}\n\nconst mapStateToProps = (state) => ({\n app: state.app,\n campaign: state.campaign,\n campaigns: state.campaigns,\n contacts: state.contacts.contacts,\n contactsCountModal: state.contacts.contactsCountModal,\n contactsModal: state.contacts.contactsModal,\n contactsPage: state.contacts.contactsPage,\n contactsPageModal: state.contacts.contactsPageModal,\n isModalVisible: state.contacts.isModalVisible,\n profile: appSelectors.appProfile(state),\n});\n\nexport default connect(mapStateToProps)(TableUsers);\n","import InputAdornment from '@mui/material/InputAdornment'\r\nimport TextField from '@mui/material/TextField'\r\nimport ArrowLeftIcon from 'assets/image/icons/svg/calendar/arrow-left-light-grey.svg'\r\nimport ArrowRightIcon from 'assets/image/icons/svg/calendar/arrow-right-light-grey.svg'\r\nimport 'react-datepicker/dist/react-datepicker.css'\r\n\r\nimport './style.scss'\r\n\r\nimport DoubleArrowLeftIcon from 'assets/image/icons/svg/calendar/double-arrow-left-grey.svg'\r\nimport DoubleArrowRightIcon from 'assets/image/icons/svg/calendar/double-arrow-right-grey.svg'\r\nimport DateIcon from 'assets/image/icons/svg/date-icon-yellow.svg'\r\nimport { useId } from 'react'\r\nimport DatePicker, { type DatePickerProps } from 'react-datepicker'\r\nimport { appDay } from 'shared/day'\r\n\r\nexport function ReactDatePicker({\r\n\tlabel,\r\n\tplaceholder,\r\n\tvalue,\r\n\t...props\r\n}: DatePickerProps & {\r\n\tlabel?: string\r\n\tplaceholder?: string\r\n\tvalue?: Date\r\n}) {\r\n\tconst uniqueId = useId()\r\n\treturn (\r\n\t\t
    \r\n\t\t\t{label && (\r\n\t\t\t\t\r\n\t\t\t)}\r\n\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t),\r\n\t\t\t\t\t\t\t\tid: uniqueId,\r\n\t\t\t\t\t\t\t\tstyle: {\r\n\t\t\t\t\t\t\t\t\tfontSize: '14px',\r\n\t\t\t\t\t\t\t\t\tmargin: 0,\r\n\t\t\t\t\t\t\t\t\tpadding: '0 6px 0 0'\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}}\r\n\t\t\t\t\t\tvariant='outlined'\r\n\t\t\t\t\t/>\r\n\t\t\t\t}\r\n\t\t\t\tdateFormat='MM-dd-yyyy'\r\n\t\t\t\t{...props}\r\n\t\t\t\tplaceholderText={placeholder}\r\n\t\t\t\trenderCustomHeader={({\r\n\t\t\t\t\tdate,\r\n\t\t\t\t\tdecreaseMonth,\r\n\t\t\t\t\tdecreaseYear,\r\n\t\t\t\t\tincreaseMonth,\r\n\t\t\t\t\tincreaseYear,\r\n\t\t\t\t\tnextMonthButtonDisabled,\r\n\t\t\t\t\tnextYearButtonDisabled,\r\n\t\t\t\t\tprevMonthButtonDisabled,\r\n\t\t\t\t\tprevYearButtonDisabled\r\n\t\t\t\t}) => (\r\n\t\t\t\t\t
    \r\n\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t{appDay(date).format('MMM YYYY')}\r\n\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t
    \r\n\t\t\t\t\t
    \r\n\t\t\t\t)}\r\n\t\t\t\tshowPopperArrow={false}\r\n\t\t\t\ttodayButton='Today'\r\n\t\t\t/>\r\n\t\t
    \r\n\t)\r\n}\r\n","// extracted by css-extract-rspack-plugin\nexport default {\"root\":\"root-J7pqUi\"};","import { ReactDatePicker } from '../ReactDatePicker/ReactDatePicker'\r\nimport css from './DatePickerRange.module.scss'\r\n\r\nexport const DatePickerRange = ({\r\n\tendDate,\r\n\tonChangeEndDate,\r\n\tonChangeStartDate,\r\n\tstartDate\r\n}: {\r\n\tendDate?: Date\r\n\tonChangeEndDate: (date: Date) => void\r\n\tonChangeStartDate: (date: Date) => void\r\n\tstartDate?: Date\r\n}) => (\r\n\t
    \r\n\t\t date instanceof Date && onChangeStartDate(date)}\r\n\t\t\tplaceholder='From'\r\n\t\t\tselected={startDate}\r\n\t\t\tselectsStart\r\n\t\t\tstartDate={startDate}\r\n\t\t/>\r\n\t\t date instanceof Date && onChangeEndDate(date)}\r\n\t\t\tplaceholder='To'\r\n\t\t\tpopperPlacement='bottom-end'\r\n\t\t\tselected={endDate}\r\n\t\t\tselectsEnd\r\n\t\t\tstartDate={startDate}\r\n\t\t/>\r\n\t
    \r\n)\r\n","import PropTypes from \"prop-types\";\nimport clsx from \"clsx\";\nimport { RadioGroup, Radio, FormControlLabel } from \"@mui/material\";\nimport makeStyles from \"@mui/styles/makeStyles\";\nimport { useId } from \"react\";\n\nRadioGroupCustom.propTypes = {\n items: PropTypes.array,\n value: PropTypes.any,\n onChange: PropTypes.func.isRequired,\n label: PropTypes.string,\n};\n\nfunction RadioGroupCustom(props) {\n const label = labelStyles();\n const radio = radioStyles();\n const uniqueId = useId();\n\n return (\n
    \n {props.label && (\n \n )}\n \n {props.items.map((item) => {\n return (\n \n
    \n
    \n }\n icon={
    }\n />\n }\n label={item.text}\n classes={label}\n />\n );\n })}\n \n
    \n );\n}\n\nconst labelStyles = makeStyles((theme) => ({\n label: {\n fontSize: \"14px !important\",\n lineHeight: \"20px !important\",\n color: \"#202020 !important\",\n },\n}));\n\nconst radioStyles = makeStyles((theme) => ({\n root: {\n color: \"#0cb39f !important\",\n \"&:hover\": {\n backgroundColor: \"transparent !important\",\n },\n },\n checked: {\n color: \"#0cb39f !important\",\n \"&:hover\": {\n backgroundColor: \"transparent !important\",\n },\n },\n icon: {\n borderRadius: \"50%\",\n width: 16,\n height: 16,\n backgroundColor: \"transparent\",\n border: \"1px solid #EBEDF2\",\n },\n checkedIconDot: {\n width: 8,\n height: 8,\n borderRadius: \"50%\",\n backgroundColor: \"#016069\",\n },\n checkedIcon: {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"transparent\",\n backgroundImage: \"none\",\n },\n}));\n\nexport default RadioGroupCustom;\n","const filterDataInitial = [\r\n\t{\r\n\t\texclude: false,\r\n\t\tid: 1,\r\n\t\tname: 'connection',\r\n\t\tsearch: false,\r\n\t\ttag: '',\r\n\t\tvalue: []\r\n\t},\r\n\t{\r\n\t\texclude: false,\r\n\t\tid: 2,\r\n\t\tname: 'location',\r\n\t\tsearch: false,\r\n\t\ttag: '',\r\n\t\tvalue: []\r\n\t},\r\n\t{\r\n\t\texclude: false,\r\n\t\tid: 3,\r\n\t\tname: 'industry',\r\n\t\tsearch: false,\r\n\t\ttag: '',\r\n\t\tvalue: []\r\n\t},\r\n\t{\r\n\t\texclude: false,\r\n\t\tid: 4,\r\n\t\tname: 'keywords',\r\n\t\tsearch: true,\r\n\t\ttag: '',\r\n\t\tvalue: []\r\n\t},\r\n\t{\r\n\t\texclude: false,\r\n\t\tid: 5,\r\n\t\tname: 'company',\r\n\t\tsearch: false,\r\n\t\ttag: '',\r\n\t\tvalue: []\r\n\t},\r\n\t{\r\n\t\texclude: false,\r\n\t\tid: 6,\r\n\t\tname: 'contacted',\r\n\t\tsearch: false,\r\n\t\tselectId: 9,\r\n\t\ttag: '',\r\n\t\tvalue: [\r\n\t\t\t{ id: 1, value: null },\r\n\t\t\t{ id: 2, value: null }\r\n\t\t]\r\n\t},\r\n\t{\r\n\t\texclude: false,\r\n\t\tid: 7,\r\n\t\tname: 'status',\r\n\t\tsearch: false,\r\n\t\ttag: '',\r\n\t\tvalue: ''\r\n\t},\r\n\t{\r\n\t\texclude: false,\r\n\t\tid: 8,\r\n\t\tname: 'createdSelect',\r\n\t\tsearch: false,\r\n\t\tvalue: null\r\n\t},\r\n\t{\r\n\t\texclude: false,\r\n\t\tid: 9,\r\n\t\tname: 'contactedSelect',\r\n\t\tsearch: false,\r\n\t\tvalue: null\r\n\t},\r\n\t{\r\n\t\texclude: false,\r\n\t\tid: 10,\r\n\t\tname: 'campaigns',\r\n\t\tsearch: false,\r\n\t\ttag: '',\r\n\t\tvalue: []\r\n\t},\r\n\t{\r\n\t\texclude: false,\r\n\t\tid: 11,\r\n\t\tname: 'exclude contactedSelect',\r\n\t\tsearch: false,\r\n\t\tvalue: null\r\n\t},\r\n\t{\r\n\t\texclude: true,\r\n\t\tid: 12,\r\n\t\tname: 'NOT: keywords',\r\n\t\tsearch: true,\r\n\t\ttag: '',\r\n\t\tvalue: []\r\n\t},\r\n\t{\r\n\t\texclude: true,\r\n\t\tid: 13,\r\n\t\tname: 'NOT: campaigns',\r\n\t\tsearch: false,\r\n\t\ttag: '',\r\n\t\tvalue: []\r\n\t},\r\n\t{\r\n\t\texclude: true,\r\n\t\tid: 14,\r\n\t\tname: 'NOT: contacted',\r\n\t\tsearch: false,\r\n\t\tselectId: 11,\r\n\t\ttag: '',\r\n\t\tvalue: [\r\n\t\t\t{ id: 1, value: null },\r\n\t\t\t{ id: 2, value: null }\r\n\t\t]\r\n\t},\r\n\t{\r\n\t\texclude: false,\r\n\t\tid: 15,\r\n\t\tname: 'created',\r\n\t\tsearch: false,\r\n\t\tselectId: 8,\r\n\t\ttag: '',\r\n\t\tvalue: [\r\n\t\t\t{ id: 1, value: null },\r\n\t\t\t{ id: 2, value: null }\r\n\t\t]\r\n\t}\r\n]\r\n\r\nexport type FilterItem = (typeof filterDataInitial)[number]\r\n\r\nexport { filterDataInitial }\r\n","import Grid from \"@mui/material/Grid\";\nimport { app } from \"actions/app\";\nimport { contacts } from \"actions/contacts\";\n\n// Style\nimport \"./style.scss\";\n\nimport { filters } from \"actions/filters\";\nimport LocationIcon from \"assets/image/icons/svg/location-icon-yellow.svg\";\nimport { CONSTS } from \"config/objectConst\";\nimport isEqual from \"lodash/isEqual\";\nimport PropTypes from \"prop-types\";\nimport { Component } from \"react\";\nimport { connect } from \"react-redux\";\nimport { withRouter } from \"react-router-dom\";\nimport { appDay } from \"shared/day\";\nimport { Button } from \"shared/ui\";\n\nimport { DatePickerRange } from \"../../atoms/DatePickerRange/DatePickerRange\";\nimport DropdownSimple from \"../../atoms/DropdownSimple\";\nimport RadioGroupCustom from \"../../atoms/RadioGroupCustom\";\nimport { filterDataInitial } from \"./const\";\nimport css from \"./Filters.module.scss\";\n\nexport class Filters extends Component {\n static propTypes = {\n filtersData: PropTypes.array,\n };\n\n /** @return {import(\"./const\").FilterItem[]} */\n get filterData() {\n return this.isModal ? this.state.filterDataForModal : this.state.filterData;\n }\n\n get filterKey() {\n return this.isModal ? \"filterDataForModal\" : \"filterData\";\n }\n\n get isModal() {\n return this.props.from === \"addToCampaignOfModal\";\n }\n\n constructor(props) {\n super(props);\n\n this.state = this.createStateFromProps();\n }\n\n applyFilter = async () => {\n const filterData = structuredClone(this.filterData);\n\n const activeImportId = this.props.match.params.id;\n\n filters.changeAllTags(filterData);\n if (this.isModal) {\n this.props.loadHandlerForModal(true);\n this.props.pageHandler(0);\n\n const filter = [`not (campaigns/any(c:c eq '${activeImportId}'))`];\n const filtersQuery = filters.buildFilterQuery(filterData);\n if (filtersQuery) {\n filter.push(filtersQuery);\n }\n\n filters.changeFiltersQueryForModal(\n filterData,\n this.props.from,\n activeImportId\n );\n this.props.getContacts({\n filter: filter.join(\" and \"),\n keywords: this.props.keywordsForModal,\n orderby: this.props.orderby,\n skip: 0,\n });\n filters.changeFiltersForModal(filterData, true);\n } else {\n app.changeTableContentLoaderStatus(true);\n contacts.changeContactsPage(0);\n contacts.changeContactsPageModal(0);\n await filters.getContacts(\n filterData,\n activeImportId,\n this.props.from,\n this.props.page,\n this.props.keywords,\n this.props.history.location.pathname,\n this.props.isFiltering\n );\n filters.changeFilters(filterData, true);\n }\n\n if (this.props.show === true) {\n this.props.filtersControllerToggle();\n }\n this.props.clearFilterController(false);\n };\n\n clearFilterData = () => {\n const key = this.filterKey;\n this.setState({ [key]: filterDataInitial });\n };\n\n clearValue = (id, option) => {\n const isModal = this.isModal;\n const filterData = this.filterData;\n\n const index = this.findIndexById(id);\n\n if (index === -1) {\n return;\n }\n const old = filterData[index];\n\n filterData[index] = {\n ...old,\n value: old.value?.filter((item) => option.key !== item.key),\n };\n\n const key = this.filterKey;\n this.setState({ [key]: filterData });\n };\n\n /* TODO #596 `Состояние фильтров не делиться между страницами, а обнуляется.`\n clearAllFilters when change router and component mount\n */\n componentDidMount() {\n // this.clearFilterData();\n }\n\n componentDidUpdate(prevProps, prevState, snapshot) {\n // Here are coming actual props, not previous.\n // Most likely they are improperly maintained\n // Due to this we store previous props in local state as a workaround\n if (\n !isEqual(\n this.props.filters.filterDataForModal,\n this.state.previousPropsFilterDataForModal\n ) ||\n !isEqual(\n this.props.filters.filterData,\n this.state.previousPropsFilterData\n )\n ) {\n this.setState(this.createStateFromProps());\n }\n\n if (\n this.props.keywordsForModal !== prevProps.keywordsForModal ||\n this.props.keywords !== prevProps.keywords\n ) {\n this.setState(this.createStateFromProps(), async () => {\n await this.applyFilter();\n });\n }\n }\n\n componentWillUnmount() {\n this.unlisten();\n }\n\n createStateFromProps() {\n const result = {\n filterData: structuredClone(this.props.filters.filterData),\n\n filterDataForModal: structuredClone(\n this.props.filters.filterDataForModal\n ),\n\n previousPropsFilterData: structuredClone(this.props.filters.filterData),\n\n previousPropsFilterDataForModal: structuredClone(\n this.props.filters.filterDataForModal\n ),\n };\n return result;\n }\n\n findIndexById = (id) => this.filterData.findIndex((item) => item.id === id);\n\n getById = (id) => this.filterData.find((item) => item.id === id);\n\n getStartEndValue = (id, dateId) => {\n const values = this.getValue(id);\n const found = values?.find((item) => \"id\" in item && item.id === dateId);\n return found?.value;\n };\n\n getValue = (id) => this.getById(id)?.value;\n\n isActiveCustom = (id) => this.getValue(id)?.value === \"custom\";\n\n render() {\n return (\n