From 29d6472c48de3058dbfa267563de3af243c31509 Mon Sep 17 00:00:00 2001 From: Rishad Alam <101513331+RishadAlam@users.noreply.github.com> Date: Mon, 9 Feb 2026 18:25:31 +0600 Subject: [PATCH 1/7] feat: user registration and membership integration added --- .../components/AllIntegrations/EditInteg.jsx | 5 + .../components/AllIntegrations/IntegInfo.jsx | 11 ++ .../components/AllIntegrations/NewInteg.jsx | 12 ++ .../EditUserRegistrationMembership.jsx | 75 ++++++++ .../UserRegistrationMembership.jsx | 119 ++++++++++++ .../UserRegistrationMembershipActions.jsx | 30 +++ ...serRegistrationMembershipAuthorization.jsx | 84 +++++++++ .../UserRegistrationMembershipCommonFunc.js | 161 +++++++++++++++++ .../UserRegistrationMembershipFieldMap.jsx | 114 ++++++++++++ .../UserRegistrationMembershipIntegLayout.jsx | 171 ++++++++++++++++++ .../UserRegistrationMembership/staticData.js | 5 + .../src/components/Flow/New/SelectAction.jsx | 7 +- .../img/integ/userRegistrationMembership.webp | Bin 0 -> 3914 bytes .../RecordApiHelper.php | 81 +++++++++ .../UserRegistrationMembership/Routes.php | 12 ++ .../UserRegistrationMembershipController.php | 99 ++++++++++ includes/Flow/Flow.php | 5 + 17 files changed, 988 insertions(+), 3 deletions(-) create mode 100644 frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/EditUserRegistrationMembership.jsx create mode 100644 frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembership.jsx create mode 100644 frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipActions.jsx create mode 100644 frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipAuthorization.jsx create mode 100644 frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipCommonFunc.js create mode 100644 frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipFieldMap.jsx create mode 100644 frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx create mode 100644 frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/staticData.js create mode 100644 frontend-dev/src/resource/img/integ/userRegistrationMembership.webp create mode 100644 includes/Actions/UserRegistrationMembership/RecordApiHelper.php create mode 100644 includes/Actions/UserRegistrationMembership/Routes.php create mode 100644 includes/Actions/UserRegistrationMembership/UserRegistrationMembershipController.php diff --git a/frontend-dev/src/components/AllIntegrations/EditInteg.jsx b/frontend-dev/src/components/AllIntegrations/EditInteg.jsx index 2de4d846..c1fe1b43 100644 --- a/frontend-dev/src/components/AllIntegrations/EditInteg.jsx +++ b/frontend-dev/src/components/AllIntegrations/EditInteg.jsx @@ -175,6 +175,9 @@ const EditTeamsForWooCommerceMemberships = lazy( () => import('./TeamsForWooCommerceMemberships/EditTeamsForWooCommerceMemberships') ) const EditSeoPress = lazy(() => import('./SeoPress/EditSeoPress')) +const EditUserRegistrationMembership = lazy( + () => import('./UserRegistrationMembership/EditUserRegistrationMembership') +) const loaderStyle = { display: 'flex', @@ -352,6 +355,8 @@ const IntegType = memo(({ allIntegURL, flow }) => { return case 'Keap': return + case 'User Registration & Membership': + return case 'Freshdesk': return case 'Zoom': diff --git a/frontend-dev/src/components/AllIntegrations/IntegInfo.jsx b/frontend-dev/src/components/AllIntegrations/IntegInfo.jsx index 03a4bf23..f0c5af83 100644 --- a/frontend-dev/src/components/AllIntegrations/IntegInfo.jsx +++ b/frontend-dev/src/components/AllIntegrations/IntegInfo.jsx @@ -176,6 +176,9 @@ const TeamsForWooCommerceMembershipsAuthorization = lazy( () => import('./TeamsForWooCommerceMemberships/TeamsForWooCommerceMembershipsAuthorization') ) const SeoPressAuthorization = lazy(() => import('./SeoPress/SeoPressAuthorization')) +const UserRegistrationMembershipAuthorization = lazy( + () => import('./UserRegistrationMembership/UserRegistrationMembershipAuthorization') +) export default function IntegInfo() { const { id, type } = useParams() @@ -278,6 +281,14 @@ export default function IntegInfo() { isInfo /> ) + case 'User Registration & Membership': + return ( + + ) case 'Zoho Bigin': return ( import('./TeamsForWooCommerceMemberships/TeamsForWooCommerceMemberships') ) const SeoPress = lazy(() => import('./SeoPress/SeoPress')) +const UserRegistrationMembership = lazy( + () => import('./UserRegistrationMembership/UserRegistrationMembership') +) export default function NewInteg({ allIntegURL }) { const { integUrlName } = useParams() @@ -809,6 +812,15 @@ export default function NewInteg({ allIntegURL }) { setFlow={setFlow} /> ) + case 'User Registration & Membership': + return ( + + ) case 'Mailercloud': return ( + + +
+ {__('Integration Name:', 'bit-integrations')} + handleInput(e, userRegistrationConf, setUserRegistrationConf)} + name="name" + value={userRegistrationConf.name} + type="text" + placeholder={__('Integration Name...', 'bit-integrations')} + /> +
+
+ + + + + + + saveActionConf({ + flow, + setFlow, + allIntegURL, + conf: userRegistrationConf, + navigate, + id, + edit: 1, + setIsLoading, + setSnackbar + }) + } + disabled={!checkMappedFields(userRegistrationConf)} + isLoading={isLoading} + dataConf={userRegistrationConf} + setDataConf={setUserRegistrationConf} + formFields={formFields} + /> +
+ + ) +} diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembership.jsx b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembership.jsx new file mode 100644 index 00000000..91d55802 --- /dev/null +++ b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembership.jsx @@ -0,0 +1,119 @@ +import { useState } from 'react' +import 'react-multiple-select-dropdown-lite/dist/index.css' +import { useNavigate, useParams } from 'react-router-dom' +import BackIcn from '../../../Icons/BackIcn' +import { __ } from '../../../Utils/i18nwrap' +import SnackMsg from '../../Utilities/SnackMsg' +import { saveIntegConfig } from '../IntegrationHelpers/IntegrationHelpers' +import IntegrationStepThree from '../IntegrationHelpers/IntegrationStepThree' +import UserRegistrationMembershipAuthorization from './UserRegistrationMembershipAuthorization' +import { checkMappedFields } from './UserRegistrationMembershipCommonFunc' +import UserRegistrationMembershipIntegLayout from './UserRegistrationMembershipIntegLayout' + +export default function UserRegistrationMembership({ formFields, setFlow, flow, allIntegURL }) { + const navigate = useNavigate() + const [isLoading, setIsLoading] = useState(false) + const [step, setStep] = useState(1) + const [snack, setSnackbar] = useState({ show: false }) + const [userRegistrationConf, setUserRegistrationConf] = useState({ + name: 'User Registration & Membership', + type: 'User Registration & Membership', + field_map: [{ formField: '', userRegistrationField: '' }], + actions: {}, + mainAction: '' + }) + + const nextPage = val => { + setTimeout(() => { + document.getElementById('btcd-settings-wrp').scrollTop = 0 + }, 300) + + if (val === 3) { + if (!checkMappedFields(userRegistrationConf)) { + setSnackbar({ + show: true, + msg: __('Please map all required fields to continue.', 'bit-integrations') + }) + return + } + + if (userRegistrationConf.name !== '' && userRegistrationConf.field_map.length > 0) { + setStep(val) + } + } else { + setStep(val) + } + } + + return ( +
+ +
{/* */}
+ + {/* STEP 1 */} + + + {/* STEP 2 */} +
+ +
+
+
+ +
+ + {/* STEP 3 */} + + saveIntegConfig( + flow, + setFlow, + allIntegURL, + userRegistrationConf, + navigate, + '', + '', + setIsLoading + ) + } + isLoading={isLoading} + dataConf={userRegistrationConf} + setDataConf={setUserRegistrationConf} + formFields={formFields} + /> +
+ ) +} diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipActions.jsx b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipActions.jsx new file mode 100644 index 00000000..52904974 --- /dev/null +++ b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipActions.jsx @@ -0,0 +1,30 @@ +/* eslint-disable no-param-reassign */ +// import { __ } from '../../../Utils/i18nwrap' +// import TableCheckBox from '../../Utilities/TableCheckBox' + +export default function UserRegistrationMembershipActions({ userRegistrationConf, setUserRegistrationConf }) { + // const actionHandler = (e, type) => { + // const newConf = { ...userRegistrationConf } + // if (type === 'update') { + // if (e.target.checked) { + // newConf.actions.update = true + // } else { + // delete newConf.actions.update + // } + // } + // setUserRegistrationConf({ ...newConf }) + // } + + return ( +
+ {/* actionHandler(e, 'update')} + className="wdt-200 mt-4 mr-2" + value="user_update" + title={__('Update User', 'bit-integrations')} + subTitle={__('Update existing user if user already exists', 'bit-integrations')} + /> */} +
+ ) +} diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipAuthorization.jsx b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipAuthorization.jsx new file mode 100644 index 00000000..bbedd0f4 --- /dev/null +++ b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipAuthorization.jsx @@ -0,0 +1,84 @@ +import { useState } from 'react' +import { __ } from '../../../Utils/i18nwrap' +import LoaderSm from '../../Loaders/LoaderSm' +import Note from '../../Utilities/Note' +import { userRegistrationAuthorize } from './UserRegistrationMembershipCommonFunc' +import tutorialLinks from '../../../Utils/StaticData/tutorialLinks' +import TutorialLink from '../../Utilities/TutorialLink' + +export default function UserRegistrationMembershipAuthorization({ + userRegistrationConf, + setUserRegistrationConf, + step, + nextPage, + isLoading, + setIsLoading, + setSnackbar +}) { + const [isAuthorized, setIsAuthorized] = useState(false) + const [showAuthMsg, setShowAuthMsg] = useState(false) + const { userRegistrationMembership } = tutorialLinks + + const handleAuthorize = () => { + userRegistrationAuthorize(setIsAuthorized, setShowAuthMsg, setIsLoading, setSnackbar, nextPage) + } + + return ( +
+ {userRegistrationMembership?.youTubeLink && ( + + )} + {userRegistrationMembership?.docLink && ( + + )} + +
+ {__('Integration Name:', 'bit-integrations')} +
+ setUserRegistrationConf({ ...userRegistrationConf, name: e.target.value })} + name="name" + value={userRegistrationConf.name} + type="text" + placeholder={__('Integration Name...', 'bit-integrations')} + disabled={isAuthorized} + /> + + +
+ {showAuthMsg && isAuthorized && ( +
+ +
+ )} + +
+ ) +} diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipCommonFunc.js b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipCommonFunc.js new file mode 100644 index 00000000..acc6d2aa --- /dev/null +++ b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipCommonFunc.js @@ -0,0 +1,161 @@ +import { __ } from '../../../Utils/i18nwrap' +import bitsFetch from '../../../Utils/bitsFetch' + +export const handleInput = (e, userRegistrationConf, setUserRegistrationConf) => { + const { name, value } = e.target + const newConf = { ...userRegistrationConf } + newConf[name] = value + setUserRegistrationConf(newConf) +} + +export const userRegistrationAuthorize = ( + setIsAuthorized, + setShowAuthMsg, + setIsLoading, + setSnackbar, + nextPage +) => { + setIsLoading(true) + bitsFetch({}, 'user_registration_authorize') + .then(result => { + if (result?.success) { + setIsAuthorized(true) + setShowAuthMsg(true) + setSnackbar({ + show: true, + msg: __('Connected Successfully', 'bit-integrations') + }) + nextPage(2) + } else { + setSnackbar({ + show: true, + msg: __( + result?.data || + 'Connection failed. Please make sure User Registration and Membership plugin is installed and activated.', + 'bit-integrations' + ) + }) + } + setIsLoading(false) + }) + .catch(error => { + setSnackbar({ + show: true, + msg: __('Connection failed', 'bit-integrations') + }) + setIsLoading(false) + }) +} + +export const refreshForms = ( + userRegistrationConf, + setUserRegistrationConf, + setIsLoading, + setSnackbar +) => { + setIsLoading(true) + bitsFetch({}, 'refresh_user_registration_forms') + .then(result => { + if (result?.success && result?.data) { + const newConf = { ...userRegistrationConf } + if (!newConf.default) { + newConf.default = {} + } + newConf.default.forms = result.data.forms || [] + setUserRegistrationConf(newConf) + setSnackbar({ + show: true, + msg: __('Forms refreshed successfully', 'bit-integrations') + }) + } else { + setSnackbar({ + show: true, + msg: __('Failed to refresh forms', 'bit-integrations') + }) + } + setIsLoading(false) + }) + .catch(() => { + setSnackbar({ + show: true, + msg: __('Failed to refresh forms', 'bit-integrations') + }) + setIsLoading(false) + }) +} + +export const refreshFormFields = ( + formId, + userRegistrationConf, + setUserRegistrationConf, + setIsLoading, + setSnackbar +) => { + if (!formId) { + return + } + + setIsLoading(true) + bitsFetch({ form_id: formId }, 'refresh_user_registration_form_fields') + .then(result => { + if (result?.success && result?.data) { + const newConf = { ...userRegistrationConf } + if (!newConf.default) { + newConf.default = {} + } + newConf.default.formFields = result.data.fields || [] + newConf.field_map = generateMappedField(newConf.default.formFields) + setUserRegistrationConf(newConf) + setSnackbar({ + show: true, + msg: __('Form fields refreshed successfully', 'bit-integrations') + }) + } else { + setSnackbar({ + show: true, + msg: __('Failed to refresh form fields', 'bit-integrations') + }) + } + setIsLoading(false) + }) + .catch(() => { + setSnackbar({ + show: true, + msg: __('Failed to refresh form fields', 'bit-integrations') + }) + setIsLoading(false) + }) +} + +export const generateMappedField = fields => { + const requiredFlds = fields.filter(fld => fld.required === true) + return requiredFlds.length > 0 + ? requiredFlds.map(field => ({ + formField: '', + userRegistrationField: field.value || field.key + })) + : [{ formField: '', userRegistrationField: '' }] +} + +export const checkMappedFields = userRegistrationConf => { + const { mainAction, field_map, selectedForm } = userRegistrationConf + + if (!mainAction || mainAction !== 'create_user') { + return false + } + + if (!selectedForm) { + return false + } + + const formFields = userRegistrationConf?.default?.formFields || [] + const requiredFields = formFields.filter(fld => fld.required === true || fld.required === 'true') + + if (requiredFields.length === 0) { + return field_map.length > 0 + } + + const mappedFields = field_map.map(field => field.userRegistrationField).filter(f => f) + + return requiredFields.every(reqField => mappedFields.includes(reqField.value)) +} diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipFieldMap.jsx b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipFieldMap.jsx new file mode 100644 index 00000000..c1308b53 --- /dev/null +++ b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipFieldMap.jsx @@ -0,0 +1,114 @@ +import { useRecoilValue } from 'recoil' +import { $btcbi } from '../../../GlobalStates' +import { __, sprintf } from '../../../Utils/i18nwrap' +import { SmartTagField } from '../../../Utils/StaticData/SmartTagField' +import TagifyInput from '../../Utilities/TagifyInput' +import { + addFieldMap, + delFieldMap, + handleCustomValue, + handleFieldMapping +} from '../GlobalIntegrationHelper' + +export default function UserRegistrationMembershipFieldMap({ + i, + formFields, + field, + userRegistrationConf, + setUserRegistrationConf +}) { + const btcbi = useRecoilValue($btcbi) + const { isPro } = btcbi + + const requiredFlds = + userRegistrationConf?.default?.formFields?.filter(fld => fld.required === true) || [] + const nonRequiredFlds = + userRegistrationConf?.default?.formFields?.filter(fld => fld.required === false) || [] + console.log(formFields) + return ( +
+
+
+ + + {field.formField === 'custom' && ( + handleCustomValue(e, i, userRegistrationConf, setUserRegistrationConf)} + label={__('Custom Value', 'bit-integrations')} + className="mr-2" + type="text" + value={field.customValue} + placeholder={__('Custom Value', 'bit-integrations')} + formFields={formFields} + /> + )} + + +
+ {i >= requiredFlds.length && ( + <> + + + + )} +
+
+ ) +} diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx new file mode 100644 index 00000000..f7ab0881 --- /dev/null +++ b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx @@ -0,0 +1,171 @@ +import { useEffect, useState } from 'react' +import MultiSelect from 'react-multiple-select-dropdown-lite' +import 'react-multiple-select-dropdown-lite/dist/index.css' +import { useRecoilValue } from 'recoil' +import { $btcbi } from '../../../GlobalStates' +import { __ } from '../../../Utils/i18nwrap' +import Loader from '../../Loaders/Loader' +import { checkIsPro, getProLabel } from '../../Utilities/ProUtilHelpers' +import { addFieldMap, delFieldMap, handleFieldMapping } from '../IntegrationHelpers/IntegrationHelpers' +import UserRegistrationMembershipFieldMap from './UserRegistrationMembershipFieldMap' +import { refreshForms, refreshFormFields } from './UserRegistrationMembershipCommonFunc' +import { modules } from './staticData' + +export default function UserRegistrationMembershipIntegLayout({ + formFields, + userRegistrationConf, + setUserRegistrationConf, + setIsLoading, + isLoading, + setSnackbar +}) { + const btcbi = useRecoilValue($btcbi) + const { isPro } = btcbi + + const changeHandler = (val, name) => { + const newConf = { ...userRegistrationConf } + + if (name === 'mainAction') { + newConf.mainAction = val + newConf.field_map = [{ formField: '', userRegistrationField: '' }] + + refreshForms(newConf, setUserRegistrationConf, setIsLoading, setSnackbar) + } else if (name === 'selectedForm') { + newConf.selectedForm = val + refreshFormFields(val, newConf, setUserRegistrationConf, setIsLoading, setSnackbar) + } else { + newConf[name] = val + } + + setUserRegistrationConf(newConf) + } + return ( + <> +
+ +
+ {__('Select Action:', 'bit-integrations')} + changeHandler(value, 'mainAction')} + options={modules?.map(module => ({ + label: checkIsPro(isPro, module.is_pro) ? module.label : getProLabel(module.label), + value: module.name, + disabled: checkIsPro(isPro, module.is_pro) ? false : true + }))} + singleSelect + closeOnSelect + /> +
+ + {userRegistrationConf.mainAction === 'create_user' && ( + <> +
+
+ {__('Select Form:', 'bit-integrations')} + + + + )} + + {isLoading && ( + + )} + + {userRegistrationConf.mainAction && userRegistrationConf.selectedForm && ( +
+ {__('Map Fields', 'bit-integrations')} + +
+ )} + + {userRegistrationConf.mainAction && userRegistrationConf.selectedForm && ( + <> +
+
+
+ {__('Form Fields', 'bit-integrations')} +
+
+ {__('User Registration Fields', 'bit-integrations')} +
+
+ + {userRegistrationConf.field_map.map((itm, i) => ( + + ))} + +
+ +
+
+
+ + )} + + ) +} diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/staticData.js b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/staticData.js new file mode 100644 index 00000000..e9662f14 --- /dev/null +++ b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/staticData.js @@ -0,0 +1,5 @@ +import { __ } from '../../../Utils/i18nwrap' + +export const modules = [ + { name: 'create_user', label: __('Create User', 'bit-integrations'), is_pro: true } +] diff --git a/frontend-dev/src/components/Flow/New/SelectAction.jsx b/frontend-dev/src/components/Flow/New/SelectAction.jsx index 9b1fe80d..0eeeb080 100644 --- a/frontend-dev/src/components/Flow/New/SelectAction.jsx +++ b/frontend-dev/src/components/Flow/New/SelectAction.jsx @@ -176,7 +176,8 @@ export default function SelectAction() { { type: 'FluentCart' }, { type: 'WPCafe' }, { type: 'Teams For WooCommerce Memberships' }, - { type: 'SeoPress' } + { type: 'SeoPress' }, + { type: 'User Registration & Membership', logo_url: 'userRegistrationMembership' } ] const [availableIntegs, setAvailableIntegs] = useState(sortByField(integs, 'type', 'ASC') || integs) @@ -252,8 +253,8 @@ export default function SelectAction() {
)} - {/* */} - + +
{inte.type}
))} diff --git a/frontend-dev/src/resource/img/integ/userRegistrationMembership.webp b/frontend-dev/src/resource/img/integ/userRegistrationMembership.webp new file mode 100644 index 0000000000000000000000000000000000000000..5e002de5662c42b244893163c272ac7388dfb9dc GIT binary patch literal 3914 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 literal 0 HcmV?d00001 diff --git a/includes/Actions/UserRegistrationMembership/RecordApiHelper.php b/includes/Actions/UserRegistrationMembership/RecordApiHelper.php new file mode 100644 index 00000000..f32d7ebf --- /dev/null +++ b/includes/Actions/UserRegistrationMembership/RecordApiHelper.php @@ -0,0 +1,81 @@ +_integrationDetails = $integrationDetails; + $this->_integrationID = $integId; + } + + public function execute($fieldValues, $fieldMap) + { + if (!class_exists('UserRegistration')) { + $response = [ + 'success' => false, + 'message' => __('User Registration and Membership is not installed or activated', 'bit-integrations') + ]; + + LogHandler::save($this->_integrationID, ['type' => 'User Registration', 'type_name' => 'check'], 'error', $response); + + return $response; + } + + $fieldData = $this->generateReqDataFromFieldMap($fieldMap, $fieldValues); + $mainAction = $this->_integrationDetails->mainAction ?? 'create_user'; + $response = $this->processAction($mainAction, $fieldData); + + $responseType = !empty($response['success']) ? 'success' : 'error'; + LogHandler::save($this->_integrationID, ['type' => 'User Registration', 'type_name' => $mainAction], $responseType, $response); + + return $response; + } + + private function processAction($mainAction, $fieldData) + { + $defaultResponse = [ + 'success' => false, + 'message' => wp_sprintf(__('%s plugin is not installed or activate', 'bit-integrations'), 'Bit Integrations Pro') + ]; + + switch ($mainAction) { + case 'create_user': + return apply_filters('btcbi_user_registration_create_user', $defaultResponse, $fieldData, $this->_integrationDetails); + + default: + return [ + 'success' => false, + 'message' => __('Invalid action', 'bit-integrations') + ]; + } + } + + private function generateReqDataFromFieldMap($fieldMap, $fieldValues) + { + $dataFinal = []; + + foreach ($fieldMap as $item) { + if (empty($item->userRegistrationField)) { + continue; + } + + $dataFinal[$item->userRegistrationField] = $item->formField === 'custom' && isset($item->customValue) + ? Common::replaceFieldWithValue($item->customValue, $fieldValues) + : ($fieldValues[$item->formField] ?? ''); + } + + return $dataFinal; + } +} diff --git a/includes/Actions/UserRegistrationMembership/Routes.php b/includes/Actions/UserRegistrationMembership/Routes.php new file mode 100644 index 00000000..4cb006f7 --- /dev/null +++ b/includes/Actions/UserRegistrationMembership/Routes.php @@ -0,0 +1,12 @@ + 'user_registration', + 'post_status' => 'publish', + 'orderby' => 'ID', + 'order' => 'DESC', + 'no_found_rows' => true, + 'nopaging' => true, + ]); + + $forms = array_map( + fn ($form) => (object) [ + 'value' => $form->ID, + 'label' => $form->post_title, + ], + $allForms + ); + + wp_send_json_success(['forms' => $forms], 200); + } + + public function refreshFormFields($request) + { + self::checkPluginExists(); + + $formId = absint($request->form_id ?? 0); + + if (empty($formId)) { + wp_send_json_error(__('Form ID is required', 'bit-integrations'), 400); + } + + $fields = $this->getFormFields($formId); + + wp_send_json_success(['fields' => array_values($fields)], 200); + } + + public function execute($integrationData, $fieldValues) + { + $integrationDetails = $integrationData->flow_details; + $fieldMap = $integrationDetails->field_map ?? []; + + if (empty($fieldMap)) { + return new WP_Error('field_map_empty', __('Field map is empty', 'bit-integrations')); + } + + $recordApiHelper = new RecordApiHelper($integrationDetails, $integrationData->id); + $response = $recordApiHelper->execute($fieldValues, $fieldMap); + + return is_wp_error($response) ? $response : $response; + } + + private function getFormFields($formId) + { + if (!\function_exists('ur_get_form_fields')) { + return []; + } + + $formFields = ur_get_form_fields($formId); + + return array_map( + fn ($field) => (object) [ + 'label' => $field->general_setting->label ?? $field->field_key, + 'value' => $field->field_key, + 'required' => !empty($field->general_setting->required) + ], + $formFields + ); + } + + private static function checkPluginExists() + { + if (!class_exists('UserRegistration')) { + wp_send_json_error( + __('User Registration and Membership is not activated or not installed', 'bit-integrations'), + 400 + ); + } + } +} diff --git a/includes/Flow/Flow.php b/includes/Flow/Flow.php index 75ea7ffb..951587da 100644 --- a/includes/Flow/Flow.php +++ b/includes/Flow/Flow.php @@ -486,6 +486,11 @@ public static function execute($triggered_entity, $triggered_entity_id, $data, $ break; + case 'UserRegistration&Membership': + $integrationName = 'UserRegistrationMembership'; + + break; + default: $integrationName = $integrationName; From 43eacf9d69803118e3f2a0b0526bbf2571a63f3e Mon Sep 17 00:00:00 2001 From: Rishad Alam <101513331+RishadAlam@users.noreply.github.com> Date: Tue, 10 Feb 2026 10:45:58 +0600 Subject: [PATCH 2/7] fix: user registration blank page issue --- frontend-dev/src/Utils/StaticData/webhookIntegrations.js | 3 ++- .../UserRegistrationMembership.jsx | 3 +-- .../UserRegistrationMembershipFieldMap.jsx | 2 +- .../UserRegistrationMembershipIntegLayout.jsx | 5 ++++- .../AllIntegrations/UserRegistrationMembership/staticData.js | 5 ----- includes/Core/Util/AllTriggersName.php | 1 + 6 files changed, 9 insertions(+), 10 deletions(-) delete mode 100644 frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/staticData.js diff --git a/frontend-dev/src/Utils/StaticData/webhookIntegrations.js b/frontend-dev/src/Utils/StaticData/webhookIntegrations.js index 40988a86..8a4591ec 100644 --- a/frontend-dev/src/Utils/StaticData/webhookIntegrations.js +++ b/frontend-dev/src/Utils/StaticData/webhookIntegrations.js @@ -87,7 +87,8 @@ export const customFormIntegrations = [ 'TeamsForWooCommerceMemberships', 'WPCafe', 'SeoPress', - 'ThriveLeads' + 'ThriveLeads', + 'UserRegistrationMembership' ] export const actionHookIntegrations = ['ActionHook'] diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembership.jsx b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembership.jsx index 91d55802..48d7cd6f 100644 --- a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembership.jsx +++ b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembership.jsx @@ -70,8 +70,7 @@ export default function UserRegistrationMembership({ formFields, setFlow, flow, minHeight: step === 2 && `${200}px` }}> fld.required === true) || [] const nonRequiredFlds = userRegistrationConf?.default?.formFields?.filter(fld => fld.required === false) || [] - console.log(formFields) + return (
diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx index f7ab0881..62ba4f96 100644 --- a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx +++ b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx @@ -9,7 +9,10 @@ import { checkIsPro, getProLabel } from '../../Utilities/ProUtilHelpers' import { addFieldMap, delFieldMap, handleFieldMapping } from '../IntegrationHelpers/IntegrationHelpers' import UserRegistrationMembershipFieldMap from './UserRegistrationMembershipFieldMap' import { refreshForms, refreshFormFields } from './UserRegistrationMembershipCommonFunc' -import { modules } from './staticData' + +export const modules = [ + { name: 'create_user', label: __('Create User', 'bit-integrations'), is_pro: true } +] export default function UserRegistrationMembershipIntegLayout({ formFields, diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/staticData.js b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/staticData.js deleted file mode 100644 index e9662f14..00000000 --- a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/staticData.js +++ /dev/null @@ -1,5 +0,0 @@ -import { __ } from '../../../Utils/i18nwrap' - -export const modules = [ - { name: 'create_user', label: __('Create User', 'bit-integrations'), is_pro: true } -] diff --git a/includes/Core/Util/AllTriggersName.php b/includes/Core/Util/AllTriggersName.php index b3fd6f58..3469532b 100644 --- a/includes/Core/Util/AllTriggersName.php +++ b/includes/Core/Util/AllTriggersName.php @@ -132,6 +132,7 @@ public static function allTriggersName() 'Tripetto' => ['name' => 'Tripetto', 'isPro' => true, 'is_active' => false], 'TutorLms' => ['name' => 'Tutor LMS', 'isPro' => true, 'is_active' => false], 'TeamsForWooCommerceMemberships' => ['name' => 'Teams For WooCommerce Memberships', 'isPro' => true, 'is_active' => false], + 'UserRegistrationMembership' => ['name' => 'User Registration & Membership', 'isPro' => true, 'is_active' => false], 'UltimateMember' => ['name' => 'UltimateMember', 'isPro' => true, 'is_active' => false], 'UserFeedback' => ['name' => 'UserFeedback', 'isPro' => true, 'is_active' => false], 'Voxel' => ['name' => 'Voxel', 'isPro' => true, 'is_active' => false], From e44105366cf5fc886e0893020cfc69e6abf892af Mon Sep 17 00:00:00 2001 From: Rishad Alam <101513331+RishadAlam@users.noreply.github.com> Date: Tue, 10 Feb 2026 11:03:01 +0600 Subject: [PATCH 3/7] feat: user registration membership action doc link added --- frontend-dev/src/Utils/StaticData/tutorialLinks.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend-dev/src/Utils/StaticData/tutorialLinks.js b/frontend-dev/src/Utils/StaticData/tutorialLinks.js index ef86b252..8c5666cd 100644 --- a/frontend-dev/src/Utils/StaticData/tutorialLinks.js +++ b/frontend-dev/src/Utils/StaticData/tutorialLinks.js @@ -658,6 +658,10 @@ const tutorialLinks = { seoPress: { youTubeLink: '', docLink: 'https://bit-integrations.com/wp-docs/actions/seopress-integrations-as-action/' + }, + userRegistrationMembership: { + youTubeLink: '', + docLink: 'https://bit-integrations.com/wp-docs/actions/user-registration-and-membership-as-action/' } } export default tutorialLinks From 46db2ec6dbccf127b62613024fc1badd2bb4a16f Mon Sep 17 00:00:00 2001 From: Rishad Alam <101513331+RishadAlam@users.noreply.github.com> Date: Sat, 14 Feb 2026 11:06:13 +0600 Subject: [PATCH 4/7] fix: select action logo names --- frontend-dev/src/components/Flow/New/SelectAction.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend-dev/src/components/Flow/New/SelectAction.jsx b/frontend-dev/src/components/Flow/New/SelectAction.jsx index 0eeeb080..e0288854 100644 --- a/frontend-dev/src/components/Flow/New/SelectAction.jsx +++ b/frontend-dev/src/components/Flow/New/SelectAction.jsx @@ -177,7 +177,7 @@ export default function SelectAction() { { type: 'WPCafe' }, { type: 'Teams For WooCommerce Memberships' }, { type: 'SeoPress' }, - { type: 'User Registration & Membership', logo_url: 'userRegistrationMembership' } + { type: 'User Registration & Membership', logo: 'userRegistrationMembership' } ] const [availableIntegs, setAvailableIntegs] = useState(sortByField(integs, 'type', 'ASC') || integs) @@ -254,7 +254,7 @@ export default function SelectAction() {
)} - +
{inte.type}
))} From cb73c4c81997d44f2ec357aa335619cfe754bccf Mon Sep 17 00:00:00 2001 From: Rishad Alam <101513331+RishadAlam@users.noreply.github.com> Date: Thu, 12 Mar 2026 11:19:39 +0600 Subject: [PATCH 5/7] refactor: userRegistrationMembership action directories --- .../RecordApiHelper.php | 11 +- .../UserRegistrationMembership/Routes.php | 4 +- .../UserRegistrationMembershipController.php | 7 +- backend/Core/Util/Common.php | 2 +- .../UserRegistrationMembershipFieldMap.jsx | 4 +- .../UserRegistrationMembershipIntegLayout.jsx | 4 +- .../AllIntegrations/SeoPress/SeoPress.jsx | 1 - .../EditUserRegistrationMembership.jsx | 75 ++++++++ .../UserRegistrationMembership.jsx | 119 ++++++++++++ .../UserRegistrationMembershipActions.jsx | 30 +++ ...serRegistrationMembershipAuthorization.jsx | 84 +++++++++ .../UserRegistrationMembershipCommonFunc.js | 161 ++++++++++++++++ .../UserRegistrationMembershipFieldMap.jsx | 114 ++++++++++++ .../UserRegistrationMembershipIntegLayout.jsx | 174 ++++++++++++++++++ 14 files changed, 773 insertions(+), 17 deletions(-) rename {includes => backend}/Actions/UserRegistrationMembership/RecordApiHelper.php (87%) rename {includes => backend}/Actions/UserRegistrationMembership/Routes.php (74%) rename {includes => backend}/Actions/UserRegistrationMembership/UserRegistrationMembershipController.php (92%) create mode 100644 frontend/src/components/AllIntegrations/UserRegistrationMembership/EditUserRegistrationMembership.jsx create mode 100644 frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembership.jsx create mode 100644 frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipActions.jsx create mode 100644 frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipAuthorization.jsx create mode 100644 frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipCommonFunc.js create mode 100644 frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipFieldMap.jsx create mode 100644 frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx diff --git a/includes/Actions/UserRegistrationMembership/RecordApiHelper.php b/backend/Actions/UserRegistrationMembership/RecordApiHelper.php similarity index 87% rename from includes/Actions/UserRegistrationMembership/RecordApiHelper.php rename to backend/Actions/UserRegistrationMembership/RecordApiHelper.php index f32d7ebf..0f79730f 100644 --- a/includes/Actions/UserRegistrationMembership/RecordApiHelper.php +++ b/backend/Actions/UserRegistrationMembership/RecordApiHelper.php @@ -1,12 +1,13 @@ _integrationDetails); + return apply_filters(Config::withPrefix('user_registration_create_user'), $defaultResponse, $fieldData, $this->_integrationDetails); default: return [ diff --git a/includes/Actions/UserRegistrationMembership/Routes.php b/backend/Actions/UserRegistrationMembership/Routes.php similarity index 74% rename from includes/Actions/UserRegistrationMembership/Routes.php rename to backend/Actions/UserRegistrationMembership/Routes.php index 4cb006f7..0c166eca 100644 --- a/includes/Actions/UserRegistrationMembership/Routes.php +++ b/backend/Actions/UserRegistrationMembership/Routes.php @@ -4,8 +4,8 @@ exit; } -use BitCode\FI\Actions\UserRegistrationMembership\UserRegistrationMembershipController; -use BitCode\FI\Core\Util\Route; +use BitApps\Integrations\Actions\UserRegistrationMembership\UserRegistrationMembershipController; +use BitApps\Integrations\Core\Util\Route; Route::post('user_registration_authorize', [UserRegistrationMembershipController::class, 'userRegistrationAuthorize']); Route::post('refresh_user_registration_forms', [UserRegistrationMembershipController::class, 'refreshForms']); diff --git a/includes/Actions/UserRegistrationMembership/UserRegistrationMembershipController.php b/backend/Actions/UserRegistrationMembership/UserRegistrationMembershipController.php similarity index 92% rename from includes/Actions/UserRegistrationMembership/UserRegistrationMembershipController.php rename to backend/Actions/UserRegistrationMembership/UserRegistrationMembershipController.php index b4807c91..4c06b8b4 100644 --- a/includes/Actions/UserRegistrationMembership/UserRegistrationMembershipController.php +++ b/backend/Actions/UserRegistrationMembership/UserRegistrationMembershipController.php @@ -1,11 +1,11 @@ id); - $response = $recordApiHelper->execute($fieldValues, $fieldMap); - return is_wp_error($response) ? $response : $response; + return $recordApiHelper->execute($fieldValues, $fieldMap); } private function getFormFields($formId) diff --git a/backend/Core/Util/Common.php b/backend/Core/Util/Common.php index a6e1ac03..f48aa34e 100644 --- a/backend/Core/Util/Common.php +++ b/backend/Core/Util/Common.php @@ -294,7 +294,7 @@ private static function replaceFieldWithValueHelper($stringToReplaceField, $fiel $fieldName = substr($field, 2, \strlen($field) - 3); $smartTagValue = SmartTags::getSmartTagValue($fieldName, true); if (isset($fieldValues[$fieldName]) && !self::isEmpty($fieldValues[$fieldName])) { - $stringToReplaceField = !\is_array($fieldValues[$fieldName]) ? str_replace($field, $fieldValues[$fieldName], $stringToReplaceField) + $stringToReplaceField = !\is_array($fieldValues[$fieldName]) && !\is_object($fieldValues[$fieldName]) ? str_replace($field, $fieldValues[$fieldName], $stringToReplaceField) : str_replace(['"' . $field . '"', $field], wp_json_encode($fieldValues[$fieldName], JSON_UNESCAPED_UNICODE), $stringToReplaceField); } elseif (!empty($smartTagValue)) { $stringToReplaceField = str_replace($field, $smartTagValue, $stringToReplaceField); diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipFieldMap.jsx b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipFieldMap.jsx index db6447ca..548aabb2 100644 --- a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipFieldMap.jsx +++ b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipFieldMap.jsx @@ -1,5 +1,5 @@ import { useRecoilValue } from 'recoil' -import { $btcbi } from '../../../GlobalStates' +import { $appConfigState } from '../../../GlobalStates' import { __, sprintf } from '../../../Utils/i18nwrap' import { SmartTagField } from '../../../Utils/StaticData/SmartTagField' import TagifyInput from '../../Utilities/TagifyInput' @@ -17,7 +17,7 @@ export default function UserRegistrationMembershipFieldMap({ userRegistrationConf, setUserRegistrationConf }) { - const btcbi = useRecoilValue($btcbi) + const btcbi = useRecoilValue($appConfigState) const { isPro } = btcbi const requiredFlds = diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx index 62ba4f96..adff766e 100644 --- a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx +++ b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react' import MultiSelect from 'react-multiple-select-dropdown-lite' import 'react-multiple-select-dropdown-lite/dist/index.css' import { useRecoilValue } from 'recoil' -import { $btcbi } from '../../../GlobalStates' +import { $appConfigState } from '../../../GlobalStates' import { __ } from '../../../Utils/i18nwrap' import Loader from '../../Loaders/Loader' import { checkIsPro, getProLabel } from '../../Utilities/ProUtilHelpers' @@ -22,7 +22,7 @@ export default function UserRegistrationMembershipIntegLayout({ isLoading, setSnackbar }) { - const btcbi = useRecoilValue($btcbi) + const btcbi = useRecoilValue($appConfigState) const { isPro } = btcbi const changeHandler = (val, name) => { diff --git a/frontend/src/components/AllIntegrations/SeoPress/SeoPress.jsx b/frontend/src/components/AllIntegrations/SeoPress/SeoPress.jsx index b83ddbe0..c7e6e24c 100644 --- a/frontend/src/components/AllIntegrations/SeoPress/SeoPress.jsx +++ b/frontend/src/components/AllIntegrations/SeoPress/SeoPress.jsx @@ -85,7 +85,6 @@ export default function SeoPress({ formFields, setFlow, flow, allIntegURL }) {
+ + + {/* STEP 3 */} + + saveIntegConfig( + flow, + setFlow, + allIntegURL, + userRegistrationConf, + navigate, + '', + '', + setIsLoading + ) + } + isLoading={isLoading} + dataConf={userRegistrationConf} + setDataConf={setUserRegistrationConf} + formFields={formFields} + /> + + ) +} diff --git a/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipActions.jsx b/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipActions.jsx new file mode 100644 index 00000000..52904974 --- /dev/null +++ b/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipActions.jsx @@ -0,0 +1,30 @@ +/* eslint-disable no-param-reassign */ +// import { __ } from '../../../Utils/i18nwrap' +// import TableCheckBox from '../../Utilities/TableCheckBox' + +export default function UserRegistrationMembershipActions({ userRegistrationConf, setUserRegistrationConf }) { + // const actionHandler = (e, type) => { + // const newConf = { ...userRegistrationConf } + // if (type === 'update') { + // if (e.target.checked) { + // newConf.actions.update = true + // } else { + // delete newConf.actions.update + // } + // } + // setUserRegistrationConf({ ...newConf }) + // } + + return ( +
+ {/* actionHandler(e, 'update')} + className="wdt-200 mt-4 mr-2" + value="user_update" + title={__('Update User', 'bit-integrations')} + subTitle={__('Update existing user if user already exists', 'bit-integrations')} + /> */} +
+ ) +} diff --git a/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipAuthorization.jsx b/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipAuthorization.jsx new file mode 100644 index 00000000..bbedd0f4 --- /dev/null +++ b/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipAuthorization.jsx @@ -0,0 +1,84 @@ +import { useState } from 'react' +import { __ } from '../../../Utils/i18nwrap' +import LoaderSm from '../../Loaders/LoaderSm' +import Note from '../../Utilities/Note' +import { userRegistrationAuthorize } from './UserRegistrationMembershipCommonFunc' +import tutorialLinks from '../../../Utils/StaticData/tutorialLinks' +import TutorialLink from '../../Utilities/TutorialLink' + +export default function UserRegistrationMembershipAuthorization({ + userRegistrationConf, + setUserRegistrationConf, + step, + nextPage, + isLoading, + setIsLoading, + setSnackbar +}) { + const [isAuthorized, setIsAuthorized] = useState(false) + const [showAuthMsg, setShowAuthMsg] = useState(false) + const { userRegistrationMembership } = tutorialLinks + + const handleAuthorize = () => { + userRegistrationAuthorize(setIsAuthorized, setShowAuthMsg, setIsLoading, setSnackbar, nextPage) + } + + return ( +
+ {userRegistrationMembership?.youTubeLink && ( + + )} + {userRegistrationMembership?.docLink && ( + + )} + +
+ {__('Integration Name:', 'bit-integrations')} +
+ setUserRegistrationConf({ ...userRegistrationConf, name: e.target.value })} + name="name" + value={userRegistrationConf.name} + type="text" + placeholder={__('Integration Name...', 'bit-integrations')} + disabled={isAuthorized} + /> + + +
+ {showAuthMsg && isAuthorized && ( +
+ +
+ )} + +
+ ) +} diff --git a/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipCommonFunc.js b/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipCommonFunc.js new file mode 100644 index 00000000..acc6d2aa --- /dev/null +++ b/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipCommonFunc.js @@ -0,0 +1,161 @@ +import { __ } from '../../../Utils/i18nwrap' +import bitsFetch from '../../../Utils/bitsFetch' + +export const handleInput = (e, userRegistrationConf, setUserRegistrationConf) => { + const { name, value } = e.target + const newConf = { ...userRegistrationConf } + newConf[name] = value + setUserRegistrationConf(newConf) +} + +export const userRegistrationAuthorize = ( + setIsAuthorized, + setShowAuthMsg, + setIsLoading, + setSnackbar, + nextPage +) => { + setIsLoading(true) + bitsFetch({}, 'user_registration_authorize') + .then(result => { + if (result?.success) { + setIsAuthorized(true) + setShowAuthMsg(true) + setSnackbar({ + show: true, + msg: __('Connected Successfully', 'bit-integrations') + }) + nextPage(2) + } else { + setSnackbar({ + show: true, + msg: __( + result?.data || + 'Connection failed. Please make sure User Registration and Membership plugin is installed and activated.', + 'bit-integrations' + ) + }) + } + setIsLoading(false) + }) + .catch(error => { + setSnackbar({ + show: true, + msg: __('Connection failed', 'bit-integrations') + }) + setIsLoading(false) + }) +} + +export const refreshForms = ( + userRegistrationConf, + setUserRegistrationConf, + setIsLoading, + setSnackbar +) => { + setIsLoading(true) + bitsFetch({}, 'refresh_user_registration_forms') + .then(result => { + if (result?.success && result?.data) { + const newConf = { ...userRegistrationConf } + if (!newConf.default) { + newConf.default = {} + } + newConf.default.forms = result.data.forms || [] + setUserRegistrationConf(newConf) + setSnackbar({ + show: true, + msg: __('Forms refreshed successfully', 'bit-integrations') + }) + } else { + setSnackbar({ + show: true, + msg: __('Failed to refresh forms', 'bit-integrations') + }) + } + setIsLoading(false) + }) + .catch(() => { + setSnackbar({ + show: true, + msg: __('Failed to refresh forms', 'bit-integrations') + }) + setIsLoading(false) + }) +} + +export const refreshFormFields = ( + formId, + userRegistrationConf, + setUserRegistrationConf, + setIsLoading, + setSnackbar +) => { + if (!formId) { + return + } + + setIsLoading(true) + bitsFetch({ form_id: formId }, 'refresh_user_registration_form_fields') + .then(result => { + if (result?.success && result?.data) { + const newConf = { ...userRegistrationConf } + if (!newConf.default) { + newConf.default = {} + } + newConf.default.formFields = result.data.fields || [] + newConf.field_map = generateMappedField(newConf.default.formFields) + setUserRegistrationConf(newConf) + setSnackbar({ + show: true, + msg: __('Form fields refreshed successfully', 'bit-integrations') + }) + } else { + setSnackbar({ + show: true, + msg: __('Failed to refresh form fields', 'bit-integrations') + }) + } + setIsLoading(false) + }) + .catch(() => { + setSnackbar({ + show: true, + msg: __('Failed to refresh form fields', 'bit-integrations') + }) + setIsLoading(false) + }) +} + +export const generateMappedField = fields => { + const requiredFlds = fields.filter(fld => fld.required === true) + return requiredFlds.length > 0 + ? requiredFlds.map(field => ({ + formField: '', + userRegistrationField: field.value || field.key + })) + : [{ formField: '', userRegistrationField: '' }] +} + +export const checkMappedFields = userRegistrationConf => { + const { mainAction, field_map, selectedForm } = userRegistrationConf + + if (!mainAction || mainAction !== 'create_user') { + return false + } + + if (!selectedForm) { + return false + } + + const formFields = userRegistrationConf?.default?.formFields || [] + const requiredFields = formFields.filter(fld => fld.required === true || fld.required === 'true') + + if (requiredFields.length === 0) { + return field_map.length > 0 + } + + const mappedFields = field_map.map(field => field.userRegistrationField).filter(f => f) + + return requiredFields.every(reqField => mappedFields.includes(reqField.value)) +} diff --git a/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipFieldMap.jsx b/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipFieldMap.jsx new file mode 100644 index 00000000..548aabb2 --- /dev/null +++ b/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipFieldMap.jsx @@ -0,0 +1,114 @@ +import { useRecoilValue } from 'recoil' +import { $appConfigState } from '../../../GlobalStates' +import { __, sprintf } from '../../../Utils/i18nwrap' +import { SmartTagField } from '../../../Utils/StaticData/SmartTagField' +import TagifyInput from '../../Utilities/TagifyInput' +import { + addFieldMap, + delFieldMap, + handleCustomValue, + handleFieldMapping +} from '../GlobalIntegrationHelper' + +export default function UserRegistrationMembershipFieldMap({ + i, + formFields, + field, + userRegistrationConf, + setUserRegistrationConf +}) { + const btcbi = useRecoilValue($appConfigState) + const { isPro } = btcbi + + const requiredFlds = + userRegistrationConf?.default?.formFields?.filter(fld => fld.required === true) || [] + const nonRequiredFlds = + userRegistrationConf?.default?.formFields?.filter(fld => fld.required === false) || [] + + return ( +
+
+
+ + + {field.formField === 'custom' && ( + handleCustomValue(e, i, userRegistrationConf, setUserRegistrationConf)} + label={__('Custom Value', 'bit-integrations')} + className="mr-2" + type="text" + value={field.customValue} + placeholder={__('Custom Value', 'bit-integrations')} + formFields={formFields} + /> + )} + + +
+ {i >= requiredFlds.length && ( + <> + + + + )} +
+
+ ) +} diff --git a/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx b/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx new file mode 100644 index 00000000..adff766e --- /dev/null +++ b/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx @@ -0,0 +1,174 @@ +import { useEffect, useState } from 'react' +import MultiSelect from 'react-multiple-select-dropdown-lite' +import 'react-multiple-select-dropdown-lite/dist/index.css' +import { useRecoilValue } from 'recoil' +import { $appConfigState } from '../../../GlobalStates' +import { __ } from '../../../Utils/i18nwrap' +import Loader from '../../Loaders/Loader' +import { checkIsPro, getProLabel } from '../../Utilities/ProUtilHelpers' +import { addFieldMap, delFieldMap, handleFieldMapping } from '../IntegrationHelpers/IntegrationHelpers' +import UserRegistrationMembershipFieldMap from './UserRegistrationMembershipFieldMap' +import { refreshForms, refreshFormFields } from './UserRegistrationMembershipCommonFunc' + +export const modules = [ + { name: 'create_user', label: __('Create User', 'bit-integrations'), is_pro: true } +] + +export default function UserRegistrationMembershipIntegLayout({ + formFields, + userRegistrationConf, + setUserRegistrationConf, + setIsLoading, + isLoading, + setSnackbar +}) { + const btcbi = useRecoilValue($appConfigState) + const { isPro } = btcbi + + const changeHandler = (val, name) => { + const newConf = { ...userRegistrationConf } + + if (name === 'mainAction') { + newConf.mainAction = val + newConf.field_map = [{ formField: '', userRegistrationField: '' }] + + refreshForms(newConf, setUserRegistrationConf, setIsLoading, setSnackbar) + } else if (name === 'selectedForm') { + newConf.selectedForm = val + refreshFormFields(val, newConf, setUserRegistrationConf, setIsLoading, setSnackbar) + } else { + newConf[name] = val + } + + setUserRegistrationConf(newConf) + } + return ( + <> +
+ +
+ {__('Select Action:', 'bit-integrations')} + changeHandler(value, 'mainAction')} + options={modules?.map(module => ({ + label: checkIsPro(isPro, module.is_pro) ? module.label : getProLabel(module.label), + value: module.name, + disabled: checkIsPro(isPro, module.is_pro) ? false : true + }))} + singleSelect + closeOnSelect + /> +
+ + {userRegistrationConf.mainAction === 'create_user' && ( + <> +
+
+ {__('Select Form:', 'bit-integrations')} + + + + )} + + {isLoading && ( + + )} + + {userRegistrationConf.mainAction && userRegistrationConf.selectedForm && ( +
+ {__('Map Fields', 'bit-integrations')} + +
+ )} + + {userRegistrationConf.mainAction && userRegistrationConf.selectedForm && ( + <> +
+
+
+ {__('Form Fields', 'bit-integrations')} +
+
+ {__('User Registration Fields', 'bit-integrations')} +
+
+ + {userRegistrationConf.field_map.map((itm, i) => ( + + ))} + +
+ +
+
+
+ + )} + + ) +} From 831b7f4726807618e440fd359cccb83282c120f2 Mon Sep 17 00:00:00 2001 From: Rishad Alam <101513331+RishadAlam@users.noreply.github.com> Date: Thu, 12 Mar 2026 11:20:40 +0600 Subject: [PATCH 6/7] refactor: userRegistrationMembership action old directories removed --- .../EditUserRegistrationMembership.jsx | 75 -------- .../UserRegistrationMembership.jsx | 118 ------------ .../UserRegistrationMembershipActions.jsx | 30 --- ...serRegistrationMembershipAuthorization.jsx | 84 --------- .../UserRegistrationMembershipCommonFunc.js | 161 ---------------- .../UserRegistrationMembershipFieldMap.jsx | 114 ------------ .../UserRegistrationMembershipIntegLayout.jsx | 174 ------------------ 7 files changed, 756 deletions(-) delete mode 100644 frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/EditUserRegistrationMembership.jsx delete mode 100644 frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembership.jsx delete mode 100644 frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipActions.jsx delete mode 100644 frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipAuthorization.jsx delete mode 100644 frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipCommonFunc.js delete mode 100644 frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipFieldMap.jsx delete mode 100644 frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/EditUserRegistrationMembership.jsx b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/EditUserRegistrationMembership.jsx deleted file mode 100644 index fd47b3e6..00000000 --- a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/EditUserRegistrationMembership.jsx +++ /dev/null @@ -1,75 +0,0 @@ -import { useState } from 'react' -import { useNavigate, useParams } from 'react-router-dom' -import { useRecoilState, useRecoilValue } from 'recoil' -import { $actionConf, $formFields, $newFlow } from '../../../GlobalStates' -import { __ } from '../../../Utils/i18nwrap' -import SnackMsg from '../../Utilities/SnackMsg' -import { saveActionConf } from '../IntegrationHelpers/IntegrationHelpers' -import IntegrationStepThree from '../IntegrationHelpers/IntegrationStepThree' -import SetEditIntegComponents from '../IntegrationHelpers/SetEditIntegComponents' -import { checkMappedFields, handleInput } from './UserRegistrationMembershipCommonFunc' -import UserRegistrationMembershipIntegLayout from './UserRegistrationMembershipIntegLayout' - -export default function EditUserRegistrationMembership({ allIntegURL }) { - const navigate = useNavigate() - const { id } = useParams() - - const [userRegistrationConf, setUserRegistrationConf] = useRecoilState($actionConf) - const [flow, setFlow] = useRecoilState($newFlow) - const formFields = useRecoilValue($formFields) - const [isLoading, setIsLoading] = useState(false) - const [snack, setSnackbar] = useState({ show: false }) - - return ( -
- - -
- {__('Integration Name:', 'bit-integrations')} - handleInput(e, userRegistrationConf, setUserRegistrationConf)} - name="name" - value={userRegistrationConf.name} - type="text" - placeholder={__('Integration Name...', 'bit-integrations')} - /> -
-
- - - - - - - saveActionConf({ - flow, - setFlow, - allIntegURL, - conf: userRegistrationConf, - navigate, - id, - edit: 1, - setIsLoading, - setSnackbar - }) - } - disabled={!checkMappedFields(userRegistrationConf)} - isLoading={isLoading} - dataConf={userRegistrationConf} - setDataConf={setUserRegistrationConf} - formFields={formFields} - /> -
-
- ) -} diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembership.jsx b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembership.jsx deleted file mode 100644 index 48d7cd6f..00000000 --- a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembership.jsx +++ /dev/null @@ -1,118 +0,0 @@ -import { useState } from 'react' -import 'react-multiple-select-dropdown-lite/dist/index.css' -import { useNavigate, useParams } from 'react-router-dom' -import BackIcn from '../../../Icons/BackIcn' -import { __ } from '../../../Utils/i18nwrap' -import SnackMsg from '../../Utilities/SnackMsg' -import { saveIntegConfig } from '../IntegrationHelpers/IntegrationHelpers' -import IntegrationStepThree from '../IntegrationHelpers/IntegrationStepThree' -import UserRegistrationMembershipAuthorization from './UserRegistrationMembershipAuthorization' -import { checkMappedFields } from './UserRegistrationMembershipCommonFunc' -import UserRegistrationMembershipIntegLayout from './UserRegistrationMembershipIntegLayout' - -export default function UserRegistrationMembership({ formFields, setFlow, flow, allIntegURL }) { - const navigate = useNavigate() - const [isLoading, setIsLoading] = useState(false) - const [step, setStep] = useState(1) - const [snack, setSnackbar] = useState({ show: false }) - const [userRegistrationConf, setUserRegistrationConf] = useState({ - name: 'User Registration & Membership', - type: 'User Registration & Membership', - field_map: [{ formField: '', userRegistrationField: '' }], - actions: {}, - mainAction: '' - }) - - const nextPage = val => { - setTimeout(() => { - document.getElementById('btcd-settings-wrp').scrollTop = 0 - }, 300) - - if (val === 3) { - if (!checkMappedFields(userRegistrationConf)) { - setSnackbar({ - show: true, - msg: __('Please map all required fields to continue.', 'bit-integrations') - }) - return - } - - if (userRegistrationConf.name !== '' && userRegistrationConf.field_map.length > 0) { - setStep(val) - } - } else { - setStep(val) - } - } - - return ( -
- -
{/* */}
- - {/* STEP 1 */} - - - {/* STEP 2 */} -
- -
-
-
- -
- - {/* STEP 3 */} - - saveIntegConfig( - flow, - setFlow, - allIntegURL, - userRegistrationConf, - navigate, - '', - '', - setIsLoading - ) - } - isLoading={isLoading} - dataConf={userRegistrationConf} - setDataConf={setUserRegistrationConf} - formFields={formFields} - /> -
- ) -} diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipActions.jsx b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipActions.jsx deleted file mode 100644 index 52904974..00000000 --- a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipActions.jsx +++ /dev/null @@ -1,30 +0,0 @@ -/* eslint-disable no-param-reassign */ -// import { __ } from '../../../Utils/i18nwrap' -// import TableCheckBox from '../../Utilities/TableCheckBox' - -export default function UserRegistrationMembershipActions({ userRegistrationConf, setUserRegistrationConf }) { - // const actionHandler = (e, type) => { - // const newConf = { ...userRegistrationConf } - // if (type === 'update') { - // if (e.target.checked) { - // newConf.actions.update = true - // } else { - // delete newConf.actions.update - // } - // } - // setUserRegistrationConf({ ...newConf }) - // } - - return ( -
- {/* actionHandler(e, 'update')} - className="wdt-200 mt-4 mr-2" - value="user_update" - title={__('Update User', 'bit-integrations')} - subTitle={__('Update existing user if user already exists', 'bit-integrations')} - /> */} -
- ) -} diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipAuthorization.jsx b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipAuthorization.jsx deleted file mode 100644 index bbedd0f4..00000000 --- a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipAuthorization.jsx +++ /dev/null @@ -1,84 +0,0 @@ -import { useState } from 'react' -import { __ } from '../../../Utils/i18nwrap' -import LoaderSm from '../../Loaders/LoaderSm' -import Note from '../../Utilities/Note' -import { userRegistrationAuthorize } from './UserRegistrationMembershipCommonFunc' -import tutorialLinks from '../../../Utils/StaticData/tutorialLinks' -import TutorialLink from '../../Utilities/TutorialLink' - -export default function UserRegistrationMembershipAuthorization({ - userRegistrationConf, - setUserRegistrationConf, - step, - nextPage, - isLoading, - setIsLoading, - setSnackbar -}) { - const [isAuthorized, setIsAuthorized] = useState(false) - const [showAuthMsg, setShowAuthMsg] = useState(false) - const { userRegistrationMembership } = tutorialLinks - - const handleAuthorize = () => { - userRegistrationAuthorize(setIsAuthorized, setShowAuthMsg, setIsLoading, setSnackbar, nextPage) - } - - return ( -
- {userRegistrationMembership?.youTubeLink && ( - - )} - {userRegistrationMembership?.docLink && ( - - )} - -
- {__('Integration Name:', 'bit-integrations')} -
- setUserRegistrationConf({ ...userRegistrationConf, name: e.target.value })} - name="name" - value={userRegistrationConf.name} - type="text" - placeholder={__('Integration Name...', 'bit-integrations')} - disabled={isAuthorized} - /> - - -
- {showAuthMsg && isAuthorized && ( -
- -
- )} - -
- ) -} diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipCommonFunc.js b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipCommonFunc.js deleted file mode 100644 index acc6d2aa..00000000 --- a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipCommonFunc.js +++ /dev/null @@ -1,161 +0,0 @@ -import { __ } from '../../../Utils/i18nwrap' -import bitsFetch from '../../../Utils/bitsFetch' - -export const handleInput = (e, userRegistrationConf, setUserRegistrationConf) => { - const { name, value } = e.target - const newConf = { ...userRegistrationConf } - newConf[name] = value - setUserRegistrationConf(newConf) -} - -export const userRegistrationAuthorize = ( - setIsAuthorized, - setShowAuthMsg, - setIsLoading, - setSnackbar, - nextPage -) => { - setIsLoading(true) - bitsFetch({}, 'user_registration_authorize') - .then(result => { - if (result?.success) { - setIsAuthorized(true) - setShowAuthMsg(true) - setSnackbar({ - show: true, - msg: __('Connected Successfully', 'bit-integrations') - }) - nextPage(2) - } else { - setSnackbar({ - show: true, - msg: __( - result?.data || - 'Connection failed. Please make sure User Registration and Membership plugin is installed and activated.', - 'bit-integrations' - ) - }) - } - setIsLoading(false) - }) - .catch(error => { - setSnackbar({ - show: true, - msg: __('Connection failed', 'bit-integrations') - }) - setIsLoading(false) - }) -} - -export const refreshForms = ( - userRegistrationConf, - setUserRegistrationConf, - setIsLoading, - setSnackbar -) => { - setIsLoading(true) - bitsFetch({}, 'refresh_user_registration_forms') - .then(result => { - if (result?.success && result?.data) { - const newConf = { ...userRegistrationConf } - if (!newConf.default) { - newConf.default = {} - } - newConf.default.forms = result.data.forms || [] - setUserRegistrationConf(newConf) - setSnackbar({ - show: true, - msg: __('Forms refreshed successfully', 'bit-integrations') - }) - } else { - setSnackbar({ - show: true, - msg: __('Failed to refresh forms', 'bit-integrations') - }) - } - setIsLoading(false) - }) - .catch(() => { - setSnackbar({ - show: true, - msg: __('Failed to refresh forms', 'bit-integrations') - }) - setIsLoading(false) - }) -} - -export const refreshFormFields = ( - formId, - userRegistrationConf, - setUserRegistrationConf, - setIsLoading, - setSnackbar -) => { - if (!formId) { - return - } - - setIsLoading(true) - bitsFetch({ form_id: formId }, 'refresh_user_registration_form_fields') - .then(result => { - if (result?.success && result?.data) { - const newConf = { ...userRegistrationConf } - if (!newConf.default) { - newConf.default = {} - } - newConf.default.formFields = result.data.fields || [] - newConf.field_map = generateMappedField(newConf.default.formFields) - setUserRegistrationConf(newConf) - setSnackbar({ - show: true, - msg: __('Form fields refreshed successfully', 'bit-integrations') - }) - } else { - setSnackbar({ - show: true, - msg: __('Failed to refresh form fields', 'bit-integrations') - }) - } - setIsLoading(false) - }) - .catch(() => { - setSnackbar({ - show: true, - msg: __('Failed to refresh form fields', 'bit-integrations') - }) - setIsLoading(false) - }) -} - -export const generateMappedField = fields => { - const requiredFlds = fields.filter(fld => fld.required === true) - return requiredFlds.length > 0 - ? requiredFlds.map(field => ({ - formField: '', - userRegistrationField: field.value || field.key - })) - : [{ formField: '', userRegistrationField: '' }] -} - -export const checkMappedFields = userRegistrationConf => { - const { mainAction, field_map, selectedForm } = userRegistrationConf - - if (!mainAction || mainAction !== 'create_user') { - return false - } - - if (!selectedForm) { - return false - } - - const formFields = userRegistrationConf?.default?.formFields || [] - const requiredFields = formFields.filter(fld => fld.required === true || fld.required === 'true') - - if (requiredFields.length === 0) { - return field_map.length > 0 - } - - const mappedFields = field_map.map(field => field.userRegistrationField).filter(f => f) - - return requiredFields.every(reqField => mappedFields.includes(reqField.value)) -} diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipFieldMap.jsx b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipFieldMap.jsx deleted file mode 100644 index 548aabb2..00000000 --- a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipFieldMap.jsx +++ /dev/null @@ -1,114 +0,0 @@ -import { useRecoilValue } from 'recoil' -import { $appConfigState } from '../../../GlobalStates' -import { __, sprintf } from '../../../Utils/i18nwrap' -import { SmartTagField } from '../../../Utils/StaticData/SmartTagField' -import TagifyInput from '../../Utilities/TagifyInput' -import { - addFieldMap, - delFieldMap, - handleCustomValue, - handleFieldMapping -} from '../GlobalIntegrationHelper' - -export default function UserRegistrationMembershipFieldMap({ - i, - formFields, - field, - userRegistrationConf, - setUserRegistrationConf -}) { - const btcbi = useRecoilValue($appConfigState) - const { isPro } = btcbi - - const requiredFlds = - userRegistrationConf?.default?.formFields?.filter(fld => fld.required === true) || [] - const nonRequiredFlds = - userRegistrationConf?.default?.formFields?.filter(fld => fld.required === false) || [] - - return ( -
-
-
- - - {field.formField === 'custom' && ( - handleCustomValue(e, i, userRegistrationConf, setUserRegistrationConf)} - label={__('Custom Value', 'bit-integrations')} - className="mr-2" - type="text" - value={field.customValue} - placeholder={__('Custom Value', 'bit-integrations')} - formFields={formFields} - /> - )} - - -
- {i >= requiredFlds.length && ( - <> - - - - )} -
-
- ) -} diff --git a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx b/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx deleted file mode 100644 index adff766e..00000000 --- a/frontend-dev/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipIntegLayout.jsx +++ /dev/null @@ -1,174 +0,0 @@ -import { useEffect, useState } from 'react' -import MultiSelect from 'react-multiple-select-dropdown-lite' -import 'react-multiple-select-dropdown-lite/dist/index.css' -import { useRecoilValue } from 'recoil' -import { $appConfigState } from '../../../GlobalStates' -import { __ } from '../../../Utils/i18nwrap' -import Loader from '../../Loaders/Loader' -import { checkIsPro, getProLabel } from '../../Utilities/ProUtilHelpers' -import { addFieldMap, delFieldMap, handleFieldMapping } from '../IntegrationHelpers/IntegrationHelpers' -import UserRegistrationMembershipFieldMap from './UserRegistrationMembershipFieldMap' -import { refreshForms, refreshFormFields } from './UserRegistrationMembershipCommonFunc' - -export const modules = [ - { name: 'create_user', label: __('Create User', 'bit-integrations'), is_pro: true } -] - -export default function UserRegistrationMembershipIntegLayout({ - formFields, - userRegistrationConf, - setUserRegistrationConf, - setIsLoading, - isLoading, - setSnackbar -}) { - const btcbi = useRecoilValue($appConfigState) - const { isPro } = btcbi - - const changeHandler = (val, name) => { - const newConf = { ...userRegistrationConf } - - if (name === 'mainAction') { - newConf.mainAction = val - newConf.field_map = [{ formField: '', userRegistrationField: '' }] - - refreshForms(newConf, setUserRegistrationConf, setIsLoading, setSnackbar) - } else if (name === 'selectedForm') { - newConf.selectedForm = val - refreshFormFields(val, newConf, setUserRegistrationConf, setIsLoading, setSnackbar) - } else { - newConf[name] = val - } - - setUserRegistrationConf(newConf) - } - return ( - <> -
- -
- {__('Select Action:', 'bit-integrations')} - changeHandler(value, 'mainAction')} - options={modules?.map(module => ({ - label: checkIsPro(isPro, module.is_pro) ? module.label : getProLabel(module.label), - value: module.name, - disabled: checkIsPro(isPro, module.is_pro) ? false : true - }))} - singleSelect - closeOnSelect - /> -
- - {userRegistrationConf.mainAction === 'create_user' && ( - <> -
-
- {__('Select Form:', 'bit-integrations')} - - - - )} - - {isLoading && ( - - )} - - {userRegistrationConf.mainAction && userRegistrationConf.selectedForm && ( -
- {__('Map Fields', 'bit-integrations')} - -
- )} - - {userRegistrationConf.mainAction && userRegistrationConf.selectedForm && ( - <> -
-
-
- {__('Form Fields', 'bit-integrations')} -
-
- {__('User Registration Fields', 'bit-integrations')} -
-
- - {userRegistrationConf.field_map.map((itm, i) => ( - - ))} - -
- -
-
-
- - )} - - ) -} From f53f0665039bd3fa09b702ec8e646f79f1e29caf Mon Sep 17 00:00:00 2001 From: Rishad Alam <101513331+RishadAlam@users.noreply.github.com> Date: Mon, 16 Mar 2026 14:43:41 +0600 Subject: [PATCH 7/7] refactor: user registration and membership sanitize code --- .../RecordApiHelper.php | 2 +- .../UserRegistrationMembershipController.php | 8 ++--- .../components/AllIntegrations/IntegInfo.jsx | 6 ++-- .../UserRegistrationMembership.jsx | 8 ++--- .../UserRegistrationMembershipActions.jsx | 30 ------------------- ...serRegistrationMembershipAuthorization.jsx | 4 +-- .../UserRegistrationMembershipCommonFunc.js | 2 +- .../UserRegistrationMembershipIntegLayout.jsx | 5 ++-- 8 files changed, 15 insertions(+), 50 deletions(-) delete mode 100644 frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembershipActions.jsx diff --git a/backend/Actions/UserRegistrationMembership/RecordApiHelper.php b/backend/Actions/UserRegistrationMembership/RecordApiHelper.php index 0f79730f..db74686b 100644 --- a/backend/Actions/UserRegistrationMembership/RecordApiHelper.php +++ b/backend/Actions/UserRegistrationMembership/RecordApiHelper.php @@ -48,7 +48,7 @@ private function processAction($mainAction, $fieldData) { $defaultResponse = [ 'success' => false, - 'message' => wp_sprintf(__('%s plugin is not installed or activate', 'bit-integrations'), 'Bit Integrations Pro') + 'message' => wp_sprintf(__('%s plugin is not installed or activated', 'bit-integrations'), 'Bit Integrations Pro') ]; switch ($mainAction) { diff --git a/backend/Actions/UserRegistrationMembership/UserRegistrationMembershipController.php b/backend/Actions/UserRegistrationMembership/UserRegistrationMembershipController.php index 4c06b8b4..1551425f 100644 --- a/backend/Actions/UserRegistrationMembership/UserRegistrationMembershipController.php +++ b/backend/Actions/UserRegistrationMembership/UserRegistrationMembershipController.php @@ -15,7 +15,7 @@ public static function userRegistrationAuthorize() wp_send_json_success(true); } - public function refreshForms() + public static function refreshForms() { self::checkPluginExists(); @@ -39,7 +39,7 @@ public function refreshForms() wp_send_json_success(['forms' => $forms], 200); } - public function refreshFormFields($request) + public static function refreshFormFields($request) { self::checkPluginExists(); @@ -49,7 +49,7 @@ public function refreshFormFields($request) wp_send_json_error(__('Form ID is required', 'bit-integrations'), 400); } - $fields = $this->getFormFields($formId); + $fields = self::getFormFields($formId); wp_send_json_success(['fields' => array_values($fields)], 200); } @@ -68,7 +68,7 @@ public function execute($integrationData, $fieldValues) return $recordApiHelper->execute($fieldValues, $fieldMap); } - private function getFormFields($formId) + private static function getFormFields($formId) { if (!\function_exists('ur_get_form_fields')) { return []; diff --git a/frontend/src/components/AllIntegrations/IntegInfo.jsx b/frontend/src/components/AllIntegrations/IntegInfo.jsx index 2670e057..e546be47 100644 --- a/frontend/src/components/AllIntegrations/IntegInfo.jsx +++ b/frontend/src/components/AllIntegrations/IntegInfo.jsx @@ -284,9 +284,9 @@ export default function IntegInfo() { case 'User Registration & Membership': return ( ) case 'Zoho Bigin': diff --git a/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembership.jsx b/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembership.jsx index 8fc8bc65..d425b701 100644 --- a/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembership.jsx +++ b/frontend/src/components/AllIntegrations/UserRegistrationMembership/UserRegistrationMembership.jsx @@ -1,6 +1,6 @@ import { useState } from 'react' import 'react-multiple-select-dropdown-lite/dist/index.css' -import { useNavigate, useParams } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import BackIcn from '../../../Icons/BackIcn' import { __ } from '../../../Utils/i18nwrap' import SnackMsg from '../../Utilities/SnackMsg' @@ -82,11 +82,7 @@ export default function UserRegistrationMembership({ formFields, setFlow, flow,